Chromium Code Reviews| Index: content/common/gpu/media/vt_video_decode_accelerator.cc |
| diff --git a/content/common/gpu/media/vt_video_decode_accelerator.cc b/content/common/gpu/media/vt_video_decode_accelerator.cc |
| index 5b916501b1b3fdbb532014842e48422584976874..3da6562fad7efed25c7d7964eeb673dfa8ebaa0e 100644 |
| --- a/content/common/gpu/media/vt_video_decode_accelerator.cc |
| +++ b/content/common/gpu/media/vt_video_decode_accelerator.cc |
| @@ -39,7 +39,6 @@ static void OutputThunk( |
| CVImageBufferRef image_buffer, |
| CMTime presentation_time_stamp, |
| CMTime presentation_duration) { |
| - // TODO(sandersd): Implement flush-before-delete to guarantee validity. |
| VTVideoDecodeAccelerator* vda = |
| reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon); |
| int32_t bitstream_id = reinterpret_cast<intptr_t>(source_frame_refcon); |
| @@ -59,6 +58,8 @@ VTVideoDecodeAccelerator::DecodedFrame::~DecodedFrame() { |
| VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context) |
| : cgl_context_(cgl_context), |
| client_(NULL), |
| + state_(NORMAL), |
| + frames_pending_decode_(0), |
| format_(NULL), |
| session_(NULL), |
| gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| @@ -159,7 +160,6 @@ void VTVideoDecodeAccelerator::ConfigureDecoder( |
| image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue); |
| // TODO(sandersd): Check if the session is already compatible. |
| - // TODO(sandersd): Flush. |
| session_.reset(); |
| CHECK(!VTDecompressionSessionCreate( |
| kCFAllocatorDefault, |
| @@ -182,8 +182,7 @@ void VTVideoDecodeAccelerator::ConfigureDecoder( |
| void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) { |
| DCHECK(CalledOnValidThread()); |
| - // TODO(sandersd): Test what happens if bitstream buffers are passed to VT out |
| - // of order. |
| + frames_pending_decode_++; |
|
Pawel Osciak
2014/08/27 08:25:20
Client will keep calling Decode()s after it calls
sandersd (OOO until July 31)
2014/08/27 21:40:43
video_decoder.h specifies that no decode calls are
Pawel Osciak
2014/08/28 12:09:12
This class implements VideoDecodeAccelerator, not
|
| decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( |
| &VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this), |
| bitstream)); |
| @@ -309,8 +308,16 @@ void VTVideoDecodeAccelerator::Output( |
| void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) { |
| DCHECK(CalledOnValidThread()); |
| - decoded_frames_.push(frame); |
| - SendPictures(); |
| + if (state_ == RESETTING || state_ == DESTROYING) { |
| + // Drop all decoded frames when resetting or destroying. |
| + client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id); |
| + frames_pending_decode_--; |
| + if (!frames_pending_decode_) |
| + FlushDone(); |
| + } else { |
| + decoded_frames_.push(frame); |
| + SendPictures(); |
| + } |
| } |
| void VTVideoDecodeAccelerator::SizeChangedTask(gfx::Size coded_size) { |
| @@ -332,7 +339,8 @@ void VTVideoDecodeAccelerator::AssignPictureBuffers( |
| } |
| // Pictures are not marked as uncleared until this method returns. They will |
| - // become broken if they are used before that happens. |
| + // become broken if they are used before that happens. So, instead of calling |
| + // SendPictures(), arrange for it to be called later. |
| gpu_task_runner_->PostTask(FROM_HERE, base::Bind( |
| &VTVideoDecodeAccelerator::SendPictures, |
| weak_this_factory_.GetWeakPtr())); |
| @@ -362,6 +370,7 @@ void VTVideoDecodeAccelerator::SendPictures() { |
| decoded_frames_.pop(); |
| IOSurfaceRef surface = CVPixelBufferGetIOSurface(frame.image_buffer); |
| + // TODO(sandersd): Find out why this fails due to no GL context sometimes. |
| gfx::ScopedTextureBinder |
| texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]); |
| CHECK(!CGLTexImageIOSurface2D( |
| @@ -378,25 +387,76 @@ void VTVideoDecodeAccelerator::SendPictures() { |
| picture_bindings_[picture_id] = frame.image_buffer; |
| client_->PictureReady(media::Picture(picture_id, frame.bitstream_id)); |
| client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id); |
| + frames_pending_decode_--; |
| } |
| glDisable(GL_TEXTURE_RECTANGLE_ARB); |
| + |
| + if (state_ != NORMAL && !frames_pending_decode_) |
| + FlushDone(); |
| +} |
| + |
| +void VTVideoDecodeAccelerator::FlushStart(State state) { |
| + DCHECK(CalledOnValidThread()); |
| + state_ = state; |
| + |
| + // If resetting or destroying, drop all pending frames. |
| + if (state_ == RESETTING || state_ == DESTROYING) { |
| + while (!decoded_frames_.empty()) { |
| + DecodedFrame frame = decoded_frames_.front(); |
| + decoded_frames_.pop(); |
| + client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id); |
| + frames_pending_decode_--; |
| + } |
| + } |
| + |
| + if (frames_pending_decode_) { |
| + decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( |
| + &VTVideoDecodeAccelerator::FlushTask, base::Unretained(this))); |
| + } else { |
| + FlushDone(); |
| + } |
| +} |
| + |
| +void VTVideoDecodeAccelerator::FlushTask() { |
| + DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| + if (session_) |
| + CHECK(!VTDecompressionSessionFinishDelayedFrames(session_)); |
| +} |
| + |
| +void VTVideoDecodeAccelerator::FlushDone() { |
| + DCHECK(CalledOnValidThread()); |
| + switch (state_) { |
| + case NORMAL: |
| + NOTREACHED(); |
| + break; |
| + case FLUSHING: |
| + client_->NotifyFlushDone(); |
| + state_ = NORMAL; |
| + break; |
| + case RESETTING: |
| + client_->NotifyResetDone(); |
| + state_ = NORMAL; |
| + break; |
| + case DESTROYING: |
| + delete this; |
| + break; |
| + } |
| } |
| void VTVideoDecodeAccelerator::Flush() { |
| DCHECK(CalledOnValidThread()); |
| - // TODO(sandersd): Trigger flush, sending frames. |
| + FlushStart(FLUSHING); |
| } |
| void VTVideoDecodeAccelerator::Reset() { |
| DCHECK(CalledOnValidThread()); |
| - // TODO(sandersd): Trigger flush, discarding frames. |
| + FlushStart(RESETTING); |
| } |
| void VTVideoDecodeAccelerator::Destroy() { |
| DCHECK(CalledOnValidThread()); |
| - // TODO(sandersd): Trigger flush, discarding frames, and wait for them. |
| - delete this; |
| + FlushStart(DESTROYING); |
| } |
| bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { |