Add a muxer option to normalize PTS to start from 0

Some players do not like non-zero starting PTS. We need to do PTS
normalization to make it work on those players.

Bug: 12686658

Change-Id: I0958c25395e4ea87d8208db9a5f6c5816827eb99
This commit is contained in:
Kongqun Yang 2014-01-22 15:51:26 -08:00 committed by KongQun Yang
parent 1e79eeb086
commit 522048b0d9
7 changed files with 46 additions and 10 deletions

View File

@ -37,6 +37,10 @@ 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 "

View File

@ -88,6 +88,8 @@ 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->output_file_name = FLAGS_output;
muxer_options->segment_template = FLAGS_segment_template;

View File

@ -12,6 +12,7 @@ MuxerOptions::MuxerOptions()
fragment_duration(0),
segment_sap_aligned(false),
fragment_sap_aligned(false),
normalize_presentation_timestamp(false),
num_subsegments_per_sidx(0) {}
MuxerOptions::~MuxerOptions() {}

View File

@ -35,6 +35,9 @@ struct MuxerOptions {
// that segment_sap_aligned is true as well.
bool fragment_sap_aligned;
// Set to true to normalize the presentation timestamps 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

View File

@ -42,14 +42,17 @@ namespace mp4 {
MP4Fragmenter::MP4Fragmenter(TrackFragment* traf,
scoped_ptr<AesCtrEncryptor> encryptor,
int64 clear_time,
uint8 nalu_length_size)
uint8 nalu_length_size,
bool normalize_presentation_timestamp)
: encryptor_(encryptor.Pass()),
nalu_length_size_(nalu_length_size),
traf_(traf),
fragment_finalized_(false),
fragment_duration_(0),
earliest_presentation_time_(0),
first_sap_time_(0),
normalize_presentation_timestamp_(normalize_presentation_timestamp),
presentation_start_time_(kInvalidTime),
earliest_presentation_time_(kInvalidTime),
first_sap_time_(kInvalidTime),
clear_time_(clear_time) {}
MP4Fragmenter::~MP4Fragmenter() {}
@ -78,12 +81,30 @@ Status MP4Fragmenter::AddSample(scoped_refptr<MediaSample> sample) {
data_->AppendArray(sample->data(), sample->data_size());
fragment_duration_ += sample->duration();
if (earliest_presentation_time_ > sample->pts())
earliest_presentation_time_ = sample->pts();
int64 pts = sample->pts();
if (normalize_presentation_timestamp_) {
// Normalize PTS to start from 0. Some players do not like non-zero
// presentation starting time.
// TODO(kqyang): Do we need to add an EditList?
if (presentation_start_time_ == kInvalidTime) {
presentation_start_time_ = pts;
pts = 0;
} else {
// Can we safely assume the first sample in the media has the earliest
// presentation timestamp?
DCHECK_GT(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).
if (earliest_presentation_time_ > pts)
earliest_presentation_time_ = pts;
if (sample->is_key_frame()) {
if (kInvalidTime == first_sap_time_)
first_sap_time_ = sample->pts();
if (first_sap_time_ == kInvalidTime)
first_sap_time_ = pts;
}
return Status::OK;
}

View File

@ -31,11 +31,13 @@ class MP4Fragmenter {
// Caller retains the ownership of |traf| and transfers ownership of
// |encryptor|. |clear_time| specifies clear time in the current track
// timescale. |nalu_length_size| specifies NAL unit length size, for
// subsample encryption.
// subsample encryption. |normalize_presentation_timestamp| defines whether
// PTS should be normalized to start from zero.
MP4Fragmenter(TrackFragment* traf,
scoped_ptr<AesCtrEncryptor> encryptor,
int64 clear_time,
uint8 nalu_length_size);
uint8 nalu_length_size,
bool normalize_presentation_timestamp);
~MP4Fragmenter();
virtual Status AddSample(scoped_refptr<MediaSample> sample);
@ -81,6 +83,8 @@ class MP4Fragmenter {
TrackFragment* traf_;
bool fragment_finalized_;
uint64 fragment_duration_;
bool normalize_presentation_timestamp_;
int64 presentation_start_time_;
uint64 earliest_presentation_time_;
uint64 first_sap_time_;
int64 clear_time_;

View File

@ -70,7 +70,8 @@ Status MP4Segmenter::Initialize(EncryptorSource* encryptor_source,
&moof_->tracks[i],
encryptor.Pass(),
clear_lead_in_seconds * streams[i]->info()->time_scale(),
nalu_length_size);
nalu_length_size,
options_.normalize_presentation_timestamp);
}
// Choose the first stream if there is no VIDEO.