summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorralphl@chromium.org <ralphl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-25 23:53:16 +0000
committerralphl@chromium.org <ralphl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-25 23:53:16 +0000
commita28e0e48a6d0f1e8b25a45a8e6d7089c276f3c44 (patch)
tree17f9ade0447bf18ec387c7f5489d883c959bf656 /media
parent24062acc468ac7c21b0dde801c02d6b72a2330e1 (diff)
downloadchromium_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.h57
-rwxr-xr-xmedia/base/data_buffer.cc24
-rwxr-xr-xmedia/base/data_buffer.h10
-rw-r--r--media/base/data_buffer_unittest.cc13
-rw-r--r--media/base/mock_media_filters.h119
-rw-r--r--media/filters/test_video_renderer.h3
-rw-r--r--media/filters/video_renderer_base.cc28
-rw-r--r--media/filters/video_renderer_unittest.cc24
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);
+}