📄 mp4.c
字号:
/***************************************************************************** * mp4.c ***************************************************************************** * Copyright (C) 2001, 2002, 2003 VideoLAN * $Id: mp4.c,v 1.3 2003/08/01 20:06:43 gbazin 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>#include <string.h>#include <errno.h>#include <vlc/vlc.h>#include <vlc/input.h>#include <vlc/sout.h>#ifdef HAVE_TIME_H#include <time.h>#endif#include "codecs.h"/***************************************************************************** * Exported prototypes *****************************************************************************/static int Open ( vlc_object_t * );static void Close ( vlc_object_t * );static int Capability(sout_mux_t *, int, void *, void * );static int AddStream( sout_mux_t *, sout_input_t * );static int DelStream( sout_mux_t *, sout_input_t * );static int Mux ( sout_mux_t * );/***************************************************************************** * Module descriptor *****************************************************************************/vlc_module_begin(); set_description( _("MP4/MOV muxer") ); set_capability( "sout mux", 5 ); add_shortcut( "mp4" ); add_shortcut( "mov" ); set_callbacks( Open, Close );vlc_module_end();typedef struct{ uint64_t i_pos; int i_size; mtime_t i_pts; mtime_t i_dts; mtime_t i_length;} mp4_entry_t;typedef struct{ sout_format_t *p_fmt; int i_track_id; /* index */ unsigned int i_entry_count; unsigned int i_entry_max; mp4_entry_t *entry; /* stats */ mtime_t i_duration;} mp4_stream_t;struct sout_mux_sys_t{ vlc_bool_t b_mov; uint64_t i_mdat_pos; uint64_t i_pos; int i_nb_streams; mp4_stream_t **pp_streams;};typedef struct bo_t bo_t;struct bo_t{ vlc_bool_t b_grow; int i_buffer_size; int i_buffer; uint8_t *p_buffer;};static void bo_init ( bo_t *, int , uint8_t *, vlc_bool_t );static void bo_add_8 ( bo_t *, uint8_t );static void bo_add_16be ( bo_t *, uint16_t );static void bo_add_24be ( bo_t *, uint32_t );static void bo_add_32be ( bo_t *, uint32_t );static void bo_add_64be ( bo_t *, uint64_t );static void bo_add_fourcc(bo_t *, char * );static void bo_add_bo ( bo_t *, bo_t * );static void bo_add_mem ( bo_t *, int , uint8_t * );static void bo_fix_32be ( bo_t *, int , uint32_t );static bo_t *box_new ( char *fcc );static bo_t *box_full_new( char *fcc, uint8_t v, uint32_t f );static void box_fix ( bo_t *box );static void box_free ( bo_t *box );static void box_gather ( bo_t *box, bo_t *box2 );static void box_send( sout_mux_t *p_mux, bo_t *box );static int64_t get_timestamp();static sout_buffer_t * bo_to_sout( sout_instance_t *p_sout, bo_t *box );/***************************************************************************** * Open: *****************************************************************************/static int Open( vlc_object_t *p_this ){ sout_mux_t *p_mux = (sout_mux_t*)p_this; sout_mux_sys_t *p_sys; bo_t *box; p_sys = malloc( sizeof( sout_mux_sys_t ) ); p_sys->i_pos = 0; p_sys->i_nb_streams = 0; p_sys->pp_streams = NULL; p_sys->i_mdat_pos = 0; p_sys->b_mov = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mov" ); msg_Info( p_mux, "Open" ); p_mux->pf_capacity = Capability; p_mux->pf_addstream = AddStream; p_mux->pf_delstream = DelStream; p_mux->pf_mux = Mux; p_mux->p_sys = p_sys; if( !p_sys->b_mov ) { /* Now add ftyp header */ box = box_new( "ftyp" ); bo_add_fourcc( box, "isom" ); bo_add_32be ( box, 0 ); bo_add_fourcc( box, "mp41" ); box_fix( box ); p_sys->i_pos += box->i_buffer; p_sys->i_mdat_pos = p_sys->i_pos; box_send( p_mux, box ); } /* Now add mdat header */ box = box_new( "mdat" ); bo_add_64be ( box, 0 ); // enough to store an extended size p_sys->i_pos += box->i_buffer; box_send( p_mux, box ); return VLC_SUCCESS;}static uint32_t GetDescriptorLength24b( int i_length ){ uint32_t i_l1, i_l2, i_l3; i_l1 = i_length&0x7f; i_l2 = ( i_length >> 7 )&0x7f; i_l3 = ( i_length >> 14 )&0x7f; return( 0x808000 | ( i_l3 << 16 ) | ( i_l2 << 8 ) | i_l1 );}static bo_t *GetESDS( mp4_stream_t *p_stream ){ bo_t *esds; int i_stream_type; int i_object_type_indication; int i_decoder_specific_info_size; if( p_stream->p_fmt->i_extra_data > 0 ) { i_decoder_specific_info_size = p_stream->p_fmt->i_extra_data + 4; } else { i_decoder_specific_info_size = 0; } esds = box_full_new( "esds", 0, 0 ); bo_add_8 ( esds, 0x03 ); // ES_DescrTag bo_add_24be( esds, GetDescriptorLength24b( 25 + i_decoder_specific_info_size ) ); bo_add_16be( esds, p_stream->i_track_id ); bo_add_8 ( esds, 0x1f ); // flags=0|streamPriority=0x1f bo_add_8 ( esds, 0x04 ); // DecoderConfigDescrTag bo_add_24be( esds, GetDescriptorLength24b( 13 + i_decoder_specific_info_size ) ); switch( p_stream->p_fmt->i_fourcc ) { case VLC_FOURCC( 'm', 'p', '4', 'v' ): i_object_type_indication = 0x20; break; case VLC_FOURCC( 'm', 'p', 'g', 'v' ): /* FIXME MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */ i_object_type_indication = 0x60; break; case VLC_FOURCC( 'm', 'p', '4', 'a' ): /* FIXME for mpeg2-aac == 0x66->0x68 */ i_object_type_indication = 0x40; break; case VLC_FOURCC( 'm', 'p', 'g', 'a' ): i_object_type_indication = p_stream->p_fmt->i_sample_rate < 32000 ? 0x69 : 0x6b; break; default: i_object_type_indication = 0x00; break; } i_stream_type = p_stream->p_fmt->i_cat == VIDEO_ES ? 0x04 : 0x05; bo_add_8 ( esds, i_object_type_indication ); bo_add_8 ( esds, ( i_stream_type << 2 ) | 1 ); bo_add_24be( esds, 1024 * 1024 ); // bufferSizeDB bo_add_32be( esds, 0x7fffffff ); // maxBitrate bo_add_32be( esds, 0 ); // avgBitrate if( p_stream->p_fmt->i_extra_data > 0 ) { int i; bo_add_8 ( esds, 0x05 ); // DecoderSpecificInfo bo_add_24be( esds, GetDescriptorLength24b( p_stream->p_fmt->i_extra_data ) ); for( i = 0; i < p_stream->p_fmt->i_extra_data; i++ ) { bo_add_8( esds, p_stream->p_fmt->p_extra_data[i] ); } } /* SL_Descr mandatory */ bo_add_8 ( esds, 0x06 ); // SLConfigDescriptorTag bo_add_24be( esds, GetDescriptorLength24b( 1 ) ); bo_add_8 ( esds, 0x02 ); // sl_predefined box_fix( esds ); return esds;}/***************************************************************************** * Close: *****************************************************************************/static uint32_t mvhd_matrix[9] = { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };static void Close( vlc_object_t * p_this ){ sout_mux_t *p_mux = (sout_mux_t*)p_this; sout_mux_sys_t *p_sys = p_mux->p_sys; sout_buffer_t *p_hdr; bo_t bo; bo_t *moov, *mvhd; unsigned int i; int i_trak, i_index; uint32_t i_movie_timescale = 90000; int64_t i_movie_duration = 0; msg_Info( p_mux, "Close" ); /* create general info */ for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ ) { mp4_stream_t *p_stream; p_stream = p_sys->pp_streams[i_trak]; i_movie_duration = __MAX( i_movie_duration, p_stream->i_duration ); } msg_Dbg( p_mux, "movie duration %ds", (uint32_t)( i_movie_duration / (mtime_t)1000000 ) ); i_movie_duration = i_movie_duration * (int64_t)i_movie_timescale / (int64_t)1000000; /* *** update mdat size *** */ bo_init ( &bo, 0, NULL, VLC_TRUE ); if( p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32) ) { /* Extended size */ bo_add_32be ( &bo, 1 ); bo_add_fourcc( &bo, "mdat" ); bo_add_64be ( &bo, p_sys->i_pos - p_sys->i_mdat_pos ); } else { bo_add_32be ( &bo, 8 ); bo_add_fourcc( &bo, "wide" ); bo_add_32be ( &bo, p_sys->i_pos - p_sys->i_mdat_pos - 8 ); bo_add_fourcc( &bo, "mdat" ); } p_hdr = bo_to_sout( p_mux->p_sout, &bo ); free( bo.p_buffer ); /* seek to mdat */ sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos ); sout_AccessOutWrite( p_mux->p_access, p_hdr ); /* Now create header */ sout_AccessOutSeek( p_mux->p_access, p_sys->i_pos ); moov = box_new( "moov" ); /* *** add /moov/mvhd *** */ if( p_sys->b_mov ) { mvhd = box_full_new( "mvhd", 0, 0 ); bo_add_32be( mvhd, get_timestamp() ); // creation time bo_add_32be( mvhd, get_timestamp() ); // modification time bo_add_32be( mvhd, i_movie_timescale); // timescale bo_add_32be( mvhd, i_movie_duration ); // duration } else { mvhd = box_full_new( "mvhd", 1, 0 ); bo_add_64be( mvhd, get_timestamp() ); // creation time bo_add_64be( mvhd, get_timestamp() ); // modification time bo_add_32be( mvhd, i_movie_timescale); // timescale bo_add_64be( mvhd, i_movie_duration ); // duration } bo_add_32be( mvhd, 0x10000 ); // rate bo_add_16be( mvhd, 0x100 ); // volume bo_add_16be( mvhd, 0 ); // reserved for( i = 0; i < 2; i++ ) { bo_add_32be( mvhd, 0 ); // reserved } for( i = 0; i < 9; i++ ) { bo_add_32be( mvhd, mvhd_matrix[i] );// matrix } for( i = 0; i < 6; i++ ) { bo_add_32be( mvhd, 0 ); // pre-defined } /* Find the 1st track id */ for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ ) { mp4_stream_t *p_stream = p_sys->pp_streams[i_trak]; if( p_stream->p_fmt->i_cat == AUDIO_ES || p_stream->p_fmt->i_cat == VIDEO_ES ) { /* Found it */ bo_add_32be( mvhd, p_stream->i_track_id ); // next-track-id break; } } if( i_trak == p_sys->i_nb_streams ) /* Just for sanity reasons */ bo_add_32be( mvhd, 0xffffffff ); box_fix( mvhd ); box_gather( moov, mvhd ); for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ ) { mp4_stream_t *p_stream; uint32_t i_timescale; uint32_t i_chunk_count; bo_t *trak; bo_t *tkhd; bo_t *mdia; bo_t *mdhd, *hdlr; bo_t *minf; bo_t *dinf; bo_t *dref;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -