Drepcate --num_subsegments_per_sidx

This flag was designed for two purpose:
- Grouping fragments into subsegments, achieving three level hierarchy:
  segment < subsegment < fragment.
- Indicate whether to generate 'sidx' box in media segments (when the
  value is set to a negative number).

There are no practical use case for the first purpose. Removing it to
simplify the code and reduce the confusion.

Introduce another flag --generate_sidx_in_media_segments for the second
purpose.

Change-Id: I4be7cd42662fb324c1158b978e05768ee49dd048
This commit is contained in:
KongQun Yang 2018-06-15 11:59:02 -07:00
parent f089d1d0d4
commit 1742e03471
12 changed files with 47 additions and 102 deletions

View File

@ -9,9 +9,9 @@ MP4 output options
Deprecated. Do not use. Deprecated. Do not use.
--num_subsegments_per_sidx <number> --generate_sidx_in_media_segments
--nogenerate_sidx_in_media_segments
Set the number of subsegments in each SIDX box. If 0, a single SIDX box is For MP4 with DASH live profile only: Indicates whether to generate 'sidx'
used per segment; if -1, no SIDX box is used; Otherwise, the muxer packs N box in media segments. Note that it is reuqired by spec if segment template
subsegments in the root SIDX of the segment, with contains $Time$ specifier.
segment_duration/N/fragment_duration fragments per subsegment.

View File

