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:
parent
1e79eeb086
commit
522048b0d9
|
@ -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 "
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue