OSDN Git Service

MacGui: Fixed the warning in ChapterTitles for real this time.
[handbrake-jp/handbrake-jp-git.git] / libhb / muxmp4.c
1 /* $Id: muxmp4.c,v 1.24 2005/11/04 13:09:41 titer Exp $
2
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. */
6
7 /* libmp4v2 header */
8 #include "mp4.h"
9
10 #include "hb.h"
11
12 void AddIPodUUID(MP4FileHandle, MP4TrackId);
13
14 struct hb_mux_object_s
15 {
16     HB_MUX_COMMON;
17
18     hb_job_t * job;
19
20     /* libmp4v2 handle */
21     MP4FileHandle file;
22
23     /* Cumulated durations so far, in output & input timescale units (see MP4Mux) */
24     int64_t sum_dur;        // duration in output timescale units
25     int64_t sum_dur_in;     // duration in input 90KHz timescale units
26
27     // bias to keep render offsets in ctts atom positive (set up by encx264)
28     int64_t init_delay;
29
30     /* Chapter state information for muxing */
31     MP4TrackId chapter_track;
32     int current_chapter;
33     uint64_t chapter_duration;
34
35     /* Sample rate of the first audio track.
36      * Used for the timescale
37      */
38     int samplerate;
39 };
40
41 struct hb_mux_data_s
42 {
43     MP4TrackId track;
44 };
45
46 struct hb_text_sample_s
47 {
48     uint8_t     sample[1280];
49     uint32_t    length;
50     MP4Duration duration;
51 };
52
53 /**********************************************************************
54  * MP4CreateTextSample
55  **********************************************************************
56  * Creates a buffer for a text track sample
57  *********************************************************************/
58 static struct hb_text_sample_s *MP4CreateTextSample( char *textString, uint64_t duration )
59 {
60     struct hb_text_sample_s *sample = NULL;
61     int stringLength = strlen(textString);
62     int x;
63
64     if( stringLength < 1024 )
65     {
66         sample = malloc( sizeof( struct hb_text_sample_s ) );
67
68         //textLength = (stringLength; // Account for BOM
69         sample->length = stringLength + 2 + 12; // Account for text length code and other marker
70         sample->duration = (MP4Duration)duration;
71
72         // 2-byte length marker
73         sample->sample[0] = (stringLength >> 8) & 0xff;
74         sample->sample[1] = stringLength & 0xff;
75
76         strncpy( (char *)&(sample->sample[2]), textString, stringLength );
77
78         x = 2 + stringLength;
79
80         // Modifier Length Marker
81         sample->sample[x] = 0x00;
82         sample->sample[x+1] = 0x00;
83         sample->sample[x+2] = 0x00;
84         sample->sample[x+3] = 0x0C;
85
86         // Modifier Type Code
87         sample->sample[x+4] = 'e';
88         sample->sample[x+5] = 'n';
89         sample->sample[x+6] = 'c';
90         sample->sample[x+7] = 'd';
91
92         // Modifier Value
93         sample->sample[x+8] = 0x00;
94         sample->sample[x+9] = 0x00;
95         sample->sample[x+10] = (256 >> 8) & 0xff;
96         sample->sample[x+11] = 256 & 0xff;
97     }
98
99     return sample;
100 }
101
102 /**********************************************************************
103  * MP4GenerateChapterSample
104  **********************************************************************
105  * Creates a buffer for a text track sample
106  *********************************************************************/
107 static struct hb_text_sample_s *MP4GenerateChapterSample( hb_mux_object_t * m,
108                                                           uint64_t duration,
109                                                           int chapter )
110 {
111     // We substract 1 from the chapter number because the chapters start at
112     // 1 but our name array starts at 0. We substract another 1 because we're
113     // writing the text of the previous chapter mark (when we get the start
114     // of chapter 2 we know the duration of chapter 1 & can write its mark).
115     hb_chapter_t *chapter_data = hb_list_item( m->job->title->list_chapter,
116                                                chapter - 2 );
117     char tmp_buffer[1024];
118     char *string = tmp_buffer;
119
120     tmp_buffer[0] = '\0';
121
122     if( chapter_data != NULL )
123     {
124         string = chapter_data->title;
125     }
126
127     if( strlen(string) == 0 || strlen(string) >= 1024 )
128     {
129         snprintf( tmp_buffer, 1023, "Chapter %03i", chapter - 2 );
130         string = tmp_buffer;
131     }
132
133     return MP4CreateTextSample( string, duration );
134 }
135
136
137 /**********************************************************************
138  * MP4Init
139  **********************************************************************
140  * Allocates hb_mux_data_t structures, create file and write headers
141  *********************************************************************/
142 static int MP4Init( hb_mux_object_t * m )
143 {
144     hb_job_t   * job   = m->job;
145     hb_title_t * title = job->title;
146
147     hb_audio_t    * audio;
148     hb_mux_data_t * mux_data;
149     int i;
150     u_int16_t language_code;
151
152     /* Flags for enabling/disabling tracks in an MP4. */
153     typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8}  track_header_flags;
154
155     if( (audio = hb_list_item(title->list_audio, 0)) != NULL )
156     {
157         /* Need the sample rate of the first audio track to use as the timescale. */
158         m->samplerate = audio->config.out.samplerate;
159         audio = NULL;
160     }
161     else
162     {
163         m->samplerate = 90000;
164     }
165
166     /* Create an empty mp4 file */
167     if (job->largeFileSize)
168     /* Use 64-bit MP4 file */
169     {
170         m->file = MP4Create( job->file, MP4_DETAILS_ERROR, MP4_CREATE_64BIT_DATA );
171         hb_log("Using 64-bit MP4 formatting.");
172     }
173     else
174     /* Limit MP4s to less than 4 GB */
175     {
176         m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
177     }
178
179     if (m->file == MP4_INVALID_FILE_HANDLE)
180     {
181         hb_error("muxmp4.c: MP4Create failed!");
182         *job->die = 1;
183         return 0;
184     }
185
186     /* Video track */
187     mux_data      = malloc( sizeof( hb_mux_data_t ) );
188     job->mux_data = mux_data;
189
190     /* When using the standard 90000 timescale, QuickTime tends to have
191        synchronization issues (audio not playing at the correct speed).
192        To workaround this, we use the audio samplerate as the
193        timescale */
194     if (!(MP4SetTimeScale( m->file, m->samplerate )))
195     {
196         hb_error("muxmp4.c: MP4SetTimeScale failed!");
197         *job->die = 1;
198         return 0;
199     }
200
201     if( job->vcodec == HB_VCODEC_X264 )
202     {
203         /* Stolen from mp4creator */
204         if(!(MP4SetVideoProfileLevel( m->file, 0x7F )))
205         {
206             hb_error("muxmp4.c: MP4SetVideoProfileLevel failed!");
207             *job->die = 1;
208             return 0;
209         }
210
211                 mux_data->track = MP4AddH264VideoTrack( m->file, m->samplerate,
212                         MP4_INVALID_DURATION, job->width, job->height,
213                         job->config.h264.sps[1], /* AVCProfileIndication */
214                         job->config.h264.sps[2], /* profile_compat */
215                         job->config.h264.sps[3], /* AVCLevelIndication */
216                         3 );      /* 4 bytes length before each NAL unit */
217
218
219         MP4AddH264SequenceParameterSet( m->file, mux_data->track,
220                 job->config.h264.sps, job->config.h264.sps_length );
221         MP4AddH264PictureParameterSet( m->file, mux_data->track,
222                 job->config.h264.pps, job->config.h264.pps_length );
223
224                 if( job->h264_level == 30 || job->ipod_atom)
225                 {
226                         hb_log("About to add iPod atom");
227                         AddIPodUUID(m->file, mux_data->track);
228                 }
229
230         m->init_delay = job->config.h264.init_delay;
231     }
232     else /* FFmpeg or XviD */
233     {
234         if(!(MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 )))
235         {
236             hb_error("muxmp4.c: MP4SetVideoProfileLevel failed!");
237             *job->die = 1;
238             return 0;
239         }
240         mux_data->track = MP4AddVideoTrack( m->file, m->samplerate,
241                 MP4_INVALID_DURATION, job->width, job->height,
242                 MP4_MPEG4_VIDEO_TYPE );
243         if (mux_data->track == MP4_INVALID_TRACK_ID)
244         {
245             hb_error("muxmp4.c: MP4AddVideoTrack failed!");
246             *job->die = 1;
247             return 0;
248         }
249
250
251         /* VOL from FFmpeg or XviD */
252         if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
253                 job->config.mpeg4.bytes, job->config.mpeg4.length )))
254         {
255             hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
256             *job->die = 1;
257             return 0;
258         }
259     }
260
261     // COLR atom for color and gamma correction.
262     // Per the notes at:
263     //   http://developer.apple.com/quicktime/icefloe/dispatch019.html#colr
264     //   http://forum.doom9.org/showthread.php?t=133982#post1090068
265     // we say anything that's likely to be HD content is ITU BT.709 and
266     // DVD, SD TV & other content is ITU BT.601.  We look at the title height
267     // rather than the job height here to get uncropped input dimensions.
268     if ( job->title->height >= 720 )
269     {
270         // we guess that 720p or above is ITU BT.709 HD content
271         MP4AddColr(m->file, mux_data->track, 1, 1, 1);
272     }
273     else
274     {
275         // ITU BT.601 DVD or SD TV content
276         MP4AddColr(m->file, mux_data->track, 6, 1, 6);
277     }
278
279     if( job->pixel_ratio )
280     {
281         /* PASP atom for anamorphic video */
282         float width, height;
283
284         width = job->pixel_aspect_width;
285
286         height = job->pixel_aspect_height;
287
288         MP4AddPixelAspectRatio(m->file, mux_data->track, (uint32_t)width, (uint32_t)height);
289
290         MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height));
291     }
292
293         /* add the audio tracks */
294     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
295     {
296         static u_int8_t reserved2[16] = {
297                 0x00, 0x00, 0x00, 0x00,
298                 0x00, 0x00, 0x00, 0x00,
299                 0x00, 0x02, 0x00, 0x10,
300                 0x00, 0x00, 0x00, 0x00,
301             };
302
303         audio = hb_list_item( title->list_audio, i );
304         mux_data = malloc( sizeof( hb_mux_data_t ) );
305         audio->priv.mux_data = mux_data;
306
307         if( audio->config.out.codec == HB_ACODEC_AC3 )
308         {
309             mux_data->track = MP4AddAC3AudioTrack(
310                 m->file,
311                 m->samplerate, 1536, MP4_MPEG4_AUDIO_TYPE );
312             MP4SetTrackBytesProperty(
313                 m->file, mux_data->track,
314                 "udta.name.value",
315                 (const u_int8_t*)"Surround", strlen("Surround"));
316         } else {
317             mux_data->track = MP4AddAudioTrack(
318                 m->file,
319                 m->samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
320             MP4SetTrackBytesProperty(
321                 m->file, mux_data->track,
322                 "udta.name.value",
323                 (const u_int8_t*)"Stereo", strlen("Stereo"));
324
325             MP4SetAudioProfileLevel( m->file, 0x0F );
326             MP4SetTrackESConfiguration(
327                 m->file, mux_data->track,
328                 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
329
330             /* Set the correct number of channels for this track */
331             reserved2[9] = (u_int8_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
332             MP4SetTrackBytesProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.reserved2", reserved2, sizeof(reserved2));
333
334         }
335         /* Set the language for this track */
336         /* The language is stored as 5-bit text - 0x60 */
337         language_code = audio->config.lang.iso639_2[0] - 0x60;   language_code <<= 5;
338         language_code |= audio->config.lang.iso639_2[1] - 0x60;  language_code <<= 5;
339         language_code |= audio->config.lang.iso639_2[2] - 0x60;
340         MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.mdhd.language", language_code);
341
342
343         /* Set the audio track alternate group */
344         MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
345
346         /* If we ever upgrade mpeg4ip, the line above should be replaced with the line below.*/
347 //        MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels",  (u_int16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown));
348
349         if (i == 0) {
350             /* Enable the first audio track */
351             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
352         }
353         else
354             /* Disable the other audio tracks so QuickTime doesn't play
355                them all at once. */
356         {
357             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
358             hb_log("Disabled extra audio track %i", mux_data->track-1);
359         }
360
361     }
362
363         if (job->chapter_markers)
364     {
365         /* add a text track for the chapters. We add the 'chap' atom to track
366            one which is usually the video track & should never be disabled.
367            The Quicktime spec says it doesn't matter which media track the
368            chap atom is on but it has to be an enabled track. */
369         MP4TrackId textTrack;
370         textTrack = MP4AddChapterTextTrack(m->file, 1);
371
372         m->chapter_track = textTrack;
373         m->chapter_duration = 0;
374         m->current_chapter = job->chapter_start;
375     }
376
377     /* Add encoded-by metadata listing version and build date */
378     char *tool_string;
379     tool_string = (char *)malloc(80);
380     snprintf( tool_string, 80, "HandBrake %s %i", HB_VERSION, HB_BUILD);
381     MP4SetMetadataTool(m->file, tool_string);
382     free(tool_string);
383
384     return 0;
385 }
386
387 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
388                    hb_buffer_t * buf )
389 {
390     hb_job_t * job = m->job;
391     int64_t duration;
392     int64_t offset = 0;
393
394     if( mux_data == job->mux_data )
395     {
396         /* Video */
397
398         // if there are b-frames compute the render offset
399         // (we'll need it for both the video frame & the chapter track)
400         if ( m->init_delay )
401         {
402             offset = ( buf->start + m->init_delay ) * m->samplerate / 90000 -
403                      m->sum_dur;
404         }
405         /* Add the sample before the new frame.
406            It is important that this be calculated prior to the duration
407            of the new video sample, as we want to sync to right after it.
408            (This is because of how durations for text tracks work in QT) */
409         if( job->chapter_markers && buf->new_chap )
410         {
411             struct hb_text_sample_s *sample;
412
413             // this chapter is postioned by writing out the previous chapter.
414             // the duration of the previous chapter is the duration up to but
415             // not including the current frame minus the duration of all
416             // chapters up to the previous.
417             duration = m->sum_dur - m->chapter_duration + offset;
418             if ( duration <= 0 )
419             {
420                 /* The initial & final chapters can have very short durations
421                  * (less than the error in our total duration estimate) so
422                  * the duration calc above can result in a negative number.
423                  * when this happens give the chapter a short duration (1/3
424                  * of an ntsc frame time). */
425                 duration = 1000 * m->samplerate / 90000;
426             }
427
428             sample = MP4GenerateChapterSample( m, duration, buf->new_chap );
429
430             if( !MP4WriteSample(m->file,
431                                 m->chapter_track,
432                                 sample->sample,
433                                 sample->length,
434                                 sample->duration,
435                                 0, true) )
436             {
437                 hb_error("Failed to write to output file, disk full?");
438                 *job->die = 1;
439             }
440             free(sample);
441             m->current_chapter = buf->new_chap;
442             m->chapter_duration += duration;
443         }
444
445         // since we're changing the sample rate we need to keep track of
446         // the truncation bias so that the audio and video don't go out
447         // of sync. m->sum_dur_in is the sum of the input durations so far.
448         // m->sum_dur is the sum of the output durations. Their difference
449         // (in output sample rate units) is the accumulated truncation bias.
450         int64_t bias = ( m->sum_dur_in * m->samplerate / 90000 ) - m->sum_dur;
451         int64_t dur_in = buf->stop - buf->start;
452         duration = dur_in * m->samplerate / 90000 + bias;
453         if ( duration <= 0 )
454         {
455             /* We got an illegal mp4/h264 duration. This shouldn't
456                be possible and usually indicates a bug in the upstream code.
457                Complain in the hope that someone will go find the bug but
458                try to fix the error so that the file will still be playable. */
459             hb_log("MP4Mux: illegal duration %lld, bias %lld, start %lld (%lld),"
460                    "stop %lld (%lld), sum_dur %lld",
461                    duration, bias, buf->start * m->samplerate / 90000, buf->start,
462                    buf->stop * m->samplerate / 90000, buf->stop, m->sum_dur );
463             /* we don't know when the next frame starts so we can't pick a
464                valid duration for this one so we pick something "short"
465                (roughly 1/3 of an NTSC frame time) and rely on the bias calc
466                for the next frame to correct things (a duration underestimate
467                just results in a large bias on the next frame). */
468             duration = 1000 * m->samplerate / 90000;
469         }
470         m->sum_dur += duration;
471         m->sum_dur_in += dur_in;
472     }
473     else
474     {
475         /* Audio */
476         duration = MP4_INVALID_DURATION;
477     }
478
479     // Here's where the sample actually gets muxed.
480     if( !MP4WriteSample( m->file,
481                          mux_data->track,
482                          buf->data,
483                          buf->size,
484                          duration,
485                          offset,
486                          ((buf->frametype & HB_FRAME_KEY) != 0) ) )
487     {
488         hb_error("Failed to write to output file, disk full?");
489         *job->die = 1;
490     }
491
492     return 0;
493 }
494
495 static int MP4End( hb_mux_object_t * m )
496 {
497     hb_job_t   * job   = m->job;
498
499     /* Write our final chapter marker */
500     if( m->job->chapter_markers )
501     {
502         int64_t duration = m->sum_dur - m->chapter_duration;
503         /* The final chapter can have a very short duration - if it's less
504          * than a second just skip it. */
505         if ( duration >= m->samplerate )
506         {
507
508             struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, duration,
509                                                     m->current_chapter + 1 );
510             if( ! MP4WriteSample(m->file, m->chapter_track, sample->sample,
511                                  sample->length, sample->duration, 0, true) )
512             {
513                 hb_error("Failed to write to output file, disk full?");
514                 *job->die = 1;
515             }
516             free(sample);
517         }
518     }
519
520     if (job->areBframes)
521     {
522            // Insert track edit to get A/V back in sync.  The edit amount is
523            // the init_delay.
524            int64_t edit_amt = m->init_delay * m->samplerate / 90000;
525            MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt,
526                            MP4GetTrackDuration(m->file, 1), 0);
527             if ( m->job->chapter_markers )
528             {
529                 // apply same edit to chapter track to keep it in sync with video
530                 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
531                                 edit_amt,
532                                 MP4GetTrackDuration(m->file, m->chapter_track), 0);
533             }
534      }
535
536     MP4Close( m->file );
537
538     if ( job->mp4_optimize )
539     {
540         hb_log( "muxmp4: optimizing file" );
541         char filename[1024]; memset( filename, 0, 1024 );
542         snprintf( filename, 1024, "%s.tmp", job->file );
543         MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
544         remove( job->file );
545         rename( filename, job->file );
546     }
547
548     return 0;
549 }
550
551 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
552 {
553     hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );
554     m->init      = MP4Init;
555     m->mux       = MP4Mux;
556     m->end       = MP4End;
557     m->job       = job;
558     return m;
559 }
560