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.fr/>.
5 It may be used under the terms of the GNU General Public License. */
12 void AddIPodUUID(MP4FileHandle, MP4TrackId);
14 struct hb_mux_object_s
23 /* Cumulated durations so far, in timescale units (see MP4Mux) */
26 /* Chapter state information for muxing */
27 MP4TrackId chapter_track;
29 uint64_t chapter_duration;
31 /* Sample rate of the first audio track.
32 * Used for the timescale
42 struct hb_text_sample_s
49 /**********************************************************************
51 **********************************************************************
52 * Creates a buffer for a text track sample
53 *********************************************************************/
54 static struct hb_text_sample_s *MP4CreateTextSample( char *textString, uint64_t duration )
56 struct hb_text_sample_s *sample = NULL;
57 int stringLength = strlen(textString);
60 if( stringLength < 1024 )
62 sample = malloc( sizeof( struct hb_text_sample_s ) );
64 //textLength = (stringLength; // Account for BOM
65 sample->length = stringLength + 2 + 12; // Account for text length code and other marker
66 sample->duration = (MP4Duration)duration;
68 // 2-byte length marker
69 sample->sample[0] = (stringLength >> 8) & 0xff;
70 sample->sample[1] = stringLength & 0xff;
72 strncpy( (char *)&(sample->sample[2]), textString, stringLength );
76 // Modifier Length Marker
77 sample->sample[x] = 0x00;
78 sample->sample[x+1] = 0x00;
79 sample->sample[x+2] = 0x00;
80 sample->sample[x+3] = 0x0C;
83 sample->sample[x+4] = 'e';
84 sample->sample[x+5] = 'n';
85 sample->sample[x+6] = 'c';
86 sample->sample[x+7] = 'd';
89 sample->sample[x+8] = 0x00;
90 sample->sample[x+9] = 0x00;
91 sample->sample[x+10] = (256 >> 8) & 0xff;
92 sample->sample[x+11] = 256 & 0xff;
98 /**********************************************************************
99 * MP4GenerateChapterSample
100 **********************************************************************
101 * Creates a buffer for a text track sample
102 *********************************************************************/
103 static struct hb_text_sample_s *MP4GenerateChapterSample( hb_mux_object_t * m,
107 // We substract 1 from the chapter number because the chapters start at
108 // 1 but our name array starts at 0. We substract another 1 because we're
109 // writing the text of the previous chapter mark (when we get the start
110 // of chapter 2 we know the duration of chapter 1 & can write its mark).
111 hb_chapter_t *chapter_data = hb_list_item( m->job->title->list_chapter,
113 char tmp_buffer[1024];
114 char *string = tmp_buffer;
116 tmp_buffer[0] = '\0';
118 if( chapter_data != NULL )
120 string = chapter_data->title;
123 if( strlen(string) == 0 || strlen(string) >= 1024 )
125 snprintf( tmp_buffer, 1023, "Chapter %03i", chapter - 2 );
129 return MP4CreateTextSample( string, duration );
133 /**********************************************************************
135 **********************************************************************
136 * Allocates hb_mux_data_t structures, create file and write headers
137 *********************************************************************/
138 static int MP4Init( hb_mux_object_t * m )
140 hb_job_t * job = m->job;
141 hb_title_t * title = job->title;
144 hb_mux_data_t * mux_data;
146 u_int16_t language_code;
148 /* Flags for enabling/disabling tracks in an MP4. */
149 typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8} track_header_flags;
151 /* Need the sample rate of the first audio track to use as the timescale. */
152 audio = hb_list_item(title->list_audio, 0);
153 m->samplerate = audio->config.out.samplerate;
156 /* Create an empty mp4 file */
157 if (job->largeFileSize)
158 /* Use 64-bit MP4 file */
160 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, MP4_CREATE_64BIT_DATA );
161 hb_log("Using 64-bit MP4 formatting.");
164 /* Limit MP4s to less than 4 GB */
166 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
169 if (m->file == MP4_INVALID_FILE_HANDLE)
171 hb_error("muxmp4.c: MP4Create failed!");
177 mux_data = malloc( sizeof( hb_mux_data_t ) );
178 job->mux_data = mux_data;
180 /* When using the standard 90000 timescale, QuickTime tends to have
181 synchronization issues (audio not playing at the correct speed).
182 To workaround this, we use the audio samplerate as the
184 if (!(MP4SetTimeScale( m->file, m->samplerate )))
186 hb_error("muxmp4.c: MP4SetTimeScale failed!");
191 if( job->vcodec == HB_VCODEC_X264 )
193 /* Stolen from mp4creator */
194 if(!(MP4SetVideoProfileLevel( m->file, 0x7F )))
196 hb_error("muxmp4.c: MP4SetVideoProfileLevel failed!");
201 mux_data->track = MP4AddH264VideoTrack( m->file, m->samplerate,
202 MP4_INVALID_DURATION, job->width, job->height,
203 job->config.h264.sps[1], /* AVCProfileIndication */
204 job->config.h264.sps[2], /* profile_compat */
205 job->config.h264.sps[3], /* AVCLevelIndication */
206 3 ); /* 4 bytes length before each NAL unit */
209 MP4AddH264SequenceParameterSet( m->file, mux_data->track,
210 job->config.h264.sps, job->config.h264.sps_length );
211 MP4AddH264PictureParameterSet( m->file, mux_data->track,
212 job->config.h264.pps, job->config.h264.pps_length );
214 if( job->h264_level == 30 || job->ipod_atom)
216 hb_log("About to add iPod atom");
217 AddIPodUUID(m->file, mux_data->track);
221 else /* FFmpeg or XviD */
223 if(!(MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 )))
225 hb_error("muxmp4.c: MP4SetVideoProfileLevel failed!");
229 mux_data->track = MP4AddVideoTrack( m->file, m->samplerate,
230 MP4_INVALID_DURATION, job->width, job->height,
231 MP4_MPEG4_VIDEO_TYPE );
232 if (mux_data->track == MP4_INVALID_TRACK_ID)
234 hb_error("muxmp4.c: MP4AddVideoTrack failed!");
240 /* VOL from FFmpeg or XviD */
241 if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
242 job->config.mpeg4.bytes, job->config.mpeg4.length )))
244 hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
250 if( job->pixel_ratio )
252 /* PASP atom for anamorphic video */
255 width = job->pixel_aspect_width;
257 height = job->pixel_aspect_height;
259 MP4AddPixelAspectRatio(m->file, mux_data->track, (uint32_t)width, (uint32_t)height);
261 MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height));
264 /* firstAudioTrack will be used to reference the first audio track when we add a chapter track */
265 MP4TrackId firstAudioTrack = 0;
267 /* add the audio tracks */
268 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
270 static u_int8_t reserved2[16] = {
271 0x00, 0x00, 0x00, 0x00,
272 0x00, 0x00, 0x00, 0x00,
273 0x00, 0x02, 0x00, 0x10,
274 0x00, 0x00, 0x00, 0x00,
277 audio = hb_list_item( title->list_audio, i );
278 mux_data = malloc( sizeof( hb_mux_data_t ) );
279 audio->priv.mux_data = mux_data;
281 if( audio->config.out.codec == HB_ACODEC_AC3 )
283 mux_data->track = MP4AddAC3AudioTrack(
285 m->samplerate, 1536, MP4_MPEG4_AUDIO_TYPE );
286 MP4SetTrackBytesProperty(
287 m->file, mux_data->track,
289 (const u_int8_t*)"Surround", strlen("Surround"));
291 mux_data->track = MP4AddAudioTrack(
293 m->samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
294 MP4SetTrackBytesProperty(
295 m->file, mux_data->track,
297 (const u_int8_t*)"Stereo", strlen("Stereo"));
299 MP4SetAudioProfileLevel( m->file, 0x0F );
300 MP4SetTrackESConfiguration(
301 m->file, mux_data->track,
302 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
304 /* Set the correct number of channels for this track */
305 reserved2[9] = (u_int8_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
306 MP4SetTrackBytesProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.reserved2", reserved2, sizeof(reserved2));
309 /* Set the language for this track */
310 /* The language is stored as 5-bit text - 0x60 */
311 language_code = audio->config.lang.iso639_2[0] - 0x60; language_code <<= 5;
312 language_code |= audio->config.lang.iso639_2[1] - 0x60; language_code <<= 5;
313 language_code |= audio->config.lang.iso639_2[2] - 0x60;
314 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.mdhd.language", language_code);
317 /* Set the audio track alternate group */
318 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
320 /* If we ever upgrade mpeg4ip, the line above should be replaced with the line below.*/
321 // MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (u_int16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown));
323 /* store a reference to the first audio track,
324 so we can use it to feed the chapter text track's sample rate */
326 firstAudioTrack = mux_data->track;
328 /* Enable the first audio track */
329 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
333 /* Disable the other audio tracks so QuickTime doesn't play
336 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
337 hb_log("Disabled extra audio track %i", mux_data->track-1);
342 if (job->chapter_markers)
344 /* add a text track for the chapters */
345 MP4TrackId textTrack;
346 textTrack = MP4AddChapterTextTrack(m->file, firstAudioTrack);
348 m->chapter_track = textTrack;
349 m->chapter_duration = 0;
350 m->current_chapter = job->chapter_start;
353 /* Add encoded-by metadata listing version and build date */
355 tool_string = (char *)malloc(80);
356 snprintf( tool_string, 80, "HandBrake %s %i", HB_VERSION, HB_BUILD);
357 MP4SetMetadataTool(m->file, tool_string);
363 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
366 hb_job_t * job = m->job;
370 if( mux_data == job->mux_data )
372 /* Add the sample before the new frame.
373 It is important that this be calculated prior to the duration
374 of the new video sample, as we want to sync to right after it.
375 (This is because of how durations for text tracks work in QT) */
376 if( job->chapter_markers && buf->new_chap )
378 struct hb_text_sample_s *sample;
380 /* If this is an x264 encode with bframes the IDR frame we're
381 trying to mark will be displayed offset by its renderOffset
382 so we need to offset the chapter by the same amount.
383 MP4 render offsets don't seem to work for text tracks so
384 we have to fudge the duration instead. */
385 duration = m->sum_dur - m->chapter_duration;
387 if ( job->areBframes )
389 duration += buf->renderOffset * m->samplerate / 90000;
392 sample = MP4GenerateChapterSample( m, duration, buf->new_chap );
394 if( !MP4WriteSample(m->file,
401 hb_error("Failed to write to output file, disk full?");
405 m->current_chapter = buf->new_chap;
406 m->chapter_duration += duration;
410 /* Because we use the audio samplerate as the timescale,
411 we have to use potentially variable durations so the video
412 doesn't go out of sync */
413 int64_t bias = ( buf->start * m->samplerate / 90000 ) - m->sum_dur;
414 duration = ( buf->stop - buf->start ) * m->samplerate / 90000 + bias;
417 /* We got an illegal mp4/h264 duration. This shouldn't
418 be possible and usually indicates a bug in the upstream code.
419 Complain in the hope that someone will go find the bug but
420 try to fix the error so that the file will still be playable. */
421 hb_log("MP4Mux: illegal duration %lld, bias %lld, start %lld (%lld),"
422 "stop %lld (%lld), sum_dur %lld",
423 duration, bias, buf->start * m->samplerate / 90000, buf->start,
424 buf->stop * m->samplerate / 90000, buf->stop, m->sum_dur );
425 /* we don't know when the next frame starts so we can't pick a
426 valid duration for this one so we pick something "short"
427 (roughly 1/3 of an NTSC frame time) and rely on the bias calc
428 for the next frame to correct things (a duration underestimate
429 just results in a large bias on the next frame). */
430 duration = 1000 * m->samplerate / 90000;
432 m->sum_dur += duration;
437 duration = MP4_INVALID_DURATION;
440 /* Here's where the sample actually gets muxed.
441 If it's an audio sample, don't offset the sample's playback.
442 If it's a video sample and there are no b-frames, ditto.
443 If there are b-frames, offset by the initDelay plus the
444 difference between the presentation time stamp x264 gives
445 and the decoding time stamp from the buffer data. */
446 if( !MP4WriteSample( m->file,
451 ((mux_data->track != 1) ||
452 (job->areBframes==0) ||
453 (job->vcodec != HB_VCODEC_X264)) ? 0 : ( buf->renderOffset * m->samplerate / 90000),
454 ((buf->frametype & HB_FRAME_KEY) != 0) ) )
456 hb_error("Failed to write to output file, disk full?");
463 static int MP4End( hb_mux_object_t * m )
465 hb_job_t * job = m->job;
467 /* Write our final chapter marker */
468 if( m->job->chapter_markers )
470 struct hb_text_sample_s *sample = MP4GenerateChapterSample( m,
471 (m->sum_dur - m->chapter_duration),
472 m->current_chapter + 1 );
474 if( !MP4WriteSample(m->file,
481 hb_error("Failed to write to output file, disk full?");
489 // Insert track edit to get A/V back in sync. The edit amount is
490 // the rendering offset of the first sample.
491 MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, MP4GetSampleRenderingOffset(m->file,1,1),
492 MP4GetTrackDuration(m->file, 1), 0);
493 if ( m->job->chapter_markers )
495 // apply same edit to chapter track to keep it in sync with video
496 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
497 MP4GetSampleRenderingOffset(m->file,1,1),
498 MP4GetTrackDuration(m->file, m->chapter_track), 0);
504 if ( job->mp4_optimize )
506 hb_log( "muxmp4: optimizing file" );
507 char filename[1024]; memset( filename, 0, 1024 );
508 snprintf( filename, 1024, "%s.tmp", job->file );
509 MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
511 rename( filename, job->file );
517 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
519 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );