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

📄 libmp4.c

📁 VLC Player Source Code
💻 C
📖 第 1 页 / 共 5 页
字号:
/***************************************************************************** * libmp4.c : LibMP4 library for mp4 module for vlc ***************************************************************************** * Copyright (C) 2001-2004 the VideoLAN team * $Id$ * * Author: 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_demux.h>#ifdef HAVE_ZLIB_H#   include <zlib.h>                                  /* for compressed moov */#endif#include "libmp4.h"#include "drms.h"/***************************************************************************** * Here are defined some macro to make life simpler but before using it *  *look* at the code. * *****************************************************************************/#define MP4_BOX_HEADERSIZE( p_box )             \  ( 8 + ( p_box->i_shortsize == 1 ? 8 : 0 )     \      + ( p_box->i_type == FOURCC_uuid ? 16 : 0 ) )#define MP4_GETX_PRIVATE(dst, code, size) do { \    if( (i_read) >= (size) ) { dst = (code); p_peek += (size); } \    else { dst = 0; }   \    i_read -= (size);   \  } while(0)#define MP4_GET1BYTE( dst )  MP4_GETX_PRIVATE( dst, *p_peek, 1 )#define MP4_GET2BYTES( dst ) MP4_GETX_PRIVATE( dst, GetWBE(p_peek), 2 )#define MP4_GET3BYTES( dst ) MP4_GETX_PRIVATE( dst, Get24bBE(p_peek), 3 )#define MP4_GET4BYTES( dst ) MP4_GETX_PRIVATE( dst, GetDWBE(p_peek), 4 )#define MP4_GET8BYTES( dst ) MP4_GETX_PRIVATE( dst, GetQWBE(p_peek), 8 )#define MP4_GETFOURCC( dst ) MP4_GETX_PRIVATE( dst, \                VLC_FOURCC(p_peek[0],p_peek[1],p_peek[2],p_peek[3]), 4)#define MP4_GETVERSIONFLAGS( p_void ) \    MP4_GET1BYTE( p_void->i_version ); \    MP4_GET3BYTES( p_void->i_flags )#define MP4_GETSTRINGZ( p_str )         \    if( (i_read > 0) && (p_peek[0]) )   \    {       \        const int __i_copy__ = strnlen( (char*)p_peek, i_read-1 );  \        p_str = malloc( __i_copy__+1 );               \        if( p_str ) \        { \             memcpy( p_str, p_peek, __i_copy__ ); \             p_str[__i_copy__] = 0; \        } \        p_peek += __i_copy__ + 1;   \        i_read -= __i_copy__ + 1;   \    }       \    else    \    {       \        p_str = NULL; \    }#define MP4_READBOX_ENTER( MP4_Box_data_TYPE_t ) \    int64_t  i_read = p_box->i_size; \    uint8_t *p_peek, *p_buff; \    int i_actually_read; \    if( !( p_peek = p_buff = malloc( i_read ) ) ) \    { \        return( 0 ); \    } \    i_actually_read = stream_Read( p_stream, p_peek, i_read ); \    if( i_actually_read < 0 || (int64_t)i_actually_read < i_read )\    { \        free( p_buff ); \        return( 0 ); \    } \    p_peek += MP4_BOX_HEADERSIZE( p_box ); \    i_read -= MP4_BOX_HEADERSIZE( p_box ); \    if( !( p_box->data.p_data = calloc( 1, sizeof( MP4_Box_data_TYPE_t ) ) ) ) \    { \      free( p_buff ); \      return( 0 ); \    }#define MP4_READBOX_EXIT( i_code ) \    do \    { \        free( p_buff ); \        if( i_read < 0 ) \            msg_Warn( p_stream, "Not enough data" ); \        return( i_code ); \    } while (0)/* Some assumptions:        * The input method HAVE to be seekable*//* This macro is used when we want to printf the box type * APPLE annotation box is : *  either 0xA9 + 24-bit ASCII text string (and 0xA9 isn't printable) *  either 32-bit ASCII text string */#define MP4_BOX_TYPE_ASCII() ( ((char*)&p_box->i_type)[0] != (char)0xA9 )static uint32_t Get24bBE( const uint8_t *p ){    return( ( p[0] <<16 ) + ( p[1] <<8 ) + p[2] );}static void GetUUID( UUID_t *p_uuid, const uint8_t *p_buff ){    memcpy( p_uuid, p_buff, 16 );}static void CreateUUID( UUID_t *p_uuid, uint32_t i_fourcc ){    /* made by 0xXXXXXXXX-0011-0010-8000-00aa00389b71            where XXXXXXXX is the fourcc */    /* FIXME implement this */    (void)p_uuid;    (void)i_fourcc;}/* some functions for mp4 encoding of variables */static void MP4_ConvertDate2Str( char *psz, uint64_t i_date ){    int i_day;    int i_hour;    int i_min;    int i_sec;    /* date begin at 1 jan 1904 */    i_date += ((INT64_C(1904) * 365) + 17) * 24 * 60 * 60;    i_day = i_date / ( 60*60*24);    i_hour = ( i_date /( 60*60 ) ) % 60;    i_min  = ( i_date / 60 ) % 60;    i_sec =  i_date % 60;    sprintf( psz, "%dd-%2.2dh:%2.2dm:%2.2ds", i_day, i_hour, i_min, i_sec );}/***************************************************************************** * Some prototypes. *****************************************************************************/static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father );/***************************************************************************** * MP4_ReadBoxCommon : Load only common parameters for all boxes ***************************************************************************** * p_box need to be an already allocated MP4_Box_t, and all data *  will only be peek not read * * RETURN : 0 if it fail, 1 otherwise *****************************************************************************/int MP4_ReadBoxCommon( stream_t *p_stream, MP4_Box_t *p_box ){    int      i_read;    const uint8_t  *p_peek;    if( ( ( i_read = stream_Peek( p_stream, &p_peek, 32 ) ) < 8 ) )    {        return 0;    }    p_box->i_pos = stream_Tell( p_stream );    p_box->data.p_data = NULL;    p_box->p_father = NULL;    p_box->p_first  = NULL;    p_box->p_last  = NULL;    p_box->p_next   = NULL;    MP4_GET4BYTES( p_box->i_shortsize );    MP4_GETFOURCC( p_box->i_type );    /* Now special case */    if( p_box->i_shortsize == 1 )    {        /* get the true size on 64 bits */        MP4_GET8BYTES( p_box->i_size );    }    else    {        p_box->i_size = p_box->i_shortsize;        /* XXX size of 0 means that the box extends to end of file */    }    if( p_box->i_type == FOURCC_uuid )    {        /* get extented type on 16 bytes */        GetUUID( &p_box->i_uuid, p_peek );        p_peek += 16; i_read -= 16;    }    else    {        CreateUUID( &p_box->i_uuid, p_box->i_type );    }#ifdef MP4_VERBOSE    if( p_box->i_size )    {        if MP4_BOX_TYPE_ASCII()            msg_Dbg( p_stream, "found Box: %4.4s size %"PRId64,                    (char*)&p_box->i_type, p_box->i_size );        else            msg_Dbg( p_stream, "found Box: c%3.3s size %"PRId64,                    (char*)&p_box->i_type+1, p_box->i_size );    }#endif    return 1;}/***************************************************************************** * MP4_NextBox : Go to the next box ***************************************************************************** * if p_box == NULL, go to the next box in which we are( at the begining ). *****************************************************************************/static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box ){    MP4_Box_t box;    if( !p_box )    {        MP4_ReadBoxCommon( p_stream, &box );        p_box = &box;    }    if( !p_box->i_size )    {        return 2; /* Box with infinite size */    }    if( p_box->p_father )    {        const off_t i_box_end = p_box->i_size + p_box->i_pos;        const off_t i_father_end = p_box->p_father->i_size + p_box->p_father->i_pos;        /* check if it's within p-father */        if( i_box_end >= i_father_end )        {            if( i_box_end > i_father_end )                msg_Dbg( p_stream, "out of bound child" );            return 0; /* out of bound */        }    }    if( stream_Seek( p_stream, p_box->i_size + p_box->i_pos ) )    {        return 0;    }    return 1;}/***************************************************************************** * For all known box a loader is given, *  XXX: all common struct have to be already read by MP4_ReadBoxCommon *       after called one of theses functions, file position is unknown *       you need to call MP4_GotoBox to go where you want *****************************************************************************/static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container ){    MP4_Box_t *p_box;    if( stream_Tell( p_stream ) + 8 >        (off_t)(p_container->i_pos + p_container->i_size) )    {        /* there is no box to load */        return 0;    }    do    {        if( ( p_box = MP4_ReadBox( p_stream, p_container ) ) == NULL ) break;        /* chain this box with the father and the other at same level */        if( !p_container->p_first ) p_container->p_first = p_box;        else p_container->p_last->p_next = p_box;        p_container->p_last = p_box;    } while( MP4_NextBox( p_stream, p_box ) == 1 );    return 1;}static int MP4_ReadBoxContainer( stream_t *p_stream, MP4_Box_t *p_container ){    if( p_container->i_size <= (size_t)MP4_BOX_HEADERSIZE(p_container ) + 8 )    {        /* container is empty, 8 stand for the first header in this box */        return 1;    }    /* enter box */    stream_Seek( p_stream, p_container->i_pos +                 MP4_BOX_HEADERSIZE( p_container ) );    return MP4_ReadBoxContainerRaw( p_stream, p_container );}static void MP4_FreeBox_Common( MP4_Box_t *p_box ){    /* Up to now do nothing */    (void)p_box;}static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box ){    /* XXX sometime moov is hiden in a free box */    if( p_box->p_father &&        p_box->p_father->i_type == VLC_FOURCC( 'r', 'o', 'o', 't' ) &&        p_box->i_type == FOURCC_free )    {        const uint8_t *p_peek;        int     i_read;        vlc_fourcc_t i_fcc;        i_read  = stream_Peek( p_stream, &p_peek, 44 );        p_peek += MP4_BOX_HEADERSIZE( p_box ) + 4;        i_read -= MP4_BOX_HEADERSIZE( p_box ) + 4;        if( i_read >= 8 )        {            i_fcc = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] );            if( i_fcc == FOURCC_cmov || i_fcc == FOURCC_mvhd )            {                msg_Warn( p_stream, "detected moov hidden in a free box ..." );                p_box->i_type = FOURCC_foov;                return MP4_ReadBoxContainer( p_stream, p_box );            }        }    }    /* Nothing to do */#ifdef MP4_VERBOSE    if MP4_BOX_TYPE_ASCII()        msg_Dbg( p_stream, "skip box: \"%4.4s\"", (char*)&p_box->i_type );    else        msg_Dbg( p_stream, "skip box: \"c%3.3s\"", (char*)&p_box->i_type+1 );#endif    return 1;}static int MP4_ReadBox_ftyp( stream_t *p_stream, MP4_Box_t *p_box ){    MP4_READBOX_ENTER( MP4_Box_data_ftyp_t );    MP4_GETFOURCC( p_box->data.p_ftyp->i_major_brand );    MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version );    if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) )    {        unsigned int i;        uint32_t *tab = p_box->data.p_ftyp->i_compatible_brands =            calloc( p_box->data.p_ftyp->i_compatible_brands_count,                    sizeof(uint32_t));        if( tab == NULL )            MP4_READBOX_EXIT( 0 );        for( i =0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )        {            MP4_GETFOURCC( tab[i] );        }    }    else    {        p_box->data.p_ftyp->i_compatible_brands = NULL;    }    MP4_READBOX_EXIT( 1 );}static void MP4_FreeBox_ftyp( MP4_Box_t *p_box ){    FREENULL( p_box->data.p_ftyp->i_compatible_brands );}static int MP4_ReadBox_mvhd(  stream_t *p_stream, MP4_Box_t *p_box ){    unsigned int i;#ifdef MP4_VERBOSE    char s_creation_time[128];    char s_modification_time[128];    char s_duration[128];#endif    MP4_READBOX_ENTER( MP4_Box_data_mvhd_t );    MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );    if( p_box->data.p_mvhd->i_version )    {        MP4_GET8BYTES( p_box->data.p_mvhd->i_creation_time );        MP4_GET8BYTES( p_box->data.p_mvhd->i_modification_time );        MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );        MP4_GET8BYTES( p_box->data.p_mvhd->i_duration );    }    else    {        MP4_GET4BYTES( p_box->data.p_mvhd->i_creation_time );        MP4_GET4BYTES( p_box->data.p_mvhd->i_modification_time );        MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );

⌨️ 快捷键说明

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