diff --git a/modules/demux/smooth/playlist/ForgedInitSegment.cpp b/modules/demux/smooth/playlist/ForgedInitSegment.cpp index 8375e0a243a9dd17627629361e23a6e4eb47a5b0..a4fa11e2587c2be7d16d49c8fe1a4701f4c2c002 100644 --- a/modules/demux/smooth/playlist/ForgedInitSegment.cpp +++ b/modules/demux/smooth/playlist/ForgedInitSegment.cpp @@ -283,11 +283,7 @@ block_t * ForgedInitSegment::buildMoovBox() 0x01, /* Will always be 1st and unique track; tfhd patched on block read */ &fmt, (uint32_t) trackTimescale); if(p_track) - { - p_track->i_read_duration = duration.Get(); - p_track->i_trex_default_length = 1; - p_track->i_trex_default_size = 1; - } + mp4mux_track_ForceDuration(p_track, duration.Get()); } box = mp4mux_GetMoov(muxh, NULL, trackTimescale.ToTime(duration.Get())); diff --git a/modules/mux/mp4/libmp4mux.c b/modules/mux/mp4/libmp4mux.c index 88dfaa348c39a82fce5af4274dad4bc36f9fd164..d4cc8218c17efa90e101e09f917c3c3fa0bfdebd 100644 --- a/modules/mux/mp4/libmp4mux.c +++ b/modules/mux/mp4/libmp4mux.c @@ -39,6 +39,38 @@ #include <assert.h> #include <time.h> +struct mp4mux_trackinfo_t +{ + unsigned i_track_id; + es_format_t fmt; + + /* index */ + unsigned int i_samples_count; + unsigned int i_samples_max; + mp4mux_sample_t *samples; + + /* XXX: needed for other codecs too, see lavf */ + struct + { + size_t i_data; + uint8_t *p_data; + } sample_priv; + + /* stats */ + vlc_tick_t i_read_duration; + uint32_t i_timescale; + bool b_hasbframes; + + /* frags */ + vlc_tick_t i_trex_default_length; + uint32_t i_trex_default_size; + + /* edit list */ + unsigned int i_edits_count; + mp4mux_edit_t *p_edits; + +}; + struct mp4mux_handle_t { unsigned options; @@ -60,8 +92,7 @@ static bool mp4mux_trackinfo_Init(mp4mux_trackinfo_t *p_stream, unsigned i_id, static void mp4mux_trackinfo_Clear(mp4mux_trackinfo_t *p_stream) { es_format_Clean(&p_stream->fmt); - if (p_stream->a52_frame) - block_Release(p_stream->a52_frame); + mp4mux_track_SetSamplePriv(p_stream, NULL, 0); free(p_stream->samples); free(p_stream->p_edits); } @@ -77,7 +108,6 @@ mp4mux_trackinfo_t * mp4mux_track_Add(mp4mux_handle_t *h, unsigned id, } t->i_track_id = id; t->i_timescale = timescale; - t->i_firstdts = VLC_TICK_INVALID; es_format_Init(&t->fmt, fmt->i_cat, fmt->i_codec); es_format_Copy(&t->fmt, fmt); vlc_array_append(&h->tracks, t); @@ -129,16 +159,102 @@ bool mp4mux_track_AddSample(mp4mux_trackinfo_t *t, const mp4mux_sample_t *entry) t->i_samples_max += 1000; } t->samples[t->i_samples_count++] = *entry; + if(!t->b_hasbframes && entry->i_pts_dts != 0) + t->b_hasbframes = true; + t->i_read_duration += __MAX(0, entry->i_length); return true; } -mp4mux_sample_t *mp4mux_track_GetLastSample(mp4mux_trackinfo_t *t) +const mp4mux_sample_t *mp4mux_track_GetLastSample(const mp4mux_trackinfo_t *t) { if(t->i_samples_count) return &t->samples[t->i_samples_count - 1]; else return NULL; } +unsigned mp4mux_track_GetSampleCount(const mp4mux_trackinfo_t *t) +{ + return t->i_samples_count; +} + +void mp4mux_track_UpdateLastSample(mp4mux_trackinfo_t *t, + const mp4mux_sample_t *entry) +{ + if(t->i_samples_count) + { + mp4mux_sample_t *e = &t->samples[t->i_samples_count - 1]; + t->i_read_duration -= e->i_length; + t->i_read_duration += entry->i_length; + *e = *entry; + } +} + +vlc_tick_t mp4mux_track_GetDefaultSampleDuration(const mp4mux_trackinfo_t *t) +{ + return t->i_trex_default_length; +} + +uint32_t mp4mux_track_GetDefaultSampleSize(const mp4mux_trackinfo_t *t) +{ + return t->i_trex_default_size; +} + +bool mp4mux_track_HasBFrames(const mp4mux_trackinfo_t *t) +{ + return t->b_hasbframes; +} + +void mp4mux_track_SetHasBFrames(mp4mux_trackinfo_t *t) +{ + t->b_hasbframes = true; +} + +uint32_t mp4mux_track_GetTimescale(const mp4mux_trackinfo_t *t) +{ + return t->i_timescale; +} + +vlc_tick_t mp4mux_track_GetDuration(const mp4mux_trackinfo_t *t) +{ + return t->i_read_duration; +} + +void mp4mux_track_ForceDuration(mp4mux_trackinfo_t *t, vlc_tick_t d) +{ + t->i_read_duration = d; +} + +uint32_t mp4mux_track_GetID(const mp4mux_trackinfo_t *t) +{ + return t->i_track_id; +} + +void mp4mux_track_SetSamplePriv(mp4mux_trackinfo_t *t, + const uint8_t *p_data, size_t i_data) +{ + if(t->sample_priv.p_data) + { + free(t->sample_priv.p_data); + t->sample_priv.p_data = NULL; + t->sample_priv.i_data = 0; + } + + if(p_data && i_data) + { + t->sample_priv.p_data = malloc(i_data); + if(i_data) + { + memcpy(t->sample_priv.p_data, p_data, i_data); + t->sample_priv.i_data = i_data; + } + } +} + +bool mp4mux_track_HasSamplePriv(const mp4mux_trackinfo_t *t) +{ + return t->sample_priv.i_data != 0; +} + void mp4mux_ShiftSamples(mp4mux_handle_t *h, int64_t offset) { for(size_t i_track = 0; i_track < vlc_array_count(&h->tracks); i_track++) @@ -495,13 +611,14 @@ static bo_t *GetWaveTag(mp4mux_trackinfo_t *p_track) return wave; } -static bo_t *GetDec3Tag(es_format_t *p_fmt, block_t *a52_frame) +static bo_t *GetDec3Tag(es_format_t *p_fmt, + const uint8_t *p_data, size_t i_data) { - if (!a52_frame) + if (!i_data) return NULL; bs_t s; - bs_write_init(&s, a52_frame->p_buffer, sizeof(a52_frame->i_buffer)); + bs_init(&s, p_data, i_data); bs_skip(&s, 16); // syncword uint8_t fscod, bsid, bsmod, acmod, lfeon, strmtyp; @@ -596,7 +713,7 @@ static bo_t *GetDec3Tag(es_format_t *p_fmt, block_t *a52_frame) bsmod = bs_read(&s, 3); uint8_t mp4_eac3_header[5] = {0}; - bs_init(&s, mp4_eac3_header, sizeof(mp4_eac3_header)); + bs_write_init(&s, mp4_eac3_header, sizeof(mp4_eac3_header)); int data_rate = p_fmt->i_bitrate / 1000; bs_write(&s, 13, data_rate); @@ -617,9 +734,9 @@ static bo_t *GetDec3Tag(es_format_t *p_fmt, block_t *a52_frame) return dec3; } -static bo_t *GetDac3Tag(block_t *a52_frame) +static bo_t *GetDac3Tag(const uint8_t *p_data, size_t i_data) { - if (!a52_frame) + if (!i_data) return NULL; bo_t *dac3 = box_new("dac3"); @@ -627,7 +744,7 @@ static bo_t *GetDac3Tag(block_t *a52_frame) return NULL; bs_t s; - bs_init(&s, a52_frame->p_buffer, sizeof(a52_frame->i_buffer)); + bs_init(&s, p_data, i_data); uint8_t fscod, bsid, bsmod, acmod, lfeon, frmsizecod; @@ -650,7 +767,7 @@ static bo_t *GetDac3Tag(block_t *a52_frame) lfeon = bs_read1(&s); uint8_t mp4_a52_header[3]; - bs_init(&s, mp4_a52_header, sizeof(mp4_a52_header)); + bs_write_init(&s, mp4_a52_header, sizeof(mp4_a52_header)); bs_write(&s, 2, fscod); bs_write(&s, 5, bsid); @@ -1085,9 +1202,9 @@ static bo_t *GetSounBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b else if (codec == VLC_CODEC_AMR_NB) box = GetDamrTag(&p_track->fmt); else if (codec == VLC_CODEC_A52) - box = GetDac3Tag(p_track->a52_frame); + box = GetDac3Tag(p_track->sample_priv.p_data, p_track->sample_priv.i_data); else if (codec == VLC_CODEC_EAC3) - box = GetDec3Tag(&p_track->fmt, p_track->a52_frame); + box = GetDec3Tag(&p_track->fmt, p_track->sample_priv.p_data, p_track->sample_priv.i_data); else if (codec == VLC_CODEC_WMAP) box = GetWaveFormatExTag(&p_track->fmt, "wfex"); else @@ -1991,6 +2108,11 @@ bo_t * mp4mux_GetMoov(mp4mux_handle_t *h, vlc_object_t *p_obj, vlc_tick_t i_dura p_stream->i_trex_default_length = p_stream->samples[0].i_length; p_stream->i_trex_default_size = p_stream->samples[0].i_size; } + else + { + p_stream->i_trex_default_length = 1; + p_stream->i_trex_default_size = 1; + } /* *** add /mvex/trex *** */ bo_t *trex = box_full_new("trex", 0, 0); diff --git a/modules/mux/mp4/libmp4mux.h b/modules/mux/mp4/libmp4mux.h index 1da7e88e1bc1c0e1cb02f35ba7eccecdade98b9a..025bc8e8a8274c69dc1dc8f3725b260de42ffe27 100644 --- a/modules/mux/mp4/libmp4mux.h +++ b/modules/mux/mp4/libmp4mux.h @@ -25,52 +25,7 @@ #include <vlc_boxes.h> typedef struct mp4mux_handle_t mp4mux_handle_t; - -typedef struct -{ - uint64_t i_pos; - int i_size; - - vlc_tick_t i_pts_dts; - vlc_tick_t i_length; - unsigned int i_flags; -} mp4mux_sample_t; - -typedef struct -{ - vlc_tick_t i_duration; - vlc_tick_t i_start_time; - vlc_tick_t i_start_offset; -} mp4mux_edit_t; - -typedef struct -{ - unsigned i_track_id; - es_format_t fmt; - - /* index */ - unsigned int i_samples_count; - unsigned int i_samples_max; - mp4mux_sample_t *samples; - - /* XXX: needed for other codecs too, see lavf */ - block_t *a52_frame; - - /* stats */ - vlc_tick_t i_read_duration; - uint32_t i_timescale; - vlc_tick_t i_firstdts; /* the really first packet */ - bool b_hasbframes; - - /* frags */ - vlc_tick_t i_trex_default_length; - uint32_t i_trex_default_size; - - /* edit list */ - unsigned int i_edits_count; - mp4mux_edit_t *p_edits; - -} mp4mux_trackinfo_t; +typedef struct mp4mux_trackinfo_t mp4mux_trackinfo_t; enum mp4mux_options { @@ -86,16 +41,46 @@ bool mp4mux_Is(mp4mux_handle_t *, enum mp4mux_options); mp4mux_trackinfo_t * mp4mux_track_Add(mp4mux_handle_t *, unsigned id, const es_format_t *fmt, uint32_t timescale); +/* Track properties */ +uint32_t mp4mux_track_GetID(const mp4mux_trackinfo_t *); +uint32_t mp4mux_track_GetTimescale(const mp4mux_trackinfo_t *); +vlc_tick_t mp4mux_track_GetDuration(const mp4mux_trackinfo_t *); +void mp4mux_track_ForceDuration(mp4mux_trackinfo_t *, vlc_tick_t); /* Used by frag */ +bool mp4mux_track_HasBFrames(const mp4mux_trackinfo_t *); +void mp4mux_track_SetHasBFrames(mp4mux_trackinfo_t *); +void mp4mux_track_SetSamplePriv(mp4mux_trackinfo_t *, const uint8_t *, size_t); +bool mp4mux_track_HasSamplePriv(const mp4mux_trackinfo_t *); +vlc_tick_t mp4mux_track_GetDefaultSampleDuration(const mp4mux_trackinfo_t *); +uint32_t mp4mux_track_GetDefaultSampleSize(const mp4mux_trackinfo_t *); + /* ELST */ -bool mp4mux_track_AddEdit(mp4mux_trackinfo_t *, const mp4mux_edit_t *); +typedef struct +{ + vlc_tick_t i_duration; + vlc_tick_t i_start_time; + vlc_tick_t i_start_offset; +} mp4mux_edit_t; +bool mp4mux_track_AddEdit(mp4mux_trackinfo_t *, const mp4mux_edit_t *); const mp4mux_edit_t *mp4mux_track_GetLastEdit(const mp4mux_trackinfo_t *); -void mp4mux_track_DebugEdits(vlc_object_t *, const mp4mux_trackinfo_t *); +void mp4mux_track_DebugEdits(vlc_object_t *, const mp4mux_trackinfo_t *); + /* Samples */ -bool mp4mux_track_AddSample(mp4mux_trackinfo_t *, const mp4mux_sample_t *); -mp4mux_sample_t *mp4mux_track_GetLastSample(mp4mux_trackinfo_t *); +typedef struct +{ + uint64_t i_pos; + int i_size; + + vlc_tick_t i_pts_dts; + vlc_tick_t i_length; + unsigned int i_flags; +} mp4mux_sample_t; +bool mp4mux_track_AddSample(mp4mux_trackinfo_t *, const mp4mux_sample_t *); +const mp4mux_sample_t *mp4mux_track_GetLastSample(const mp4mux_trackinfo_t *); +unsigned mp4mux_track_GetSampleCount(const mp4mux_trackinfo_t *); +void mp4mux_track_UpdateLastSample(mp4mux_trackinfo_t *, const mp4mux_sample_t *); bo_t *mp4mux_GetMoov(mp4mux_handle_t *, vlc_object_t *, vlc_tick_t i_movie_duration); -void mp4mux_ShiftSamples(mp4mux_handle_t *, int64_t offset); +void mp4mux_ShiftSamples(mp4mux_handle_t *, int64_t offset); /* old */ diff --git a/modules/mux/mp4/mp4.c b/modules/mux/mp4/mp4.c index 1961cc7ca4057880c68acff04b22c91eb7d01a60..b64f430881c332cf1815b770173d5716844696c0 100644 --- a/modules/mux/mp4/mp4.c +++ b/modules/mux/mp4/mp4.c @@ -128,6 +128,7 @@ typedef struct mp4_fragqueue_t typedef struct { mp4mux_trackinfo_t *tinfo; + const es_format_t *p_fmt; /* index */ vlc_tick_t i_length_neg; @@ -480,6 +481,7 @@ static int AddStream(sout_mux_t *p_mux, sout_input_t *p_input) return VLC_ENOMEM; } + p_stream->p_fmt = p_input->p_fmt; p_stream->i_length_neg = 0; p_stream->i_last_dts = VLC_TICK_INVALID; p_stream->i_last_pts = VLC_TICK_INVALID; @@ -538,7 +540,8 @@ static bool CreateCurrentEdit(mp4_stream_t *p_stream, vlc_tick_t i_mux_start_dts if(p_lastedit != NULL && b_fragmented) return true; - if(p_stream->tinfo->i_samples_count == 0) + const mp4mux_sample_t *p_lastsample = mp4mux_track_GetLastSample(p_stream->tinfo); + if(p_lastsample == NULL) return true; mp4mux_edit_t newedit; @@ -564,8 +567,8 @@ static bool CreateCurrentEdit(mp4_stream_t *p_stream, vlc_tick_t i_mux_start_dts newedit.i_duration = p_stream->i_last_pts - p_stream->i_first_dts; else newedit.i_duration = p_stream->i_last_dts - p_stream->i_first_dts; - if(p_stream->tinfo->i_samples_count) - newedit.i_duration += p_stream->tinfo->samples[p_stream->tinfo->i_samples_count - 1].i_length; + + newedit.i_duration += p_lastsample->i_length; } return mp4mux_track_AddEdit(p_stream->tinfo, &newedit); @@ -577,7 +580,7 @@ static block_t * BlockDequeue(sout_input_t *p_input, mp4_stream_t *p_stream) if(unlikely(!p_block)) return NULL; - switch(p_stream->tinfo->fmt.i_codec) + switch(p_stream->p_fmt->i_codec) { case VLC_CODEC_AV1: p_block = AV1_Pack_Sample(p_block); @@ -591,8 +594,12 @@ static block_t * BlockDequeue(sout_input_t *p_input, mp4_stream_t *p_stream) break; case VLC_CODEC_A52: case VLC_CODEC_EAC3: - if (p_stream->tinfo->a52_frame == NULL && p_block->i_buffer >= 8) - p_stream->tinfo->a52_frame = block_Duplicate(p_block); + if(!mp4mux_track_HasSamplePriv(p_stream->tinfo) && + p_block->i_buffer >= 8) + { + mp4mux_track_SetSamplePriv(p_stream->tinfo, + p_block->p_buffer, p_block->i_buffer); + } break; default: break; @@ -615,7 +622,8 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s return VLC_SUCCESS; /* Reset reference dts in case of discontinuity (ex: gather sout) */ - if (p_data->i_flags & BLOCK_FLAG_DISCONTINUITY && p_stream->tinfo->i_samples_count) + if (p_data->i_flags & BLOCK_FLAG_DISCONTINUITY && + mp4mux_track_GetLastSample(p_stream->tinfo) != NULL) { if(p_stream->i_first_dts != VLC_TICK_INVALID) { @@ -641,7 +649,7 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s p_sys->i_start_dts = p_stream->i_first_dts; } - if (p_stream->tinfo->fmt.i_cat != SPU_ES) + if (p_stream->p_fmt->i_cat != SPU_ES) { /* Fix length of the sample */ if (block_FifoCount(p_input->p_fifo) > 0) @@ -649,29 +657,32 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s block_t *p_next = block_FifoShow(p_input->p_fifo); if ( p_next->i_flags & BLOCK_FLAG_DISCONTINUITY ) { /* we have no way to know real length except by decoding */ - if ( p_stream->tinfo->fmt.i_cat == VIDEO_ES ) + if ( p_stream->p_fmt->i_cat == VIDEO_ES ) { p_data->i_length = vlc_tick_from_samples( - p_stream->tinfo->fmt.video.i_frame_rate_base, - p_stream->tinfo->fmt.video.i_frame_rate ); + p_stream->p_fmt->video.i_frame_rate_base, + p_stream->p_fmt->video.i_frame_rate ); if( p_data->i_flags & BLOCK_FLAG_SINGLE_FIELD ) p_data->i_length >>= 1; msg_Dbg( p_mux, "video track %u fixup to %"PRId64" for sample %u", - p_stream->tinfo->i_track_id, p_data->i_length, p_stream->tinfo->i_samples_count ); + mp4mux_track_GetID(p_stream->tinfo), p_data->i_length, + mp4mux_track_GetSampleCount(p_stream->tinfo) ); } - else if ( p_stream->tinfo->fmt.i_cat == AUDIO_ES && - p_stream->tinfo->fmt.audio.i_rate && + else if ( p_stream->p_fmt->i_cat == AUDIO_ES && + p_stream->p_fmt->audio.i_rate && p_data->i_nb_samples ) { p_data->i_length = vlc_tick_from_samples(p_data->i_nb_samples, - p_stream->tinfo->fmt.audio.i_rate); + p_stream->p_fmt->audio.i_rate); msg_Dbg( p_mux, "audio track %u fixup to %"PRId64" for sample %u", - p_stream->tinfo->i_track_id, p_data->i_length, p_stream->tinfo->i_samples_count ); + mp4mux_track_GetID(p_stream->tinfo), p_data->i_length, + mp4mux_track_GetSampleCount(p_stream->tinfo) ); } else if ( p_data->i_length <= 0 ) { msg_Warn( p_mux, "unknown length for track %u sample %u", - p_stream->tinfo->i_track_id, p_stream->tinfo->i_samples_count ); + mp4mux_track_GetID(p_stream->tinfo), + mp4mux_track_GetSampleCount(p_stream->tinfo) ); p_data->i_length = 1; } } @@ -695,16 +706,17 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s } else /* SPU_ES */ { - mp4mux_sample_t *p_lastsample = mp4mux_track_GetLastSample(p_stream->tinfo); + const mp4mux_sample_t *p_lastsample = mp4mux_track_GetLastSample(p_stream->tinfo); if (p_lastsample != NULL && p_lastsample->i_length == 0) { + mp4mux_sample_t updated = *p_lastsample; /* length of previous spu, stored in spu clearer */ int64_t i_length = dts_fb_pts( p_data ) - p_stream->i_last_dts; if(i_length < 0) i_length = 0; /* Fix entry */ - p_lastsample->i_length = i_length; - p_stream->tinfo->i_read_duration += i_length; + updated.i_length = i_length; + mp4mux_track_UpdateLastSample(p_stream->tinfo, &updated); } } @@ -719,18 +731,14 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s sample.i_size = p_data->i_buffer; if ( p_data->i_dts != VLC_TICK_INVALID && p_data->i_pts > p_data->i_dts ) - { sample.i_pts_dts = p_data->i_pts - p_data->i_dts; - if ( !p_stream->tinfo->b_hasbframes ) - p_stream->tinfo->b_hasbframes = true; - } - else sample.i_pts_dts = 0; + else + sample.i_pts_dts = 0; sample.i_length = p_data->i_length; sample.i_flags = p_data->i_flags; /* update */ - p_stream->tinfo->i_read_duration += __MAX( 0, p_data->i_length ); p_stream->i_last_dts = dts_fb_pts( p_data ); /* write data */ @@ -741,12 +749,12 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s } /* Add SPU clearing tag (duration tb fixed on next SPU or stream end )*/ - if ( p_stream->tinfo->fmt.i_cat == SPU_ES && sample.i_length > 0 ) + if ( p_stream->p_fmt->i_cat == SPU_ES && sample.i_length > 0 ) { block_t *p_empty = NULL; - if(p_stream->tinfo->fmt.i_codec == VLC_CODEC_SUBT|| - p_stream->tinfo->fmt.i_codec == VLC_CODEC_QTXT|| - p_stream->tinfo->fmt.i_codec == VLC_CODEC_TX3G) + if(p_stream->p_fmt->i_codec == VLC_CODEC_SUBT|| + p_stream->p_fmt->i_codec == VLC_CODEC_QTXT|| + p_stream->p_fmt->i_codec == VLC_CODEC_TX3G) { p_empty = block_Alloc(3); if(p_empty) @@ -757,13 +765,13 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s p_empty->p_buffer[2] = ' '; } } - else if(p_stream->tinfo->fmt.i_codec == VLC_CODEC_TTML) + else if(p_stream->p_fmt->i_codec == VLC_CODEC_TTML) { p_empty = block_Alloc(40); if(p_empty) memcpy(p_empty->p_buffer, "<tt><body><div><p></p></div></body></tt>", 40); } - else if(p_stream->tinfo->fmt.i_codec == VLC_CODEC_WEBVTT) + else if(p_stream->p_fmt->i_codec == VLC_CODEC_WEBVTT) { p_empty = block_Alloc(8); if(p_empty) @@ -793,8 +801,8 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s } /* Update the global segment/media duration */ - if( p_stream->tinfo->i_read_duration > p_sys->i_read_duration ) - p_sys->i_read_duration = p_stream->tinfo->i_read_duration; + if( mp4mux_track_GetDuration(p_stream->tinfo) > p_sys->i_read_duration ) + p_sys->i_read_duration = mp4mux_track_GetDuration(p_stream->tinfo); return VLC_SUCCESS; } @@ -970,13 +978,15 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size, { /* Current segment have all same duration value, different than trex's default */ if (b_allsamelength && - p_stream->read.p_first->p_block->i_length != p_stream->tinfo->i_trex_default_length && + p_stream->read.p_first->p_block->i_length != + mp4mux_track_GetDefaultSampleDuration(p_stream->tinfo) && p_stream->read.p_first->p_block->i_length) i_tfhd_flags |= MP4_TFHD_DFLT_SAMPLE_DURATION; /* Current segment have all same size value, different than trex's default */ if (b_allsamesize && - p_stream->read.p_first->p_block->i_buffer != p_stream->tinfo->i_trex_default_size && + p_stream->read.p_first->p_block->i_buffer != + mp4mux_track_GetDefaultSampleSize(p_stream->tinfo) && p_stream->read.p_first->p_block->i_buffer) i_tfhd_flags |= MP4_TFHD_DFLT_SAMPLE_SIZE; } @@ -993,11 +1003,12 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size, bo_free(traf); continue; } - bo_add_32be(tfhd, p_stream->tinfo->i_track_id); + bo_add_32be(tfhd, mp4mux_track_GetID(p_stream->tinfo)); /* set the local sample duration default */ if (i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_DURATION) - bo_add_32be(tfhd, samples_from_vlc_tick(p_stream->read.p_first->p_block->i_length, p_stream->tinfo->i_timescale)); + bo_add_32be(tfhd, samples_from_vlc_tick(p_stream->read.p_first->p_block->i_length, + mp4mux_track_GetTimescale(p_stream->tinfo))); /* set the local sample size default */ if (i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_SIZE) @@ -1012,7 +1023,8 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size, bo_free(traf); continue; } - bo_add_64be(tfdt, samples_from_vlc_tick(p_stream->i_written_duration, p_stream->tinfo->i_timescale) ); + bo_add_64be(tfdt, samples_from_vlc_tick(p_stream->i_written_duration, + mp4mux_track_GetTimescale(p_stream->tinfo)) ); box_gather(traf, tfdt); /* *** add /moof/traf/trun *** */ @@ -1024,14 +1036,16 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size, i_trun_flags |= MP4_TRUN_FIRST_FLAGS; if (!b_allsamelength || - ( !(i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_DURATION) && p_stream->tinfo->i_trex_default_length == 0 )) + ( !(i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_DURATION) && + mp4mux_track_GetDefaultSampleDuration(p_stream->tinfo) == 0 )) i_trun_flags |= MP4_TRUN_SAMPLE_DURATION; if (!b_allsamesize || - ( !(i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_SIZE) && p_stream->tinfo->i_trex_default_size == 0 )) + ( !(i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_SIZE) && + mp4mux_track_GetDefaultSampleSize(p_stream->tinfo) == 0 )) i_trun_flags |= MP4_TRUN_SAMPLE_SIZE; - if (p_stream->tinfo->b_hasbframes) + if (mp4mux_track_HasBFrames(p_stream->tinfo)) i_trun_flags |= MP4_TRUN_SAMPLE_TIME_OFFSET; if (i_fixupoffset == 0) @@ -1072,7 +1086,8 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size, DEQUEUE_ENTRY(p_stream->read, p_entry); if (i_trun_flags & MP4_TRUN_SAMPLE_DURATION) - bo_add_32be(trun, samples_from_vlc_tick(p_entry->p_block->i_length, p_stream->tinfo->i_timescale)); // sample duration + bo_add_32be(trun, samples_from_vlc_tick(p_entry->p_block->i_length, + mp4mux_track_GetTimescale(p_stream->tinfo))); // sample duration if (i_trun_flags & MP4_TRUN_SAMPLE_SIZE) bo_add_32be(trun, p_entry->p_block->i_buffer); // sample size @@ -1085,7 +1100,7 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size, { i_diff = p_entry->p_block->i_pts - p_entry->p_block->i_dts; } - bo_add_32be(trun, samples_from_vlc_tick(i_diff, p_stream->tinfo->i_timescale)); // ctts + bo_add_32be(trun, samples_from_vlc_tick(i_diff, mp4mux_track_GetTimescale(p_stream->tinfo))); // ctts } *pi_mdat_total_size += p_entry->p_block->i_buffer; @@ -1096,7 +1111,7 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size, /* Add keyframe entry if needed */ if (p_stream->b_hasiframes && (p_entry->p_block->i_flags & BLOCK_FLAG_TYPE_I) && - (p_stream->tinfo->fmt.i_cat == VIDEO_ES || p_stream->tinfo->fmt.i_cat == AUDIO_ES)) + (p_stream->p_fmt->i_cat == VIDEO_ES || p_stream->p_fmt->i_cat == AUDIO_ES)) { AddKeyframeEntry(p_stream, i_write_pos, i_trak, i_sample, i_time); } @@ -1179,7 +1194,7 @@ static bo_t *GetMfraBox(sout_mux_t *p_mux) { bo_t *tfra = box_full_new("tfra", 0, 0x0); if (!tfra) continue; - bo_add_32be(tfra, p_stream->tinfo->i_track_id); + bo_add_32be(tfra, mp4mux_track_GetID(p_stream->tinfo)); bo_add_32be(tfra, 0x3); // reserved + lengths (1,1,4)=>(0,0,3) bo_add_32be(tfra, p_stream->i_indexentries); for(uint32_t i_index=0; i_index<p_stream->i_indexentries; i_index++) @@ -1259,8 +1274,8 @@ static void WriteFragments(sout_mux_t *p_mux, bool b_flush) /* set a barrier so we try to align to keyframe */ if (p_stream->b_hasiframes && p_stream->i_last_iframe_time > p_stream->i_written_duration && - (p_stream->tinfo->fmt.i_cat == VIDEO_ES || - p_stream->tinfo->fmt.i_cat == AUDIO_ES) ) + (p_stream->p_fmt->i_cat == VIDEO_ES || + p_stream->p_fmt->i_cat == AUDIO_ES) ) { i_barrier_time = __MIN(i_barrier_time, p_stream->i_last_iframe_time); } @@ -1301,27 +1316,30 @@ static void WriteFragments(sout_mux_t *p_mux, bool b_flush) * This is the end boundary case. */ static void LengthLocalFixup(sout_mux_t *p_mux, const mp4_stream_t *p_stream, block_t *p_entrydata) { - if ( p_stream->tinfo->fmt.i_cat == VIDEO_ES && p_stream->tinfo->fmt.video.i_frame_rate ) + if ( p_stream->p_fmt->i_cat == VIDEO_ES && p_stream->p_fmt->video.i_frame_rate ) { p_entrydata->i_length = vlc_tick_from_samples( - p_stream->tinfo->fmt.video.i_frame_rate_base, - p_stream->tinfo->fmt.video.i_frame_rate); + p_stream->p_fmt->video.i_frame_rate_base, + p_stream->p_fmt->video.i_frame_rate); msg_Dbg(p_mux, "video track %d fixup to %"PRId64" for sample %u", - p_stream->tinfo->i_track_id, p_entrydata->i_length, p_stream->tinfo->i_samples_count - 1); + mp4mux_track_GetID(p_stream->tinfo), p_entrydata->i_length, + mp4mux_track_GetSampleCount(p_stream->tinfo) - 1); } - else if (p_stream->tinfo->fmt.i_cat == AUDIO_ES && - p_stream->tinfo->fmt.audio.i_rate && - p_entrydata->i_nb_samples && p_stream->tinfo->fmt.audio.i_rate) + else if (p_stream->p_fmt->i_cat == AUDIO_ES && + p_stream->p_fmt->audio.i_rate && + p_entrydata->i_nb_samples && p_stream->p_fmt->audio.i_rate) { p_entrydata->i_length = vlc_tick_from_samples(p_entrydata->i_nb_samples, - p_stream->tinfo->fmt.audio.i_rate); + p_stream->p_fmt->audio.i_rate); msg_Dbg(p_mux, "audio track %d fixup to %"PRId64" for sample %u", - p_stream->tinfo->i_track_id, p_entrydata->i_length, p_stream->tinfo->i_samples_count - 1); + mp4mux_track_GetID(p_stream->tinfo), p_entrydata->i_length, + mp4mux_track_GetSampleCount(p_stream->tinfo) - 1); } else { msg_Warn(p_mux, "unknown length for track %d sample %u", - p_stream->tinfo->i_track_id, p_stream->tinfo->i_samples_count - 1); + mp4mux_track_GetID(p_stream->tinfo), + mp4mux_track_GetSampleCount(p_stream->tinfo) - 1); p_entrydata->i_length = 1; } } @@ -1447,15 +1465,17 @@ static int MuxFrag(sout_mux_t *p_mux) p_stream->p_held_entry = NULL; if (p_stream->b_hasiframes && (p_heldblock->i_flags & BLOCK_FLAG_TYPE_I) && - p_stream->tinfo->i_read_duration - p_sys->i_written_duration < FRAGMENT_LENGTH) + mp4mux_track_GetDuration(p_stream->tinfo) - p_sys->i_written_duration < FRAGMENT_LENGTH) { /* Flag the last iframe time, we'll use it as boundary so it will start next fragment */ - p_stream->i_last_iframe_time = p_stream->tinfo->i_read_duration; + p_stream->i_last_iframe_time = mp4mux_track_GetDuration(p_stream->tinfo); } /* update buffered time */ - p_stream->tinfo->i_read_duration += __MAX(0, p_heldblock->i_length); + mp4mux_track_ForceDuration(p_stream->tinfo, + mp4mux_track_GetDuration(p_stream->tinfo) + + __MAX(0, p_heldblock->i_length)); } @@ -1468,26 +1488,27 @@ static int MuxFrag(sout_mux_t *p_mux) p_stream->p_held_entry->i_run = p_stream->i_current_run; p_stream->p_held_entry->p_next = NULL; - if (p_stream->tinfo->fmt.i_cat == VIDEO_ES ) + if (p_stream->p_fmt->i_cat == VIDEO_ES ) { if (!p_stream->b_hasiframes && (p_currentblock->i_flags & BLOCK_FLAG_TYPE_I)) p_stream->b_hasiframes = true; - if (!p_stream->tinfo->b_hasbframes && p_currentblock->i_dts != VLC_TICK_INVALID && + if (!mp4mux_track_HasBFrames(p_stream->tinfo) && + p_currentblock->i_dts != VLC_TICK_INVALID && p_currentblock->i_pts > p_currentblock->i_dts) - p_stream->tinfo->b_hasbframes = true; + mp4mux_track_SetHasBFrames(p_stream->tinfo); } /* Update the global fragment/media duration */ - vlc_tick_t i_min_read_duration = p_stream->tinfo->i_read_duration; + vlc_tick_t i_min_read_duration = mp4mux_track_GetDuration(p_stream->tinfo); vlc_tick_t i_min_written_duration = p_stream->i_written_duration; for (unsigned int i=0; i<p_sys->i_nb_streams; i++) { const mp4_stream_t *p_s = p_sys->pp_streams[i]; - if (p_s->tinfo->fmt.i_cat != VIDEO_ES && p_s->tinfo->fmt.i_cat != AUDIO_ES) + if (p_s->p_fmt->i_cat != VIDEO_ES && p_s->p_fmt->i_cat != AUDIO_ES) continue; - if (p_s->tinfo->i_read_duration < i_min_read_duration) - i_min_read_duration = p_s->tinfo->i_read_duration; + if (mp4mux_track_GetDuration(p_s->tinfo) < i_min_read_duration) + i_min_read_duration = mp4mux_track_GetDuration(p_s->tinfo); if (p_s->i_written_duration < i_min_written_duration) i_min_written_duration = p_s->i_written_duration;