Add a runtime flag to use dts in timeline for mp4

This flag is needed to workaround the Chromium bug
https://crbug.com/398130, which uses decoding timestamp
in buffered range.

Closes #113

Change-Id: Ib8f18be7165dd968bdc36c18ce29f694235c0c26
This commit is contained in:
Kongqun Yang 2016-07-12 13:48:28 -07:00 committed by KongQun Yang
parent a80995538d
commit fae7874c4c
7 changed files with 55 additions and 11 deletions

View File

@ -25,6 +25,12 @@
#include "packager/media/file/file.h" #include "packager/media/file/file.h"
#include "packager/mpd/base/mpd_builder.h" #include "packager/mpd/base/mpd_builder.h"
DEFINE_bool(mp4_use_decoding_timestamp_in_timeline,
false,
"If set, decoding timestamp instead of presentation timestamp will "
"be used when generating media timeline, e.g. timestamps in sidx "
"and mpd. This is to workaround a Chromium bug that decoding "
"timestamp is used in buffered range, https://crbug.com/398130.");
DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info."); DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info.");
namespace shaka { namespace shaka {
@ -148,6 +154,16 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) {
muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned; muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned;
muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned; muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned;
muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx; muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
if (FLAGS_mp4_use_decoding_timestamp_in_timeline) {
LOG(WARNING) << "Flag --mp4_use_decoding_timestamp_in_timeline is set. "
"Note that it is a temporary hack to workaround Chromium "
"bug https://crbug.com/398130. The flag may be removed "
"when the Chromium bug is fixed.";
}
muxer_options->mp4_use_decoding_timestamp_in_timeline =
FLAGS_mp4_use_decoding_timestamp_in_timeline;
muxer_options->temp_dir = FLAGS_temp_dir; muxer_options->temp_dir = FLAGS_temp_dir;
return true; return true;
} }

View File

@ -16,6 +16,7 @@ MuxerOptions::MuxerOptions()
segment_sap_aligned(false), segment_sap_aligned(false),
fragment_sap_aligned(false), fragment_sap_aligned(false),
num_subsegments_per_sidx(0), num_subsegments_per_sidx(0),
mp4_use_decoding_timestamp_in_timeline(false),
bandwidth(0) {} bandwidth(0) {}
MuxerOptions::~MuxerOptions() {} MuxerOptions::~MuxerOptions() {}

View File

