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. */
7 #include "mp4v2/mp4v2.h"
8 #include "a52dec/a52.h"
12 struct hb_mux_object_s
21 /* Cumulated durations so far, in output & input timescale units (see MP4Mux) */
22 int64_t sum_dur; // duration in output timescale units
23 int64_t sum_dur_in; // duration in input 90KHz timescale units
25 // bias to keep render offsets in ctts atom positive (set up by encx264)
28 /* Chapter state information for muxing */
29 MP4TrackId chapter_track;
31 uint64_t chapter_duration;
33 /* Sample rate of the first audio track.
34 * Used for the timescale
44 /* Tune video track chunk duration.
45 * libmp4v2 default duration == dusamplerate == 1 second.
46 * Per van's suggestion we desire duration == 4 frames.
47 * Should be invoked immediately after track creation.
49 * return true on fail, false on success.
51 static int MP4TuneTrackDurationPerChunk( hb_mux_object_t* m, MP4TrackId trackId )
56 tscale = MP4GetTrackTimeScale( m->file, trackId );
57 dur = (MP4Duration)ceil( (double)tscale * (double)m->job->vrate_base / (double)m->job->vrate * 4.0 );
59 if( !MP4SetTrackDurationPerChunk( m->file, trackId, dur ))
61 hb_error( "muxmp4.c: MP4SetTrackDurationPerChunk failed!" );
66 hb_deep_log( 2, "muxmp4: track %u, chunk duration %llu", MP4FindTrackIndex( m->file, trackId ), dur );
70 /**********************************************************************
72 **********************************************************************
73 * Allocates hb_mux_data_t structures, create file and write headers
74 *********************************************************************/
75 static int MP4Init( hb_mux_object_t * m )
77 hb_job_t * job = m->job;
78 hb_title_t * title = job->title;
81 hb_mux_data_t * mux_data;
84 /* Flags for enabling/disabling tracks in an MP4. */
85 typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8} track_header_flags;
87 if( (audio = hb_list_item(title->list_audio, 0)) != NULL )
89 /* Need the sample rate of the first audio track to use as the timescale. */
90 m->samplerate = audio->config.out.samplerate;
95 m->samplerate = 90000;
98 /* Create an empty mp4 file */
99 if (job->largeFileSize)
100 /* Use 64-bit MP4 file */
102 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, MP4_CREATE_64BIT_DATA );
103 hb_deep_log( 2, "muxmp4: using 64-bit MP4 formatting.");
106 /* Limit MP4s to less than 4 GB */
108 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
111 if (m->file == MP4_INVALID_FILE_HANDLE)
113 hb_error("muxmp4.c: MP4Create failed!");
119 mux_data = malloc( sizeof( hb_mux_data_t ) );
120 job->mux_data = mux_data;
122 /* When using the standard 90000 timescale, QuickTime tends to have
123 synchronization issues (audio not playing at the correct speed).
124 To workaround this, we use the audio samplerate as the
126 if (!(MP4SetTimeScale( m->file, m->samplerate )))
128 hb_error("muxmp4.c: MP4SetTimeScale failed!");
133 if( job->vcodec == HB_VCODEC_X264 )
135 /* Stolen from mp4creator */
136 MP4SetVideoProfileLevel( m->file, 0x7F );
137 mux_data->track = MP4AddH264VideoTrack( m->file, m->samplerate,
138 MP4_INVALID_DURATION, job->width, job->height,
139 job->config.h264.sps[1], /* AVCProfileIndication */
140 job->config.h264.sps[2], /* profile_compat */
141 job->config.h264.sps[3], /* AVCLevelIndication */
142 3 ); /* 4 bytes length before each NAL unit */
143 if ( mux_data->track == MP4_INVALID_TRACK_ID )
145 hb_error( "muxmp4.c: MP4AddH264VideoTrack failed!" );
150 /* Tune track chunk duration */
151 if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
156 MP4AddH264SequenceParameterSet( m->file, mux_data->track,
157 job->config.h264.sps, job->config.h264.sps_length );
158 MP4AddH264PictureParameterSet( m->file, mux_data->track,
159 job->config.h264.pps, job->config.h264.pps_length );
161 if( job->h264_level == 30 || job->ipod_atom)
163 hb_deep_log( 2, "muxmp4: adding iPod atom");
164 MP4AddIPodUUID(m->file, mux_data->track);
167 m->init_delay = job->config.h264.init_delay;
169 else /* FFmpeg or XviD */
171 MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 );
172 mux_data->track = MP4AddVideoTrack( m->file, m->samplerate,
173 MP4_INVALID_DURATION, job->width, job->height,
174 MP4_MPEG4_VIDEO_TYPE );
175 if (mux_data->track == MP4_INVALID_TRACK_ID)
177 hb_error("muxmp4.c: MP4AddVideoTrack failed!");
182 /* Tune track chunk duration */
183 if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
188 /* VOL from FFmpeg or XviD */
189 if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
190 job->config.mpeg4.bytes, job->config.mpeg4.length )))
192 hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
198 // COLR atom for color and gamma correction.
200 // http://developer.apple.com/quicktime/icefloe/dispatch019.html#colr
201 // http://forum.doom9.org/showthread.php?t=133982#post1090068
202 // the user can set it from job->color_matrix, otherwise by default
203 // we say anything that's likely to be HD content is ITU BT.709 and
204 // DVD, SD TV & other content is ITU BT.601. We look at the title height
205 // rather than the job height here to get uncropped input dimensions.
206 if( job->color_matrix == 1 )
208 // ITU BT.601 DVD or SD TV content
209 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
211 else if( job->color_matrix == 2 )
213 // ITU BT.709 HD content
214 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
216 else if ( job->title->width >= 1280 || job->title->height >= 720 )
218 // we guess that 720p or above is ITU BT.709 HD content
219 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
223 // ITU BT.601 DVD or SD TV content
224 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
227 if( job->anamorphic.mode )
229 /* PASP atom for anamorphic video */
232 width = job->anamorphic.par_width;
234 height = job->anamorphic.par_height;
236 MP4AddPixelAspectRatio(m->file, mux_data->track, (uint32_t)width, (uint32_t)height);
238 MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height));
241 /* add the audio tracks */
242 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
244 audio = hb_list_item( title->list_audio, i );
245 mux_data = malloc( sizeof( hb_mux_data_t ) );
246 audio->priv.mux_data = mux_data;
248 if( audio->config.out.codec == HB_ACODEC_AC3 )
251 uint8_t bsid = audio->config.in.version;
252 uint8_t bsmod = audio->config.in.mode;
253 uint8_t acmod = audio->config.flags.ac3 & 0x7;
254 uint8_t lfeon = (audio->config.flags.ac3 & A52_LFE) ? 1 : 0;
255 uint8_t bit_rate_code = 0;
258 * Rewrite AC3 information into correct format for dac3 atom
260 switch( audio->config.in.samplerate )
273 * Error value, tells decoder to not decode this audio.
279 switch( audio->config.in.bitrate )
339 hb_error("Unknown AC3 bitrate");
344 mux_data->track = MP4AddAC3AudioTrack(
346 audio->config.out.samplerate,
354 /* Tune track chunk duration */
355 MP4TuneTrackDurationPerChunk( m, mux_data->track );
357 if (audio->config.out.name == NULL) {
358 MP4SetTrackBytesProperty(
359 m->file, mux_data->track,
361 (const uint8_t*)"Surround", strlen("Surround"));
364 MP4SetTrackBytesProperty(
365 m->file, mux_data->track,
367 (const uint8_t*)(audio->config.out.name),
368 strlen(audio->config.out.name));
371 mux_data->track = MP4AddAudioTrack(
373 audio->config.out.samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
375 /* Tune track chunk duration */
376 MP4TuneTrackDurationPerChunk( m, mux_data->track );
378 if (audio->config.out.name == NULL) {
379 MP4SetTrackBytesProperty(
380 m->file, mux_data->track,
382 (const uint8_t*)"Stereo", strlen("Stereo"));
385 MP4SetTrackBytesProperty(
386 m->file, mux_data->track,
388 (const uint8_t*)(audio->config.out.name),
389 strlen(audio->config.out.name));
392 MP4SetAudioProfileLevel( m->file, 0x0F );
393 MP4SetTrackESConfiguration(
394 m->file, mux_data->track,
395 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
397 /* Set the correct number of channels for this track */
398 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown));
401 /* Set the language for this track */
402 MP4SetTrackLanguage(m->file, mux_data->track, audio->config.lang.iso639_2);
404 if( hb_list_count( title->list_audio ) > 1 )
406 /* Set the audio track alternate group */
407 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
411 /* Enable the first audio track */
412 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
415 /* Disable the other audio tracks so QuickTime doesn't play
418 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
419 hb_deep_log( 2, "muxmp4: disabled extra audio track %u", MP4FindTrackIndex( m->file, mux_data->track ));
424 if (job->chapter_markers)
426 /* add a text track for the chapters. We add the 'chap' atom to track
427 one which is usually the video track & should never be disabled.
428 The Quicktime spec says it doesn't matter which media track the
429 chap atom is on but it has to be an enabled track. */
430 MP4TrackId textTrack;
431 textTrack = MP4AddChapterTextTrack(m->file, 1, 0);
433 m->chapter_track = textTrack;
434 m->chapter_duration = 0;
435 m->current_chapter = job->chapter_start;
438 /* Add encoded-by metadata listing version and build date */
440 tool_string = (char *)malloc(80);
441 snprintf( tool_string, 80, "HandBrake %s %i", HB_PROJECT_VERSION, HB_PROJECT_BUILD);
443 /* allocate,fetch,populate,store,free tags structure */
445 tags = MP4TagsAlloc();
446 MP4TagsFetch( tags, m->file );
447 MP4TagsSetEncodingTool( tags, tool_string );
448 MP4TagsStore( tags, m->file );
456 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
459 hb_job_t * job = m->job;
463 if( mux_data == job->mux_data )
467 // if there are b-frames compute the render offset
468 // (we'll need it for both the video frame & the chapter track)
471 offset = ( buf->start + m->init_delay ) * m->samplerate / 90000 -
475 /* Add the sample before the new frame.
476 It is important that this be calculated prior to the duration
477 of the new video sample, as we want to sync to right after it.
478 (This is because of how durations for text tracks work in QT) */
479 if( job->chapter_markers && buf->new_chap )
481 hb_chapter_t *chapter = NULL;
483 // this chapter is postioned by writing out the previous chapter.
484 // the duration of the previous chapter is the duration up to but
485 // not including the current frame minus the duration of all
486 // chapters up to the previous.
487 duration = m->sum_dur - m->chapter_duration + offset;
490 /* The initial & final chapters can have very short durations
491 * (less than the error in our total duration estimate) so
492 * the duration calc above can result in a negative number.
493 * when this happens give the chapter a short duration (1/3
494 * of an ntsc frame time). */
495 duration = 1000 * m->samplerate / 90000;
498 chapter = hb_list_item( m->job->title->list_chapter,
501 MP4AddChapter( m->file,
504 (chapter != NULL) ? chapter->title : NULL);
506 m->current_chapter = buf->new_chap;
507 m->chapter_duration += duration;
510 // since we're changing the sample rate we need to keep track of
511 // the truncation bias so that the audio and video don't go out
512 // of sync. m->sum_dur_in is the sum of the input durations so far.
513 // m->sum_dur is the sum of the output durations. Their difference
514 // (in output sample rate units) is the accumulated truncation bias.
515 int64_t bias = ( m->sum_dur_in * m->samplerate / 90000 ) - m->sum_dur;
516 int64_t dur_in = buf->stop - buf->start;
517 duration = dur_in * m->samplerate / 90000 + bias;
520 /* We got an illegal mp4/h264 duration. This shouldn't
521 be possible and usually indicates a bug in the upstream code.
522 Complain in the hope that someone will go find the bug but
523 try to fix the error so that the file will still be playable. */
524 hb_log("MP4Mux: illegal duration %lld, bias %lld, start %lld (%lld),"
525 "stop %lld (%lld), sum_dur %lld",
526 duration, bias, buf->start * m->samplerate / 90000, buf->start,
527 buf->stop * m->samplerate / 90000, buf->stop, m->sum_dur );
528 /* we don't know when the next frame starts so we can't pick a
529 valid duration for this one so we pick something "short"
530 (roughly 1/3 of an NTSC frame time) and rely on the bias calc
531 for the next frame to correct things (a duration underestimate
532 just results in a large bias on the next frame). */
533 duration = 1000 * m->samplerate / 90000;
535 m->sum_dur += duration;
536 m->sum_dur_in += dur_in;
541 duration = MP4_INVALID_DURATION;
544 // Here's where the sample actually gets muxed.
545 if( !MP4WriteSample( m->file,
551 ( job->vcodec == HB_VCODEC_X264 && mux_data == job->mux_data ) ?
552 ( buf->frametype == HB_FRAME_IDR ) : ( ( buf->frametype & HB_FRAME_KEY ) != 0 ) ) )
554 hb_error("Failed to write to output file, disk full?");
561 static int MP4End( hb_mux_object_t * m )
563 hb_job_t * job = m->job;
564 hb_title_t * title = job->title;
566 /* Write our final chapter marker */
567 if( m->job->chapter_markers )
569 hb_chapter_t *chapter = NULL;
570 int64_t duration = m->sum_dur - m->chapter_duration;
571 /* The final chapter can have a very short duration - if it's less
572 * than a second just skip it. */
573 if ( duration >= m->samplerate )
576 chapter = hb_list_item( m->job->title->list_chapter,
577 m->current_chapter - 1 );
579 MP4AddChapter( m->file,
582 (chapter != NULL) ? chapter->title : NULL);
588 // Insert track edit to get A/V back in sync. The edit amount is
590 int64_t edit_amt = m->init_delay * m->samplerate / 90000;
591 MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt,
592 MP4GetTrackDuration(m->file, 1), 0);
593 if ( m->job->chapter_markers )
595 // apply same edit to chapter track to keep it in sync with video
596 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
598 MP4GetTrackDuration(m->file, m->chapter_track), 0);
603 * Write the MP4 iTunes metadata if we have any metadata
605 if( title->metadata )
607 hb_metadata_t *md = title->metadata;
610 hb_deep_log( 2, "Writing Metadata to output file...");
612 /* allocate tags structure */
613 tags = MP4TagsAlloc();
614 /* fetch data from MP4 file (in case it already has some data) */
615 MP4TagsFetch( tags, m->file );
618 MP4TagsSetName( tags, md->name );
619 MP4TagsSetArtist( tags, md->artist );
620 MP4TagsSetComposer( tags, md->composer );
621 MP4TagsSetComments( tags, md->comment );
622 MP4TagsSetReleaseDate( tags, md->release_date );
623 MP4TagsSetAlbum( tags, md->album );
624 MP4TagsSetGenre( tags, md->genre );
629 art.data = md->coverart;
630 art.size = md->coverart_size;
631 art.type = MP4_ART_UNDEFINED; // delegate typing to libmp4v2
632 MP4TagsAddArtwork( tags, &art );
635 /* push data to MP4 file */
636 MP4TagsStore( tags, m->file );
637 /* free memory associated with structure */
643 if ( job->mp4_optimize )
645 hb_log( "muxmp4: optimizing file" );
646 char filename[1024]; memset( filename, 0, 1024 );
647 snprintf( filename, 1024, "%s.tmp", job->file );
648 MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
650 rename( filename, job->file );
656 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
658 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );