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 int64_t sum_dur; // sum of video frame durations so far
23 // bias to keep render offsets in ctts atom positive (set up by encx264)
26 /* Chapter state information for muxing */
27 MP4TrackId chapter_track;
29 uint64_t chapter_duration;
39 /* Tune video track chunk duration.
40 * libmp4v2 default duration == dusamplerate == 1 second.
41 * Per van's suggestion we desire duration == 4 frames.
42 * Should be invoked immediately after track creation.
44 * return true on fail, false on success.
46 static int MP4TuneTrackDurationPerChunk( hb_mux_object_t* m, MP4TrackId trackId )
51 tscale = MP4GetTrackTimeScale( m->file, trackId );
52 dur = (MP4Duration)ceil( (double)tscale * (double)m->job->vrate_base / (double)m->job->vrate * 4.0 );
54 if( !MP4SetTrackDurationPerChunk( m->file, trackId, dur ))
56 hb_error( "muxmp4.c: MP4SetTrackDurationPerChunk failed!" );
61 hb_deep_log( 2, "muxmp4: track %u, chunk duration %llu", MP4FindTrackIndex( m->file, trackId ), dur );
65 /**********************************************************************
67 **********************************************************************
68 * Allocates hb_mux_data_t structures, create file and write headers
69 *********************************************************************/
70 static int MP4Init( hb_mux_object_t * m )
72 hb_job_t * job = m->job;
73 hb_title_t * title = job->title;
76 hb_mux_data_t * mux_data;
79 /* Flags for enabling/disabling tracks in an MP4. */
80 typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8} track_header_flags;
82 /* Create an empty mp4 file */
83 if (job->largeFileSize)
84 /* Use 64-bit MP4 file */
86 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, MP4_CREATE_64BIT_DATA );
87 hb_deep_log( 2, "muxmp4: using 64-bit MP4 formatting.");
90 /* Limit MP4s to less than 4 GB */
92 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
95 if (m->file == MP4_INVALID_FILE_HANDLE)
97 hb_error("muxmp4.c: MP4Create failed!");
103 mux_data = calloc(1, sizeof( hb_mux_data_t ) );
104 job->mux_data = mux_data;
106 if (!(MP4SetTimeScale( m->file, 90000 )))
108 hb_error("muxmp4.c: MP4SetTimeScale failed!");
113 if( job->vcodec == HB_VCODEC_X264 )
115 /* Stolen from mp4creator */
116 MP4SetVideoProfileLevel( m->file, 0x7F );
117 mux_data->track = MP4AddH264VideoTrack( m->file, 90000,
118 MP4_INVALID_DURATION, job->width, job->height,
119 job->config.h264.sps[1], /* AVCProfileIndication */
120 job->config.h264.sps[2], /* profile_compat */
121 job->config.h264.sps[3], /* AVCLevelIndication */
122 3 ); /* 4 bytes length before each NAL unit */
123 if ( mux_data->track == MP4_INVALID_TRACK_ID )
125 hb_error( "muxmp4.c: MP4AddH264VideoTrack failed!" );
130 /* Tune track chunk duration */
131 if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
136 MP4AddH264SequenceParameterSet( m->file, mux_data->track,
137 job->config.h264.sps, job->config.h264.sps_length );
138 MP4AddH264PictureParameterSet( m->file, mux_data->track,
139 job->config.h264.pps, job->config.h264.pps_length );
141 if( job->h264_level == 30 || job->ipod_atom)
143 hb_deep_log( 2, "muxmp4: adding iPod atom");
144 MP4AddIPodUUID(m->file, mux_data->track);
147 m->init_delay = job->config.h264.init_delay;
149 else /* FFmpeg or XviD */
151 MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 );
152 mux_data->track = MP4AddVideoTrack( m->file, 90000,
153 MP4_INVALID_DURATION, job->width, job->height,
154 MP4_MPEG4_VIDEO_TYPE );
155 if (mux_data->track == MP4_INVALID_TRACK_ID)
157 hb_error("muxmp4.c: MP4AddVideoTrack failed!");
162 /* Tune track chunk duration */
163 if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
168 /* VOL from FFmpeg or XviD */
169 if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
170 job->config.mpeg4.bytes, job->config.mpeg4.length )))
172 hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
178 // COLR atom for color and gamma correction.
180 // http://developer.apple.com/quicktime/icefloe/dispatch019.html#colr
181 // http://forum.doom9.org/showthread.php?t=133982#post1090068
182 // the user can set it from job->color_matrix, otherwise by default
183 // we say anything that's likely to be HD content is ITU BT.709 and
184 // DVD, SD TV & other content is ITU BT.601. We look at the title height
185 // rather than the job height here to get uncropped input dimensions.
186 if( job->color_matrix == 1 )
188 // ITU BT.601 DVD or SD TV content
189 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
191 else if( job->color_matrix == 2 )
193 // ITU BT.709 HD content
194 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
196 else if ( job->title->width >= 1280 || job->title->height >= 720 )
198 // we guess that 720p or above is ITU BT.709 HD content
199 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
203 // ITU BT.601 DVD or SD TV content
204 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
207 if( job->anamorphic.mode )
209 /* PASP atom for anamorphic video */
212 width = job->anamorphic.par_width;
214 height = job->anamorphic.par_height;
216 MP4AddPixelAspectRatio(m->file, mux_data->track, (uint32_t)width, (uint32_t)height);
218 MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height));
221 /* add the audio tracks */
222 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
224 audio = hb_list_item( title->list_audio, i );
225 mux_data = calloc(1, sizeof( hb_mux_data_t ) );
226 audio->priv.mux_data = mux_data;
228 if( audio->config.out.codec == HB_ACODEC_AC3 )
231 uint8_t bsid = audio->config.in.version;
232 uint8_t bsmod = audio->config.in.mode;
233 uint8_t acmod = audio->config.flags.ac3 & 0x7;
234 uint8_t lfeon = (audio->config.flags.ac3 & A52_LFE) ? 1 : 0;
235 uint8_t bit_rate_code = 0;
238 * Rewrite AC3 information into correct format for dac3 atom
240 switch( audio->config.in.samplerate )
253 * Error value, tells decoder to not decode this audio.
259 switch( audio->config.in.bitrate )
319 hb_error("Unknown AC3 bitrate");
324 mux_data->track = MP4AddAC3AudioTrack(
326 audio->config.out.samplerate,
334 /* Tune track chunk duration */
335 MP4TuneTrackDurationPerChunk( m, mux_data->track );
337 if (audio->config.out.name == NULL) {
338 MP4SetTrackBytesProperty(
339 m->file, mux_data->track,
341 (const uint8_t*)"Surround", strlen("Surround"));
344 MP4SetTrackBytesProperty(
345 m->file, mux_data->track,
347 (const uint8_t*)(audio->config.out.name),
348 strlen(audio->config.out.name));
351 mux_data->track = MP4AddAudioTrack(
353 audio->config.out.samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
355 /* Tune track chunk duration */
356 MP4TuneTrackDurationPerChunk( m, mux_data->track );
358 if (audio->config.out.name == NULL) {
359 MP4SetTrackBytesProperty(
360 m->file, mux_data->track,
362 (const uint8_t*)"Stereo", strlen("Stereo"));
365 MP4SetTrackBytesProperty(
366 m->file, mux_data->track,
368 (const uint8_t*)(audio->config.out.name),
369 strlen(audio->config.out.name));
372 MP4SetAudioProfileLevel( m->file, 0x0F );
373 MP4SetTrackESConfiguration(
374 m->file, mux_data->track,
375 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
377 /* Set the correct number of channels for this track */
378 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown));
381 /* Set the language for this track */
382 MP4SetTrackLanguage(m->file, mux_data->track, audio->config.lang.iso639_2);
384 if( hb_list_count( title->list_audio ) > 1 )
386 /* Set the audio track alternate group */
387 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
391 /* Enable the first audio track */
392 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
395 /* Disable the other audio tracks so QuickTime doesn't play
398 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
399 hb_deep_log( 2, "muxmp4: disabled extra audio track %u", MP4FindTrackIndex( m->file, mux_data->track ));
404 for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
406 hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i );
408 if( subtitle && subtitle->format == TEXTSUB &&
409 subtitle->dest == PASSTHRUSUB )
411 mux_data = calloc(1, sizeof( hb_mux_data_t ) );
412 subtitle->mux_data = mux_data;
413 mux_data->subtitle = 1;
414 mux_data->sub_format = subtitle->format;
415 // TODO: add subtitle track
416 // mux_data->track = MP4AddSubtitleTrack(....);
420 if (job->chapter_markers)
422 /* add a text track for the chapters. We add the 'chap' atom to track
423 one which is usually the video track & should never be disabled.
424 The Quicktime spec says it doesn't matter which media track the
425 chap atom is on but it has to be an enabled track. */
426 MP4TrackId textTrack;
427 textTrack = MP4AddChapterTextTrack(m->file, 1, 0);
429 m->chapter_track = textTrack;
430 m->chapter_duration = 0;
431 m->current_chapter = job->chapter_start;
434 /* Add encoded-by metadata listing version and build date */
436 tool_string = (char *)malloc(80);
437 snprintf( tool_string, 80, "HandBrake %s %i", HB_PROJECT_VERSION, HB_PROJECT_BUILD);
439 /* allocate,fetch,populate,store,free tags structure */
441 tags = MP4TagsAlloc();
442 MP4TagsFetch( tags, m->file );
443 MP4TagsSetEncodingTool( tags, tool_string );
444 MP4TagsStore( tags, m->file );
452 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
455 hb_job_t * job = m->job;
459 if( mux_data == job->mux_data )
463 // if there are b-frames compute the render offset
464 // (we'll need it for both the video frame & the chapter track)
467 offset = buf->start + m->init_delay - m->sum_dur;
470 hb_log("MP4Mux: illegal render offset %lld, start %lld,"
471 "stop %lld, sum_dur %lld",
472 offset, buf->start, buf->stop, m->sum_dur );
477 /* Add the sample before the new frame.
478 It is important that this be calculated prior to the duration
479 of the new video sample, as we want to sync to right after it.
480 (This is because of how durations for text tracks work in QT) */
481 if( job->chapter_markers && buf->new_chap )
483 hb_chapter_t *chapter = NULL;
485 // this chapter is postioned by writing out the previous chapter.
486 // the duration of the previous chapter is the duration up to but
487 // not including the current frame minus the duration of all
488 // chapters up to the previous.
489 // The initial and final chapters can be very short (a second or
490 // less) since they're not really chapters but just a placeholder to
491 // insert a cell command. We don't write chapters shorter than 1.5 sec.
492 duration = m->sum_dur - m->chapter_duration + offset;
493 if ( duration >= (90000*3)/2 )
495 chapter = hb_list_item( m->job->title->list_chapter,
498 MP4AddChapter( m->file,
501 (chapter != NULL) ? chapter->title : NULL);
503 m->current_chapter = buf->new_chap;
504 m->chapter_duration += duration;
508 // We're getting the frames in decode order but the timestamps are
509 // for presentation so we have to use durations and effectively
511 duration = buf->stop - buf->start;
514 /* We got an illegal mp4/h264 duration. This shouldn't
515 be possible and usually indicates a bug in the upstream code.
516 Complain in the hope that someone will go find the bug but
517 try to fix the error so that the file will still be playable. */
518 hb_log("MP4Mux: illegal duration %lld, start %lld,"
519 "stop %lld, sum_dur %lld",
520 duration, buf->start, buf->stop, m->sum_dur );
521 /* we don't know when the next frame starts so we can't pick a
522 valid duration for this one. we pick something "short"
523 (roughly 1/3 of an NTSC frame time) to take time from
527 m->sum_dur += duration;
532 duration = MP4_INVALID_DURATION;
535 /* Here's where the sample actually gets muxed. */
536 if( job->vcodec == HB_VCODEC_X264 && mux_data == job->mux_data )
538 /* Compute dependency flags.
540 * This mechanism is (optionally) used by media players such as QuickTime
541 * to offer better scrubbing performance. The most influential bits are
542 * MP4_SDT_HAS_NO_DEPENDENTS and MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED.
544 * Other bits are possible but no example media using such bits have been
547 * It is acceptable to supply 0-bits for any samples which characteristics
548 * cannot be positively guaranteed.
553 /* encoding layer signals if frame is referenced by other frames */
554 if( buf->flags & HB_FRAME_REF )
555 dflags |= MP4_SDT_HAS_DEPENDENTS;
557 dflags |= MP4_SDT_HAS_NO_DEPENDENTS; /* disposable */
559 switch( buf->frametype )
565 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
568 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
573 break; /* nothing to mark */
576 if( !MP4WriteSampleDependency( m->file,
585 hb_error("Failed to write to output file, disk full?");
589 else if (mux_data->subtitle)
591 if( mux_data->sub_format == TEXTSUB )
593 hb_log("MuxMP4: Text Sub:%lld: %s", buf->start, buf->data);
598 if( !MP4WriteSample( m->file,
604 ( buf->frametype & HB_FRAME_KEY ) != 0 ))
606 hb_error("Failed to write to output file, disk full?");
615 static int MP4End( hb_mux_object_t * m )
617 hb_job_t * job = m->job;
618 hb_title_t * title = job->title;
620 /* Write our final chapter marker */
621 if( m->job->chapter_markers )
623 hb_chapter_t *chapter = NULL;
624 int64_t duration = m->sum_dur - m->chapter_duration;
625 /* The final chapter can have a very short duration - if it's less
626 * than 1.5 seconds just skip it. */
627 if ( duration >= (90000*3)/2 )
630 chapter = hb_list_item( m->job->title->list_chapter,
631 m->current_chapter - 1 );
633 MP4AddChapter( m->file,
636 (chapter != NULL) ? chapter->title : NULL);
642 // Insert track edit to get A/V back in sync. The edit amount is
644 int64_t edit_amt = m->init_delay;
645 MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt,
646 MP4GetTrackDuration(m->file, 1), 0);
647 if ( m->job->chapter_markers )
649 // apply same edit to chapter track to keep it in sync with video
650 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
652 MP4GetTrackDuration(m->file, m->chapter_track), 0);
657 * Write the MP4 iTunes metadata if we have any metadata
659 if( title->metadata )
661 hb_metadata_t *md = title->metadata;
664 hb_deep_log( 2, "Writing Metadata to output file...");
666 /* allocate tags structure */
667 tags = MP4TagsAlloc();
668 /* fetch data from MP4 file (in case it already has some data) */
669 MP4TagsFetch( tags, m->file );
672 MP4TagsSetName( tags, md->name );
673 MP4TagsSetArtist( tags, md->artist );
674 MP4TagsSetComposer( tags, md->composer );
675 MP4TagsSetComments( tags, md->comment );
676 MP4TagsSetReleaseDate( tags, md->release_date );
677 MP4TagsSetAlbum( tags, md->album );
678 MP4TagsSetGenre( tags, md->genre );
683 art.data = md->coverart;
684 art.size = md->coverart_size;
685 art.type = MP4_ART_UNDEFINED; // delegate typing to libmp4v2
686 MP4TagsAddArtwork( tags, &art );
689 /* push data to MP4 file */
690 MP4TagsStore( tags, m->file );
691 /* free memory associated with structure */
697 if ( job->mp4_optimize )
699 hb_log( "muxmp4: optimizing file" );
700 char filename[1024]; memset( filename, 0, 1024 );
701 snprintf( filename, 1024, "%s.tmp", job->file );
702 MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
704 rename( filename, job->file );
710 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
712 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );