diff options
author | handbrake <[email protected]> | 2006-01-14 13:40:38 +0000 |
---|---|---|
committer | handbrake <[email protected]> | 2006-01-14 13:40:38 +0000 |
commit | 56bb6ce496b475944bb9577c7586e84be1cb831e (patch) | |
tree | 7720c135a160a34f22ce8f1f911f350e18207eaa /libhb/muxmp4.c | |
parent | d35a2a23fe450c88925128b9db7c63a5f1ed395d (diff) |
HandBrake 0.7.0
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@16 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/muxmp4.c')
-rw-r--r-- | libhb/muxmp4.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c new file mode 100644 index 000000000..a02a05232 --- /dev/null +++ b/libhb/muxmp4.c @@ -0,0 +1,160 @@ +/* $Id: muxmp4.c,v 1.24 2005/11/04 13:09:41 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +/* libmp4v2 header */ +#include "mp4.h" + +#include "hb.h" + +struct hb_mux_object_s +{ + HB_MUX_COMMON; + + hb_job_t * job; + + /* libmp4v2 handle */ + MP4FileHandle file; + + /* Cumulated durations so far, in timescale units (see MP4Mux) */ + uint64_t sum_dur; +}; + +struct hb_mux_data_s +{ + MP4TrackId track; +}; + +/********************************************************************** + * MP4Init + ********************************************************************** + * Allocates hb_mux_data_t structures, create file and write headers + *********************************************************************/ +static int MP4Init( hb_mux_object_t * m ) +{ + hb_job_t * job = m->job; + hb_title_t * title = job->title; + + hb_audio_t * audio; + hb_mux_data_t * mux_data; + int i; + + /* Create an empty mp4 file */ + m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 ); + + /* Video track */ + mux_data = malloc( sizeof( hb_mux_data_t ) ); + job->mux_data = mux_data; + + /* When using the standard 90000 timescale, QuickTime tends to have + synchronization issues (audio not playing at the correct speed). + To workaround this, we use the audio samplerate as the + timescale */ + MP4SetTimeScale( m->file, job->arate ); + + if( job->vcodec == HB_VCODEC_X264 ) + { +#define c job->config.h264 + /* Stolen from mp4creator */ + MP4SetVideoProfileLevel( m->file, 0x7F ); + + mux_data->track = MP4AddH264VideoTrack( m->file, job->arate, + MP4_INVALID_DURATION, job->width, job->height, + c.sps[1], /* AVCProfileIndication */ + c.sps[2], /* profile_compat */ + c.sps[3], /* AVCLevelIndication */ + 3 ); /* 4 bytes length before each NAL unit */ + + MP4AddH264SequenceParameterSet( m->file, mux_data->track, + c.sps, c.sps_length ); + MP4AddH264PictureParameterSet( m->file, mux_data->track, + c.pps, c.pps_length ); +#undef c + } + else /* FFmpeg or XviD */ + { +#define c job->config.mpeg4 + MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 ); + mux_data->track = MP4AddVideoTrack( m->file, job->arate, + MP4_INVALID_DURATION, job->width, job->height, + MP4_MPEG4_VIDEO_TYPE ); + + /* VOL from FFmpeg or XviD */ + MP4SetTrackESConfiguration( m->file, mux_data->track, + c.config, c.config_length ); +#undef c + } + + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + mux_data = malloc( sizeof( hb_mux_data_t ) ); + audio->mux_data = mux_data; + + mux_data->track = MP4AddAudioTrack( m->file, + job->arate, 1024, MP4_MPEG4_AUDIO_TYPE ); + MP4SetAudioProfileLevel( m->file, 0x0F ); + MP4SetTrackESConfiguration( m->file, mux_data->track, + audio->config.faac.decinfo, audio->config.faac.size ); + } + + return 0; +} + +static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, + hb_buffer_t * buf ) +{ + hb_job_t * job = m->job; + + uint64_t duration; + + if( mux_data == job->mux_data ) + { + /* Video */ + /* Because we use the audio samplerate as the timescale, + we have to use potentially variable durations so the video + doesn't go out of sync */ + duration = ( buf->stop * job->arate / 90000 ) - m->sum_dur; + m->sum_dur += duration; + } + else + { + /* Audio */ + duration = MP4_INVALID_DURATION; + } + + MP4WriteSample( m->file, mux_data->track, buf->data, buf->size, + duration, 0, buf->key ); + return 0; +} + +static int MP4End( hb_mux_object_t * m ) +{ + hb_job_t * job = m->job; + char filename[1024]; memset( filename, 0, 1024 ); + + MP4Close( m->file ); + +#if 0 + hb_log( "muxmp4: optimizing file" ); + snprintf( filename, 1024, "%s.tmp", job->file ); + MP4Optimize( job->file, filename, MP4_DETAILS_ERROR ); + remove( job->file ); + rename( filename, job->file ); +#endif + + return 0; +} + +hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job ) +{ + hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 ); + m->init = MP4Init; + m->mux = MP4Mux; + m->end = MP4End; + m->job = job; + return m; +} + |