summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/base/video_frame.cc3
-rw-r--r--media/base/video_frame.h11
-rw-r--r--media/filters/gpu_video_decoder.cc16
-rw-r--r--media/filters/gpu_video_decoder.h13
-rw-r--r--media/filters/skcanvas_video_renderer.cc2
-rw-r--r--media/filters/video_renderer_base.cc9
-rw-r--r--media/test/data/rapid_video_change_test.html47
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>