diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/base/video_frame.cc | 3 | ||||
-rw-r--r-- | media/base/video_frame.h | 11 | ||||
-rw-r--r-- | media/filters/gpu_video_decoder.cc | 16 | ||||
-rw-r--r-- | media/filters/gpu_video_decoder.h | 13 | ||||
-rw-r--r-- | media/filters/skcanvas_video_renderer.cc | 2 | ||||
-rw-r--r-- | media/filters/video_renderer_base.cc | 9 | ||||
-rw-r--r-- | media/test/data/rapid_video_change_test.html | 47 |
7 files changed, 85 insertions, 16 deletions
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index 70b77fb..62e81ca 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc @@ -13,6 +13,7 @@ #include "base/string_piece.h" #include "media/base/limits.h" #include "media/base/video_util.h" +#include "third_party/skia/include/core/SkBitmap.h" namespace media { @@ -79,7 +80,7 @@ scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( return frame; } -void VideoFrame::ReadPixelsFromNativeTexture(void* pixels) { +void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap& pixels) { DCHECK_EQ(format_, NATIVE_TEXTURE); if (!read_pixels_cb_.is_null()) read_pixels_cb_.Run(pixels); diff --git a/media/base/video_frame.h b/media/base/video_frame.h index 5307df9..9a6f0a6 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h @@ -11,6 +11,8 @@ #include "ui/gfx/rect.h" #include "ui/gfx/size.h" +class SkBitmap; + namespace media { class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { @@ -69,8 +71,8 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { const gfx::Size& natural_size); // CB to write pixels from the texture backing this frame into the - // |void*| parameter. - typedef base::Callback<void(void*)> ReadPixelsCB; + // |const SkBitmap&| parameter. + typedef base::Callback<void(const SkBitmap&)> ReadPixelsCB; // Wraps a native texture of the given parameters with a VideoFrame. When the // frame is destroyed |no_longer_needed_cb.Run()| will be called. @@ -79,6 +81,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // any) is applied. // |natural_size| is the width and height of the frame when the frame's aspect // ratio is applied to |visible_rect|. + // |read_pixels_cb| may be used to do (slow!) readbacks from the // texture to main memory. static scoped_refptr<VideoFrame> WrapNativeTexture( @@ -92,9 +95,9 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { const base::Closure& no_longer_needed_cb); // Read pixels from the native texture backing |*this| and write - // them to |*pixels| as BGRA. |pixels| must point to a buffer at + // them to |pixels| as BGRA. |pixels| must point to a buffer at // least as large as 4*visible_rect().width()*visible_rect().height(). - void ReadPixelsFromNativeTexture(void* pixels); + void ReadPixelsFromNativeTexture(const SkBitmap& pixels); // Wraps external YUV data of the given parameters with a VideoFrame. // The returned VideoFrame does not own the data passed in. When the frame diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc index cbad87d..7199415 100644 --- a/media/filters/gpu_video_decoder.cc +++ b/media/filters/gpu_video_decoder.cc @@ -69,7 +69,7 @@ GpuVideoDecoder::GpuVideoDecoder( void GpuVideoDecoder::Reset(const base::Closure& closure) { DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); - if (state_ == kDrainingDecoder) { + if (state_ == kDrainingDecoder && !factories_->IsAborted()) { gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( &GpuVideoDecoder::Reset, this, closure)); // NOTE: if we're deferring Reset() until a Flush() completes, return @@ -103,6 +103,10 @@ void GpuVideoDecoder::Stop(const base::Closure& closure) { DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); if (vda_.get()) DestroyVDA(); + if (!pending_read_cb_.is_null()) + EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); + if (!pending_reset_cb_.is_null()) + base::ResetAndReturn(&pending_reset_cb_).Run(); BindToCurrentLoop(closure).Run(); } @@ -283,6 +287,9 @@ void GpuVideoDecoder::RequestBufferDecode( size_t size = buffer->GetDataSize(); SHMBuffer* shm_buffer = GetSHM(size); + if (!shm_buffer) + return; + memcpy(shm_buffer->shm->memory(), buffer->GetData(), size); BitstreamBuffer bitstream_buffer( next_bitstream_buffer_id_, shm_buffer->shm->handle(), size); @@ -479,7 +486,9 @@ GpuVideoDecoder::SHMBuffer* GpuVideoDecoder::GetSHM(size_t min_size) { available_shm_segments_.back()->size < min_size) { size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate); - DCHECK(shm); + // CreateSharedMemory() can return NULL during Shutdown. + if (!shm) + return NULL; return new SHMBuffer(shm, size_to_allocate); } SHMBuffer* ret = available_shm_segments_.back(); @@ -568,9 +577,6 @@ void GpuVideoDecoder::NotifyResetDone() { return; } - if (!vda_.get()) - return; - DCHECK(ready_video_frames_.empty()); // This needs to happen after the Reset() on vda_ is done to ensure pictures diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h index 61c8b56..d92c045 100644 --- a/media/filters/gpu_video_decoder.h +++ b/media/filters/gpu_video_decoder.h @@ -22,6 +22,8 @@ class MessageLoopProxy; class SharedMemory; } +class SkBitmap; + namespace media { class DecoderBuffer; @@ -47,9 +49,9 @@ class MEDIA_EXPORT GpuVideoDecoder uint32 texture_target) = 0; virtual void DeleteTexture(uint32 texture_id) = 0; - // Read pixels from a native texture and store into |*pixels| as RGBA. + // Read pixels from a native texture and store into |pixels| as RGBA. virtual void ReadPixels(uint32 texture_id, uint32 texture_target, - const gfx::Size& size, void* pixels) = 0; + const gfx::Size& size, const SkBitmap& pixels) = 0; // Allocate & return a shared memory segment. Caller is responsible for // Close()ing the returned pointer. @@ -58,6 +60,13 @@ class MEDIA_EXPORT GpuVideoDecoder // Returns the message loop the VideoDecodeAccelerator runs on. virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() = 0; + // Abort any outstanding factory operations and error any future + // attempts at factory operations + virtual void Abort() = 0; + + // Returns true if Abort has been called. + virtual bool IsAborted() = 0; + protected: friend class base::RefCountedThreadSafe<Factories>; virtual ~Factories(); diff --git a/media/filters/skcanvas_video_renderer.cc b/media/filters/skcanvas_video_renderer.cc index 53b5b2d..b478a73 100644 --- a/media/filters/skcanvas_video_renderer.cc +++ b/media/filters/skcanvas_video_renderer.cc @@ -227,7 +227,7 @@ static void ConvertVideoFrameToBitmap( yuv_type); } else { DCHECK_EQ(video_frame->format(), media::VideoFrame::NATIVE_TEXTURE); - video_frame->ReadPixelsFromNativeTexture(bitmap->getPixels()); + video_frame->ReadPixelsFromNativeTexture(*bitmap); } bitmap->notifyPixelsChanged(); bitmap->unlockPixels(); diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc index 4a5af4d..78f27b3 100644 --- a/media/filters/video_renderer_base.cc +++ b/media/filters/video_renderer_base.cc @@ -72,6 +72,10 @@ void VideoRendererBase::Flush(const base::Closure& callback) { flush_cb_ = callback; state_ = kFlushingDecoder; + // This is necessary if the decoder has already seen an end of stream and + // needs to drain it before flushing it. + ready_frames_.clear(); + received_end_of_stream_ = false; video_frame_stream_.Reset(base::Bind( &VideoRendererBase::OnVideoFrameStreamResetDone, weak_this_)); } @@ -488,9 +492,8 @@ void VideoRendererBase::OnVideoFrameStreamResetDone() { void VideoRendererBase::AttemptFlush_Locked() { lock_.AssertAcquired(); DCHECK_EQ(kFlushing, state_); - - ready_frames_.clear(); - received_end_of_stream_ = false; + DCHECK(ready_frames_.empty()); + DCHECK(!received_end_of_stream_); if (pending_read_) return; diff --git a/media/test/data/rapid_video_change_test.html b/media/test/data/rapid_video_change_test.html new file mode 100644 index 0000000..81a853b --- /dev/null +++ b/media/test/data/rapid_video_change_test.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<html> + <head> + <title>HTML 5 Change H.264 Video Test</title> + <script> + var changeVideoInterval; + var changeVideoCounter = 0; + + function changeVideo() { + try { + if (changeVideoCounter == 40) { + alert('40 video changes done. Test over'); + window.clearInterval(changeVideoInterval); + return; + } + var video = document.getElementById('video'); + video.pause(); + video.src = 'bear-1280x720.mp4?counter=' + + changeVideoCounter.toString(); + ++changeVideoCounter; + video.play(); + video.currentTime = 1; + } + + catch (e) { + } + } + + function onLoad() { + var video = document.getElementById('video'); + video.play(); + video.currentTime = 1; + changeVideoInterval = setInterval(changeVideo, 200); + } + </script> + </head> + + <body onload='onLoad();'> <b> This test tests the case where in H.264 H/W + decoded videos are added and removed a number of times from the page, + while they are playing. <br> This should not cause the browser to hang. + <div id='videoDiv'> + <video id='video' width=320 height=240 src='bear-1280x720.mp4' + controls='controls'> + </video> + </div> + </body> +</html> |