diff --git a/docs/source/options/mp4_output_options.rst b/docs/source/options/mp4_output_options.rst index b8cc84da84..582f4cb5d6 100644 --- a/docs/source/options/mp4_output_options.rst +++ b/docs/source/options/mp4_output_options.rst @@ -9,9 +9,9 @@ MP4 output options Deprecated. Do not use. ---num_subsegments_per_sidx +--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. diff --git a/packager/app/muxer_flags.cc b/packager/app/muxer_flags.cc index 4c31fbdb00..37acec6b0b 100644 --- a/packager/app/muxer_flags.cc +++ b/packager/app/muxer_flags.cc @@ -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) " diff --git a/packager/app/muxer_flags.h b/packager/app/muxer_flags.h index 608529a351..73df416837 100644 --- a/packager/app/muxer_flags.h +++ b/packager/app/muxer_flags.h @@ -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); diff --git a/packager/app/packager_main.cc b/packager/app/packager_main.cc index f04c235987..5dba8f1802 100644 --- a/packager/app/packager_main.cc +++ b/packager/app/packager_main.cc @@ -377,7 +377,8 @@ base::Optional 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; diff --git a/packager/app/retired_flags.cc b/packager/app/retired_flags.cc index 8b6c80d2c3..b2c6be8e0f 100644 --- a/packager/app/retired_flags.cc +++ b/packager/app/retired_flags.cc @@ -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); diff --git a/packager/app/retired_flags.h b/packager/app/retired_flags.h index bbe235f670..679fe958c9 100644 --- a/packager/app/retired_flags.h +++ b/packager/app/retired_flags.h @@ -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); diff --git a/packager/media/event/mpd_notify_muxer_listener_unittest.cc b/packager/media/event/mpd_notify_muxer_listener_unittest.cc index 52540ac036..5323d6a33d 100644 --- a/packager/media/event/mpd_notify_muxer_listener_unittest.cc +++ b/packager/media/event/mpd_notify_muxer_listener_unittest.cc @@ -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(); diff --git a/packager/media/event/muxer_listener_test_helper.cc b/packager/media/event/muxer_listener_test_helper.cc index e57136fb1e..2c2703fbd5 100644 --- a/packager/media/event/muxer_listener_test_helper.cc +++ b/packager/media/event/muxer_listener_test_helper.cc @@ -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(); diff --git a/packager/media/formats/mp4/multi_segment_segmenter.cc b/packager/media/formats/mp4/multi_segment_segmenter.cc index cf257012c4..0ae18cb13f 100644 --- a/packager/media/formats/mp4/multi_segment_segmenter.cc +++ b/packager/media/formats/mp4/multi_segment_segmenter.cc @@ -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& 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(); diff --git a/packager/media/formats/mp4/multi_segment_segmenter.h b/packager/media/formats/mp4/multi_segment_segmenter.h index 5fff12d6c3..b1c524da21 100644 --- a/packager/media/formats/mp4/multi_segment_segmenter.h +++ b/packager/media/formats/mp4/multi_segment_segmenter.h @@ -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, diff --git a/packager/media/formats/mp4/single_segment_segmenter.h b/packager/media/formats/mp4/single_segment_segmenter.h index 37268c2e8f..4659f35435 100644 --- a/packager/media/formats/mp4/single_segment_segmenter.h +++ b/packager/media/formats/mp4/single_segment_segmenter.h @@ -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, diff --git a/packager/media/public/mp4_output_params.h b/packager/media/public/mp4_output_params.h index dd963cea18..0d286b0d6c 100644 --- a/packager/media/public/mp4_output_params.h +++ b/packager/media/public/mp4_output_params.h @@ -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