@ -29,14 +29,11 @@ DEFINE_bool(fragment_sap_aligned,
true, true,
"Force fragments to begin with stream access points. This flag " "Force fragments to begin with stream access points. This flag "
"implies segment_sap_aligned."); "implies segment_sap_aligned.");
DEFINE_int32(num_subsegments_per_sidx, DEFINE_bool(generate_sidx_in_media_segments,
1, true,
"For ISO BMFF only. Set the number of subsegments in each " "For ISO BMFF with DASH live profile only. Indicates whether to "
"SIDX box. If 0, a single SIDX box is used per segment; if " "generate 'sidx' box in media segments. Note that it is required "
"-1, no SIDX box is used; Otherwise, the muxer packs N " "by spec if segment template contains $Time$ specifier.");
"subsegments in the root SIDX of the segment, with "
"segment_duration/N/fragment_duration fragments per "
"subsegment.");
DEFINE_string(temp_dir, DEFINE_string(temp_dir,
"", "",
"Specify a directory in which to store temporary (intermediate) " "Specify a directory in which to store temporary (intermediate) "

View File

@ -16,7 +16,7 @@ DECLARE_double(segment_duration);
DECLARE_bool(segment_sap_aligned); DECLARE_bool(segment_sap_aligned);
DECLARE_double(fragment_duration); DECLARE_double(fragment_duration);
DECLARE_bool(fragment_sap_aligned); DECLARE_bool(fragment_sap_aligned);
DECLARE_int32(num_subsegments_per_sidx); DECLARE_bool(generate_sidx_in_media_segments);
DECLARE_string(temp_dir); DECLARE_string(temp_dir);
DECLARE_bool(mp4_include_pssh_in_stream); DECLARE_bool(mp4_include_pssh_in_stream);

View File

@ -377,7 +377,8 @@ base::Optional<PackagingParams> GetPackagingParams() {
} }
Mp4OutputParams& mp4_params = packaging_params.mp4_output_params; Mp4OutputParams& mp4_params = packaging_params.mp4_output_params;
mp4_params.num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx; mp4_params.generate_sidx_in_media_segments =
FLAGS_generate_sidx_in_media_segments;
mp4_params.include_pssh_in_stream = FLAGS_mp4_include_pssh_in_stream; mp4_params.include_pssh_in_stream = FLAGS_mp4_include_pssh_in_stream;
packaging_params.output_media_info = FLAGS_output_media_info; packaging_params.output_media_info = FLAGS_output_media_info;

View File

@ -31,6 +31,10 @@ DEFINE_string(playready_key,
DEFINE_bool(mp4_use_decoding_timestamp_in_timeline, DEFINE_bool(mp4_use_decoding_timestamp_in_timeline,
false, false,
"This flag is deprecated. Do not use."); "This flag is deprecated. Do not use.");
DEFINE_int32(
num_subsegments_per_sidx,
0,
"This flag is deprecated. Use --generate_sidx_in_media_segments instead.");
// The current gflags library does not provide a way to check whether a flag is // The current gflags library does not provide a way to check whether a flag is
// set in command line. If a flag has a different value to its default value, // set in command line. If a flag has a different value to its default value,
@ -60,6 +64,12 @@ bool InformRetiredDefaultDoubleFlag(const char* flagname, double value) {
return true; return true;
} }
bool InformRetiredDefaultInt32Flag(const char* flagname, int32_t value) {
if (value != 0)
fprintf(stderr, "WARNING: %s is deprecated and ignored.\n", flagname);
return true;
}
DEFINE_validator(profile, &InformRetiredStringFlag); DEFINE_validator(profile, &InformRetiredStringFlag);
DEFINE_validator(single_segment, &InformRetiredDefaultTrueFlag); DEFINE_validator(single_segment, &InformRetiredDefaultTrueFlag);
DEFINE_validator(webm_subsample_encryption, &InformRetiredDefaultTrueFlag); DEFINE_validator(webm_subsample_encryption, &InformRetiredDefaultTrueFlag);
@ -68,3 +78,4 @@ DEFINE_validator(playready_key_id, &InformRetiredStringFlag);
DEFINE_validator(playready_key, &InformRetiredStringFlag); DEFINE_validator(playready_key, &InformRetiredStringFlag);
DEFINE_validator(mp4_use_decoding_timestamp_in_timeline, DEFINE_validator(mp4_use_decoding_timestamp_in_timeline,
&InformRetiredDefaultFalseFlag); &InformRetiredDefaultFalseFlag);
DEFINE_validator(num_subsegments_per_sidx, &InformRetiredDefaultInt32Flag);

View File

@ -13,3 +13,4 @@ DECLARE_double(availability_time_offset);
DECLARE_string(playready_key_id); DECLARE_string(playready_key_id);
DECLARE_string(playready_key); DECLARE_string(playready_key);
DECLARE_bool(mp4_use_decoding_timestamp_in_timeline); DECLARE_bool(mp4_use_decoding_timestamp_in_timeline);
DECLARE_int32(num_subsegments_per_sidx);

View File

@ -46,7 +46,6 @@ MediaInfo ConvertToMediaInfo(const std::string& media_info_string) {
} }
void SetDefaultLiveMuxerOptions(media::MuxerOptions* muxer_options) { void SetDefaultLiveMuxerOptions(media::MuxerOptions* muxer_options) {
muxer_options->mp4_params.num_subsegments_per_sidx = 0;
muxer_options->output_file_name = "liveinit.mp4"; muxer_options->output_file_name = "liveinit.mp4";
muxer_options->segment_template = "live-$NUMBER$.mp4"; muxer_options->segment_template = "live-$NUMBER$.mp4";
muxer_options->temp_dir.clear(); muxer_options->temp_dir.clear();

View File

@ -87,7 +87,6 @@ OnMediaEndParameters GetDefaultOnMediaEndParams() {
} }
void SetDefaultMuxerOptions(MuxerOptions* muxer_options) { void SetDefaultMuxerOptions(MuxerOptions* muxer_options) {
muxer_options->mp4_params.num_subsegments_per_sidx = 0;
muxer_options->output_file_name = "test_output_file_name.mp4"; muxer_options->output_file_name = "test_output_file_name.mp4";
muxer_options->segment_template.clear(); muxer_options->segment_template.clear();
muxer_options->temp_dir.clear(); muxer_options->temp_dir.clear();

View File

@ -68,63 +68,6 @@ Status MultiSegmentSegmenter::DoFinalize() {
} }
Status MultiSegmentSegmenter::DoFinalizeSegment() { Status MultiSegmentSegmenter::DoFinalizeSegment() {
DCHECK(sidx());
// earliest_presentation_time is the earliest presentation time of any
// access unit in the reference stream in the first subsegment.
// It will be re-calculated later when subsegments are finalized.
sidx()->earliest_presentation_time =
sidx()->references[0].earliest_presentation_time;
if (options().mp4_params.num_subsegments_per_sidx <= 0)
return WriteSegment();
// sidx() contains pre-generated segment references with one reference per
// fragment. Calculate |num_fragments_per_subsegment| and combine
// pre-generated references into final subsegment references.
size_t num_fragments = sidx()->references.size();
size_t num_fragments_per_subsegment =
(num_fragments - 1) / options().mp4_params.num_subsegments_per_sidx + 1;
if (num_fragments_per_subsegment <= 1)
return WriteSegment();
size_t frag_index = 0;
size_t subseg_index = 0;
std::vector<SegmentReference>& refs = sidx()->references;
uint64_t first_sap_time =
refs[0].sap_delta_time + refs[0].earliest_presentation_time;
for (size_t i = 1; i < num_fragments; ++i) {
refs[subseg_index].referenced_size += refs[i].referenced_size;
refs[subseg_index].subsegment_duration += refs[i].subsegment_duration;
refs[subseg_index].earliest_presentation_time =
std::min(refs[subseg_index].earliest_presentation_time,
refs[i].earliest_presentation_time);
if (refs[subseg_index].sap_type == SegmentReference::TypeUnknown &&
refs[i].sap_type != SegmentReference::TypeUnknown) {
refs[subseg_index].sap_type = refs[i].sap_type;
first_sap_time =
refs[i].sap_delta_time + refs[i].earliest_presentation_time;
}
if (++frag_index >= num_fragments_per_subsegment) {
// Calculate sap delta time w.r.t. sidx_->earliest_presentation_time.
if (refs[subseg_index].sap_type != SegmentReference::TypeUnknown) {
refs[subseg_index].sap_delta_time =
first_sap_time - refs[subseg_index].earliest_presentation_time;
}
if (++i >= num_fragments)
break;
refs[++subseg_index] = refs[i];
first_sap_time =
refs[i].sap_delta_time + refs[i].earliest_presentation_time;
frag_index = 1;
}
}
refs.resize(options().mp4_params.num_subsegments_per_sidx);
// earliest_presentation_time is the earliest presentation time of any
// access unit in the reference stream in the first subsegment.
sidx()->earliest_presentation_time = refs[0].earliest_presentation_time;
return WriteSegment(); return WriteSegment();
} }
@ -172,9 +115,15 @@ Status MultiSegmentSegmenter::WriteSegment() {
styp_->Write(buffer.get()); styp_->Write(buffer.get());
} }
// If num_subsegments_per_sidx is negative, no SIDX box is generated. if (options().mp4_params.generate_sidx_in_media_segments) {
if (options().mp4_params.num_subsegments_per_sidx >= 0) DCHECK(sidx());
DCHECK(!sidx()->references.empty());
// earliest_presentation_time is the earliest presentation time of any
// access unit in the reference stream in the first subsegment.
sidx()->earliest_presentation_time =
sidx()->references[0].earliest_presentation_time;
sidx()->Write(buffer.get()); sidx()->Write(buffer.get());
}
const size_t segment_header_size = buffer->Size(); const size_t segment_header_size = buffer->Size();
const size_t segment_size = segment_header_size + fragment_buffer()->Size(); const size_t segment_size = segment_header_size + fragment_buffer()->Size();

View File

@ -15,19 +15,11 @@ namespace mp4 {
struct SegmentType; struct SegmentType;
/// Segmenter for MP4 live, main and simple profiles. The generated media file /// Segmenter for MP4 live, main and simple profiles. There can be multiple
/// can contain one or many segments with segment duration defined by @b /// media segments, which can contain multiple fragments. The generated segments
/// MuxerOptions.segment_duration. A segment can contain one or many /// are written to files defined by @b MuxerOptions.segment_template if
/// subsegments defined by @b num_subsegments_per_sidx. A subsegment can /// specified; otherwise, the segments are appended to the main output file
/// contain one or many fragments with fragment duration defined by @b /// specified by @b MuxerOptions.output_file_name.
/// MuxerOptions.fragment_duration. The actual segment or fragment duration
/// may not match the requested duration exactly, but will be approximated.
/// That is, the Segmenter tries to end segment/fragment at the first sample
/// with overall segment/fragment duration not smaller than defined duration
/// and yet meet SAP requirements. The generated segments are written to files
/// defined by @b MuxerOptions.segment_template if specified; otherwise,
/// the segments are appended to the main output file specified by @b
/// MuxerOptions.output_file_name.
class MultiSegmentSegmenter : public Segmenter { class MultiSegmentSegmenter : public Segmenter {
public: public:
MultiSegmentSegmenter(const MuxerOptions& options, MultiSegmentSegmenter(const MuxerOptions& options,

View File

@ -25,7 +25,7 @@ namespace mp4 {
/// is, the Segmenter tries to end subsegment/fragment at the first sample with /// is, the Segmenter tries to end subsegment/fragment at the first sample with
/// overall subsegment/fragment duration not smaller than defined duration and /// overall subsegment/fragment duration not smaller than defined duration and
/// yet meet SAP requirements. SingleSegmentSegmenter ignores @b /// yet meet SAP requirements. SingleSegmentSegmenter ignores @b
/// MuxerOptions.num_subsegments_per_sidx. /// MuxerOptions.mp4_params.generate_sidx_in_media_segments.
class SingleSegmentSegmenter : public Segmenter { class SingleSegmentSegmenter : public Segmenter {
public: public:
SingleSegmentSegmenter(const MuxerOptions& options, SingleSegmentSegmenter(const MuxerOptions& options,

View File

@ -11,19 +11,15 @@ namespace shaka {
/// MP4 (ISO-BMFF) output related parameters. /// MP4 (ISO-BMFF) output related parameters.
struct Mp4OutputParams { struct Mp4OutputParams {
// Include pssh in the encrypted stream. CMAF and DASH-IF recommends carrying /// Include pssh in the encrypted stream. CMAF and DASH-IF recommends carrying
// license acquisition information in the manifest and not duplicate the /// license acquisition information in the manifest and not duplicate the
// information in the stream. (This is not a hard requirement so we are still /// information in the stream. (This is not a hard requirement so we are still
// CMAF compatible even if pssh is included in the stream.) /// CMAF compatible even if pssh is included in the stream.)
bool include_pssh_in_stream = true; bool include_pssh_in_stream = true;
/// Set the number of subsegments in each SIDX box. If 0, a single SIDX box /// Indicates whether a 'sidx' box should be generated in the media segments.
/// is used per segment. If -1, no SIDX box is used. Otherwise, the Muxer /// Note that it is required by spec if segment_template contains $Times$
/// will pack N subsegments in the root SIDX of the segment, with /// specifier.
/// segment_duration/N/subsegment_duration fragments per subsegment. bool generate_sidx_in_media_segments = true;
/// This flag is ingored for DASH MPD with on-demand profile.
static constexpr int kNoSidxBoxInSegment = -1;
static constexpr int kSingleSidxPerSegment = 0;
int num_subsegments_per_sidx = kSingleSidxPerSegment;
}; };
} // namespace shaka } // namespace shaka