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
This commit is contained in:
KongQun Yang 2014-06-30 09:32:06 -07:00
parent fc85154bca
commit 50aea3e6f6
7 changed files with 32 additions and 30 deletions

View File

@ -90,7 +90,6 @@ bool AssignFlagsFromProfile() {
bool normalize_pts = FLAGS_normalize_presentation_timestamp; bool normalize_pts = FLAGS_normalize_presentation_timestamp;
if (FLAGS_profile == "on-demand") { if (FLAGS_profile == "on-demand") {
single_segment = true; single_segment = true;
normalize_pts = true;
} else if (FLAGS_profile == "live") { } else if (FLAGS_profile == "live") {
single_segment = false; single_segment = false;
normalize_pts = false; normalize_pts = false;

View File

@ -38,6 +38,11 @@ EncryptingFragmenter::~EncryptingFragmenter() {}
Status EncryptingFragmenter::AddSample(scoped_refptr<MediaSample> sample) { Status EncryptingFragmenter::AddSample(scoped_refptr<MediaSample> sample) {
DCHECK(sample); DCHECK(sample);
if (!fragment_initialized()) {
Status status = InitializeFragment(sample->dts());
if (!status.ok())
return status;
}
if (encryptor_) { if (encryptor_) {
Status status = EncryptSample(sample); Status status = EncryptSample(sample);
if (!status.ok()) if (!status.ok())
@ -46,8 +51,8 @@ Status EncryptingFragmenter::AddSample(scoped_refptr<MediaSample> sample) {
return Fragmenter::AddSample(sample); return Fragmenter::AddSample(sample);
} }
Status EncryptingFragmenter::InitializeFragment() { Status EncryptingFragmenter::InitializeFragment(int64 first_sample_dts) {
Status status = Fragmenter::InitializeFragment(); Status status = Fragmenter::InitializeFragment(first_sample_dts);
if (!status.ok()) if (!status.ok())
return status; return status;

View File

@ -38,7 +38,7 @@ class EncryptingFragmenter : public Fragmenter {
/// @name Fragmenter implementation overrides. /// @name Fragmenter implementation overrides.
/// @{ /// @{
virtual Status AddSample(scoped_refptr<MediaSample> sample) OVERRIDE; virtual Status AddSample(scoped_refptr<MediaSample> sample) OVERRIDE;
virtual Status InitializeFragment() OVERRIDE; virtual Status InitializeFragment(int64 first_sample_dts) OVERRIDE;
virtual void FinalizeFragment() OVERRIDE; virtual void FinalizeFragment() OVERRIDE;
/// @} /// @}

View File

@ -20,6 +20,7 @@ const int64 kInvalidTime = kint64max;
Fragmenter::Fragmenter(TrackFragment* traf, Fragmenter::Fragmenter(TrackFragment* traf,
bool normalize_presentation_timestamp) bool normalize_presentation_timestamp)
: traf_(traf), : traf_(traf),
fragment_initialized_(false),
fragment_finalized_(false), fragment_finalized_(false),
fragment_duration_(0), fragment_duration_(0),
normalize_presentation_timestamp_(normalize_presentation_timestamp), normalize_presentation_timestamp_(normalize_presentation_timestamp),
@ -35,15 +36,17 @@ Status Fragmenter::AddSample(scoped_refptr<MediaSample> sample) {
DCHECK(sample); DCHECK(sample);
CHECK_GT(sample->duration(), 0); 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. // Fill in sample parameters. It will be optimized later.
traf_->runs[0].sample_sizes.push_back(sample->data_size()); traf_->runs[0].sample_sizes.push_back(sample->data_size());
traf_->runs[0].sample_durations.push_back(sample->duration()); traf_->runs[0].sample_durations.push_back(sample->duration());
traf_->runs[0].sample_flags.push_back( traf_->runs[0].sample_flags.push_back(
sample->is_key_frame() ? 0 : TrackFragmentHeader::kNonKeySampleMask); 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()); data_->AppendArray(sample->data(), sample->data_size());
fragment_duration_ += sample->duration(); fragment_duration_ += sample->duration();
@ -70,6 +73,10 @@ Status Fragmenter::AddSample(scoped_refptr<MediaSample> sample) {
if (earliest_presentation_time_ > pts) if (earliest_presentation_time_ > pts)
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 (sample->is_key_frame()) {
if (first_sap_time_ == kInvalidTime) if (first_sap_time_ == kInvalidTime)
first_sap_time_ = pts; first_sap_time_ = pts;
@ -77,9 +84,10 @@ Status Fragmenter::AddSample(scoped_refptr<MediaSample> sample) {
return Status::OK; return Status::OK;
} }
Status Fragmenter::InitializeFragment() { Status Fragmenter::InitializeFragment(int64 first_sample_dts) {
fragment_initialized_ = true;
fragment_finalized_ = false; fragment_finalized_ = false;
traf_->decode_time.decode_time += fragment_duration_; traf_->decode_time.decode_time = first_sample_dts;
traf_->runs.clear(); traf_->runs.clear();
traf_->runs.resize(1); traf_->runs.resize(1);
traf_->runs[0].flags = TrackFragmentRun::kDataOffsetPresentMask; traf_->runs[0].flags = TrackFragmentRun::kDataOffsetPresentMask;
@ -116,6 +124,7 @@ void Fragmenter::FinalizeFragment() {
} }
fragment_finalized_ = true; fragment_finalized_ = true;
fragment_initialized_ = false;
} }
void Fragmenter::GenerateSegmentReference(SegmentReference* reference) { void Fragmenter::GenerateSegmentReference(SegmentReference* reference) {

View File

@ -40,8 +40,10 @@ class Fragmenter {
virtual Status AddSample(scoped_refptr<MediaSample> sample); virtual Status AddSample(scoped_refptr<MediaSample> sample);
/// Initialize the fragment with default data. /// 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. /// @return OK on success, an error status otherwise.
virtual Status InitializeFragment(); virtual Status InitializeFragment(int64 first_sample_dts);
/// Finalize and optimize the fragment. /// Finalize and optimize the fragment.
virtual void FinalizeFragment(); virtual void FinalizeFragment();
@ -54,6 +56,7 @@ class Fragmenter {
uint64 earliest_presentation_time() const { uint64 earliest_presentation_time() const {
return earliest_presentation_time_; return earliest_presentation_time_;
} }
bool fragment_initialized() const { return fragment_initialized_; }
bool fragment_finalized() const { return fragment_finalized_; } bool fragment_finalized() const { return fragment_finalized_; }
BufferWriter* data() { return data_.get(); } BufferWriter* data() { return data_.get(); }
BufferWriter* aux_data() { return aux_data_.get(); } BufferWriter* aux_data() { return aux_data_.get(); }
@ -72,6 +75,7 @@ class Fragmenter {
bool StartsWithSAP(); bool StartsWithSAP();
TrackFragment* traf_; TrackFragment* traf_;
bool fragment_initialized_;
bool fragment_finalized_; bool fragment_finalized_;
uint64 fragment_duration_; uint64 fragment_duration_;
bool normalize_presentation_timestamp_; bool normalize_presentation_timestamp_;

View File

@ -204,8 +204,8 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
// Use the reference stream's time scale as movie time scale. // Use the reference stream's time scale as movie time scale.
moov_->header.timescale = sidx_->timescale; moov_->header.timescale = sidx_->timescale;
Status status = InitializeFragments(); moof_->header.sequence_number = 1;
return status.ok() ? DoInitialize() : status; return DoInitialize();
} }
Status Segmenter::Finalize() { Status Segmenter::Finalize() {
@ -320,19 +320,6 @@ uint32 Segmenter::GetReferenceStreamId() {
return sidx_->reference_id - 1; return sidx_->reference_id - 1;
} }
Status Segmenter::InitializeFragments() {
++moof_->header.sequence_number;
Status status;
for (std::vector<Fragmenter*>::iterator it = fragmenters_.begin();
it != fragmenters_.end();
++it) {
status = (*it)->InitializeFragment();
if (!status.ok())
return status;
}
return Status::OK;
}
Status Segmenter::FinalizeFragment(Fragmenter* fragmenter) { Status Segmenter::FinalizeFragment(Fragmenter* fragmenter) {
fragmenter->FinalizeFragment(); fragmenter->FinalizeFragment();
@ -379,9 +366,8 @@ Status Segmenter::FinalizeFragment(Fragmenter* fragmenter) {
fragment_buffer_->AppendBuffer(*fragmenter->data()); fragment_buffer_->AppendBuffer(*fragmenter->data());
} }
Status status = InitializeFragments(); // Increase sequence_number for next fragment.
if (!status.ok()) ++moof_->header.sequence_number;
return status;
if (end_of_segment_) if (end_of_segment_)
return FinalizeSegment(); return FinalizeSegment();

View File

@ -111,7 +111,6 @@ class Segmenter {
Status FinalizeSegment(); Status FinalizeSegment();
uint32 GetReferenceStreamId(); uint32 GetReferenceStreamId();
Status InitializeFragments();
Status FinalizeFragment(Fragmenter* fragment); Status FinalizeFragment(Fragmenter* fragment);
const MuxerOptions& options_; const MuxerOptions& options_;