📄 mp4.c
字号:
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_input, "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; 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; int i; msg_Warn( p_input, "elst box found" ); for( i = 0; i < elst->i_entry_count; i++ ) { msg_Dbg( p_input, " - [%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 ? elst->i_media_time[i] * 1000 / p_track->i_timescale : -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 ); } /* fxi i_timescale for AUDIO_ES with i_qt_version == 0 */ if( p_track->fmt.i_cat == AUDIO_ES ) //&& p_track->i_sample_size == 1 ) { MP4_Box_t *p_sample; p_sample = MP4_BoxGet( p_track->p_stsd, "[0]" ); if( p_sample && p_sample->data.p_sample_soun) { MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun; if( p_soun->i_qt_version == 0 && p_track->i_timescale != p_soun->i_sampleratehi ) { msg_Warn( p_input, "i_timescale ("I64Fu") != i_sampleratehi (%u) with " "qt_version == 0\n" "Making both equal. (report any problem)", p_track->i_timescale, p_soun->i_sampleratehi ); if( p_soun->i_sampleratehi ) p_track->i_timescale = p_soun->i_sampleratehi; else p_soun->i_sampleratehi = p_track->i_timescale; } } } /* Create chunk index table and sample index table */ if( TrackCreateChunksIndex( p_input,p_track ) || TrackCreateSamplesIndex( p_input, p_track ) ) { return; /* cannot create chunks index */ } p_track->i_chunk = 0; p_track->i_sample = 0; /* now create es */ if( TrackCreateES( p_input, p_track, p_track->i_chunk, &p_track->p_es ) ) { msg_Err( p_input, "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( input_thread_t *p_input, 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_Init( &p_track->fmt, UNKNOWN_ES, 0 ); for( i_chunk = 0; i_chunk < p_track->i_chunk_count; i_chunk++ ) { if( p_track->chunk ) { FREE(p_track->chunk[i_chunk].p_sample_count_dts); FREE(p_track->chunk[i_chunk].p_sample_delta_dts ); } } FREE( p_track->chunk ); if( !p_track->i_sample_size ) { FREE( p_track->p_sample_size ); }}static int MP4_TrackSelect ( input_thread_t *p_input, mp4_track_t *p_track, mtime_t i_start ){ if( !p_track->b_ok ) { return VLC_EGENERIC; } if( p_track->b_selected ) { msg_Warn( p_input, "track[Id 0x%x] already selected", p_track->i_track_ID ); return VLC_SUCCESS; } return MP4_TrackSeek( p_input, p_track, i_start );}static void MP4_TrackUnselect(input_thread_t *p_input, mp4_track_t *p_track ){ if( !p_track->b_ok ) { return; } if( !p_track->b_selected ) { msg_Warn( p_input, "track[Id 0x%x] already unselected", p_track->i_track_ID ); return; } if( p_track->p_es ) { es_out_Control( p_input->p_es_out, ES_OUT_SET_ES_STATE, p_track->p_es, VLC_FALSE ); } p_track->b_selected = VLC_FALSE;}static int MP4_TrackSeek ( input_thread_t *p_input, mp4_track_t *p_track, mtime_t i_start ){ uint32_t i_chunk; uint32_t i_sample; if( !p_track->b_ok ) { return( VLC_EGENERIC ); } if( TrackTimeToSampleChunk( p_input, p_track, i_start, &i_chunk, &i_sample ) ) { msg_Warn( p_input, "cannot select track[Id 0x%x]", p_track->i_track_ID ); return( VLC_EGENERIC ); } p_track->b_selected = VLC_TRUE; if( TrackGotoChunkSample( p_input, p_track, i_chunk, i_sample ) ) { p_track->b_selected = VLC_FALSE; } return( p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC );}/* * 3 types: for audio * */#define QT_V0_MAX_SAMPLES 1500static int MP4_TrackSampleSize( mp4_track_t *p_track ){ int i_size; MP4_Box_data_sample_soun_t *p_soun; if( p_track->i_sample_size == 0 ) { /* most simple case */ return( p_track->p_sample_size[p_track->i_sample] ); } if( p_track->fmt.i_cat != AUDIO_ES ) { return( p_track->i_sample_size ); } if( p_track->i_sample_size != 1 ) { //msg_Warn( p_input, "SampleSize != 1" ); return( p_track->i_sample_size ); } p_soun = p_track->p_sample->data.p_sample_soun; if( p_soun->i_qt_version == 1 ) { i_size = p_track->chunk[p_track->i_chunk].i_sample_count / p_soun->i_sample_per_packet * p_soun->i_bytes_per_frame; } else { /* FIXME */ int i_samples = p_track->chunk[p_track->i_chunk].i_sample_count - ( p_track->i_sample - p_track->chunk[p_track->i_chunk].i_sample_first ); if( i_samples > QT_V0_MAX_SAMPLES ) { i_samples = QT_V0_MAX_SAMPLES; } i_size = i_samples * p_soun->i_channelcount * p_soun->i_samplesize / 8; } //fprintf( stderr, "size=%d\n", i_size ); return( i_size );}static uint64_t MP4_TrackGetPos( mp4_track_t *p_track ){ unsigned int i_sample; uint64_t i_pos; i_pos = p_track->chunk[p_track->i_chunk].i_offset; if( p_track->i_sample_size ) { MP4_Box_data_sample_soun_t *p_soun = p_track->p_sample->data.p_sample_soun; if( p_soun->i_qt_version == 0 ) { i_pos += ( p_track->i_sample - p_track->chunk[p_track->i_chunk].i_sample_first ) * p_soun->i_channelcount * p_soun->i_samplesize / 8; } else { /* we read chunk by chunk */ i_pos += 0; } } else { for( i_sample = p_track->chunk[p_track->i_chunk].i_sample_first; i_sample < p_track->i_sample; i_sample++ ) { i_pos += p_track->p_sample_size[i_sample]; } } return( i_pos );}static int MP4_TrackNextSample( input_thread_t *p_input, mp4_track_t *p_track ){ if( p_track->fmt.i_cat == AUDIO_ES && p_track->i_sample_size != 0 ) { MP4_Box_data_sample_soun_t *p_soun; p_soun = p_track->p_sample->data.p_sample_soun; if( p_soun->i_qt_version == 1 ) { /* chunk by chunk */ p_track->i_sample = p_track->chunk[p_track->i_chunk].i_sample_first + p_track->chunk[p_track->i_chunk].i_sample_count; } else { /* FIXME */ p_track->i_sample += QT_V0_MAX_SAMPLES; if( p_track->i_sample > p_track->chunk[p_track->i_chunk].i_sample_first + p_track->chunk[p_track->i_chunk].i_sample_count ) { p_track->i_sample = p_track->chunk[p_track->i_chunk].i_sample_first + p_track->chunk[p_track->i_chunk].i_sample_count; } } } else { p_track->i_sample++; } if( p_track->i_sample >= p_track->i_sample_count ) { /* we have reach end of the track so free decoder stuff */ msg_Warn( p_input, "track[0x%x] will be disabled", p_track->i_track_ID ); MP4_TrackUnselect( p_input, p_track ); return VLC_EGENERIC; } /* Have we changed chunk ? */ if( p_track->i_sample >= p_track->chunk[p_track->i_chunk].i_sample_first + p_track->chunk[p_track->i_chunk].i_sample_count ) { if( TrackGotoChunkSample( p_input, p_track, p_track->i_chunk + 1, p_track->i_sample ) ) { msg_Warn( p_input, "track[0x%x] will be disabled (cannot restart decoder)", p_track->i_track_ID ); MP4_TrackUnselect( p_input, p_track ); return VLC_EGENERIC; } } /* Have we changed elst */ if( p_track->p_elst && p_track->p_elst->data.p_elst->i_entry_count > 0 ) { demux_sys_t *p_sys = p_input->p_demux_data; MP4_Box_data_elst_t *elst = p_track->p_elst->data.p_elst; int64_t i_mvt = MP4_TrackGetPTS( p_input, p_track ) * p_sys->i_timescale / (int64_t)1000000; if( p_track->i_elst < elst->i_entry_count && i_mvt >= p_track->i_elst_time + elst->i_segment_duration[p_track->i_elst] ) { MP4_TrackSetELST( p_input, p_track, MP4_TrackGetPTS( p_input, p_track ) ); } } return VLC_SUCCESS;}static void MP4_TrackSetELST( input_thread_t *p_input, mp4_track_t *tk, int64_t i_time ){ demux_sys_t *p_sys = p_input->p_demux_data; int i_elst_last = tk->i_elst; /* handle elst (find the correct one) */ tk->i_elst = 0; tk->i_elst_time = 0; if( tk->p_elst && tk->p_elst->data.p_elst->i_entry_count > 0 ) { MP4_Box_data_elst_t *elst = tk->p_elst->data.p_elst; int64_t i_mvt= i_time * p_sys->i_timescale / (int64_t)1000000; for( tk->i_elst = 0; tk->i_elst < elst->i_entry_count; tk->i_elst++ ) { mtime_t i_dur = elst->i_segment_duration[tk->i_elst]; if( tk->i_elst_time <= i_mvt && i_mvt < tk->i_elst_time + i_dur ) { break; } tk->i_elst_time += i_dur; } if( tk->i_elst >= elst->i_entry_count ) { /* msg_Dbg( p_input, "invalid number of entry in elst" ); */ tk->i_elst = elst->i_entry_count - 1; tk->i_elst_time -= elst->i_segment_duration[tk->i_elst]; } if( elst->i_media_time[tk->i_elst] < 0 ) { /* track offset */ tk->i_elst_time += elst->i_segment_duration[tk->i_elst]; } } if( i_elst_last != tk->i_elst ) { msg_Warn( p_input, "elst old=%d new=%d", i_elst_last, tk->i_elst ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -