⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp4.c

📁 VLC媒体播放程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/***************************************************************************** * mp4.c : MP4 file input module for vlc ***************************************************************************** * Copyright (C) 2001-2004 VideoLAN * $Id: mp4.c,v 1.59 2004/02/07 13:26:24 fenrir Exp $ * 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 "libmp4.h"#include "mp4.h"#include "drms.h"/***************************************************************************** * Module descriptor *****************************************************************************/static int  Open ( vlc_object_t * );static void Close( vlc_object_t * );vlc_module_begin();    set_description( _("MP4 stream demuxer") );    set_capability( "demux", 242 );    set_callbacks( Open, Close );vlc_module_end();/* TODO: *  - DEMUX_GET_META and meta parsing *//***************************************************************************** * Local prototypes *****************************************************************************/static int    Demux   ( input_thread_t * );static int    DemuxRef( input_thread_t *p_input ){    return 0;}static int   Seek     ( input_thread_t *, mtime_t );static int   Control  ( input_thread_t *, int, va_list );/***************************************************************************** * Declaration of local function *****************************************************************************/static void MP4_TrackCreate ( input_thread_t *, mp4_track_t *, MP4_Box_t  *);static void MP4_TrackDestroy( input_thread_t *, mp4_track_t * );static int  MP4_TrackSelect ( input_thread_t *, mp4_track_t *, mtime_t );static void MP4_TrackUnselect(input_thread_t *, mp4_track_t * );static int  MP4_TrackSeek   ( input_thread_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( input_thread_t *, mp4_track_t * );static void     MP4_TrackSetELST( input_thread_t *, mp4_track_t *, int64_t );/* Return time in 祍 of a track */static inline int64_t MP4_TrackGetPTS( input_thread_t *p_input, mp4_track_t *p_track ){    unsigned int i_sample;    unsigned int i_index;    int64_t i_dts;    i_sample = p_track->i_sample - p_track->chunk[p_track->i_chunk].i_sample_first;    i_dts = p_track->chunk[p_track->i_chunk].i_first_dts;    i_index = 0;    while( i_sample > 0 )    {        if( i_sample > p_track->chunk[p_track->i_chunk].p_sample_count_dts[i_index] )        {            i_dts += p_track->chunk[p_track->i_chunk].p_sample_count_dts[i_index] *                        p_track->chunk[p_track->i_chunk].p_sample_delta_dts[i_index];            i_sample -= p_track->chunk[p_track->i_chunk].p_sample_count_dts[i_index];            i_index++;        }        else        {            i_dts += i_sample *                        p_track->chunk[p_track->i_chunk].p_sample_delta_dts[i_index];            i_sample = 0;            break;        }    }    /* now handle elst */    if( p_track->p_elst )    {        demux_sys_t         *p_sys = p_input->p_demux_data;        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 (int64_t)1000000 * i_dts / p_track->i_timescale;}static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys ){    return (int64_t)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 ){    input_thread_t  *p_input = (input_thread_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_input->s, &p_peek, 8 ) < 8 )    {        msg_Warn( p_input, "MP4 plugin discarded (cannot peek)" );        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:            msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );            return VLC_EGENERIC;    }    /* I need to seek */    stream_Control( p_input->s, STREAM_CAN_SEEK, &b_seekable );    if( !b_seekable )    {        msg_Warn( p_input, "MP4 plugin discarded (unseekable)" );        return VLC_EGENERIC;    }    /*Set exported functions */    p_input->pf_demux = Demux;    p_input->pf_demux_control = Control;    /* create our structure that will contains all data */    p_input->p_demux_data = 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_input ) ) == NULL )    {        msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );        goto error;    }    MP4_BoxDumpStructure( p_input, 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_input,                         "ISO Media file (isom) version %d.",                         p_ftyp->data.p_ftyp->i_minor_version );                break;            default:                msg_Dbg( p_input,                         "unrecognized major file specification (%4.4s).",                          (char*)&p_ftyp->data.p_ftyp->i_major_brand );                break;        }    }    else    {        msg_Dbg( p_input, "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_input, "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;        int        i_count = MP4_BoxCount( p_rmra, "rmda" );        int        i;        msg_Dbg( p_input, "detected playlist mov file (%d ref)", i_count );        p_playlist =            (playlist_t *)vlc_object_find( p_input,                                           VLC_OBJECT_PLAYLIST,                                           FIND_ANYWHERE );        if( p_playlist )        {            //p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;            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_input, "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_input, "ignoring pseudo ref =`%s'", psz_ref );                        continue;                    }                    if( !strncmp( psz_ref, "http://", 7 ) ||                        !strncmp( psz_ref, "rtsp://", 7 ) )                    {                        msg_Dbg( p_input, "adding ref = `%s'", psz_ref );                        playlist_Add( p_playlist, psz_ref, psz_ref,                                      PLAYLIST_APPEND, PLAYLIST_END );                    }                    else                    {                        /* msg dbg relative ? */                        char *psz_absolute = alloca( strlen( p_input->psz_source ) + strlen( psz_ref ) + 1);                        char *end = strrchr( p_input->psz_source, '/' );                        if( end )                        {                            int i_len = end + 1 - p_input->psz_source;                            strncpy( psz_absolute, p_input->psz_source, i_len);                            psz_absolute[i_len] = '\0';                        }                        else                        {                            strcpy( psz_absolute, "" );                        }                        strcat( psz_absolute, psz_ref );                        msg_Dbg( p_input, "adding ref = `%s'", psz_absolute );                        playlist_Add( p_playlist, psz_absolute, psz_absolute,                                      PLAYLIST_APPEND, PLAYLIST_END );                    }                }                else                {                    msg_Err( p_input, "unknown ref type=%4.4s FIXME (send a bug report)",                             (char*)&p_rdrf->data.p_rdrf->i_ref_type );                }            }            vlc_object_release( p_playlist );        }        else        {            msg_Err( p_input, "can't find playlist" );        }    }    if( !(p_mvhd = MP4_BoxGet( p_sys->p_root, "/moov/mvhd" ) ) )    {        if( !p_rmra )        {            msg_Err( p_input, "cannot find /moov/mvhd" );            goto error;        }        else        {            msg_Warn( p_input, "cannot find /moov/mvhd (pure ref file)" );            p_input->pf_demux = DemuxRef;            return VLC_SUCCESS;        }    }    else    {        p_sys->i_timescale = p_mvhd->data.p_mvhd->i_timescale;        p_sys->i_duration = p_mvhd->data.p_mvhd->i_duration;    }    if( !( p_sys->i_tracks = MP4_BoxCount( p_sys->p_root, "/moov/trak" ) ) )    {        msg_Err( p_input, "cannot find any /moov/trak" );        goto error;    }    msg_Dbg( p_input, "find %d track%c",                        p_sys->i_tracks,                        p_sys->i_tracks ? 's':' ' );    /*  create one program */    vlc_mutex_lock( &p_input->stream.stream_lock );    if( input_InitStream( p_input, 0 ) == -1)    {        vlc_mutex_unlock( &p_input->stream.stream_lock );        msg_Err( p_input, "cannot init stream" );        goto error;    }    if( p_sys->i_duration/p_sys->i_timescale > 0 )    {        p_input->stream.i_mux_rate =            p_input->stream.p_selected_area->i_size / 50 /            ( p_sys->i_duration / p_sys->i_timescale );    }    else    {        p_input->stream.i_mux_rate = 0;    }    vlc_mutex_unlock( &p_input->stream.stream_lock );    /* allocate memory */    p_sys->track = calloc( p_sys->i_tracks, sizeof( mp4_track_t ) );    memset( p_sys->track, 0, p_sys->i_tracks * sizeof( mp4_track_t ) );    /* now process each track and extract all usefull informations */    for( i = 0; i < p_sys->i_tracks; i++ )    {        p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[%d]", i );        MP4_TrackCreate( p_input, &p_sys->track[i], p_trak );        if( p_sys->track[i].b_ok )        {            char *psz_cat;            switch( p_sys->track[i].fmt.i_cat )            {                case( VIDEO_ES ):                    psz_cat = "video";                    break;                case( AUDIO_ES ):                    psz_cat = "audio";                    break;                default:                    psz_cat = "unknown";                    break;            }            msg_Dbg( p_input, "adding track[Id 0x%x] %s (%s) language %s",                            p_sys->track[i].i_track_ID,                            psz_cat,                            p_sys->track[i].b_enable ? "enable":"disable",                            p_sys->track[i].fmt.psz_language ? p_sys->track[i].fmt.psz_language : "undef" );        }        else        {            msg_Dbg( p_input, "ignoring track[Id 0x%x]", p_sys->track[i].i_track_ID );        }    }    return VLC_SUCCESS;error:    if( p_sys->p_root )    {        MP4_BoxFree( p_input, p_sys->p_root );    }    free( p_sys );    return VLC_EGENERIC;}/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * TODO check for newly selected track (ie audio upt to now ) *****************************************************************************/static int Demux( input_thread_t *p_input ){    demux_sys_t *p_sys = p_input->p_demux_data;    unsigned int i_track;    unsigned int i_track_selected;    vlc_bool_t   b_play_audio;    /* check for newly selected/unselected track */    for( i_track = 0, i_track_selected = 0; i_track <  p_sys->i_tracks; i_track++ )    {        mp4_track_t *tk = &p_sys->track[i_track];        if( tk->b_selected && tk->i_sample >= tk->i_sample_count )        {            msg_Warn( p_input, "track[0x%x] will be disabled", tk->i_track_ID );            MP4_TrackUnselect( p_input, tk);        }        else if( tk->b_ok )        {            vlc_bool_t b;            es_out_Control( p_input->p_es_out, ES_OUT_GET_ES_STATE, tk->p_es, &b );            if( tk->b_selected && !b )            {                MP4_TrackUnselect( p_input, tk );            }            else if( !tk->b_selected && b)            {                MP4_TrackSelect( p_input, tk, MP4_GetMoviePTS( p_sys ) );            }            if( tk->b_selected )            {                i_track_selected++;            }        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -