summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorfischman@chromium.org <fischman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-10 01:03:23 +0000
committerfischman@chromium.org <fischman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-10 01:03:23 +0000
commit907bc6fb0e9db6b31eef1d3403b116e43ea7bec9 (patch)
treeeb41d143dab8fca0cb5c55296125160462617833 /media
parentbb12d853e4af985379bd56ba3025ec0d2b087148 (diff)
downloadchromium_src-907bc6fb0e9db6b31eef1d3403b116e43ea7bec9.zip
chromium_src-907bc6fb0e9db6b31eef1d3403b116e43ea7bec9.tar.gz
chromium_src-907bc6fb0e9db6b31eef1d3403b116e43ea7bec9.tar.bz2
Revert 113895 - <video> decode in hardware!
This uses the GpuVideoDecodeAccelerator machinery (already written to enable ppapi to take advantage of OpenMAX HW where available) to decode <video> data. This increases idle CPU from 20% to 45% on one particularly large (internal) test video (red0.mp4), on an ARM crosbook. HW decode is done on a best-effort basis; if the GPU code doesn't know how to deal with a codec/profile we still fall back to ffmpeg for decode. Because the vast majority of chrome installs will be on HW with no video decode support (yet) we only attempt HW video decode on platforms we know have a shot at it. BUG=104579 TEST=manual testing w/ video test matrix, trybots. Review URL: http://codereview.chromium.org/8686010 TBR=fischman@chromium.org Review URL: http://codereview.chromium.org/8897022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113908 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/composite_filter.cc21
-rw-r--r--media/base/composite_filter.h3
-rw-r--r--media/base/composite_filter_unittest.cc18
-rw-r--r--media/base/filter_collection.h1
-rw-r--r--media/base/filters.cc5
-rw-r--r--media/base/filters.h13
-rw-r--r--media/base/mock_filters.cc4
-rw-r--r--media/base/mock_filters.h3
-rw-r--r--media/base/pipeline_impl.cc32
-rw-r--r--media/base/pipeline_impl.h9
-rw-r--r--media/base/pipeline_impl_unittest.cc4
-rw-r--r--media/base/video_decoder_config.cc34
-rw-r--r--media/base/video_decoder_config.h32
-rw-r--r--media/base/video_frame.cc48
-rw-r--r--media/base/video_frame.h33
-rw-r--r--media/ffmpeg/ffmpeg_common.cc44
-rw-r--r--media/filters/ffmpeg_video_decoder.cc33
-rw-r--r--media/filters/ffmpeg_video_decoder.h2
-rw-r--r--media/filters/ffmpeg_video_decoder_unittest.cc33
-rw-r--r--media/filters/gpu_video_decoder.cc443
-rw-r--r--media/filters/gpu_video_decoder.h169
-rw-r--r--media/filters/video_renderer_base.cc22
-rw-r--r--media/media.gyp2
-rw-r--r--media/video/video_decode_accelerator.h22
24 files changed, 115 insertions, 915 deletions
diff --git a/media/base/composite_filter.cc b/media/base/composite_filter.cc
index d6e45df..5c4b1c5 100644
--- a/media/base/composite_filter.cc
+++ b/media/base/composite_filter.cc
@@ -57,8 +57,6 @@ CompositeFilter::~CompositeFilter() {
}
bool CompositeFilter::AddFilter(scoped_refptr<Filter> filter) {
- // TODO(fischman,scherkus): s/bool/void/ the return type and CHECK on failure
- // of the sanity-checks that return false today.
DCHECK_EQ(message_loop_, MessageLoop::current());
if (!filter.get() || state_ != kCreated || !host())
return false;
@@ -69,23 +67,6 @@ bool CompositeFilter::AddFilter(scoped_refptr<Filter> filter) {
return true;
}
-void CompositeFilter::RemoveFilter(scoped_refptr<Filter> filter) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- if (!filter.get() || state_ != kCreated || !host())
- LOG(FATAL) << "Unknown filter, or in unexpected state.";
-
- bool found = false;
- for (FilterVector::iterator it = filters_.begin();
- it != filters_.end() && !found; ++it) {
- if (it->get() == filter.get()) {
- filters_.erase(it);
- found = true;
- }
- }
- filter->clear_host();
- CHECK(found);
-}
-
void CompositeFilter::set_host(FilterHost* host) {
DCHECK_EQ(message_loop_, MessageLoop::current());
DCHECK(host);
@@ -356,6 +337,7 @@ void CompositeFilter::SerialCallback() {
DispatchPendingCallback(status_);
return;
}
+
if (!filters_.empty())
sequence_index_++;
@@ -393,6 +375,7 @@ void CompositeFilter::ParallelCallback() {
void CompositeFilter::OnCallSequenceDone() {
State next_state = GetNextState(state_);
+
if (next_state == kInvalid) {
// We somehow got into an unexpected state.
ChangeState(kError);
diff --git a/media/base/composite_filter.h b/media/base/composite_filter.h
index 9821d03f..4b35be3 100644
--- a/media/base/composite_filter.h
+++ b/media/base/composite_filter.h
@@ -27,9 +27,6 @@ class MEDIA_EXPORT CompositeFilter : public Filter {
// because the composite is in the wrong state.
bool AddFilter(scoped_refptr<Filter> filter);
- // Undoes AddFilter's actions. CHECK-fails if |filter| is unknown.
- void RemoveFilter(scoped_refptr<Filter> filter);
-
// media::Filter methods.
virtual void set_host(FilterHost* host) OVERRIDE;
virtual FilterHost* host() OVERRIDE;
diff --git a/media/base/composite_filter_unittest.cc b/media/base/composite_filter_unittest.cc
index 36ea0b8..23b7f56 100644
--- a/media/base/composite_filter_unittest.cc
+++ b/media/base/composite_filter_unittest.cc
@@ -379,8 +379,8 @@ TEST_F(CompositeFilterTest, TestAddFilterFailCases) {
EXPECT_FALSE(composite_->AddFilter(filter));
}
-// Test successful {Add,Remove}Filter() cases.
-TEST_F(CompositeFilterTest, TestAddRemoveFilter) {
+// Test successful AddFilter() cases.
+TEST_F(CompositeFilterTest, TestAddFilter) {
composite_->set_host(mock_filter_host_.get());
// Add a filter.
@@ -388,20 +388,8 @@ TEST_F(CompositeFilterTest, TestAddRemoveFilter) {
EXPECT_EQ(NULL, filter->host());
EXPECT_TRUE(composite_->AddFilter(filter));
- EXPECT_TRUE(filter->host() != NULL);
-
- composite_->RemoveFilter(filter);
- EXPECT_TRUE(filter->host() == NULL);
-}
-
-class CompositeFilterDeathTest : public CompositeFilterTest {};
-// Test failure of RemoveFilter() on an unknown filter.
-TEST_F(CompositeFilterDeathTest, TestRemoveUnknownFilter) {
- composite_->set_host(mock_filter_host_.get());
- // Remove unknown filter.
- scoped_refptr<StrictMock<MockFilter> > filter = new StrictMock<MockFilter>();
- EXPECT_DEATH(composite_->RemoveFilter(filter), "");
+ EXPECT_TRUE(filter->host() != NULL);
}
TEST_F(CompositeFilterTest, TestPlay) {
diff --git a/media/base/filter_collection.h b/media/base/filter_collection.h
index edf6b29..97e7232 100644
--- a/media/base/filter_collection.h
+++ b/media/base/filter_collection.h
@@ -40,7 +40,6 @@ class MEDIA_EXPORT FilterCollection {
// Selects a filter of the specified type from the collection.
// If the required filter cannot be found, NULL is returned.
// If a filter is returned it is removed from the collection.
- // Filters are selected in FIFO order.
void SelectVideoDecoder(scoped_refptr<VideoDecoder>* filter_out);
void SelectAudioDecoder(scoped_refptr<AudioDecoder>* filter_out);
void SelectVideoRenderer(scoped_refptr<VideoRenderer>* filter_out);
diff --git a/media/base/filters.cc b/media/base/filters.cc
index ace7d4e..877f391 100644
--- a/media/base/filters.cc
+++ b/media/base/filters.cc
@@ -29,11 +29,6 @@ Filter::Filter() : host_(NULL) {}
Filter::~Filter() {}
-void Filter::clear_host() {
- DCHECK(host_);
- host_ = NULL;
-}
-
void Filter::set_host(FilterHost* host) {
DCHECK(host);
DCHECK(!host_);
diff --git a/media/base/filters.h b/media/base/filters.h
index 5cd4cf8..e464202 100644
--- a/media/base/filters.h
+++ b/media/base/filters.h
@@ -62,8 +62,8 @@ enum Preload {
// Used for completing asynchronous methods.
typedef base::Callback<void(PipelineStatus)> FilterStatusCB;
-// These functions copy |*cb|, call Reset() on |*cb|, and then call Run()
-// on the copy. This is used in the common case where you need to clear
+// This function copies |*cb|, calls Reset() on |*cb|, and then calls Run()
+// on the copy. This is used in the common case where you need to clear
// a callback member variable before running the callback.
MEDIA_EXPORT void ResetAndRunCB(FilterStatusCB* cb, PipelineStatus status);
MEDIA_EXPORT void ResetAndRunCB(base::Closure* cb);
@@ -81,10 +81,6 @@ class MEDIA_EXPORT Filter : public base::RefCountedThreadSafe<Filter> {
// to be released before the host object is destroyed by the pipeline.
virtual void set_host(FilterHost* host);
- // Clear |host_| to signal abandonment. Must be called after set_host() and
- // before any state-changing method below.
- virtual void clear_host();
-
virtual FilterHost* host();
// The pipeline has resumed playback. Filters can continue requesting reads.
@@ -168,8 +164,9 @@ class MEDIA_EXPORT VideoDecoder : public Filter {
// Initialize a VideoDecoder with the given DemuxerStream, executing the
// callback upon completion.
// stats_callback is used to update global pipeline statistics.
- virtual void Initialize(DemuxerStream* stream,
- const PipelineStatusCB& callback,
+ //
+ // TODO(scherkus): switch to PipelineStatus callback.
+ virtual void Initialize(DemuxerStream* stream, const base::Closure& callback,
const StatisticsCallback& stats_callback) = 0;
// Request a frame to be decoded and returned via the provided callback.
diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc
index c8f71e8..d398448 100644
--- a/media/base/mock_filters.cc
+++ b/media/base/mock_filters.cc
@@ -166,10 +166,6 @@ void RunPipelineStatusCB(PipelineStatus status, const PipelineStatusCB& cb) {
cb.Run(status);
}
-void RunPipelineStatusOKCB(const PipelineStatusCB& cb) {
- cb.Run(PIPELINE_OK);
-}
-
void RunFilterCallback3(::testing::Unused, const base::Closure& callback,
::testing::Unused) {
callback.Run();
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index 5c36b10..13a8d2c 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -188,7 +188,7 @@ class MockVideoDecoder : public VideoDecoder {
// VideoDecoder implementation.
MOCK_METHOD3(Initialize, void(DemuxerStream* stream,
- const PipelineStatusCB& callback,
+ const base::Closure& callback,
const StatisticsCallback& stats_callback));
MOCK_METHOD1(Read, void(const ReadCB& callback));
MOCK_METHOD0(natural_size, const gfx::Size&());
@@ -322,7 +322,6 @@ class MockFilterCollection {
void RunFilterCallback(::testing::Unused, const base::Closure& callback);
void RunFilterStatusCB(::testing::Unused, const FilterStatusCB& cb);
void RunPipelineStatusCB(PipelineStatus status, const PipelineStatusCB& cb);
-void RunPipelineStatusOKCB(const PipelineStatusCB& cb); // Always PIPELINE_OK.
void RunFilterCallback3(::testing::Unused, const base::Closure& callback,
::testing::Unused);
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc
index aa5ac3b..d4c1b8e 100644
--- a/media/base/pipeline_impl.cc
+++ b/media/base/pipeline_impl.cc
@@ -586,10 +586,10 @@ void PipelineImpl::DisableAudioRenderer() {
}
// Called from any thread.
-void PipelineImpl::OnFilterInitialize(PipelineStatus status) {
+void PipelineImpl::OnFilterInitialize() {
// Continue the initialize task by proceeding to the next stage.
- message_loop_->PostTask(
- FROM_HERE, base::Bind(&PipelineImpl::InitializeTask, this, status));
+ message_loop_->PostTask(FROM_HERE,
+ base::Bind(&PipelineImpl::InitializeTask, this));
}
// Called from any thread.
@@ -661,21 +661,9 @@ void PipelineImpl::StartTask(FilterCollection* filter_collection,
// TODO(hclam): InitializeTask() is now starting the pipeline asynchronously. It
// works like a big state change table. If we no longer need to start filters
// in order, we need to get rid of all the state change.
-void PipelineImpl::InitializeTask(PipelineStatus last_stage_status) {
+void PipelineImpl::InitializeTask() {
DCHECK_EQ(MessageLoop::current(), message_loop_);
- if (last_stage_status != PIPELINE_OK) {
- // Currently only VideoDecoders have a recoverable error code.
- if (state_ == kInitVideoDecoder &&
- last_stage_status == DECODER_ERROR_NOT_SUPPORTED) {
- pipeline_init_state_->composite_->RemoveFilter(
- pipeline_init_state_->video_decoder_.get());
- state_ = kInitAudioRenderer;
- } else {
- SetError(last_stage_status);
- }
- }
-
// If we have received the stop or error signal, return immediately.
if (IsPipelineStopPending() || IsPipelineStopped() || !IsPipelineOk())
return;
@@ -1123,8 +1111,10 @@ void PipelineImpl::FinishDestroyingFiltersTask() {
bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) {
bool ret = pipeline_init_state_->composite_->AddFilter(filter.get());
- if (!ret)
+
+ if (!ret) {
SetError(PIPELINE_ERROR_INITIALIZATION_FAILED);
+ }
return ret;
}
@@ -1165,7 +1155,7 @@ void PipelineImpl::OnDemuxerBuilt(PipelineStatus status, Demuxer* demuxer) {
clock_->SetTime(demuxer_->GetStartTime());
}
- OnFilterInitialize(PIPELINE_OK);
+ OnFilterInitialize();
}
bool PipelineImpl::InitializeAudioDecoder(
@@ -1193,7 +1183,7 @@ bool PipelineImpl::InitializeAudioDecoder(
pipeline_init_state_->audio_decoder_ = audio_decoder;
audio_decoder->Initialize(
stream,
- base::Bind(&PipelineImpl::OnFilterInitialize, this, PIPELINE_OK),
+ base::Bind(&PipelineImpl::OnFilterInitialize, this),
base::Bind(&PipelineImpl::OnUpdateStatistics, this));
return true;
}
@@ -1250,7 +1240,7 @@ bool PipelineImpl::InitializeAudioRenderer(
audio_renderer_->Initialize(
decoder,
- base::Bind(&PipelineImpl::OnFilterInitialize, this, PIPELINE_OK),
+ base::Bind(&PipelineImpl::OnFilterInitialize, this),
base::Bind(&PipelineImpl::OnAudioUnderflow, this));
return true;
}
@@ -1274,7 +1264,7 @@ bool PipelineImpl::InitializeVideoRenderer(
video_renderer_->Initialize(
decoder,
- base::Bind(&PipelineImpl::OnFilterInitialize, this, PIPELINE_OK),
+ base::Bind(&PipelineImpl::OnFilterInitialize, this),
base::Bind(&PipelineImpl::OnUpdateStatistics, this));
return true;
}
diff --git a/media/base/pipeline_impl.h b/media/base/pipeline_impl.h
index 9426688..5fb8f82 100644
--- a/media/base/pipeline_impl.h
+++ b/media/base/pipeline_impl.h
@@ -206,8 +206,8 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline, public FilterHost {
virtual void SetCurrentReadPosition(int64 offset) OVERRIDE;
virtual int64 GetCurrentReadPosition() OVERRIDE;
- // Callbacks executed by filters upon completing initialization.
- void OnFilterInitialize(PipelineStatus status);
+ // Callback executed by filters upon completing initialization.
+ void OnFilterInitialize();
// Callback executed by filters upon completing Play(), Pause(), or Stop().
void OnFilterStateTransition();
@@ -231,9 +231,8 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline, public FilterHost {
// InitializeTask() performs initialization in multiple passes. It is executed
// as a result of calling Start() or InitializationComplete() that advances
// initialization to the next state. It works as a hub of state transition for
- // initialization. One stage communicates its status to the next through
- // |last_stage_status|.
- void InitializeTask(PipelineStatus last_stage_status);
+ // initialization.
+ void InitializeTask();
// Stops and destroys all filters, placing the pipeline in the kStopped state.
void StopTask(const PipelineStatusCB& stop_callback);
diff --git a/media/base/pipeline_impl_unittest.cc b/media/base/pipeline_impl_unittest.cc
index 76f7a0c..fc9692e 100644
--- a/media/base/pipeline_impl_unittest.cc
+++ b/media/base/pipeline_impl_unittest.cc
@@ -21,13 +21,11 @@ using ::testing::_;
using ::testing::DeleteArg;
using ::testing::InSequence;
using ::testing::Invoke;
-using ::testing::InvokeArgument;
using ::testing::Mock;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::StrictMock;
-using ::testing::WithArg;
namespace media {
@@ -128,7 +126,7 @@ class PipelineImplTest : public ::testing::Test {
void InitializeVideoDecoder(MockDemuxerStream* stream) {
EXPECT_CALL(*mocks_->video_decoder(),
Initialize(stream, _, _))
- .WillOnce(WithArg<1>(Invoke(&RunPipelineStatusOKCB)));
+ .WillOnce(Invoke(&RunFilterCallback3));
EXPECT_CALL(*mocks_->video_decoder(), SetPlaybackRate(0.0f));
EXPECT_CALL(*mocks_->video_decoder(),
Seek(mocks_->demuxer()->GetStartTime(), _))
diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc
index 07bf9a5..ee334d3 100644
--- a/media/base/video_decoder_config.cc
+++ b/media/base/video_decoder_config.cc
@@ -14,7 +14,6 @@ namespace media {
VideoDecoderConfig::VideoDecoderConfig()
: codec_(kUnknownVideoCodec),
- profile_(VIDEO_CODEC_PROFILE_UNKNOWN),
format_(VideoFrame::INVALID),
frame_rate_numerator_(0),
frame_rate_denominator_(0),
@@ -24,7 +23,6 @@ VideoDecoderConfig::VideoDecoderConfig()
}
VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec,
- VideoCodecProfile profile,
VideoFrame::Format format,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
@@ -34,7 +32,7 @@ VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec,
int aspect_ratio_denominator,
const uint8* extra_data,
size_t extra_data_size) {
- Initialize(codec, profile, format, coded_size, visible_rect,
+ Initialize(codec, format, coded_size, visible_rect,
frame_rate_numerator, frame_rate_denominator,
aspect_ratio_numerator, aspect_ratio_denominator,
extra_data, extra_data_size);
@@ -64,9 +62,7 @@ static void UmaHistogramAspectRatio(const char* name, const T& size) {
kCommonAspectRatios100, arraysize(kCommonAspectRatios100)));
}
-void VideoDecoderConfig::Initialize(VideoCodec codec,
- VideoCodecProfile profile,
- VideoFrame::Format format,
+void VideoDecoderConfig::Initialize(VideoCodec codec, VideoFrame::Format format,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
int frame_rate_numerator,
@@ -78,15 +74,12 @@ void VideoDecoderConfig::Initialize(VideoCodec codec,
CHECK((extra_data_size != 0) == (extra_data != NULL));
UMA_HISTOGRAM_ENUMERATION("Media.VideoCodec", codec, kVideoCodecMax + 1);
- UMA_HISTOGRAM_ENUMERATION("Media.VideoCodecProfile", profile,
- VIDEO_CODEC_PROFILE_MAX + 1);
UMA_HISTOGRAM_COUNTS_10000("Media.VideoCodedWidth", coded_size.width());
UmaHistogramAspectRatio("Media.VideoCodedAspectRatio", coded_size);
UMA_HISTOGRAM_COUNTS_10000("Media.VideoVisibleWidth", visible_rect.width());
UmaHistogramAspectRatio("Media.VideoVisibleAspectRatio", visible_rect);
codec_ = codec;
- profile_ = profile;
format_ = format;
coded_size_ = coded_size;
visible_rect_ = visible_rect;
@@ -132,33 +125,10 @@ bool VideoDecoderConfig::IsValidConfig() const {
natural_size_.GetArea() <= limits::kMaxCanvas;
}
-std::string VideoDecoderConfig::AsHumanReadableString() const {
- std::ostringstream s;
- s << "codec: " << codec()
- << " format: " << format()
- << " coded size: [" << coded_size().width()
- << "," << coded_size().height() << "]"
- << " visible rect: [" << visible_rect().x()
- << "," << visible_rect().y()
- << "," << visible_rect().width()
- << "," << visible_rect().height() << "]"
- << " natural size: [" << natural_size().width()
- << "," << natural_size().height() << "]"
- << " frame rate: " << frame_rate_numerator()
- << "/" << frame_rate_denominator()
- << " aspect ratio: " << aspect_ratio_numerator()
- << "/" << aspect_ratio_denominator();
- return s.str();
-}
-
VideoCodec VideoDecoderConfig::codec() const {
return codec_;
}
-VideoCodecProfile VideoDecoderConfig::profile() const {
- return profile_;
-}
-
VideoFrame::Format VideoDecoderConfig::format() const {
return format_;
}
diff --git a/media/base/video_decoder_config.h b/media/base/video_decoder_config.h
index 28b1106..b02bee8 100644
--- a/media/base/video_decoder_config.h
+++ b/media/base/video_decoder_config.h
@@ -14,7 +14,7 @@
namespace media {
-enum MEDIA_EXPORT VideoCodec {
+enum VideoCodec {
// These values are histogrammed over time; do not change their ordinal
// values. When deleting a codec replace it with a dummy value; when adding a
// codec, do so at the bottom (and update kVideoCodecMax).
@@ -33,28 +33,6 @@ enum MEDIA_EXPORT VideoCodec {
kVideoCodecMax = kCodecVP8 // Must equal the last "real" codec above.
};
-// Video stream profile. This *must* match PP_VideoDecoder_Profile.
-enum MEDIA_EXPORT VideoCodecProfile {
- // Keep the values in this enum unique, as they imply format (h.264 vs. VP8,
- // for example), and keep the values for a particular format grouped
- // together for clarity.
- VIDEO_CODEC_PROFILE_UNKNOWN = -1,
- H264PROFILE_MIN = 0,
- H264PROFILE_BASELINE = H264PROFILE_MIN,
- H264PROFILE_MAIN,
- H264PROFILE_EXTENDED,
- H264PROFILE_HIGH,
- H264PROFILE_HIGH10PROFILE,
- H264PROFILE_HIGH422PROFILE,
- H264PROFILE_HIGH444PREDICTIVEPROFILE,
- H264PROFILE_SCALABLEBASELINE,
- H264PROFILE_SCALABLEHIGH,
- H264PROFILE_STEREOHIGH,
- H264PROFILE_MULTIVIEWHIGH,
- H264PROFILE_MAX = H264PROFILE_MULTIVIEWHIGH,
- VIDEO_CODEC_PROFILE_MAX = H264PROFILE_MAX,
-};
-
class MEDIA_EXPORT VideoDecoderConfig {
public:
// Constructs an uninitialized object. Clients should call Initialize() with
@@ -64,7 +42,6 @@ class MEDIA_EXPORT VideoDecoderConfig {
// Constructs an initialized object. It is acceptable to pass in NULL for
// |extra_data|, otherwise the memory is copied.
VideoDecoderConfig(VideoCodec codec,
- VideoCodecProfile profile,
VideoFrame::Format format,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
@@ -76,7 +53,6 @@ class MEDIA_EXPORT VideoDecoderConfig {
// Resets the internal state of this object.
void Initialize(VideoCodec codec,
- VideoCodecProfile profile,
VideoFrame::Format format,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
@@ -88,12 +64,7 @@ class MEDIA_EXPORT VideoDecoderConfig {
// otherwise.
bool IsValidConfig() const;
- // Returns a human-readable string describing |*this|. For debugging & test
- // output only.
- std::string AsHumanReadableString() const;
-
VideoCodec codec() const;
- VideoCodecProfile profile() const;
// Video format used to determine YUV buffer sizes.
VideoFrame::Format format() const;
@@ -131,7 +102,6 @@ class MEDIA_EXPORT VideoDecoderConfig {
private:
VideoCodec codec_;
- VideoCodecProfile profile_;
VideoFrame::Format format_;
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 29c4223..a0dc579 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -17,8 +17,9 @@ scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
base::TimeDelta duration) {
DCHECK(width > 0 && height > 0);
DCHECK(width * height < 100000000);
- scoped_refptr<VideoFrame> frame(new VideoFrame(
- format, width, height, timestamp, duration));
+ scoped_refptr<VideoFrame> frame(new VideoFrame(format, width, height));
+ frame->SetTimestamp(timestamp);
+ frame->SetDuration(duration);
switch (format) {
case VideoFrame::RGB555:
case VideoFrame::RGB565:
@@ -46,25 +47,8 @@ scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
}
// static
-scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
- uint32 texture_id,
- size_t width,
- size_t height,
- base::TimeDelta timestamp,
- base::TimeDelta duration,
- const base::Closure& no_longer_needed) {
- scoped_refptr<VideoFrame> frame(
- new VideoFrame(NATIVE_TEXTURE, width, height, timestamp, duration));
- frame->planes_ = 0;
- frame->texture_id_ = texture_id;
- frame->texture_no_longer_needed_ = no_longer_needed;
- return frame;
-}
-
-// static
scoped_refptr<VideoFrame> VideoFrame::CreateEmptyFrame() {
- return new VideoFrame(
- VideoFrame::EMPTY, 0, 0, base::TimeDelta(), base::TimeDelta());
+ return new VideoFrame(VideoFrame::EMPTY, 0, 0);
}
// static
@@ -154,26 +138,16 @@ void VideoFrame::AllocateYUV() {
VideoFrame::VideoFrame(VideoFrame::Format format,
size_t width,
- size_t height,
- base::TimeDelta timestamp,
- base::TimeDelta duration)
+ size_t height)
: format_(format),
width_(width),
height_(height),
- planes_(0),
- texture_id_(0) {
- SetTimestamp(timestamp);
- SetDuration(duration);
+ planes_(0) {
memset(&strides_, 0, sizeof(strides_));
memset(&data_, 0, sizeof(data_));
}
VideoFrame::~VideoFrame() {
- if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) {
- texture_no_longer_needed_.Run();
- texture_no_longer_needed_.Reset();
- }
-
// In multi-plane allocations, only a single block of memory is allocated
// on the heap, and other |data| pointers point inside the same, single block
// so just delete index 0.
@@ -193,10 +167,6 @@ bool VideoFrame::IsValidPlane(size_t plane) const {
case YV16:
return plane == kYPlane || plane == kUPlane || plane == kVPlane;
- case NATIVE_TEXTURE:
- NOTREACHED() << "NATIVE_TEXTUREs don't use plane-related methods!";
- return false;
-
default:
break;
}
@@ -266,12 +236,6 @@ uint8* VideoFrame::data(size_t plane) const {
return data_[plane];
}
-uint32 VideoFrame::texture_id() const {
- DCHECK_EQ(format_, NATIVE_TEXTURE);
- DCHECK_EQ(planes_, 0U);
- return texture_id_;
-}
-
bool VideoFrame::IsEndOfStream() const {
return format_ == VideoFrame::EMPTY;
}
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index 1801077..ab96544 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -5,7 +5,6 @@
#ifndef MEDIA_BASE_VIDEO_FRAME_H_
#define MEDIA_BASE_VIDEO_FRAME_H_
-#include "base/callback.h"
#include "media/base/buffers.h"
namespace media {
@@ -26,7 +25,6 @@ class MEDIA_EXPORT VideoFrame : public StreamSample {
// Surface formats roughly based on FOURCC labels, see:
// http://www.fourcc.org/rgb.php
// http://www.fourcc.org/yuv.php
- // Keep in sync with WebKit::WebVideoFrame!
enum Format {
INVALID, // Invalid format value. Used for error reporting.
RGB555, // 16bpp RGB packed 5:5:5
@@ -40,7 +38,6 @@ class MEDIA_EXPORT VideoFrame : public StreamSample {
EMPTY, // An empty frame.
ASCII, // A frame with ASCII content. For testing only.
I420, // 12bpp YVU planar 1x1 Y, 2x2 UV samples.
- NATIVE_TEXTURE, // Opaque native texture. Pixel-format agnostic.
};
// Creates a new frame in system memory with given parameters. Buffers for
@@ -52,16 +49,6 @@ class MEDIA_EXPORT VideoFrame : public StreamSample {
base::TimeDelta timestamp,
base::TimeDelta duration);
- // Wraps a native texture of the given parameters with a VideoFrame. When the
- // frame is destroyed |no_longer_needed.Run()| will be called.
- static scoped_refptr<VideoFrame> WrapNativeTexture(
- uint32 texture_id,
- size_t width,
- size_t height,
- base::TimeDelta timestamp,
- base::TimeDelta duration,
- const base::Closure& no_longer_needed);
-
// Creates a frame with format equals to VideoFrame::EMPTY, width, height
// timestamp and duration are all 0.
static scoped_refptr<VideoFrame> CreateEmptyFrame();
@@ -91,20 +78,14 @@ class MEDIA_EXPORT VideoFrame : public StreamSample {
// VideoFrame object and must not be freed by the caller.
uint8* data(size_t plane) const;
- // Returns the ID of the native texture wrapped by this frame. Only valid to
- // call if this is a NATIVE_TEXTURE frame.
- uint32 texture_id() const;
-
// StreamSample interface.
virtual bool IsEndOfStream() const OVERRIDE;
- private:
+ protected:
// Clients must use the static CreateFrame() method to create a new frame.
VideoFrame(Format format,
size_t video_width,
- size_t video_height,
- base::TimeDelta timestamp,
- base::TimeDelta duration);
+ size_t video_height);
virtual ~VideoFrame();
@@ -122,8 +103,8 @@ class MEDIA_EXPORT VideoFrame : public StreamSample {
size_t width_;
size_t height_;
- // Number of planes, typically 1 for packed RGB formats, 3 for planar
- // YUV formats, and 0 for native textures.
+ // Number of planes, typically 1 for packed RGB formats and 3 for planar
+ // YUV formats.
size_t planes_;
// Array of strides for each plane, typically greater or equal to the width
@@ -134,11 +115,7 @@ class MEDIA_EXPORT VideoFrame : public StreamSample {
// Array of data pointers to each plane.
uint8* data_[kMaxPlanes];
- // Native texture ID, if this is a NATIVE_TEXTURE frame.
- uint32 texture_id_;
- base::Closure texture_no_longer_needed_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(VideoFrame);
+ DISALLOW_COPY_AND_ASSIGN(VideoFrame);
};
} // namespace media
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index b9776fe..396ee03 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -127,48 +127,6 @@ static CodecID VideoCodecToCodecID(VideoCodec video_codec) {
return CODEC_ID_NONE;
}
-static VideoCodecProfile ProfileIDToVideoCodecProfile(int profile) {
- switch (profile) {
- case FF_PROFILE_H264_BASELINE:
- return H264PROFILE_BASELINE;
- case FF_PROFILE_H264_MAIN:
- return H264PROFILE_MAIN;
- case FF_PROFILE_H264_EXTENDED:
- return H264PROFILE_EXTENDED;
- case FF_PROFILE_H264_HIGH:
- return H264PROFILE_HIGH;
- case FF_PROFILE_H264_HIGH_10:
- return H264PROFILE_HIGH10PROFILE;
- case FF_PROFILE_H264_HIGH_422:
- return H264PROFILE_HIGH422PROFILE;
- case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
- return H264PROFILE_HIGH444PREDICTIVEPROFILE;
- default:
- return VIDEO_CODEC_PROFILE_UNKNOWN;
- }
-}
-
-static int VideoCodecProfileToProfileID(VideoCodecProfile profile) {
- switch (profile) {
- case H264PROFILE_BASELINE:
- return FF_PROFILE_H264_BASELINE;
- case H264PROFILE_MAIN:
- return FF_PROFILE_H264_MAIN;
- case H264PROFILE_EXTENDED:
- return FF_PROFILE_H264_EXTENDED;
- case H264PROFILE_HIGH:
- return FF_PROFILE_H264_HIGH;
- case H264PROFILE_HIGH10PROFILE:
- return FF_PROFILE_H264_HIGH_10;
- case H264PROFILE_HIGH422PROFILE:
- return FF_PROFILE_H264_HIGH_422;
- case H264PROFILE_HIGH444PREDICTIVEPROFILE:
- return FF_PROFILE_H264_HIGH_444_PREDICTIVE;
- default:
- return FF_PROFILE_UNKNOWN;
- }
-}
-
void AVCodecContextToAudioDecoderConfig(
const AVCodecContext* codec_context,
AudioDecoderConfig* config) {
@@ -246,7 +204,6 @@ void AVStreamToVideoDecoderConfig(
aspect_ratio = stream->codec->sample_aspect_ratio;
config->Initialize(CodecIDToVideoCodec(stream->codec->codec_id),
- ProfileIDToVideoCodecProfile(stream->codec->profile),
PixelFormatToVideoFormat(stream->codec->pix_fmt),
coded_size, visible_rect,
stream->r_frame_rate.num,
@@ -262,7 +219,6 @@ void VideoDecoderConfigToAVCodecContext(
AVCodecContext* codec_context) {
codec_context->codec_type = AVMEDIA_TYPE_VIDEO;
codec_context->codec_id = VideoCodecToCodecID(config.codec());
- codec_context->profile = VideoCodecProfileToProfileID(config.profile());
codec_context->coded_width = config.coded_size().width();
codec_context->coded_height = config.coded_size().height();
codec_context->pix_fmt = VideoFormatToPixelFormat(config.format());
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index 66b25b6..39d9e39 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -64,7 +64,7 @@ FFmpegVideoDecoder::~FFmpegVideoDecoder() {
}
void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
- const PipelineStatusCB& callback,
+ const base::Closure& callback,
const StatisticsCallback& stats_callback) {
if (MessageLoop::current() != message_loop_) {
message_loop_->PostTask(FROM_HERE, base::Bind(
@@ -76,7 +76,8 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
DCHECK(!demuxer_stream_);
if (!demuxer_stream) {
- callback.Run(PIPELINE_ERROR_DECODE);
+ host()->SetError(PIPELINE_ERROR_DECODE);
+ callback.Run();
return;
}
@@ -88,8 +89,24 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
// TODO(scherkus): this check should go in PipelineImpl prior to creating
// decoder objects.
if (!config.IsValidConfig()) {
- DLOG(ERROR) << "Invalid video stream - " << config.AsHumanReadableString();
- callback.Run(PIPELINE_ERROR_DECODE);
+ DLOG(ERROR) << "Invalid video stream -"
+ << " codec: " << config.codec()
+ << " format: " << config.format()
+ << " coded size: [" << config.coded_size().width()
+ << "," << config.coded_size().height() << "]"
+ << " visible rect: [" << config.visible_rect().x()
+ << "," << config.visible_rect().y()
+ << "," << config.visible_rect().width()
+ << "," << config.visible_rect().height() << "]"
+ << " natural size: [" << config.natural_size().width()
+ << "," << config.natural_size().height() << "]"
+ << " frame rate: " << config.frame_rate_numerator()
+ << "/" << config.frame_rate_denominator()
+ << " aspect ratio: " << config.aspect_ratio_numerator()
+ << "/" << config.aspect_ratio_denominator();
+
+ host()->SetError(PIPELINE_ERROR_DECODE);
+ callback.Run();
return;
}
@@ -105,12 +122,14 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
if (!codec) {
- callback.Run(PIPELINE_ERROR_DECODE);
+ host()->SetError(PIPELINE_ERROR_DECODE);
+ callback.Run();
return;
}
if (avcodec_open(codec_context_, codec) < 0) {
- callback.Run(PIPELINE_ERROR_DECODE);
+ host()->SetError(PIPELINE_ERROR_DECODE);
+ callback.Run();
return;
}
@@ -121,7 +140,7 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
natural_size_ = config.natural_size();
frame_rate_numerator_ = config.frame_rate_numerator();
frame_rate_denominator_ = config.frame_rate_denominator();
- callback.Run(PIPELINE_OK);
+ callback.Run();
}
void FFmpegVideoDecoder::Stop(const base::Closure& callback) {
diff --git a/media/filters/ffmpeg_video_decoder.h b/media/filters/ffmpeg_video_decoder.h
index c5a412f..34cf700 100644
--- a/media/filters/ffmpeg_video_decoder.h
+++ b/media/filters/ffmpeg_video_decoder.h
@@ -32,7 +32,7 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder {
// VideoDecoder implementation.
virtual void Initialize(DemuxerStream* demuxer_stream,
- const PipelineStatusCB& callback,
+ const base::Closure& callback,
const StatisticsCallback& stats_callback) OVERRIDE;
virtual void Read(const ReadCB& callback) OVERRIDE;
virtual const gfx::Size& natural_size() OVERRIDE;
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index b072993..30ed2b4 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -58,8 +58,7 @@ class FFmpegVideoDecoderTest : public testing::Test {
ReadTestDataFile("vp8-I-frame-320x240", &i_frame_buffer_);
ReadTestDataFile("vp8-corrupt-I-frame", &corrupt_i_frame_buffer_);
- config_.Initialize(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
- kVideoFormat, kCodedSize, kVisibleRect,
+ config_.Initialize(kCodecVP8, kVideoFormat, kCodedSize, kVisibleRect,
kFrameRate.num, kFrameRate.den,
kAspectRatio.num, kAspectRatio.den,
NULL, 0);
@@ -71,22 +70,17 @@ class FFmpegVideoDecoderTest : public testing::Test {
InitializeWithConfig(config_);
}
- void InitializeWithConfigAndStatus(const VideoDecoderConfig& config,
- PipelineStatus status) {
+ void InitializeWithConfig(const VideoDecoderConfig& config) {
EXPECT_CALL(*demuxer_, video_decoder_config())
.WillOnce(ReturnRef(config));
- decoder_->Initialize(demuxer_, NewExpectedStatusCB(status),
+ decoder_->Initialize(demuxer_, NewExpectedClosure(),
base::Bind(&MockStatisticsCallback::OnStatistics,
base::Unretained(&statistics_callback_)));
message_loop_.RunAllPending();
}
- void InitializeWithConfig(const VideoDecoderConfig& config) {
- InitializeWithConfigAndStatus(config, PIPELINE_OK);
- }
-
void Pause() {
decoder_->Pause(NewExpectedClosure());
message_loop_.RunAllPending();
@@ -248,35 +242,38 @@ TEST_F(FFmpegVideoDecoderTest, Initialize_Normal) {
TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedDecoder) {
// Test avcodec_find_decoder() returning NULL.
- VideoDecoderConfig config(kUnknownVideoCodec, VIDEO_CODEC_PROFILE_UNKNOWN,
- kVideoFormat,
+ VideoDecoderConfig config(kUnknownVideoCodec, kVideoFormat,
kCodedSize, kVisibleRect,
kFrameRate.num, kFrameRate.den,
kAspectRatio.num, kAspectRatio.den,
NULL, 0);
- InitializeWithConfigAndStatus(config, PIPELINE_ERROR_DECODE);
+
+ EXPECT_CALL(host_, SetError(PIPELINE_ERROR_DECODE));
+ InitializeWithConfig(config);
}
TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedPixelFormat) {
// Ensure decoder handles unsupport pixel formats without crashing.
- VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
- VideoFrame::INVALID,
+ VideoDecoderConfig config(kCodecVP8, VideoFrame::INVALID,
kCodedSize, kVisibleRect,
kFrameRate.num, kFrameRate.den,
kAspectRatio.num, kAspectRatio.den,
NULL, 0);
- InitializeWithConfigAndStatus(config, PIPELINE_ERROR_DECODE);
+
+ EXPECT_CALL(host_, SetError(PIPELINE_ERROR_DECODE));
+ InitializeWithConfig(config);
}
TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) {
// Specify Theora w/o extra data so that avcodec_open() fails.
- VideoDecoderConfig config(kCodecTheora, VIDEO_CODEC_PROFILE_UNKNOWN,
- kVideoFormat,
+ VideoDecoderConfig config(kCodecTheora, kVideoFormat,
kCodedSize, kVisibleRect,
kFrameRate.num, kFrameRate.den,
kAspectRatio.num, kAspectRatio.den,
NULL, 0);
- InitializeWithConfigAndStatus(config, PIPELINE_ERROR_DECODE);
+
+ EXPECT_CALL(host_, SetError(PIPELINE_ERROR_DECODE));
+ InitializeWithConfig(config);
}
TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) {
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
deleted file mode 100644
index 11580a3..0000000
--- a/media/filters/gpu_video_decoder.cc
+++ /dev/null
@@ -1,443 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/filters/gpu_video_decoder.h"
-
-#include "base/bind.h"
-#include "base/message_loop.h"
-#include "base/stl_util.h"
-#include "media/base/demuxer_stream.h"
-#include "media/base/filter_host.h"
-#include "media/base/video_decoder_config.h"
-#include "media/ffmpeg/ffmpeg_common.h"
-
-namespace media {
-
-GpuVideoDecoder::Factories::~Factories() {}
-
-// Size of shared-memory segments we allocate. Since we reuse them we let them
-// be on the beefy side.
-static const size_t kSharedMemorySegmentBytes = 100 << 10;
-
-GpuVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* m, size_t s)
- : shm(m), size(s) {
-}
-
-GpuVideoDecoder::SHMBuffer::~SHMBuffer() {}
-
-GpuVideoDecoder::BufferPair::BufferPair(
- SHMBuffer* s, const scoped_refptr<Buffer>& b) : shm_buffer(s), buffer(b) {
-}
-
-GpuVideoDecoder::BufferPair::~BufferPair() {}
-
-GpuVideoDecoder::GpuVideoDecoder(
- MessageLoop* message_loop,
- Factories* factories)
- : message_loop_(message_loop),
- factories_(factories),
- flush_in_progress_(false),
- demuxer_read_in_progress_(false),
- next_picture_buffer_id_(0),
- next_bitstream_buffer_id_(0) {
- DCHECK(message_loop_ && factories_.get());
-}
-
-GpuVideoDecoder::~GpuVideoDecoder() {
- DCHECK(!vda_); // Stop should have been already called.
- STLDeleteElements(&available_shm_segments_);
- for (std::map<int32, BufferPair>::iterator it =
- bitstream_buffers_in_decoder_.begin();
- it != bitstream_buffers_in_decoder_.end(); ++it) {
- it->second.shm_buffer->shm->Close();
- }
- bitstream_buffers_in_decoder_.clear();
-}
-
-void GpuVideoDecoder::Stop(const base::Closure& callback) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::Stop, this, callback));
- return;
- }
- if (!vda_) {
- callback.Run();
- return;
- }
- vda_->Destroy();
- vda_ = NULL;
- callback.Run();
-}
-
-void GpuVideoDecoder::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::Seek, this, time, cb));
- return;
- }
- pts_stream_.Seek(time);
- cb.Run(PIPELINE_OK);
-}
-
-void GpuVideoDecoder::Pause(const base::Closure& callback) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::Pause, this, callback));
- return;
- }
- callback.Run();
-}
-
-void GpuVideoDecoder::Flush(const base::Closure& callback) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::Flush, this, callback));
- return;
- }
- // Pipeline should have quiesced (via Pause() to all filters) before calling
- // us, so there should be nothing pending.
- DCHECK(pending_read_cb_.is_null());
-
- // Throw away any already-decoded frames.
- ready_video_frames_.clear();
-
- if (!vda_) {
- callback.Run();
- return;
- }
- DCHECK(pending_flush_cb_.is_null());
- pending_flush_cb_ = callback;
- pts_stream_.Flush();
- vda_->Reset();
-}
-
-void GpuVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
- const PipelineStatusCB& callback,
- const StatisticsCallback& stats_callback) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::Initialize, this,
- make_scoped_refptr(demuxer_stream), callback, stats_callback));
- return;
- }
-
- DCHECK(!demuxer_stream_);
- if (!demuxer_stream) {
- callback.Run(PIPELINE_ERROR_DECODE);
- return;
- }
-
- const VideoDecoderConfig& config = demuxer_stream->video_decoder_config();
- // TODO(scherkus): this check should go in PipelineImpl prior to creating
- // decoder objects.
- if (!config.IsValidConfig()) {
- DLOG(ERROR) << "Invalid video stream - " << config.AsHumanReadableString();
- callback.Run(PIPELINE_ERROR_DECODE);
- return;
- }
-
- vda_ = factories_->CreateVideoDecodeAccelerator(config.profile(), this);
- if (!vda_) {
- callback.Run(DECODER_ERROR_NOT_SUPPORTED);
- return;
- }
-
- demuxer_stream_ = demuxer_stream;
- statistics_callback_ = stats_callback;
-
- demuxer_stream_->EnableBitstreamConverter();
-
- pts_stream_.Initialize(GetFrameDuration(config));
- natural_size_ = config.natural_size();
-
- callback.Run(PIPELINE_OK);
-}
-
-void GpuVideoDecoder::Read(const ReadCB& callback) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::Read, this, callback));
- return;
- }
-
- if (!vda_) {
- callback.Run(VideoFrame::CreateEmptyFrame());
- return;
- }
-
- DCHECK(pending_read_cb_.is_null());
- pending_read_cb_ = callback;
-
- if (!ready_video_frames_.empty()) {
- DeliverFrame(ready_video_frames_.front());
- ready_video_frames_.pop_front();
- return;
- }
- EnsureDemuxOrDecode();
-}
-
-void GpuVideoDecoder::RequestBufferDecode(const scoped_refptr<Buffer>& buffer) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::RequestBufferDecode, this, buffer));
- return;
- }
- demuxer_read_in_progress_ = false;
-
- if (!vda_) {
- DeliverFrame(VideoFrame::CreateEmptyFrame());
- return;
- }
-
- if (buffer->IsEndOfStream()) {
- if (!flush_in_progress_) {
- flush_in_progress_ = true;
- vda_->Flush();
- }
- return;
- }
-
- size_t size = buffer->GetDataSize();
- SHMBuffer* shm_buffer = GetSHM(size);
- memcpy(shm_buffer->shm->memory(), buffer->GetData(), size);
- BitstreamBuffer bitstream_buffer(
- next_bitstream_buffer_id_++, shm_buffer->shm->handle(), size);
- bool inserted = bitstream_buffers_in_decoder_.insert(std::make_pair(
- bitstream_buffer.id(), BufferPair(shm_buffer, buffer))).second;
- DCHECK(inserted);
- pts_stream_.EnqueuePts(buffer.get());
-
- vda_->Decode(bitstream_buffer);
-}
-
-const gfx::Size& GpuVideoDecoder::natural_size() {
- return natural_size_;
-}
-
-void GpuVideoDecoder::NotifyInitializeDone() {
- NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!";
-}
-
-void GpuVideoDecoder::ProvidePictureBuffers(uint32 count,
- const gfx::Size& size) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::ProvidePictureBuffers, this, count, size));
- return;
- }
-
- std::vector<uint32> texture_ids;
- if (!factories_->CreateTextures(count, size, &texture_ids)) {
- NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
- return;
- }
-
- if (!vda_)
- return;
-
- std::vector<PictureBuffer> picture_buffers;
- for (size_t i = 0; i < texture_ids.size(); ++i) {
- picture_buffers.push_back(PictureBuffer(
- next_picture_buffer_id_++, size, texture_ids[i]));
- bool inserted = picture_buffers_in_decoder_.insert(std::make_pair(
- picture_buffers.back().id(), picture_buffers.back())).second;
- DCHECK(inserted);
- }
- vda_->AssignPictureBuffers(picture_buffers);
-}
-
-void GpuVideoDecoder::DismissPictureBuffer(int32 id) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::DismissPictureBuffer, this, id));
- return;
- }
- std::map<int32, PictureBuffer>::iterator it =
- picture_buffers_in_decoder_.find(id);
- if (it == picture_buffers_in_decoder_.end()) {
- NOTREACHED() << "Missing picture buffer: " << id;
- return;
- }
- if (!factories_->DeleteTexture(it->second.texture_id())) {
- NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
- return;
- }
- picture_buffers_in_decoder_.erase(it);
-}
-
-static void ResetAndRunCB(VideoDecoder::ReadCB* cb,
- scoped_refptr<VideoFrame> frame) {
- DCHECK(!cb->is_null());
- VideoDecoder::ReadCB tmp_cb(*cb);
- cb->Reset();
- tmp_cb.Run(frame);
-}
-
-void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::PictureReady, this, picture));
- return;
- }
- std::map<int32, PictureBuffer>::iterator it =
- picture_buffers_in_decoder_.find(picture.picture_buffer_id());
- if (it == picture_buffers_in_decoder_.end()) {
- NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id();
- NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
- return;
- }
- const PictureBuffer& pb = it->second;
-
- // Update frame's timestamp.
- base::TimeDelta timestamp;
- base::TimeDelta duration;
- std::map<int32, BufferPair>::const_iterator buf_it =
- bitstream_buffers_in_decoder_.find(picture.bitstream_buffer_id());
- if (buf_it != bitstream_buffers_in_decoder_.end()) {
- // Sufficiently out-of-order decoding could have already called
- // NotifyEndOfBitstreamBuffer on this buffer, but that's ok since we only
- // need the buffer's time info for best-effort PTS updating.
- timestamp = buf_it->second.buffer->GetTimestamp();
- duration = buf_it->second.buffer->GetDuration();
- }
-
- scoped_refptr<VideoFrame> frame(VideoFrame::WrapNativeTexture(
- pb.texture_id(), pb.size().width(),
- pb.size().height(), timestamp, duration,
- base::Bind(&GpuVideoDecoder::ReusePictureBuffer, this,
- picture.picture_buffer_id())));
- pts_stream_.UpdatePtsAndDuration(frame.get());
- frame->SetTimestamp(pts_stream_.current_pts());
- frame->SetDuration(pts_stream_.current_duration());
-
- // Deliver the frame.
- DeliverFrame(frame);
-}
-
-void GpuVideoDecoder::DeliverFrame(const scoped_refptr<VideoFrame>& frame) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::DeliverFrameOutOfLine, this, frame));
-}
-
-void GpuVideoDecoder::DeliverFrameOutOfLine(
- const scoped_refptr<VideoFrame>& frame) {
- if (pending_read_cb_.is_null()) {
- ready_video_frames_.push_back(frame);
- return;
- }
- ResetAndRunCB(&pending_read_cb_, frame);
-}
-
-void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::ReusePictureBuffer, this, picture_buffer_id));
- return;
- }
- if (!vda_)
- return;
- vda_->ReusePictureBuffer(picture_buffer_id);
-}
-
-GpuVideoDecoder::SHMBuffer* GpuVideoDecoder::GetSHM(size_t min_size) {
- DCHECK(MessageLoop::current() == message_loop_);
- if (available_shm_segments_.empty() ||
- 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);
- return new SHMBuffer(shm, size_to_allocate);
- }
- SHMBuffer* ret = available_shm_segments_.back();
- available_shm_segments_.pop_back();
- return ret;
-}
-
-void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) {
- DCHECK(MessageLoop::current() == message_loop_);
- available_shm_segments_.push_back(shm_buffer);
-}
-
-void GpuVideoDecoder::NotifyEndOfStream() {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyEndOfStream, this));
- return;
- }
- DeliverFrame(VideoFrame::CreateEmptyFrame());
-}
-
-void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyEndOfBitstreamBuffer, this, id));
- return;
- }
-
- std::map<int32, BufferPair>::iterator it =
- bitstream_buffers_in_decoder_.find(id);
- if (it == bitstream_buffers_in_decoder_.end()) {
- NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
- NOTREACHED() << "Missing bitstream buffer: " << id;
- return;
- }
- PutSHM(it->second.shm_buffer);
- const scoped_refptr<Buffer>& buffer = it->second.buffer;
- if (buffer->GetDataSize()) {
- PipelineStatistics statistics;
- statistics.video_bytes_decoded = buffer->GetDataSize();
- statistics_callback_.Run(statistics);
- }
- bitstream_buffers_in_decoder_.erase(it);
-
- if (!pending_read_cb_.is_null()) {
- DCHECK(ready_video_frames_.empty());
- EnsureDemuxOrDecode();
- }
-}
-
-void GpuVideoDecoder::EnsureDemuxOrDecode() {
- DCHECK(MessageLoop::current() == message_loop_);
- if (demuxer_read_in_progress_ || !bitstream_buffers_in_decoder_.empty())
- return;
- demuxer_read_in_progress_ = true;
- demuxer_stream_->Read(base::Bind(
- &GpuVideoDecoder::RequestBufferDecode, this));
-}
-
-void GpuVideoDecoder::NotifyFlushDone() {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyFlushDone, this));
- return;
- }
- DCHECK(flush_in_progress_);
- flush_in_progress_ = false;
- DeliverFrame(VideoFrame::CreateEmptyFrame());
-}
-
-void GpuVideoDecoder::NotifyResetDone() {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyResetDone, this));
- return;
- }
- // Throw away any already-decoded frames that have come in during the reset.
- ready_video_frames_.clear();
- ResetAndRunCB(&pending_flush_cb_);
-}
-
-void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) {
- if (MessageLoop::current() != message_loop_) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyError, this, error));
- return;
- }
- vda_ = NULL;
- DLOG(ERROR) << "VDA Error: " << error;
- if (host())
- host()->SetError(PIPELINE_ERROR_DECODE);
-}
-
-} // namespace media
diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h
deleted file mode 100644
index 03ceadb..0000000
--- a/media/filters/gpu_video_decoder.h
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_FILTERS_GPU_VIDEO_DECODER_H_
-#define MEDIA_FILTERS_GPU_VIDEO_DECODER_H_
-
-#include <deque>
-#include <list>
-#include <map>
-
-#include "base/memory/scoped_ptr.h"
-#include "media/base/filters.h"
-#include "media/base/pipeline_status.h"
-#include "media/base/pts_stream.h"
-#include "media/video/video_decode_accelerator.h"
-#include "ui/gfx/size.h"
-
-class MessageLoop;
-namespace base {
-class SharedMemory;
-}
-
-namespace media {
-
-// GPU-accelerated video decoder implementation. Relies on
-// AcceleratedVideoDecoderMsg_Decode and friends.
-// All methods internally trampoline to the message_loop passed to the ctor.
-class MEDIA_EXPORT GpuVideoDecoder
- : public VideoDecoder,
- public VideoDecodeAccelerator::Client {
- public:
- // Helper interface for specifying factories needed to instantiate a
- // GpuVideoDecoder.
- class Factories {
- public:
- virtual ~Factories();
-
- // Caller owns returned pointer.
- virtual VideoDecodeAccelerator* CreateVideoDecodeAccelerator(
- VideoDecodeAccelerator::Profile, VideoDecodeAccelerator::Client*) = 0;
-
- // Allocate & delete native textures.
- virtual bool CreateTextures(int32 count, const gfx::Size& size,
- std::vector<uint32>* texture_ids) = 0;
- virtual bool DeleteTexture(uint32 texture_id) = 0;
-
- // Allocate & return a shared memory segment. Caller is responsible for
- // Close()ing the returned pointer.
- virtual base::SharedMemory* CreateSharedMemory(size_t size) = 0;
- };
-
- // Takes ownership of |factories| but not |message_loop|.
- GpuVideoDecoder(MessageLoop* message_loop, Factories* factories);
- virtual ~GpuVideoDecoder();
-
- // Filter implementation.
- virtual void Stop(const base::Closure& callback) OVERRIDE;
- virtual void Seek(base::TimeDelta time, const FilterStatusCB& cb) OVERRIDE;
- virtual void Pause(const base::Closure& callback) OVERRIDE;
- virtual void Flush(const base::Closure& callback) OVERRIDE;
-
- // VideoDecoder implementation.
- virtual void Initialize(DemuxerStream* demuxer_stream,
- const PipelineStatusCB& callback,
- const StatisticsCallback& stats_callback) OVERRIDE;
- virtual void Read(const ReadCB& callback) OVERRIDE;
- virtual const gfx::Size& natural_size() OVERRIDE;
-
- // VideoDecodeAccelerator::Client implementation.
- virtual void NotifyInitializeDone() OVERRIDE;
- virtual void ProvidePictureBuffers(uint32 count,
- const gfx::Size& size) OVERRIDE;
- virtual void DismissPictureBuffer(int32 id) OVERRIDE;
- virtual void PictureReady(const media::Picture& picture) OVERRIDE;
- virtual void NotifyEndOfStream() OVERRIDE;
- virtual void NotifyEndOfBitstreamBuffer(int32 id) OVERRIDE;
- virtual void NotifyFlushDone() OVERRIDE;
- virtual void NotifyResetDone() OVERRIDE;
- virtual void NotifyError(media::VideoDecodeAccelerator::Error error) OVERRIDE;
-
- private:
- // If no demuxer read is in flight and no bitstream buffers are in the
- // decoder, kick some off demuxing/decoding.
- void EnsureDemuxOrDecode();
-
- // Callback to pass to demuxer_stream_->Read() for receiving encoded bits.
- void RequestBufferDecode(const scoped_refptr<Buffer>& buffer);
-
- // Deliver a frame to the client. Because VideoDecoder::Read() promises not
- // to run its callback before returning, we need an out-of-line helper here.
- void DeliverFrame(const scoped_refptr<VideoFrame>& frame);
- void DeliverFrameOutOfLine(const scoped_refptr<VideoFrame>& frame);
-
- // Indicate the picturebuffer can be reused by the decoder.
- void ReusePictureBuffer(int64 picture_buffer_id);
-
- // A shared memory segment and its allocated size.
- struct SHMBuffer {
- SHMBuffer(base::SharedMemory* m, size_t s);
- ~SHMBuffer();
- base::SharedMemory* shm;
- size_t size;
- };
-
- // Request a shared-memory segment of at least |min_size| bytes. Will
- // allocate as necessary. Caller does not own returned pointer.
- SHMBuffer* GetSHM(size_t min_size);
-
- // Return a shared-memory segment to the available pool.
- void PutSHM(SHMBuffer* shm_buffer);
-
- PtsStream pts_stream_;
- StatisticsCallback statistics_callback_;
-
- // TODO(scherkus): I think this should be calculated by VideoRenderers based
- // on information provided by VideoDecoders (i.e., aspect ratio).
- gfx::Size natural_size_;
-
- // Pointer to the demuxer stream that will feed us compressed buffers.
- scoped_refptr<DemuxerStream> demuxer_stream_;
-
- // MessageLoop on which to do fire callbacks and to which trampoline calls to
- // this class if they arrive on other loops.
- MessageLoop* message_loop_;
-
- scoped_ptr<Factories> factories_;
-
- // Populated during Initialize() (on success) and unchanged thereafter.
- scoped_refptr<VideoDecodeAccelerator> vda_;
-
- // Callbacks that are !is_null() only during their respective operation being
- // asynchronously executed.
- ReadCB pending_read_cb_;
- base::Closure pending_flush_cb_;
-
- // Status of the decoder.
- bool flush_in_progress_;
-
- // Is a demuxer read in flight?
- bool demuxer_read_in_progress_;
-
- // Shared-memory buffer pool. Since allocating SHM segments requires a
- // round-trip to the browser process, we keep allocation out of the
- // steady-state of the decoder.
- std::vector<SHMBuffer*> available_shm_segments_;
-
- // Book-keeping variables.
- struct BufferPair {
- BufferPair(SHMBuffer* s, const scoped_refptr<Buffer>& b);
- ~BufferPair();
- SHMBuffer* shm_buffer;
- scoped_refptr<Buffer> buffer;
- };
- std::map<int32, BufferPair> bitstream_buffers_in_decoder_;
- std::map<int32, PictureBuffer> picture_buffers_in_decoder_;
-
- // picture_buffer_id and the frame wrapping the corresponding Picture, for
- // frames that have been decoded but haven't been requested by a Read() yet.
- std::list<scoped_refptr<VideoFrame> > ready_video_frames_;
- int64 next_picture_buffer_id_;
- int64 next_bitstream_buffer_id_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuVideoDecoder);
-};
-
-} // namespace media
-
-#endif // MEDIA_FILTERS_GPU_VIDEO_DECODER_H_
diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc
index 7b40fbc..4cd7775 100644
--- a/media/filters/video_renderer_base.cc
+++ b/media/filters/video_renderer_base.cc
@@ -97,15 +97,17 @@ void VideoRendererBase::SetPlaybackRate(float playback_rate) {
}
void VideoRendererBase::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
- base::AutoLock auto_lock(lock_);
- DCHECK_EQ(state_, kFlushed) << "Must flush prior to seeking.";
- DCHECK(!cb.is_null());
- DCHECK(seek_cb_.is_null());
-
- state_ = kSeeking;
- seek_cb_ = cb;
- seek_timestamp_ = time;
- AttemptRead_Locked();
+ {
+ base::AutoLock auto_lock(lock_);
+ DCHECK_EQ(state_, kFlushed) << "Must flush prior to seeking.";
+ DCHECK(!cb.is_null());
+ DCHECK(seek_cb_.is_null());
+
+ state_ = kSeeking;
+ seek_cb_ = cb;
+ seek_timestamp_ = time;
+ AttemptRead_Locked();
+ }
}
void VideoRendererBase::Initialize(VideoDecoder* decoder,
@@ -274,6 +276,7 @@ void VideoRendererBase::ThreadMain() {
frames_queue_ready_.pop_front();
AttemptRead_Locked();
}
+
// Continue waiting for the current paint to finish.
continue;
}
@@ -476,6 +479,7 @@ void VideoRendererBase::DoStopOrError_Locked() {
lock_.AssertAcquired();
current_frame_ = NULL;
last_available_frame_ = NULL;
+ DCHECK(!pending_read_);
}
} // namespace media
diff --git a/media/media.gyp b/media/media.gyp
index fa6e870..a52d4a5 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -205,8 +205,6 @@
'filters/file_data_source.h',
'filters/file_data_source_factory.cc',
'filters/file_data_source_factory.h',
- 'filters/gpu_video_decoder.cc',
- 'filters/gpu_video_decoder.h',
'filters/in_memory_url_protocol.cc',
'filters/in_memory_url_protocol.h',
'filters/null_audio_renderer.cc',
diff --git a/media/video/video_decode_accelerator.h b/media/video/video_decode_accelerator.h
index d260a7c..9a31bfd 100644
--- a/media/video/video_decode_accelerator.h
+++ b/media/video/video_decode_accelerator.h
@@ -10,7 +10,6 @@
#include "base/basictypes.h"
#include "base/callback_old.h"
#include "media/base/bitstream_buffer.h"
-#include "media/base/video_decoder_config.h"
#include "media/video/picture.h"
#include "ui/gfx/size.h"
@@ -25,8 +24,25 @@ namespace media {
class MEDIA_EXPORT VideoDecodeAccelerator
: public base::RefCountedThreadSafe<VideoDecodeAccelerator> {
public:
- // TODO(fischman): fix foreign references to this and get rid of this typedef.
- typedef VideoCodecProfile Profile;
+ // Video stream profile. This *must* match PP_VideoDecoder_Profile.
+ enum Profile {
+ // Keep the values in this enum unique, as they imply format (h.264 vs. VP8,
+ // for example), and keep the values for a particular format grouped
+ // together for clarity.
+ H264PROFILE_MIN = 0,
+ H264PROFILE_BASELINE = H264PROFILE_MIN,
+ H264PROFILE_MAIN,
+ H264PROFILE_EXTENDED,
+ H264PROFILE_HIGH,
+ H264PROFILE_HIGH10PROFILE,
+ H264PROFILE_HIGH422PROFILE,
+ H264PROFILE_HIGH444PREDICTIVEPROFILE,
+ H264PROFILE_SCALABLEBASELINE,
+ H264PROFILE_SCALABLEHIGH,
+ H264PROFILE_STEREOHIGH,
+ H264PROFILE_MULTIVIEWHIGH,
+ H264PROFILE_MAX = H264PROFILE_MULTIVIEWHIGH,
+ };
// Enumeration of potential errors generated by the API.
// Note: Keep these in sync with PP_VideoDecodeError_Dev.