1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/common/gpu/media/fake_video_decode_accelerator.h"
8 #include "base/location.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "media/base/bitstream_buffer.h"
11 #include "media/base/limits.h"
12 #include "ui/gl/gl_context.h"
13 #include "ui/gl/gl_implementation.h"
14 #include "ui/gl/gl_surface.h"
15 #include "ui/gl/gl_surface_egl.h"
16 #include "ui/gl/gl_surface_glx.h"
20 static const uint32 kDefaultTextureTarget
= GL_TEXTURE_2D
;
21 // Must be at least 2 since the rendering helper will switch between textures
22 // and if there is only one, it will wait for the next one that will never come.
23 // Must also be an even number as otherwise there won't be the same amount of
24 // white and black frames.
25 static const unsigned int kNumBuffers
= media::limits::kMaxVideoFrames
+
26 (media::limits::kMaxVideoFrames
& 1u);
28 FakeVideoDecodeAccelerator::FakeVideoDecodeAccelerator(
31 const base::Callback
<bool(void)>& make_context_current
)
32 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
34 make_context_current_(make_context_current
),
36 frame_buffer_size_(size
),
38 weak_this_factory_(this) {
41 FakeVideoDecodeAccelerator::~FakeVideoDecodeAccelerator() {
44 bool FakeVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile
,
46 DCHECK(child_task_runner_
->BelongsToCurrentThread());
47 if (profile
== media::VIDEO_CODEC_PROFILE_UNKNOWN
) {
48 LOG(ERROR
) << "unknown codec profile";
51 // V4L2VideoDecodeAccelerator waits until first decode call to ask for buffers
52 // This class asks for it on initialization instead.
54 client_
->ProvidePictureBuffers(kNumBuffers
,
56 kDefaultTextureTarget
);
60 void FakeVideoDecodeAccelerator::Decode(
61 const media::BitstreamBuffer
& bitstream_buffer
) {
62 int bitstream_buffer_id
= bitstream_buffer
.id();
63 queued_bitstream_ids_
.push(bitstream_buffer_id
);
64 child_task_runner_
->PostTask(
65 FROM_HERE
, base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady
,
66 weak_this_factory_
.GetWeakPtr()));
69 // Similar to UseOutputBitstreamBuffer for the encode accelerator.
70 void FakeVideoDecodeAccelerator::AssignPictureBuffers(
71 const std::vector
<media::PictureBuffer
>& buffers
) {
72 DCHECK(buffers
.size() == kNumBuffers
);
73 DCHECK(!(buffers
.size()%2));
75 // Save buffers and mark all buffers as ready for use.
76 scoped_ptr
<uint8
[]> white_data(
77 new uint8
[frame_buffer_size_
.width() * frame_buffer_size_
.height() * 4]);
78 memset(white_data
.get(),
80 frame_buffer_size_
.width() * frame_buffer_size_
.height() * 4);
81 scoped_ptr
<uint8
[]> black_data(
82 new uint8
[frame_buffer_size_
.width() * frame_buffer_size_
.height() * 4]);
83 memset(black_data
.get(),
85 frame_buffer_size_
.width() * frame_buffer_size_
.height() * 4);
86 if (!make_context_current_
.Run()) {
87 LOG(ERROR
) << "ReusePictureBuffer(): could not make context current";
90 for (size_t index
= 0; index
< buffers
.size(); ++index
) {
91 glBindTexture(GL_TEXTURE_2D
, buffers
[index
].texture_id());
92 // Every other frame white and the rest black.
93 uint8
* data
= index
%2 ? white_data
.get():black_data
.get();
94 glTexImage2D(GL_TEXTURE_2D
,
97 frame_buffer_size_
.width(),
98 frame_buffer_size_
.height(),
103 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
104 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
105 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
106 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
107 glBindTexture(GL_TEXTURE_2D
, 0);
108 free_output_buffers_
.push(buffers
[index
].id());
110 child_task_runner_
->PostTask(
111 FROM_HERE
, base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady
,
112 weak_this_factory_
.GetWeakPtr()));
115 void FakeVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id
) {
116 free_output_buffers_
.push(picture_buffer_id
);
117 child_task_runner_
->PostTask(
118 FROM_HERE
, base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady
,
119 weak_this_factory_
.GetWeakPtr()));
122 void FakeVideoDecodeAccelerator::Flush() {
124 child_task_runner_
->PostTask(
125 FROM_HERE
, base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady
,
126 weak_this_factory_
.GetWeakPtr()));
129 void FakeVideoDecodeAccelerator::Reset() {
130 while (!queued_bitstream_ids_
.empty()) {
131 client_
->NotifyEndOfBitstreamBuffer(queued_bitstream_ids_
.front());
132 queued_bitstream_ids_
.pop();
134 client_
->NotifyResetDone();
137 void FakeVideoDecodeAccelerator::Destroy() {
138 while (!queued_bitstream_ids_
.empty()) {
139 client_
->NotifyEndOfBitstreamBuffer(queued_bitstream_ids_
.front());
140 queued_bitstream_ids_
.pop();
145 bool FakeVideoDecodeAccelerator::CanDecodeOnIOThread() {
149 void FakeVideoDecodeAccelerator::DoPictureReady() {
150 if (flushing_
&& queued_bitstream_ids_
.empty()) {
152 client_
->NotifyFlushDone();
154 while (!free_output_buffers_
.empty() && !queued_bitstream_ids_
.empty()) {
155 int bitstream_id
= queued_bitstream_ids_
.front();
156 queued_bitstream_ids_
.pop();
157 int buffer_id
= free_output_buffers_
.front();
158 free_output_buffers_
.pop();
160 const media::Picture picture
=
161 media::Picture(buffer_id
,
163 gfx::Rect(frame_buffer_size_
),
165 client_
->PictureReady(picture
);
166 // Bitstream no longer needed.
167 client_
->NotifyEndOfBitstreamBuffer(bitstream_id
);
168 if (flushing_
&& queued_bitstream_ids_
.empty()) {
170 client_
->NotifyFlushDone();
175 } // namespace content