OSDN Git Service

Remove depreciated cpu count from the api
[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 #include "mp4v2/mp4v2.h"
8 #include "a52dec/a52.h"
9
10 #include "hb.h"
11
12 struct hb_mux_object_s
13 {
14     HB_MUX_COMMON;
15
16     hb_job_t * job;
17
18     /* libmp4v2 handle */
19     MP4FileHandle file;
20
21     int64_t sum_dur;    // sum of video frame durations so far
22
23     hb_buffer_t *delay_buf;
24
25     /* Chapter state information for muxing */
26     MP4TrackId chapter_track;
27     int current_chapter;
28     uint64_t chapter_duration;
29 };
30
31 struct hb_mux_data_s
32 {
33     MP4TrackId  track;
34     uint8_t     subtitle;
35     int         sub_format;
36
37     uint64_t    sum_dur; // sum of the frame durations so far
38 };
39
40 /* Tune video track chunk duration.
41  * libmp4v2 default duration == dusamplerate == 1 second.
42  * Per van's suggestion we desire duration == 4 frames.
43  * Should be invoked immediately after track creation.
44  *
45  * return true on fail, false on success.
46  */
47 static int MP4TuneTrackDurationPerChunk( hb_mux_object_t* m, MP4TrackId trackId )
48 {
49     uint32_t tscale;
50     MP4Duration dur;
51
52     tscale = MP4GetTrackTimeScale( m->file, trackId );
53     dur = (MP4Duration)ceil( (double)tscale * (double)m->job->vrate_base / (double)m->job->vrate * 4.0 );
54
55     if( !MP4SetTrackDurationPerChunk( m->file, trackId, dur ))
56     {
57         hb_error( "muxmp4.c: MP4SetTrackDurationPerChunk failed!" );
58         *m->job->die = 1;
59         return 0;
60     }
61
62     hb_deep_log( 2, "muxmp4: track %u, chunk duration %"PRIu64, MP4FindTrackIndex( m->file, trackId ), dur );
63     return 1;
64 }
65
66 static const uint16_t ac3_sample_rate_tab[3] = { 48000, 44100, 32000 };
67 /* possible bitrates */
68 static const uint16_t ac3_bitrate_tab[19] = {
69     32, 40, 48, 56, 64, 80, 96, 112, 128,
70     160, 192, 224, 256, 320, 384, 448, 512, 576, 640
71 };  
72
73
74 /**********************************************************************
75  * MP4Init
76  **********************************************************************
77  * Allocates hb_mux_data_t structures, create file and write headers
78  *********************************************************************/
79 static int MP4Init( hb_mux_object_t * m )
80 {
81     hb_job_t   * job   = m->job;
82     hb_title_t * title = job->title;
83
84     hb_audio_t    * audio;
85     hb_mux_data_t * mux_data;
86     int i;
87     int subtitle_default;
88
89     /* Flags for enabling/disabling tracks in an MP4. */
90     typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8}  track_header_flags;
91
92     /* Create an empty mp4 file */
93     if (job->largeFileSize)
94     /* Use 64-bit MP4 file */
95     {
96         m->file = MP4Create( job->file, MP4_DETAILS_ERROR, MP4_CREATE_64BIT_DATA );
97         hb_deep_log( 2, "muxmp4: using 64-bit MP4 formatting.");
98     }
99     else
100     /* Limit MP4s to less than 4 GB */
101     {
102         m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
103     }
104
105     if (m->file == MP4_INVALID_FILE_HANDLE)
106     {
107         hb_error("muxmp4.c: MP4Create failed!");
108         *job->die = 1;
109         return 0;
110     }
111
112     /* Video track */
113     mux_data      = calloc(1, sizeof( hb_mux_data_t ) );
114     job->mux_data = mux_data;
115
116     if (!(MP4SetTimeScale( m->file, 90000 )))
117     {
118         hb_error("muxmp4.c: MP4SetTimeScale failed!");
119         *job->die = 1;
120         return 0;
121     }
122
123     if( job->vcodec == HB_VCODEC_X264 )
124     {
125         /* Stolen from mp4creator */
126         MP4SetVideoProfileLevel( m->file, 0x7F );
127                 mux_data->track = MP4AddH264VideoTrack( m->file, 90000,
128                         MP4_INVALID_DURATION, job->width, job->height,
129                         job->config.h264.sps[1], /* AVCProfileIndication */
130                         job->config.h264.sps[2], /* profile_compat */
131                         job->config.h264.sps[3], /* AVCLevelIndication */
132                         3 );      /* 4 bytes length before each NAL unit */
133         if ( mux_data->track == MP4_INVALID_TRACK_ID )
134         {
135             hb_error( "muxmp4.c: MP4AddH264VideoTrack failed!" );
136             *job->die = 1;
137             return 0;
138         }
139
140         /* Tune track chunk duration */
141         if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
142         {
143             return 0;
144         }
145
146         MP4AddH264SequenceParameterSet( m->file, mux_data->track,
147                 job->config.h264.sps, job->config.h264.sps_length );
148         MP4AddH264PictureParameterSet( m->file, mux_data->track,
149                 job->config.h264.pps, job->config.h264.pps_length );
150
151                 if( job->ipod_atom )
152                 {
153                         hb_deep_log( 2, "muxmp4: adding iPod atom");
154                         MP4AddIPodUUID(m->file, mux_data->track);
155                 }
156     }
157     else /* FFmpeg or XviD */
158     {
159         MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 );
160         mux_data->track = MP4AddVideoTrack( m->file, 90000,
161                 MP4_INVALID_DURATION, job->width, job->height,
162                 MP4_MPEG4_VIDEO_TYPE );
163         if (mux_data->track == MP4_INVALID_TRACK_ID)
164         {
165             hb_error("muxmp4.c: MP4AddVideoTrack failed!");
166             *job->die = 1;
167             return 0;
168         }
169
170         /* Tune track chunk duration */
171         if( !MP4TuneTrackDurationPerChunk( m, mux_data->track ))
172         {
173             return 0;
174         }
175
176         /* VOL from FFmpeg or XviD */
177         if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
178                 job->config.mpeg4.bytes, job->config.mpeg4.length )))
179         {
180             hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
181             *job->die = 1;
182             return 0;
183         }
184     }
185
186     // COLR atom for color and gamma correction.
187     // Per the notes at:
188     //   http://developer.apple.com/quicktime/icefloe/dispatch019.html#colr
189     //   http://forum.doom9.org/showthread.php?t=133982#post1090068
190     // the user can set it from job->color_matrix, otherwise by default
191     // we say anything that's likely to be HD content is ITU BT.709 and
192     // DVD, SD TV & other content is ITU BT.601.  We look at the title height
193     // rather than the job height here to get uncropped input dimensions.
194     if( job->color_matrix == 1 )
195     {
196         // ITU BT.601 DVD or SD TV content
197         MP4AddColr(m->file, mux_data->track, 6, 1, 6);
198     }
199     else if( job->color_matrix == 2 )
200     {
201         // ITU BT.709 HD content
202         MP4AddColr(m->file, mux_data->track, 1, 1, 1);        
203     }
204     else if ( job->title->width >= 1280 || job->title->height >= 720 )
205     {
206         // we guess that 720p or above is ITU BT.709 HD content
207         MP4AddColr(m->file, mux_data->track, 1, 1, 1);
208     }
209     else
210     {
211         // ITU BT.601 DVD or SD TV content
212         MP4AddColr(m->file, mux_data->track, 6, 1, 6);
213     }
214
215     if( job->anamorphic.mode )
216     {
217         /* PASP atom for anamorphic video */
218         float width, height;
219
220         width  = job->anamorphic.par_width;
221
222         height = job->anamorphic.par_height;
223
224         MP4AddPixelAspectRatio(m->file, mux_data->track, (uint32_t)width, (uint32_t)height);
225
226         MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height));
227     }
228
229         /* add the audio tracks */
230     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
231     {
232         audio = hb_list_item( title->list_audio, i );
233         mux_data = calloc(1, sizeof( hb_mux_data_t ) );
234         audio->priv.mux_data = mux_data;
235
236         if( audio->config.out.codec == HB_ACODEC_AC3_PASS )
237         {
238             uint8_t bsid = audio->config.in.version;
239             uint8_t bsmod = audio->config.in.mode;
240             uint8_t acmod = audio->config.flags.ac3 & 0x7;
241             uint8_t lfeon = (audio->config.flags.ac3 & A52_LFE) ? 1 : 0;
242             uint8_t bit_rate_code = 0;
243             int ii, jj;
244             int freq = audio->config.in.samplerate;
245             int bitrate = audio->config.in.bitrate;
246             int sr_shift, sr_code;
247
248             for (ii = 0; ii < 3; ii++)
249             {
250                 for (jj = 0; jj < 3; jj++)
251                 {
252                     if ((ac3_sample_rate_tab[jj] >> ii) == freq)
253                     {
254                         goto rate_found1;
255                     }
256                 }
257             }
258             hb_error("Unknown AC3 samplerate");
259             ii = jj = 0;
260 rate_found1:
261             sr_shift = ii;
262             sr_code = jj;
263             for (ii = 0; ii < 19; ii++)
264             {
265                 if ((ac3_bitrate_tab[ii] >> sr_shift)*1000 == bitrate)
266                     break;
267             }
268             if ( ii >= 19 )
269             {
270                 hb_error("Unknown AC3 bitrate");
271                 ii = 0;
272             }
273             bit_rate_code = ii;
274
275             mux_data->track = MP4AddAC3AudioTrack(
276                 m->file,
277                 audio->config.in.samplerate, 
278                 sr_code,
279                 bsid,
280                 bsmod,
281                 acmod,
282                 lfeon,
283                 bit_rate_code);
284
285             /* Tune track chunk duration */
286             MP4TuneTrackDurationPerChunk( m, mux_data->track );
287
288             if (audio->config.out.name == NULL) {
289                 MP4SetTrackBytesProperty(
290                     m->file, mux_data->track,
291                     "udta.name.value",
292                     (const uint8_t*)"Surround", strlen("Surround"));
293             }
294             else {
295                 MP4SetTrackBytesProperty(
296                     m->file, mux_data->track,
297                     "udta.name.value",
298                     (const uint8_t*)(audio->config.out.name),
299                     strlen(audio->config.out.name));
300             }
301         }
302         else if( audio->config.out.codec == HB_ACODEC_AC3 )
303         {
304             uint8_t bsid = 8;
305             uint8_t bsmod = 0;
306             uint8_t acmod = 2;
307             uint8_t lfeon = 0;
308             uint8_t bit_rate_code = 0;
309             int ii, jj;
310             int freq = audio->config.out.samplerate;
311             int bitrate = audio->config.out.bitrate;
312             int sr_shift, sr_code;
313
314             for (ii = 0; ii < 3; ii++)
315             {
316                 for (jj = 0; jj < 3; jj++)
317                 {
318                     if ((ac3_sample_rate_tab[jj] >> ii) == freq)
319                     {
320                         goto rate_found2;
321                     }
322                 }
323             }
324             hb_error("Unknown AC3 samplerate");
325             ii = jj = 0;
326 rate_found2:
327             sr_shift = ii;
328             sr_code = jj;
329             bsid = 8 + ii;
330             for (ii = 0; ii < 19; ii++)
331             {
332                 if ((ac3_bitrate_tab[ii] >> sr_shift) == bitrate)
333                     break;
334             }
335             if ( ii >= 19 )
336             {
337                 hb_error("Unknown AC3 bitrate");
338                 ii = 0;
339             }
340             bit_rate_code = ii;
341
342             switch( audio->config.out.mixdown )
343             {
344                 case HB_AMIXDOWN_MONO:
345                     acmod = 1;
346                     break;
347
348                 case HB_AMIXDOWN_STEREO:
349                 case HB_AMIXDOWN_DOLBY:
350                 case HB_AMIXDOWN_DOLBYPLII:
351                     acmod = 2;
352                     break;
353
354                 case HB_AMIXDOWN_6CH:
355                     acmod = 7;
356                     lfeon = 1;
357                     break;
358
359                 default:
360                     hb_log(" MP4Init: bad mixdown" );
361                     break;
362             }
363
364             mux_data->track = MP4AddAC3AudioTrack(
365                 m->file,
366                 audio->config.out.samplerate, 
367                 sr_code,
368                 bsid,
369                 bsmod,
370                 acmod,
371                 lfeon,
372                 bit_rate_code);
373
374             /* Tune track chunk duration */
375             MP4TuneTrackDurationPerChunk( m, mux_data->track );
376
377             if (audio->config.out.name == NULL) {
378                 MP4SetTrackBytesProperty(
379                     m->file, mux_data->track,
380                     "udta.name.value",
381                     (const uint8_t*)"Surround", strlen("Surround"));
382             }
383             else {
384                 MP4SetTrackBytesProperty(
385                     m->file, mux_data->track,
386                     "udta.name.value",
387                     (const uint8_t*)(audio->config.out.name),
388                     strlen(audio->config.out.name));
389             }
390         } 
391         else if( audio->config.out.codec == HB_ACODEC_FAAC ||
392                  audio->config.out.codec == HB_ACODEC_CA_AAC ) 
393         {
394             mux_data->track = MP4AddAudioTrack(
395                 m->file,
396                 audio->config.out.samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
397
398             /* Tune track chunk duration */
399             MP4TuneTrackDurationPerChunk( m, mux_data->track );
400
401             if (audio->config.out.name == NULL) {
402                 MP4SetTrackBytesProperty(
403                     m->file, mux_data->track,
404                     "udta.name.value",
405                     (const uint8_t*)"Stereo", strlen("Stereo"));
406             }
407             else {
408                 MP4SetTrackBytesProperty(
409                     m->file, mux_data->track,
410                     "udta.name.value",
411                     (const uint8_t*)(audio->config.out.name),
412                     strlen(audio->config.out.name));
413             }
414
415             MP4SetAudioProfileLevel( m->file, 0x0F );
416             MP4SetTrackESConfiguration(
417                 m->file, mux_data->track,
418                 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
419
420             /* Set the correct number of channels for this track */
421              MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown));
422         } else if( audio->config.out.codec == HB_ACODEC_LAME ) {
423             mux_data->track = MP4AddAudioTrack(
424                 m->file,
425                 audio->config.out.samplerate, 1152, MP4_MPEG2_AUDIO_TYPE );
426
427             /* Tune track chunk duration */
428             MP4TuneTrackDurationPerChunk( m, mux_data->track );
429
430             if (audio->config.out.name == NULL) {
431                 MP4SetTrackBytesProperty(
432                     m->file, mux_data->track,
433                     "udta.name.value",
434                     (const uint8_t*)"Stereo", strlen("Stereo"));
435             }
436             else {
437                 MP4SetTrackBytesProperty(
438                     m->file, mux_data->track,
439                     "udta.name.value",
440                     (const uint8_t*)(audio->config.out.name),
441                     strlen(audio->config.out.name));
442             }
443
444             MP4SetAudioProfileLevel( m->file, 0x0F );
445
446             /* Set the correct number of channels for this track */
447              MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown));
448         }
449
450         /* Set the language for this track */
451         MP4SetTrackLanguage(m->file, mux_data->track, audio->config.lang.iso639_2);
452
453         if( hb_list_count( title->list_audio ) > 1 )
454         {
455             /* Set the audio track alternate group */
456             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
457         }
458
459         if (i == 0) {
460             /* Enable the first audio track */
461             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
462         }
463         else
464             /* Disable the other audio tracks so QuickTime doesn't play
465                them all at once. */
466         {
467             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
468             hb_deep_log( 2, "muxmp4: disabled extra audio track %u", MP4FindTrackIndex( m->file, mux_data->track ));
469         }
470
471     }
472
473     // Quicktime requires that at least one subtitle is enabled,
474     // else it doesn't show any of the subtitles.
475     // So check to see if any of the subtitles are flagged to be
476     // the defualt.  The default will the the enabled track, else
477     // enable the first track.
478     subtitle_default = 0;
479     for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
480     {
481         hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i );
482
483         if( subtitle && subtitle->format == TEXTSUB && 
484             subtitle->config.dest == PASSTHRUSUB )
485         {
486             if ( subtitle->config.default_track )
487                 subtitle_default = 1;
488         }
489     }
490     for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
491     {
492         hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i );
493
494         if( subtitle && subtitle->format == TEXTSUB && 
495             subtitle->config.dest == PASSTHRUSUB )
496         {
497             uint64_t width, height = 60;
498             if( job->anamorphic.mode )
499                 width = job->width * ( (float) job->anamorphic.par_width / job->anamorphic.par_height );
500             else
501                 width = job->width;
502
503             mux_data = calloc(1, sizeof( hb_mux_data_t ) );
504             subtitle->mux_data = mux_data;
505             mux_data->subtitle = 1;
506             mux_data->sub_format = subtitle->format;
507             mux_data->track = MP4AddSubtitleTrack( m->file, 90000, width, height );
508
509             MP4SetTrackLanguage(m->file, mux_data->track, subtitle->iso639_2);
510
511             /* Tune track chunk duration */
512             MP4TuneTrackDurationPerChunk( m, mux_data->track );
513
514             const uint8_t textColor[4] = { 255,255,255,255 };
515
516             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 2);
517
518             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.dataReferenceIndex", 1);
519             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.horizontalJustification", 1);
520             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.verticalJustification", 255);
521
522             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.bgColorAlpha", 255);
523
524             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.defTextBoxBottom", height);
525             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.defTextBoxRight", width);
526
527             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontID", 1);
528             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontSize", 24);
529
530             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorRed", textColor[0]);
531             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorGreen", textColor[1]);
532             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorBlue", textColor[2]);
533             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorAlpha", textColor[3]);
534             
535             /* translate the track */
536             uint8_t* val;
537             uint8_t nval[36];
538             uint32_t *ptr32 = (uint32_t*) nval;
539             uint32_t size;
540
541             MP4GetTrackBytesProperty(m->file, mux_data->track, "tkhd.matrix", &val, &size);
542             memcpy(nval, val, size);
543
544             const uint32_t ytranslation = (job->height - height) * 0x10000;
545                 
546 #ifdef WORDS_BIGENDIAN
547             ptr32[7] = ytranslation;
548 #else
549             /* we need to switch the endianness, as the file format expects big endian */
550             ptr32[7] = ((ytranslation & 0x000000FF) << 24) + ((ytranslation & 0x0000FF00) << 8) + 
551                             ((ytranslation & 0x00FF0000) >> 8) + ((ytranslation & 0xFF000000) >> 24);
552 #endif
553
554             MP4SetTrackBytesProperty(m->file, mux_data->track, "tkhd.matrix", nval, size);  
555             if ( !subtitle_default || subtitle->config.default_track ) {
556                 /* Enable the default subtitle track */
557                 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
558                 subtitle_default = 1;
559             }
560             else
561             {
562                 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
563             }
564         }
565         else if( subtitle && subtitle->format == PICTURESUB && 
566             subtitle->config.dest == PASSTHRUSUB )
567         {
568             mux_data = calloc(1, sizeof( hb_mux_data_t ) );
569             subtitle->mux_data = mux_data;
570             mux_data->subtitle = 1;
571             mux_data->sub_format = subtitle->format;
572
573             mux_data->track = MP4AddSubpicTrack( m->file, 90000, subtitle->width, subtitle->height );
574
575             MP4SetTrackLanguage(m->file, mux_data->track, subtitle->iso639_2);
576
577             /* Tune track chunk duration */
578             MP4TuneTrackDurationPerChunk( m, mux_data->track );
579             uint8_t palette[16][4];
580             int ii;
581             for ( ii = 0; ii < 16; ii++ )
582             {
583                 palette[ii][0] = 0;
584                 palette[ii][1] = (subtitle->palette[ii] >> 16) & 0xff;
585                 palette[ii][2] = (subtitle->palette[ii] >> 8) & 0xff;
586                 palette[ii][3] = (subtitle->palette[ii]) & 0xff;
587             }
588             if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
589                     (uint8_t*)palette, 16 * 4 )))
590             {
591                 hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
592                 *job->die = 1;
593                 return 0;
594             }
595             if ( !subtitle_default || subtitle->config.default_track ) {
596                 /* Enable the default subtitle track */
597                 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
598                 subtitle_default = 1;
599             }
600             else
601             {
602                 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
603             }
604         }
605     }
606
607     if (job->chapter_markers)
608     {
609         /* add a text track for the chapters. We add the 'chap' atom to track
610            one which is usually the video track & should never be disabled.
611            The Quicktime spec says it doesn't matter which media track the
612            chap atom is on but it has to be an enabled track. */
613         MP4TrackId textTrack;
614         textTrack = MP4AddChapterTextTrack(m->file, 1, 0);
615
616         m->chapter_track = textTrack;
617         m->chapter_duration = 0;
618         m->current_chapter = job->chapter_start;
619     }
620
621     /* Add encoded-by metadata listing version and build date */
622     char *tool_string;
623     tool_string = (char *)malloc(80);
624     snprintf( tool_string, 80, "HandBrake %s %i", HB_PROJECT_VERSION, HB_PROJECT_BUILD);
625
626     /* allocate,fetch,populate,store,free tags structure */
627     const MP4Tags* tags;
628     tags = MP4TagsAlloc();
629     MP4TagsFetch( tags, m->file );
630     MP4TagsSetEncodingTool( tags, tool_string );
631     MP4TagsStore( tags, m->file );
632     MP4TagsFree( tags );
633
634     free(tool_string);
635
636     return 0;
637 }
638
639 typedef struct stylerecord_s {
640     enum style_s {ITALIC, BOLD, UNDERLINE} style;
641     uint16_t start;
642     uint16_t stop;
643     struct stylerecord_s *next;
644 } stylerecord;
645
646 static void hb_makestylerecord( stylerecord **stack, 
647                                 enum style_s style, int start )
648 {
649     stylerecord *record = calloc( sizeof( stylerecord ), 1 );
650
651     if( record ) 
652     {
653         record->style = style;
654         record->start = start;
655         record->next = *stack;
656         *stack = record;
657     }
658 }
659
660 static void hb_makestyleatom( stylerecord *record, uint8_t *style)
661 {
662     uint8_t face = 1;
663     hb_deep_log(3, "Made style '%s' from %d to %d", 
664            record->style == ITALIC ? "Italic" : record->style == BOLD ? "Bold" : "Underline", record->start, record->stop);
665     
666     switch( record->style )
667     {
668     case ITALIC:
669         face = 2;
670         break;
671     case BOLD:
672         face = 1;
673         break;
674     case UNDERLINE:
675         face = 4;
676         break;
677     default:
678         face = 2;
679         break;
680     }
681
682     style[0] = (record->start >> 8) & 0xff; // startChar
683     style[1] = record->start & 0xff;
684     style[2] = (record->stop >> 8) & 0xff;   // endChar
685     style[3] = record->stop & 0xff;
686     style[4] = (1 >> 8) & 0xff;    // font-ID
687     style[5] = 1 & 0xff;
688     style[6] = face;   // face-style-flags: 1 bold; 2 italic; 4 underline
689     style[7] = 24;      // font-size
690     style[8] = 255;     // r
691     style[9] = 255;     // g
692     style[10] = 255;    // b
693     style[11] = 255;    // a
694  
695 }
696
697 /*
698  * Copy the input to output removing markup and adding markup to the style
699  * atom where appropriate.
700  */
701 static void hb_muxmp4_process_subtitle_style( uint8_t *input,
702                                               uint8_t *output,
703                                               uint8_t *style, uint16_t *stylesize )
704 {
705     uint8_t *reader = input;
706     uint8_t *writer = output;
707     uint8_t stylecount = 0;
708     uint16_t utf8_count = 0;         // utf8 count from start of subtitle
709     stylerecord *stylestack = NULL;
710     stylerecord *oldrecord = NULL;
711     
712     while(*reader != '\0') {
713         if( ( *reader & 0xc0 ) == 0x80 ) 
714         {
715             /*
716              * Track the utf8_count when doing markup so that we get the tx3g stops
717              * based on UTF8 chr counts rather than bytes.
718              */
719             utf8_count++;
720             hb_deep_log( 3, "MuxMP4: Counted %d UTF-8 chrs within subtitle so far", 
721                              utf8_count);
722         }
723         if (*reader == '<') {
724             /*
725              * possible markup, peek at the next chr
726              */
727             switch(*(reader+1)) {
728             case 'i':
729                 if (*(reader+2) == '>') {
730                     reader += 3;
731                     hb_makestylerecord(&stylestack, ITALIC, (writer - output - utf8_count));
732                 } else {
733                     *writer++ = *reader++;
734                 }
735                 break;
736             case 'b':
737                 if (*(reader+2) == '>') {
738                     reader += 3; 
739                     hb_makestylerecord(&stylestack, BOLD, (writer - output - utf8_count));
740                 } else {
741                     *writer++ = *reader++;  
742                 }
743                 break;
744             case 'u': 
745                 if (*(reader+2) == '>') {
746                     reader += 3;
747                     hb_makestylerecord(&stylestack, UNDERLINE, (writer - output - utf8_count));
748                 } else {
749                     *writer++ = *reader++;
750                 }
751                 break;
752             case '/':
753                 switch(*(reader+2)) {
754                 case 'i':
755                     if (*(reader+3) == '>') {
756                         /*
757                          * Check whether we then immediately start more markup of the same type, if so then
758                          * lets not close it now and instead continue this markup.
759                          */
760                         if ((*(reader+4) && *(reader+4) == '<') &&
761                             (*(reader+5) && *(reader+5) == 'i') &&
762                             (*(reader+6) && *(reader+6) == '>')) {
763                             /*
764                              * Opening italics right after, so don't close off these italics.
765                              */
766                             hb_deep_log(3, "Joining two sets of italics");
767                             reader += (4 + 3);
768                             continue;
769                         }
770
771
772                         if ((*(reader+4) && *(reader+4) == ' ') && 
773                             (*(reader+5) && *(reader+5) == '<') &&
774                             (*(reader+6) && *(reader+6) == 'i') &&
775                             (*(reader+7) && *(reader+7) == '>')) {
776                             /*
777                              * Opening italics right after, so don't close off these italics.
778                              */
779                             hb_deep_log(3, "Joining two sets of italics (plus space)");
780                             reader += (4 + 4);
781                             *writer++ = ' ';
782                             continue;
783                         }
784                         if (stylestack && stylestack->style == ITALIC) {
785                             uint8_t style_record[12];
786                             stylestack->stop = writer - output - utf8_count;
787                             hb_makestyleatom(stylestack, style_record);
788
789                             memcpy(style + 10 + (12 * stylecount), style_record, 12);
790                             stylecount++;
791
792                             oldrecord = stylestack;
793                             stylestack = stylestack->next;
794                             free(oldrecord);
795                         } else {
796                             hb_error("Mismatched Subtitle markup '%s'", input);
797                         }
798                         reader += 4;
799                     } else {
800                         *writer++ = *reader++;
801                     }
802                     break;
803                 case 'b':
804                     if (*(reader+3) == '>') {
805                         if (stylestack && stylestack->style == BOLD) {
806                             uint8_t style_record[12];
807                             stylestack->stop = writer - output - utf8_count;
808                             hb_makestyleatom(stylestack, style_record);
809
810                             memcpy(style + 10 + (12 * stylecount), style_record, 12);
811                             stylecount++;
812                             oldrecord = stylestack;
813                             stylestack = stylestack->next;
814                             free(oldrecord);
815                         } else {
816                             hb_error("Mismatched Subtitle markup '%s'", input);
817                         }
818
819                         reader += 4;
820                     } else {
821                         *writer++ = *reader++;
822                     }
823                     break;
824                 case 'u': 
825                     if (*(reader+3) == '>') {
826                         if (stylestack && stylestack->style == UNDERLINE) {
827                             uint8_t style_record[12];
828                             stylestack->stop = writer - output - utf8_count;
829                             hb_makestyleatom(stylestack, style_record);
830
831                             memcpy(style + 10 + (12 * stylecount), style_record, 12);
832                             stylecount++;
833
834                             oldrecord = stylestack;
835                             stylestack = stylestack->next;
836                             free(oldrecord);
837                         } else {
838                             hb_error("Mismatched Subtitle markup '%s'", input);
839                         }
840                         reader += 4;
841                     } else {
842                         *writer++ = *reader++;
843                     }
844                     break;
845                 default:
846                     *writer++ = *reader++;
847                     break;
848                 }
849                 break;
850             default:
851                 *writer++ = *reader++;
852                 break;
853             }
854         } else {
855             *writer++ = *reader++;
856         }
857     }
858     *writer = '\0';
859
860     if( stylecount )
861     {
862         *stylesize = 10 + ( stylecount * 12 );
863
864         memcpy( style + 4, "styl", 4);
865
866         style[0] = 0;
867         style[1] = 0;
868         style[2] = (*stylesize >> 8) & 0xff;
869         style[3] = *stylesize & 0xff;
870         style[8] = (stylecount >> 8) & 0xff;
871         style[9] = stylecount & 0xff;
872
873     }
874
875 }
876
877 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
878                    hb_buffer_t * buf )
879 {
880     hb_job_t * job = m->job;
881     int64_t duration;
882     int64_t offset = 0;
883     hb_buffer_t *tmp;
884
885     if( mux_data == job->mux_data )
886     {
887         /* Video */
888
889         if( job->vcodec == HB_VCODEC_X264 )
890         {
891             if ( buf && buf->start < buf->renderOffset )
892             {
893                 hb_log("MP4Mux: PTS %"PRId64" < DTS %"PRId64,
894                        buf->start, buf->renderOffset );
895                 buf->renderOffset = buf->start;
896             }
897         }
898
899         // We delay muxing video by one frame so that we can calculate
900         // the dts to dts duration of the frames.
901         tmp = buf;
902         buf = m->delay_buf;
903         m->delay_buf = tmp;
904
905         if ( !buf )
906             return 0;
907
908         if( job->vcodec == HB_VCODEC_X264 )
909         {
910             // x264 supplies us with DTS, so offset is PTS - DTS
911             offset = buf->start - buf->renderOffset;
912         }
913
914         /* Add the sample before the new frame.
915            It is important that this be calculated prior to the duration
916            of the new video sample, as we want to sync to right after it.
917            (This is because of how durations for text tracks work in QT) */
918         if( job->chapter_markers && buf->new_chap )
919         {    
920             hb_chapter_t *chapter = NULL;
921
922             // this chapter is postioned by writing out the previous chapter.
923             // the duration of the previous chapter is the duration up to but
924             // not including the current frame minus the duration of all
925             // chapters up to the previous.
926             // The initial and final chapters can be very short (a second or
927             // less) since they're not really chapters but just a placeholder to
928             // insert a cell command. We don't write chapters shorter than 1.5 sec.
929             duration = m->sum_dur - m->chapter_duration + offset;
930             if ( duration >= (90000*3)/2 )
931             {
932                 chapter = hb_list_item( m->job->title->list_chapter,
933                                         buf->new_chap - 2 );
934
935                 MP4AddChapter( m->file,
936                                m->chapter_track,
937                                duration,
938                                (chapter != NULL) ? chapter->title : NULL);
939
940                 m->current_chapter = buf->new_chap;
941                 m->chapter_duration += duration;
942             }
943         }
944
945         if( job->vcodec == HB_VCODEC_X264 )
946         {
947             // x264 supplies us with DTS
948             if ( m->delay_buf )
949             {
950                 duration = m->delay_buf->renderOffset - buf->renderOffset;
951             }
952             else
953             {
954                 duration = buf->stop - m->sum_dur;
955                 // Due to how libx264 generates DTS, it's possible for the
956                 // above calculation to be negative. 
957                 //
958                 // x264 generates DTS by rearranging PTS in this sequence:
959                 // pts0 - delay, pts1 - delay, pts2 - delay, pts1, pts2, pts3...
960                 //
961                 // where delay == pts2.  This guarantees that DTS <= PTS for
962                 // any frame, but also generates this sequence of durations:
963                 // d0 + d1 + d0 + d1 + d2 + d3 ... + d(N-2)
964                 // 
965                 // so the sum up to the last frame is:
966                 // sum_dur = d0 + d1 + d0 + d1 + d2 + d3 ... + d(N-3)
967                 //
968                 // while the original total duration of the video was:
969                 // duration = d0 + d1 + d2 + d3 ... + d(N)
970                 //
971                 // Note that if d0 + d1 != d(N-1) + d(N), the total
972                 // length of the video changes since d(N-1) and d(N) are
973                 // replaced by d0 and d1 in the final duration sum.
974                 //
975                 // To keep the total length of the video the same as the source
976                 // we try to make 
977                 // d(N-2) = duration - sum_dur
978                 //
979                 // But if d0 + d1 >= d(N-1) + d(N), the above calculation
980                 // results in a nagative value and we need to fix it.
981                 if ( duration <= 0 )
982                     duration = 90000. / ((double)job->vrate / (double)job->vrate_base);
983             }
984         }
985         else
986         {
987             // We're getting the frames in decode order but the timestamps are
988             // for presentation so we have to use durations and effectively
989             // compute a DTS.
990             duration = buf->stop - buf->start;
991         }
992
993         if ( duration <= 0 )
994         {
995             /* We got an illegal mp4/h264 duration. This shouldn't
996                be possible and usually indicates a bug in the upstream code.
997                Complain in the hope that someone will go find the bug but
998                try to fix the error so that the file will still be playable. */
999             hb_log("MP4Mux: illegal duration %"PRId64", start %"PRId64","
1000                    "stop %"PRId64", sum_dur %"PRId64,
1001                    duration, buf->start, buf->stop, m->sum_dur );
1002             /* we don't know when the next frame starts so we can't pick a
1003                valid duration for this one. we pick something "short"
1004                (roughly 1/3 of an NTSC frame time) to take time from
1005                the next frame. */
1006             duration = 1000;
1007         }
1008         m->sum_dur += duration;
1009     }
1010     else
1011     {
1012         /* Audio */
1013         duration = MP4_INVALID_DURATION;
1014     }
1015
1016     /* Here's where the sample actually gets muxed. */
1017     if( job->vcodec == HB_VCODEC_X264 && mux_data == job->mux_data )
1018     {
1019         /* Compute dependency flags.
1020          *
1021          * This mechanism is (optionally) used by media players such as QuickTime
1022          * to offer better scrubbing performance. The most influential bits are
1023          * MP4_SDT_HAS_NO_DEPENDENTS and MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED.
1024          *
1025          * Other bits are possible but no example media using such bits have been
1026          * found.
1027          *
1028          * It is acceptable to supply 0-bits for any samples which characteristics
1029          * cannot be positively guaranteed.
1030          */
1031         int sync = 0;
1032         uint32_t dflags = 0;
1033
1034         /* encoding layer signals if frame is referenced by other frames */
1035         if( buf->flags & HB_FRAME_REF )
1036             dflags |= MP4_SDT_HAS_DEPENDENTS;
1037         else
1038             dflags |= MP4_SDT_HAS_NO_DEPENDENTS; /* disposable */
1039
1040         switch( buf->frametype )
1041         {
1042             case HB_FRAME_IDR:
1043                 sync = 1;
1044                 break;
1045             case HB_FRAME_I:
1046                 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
1047                 break;
1048             case HB_FRAME_P:
1049                 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
1050                 break;
1051             case HB_FRAME_BREF:
1052             case HB_FRAME_B:
1053             default:
1054                 break; /* nothing to mark */
1055         }
1056
1057         if( !MP4WriteSampleDependency( m->file,
1058                                        mux_data->track,
1059                                        buf->data,
1060                                        buf->size,
1061                                        duration,
1062                                        offset,
1063                                        sync,
1064                                        dflags ))
1065         {
1066             hb_error("Failed to write to output file, disk full?");
1067             *job->die = 1;
1068         }
1069     }
1070     else if (mux_data->subtitle)
1071     {
1072         if( mux_data->sub_format == TEXTSUB )
1073         {
1074             /* Write an empty sample */
1075             if ( mux_data->sum_dur < buf->start )
1076             {
1077                 uint8_t empty[2] = {0,0};
1078                 if( !MP4WriteSample( m->file,
1079                                     mux_data->track,
1080                                     empty,
1081                                     2,
1082                                     buf->start - mux_data->sum_dur,
1083                                     0,
1084                                     1 ))
1085                 {
1086                     hb_error("Failed to write to output file, disk full?");
1087                     *job->die = 1;
1088                 } 
1089                 mux_data->sum_dur += buf->start - mux_data->sum_dur;
1090             }
1091             uint8_t styleatom[2048];;
1092             uint16_t stylesize = 0;
1093             uint8_t buffer[2048];
1094             uint16_t buffersize = 0;
1095             uint8_t output[2048];
1096
1097             *buffer = '\0';
1098
1099             /*
1100              * Copy the subtitle into buffer stripping markup and creating
1101              * style atoms for them.
1102              */
1103             hb_muxmp4_process_subtitle_style( buf->data,
1104                                               buffer,
1105                                               styleatom, &stylesize );
1106
1107             buffersize = strlen((char*)buffer);
1108
1109             hb_deep_log(3, "MuxMP4:Sub:%fs:%"PRId64":%"PRId64":%"PRId64": %s",
1110                         (float)buf->start / 90000, buf->start, buf->stop, 
1111                         (buf->stop - buf->start), buffer);
1112
1113             /* Write the subtitle sample */
1114             memcpy( output + 2, buffer, buffersize );
1115             memcpy( output + 2 + buffersize, styleatom, stylesize);
1116             output[0] = ( buffersize >> 8 ) & 0xff;
1117             output[1] = buffersize & 0xff;
1118
1119             if( !MP4WriteSample( m->file,
1120                                  mux_data->track,
1121                                  output,
1122                                  buffersize + stylesize + 2,
1123                                  buf->stop - buf->start,
1124                                  0,
1125                                  1 ))
1126             {
1127                 hb_error("Failed to write to output file, disk full?");
1128                 *job->die = 1;
1129             }
1130
1131             mux_data->sum_dur += (buf->stop - buf->start);
1132         }
1133         else if( mux_data->sub_format == PICTURESUB )
1134         {
1135             /* Write an empty sample */
1136             if ( mux_data->sum_dur < buf->start )
1137             {
1138                 uint8_t empty[2] = {0,0};
1139                 if( !MP4WriteSample( m->file,
1140                                     mux_data->track,
1141                                     empty,
1142                                     2,
1143                                     buf->start - mux_data->sum_dur,
1144                                     0,
1145                                     1 ))
1146                 {
1147                     hb_error("Failed to write to output file, disk full?");
1148                     *job->die = 1;
1149                 } 
1150                 mux_data->sum_dur += buf->start - mux_data->sum_dur;
1151             }
1152             if( !MP4WriteSample( m->file,
1153                                  mux_data->track,
1154                                  buf->data,
1155                                  buf->size,
1156                                  buf->stop - buf->start,
1157                                  0,
1158                                  1 ))
1159             {
1160                 hb_error("Failed to write to output file, disk full?");
1161                 *job->die = 1;
1162             }
1163
1164             mux_data->sum_dur += (buf->stop - buf->start);
1165         }
1166     }
1167     else
1168     {
1169         /*
1170          * Audio
1171          */
1172         if( !MP4WriteSample( m->file,
1173                              mux_data->track,
1174                              buf->data,
1175                              buf->size,
1176                              duration,
1177                              offset,
1178                              ( buf->frametype & HB_FRAME_KEY ) != 0 ))
1179         {
1180             hb_error("Failed to write to output file, disk full?");
1181             *job->die = 1;
1182         }
1183     }
1184     hb_buffer_close( &buf );
1185
1186     return 0;
1187 }
1188
1189 static int MP4End( hb_mux_object_t * m )
1190 {
1191     hb_job_t   * job   = m->job;
1192     hb_title_t * title = job->title;
1193
1194     // Flush the delayed frame
1195     if ( m->delay_buf )
1196         MP4Mux( m, job->mux_data, NULL );
1197
1198     /* Write our final chapter marker */
1199     if( m->job->chapter_markers )
1200     {
1201         hb_chapter_t *chapter = NULL;
1202         int64_t duration = m->sum_dur - m->chapter_duration;
1203         /* The final chapter can have a very short duration - if it's less
1204          * than 1.5 seconds just skip it. */
1205         if ( duration >= (90000*3)/2 )
1206         {
1207
1208             chapter = hb_list_item( m->job->title->list_chapter,
1209                                     m->current_chapter - 1 );
1210
1211             MP4AddChapter( m->file,
1212                            m->chapter_track,
1213                            duration,
1214                            (chapter != NULL) ? chapter->title : NULL);
1215         }
1216     }
1217
1218     if ( job->config.h264.init_delay )
1219     {
1220            // Insert track edit to get A/V back in sync.  The edit amount is
1221            // the init_delay.
1222            int64_t edit_amt = job->config.h264.init_delay;
1223            MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt,
1224                            MP4GetTrackDuration(m->file, 1), 0);
1225             if ( m->job->chapter_markers )
1226             {
1227                 // apply same edit to chapter track to keep it in sync with video
1228                 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
1229                                 edit_amt,
1230                                 MP4GetTrackDuration(m->file, m->chapter_track), 0);
1231             }
1232      }
1233
1234     /*
1235      * Write the MP4 iTunes metadata if we have any metadata
1236      */
1237     if( title->metadata )
1238     {
1239         hb_metadata_t *md = title->metadata;
1240         const MP4Tags* tags;
1241
1242         hb_deep_log( 2, "Writing Metadata to output file...");
1243
1244         /* allocate tags structure */
1245         tags = MP4TagsAlloc();
1246         /* fetch data from MP4 file (in case it already has some data) */
1247         MP4TagsFetch( tags, m->file );
1248
1249         /* populate */
1250         if( strlen( md->name ))
1251             MP4TagsSetName( tags, md->name );
1252         if( strlen( md->artist ))
1253             MP4TagsSetArtist( tags, md->artist );
1254         if( strlen( md->composer ))
1255             MP4TagsSetComposer( tags, md->composer );
1256         if( strlen( md->comment ))
1257             MP4TagsSetComments( tags, md->comment );
1258         if( strlen( md->release_date ))
1259             MP4TagsSetReleaseDate( tags, md->release_date );
1260         if( strlen( md->album ))
1261             MP4TagsSetAlbum( tags, md->album );
1262         if( strlen( md->genre ))
1263             MP4TagsSetGenre( tags, md->genre );
1264
1265         if( md->coverart )
1266         {
1267             MP4TagArtwork art;
1268             art.data = md->coverart;
1269             art.size = md->coverart_size;
1270             art.type = MP4_ART_UNDEFINED; // delegate typing to libmp4v2
1271             MP4TagsAddArtwork( tags, &art );
1272         }
1273
1274         /* push data to MP4 file */
1275         MP4TagsStore( tags, m->file );
1276         /* free memory associated with structure */
1277         MP4TagsFree( tags );
1278     }
1279
1280     MP4Close( m->file );
1281
1282     if ( job->mp4_optimize )
1283     {
1284         hb_log( "muxmp4: optimizing file" );
1285         char filename[1024]; memset( filename, 0, 1024 );
1286         snprintf( filename, 1024, "%s.tmp", job->file );
1287         MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
1288         remove( job->file );
1289         rename( filename, job->file );
1290     }
1291
1292     return 0;
1293 }
1294
1295 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
1296 {
1297     hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );
1298     m->init      = MP4Init;
1299     m->mux       = MP4Mux;
1300     m->end       = MP4End;
1301     m->job       = job;
1302     return m;
1303 }
1304