summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsuderman@chromium.org <suderman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-10 03:24:16 +0000
committersuderman@chromium.org <suderman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-10 03:24:16 +0000
commitd4f898847f005ef900304856a4f6209adf23f322 (patch)
treebb74bd0bbfb7173438a775cbfd895396ab35c013
parent5b8cfced8fe1f455dbe3933862e45683348c1c53 (diff)
downloadchromium_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.h3
-rw-r--r--media/base/fake_text_track_stream.cc4
-rw-r--r--media/base/fake_text_track_stream.h1
-rw-r--r--media/base/mock_filters.cc4
-rw-r--r--media/base/mock_filters.h2
-rw-r--r--media/base/pipeline.cc1
-rw-r--r--media/base/pipeline.h5
-rw-r--r--media/base/video_rotation.h21
-rw-r--r--media/filters/chunk_demuxer.cc4
-rw-r--r--media/filters/chunk_demuxer.h1
-rw-r--r--media/filters/decrypting_demuxer_stream.cc4
-rw-r--r--media/filters/decrypting_demuxer_stream.h1
-rw-r--r--media/filters/fake_demuxer_stream.cc4
-rw-r--r--media/filters/fake_demuxer_stream.h1
-rw-r--r--media/filters/ffmpeg_demuxer.cc30
-rw-r--r--media/filters/ffmpeg_demuxer.h4
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc36
-rw-r--r--media/filters/pipeline_integration_test.cc22
-rw-r--r--media/media.gyp1
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',