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 "media/base/bitstream_buffer.h"
10 #include "media/base/limits.h"
11 #include "ui/gl/gl_context.h"
12 #include "ui/gl/gl_implementation.h"
13 #include "ui/gl/gl_surface.h"
14 #include "ui/gl/gl_surface_egl.h"
15 #include "ui/gl/gl_surface_glx.h"
19 static const uint32 kDefaultTextureTarget
= GL_TEXTURE_2D
;
20 // Must be at least 2 since the rendering helper will switch between textures
21 // and if there is only one, it will wait for the next one that will never come.
22 // Must also be an even number as otherwise there won't be the same amount of
23 // white and black frames.
24 static const unsigned int kNumBuffers
= media::limits::kMaxVideoFrames
+
25 (media::limits::kMaxVideoFrames
& 1u);
27 FakeVideoDecodeAccelerator::FakeVideoDecodeAccelerator(
30 const base::Callback
<bool(void)>& make_context_current
)
31 : child_message_loop_proxy_(base::MessageLoopProxy::current()),
33 make_context_current_(make_context_current
),
35 frame_buffer_size_(size
),
37 weak_this_factory_(this) {
40 FakeVideoDecodeAccelerator::~FakeVideoDecodeAccelerator() {
43 bool FakeVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile
,
45 DCHECK(child_message_loop_proxy_
->BelongsToCurrentThread());
46 if (profile
== media::VIDEO_CODEC_PROFILE_UNKNOWN
) {
47 LOG(ERROR
) << "unknown codec profile";
50 // V4L2VideoDecodeAccelerator waits until first decode call to ask for buffers
51 // This class asks for it on initialization instead.
53 client_
->ProvidePictureBuffers(kNumBuffers
,
55 kDefaultTextureTarget
);
59 void FakeVideoDecodeAccelerator::Decode(
60 const media::BitstreamBuffer
& bitstream_buffer
) {
61 int bitstream_buffer_id
= bitstream_buffer
.id();
62 queued_bitstream_ids_
.push(bitstream_buffer_id
);
63 child_message_loop_proxy_
->PostTask(
65 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_message_loop_proxy_
->PostTask(
112 base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady
,
113 weak_this_factory_
.GetWeakPtr()));
116 void FakeVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id
) {
117 free_output_buffers_
.push(picture_buffer_id
);
118 child_message_loop_proxy_
->PostTask(
120 base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady
,
121 weak_this_factory_
.GetWeakPtr()));
124 void FakeVideoDecodeAccelerator::Flush() {
126 child_message_loop_proxy_
->PostTask(
128 base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady
,
129 weak_this_factory_
.GetWeakPtr()));
132 void FakeVideoDecodeAccelerator::Reset() {
133 while (!queued_bitstream_ids_
.empty()) {
134 client_
->NotifyEndOfBitstreamBuffer(queued_bitstream_ids_
.front());
135 queued_bitstream_ids_
.pop();
137 client_
->NotifyResetDone();
140 void FakeVideoDecodeAccelerator::Destroy() {
141 while (!queued_bitstream_ids_
.empty()) {
142 client_
->NotifyEndOfBitstreamBuffer(queued_bitstream_ids_
.front());
143 queued_bitstream_ids_
.pop();
148 bool FakeVideoDecodeAccelerator::CanDecodeOnIOThread() {
152 void FakeVideoDecodeAccelerator::DoPictureReady() {
153 if (flushing_
&& queued_bitstream_ids_
.empty()) {
155 client_
->NotifyFlushDone();
157 while (!free_output_buffers_
.empty() && !queued_bitstream_ids_
.empty()) {
158 int bitstream_id
= queued_bitstream_ids_
.front();
159 queued_bitstream_ids_
.pop();
160 int buffer_id
= free_output_buffers_
.front();
161 free_output_buffers_
.pop();
163 const media::Picture picture
=
164 media::Picture(buffer_id
,
166 gfx::Rect(frame_buffer_size_
),
168 client_
->PictureReady(picture
);
169 // Bitstream no longer needed.
170 client_
->NotifyEndOfBitstreamBuffer(bitstream_id
);
171 if (flushing_
&& queued_bitstream_ids_
.empty()) {
173 client_
->NotifyFlushDone();
178 } // namespace content