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.
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",
25 content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX
);
30 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \
34 NotifyError(error_code); \
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
));
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
;
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";
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
>)>&
79 : make_context_current_(make_context_current
),
80 state_(kUninitialized
),
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
,
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
;
113 if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL
) {
114 DVLOG(1) << "HW video decode acceleration not available without "
118 #elif defined(USE_OZONE)
119 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2
) {
120 DVLOG(1) << "HW video decode acceleration not available without "
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";
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();
149 void VaapiVideoDecodeAccelerator::SurfaceReady(
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
)
159 pending_output_cbs_
.push(
160 base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture
,
161 weak_this_
, va_surface
, input_id
));
166 void VaapiVideoDecodeAccelerator::OutputPicture(
167 const scoped_refptr
<VASurface
>& va_surface
,
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",
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).
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.
205 if (pending_output_cbs_
.empty() || output_buffers_
.empty())
208 OutputCB output_cb
= pending_output_cbs_
.front();
209 pending_output_cbs_
.pop();
211 VaapiPicture
* picture
= PictureById(output_buffers_
.front());
213 output_buffers_
.pop();
215 output_cb
.Run(picture
);
217 if (finish_flush_pending_
&& pending_output_cbs_
.empty())
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())
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
)) {
264 // We could have got woken up in a different state or never got to sleep
265 // due to current state; check for that.
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())
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
;
285 static_cast<uint8
*>(curr_input_buffer_
->shm
->memory()),
286 curr_input_buffer_
->size
, curr_input_buffer_
->id
);
290 // We got woken up due to being destroyed/reset, ignore any already
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
)
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
);
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
)
345 DVLOG(4) << "Decode task";
347 // Try to decode what stream data is (still) in the decoder until we run out
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();
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.
373 case VaapiH264Decoder::kRanOutOfStreamData
:
374 ReturnCurrInputBuffer_Locked();
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())
385 case VaapiH264Decoder::kDecodeError
:
386 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream",
393 void VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange(size_t num_pics
,
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_
)
419 if (!pending_output_cbs_
.empty() ||
420 pictures_
.size() != available_va_surfaces_
.size()) {
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_
));
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();
440 DVLOG(2) << "Dismissing picture id: " << iter
->first
;
442 client_
->DismissPictureBuffer(iter
->first
);
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(
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_
);
470 decoder_thread_proxy_
->PostTask(FROM_HERE
, base::Bind(
471 &VaapiVideoDecodeAccelerator::DecodeTask
,
472 base::Unretained(this)));
476 // Decoder already running, fallthrough.
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.
484 RETURN_AND_NOTIFY_ON_FAILURE(false,
485 "Decode request from client in invalid state: " << state_
,
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_
,
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();
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.",
544 pictures_
.insert(std::make_pair(buffers
[i
].id(), picture
)).second
;
547 output_buffers_
.push(buffers
[i
].id());
548 available_va_surfaces_
.push_back(va_surface_ids
[i
]);
549 surfaces_available_
.Signal();
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",
562 --num_frames_at_client_
;
563 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_
);
565 output_buffers_
.push(picture_buffer_id
);
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.",
579 // Put the decoder in idle state, ready to resume.
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_
);
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;
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.
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_
);
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_
));
693 num_stream_bufs_at_decoder_
= 0;
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()) {
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
)
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
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());
747 bool VaapiVideoDecodeAccelerator::CanDecodeOnIOThread() {
751 } // namespace content