ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / common / gpu / media / vaapi_video_decode_accelerator.cc
blobd24744d715fb386baa4787e4cfe65e22cf8b808e
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
3 // found in the LICENSE file.
5 #include "base/bind.h"
6 #include "base/logging.h"
7 #include "base/metrics/histogram.h"
8 #include "base/stl_util.h"
9 #include "base/strings/string_util.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/trace_event/trace_event.h"
12 #include "content/common/gpu/gpu_channel.h"
13 #include "content/common/gpu/media/vaapi_picture.h"
14 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
15 #include "media/base/bind_to_current_loop.h"
16 #include "media/video/picture.h"
17 #include "ui/gl/gl_bindings.h"
18 #include "ui/gl/gl_image.h"
20 static void ReportToUMA(
21 content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) {
22 UMA_HISTOGRAM_ENUMERATION(
23 "Media.VAVDAH264.DecoderFailure",
24 failure,
25 content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX);
28 namespace content {
30 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \
31 do { \
32 if (!(result)) { \
33 LOG(ERROR) << log; \
34 NotifyError(error_code); \
35 return ret; \
36 } \
37 } while (0)
39 VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) {
42 VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() {
45 void VaapiVideoDecodeAccelerator::NotifyError(Error error) {
46 if (message_loop_ != base::MessageLoop::current()) {
47 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
48 message_loop_->PostTask(FROM_HERE, base::Bind(
49 &VaapiVideoDecodeAccelerator::NotifyError, weak_this_, error));
50 return;
53 // Post Cleanup() as a task so we don't recursively acquire lock_.
54 message_loop_->PostTask(FROM_HERE, base::Bind(
55 &VaapiVideoDecodeAccelerator::Cleanup, weak_this_));
57 LOG(ERROR) << "Notifying of error " << error;
58 if (client_) {
59 client_->NotifyError(error);
60 client_ptr_factory_.reset();
64 VaapiPicture* VaapiVideoDecodeAccelerator::PictureById(
65 int32 picture_buffer_id) {
66 Pictures::iterator it = pictures_.find(picture_buffer_id);
67 if (it == pictures_.end()) {
68 LOG(ERROR) << "Picture id " << picture_buffer_id << " does not exist";
69 return NULL;
72 return it->second.get();
75 VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator(
76 const base::Callback<bool(void)>& make_context_current,
77 const base::Callback<void(uint32, uint32, scoped_refptr<gfx::GLImage>)>&
78 bind_image)
79 : make_context_current_(make_context_current),
80 state_(kUninitialized),
81 input_ready_(&lock_),
82 surfaces_available_(&lock_),
83 message_loop_(base::MessageLoop::current()),
84 decoder_thread_("VaapiDecoderThread"),
85 num_frames_at_client_(0),
86 num_stream_bufs_at_decoder_(0),
87 finish_flush_pending_(false),
88 awaiting_va_surfaces_recycle_(false),
89 requested_num_pics_(0),
90 bind_image_(bind_image),
91 weak_this_factory_(this) {
92 weak_this_ = weak_this_factory_.GetWeakPtr();
93 va_surface_release_cb_ = media::BindToCurrentLoop(
94 base::Bind(&VaapiVideoDecodeAccelerator::RecycleVASurfaceID, weak_this_));
97 VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() {
98 DCHECK_EQ(message_loop_, base::MessageLoop::current());
101 bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
102 Client* client) {
103 DCHECK_EQ(message_loop_, base::MessageLoop::current());
105 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
106 client_ = client_ptr_factory_->GetWeakPtr();
108 base::AutoLock auto_lock(lock_);
109 DCHECK_EQ(state_, kUninitialized);
110 DVLOG(2) << "Initializing VAVDA, profile: " << profile;
112 #if defined(USE_X11)
113 if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL) {
114 DVLOG(1) << "HW video decode acceleration not available without "
115 "DesktopGL (GLX).";
116 return false;
118 #elif defined(USE_OZONE)
119 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
120 DVLOG(1) << "HW video decode acceleration not available without "
121 << "EGLGLES2.";
122 return false;
124 #endif // USE_X11
126 vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec(
127 VaapiWrapper::kDecode, profile,
128 base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR));
130 if (!vaapi_wrapper_.get()) {
131 LOG(ERROR) << "Failed initializing VAAPI";
132 return false;
135 decoder_.reset(
136 new VaapiH264Decoder(
137 vaapi_wrapper_.get(),
138 media::BindToCurrentLoop(base::Bind(
139 &VaapiVideoDecodeAccelerator::SurfaceReady, weak_this_)),
140 base::Bind(&ReportToUMA)));
142 CHECK(decoder_thread_.Start());
143 decoder_thread_proxy_ = decoder_thread_.message_loop_proxy();
145 state_ = kIdle;
146 return true;
149 void VaapiVideoDecodeAccelerator::SurfaceReady(
150 int32 input_id,
151 const scoped_refptr<VASurface>& va_surface) {
152 DCHECK_EQ(message_loop_, base::MessageLoop::current());
153 DCHECK(!awaiting_va_surfaces_recycle_);
155 // Drop any requests to output if we are resetting or being destroyed.
156 if (state_ == kResetting || state_ == kDestroying)
157 return;
159 pending_output_cbs_.push(
160 base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture,
161 weak_this_, va_surface, input_id));
163 TryOutputSurface();
166 void VaapiVideoDecodeAccelerator::OutputPicture(
167 const scoped_refptr<VASurface>& va_surface,
168 int32 input_id,
169 VaapiPicture* picture) {
170 DCHECK_EQ(message_loop_, base::MessageLoop::current());
172 int32 output_id = picture->picture_buffer_id();
174 TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface",
175 "input_id", input_id,
176 "output_id", output_id);
178 DVLOG(3) << "Outputting VASurface " << va_surface->id()
179 << " into pixmap bound to picture buffer id " << output_id;
181 RETURN_AND_NOTIFY_ON_FAILURE(picture->DownloadFromSurface(va_surface),
182 "Failed putting surface into pixmap",
183 PLATFORM_FAILURE, );
185 // Notify the client a picture is ready to be displayed.
186 ++num_frames_at_client_;
187 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
188 DVLOG(4) << "Notifying output picture id " << output_id
189 << " for input "<< input_id << " is ready";
190 // TODO(posciak): Use visible size from decoder here instead
191 // (crbug.com/402760).
192 if (client_)
193 client_->PictureReady(media::Picture(output_id, input_id,
194 gfx::Rect(picture->size()),
195 picture->AllowOverlay()));
198 void VaapiVideoDecodeAccelerator::TryOutputSurface() {
199 DCHECK_EQ(message_loop_, base::MessageLoop::current());
201 // Handle Destroy() arriving while pictures are queued for output.
202 if (!client_)
203 return;
205 if (pending_output_cbs_.empty() || output_buffers_.empty())
206 return;
208 OutputCB output_cb = pending_output_cbs_.front();
209 pending_output_cbs_.pop();
211 VaapiPicture* picture = PictureById(output_buffers_.front());
212 DCHECK(picture);
213 output_buffers_.pop();
215 output_cb.Run(picture);
217 if (finish_flush_pending_ && pending_output_cbs_.empty())
218 FinishFlush();
221 void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer(
222 const media::BitstreamBuffer& bitstream_buffer) {
223 DCHECK_EQ(message_loop_, base::MessageLoop::current());
224 TRACE_EVENT1("Video Decoder", "MapAndQueueNewInputBuffer", "input_id",
225 bitstream_buffer.id());
227 DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id()
228 << " size: " << (int)bitstream_buffer.size();
230 scoped_ptr<base::SharedMemory> shm(
231 new base::SharedMemory(bitstream_buffer.handle(), true));
232 RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(bitstream_buffer.size()),
233 "Failed to map input buffer", UNREADABLE_INPUT,);
235 base::AutoLock auto_lock(lock_);
237 // Set up a new input buffer and queue it for later.
238 linked_ptr<InputBuffer> input_buffer(new InputBuffer());
239 input_buffer->shm.reset(shm.release());
240 input_buffer->id = bitstream_buffer.id();
241 input_buffer->size = bitstream_buffer.size();
243 ++num_stream_bufs_at_decoder_;
244 TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder",
245 num_stream_bufs_at_decoder_);
247 input_buffers_.push(input_buffer);
248 input_ready_.Signal();
251 bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() {
252 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
253 lock_.AssertAcquired();
255 if (curr_input_buffer_.get())
256 return true;
258 // Will only wait if it is expected that in current state new buffers will
259 // be queued from the client via Decode(). The state can change during wait.
260 while (input_buffers_.empty() && (state_ == kDecoding || state_ == kIdle)) {
261 input_ready_.Wait();
264 // We could have got woken up in a different state or never got to sleep
265 // due to current state; check for that.
266 switch (state_) {
267 case kFlushing:
268 // Here we are only interested in finishing up decoding buffers that are
269 // already queued up. Otherwise will stop decoding.
270 if (input_buffers_.empty())
271 return false;
272 // else fallthrough
273 case kDecoding:
274 case kIdle:
275 DCHECK(!input_buffers_.empty());
277 curr_input_buffer_ = input_buffers_.front();
278 input_buffers_.pop();
280 DVLOG(4) << "New current bitstream buffer, id: "
281 << curr_input_buffer_->id
282 << " size: " << curr_input_buffer_->size;
284 decoder_->SetStream(
285 static_cast<uint8*>(curr_input_buffer_->shm->memory()),
286 curr_input_buffer_->size, curr_input_buffer_->id);
287 return true;
289 default:
290 // We got woken up due to being destroyed/reset, ignore any already
291 // queued inputs.
292 return false;
296 void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() {
297 lock_.AssertAcquired();
298 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
299 DCHECK(curr_input_buffer_.get());
301 int32 id = curr_input_buffer_->id;
302 curr_input_buffer_.reset();
303 DVLOG(4) << "End of input buffer " << id;
304 message_loop_->PostTask(FROM_HERE, base::Bind(
305 &Client::NotifyEndOfBitstreamBuffer, client_, id));
307 --num_stream_bufs_at_decoder_;
308 TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder",
309 num_stream_bufs_at_decoder_);
312 bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() {
313 lock_.AssertAcquired();
314 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
316 while (available_va_surfaces_.empty() &&
317 (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) {
318 surfaces_available_.Wait();
321 if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle)
322 return false;
324 DCHECK(!awaiting_va_surfaces_recycle_);
325 while (!available_va_surfaces_.empty()) {
326 scoped_refptr<VASurface> va_surface(
327 new VASurface(available_va_surfaces_.front(), requested_pic_size_,
328 va_surface_release_cb_));
329 available_va_surfaces_.pop_front();
330 decoder_->ReuseSurface(va_surface);
333 return true;
336 void VaapiVideoDecodeAccelerator::DecodeTask() {
337 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
338 TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask");
339 base::AutoLock auto_lock(lock_);
341 if (state_ != kDecoding)
342 return;
344 // Main decode task.
345 DVLOG(4) << "Decode task";
347 // Try to decode what stream data is (still) in the decoder until we run out
348 // of it.
349 while (GetInputBuffer_Locked()) {
350 DCHECK(curr_input_buffer_.get());
352 VaapiH264Decoder::DecResult res;
354 // We are OK releasing the lock here, as decoder never calls our methods
355 // directly and we will reacquire the lock before looking at state again.
356 // This is the main decode function of the decoder and while keeping
357 // the lock for its duration would be fine, it would defeat the purpose
358 // of having a separate decoder thread.
359 base::AutoUnlock auto_unlock(lock_);
360 res = decoder_->Decode();
363 switch (res) {
364 case VaapiH264Decoder::kAllocateNewSurfaces:
365 DVLOG(1) << "Decoder requesting a new set of surfaces";
366 message_loop_->PostTask(FROM_HERE, base::Bind(
367 &VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange, weak_this_,
368 decoder_->GetRequiredNumOfPictures(),
369 decoder_->GetPicSize()));
370 // We'll get rescheduled once ProvidePictureBuffers() finishes.
371 return;
373 case VaapiH264Decoder::kRanOutOfStreamData:
374 ReturnCurrInputBuffer_Locked();
375 break;
377 case VaapiH264Decoder::kRanOutOfSurfaces:
378 // No more output buffers in the decoder, try getting more or go to
379 // sleep waiting for them.
380 if (!FeedDecoderWithOutputSurfaces_Locked())
381 return;
383 break;
385 case VaapiH264Decoder::kDecodeError:
386 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream",
387 PLATFORM_FAILURE, );
388 return;
393 void VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange(size_t num_pics,
394 gfx::Size size) {
395 DCHECK_EQ(message_loop_, base::MessageLoop::current());
396 DCHECK(!awaiting_va_surfaces_recycle_);
398 // At this point decoder has stopped running and has already posted onto our
399 // loop any remaining output request callbacks, which executed before we got
400 // here. Some of them might have been pended though, because we might not
401 // have had enough TFPictures to output surfaces to. Initiate a wait cycle,
402 // which will wait for client to return enough PictureBuffers to us, so that
403 // we can finish all pending output callbacks, releasing associated surfaces.
404 DVLOG(1) << "Initiating surface set change";
405 awaiting_va_surfaces_recycle_ = true;
407 requested_num_pics_ = num_pics;
408 requested_pic_size_ = size;
410 TryFinishSurfaceSetChange();
413 void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() {
414 DCHECK_EQ(message_loop_, base::MessageLoop::current());
416 if (!awaiting_va_surfaces_recycle_)
417 return;
419 if (!pending_output_cbs_.empty() ||
420 pictures_.size() != available_va_surfaces_.size()) {
421 // Either:
422 // 1. Not all pending pending output callbacks have been executed yet.
423 // Wait for the client to return enough pictures and retry later.
424 // 2. The above happened and all surface release callbacks have been posted
425 // as the result, but not all have executed yet. Post ourselves after them
426 // to let them release surfaces.
427 DVLOG(2) << "Awaiting pending output/surface release callbacks to finish";
428 message_loop_->PostTask(FROM_HERE, base::Bind(
429 &VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange, weak_this_));
430 return;
433 // All surfaces released, destroy them and dismiss all PictureBuffers.
434 awaiting_va_surfaces_recycle_ = false;
435 available_va_surfaces_.clear();
436 vaapi_wrapper_->DestroySurfaces();
438 for (Pictures::iterator iter = pictures_.begin(); iter != pictures_.end();
439 ++iter) {
440 DVLOG(2) << "Dismissing picture id: " << iter->first;
441 if (client_)
442 client_->DismissPictureBuffer(iter->first);
444 pictures_.clear();
446 // And ask for a new set as requested.
447 DVLOG(1) << "Requesting " << requested_num_pics_ << " pictures of size: "
448 << requested_pic_size_.ToString();
450 message_loop_->PostTask(
451 FROM_HERE,
452 base::Bind(&Client::ProvidePictureBuffers, client_, requested_num_pics_,
453 requested_pic_size_, VaapiPicture::GetGLTextureTarget()));
456 void VaapiVideoDecodeAccelerator::Decode(
457 const media::BitstreamBuffer& bitstream_buffer) {
458 DCHECK_EQ(message_loop_, base::MessageLoop::current());
460 TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "Buffer id",
461 bitstream_buffer.id());
463 // We got a new input buffer from the client, map it and queue for later use.
464 MapAndQueueNewInputBuffer(bitstream_buffer);
466 base::AutoLock auto_lock(lock_);
467 switch (state_) {
468 case kIdle:
469 state_ = kDecoding;
470 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
471 &VaapiVideoDecodeAccelerator::DecodeTask,
472 base::Unretained(this)));
473 break;
475 case kDecoding:
476 // Decoder already running, fallthrough.
477 case kResetting:
478 // When resetting, allow accumulating bitstream buffers, so that
479 // the client can queue after-seek-buffers while we are finishing with
480 // the before-seek one.
481 break;
483 default:
484 RETURN_AND_NOTIFY_ON_FAILURE(false,
485 "Decode request from client in invalid state: " << state_,
486 PLATFORM_FAILURE, );
487 break;
491 void VaapiVideoDecodeAccelerator::RecycleVASurfaceID(
492 VASurfaceID va_surface_id) {
493 DCHECK_EQ(message_loop_, base::MessageLoop::current());
494 base::AutoLock auto_lock(lock_);
496 available_va_surfaces_.push_back(va_surface_id);
497 surfaces_available_.Signal();
500 void VaapiVideoDecodeAccelerator::AssignPictureBuffers(
501 const std::vector<media::PictureBuffer>& buffers) {
502 DCHECK_EQ(message_loop_, base::MessageLoop::current());
504 base::AutoLock auto_lock(lock_);
505 DCHECK(pictures_.empty());
507 while (!output_buffers_.empty())
508 output_buffers_.pop();
510 RETURN_AND_NOTIFY_ON_FAILURE(
511 buffers.size() == requested_num_pics_,
512 "Got an invalid number of picture buffers. (Got " << buffers.size()
513 << ", requested " << requested_num_pics_ << ")", INVALID_ARGUMENT, );
514 DCHECK(requested_pic_size_ == buffers[0].size());
516 std::vector<VASurfaceID> va_surface_ids;
517 RETURN_AND_NOTIFY_ON_FAILURE(
518 vaapi_wrapper_->CreateSurfaces(requested_pic_size_,
519 buffers.size(),
520 &va_surface_ids),
521 "Failed creating VA Surfaces", PLATFORM_FAILURE, );
522 DCHECK_EQ(va_surface_ids.size(), buffers.size());
524 for (size_t i = 0; i < buffers.size(); ++i) {
525 DVLOG(2) << "Assigning picture id: " << buffers[i].id()
526 << " to texture id: " << buffers[i].texture_id()
527 << " VASurfaceID: " << va_surface_ids[i];
529 linked_ptr<VaapiPicture> picture(VaapiPicture::CreatePicture(
530 vaapi_wrapper_.get(), make_context_current_, buffers[i].id(),
531 buffers[i].texture_id(), requested_pic_size_));
533 scoped_refptr<gfx::GLImage> image = picture->GetImageToBind();
534 if (image) {
535 bind_image_.Run(buffers[i].internal_texture_id(),
536 VaapiPicture::GetGLTextureTarget(), image);
539 RETURN_AND_NOTIFY_ON_FAILURE(
540 picture.get(), "Failed assigning picture buffer to a texture.",
541 PLATFORM_FAILURE, );
543 bool inserted =
544 pictures_.insert(std::make_pair(buffers[i].id(), picture)).second;
545 DCHECK(inserted);
547 output_buffers_.push(buffers[i].id());
548 available_va_surfaces_.push_back(va_surface_ids[i]);
549 surfaces_available_.Signal();
552 state_ = kDecoding;
553 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
554 &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this)));
557 void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
558 DCHECK_EQ(message_loop_, base::MessageLoop::current());
559 TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id",
560 picture_buffer_id);
562 --num_frames_at_client_;
563 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
565 output_buffers_.push(picture_buffer_id);
566 TryOutputSurface();
569 void VaapiVideoDecodeAccelerator::FlushTask() {
570 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
571 DVLOG(1) << "Flush task";
573 // First flush all the pictures that haven't been outputted, notifying the
574 // client to output them.
575 bool res = decoder_->Flush();
576 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.",
577 PLATFORM_FAILURE, );
579 // Put the decoder in idle state, ready to resume.
580 decoder_->Reset();
582 message_loop_->PostTask(FROM_HERE, base::Bind(
583 &VaapiVideoDecodeAccelerator::FinishFlush, weak_this_));
586 void VaapiVideoDecodeAccelerator::Flush() {
587 DCHECK_EQ(message_loop_, base::MessageLoop::current());
588 DVLOG(1) << "Got flush request";
590 base::AutoLock auto_lock(lock_);
591 state_ = kFlushing;
592 // Queue a flush task after all existing decoding tasks to clean up.
593 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
594 &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this)));
596 input_ready_.Signal();
597 surfaces_available_.Signal();
600 void VaapiVideoDecodeAccelerator::FinishFlush() {
601 DCHECK_EQ(message_loop_, base::MessageLoop::current());
603 finish_flush_pending_ = false;
605 base::AutoLock auto_lock(lock_);
606 if (state_ != kFlushing) {
607 DCHECK_EQ(state_, kDestroying);
608 return; // We could've gotten destroyed already.
611 // Still waiting for textures from client to finish outputting all pending
612 // frames. Try again later.
613 if (!pending_output_cbs_.empty()) {
614 finish_flush_pending_ = true;
615 return;
618 state_ = kIdle;
620 message_loop_->PostTask(FROM_HERE, base::Bind(
621 &Client::NotifyFlushDone, client_));
623 DVLOG(1) << "Flush finished";
626 void VaapiVideoDecodeAccelerator::ResetTask() {
627 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
628 DVLOG(1) << "ResetTask";
630 // All the decoding tasks from before the reset request from client are done
631 // by now, as this task was scheduled after them and client is expected not
632 // to call Decode() after Reset() and before NotifyResetDone.
633 decoder_->Reset();
635 base::AutoLock auto_lock(lock_);
637 // Return current input buffer, if present.
638 if (curr_input_buffer_.get())
639 ReturnCurrInputBuffer_Locked();
641 // And let client know that we are done with reset.
642 message_loop_->PostTask(FROM_HERE, base::Bind(
643 &VaapiVideoDecodeAccelerator::FinishReset, weak_this_));
646 void VaapiVideoDecodeAccelerator::Reset() {
647 DCHECK_EQ(message_loop_, base::MessageLoop::current());
648 DVLOG(1) << "Got reset request";
650 // This will make any new decode tasks exit early.
651 base::AutoLock auto_lock(lock_);
652 state_ = kResetting;
653 finish_flush_pending_ = false;
655 // Drop all remaining input buffers, if present.
656 while (!input_buffers_.empty()) {
657 message_loop_->PostTask(FROM_HERE, base::Bind(
658 &Client::NotifyEndOfBitstreamBuffer, client_,
659 input_buffers_.front()->id));
660 input_buffers_.pop();
663 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
664 &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this)));
666 input_ready_.Signal();
667 surfaces_available_.Signal();
670 void VaapiVideoDecodeAccelerator::FinishReset() {
671 DCHECK_EQ(message_loop_, base::MessageLoop::current());
672 DVLOG(1) << "FinishReset";
673 base::AutoLock auto_lock(lock_);
675 if (state_ != kResetting) {
676 DCHECK(state_ == kDestroying || state_ == kUninitialized) << state_;
677 return; // We could've gotten destroyed already.
680 // Drop pending outputs.
681 while (!pending_output_cbs_.empty())
682 pending_output_cbs_.pop();
684 if (awaiting_va_surfaces_recycle_) {
685 // Decoder requested a new surface set while we were waiting for it to
686 // finish the last DecodeTask, running at the time of Reset().
687 // Let the surface set change finish first before resetting.
688 message_loop_->PostTask(FROM_HERE, base::Bind(
689 &VaapiVideoDecodeAccelerator::FinishReset, weak_this_));
690 return;
693 num_stream_bufs_at_decoder_ = 0;
694 state_ = kIdle;
696 message_loop_->PostTask(FROM_HERE, base::Bind(
697 &Client::NotifyResetDone, client_));
699 // The client might have given us new buffers via Decode() while we were
700 // resetting and might be waiting for our move, and not call Decode() anymore
701 // until we return something. Post a DecodeTask() so that we won't
702 // sleep forever waiting for Decode() in that case. Having two of them
703 // in the pipe is harmless, the additional one will return as soon as it sees
704 // that we are back in kDecoding state.
705 if (!input_buffers_.empty()) {
706 state_ = kDecoding;
707 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
708 &VaapiVideoDecodeAccelerator::DecodeTask,
709 base::Unretained(this)));
712 DVLOG(1) << "Reset finished";
715 void VaapiVideoDecodeAccelerator::Cleanup() {
716 DCHECK_EQ(message_loop_, base::MessageLoop::current());
718 if (state_ == kUninitialized || state_ == kDestroying)
719 return;
721 DVLOG(1) << "Destroying VAVDA";
722 base::AutoLock auto_lock(lock_);
723 state_ = kDestroying;
725 client_ptr_factory_.reset();
726 weak_this_factory_.InvalidateWeakPtrs();
728 // Signal all potential waiters on the decoder_thread_, let them early-exit,
729 // as we've just moved to the kDestroying state, and wait for all tasks
730 // to finish.
731 input_ready_.Signal();
732 surfaces_available_.Signal();
734 base::AutoUnlock auto_unlock(lock_);
735 decoder_thread_.Stop();
738 state_ = kUninitialized;
741 void VaapiVideoDecodeAccelerator::Destroy() {
742 DCHECK_EQ(message_loop_, base::MessageLoop::current());
743 Cleanup();
744 delete this;
747 bool VaapiVideoDecodeAccelerator::CanDecodeOnIOThread() {
748 return false;
751 } // namespace content