OSDN Git Service

646a2546ef854f79803b6da507c324c7fd9ad95c
[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 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     /* Cumulated durations so far, in timescale units (see MP4Mux) */
22     uint64_t sum_dur;
23 };
24
25 struct hb_mux_data_s
26 {
27     MP4TrackId track;
28 };
29
30 /**********************************************************************
31  * MP4Init
32  **********************************************************************
33  * Allocates hb_mux_data_t structures, create file and write headers
34  *********************************************************************/
35 static int MP4Init( hb_mux_object_t * m )
36 {
37     hb_job_t   * job   = m->job;
38     hb_title_t * title = job->title;
39     
40     hb_audio_t    * audio;
41     hb_mux_data_t * mux_data;
42     int i;
43
44     /* Create an empty mp4 file */
45     m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 );
46
47     /* Video track */
48     mux_data      = malloc( sizeof( hb_mux_data_t ) );
49     job->mux_data = mux_data;
50
51     /* When using the standard 90000 timescale, QuickTime tends to have
52        synchronization issues (audio not playing at the correct speed).
53        To workaround this, we use the audio samplerate as the
54        timescale */
55     MP4SetTimeScale( m->file, job->arate );
56
57     if( job->vcodec == HB_VCODEC_X264 )
58     {
59 #define c job->config.h264
60         /* Stolen from mp4creator */
61         MP4SetVideoProfileLevel( m->file, 0x7F );
62
63         mux_data->track = MP4AddH264VideoTrack( m->file, job->arate,
64                 MP4_INVALID_DURATION, job->width, job->height,
65                 c.sps[1], /* AVCProfileIndication */
66                 c.sps[2], /* profile_compat */
67                 c.sps[3], /* AVCLevelIndication */
68                 3 );      /* 4 bytes length before each NAL unit */
69
70         MP4AddH264SequenceParameterSet( m->file, mux_data->track,
71                 c.sps, c.sps_length );
72         MP4AddH264PictureParameterSet( m->file, mux_data->track,
73                 c.pps, c.pps_length );
74 #undef c
75     }
76     else /* FFmpeg or XviD */
77     {
78 #define c job->config.mpeg4
79         MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 );
80         mux_data->track = MP4AddVideoTrack( m->file, job->arate,
81                 MP4_INVALID_DURATION, job->width, job->height,
82                 MP4_MPEG4_VIDEO_TYPE );
83
84         /* VOL from FFmpeg or XviD */
85         MP4SetTrackESConfiguration( m->file, mux_data->track,
86                 c.config, c.config_length );
87 #undef c
88     }
89
90     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
91     {
92         audio = hb_list_item( title->list_audio, i );
93         mux_data = malloc( sizeof( hb_mux_data_t ) );
94         audio->mux_data = mux_data;
95
96         mux_data->track = MP4AddAudioTrack( m->file,
97                 job->arate, 1024, MP4_MPEG4_AUDIO_TYPE );
98         MP4SetAudioProfileLevel( m->file, 0x0F );
99         MP4SetTrackESConfiguration( m->file, mux_data->track,
100                 audio->config.faac.decinfo, audio->config.faac.size );
101     }
102
103     return 0;
104 }
105
106 static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
107                    hb_buffer_t * buf )
108 {
109     hb_job_t * job = m->job;
110
111     uint64_t duration;
112
113     if( mux_data == job->mux_data )
114     {
115         /* Video */
116         /* Because we use the audio samplerate as the timescale,
117            we have to use potentially variable durations so the video
118            doesn't go out of sync */
119         duration    = ( buf->stop * job->arate / 90000 ) - m->sum_dur;
120         m->sum_dur += duration;
121     }
122     else
123     {
124         /* Audio */
125         duration = MP4_INVALID_DURATION;
126     }
127
128     MP4WriteSample( m->file, mux_data->track, buf->data, buf->size,
129                     duration, 0, buf->key );
130     return 0;
131 }
132
133 static int MP4End( hb_mux_object_t * m )
134 {
135 #if 0
136     hb_job_t * job = m->job;
137 #endif
138     char filename[1024]; memset( filename, 0, 1024 );
139
140     MP4Close( m->file );
141
142 #if 0
143     hb_log( "muxmp4: optimizing file" );
144     snprintf( filename, 1024, "%s.tmp", job->file );
145     MP4Optimize( job->file, filename, MP4_DETAILS_ERROR );
146     remove( job->file );
147     rename( filename, job->file );
148 #endif
149
150     return 0;
151 }
152
153 hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job )
154 {
155     hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );
156     m->init      = MP4Init;
157     m->mux       = MP4Mux;
158     m->end       = MP4End;
159     m->job       = job;
160     return m;
161 }
162