diff options
author | suderman@chromium.org <suderman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-10 03:24:16 +0000 |
---|---|---|
committer | suderman@chromium.org <suderman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-10 03:24:16 +0000 |
commit | d4f898847f005ef900304856a4f6209adf23f322 (patch) | |
tree | bb74bd0bbfb7173438a775cbfd895396ab35c013 | |
parent | 5b8cfced8fe1f455dbe3933862e45683348c1c53 (diff) | |
download | chromium_src-d4f898847f005ef900304856a4f6209adf23f322.zip chromium_src-d4f898847f005ef900304856a4f6209adf23f322.tar.gz chromium_src-d4f898847f005ef900304856a4f6209adf23f322.tar.bz2 |
Update to Pipeline Metadata and Decoder stream
to track the set of video rotation metadata. This
will later be used to correctly orient rotated videos.
BUG=47554
Review URL: https://codereview.chromium.org/363813002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282236 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | media/base/demuxer_stream.h | 3 | ||||
-rw-r--r-- | media/base/fake_text_track_stream.cc | 4 | ||||
-rw-r--r-- | media/base/fake_text_track_stream.h | 1 | ||||
-rw-r--r-- | media/base/mock_filters.cc | 4 | ||||
-rw-r--r-- | media/base/mock_filters.h | 2 | ||||
-rw-r--r-- | media/base/pipeline.cc | 1 | ||||
-rw-r--r-- | media/base/pipeline.h | 5 | ||||
-rw-r--r-- | media/base/video_rotation.h | 21 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.cc | 4 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.h | 1 | ||||
-rw-r--r-- | media/filters/decrypting_demuxer_stream.cc | 4 | ||||
-rw-r--r-- | media/filters/decrypting_demuxer_stream.h | 1 | ||||
-rw-r--r-- | media/filters/fake_demuxer_stream.cc | 4 | ||||
-rw-r--r-- | media/filters/fake_demuxer_stream.h | 1 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer.cc | 30 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer.h | 4 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer_unittest.cc | 36 | ||||
-rw-r--r-- | media/filters/pipeline_integration_test.cc | 22 | ||||
-rw-r--r-- | media/media.gyp | 1 |
19 files changed, 148 insertions, 1 deletions
diff --git a/media/base/demuxer_stream.h b/media/base/demuxer_stream.h index 87f53e7..1207e18 100644 --- a/media/base/demuxer_stream.h +++ b/media/base/demuxer_stream.h @@ -8,6 +8,7 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "media/base/media_export.h" +#include "media/base/video_rotation.h" namespace media { @@ -80,6 +81,8 @@ class MEDIA_EXPORT DemuxerStream { // on this. virtual bool SupportsConfigChanges() = 0; + virtual VideoRotation video_rotation() = 0; + protected: // Only allow concrete implementations to get deleted. virtual ~DemuxerStream(); diff --git a/media/base/fake_text_track_stream.cc b/media/base/fake_text_track_stream.cc index 2e9a1e1..f18e540 100644 --- a/media/base/fake_text_track_stream.cc +++ b/media/base/fake_text_track_stream.cc @@ -38,6 +38,10 @@ DemuxerStream::Type FakeTextTrackStream::type() { bool FakeTextTrackStream::SupportsConfigChanges() { return false; } +VideoRotation FakeTextTrackStream::video_rotation() { + return VIDEO_ROTATION_0; +} + void FakeTextTrackStream::SatisfyPendingRead( const base::TimeDelta& start, const base::TimeDelta& duration, diff --git a/media/base/fake_text_track_stream.h b/media/base/fake_text_track_stream.h index db7a3e1..27baeec 100644 --- a/media/base/fake_text_track_stream.h +++ b/media/base/fake_text_track_stream.h @@ -24,6 +24,7 @@ class FakeTextTrackStream : public DemuxerStream { virtual Type type() OVERRIDE; MOCK_METHOD0(EnableBitstreamConverter, void()); virtual bool SupportsConfigChanges(); + virtual VideoRotation video_rotation() OVERRIDE; void SatisfyPendingRead(const base::TimeDelta& start, const base::TimeDelta& duration, diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc index e4faf70..42ec9bb 100644 --- a/media/base/mock_filters.cc +++ b/media/base/mock_filters.cc @@ -48,6 +48,10 @@ void MockDemuxerStream::set_video_decoder_config( video_decoder_config_ = config; } +VideoRotation MockDemuxerStream::video_rotation() { + return VIDEO_ROTATION_0; +} + MockVideoDecoder::MockVideoDecoder() { EXPECT_CALL(*this, HasAlpha()).WillRepeatedly(Return(false)); } diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index be5062b..c74190e 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h @@ -61,6 +61,8 @@ class MockDemuxerStream : public DemuxerStream { void set_audio_decoder_config(const AudioDecoderConfig& config); void set_video_decoder_config(const VideoDecoderConfig& config); + virtual VideoRotation video_rotation() OVERRIDE; + private: DemuxerStream::Type type_; AudioDecoderConfig audio_decoder_config_; diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc index 08543ec..71c7248 100644 --- a/media/base/pipeline.cc +++ b/media/base/pipeline.cc @@ -389,6 +389,7 @@ void Pipeline::StateTransitionTask(PipelineStatus status) { if (stream) { metadata.natural_size = stream->video_decoder_config().natural_size(); + metadata.video_rotation = stream->video_rotation(); } metadata_cb_.Run(metadata); } diff --git a/media/base/pipeline.h b/media/base/pipeline.h index 4c28672..6a408da 100644 --- a/media/base/pipeline.h +++ b/media/base/pipeline.h @@ -19,6 +19,7 @@ #include "media/base/pipeline_status.h" #include "media/base/ranges.h" #include "media/base/serial_runner.h" +#include "media/base/video_rotation.h" #include "ui/gfx/size.h" namespace base { @@ -37,11 +38,13 @@ class VideoRenderer; // Metadata describing a pipeline once it has been initialized. struct PipelineMetadata { - PipelineMetadata() : has_audio(false), has_video(false) {} + PipelineMetadata() + : has_audio(false), has_video(false), video_rotation(VIDEO_ROTATION_0) {} bool has_audio; bool has_video; gfx::Size natural_size; + VideoRotation video_rotation; base::Time timeline_offset; }; diff --git a/media/base/video_rotation.h b/media/base/video_rotation.h new file mode 100644 index 0000000..be28f54 --- /dev/null +++ b/media/base/video_rotation.h @@ -0,0 +1,21 @@ +// Copyright 2014 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_BASE_VIDEO_ROTATION_H_ +#define MEDIA_BASE_VIDEO_ROTATION_H_ + +namespace media { + +// Enumeration to represent 90 degree video rotation for MP4 videos +// where it can be rotated by 90 degree intervals. +enum VideoRotation { + VIDEO_ROTATION_0 = 0, + VIDEO_ROTATION_90, + VIDEO_ROTATION_180, + VIDEO_ROTATION_270 +}; + +} // namespace media + +#endif // MEDIA_BASE_VIDEO_ROTATION_H_ diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index 657859a..441d796 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc @@ -952,6 +952,10 @@ TextTrackConfig ChunkDemuxerStream::text_track_config() { return stream_->GetCurrentTextTrackConfig(); } +VideoRotation ChunkDemuxerStream::video_rotation() { + return VIDEO_ROTATION_0; +} + void ChunkDemuxerStream::ChangeState_Locked(State state) { lock_.AssertAcquired(); DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h index cd01b1e..2abeeea 100644 --- a/media/filters/chunk_demuxer.h +++ b/media/filters/chunk_demuxer.h @@ -86,6 +86,7 @@ class MEDIA_EXPORT ChunkDemuxerStream : public DemuxerStream { virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; virtual VideoDecoderConfig video_decoder_config() OVERRIDE; virtual bool SupportsConfigChanges() OVERRIDE; + virtual VideoRotation video_rotation() OVERRIDE; // Returns the text track configuration. It is an error to call this method // if type() != TEXT. diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc index 6a1de5f..8493de6 100644 --- a/media/filters/decrypting_demuxer_stream.cc +++ b/media/filters/decrypting_demuxer_stream.cc @@ -165,6 +165,10 @@ bool DecryptingDemuxerStream::SupportsConfigChanges() { return demuxer_stream_->SupportsConfigChanges(); } +VideoRotation DecryptingDemuxerStream::video_rotation() { + return VIDEO_ROTATION_0; +} + DecryptingDemuxerStream::~DecryptingDemuxerStream() { DVLOG(2) << __FUNCTION__ << " : state_ = " << state_; } diff --git a/media/filters/decrypting_demuxer_stream.h b/media/filters/decrypting_demuxer_stream.h index ec9f4b4..6d308e5 100644 --- a/media/filters/decrypting_demuxer_stream.h +++ b/media/filters/decrypting_demuxer_stream.h @@ -56,6 +56,7 @@ class MEDIA_EXPORT DecryptingDemuxerStream : public DemuxerStream { virtual Type type() OVERRIDE; virtual void EnableBitstreamConverter() OVERRIDE; virtual bool SupportsConfigChanges() OVERRIDE; + virtual VideoRotation video_rotation() OVERRIDE; private: // For a detailed state diagram please see this link: http://goo.gl/8jAok diff --git a/media/filters/fake_demuxer_stream.cc b/media/filters/fake_demuxer_stream.cc index 78386e3..941778c 100644 --- a/media/filters/fake_demuxer_stream.cc +++ b/media/filters/fake_demuxer_stream.cc @@ -97,6 +97,10 @@ bool FakeDemuxerStream::SupportsConfigChanges() { return config_changes_; } +VideoRotation FakeDemuxerStream::video_rotation() { + return VIDEO_ROTATION_0; +} + void FakeDemuxerStream::HoldNextRead() { DCHECK(task_runner_->BelongsToCurrentThread()); read_to_hold_ = next_read_num_; diff --git a/media/filters/fake_demuxer_stream.h b/media/filters/fake_demuxer_stream.h index bacf0bd..90efe6e 100644 --- a/media/filters/fake_demuxer_stream.h +++ b/media/filters/fake_demuxer_stream.h @@ -34,6 +34,7 @@ class FakeDemuxerStream : public DemuxerStream { virtual Type type() OVERRIDE; virtual void EnableBitstreamConverter() OVERRIDE; virtual bool SupportsConfigChanges() OVERRIDE; + virtual VideoRotation video_rotation() OVERRIDE; void Initialize(); diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 05fa340..e23116f 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc @@ -14,6 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop_proxy.h" #include "base/metrics/sparse_histogram.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/sys_byteorder.h" @@ -92,11 +93,14 @@ FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer, type_(UNKNOWN), end_of_stream_(false), last_packet_timestamp_(kNoTimestamp()), + video_rotation_(VIDEO_ROTATION_0), bitstream_converter_enabled_(false), fixup_negative_ogg_timestamps_(false) { DCHECK(demuxer_); bool is_encrypted = false; + int rotation = 0; + AVDictionaryEntry* rotation_entry = NULL; // Determine our media format. switch (stream->codec->codec_type) { @@ -109,6 +113,28 @@ FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer, type_ = VIDEO; AVStreamToVideoDecoderConfig(stream, &video_config_, true); is_encrypted = video_config_.is_encrypted(); + + rotation_entry = av_dict_get(stream->metadata, "rotate", NULL, 0); + if (rotation_entry && rotation_entry->value && rotation_entry->value[0]) + base::StringToInt(rotation_entry->value, &rotation); + + switch (rotation) { + case 0: + break; + case 90: + video_rotation_ = VIDEO_ROTATION_90; + break; + case 180: + video_rotation_ = VIDEO_ROTATION_180; + break; + case 270: + video_rotation_ = VIDEO_ROTATION_270; + break; + default: + LOG(ERROR) << "Unsupported video rotation metadata: " << rotation; + break; + } + break; case AVMEDIA_TYPE_SUBTITLE: type_ = TEXT; @@ -380,6 +406,10 @@ VideoDecoderConfig FFmpegDemuxerStream::video_decoder_config() { return video_config_; } +VideoRotation FFmpegDemuxerStream::video_rotation() { + return video_rotation_; +} + FFmpegDemuxerStream::~FFmpegDemuxerStream() { DCHECK(!demuxer_); DCHECK(read_cb_.is_null()); diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h index efe4032..40cddda 100644 --- a/media/filters/ffmpeg_demuxer.h +++ b/media/filters/ffmpeg_demuxer.h @@ -92,6 +92,7 @@ class FFmpegDemuxerStream : public DemuxerStream { virtual bool SupportsConfigChanges() OVERRIDE; virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; virtual VideoDecoderConfig video_decoder_config() OVERRIDE; + virtual VideoRotation video_rotation() OVERRIDE; // Returns the range of buffered data in this stream. Ranges<base::TimeDelta> GetBufferedRanges() const; @@ -133,6 +134,7 @@ class FFmpegDemuxerStream : public DemuxerStream { bool end_of_stream_; base::TimeDelta last_packet_timestamp_; Ranges<base::TimeDelta> buffered_ranges_; + VideoRotation video_rotation_; DecoderBufferQueue buffer_queue_; ReadCB read_cb_; @@ -277,6 +279,8 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer { // time if the file doesn't have an association to Time. base::Time timeline_offset_; + VideoRotation video_rotation_; + // Liveness of the stream. Liveness liveness_; diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc index 638aa0c..bf72e29 100644 --- a/media/filters/ffmpeg_demuxer_unittest.cc +++ b/media/filters/ffmpeg_demuxer_unittest.cc @@ -916,6 +916,42 @@ TEST_F(FFmpegDemuxerTest, IsValidAnnexB) { } } +TEST_F(FFmpegDemuxerTest, Rotate_Metadata_0) { + CreateDemuxer("bear_rotate_0.mp4"); + InitializeDemuxer(); + + DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); + ASSERT_TRUE(stream); + ASSERT_EQ(VIDEO_ROTATION_0, stream->video_rotation()); +} + +TEST_F(FFmpegDemuxerTest, Rotate_Metadata_90) { + CreateDemuxer("bear_rotate_90.mp4"); + InitializeDemuxer(); + + DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); + ASSERT_TRUE(stream); + ASSERT_EQ(VIDEO_ROTATION_90, stream->video_rotation()); +} + +TEST_F(FFmpegDemuxerTest, Rotate_Metadata_180) { + CreateDemuxer("bear_rotate_180.mp4"); + InitializeDemuxer(); + + DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); + ASSERT_TRUE(stream); + ASSERT_EQ(VIDEO_ROTATION_180, stream->video_rotation()); +} + +TEST_F(FFmpegDemuxerTest, Rotate_Metadata_270) { + CreateDemuxer("bear_rotate_270.mp4"); + InitializeDemuxer(); + + DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); + ASSERT_TRUE(stream); + ASSERT_EQ(VIDEO_ROTATION_270, stream->video_rotation()); +} + #endif } // namespace media diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc index a4b1e6b..5c5433d 100644 --- a/media/filters/pipeline_integration_test.cc +++ b/media/filters/pipeline_integration_test.cc @@ -1394,6 +1394,28 @@ TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) { ASSERT_TRUE(WaitUntilOnEnded()); } +#if defined(USE_PROPRIETARY_CODECS) +TEST_F(PipelineIntegrationTest, Rotated_Metadata_0) { + ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_0.mp4"), PIPELINE_OK)); + ASSERT_EQ(VIDEO_ROTATION_0, metadata_.video_rotation); +} + +TEST_F(PipelineIntegrationTest, Rotated_Metadata_90) { + ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_90.mp4"), PIPELINE_OK)); + ASSERT_EQ(VIDEO_ROTATION_90, metadata_.video_rotation); +} + +TEST_F(PipelineIntegrationTest, Rotated_Metadata_180) { + ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_180.mp4"), PIPELINE_OK)); + ASSERT_EQ(VIDEO_ROTATION_180, metadata_.video_rotation); +} + +TEST_F(PipelineIntegrationTest, Rotated_Metadata_270) { + ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_270.mp4"), PIPELINE_OK)); + ASSERT_EQ(VIDEO_ROTATION_270, metadata_.video_rotation); +} +#endif + // Verify audio decoder & renderer can handle aborted demuxer reads. TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) { ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM, diff --git a/media/media.gyp b/media/media.gyp index 58adf56..fc9ba7c 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -349,6 +349,7 @@ 'base/video_frame_pool.h', 'base/video_renderer.cc', 'base/video_renderer.h', + 'base/video_rotation.h', 'base/video_util.cc', 'base/video_util.h', 'base/yuv_convert.cc', |