diff options
author | ralphl@chromium.org <ralphl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-25 23:53:16 +0000 |
---|---|---|
committer | ralphl@chromium.org <ralphl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-25 23:53:16 +0000 |
commit | a28e0e48a6d0f1e8b25a45a8e6d7089c276f3c44 (patch) | |
tree | 17f9ade0447bf18ec387c7f5489d883c959bf656 /media | |
parent | 24062acc468ac7c21b0dde801c02d6b72a2330e1 (diff) | |
download | chromium_src-a28e0e48a6d0f1e8b25a45a8e6d7089c276f3c44.zip chromium_src-a28e0e48a6d0f1e8b25a45a8e6d7089c276f3c44.tar.gz chromium_src-a28e0e48a6d0f1e8b25a45a8e6d7089c276f3c44.tar.bz2 |
Added IsEndOfStream and IsDiscontiguous flags to buffers.
Review URL: http://codereview.chromium.org/27120
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10406 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/base/buffers.h | 57 | ||||
-rwxr-xr-x | media/base/data_buffer.cc | 24 | ||||
-rwxr-xr-x | media/base/data_buffer.h | 10 | ||||
-rw-r--r-- | media/base/data_buffer_unittest.cc | 13 | ||||
-rw-r--r-- | media/base/mock_media_filters.h | 119 | ||||
-rw-r--r-- | media/filters/test_video_renderer.h | 3 | ||||
-rw-r--r-- | media/filters/video_renderer_base.cc | 28 | ||||
-rw-r--r-- | media/filters/video_renderer_unittest.cc | 24 |
8 files changed, 169 insertions, 109 deletions
diff --git a/media/base/buffers.h b/media/base/buffers.h index b6c3935..9cd8c96 100644 --- a/media/base/buffers.h +++ b/media/base/buffers.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2008-2009 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. @@ -36,20 +36,61 @@ namespace media { class StreamSample : public base::RefCountedThreadSafe<StreamSample> { public: // Returns the timestamp of this buffer in microseconds. - virtual base::TimeDelta GetTimestamp() const = 0; + base::TimeDelta GetTimestamp() const { + return timestamp_; + } // Returns the duration of this buffer in microseconds. - virtual base::TimeDelta GetDuration() const = 0; + base::TimeDelta GetDuration() const { + return duration_; + } + + // Indicates that the sample is the last one in the stream. + bool IsEndOfStream() const { + return end_of_stream_; + } + + // Indicates that this sample is discontinuous from the previous one, for + // example, following a seek. + bool IsDiscontinuous() const { + return discontinuous_; + } // Sets the timestamp of this buffer in microseconds. - virtual void SetTimestamp(const base::TimeDelta& timestamp) = 0; + void SetTimestamp(const base::TimeDelta& timestamp) { + timestamp_ = timestamp; + } // Sets the duration of this buffer in microseconds. - virtual void SetDuration(const base::TimeDelta& duration) = 0; + void SetDuration(const base::TimeDelta& duration) { + duration_ = duration; + } + + // Sets the value returned by IsEndOfStream(). + void SetEndOfStream(bool end_of_stream) { + end_of_stream_ = end_of_stream; + } + + // Sets the value returned by IsDiscontinuous(). + void SetDiscontinuous(bool discontinuous) { + discontinuous_ = discontinuous; + } protected: friend class base::RefCountedThreadSafe<StreamSample>; + StreamSample() + : end_of_stream_(false), + discontinuous_(false) { + } virtual ~StreamSample() {} + + base::TimeDelta timestamp_; + base::TimeDelta duration_; + bool end_of_stream_; + bool discontinuous_; + + private: + DISALLOW_COPY_AND_ASSIGN(StreamSample); }; @@ -134,8 +175,8 @@ class VideoFrame : public StreamSample { // // TODO(scherkus): rethink the Assignable interface -- it's a bit kludgy. template <class BufferType> -class Assignable : - public base::RefCountedThreadSafe< Assignable<BufferType> > { +class Assignable + : public base::RefCountedThreadSafe< Assignable<BufferType> > { public: // Assigns a buffer to the owner. virtual void SetBuffer(BufferType* buffer) = 0; @@ -146,7 +187,7 @@ class Assignable : // TODO(scherkus): figure out a solution to friending a template. // See http://www.comeaucomputing.com/techtalk/templates/#friendclassT for // an explanation. - //protected: + // protected: // friend class base::RefCountedThreadSafe< Assignable<class T> >; virtual ~Assignable() {} }; diff --git a/media/base/data_buffer.cc b/media/base/data_buffer.cc index ae5314a..cdad4d7 100755 --- a/media/base/data_buffer.cc +++ b/media/base/data_buffer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2008-2009 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. @@ -12,34 +12,18 @@ DataBuffer::DataBuffer(char* data, size_t buffer_size, size_t data_size, const base::TimeDelta& duration) : data_(data), buffer_size_(buffer_size), - data_size_(data_size), - timestamp_(timestamp), - duration_(duration) { + data_size_(data_size) { DCHECK(data); DCHECK(buffer_size >= 0); DCHECK(data_size <= buffer_size); + SetTimestamp(timestamp); + SetDuration(duration); } DataBuffer::~DataBuffer() { delete [] data_; } -base::TimeDelta DataBuffer::GetTimestamp() const { - return timestamp_; -} - -void DataBuffer::SetTimestamp(const base::TimeDelta& timestamp) { - timestamp_ = timestamp; -} - -base::TimeDelta DataBuffer::GetDuration() const { - return duration_; -} - -void DataBuffer::SetDuration(const base::TimeDelta& duration) { - duration_ = duration; -} - const char* DataBuffer::GetData() const { return data_; } diff --git a/media/base/data_buffer.h b/media/base/data_buffer.h index 7aa5df8..9ee72e9 100755 --- a/media/base/data_buffer.h +++ b/media/base/data_buffer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2008-2009 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. @@ -19,12 +19,6 @@ class DataBuffer : public WritableBuffer { DataBuffer(char* data, size_t buffer_size, size_t data_size, const base::TimeDelta& timestamp, const base::TimeDelta& duration); - // StreamSample implementation. - virtual base::TimeDelta GetTimestamp() const; - virtual void SetTimestamp(const base::TimeDelta& timestamp); - virtual base::TimeDelta GetDuration() const; - virtual void SetDuration(const base::TimeDelta& duration); - // Buffer implementation. virtual const char* GetData() const; virtual size_t GetDataSize() const; @@ -41,8 +35,6 @@ class DataBuffer : public WritableBuffer { char* data_; size_t buffer_size_; size_t data_size_; - base::TimeDelta timestamp_; - base::TimeDelta duration_; }; } // namespace media diff --git a/media/base/data_buffer_unittest.cc b/media/base/data_buffer_unittest.cc index 9836ced..b0a45a1 100644 --- a/media/base/data_buffer_unittest.cc +++ b/media/base/data_buffer_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2008-2009 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. @@ -34,6 +34,8 @@ TEST(DataBufferTest, Basic) { // Test StreamSample implementation. EXPECT_TRUE(kTimestampA == buffer->GetTimestamp()); EXPECT_TRUE(kDurationA == buffer->GetDuration()); + EXPECT_FALSE(buffer->IsEndOfStream()); + EXPECT_FALSE(buffer->IsDiscontinuous()); buffer->SetTimestamp(kTimestampB); buffer->SetDuration(kDurationB); EXPECT_TRUE(kTimestampB == buffer->GetTimestamp()); @@ -51,4 +53,13 @@ TEST(DataBufferTest, Basic) { EXPECT_EQ(kNewDataSize, copied + 1); buffer->SetDataSize(kNewDataSize); EXPECT_EQ(kNewDataSize, buffer->GetDataSize()); + + buffer->SetEndOfStream(true); + EXPECT_TRUE(buffer->IsEndOfStream()); + buffer->SetEndOfStream(false); + EXPECT_FALSE(buffer->IsEndOfStream()); + buffer->SetDiscontinuous(true); + EXPECT_TRUE(buffer->IsDiscontinuous()); + buffer->SetDiscontinuous(false); + EXPECT_FALSE(buffer->IsDiscontinuous()); } diff --git a/media/base/mock_media_filters.h b/media/base/mock_media_filters.h index 386d685..ef89021 100644 --- a/media/base/mock_media_filters.h +++ b/media/base/mock_media_filters.h @@ -45,7 +45,8 @@ struct MockFilterConfig { uncompressed_audio_mime_type(mime_type::kUncompressedAudio), compressed_video_mime_type(mime_type::kH264AnnexB), uncompressed_video_mime_type(mime_type::kUncompressedVideo), - frame_duration(base::TimeDelta::FromMicroseconds(33333)) { + frame_duration(base::TimeDelta::FromMicroseconds(33333)), + media_duration(base::TimeDelta::FromSeconds(5)) { } MockDataSourceBehavior data_source_behavior; @@ -58,10 +59,11 @@ struct MockFilterConfig { std::string compressed_video_mime_type; std::string uncompressed_video_mime_type; base::TimeDelta frame_duration; + base::TimeDelta media_duration; }; -class MockDataSource : public media::DataSource { +class MockDataSource : public DataSource { public: static FilterFactory* CreateFactory(const MockFilterConfig* config) { return new FilterFactoryImpl1<MockDataSource, @@ -123,8 +125,8 @@ class MockDataSource : public media::DataSource { } private: - friend class media::FilterFactoryImpl1<MockDataSource, - const MockFilterConfig*>; + friend class FilterFactoryImpl1<MockDataSource, + const MockFilterConfig*>; explicit MockDataSource(const MockFilterConfig* config) : behavior_(config->data_source_behavior) { @@ -165,7 +167,7 @@ class MockDemuxer : public Demuxer { virtual void Stop() {} // Implementation of Demuxer. - virtual bool Initialize(media::DataSource* data_source) { + virtual bool Initialize(DataSource* data_source) { host_->InitializationComplete(); return true; } @@ -177,7 +179,7 @@ class MockDemuxer : public Demuxer { return 1; } - virtual media::DemuxerStream* GetStream(int stream_id) { + virtual DemuxerStream* GetStream(int stream_id) { switch (stream_id) { case 0: return &mock_audio_stream_; @@ -193,7 +195,7 @@ class MockDemuxer : public Demuxer { } private: - friend class media::FilterFactoryImpl1<MockDemuxer, const MockFilterConfig*>; + friend class FilterFactoryImpl1<MockDemuxer, const MockFilterConfig*>; explicit MockDemuxer(const MockFilterConfig* config) : config_(config), @@ -214,7 +216,7 @@ class MockDemuxer : public Demuxer { // Implementation of DemuxerStream. virtual const MediaFormat* GetMediaFormat() { - return &media_format_; // TODO(ralphl): implement + return &media_format_; } virtual void Read(Assignable<Buffer>* buffer) { @@ -266,8 +268,7 @@ class MockAudioDecoder : public AudioDecoder { } private: - friend class media::FilterFactoryImpl1<MockAudioDecoder, - const MockFilterConfig*>; + friend class FilterFactoryImpl1<MockAudioDecoder, const MockFilterConfig*>; explicit MockAudioDecoder(const MockFilterConfig* config) { media_format_.SetAsString(MediaFormat::kMimeType, @@ -306,8 +307,7 @@ class MockAudioRenderer : public AudioRenderer { virtual void SetVolume(float volume) {} private: - friend class media::FilterFactoryImpl1<MockAudioRenderer, - const MockFilterConfig*>; + friend class FilterFactoryImpl1<MockAudioRenderer, const MockFilterConfig*>; explicit MockAudioRenderer(const MockFilterConfig* config) {} @@ -323,44 +323,54 @@ class MockVideoFrame : public VideoFrame { explicit MockVideoFrame(const MockFilterConfig* config, base::TimeDelta timestamp) : config_(config), - surface_locked_(false), - timestamp_(timestamp), - duration_(config->frame_duration) { - } - - virtual ~MockVideoFrame() {} - - virtual base::TimeDelta GetTimestamp() const { - return timestamp_; - } - - virtual base::TimeDelta GetDuration() const { - return duration_; - } - - virtual void SetTimestamp(const base::TimeDelta& timestamp) { - timestamp_ = timestamp; + surface_locked_(false) { + SetTimestamp(timestamp); + SetDuration(config->frame_duration); + size_t y_byte_count = config_->video_width * config_->video_height; + size_t uv_byte_count = y_byte_count / 4; + surface_.format = config_->video_surface_format; + surface_.width = config_->video_width; + surface_.height = config_->video_height; + surface_.planes = 3; + surface_.data[0] = new char[y_byte_count]; + surface_.data[1] = new char[uv_byte_count]; + surface_.data[2] = new char[uv_byte_count]; + surface_.strides[0] = config_->video_width; + surface_.strides[1] = config_->video_width / 2; + surface_.strides[2] = config_->video_width / 2; + memset(surface_.data[0], 0, y_byte_count); + memset(surface_.data[1], 0x80, uv_byte_count); + memset(surface_.data[2], 0x80, uv_byte_count); + int64 num_white_pixels = y_byte_count * + timestamp.InMicroseconds() / + config_->media_duration.InMicroseconds(); + if (num_white_pixels > y_byte_count) { + ADD_FAILURE(); + num_white_pixels = y_byte_count; + } + if (num_white_pixels < 0) { + ADD_FAILURE(); + num_white_pixels = 0; + } + memset(surface_.data[0], 0xFF, static_cast<size_t>(num_white_pixels)); } - virtual void SetDuration(const base::TimeDelta& duration) { - duration_ = duration; + virtual ~MockVideoFrame() { + delete[] surface_.data[0]; + delete[] surface_.data[1]; + delete[] surface_.data[2]; } virtual bool Lock(VideoSurface* surface) { EXPECT_FALSE(surface_locked_); + if (surface_locked_) { + memset(surface, 0, sizeof(*surface)); + return false; + } surface_locked_ = true; - surface->format = config_->video_surface_format; - surface->width = config_->video_width; - surface->height = config_->video_height; - // TODO(ralphl): mock the data for video surfaces too. - surface->planes = 3; - surface->data[0] = NULL; - surface->data[1] = NULL; - surface->data[2] = NULL; - surface->strides[0] = 0; - surface->strides[1] = 0; - surface->strides[2] = 0; - return false; + DCHECK(sizeof(*surface) == sizeof(surface_)); + memcpy(surface, &surface_, sizeof(*surface)); + return true; } virtual void Unlock() { @@ -371,8 +381,7 @@ class MockVideoFrame : public VideoFrame { private: const MockFilterConfig* config_; bool surface_locked_; - base::TimeDelta timestamp_; - base::TimeDelta duration_; + VideoSurface surface_; DISALLOW_COPY_AND_ASSIGN(MockVideoFrame); }; @@ -407,8 +416,7 @@ class MockVideoDecoder : public VideoDecoder { } private: - friend class media::FilterFactoryImpl1<MockVideoDecoder, - const MockFilterConfig*>; + friend class FilterFactoryImpl1<MockVideoDecoder, const MockFilterConfig*>; explicit MockVideoDecoder(const MockFilterConfig* config) : config_(config) { @@ -419,10 +427,15 @@ class MockVideoDecoder : public VideoDecoder { } void DoRead(Assignable<VideoFrame>* buffer) { - VideoFrame* frame = new MockVideoFrame(config_, mock_frame_time_); - mock_frame_time_ += config_->frame_duration; - buffer->SetBuffer(frame); - buffer->OnAssignment(); + if (mock_frame_time_ < config_->media_duration) { + VideoFrame* frame = new MockVideoFrame(config_, mock_frame_time_); + mock_frame_time_ += config_->frame_duration; + if (mock_frame_time_ >= config_->media_duration) { + frame->SetEndOfStream(true); + } + buffer->SetBuffer(frame); + buffer->OnAssignment(); + } buffer->Release(); } @@ -459,8 +472,7 @@ class MockVideoRenderer : public VideoRenderer { } private: - friend class media::FilterFactoryImpl1<MockVideoRenderer, - const MockFilterConfig*>; + friend class FilterFactoryImpl1<MockVideoRenderer, const MockFilterConfig*>; explicit MockVideoRenderer(const MockFilterConfig* config) : config_(config) { @@ -474,7 +486,6 @@ class MockVideoRenderer : public VideoRenderer { }; - //------------------------------------------------------------------------------ // Simple class that derives from the WaitableEvent class. The event remains // in the reset state until the initialization complete callback is called from diff --git a/media/filters/test_video_renderer.h b/media/filters/test_video_renderer.h index 091acc9..f6c3c22 100644 --- a/media/filters/test_video_renderer.h +++ b/media/filters/test_video_renderer.h @@ -31,6 +31,9 @@ class TestVideoRenderer : public VideoRendererBase { scoped_refptr<VideoFrame> frame; GetCurrentFrame(&frame); if (frame.get()) { + VideoSurface video_surface; + EXPECT_TRUE(frame->Lock(&video_surface)); + frame->Unlock(); if (frame != last_frame_) { ++unique_frames_; last_frame_ = frame; diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc index fa715c1..9533bf3 100644 --- a/media/filters/video_renderer_base.cc +++ b/media/filters/video_renderer_base.cc @@ -178,24 +178,18 @@ void VideoRendererBase::OnAssignment(VideoFrame* video_frame) { { AutoLock auto_lock(lock_); if (IsRunning()) { - // TODO(ralphl): if (!preroll_complete_ && EndOfStream) call_init = true - // and preroll_complete_ = true. - // TODO(ralphl): If(Seek()) then discard but we don't have SeekFrame(). - if (false) { - // TODO(ralphl): this is the seek() logic. + if (video_frame->IsDiscontinuous()) { DiscardAllFrames(); - ++number_of_reads_needed_; - PostSubmitReadsTask(); - } else { - if (UpdateQueue(host_->GetPipelineStatus()->GetInterpolatedTime(), - video_frame)) { - request_repaint = preroll_complete_; - } - if (!preroll_complete_ && queue_.size() == number_of_frames_) { - preroll_complete_ = true; - call_initialized = true; - request_repaint = true; - } + } + if (UpdateQueue(host_->GetPipelineStatus()->GetInterpolatedTime(), + video_frame)) { + request_repaint = preroll_complete_; + } + if (!preroll_complete_ && (queue_.size() == number_of_frames_ || + video_frame->IsEndOfStream())) { + preroll_complete_ = true; + call_initialized = true; + request_repaint = true; } } } diff --git a/media/filters/video_renderer_unittest.cc b/media/filters/video_renderer_unittest.cc index c114984..a080adf 100644 --- a/media/filters/video_renderer_unittest.cc +++ b/media/filters/video_renderer_unittest.cc @@ -52,3 +52,27 @@ TEST(VideoRenderer, CreateTestRenderer) { EXPECT_LT(test_renderer->unique_frames(), num_expected_frames + 3); } +TEST(VideoRenderer, SingleVideoFrame) { + base::TimeDelta test_time = base::TimeDelta::FromMilliseconds(100); + std::string url(""); + PipelineImpl p; + scoped_refptr<TestVideoRenderer> test_renderer = new TestVideoRenderer(); + MockFilterConfig config; + config.media_duration = config.frame_duration; + scoped_refptr<FilterFactoryCollection> c = new FilterFactoryCollection(); + c->AddFactory(MockDataSource::CreateFactory(&config)); + c->AddFactory(MockDemuxer::CreateFactory(&config)); + c->AddFactory(MockAudioDecoder::CreateFactory(&config)); + c->AddFactory(MockAudioRenderer::CreateFactory(&config)); + c->AddFactory(MockVideoDecoder::CreateFactory(&config)); + c->AddFactory(new InstanceFilterFactory<TestVideoRenderer>(test_renderer)); + media::InitializationHelper h; + h.Start(&p, c, url); + h.TimedWait(base::TimeDelta::FromSeconds(1)); + EXPECT_TRUE(p.IsInitialized()); + p.SetPlaybackRate(1.0f); + PlatformThread::Sleep(static_cast<int>(test_time.InMilliseconds())); + p.Stop(); + EXPECT_EQ(test_renderer->unique_frames(), 1u); + EXPECT_EQ(test_renderer->paint_called(), 1u); +} |