1 /*****************************************************************************
2 * mp4.c: x264 mp4 output module
3 *****************************************************************************
4 * Copyright (C) 2003-2009 x264 project
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7 * Loren Merritt <lorenm@u.washington.edu>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
22 *****************************************************************************/
25 #include <gpac/isomedia.h>
30 GF_AVCConfig *p_config;
31 GF_ISOSample *p_sample;
42 static void recompute_bitrate_mp4( GF_ISOFile *p_file, int i_track )
44 u32 i, count, di, timescale, time_wnd, rate;
49 esd = gf_isom_get_esd( p_file, i_track, 1 );
53 esd->decoderConfig->avgBitrate = 0;
54 esd->decoderConfig->maxBitrate = 0;
57 timescale = gf_isom_get_media_timescale( p_file, i_track );
58 count = gf_isom_get_sample_count( p_file, i_track );
59 for( i = 0; i < count; i++ )
61 GF_ISOSample *samp = gf_isom_get_sample_info( p_file, i_track, i+1, &di, &offset );
63 if( samp->dataLength>esd->decoderConfig->bufferSizeDB )
64 esd->decoderConfig->bufferSizeDB = samp->dataLength;
66 if( esd->decoderConfig->bufferSizeDB < samp->dataLength )
67 esd->decoderConfig->bufferSizeDB = samp->dataLength;
69 esd->decoderConfig->avgBitrate += samp->dataLength;
70 rate += samp->dataLength;
71 if( samp->DTS > time_wnd + timescale )
73 if( rate > esd->decoderConfig->maxBitrate )
74 esd->decoderConfig->maxBitrate = rate;
79 gf_isom_sample_del( &samp );
82 br = (Double)(s64)gf_isom_get_media_duration( p_file, i_track );
84 esd->decoderConfig->avgBitrate = (u32)(esd->decoderConfig->avgBitrate / br);
86 esd->decoderConfig->avgBitrate *= 8;
87 esd->decoderConfig->maxBitrate *= 8;
89 gf_isom_change_mpeg4_description( p_file, i_track, 1, esd );
90 gf_odf_desc_del( (GF_Descriptor*)esd );
93 static int close_file( hnd_t handle )
95 mp4_hnd_t *p_mp4 = handle;
100 if( p_mp4->p_config )
101 gf_odf_avc_cfg_del( p_mp4->p_config );
103 if( p_mp4->p_sample )
105 if( p_mp4->p_sample->data )
106 free( p_mp4->p_sample->data );
108 gf_isom_sample_del( &p_mp4->p_sample );
113 recompute_bitrate_mp4( p_mp4->p_file, p_mp4->i_track );
114 gf_isom_set_pl_indication( p_mp4->p_file, GF_ISOM_PL_VISUAL, 0x15 );
115 gf_isom_set_storage_mode( p_mp4->p_file, GF_ISOM_STORE_FLAT );
116 gf_isom_close( p_mp4->p_file );
124 static int open_file( char *psz_filename, hnd_t *p_handle )
129 FILE *fh = fopen( psz_filename, "w" );
132 else if( !x264_is_regular_file( fh ) )
134 fprintf( stderr, "mp4 [error]: MP4 output is incompatible with non-regular file `%s'\n", psz_filename );
139 if( !(p_mp4 = malloc( sizeof(mp4_hnd_t) )) )
142 memset( p_mp4, 0, sizeof(mp4_hnd_t) );
143 p_mp4->p_file = gf_isom_open( psz_filename, GF_ISOM_OPEN_WRITE, NULL );
145 if( !(p_mp4->p_sample = gf_isom_sample_new()) )
151 gf_isom_set_brand_info( p_mp4->p_file, GF_ISOM_BRAND_AVC1, 0 );
158 static int set_param( hnd_t handle, x264_param_t *p_param )
160 mp4_hnd_t *p_mp4 = handle;
162 p_mp4->i_track = gf_isom_new_track( p_mp4->p_file, 0, GF_ISOM_MEDIA_VISUAL,
163 p_param->i_fps_num );
165 p_mp4->p_config = gf_odf_avc_cfg_new();
166 gf_isom_avc_config_new( p_mp4->p_file, p_mp4->i_track, p_mp4->p_config,
167 NULL, NULL, &p_mp4->i_descidx );
169 gf_isom_set_track_enabled( p_mp4->p_file, p_mp4->i_track, 1 );
171 gf_isom_set_visual_info( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx,
172 p_param->i_width, p_param->i_height );
174 if( p_param->vui.i_sar_width && p_param->vui.i_sar_height )
176 uint64_t dw = p_param->i_width << 16;
177 uint64_t dh = p_param->i_height << 16;
178 double sar = (double)p_param->vui.i_sar_width / p_param->vui.i_sar_height;
183 gf_isom_set_track_layout_info( p_mp4->p_file, p_mp4->i_track, dw, dh, 0, 0, 0 );
186 p_mp4->p_sample->data = malloc( p_param->i_width * p_param->i_height * 3 / 2 );
187 if( !p_mp4->p_sample->data )
190 p_mp4->i_time_res = p_param->i_fps_num;
191 p_mp4->i_time_inc = p_param->i_fps_den;
192 p_mp4->i_init_delay = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0;
193 p_mp4->i_init_delay *= p_mp4->i_time_inc;
194 fprintf( stderr, "mp4 [info]: initial delay %d (scale %d)\n",
195 p_mp4->i_init_delay, p_mp4->i_time_res );
200 static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size )
202 mp4_hnd_t *p_mp4 = handle;
203 GF_AVCConfigSlot *p_slot;
204 uint8_t type = p_nalu[4] & 0x1f;
213 p_mp4->p_config->configurationVersion = 1;
214 p_mp4->p_config->AVCProfileIndication = p_nalu[5];
215 p_mp4->p_config->profile_compatibility = p_nalu[6];
216 p_mp4->p_config->AVCLevelIndication = p_nalu[7];
217 p_slot = malloc( sizeof(GF_AVCConfigSlot) );
220 p_slot->size = i_size - 4;
221 p_slot->data = malloc( p_slot->size );
224 memcpy( p_slot->data, p_nalu + 4, i_size - 4 );
225 gf_list_add( p_mp4->p_config->sequenceParameterSets, p_slot );
235 p_slot = malloc( sizeof(GF_AVCConfigSlot) );
238 p_slot->size = i_size - 4;
239 p_slot->data = malloc( p_slot->size );
242 memcpy( p_slot->data, p_nalu + 4, i_size - 4 );
243 gf_list_add( p_mp4->p_config->pictureParameterSets, p_slot );
247 gf_isom_avc_config_update( p_mp4->p_file, p_mp4->i_track, 1, p_mp4->p_config );
256 memcpy( p_mp4->p_sample->data + p_mp4->p_sample->dataLength, p_nalu, i_size );
257 p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 0] = psize >> 24;
258 p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 1] = psize >> 16;
259 p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 2] = psize >> 8;
260 p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 3] = psize >> 0;
261 p_mp4->p_sample->dataLength += i_size;
268 static int set_eop( hnd_t handle, x264_picture_t *p_picture )
270 mp4_hnd_t *p_mp4 = handle;
271 uint64_t dts = (uint64_t)p_mp4->i_numframe * p_mp4->i_time_inc;
272 uint64_t pts = (uint64_t)p_picture->i_pts;
273 int32_t offset = p_mp4->i_init_delay + pts - dts;
275 p_mp4->p_sample->IsRAP = p_picture->i_type == X264_TYPE_IDR ? 1 : 0;
276 p_mp4->p_sample->DTS = dts;
277 p_mp4->p_sample->CTS_Offset = offset;
278 gf_isom_add_sample( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx, p_mp4->p_sample );
280 p_mp4->p_sample->dataLength = 0;
286 cli_output_t mp4_output = { open_file, set_param, write_nalu, set_eop, close_file };