OSDN Git Service

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