OSDN Git Service

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