GPU workaround to simulate Out of Memory errors with large textures
[chromium-blink-merge.git] / content / common / gpu / media / fake_video_decode_accelerator.cc
blob84a40eb9ba4801e254b64c2cf56cb687da046105
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"
7 #include "base/bind.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"
17 namespace content {
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(
28 gfx::GLContext* gl,
29 gfx::Size size,
30 const base::Callback<bool(void)>& make_context_current)
31 : child_message_loop_proxy_(base::MessageLoopProxy::current()),
32 client_(NULL),
33 make_context_current_(make_context_current),
34 gl_(gl),
35 frame_buffer_size_(size),
36 flushing_(false),
37 weak_this_factory_(this) {
40 FakeVideoDecodeAccelerator::~FakeVideoDecodeAccelerator() {
43 bool FakeVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
44 Client* client) {
45 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
46 if (profile == media::VIDEO_CODEC_PROFILE_UNKNOWN) {
47 LOG(ERROR) << "unknown codec profile";
48 return false;
50 // V4L2VideoDecodeAccelerator waits until first decode call to ask for buffers
51 // This class asks for it on initialization instead.
52 client_ = client;
53 client_->ProvidePictureBuffers(kNumBuffers,
54 frame_buffer_size_,
55 kDefaultTextureTarget);
56 return true;
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(
64 FROM_HERE,
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(),
79 UINT8_MAX,
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";
88 return;
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,
96 GL_RGBA,
97 frame_buffer_size_.width(),
98 frame_buffer_size_.height(),
100 GL_RGBA,
101 GL_UNSIGNED_BYTE,
102 data);
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(
111 FROM_HERE,
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(
119 FROM_HERE,
120 base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady,
121 weak_this_factory_.GetWeakPtr()));
124 void FakeVideoDecodeAccelerator::Flush() {
125 flushing_ = true;
126 child_message_loop_proxy_->PostTask(
127 FROM_HERE,
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();
145 delete this;
148 bool FakeVideoDecodeAccelerator::CanDecodeOnIOThread() {
149 return true;
152 void FakeVideoDecodeAccelerator::DoPictureReady() {
153 if (flushing_ && queued_bitstream_ids_.empty()) {
154 flushing_ = false;
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,
165 bitstream_id,
166 gfx::Rect(frame_buffer_size_),
167 false);
168 client_->PictureReady(picture);
169 // Bitstream no longer needed.
170 client_->NotifyEndOfBitstreamBuffer(bitstream_id);
171 if (flushing_ && queued_bitstream_ids_.empty()) {
172 flushing_ = false;
173 client_->NotifyFlushDone();
178 } // namespace content