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 f4dc57cdb5..85d67d0d46 100644 Binary files a/packager/app/test/testdata/encryption-and-ad-cues-split-content/bear-640x360-video2.mp4 and b/packager/app/test/testdata/encryption-and-ad-cues-split-content/bear-640x360-video2.mp4 differ diff --git a/packager/app/test/testdata/encryption-and-ad-cues-split-content/output.mpd b/packager/app/test/testdata/encryption-and-ad-cues-split-content/output.mpd index 2fda8f0e9d..7ef0acc944 100644 --- a/packager/app/test/testdata/encryption-and-ad-cues-split-content/output.mpd +++ b/packager/app/test/testdata/encryption-and-ad-cues-split-content/output.mpd @@ -1,6 +1,6 @@ - + @@ -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)