libmp4.c

来自「VLC媒体播放程序」· C语言 代码 · 共 2,060 行 · 第 1/5 页

C
2,060
字号
/***************************************************************************** * libmp4.c : LibMP4 library for mp4 module for vlc ***************************************************************************** * Copyright (C) 2001-2004 VideoLAN * $Id: libmp4.c,v 1.45 2004/01/25 20:05:28 hartman Exp $ * * 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA. *****************************************************************************/#include <stdlib.h>                                      /* malloc(), free() */#include <vlc/vlc.h>#include <vlc/input.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_GET1BYTE( dst ) \    dst = *p_peek; p_peek++; i_read--#define MP4_GET2BYTES( dst ) \    dst = GetWBE( p_peek ); p_peek += 2; i_read -= 2#define MP4_GET3BYTES( dst ) \    dst = Get24bBE( p_peek ); p_peek += 3; i_read -= 3#define MP4_GET4BYTES( dst ) \    dst = GetDWBE( p_peek ); p_peek += 4; i_read -= 4#define MP4_GETFOURCC( dst ) \    dst = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] ); \    p_peek += 4; i_read -= 4#define MP4_GET8BYTES( dst ) \    dst = GetQWBE( p_peek ); p_peek += 8; i_read -= 8#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] ) ) \    { \        p_str = calloc( sizeof( char ), __MIN( strlen( p_peek ), i_read )+1);\        memcpy( p_str, p_peek, __MIN( strlen( p_peek ), i_read ) ); \        p_str[__MIN( strlen( p_peek ), i_read )] = 0; \        p_peek += strlen( p_str ) + 1; \        i_read -= strlen( p_str ) + 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; \    i_read = p_box->i_size; \    if( !( p_peek = p_buff = malloc( i_read ) ) ) \    { \        return( 0 ); \    } \    if( MP4_ReadStream( p_stream, p_peek, 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 = malloc( sizeof( MP4_Box_data_TYPE_t ) ) ) ) \    { \      free( p_buff ); \      return( 0 ); \    }#define MP4_READBOX_EXIT( i_code ) \    free( p_buff ); \    if( i_read < 0 ) \    { \        msg_Warn( p_stream->p_input, "Not enough data" ); \    } \    return( i_code )#define FREE( p ) \    if( p ) {free( p ); p = NULL; }/* Some assumptions:        * The input method HAVE to be seekable*/static uint32_t Get24bBE( uint8_t *p ){    return( ( p[0] <<16 ) + ( p[1] <<8 ) + p[2] );}static void GetUUID( UUID_t *p_uuid, 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 */}/* 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 += ((1904U * 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( MP4_Stream_t *p_stream, MP4_Box_t *p_father );/***************************************************************************** * Some basic functions to manipulate MP4_Stream_t, an abstraction o p_input *  in the way that you can read from a memory buffer or from an input * *****************************************************************************//****  ------- First some function to make abstract from input --------  *//**************************************************************************** * MP4_InputStream create an stram with an input * ****************************************************************************/MP4_Stream_t *MP4_InputStream( input_thread_t *p_input ){    MP4_Stream_t *p_stream;    if( !( p_stream = malloc( sizeof( MP4_Stream_t ) ) ) )    {        return( NULL );    }    p_stream->b_memory = 0;    p_stream->p_input = p_input;    p_stream->i_start = 0;    p_stream->i_stop = 0;    p_stream->p_buffer = NULL;    return( p_stream );}/**************************************************************************** * MP4_MemoryStream create a memory stream * if p_buffer == NULL, will allocate a buffer of i_size, else *     it uses p_buffer XXX you have to unallocate it yourself ! * ****************************************************************************/MP4_Stream_t *MP4_MemoryStream( input_thread_t *p_input,                                int i_size, uint8_t *p_buffer ){    MP4_Stream_t *p_stream;    if( !( p_stream = malloc( sizeof( MP4_Stream_t ) ) ) )    {        return( NULL );    }    p_stream->b_memory = 1;    p_stream->p_input = p_input;    p_stream->i_start = 0;    p_stream->i_stop = i_size;    if( !p_buffer )    {        if( !( p_stream->p_buffer = malloc( i_size ) ) )        {            free( p_stream );            return( NULL );        }    }    else    {        p_stream->p_buffer = p_buffer;    }    return( p_stream );}/**************************************************************************** * MP4_ReadStream read from a MP4_Stream_t * ****************************************************************************/int MP4_ReadStream( MP4_Stream_t *p_stream, uint8_t *p_buff, int i_size ){    if( p_stream->b_memory )    {        if( i_size > p_stream->i_stop - p_stream->i_start )        {            return( VLC_EGENERIC );        }        memcpy( p_buff,                p_stream->p_buffer + p_stream->i_start,                i_size );        p_stream->i_start += i_size;        return( VLC_SUCCESS );    }    else    {        return( stream_Read( p_stream->p_input->s, p_buff, i_size ) < i_size ? VLC_EGENERIC : VLC_SUCCESS);    }}/**************************************************************************** * MP4_PeekStream peek from a MP4_Stream_t * ****************************************************************************/int MP4_PeekStream( MP4_Stream_t *p_stream, uint8_t **pp_peek, int i_size ){    if( p_stream->b_memory )    {        *pp_peek = p_stream->p_buffer + p_stream->i_start;        return( __MIN(i_size,p_stream->i_stop - p_stream->i_start ));    }    else    {        if( p_stream->p_input->stream.p_selected_area->i_size > 0 )        {            int64_t i_max =                p_stream->p_input->stream.p_selected_area->i_size - stream_Tell( p_stream->p_input->s );            if( i_size > i_max )            {                i_size = i_max;            }        }        return( stream_Peek( p_stream->p_input->s, pp_peek, i_size ) );    }}/**************************************************************************** * MP4_TellStream give absolute position in the stream * XXX for a memory stream give position from begining of the buffer ****************************************************************************/off_t MP4_TellStream( MP4_Stream_t *p_stream ){    if( p_stream->b_memory )    {        return( p_stream->i_start );    }    else    {        return( stream_Tell( p_stream->p_input->s ) );    }}/**************************************************************************** * MP4_SeekStream seek in a MP4_Stream_t * ****************************************************************************/int MP4_SeekStream( MP4_Stream_t *p_stream, off_t i_pos){    if( p_stream->b_memory )    {        if( i_pos < p_stream->i_stop )        {            p_stream->i_start = i_pos;            return( VLC_SUCCESS );        }        else        {            return( VLC_EGENERIC );        }    }    else    {        return( stream_Seek( p_stream->p_input->s, (int64_t)i_pos ) );    }}/***************************************************************************** * 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 *****************************************************************************/static int MP4_ReadBoxCommon( MP4_Stream_t *p_stream, MP4_Box_t *p_box ){    int      i_read;    uint8_t  *p_peek;    if( ( ( i_read = MP4_PeekStream( p_stream, &p_peek, 32 ) ) < 8 ) )    {        return( 0 );    }    p_box->i_pos = MP4_TellStream( 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 )    {        msg_Dbg( p_stream->p_input, "found Box: %4.4s size "I64Fd,                 (char*)&p_box->i_type,                 p_box->i_size );    }#endif    return( 1 );}/***************************************************************************** * MP4_NextBox : Go to the next box ***************************************************************************** * if p_box == NULL, go to the next box in witch we are( at the begining ). *****************************************************************************/static int MP4_NextBox( MP4_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 )    {        /* check if it's within p-father */        if( p_box->i_size + p_box->i_pos >=                    p_box->p_father->i_size + p_box->p_father->i_pos )        {            return( 0 ); /* out of bound */        }    }

⌨️ 快捷键说明

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