1 /* $Id: muxmp4.c,v 1.24 2005/11/04 13:09:41 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.m0k.org/>.
5 It may be used under the terms of the GNU General Public License. */
12 void AddIPodUUID(MP4FileHandle, MP4TrackId);
15 struct hb_mux_object_s
24 /* Cumulated durations so far, in timescale units (see MP4Mux) */
33 /**********************************************************************
35 **********************************************************************
36 * Allocates hb_mux_data_t structures, create file and write headers
37 *********************************************************************/
38 static int MP4Init( hb_mux_object_t * m )
40 hb_job_t * job = m->job;
41 hb_title_t * title = job->title;
44 hb_mux_data_t * mux_data;
47 /* Create an empty mp4 file */
48 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
51 mux_data = malloc( sizeof( hb_mux_data_t ) );
52 job->mux_data = mux_data;
54 /* When using the standard 90000 timescale, QuickTime tends to have
55 synchronization issues (audio not playing at the correct speed).
56 To workaround this, we use the audio samplerate as the
58 MP4SetTimeScale( m->file, job->arate );
60 if( job->vcodec == HB_VCODEC_X264 )
62 /* Stolen from mp4creator */
63 MP4SetVideoProfileLevel( m->file, 0x7F );
65 if (job->areBframes == 1)
67 hb_log("muxmp4: Adjusting duration for B-frames");
68 mux_data->track = MP4AddH264VideoTrack( m->file, job->arate,
69 MP4_INVALID_DURATION+1, job->width, job->height,
70 job->config.h264.sps[1], /* AVCProfileIndication */
71 job->config.h264.sps[2], /* profile_compat */
72 job->config.h264.sps[3], /* AVCLevelIndication */
73 3 ); /* 4 bytes length before each NAL unit */
77 hb_log("muxmp4: Using default duration as there are no B-frames");
78 mux_data->track = MP4AddH264VideoTrack( m->file, job->arate,
79 MP4_INVALID_DURATION, job->width, job->height,
80 job->config.h264.sps[1], /* AVCProfileIndication */
81 job->config.h264.sps[2], /* profile_compat */
82 job->config.h264.sps[3], /* AVCLevelIndication */
83 3 ); /* 4 bytes length before each NAL unit */
86 MP4AddH264SequenceParameterSet( m->file, mux_data->track,
87 job->config.h264.sps, job->config.h264.sps_length );
88 MP4AddH264PictureParameterSet( m->file, mux_data->track,
89 job->config.h264.pps, job->config.h264.pps_length );
91 if( job->h264_level == 30)
93 hb_log("About to add iPod atom");
94 AddIPodUUID(m->file, mux_data->track);
98 else /* FFmpeg or XviD */
100 MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 );
101 mux_data->track = MP4AddVideoTrack( m->file, job->arate,
102 MP4_INVALID_DURATION, job->width, job->height,
103 MP4_MPEG4_VIDEO_TYPE );
105 /* VOL from FFmpeg or XviD */
106 MP4SetTrackESConfiguration( m->file, mux_data->track,
107 job->config.mpeg4.bytes, job->config.mpeg4.length );
110 /* apply the anamorphic transformation matrix if needed */
112 if( job->pixel_ratio ) {
116 uint32_t *ptr32 = (uint32_t*) (nval + 2);
119 MP4GetBytesProperty(m->file, "moov.trak.tkhd.reserved3", &val, &size);
123 memcpy(nval, val, size);
127 width = job->pixel_aspect_width;
128 height = job->pixel_aspect_height;
129 widthRatio = (width / height) * 0x10000;
131 uint32_t widthRatioInt;
132 widthRatioInt = (uint32_t)widthRatio;
134 #ifdef WORDS_BIGENDIAN
135 ptr32[0] = widthRatioInt;
137 /* we need to switch the endianness, as the file format expects big endian */
138 ptr32[0] = ((widthRatioInt & 0x000000FF) << 24) + ((widthRatioInt & 0x0000FF00) << 8) + ((widthRatioInt & 0x00FF0000) >> 8) + ((widthRatioInt & 0xFF000000) >> 24);
141 if(!MP4SetBytesProperty(m->file, "moov.trak.tkhd.reserved3", nval, size)) {
142 hb_log("Problem setting transform matrix");
149 /* end of transformation matrix */
152 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
154 audio = hb_list_item( title->list_audio, i );
155 mux_data = malloc( sizeof( hb_mux_data_t ) );
156 audio->mux_data = mux_data;
158 mux_data->track = MP4AddAudioTrack( m->file,
159 job->arate, 1024, MP4_MPEG4_AUDIO_TYPE );
160 MP4SetAudioProfileLevel( m->file, 0x0F );
161 MP4SetTrackESConfiguration( m->file, mux_data->track,
162 audio->config.aac.bytes, audio->config.aac.length );
168 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
171 hb_job_t * job = m->job;
175 if( mux_data == job->mux_data )
178 /* Because we use the audio samplerate as the timescale,
179 we have to use potentially variable durations so the video
180 doesn't go out of sync */
181 duration = ( buf->stop * job->arate / 90000 ) - m->sum_dur;
182 m->sum_dur += duration;
187 duration = MP4_INVALID_DURATION;
190 MP4WriteSample( m->file, mux_data->track, buf->data, buf->size,
191 duration, 0, buf->key );
195 static int MP4End( hb_mux_object_t * m )
198 hb_job_t * job = m->job;
200 char filename[1024]; memset( filename, 0, 1024 );
205 hb_log( "muxmp4: optimizing file" );
206 snprintf( filename, 1024, "%s.tmp", job->file );
207 MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
209 rename( filename, job->file );
215 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
217 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );