diff --git a/README.md b/README.md index 1c1503866d..c644160436 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ This document provides the information needed to create a DASH packager that is ```Shell ninja -C out/Debug # build all modules in Debug mode ninja -C out/Release # build all modules in Release mode - ninja -C out/Release mp4 # build mp4 module in Debug mode + ninja -C out/Release mp4 # build mp4 module in Release mode ``` Refer to ninja manual for details. @@ -177,9 +177,6 @@ muxer_options.segment_sap_aligned = true; // segment_sap_aligned. muxer_options.fragment_sap_aligned = true; -// Set to true to normalize the presentation timestamps to start from zero. -muxer_options.normalize_presentation_timestamp = true; - // For ISO BMFF only. // Set the number of subsegments in each SIDX box. If 0, a single SIDX box // is used per segment. If -1, no SIDX box is used. Otherwise, the Muxer diff --git a/app/muxer_flags.cc b/app/muxer_flags.cc index f70283043c..3925b9b1b0 100644 --- a/app/muxer_flags.cc +++ b/app/muxer_flags.cc @@ -38,10 +38,6 @@ DEFINE_bool(fragment_sap_aligned, true, "Force fragments to begin with stream access points. This flag " "implies segment_sap_aligned."); -DEFINE_bool(normalize_presentation_timestamp, - true, - "Set to true to normalize the presentation timestamps to start" - "from zero."); DEFINE_int32(num_subsegments_per_sidx, 1, "For ISO BMFF only. Set the number of subsegments in each " diff --git a/app/muxer_flags.h b/app/muxer_flags.h index b35a6992b4..b9e682e709 100644 --- a/app/muxer_flags.h +++ b/app/muxer_flags.h @@ -18,7 +18,6 @@ DECLARE_double(segment_duration); DECLARE_bool(segment_sap_aligned); DECLARE_double(fragment_duration); DECLARE_bool(fragment_sap_aligned); -DECLARE_bool(normalize_presentation_timestamp); DECLARE_int32(num_subsegments_per_sidx); DECLARE_string(temp_dir); diff --git a/app/packager_util.cc b/app/packager_util.cc index 7836131aaa..02505f39f0 100644 --- a/app/packager_util.cc +++ b/app/packager_util.cc @@ -91,12 +91,10 @@ scoped_ptr CreateEncryptionKeySource() { bool AssignFlagsFromProfile() { bool single_segment = FLAGS_single_segment; - bool normalize_pts = FLAGS_normalize_presentation_timestamp; if (FLAGS_profile == "on-demand") { single_segment = true; } else if (FLAGS_profile == "live") { single_segment = false; - normalize_pts = false; } else if (FLAGS_profile != "") { fprintf(stderr, "ERROR: --profile '%s' is not supported.\n", FLAGS_profile.c_str()); @@ -108,12 +106,6 @@ bool AssignFlagsFromProfile() { fprintf(stdout, "Profile %s: set --single_segment to %s.\n", FLAGS_profile.c_str(), single_segment ? "true" : "false"); } - if (FLAGS_normalize_presentation_timestamp != normalize_pts) { - FLAGS_normalize_presentation_timestamp = normalize_pts; - fprintf(stdout, - "Profile %s: set --normalize_presentation_timestamp to %s.\n", - FLAGS_profile.c_str(), normalize_pts ? "true" : "false"); - } return true; } @@ -125,8 +117,6 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) { muxer_options->fragment_duration = FLAGS_fragment_duration; muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned; muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned; - muxer_options->normalize_presentation_timestamp = - FLAGS_normalize_presentation_timestamp; muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx; muxer_options->temp_dir = FLAGS_temp_dir; return true; diff --git a/media/base/muxer_options.cc b/media/base/muxer_options.cc index ec1530920b..5af50c4d9a 100644 --- a/media/base/muxer_options.cc +++ b/media/base/muxer_options.cc @@ -14,7 +14,6 @@ MuxerOptions::MuxerOptions() fragment_duration(0), segment_sap_aligned(false), fragment_sap_aligned(false), - normalize_presentation_timestamp(false), num_subsegments_per_sidx(0), bandwidth(0) {} MuxerOptions::~MuxerOptions() {} diff --git a/media/base/muxer_options.h b/media/base/muxer_options.h index 5589817a44..11b06f1648 100644 --- a/media/base/muxer_options.h +++ b/media/base/muxer_options.h @@ -43,9 +43,6 @@ struct MuxerOptions { /// implies that segment_sap_aligned is true as well. bool fragment_sap_aligned; - /// Set to true to normalize the presentation timestamp to start from zero. - bool normalize_presentation_timestamp; - /// For ISO BMFF only. /// Set the number of subsegments in each SIDX box. If 0, a single SIDX box /// is used per segment. If -1, no SIDX box is used. Otherwise, the Muxer diff --git a/media/formats/mp4/encrypting_fragmenter.cc b/media/formats/mp4/encrypting_fragmenter.cc index 08f9569509..3e283ca5ba 100644 --- a/media/formats/mp4/encrypting_fragmenter.cc +++ b/media/formats/mp4/encrypting_fragmenter.cc @@ -23,11 +23,10 @@ namespace mp4 { EncryptingFragmenter::EncryptingFragmenter( TrackFragment* traf, - bool normalize_presentation_timestamp, scoped_ptr encryption_key, int64 clear_time, uint8 nalu_length_size) - : Fragmenter(traf, normalize_presentation_timestamp), + : Fragmenter(traf), encryption_key_(encryption_key.Pass()), nalu_length_size_(nalu_length_size), clear_time_(clear_time) { diff --git a/media/formats/mp4/encrypting_fragmenter.h b/media/formats/mp4/encrypting_fragmenter.h index 2d79991f33..acbb476bd1 100644 --- a/media/formats/mp4/encrypting_fragmenter.h +++ b/media/formats/mp4/encrypting_fragmenter.h @@ -20,15 +20,12 @@ namespace mp4 { class EncryptingFragmenter : public Fragmenter { public: /// @param traf points to a TrackFragment box. - /// @param normalize_presentation_timestamp defines whether PTS should be - /// normalized to start from zero. /// @param encryption_key contains the encryption parameters. /// @param clear_time specifies clear lead duration in units of the current /// track's timescale. /// @param nalu_length_size specifies the size of NAL unit length, in bytes, /// for subsample encryption. EncryptingFragmenter(TrackFragment* traf, - bool normalize_presentation_timestamp, scoped_ptr encryption_key, int64 clear_time, uint8 nalu_length_size); diff --git a/media/formats/mp4/fragmenter.cc b/media/formats/mp4/fragmenter.cc index 923c2c0630..caab6aecf6 100644 --- a/media/formats/mp4/fragmenter.cc +++ b/media/formats/mp4/fragmenter.cc @@ -17,13 +17,11 @@ namespace { const int64 kInvalidTime = kint64max; } // namespace -Fragmenter::Fragmenter(TrackFragment* traf, - bool normalize_presentation_timestamp) +Fragmenter::Fragmenter(TrackFragment* traf) : traf_(traf), fragment_initialized_(false), fragment_finalized_(false), fragment_duration_(0), - normalize_presentation_timestamp_(normalize_presentation_timestamp), presentation_start_time_(kInvalidTime), earliest_presentation_time_(kInvalidTime), first_sap_time_(kInvalidTime) { @@ -52,21 +50,6 @@ Status Fragmenter::AddSample(scoped_refptr sample) { fragment_duration_ += sample->duration(); int64 pts = sample->pts(); - if (normalize_presentation_timestamp_) { - // Normalize PTS to start from 0. Some players do not like non-zero - // presentation starting time. - // NOTE: The timeline of the remuxed video may not be exactly the same as - // the original video. An EditList box may be useful to solve this. - if (presentation_start_time_ == kInvalidTime) { - presentation_start_time_ = pts; - pts = 0; - } else { - // Is it safe to assume the first sample in the media has the earliest - // presentation timestamp? - DCHECK_GE(pts, presentation_start_time_); - pts -= presentation_start_time_; - } - } // Set |earliest_presentation_time_| to |pts| if |pts| is smaller or if it is // not yet initialized (kInvalidTime > pts is always true). diff --git a/media/formats/mp4/fragmenter.h b/media/formats/mp4/fragmenter.h index 4c55480663..40faf79004 100644 --- a/media/formats/mp4/fragmenter.h +++ b/media/formats/mp4/fragmenter.h @@ -28,9 +28,7 @@ struct TrackFragment; class Fragmenter { public: /// @param traf points to a TrackFragment box. - /// @param normalize_presentation_timestamp defines whether PTS should be - /// normalized to start from zero. - Fragmenter(TrackFragment* traf, bool normalize_presentation_timestamp); + Fragmenter(TrackFragment* traf); virtual ~Fragmenter(); @@ -78,7 +76,6 @@ class Fragmenter { bool fragment_initialized_; bool fragment_finalized_; uint64 fragment_duration_; - bool normalize_presentation_timestamp_; int64 presentation_start_time_; int64 earliest_presentation_time_; int64 first_sap_time_; diff --git a/media/formats/mp4/key_rotation_fragmenter.cc b/media/formats/mp4/key_rotation_fragmenter.cc index 6d4944aaa2..dfb603a1e1 100644 --- a/media/formats/mp4/key_rotation_fragmenter.cc +++ b/media/formats/mp4/key_rotation_fragmenter.cc @@ -15,14 +15,12 @@ namespace mp4 { KeyRotationFragmenter::KeyRotationFragmenter( MovieFragment* moof, TrackFragment* traf, - bool normalize_presentation_timestamp, EncryptionKeySource* encryption_key_source, EncryptionKeySource::TrackType track_type, int64 crypto_period_duration, int64 clear_time, uint8 nalu_length_size) : EncryptingFragmenter(traf, - normalize_presentation_timestamp, scoped_ptr(new EncryptionKey()), clear_time, nalu_length_size), diff --git a/media/formats/mp4/key_rotation_fragmenter.h b/media/formats/mp4/key_rotation_fragmenter.h index 9c5a8d7718..c29907aaef 100644 --- a/media/formats/mp4/key_rotation_fragmenter.h +++ b/media/formats/mp4/key_rotation_fragmenter.h @@ -21,8 +21,6 @@ class KeyRotationFragmenter : public EncryptingFragmenter { public: /// @param moof points to a MovieFragment box. /// @param traf points to a TrackFragment box. - /// @param normalize_presentation_timestamp defines whether PTS should be - /// normalized to start from zero. /// @param encryption_key_source points to the source which generates /// encryption keys. /// @param track_type indicates whether SD key or HD key should be used to @@ -35,7 +33,6 @@ class KeyRotationFragmenter : public EncryptingFragmenter { /// encryption. KeyRotationFragmenter(MovieFragment* moof, TrackFragment* traf, - bool normalize_presentation_timestamp, EncryptionKeySource* encryption_key_source, EncryptionKeySource::TrackType track_type, int64 crypto_period_duration, diff --git a/media/formats/mp4/segmenter.cc b/media/formats/mp4/segmenter.cc index de8d39f14e..c225714bae 100644 --- a/media/formats/mp4/segmenter.cc +++ b/media/formats/mp4/segmenter.cc @@ -146,8 +146,7 @@ Status Segmenter::Initialize(const std::vector& streams, sidx_->reference_id = i + 1; } if (!encryption_key_source) { - fragmenters_[i] = new Fragmenter( - &moof_->tracks[i], options_.normalize_presentation_timestamp); + fragmenters_[i] = new Fragmenter(&moof_->tracks[i]); continue; } @@ -165,7 +164,6 @@ Status Segmenter::Initialize(const std::vector& streams, fragmenters_[i] = new KeyRotationFragmenter( moof_.get(), &moof_->tracks[i], - options_.normalize_presentation_timestamp, encryption_key_source, track_type, crypto_period_duration_in_seconds * streams[i]->info()->time_scale(), @@ -191,7 +189,6 @@ Status Segmenter::Initialize(const std::vector& streams, fragmenters_[i] = new EncryptingFragmenter( &moof_->tracks[i], - options_.normalize_presentation_timestamp, encryption_key.Pass(), clear_lead_in_seconds * streams[i]->info()->time_scale(), nalu_length_size); diff --git a/media/formats/mp4/single_segment_segmenter.cc b/media/formats/mp4/single_segment_segmenter.cc index 96668d7f64..663b929c7c 100644 --- a/media/formats/mp4/single_segment_segmenter.cc +++ b/media/formats/mp4/single_segment_segmenter.cc @@ -144,9 +144,25 @@ Status SingleSegmentSegmenter::DoFinalizeSegment() { vod_sidx_.reset(new SegmentIndex()); vod_sidx_->reference_id = sidx()->reference_id; vod_sidx_->timescale = sidx()->timescale; - // earliest_presentation_time is the earliest presentation time of any - // access unit in the reference stream in the first subsegment. - vod_sidx_->earliest_presentation_time = vod_ref.earliest_presentation_time; + + if (vod_ref.earliest_presentation_time > 0) { + const double starting_time_in_seconds = + static_cast(vod_ref.earliest_presentation_time) / + GetReferenceTimeScale(); + // Give a warning if it is significant. + if (starting_time_in_seconds > 0.5) { + // Note that DASH IF player requires presentationTimeOffset to be set in + // Segment{Base,List,Template} if there is non-zero starting time. Since + // current Chromium's MSE implementation uses DTS, the player expects + // DTS to be used. + LOG(WARNING) << "Warning! Non-zero starting time (in seconds): " + << starting_time_in_seconds + << ". Manual adjustment of presentationTimeOffset in " + "mpd might be necessary."; + } + } + // Force earliest_presentation_time to start from 0 for VOD. + vod_sidx_->earliest_presentation_time = 0; } vod_sidx_->references.push_back(vod_ref); diff --git a/media/test/packager_test.cc b/media/test/packager_test.cc index 25a7b9aff9..8ba3a77e37 100644 --- a/media/test/packager_test.cc +++ b/media/test/packager_test.cc @@ -132,10 +132,6 @@ MuxerOptions PackagerTestBasic::SetupOptions(const std::string& output, options.fragment_duration = kFragmentDurationInSecodns; options.segment_sap_aligned = kSegmentSapAligned; options.fragment_sap_aligned = kFragmentSapAligned; - // The mp4 muxer does not generate EditList, so the starting timestamp in the - // source is not carried over. Normalize the PTS so a second parse of the - // muxed output generates the same output. - options.normalize_presentation_timestamp = true; options.num_subsegments_per_sidx = kNumSubsegmentsPerSidx; options.output_file_name = GetFullPath(output);