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 if( (audio = hb_list_item(title->list_audio, 0)) != NULL )
153 /* Need the sample rate of the first audio track to use as the timescale. */
154 m->samplerate = audio->config.out.samplerate;
159 m->samplerate = 90000;
162 /* Create an empty mp4 file */
163 if (job->largeFileSize)
164 /* Use 64-bit MP4 file */
166 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, MP4_CREATE_64BIT_DATA );
167 hb_log("Using 64-bit MP4 formatting.");
170 /* Limit MP4s to less than 4 GB */
172 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
175 if (m->file == MP4_INVALID_FILE_HANDLE)
177 hb_error("muxmp4.c: MP4Create failed!");
183 mux_data = malloc( sizeof( hb_mux_data_t ) );
184 job->mux_data = mux_data;
186 /* When using the standard 90000 timescale, QuickTime tends to have
187 synchronization issues (audio not playing at the correct speed).
188 To workaround this, we use the audio samplerate as the
190 if (!(MP4SetTimeScale( m->file, m->samplerate )))
192 hb_error("muxmp4.c: MP4SetTimeScale failed!");
197 if( job->vcodec == HB_VCODEC_X264 )
199 /* Stolen from mp4creator */
200 if(!(MP4SetVideoProfileLevel( m->file, 0x7F )))
202 hb_error("muxmp4.c: MP4SetVideoProfileLevel failed!");
207 mux_data->track = MP4AddH264VideoTrack( m->file, m->samplerate,
208 MP4_INVALID_DURATION, job->width, job->height,
209 job->config.h264.sps[1], /* AVCProfileIndication */
210 job->config.h264.sps[2], /* profile_compat */
211 job->config.h264.sps[3], /* AVCLevelIndication */
212 3 ); /* 4 bytes length before each NAL unit */
215 MP4AddH264SequenceParameterSet( m->file, mux_data->track,
216 job->config.h264.sps, job->config.h264.sps_length );
217 MP4AddH264PictureParameterSet( m->file, mux_data->track,
218 job->config.h264.pps, job->config.h264.pps_length );
220 if( job->h264_level == 30 || job->ipod_atom)
222 hb_log("About to add iPod atom");
223 AddIPodUUID(m->file, mux_data->track);
227 else /* FFmpeg or XviD */
229 if(!(MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 )))
231 hb_error("muxmp4.c: MP4SetVideoProfileLevel failed!");
235 mux_data->track = MP4AddVideoTrack( m->file, m->samplerate,
236 MP4_INVALID_DURATION, job->width, job->height,
237 MP4_MPEG4_VIDEO_TYPE );
238 if (mux_data->track == MP4_INVALID_TRACK_ID)
240 hb_error("muxmp4.c: MP4AddVideoTrack failed!");
246 /* VOL from FFmpeg or XviD */
247 if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
248 job->config.mpeg4.bytes, job->config.mpeg4.length )))
250 hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
256 // COLR atom for color and gamma correction.
258 // http://developer.apple.com/quicktime/icefloe/dispatch019.html#colr
259 // http://forum.doom9.org/showthread.php?t=133982#post1090068
260 // we say anything that's likely to be HD content is ITU BT.709 and
261 // DVD, SD TV & other content is ITU BT.601. We look at the title height
262 // rather than the job height here to get uncropped input dimensions.
263 if ( job->title->height >= 720 )
265 // we guess that 720p or above is ITU BT.709 HD content
266 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
270 // ITU BT.601 DVD or SD TV content
271 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
274 if( job->pixel_ratio )
276 /* PASP atom for anamorphic video */
279 width = job->pixel_aspect_width;
281 height = job->pixel_aspect_height;
283 MP4AddPixelAspectRatio(m->file, mux_data->track, (uint32_t)width, (uint32_t)height);
285 MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height));
288 /* firstAudioTrack will be used to reference the first audio track when we add a chapter track */
289 MP4TrackId firstAudioTrack = 0;
291 /* add the audio tracks */
292 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
294 static u_int8_t reserved2[16] = {
295 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x02, 0x00, 0x10,
298 0x00, 0x00, 0x00, 0x00,
301 audio = hb_list_item( title->list_audio, i );
302 mux_data = malloc( sizeof( hb_mux_data_t ) );
303 audio->priv.mux_data = mux_data;
305 if( audio->config.out.codec == HB_ACODEC_AC3 )
307 mux_data->track = MP4AddAC3AudioTrack(
309 m->samplerate, 1536, MP4_MPEG4_AUDIO_TYPE );
310 MP4SetTrackBytesProperty(
311 m->file, mux_data->track,
313 (const u_int8_t*)"Surround", strlen("Surround"));
315 mux_data->track = MP4AddAudioTrack(
317 m->samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
318 MP4SetTrackBytesProperty(
319 m->file, mux_data->track,
321 (const u_int8_t*)"Stereo", strlen("Stereo"));
323 MP4SetAudioProfileLevel( m->file, 0x0F );
324 MP4SetTrackESConfiguration(
325 m->file, mux_data->track,
326 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
328 /* Set the correct number of channels for this track */
329 reserved2[9] = (u_int8_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
330 MP4SetTrackBytesProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.reserved2", reserved2, sizeof(reserved2));
333 /* Set the language for this track */
334 /* The language is stored as 5-bit text - 0x60 */
335 language_code = audio->config.lang.iso639_2[0] - 0x60; language_code <<= 5;
336 language_code |= audio->config.lang.iso639_2[1] - 0x60; language_code <<= 5;
337 language_code |= audio->config.lang.iso639_2[2] - 0x60;
338 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.mdhd.language", language_code);
341 /* Set the audio track alternate group */
342 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
344 /* If we ever upgrade mpeg4ip, the line above should be replaced with the line below.*/
345 // MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (u_int16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown));
347 /* store a reference to the first audio track,
348 so we can use it to feed the chapter text track's sample rate */
350 firstAudioTrack = mux_data->track;
352 /* Enable the first audio track */
353 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
357 /* Disable the other audio tracks so QuickTime doesn't play
360 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
361 hb_log("Disabled extra audio track %i", mux_data->track-1);
366 if (job->chapter_markers)
368 /* add a text track for the chapters */
369 MP4TrackId textTrack;
370 textTrack = MP4AddChapterTextTrack(m->file, firstAudioTrack);
372 m->chapter_track = textTrack;
373 m->chapter_duration = 0;
374 m->current_chapter = job->chapter_start;
377 /* Add encoded-by metadata listing version and build date */
379 tool_string = (char *)malloc(80);
380 snprintf( tool_string, 80, "HandBrake %s %i", HB_VERSION, HB_BUILD);
381 MP4SetMetadataTool(m->file, tool_string);
387 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
390 hb_job_t * job = m->job;
394 if( mux_data == job->mux_data )
396 /* Add the sample before the new frame.
397 It is important that this be calculated prior to the duration
398 of the new video sample, as we want to sync to right after it.
399 (This is because of how durations for text tracks work in QT) */
400 if( job->chapter_markers && buf->new_chap )
402 struct hb_text_sample_s *sample;
404 /* If this is an x264 encode with bframes the IDR frame we're
405 trying to mark will be displayed offset by its renderOffset
406 so we need to offset the chapter by the same amount.
407 MP4 render offsets don't seem to work for text tracks so
408 we have to fudge the duration instead. */
409 duration = m->sum_dur - m->chapter_duration;
411 if ( job->areBframes )
413 duration += buf->renderOffset * m->samplerate / 90000;
417 /* The initial & final chapters can have very short durations
418 * (less than the error in our total duration estimate) so
419 * the duration calc above can result in a negative number.
420 * when this happens give the chapter a short duration (1/3
421 * of an ntsc frame time). */
422 duration = 1000 * m->samplerate / 90000;
425 sample = MP4GenerateChapterSample( m, duration, buf->new_chap );
427 if( !MP4WriteSample(m->file,
434 hb_error("Failed to write to output file, disk full?");
438 m->current_chapter = buf->new_chap;
439 m->chapter_duration += duration;
443 /* Because we use the audio samplerate as the timescale,
444 we have to use potentially variable durations so the video
445 doesn't go out of sync */
446 int64_t bias = ( buf->start * m->samplerate / 90000 ) - m->sum_dur;
447 duration = ( buf->stop - buf->start ) * m->samplerate / 90000 + bias;
450 /* We got an illegal mp4/h264 duration. This shouldn't
451 be possible and usually indicates a bug in the upstream code.
452 Complain in the hope that someone will go find the bug but
453 try to fix the error so that the file will still be playable. */
454 hb_log("MP4Mux: illegal duration %lld, bias %lld, start %lld (%lld),"
455 "stop %lld (%lld), sum_dur %lld",
456 duration, bias, buf->start * m->samplerate / 90000, buf->start,
457 buf->stop * m->samplerate / 90000, buf->stop, m->sum_dur );
458 /* we don't know when the next frame starts so we can't pick a
459 valid duration for this one so we pick something "short"
460 (roughly 1/3 of an NTSC frame time) and rely on the bias calc
461 for the next frame to correct things (a duration underestimate
462 just results in a large bias on the next frame). */
463 duration = 1000 * m->samplerate / 90000;
465 m->sum_dur += duration;
470 duration = MP4_INVALID_DURATION;
473 /* Here's where the sample actually gets muxed.
474 If it's an audio sample, don't offset the sample's playback.
475 If it's a video sample and there are no b-frames, ditto.
476 If there are b-frames, offset by the initDelay plus the
477 difference between the presentation time stamp x264 gives
478 and the decoding time stamp from the buffer data. */
479 if( !MP4WriteSample( m->file,
484 ((mux_data->track != 1) ||
485 (job->areBframes==0) ||
486 (job->vcodec != HB_VCODEC_X264)) ? 0 : ( buf->renderOffset * m->samplerate / 90000),
487 ((buf->frametype & HB_FRAME_KEY) != 0) ) )
489 hb_error("Failed to write to output file, disk full?");
496 static int MP4End( hb_mux_object_t * m )
498 hb_job_t * job = m->job;
500 /* Write our final chapter marker */
501 if( m->job->chapter_markers )
503 int64_t duration = m->sum_dur - m->chapter_duration;
506 /* The initial & final chapters can have very short durations
507 * (less than the error in our total duration estimate) so
508 * the duration calc above can result in a negative number.
509 * when this happens give the chapter a short duration (1/3
510 * of an ntsc frame time). */
511 duration = 1000 * m->samplerate / 90000;
514 struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, duration,
515 m->current_chapter + 1 );
517 if( !MP4WriteSample(m->file,
524 hb_error("Failed to write to output file, disk full?");
532 // Insert track edit to get A/V back in sync. The edit amount is
533 // the rendering offset of the first sample.
534 MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, MP4GetSampleRenderingOffset(m->file,1,1),
535 MP4GetTrackDuration(m->file, 1), 0);
536 if ( m->job->chapter_markers )
538 // apply same edit to chapter track to keep it in sync with video
539 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
540 MP4GetSampleRenderingOffset(m->file,1,1),
541 MP4GetTrackDuration(m->file, m->chapter_track), 0);
547 if ( job->mp4_optimize )
549 hb_log( "muxmp4: optimizing file" );
550 char filename[1024]; memset( filename, 0, 1024 );
551 snprintf( filename, 1024, "%s.tmp", job->file );
552 MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
554 rename( filename, job->file );
560 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
562 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );