Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(771)

Side by Side Diff: content/common/gpu/media/vaapi_video_decode_accelerator.cc

Issue 14914009: VAVDA: Redesign stage 1. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/bind.h" 5 #include "base/bind.h"
6 #include "base/command_line.h"
7 #include "base/debug/trace_event.h" 6 #include "base/debug/trace_event.h"
8 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "base/synchronization/waitable_event.h" 11 #include "base/synchronization/waitable_event.h"
12 #include "gpu/command_buffer/service/gpu_switches.h"
13 #include "content/public/common/content_switches.h"
14 #include "content/common/gpu/gpu_channel.h" 12 #include "content/common/gpu/gpu_channel.h"
15 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" 13 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
16 #include "media/base/bind_to_loop.h" 14 #include "media/base/bind_to_loop.h"
17 #include "media/video/picture.h" 15 #include "media/video/picture.h"
18 #include "third_party/libva/va/va.h"
19 #include "ui/gl/gl_bindings.h" 16 #include "ui/gl/gl_bindings.h"
17 #include "ui/gl/scoped_binders.h"
18
19 namespace {
20
21 static void ReportToUMA(
22 content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) {
23 UMA_HISTOGRAM_ENUMERATION(
24 "Media.VAVDAH264.DecoderFailure",
25 failure,
26 content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX);
27 }
28
29 } // namespace
20 30
21 namespace content { 31 namespace content {
22 32
23 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \ 33 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \
24 do { \ 34 do { \
25 if (!(result)) { \ 35 if (!(result)) { \
26 DVLOG(1) << log; \ 36 DVLOG(1) << log; \
27 NotifyError(error_code); \ 37 NotifyError(error_code); \
28 return ret; \ 38 return ret; \
29 } \ 39 } \
(...skipping 17 matching lines...) Expand all
47 message_loop_->PostTask(FROM_HERE, base::Bind( 57 message_loop_->PostTask(FROM_HERE, base::Bind(
48 &VaapiVideoDecodeAccelerator::Cleanup, weak_this_)); 58 &VaapiVideoDecodeAccelerator::Cleanup, weak_this_));
49 59
50 DVLOG(1) << "Notifying of error " << error; 60 DVLOG(1) << "Notifying of error " << error;
51 if (client_) { 61 if (client_) {
52 client_->NotifyError(error); 62 client_->NotifyError(error);
53 client_ptr_factory_.InvalidateWeakPtrs(); 63 client_ptr_factory_.InvalidateWeakPtrs();
54 } 64 }
55 } 65 }
56 66
67 // TFPPicture allocates X Pixmaps and binds them to textures passed
68 // in PictureBuffers from clients to them. TFPPictures are created as
69 // a consequence of receiving a set of PictureBuffers from clients and released
70 // at the end of decode (or when a new set of PictureBuffers is required).
71 //
72 // TFPPictures are used for output, contents of VASurfaces passed from decoder
73 // are put into the associated pixmap memory and sent to client.
74 class VaapiVideoDecodeAccelerator::TFPPicture {
75 public:
76 ~TFPPicture();
77
78 static linked_ptr<TFPPicture> Create(
79 const base::Callback<bool(void)>& make_context_current,
80 const GLXFBConfig& fb_config,
Ami GONE FROM CHROMIUM 2013/05/22 23:59:47 I was asking for the members, accessors, params to
Pawel Osciak 2013/05/24 01:46:39 Done.
81 Display* x_display,
82 int32 picture_buffer_id,
83 uint32 texture_id,
84 gfx::Size size);
85
86 int32 picture_buffer_id() {
87 return picture_buffer_id_;
88 }
89
90 uint32 texture_id() {
91 return texture_id_;
92 }
93
94 gfx::Size size() {
95 return size_;
96 }
97
98 int x_pixmap() {
99 return x_pixmap_;
100 }
101
102 // Bind texture to pixmap. Needs to be called every frame.
103 bool Bind();
104
105 private:
106 TFPPicture(const base::Callback<bool(void)>& make_context_current,
107 Display* x_display,
108 int32 picture_buffer_id,
109 uint32 texture_id,
110 gfx::Size size);
111
112 bool Initialize(const GLXFBConfig& fb_config);
113
114 base::Callback<bool(void)> make_context_current_;
115
116 // Output id for the client.
117 int32 picture_buffer_id_;
118 uint32 texture_id_;
119
120 gfx::Size size_;
121
122 // Pixmaps bound to this texture.
123 Pixmap x_pixmap_;
124 GLXPixmap glx_pixmap_;
125
126 Display* x_display_;
127
128 DISALLOW_COPY_AND_ASSIGN(TFPPicture);
129 };
130
131 VaapiVideoDecodeAccelerator::TFPPicture::TFPPicture(
132 const base::Callback<bool(void)>& make_context_current,
133 Display* x_display,
134 int32 picture_buffer_id,
135 uint32 texture_id,
136 gfx::Size size)
137 : make_context_current_(make_context_current),
138 picture_buffer_id_(picture_buffer_id),
139 texture_id_(texture_id),
140 size_(size),
141 x_pixmap_(0),
142 glx_pixmap_(0),
143 x_display_(x_display) {
144 DCHECK(!make_context_current_.is_null());
145 };
146
147 linked_ptr<VaapiVideoDecodeAccelerator::TFPPicture>
148 VaapiVideoDecodeAccelerator::TFPPicture::Create(
149 const base::Callback<bool(void)>& make_context_current,
150 const GLXFBConfig& fb_config,
151 Display* x_display,
152 int32 picture_buffer_id,
153 uint32 texture_id,
154 gfx::Size size) {
155
156 linked_ptr<TFPPicture> tfp_picture(
157 new TFPPicture(make_context_current, x_display, picture_buffer_id,
158 texture_id, size));
159
160 if (!tfp_picture->Initialize(fb_config))
161 tfp_picture.reset();
162
163 return tfp_picture;
164 }
165
166 bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize(
167 const GLXFBConfig& fb_config) {
168 if (!make_context_current_.Run())
169 return false;
170
171 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
172 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
173
174 XWindowAttributes win_attr;
175 int screen = DefaultScreen(x_display_);
176 XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr);
177 //TODO(posciak): pass the depth required by libva, not the RootWindow's depth
178 x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen),
179 size_.width(), size_.height(), win_attr.depth);
180 if (!x_pixmap_) {
181 DVLOG(1) << "Failed creating an X Pixmap for TFP";
182 return NULL;
183 }
184
185 static const int pixmap_attr[] = {
186 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
187 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
188 GL_NONE,
189 };
190
191 glx_pixmap_ = glXCreatePixmap(x_display_, fb_config, x_pixmap_, pixmap_attr);
192 if (!glx_pixmap_) {
193 // x_pixmap_ will be freed in the destructor.
194 DVLOG(1) << "Failed creating a GLX Pixmap for TFP";
195 return NULL;
196 }
197
198 return true;
199 }
200
201 VaapiVideoDecodeAccelerator::TFPPicture::~TFPPicture() {
202 // Unbind surface from texture and deallocate resources.
203 if (glx_pixmap_ && make_context_current_.Run()) {
204 glXReleaseTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT);
205 glXDestroyPixmap(x_display_, glx_pixmap_);
206 }
207
208 if (x_pixmap_)
209 XFreePixmap(x_display_, x_pixmap_);
210 XSync(x_display_, False); // Needed to work around buggy vdpau-driver.
211 }
212
213 bool VaapiVideoDecodeAccelerator::TFPPicture::Bind() {
214 DCHECK(x_pixmap_);
215 DCHECK(glx_pixmap_);
marcheu 2013/05/23 03:02:55 Maybe here CHECK/DCHECK that you're on the main th
Pawel Osciak 2013/05/24 01:46:39 I didn't want to pass message loops to TFPPicture.
216
217 if (!make_context_current_.Run())
218 return false;
219
220 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_);
221 glXBindTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL);
222
223 return true;
224 }
225
226 VaapiVideoDecodeAccelerator::TFPPicture*
227 VaapiVideoDecodeAccelerator::TFPPictureById(int32 picture_buffer_id) {
228 TFPPictures::iterator it = tfp_pictures_.find(picture_buffer_id);
229 if (it == tfp_pictures_.end()) {
230 DVLOG(1) << "Picture id " << picture_buffer_id << " does not exist";
231 return NULL;
232 }
233
234 return it->second.get();
235 }
236
57 VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( 237 VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator(
58 Display* x_display, GLXContext glx_context, 238 Display* x_display, GLXContext glx_context,
59 Client* client, 239 Client* client,
60 const base::Callback<bool(void)>& make_context_current) 240 const base::Callback<bool(void)>& make_context_current)
61 : x_display_(x_display), 241 : x_display_(x_display),
62 glx_context_(glx_context), 242 glx_context_(glx_context),
63 make_context_current_(make_context_current), 243 make_context_current_(make_context_current),
64 state_(kUninitialized), 244 state_(kUninitialized),
65 input_ready_(&lock_), 245 input_ready_(&lock_),
66 output_ready_(&lock_), 246 surfaces_available_(&lock_),
67 message_loop_(base::MessageLoop::current()), 247 message_loop_(base::MessageLoop::current()),
68 weak_this_(base::AsWeakPtr(this)), 248 weak_this_(base::AsWeakPtr(this)),
69 client_ptr_factory_(client), 249 client_ptr_factory_(client),
70 client_(client_ptr_factory_.GetWeakPtr()), 250 client_(client_ptr_factory_.GetWeakPtr()),
71 decoder_thread_("VaapiDecoderThread"), 251 decoder_thread_("VaapiDecoderThread"),
72 num_frames_at_client_(0), 252 num_frames_at_client_(0),
73 num_stream_bufs_at_decoder_(0) { 253 num_stream_bufs_at_decoder_(0) {
74 DCHECK(client); 254 DCHECK(client);
75 static bool vaapi_functions_initialized = PostSandboxInitialization();
76 RETURN_AND_NOTIFY_ON_FAILURE(vaapi_functions_initialized,
77 "Failed to initialize VAAPI libs",
78 PLATFORM_FAILURE, );
79 } 255 }
80 256
81 VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { 257 VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() {
82 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 258 DCHECK_EQ(message_loop_, base::MessageLoop::current());
83 } 259 }
84 260
261 class ScopedPtrXFree {
262 public:
263 void operator()(void* x) const {
264 ::XFree(x);
265 }
266 };
267
268 bool VaapiVideoDecodeAccelerator::InitializeFBConfig() {
269 const int fbconfig_attr[] = {
270 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
271 GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
272 GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE,
273 GLX_Y_INVERTED_EXT, GL_TRUE,
274 GL_NONE,
275 };
276
277 int num_fbconfigs;
278 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> glx_fb_configs(
279 glXChooseFBConfig(x_display_, DefaultScreen(x_display_), fbconfig_attr,
280 &num_fbconfigs));
281 if (!glx_fb_configs)
282 return false;
283 if (!num_fbconfigs)
284 return false;
285
286 fb_config_ = glx_fb_configs.get()[0];
287 return true;
288 }
289
85 bool VaapiVideoDecodeAccelerator::Initialize( 290 bool VaapiVideoDecodeAccelerator::Initialize(
86 media::VideoCodecProfile profile) { 291 media::VideoCodecProfile profile) {
87 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 292 DCHECK_EQ(message_loop_, base::MessageLoop::current());
88 293
89 base::AutoLock auto_lock(lock_); 294 base::AutoLock auto_lock(lock_);
90 DCHECK_EQ(state_, kUninitialized); 295 DCHECK_EQ(state_, kUninitialized);
91 DVLOG(2) << "Initializing VAVDA, profile: " << profile; 296 DVLOG(2) << "Initializing VAVDA, profile: " << profile;
92 297
93 bool res = decoder_.Initialize( 298 if (!make_context_current_.Run())
94 profile, x_display_, glx_context_, make_context_current_, 299 return false;
95 media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind( 300
96 &VaapiVideoDecodeAccelerator::NotifyPictureReady, weak_this_)), 301 if (!InitializeFBConfig()) {
97 media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind( 302 DVLOG(1) << "Could not get a usable FBConfig";
98 &VaapiVideoDecodeAccelerator::SubmitDecode, weak_this_)));
99 if (!res) {
100 DVLOG(1) << "Failed initializing decoder";
101 return false; 303 return false;
102 } 304 }
103 305
306 vaapi_delegate_ = VaapiDelegate::Create(
307 profile, x_display_,
308 base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR));
309
310 if (!vaapi_delegate_.get()) {
311 DVLOG(1) << "Failed initializing VAAPI";
312 return false;
313 }
314
315 decoder_.reset(
316 new VaapiH264Decoder(
317 vaapi_delegate_,
318 media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind(
319 &VaapiVideoDecodeAccelerator::SurfaceReady, weak_this_)),
320 base::Bind(&ReportToUMA)));
321
104 CHECK(decoder_thread_.Start()); 322 CHECK(decoder_thread_.Start());
105 323
106 state_ = kInitialized; 324 state_ = kInitialized;
107 325
108 message_loop_->PostTask(FROM_HERE, base::Bind( 326 message_loop_->PostTask(FROM_HERE, base::Bind(
109 &Client::NotifyInitializeDone, client_)); 327 &Client::NotifyInitializeDone, client_));
110 return true; 328 return true;
111 } 329 }
112 330
113 void VaapiVideoDecodeAccelerator::SubmitDecode( 331 void VaapiVideoDecodeAccelerator::SurfaceReady(
114 int32 output_id, 332 int32 input_id,
115 scoped_ptr<std::queue<VABufferID> > va_bufs, 333 const scoped_refptr<VASurface>& va_surface) {
116 scoped_ptr<std::queue<VABufferID> > slice_bufs) {
117 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 334 DCHECK_EQ(message_loop_, base::MessageLoop::current());
118 base::AutoLock auto_lock(lock_);
119 335
120 TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "output_id", output_id); 336 // Drop any requests to output if we are resetting.
337 if (state_ == kResetting || state_ == kDestroying)
338 return;
339
340 pending_output_cbs_.push(
341 base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture,
342 weak_this_, va_surface, input_id));
343
344 TryOutputSurface();
345 }
346
347 void VaapiVideoDecodeAccelerator::OutputPicture(
348 const scoped_refptr<VASurface>& va_surface,
349 int32 input_id,
350 TFPPicture* tfp_picture) {
351 DCHECK_EQ(message_loop_, base::MessageLoop::current());
352
353 int32 output_id = tfp_picture->picture_buffer_id();
354
355 TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface",
356 "input_id", input_id,
357 "output_id", output_id);
358
359 DVLOG(3) << "Outputting VASurface " << va_surface->id()
360 << " into pixmap bound to picture buffer id " << output_id;
361
362 RETURN_AND_NOTIFY_ON_FAILURE(tfp_picture->Bind(),
363 "Failed binding texture to pixmap",
364 PLATFORM_FAILURE, );
365
366 RETURN_AND_NOTIFY_ON_FAILURE(
367 vaapi_delegate_->PutSurfaceIntoPixmap(va_surface->id(),
368 tfp_picture->x_pixmap(),
369 tfp_picture->size()),
370 "Failed putting surface into pixmap", PLATFORM_FAILURE, );
371
372 // Notify the client a picture is ready to be displayed.
373 ++num_frames_at_client_;
374 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
375 DVLOG(4) << "Notifying output picture id " << output_id
376 << " for input "<< input_id << " is ready";
377 client_->PictureReady(media::Picture(output_id, input_id));
378 }
379
380 void VaapiVideoDecodeAccelerator::TryOutputSurface() {
381 DCHECK_EQ(message_loop_, base::MessageLoop::current());
121 382
122 // Handle Destroy() arriving while pictures are queued for output. 383 // Handle Destroy() arriving while pictures are queued for output.
123 if (!client_) 384 if (!client_)
124 return; 385 return;
125 386
126 RETURN_AND_NOTIFY_ON_FAILURE( 387 if (pending_output_cbs_.empty() || output_buffers_.empty())
127 decoder_.SubmitDecode(output_id, va_bufs.Pass(), slice_bufs.Pass()),
128 "Failed putting picture to texture",
129 PLATFORM_FAILURE, );
130 }
131
132 void VaapiVideoDecodeAccelerator::NotifyPictureReady(int32 input_id,
133 int32 output_id) {
134 DCHECK_EQ(message_loop_, base::MessageLoop::current());
135 TRACE_EVENT2("Video Decoder", "VAVDA::NotifyPictureReady",
136 "input_id", input_id, "output_id", output_id);
137
138 // Handle Destroy() arriving while pictures are queued for output.
139 if (!client_)
140 return; 388 return;
141 389
142 // Don't return any pictures that we might want to return during resetting 390 OutputCB output_cb = pending_output_cbs_.front();
143 // as a consequence of finishing up the decode that was running during 391 pending_output_cbs_.pop();
144 // Reset() call from the client. Reuse it instead.
145 {
146 base::AutoLock auto_lock(lock_);
147 if (state_ == kResetting) {
148 output_buffers_.push(output_id);
149 return;
150 }
151 }
152 392
153 ++num_frames_at_client_; 393 TFPPicture* tfp_picture = TFPPictureById(output_buffers_.front());
154 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); 394 DCHECK(tfp_picture);
395 output_buffers_.pop();
155 396
156 // Notify the client a picture is ready to be displayed. 397 output_cb.Run(tfp_picture);
157 DVLOG(4) << "Notifying output picture id " << output_id
158 << " for input "<< input_id << " is ready";
159 client_->PictureReady(media::Picture(output_id, input_id));
160 } 398 }
161 399
162 void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer( 400 void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer(
163 const media::BitstreamBuffer& bitstream_buffer) { 401 const media::BitstreamBuffer& bitstream_buffer) {
164 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 402 DCHECK_EQ(message_loop_, base::MessageLoop::current());
165 TRACE_EVENT1("Video Decoder", "MapAndQueueNewInputBuffer", "input_id", 403 TRACE_EVENT1("Video Decoder", "MapAndQueueNewInputBuffer", "input_id",
166 bitstream_buffer.id()); 404 bitstream_buffer.id());
167 405
168 DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id() 406 DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id()
169 << " size: " << (int)bitstream_buffer.size(); 407 << " size: " << (int)bitstream_buffer.size();
(...skipping 28 matching lines...) Expand all
198 DCHECK(curr_input_buffer_.get()); 436 DCHECK(curr_input_buffer_.get());
199 437
200 // Since multiple Decode()'s can be in flight at once, it's possible that a 438 // Since multiple Decode()'s can be in flight at once, it's possible that a
201 // Decode() that seemed like an initial one is actually later in the stream 439 // Decode() that seemed like an initial one is actually later in the stream
202 // and we're already kDecoding. Let the normal DecodeTask take over in that 440 // and we're already kDecoding. Let the normal DecodeTask take over in that
203 // case. 441 // case.
204 if (state_ != kInitialized && state_ != kIdle) 442 if (state_ != kInitialized && state_ != kIdle)
205 return; 443 return;
206 444
207 VaapiH264Decoder::DecResult res = 445 VaapiH264Decoder::DecResult res =
208 decoder_.DecodeInitial(curr_input_buffer_->id); 446 decoder_->DecodeInitial(curr_input_buffer_->id);
209 switch (res) { 447 switch (res) {
210 case VaapiH264Decoder::kReadyToDecode: 448 case VaapiH264Decoder::kReadyToDecode:
211 if (state_ == kInitialized) { 449 if (state_ == kInitialized) {
212 state_ = kPicturesRequested; 450 state_ = kPicturesRequested;
213 size_t num_pics = decoder_.GetRequiredNumOfPictures(); 451 num_pics_ = decoder_->GetRequiredNumOfPictures();
214 gfx::Size size(decoder_.pic_width(), decoder_.pic_height()); 452 pic_size_ = decoder_->GetPicSize();
215 DVLOG(1) << "Requesting " << num_pics << " pictures of size: " 453 DVLOG(1) << "Requesting " << num_pics_ << " pictures of size: "
216 << size.width() << "x" << size.height(); 454 << pic_size_.width() << "x" << pic_size_.height();
217 message_loop_->PostTask(FROM_HERE, base::Bind( 455 message_loop_->PostTask(FROM_HERE, base::Bind(
218 &Client::ProvidePictureBuffers, client_, 456 &Client::ProvidePictureBuffers, client_,
219 num_pics, size, GL_TEXTURE_2D)); 457 num_pics_, pic_size_, GL_TEXTURE_2D));
220 } else { 458 } else {
221 DCHECK_EQ(state_, kIdle); 459 DCHECK_EQ(state_, kIdle);
222 state_ = kDecoding; 460 state_ = kDecoding;
223 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( 461 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
224 &VaapiVideoDecodeAccelerator::DecodeTask, 462 &VaapiVideoDecodeAccelerator::DecodeTask,
225 base::Unretained(this))); 463 base::Unretained(this)));
226 } 464 }
227 return; 465 return;
228 466
229 case VaapiH264Decoder::kNeedMoreStreamData: 467 case VaapiH264Decoder::kNeedMoreStreamData:
230 ReturnCurrInputBuffer_Locked(); 468 ReturnCurrInputBuffer_Locked();
231 break; 469 break;
232 470
233 case VaapiH264Decoder::kNoOutputAvailable: 471 case VaapiH264Decoder::kNoOutputAvailable:
234 if (state_ == kIdle) { 472 if (state_ == kIdle) {
235 // No more output buffers in the decoder, try getting more or go to 473 // No more output buffers in the decoder, try getting more or go to
236 // sleep waiting for them. 474 // sleep waiting for them.
237 GetOutputBuffers_Locked(); 475 FeedDecoderWithOutputSurfaces_Locked();
238 return; 476 return;
239 } 477 }
240 // else fallthrough 478 // else fallthrough
241 case VaapiH264Decoder::kDecodeError: 479 case VaapiH264Decoder::kDecodeError:
242 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error in decoding", 480 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error in decoding",
243 PLATFORM_FAILURE, ); 481 PLATFORM_FAILURE, );
244 482
245 default: 483 default:
246 RETURN_AND_NOTIFY_ON_FAILURE(false, 484 RETURN_AND_NOTIFY_ON_FAILURE(false,
247 "Unexpected result from decoder: " << res, 485 "Unexpected result from decoder: " << res,
(...skipping 30 matching lines...) Expand all
278 case kIdle: 516 case kIdle:
279 DCHECK(!input_buffers_.empty()); 517 DCHECK(!input_buffers_.empty());
280 518
281 curr_input_buffer_ = input_buffers_.front(); 519 curr_input_buffer_ = input_buffers_.front();
282 input_buffers_.pop(); 520 input_buffers_.pop();
283 521
284 DVLOG(4) << "New current bitstream buffer, id: " 522 DVLOG(4) << "New current bitstream buffer, id: "
285 << curr_input_buffer_->id 523 << curr_input_buffer_->id
286 << " size: " << curr_input_buffer_->size; 524 << " size: " << curr_input_buffer_->size;
287 525
288 decoder_.SetStream( 526 decoder_->SetStream(
289 static_cast<uint8*>(curr_input_buffer_->shm->memory()), 527 static_cast<uint8*>(curr_input_buffer_->shm->memory()),
290 curr_input_buffer_->size); 528 curr_input_buffer_->size);
291 return true; 529 return true;
292 530
293 default: 531 default:
294 // We got woken up due to being destroyed/reset, ignore any already 532 // We got woken up due to being destroyed/reset, ignore any already
295 // queued inputs. 533 // queued inputs.
296 return false; 534 return false;
297 } 535 }
298 } 536 }
299 537
300 void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() { 538 void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() {
301 lock_.AssertAcquired(); 539 lock_.AssertAcquired();
302 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); 540 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
303 DCHECK(curr_input_buffer_.get()); 541 DCHECK(curr_input_buffer_.get());
304 542
305 int32 id = curr_input_buffer_->id; 543 int32 id = curr_input_buffer_->id;
306 curr_input_buffer_.reset(); 544 curr_input_buffer_.reset();
307 DVLOG(4) << "End of input buffer " << id; 545 DVLOG(4) << "End of input buffer " << id;
308 message_loop_->PostTask(FROM_HERE, base::Bind( 546 message_loop_->PostTask(FROM_HERE, base::Bind(
309 &Client::NotifyEndOfBitstreamBuffer, client_, id)); 547 &Client::NotifyEndOfBitstreamBuffer, client_, id));
310 548
311 --num_stream_bufs_at_decoder_; 549 --num_stream_bufs_at_decoder_;
312 TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder", 550 TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder",
313 num_stream_bufs_at_decoder_); 551 num_stream_bufs_at_decoder_);
314 } 552 }
315 553
316 bool VaapiVideoDecodeAccelerator::GetOutputBuffers_Locked() { 554 bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() {
317 lock_.AssertAcquired(); 555 lock_.AssertAcquired();
318 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); 556 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
319 557
320 while (output_buffers_.empty() && 558 while (available_va_surfaces_.empty() &&
321 (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) { 559 (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) {
322 output_ready_.Wait(); 560 surfaces_available_.Wait();
323 } 561 }
324 562
325 if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle) 563 if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle)
326 return false; 564 return false;
327 565
328 while (!output_buffers_.empty()) { 566 VASurface::ReleaseCB va_surface_release_cb =
329 decoder_.ReusePictureBuffer(output_buffers_.front()); 567 media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind(
330 output_buffers_.pop(); 568 &VaapiVideoDecodeAccelerator::RecycleVASurfaceID, weak_this_));
569
570 while (!available_va_surfaces_.empty()) {
571 scoped_refptr<VASurface> va_surface(
572 new VASurface(available_va_surfaces_.front(), va_surface_release_cb));
573 available_va_surfaces_.pop_front();
574 decoder_->ReuseSurface(va_surface);
331 } 575 }
332 576
333 return true; 577 return true;
334 } 578 }
335 579
336 void VaapiVideoDecodeAccelerator::DecodeTask() { 580 void VaapiVideoDecodeAccelerator::DecodeTask() {
337 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); 581 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
338 TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask"); 582 TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask");
339 base::AutoLock auto_lock(lock_); 583 base::AutoLock auto_lock(lock_);
340 584
341 // Main decode task. 585 // Main decode task.
342 DVLOG(4) << "Decode task"; 586 DVLOG(4) << "Decode task";
343 587
344 // Try to decode what stream data is (still) in the decoder until we run out 588 // Try to decode what stream data is (still) in the decoder until we run out
345 // of it. 589 // of it.
346 while (GetInputBuffer_Locked()) { 590 while (GetInputBuffer_Locked()) {
347 DCHECK(curr_input_buffer_.get()); 591 DCHECK(curr_input_buffer_.get());
348 592
349 VaapiH264Decoder::DecResult res; 593 VaapiH264Decoder::DecResult res;
350 res = decoder_.DecodeOneFrame(curr_input_buffer_->id); 594 {
595 // We are OK releasing the lock here, as decoder never calls our methods
596 // directly and we will reacquire the lock before looking at state again.
597 // This is the main decode function of the decoder and while keeping
598 // the lock for its duration would be fine, it would defeat the purpose
599 // of having a separate decoder thread.
600 base::AutoUnlock auto_unlock(lock_);
601 res = decoder_->DecodeOneFrame(curr_input_buffer_->id);
602 }
351 603
352 switch (res) { 604 switch (res) {
353 case VaapiH264Decoder::kNeedMoreStreamData: 605 case VaapiH264Decoder::kNeedMoreStreamData:
354 ReturnCurrInputBuffer_Locked(); 606 ReturnCurrInputBuffer_Locked();
355 break; 607 break;
356 608
357 case VaapiH264Decoder::kDecodedFrame:
358 // May still have more stream data, continue decoding.
359 break;
360
361 case VaapiH264Decoder::kNoOutputAvailable: 609 case VaapiH264Decoder::kNoOutputAvailable:
362 // No more output buffers in the decoder, try getting more or go to 610 // No more output buffers in the decoder, try getting more or go to
363 // sleep waiting for them. 611 // sleep waiting for them.
364 if (!GetOutputBuffers_Locked()) 612 if (!FeedDecoderWithOutputSurfaces_Locked())
365 return; 613 return;
366 break; 614 break;
367 615
368 case VaapiH264Decoder::kDecodeError: 616 case VaapiH264Decoder::kDecodeError:
369 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream", 617 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream",
370 PLATFORM_FAILURE, ); 618 PLATFORM_FAILURE, );
371 return; 619 return;
372 620
373 default: 621 default:
374 RETURN_AND_NOTIFY_ON_FAILURE( 622 RETURN_AND_NOTIFY_ON_FAILURE(
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 break; 664 break;
417 665
418 default: 666 default:
419 RETURN_AND_NOTIFY_ON_FAILURE(false, 667 RETURN_AND_NOTIFY_ON_FAILURE(false,
420 "Decode request from client in invalid state: " << state_, 668 "Decode request from client in invalid state: " << state_,
421 PLATFORM_FAILURE, ); 669 PLATFORM_FAILURE, );
422 return; 670 return;
423 } 671 }
424 } 672 }
425 673
674 void VaapiVideoDecodeAccelerator::RecycleVASurfaceID(
675 VASurfaceID va_surface_id) {
676 DCHECK_EQ(message_loop_, base::MessageLoop::current());
677
678 base::AutoLock auto_lock(lock_);
679
680 available_va_surfaces_.push_back(va_surface_id);
681 surfaces_available_.Signal();
682 }
683
426 void VaapiVideoDecodeAccelerator::AssignPictureBuffers( 684 void VaapiVideoDecodeAccelerator::AssignPictureBuffers(
427 const std::vector<media::PictureBuffer>& buffers) { 685 const std::vector<media::PictureBuffer>& buffers) {
428 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 686 DCHECK_EQ(message_loop_, base::MessageLoop::current());
429 687
430 base::AutoLock auto_lock(lock_); 688 base::AutoLock auto_lock(lock_);
431 DCHECK_EQ(state_, kPicturesRequested); 689 DCHECK_EQ(state_, kPicturesRequested);
432 size_t num_pics = decoder_.GetRequiredNumOfPictures(); 690 DCHECK(tfp_pictures_.empty());
433 RETURN_AND_NOTIFY_ON_FAILURE((num_pics == buffers.size()), 691
434 "Failed to provide requested picture buffers. (Got " << buffers.size() << 692 RETURN_AND_NOTIFY_ON_FAILURE(
435 ", requested " << num_pics << ")", INVALID_ARGUMENT,); 693 buffers.size() == num_pics_,
694 "Got an invalid number of picture buffers. (Got " << buffers.size()
695 << ", requested " << num_pics_ << ")", INVALID_ARGUMENT, );
696
697 std::vector<VASurfaceID> va_surface_ids;
698 RETURN_AND_NOTIFY_ON_FAILURE(
699 vaapi_delegate_->CreateSurfaces(pic_size_,
700 buffers.size(),
701 &va_surface_ids),
702 "Failed creating VA Surfaces", PLATFORM_FAILURE, );
703 DCHECK_EQ(va_surface_ids.size(), buffers.size());
436 704
437 for (size_t i = 0; i < buffers.size(); ++i) { 705 for (size_t i = 0; i < buffers.size(); ++i) {
438 DVLOG(2) << "Assigning picture id " << buffers[i].id() 706 DVLOG(2) << "Assigning picture id: " << buffers[i].id()
439 << " to texture id " << buffers[i].texture_id(); 707 << " to texture id: " << buffers[i].texture_id()
708 << " VASurfaceID: " << va_surface_ids[i];
440 709
441 bool res = decoder_.AssignPictureBuffer(buffers[i].id(), 710 linked_ptr<TFPPicture> tfp_picture(
442 buffers[i].texture_id()); 711 TFPPicture::Create(make_context_current_, fb_config_, x_display_,
712 buffers[i].id(), buffers[i].texture_id(),
713 pic_size_));
714
443 RETURN_AND_NOTIFY_ON_FAILURE( 715 RETURN_AND_NOTIFY_ON_FAILURE(
444 res, "Failed assigning picture buffer id: " << buffers[i].id() << 716 tfp_picture.get(), "Failed assigning picture buffer to a texture.",
445 ", texture id: " << buffers[i].texture_id(), PLATFORM_FAILURE, ); 717 PLATFORM_FAILURE, );
718
719 bool inserted = tfp_pictures_.insert(std::make_pair(
720 buffers[i].id(), tfp_picture)).second;
721 DCHECK(inserted);
722
723 output_buffers_.push(buffers[i].id());
724 available_va_surfaces_.push_back(va_surface_ids[i]);
725 surfaces_available_.Signal();
446 } 726 }
447 727
448 state_ = kDecoding; 728 state_ = kDecoding;
449 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( 729 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
450 &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this))); 730 &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this)));
451 } 731 }
452 732
453 void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { 733 void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
454 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 734 DCHECK_EQ(message_loop_, base::MessageLoop::current());
455 TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id", 735 TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id",
456 picture_buffer_id); 736 picture_buffer_id);
457 737
458 --num_frames_at_client_; 738 --num_frames_at_client_;
459 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); 739 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
460 740
461 base::AutoLock auto_lock(lock_);
462 output_buffers_.push(picture_buffer_id); 741 output_buffers_.push(picture_buffer_id);
463 output_ready_.Signal(); 742 TryOutputSurface();
464 } 743 }
465 744
466 void VaapiVideoDecodeAccelerator::FlushTask() { 745 void VaapiVideoDecodeAccelerator::FlushTask() {
467 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); 746 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
468 DVLOG(1) << "Flush task"; 747 DVLOG(1) << "Flush task";
469 748
470 base::AutoLock auto_lock(lock_);
471
472 // First flush all the pictures that haven't been outputted, notifying the 749 // First flush all the pictures that haven't been outputted, notifying the
473 // client to output them. 750 // client to output them.
474 bool res = decoder_.Flush(); 751 bool res = decoder_->Flush();
475 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.", 752 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.",
476 PLATFORM_FAILURE, ); 753 PLATFORM_FAILURE, );
477 754
478 // Put the decoder in idle state, ready to resume. 755 // Put the decoder in idle state, ready to resume.
479 decoder_.Reset(); 756 decoder_->Reset();
480 757
481 message_loop_->PostTask(FROM_HERE, base::Bind( 758 message_loop_->PostTask(FROM_HERE, base::Bind(
482 &VaapiVideoDecodeAccelerator::FinishFlush, weak_this_)); 759 &VaapiVideoDecodeAccelerator::FinishFlush, weak_this_));
483 } 760 }
484 761
485 void VaapiVideoDecodeAccelerator::Flush() { 762 void VaapiVideoDecodeAccelerator::Flush() {
486 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 763 DCHECK_EQ(message_loop_, base::MessageLoop::current());
487 DVLOG(1) << "Got flush request"; 764 DVLOG(1) << "Got flush request";
488 765
489 base::AutoLock auto_lock(lock_); 766 base::AutoLock auto_lock(lock_);
490 state_ = kFlushing; 767 state_ = kFlushing;
491 // Queue a flush task after all existing decoding tasks to clean up. 768 // Queue a flush task after all existing decoding tasks to clean up.
492 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( 769 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
493 &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this))); 770 &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this)));
494 771
495 input_ready_.Signal(); 772 input_ready_.Signal();
496 output_ready_.Signal(); 773 surfaces_available_.Signal();
497 } 774 }
498 775
499 void VaapiVideoDecodeAccelerator::FinishFlush() { 776 void VaapiVideoDecodeAccelerator::FinishFlush() {
500 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 777 DCHECK_EQ(message_loop_, base::MessageLoop::current());
501 778
502 base::AutoLock auto_lock(lock_); 779 base::AutoLock auto_lock(lock_);
503 if (state_ != kFlushing) { 780 if (state_ != kFlushing) {
504 DCHECK_EQ(state_, kDestroying); 781 DCHECK_EQ(state_, kDestroying);
505 return; // We could've gotten destroyed already. 782 return; // We could've gotten destroyed already.
506 } 783 }
507 784
508 state_ = kIdle; 785 state_ = kIdle;
509 786
510 message_loop_->PostTask(FROM_HERE, base::Bind( 787 message_loop_->PostTask(FROM_HERE, base::Bind(
511 &Client::NotifyFlushDone, client_)); 788 &Client::NotifyFlushDone, client_));
512 789
513 DVLOG(1) << "Flush finished"; 790 DVLOG(1) << "Flush finished";
514 } 791 }
515 792
516 void VaapiVideoDecodeAccelerator::ResetTask() { 793 void VaapiVideoDecodeAccelerator::ResetTask() {
517 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); 794 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
518 795
519 base::AutoLock auto_lock(lock_);
520
521 // All the decoding tasks from before the reset request from client are done 796 // All the decoding tasks from before the reset request from client are done
522 // by now, as this task was scheduled after them and client is expected not 797 // by now, as this task was scheduled after them and client is expected not
523 // to call Decode() after Reset() and before NotifyResetDone. 798 // to call Decode() after Reset() and before NotifyResetDone.
524 decoder_.Reset(); 799 decoder_->Reset();
800
801 base::AutoLock auto_lock(lock_);
525 802
526 // Return current input buffer, if present. 803 // Return current input buffer, if present.
527 if (curr_input_buffer_.get()) 804 if (curr_input_buffer_.get())
528 ReturnCurrInputBuffer_Locked(); 805 ReturnCurrInputBuffer_Locked();
529 806
530 // And let client know that we are done with reset. 807 // And let client know that we are done with reset.
531 message_loop_->PostTask(FROM_HERE, base::Bind( 808 message_loop_->PostTask(FROM_HERE, base::Bind(
532 &VaapiVideoDecodeAccelerator::FinishReset, weak_this_)); 809 &VaapiVideoDecodeAccelerator::FinishReset, weak_this_));
533 } 810 }
534 811
(...skipping 10 matching lines...) Expand all
545 message_loop_->PostTask(FROM_HERE, base::Bind( 822 message_loop_->PostTask(FROM_HERE, base::Bind(
546 &Client::NotifyEndOfBitstreamBuffer, client_, 823 &Client::NotifyEndOfBitstreamBuffer, client_,
547 input_buffers_.front()->id)); 824 input_buffers_.front()->id));
548 input_buffers_.pop(); 825 input_buffers_.pop();
549 } 826 }
550 827
551 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( 828 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
552 &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this))); 829 &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this)));
553 830
554 input_ready_.Signal(); 831 input_ready_.Signal();
555 output_ready_.Signal(); 832 surfaces_available_.Signal();
556 } 833 }
557 834
558 void VaapiVideoDecodeAccelerator::FinishReset() { 835 void VaapiVideoDecodeAccelerator::FinishReset() {
559 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 836 DCHECK_EQ(message_loop_, base::MessageLoop::current());
560 837
561 base::AutoLock auto_lock(lock_); 838 base::AutoLock auto_lock(lock_);
562 if (state_ != kResetting) { 839 if (state_ != kResetting) {
563 DCHECK(state_ == kDestroying || state_ == kUninitialized) << state_; 840 DCHECK(state_ == kDestroying || state_ == kUninitialized) << state_;
564 return; // We could've gotten destroyed already. 841 return; // We could've gotten destroyed already.
565 } 842 }
566 843
567 state_ = kIdle; 844 state_ = kIdle;
568 num_stream_bufs_at_decoder_ = 0; 845 num_stream_bufs_at_decoder_ = 0;
569 846
847 while(!pending_output_cbs_.empty())
848 pending_output_cbs_.pop();
849
570 message_loop_->PostTask(FROM_HERE, base::Bind( 850 message_loop_->PostTask(FROM_HERE, base::Bind(
571 &Client::NotifyResetDone, client_)); 851 &Client::NotifyResetDone, client_));
572 852
573 // The client might have given us new buffers via Decode() while we were 853 // The client might have given us new buffers via Decode() while we were
574 // resetting and might be waiting for our move, and not call Decode() anymore 854 // resetting and might be waiting for our move, and not call Decode() anymore
575 // until we return something. Post an InitialDecodeTask() so that we won't 855 // until we return something. Post an InitialDecodeTask() so that we won't
576 // sleep forever waiting for Decode() in that case. Having two of them 856 // sleep forever waiting for Decode() in that case. Having two of them
577 // in the pipe is harmless, the additional one will return as soon as it sees 857 // in the pipe is harmless, the additional one will return as soon as it sees
578 // that we are back in kDecoding state. 858 // that we are back in kDecoding state.
579 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( 859 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
(...skipping 15 matching lines...) Expand all
595 875
596 client_ptr_factory_.InvalidateWeakPtrs(); 876 client_ptr_factory_.InvalidateWeakPtrs();
597 877
598 { 878 {
599 base::AutoUnlock auto_unlock(lock_); 879 base::AutoUnlock auto_unlock(lock_);
600 // Post a dummy task to the decoder_thread_ to ensure it is drained. 880 // Post a dummy task to the decoder_thread_ to ensure it is drained.
601 base::WaitableEvent waiter(false, false); 881 base::WaitableEvent waiter(false, false);
602 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( 882 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
603 &base::WaitableEvent::Signal, base::Unretained(&waiter))); 883 &base::WaitableEvent::Signal, base::Unretained(&waiter)));
604 input_ready_.Signal(); 884 input_ready_.Signal();
605 output_ready_.Signal(); 885 surfaces_available_.Signal();
606 waiter.Wait(); 886 waiter.Wait();
607 decoder_thread_.Stop(); 887 decoder_thread_.Stop();
608 } 888 }
609 889
610 decoder_.Destroy();
611 state_ = kUninitialized; 890 state_ = kUninitialized;
612 } 891 }
613 892
614 void VaapiVideoDecodeAccelerator::Destroy() { 893 void VaapiVideoDecodeAccelerator::Destroy() {
615 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 894 DCHECK_EQ(message_loop_, base::MessageLoop::current());
616 Cleanup(); 895 Cleanup();
617 delete this; 896 delete this;
618 } 897 }
619 898
620 // static
621 void VaapiVideoDecodeAccelerator::PreSandboxInitialization() {
622 VaapiH264Decoder::PreSandboxInitialization();
623 }
624
625 // static
626 bool VaapiVideoDecodeAccelerator::PostSandboxInitialization() {
627 return VaapiH264Decoder::PostSandboxInitialization();
628 }
629
630 } // namespace content 899 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698