OSDN Git Service

Merge the 5.1 branch into the trunk.
[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
15 struct hb_mux_object_s
16 {
17     HB_MUX_COMMON;
18
19     hb_job_t * job;
20
21     /* libmp4v2 handle */
22     MP4FileHandle file;
23
24     /* Cumulated durations so far, in timescale units (see MP4Mux) */
25     uint64_t sum_dur;
26 };
27
28 struct hb_mux_data_s
29 {
30     MP4TrackId track;
31 };
32
33 /**********************************************************************
34  * MP4Init
35  **********************************************************************
36  * Allocates hb_mux_data_t structures, create file and write headers
37  *********************************************************************/
38 static int MP4Init( hb_mux_object_t * m )
39 {
40     hb_job_t   * job   = m->job;
41     hb_title_t * title = job->title;
42     
43     hb_audio_t    * audio;
44     hb_mux_data_t * mux_data;
45     int i;
46
47     /* Create an empty mp4 file */
48     m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
49
50     /* Video track */
51     mux_data      = malloc( sizeof( hb_mux_data_t ) );
52     job->mux_data = mux_data;
53
54     /* When using the standard 90000 timescale, QuickTime tends to have
55        synchronization issues (audio not playing at the correct speed).
56        To workaround this, we use the audio samplerate as the
57        timescale */
58     MP4SetTimeScale( m->file, job->arate );
59
60     if( job->vcodec == HB_VCODEC_X264 )
61     {
62         /* Stolen from mp4creator */
63         MP4SetVideoProfileLevel( m->file, 0x7F );
64
65                 if (job->areBframes == 1)
66                 {
67                         hb_log("muxmp4: Adjusting duration for B-frames");
68                     mux_data->track = MP4AddH264VideoTrack( m->file, job->arate,
69                             MP4_INVALID_DURATION+1, job->width, job->height,
70                             job->config.h264.sps[1], /* AVCProfileIndication */
71                             job->config.h264.sps[2], /* profile_compat */
72                             job->config.h264.sps[3], /* AVCLevelIndication */
73                             3 );      /* 4 bytes length before each NAL unit */                 
74                 }
75                 else
76                 {
77                         hb_log("muxmp4: Using default duration as there are no B-frames");
78                 mux_data->track = MP4AddH264VideoTrack( m->file, job->arate,
79                         MP4_INVALID_DURATION, job->width, job->height,
80                         job->config.h264.sps[1], /* AVCProfileIndication */
81                         job->config.h264.sps[2], /* profile_compat */
82                         job->config.h264.sps[3], /* AVCLevelIndication */
83                         3 );      /* 4 bytes length before each NAL unit */
84                 }
85
86         MP4AddH264SequenceParameterSet( m->file, mux_data->track,
87                 job->config.h264.sps, job->config.h264.sps_length );
88         MP4AddH264PictureParameterSet( m->file, mux_data->track,
89                 job->config.h264.pps, job->config.h264.pps_length );
90
91                 if( job->h264_level == 30)
92                 {
93                         hb_log("About to add iPod atom");
94                         AddIPodUUID(m->file, mux_data->track);
95                 }
96
97     }
98     else /* FFmpeg or XviD */
99     {
100         MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 );
101         mux_data->track = MP4AddVideoTrack( m->file, job->arate,
102                 MP4_INVALID_DURATION, job->width, job->height,
103                 MP4_MPEG4_VIDEO_TYPE );
104
105         /* VOL from FFmpeg or XviD */
106         MP4SetTrackESConfiguration( m->file, mux_data->track,
107                 job->config.mpeg4.bytes, job->config.mpeg4.length );
108     }
109
110         /* apply the anamorphic transformation matrix if needed */
111
112         if( job->pixel_ratio ) {
113
114                 uint8_t* val;
115                 uint8_t nval[38];
116                 uint32_t *ptr32 = (uint32_t*) (nval + 2);
117                 uint32_t size;
118
119                 MP4GetBytesProperty(m->file, "moov.trak.tkhd.reserved3", &val, &size);
120
121                 if (size == 38) {
122
123                         memcpy(nval, val, size);
124
125                         float width, height;
126                         float widthRatio;
127                         width = job->pixel_aspect_width;
128                         height = job->pixel_aspect_height;
129                         widthRatio = (width / height) * 0x10000;
130
131                         uint32_t widthRatioInt;
132                         widthRatioInt = (uint32_t)widthRatio;
133
134 #ifdef WORDS_BIGENDIAN
135                         ptr32[0] = widthRatioInt;
136 #else
137                         /* we need to switch the endianness, as the file format expects big endian */
138                         ptr32[0] = ((widthRatioInt & 0x000000FF) << 24) + ((widthRatioInt & 0x0000FF00) << 8) + ((widthRatioInt & 0x00FF0000) >> 8) + ((widthRatioInt & 0xFF000000) >> 24);
139 #endif
140
141                         if(!MP4SetBytesProperty(m->file, "moov.trak.tkhd.reserved3", nval, size)) {
142                                 hb_log("Problem setting transform matrix");
143                         }
144
145                 }
146
147         }
148
149         /* end of transformation matrix */
150
151
152     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
153     {
154         audio = hb_list_item( title->list_audio, i );
155         mux_data = malloc( sizeof( hb_mux_data_t ) );
156         audio->mux_data = mux_data;
157
158         mux_data->track = MP4AddAudioTrack( m->file,
159                 job->arate, 1024, MP4_MPEG4_AUDIO_TYPE );
160         MP4SetAudioProfileLevel( m->file, 0x0F );
161         MP4SetTrackESConfiguration( m->file, mux_data->track,
162                 audio->config.aac.bytes, audio->config.aac.length );
163     }
164
165     return 0;
166 }
167
168 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
169                    hb_buffer_t * buf )
170 {
171     hb_job_t * job = m->job;
172
173     uint64_t duration;
174
175     if( mux_data == job->mux_data )
176     {
177         /* Video */
178         /* Because we use the audio samplerate as the timescale,
179            we have to use potentially variable durations so the video
180            doesn't go out of sync */
181         duration    = ( buf->stop * job->arate / 90000 ) - m->sum_dur;
182         m->sum_dur += duration;
183     }
184     else
185     {
186         /* Audio */
187         duration = MP4_INVALID_DURATION;
188     }
189
190     MP4WriteSample( m->file, mux_data->track, buf->data, buf->size,
191                     duration, 0, buf->key );
192     return 0;
193 }
194
195 static int MP4End( hb_mux_object_t * m )
196 {
197 #if 0
198     hb_job_t * job = m->job;
199 #endif
200     char filename[1024]; memset( filename, 0, 1024 );
201
202     MP4Close( m->file );
203
204 #if 0
205     hb_log( "muxmp4: optimizing file" );
206     snprintf( filename, 1024, "%s.tmp", job->file );
207     MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
208     remove( job->file );
209     rename( filename, job->file );
210 #endif
211
212     return 0;
213 }
214
215 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
216 {
217     hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );
218     m->init      = MP4Init;
219     m->mux       = MP4Mux;
220     m->end       = MP4End;
221     m->job       = job;
222     return m;
223 }
224