From 50aea3e6f68d292a8b3eb749c23e2152c8fa659d Mon Sep 17 00:00:00 2001 From: KongQun Yang Date: Mon, 30 Jun 2014 09:32:06 -0700 Subject: [PATCH] Set fragment decoding time from input sample dts For live streams, we cannot assume that the input decoding timestamp starts from zero. Also don't overwrite |normalize_presentation_timestamp| if the user does not want to enable it for on-demand profile. Change-Id: I1abe7926e0b25eb11dee021be964d126484d4036 --- app/packager_util.cc | 1 - media/formats/mp4/encrypting_fragmenter.cc | 9 +++++++-- media/formats/mp4/encrypting_fragmenter.h | 2 +- media/formats/mp4/fragmenter.cc | 21 +++++++++++++++------ media/formats/mp4/fragmenter.h | 6 +++++- media/formats/mp4/segmenter.cc | 22 ++++------------------ media/formats/mp4/segmenter.h | 1 - 7 files changed, 32 insertions(+), 30 deletions(-) diff --git a/app/packager_util.cc b/app/packager_util.cc index 1702c414a5..159dcdd395 100644 --- a/app/packager_util.cc +++ b/app/packager_util.cc @@ -90,7 +90,6 @@ bool AssignFlagsFromProfile() { bool normalize_pts = FLAGS_normalize_presentation_timestamp; if (FLAGS_profile == "on-demand") { single_segment = true; - normalize_pts = true; } else if (FLAGS_profile == "live") { single_segment = false; normalize_pts = false; diff --git a/media/formats/mp4/encrypting_fragmenter.cc b/media/formats/mp4/encrypting_fragmenter.cc index dd9bb677f5..08f9569509 100644 --- a/media/formats/mp4/encrypting_fragmenter.cc +++ b/media/formats/mp4/encrypting_fragmenter.cc @@ -38,6 +38,11 @@ EncryptingFragmenter::~EncryptingFragmenter() {} Status EncryptingFragmenter::AddSample(scoped_refptr sample) { DCHECK(sample); + if (!fragment_initialized()) { + Status status = InitializeFragment(sample->dts()); + if (!status.ok()) + return status; + } if (encryptor_) { Status status = EncryptSample(sample); if (!status.ok()) @@ -46,8 +51,8 @@ Status EncryptingFragmenter::AddSample(scoped_refptr sample) { return Fragmenter::AddSample(sample); } -Status EncryptingFragmenter::InitializeFragment() { - Status status = Fragmenter::InitializeFragment(); +Status EncryptingFragmenter::InitializeFragment(int64 first_sample_dts) { + Status status = Fragmenter::InitializeFragment(first_sample_dts); if (!status.ok()) return status; diff --git a/media/formats/mp4/encrypting_fragmenter.h b/media/formats/mp4/encrypting_fragmenter.h index be4c411222..2d79991f33 100644 --- a/media/formats/mp4/encrypting_fragmenter.h +++ b/media/formats/mp4/encrypting_fragmenter.h @@ -38,7 +38,7 @@ class EncryptingFragmenter : public Fragmenter { /// @name Fragmenter implementation overrides. /// @{ virtual Status AddSample(scoped_refptr sample) OVERRIDE; - virtual Status InitializeFragment() OVERRIDE; + virtual Status InitializeFragment(int64 first_sample_dts) OVERRIDE; virtual void FinalizeFragment() OVERRIDE; /// @} diff --git a/media/formats/mp4/fragmenter.cc b/media/formats/mp4/fragmenter.cc index 880f741682..923c2c0630 100644 --- a/media/formats/mp4/fragmenter.cc +++ b/media/formats/mp4/fragmenter.cc @@ -20,6 +20,7 @@ const int64 kInvalidTime = kint64max; Fragmenter::Fragmenter(TrackFragment* traf, bool normalize_presentation_timestamp) : traf_(traf), + fragment_initialized_(false), fragment_finalized_(false), fragment_duration_(0), normalize_presentation_timestamp_(normalize_presentation_timestamp), @@ -35,15 +36,17 @@ Status Fragmenter::AddSample(scoped_refptr sample) { DCHECK(sample); CHECK_GT(sample->duration(), 0); + if (!fragment_initialized_) { + Status status = InitializeFragment(sample->dts()); + if (!status.ok()) + return status; + } + // Fill in sample parameters. It will be optimized later. traf_->runs[0].sample_sizes.push_back(sample->data_size()); traf_->runs[0].sample_durations.push_back(sample->duration()); traf_->runs[0].sample_flags.push_back( sample->is_key_frame() ? 0 : TrackFragmentHeader::kNonKeySampleMask); - traf_->runs[0].sample_composition_time_offsets.push_back(sample->pts() - - sample->dts()); - if (sample->pts() != sample->dts()) - traf_->runs[0].flags |= TrackFragmentRun::kSampleCompTimeOffsetsPresentMask; data_->AppendArray(sample->data(), sample->data_size()); fragment_duration_ += sample->duration(); @@ -70,6 +73,10 @@ Status Fragmenter::AddSample(scoped_refptr sample) { if (earliest_presentation_time_ > pts) earliest_presentation_time_ = pts; + traf_->runs[0].sample_composition_time_offsets.push_back(pts - sample->dts()); + if (pts != sample->dts()) + traf_->runs[0].flags |= TrackFragmentRun::kSampleCompTimeOffsetsPresentMask; + if (sample->is_key_frame()) { if (first_sap_time_ == kInvalidTime) first_sap_time_ = pts; @@ -77,9 +84,10 @@ Status Fragmenter::AddSample(scoped_refptr sample) { return Status::OK; } -Status Fragmenter::InitializeFragment() { +Status Fragmenter::InitializeFragment(int64 first_sample_dts) { + fragment_initialized_ = true; fragment_finalized_ = false; - traf_->decode_time.decode_time += fragment_duration_; + traf_->decode_time.decode_time = first_sample_dts; traf_->runs.clear(); traf_->runs.resize(1); traf_->runs[0].flags = TrackFragmentRun::kDataOffsetPresentMask; @@ -116,6 +124,7 @@ void Fragmenter::FinalizeFragment() { } fragment_finalized_ = true; + fragment_initialized_ = false; } void Fragmenter::GenerateSegmentReference(SegmentReference* reference) { diff --git a/media/formats/mp4/fragmenter.h b/media/formats/mp4/fragmenter.h index c1de2341c0..4c55480663 100644 --- a/media/formats/mp4/fragmenter.h +++ b/media/formats/mp4/fragmenter.h @@ -40,8 +40,10 @@ class Fragmenter { virtual Status AddSample(scoped_refptr sample); /// Initialize the fragment with default data. + /// @param first_sample_dts specifies the decoding timestamp for the first + /// sample for this fragment. /// @return OK on success, an error status otherwise. - virtual Status InitializeFragment(); + virtual Status InitializeFragment(int64 first_sample_dts); /// Finalize and optimize the fragment. virtual void FinalizeFragment(); @@ -54,6 +56,7 @@ class Fragmenter { uint64 earliest_presentation_time() const { return earliest_presentation_time_; } + bool fragment_initialized() const { return fragment_initialized_; } bool fragment_finalized() const { return fragment_finalized_; } BufferWriter* data() { return data_.get(); } BufferWriter* aux_data() { return aux_data_.get(); } @@ -72,6 +75,7 @@ class Fragmenter { bool StartsWithSAP(); TrackFragment* traf_; + bool fragment_initialized_; bool fragment_finalized_; uint64 fragment_duration_; bool normalize_presentation_timestamp_; diff --git a/media/formats/mp4/segmenter.cc b/media/formats/mp4/segmenter.cc index 97dcf7584d..de8d39f14e 100644 --- a/media/formats/mp4/segmenter.cc +++ b/media/formats/mp4/segmenter.cc @@ -204,8 +204,8 @@ Status Segmenter::Initialize(const std::vector& streams, // Use the reference stream's time scale as movie time scale. moov_->header.timescale = sidx_->timescale; - Status status = InitializeFragments(); - return status.ok() ? DoInitialize() : status; + moof_->header.sequence_number = 1; + return DoInitialize(); } Status Segmenter::Finalize() { @@ -320,19 +320,6 @@ uint32 Segmenter::GetReferenceStreamId() { return sidx_->reference_id - 1; } -Status Segmenter::InitializeFragments() { - ++moof_->header.sequence_number; - Status status; - for (std::vector::iterator it = fragmenters_.begin(); - it != fragmenters_.end(); - ++it) { - status = (*it)->InitializeFragment(); - if (!status.ok()) - return status; - } - return Status::OK; -} - Status Segmenter::FinalizeFragment(Fragmenter* fragmenter) { fragmenter->FinalizeFragment(); @@ -379,9 +366,8 @@ Status Segmenter::FinalizeFragment(Fragmenter* fragmenter) { fragment_buffer_->AppendBuffer(*fragmenter->data()); } - Status status = InitializeFragments(); - if (!status.ok()) - return status; + // Increase sequence_number for next fragment. + ++moof_->header.sequence_number; if (end_of_segment_) return FinalizeSegment(); diff --git a/media/formats/mp4/segmenter.h b/media/formats/mp4/segmenter.h index 2bf48e53ef..04e41b5d7f 100644 --- a/media/formats/mp4/segmenter.h +++ b/media/formats/mp4/segmenter.h @@ -111,7 +111,6 @@ class Segmenter { Status FinalizeSegment(); uint32 GetReferenceStreamId(); - Status InitializeFragments(); Status FinalizeFragment(Fragmenter* fragment); const MuxerOptions& options_;