📄 mp4.c
字号:
ck->p_sample_delta_dts = NULL; ck->p_sample_count_pts = NULL; ck->p_sample_offset_pts = NULL; } /* now we read index for SampleEntry( soun vide mp4a mp4v ...) to be used for the sample XXX begin to 1 We construct it begining at the end */ i_last = p_demux_track->i_chunk_count; /* last chunk proceded */ i_index = p_stsc->data.p_stsc->i_entry_count; if( !i_index ) { msg_Warn( p_demux, "cannot read chunk table or table empty" ); return( VLC_EGENERIC ); } while( i_index-- ) { for( i_chunk = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1; i_chunk < i_last; i_chunk++ ) { if( i_chunk >= p_demux_track->i_chunk_count ) { msg_Warn( p_demux, "corrupted chunk table" ); return VLC_EGENERIC; } p_demux_track->chunk[i_chunk].i_sample_description_index = p_stsc->data.p_stsc->i_sample_description_index[i_index]; p_demux_track->chunk[i_chunk].i_sample_count = p_stsc->data.p_stsc->i_samples_per_chunk[i_index]; } i_last = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1; } p_demux_track->chunk[0].i_sample_first = 0; for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) { p_demux_track->chunk[i_chunk].i_sample_first = p_demux_track->chunk[i_chunk-1].i_sample_first + p_demux_track->chunk[i_chunk-1].i_sample_count; } msg_Dbg( p_demux, "track[Id 0x%x] read %d chunk", p_demux_track->i_track_ID, p_demux_track->i_chunk_count ); return VLC_SUCCESS;}static int TrackCreateSamplesIndex( demux_t *p_demux, mp4_track_t *p_demux_track ){ MP4_Box_t *p_box; MP4_Box_data_stsz_t *stsz; MP4_Box_data_stts_t *stts; /* TODO use also stss and stsh table for seeking */ /* FIXME use edit table */ int64_t i_sample; int64_t i_chunk; int64_t i_index; int64_t i_index_sample_used; int64_t i_last_dts; /* Find stsz * Gives the sample size for each samples. There is also a stz2 table * (compressed form) that we need to implement TODO */ p_box = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); if( !p_box ) { /* FIXME and stz2 */ msg_Warn( p_demux, "cannot find STSZ box" ); return VLC_EGENERIC; } stsz = p_box->data.p_stsz; /* Find stts * Gives mapping between sample and decoding time */ p_box = MP4_BoxGet( p_demux_track->p_stbl, "stts" ); if( !p_box ) { msg_Warn( p_demux, "cannot find STTS box" ); return VLC_EGENERIC; } stts = p_box->data.p_stts; /* Use stsz table to create a sample number -> sample size table */ p_demux_track->i_sample_count = stsz->i_sample_count; if( stsz->i_sample_size ) { /* 1: all sample have the same size, so no need to construct a table */ p_demux_track->i_sample_size = stsz->i_sample_size; p_demux_track->p_sample_size = NULL; } else { /* 2: each sample can have a different size */ p_demux_track->i_sample_size = 0; p_demux_track->p_sample_size = calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) ); if( p_demux_track->p_sample_size == NULL ) return VLC_ENOMEM; for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ ) { p_demux_track->p_sample_size[i_sample] = stsz->i_entry_size[i_sample]; } } /* Use stts table to create a sample number -> dts table. * XXX: if we don't want to waste too much memory, we can't expand * the box! so each chunk will contain an "extract" of this table * for fast research (problem with raw stream where a sample is sometime * just channels*bits_per_sample/8 */ i_last_dts = 0; i_index = 0; i_index_sample_used = 0; for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) { mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk]; int64_t i_entry, i_sample_count, i; /* save last dts */ ck->i_first_dts = i_last_dts; /* count how many entries are needed for this chunk * for p_sample_delta_dts and p_sample_count_dts */ i_sample_count = ck->i_sample_count; i_entry = 0; while( i_sample_count > 0 ) { i_sample_count -= stts->i_sample_count[i_index+i_entry]; /* don't count already used sample in this entry */ if( i_entry == 0 ) i_sample_count += i_index_sample_used; i_entry++; } /* allocate them */ ck->p_sample_count_dts = calloc( i_entry, sizeof( uint32_t ) ); ck->p_sample_delta_dts = calloc( i_entry, sizeof( uint32_t ) ); if( !ck->p_sample_count_dts || !ck->p_sample_delta_dts ) return VLC_ENOMEM; /* now copy */ i_sample_count = ck->i_sample_count; for( i = 0; i < i_entry; i++ ) { int64_t i_used; int64_t i_rest; i_rest = stts->i_sample_count[i_index] - i_index_sample_used; i_used = __MIN( i_rest, i_sample_count ); i_index_sample_used += i_used; i_sample_count -= i_used; ck->p_sample_count_dts[i] = i_used; ck->p_sample_delta_dts[i] = stts->i_sample_delta[i_index]; i_last_dts += i_used * ck->p_sample_delta_dts[i]; if( i_index_sample_used >= stts->i_sample_count[i_index] ) { i_index++; i_index_sample_used = 0; } } } /* Find ctts * Gives the delta between decoding time (dts) and composition table (pts) */ p_box = MP4_BoxGet( p_demux_track->p_stbl, "ctts" ); if( p_box ) { MP4_Box_data_ctts_t *ctts = p_box->data.p_ctts; msg_Warn( p_demux, "CTTS table" ); /* Create pts-dts table per chunk */ i_index = 0; i_index_sample_used = 0; for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) { mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk]; int64_t i_entry, i_sample_count, i; /* count how many entries are needed for this chunk * for p_sample_delta_dts and p_sample_count_dts */ i_sample_count = ck->i_sample_count; i_entry = 0; while( i_sample_count > 0 ) { i_sample_count -= ctts->i_sample_count[i_index+i_entry]; /* don't count already used sample in this entry */ if( i_entry == 0 ) i_sample_count += i_index_sample_used; i_entry++; } /* allocate them */ ck->p_sample_count_pts = calloc( i_entry, sizeof( uint32_t ) ); ck->p_sample_offset_pts = calloc( i_entry, sizeof( int32_t ) ); if( !ck->p_sample_count_pts || !ck->p_sample_offset_pts ) return VLC_ENOMEM; /* now copy */ i_sample_count = ck->i_sample_count; for( i = 0; i < i_entry; i++ ) { int64_t i_used; int64_t i_rest; i_rest = ctts->i_sample_count[i_index] - i_index_sample_used; i_used = __MIN( i_rest, i_sample_count ); i_index_sample_used += i_used; i_sample_count -= i_used; ck->p_sample_count_pts[i] = i_used; ck->p_sample_offset_pts[i] = ctts->i_sample_offset[i_index]; if( i_index_sample_used >= ctts->i_sample_count[i_index] ) { i_index++; i_index_sample_used = 0; } } } } msg_Dbg( p_demux, "track[Id 0x%x] read %d samples length:%"PRId64"s", p_demux_track->i_track_ID, p_demux_track->i_sample_count, i_last_dts / p_demux_track->i_timescale ); return VLC_SUCCESS;}/* * TrackCreateES: * Create ES and PES to init decoder if needed, for a track starting at i_chunk */static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, unsigned int i_chunk, es_out_id_t **pp_es ){ MP4_Box_t *p_sample; MP4_Box_t *p_esds; MP4_Box_t *p_box; if( pp_es ) *pp_es = NULL; if( !p_track->chunk[i_chunk].i_sample_description_index ) { msg_Warn( p_demux, "invalid SampleEntry index (track[Id 0x%x])", p_track->i_track_ID ); return VLC_EGENERIC; } p_sample = MP4_BoxGet( p_track->p_stsd, "[%d]", p_track->chunk[i_chunk].i_sample_description_index - 1 ); if( !p_sample || ( !p_sample->data.p_data && p_track->fmt.i_cat != SPU_ES ) ) { msg_Warn( p_demux, "cannot find SampleEntry (track[Id 0x%x])", p_track->i_track_ID ); return VLC_EGENERIC; } p_track->p_sample = p_sample; if( p_track->fmt.i_cat == AUDIO_ES && ( p_track->i_sample_size == 1 || p_track->i_sample_size == 2 ) ) { MP4_Box_data_sample_soun_t *p_soun; p_soun = p_sample->data.p_sample_soun; if( p_soun->i_qt_version == 0 ) { switch( p_sample->i_type ) { case VLC_FOURCC( 'i', 'm', 'a', '4' ): p_soun->i_qt_version = 1; p_soun->i_sample_per_packet = 64; p_soun->i_bytes_per_packet = 34; p_soun->i_bytes_per_frame = 34 * p_soun->i_channelcount; p_soun->i_bytes_per_sample = 2; break; case VLC_FOURCC( 'M', 'A', 'C', '3' ): p_soun->i_qt_version = 1; p_soun->i_sample_per_packet = 6; p_soun->i_bytes_per_packet = 2; p_soun->i_bytes_per_frame = 2 * p_soun->i_channelcount; p_soun->i_bytes_per_sample = 2; break; case VLC_FOURCC( 'M', 'A', 'C', '6' ): p_soun->i_qt_version = 1; p_soun->i_sample_per_packet = 12; p_soun->i_bytes_per_packet = 2; p_soun->i_bytes_per_frame = 2 * p_soun->i_channelcount; p_soun->i_bytes_per_sample = 2; break; case VLC_FOURCC( 'a', 'l', 'a', 'w' ): case VLC_FOURCC( 'u', 'l', 'a', 'w' ): p_soun->i_samplesize = 8; break; case VLC_FOURCC( 'N', 'O', 'N', 'E' ): case VLC_FOURCC( 'r', 'a', 'w', ' ' ): case VLC_FOURCC( 't', 'w', 'o', 's' ): case VLC_FOURCC( 's', 'o', 'w', 't' ): /* What would be the fun if you could trust the .mov */ p_track->i_sample_size = ((p_soun->i_samplesize+7)/8) * p_soun->i_channelcount; break; default: break; } } else if( p_soun->i_qt_version == 1 && p_soun->i_sample_per_packet <= 0 ) { p_soun->i_qt_version = 0; } } /* It's a little ugly but .. there are special cases */ switch( p_sample->i_type ) { case( VLC_FOURCC( '.', 'm', 'p', '3' ) ): case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ): { MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun; p_track->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' ); if( p_track->i_sample_size > 1 ) p_soun->i_qt_version = 0; break; } case( VLC_FOURCC( 'r', 'a', 'w', ' ' ) ): case( VLC_FOURCC( 'N', 'O', 'N', 'E' ) ): { MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun; if(p_soun && (p_soun->i_samplesize+7)/8 == 1 ) p_track->fmt.i_codec = VLC_FOURCC( 'u', '8', ' ', ' ' ); else p_track->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' ); /* Buggy files workaround */ if( p_sample->data.p_sample_soun && (p_track->i_timescale != p_sample->data.p_sample_soun->i_sampleratehi) ) { MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun; msg_Warn( p_demux, "i_timescale (%"PRIu64") != i_sampleratehi " "(%u), 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -