OSDN Git Service

use DTS generated by x264 when computing duration and offset in muxmp4
[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 {
351             mux_data->track = MP4AddAudioTrack(
352                 m->file,
353                 audio->config.out.samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
354
355             /* Tune track chunk duration */
356             MP4TuneTrackDurationPerChunk( m, mux_data->track );
357
358             if (audio->config.out.name == NULL) {
359                 MP4SetTrackBytesProperty(
360                     m->file, mux_data->track,
361                     "udta.name.value",
362                     (const uint8_t*)"Stereo", strlen("Stereo"));
363             }
364             else {
365                 MP4SetTrackBytesProperty(
366                     m->file, mux_data->track,
367                     "udta.name.value",
368                     (const uint8_t*)(audio->config.out.name),
369                     strlen(audio->config.out.name));
370             }
371
372             MP4SetAudioProfileLevel( m->file, 0x0F );
373             MP4SetTrackESConfiguration(
374                 m->file, mux_data->track,
375                 audio->priv.config.aac.bytes, audio->priv.config.aac.length );
376
377             /* Set the correct number of channels for this track */
378              MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown));
379         }
380
381         /* Set the language for this track */
382         MP4SetTrackLanguage(m->file, mux_data->track, audio->config.lang.iso639_2);
383
384         if( hb_list_count( title->list_audio ) > 1 )
385         {
386             /* Set the audio track alternate group */
387             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1);
388         }
389
390         if (i == 0) {
391             /* Enable the first audio track */
392             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
393         }
394         else
395             /* Disable the other audio tracks so QuickTime doesn't play
396                them all at once. */
397         {
398             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
399             hb_deep_log( 2, "muxmp4: disabled extra audio track %u", MP4FindTrackIndex( m->file, mux_data->track ));
400         }
401
402     }
403
404     // Quicktime requires that at least one subtitle is enabled,
405     // else it doesn't show any of the subtitles.
406     // So check to see if any of the subtitles are flagged to be
407     // the defualt.  The default will the the enabled track, else
408     // enable the first track.
409     subtitle_default = 0;
410     for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
411     {
412         hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i );
413
414         if( subtitle && subtitle->format == TEXTSUB && 
415             subtitle->config.dest == PASSTHRUSUB )
416         {
417             if ( subtitle->config.default_track )
418                 subtitle_default = 1;
419         }
420     }
421     for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
422     {
423         hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i );
424
425         if( subtitle && subtitle->format == TEXTSUB && 
426             subtitle->config.dest == PASSTHRUSUB )
427         {
428             uint64_t width, height = 60;
429             if( job->anamorphic.mode )
430                 width = job->width * ( (float) job->anamorphic.par_width / job->anamorphic.par_height );
431             else
432                 width = job->width;
433
434             mux_data = calloc(1, sizeof( hb_mux_data_t ) );
435             subtitle->mux_data = mux_data;
436             mux_data->subtitle = 1;
437             mux_data->sub_format = subtitle->format;
438             mux_data->track = MP4AddSubtitleTrack( m->file, 90000, width, height );
439
440             MP4SetTrackLanguage(m->file, mux_data->track, subtitle->iso639_2);
441
442             /* Tune track chunk duration */
443             MP4TuneTrackDurationPerChunk( m, mux_data->track );
444
445             const uint8_t textColor[4] = { 255,255,255,255 };
446
447             MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 2);
448
449             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.dataReferenceIndex", 1);
450             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.horizontalJustification", 1);
451             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.verticalJustification", 255);
452
453             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.bgColorAlpha", 255);
454
455             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.defTextBoxBottom", height);
456             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.defTextBoxRight", width);
457
458             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontID", 1);
459             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontSize", 24);
460
461             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorRed", textColor[0]);
462             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorGreen", textColor[1]);
463             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorBlue", textColor[2]);
464             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorAlpha", textColor[3]);
465             
466             /* translate the track */
467             uint8_t* val;
468             uint8_t nval[36];
469             uint32_t *ptr32 = (uint32_t*) nval;
470             uint32_t size;
471
472             MP4GetTrackBytesProperty(m->file, mux_data->track, "tkhd.matrix", &val, &size);
473             memcpy(nval, val, size);
474
475             const uint32_t ytranslation = (job->height - height) * 0x10000;
476                 
477 #ifdef WORDS_BIGENDIAN
478             ptr32[7] = ytranslation;
479 #else
480             /* we need to switch the endianness, as the file format expects big endian */
481             ptr32[7] = ((ytranslation & 0x000000FF) << 24) + ((ytranslation & 0x0000FF00) << 8) + 
482                             ((ytranslation & 0x00FF0000) >> 8) + ((ytranslation & 0xFF000000) >> 24);
483 #endif
484
485             MP4SetTrackBytesProperty(m->file, mux_data->track, "tkhd.matrix", nval, size);  
486             if ( !subtitle_default || subtitle->config.default_track ) {
487                 /* Enable the default subtitle track */
488                 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
489                 subtitle_default = 1;
490             }
491             else
492             {
493                 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
494             }
495         }
496     }
497
498     if (job->chapter_markers)
499     {
500         /* add a text track for the chapters. We add the 'chap' atom to track
501            one which is usually the video track & should never be disabled.
502            The Quicktime spec says it doesn't matter which media track the
503            chap atom is on but it has to be an enabled track. */
504         MP4TrackId textTrack;
505         textTrack = MP4AddChapterTextTrack(m->file, 1, 0);
506
507         m->chapter_track = textTrack;
508         m->chapter_duration = 0;
509         m->current_chapter = job->chapter_start;
510     }
511
512     /* Add encoded-by metadata listing version and build date */
513     char *tool_string;
514     tool_string = (char *)malloc(80);
515     snprintf( tool_string, 80, "HandBrake %s %i", HB_PROJECT_VERSION, HB_PROJECT_BUILD);
516
517     /* allocate,fetch,populate,store,free tags structure */
518     const MP4Tags* tags;
519     tags = MP4TagsAlloc();
520     MP4TagsFetch( tags, m->file );
521     MP4TagsSetEncodingTool( tags, tool_string );
522     MP4TagsStore( tags, m->file );
523     MP4TagsFree( tags );
524
525     free(tool_string);
526
527     return 0;
528 }
529
530 typedef struct stylerecord_s {
531     enum style_s {ITALIC, BOLD, UNDERLINE} style;
532     uint16_t start;
533     uint16_t stop;
534     struct stylerecord_s *next;
535 } stylerecord;
536
537 static void hb_makestylerecord( stylerecord **stack, 
538                                 enum style_s style, int start )
539 {
540     stylerecord *record = calloc( sizeof( stylerecord ), 1 );
541
542     if( record ) 
543     {
544         record->style = style;
545         record->start = start;
546         record->next = *stack;
547         *stack = record;
548     }
549 }
550
551 static void hb_makestyleatom( stylerecord *record, uint8_t *style)
552 {
553     uint8_t face = 1;
554     hb_deep_log(3, "Made style '%s' from %d to %d", 
555            record->style == ITALIC ? "Italic" : record->style == BOLD ? "Bold" : "Underline", record->start, record->stop);
556     
557     switch( record->style )
558     {
559     case ITALIC:
560         face = 2;
561         break;
562     case BOLD:
563         face = 1;
564         break;
565     case UNDERLINE:
566         face = 4;
567         break;
568     default:
569         face = 2;
570         break;
571     }
572
573     style[0] = (record->start >> 8) & 0xff; // startChar
574     style[1] = record->start & 0xff;
575     style[2] = (record->stop >> 8) & 0xff;   // endChar
576     style[3] = record->stop & 0xff;
577     style[4] = (1 >> 8) & 0xff;    // font-ID
578     style[5] = 1 & 0xff;
579     style[6] = face;   // face-style-flags: 1 bold; 2 italic; 4 underline
580     style[7] = 24;      // font-size
581     style[8] = 255;     // r
582     style[9] = 255;     // g
583     style[10] = 255;    // b
584     style[11] = 255;    // a
585  
586 }
587
588 /*
589  * Copy the input to output removing markup and adding markup to the style
590  * atom where appropriate.
591  */
592 static void hb_muxmp4_process_subtitle_style( uint8_t *input,
593                                               uint8_t *output,
594                                               uint8_t *style, uint16_t *stylesize )
595 {
596     uint8_t *reader = input;
597     uint8_t *writer = output;
598     uint8_t stylecount = 0;
599     uint16_t utf8_count = 0;         // utf8 count from start of subtitle
600     stylerecord *stylestack = NULL;
601     stylerecord *oldrecord = NULL;
602     
603     while(*reader != '\0') {
604         if( ( *reader & 0xc0 ) == 0x80 ) 
605         {
606             /*
607              * Track the utf8_count when doing markup so that we get the tx3g stops
608              * based on UTF8 chr counts rather than bytes.
609              */
610             utf8_count++;
611             hb_deep_log( 3, "MuxMP4: Counted %d UTF-8 chrs within subtitle so far", 
612                              utf8_count);
613         }
614         if (*reader == '<') {
615             /*
616              * possible markup, peek at the next chr
617              */
618             switch(*(reader+1)) {
619             case 'i':
620                 if (*(reader+2) == '>') {
621                     reader += 3;
622                     hb_makestylerecord(&stylestack, ITALIC, (writer - output - utf8_count));
623                 } else {
624                     *writer++ = *reader++;
625                 }
626                 break;
627             case 'b':
628                 if (*(reader+2) == '>') {
629                     reader += 3; 
630                     hb_makestylerecord(&stylestack, BOLD, (writer - output - utf8_count));
631                 } else {
632                     *writer++ = *reader++;  
633                 }
634                 break;
635             case 'u': 
636                 if (*(reader+2) == '>') {
637                     reader += 3;
638                     hb_makestylerecord(&stylestack, UNDERLINE, (writer - output - utf8_count));
639                 } else {
640                     *writer++ = *reader++;
641                 }
642                 break;
643             case '/':
644                 switch(*(reader+2)) {
645                 case 'i':
646                     if (*(reader+3) == '>') {
647                         /*
648                          * Check whether we then immediately start more markup of the same type, if so then
649                          * lets not close it now and instead continue this markup.
650                          */
651                         if ((*(reader+4) && *(reader+4) == '<') &&
652                             (*(reader+5) && *(reader+5) == 'i') &&
653                             (*(reader+6) && *(reader+6) == '>')) {
654                             /*
655                              * Opening italics right after, so don't close off these italics.
656                              */
657                             hb_deep_log(3, "Joining two sets of italics");
658                             reader += (4 + 3);
659                             continue;
660                         }
661
662
663                         if ((*(reader+4) && *(reader+4) == ' ') && 
664                             (*(reader+5) && *(reader+5) == '<') &&
665                             (*(reader+6) && *(reader+6) == 'i') &&
666                             (*(reader+7) && *(reader+7) == '>')) {
667                             /*
668                              * Opening italics right after, so don't close off these italics.
669                              */
670                             hb_deep_log(3, "Joining two sets of italics (plus space)");
671                             reader += (4 + 4);
672                             *writer++ = ' ';
673                             continue;
674                         }
675                         if (stylestack && stylestack->style == ITALIC) {
676                             uint8_t style_record[12];
677                             stylestack->stop = writer - output - utf8_count;
678                             hb_makestyleatom(stylestack, style_record);
679
680                             memcpy(style + 10 + (12 * stylecount), style_record, 12);
681                             stylecount++;
682
683                             oldrecord = stylestack;
684                             stylestack = stylestack->next;
685                             free(oldrecord);
686                         } else {
687                             hb_error("Mismatched Subtitle markup '%s'", input);
688                         }
689                         reader += 4;
690                     } else {
691                         *writer++ = *reader++;
692                     }
693                     break;
694                 case 'b':
695                     if (*(reader+3) == '>') {
696                         if (stylestack && stylestack->style == BOLD) {
697                             uint8_t style_record[12];
698                             stylestack->stop = writer - output - utf8_count;
699                             hb_makestyleatom(stylestack, style_record);
700
701                             memcpy(style + 10 + (12 * stylecount), style_record, 12);
702                             stylecount++;
703                             oldrecord = stylestack;
704                             stylestack = stylestack->next;
705                             free(oldrecord);
706                         } else {
707                             hb_error("Mismatched Subtitle markup '%s'", input);
708                         }
709
710                         reader += 4;
711                     } else {
712                         *writer++ = *reader++;
713                     }
714                     break;
715                 case 'u': 
716                     if (*(reader+3) == '>') {
717                         if (stylestack && stylestack->style == UNDERLINE) {
718                             uint8_t style_record[12];
719                             stylestack->stop = writer - output - utf8_count;
720                             hb_makestyleatom(stylestack, style_record);
721
722                             memcpy(style + 10 + (12 * stylecount), style_record, 12);
723                             stylecount++;
724
725                             oldrecord = stylestack;
726                             stylestack = stylestack->next;
727                             free(oldrecord);
728                         } else {
729                             hb_error("Mismatched Subtitle markup '%s'", input);
730                         }
731                         reader += 4;
732                     } else {
733                         *writer++ = *reader++;
734                     }
735                     break;
736                 default:
737                     *writer++ = *reader++;
738                     break;
739                 }
740                 break;
741             default:
742                 *writer++ = *reader++;
743                 break;
744             }
745         } else {
746             *writer++ = *reader++;
747         }
748     }
749     *writer = '\0';
750
751     if( stylecount )
752     {
753         *stylesize = 10 + ( stylecount * 12 );
754
755         memcpy( style + 4, "styl", 4);
756
757         style[0] = 0;
758         style[1] = 0;
759         style[2] = (*stylesize >> 8) & 0xff;
760         style[3] = *stylesize & 0xff;
761         style[8] = (stylecount >> 8) & 0xff;
762         style[9] = stylecount & 0xff;
763
764     }
765
766 }
767
768 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
769                    hb_buffer_t * buf )
770 {
771     hb_job_t * job = m->job;
772     int64_t duration;
773     int64_t offset = 0;
774     hb_buffer_t *tmp;
775
776     if( mux_data == job->mux_data )
777     {
778         /* Video */
779
780         if( job->vcodec == HB_VCODEC_X264 )
781         {
782             if ( buf && buf->start < buf->renderOffset )
783             {
784                 hb_log("MP4Mux: PTS %"PRId64" < DTS %"PRId64,
785                        buf->start, buf->renderOffset );
786                 buf->renderOffset = buf->start;
787             }
788         }
789
790         // We delay muxing video by one frame so that we can calculate
791         // the dts to dts duration of the frames.
792         tmp = buf;
793         buf = m->delay_buf;
794         m->delay_buf = tmp;
795
796         if ( !buf )
797             return 0;
798
799         if( job->vcodec == HB_VCODEC_X264 )
800         {
801             // x264 supplies us with DTS, so offset is PTS - DTS
802             offset = buf->start - buf->renderOffset;
803         }
804
805         /* Add the sample before the new frame.
806            It is important that this be calculated prior to the duration
807            of the new video sample, as we want to sync to right after it.
808            (This is because of how durations for text tracks work in QT) */
809         if( job->chapter_markers && buf->new_chap )
810         {    
811             hb_chapter_t *chapter = NULL;
812
813             // this chapter is postioned by writing out the previous chapter.
814             // the duration of the previous chapter is the duration up to but
815             // not including the current frame minus the duration of all
816             // chapters up to the previous.
817             // The initial and final chapters can be very short (a second or
818             // less) since they're not really chapters but just a placeholder to
819             // insert a cell command. We don't write chapters shorter than 1.5 sec.
820             duration = m->sum_dur - m->chapter_duration + offset;
821             if ( duration >= (90000*3)/2 )
822             {
823                 chapter = hb_list_item( m->job->title->list_chapter,
824                                         buf->new_chap - 2 );
825
826                 MP4AddChapter( m->file,
827                                m->chapter_track,
828                                duration,
829                                (chapter != NULL) ? chapter->title : NULL);
830
831                 m->current_chapter = buf->new_chap;
832                 m->chapter_duration += duration;
833             }
834         }
835
836         if( job->vcodec == HB_VCODEC_X264 )
837         {
838             // x264 supplies us with DTS
839             if ( m->delay_buf )
840             {
841                 duration = m->delay_buf->renderOffset - buf->renderOffset;
842             }
843             else
844             {
845                 duration = buf->stop - m->sum_dur;
846                 // Due to how libx264 generates DTS, it's possible for the
847                 // above calculation to be negative. 
848                 //
849                 // x264 generates DTS by rearranging PTS in this sequence:
850                 // pts0 - delay, pts1 - delay, pts2 - delay, pts1, pts2, pts3...
851                 //
852                 // where delay == pts2.  This guarantees that DTS <= PTS for
853                 // any frame, but also generates this sequence of durations:
854                 // d0 + d1 + d0 + d1 + d2 + d3 ... + d(N-2)
855                 // 
856                 // so the sum up to the last frame is:
857                 // sum_dur = d0 + d1 + d0 + d1 + d2 + d3 ... + d(N-3)
858                 //
859                 // while the original total duration of the video was:
860                 // duration = d0 + d1 + d2 + d3 ... + d(N)
861                 //
862                 // Note that if d0 + d1 != d(N-1) + d(N), the total
863                 // length of the video changes since d(N-1) and d(N) are
864                 // replaced by d0 and d1 in the final duration sum.
865                 //
866                 // To keep the total length of the video the same as the source
867                 // we try to make 
868                 // d(N-2) = duration - sum_dur
869                 //
870                 // But if d0 + d1 >= d(N-1) + d(N), the above calculation
871                 // results in a nagative value and we need to fix it.
872                 if ( duration <= 0 )
873                     duration = 90000. / ((double)job->vrate / (double)job->vrate_base);
874             }
875         }
876         else
877         {
878             // We're getting the frames in decode order but the timestamps are
879             // for presentation so we have to use durations and effectively
880             // compute a DTS.
881             duration = buf->stop - buf->start;
882         }
883
884         if ( duration <= 0 )
885         {
886             /* We got an illegal mp4/h264 duration. This shouldn't
887                be possible and usually indicates a bug in the upstream code.
888                Complain in the hope that someone will go find the bug but
889                try to fix the error so that the file will still be playable. */
890             hb_log("MP4Mux: illegal duration %"PRId64", start %"PRId64","
891                    "stop %"PRId64", sum_dur %"PRId64,
892                    duration, buf->start, buf->stop, m->sum_dur );
893             /* we don't know when the next frame starts so we can't pick a
894                valid duration for this one. we pick something "short"
895                (roughly 1/3 of an NTSC frame time) to take time from
896                the next frame. */
897             duration = 1000;
898         }
899         m->sum_dur += duration;
900     }
901     else
902     {
903         /* Audio */
904         duration = MP4_INVALID_DURATION;
905     }
906
907     /* Here's where the sample actually gets muxed. */
908     if( job->vcodec == HB_VCODEC_X264 && mux_data == job->mux_data )
909     {
910         /* Compute dependency flags.
911          *
912          * This mechanism is (optionally) used by media players such as QuickTime
913          * to offer better scrubbing performance. The most influential bits are
914          * MP4_SDT_HAS_NO_DEPENDENTS and MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED.
915          *
916          * Other bits are possible but no example media using such bits have been
917          * found.
918          *
919          * It is acceptable to supply 0-bits for any samples which characteristics
920          * cannot be positively guaranteed.
921          */
922         int sync = 0;
923         uint32_t dflags = 0;
924
925         /* encoding layer signals if frame is referenced by other frames */
926         if( buf->flags & HB_FRAME_REF )
927             dflags |= MP4_SDT_HAS_DEPENDENTS;
928         else
929             dflags |= MP4_SDT_HAS_NO_DEPENDENTS; /* disposable */
930
931         switch( buf->frametype )
932         {
933             case HB_FRAME_IDR:
934                 sync = 1;
935                 break;
936             case HB_FRAME_I:
937                 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
938                 break;
939             case HB_FRAME_P:
940                 dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED;
941                 break;
942             case HB_FRAME_BREF:
943             case HB_FRAME_B:
944             default:
945                 break; /* nothing to mark */
946         }
947
948         if( !MP4WriteSampleDependency( m->file,
949                                        mux_data->track,
950                                        buf->data,
951                                        buf->size,
952                                        duration,
953                                        offset,
954                                        sync,
955                                        dflags ))
956         {
957             hb_error("Failed to write to output file, disk full?");
958             *job->die = 1;
959         }
960     }
961     else if (mux_data->subtitle)
962     {
963         if( mux_data->sub_format == TEXTSUB )
964         {
965             /* Write an empty sample */
966             if ( mux_data->sum_dur < buf->start )
967             {
968                 uint8_t empty[2] = {0,0};
969                 if( !MP4WriteSample( m->file,
970                                     mux_data->track,
971                                     empty,
972                                     2,
973                                     buf->start - mux_data->sum_dur,
974                                     0,
975                                     1 ))
976                 {
977                     hb_error("Failed to write to output file, disk full?");
978                     *job->die = 1;
979                 } 
980                 mux_data->sum_dur += buf->start - mux_data->sum_dur;
981             }
982             uint8_t styleatom[2048];;
983             uint16_t stylesize = 0;
984             uint8_t buffer[2048];
985             uint16_t buffersize = 0;
986             uint8_t output[2048];
987
988             *buffer = '\0';
989
990             /*
991              * Copy the subtitle into buffer stripping markup and creating
992              * style atoms for them.
993              */
994             hb_muxmp4_process_subtitle_style( buf->data,
995                                               buffer,
996                                               styleatom, &stylesize );
997
998             buffersize = strlen((char*)buffer);
999
1000             hb_deep_log(3, "MuxMP4:Sub:%fs:%"PRId64":%"PRId64":%"PRId64": %s",
1001                         (float)buf->start / 90000, buf->start, buf->stop, 
1002                         (buf->stop - buf->start), buffer);
1003
1004             /* Write the subtitle sample */
1005             memcpy( output + 2, buffer, buffersize );
1006             memcpy( output + 2 + buffersize, styleatom, stylesize);
1007             output[0] = ( buffersize >> 8 ) & 0xff;
1008             output[1] = buffersize & 0xff;
1009
1010             if( !MP4WriteSample( m->file,
1011                                  mux_data->track,
1012                                  output,
1013                                  buffersize + stylesize + 2,
1014                                  buf->stop - buf->start,
1015                                  0,
1016                                  1 ))
1017             {
1018                 hb_error("Failed to write to output file, disk full?");
1019                 *job->die = 1;
1020             }
1021
1022             mux_data->sum_dur += (buf->stop - buf->start);
1023         }
1024     }
1025     else
1026     {
1027         /*
1028          * Audio
1029          */
1030         if( !MP4WriteSample( m->file,
1031                              mux_data->track,
1032                              buf->data,
1033                              buf->size,
1034                              duration,
1035                              offset,
1036                              ( buf->frametype & HB_FRAME_KEY ) != 0 ))
1037         {
1038             hb_error("Failed to write to output file, disk full?");
1039             *job->die = 1;
1040         }
1041     }
1042     hb_buffer_close( &buf );
1043
1044     return 0;
1045 }
1046
1047 static int MP4End( hb_mux_object_t * m )
1048 {
1049     hb_job_t   * job   = m->job;
1050     hb_title_t * title = job->title;
1051
1052     // Flush the delayed frame
1053     if ( m->delay_buf )
1054         MP4Mux( m, job->mux_data, NULL );
1055
1056     /* Write our final chapter marker */
1057     if( m->job->chapter_markers )
1058     {
1059         hb_chapter_t *chapter = NULL;
1060         int64_t duration = m->sum_dur - m->chapter_duration;
1061         /* The final chapter can have a very short duration - if it's less
1062          * than 1.5 seconds just skip it. */
1063         if ( duration >= (90000*3)/2 )
1064         {
1065
1066             chapter = hb_list_item( m->job->title->list_chapter,
1067                                     m->current_chapter - 1 );
1068
1069             MP4AddChapter( m->file,
1070                            m->chapter_track,
1071                            duration,
1072                            (chapter != NULL) ? chapter->title : NULL);
1073         }
1074     }
1075
1076     if ( job->config.h264.init_delay )
1077     {
1078            // Insert track edit to get A/V back in sync.  The edit amount is
1079            // the init_delay.
1080            int64_t edit_amt = job->config.h264.init_delay;
1081            MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt,
1082                            MP4GetTrackDuration(m->file, 1), 0);
1083             if ( m->job->chapter_markers )
1084             {
1085                 // apply same edit to chapter track to keep it in sync with video
1086                 MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID,
1087                                 edit_amt,
1088                                 MP4GetTrackDuration(m->file, m->chapter_track), 0);
1089             }
1090      }
1091
1092     /*
1093      * Write the MP4 iTunes metadata if we have any metadata
1094      */
1095     if( title->metadata )
1096     {
1097         hb_metadata_t *md = title->metadata;
1098         const MP4Tags* tags;
1099
1100         hb_deep_log( 2, "Writing Metadata to output file...");
1101
1102         /* allocate tags structure */
1103         tags = MP4TagsAlloc();
1104         /* fetch data from MP4 file (in case it already has some data) */
1105         MP4TagsFetch( tags, m->file );
1106
1107         /* populate */
1108         if( strlen( md->name ))
1109             MP4TagsSetName( tags, md->name );
1110         if( strlen( md->artist ))
1111             MP4TagsSetArtist( tags, md->artist );
1112         if( strlen( md->composer ))
1113             MP4TagsSetComposer( tags, md->composer );
1114         if( strlen( md->comment ))
1115             MP4TagsSetComments( tags, md->comment );
1116         if( strlen( md->release_date ))
1117             MP4TagsSetReleaseDate( tags, md->release_date );
1118         if( strlen( md->album ))
1119             MP4TagsSetAlbum( tags, md->album );
1120         if( strlen( md->genre ))
1121             MP4TagsSetGenre( tags, md->genre );
1122
1123         if( md->coverart )
1124         {
1125             MP4TagArtwork art;
1126             art.data = md->coverart;
1127             art.size = md->coverart_size;
1128             art.type = MP4_ART_UNDEFINED; // delegate typing to libmp4v2
1129             MP4TagsAddArtwork( tags, &art );
1130         }
1131
1132         /* push data to MP4 file */
1133         MP4TagsStore( tags, m->file );
1134         /* free memory associated with structure */
1135         MP4TagsFree( tags );
1136     }
1137
1138     MP4Close( m->file );
1139
1140     if ( job->mp4_optimize )
1141     {
1142         hb_log( "muxmp4: optimizing file" );
1143         char filename[1024]; memset( filename, 0, 1024 );
1144         snprintf( filename, 1024, "%s.tmp", job->file );
1145         MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
1146         remove( job->file );
1147         rename( filename, job->file );
1148     }
1149
1150     return 0;
1151 }
1152
1153 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
1154 {
1155     hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );
1156     m->init      = MP4Init;
1157     m->mux       = MP4Mux;
1158     m->end       = MP4End;
1159     m->job       = job;
1160     return m;
1161 }
1162