📄 libmp4.c
字号:
/***************************************************************************** * libmp4.c : LibMP4 library for mp4 module for vlc ***************************************************************************** * Copyright (C) 2001-2004 VideoLAN * $Id: libmp4.c 10750 2005-04-20 10:41:11Z gbazin $ * * 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( stream_Read( p_stream, p_peek, i_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 = 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, "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 += ((I64C(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; 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 ) { msg_Dbg( p_stream, "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( 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 */ } } 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 */}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 ) { 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 msg_Dbg( p_stream, "skip box: \"%4.4s\"", (char*)&p_box->i_type );#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; p_box->data.p_ftyp->i_compatible_brands = calloc( p_box->data.p_ftyp->i_compatible_brands_count, sizeof(uint32_t)); for( i =0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ ) { MP4_GETFOURCC( p_box->data.p_ftyp->i_compatible_brands[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 ){ FREE( 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 ); MP4_GET4BYTES( p_box->data.p_mvhd->i_duration ); } MP4_GET4BYTES( p_box->data.p_mvhd->i_rate ); MP4_GET2BYTES( p_box->data.p_mvhd->i_volume ); MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 ); for( i = 0; i < 2; i++ ) { MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] ); } for( i = 0; i < 9; i++ ) { MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] ); } for( i = 0; i < 6; i++ ) { MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] ); } MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -