From 55050fe6b5ac44ce10c120f07149e34d89d16573 Mon Sep 17 00:00:00 2001 From: KongQun Yang Date: Wed, 30 May 2018 15:02:33 -0700 Subject: [PATCH] [Ad Insertion] Avoid adjusting EPT except for the first file EPT (earliest presentation time) may be adjusted not to be lower than the decoding timestamp (dts), but the adjustment should only be done on the first file when there is one file per Representation per Period. The second file and onwards should not be adjusted otherwise a GAP would be created. Closes #384 Closes b/78517422 Change-Id: I56771ad8fbbe6a87b832ec58854cfbf37d5f1817 --- .../bear-640x360-video.m3u8 | 2 +- .../bear-640x360-video2.mp4 | Bin 81202 -> 81202 bytes .../output.mpd | 10 +++---- packager/media/base/muxer.cc | 5 ++-- packager/media/base/muxer.h | 12 ++++---- packager/media/base/muxer_options.h | 7 +++++ packager/media/formats/mp4/fragmenter.cc | 28 ++++++++++-------- packager/media/formats/mp4/fragmenter.h | 10 +++++++ packager/media/formats/mp4/segmenter.cc | 5 ++++ 9 files changed, 53 insertions(+), 26 deletions(-) diff --git a/packager/app/test/testdata/encryption-and-ad-cues-split-content/bear-640x360-video.m3u8 b/packager/app/test/testdata/encryption-and-ad-cues-split-content/bear-640x360-video.m3u8 index 9c101d35f7..f27353ae67 100644 --- a/packager/app/test/testdata/encryption-and-ad-cues-split-content/bear-640x360-video.m3u8 +++ b/packager/app/test/testdata/encryption-and-ad-cues-split-content/bear-640x360-video.m3u8 @@ -13,7 +13,7 @@ bear-640x360-video1.mp4 bear-640x360-video1.mp4 #EXT-X-PLACEMENT-OPPORTUNITY #EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="data:text/plain;base64,MTIzNDU2Nzg5MDEyMzQ1Ng==",KEYFORMAT="identity" -#EXTINF:0.801, +#EXTINF:0.734, #EXT-X-BYTERANGE:80067@1135 bear-640x360-video2.mp4 #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/encryption-and-ad-cues-split-content/bear-640x360-video2.mp4 b/packager/app/test/testdata/encryption-and-ad-cues-split-content/bear-640x360-video2.mp4 index f4dc57cdb5971a96f540bb7a2473acc455ddfff8..85d67d0d46b539fabc2d2c29539fa33b101bb6ba 100644 GIT binary patch delta 41 rcmdn=i)GU - + @@ -28,15 +28,15 @@ - + AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + bear-640x360-video2.mp4 - + @@ -49,7 +49,7 @@ bear-640x360-audio2.mp4 - + diff --git a/packager/media/base/muxer.cc b/packager/media/base/muxer.cc index cf8212d75f..7fe7918374 100644 --- a/packager/media/base/muxer.cc +++ b/packager/media/base/muxer.cc @@ -110,8 +110,9 @@ Status Muxer::ReinitializeMuxer(int64_t timestamp) { current_key_id_ = encryption_config.key_id; } if (!output_file_template_.empty()) { - // Update |output_file_name| with an actual file name, which will be used by - // the subclasses. + // Update |output_file_index| and |output_file_name| with an actual file + // name, which will be used by the subclasses. + options_.output_file_index = output_file_index_; options_.output_file_name = GetSegmentName(output_file_template_, timestamp, output_file_index_++, options_.bandwidth); diff --git a/packager/media/base/muxer.h b/packager/media/base/muxer.h index d06fd21a36..3b01fa6827 100644 --- a/packager/media/base/muxer.h +++ b/packager/media/base/muxer.h @@ -75,11 +75,9 @@ class Muxer : public MediaHandler { Muxer(const Muxer&) = delete; Muxer& operator=(const Muxer&) = delete; - // Re-initialize Muxer. Could be called on StreamInfo or CueEvent. - // |timestamp| may be used to set the output file name. - Status ReinitializeMuxer(int64_t timestamp); - - // Initialize the muxer. + // Initialize the muxer. InitializeMuxer may be called multiple times with + // |options()| updated between calls, which is used to support separate file + // per Representation per Period for Ad Insertion. virtual Status InitializeMuxer() = 0; // Final clean up. @@ -95,6 +93,10 @@ class Muxer : public MediaHandler { size_t stream_id, const SegmentInfo& segment_info) = 0; + // Re-initialize Muxer. Could be called on StreamInfo or CueEvent. + // |timestamp| may be used to set the output file name. + Status ReinitializeMuxer(int64_t timestamp); + MuxerOptions options_; std::vector> streams_; std::vector current_key_id_; diff --git a/packager/media/base/muxer_options.h b/packager/media/base/muxer_options.h index f409e19fdf..e591710543 100644 --- a/packager/media/base/muxer_options.h +++ b/packager/media/base/muxer_options.h @@ -29,6 +29,13 @@ struct MuxerOptions { /// Otherwise, it specifies the init segment name. std::string output_file_name; + /// Output file index. With one file per Representation per Period, there + /// could be more than one file generated with Ad Cues present. This is the + /// 0-based index of the output file. + /// TODO(kqyang): Remove when the EPT adjustment logic in + /// Fragmenter::FinalizeFragment is removed. + size_t output_file_index = 0; + /// Specify output segment name pattern for generated segments. It can /// furthermore be configured by using a subset of the SegmentTemplate /// identifiers: $RepresentationID$, $Number$, $Bandwidth$ and $Time. diff --git a/packager/media/formats/mp4/fragmenter.cc b/packager/media/formats/mp4/fragmenter.cc index d637e467ce..3654b6d8fa 100644 --- a/packager/media/formats/mp4/fragmenter.cc +++ b/packager/media/formats/mp4/fragmenter.cc @@ -152,19 +152,21 @@ Status Fragmenter::FinalizeFragment() { } if (first_fragment_) { - // Chrome (as of v66 https://crbug.com/398141) does not like negative values - // for adjusted dts = dts + Period@start (0 for first Period) - // - presentationTimeOffset - // Since |earliest_presentation_time| of the first fragment will be used to - // set presentationTimeOffset, the adjusted dts can become negative for the - // frames in the first segment in the first Period. To avoid seeing that, - // |earliest_presentation_time| is adjusted so it is not larger than the - // dts. - const int64_t dts = traf_->decode_time.decode_time; - if (earliest_presentation_time_ > dts) { - const uint64_t delta = earliest_presentation_time_ - dts; - earliest_presentation_time_ = dts; - fragment_duration_ += delta; + if (allow_adjust_earliest_presentation_time_) { + // Chrome (as of v66 https://crbug.com/398141) does not like negative + // values for adjusted dts = dts + Period@start (0 for first Period) + // - presentationTimeOffset + // Since |earliest_presentation_time| of the first fragment will be used + // to set presentationTimeOffset, the adjusted dts can become negative for + // the frames in the first segment in the first Period. To avoid seeing + // that, |earliest_presentation_time| is adjusted so it is not larger than + // the dts. + const int64_t dts = traf_->decode_time.decode_time; + if (earliest_presentation_time_ > dts) { + const uint64_t delta = earliest_presentation_time_ - dts; + earliest_presentation_time_ = dts; + fragment_duration_ += delta; + } } first_fragment_ = false; } diff --git a/packager/media/formats/mp4/fragmenter.h b/packager/media/formats/mp4/fragmenter.h index 4edf5c116b..799d9396ba 100644 --- a/packager/media/formats/mp4/fragmenter.h +++ b/packager/media/formats/mp4/fragmenter.h @@ -76,6 +76,15 @@ class Fragmenter { use_decoding_timestamp_in_timeline_ = use_decoding_timestamp_in_timeline; } + /// Set the flag allow_use_adjust_earliest_presentation_time, which if set to + /// true, earlist_presentation_time (EPT) may be adjusted not to be smaller + /// than the decoding timestamp (dts) for the first fragment. + void set_allow_adjust_earliest_presentation_time( + bool allow_adjust_earliest_presentation_time) { + allow_adjust_earliest_presentation_time_ = + allow_adjust_earliest_presentation_time; + } + protected: TrackFragment* traf() { return traf_; } @@ -99,6 +108,7 @@ class Fragmenter { uint64_t fragment_duration_; int64_t earliest_presentation_time_; bool first_fragment_ = true; + bool allow_adjust_earliest_presentation_time_ = false; int64_t first_sap_time_; std::unique_ptr data_; // Saves key frames information, for Video. diff --git a/packager/media/formats/mp4/segmenter.cc b/packager/media/formats/mp4/segmenter.cc index e4f4bf4227..1d83e311c1 100644 --- a/packager/media/formats/mp4/segmenter.cc +++ b/packager/media/formats/mp4/segmenter.cc @@ -75,6 +75,11 @@ Status Segmenter::Initialize( for (uint32_t i = 0; i < streams.size(); ++i) fragmenters_[i]->set_use_decoding_timestamp_in_timeline(true); } + // Only allow |EPT| to be adjusted for the first file. + if (options_.output_file_index == 0) { + for (uint32_t i = 0; i < streams.size(); ++i) + fragmenters_[i]->set_allow_adjust_earliest_presentation_time(true); + } // Choose the first stream if there is no VIDEO. if (sidx_->reference_id == 0)