Commit da897185 authored by François Cartegnie's avatar François Cartegnie 🤞

mux: mp4: split stream muxing

parent d92bb2cc
...@@ -583,111 +583,105 @@ static inline mtime_t dts_fb_pts( const block_t *p_data ) ...@@ -583,111 +583,105 @@ static inline mtime_t dts_fb_pts( const block_t *p_data )
return p_data->i_dts > VLC_TS_INVALID ? p_data->i_dts: p_data->i_pts; return p_data->i_dts > VLC_TS_INVALID ? p_data->i_dts: p_data->i_pts;
} }
static int Mux(sout_mux_t *p_mux) static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_stream)
{ {
sout_mux_sys_t *p_sys = p_mux->p_sys; sout_mux_sys_t *p_sys = p_mux->p_sys;
for (;;) { block_t *p_data = BlockDequeue(p_input, p_stream);
int i_stream = sout_MuxGetStream(p_mux, 2, NULL); if(!p_data)
if (i_stream < 0) return VLC_SUCCESS;
return(VLC_SUCCESS);
sout_input_t *p_input = p_mux->pp_inputs[i_stream];
mp4_stream_t *p_stream = (mp4_stream_t*)p_input->p_sys;
block_t *p_data = BlockDequeue(p_input, p_stream);
if(!p_data)
return VLC_SUCCESS;
/* Reset reference dts in case of discontinuity (ex: gather sout) */ /* Reset reference dts in case of discontinuity (ex: gather sout) */
if (p_data->i_flags & BLOCK_FLAG_DISCONTINUITY && p_stream->mux.i_entry_count) if (p_data->i_flags & BLOCK_FLAG_DISCONTINUITY && p_stream->mux.i_entry_count)
{
if(p_stream->i_first_dts != VLC_TS_INVALID)
{ {
if(p_stream->i_first_dts != VLC_TS_INVALID) if(!CreateCurrentEdit(p_stream, p_sys->i_start_dts, p_sys->b_fragmented))
{ {
if(!CreateCurrentEdit(p_stream, p_sys->i_start_dts, p_sys->b_fragmented)) block_Release( p_data );
{ return VLC_ENOMEM;
block_Release( p_data );
return VLC_ENOMEM;
}
} }
p_stream->i_length_neg = 0;
p_stream->i_first_dts = VLC_TS_INVALID;
p_stream->i_last_dts = VLC_TS_INVALID;
p_stream->i_last_pts = VLC_TS_INVALID;
} }
/* XXX: -1 to always have 2 entry for easy adding of empty SPU */ p_stream->i_length_neg = 0;
if (p_stream->mux.i_entry_count >= p_stream->mux.i_entry_max - 2) { p_stream->i_first_dts = VLC_TS_INVALID;
p_stream->mux.i_entry_max += 1000; p_stream->i_last_dts = VLC_TS_INVALID;
p_stream->mux.entry = xrealloc(p_stream->mux.entry, p_stream->i_last_pts = VLC_TS_INVALID;
p_stream->mux.i_entry_max * sizeof(mp4mux_entry_t)); }
}
/* Set current segment ranges */ /* XXX: -1 to always have 2 entry for easy adding of empty SPU */
if( p_stream->i_first_dts == VLC_TS_INVALID ) if (p_stream->mux.i_entry_count >= p_stream->mux.i_entry_max - 2) {
{ p_stream->mux.i_entry_max += 1000;
p_stream->i_first_dts = dts_fb_pts( p_data ); p_stream->mux.entry = xrealloc(p_stream->mux.entry,
if( p_sys->i_start_dts == VLC_TS_INVALID ) p_stream->mux.i_entry_max * sizeof(mp4mux_entry_t));
p_sys->i_start_dts = p_stream->i_first_dts; }
}
if (p_stream->mux.fmt.i_cat != SPU_ES) { /* Set current segment ranges */
/* Fix length of the sample */ if( p_stream->i_first_dts == VLC_TS_INVALID )
if (block_FifoCount(p_input->p_fifo) > 0) { {
block_t *p_next = block_FifoShow(p_input->p_fifo); p_stream->i_first_dts = dts_fb_pts( p_data );
if ( p_next->i_flags & BLOCK_FLAG_DISCONTINUITY ) if( p_sys->i_start_dts == VLC_TS_INVALID )
{ /* we have no way to know real length except by decoding */ p_sys->i_start_dts = p_stream->i_first_dts;
if ( p_stream->mux.fmt.i_cat == VIDEO_ES ) }
{
p_data->i_length = CLOCK_FREQ * if (p_stream->mux.fmt.i_cat != SPU_ES)
p_stream->mux.fmt.video.i_frame_rate_base / {
p_stream->mux.fmt.video.i_frame_rate; /* Fix length of the sample */
if( p_data->i_flags & BLOCK_FLAG_SINGLE_FIELD ) if (block_FifoCount(p_input->p_fifo) > 0)
p_data->i_length >>= 1; {
msg_Dbg( p_mux, "video track %u fixup to %"PRId64" for sample %u", block_t *p_next = block_FifoShow(p_input->p_fifo);
p_stream->mux.i_track_id, p_data->i_length, p_stream->mux.i_entry_count ); if ( p_next->i_flags & BLOCK_FLAG_DISCONTINUITY )
} { /* we have no way to know real length except by decoding */
else if ( p_stream->mux.fmt.i_cat == AUDIO_ES && if ( p_stream->mux.fmt.i_cat == VIDEO_ES )
p_stream->mux.fmt.audio.i_rate && {
p_data->i_nb_samples ) p_data->i_length = CLOCK_FREQ *
{ p_stream->mux.fmt.video.i_frame_rate_base /
p_data->i_length = CLOCK_FREQ * p_data->i_nb_samples / p_stream->mux.fmt.video.i_frame_rate;
p_stream->mux.fmt.audio.i_rate; if( p_data->i_flags & BLOCK_FLAG_SINGLE_FIELD )
msg_Dbg( p_mux, "audio track %u fixup to %"PRId64" for sample %u", p_data->i_length >>= 1;
p_stream->mux.i_track_id, p_data->i_length, p_stream->mux.i_entry_count ); msg_Dbg( p_mux, "video track %u fixup to %"PRId64" for sample %u",
} p_stream->mux.i_track_id, p_data->i_length, p_stream->mux.i_entry_count );
else if ( p_data->i_length <= 0 )
{
msg_Warn( p_mux, "unknown length for track %u sample %u",
p_stream->mux.i_track_id, p_stream->mux.i_entry_count );
p_data->i_length = 1;
}
} }
else else if ( p_stream->mux.fmt.i_cat == AUDIO_ES &&
p_stream->mux.fmt.audio.i_rate &&
p_data->i_nb_samples )
{ {
int64_t i_diff = dts_fb_pts( p_next ) - dts_fb_pts( p_data ); p_data->i_length = CLOCK_FREQ * p_data->i_nb_samples /
if (i_diff < CLOCK_FREQ) /* protection */ p_stream->mux.fmt.audio.i_rate;
p_data->i_length = i_diff; msg_Dbg( p_mux, "audio track %u fixup to %"PRId64" for sample %u",
p_stream->mux.i_track_id, p_data->i_length, p_stream->mux.i_entry_count );
}
else if ( p_data->i_length <= 0 )
{
msg_Warn( p_mux, "unknown length for track %u sample %u",
p_stream->mux.i_track_id, p_stream->mux.i_entry_count );
p_data->i_length = 1;
} }
} }
if (p_data->i_length <= 0) { else
msg_Warn(p_mux, "i_length <= 0"); {
p_stream->i_length_neg += p_data->i_length - 1; int64_t i_diff = dts_fb_pts( p_next ) - dts_fb_pts( p_data );
p_data->i_length = 1; if (i_diff < CLOCK_FREQ) /* protection */
} else if (p_stream->i_length_neg < 0) { p_data->i_length = i_diff;
int64_t i_recover = __MIN(p_data->i_length / 4, - p_stream->i_length_neg);
p_data->i_length -= i_recover;
p_stream->i_length_neg += i_recover;
} }
} }
if (p_data->i_length <= 0) {
if (p_stream->mux.fmt.i_cat == SPU_ES && msg_Warn(p_mux, "i_length <= 0");
p_stream->mux.i_entry_count > 0 && p_stream->i_length_neg += p_data->i_length - 1;
p_data->i_length = 1;
} else if (p_stream->i_length_neg < 0) {
int64_t i_recover = __MIN(p_data->i_length / 4, - p_stream->i_length_neg);
p_data->i_length -= i_recover;
p_stream->i_length_neg += i_recover;
}
}
else /* SPU_ES */
{
if (p_stream->mux.i_entry_count > 0 &&
p_stream->mux.entry[p_stream->mux.i_entry_count-1].i_length == 0) p_stream->mux.entry[p_stream->mux.i_entry_count-1].i_length == 0)
{ {
/* length of previous spu, stored in spu clearer */ /* length of previous spu, stored in spu clearer */
int64_t i_length = dts_fb_pts( p_data ) - p_stream->i_last_dts; int64_t i_length = dts_fb_pts( p_data ) - p_stream->i_last_dts;
if(i_length < 0) if(i_length < 0)
i_length = 0; i_length = 0;
...@@ -695,77 +689,96 @@ static int Mux(sout_mux_t *p_mux) ...@@ -695,77 +689,96 @@ static int Mux(sout_mux_t *p_mux)
p_stream->mux.entry[p_stream->mux.i_entry_count-1].i_length = i_length; p_stream->mux.entry[p_stream->mux.i_entry_count-1].i_length = i_length;
p_stream->mux.i_read_duration += i_length; p_stream->mux.i_read_duration += i_length;
} }
}
/* Update (Not earlier for SPU!) */ /* Update (Not earlier for SPU!) */
p_stream->i_last_dts = dts_fb_pts( p_data ); p_stream->i_last_dts = dts_fb_pts( p_data );
if( p_data->i_pts > p_stream->i_last_pts ) if( p_data->i_pts > p_stream->i_last_pts )
p_stream->i_last_pts = p_data->i_pts; p_stream->i_last_pts = p_data->i_pts;
/* add index entry */ /* add index entry */
mp4mux_entry_t *e = &p_stream->mux.entry[p_stream->mux.i_entry_count++]; mp4mux_entry_t *e = &p_stream->mux.entry[p_stream->mux.i_entry_count++];
e->i_pos = p_sys->i_pos; e->i_pos = p_sys->i_pos;
e->i_size = p_data->i_buffer; e->i_size = p_data->i_buffer;
if ( p_data->i_dts > VLC_TS_INVALID && p_data->i_pts > p_data->i_dts ) if ( p_data->i_dts > VLC_TS_INVALID && p_data->i_pts > p_data->i_dts )
{ {
e->i_pts_dts = p_data->i_pts - p_data->i_dts; e->i_pts_dts = p_data->i_pts - p_data->i_dts;
if ( !p_stream->mux.b_hasbframes ) if ( !p_stream->mux.b_hasbframes )
p_stream->mux.b_hasbframes = true; p_stream->mux.b_hasbframes = true;
} }
else e->i_pts_dts = 0; else e->i_pts_dts = 0;
e->i_length = p_data->i_length; e->i_length = p_data->i_length;
e->i_flags = p_data->i_flags; e->i_flags = p_data->i_flags;
/* update */ /* update */
p_stream->mux.i_read_duration += __MAX( 0, p_data->i_length ); p_stream->mux.i_read_duration += __MAX( 0, p_data->i_length );
p_stream->i_last_dts = dts_fb_pts( p_data ); p_stream->i_last_dts = dts_fb_pts( p_data );
/* write data */ /* write data */
p_sys->i_pos += p_data->i_buffer; p_sys->i_pos += p_data->i_buffer;
sout_AccessOutWrite(p_mux->p_access, p_data); sout_AccessOutWrite(p_mux->p_access, p_data);
/* Add SPU clearing tag (duration tb fixed on next SPU or stream end )*/ /* Add SPU clearing tag (duration tb fixed on next SPU or stream end )*/
if (p_stream->mux.fmt.i_cat == SPU_ES) if (p_stream->mux.fmt.i_cat == SPU_ES )
{
block_t *p_empty = NULL;
if(p_stream->mux.fmt.i_codec == VLC_CODEC_SUBT)
{ {
block_t *p_empty = NULL; p_empty = block_Alloc(3);
if(p_stream->mux.fmt.i_codec == VLC_CODEC_SUBT)
{
p_empty = block_Alloc(3);
if (p_empty)
{
/* point to start of our empty */
p_stream->i_last_dts += e->i_length;
/* Write a " " */
p_empty->p_buffer[0] = 0;
p_empty->p_buffer[1] = 1;
p_empty->p_buffer[2] = ' ';
}
}
if(p_empty) if(p_empty)
{ {
/* Append a idx entry */ /* point to start of our empty */
/* XXX: No need to grow the entry here */ p_stream->i_last_dts += e->i_length;
mp4mux_entry_t *e_empty = &p_stream->mux.entry[p_stream->mux.i_entry_count++];
e_empty->i_pos = p_sys->i_pos; /* Write a " " */
e_empty->i_size = p_empty->i_buffer; p_empty->p_buffer[0] = 0;
e_empty->i_pts_dts= 0; p_empty->p_buffer[1] = 1;
e_empty->i_length = 0; /* will add dts diff later*/ p_empty->p_buffer[2] = ' ';
e_empty->i_flags = 0;
p_sys->i_pos += p_empty->i_buffer;
sout_AccessOutWrite(p_mux->p_access, p_empty);
} }
} }
/* Update the global segment/media duration */ if(p_empty)
if( p_stream->mux.i_read_duration > p_sys->i_read_duration ) {
p_sys->i_read_duration = p_stream->mux.i_read_duration; /* Append a idx entry */
/* XXX: No need to grow the entry here */
mp4mux_entry_t *e_empty = &p_stream->mux.entry[p_stream->mux.i_entry_count++];
e_empty->i_pos = p_sys->i_pos;
e_empty->i_size = p_empty->i_buffer;
e_empty->i_pts_dts= 0;
e_empty->i_length = 0; /* will add dts diff later*/
e_empty->i_flags = 0;
p_sys->i_pos += p_empty->i_buffer;
sout_AccessOutWrite(p_mux->p_access, p_empty);
}
} }
return(VLC_SUCCESS); /* Update the global segment/media duration */
if( p_stream->mux.i_read_duration > p_sys->i_read_duration )
p_sys->i_read_duration = p_stream->mux.i_read_duration;
return VLC_SUCCESS;
}
static int Mux(sout_mux_t *p_mux)
{
int i_ret = VLC_SUCCESS;
do
{
int i_stream = sout_MuxGetStream(p_mux, 2, NULL);
if (i_stream < 0)
break;
sout_input_t *p_input = p_mux->pp_inputs[i_stream];
mp4_stream_t *p_stream = (mp4_stream_t*)p_input->p_sys;
i_ret = MuxStream(p_mux, p_input, p_stream);
} while( i_ret == VLC_SUCCESS );
return i_ret;
} }
/***************************************************************************** /*****************************************************************************
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment