📄 mp4.c
字号:
{ i_start += elst->i_media_time[p_track->i_elst]; } msg_Dbg( p_demux, "elst (%d) gives "I64Fd"ms (movie)-> "I64Fd "ms (track)", p_track->i_elst, i_mvt * 1000 / p_sys->i_timescale, i_start * 1000 / p_track->i_timescale ); } else { /* convert absolute time to in timescale unit */ i_start = i_start * p_track->i_timescale / (int64_t)1000000; } /* we start from sample 0/chunk 0, hope it won't take too much time */ /* *** find good chunk *** */ for( i_chunk = 0; ; i_chunk++ ) { if( i_chunk + 1 >= p_track->i_chunk_count ) { /* at the end and can't check if i_start in this chunk, it will be check while searching i_sample */ i_chunk = p_track->i_chunk_count - 1; break; } if( (uint64_t)i_start >= p_track->chunk[i_chunk].i_first_dts && (uint64_t)i_start < p_track->chunk[i_chunk + 1].i_first_dts ) { break; } } /* *** find sample in the chunk *** */ i_sample = p_track->chunk[i_chunk].i_sample_first; i_dts = p_track->chunk[i_chunk].i_first_dts; for( i_index = 0; i_sample < p_track->chunk[i_chunk].i_sample_count; ) { if( i_dts + p_track->chunk[i_chunk].p_sample_count_dts[i_index] * p_track->chunk[i_chunk].p_sample_delta_dts[i_index] < (uint64_t)i_start ) { i_dts += p_track->chunk[i_chunk].p_sample_count_dts[i_index] * p_track->chunk[i_chunk].p_sample_delta_dts[i_index]; i_sample += p_track->chunk[i_chunk].p_sample_count_dts[i_index]; i_index++; } else { if( p_track->chunk[i_chunk].p_sample_delta_dts[i_index] <= 0 ) { break; } i_sample += ( i_start - i_dts ) / p_track->chunk[i_chunk].p_sample_delta_dts[i_index]; break; } } if( i_sample >= p_track->i_sample_count ) { msg_Warn( p_demux, "track[Id 0x%x] will be disabled " "(seeking too far) chunk=%d sample=%d", p_track->i_track_ID, i_chunk, i_sample ); return( VLC_EGENERIC ); } /* *** Try to find nearest sync points *** */ if( ( p_stss = MP4_BoxGet( p_track->p_stbl, "stss" ) ) ) { unsigned int i_index; msg_Dbg( p_demux, "track[Id 0x%x] using Sync Sample Box (stss)", p_track->i_track_ID ); for( i_index = 0; i_index < p_stss->data.p_stss->i_entry_count; i_index++ ) { if( p_stss->data.p_stss->i_sample_number[i_index] >= i_sample ) { if( i_index > 0 ) { msg_Dbg( p_demux, "stts gives %d --> %d (sample number)", i_sample, p_stss->data.p_stss->i_sample_number[i_index-1] ); i_sample = p_stss->data.p_stss->i_sample_number[i_index-1]; /* new i_sample is less than old so i_chunk can only decreased */ while( i_chunk > 0 && i_sample < p_track->chunk[i_chunk].i_sample_first ) { i_chunk--; } } else { msg_Dbg( p_demux, "stts gives %d --> %d (sample number)", i_sample, p_stss->data.p_stss->i_sample_number[i_index] ); i_sample = p_stss->data.p_stss->i_sample_number[i_index]; /* new i_sample is more than old so i_chunk can only increased */ while( i_chunk < p_track->i_chunk_count - 1 && i_sample >= p_track->chunk[i_chunk].i_sample_first + p_track->chunk[i_chunk].i_sample_count ) { i_chunk++; } } break; } } } else { msg_Dbg( p_demux, "track[Id 0x%x] does not provide Sync " "Sample Box (stss)", p_track->i_track_ID ); } *pi_chunk = i_chunk; *pi_sample = i_sample; return VLC_SUCCESS;}static int TrackGotoChunkSample( demux_t *p_demux, mp4_track_t *p_track, unsigned int i_chunk, unsigned int i_sample ){ vlc_bool_t b_reselect = VLC_FALSE; /* now see if actual es is ok */ if( p_track->i_chunk < 0 || p_track->i_chunk >= p_track->i_chunk_count - 1 || p_track->chunk[p_track->i_chunk].i_sample_description_index != p_track->chunk[i_chunk].i_sample_description_index ) { msg_Warn( p_demux, "recreate ES for track[Id 0x%x]", p_track->i_track_ID ); es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, p_track->p_es, &b_reselect ); es_out_Del( p_demux->out, p_track->p_es ); p_track->p_es = NULL; if( TrackCreateES( p_demux, p_track, i_chunk, &p_track->p_es ) ) { msg_Err( p_demux, "cannot create es for track[Id 0x%x]", p_track->i_track_ID ); p_track->b_ok = VLC_FALSE; p_track->b_selected = VLC_FALSE; return VLC_EGENERIC; } } /* select again the new decoder */ if( b_reselect ) { es_out_Control( p_demux->out, ES_OUT_SET_ES, p_track->p_es ); } p_track->i_chunk = i_chunk; p_track->i_sample = i_sample; return p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC;}/**************************************************************************** * MP4_TrackCreate: **************************************************************************** * Parse track information and create all needed data to run a track * If it succeed b_ok is set to 1 else to 0 ****************************************************************************/static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, MP4_Box_t *p_box_trak ){ demux_sys_t *p_sys = p_demux->p_sys; MP4_Box_t *p_tkhd = MP4_BoxGet( p_box_trak, "tkhd" ); MP4_Box_t *p_tref = MP4_BoxGet( p_box_trak, "tref" ); MP4_Box_t *p_elst; MP4_Box_t *p_mdhd; MP4_Box_t *p_udta; MP4_Box_t *p_hdlr; MP4_Box_t *p_vmhd; MP4_Box_t *p_smhd; MP4_Box_t *p_drms; unsigned int i; char language[4]; /* hint track unsupported */ /* set default value (-> track unusable) */ p_track->b_ok = VLC_FALSE; p_track->b_enable = VLC_FALSE; p_track->b_selected = VLC_FALSE; es_format_Init( &p_track->fmt, UNKNOWN_ES, 0 ); if( !p_tkhd ) { return; } /* do we launch this track by default ? */ p_track->b_enable = ( ( p_tkhd->data.p_tkhd->i_flags&MP4_TRACK_ENABLED ) != 0 ); p_track->i_track_ID = p_tkhd->data.p_tkhd->i_track_ID; p_track->i_width = p_tkhd->data.p_tkhd->i_width / 65536; p_track->i_height = p_tkhd->data.p_tkhd->i_height / 65536; if( p_tref ) {/* msg_Warn( p_demux, "unhandled box: tref --> FIXME" ); */ } p_mdhd = MP4_BoxGet( p_box_trak, "mdia/mdhd" ); p_hdlr = MP4_BoxGet( p_box_trak, "mdia/hdlr" ); if( ( !p_mdhd )||( !p_hdlr ) ) { return; } p_track->i_timescale = p_mdhd->data.p_mdhd->i_timescale; for( i = 0; i < 3; i++ ) { language[i] = p_mdhd->data.p_mdhd->i_language[i]; } language[3] = '\0'; switch( p_hdlr->data.p_hdlr->i_handler_type ) { case( FOURCC_soun ): if( !( p_smhd = MP4_BoxGet( p_box_trak, "mdia/minf/smhd" ) ) ) { return; } p_track->fmt.i_cat = AUDIO_ES; break; case( FOURCC_vide ): if( !( p_vmhd = MP4_BoxGet( p_box_trak, "mdia/minf/vmhd" ) ) ) { return; } p_track->fmt.i_cat = VIDEO_ES; break; case( FOURCC_text ): case( FOURCC_subp ): case( FOURCC_tx3g ): p_track->fmt.i_cat = SPU_ES; break; default: return; } p_track->i_elst = 0; p_track->i_elst_time = 0; if( ( p_track->p_elst = p_elst = MP4_BoxGet( p_box_trak, "edts/elst" ) ) ) { MP4_Box_data_elst_t *elst = p_elst->data.p_elst; unsigned int i; msg_Warn( p_demux, "elst box found" ); for( i = 0; i < elst->i_entry_count; i++ ) { msg_Dbg( p_demux, " - [%d] duration="I64Fd"ms media time="I64Fd "ms) rate=%d.%d", i, elst->i_segment_duration[i] * 1000 / p_sys->i_timescale, elst->i_media_time[i] >= 0 ? (int64_t)(elst->i_media_time[i] * 1000 / p_track->i_timescale) : I64C(-1), elst->i_media_rate_integer[i], elst->i_media_rate_fraction[i] ); } }/* TODO add support for: p_dinf = MP4_BoxGet( p_minf, "dinf" );*/ if( !( p_track->p_stbl = MP4_BoxGet( p_box_trak,"mdia/minf/stbl" ) ) || !( p_track->p_stsd = MP4_BoxGet( p_box_trak,"mdia/minf/stbl/stsd") ) ) { return; } p_drms = MP4_BoxGet( p_track->p_stsd, "drms" ); p_track->b_drms = p_drms != NULL; p_track->p_drms = p_track->b_drms ? p_drms->data.p_sample_soun->p_drms : NULL; /* Set language */ if( strcmp( language, "```" ) && strcmp( language, "und" ) ) { p_track->fmt.psz_language = strdup( language ); } p_udta = MP4_BoxGet( p_box_trak, "udta" ); if( p_udta ) { MP4_Box_t *p_0xa9xxx; for( p_0xa9xxx = p_udta->p_first; p_0xa9xxx != NULL; p_0xa9xxx = p_0xa9xxx->p_next ) { switch( p_0xa9xxx->i_type ) { case FOURCC_0xa9nam: p_track->fmt.psz_description = strdup( p_0xa9xxx->data.p_0xa9xxx->psz_text ); break; } } } /* Create chunk index table and sample index table */ if( TrackCreateChunksIndex( p_demux,p_track ) || TrackCreateSamplesIndex( p_demux, p_track ) ) { return; /* cannot create chunks index */ } p_track->i_chunk = 0; p_track->i_sample = 0; /* now create es */ if( TrackCreateES( p_demux, p_track, p_track->i_chunk, &p_track->p_es ) ) { msg_Err( p_demux, "cannot create es for track[Id 0x%x]", p_track->i_track_ID ); return; }#if 0 { int i; for( i = 0; i < p_track->i_chunk_count; i++ ) { fprintf( stderr, "%-5d sample_count=%d pts=%lld\n", i, p_track->chunk[i].i_sample_count, p_track->chunk[i].i_first_dts ); } }#endif p_track->b_ok = VLC_TRUE;}/**************************************************************************** * MP4_TrackDestroy: **************************************************************************** * Destroy a track created by MP4_TrackCreate. ****************************************************************************/static void MP4_TrackDestroy( demux_t *p_demux, mp4_track_t *p_track ){ unsigned int i_chunk; p_track->b_ok = VLC_FALSE; p_track->b_enable = VLC_FALSE; p_track->b_selected = VLC_FALSE; es_format_Clean( &p_track->fmt ); for( i_chunk = 0; i_chunk < p_track->i_chunk_count; i_chunk++ ) { if( p_track->chunk ) { FREE(p_track
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -