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;
38 uint64_t sum_dur; // sum of the frame durations so far
41 /* Tune video track chunk duration.
42 * libmp4v2 default duration == dusamplerate == 1 second.
43 * Per van's suggestion we desire duration == 4 frames.
44 * Should be invoked immediately after track creation.
46 * return true on fail, false on success.
48 static int MP4TuneTrackDurationPerChunk( hb_mux_object_t* m, MP4TrackId trackId )
53 tscale = MP4GetTrackTimeScale( m->file, trackId );
54 dur = (MP4Duration)ceil( (double)tscale * (double)m->job->vrate_base / (double)m->job->vrate * 4.0 );
56 if( !MP4SetTrackDurationPerChunk( m->file, trackId, dur ))
58 hb_error( "muxmp4.c: MP4SetTrackDurationPerChunk failed!" );
63 hb_deep_log( 2, "muxmp4: track %u, chunk duration %"PRIu64, MP4FindTrackIndex( m->file, trackId ), dur );
67 /**********************************************************************
69 **********************************************************************
70 * Allocates hb_mux_data_t structures, create file and write headers
71 *********************************************************************/
72 static int MP4Init( hb_mux_object_t * m )
74 hb_job_t * job = m->job;
75 hb_title_t * title = job->title;
78 hb_mux_data_t * mux_data;
82 /* Flags for enabling/disabling tracks in an MP4. */
83 typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8} track_header_flags;
85 /* Create an empty mp4 file */
86 if (job->largeFileSize)
87 /* Use 64-bit MP4 file */
89 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, MP4_CREATE_64BIT_DATA );
90 hb_deep_log( 2, "muxmp4: using 64-bit MP4 formatting.");
93 /* Limit MP4s to less than 4 GB */
95 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
98 if (m->file == MP4_INVALID_FILE_HANDLE)
100 hb_error("muxmp4.c: MP4Create failed!");
106 mux_data = calloc(1, sizeof( hb_mux_data_t ) );
107 job->mux_data = mux_data;
109 if (!(MP4SetTimeScale( m->file, 90000 )))
111 hb_error("muxmp4.c: MP4SetTimeScale failed!");
116 if( job->vcodec == HB_VCODEC_X264 )
118 /* Stolen from mp4creator */
119 MP4SetVideoProfileLevel( m->file, 0x7F );
120 mux_data->track = MP4AddH264VideoTrack( m->file, 90000,
121 MP4_INVALID_DURATION, job->width, job->height,
122 job->config.h264.sps[1], /* AVCProfileIndication */
123 job->config.h264.sps[2], /* profile_compat */
124 job->config.h264.sps[3], /* AVCLevelIndication */
125 3 ); /* 4 bytes length before each NAL unit */
126 if ( mux_data->track == MP4_INVALID_TRACK_ID )
128 hb_error( "muxmp4.c: MP4AddH264VideoTrack failed!" );
133 /* Tune track chunk duration */
134 if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
139 MP4AddH264SequenceParameterSet( m->file, mux_data->track,
140 job->config.h264.sps, job->config.h264.sps_length );
141 MP4AddH264PictureParameterSet( m->file, mux_data->track,
142 job->config.h264.pps, job->config.h264.pps_length );
144 if( job->h264_level == 30 || job->ipod_atom)
146 hb_deep_log( 2, "muxmp4: adding iPod atom");
147 MP4AddIPodUUID(m->file, mux_data->track);
150 m->init_delay = job->config.h264.init_delay;
152 else /* FFmpeg or XviD */
154 MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 );
155 mux_data->track = MP4AddVideoTrack( m->file, 90000,
156 MP4_INVALID_DURATION, job->width, job->height,
157 MP4_MPEG4_VIDEO_TYPE );
158 if (mux_data->track == MP4_INVALID_TRACK_ID)
160 hb_error("muxmp4.c: MP4AddVideoTrack failed!");
165 /* Tune track chunk duration */
166 if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
171 /* VOL from FFmpeg or XviD */
172 if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
173 job->config.mpeg4.bytes, job->config.mpeg4.length )))
175 hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
181 // COLR atom for color and gamma correction.
183 // http://developer.apple.com/quicktime/icefloe/dispatch019.html#colr
184 // http://forum.doom9.org/showthread.php?t=133982#post1090068
185 // the user can set it from job->color_matrix, otherwise by default
186 // we say anything that's likely to be HD content is ITU BT.709 and
187 // DVD, SD TV & other content is ITU BT.601. We look at the title height
188 // rather than the job height here to get uncropped input dimensions.
189 if( job->color_matrix == 1 )
191 // ITU BT.601 DVD or SD TV content
192 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
194 else if( job->color_matrix == 2 )
196 // ITU BT.709 HD content
197 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
199 else if ( job->title->width >= 1280 || job->title->height >= 720 )
201 // we guess that 720p or above is ITU BT.709 HD content
202 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
206 // ITU BT.601 DVD or SD TV content
207 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
210 if( job->anamorphic.mode )
212 /* PASP atom for anamorphic video */
215 width = job->anamorphic.par_width;
217 height = job->anamorphic.par_height;
219 MP4AddPixelAspectRatio(m->file, mux_data->track, (uint32_t)width, (uint32_t)height);
221 MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height));
224 /* add the audio tracks */
225 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
227 audio = hb_list_item( title->list_audio, i );
228 mux_data = calloc(1, sizeof( hb_mux_data_t ) );
229 audio->priv.mux_data = mux_data;
231 if( audio->config.out.codec == HB_ACODEC_AC3 )
234 uint8_t bsid = audio->config.in.version;
235 uint8_t bsmod = audio->config.in.mode;
236 uint8_t acmod = audio->config.flags.ac3 & 0x7;
237 uint8_t lfeon = (audio->config.flags.ac3 & A52_LFE) ? 1 : 0;
238 uint8_t bit_rate_code = 0;
241 * Rewrite AC3 information into correct format for dac3 atom
243 switch( audio->config.in.samplerate )
256 * Error value, tells decoder to not decode this audio.
262 switch( audio->config.in.bitrate )
322 hb_error("Unknown AC3 bitrate");
327 mux_data->track = MP4AddAC3AudioTrack(
329 audio->config.out.samplerate,
337 /* Tune track chunk duration */
338 MP4TuneTrackDurationPerChunk( m, mux_data->track );
340 if (audio->config.out.name == NULL) {
341 MP4SetTrackBytesProperty(
342 m->file, mux_data->track,
344 (const uint8_t*)"Surround", strlen("Surround"));
347 MP4SetTrackBytesProperty(
348 m->file, mux_data->track,
350 (const uint8_t*)(audio->config.out.name),
351 strlen(audio->config.out.name));
354 mux_data->track = MP4AddAudioTrack(
356 audio->config.out.samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
358 /* Tune track chunk duration */
359 MP4TuneTrackDurationPerChunk( m, mux_data->track );
361 if (audio->config.out.name == NULL) {
362 MP4SetTrackBytesProperty(
363 m->file, mux_data->track,
365 (const uint8_t*)"Stereo", strlen("Stereo"));
368 MP4SetTrackBytesProperty(
369 m->file, mux_data->track,
371 (const uint8_t*)(audio->config.out.name),
372 strlen(audio->config.out.name));
375 MP4SetAudioProfileLevel( m->file, 0x0F );
376 MP4SetTrackESConfiguration(
377 m->file, mux_data->track,
378 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
380 /* Set the correct number of channels for this track */
381 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown));
384 /* Set the language for this track */
385 MP4SetTrackLanguage(m->file, mux_data->track, audio->config.lang.iso639_2);
387 if( hb_list_count( title->list_audio ) > 1 )
389 /* Set the audio track alternate group */
390 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
394 /* Enable the first audio track */
395 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
398 /* Disable the other audio tracks so QuickTime doesn't play
401 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
402 hb_deep_log( 2, "muxmp4: disabled extra audio track %u", MP4FindTrackIndex( m->file, mux_data->track ));
407 // Quicktime requires that at least one subtitle is enabled,
408 // else it doesn't show any of the subtitles.
409 // So check to see if any of the subtitles are flagged to be
410 // the defualt. The default will the the enabled track, else
411 // enable the first track.
412 subtitle_default = 0;
413 for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
415 hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i );
417 if( subtitle && subtitle->format == TEXTSUB &&
418 subtitle->config.dest == PASSTHRUSUB )
420 if ( subtitle->config.default_track )
421 subtitle_default = 1;
424 for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
426 hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i );
428 if( subtitle && subtitle->format == TEXTSUB &&
429 subtitle->config.dest == PASSTHRUSUB )
431 uint64_t width, height = 60;
432 if( job->anamorphic.mode )
433 width = job->width * ( (float) job->anamorphic.par_width / job->anamorphic.par_height );
437 mux_data = calloc(1, sizeof( hb_mux_data_t ) );
438 subtitle->mux_data = mux_data;
439 mux_data->subtitle = 1;
440 mux_data->sub_format = subtitle->format;
441 mux_data->track = MP4AddSubtitleTrack( m->file, 90000, width, height );
443 MP4SetTrackLanguage(m->file, mux_data->track, subtitle->iso639_2);
445 /* Tune track chunk duration */
446 MP4TuneTrackDurationPerChunk( m, mux_data->track );
448 const uint8_t textColor[4] = { 255,255,255,255 };
450 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 2);
452 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.dataReferenceIndex", 1);
453 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.horizontalJustification", 1);
454 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.verticalJustification", 0);
456 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.bgColorAlpha", 255);
458 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.defTextBoxBottom", height);
459 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.defTextBoxRight", width);
461 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontID", 1);
462 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontSize", 24);
464 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorRed", textColor[0]);
465 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorGreen", textColor[1]);
466 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorBlue", textColor[2]);
467 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorAlpha", textColor[3]);
469 /* translate the track */
472 uint32_t *ptr32 = (uint32_t*) nval;
475 MP4GetTrackBytesProperty(m->file, mux_data->track, "tkhd.matrix", &val, &size);
476 memcpy(nval, val, size);
478 const uint32_t ytranslation = (job->height - height) * 0x10000;
480 #ifdef WORDS_BIGENDIAN
481 ptr32[7] = ytranslation;
483 /* we need to switch the endianness, as the file format expects big endian */
484 ptr32[7] = ((ytranslation & 0x000000FF) << 24) + ((ytranslation & 0x0000FF00) << 8) +
485 ((ytranslation & 0x00FF0000) >> 8) + ((ytranslation & 0xFF000000) >> 24);
488 MP4SetTrackBytesProperty(m->file, mux_data->track, "tkhd.matrix", nval, size);
489 if ( !subtitle_default || subtitle->config.default_track ) {
490 /* Enable the default subtitle track */
491 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
492 subtitle_default = 1;
496 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
501 if (job->chapter_markers)
503 /* add a text track for the chapters. We add the 'chap' atom to track
504 one which is usually the video track & should never be disabled.
505 The Quicktime spec says it doesn't matter which media track the
506 chap atom is on but it has to be an enabled track. */
507 MP4TrackId textTrack;
508 textTrack = MP4AddChapterTextTrack(m->file, 1, 0);
510 m->chapter_track = textTrack;
511 m->chapter_duration = 0;
512 m->current_chapter = job->chapter_start;
515 /* Add encoded-by metadata listing version and build date */
517 tool_string = (char *)malloc(80);
518 snprintf( tool_string, 80, "HandBrake %s %i", HB_PROJECT_VERSION, HB_PROJECT_BUILD);
520 /* allocate,fetch,populate,store,free tags structure */
522 tags = MP4TagsAlloc();
523 MP4TagsFetch( tags, m->file );
524 MP4TagsSetEncodingTool( tags, tool_string );
525 MP4TagsStore( tags, m->file );
533 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
536 hb_job_t * job = m->job;
540 if( mux_data == job->mux_data )
544 // if there are b-frames compute the render offset
545 // (we'll need it for both the video frame & the chapter track)
548 offset = buf->start + m->init_delay - m->sum_dur;
551 hb_log("MP4Mux: illegal render offset %"PRId64", start %"PRId64","
552 "stop %"PRId64", sum_dur %"PRId64,
553 offset, buf->start, buf->stop, m->sum_dur );
558 /* Add the sample before the new frame.
559 It is important that this be calculated prior to the duration
560 of the new video sample, as we want to sync to right after it.
561 (This is because of how durations for text tracks work in QT) */
562 if( job->chapter_markers && buf->new_chap )
564 hb_chapter_t *chapter = NULL;
566 // this chapter is postioned by writing out the previous chapter.
567 // the duration of the previous chapter is the duration up to but
568 // not including the current frame minus the duration of all
569 // chapters up to the previous.
570 // The initial and final chapters can be very short (a second or
571 // less) since they're not really chapters but just a placeholder to
572 // insert a cell command. We don't write chapters shorter than 1.5 sec.
573 duration = m->sum_dur - m->chapter_duration + offset;
574 if ( duration >= (90000*3)/2 )
576 chapter = hb_list_item( m->job->title->list_chapter,
579 MP4AddChapter( m->file,
582 (chapter != NULL) ? chapter->title : NULL);
584 m->current_chapter = buf->new_chap;
585 m->chapter_duration += duration;
589 // We're getting the frames in decode order but the timestamps are
590 // for presentation so we have to use durations and effectively
592 duration = buf->stop - buf->start;
595 /* We got an illegal mp4/h264 duration. This shouldn't
596 be possible and usually indicates a bug in the upstream code.
597 Complain in the hope that someone will go find the bug but
598 try to fix the error so that the file will still be playable. */
599 hb_log("MP4Mux: illegal duration %"PRId64", start %"PRId64","
600 "stop %"PRId64", sum_dur %"PRId64,
601 duration, buf->start, buf->stop, m->sum_dur );
602 /* we don't know when the next frame starts so we can't pick a
603 valid duration for this one. we pick something "short"
604 (roughly 1/3 of an NTSC frame time) to take time from
608 m->sum_dur += duration;
613 duration = MP4_INVALID_DURATION;
616 /* Here's where the sample actually gets muxed. */
617 if( job->vcodec == HB_VCODEC_X264 && mux_data == job->mux_data )
619 /* Compute dependency flags.
621 * This mechanism is (optionally) used by media players such as QuickTime
622 * to offer better scrubbing performance. The most influential bits are
623 * MP4_SDT_HAS_NO_DEPENDENTS and MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED.
625 * Other bits are possible but no example media using such bits have been
628 * It is acceptable to supply 0-bits for any samples which characteristics
629 * cannot be positively guaranteed.
634 /* encoding layer signals if frame is referenced by other frames */
635 if( buf->flags & HB_FRAME_REF )
636 dflags |= MP4_SDT_HAS_DEPENDENTS;
638 dflags |= MP4_SDT_HAS_NO_DEPENDENTS; /* disposable */
640 switch( buf->frametype )
646 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
649 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
654 break; /* nothing to mark */
657 if( !MP4WriteSampleDependency( m->file,
666 hb_error("Failed to write to output file, disk full?");
670 else if (mux_data->subtitle)
672 if( mux_data->sub_format == TEXTSUB )
674 /* Write an empty sample */
675 if ( mux_data->sum_dur < buf->start )
677 uint8_t empty[2] = {0,0};
678 if( !MP4WriteSample( m->file,
682 buf->start - mux_data->sum_dur,
686 hb_error("Failed to write to output file, disk full?");
689 mux_data->sum_dur += buf->start - mux_data->sum_dur;
692 /* Write the subtitle sample */
693 uint8_t buffer[2048];
694 memcpy( buffer + 2, buf->data, buf->size );
695 buffer[0] = ( buf->size >> 8 ) & 0xff;
696 buffer[1] = buf->size & 0xff;
698 if( !MP4WriteSample( m->file,
702 buf->stop - buf->start,
706 hb_error("Failed to write to output file, disk full?");
710 mux_data->sum_dur += (buf->stop - buf->start);
711 hb_deep_log(3, "MuxMP4:Sub:%fs:%"PRId64":%"PRId64":%"PRId64": %s", (float)buf->start / 90000, buf->start, buf->stop,
712 (buf->stop - buf->start), buf->data);
713 hb_deep_log(3, "MuxMP4:Total time elapsed:%"PRId64, mux_data->sum_dur);
721 if( !MP4WriteSample( m->file,
727 ( buf->frametype & HB_FRAME_KEY ) != 0 ))
729 hb_error("Failed to write to output file, disk full?");
738 static int MP4End( hb_mux_object_t * m )
740 hb_job_t * job = m->job;
741 hb_title_t * title = job->title;
743 /* Write our final chapter marker */
744 if( m->job->chapter_markers )
746 hb_chapter_t *chapter = NULL;
747 int64_t duration = m->sum_dur - m->chapter_duration;
748 /* The final chapter can have a very short duration - if it's less
749 * than 1.5 seconds just skip it. */
750 if ( duration >= (90000*3)/2 )
753 chapter = hb_list_item( m->job->title->list_chapter,
754 m->current_chapter - 1 );
756 MP4AddChapter( m->file,
759 (chapter != NULL) ? chapter->title : NULL);
765 // Insert track edit to get A/V back in sync. The edit amount is
767 int64_t edit_amt = m->init_delay;
768 MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt,
769 MP4GetTrackDuration(m->file, 1), 0);
770 if ( m->job->chapter_markers )
772 // apply same edit to chapter track to keep it in sync with video
773 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
775 MP4GetTrackDuration(m->file, m->chapter_track), 0);
780 * Write the MP4 iTunes metadata if we have any metadata
782 if( title->metadata )
784 hb_metadata_t *md = title->metadata;
787 hb_deep_log( 2, "Writing Metadata to output file...");
789 /* allocate tags structure */
790 tags = MP4TagsAlloc();
791 /* fetch data from MP4 file (in case it already has some data) */
792 MP4TagsFetch( tags, m->file );
795 if( strlen( md->name ))
796 MP4TagsSetName( tags, md->name );
797 if( strlen( md->artist ))
798 MP4TagsSetArtist( tags, md->artist );
799 if( strlen( md->composer ))
800 MP4TagsSetComposer( tags, md->composer );
801 if( strlen( md->comment ))
802 MP4TagsSetComments( tags, md->comment );
803 if( strlen( md->release_date ))
804 MP4TagsSetReleaseDate( tags, md->release_date );
805 if( strlen( md->album ))
806 MP4TagsSetAlbum( tags, md->album );
807 if( strlen( md->genre ))
808 MP4TagsSetGenre( tags, md->genre );
813 art.data = md->coverart;
814 art.size = md->coverart_size;
815 art.type = MP4_ART_UNDEFINED; // delegate typing to libmp4v2
816 MP4TagsAddArtwork( tags, &art );
819 /* push data to MP4 file */
820 MP4TagsStore( tags, m->file );
821 /* free memory associated with structure */
827 if ( job->mp4_optimize )
829 hb_log( "muxmp4: optimizing file" );
830 char filename[1024]; memset( filename, 0, 1024 );
831 snprintf( filename, 1024, "%s.tmp", job->file );
832 MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
834 rename( filename, job->file );
840 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
842 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );