📄 mp4.c
字号:
(double)p_sys->i_timescale ); return Seek( p_demux, i64 ); } else return VLC_SUCCESS; case DEMUX_GET_TIME: pi64 = (int64_t*)va_arg( args, int64_t * ); if( p_sys->i_timescale > 0 ) { *pi64 = (mtime_t)1000000 * (mtime_t)p_sys->i_time / (mtime_t)p_sys->i_timescale; } else *pi64 = 0; return VLC_SUCCESS; case DEMUX_SET_TIME: i64 = (int64_t)va_arg( args, int64_t ); return Seek( p_demux, i64 ); case DEMUX_GET_LENGTH: pi64 = (int64_t*)va_arg( args, int64_t * ); if( p_sys->i_timescale > 0 ) { *pi64 = (mtime_t)1000000 * (mtime_t)p_sys->i_duration / (mtime_t)p_sys->i_timescale; } else *pi64 = 0; return VLC_SUCCESS; case DEMUX_GET_FPS: msg_Warn( p_demux, "DEMUX_GET_FPS unimplemented !!" ); return VLC_EGENERIC; case DEMUX_GET_META: { vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** ); vlc_meta_t *meta; MP4_Box_t *p_udta = MP4_BoxGet( p_sys->p_root, "/moov/udta" ); MP4_Box_t *p_0xa9xxx; if( p_udta == NULL ) { return VLC_EGENERIC; } *pp_meta = meta = vlc_meta_New(); for( p_0xa9xxx = p_udta->p_first; p_0xa9xxx != NULL; p_0xa9xxx = p_0xa9xxx->p_next ) { switch( p_0xa9xxx->i_type ) { case FOURCC_0xa9nam: /* Full name */ vlc_meta_Add( meta, VLC_META_TITLE, p_0xa9xxx->data.p_0xa9xxx->psz_text ); break; case FOURCC_0xa9aut: vlc_meta_Add( meta, VLC_META_AUTHOR, p_0xa9xxx->data.p_0xa9xxx->psz_text ); break; case FOURCC_0xa9ART: vlc_meta_Add( meta, VLC_META_ARTIST, p_0xa9xxx->data.p_0xa9xxx->psz_text ); break; case FOURCC_0xa9cpy: vlc_meta_Add( meta, VLC_META_COPYRIGHT, p_0xa9xxx->data.p_0xa9xxx->psz_text ); break; case FOURCC_0xa9day: /* Creation Date */ vlc_meta_Add( meta, VLC_META_DATE, p_0xa9xxx->data.p_0xa9xxx->psz_text ); break; case FOURCC_0xa9des: /* Description */ vlc_meta_Add( meta, VLC_META_DESCRIPTION, p_0xa9xxx->data.p_0xa9xxx->psz_text ); break; case FOURCC_0xa9gen: /* Genre */ vlc_meta_Add( meta, VLC_META_GENRE, p_0xa9xxx->data.p_0xa9xxx->psz_text ); break; case FOURCC_0xa9swr: case FOURCC_0xa9inf: /* Information */ case FOURCC_0xa9alb: /* Album */ case FOURCC_0xa9dir: /* Director */ case FOURCC_0xa9dis: /* Disclaimer */ case FOURCC_0xa9enc: /* Encoded By */ case FOURCC_0xa9trk: /* Track */ case FOURCC_0xa9cmt: /* Commment */ case FOURCC_0xa9url: /* URL */ case FOURCC_0xa9req: /* Requirements */ case FOURCC_0xa9fmt: /* Original Format */ case FOURCC_0xa9dsa: /* Display Source As */ case FOURCC_0xa9hst: /* Host Computer */ case FOURCC_0xa9prd: /* Producer */ case FOURCC_0xa9prf: /* Performers */ case FOURCC_0xa9ope: /* Original Performer */ case FOURCC_0xa9src: /* Providers Source Content */ case FOURCC_0xa9wrt: /* Writer */ case FOURCC_0xa9com: /* Composer */ case FOURCC_WLOC: /* Window Location */ /* TODO one day, but they aren't really meaningfull */ break; default: break; } } return VLC_SUCCESS; } case DEMUX_GET_TITLE_INFO: case DEMUX_SET_NEXT_DEMUX_TIME: case DEMUX_SET_GROUP: return VLC_EGENERIC; default: msg_Warn( p_demux, "control query unimplemented !!!" ); return VLC_EGENERIC; }}/***************************************************************************** * Close: frees unused data *****************************************************************************/static void Close ( vlc_object_t * p_this ){ unsigned int i_track; demux_t * p_demux = (demux_t *)p_this; demux_sys_t *p_sys = p_demux->p_sys; msg_Dbg( p_demux, "freeing all memory" ); MP4_BoxFree( p_demux->s, p_sys->p_root ); for( i_track = 0; i_track < p_sys->i_tracks; i_track++ ) { MP4_TrackDestroy( p_demux, &p_sys->track[i_track] ); } FREE( p_sys->track ); free( p_sys );}/**************************************************************************** * Local functions, specific to vlc ****************************************************************************//* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */static int TrackCreateChunksIndex( demux_t *p_demux, mp4_track_t *p_demux_track ){ MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */ MP4_Box_t *p_stsc; unsigned int i_chunk; unsigned int i_index, i_last; if( ( !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "stco" ) )&& !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "co64" ) ) )|| ( !(p_stsc = MP4_BoxGet( p_demux_track->p_stbl, "stsc" ) ) )) { return( VLC_EGENERIC ); } p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count; if( !p_demux_track->i_chunk_count ) { msg_Warn( p_demux, "no chunk defined" ); return( VLC_EGENERIC ); } p_demux_track->chunk = calloc( p_demux_track->i_chunk_count, sizeof( mp4_chunk_t ) ); /* first we read chunk offset */ for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) { mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk]; ck->i_offset = p_co64->data.p_co64->i_chunk_offset[i_chunk]; ck->i_first_dts = 0; ck->p_sample_count_dts = NULL; 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++ ) { 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 ) ); 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 ) ); /* 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++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -