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.
--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
used per segment; if -1, no SIDX box is used; Otherwise, the muxer packs N
subsegments in the root SIDX of the segment, with
segment_duration/N/fragment_duration fragments per subsegment.
For MP4 with DASH live profile only: Indicates whether to generate 'sidx'
box in media segments. Note that it is reuqired by spec if segment template
contains $Time$ specifier.

View File

@ -29,14 +29,11 @@ DEFINE_bool(fragment_sap_aligned,
true,
"Force fragments to begin with stream access points. This flag "
"implies segment_sap_aligned.");
DEFINE_int32(num_subsegments_per_sidx,
1,
"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 packs N "
"subsegments in the root SIDX of the segment, with "
"segment_duration/N/fragment_duration fragments per "
"subsegment.");
DEFINE_bool(generate_sidx_in_media_segments,
true,
"For ISO BMFF with DASH live profile only. Indicates whether to "
"generate 'sidx' box in media segments. Note that it is required "
"by spec if segment template contains $Time$ specifier.");
DEFINE_string(temp_dir,
"",
"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_double(fragment_duration);
DECLARE_bool(fragment_sap_aligned);
DECLARE_int32(num_subsegments_per_sidx);
DECLARE_bool(generate_sidx_in_media_segments);
DECLARE_string(temp_dir);
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;
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;
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,
false,
"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
// 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;
}
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(single_segment, &InformRetiredDefaultTrueFlag);
DEFINE_validator(webm_subsample_encryption, &InformRetiredDefaultTrueFlag);
@ -68,3 +78,4 @@ DEFINE_validator(playready_key_id, &InformRetiredStringFlag);
DEFINE_validator(playready_key, &InformRetiredStringFlag);
DEFINE_validator(mp4_use_decoding_timestamp_in_timeline,
&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);
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) {
muxer_options->mp4_params.num_subsegments_per_sidx = 0;
muxer_options->output_file_name = "liveinit.mp4";
muxer_options->segment_template = "live-$NUMBER$.mp4";
muxer_options->temp_dir.clear();

View File

@ -87,7 +87,6 @@ OnMediaEndParameters GetDefaultOnMediaEndParams() {
}
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->segment_template.clear();
muxer_options->temp_dir.clear();

View File

@ -68,63 +68,6 @@ Status MultiSegmentSegmenter::DoFinalize() {
}
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();
}
@ -172,9 +115,15 @@ Status MultiSegmentSegmenter::WriteSegment() {
styp_->Write(buffer.get());
}
// If num_subsegments_per_sidx is negative, no SIDX box is generated.
if (options().mp4_params.num_subsegments_per_sidx >= 0)
if (options().mp4_params.generate_sidx_in_media_segments) {
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());
}
const size_t segment_header_size = buffer->Size();
const size_t segment_size = segment_header_size + fragment_buffer()->Size();

View File

@ -15,19 +15,11 @@ namespace mp4 {
struct SegmentType;
/// Segmenter for MP4 live, main and simple profiles. The generated media file
/// can contain one or many segments with segment duration defined by @b
/// MuxerOptions.segment_duration. A segment can contain one or many
/// subsegments defined by @b num_subsegments_per_sidx. A subsegment can
/// contain one or many fragments with fragment duration defined by @b
/// 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.
/// Segmenter for MP4 live, main and simple profiles. There can be multiple
/// media segments, which can contain multiple fragments. 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 {
public:
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
/// overall subsegment/fragment duration not smaller than defined duration and
/// yet meet SAP requirements. SingleSegmentSegmenter ignores @b
/// MuxerOptions.num_subsegments_per_sidx.
/// MuxerOptions.mp4_params.generate_sidx_in_media_segments.
class SingleSegmentSegmenter : public Segmenter {
public:
SingleSegmentSegmenter(const MuxerOptions& options,

View File

@ -11,19 +11,15 @@ namespace shaka {
/// MP4 (ISO-BMFF) output related parameters.
struct Mp4OutputParams {
// Include pssh in the encrypted stream. CMAF and DASH-IF recommends carrying
// license acquisition information in the manifest and not duplicate the
// information in the stream. (This is not a hard requirement so we are still
// CMAF compatible even if pssh is included in the stream.)
/// Include pssh in the encrypted stream. CMAF and DASH-IF recommends carrying
/// license acquisition information in the manifest and not duplicate the
/// information in the stream. (This is not a hard requirement so we are still
/// CMAF compatible even if pssh is included in the stream.)
bool include_pssh_in_stream = true;
/// 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
/// will pack N subsegments in the root SIDX of the segment, with
/// segment_duration/N/subsegment_duration fragments per subsegment.
/// 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;
/// Indicates whether a 'sidx' box should be generated in the media segments.
/// Note that it is required by spec if segment_template contains $Times$
/// specifier.
bool generate_sidx_in_media_segments = true;
};
} // namespace shaka