OSDN Git Service

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