Commit c26b4106 authored by Francois Cartegnie's avatar Francois Cartegnie

demux: mp4: rewrite and strengthen the restart stuff

Also adds the missing restart on MP4Leaf demux mode
parent acc5cdf9
...@@ -113,8 +113,9 @@ struct demux_sys_t ...@@ -113,8 +113,9 @@ struct demux_sys_t
/***************************************************************************** /*****************************************************************************
* Declaration of local function * Declaration of local function
*****************************************************************************/ *****************************************************************************/
static void MP4_TrackCreate ( demux_t *, mp4_track_t *, MP4_Box_t *, bool b_force_enable ); static void MP4_TrackCreate ( demux_t *, mp4_track_t *, MP4_Box_t *, bool, bool );
static int MP4_SmoothTrackCreate( demux_t *, mp4_track_t *, const MP4_Box_t *); static int MP4_SmoothTrackCreate( demux_t *, mp4_track_t *, const mp4_chunk_t *,
const MP4_Box_t *, bool );
static void MP4_TrackDestroy( demux_t *, mp4_track_t * ); static void MP4_TrackDestroy( demux_t *, mp4_track_t * );
static block_t * MP4_Block_Read( demux_t *, const mp4_track_t *, int ); static block_t * MP4_Block_Read( demux_t *, const mp4_track_t *, int );
...@@ -417,7 +418,7 @@ static int CreateTracksFromSmooBox( demux_t *p_demux ) ...@@ -417,7 +418,7 @@ static int CreateTracksFromSmooBox( demux_t *p_demux )
BOXDATA(p_stra) && BOXDATA(p_stra)->i_track_ID > 0 ) BOXDATA(p_stra) && BOXDATA(p_stra)->i_track_ID > 0 )
{ {
mp4_track_t *p_track = &p_sys->track[j++]; mp4_track_t *p_track = &p_sys->track[j++];
MP4_SmoothTrackCreate( p_demux, p_track, p_stra ); MP4_SmoothTrackCreate( p_demux, p_track, p_track->cchunk, p_stra, true );
} }
p_stra = p_stra->p_next; p_stra = p_stra->p_next;
} }
...@@ -863,7 +864,7 @@ static int Open( vlc_object_t * p_this ) ...@@ -863,7 +864,7 @@ static int Open( vlc_object_t * p_this )
for( i = 0; i < p_sys->i_tracks; i++ ) for( i = 0; i < p_sys->i_tracks; i++ )
{ {
p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[%d]", i ); p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[%d]", i );
MP4_TrackCreate( p_demux, &p_sys->track[i], p_trak, !b_enabled_es ); MP4_TrackCreate( p_demux, &p_sys->track[i], p_trak, true, !b_enabled_es );
if( p_sys->track[i].b_ok && !p_sys->track[i].b_chapter ) if( p_sys->track[i].b_ok && !p_sys->track[i].b_chapter )
{ {
...@@ -2617,6 +2618,84 @@ static int TrackGotoChunkSample( demux_t *p_demux, mp4_track_t *p_track, ...@@ -2617,6 +2618,84 @@ static int TrackGotoChunkSample( demux_t *p_demux, mp4_track_t *p_track,
return p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC; return p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC;
} }
static void MP4_TrackRestart( demux_t *p_demux, mp4_track_t *p_track,
MP4_Box_t *p_params_box )
{
bool b_reselect = false;
if( p_track->p_es )
{
es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
p_track->p_es, &b_reselect );
}
/* Save previous fragmented pos */
uint32_t i_sample_pos_backup = p_track->i_sample;
mp4_chunk_t *cchunk_backup = p_track->cchunk;
p_track->cchunk = NULL;
mtime_t time_backup = p_track->i_time * p_track->i_timescale;
/* Save previous format and ES */
es_format_t fmtbackup;
es_out_id_t *p_es_backup = p_track->p_es;
p_track->p_es = NULL;
es_format_Init( &fmtbackup, UNKNOWN_ES, 0 );
es_format_Copy( &fmtbackup, &p_track->fmt );
es_format_Clean( &p_track->fmt );
/* do the cleanup and recycle track / restart */
MP4_TrackDestroy( p_demux, p_track );
memset( p_track, 0, sizeof(*p_track) );
if( p_demux->p_sys->b_smooth )
{
assert(p_params_box->i_type == ATOM_uuid && !CmpUUID( &p_params_box->i_uuid, &StraBoxUUID ) );
MP4_SmoothTrackCreate( p_demux, p_track, cchunk_backup, p_params_box, false );
}
else
{
assert(p_params_box->i_type == ATOM_trak);
MP4_TrackCreate( p_demux, p_track, p_params_box, false, true );
}
if( p_track->b_ok )
{
if( !es_format_IsSimilar( &fmtbackup, &p_track->fmt ) ||
fmtbackup.i_extra != p_track->fmt.i_extra ||
memcmp( &fmtbackup.p_extra, &p_track->fmt.p_extra, fmtbackup.i_extra ) )
{
if( p_es_backup )
es_out_Del( p_demux->out, p_es_backup );
if( !p_track->b_chapter )
{
p_track->p_es = es_out_Add( p_demux->out, &p_track->fmt );
p_track->b_ok = !!p_track->p_es;
}
}
else
{
p_track->p_es = p_es_backup;
}
}
else if( p_es_backup )
{
es_out_Del( p_demux->out, p_es_backup );
}
/* select again the new decoder */
if( b_reselect && p_track->p_es )
es_out_Control( p_demux->out, ES_OUT_SET_ES, p_track->p_es );
es_format_Clean( &fmtbackup );
/* Restore fragmented pos */
p_track->cchunk = cchunk_backup;
p_track->i_sample = i_sample_pos_backup;
if( p_track->i_timescale )
p_track->i_time = time_backup / p_track->i_timescale;
}
/**************************************************************************** /****************************************************************************
* MP4_TrackCreate: * MP4_TrackCreate:
**************************************************************************** ****************************************************************************
...@@ -2625,7 +2704,7 @@ static int TrackGotoChunkSample( demux_t *p_demux, mp4_track_t *p_track, ...@@ -2625,7 +2704,7 @@ static int TrackGotoChunkSample( demux_t *p_demux, mp4_track_t *p_track,
****************************************************************************/ ****************************************************************************/
static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track,
MP4_Box_t *p_box_trak, MP4_Box_t *p_box_trak,
bool b_force_enable ) bool b_create_es, bool b_force_enable )
{ {
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
...@@ -2633,15 +2712,6 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, ...@@ -2633,15 +2712,6 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track,
char language[4] = { '\0' }; char language[4] = { '\0' };
/* hint track unsupported */
/* set default value (-> track unusable) */
p_track->b_ok = false;
p_track->b_enable = false;
p_track->b_selected = false;
p_track->b_chapter = false;
p_track->b_mac_encoding = false;
es_format_Init( &p_track->fmt, UNKNOWN_ES, 0 ); es_format_Init( &p_track->fmt, UNKNOWN_ES, 0 );
const MP4_Box_t *p_tkhd = MP4_BoxGet( p_box_trak, "tkhd" ); const MP4_Box_t *p_tkhd = MP4_BoxGet( p_box_trak, "tkhd" );
...@@ -2850,17 +2920,16 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, ...@@ -2850,17 +2920,16 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track,
} }
} }
p_track->p_es = NULL;
if( TrackCreateES( p_demux, if( TrackCreateES( p_demux,
p_track, p_track->i_chunk, p_track, p_track->i_chunk,
p_track->b_chapter ? NULL : &p_track->p_es ) ) (p_track->b_chapter || !b_create_es) ? NULL : &p_track->p_es ) )
{ {
msg_Err( p_demux, "cannot create es for track[Id 0x%x]", msg_Err( p_demux, "cannot create es for track[Id 0x%x]",
p_track->i_track_ID ); p_track->i_track_ID );
return; return;
} }
p_track->b_ok = p_track->b_chapter || !!p_track->p_es; p_track->b_ok = true;
} }
static void DestroyChunk( mp4_chunk_t *ck ) static void DestroyChunk( mp4_chunk_t *ck )
...@@ -3313,24 +3382,22 @@ static void MP4_TrackSetELST( demux_t *p_demux, mp4_track_t *tk, ...@@ -3313,24 +3382,22 @@ static void MP4_TrackSetELST( demux_t *p_demux, mp4_track_t *tk,
* It computes the sample rate for a video track using current video chunk * It computes the sample rate for a video track using current video chunk
*/ */
static void ChunkGetESSampleRate( unsigned *pi_num, unsigned *pi_den, static void ChunkGetESSampleRate( unsigned *pi_num, unsigned *pi_den,
const mp4_track_t *p_track ) const mp4_chunk_t *p_cchunk,
uint32_t i_timescale )
{ {
if( p_track->cchunk->i_last_dts == 0 ) if( !p_cchunk || p_cchunk->i_last_dts == 0 || i_timescale == 0 )
return; return;
*pi_num = 0; *pi_num = 0;
*pi_den = 0; *pi_den = 0;
/* */ uint32_t i_sample = p_cchunk->i_sample_count;
const mp4_chunk_t *p_chunk = p_track->cchunk; uint64_t i_first_dts = p_cchunk->i_first_dts;
uint64_t i_last_dts = p_cchunk->i_last_dts;
uint32_t i_sample = p_chunk->i_sample_count;
uint64_t i_first_dts = p_chunk->i_first_dts;
uint64_t i_last_dts = p_chunk->i_last_dts;
if( i_sample > 1 && i_first_dts < i_last_dts ) if( i_sample > 1 && i_first_dts < i_last_dts )
vlc_ureduce( pi_num, pi_den, vlc_ureduce( pi_num, pi_den,
( i_sample - 1) * p_track->i_timescale, ( i_sample - 1) * i_timescale,
i_last_dts - i_first_dts, i_last_dts - i_first_dts,
UINT16_MAX); UINT16_MAX);
} }
...@@ -3416,12 +3483,13 @@ static inline int MP4_SetCodecExtraData( es_format_t *fmt, const MP4_Box_data_st ...@@ -3416,12 +3483,13 @@ static inline int MP4_SetCodecExtraData( es_format_t *fmt, const MP4_Box_data_st
return VLC_SUCCESS; return VLC_SUCCESS;
} }
static int MP4_SmoothFormatFill( const MP4_Box_data_stra_t *p_data, const mp4_track_t *p_track, static int MP4_SmoothFormatFill( const MP4_Box_data_stra_t *p_data,
es_format_t *fmt ) es_format_t *fmt )
{ {
/* Set language FIXME */ /* Set language FIXME */
fmt->psz_language = strdup( "en" ); fmt->psz_language = strdup( "en" );
fmt->i_cat = p_data->i_es_cat;
fmt->i_original_fourcc = p_data->FourCC; fmt->i_original_fourcc = p_data->FourCC;
fmt->i_codec = vlc_fourcc_GetCodec( fmt->i_cat, p_data->FourCC ); fmt->i_codec = vlc_fourcc_GetCodec( fmt->i_cat, p_data->FourCC );
...@@ -3449,11 +3517,6 @@ static int MP4_SmoothFormatFill( const MP4_Box_data_stra_t *p_data, const mp4_tr ...@@ -3449,11 +3517,6 @@ static int MP4_SmoothFormatFill( const MP4_Box_data_stra_t *p_data, const mp4_tr
fmt->video.i_bits_per_pixel = 0x18; fmt->video.i_bits_per_pixel = 0x18;
fmt->video.i_visible_width = p_data->MaxWidth; fmt->video.i_visible_width = p_data->MaxWidth;
fmt->video.i_visible_height = p_data->MaxHeight; fmt->video.i_visible_height = p_data->MaxHeight;
/* Frame rate */
ChunkGetESSampleRate( &fmt->video.i_frame_rate,
&fmt->video.i_frame_rate_base, p_track );
break; break;
case AUDIO_ES: case AUDIO_ES:
...@@ -3476,14 +3539,13 @@ static int MP4_SmoothFormatFill( const MP4_Box_data_stra_t *p_data, const mp4_tr ...@@ -3476,14 +3539,13 @@ static int MP4_SmoothFormatFill( const MP4_Box_data_stra_t *p_data, const mp4_tr
return VLC_SUCCESS; return VLC_SUCCESS;
} }
static int MP4_SmoothTrackCreate( demux_t *p_demux, mp4_track_t *p_track, const MP4_Box_t *p_stra ) static int MP4_SmoothTrackCreate( demux_t *p_demux, mp4_track_t *p_track,
const mp4_chunk_t *p_cchunk,
const MP4_Box_t *p_stra, bool b_create_es )
{ {
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
es_format_t *fmt = &p_track->fmt; es_format_t *fmt = &p_track->fmt;
p_track->b_ok = false;
p_track->b_selected = false;
MP4_Box_data_stra_t *p_data = BOXDATA(p_stra); MP4_Box_data_stra_t *p_data = BOXDATA(p_stra);
if( !p_data ) if( !p_data )
return VLC_EGENERIC; return VLC_EGENERIC;
...@@ -3495,37 +3557,21 @@ static int MP4_SmoothTrackCreate( demux_t *p_demux, mp4_track_t *p_track, const ...@@ -3495,37 +3557,21 @@ static int MP4_SmoothTrackCreate( demux_t *p_demux, mp4_track_t *p_track, const
p_track->i_width = 0; p_track->i_width = 0;
p_track->i_height = 0; p_track->i_height = 0;
es_format_t newfmt; es_format_Init( fmt, p_data->i_es_cat, 0 );
es_format_Init( &newfmt, p_data->i_es_cat, 0 );
if( MP4_SmoothFormatFill( BOXDATA(p_stra), p_track, &newfmt ) != VLC_SUCCESS )
{
es_format_Clean(&newfmt);
if( p_track->p_es )
{
es_out_Del( p_demux->out, p_track->p_es );
p_track->p_es = NULL;
}
return VLC_EGENERIC;
}
/* If format now differs from current (new or updated) */ if( MP4_SmoothFormatFill( p_data, fmt ) != VLC_SUCCESS )
if( !es_format_IsSimilar( &newfmt, fmt ) || return VLC_EGENERIC;
newfmt.i_extra != fmt->i_extra ||
memcmp( &newfmt.p_extra, fmt->p_extra, newfmt.i_extra ) )
{
es_format_Clean( fmt );
es_format_Copy( fmt, &newfmt );
if( p_track->p_es )
es_out_Del( p_demux->out, p_track->p_es );
p_track->p_es = es_out_Add( p_demux->out, fmt );
}
es_format_Clean( &newfmt );
if( fmt->i_cat == VIDEO_ES ) if( fmt->i_cat == VIDEO_ES )
{ {
p_track->i_width = fmt->video.i_visible_width; p_track->i_width = fmt->video.i_visible_width;
p_track->i_height = fmt->video.i_visible_height; p_track->i_height = fmt->video.i_visible_height;
/* Frame rate */
ChunkGetESSampleRate( &fmt->video.i_frame_rate,
&fmt->video.i_frame_rate_base,
p_cchunk, p_track->i_timescale );
if( fmt->video.i_frame_rate_base != 0 ) if( fmt->video.i_frame_rate_base != 0 )
{ {
p_demux->p_sys->f_fps = (float)fmt->video.i_frame_rate / p_demux->p_sys->f_fps = (float)fmt->video.i_frame_rate /
...@@ -3535,7 +3581,14 @@ static int MP4_SmoothTrackCreate( demux_t *p_demux, mp4_track_t *p_track, const ...@@ -3535,7 +3581,14 @@ static int MP4_SmoothTrackCreate( demux_t *p_demux, mp4_track_t *p_track, const
p_demux->p_sys->f_fps = 24; p_demux->p_sys->f_fps = 24;
} }
p_track->b_ok = !!p_track->p_es; if( b_create_es )
{
p_track->p_es = es_out_Add( p_demux->out, fmt );
if( !p_track->p_es )
return VLC_EGENERIC;
}
p_track->b_ok = true;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -3602,40 +3655,30 @@ static void FlushChunk( demux_t *p_demux, mp4_track_t *tk ) ...@@ -3602,40 +3655,30 @@ static void FlushChunk( demux_t *p_demux, mp4_track_t *tk )
* before the track has been selected by MP4_TrackSelect * before the track has been selected by MP4_TrackSelect
* (during the first execution of Demux), then the track gets disabled * (during the first execution of Demux), then the track gets disabled
*/ */
static int ReInitDecoder( demux_t *p_demux, mp4_track_t *p_track ) static int ReInitDecoder( demux_t *p_demux, const MP4_Box_t *p_root,
mp4_track_t *p_track )
{ {
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
uint32_t i_sample = p_track->i_sample; MP4_Box_t *p_paramsbox; /* trak or stra */
if( p_sys->b_smooth ) if( p_sys->b_smooth )
{ {
MP4_Box_t *p_stra = MP4_BoxGet( p_sys->p_root, "uuid/uuid[0]" ); p_paramsbox = MP4_BoxGet( p_root, "uuid/uuid[0]" );
if( !p_stra || CmpUUID( &p_stra->i_uuid, &StraBoxUUID ) || if( !p_paramsbox || CmpUUID( &p_paramsbox->i_uuid, &StraBoxUUID ) )
MP4_SmoothTrackCreate( p_demux, p_track, p_stra ) != VLC_SUCCESS )
return VLC_EGENERIC; return VLC_EGENERIC;
} }
else /* DASH */ else /* DASH */
{ {
MP4_Box_t *p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[0]" ); p_paramsbox = MP4_BoxGet( p_root, "/moov/trak[0]" );
if( !p_trak ) if( !p_paramsbox )
return VLC_EGENERIC; return VLC_EGENERIC;
es_out_Del( p_demux->out, p_track->p_es );
p_track->p_es = NULL;
es_format_Clean( &p_track->fmt );
MP4_TrackCreate( p_demux, p_track, p_trak, true );
if(!p_track->p_es)
p_track->p_es = es_out_Add( p_demux->out, &p_track->fmt );
p_track->b_ok = !!p_track->p_es;
} }
p_track->i_sample = i_sample; MP4_TrackRestart( p_demux, p_track, p_paramsbox );
/* Temporary hack until we support track selection */ /* Temporary hack until we support track selection */
p_track->b_selected = true; p_track->b_selected = true;
p_track->b_enable = true; p_track->b_enable = true;
p_track->b_codec_need_restart = false;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -3799,9 +3842,11 @@ static int MP4_frg_GetChunk( demux_t *p_demux, MP4_Box_t *p_chunk, unsigned *i_t ...@@ -3799,9 +3842,11 @@ static int MP4_frg_GetChunk( demux_t *p_demux, MP4_Box_t *p_chunk, unsigned *i_t
ret->i_last_dts = ret->i_first_dts + chunk_duration - dur; ret->i_last_dts = ret->i_first_dts + chunk_duration - dur;
p_track->i_first_dts = chunk_duration + ret->i_first_dts; p_track->i_first_dts = chunk_duration + ret->i_first_dts;
if( p_track->b_codec_need_restart && if( p_track->b_codec_need_restart )
p_track->fmt.i_cat == VIDEO_ES ) {
ReInitDecoder( p_demux, p_track ); ReInitDecoder( p_demux, p_demux->p_sys->p_root, p_track );
p_track->b_codec_need_restart = false;
}
/* Skip if we didn't reach the end of mdat box */ /* Skip if we didn't reach the end of mdat box */
if ( chunk_size < (i_mdatlen - 8) ) if ( chunk_size < (i_mdatlen - 8) )
...@@ -5092,6 +5137,20 @@ end: ...@@ -5092,6 +5137,20 @@ end:
return VLC_SUCCESS; return VLC_SUCCESS;
} }
static void RestartAllTracks( demux_t *p_demux, const MP4_Box_t *p_root )
{
demux_sys_t *p_sys = p_demux->p_sys;
for( unsigned i_track = 0; i_track < p_sys->i_tracks; i_track++ )
{
mp4_track_t *tk = &p_sys->track[i_track];
if( !tk->b_ok || tk->b_chapter )
continue;
ReInitDecoder( p_demux, p_root, tk );
}
}
static int DemuxAsLeaf( demux_t *p_demux ) static int DemuxAsLeaf( demux_t *p_demux )
{ {
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
...@@ -5143,7 +5202,10 @@ static int DemuxAsLeaf( demux_t *p_demux ) ...@@ -5143,7 +5202,10 @@ static int DemuxAsLeaf( demux_t *p_demux )
MP4_Box_t *p_fragbox = MP4_BoxGet( p_vroot, "moof" ); MP4_Box_t *p_fragbox = MP4_BoxGet( p_vroot, "moof" );
if( !p_fragbox ) if( !p_fragbox )
{
p_fragbox = MP4_BoxGet( p_vroot, "moov" ); p_fragbox = MP4_BoxGet( p_vroot, "moov" );
RestartAllTracks( p_demux, p_vroot );
}
if(!p_fragbox) if(!p_fragbox)
{ {
......
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