OSDN Git Service

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