@ -49,6 +49,13 @@ struct MuxerOptions {
/// segment_duration/N/fragment_duration fragments per subsegment. /// segment_duration/N/fragment_duration fragments per subsegment.
int num_subsegments_per_sidx; int num_subsegments_per_sidx;
/// For ISO BMFF only.
/// Set the flag use_decoding_timestamp_in_timeline, which if set to true, use
/// decoding timestamp instead of presentation timestamp in media timeline,
/// which is needed to workaround a Chromium bug that decoding timestamp is
/// used in buffered range, https://crbug.com/398130.
bool mp4_use_decoding_timestamp_in_timeline;
/// Output file name. If segment_template is not specified, the Muxer /// Output file name. If segment_template is not specified, the Muxer
/// generates this single output file with all segments concatenated; /// generates this single output file with all segments concatenated;
/// Otherwise, it specifies the init segment name. /// Otherwise, it specifies the init segment name.

View File

@ -6,9 +6,9 @@
#include "packager/media/file/file.h" #include "packager/media/file/file.h"
#include <gflags/gflags.h>
#include <algorithm> #include <algorithm>
#include <gflags/gflags.h>
#include "packager/base/logging.h" #include "packager/base/logging.h"
#include "packager/base/memory/scoped_ptr.h" #include "packager/base/memory/scoped_ptr.h"
#include "packager/media/file/local_file.h" #include "packager/media/file/local_file.h"

View File

@ -21,7 +21,8 @@ namespace {
const int64_t kInvalidTime = std::numeric_limits<int64_t>::max(); const int64_t kInvalidTime = std::numeric_limits<int64_t>::max();
uint64_t GetSeekPreroll(const StreamInfo& stream_info) { uint64_t GetSeekPreroll(const StreamInfo& stream_info) {
if (stream_info.stream_type() != kStreamAudio) return 0; if (stream_info.stream_type() != kStreamAudio)
return 0;
const AudioStreamInfo& audio_stream_info = const AudioStreamInfo& audio_stream_info =
static_cast<const AudioStreamInfo&>(stream_info); static_cast<const AudioStreamInfo&>(stream_info);
return audio_stream_info.seek_preroll_ns(); return audio_stream_info.seek_preroll_ns();
@ -29,7 +30,8 @@ uint64_t GetSeekPreroll(const StreamInfo& stream_info) {
} // namespace } // namespace
Fragmenter::Fragmenter(scoped_refptr<StreamInfo> info, TrackFragment* traf) Fragmenter::Fragmenter(scoped_refptr<StreamInfo> info, TrackFragment* traf)
: traf_(traf), : use_decoding_timestamp_in_timeline_(false),
traf_(traf),
seek_preroll_(GetSeekPreroll(*info)), seek_preroll_(GetSeekPreroll(*info)),
fragment_initialized_(false), fragment_initialized_(false),
fragment_finalized_(false), fragment_finalized_(false),
@ -64,15 +66,17 @@ Status Fragmenter::AddSample(scoped_refptr<MediaSample> sample) {
data_->AppendArray(sample->data(), sample->data_size()); data_->AppendArray(sample->data(), sample->data_size());
fragment_duration_ += sample->duration(); fragment_duration_ += sample->duration();
int64_t pts = sample->pts(); const int64_t pts = sample->pts();
const int64_t dts = sample->dts();
// Set |earliest_presentation_time_| to |pts| if |pts| is smaller or if it is const int64_t timestamp = use_decoding_timestamp_in_timeline_ ? dts : pts;
// not yet initialized (kInvalidTime > pts is always true). // Set |earliest_presentation_time_| to |timestamp| if |timestamp| is smaller
if (earliest_presentation_time_ > pts) // or if it is not yet initialized (kInvalidTime > timestamp is always true).
earliest_presentation_time_ = pts; if (earliest_presentation_time_ > timestamp)
earliest_presentation_time_ = timestamp;
traf_->runs[0].sample_composition_time_offsets.push_back(pts - sample->dts()); traf_->runs[0].sample_composition_time_offsets.push_back(pts - dts);
if (pts != sample->dts()) if (pts != dts)
traf_->runs[0].flags |= TrackFragmentRun::kSampleCompTimeOffsetsPresentMask; traf_->runs[0].flags |= TrackFragmentRun::kSampleCompTimeOffsetsPresentMask;
if (sample->is_key_frame()) { if (sample->is_key_frame()) {
@ -141,7 +145,8 @@ void Fragmenter::FinalizeFragment() {
sample_to_group_entry.group_description_index = sample_to_group_entry.group_description_index =
SampleToGroupEntry::kTrackGroupDescriptionIndexBase + 1; SampleToGroupEntry::kTrackGroupDescriptionIndexBase + 1;
} }
for (const auto& sample_group_description : traf_->sample_group_descriptions) { for (const auto& sample_group_description :
traf_->sample_group_descriptions) {
traf_->sample_to_groups.resize(traf_->sample_to_groups.size() + 1); traf_->sample_to_groups.resize(traf_->sample_to_groups.size() + 1);
SampleToGroup& sample_to_group = traf_->sample_to_groups.back(); SampleToGroup& sample_to_group = traf_->sample_to_groups.back();
sample_to_group.grouping_type = sample_group_description.grouping_type; sample_to_group.grouping_type = sample_group_description.grouping_type;

View File

@ -62,6 +62,15 @@ class Fragmenter {
bool fragment_finalized() const { return fragment_finalized_; } bool fragment_finalized() const { return fragment_finalized_; }
BufferWriter* data() { return data_.get(); } BufferWriter* data() { return data_.get(); }
/// Set the flag use_decoding_timestamp_in_timeline, which if set to true, use
/// decoding timestamp instead of presentation timestamp in media timeline,
/// which is needed to workaround a Chromium bug that decoding timestamp is
/// used in buffered range, https://crbug.com/398130.
void set_use_decoding_timestamp_in_timeline(
bool use_decoding_timestamp_in_timeline) {
use_decoding_timestamp_in_timeline_ = use_decoding_timestamp_in_timeline;
}
protected: protected:
TrackFragment* traf() { return traf_; } TrackFragment* traf() { return traf_; }
@ -75,6 +84,7 @@ class Fragmenter {
// Check if the current fragment starts with SAP. // Check if the current fragment starts with SAP.
bool StartsWithSAP(); bool StartsWithSAP();
bool use_decoding_timestamp_in_timeline_;
TrackFragment* traf_; TrackFragment* traf_;
uint64_t seek_preroll_; uint64_t seek_preroll_;
bool fragment_initialized_; bool fragment_initialized_;

View File

@ -264,6 +264,11 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
muxer_listener_); muxer_listener_);
} }
if (options_.mp4_use_decoding_timestamp_in_timeline) {
for (uint32_t i = 0; i < streams.size(); ++i)
fragmenters_[i]->set_use_decoding_timestamp_in_timeline(true);
}
// Choose the first stream if there is no VIDEO. // Choose the first stream if there is no VIDEO.
if (sidx_->reference_id == 0) if (sidx_->reference_id == 0)
sidx_->reference_id = 1; sidx_->reference_id = 1;