📄 mp4.c
字号:
/* First update update global time */ p_sys->i_time = i_date * p_sys->i_timescale / 1000000; p_sys->i_pcr = i_date; /* Now for each stream try to go to this time */ for( i_track = 0; i_track < p_sys->i_tracks; i_track++ ) { mp4_track_t *tk = &p_sys->track[i_track]; MP4_TrackSeek( p_demux, tk, i_date ); } MP4_UpdateSeekpoint( p_demux ); return VLC_SUCCESS;}/***************************************************************************** * Control: *****************************************************************************/static int Control( demux_t *p_demux, int i_query, va_list args ){ demux_sys_t *p_sys = p_demux->p_sys; double f, *pf; int64_t i64, *pi64; switch( i_query ) { case DEMUX_GET_POSITION: pf = (double*)va_arg( args, double * ); if( p_sys->i_duration > 0 ) { *pf = (double)p_sys->i_time / (double)p_sys->i_duration; } else { *pf = 0.0; } return VLC_SUCCESS; case DEMUX_SET_POSITION: f = (double)va_arg( args, double ); if( p_sys->i_timescale > 0 ) { i64 = (int64_t)( f * (double)1000000 * (double)p_sys->i_duration / (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 *p_meta = (vlc_meta_t *)va_arg( args, vlc_meta_t*); MP4_Box_t *p_0xa9xxx; MP4_Box_t *p_udta = MP4_BoxGet( p_sys->p_root, "/moov/udta/meta/ilst" ); if( p_udta == NULL ) { p_udta = MP4_BoxGet( p_sys->p_root, "/moov/udta" ); if( p_udta == NULL ) { return VLC_EGENERIC; } } for( p_0xa9xxx = p_udta->p_first; p_0xa9xxx != NULL; p_0xa9xxx = p_0xa9xxx->p_next ) { if( !p_0xa9xxx || !p_0xa9xxx->data.p_0xa9xxx ) continue; /* FIXME FIXME: should convert from whatever the character * encoding of MP4 meta data is to UTF-8. */#define SET(fct) do { char *psz_utf = strdup( p_0xa9xxx->data.p_0xa9xxx->psz_text ? p_0xa9xxx->data.p_0xa9xxx->psz_text : "" ); \ if( psz_utf ) { EnsureUTF8( psz_utf ); \ fct( p_meta, psz_utf ); free( psz_utf ); } } while(0) /* XXX Becarefull p_udta can have box that are not 0xa9xx */ switch( p_0xa9xxx->i_type ) { case FOURCC_0xa9nam: /* Full name */ SET( vlc_meta_SetTitle ); break; case FOURCC_0xa9aut: SET( vlc_meta_SetArtist ); break; case FOURCC_0xa9ART: SET( vlc_meta_SetArtist ); break; case FOURCC_0xa9cpy: SET( vlc_meta_SetCopyright ); break; case FOURCC_0xa9day: /* Creation Date */ SET( vlc_meta_SetDate ); break; case FOURCC_0xa9des: /* Description */ SET( vlc_meta_SetDescription ); break; case FOURCC_0xa9gen: /* Genre */ SET( vlc_meta_SetGenre ); break; case FOURCC_0xa9alb: /* Album */ SET( vlc_meta_SetAlbum ); break; case FOURCC_0xa9trk: /* Track */ SET( vlc_meta_SetTracknum ); break; case FOURCC_0xa9cmt: /* Commment */ SET( vlc_meta_SetDescription ); break; case FOURCC_0xa9url: /* URL */ SET( vlc_meta_SetURL ); break; case FOURCC_0xa9enc: /* Encoded By */ SET( vlc_meta_SetEncodedBy ); break; case FOURCC_0xa9swr: case FOURCC_0xa9inf: /* Information */ case FOURCC_0xa9dir: /* Director */ case FOURCC_0xa9dis: /* Disclaimer */ 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;#undef SET default: break; } } return VLC_SUCCESS; } case DEMUX_GET_TITLE_INFO: { input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** ); int *pi_int = (int*)va_arg( args, int* ); int *pi_title_offset = (int*)va_arg( args, int* ); int *pi_seekpoint_offset = (int*)va_arg( args, int* ); if( !p_sys->p_title ) return VLC_EGENERIC; *pi_int = 1; *ppp_title = malloc( sizeof( input_title_t**) ); (*ppp_title)[0] = vlc_input_title_Duplicate( p_sys->p_title ); *pi_title_offset = 0; *pi_seekpoint_offset = 0; return VLC_SUCCESS; } case DEMUX_SET_TITLE: { const int i_title = (int)va_arg( args, int ); if( !p_sys->p_title || i_title != 0 ) return VLC_EGENERIC; return VLC_SUCCESS; } case DEMUX_SET_SEEKPOINT: { const int i_seekpoint = (int)va_arg( args, int ); if( !p_sys->p_title ) return VLC_EGENERIC; return Seek( p_demux, p_sys->p_title->seekpoint[i_seekpoint]->i_time_offset ); } case DEMUX_SET_NEXT_DEMUX_TIME: case DEMUX_SET_GROUP: case DEMUX_HAS_UNSUPPORTED_META: case DEMUX_GET_ATTACHMENTS: return VLC_EGENERIC; default: msg_Warn( p_demux, "control query %u unimplemented", i_query ); return VLC_EGENERIC; }}/***************************************************************************** * Close: frees unused data *****************************************************************************/static void Close ( vlc_object_t * p_this ){ demux_t * p_demux = (demux_t *)p_this; demux_sys_t *p_sys = p_demux->p_sys; unsigned int i_track; 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_sys->track[i_track] ); } FREENULL( p_sys->track ); if( p_sys->p_title ) vlc_input_title_Delete( p_sys->p_title ); free( p_sys );}/**************************************************************************** * Local functions, specific to vlc ****************************************************************************//* Chapters */static void LoadChapterGpac( demux_t *p_demux, MP4_Box_t *p_chpl ){ demux_sys_t *p_sys = p_demux->p_sys; int i; p_sys->p_title = vlc_input_title_New(); for( i = 0; i < p_chpl->data.p_chpl->i_chapter; i++ ) { seekpoint_t *s = vlc_seekpoint_New(); s->psz_name = strdup( p_chpl->data.p_chpl->chapter[i].psz_name ); EnsureUTF8( s->psz_name ); s->i_time_offset = p_chpl->data.p_chpl->chapter[i].i_start / 10; TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s ); }}static void LoadChapterApple( demux_t *p_demux, mp4_track_t *tk ){ demux_sys_t *p_sys = p_demux->p_sys; for( tk->i_sample = 0; tk->i_sample < tk->i_sample_count; tk->i_sample++ ) { const int64_t i_dts = MP4_TrackGetDTS( p_demux, tk ); const int64_t i_pts_delta = MP4_TrackGetPTSDelta( tk ); const unsigned int i_size = MP4_TrackSampleSize( tk ); if( i_size > 0 && !stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) ) { char p_buffer[256]; const int i_read = stream_Read( p_demux->s, p_buffer, __MIN( sizeof(p_buffer), i_size ) ); const int i_len = __MIN( GetWBE(p_buffer), i_read-2 ); if( i_len > 0 ) { seekpoint_t *s = vlc_seekpoint_New(); s->psz_name = strndup( &p_buffer[2], i_len ); EnsureUTF8( s->psz_name ); s->i_time_offset = i_dts + __MAX( i_pts_delta, 0 ); if( !p_sys->p_title ) p_sys->p_title = vlc_input_title_New(); TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s ); } } if( tk->i_sample+1 >= tk->chunk[tk->i_chunk].i_sample_first + tk->chunk[tk->i_chunk].i_sample_count ) tk->i_chunk++; }}static void LoadChapter( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; MP4_Box_t *p_chpl; if( ( p_chpl = MP4_BoxGet( p_sys->p_root, "/moov/udta/chpl" ) ) && p_chpl->data.p_chpl->i_chapter > 0 ) { LoadChapterGpac( p_demux, p_chpl ); } else if( p_sys->p_tref_chap ) { MP4_Box_data_tref_generic_t *p_chap = p_sys->p_tref_chap->data.p_tref_generic; unsigned int i, j; /* Load the first subtitle track like quicktime */ for( i = 0; i < p_chap->i_entry_count; i++ ) { for( j = 0; j < p_sys->i_tracks; j++ ) { mp4_track_t *tk = &p_sys->track[j]; if( tk->b_ok && tk->i_track_ID == p_chap->i_track_ID[i] && tk->fmt.i_cat == SPU_ES && tk->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) ) break; } if( j < p_sys->i_tracks ) { LoadChapterApple( p_demux, &p_sys->track[j] ); break; } } }}/* 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 ) ); if( p_demux_track->chunk == NULL ) { return VLC_ENOMEM; } /* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -