📄 mp4.c
字号:
/***************************************************************************** * mp4.c : MP4 file input module for vlc ***************************************************************************** * Copyright (C) 2001-2004 VideoLAN * $Id: mp4.c 11515 2005-06-24 20:39:26Z gbazin $ * Authors: Laurent Aimar <fenrir@via.ecp.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <stdlib.h> /* malloc(), free() */#include <vlc/vlc.h>#include <vlc/input.h>#include <vlc_playlist.h>#include "iso_lang.h"#include "vlc_meta.h"#include "libmp4.h"#include "drms.h"#ifdef UNDER_CE#define uint64_t int64_t#endif/***************************************************************************** * Module descriptor *****************************************************************************/static int Open ( vlc_object_t * );static void Close( vlc_object_t * );vlc_module_begin(); set_category( CAT_INPUT ); set_subcategory( SUBCAT_INPUT_DEMUX ); set_description( _("MP4 stream demuxer") ); set_capability( "demux2", 242 ); set_callbacks( Open, Close );vlc_module_end();/***************************************************************************** * Local prototypes *****************************************************************************/static int Demux ( demux_t * );static int DemuxRef( demux_t *p_demux ){ return 0;}static int Seek ( demux_t *, mtime_t );static int Control ( demux_t *, int, va_list );/* Contain all information about a chunk */typedef struct{ uint64_t i_offset; /* absolute position of this chunk in the file */ uint32_t i_sample_description_index; /* index for SampleEntry to use */ uint32_t i_sample_count; /* how many samples in this chunk */ uint32_t i_sample_first; /* index of the first sample in this chunk */ /* now provide way to calculate pts, dts, and offset without to much memory and with fast acces */ /* with this we can calculate dts/pts without waste memory */ uint64_t i_first_dts; uint32_t *p_sample_count_dts; uint32_t *p_sample_delta_dts; /* dts delta */ uint32_t *p_sample_count_pts; int32_t *p_sample_offset_pts; /* pts-dts */ /* TODO if needed add pts but quickly *add* support for edts and seeking */} mp4_chunk_t; /* Contain all needed information for read all track with vlc */typedef struct{ int i_track_ID; /* this should be unique */ int b_ok; /* The track is usable */ int b_enable; /* is the trak enable by default */ vlc_bool_t b_selected; /* is the trak being played */ es_format_t fmt; es_out_id_t *p_es; /* display size only ! */ int i_width; int i_height; /* more internal data */ uint64_t i_timescale; /* time scale for this track only */ /* elst */ int i_elst; /* current elst */ int64_t i_elst_time; /* current elst start time (in movie time scale)*/ MP4_Box_t *p_elst; /* elst (could be NULL) */ /* give the next sample to read, i_chunk is to find quickly where the sample is located */ uint32_t i_sample; /* next sample to read */ uint32_t i_chunk; /* chunk where next sample is stored */ /* total count of chunk and sample */ uint32_t i_chunk_count; uint32_t i_sample_count; mp4_chunk_t *chunk; /* always defined for each chunk */ /* sample size, p_sample_size defined only if i_sample_size == 0 else i_sample_size is size for all sample */ uint32_t i_sample_size; uint32_t *p_sample_size; /* XXX perhaps add file offset if take too much time to do sumations each time*/ MP4_Box_t *p_stbl; /* will contain all timing information */ MP4_Box_t *p_stsd; /* will contain all data to initialize decoder */ MP4_Box_t *p_sample;/* point on actual sdsd */ vlc_bool_t b_drms; void *p_drms;} mp4_track_t;struct demux_sys_t{ MP4_Box_t *p_root; /* container for the whole file */ mtime_t i_pcr; uint64_t i_time; /* time position of the presentation * in movie timescale */ uint64_t i_timescale; /* movie time scale */ uint64_t i_duration; /* movie duration */ unsigned int i_tracks; /* number of tracks */ mp4_track_t *track; /* array of track */};/***************************************************************************** * Declaration of local function *****************************************************************************/static void MP4_TrackCreate ( demux_t *, mp4_track_t *, MP4_Box_t *);static void MP4_TrackDestroy( demux_t *, mp4_track_t * );static int MP4_TrackSelect ( demux_t *, mp4_track_t *, mtime_t );static void MP4_TrackUnselect(demux_t *, mp4_track_t * );static int MP4_TrackSeek ( demux_t *, mp4_track_t *, mtime_t );static uint64_t MP4_TrackGetPos ( mp4_track_t * );static int MP4_TrackSampleSize( mp4_track_t * );static int MP4_TrackNextSample( demux_t *, mp4_track_t * );static void MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t );/* Return time in 祍 of a track */static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track ){#define chunk p_track->chunk[p_track->i_chunk] unsigned int i_index = 0; unsigned int i_sample = p_track->i_sample - chunk.i_sample_first; int64_t i_dts = chunk.i_first_dts; while( i_sample > 0 ) { if( i_sample > chunk.p_sample_count_dts[i_index] ) { i_dts += chunk.p_sample_count_dts[i_index] * chunk.p_sample_delta_dts[i_index]; i_sample -= chunk.p_sample_count_dts[i_index]; i_index++; } else { i_dts += i_sample * chunk.p_sample_delta_dts[i_index]; i_sample = 0; break; } }#undef chunk /* now handle elst */ if( p_track->p_elst ) { demux_sys_t *p_sys = p_demux->p_sys; MP4_Box_data_elst_t *elst = p_track->p_elst->data.p_elst; /* convert to offset */ if( ( elst->i_media_rate_integer[p_track->i_elst] > 0 || elst->i_media_rate_fraction[p_track->i_elst] > 0 ) && elst->i_media_time[p_track->i_elst] > 0 ) { i_dts -= elst->i_media_time[p_track->i_elst]; } /* add i_elst_time */ i_dts += p_track->i_elst_time * p_track->i_timescale / p_sys->i_timescale; if( i_dts < 0 ) i_dts = 0; } return I64C(1000000) * i_dts / p_track->i_timescale;}static inline int64_t MP4_TrackGetPTSDelta( demux_t *p_demux, mp4_track_t *p_track ){ mp4_chunk_t *ck = &p_track->chunk[p_track->i_chunk]; unsigned int i_index = 0; unsigned int i_sample = p_track->i_sample - ck->i_sample_first; if( ck->p_sample_count_pts == NULL || ck->p_sample_offset_pts == NULL ) return -1; for( i_index = 0;; i_index++ ) { if( i_sample < ck->p_sample_count_pts[i_index] ) return ck->p_sample_offset_pts[i_index] * I64C(1000000) / (int64_t)p_track->i_timescale; i_sample -= ck->p_sample_count_pts[i_index]; }}static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys ){ return I64C(1000000) * p_sys->i_time / p_sys->i_timescale;}#define FREE( p ) if( p ) { free( p ); (p) = NULL;}/***************************************************************************** * Open: check file and initializes MP4 structures *****************************************************************************/static int Open( vlc_object_t * p_this ){ demux_t *p_demux = (demux_t *)p_this; demux_sys_t *p_sys; uint8_t *p_peek; MP4_Box_t *p_ftyp; MP4_Box_t *p_rmra; MP4_Box_t *p_mvhd; MP4_Box_t *p_trak; unsigned int i; vlc_bool_t b_seekable; /* A little test to see if it could be a mp4 */ if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 ) return VLC_EGENERIC; switch( VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] ) ) { case FOURCC_ftyp: case FOURCC_moov: case FOURCC_foov: case FOURCC_moof: case FOURCC_mdat: case FOURCC_udta: case FOURCC_free: case FOURCC_skip: case FOURCC_wide: case VLC_FOURCC( 'p', 'n', 'o', 't' ): break; default: return VLC_EGENERIC; } /* I need to seek */ stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_seekable ); if( !b_seekable ) { msg_Warn( p_demux, "MP4 plugin discarded (unseekable)" ); return VLC_EGENERIC; } /*Set exported functions */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; /* create our structure that will contains all data */ p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); memset( p_sys, 0, sizeof( demux_sys_t ) ); /* Now load all boxes ( except raw data ) */ if( ( p_sys->p_root = MP4_BoxGetRoot( p_demux->s ) ) == NULL ) { msg_Warn( p_demux, "MP4 plugin discarded (not a valid file)" ); goto error; } MP4_BoxDumpStructure( p_demux->s, p_sys->p_root ); if( ( p_ftyp = MP4_BoxGet( p_sys->p_root, "/ftyp" ) ) ) { switch( p_ftyp->data.p_ftyp->i_major_brand ) { case( FOURCC_isom ): msg_Dbg( p_demux, "ISO Media file (isom) version %d.", p_ftyp->data.p_ftyp->i_minor_version ); break; default: msg_Dbg( p_demux, "unrecognized major file specification (%4.4s).", (char*)&p_ftyp->data.p_ftyp->i_major_brand ); break; } } else { msg_Dbg( p_demux, "file type box missing (assuming ISO Media file)" ); } /* the file need to have one moov box */ if( MP4_BoxCount( p_sys->p_root, "/moov" ) <= 0 ) { MP4_Box_t *p_foov = MP4_BoxGet( p_sys->p_root, "/foov" ); if( !p_foov ) { msg_Err( p_demux, "MP4 plugin discarded (no moov box)" ); goto error; } /* we have a free box as a moov, rename it */ p_foov->i_type = FOURCC_moov; } if( ( p_rmra = MP4_BoxGet( p_sys->p_root, "/moov/rmra" ) ) ) { playlist_t *p_playlist; playlist_item_t *p_item; int i_count = MP4_BoxCount( p_rmra, "rmda" ); int i; vlc_bool_t b_play = VLC_FALSE; msg_Dbg( p_demux, "detected playlist mov file (%d ref)", i_count ); p_playlist = (playlist_t *)vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( p_playlist ) { p_item = playlist_LockItemGetByInput( p_playlist, ((input_thread_t *)p_demux->p_parent)->input.p_item ); playlist_ItemToNode( p_playlist, p_item ); for( i = 0; i < i_count; i++ ) { MP4_Box_t *p_rdrf = MP4_BoxGet( p_rmra, "rmda[%d]/rdrf", i ); char *psz_ref; uint32_t i_ref_type; if( !p_rdrf || !( psz_ref = p_rdrf->data.p_rdrf->psz_ref ) ) { continue; } i_ref_type = p_rdrf->data.p_rdrf->i_ref_type; msg_Dbg( p_demux, "new ref=`%s' type=%4.4s", psz_ref, (char*)&i_ref_type ); if( i_ref_type == VLC_FOURCC( 'u', 'r', 'l', ' ' ) ) { if( strstr( psz_ref, "qt5gateQT" ) ) { msg_Dbg( p_demux, "ignoring pseudo ref =`%s'", psz_ref );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -