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;
37 /* Tune video track chunk duration.
38 * libmp4v2 default duration == dusamplerate == 1 second.
39 * Per van's suggestion we desire duration == 4 frames.
40 * Should be invoked immediately after track creation.
42 * return true on fail, false on success.
44 static int MP4TuneTrackDurationPerChunk( hb_mux_object_t* m, MP4TrackId trackId )
49 tscale = MP4GetTrackTimeScale( m->file, trackId );
50 dur = (MP4Duration)ceil( (double)tscale * (double)m->job->vrate_base / (double)m->job->vrate * 4.0 );
52 if( !MP4SetTrackDurationPerChunk( m->file, trackId, dur ))
54 hb_error( "muxmp4.c: MP4SetTrackDurationPerChunk failed!" );
59 hb_deep_log( 2, "muxmp4: track %u, chunk duration %llu", MP4FindTrackIndex( m->file, trackId ), dur );
63 /**********************************************************************
65 **********************************************************************
66 * Allocates hb_mux_data_t structures, create file and write headers
67 *********************************************************************/
68 static int MP4Init( hb_mux_object_t * m )
70 hb_job_t * job = m->job;
71 hb_title_t * title = job->title;
74 hb_mux_data_t * mux_data;
77 /* Flags for enabling/disabling tracks in an MP4. */
78 typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8} track_header_flags;
80 /* Create an empty mp4 file */
81 if (job->largeFileSize)
82 /* Use 64-bit MP4 file */
84 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, MP4_CREATE_64BIT_DATA );
85 hb_deep_log( 2, "muxmp4: using 64-bit MP4 formatting.");
88 /* Limit MP4s to less than 4 GB */
90 m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
93 if (m->file == MP4_INVALID_FILE_HANDLE)
95 hb_error("muxmp4.c: MP4Create failed!");
101 mux_data = malloc( sizeof( hb_mux_data_t ) );
102 job->mux_data = mux_data;
104 if (!(MP4SetTimeScale( m->file, 90000 )))
106 hb_error("muxmp4.c: MP4SetTimeScale failed!");
111 if( job->vcodec == HB_VCODEC_X264 )
113 /* Stolen from mp4creator */
114 MP4SetVideoProfileLevel( m->file, 0x7F );
115 mux_data->track = MP4AddH264VideoTrack( m->file, 90000,
116 MP4_INVALID_DURATION, job->width, job->height,
117 job->config.h264.sps[1], /* AVCProfileIndication */
118 job->config.h264.sps[2], /* profile_compat */
119 job->config.h264.sps[3], /* AVCLevelIndication */
120 3 ); /* 4 bytes length before each NAL unit */
121 if ( mux_data->track == MP4_INVALID_TRACK_ID )
123 hb_error( "muxmp4.c: MP4AddH264VideoTrack failed!" );
128 /* Tune track chunk duration */
129 if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
134 MP4AddH264SequenceParameterSet( m->file, mux_data->track,
135 job->config.h264.sps, job->config.h264.sps_length );
136 MP4AddH264PictureParameterSet( m->file, mux_data->track,
137 job->config.h264.pps, job->config.h264.pps_length );
139 if( job->h264_level == 30 || job->ipod_atom)
141 hb_deep_log( 2, "muxmp4: adding iPod atom");
142 MP4AddIPodUUID(m->file, mux_data->track);
145 m->init_delay = job->config.h264.init_delay;
147 else /* FFmpeg or XviD */
149 MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 );
150 mux_data->track = MP4AddVideoTrack( m->file, 90000,
151 MP4_INVALID_DURATION, job->width, job->height,
152 MP4_MPEG4_VIDEO_TYPE );
153 if (mux_data->track == MP4_INVALID_TRACK_ID)
155 hb_error("muxmp4.c: MP4AddVideoTrack failed!");
160 /* Tune track chunk duration */
161 if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
166 /* VOL from FFmpeg or XviD */
167 if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
168 job->config.mpeg4.bytes, job->config.mpeg4.length )))
170 hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
176 // COLR atom for color and gamma correction.
178 // http://developer.apple.com/quicktime/icefloe/dispatch019.html#colr
179 // http://forum.doom9.org/showthread.php?t=133982#post1090068
180 // the user can set it from job->color_matrix, otherwise by default
181 // we say anything that's likely to be HD content is ITU BT.709 and
182 // DVD, SD TV & other content is ITU BT.601. We look at the title height
183 // rather than the job height here to get uncropped input dimensions.
184 if( job->color_matrix == 1 )
186 // ITU BT.601 DVD or SD TV content
187 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
189 else if( job->color_matrix == 2 )
191 // ITU BT.709 HD content
192 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
194 else if ( job->title->width >= 1280 || job->title->height >= 720 )
196 // we guess that 720p or above is ITU BT.709 HD content
197 MP4AddColr(m->file, mux_data->track, 1, 1, 1);
201 // ITU BT.601 DVD or SD TV content
202 MP4AddColr(m->file, mux_data->track, 6, 1, 6);
205 if( job->anamorphic.mode )
207 /* PASP atom for anamorphic video */
210 width = job->anamorphic.par_width;
212 height = job->anamorphic.par_height;
214 MP4AddPixelAspectRatio(m->file, mux_data->track, (uint32_t)width, (uint32_t)height);
216 MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height));
219 /* add the audio tracks */
220 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
222 audio = hb_list_item( title->list_audio, i );
223 mux_data = malloc( sizeof( hb_mux_data_t ) );
224 audio->priv.mux_data = mux_data;
226 if( audio->config.out.codec == HB_ACODEC_AC3 )
229 uint8_t bsid = audio->config.in.version;
230 uint8_t bsmod = audio->config.in.mode;
231 uint8_t acmod = audio->config.flags.ac3 & 0x7;
232 uint8_t lfeon = (audio->config.flags.ac3 & A52_LFE) ? 1 : 0;
233 uint8_t bit_rate_code = 0;
236 * Rewrite AC3 information into correct format for dac3 atom
238 switch( audio->config.in.samplerate )
251 * Error value, tells decoder to not decode this audio.
257 switch( audio->config.in.bitrate )
317 hb_error("Unknown AC3 bitrate");
322 mux_data->track = MP4AddAC3AudioTrack(
324 audio->config.out.samplerate,
332 /* Tune track chunk duration */
333 MP4TuneTrackDurationPerChunk( m, mux_data->track );
335 if (audio->config.out.name == NULL) {
336 MP4SetTrackBytesProperty(
337 m->file, mux_data->track,
339 (const uint8_t*)"Surround", strlen("Surround"));
342 MP4SetTrackBytesProperty(
343 m->file, mux_data->track,
345 (const uint8_t*)(audio->config.out.name),
346 strlen(audio->config.out.name));
349 mux_data->track = MP4AddAudioTrack(
351 audio->config.out.samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
353 /* Tune track chunk duration */
354 MP4TuneTrackDurationPerChunk( m, mux_data->track );
356 if (audio->config.out.name == NULL) {
357 MP4SetTrackBytesProperty(
358 m->file, mux_data->track,
360 (const uint8_t*)"Stereo", strlen("Stereo"));
363 MP4SetTrackBytesProperty(
364 m->file, mux_data->track,
366 (const uint8_t*)(audio->config.out.name),
367 strlen(audio->config.out.name));
370 MP4SetAudioProfileLevel( m->file, 0x0F );
371 MP4SetTrackESConfiguration(
372 m->file, mux_data->track,
373 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
375 /* Set the correct number of channels for this track */
376 MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown));
379 /* Set the language for this track */
380 MP4SetTrackLanguage(m->file, mux_data->track, audio->config.lang.iso639_2);
382 if( hb_list_count( title->list_audio ) > 1 )
384 /* Set the audio track alternate group */
385 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
389 /* Enable the first audio track */
390 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
393 /* Disable the other audio tracks so QuickTime doesn't play
396 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
397 hb_deep_log( 2, "muxmp4: disabled extra audio track %u", MP4FindTrackIndex( m->file, mux_data->track ));
402 if (job->chapter_markers)
404 /* add a text track for the chapters. We add the 'chap' atom to track
405 one which is usually the video track & should never be disabled.
406 The Quicktime spec says it doesn't matter which media track the
407 chap atom is on but it has to be an enabled track. */
408 MP4TrackId textTrack;
409 textTrack = MP4AddChapterTextTrack(m->file, 1, 0);
411 m->chapter_track = textTrack;
412 m->chapter_duration = 0;
413 m->current_chapter = job->chapter_start;
416 /* Add encoded-by metadata listing version and build date */
418 tool_string = (char *)malloc(80);
419 snprintf( tool_string, 80, "HandBrake %s %i", HB_PROJECT_VERSION, HB_PROJECT_BUILD);
421 /* allocate,fetch,populate,store,free tags structure */
423 tags = MP4TagsAlloc();
424 MP4TagsFetch( tags, m->file );
425 MP4TagsSetEncodingTool( tags, tool_string );
426 MP4TagsStore( tags, m->file );
434 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
437 hb_job_t * job = m->job;
442 if( mux_data == job->mux_data )
446 // if there are b-frames compute the render offset
447 // (we'll need it for both the video frame & the chapter track)
450 offset = buf->start + m->init_delay - m->sum_dur;
453 hb_log("MP4Mux: illegal render offset %lld, start %lld,"
454 "stop %lld, sum_dur %lld",
455 offset, buf->start, buf->stop, m->sum_dur );
460 /* Add the sample before the new frame.
461 It is important that this be calculated prior to the duration
462 of the new video sample, as we want to sync to right after it.
463 (This is because of how durations for text tracks work in QT) */
464 if( job->chapter_markers && buf->new_chap )
466 hb_chapter_t *chapter = NULL;
468 // this chapter is postioned by writing out the previous chapter.
469 // the duration of the previous chapter is the duration up to but
470 // not including the current frame minus the duration of all
471 // chapters up to the previous.
472 // The initial and final chapters can be very short (a second or
473 // less) since they're not really chapters but just a placeholder to
474 // insert a cell command. We don't write chapters shorter than 1.5 sec.
475 duration = m->sum_dur - m->chapter_duration + offset;
476 if ( duration >= (90000*3)/2 )
478 chapter = hb_list_item( m->job->title->list_chapter,
481 MP4AddChapter( m->file,
484 (chapter != NULL) ? chapter->title : NULL);
486 m->current_chapter = buf->new_chap;
487 m->chapter_duration += duration;
491 // We're getting the frames in decode order but the timestamps are
492 // for presentation so we have to use durations and effectively
494 duration = buf->stop - buf->start;
497 /* We got an illegal mp4/h264 duration. This shouldn't
498 be possible and usually indicates a bug in the upstream code.
499 Complain in the hope that someone will go find the bug but
500 try to fix the error so that the file will still be playable. */
501 hb_log("MP4Mux: illegal duration %lld, start %lld,"
502 "stop %lld, sum_dur %lld",
503 duration, buf->start, buf->stop, m->sum_dur );
504 /* we don't know when the next frame starts so we can't pick a
505 valid duration for this one. we pick something "short"
506 (roughly 1/3 of an NTSC frame time) to take time from
510 m->sum_dur += duration;
515 duration = MP4_INVALID_DURATION;
518 /* Here's where the sample actually gets muxed. */
519 if( job->vcodec == HB_VCODEC_X264 && mux_data == job->mux_data )
521 /* Compute dependency flags.
523 * This mechanism is (optionally) used by media players such as QuickTime
524 * to offer better scrubbing performance. The most influential bits are
525 * MP4_SDT_HAS_NO_DEPENDENTS and MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED.
527 * Other bits are possible but no example media using such bits have been
530 * It is acceptable to supply 0-bits for any samples which characteristics
531 * cannot be positively guaranteed.
536 /* encoding layer signals if frame is referenced by other frames */
537 if( buf->flags & HB_FRAME_REF )
538 dflags |= MP4_SDT_HAS_DEPENDENTS;
540 dflags |= MP4_SDT_HAS_NO_DEPENDENTS; /* disposable */
542 switch( buf->frametype )
548 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
551 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
556 break; /* nothing to mark */
559 if( !MP4WriteSampleDependency( m->file,
568 hb_error("Failed to write to output file, disk full?");
574 if( !MP4WriteSample( m->file,
580 ( buf->frametype & HB_FRAME_KEY ) != 0 ))
582 hb_error("Failed to write to output file, disk full?");
587 for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
589 hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i );
591 if( subtitle && subtitle->format == TEXTSUB &&
592 subtitle->dest == PASSTHRUSUB )
595 * Should be adding this one if the timestamp is right.
599 while( ( sub = hb_fifo_see( subtitle->fifo_out )) != NULL )
606 hb_log("MuxMP4: Text Sub: EOF");
607 sub = hb_fifo_get( subtitle->fifo_out );
608 hb_buffer_close( &sub );
610 if( sub->start < buf->start ) {
611 sub = hb_fifo_get( subtitle->fifo_out );
612 hb_log("MuxMP4: Text Sub:%lld: %s", sub->start, sub->data);
613 hb_buffer_close( &sub );
628 static int MP4End( hb_mux_object_t * m )
630 hb_job_t * job = m->job;
631 hb_title_t * title = job->title;
633 /* Write our final chapter marker */
634 if( m->job->chapter_markers )
636 hb_chapter_t *chapter = NULL;
637 int64_t duration = m->sum_dur - m->chapter_duration;
638 /* The final chapter can have a very short duration - if it's less
639 * than 1.5 seconds just skip it. */
640 if ( duration >= (90000*3)/2 )
643 chapter = hb_list_item( m->job->title->list_chapter,
644 m->current_chapter - 1 );
646 MP4AddChapter( m->file,
649 (chapter != NULL) ? chapter->title : NULL);
655 // Insert track edit to get A/V back in sync. The edit amount is
657 int64_t edit_amt = m->init_delay;
658 MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt,
659 MP4GetTrackDuration(m->file, 1), 0);
660 if ( m->job->chapter_markers )
662 // apply same edit to chapter track to keep it in sync with video
663 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
665 MP4GetTrackDuration(m->file, m->chapter_track), 0);
670 * Write the MP4 iTunes metadata if we have any metadata
672 if( title->metadata )
674 hb_metadata_t *md = title->metadata;
677 hb_deep_log( 2, "Writing Metadata to output file...");
679 /* allocate tags structure */
680 tags = MP4TagsAlloc();
681 /* fetch data from MP4 file (in case it already has some data) */
682 MP4TagsFetch( tags, m->file );
685 MP4TagsSetName( tags, md->name );
686 MP4TagsSetArtist( tags, md->artist );
687 MP4TagsSetComposer( tags, md->composer );
688 MP4TagsSetComments( tags, md->comment );
689 MP4TagsSetReleaseDate( tags, md->release_date );
690 MP4TagsSetAlbum( tags, md->album );
691 MP4TagsSetGenre( tags, md->genre );
696 art.data = md->coverart;
697 art.size = md->coverart_size;
698 art.type = MP4_ART_UNDEFINED; // delegate typing to libmp4v2
699 MP4TagsAddArtwork( tags, &art );
702 /* push data to MP4 file */
703 MP4TagsStore( tags, m->file );
704 /* free memory associated with structure */
710 if ( job->mp4_optimize )
712 hb_log( "muxmp4: optimizing file" );
713 char filename[1024]; memset( filename, 0, 1024 );
714 snprintf( filename, 1024, "%s.tmp", job->file );
715 MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
717 rename( filename, job->file );
723 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
725 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );