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 uint64_t sum_sub_duration; // sum of subtitle frame durations so far
28 /* Chapter state information for muxing */
29 MP4TrackId chapter_track;
31 uint64_t chapter_duration;
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 %llu", 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;
81 /* Flags for enabling/disabling tracks in an MP4. */
82 typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8} track_header_flags;
84 /* Create an empty mp4 file */
85 if (job->largeFileSize)
86 /* Use 64-bit MP4 file */
88 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, MP4_CREATE_64BIT_DATA );
89 hb_deep_log( 2, "muxmp4: using 64-bit MP4 formatting.");
92 /* Limit MP4s to less than 4 GB */
94 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
97 if (m->file == MP4_INVALID_FILE_HANDLE)
99 hb_error("muxmp4.c: MP4Create failed!");
105 mux_data = calloc(1, sizeof( hb_mux_data_t ) );
106 job->mux_data = mux_data;
108 if (!(MP4SetTimeScale( m->file, 90000 )))
110 hb_error("muxmp4.c: MP4SetTimeScale failed!");
115 if( job->vcodec == HB_VCODEC_X264 )
117 /* Stolen from mp4creator */
118 MP4SetVideoProfileLevel( m->file, 0x7F );
119 mux_data->track = MP4AddH264VideoTrack( m->file, 90000,
120 MP4_INVALID_DURATION, job->width, job->height,
121 job->config.h264.sps[1], /* AVCProfileIndication */
122 job->config.h264.sps[2], /* profile_compat */
123 job->config.h264.sps[3], /* AVCLevelIndication */
124 3 ); /* 4 bytes length before each NAL unit */
125 if ( mux_data->track == MP4_INVALID_TRACK_ID )
127 hb_error( "muxmp4.c: MP4AddH264VideoTrack failed!" );
132 /* Tune track chunk duration */
133 if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
138 MP4AddH264SequenceParameterSet( m->file, mux_data->track,
139 job->config.h264.sps, job->config.h264.sps_length );
140 MP4AddH264PictureParameterSet( m->file, mux_data->track,
141 job->config.h264.pps, job->config.h264.pps_length );
143 if( job->h264_level == 30 || job->ipod_atom)
145 hb_deep_log( 2, "muxmp4: adding iPod atom");
146 MP4AddIPodUUID(m->file, mux_data->track);
149 m->init_delay = job->config.h264.init_delay;
151 else /* FFmpeg or XviD */
153 MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 );
154 mux_data->track = MP4AddVideoTrack( m->file, 90000,
155 MP4_INVALID_DURATION, job->width, job->height,
156 MP4_MPEG4_VIDEO_TYPE );
157 if (mux_data->track == MP4_INVALID_TRACK_ID)
159 hb_error("muxmp4.c: MP4AddVideoTrack failed!");
164 /* Tune track chunk duration */
165 if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
170 /* VOL from FFmpeg or XviD */
171 if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
172 job->config.mpeg4.bytes, job->config.mpeg4.length )))
174 hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
180 // COLR atom for color and gamma correction.
182 // http://developer.apple.com/quicktime/icefloe/dispatch019.html#colr
183 // http://forum.doom9.org/showthread.php?t=133982#post1090068
184 // the user can set it from job->color_matrix, otherwise by default
185 // we say anything that's likely to be HD content is ITU BT.709 and
186 // DVD, SD TV & other content is ITU BT.601. We look at the title height
187 // rather than the job height here to get uncropped input dimensions.
188 if( job->color_matrix == 1 )
190 // ITU BT.601 DVD or SD TV content
191 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
193 else if( job->color_matrix == 2 )
195 // ITU BT.709 HD content
196 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
198 else if ( job->title->width >= 1280 || job->title->height >= 720 )
200 // we guess that 720p or above is ITU BT.709 HD content
201 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
205 // ITU BT.601 DVD or SD TV content
206 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
209 if( job->anamorphic.mode )
211 /* PASP atom for anamorphic video */
214 width = job->anamorphic.par_width;
216 height = job->anamorphic.par_height;
218 MP4AddPixelAspectRatio(m->file, mux_data->track, (uint32_t)width, (uint32_t)height);
220 MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height));
223 /* add the audio tracks */
224 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
226 audio = hb_list_item( title->list_audio, i );
227 mux_data = calloc(1, sizeof( hb_mux_data_t ) );
228 audio->priv.mux_data = mux_data;
230 if( audio->config.out.codec == HB_ACODEC_AC3 )
233 uint8_t bsid = audio->config.in.version;
234 uint8_t bsmod = audio->config.in.mode;
235 uint8_t acmod = audio->config.flags.ac3 & 0x7;
236 uint8_t lfeon = (audio->config.flags.ac3 & A52_LFE) ? 1 : 0;
237 uint8_t bit_rate_code = 0;
240 * Rewrite AC3 information into correct format for dac3 atom
242 switch( audio->config.in.samplerate )
255 * Error value, tells decoder to not decode this audio.
261 switch( audio->config.in.bitrate )
321 hb_error("Unknown AC3 bitrate");
326 mux_data->track = MP4AddAC3AudioTrack(
328 audio->config.out.samplerate,
336 /* Tune track chunk duration */
337 MP4TuneTrackDurationPerChunk( m, mux_data->track );
339 if (audio->config.out.name == NULL) {
340 MP4SetTrackBytesProperty(
341 m->file, mux_data->track,
343 (const uint8_t*)"Surround", strlen("Surround"));
346 MP4SetTrackBytesProperty(
347 m->file, mux_data->track,
349 (const uint8_t*)(audio->config.out.name),
350 strlen(audio->config.out.name));
353 mux_data->track = MP4AddAudioTrack(
355 audio->config.out.samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
357 /* Tune track chunk duration */
358 MP4TuneTrackDurationPerChunk( m, mux_data->track );
360 if (audio->config.out.name == NULL) {
361 MP4SetTrackBytesProperty(
362 m->file, mux_data->track,
364 (const uint8_t*)"Stereo", strlen("Stereo"));
367 MP4SetTrackBytesProperty(
368 m->file, mux_data->track,
370 (const uint8_t*)(audio->config.out.name),
371 strlen(audio->config.out.name));
374 MP4SetAudioProfileLevel( m->file, 0x0F );
375 MP4SetTrackESConfiguration(
376 m->file, mux_data->track,
377 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
379 /* Set the correct number of channels for this track */
380 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown));
383 /* Set the language for this track */
384 MP4SetTrackLanguage(m->file, mux_data->track, audio->config.lang.iso639_2);
386 if( hb_list_count( title->list_audio ) > 1 )
388 /* Set the audio track alternate group */
389 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
393 /* Enable the first audio track */
394 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
397 /* Disable the other audio tracks so QuickTime doesn't play
400 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
401 hb_deep_log( 2, "muxmp4: disabled extra audio track %u", MP4FindTrackIndex( m->file, mux_data->track ));
406 for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
408 hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i );
410 if( subtitle && subtitle->format == TEXTSUB &&
411 subtitle->dest == PASSTHRUSUB )
413 mux_data = calloc(1, sizeof( hb_mux_data_t ) );
414 subtitle->mux_data = mux_data;
415 mux_data->subtitle = 1;
416 mux_data->sub_format = subtitle->format;
417 mux_data->track = MP4AddSubtitleTrack( m->file, 1 );
419 MP4SetTrackLanguage(m->file, mux_data->track, subtitle->iso639_2);
421 /* Tune track chunk duration */
422 MP4TuneTrackDurationPerChunk( m, mux_data->track );
424 const uint8_t textColor[4] = { 255,255,255,255 };
425 uint64_t subHeight = 60;
427 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 2);
429 MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width);
430 MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.height", subHeight);
432 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.dataReferenceIndex", 1);
433 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.horizontalJustification", 1);
434 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.verticalJustification", 0);
436 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.bgColorAlpha", 255);
438 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.defTextBoxBottom", subHeight);
439 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.defTextBoxRight", job->width);
441 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontID", 1);
442 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontSize", 24);
444 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorRed", textColor[0]);
445 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorGreen", textColor[1]);
446 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorBlue", textColor[2]);
447 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorAlpha", textColor[3]);
449 /* translate the track */
452 uint32_t *ptr32 = (uint32_t*) nval;
455 MP4GetTrackBytesProperty(m->file, mux_data->track, "tkhd.matrix", &val, &size);
456 memcpy(nval, val, size);
458 const uint32_t ytranslation = (job->height - subHeight) * 0x10000;
460 #ifdef WORDS_BIGENDIAN
461 ptr32[7] = ytranslation;
463 /* we need to switch the endianness, as the file format expects big endian */
464 ptr32[7] = ((ytranslation & 0x000000FF) << 24) + ((ytranslation & 0x0000FF00) << 8) +
465 ((ytranslation & 0x00FF0000) >> 8) + ((ytranslation & 0xFF000000) >> 24);
468 MP4SetTrackBytesProperty(m->file, mux_data->track, "tkhd.matrix", nval, size);
472 if (job->chapter_markers)
474 /* add a text track for the chapters. We add the 'chap' atom to track
475 one which is usually the video track & should never be disabled.
476 The Quicktime spec says it doesn't matter which media track the
477 chap atom is on but it has to be an enabled track. */
478 MP4TrackId textTrack;
479 textTrack = MP4AddChapterTextTrack(m->file, 1, 0);
481 m->chapter_track = textTrack;
482 m->chapter_duration = 0;
483 m->current_chapter = job->chapter_start;
486 /* Add encoded-by metadata listing version and build date */
488 tool_string = (char *)malloc(80);
489 snprintf( tool_string, 80, "HandBrake %s %i", HB_PROJECT_VERSION, HB_PROJECT_BUILD);
491 /* allocate,fetch,populate,store,free tags structure */
493 tags = MP4TagsAlloc();
494 MP4TagsFetch( tags, m->file );
495 MP4TagsSetEncodingTool( tags, tool_string );
496 MP4TagsStore( tags, m->file );
504 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
507 hb_job_t * job = m->job;
511 if( mux_data == job->mux_data )
515 // if there are b-frames compute the render offset
516 // (we'll need it for both the video frame & the chapter track)
519 offset = buf->start + m->init_delay - m->sum_dur;
522 hb_log("MP4Mux: illegal render offset %lld, start %lld,"
523 "stop %lld, sum_dur %lld",
524 offset, buf->start, buf->stop, m->sum_dur );
529 /* Add the sample before the new frame.
530 It is important that this be calculated prior to the duration
531 of the new video sample, as we want to sync to right after it.
532 (This is because of how durations for text tracks work in QT) */
533 if( job->chapter_markers && buf->new_chap )
535 hb_chapter_t *chapter = NULL;
537 // this chapter is postioned by writing out the previous chapter.
538 // the duration of the previous chapter is the duration up to but
539 // not including the current frame minus the duration of all
540 // chapters up to the previous.
541 // The initial and final chapters can be very short (a second or
542 // less) since they're not really chapters but just a placeholder to
543 // insert a cell command. We don't write chapters shorter than 1.5 sec.
544 duration = m->sum_dur - m->chapter_duration + offset;
545 if ( duration >= (90000*3)/2 )
547 chapter = hb_list_item( m->job->title->list_chapter,
550 MP4AddChapter( m->file,
553 (chapter != NULL) ? chapter->title : NULL);
555 m->current_chapter = buf->new_chap;
556 m->chapter_duration += duration;
560 // We're getting the frames in decode order but the timestamps are
561 // for presentation so we have to use durations and effectively
563 duration = buf->stop - buf->start;
566 /* We got an illegal mp4/h264 duration. This shouldn't
567 be possible and usually indicates a bug in the upstream code.
568 Complain in the hope that someone will go find the bug but
569 try to fix the error so that the file will still be playable. */
570 hb_log("MP4Mux: illegal duration %lld, start %lld,"
571 "stop %lld, sum_dur %lld",
572 duration, buf->start, buf->stop, m->sum_dur );
573 /* we don't know when the next frame starts so we can't pick a
574 valid duration for this one. we pick something "short"
575 (roughly 1/3 of an NTSC frame time) to take time from
579 m->sum_dur += duration;
584 duration = MP4_INVALID_DURATION;
587 /* Here's where the sample actually gets muxed. */
588 if( job->vcodec == HB_VCODEC_X264 && mux_data == job->mux_data )
590 /* Compute dependency flags.
592 * This mechanism is (optionally) used by media players such as QuickTime
593 * to offer better scrubbing performance. The most influential bits are
594 * MP4_SDT_HAS_NO_DEPENDENTS and MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED.
596 * Other bits are possible but no example media using such bits have been
599 * It is acceptable to supply 0-bits for any samples which characteristics
600 * cannot be positively guaranteed.
605 /* encoding layer signals if frame is referenced by other frames */
606 if( buf->flags & HB_FRAME_REF )
607 dflags |= MP4_SDT_HAS_DEPENDENTS;
609 dflags |= MP4_SDT_HAS_NO_DEPENDENTS; /* disposable */
611 switch( buf->frametype )
617 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
620 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
625 break; /* nothing to mark */
628 if( !MP4WriteSampleDependency( m->file,
637 hb_error("Failed to write to output file, disk full?");
641 else if (mux_data->subtitle)
643 if( mux_data->sub_format == TEXTSUB )
645 /* Write an empty sample */
646 if ( m->sum_sub_duration < buf->start )
648 uint8_t empty[2] = {0,0};
649 if( !MP4WriteSample( m->file,
653 buf->start - m->sum_sub_duration,
657 hb_error("Failed to write to output file, disk full?");
660 m->sum_sub_duration += buf->start - m->sum_sub_duration;
663 /* Write the subtitle sample */
664 uint8_t buffer[2048];
665 memcpy( buffer + 2, buf->data, buf->size );
666 buffer[0] = ( buf->size >> 8 ) & 0xff;
667 buffer[1] = buf->size & 0xff;
669 if( !MP4WriteSample( m->file,
673 buf->stop - buf->start,
677 hb_error("Failed to write to output file, disk full?");
681 m->sum_sub_duration += (buf->stop - buf->start);
682 hb_deep_log(3, "MuxMP4:Sub:%fs:%lld:%lld:%lld: %s", (float)buf->start / 90000, buf->start, buf->stop,
683 (buf->stop - buf->start), buf->data);
684 hb_deep_log(3, "MuxMP4:Total time elapsed:%lld", m->sum_sub_duration);
692 if( !MP4WriteSample( m->file,
698 ( buf->frametype & HB_FRAME_KEY ) != 0 ))
700 hb_error("Failed to write to output file, disk full?");
709 static int MP4End( hb_mux_object_t * m )
711 hb_job_t * job = m->job;
712 hb_title_t * title = job->title;
714 /* Write our final chapter marker */
715 if( m->job->chapter_markers )
717 hb_chapter_t *chapter = NULL;
718 int64_t duration = m->sum_dur - m->chapter_duration;
719 /* The final chapter can have a very short duration - if it's less
720 * than 1.5 seconds just skip it. */
721 if ( duration >= (90000*3)/2 )
724 chapter = hb_list_item( m->job->title->list_chapter,
725 m->current_chapter - 1 );
727 MP4AddChapter( m->file,
730 (chapter != NULL) ? chapter->title : NULL);
736 // Insert track edit to get A/V back in sync. The edit amount is
738 int64_t edit_amt = m->init_delay;
739 MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt,
740 MP4GetTrackDuration(m->file, 1), 0);
741 if ( m->job->chapter_markers )
743 // apply same edit to chapter track to keep it in sync with video
744 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
746 MP4GetTrackDuration(m->file, m->chapter_track), 0);
751 * Write the MP4 iTunes metadata if we have any metadata
753 if( title->metadata )
755 hb_metadata_t *md = title->metadata;
758 hb_deep_log( 2, "Writing Metadata to output file...");
760 /* allocate tags structure */
761 tags = MP4TagsAlloc();
762 /* fetch data from MP4 file (in case it already has some data) */
763 MP4TagsFetch( tags, m->file );
766 MP4TagsSetName( tags, md->name );
767 MP4TagsSetArtist( tags, md->artist );
768 MP4TagsSetComposer( tags, md->composer );
769 MP4TagsSetComments( tags, md->comment );
770 MP4TagsSetReleaseDate( tags, md->release_date );
771 MP4TagsSetAlbum( tags, md->album );
772 MP4TagsSetGenre( tags, md->genre );
777 art.data = md->coverart;
778 art.size = md->coverart_size;
779 art.type = MP4_ART_UNDEFINED; // delegate typing to libmp4v2
780 MP4TagsAddArtwork( tags, &art );
783 /* push data to MP4 file */
784 MP4TagsStore( tags, m->file );
785 /* free memory associated with structure */
791 if ( job->mp4_optimize )
793 hb_log( "muxmp4: optimizing file" );
794 char filename[1024]; memset( filename, 0, 1024 );
795 snprintf( filename, 1024, "%s.tmp", job->file );
796 MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
798 rename( filename, job->file );
804 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
806 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );