summaryrefslogtreecommitdiffstats
path: root/media/mp4
diff options
context:
space:
mode:
authorstrobe@google.com <strobe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-08 01:33:35 +0000
committerstrobe@google.com <strobe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-08 01:33:35 +0000
commitcbbc13c504ad023a69dcaba56d9064eb77577fa1 (patch)
tree187f2dad8f5106ef93518de17761ff414488acca /media/mp4
parent3422af1d763d8fe33d31863ff1bd1bfe103681a1 (diff)
downloadchromium_src-cbbc13c504ad023a69dcaba56d9064eb77577fa1.zip
chromium_src-cbbc13c504ad023a69dcaba56d9064eb77577fa1.tar.gz
chromium_src-cbbc13c504ad023a69dcaba56d9064eb77577fa1.tar.bz2
Add initial support for edit lists in MSE BMFF.
BUG=135665 TEST=TrackRunIteratorTest.ReorderingTest Review URL: https://chromiumcodereview.appspot.com/10832176 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@150478 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/mp4')
-rw-r--r--media/mp4/mp4_stream_parser.cc1
-rw-r--r--media/mp4/track_run_iterator.cc22
-rw-r--r--media/mp4/track_run_iterator_unittest.cc38
3 files changed, 56 insertions, 5 deletions
diff --git a/media/mp4/mp4_stream_parser.cc b/media/mp4/mp4_stream_parser.cc
index 9c9b750..1aa8c70 100644
--- a/media/mp4/mp4_stream_parser.cc
+++ b/media/mp4/mp4_stream_parser.cc
@@ -145,7 +145,6 @@ bool MP4StreamParser::ParseBox(bool* err) {
bool MP4StreamParser::ParseMoov(BoxReader* reader) {
- // TODO(strobe): Respect edit lists.
moov_.reset(new Movie);
RCHECK(moov_->Parse(reader));
runs_.reset(new TrackRunIterator(moov_.get()));
diff --git a/media/mp4/track_run_iterator.cc b/media/mp4/track_run_iterator.cc
index 59bc229..073eeee 100644
--- a/media/mp4/track_run_iterator.cc
+++ b/media/mp4/track_run_iterator.cc
@@ -71,6 +71,7 @@ TrackRunIterator::~TrackRunIterator() {}
static void PopulateSampleInfo(const TrackExtends& trex,
const TrackFragmentHeader& tfhd,
const TrackFragmentRun& trun,
+ const int64 edit_list_offset,
const uint32 i,
SampleInfo* sample_info) {
if (i < trun.sample_sizes.size()) {
@@ -94,6 +95,7 @@ static void PopulateSampleInfo(const TrackExtends& trex,
} else {
sample_info->cts_offset = 0;
}
+ sample_info->cts_offset += edit_list_offset;
uint32 flags;
if (i < trun.sample_flags.size()) {
@@ -164,6 +166,23 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
RCHECK(desc_idx > 0); // Descriptions are one-indexed in the file
desc_idx -= 1;
+ // Process edit list to remove CTS offset introduced in the presence of
+ // B-frames (those that contain a single edit with a nonnegative media
+ // time). Other uses of edit lists are not supported, as they are
+ // both uncommon and better served by higher-level protocols.
+ int64 edit_list_offset = 0;
+ const std::vector<EditListEntry>& edits = trak->edit.list.edits;
+ if (!edits.empty()) {
+ if (edits.size() > 1)
+ DVLOG(1) << "Multi-entry edit box detected; some components ignored.";
+
+ if (edits[0].media_time < 0) {
+ DVLOG(1) << "Empty edit list entry ignored.";
+ } else {
+ edit_list_offset = -edits[0].media_time;
+ }
+ }
+
int64 run_start_dts = traf.decode_time.decode_time;
int sample_count_sum = 0;
@@ -226,7 +245,8 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
tri.samples.resize(trun.sample_count);
for (size_t k = 0; k < trun.sample_count; k++) {
- PopulateSampleInfo(*trex, traf.header, trun, k, &tri.samples[k]);
+ PopulateSampleInfo(*trex, traf.header, trun, edit_list_offset,
+ k, &tri.samples[k]);
run_start_dts += tri.samples[k].duration;
}
runs_.push_back(tri);
diff --git a/media/mp4/track_run_iterator_unittest.cc b/media/mp4/track_run_iterator_unittest.cc
index e1c1a03..40385cc 100644
--- a/media/mp4/track_run_iterator_unittest.cc
+++ b/media/mp4/track_run_iterator_unittest.cc
@@ -261,23 +261,55 @@ TEST_F(TrackRunIteratorTest, MinDecodeTest) {
}
TEST_F(TrackRunIteratorTest, ReorderingTest) {
+ // Test frame reordering and edit list support. The frames have the following
+ // decode timestamps:
+ //
+ // 0ms 40ms 120ms 240ms
+ // | 0 | 1 - | 2 - - |
+ //
+ // ...and these composition timestamps, after edit list adjustment:
+ //
+ // 0ms 40ms 160ms 240ms
+ // | 0 | 2 - - | 1 - |
+
+ // Create an edit list with one entry, with an initial start time of 80ms
+ // (that is, 2 / kVideoTimescale) and a duration of zero (which is treated as
+ // infinite according to 14496-12:2012). This will cause the first 80ms of the
+ // media timeline - which will be empty, due to CTS biasing - to be discarded.
iter_.reset(new TrackRunIterator(&moov_));
+ EditListEntry entry;
+ entry.segment_duration = 0;
+ entry.media_time = 2;
+ entry.media_rate_integer = 1;
+ entry.media_rate_fraction = 0;
+ moov_.tracks[1].edit.list.edits.push_back(entry);
+
+ // Add CTS offsets. Without bias, the CTS offsets for the first three frames
+ // would simply be [0, 3, -2]. Since CTS offsets should be non-negative for
+ // maximum compatibility, these values are biased up to [2, 5, 0], and the
+ // extra 80ms is removed via the edit list.
MovieFragment moof = CreateFragment();
std::vector<int32>& cts_offsets =
moof.tracks[1].runs[0].sample_composition_time_offsets;
cts_offsets.resize(10);
cts_offsets[0] = 2;
- cts_offsets[1] = -1;
+ cts_offsets[1] = 5;
+ cts_offsets[2] = 0;
moof.tracks[1].decode_time.decode_time = 0;
+
ASSERT_TRUE(iter_->Init(moof));
iter_->AdvanceRun();
EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(0, kVideoScale));
- EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(2, kVideoScale));
+ EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(0, kVideoScale));
EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(1, kVideoScale));
iter_->AdvanceSample();
EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(1, kVideoScale));
- EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(0, kVideoScale));
+ EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(4, kVideoScale));
EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(2, kVideoScale));
+ iter_->AdvanceSample();
+ EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(3, kVideoScale));
+ EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(1, kVideoScale));
+ EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(3, kVideoScale));
}
TEST_F(TrackRunIteratorTest, IgnoreUnknownAuxInfoTest) {