OSDN Git Service

d36da397d5f29f8084f45068e418e96cd9b33ce9
[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_deep_log( 2, "muxmp4: 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_deep_log( 2, "muxmp4: adding 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             if (audio->config.out.name == NULL) {
313                 MP4SetTrackBytesProperty(
314                     m->file, mux_data->track,
315                     "udta.name.value",
316                     (const u_int8_t*)"Surround", strlen("Surround"));
317             }
318             else {
319                 MP4SetTrackBytesProperty(
320                     m->file, mux_data->track,
321                     "udta.name.value",
322                     (const u_int8_t*)(audio->config.out.name),
323                     strlen(audio->config.out.name));
324             }
325         } else {
326             mux_data->track = MP4AddAudioTrack(
327                 m->file,
328                 m->samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
329             if (audio->config.out.name == NULL) {
330                 MP4SetTrackBytesProperty(
331                     m->file, mux_data->track,
332                     "udta.name.value",
333                     (const u_int8_t*)"Stereo", strlen("Stereo"));
334             }
335             else {
336                 MP4SetTrackBytesProperty(
337                     m->file, mux_data->track,
338                     "udta.name.value",
339                     (const u_int8_t*)(audio->config.out.name),
340                     strlen(audio->config.out.name));
341             }
342
343             MP4SetAudioProfileLevel( m->file, 0x0F );
344             MP4SetTrackESConfiguration(
345                 m->file, mux_data->track,
346                 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
347
348             /* Set the correct number of channels for this track */
349             reserved2[9] = (u_int8_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
350             MP4SetTrackBytesProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.reserved2", reserved2, sizeof(reserved2));
351
352             /* If we ever upgrade mpeg4ip, the line above should be replaced with the line below.*/
353             // MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (u_int16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown));
354         }
355
356         /* Set the language for this track */
357         /* The language is stored as 5-bit text - 0x60 */
358         language_code = audio->config.lang.iso639_2[0] - 0x60;   language_code <<= 5;
359         language_code |= audio->config.lang.iso639_2[1] - 0x60;  language_code <<= 5;
360         language_code |= audio->config.lang.iso639_2[2] - 0x60;
361         MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.mdhd.language", language_code);
362
363         if( hb_list_count( title->list_audio ) > 1 )
364         {
365             /* Set the audio track alternate group */
366             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
367         }
368
369         if (i == 0) {
370             /* Enable the first audio track */
371             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
372         }
373         else
374             /* Disable the other audio tracks so QuickTime doesn't play
375                them all at once. */
376         {
377             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
378             hb_deep_log( 2, "muxp4: disabled extra audio track %i", mux_data->track-1);
379         }
380
381     }
382
383         if (job->chapter_markers)
384     {
385         /* add a text track for the chapters. We add the 'chap' atom to track
386            one which is usually the video track & should never be disabled.
387            The Quicktime spec says it doesn't matter which media track the
388            chap atom is on but it has to be an enabled track. */
389         MP4TrackId textTrack;
390         textTrack = MP4AddChapterTextTrack(m->file, 1);
391
392         m->chapter_track = textTrack;
393         m->chapter_duration = 0;
394         m->current_chapter = job->chapter_start;
395     }
396
397     /* Add encoded-by metadata listing version and build date */
398     char *tool_string;
399     tool_string = (char *)malloc(80);
400     snprintf( tool_string, 80, "HandBrake %s %i", HB_VERSION, HB_BUILD);
401     MP4SetMetadataTool(m->file, tool_string);
402     free(tool_string);
403
404     return 0;
405 }
406
407 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
408                    hb_buffer_t * buf )
409 {
410     hb_job_t * job = m->job;
411     int64_t duration;
412     int64_t offset = 0;
413
414     if( mux_data == job->mux_data )
415     {
416         /* Video */
417
418         // if there are b-frames compute the render offset
419         // (we'll need it for both the video frame & the chapter track)
420         if ( m->init_delay )
421         {
422             offset = ( buf->start + m->init_delay ) * m->samplerate / 90000 -
423                      m->sum_dur;
424         }
425         /* Add the sample before the new frame.
426            It is important that this be calculated prior to the duration
427            of the new video sample, as we want to sync to right after it.
428            (This is because of how durations for text tracks work in QT) */
429         if( job->chapter_markers && buf->new_chap )
430         {
431             struct hb_text_sample_s *sample;
432
433             // this chapter is postioned by writing out the previous chapter.
434             // the duration of the previous chapter is the duration up to but
435             // not including the current frame minus the duration of all
436             // chapters up to the previous.
437             duration = m->sum_dur - m->chapter_duration + offset;
438             if ( duration <= 0 )
439             {
440                 /* The initial & final chapters can have very short durations
441                  * (less than the error in our total duration estimate) so
442                  * the duration calc above can result in a negative number.
443                  * when this happens give the chapter a short duration (1/3
444                  * of an ntsc frame time). */
445                 duration = 1000 * m->samplerate / 90000;
446             }
447
448             sample = MP4GenerateChapterSample( m, duration, buf->new_chap );
449
450             if( !MP4WriteSample(m->file,
451                                 m->chapter_track,
452                                 sample->sample,
453                                 sample->length,
454                                 sample->duration,
455                                 0, true) )
456             {
457                 hb_error("Failed to write to output file, disk full?");
458                 *job->die = 1;
459             }
460             free(sample);
461             m->current_chapter = buf->new_chap;
462             m->chapter_duration += duration;
463         }
464
465         // since we're changing the sample rate we need to keep track of
466         // the truncation bias so that the audio and video don't go out
467         // of sync. m->sum_dur_in is the sum of the input durations so far.
468         // m->sum_dur is the sum of the output durations. Their difference
469         // (in output sample rate units) is the accumulated truncation bias.
470         int64_t bias = ( m->sum_dur_in * m->samplerate / 90000 ) - m->sum_dur;
471         int64_t dur_in = buf->stop - buf->start;
472         duration = dur_in * m->samplerate / 90000 + bias;
473         if ( duration <= 0 )
474         {
475             /* We got an illegal mp4/h264 duration. This shouldn't
476                be possible and usually indicates a bug in the upstream code.
477                Complain in the hope that someone will go find the bug but
478                try to fix the error so that the file will still be playable. */
479             hb_log("MP4Mux: illegal duration %lld, bias %lld, start %lld (%lld),"
480                    "stop %lld (%lld), sum_dur %lld",
481                    duration, bias, buf->start * m->samplerate / 90000, buf->start,
482                    buf->stop * m->samplerate / 90000, buf->stop, m->sum_dur );
483             /* we don't know when the next frame starts so we can't pick a
484                valid duration for this one so we pick something "short"
485                (roughly 1/3 of an NTSC frame time) and rely on the bias calc
486                for the next frame to correct things (a duration underestimate
487                just results in a large bias on the next frame). */
488             duration = 1000 * m->samplerate / 90000;
489         }
490         m->sum_dur += duration;
491         m->sum_dur_in += dur_in;
492     }
493     else
494     {
495         /* Audio */
496         duration = MP4_INVALID_DURATION;
497     }
498
499     // Here's where the sample actually gets muxed.
500     if( !MP4WriteSample( m->file,
501                          mux_data->track,
502                          buf->data,
503                          buf->size,
504                          duration,
505                          offset,
506                          ((buf->frametype & HB_FRAME_KEY) != 0) ) )
507     {
508         hb_error("Failed to write to output file, disk full?");
509         *job->die = 1;
510     }
511
512     return 0;
513 }
514
515 static int MP4End( hb_mux_object_t * m )
516 {
517     hb_job_t   * job   = m->job;
518
519     /* Write our final chapter marker */
520     if( m->job->chapter_markers )
521     {
522         int64_t duration = m->sum_dur - m->chapter_duration;
523         /* The final chapter can have a very short duration - if it's less
524          * than a second just skip it. */
525         if ( duration >= m->samplerate )
526         {
527
528             struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, duration,
529                                                     m->current_chapter + 1 );
530             if( ! MP4WriteSample(m->file, m->chapter_track, sample->sample,
531                                  sample->length, sample->duration, 0, true) )
532             {
533                 hb_error("Failed to write to output file, disk full?");
534                 *job->die = 1;
535             }
536             free(sample);
537         }
538     }
539
540     if (job->areBframes)
541     {
542            // Insert track edit to get A/V back in sync.  The edit amount is
543            // the init_delay.
544            int64_t edit_amt = m->init_delay * m->samplerate / 90000;
545            MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt,
546                            MP4GetTrackDuration(m->file, 1), 0);
547             if ( m->job->chapter_markers )
548             {
549                 // apply same edit to chapter track to keep it in sync with video
550                 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
551                                 edit_amt,
552                                 MP4GetTrackDuration(m->file, m->chapter_track), 0);
553             }
554      }
555
556     MP4Close( m->file );
557
558     if ( job->mp4_optimize )
559     {
560         hb_log( "muxmp4: optimizing file" );
561         char filename[1024]; memset( filename, 0, 1024 );
562         snprintf( filename, 1024, "%s.tmp", job->file );
563         MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
564         remove( job->file );
565         rename( filename, job->file );
566     }
567
568     return 0;
569 }
570
571 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
572 {
573     hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );
574     m->init      = MP4Init;
575     m->mux       = MP4Mux;
576     m->end       = MP4End;
577     m->job       = job;
578     return m;
579 }
580