Refer to transitions in the presence-or-lack-thereof of progressive flags on MPEG...
[HandBrake.git] / libhb / muxogm.c
blob86e44f0e90fb948575ea1d2c79e73f3cc4a498d2
1 /* $Id: muxogm.c,v 1.4 2005/02/20 00:41:56 titer Exp $
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. */
7 #include "hb.h"
9 #include <ogg/ogg.h>
11 struct hb_mux_object_s
13 HB_MUX_COMMON;
15 hb_job_t * job;
17 FILE * file;
20 struct hb_mux_data_s
22 int codec;
23 ogg_stream_state os;
24 int i_packet_no;
27 typedef struct __attribute__((__packed__))
29 uint8_t i_packet_type;
31 char stream_type[8];
32 char sub_type[4];
34 int32_t i_size;
36 int64_t i_time_unit;
37 int64_t i_samples_per_unit;
38 int32_t i_default_len;
40 int32_t i_buffer_size;
41 int16_t i_bits_per_sample;
42 int16_t i_padding_0; // hum hum
43 union
45 struct
47 int32_t i_width;
48 int32_t i_height;
50 } video;
51 struct
53 int16_t i_channels;
54 int16_t i_block_align;
55 int32_t i_avgbytespersec;
56 } audio;
57 } header;
59 } ogg_stream_header_t;
61 #define SetWLE( p, v ) _SetWLE( (uint8_t*)p, v)
62 static void _SetWLE( uint8_t *p, uint16_t i_dw )
64 p[1] = ( i_dw >> 8 )&0xff;
65 p[0] = ( i_dw )&0xff;
68 #define SetDWLE( p, v ) _SetDWLE( (uint8_t*)p, v)
69 static void _SetDWLE( uint8_t *p, uint32_t i_dw )
71 p[3] = ( i_dw >> 24 )&0xff;
72 p[2] = ( i_dw >> 16 )&0xff;
73 p[1] = ( i_dw >> 8 )&0xff;
74 p[0] = ( i_dw )&0xff;
76 #define SetQWLE( p, v ) _SetQWLE( (uint8_t*)p, v)
77 static void _SetQWLE( uint8_t *p, uint64_t i_qw )
79 SetDWLE( p, i_qw&0xffffffff );
80 SetDWLE( p+4, ( i_qw >> 32)&0xffffffff );
83 static int OGMFlush( hb_mux_object_t * m, hb_mux_data_t * mux_data )
85 for( ;; )
87 ogg_page og;
88 if( ogg_stream_flush( &mux_data->os, &og ) == 0 )
90 break;
92 if( fwrite( og.header, og.header_len, 1, m->file ) <= 0 ||
93 fwrite( og.body, og.body_len, 1, m->file ) <= 0 )
95 return -1;
98 return 0;
101 /**********************************************************************
102 * OGMInit
103 **********************************************************************
104 * Allocates hb_mux_data_t structures, create file and write headers
105 *********************************************************************/
106 static int OGMInit( hb_mux_object_t * m )
108 hb_job_t * job = m->job;
109 hb_title_t * title = job->title;
111 hb_audio_t * audio;
112 hb_mux_data_t * mux_data;
113 int i;
115 ogg_packet op;
116 ogg_stream_header_t h;
118 /* Open output file */
119 if( ( m->file = fopen( job->file, "wb" ) ) == NULL )
121 hb_log( "muxogm: failed to open `%s'", job->file );
122 return -1;
124 hb_log( "muxogm: `%s' opened", job->file );
126 /* Video track */
127 mux_data = malloc( sizeof( hb_mux_data_t ) );
128 mux_data->codec = job->vcodec;
129 mux_data->i_packet_no = 0;
130 job->mux_data = mux_data;
131 ogg_stream_init( &mux_data->os, 0 );
133 /* Audio */
134 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
136 audio = hb_list_item( title->list_audio, i );
137 mux_data = malloc( sizeof( hb_mux_data_t ) );
138 mux_data->codec = job->acodec;
139 mux_data->i_packet_no = 0;
140 audio->mux_data = mux_data;
141 ogg_stream_init( &mux_data->os, i + 1 );
145 /* First pass: all b_o_s packets */
147 /* Video */
148 mux_data = job->mux_data;
149 memset( &h, 0, sizeof( ogg_stream_header_t ) );
150 h.i_packet_type = 0x01;
151 memcpy( h.stream_type, "video ", 8 );
152 if( mux_data->codec == HB_VCODEC_X264 )
154 memcpy( h.sub_type, "H264", 4 );
156 else if( mux_data->codec == HB_VCODEC_XVID )
158 memcpy( h.sub_type, "XVID", 4 );
160 else
162 memcpy( h.sub_type, "DX50", 4 );
164 SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1);
165 SetQWLE( &h.i_time_unit, (int64_t) 10 * 1000 * 1000 *
166 (int64_t) job->vrate_base / (int64_t) job->vrate );
167 SetQWLE( &h.i_samples_per_unit, 1 );
168 SetDWLE( &h.i_default_len, 0 );
169 SetDWLE( &h.i_buffer_size, 1024*1024 );
170 SetWLE ( &h.i_bits_per_sample, 0 );
171 SetDWLE( &h.header.video.i_width, job->width );
172 SetDWLE( &h.header.video.i_height, job->height );
173 op.packet = (unsigned char*)&h;
174 op.bytes = sizeof( ogg_stream_header_t );
175 op.b_o_s = 1;
176 op.e_o_s = 0;
177 op.granulepos = 0;
178 op.packetno = mux_data->i_packet_no++;
179 ogg_stream_packetin( &mux_data->os, &op );
180 OGMFlush( m, mux_data );
182 /* Audio */
183 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
185 audio = hb_list_item( title->list_audio, i );
186 mux_data = audio->mux_data;
187 memset( &h, 0, sizeof( ogg_stream_header_t ) );
188 switch( job->acodec )
190 case HB_ACODEC_LAME:
192 h.i_packet_type = 0x01;
193 memcpy( h.stream_type, "audio ", 8 );
194 memcpy( h.sub_type, "55 ", 4 );
196 SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1);
197 SetQWLE( &h.i_time_unit, 0 );
198 SetQWLE( &h.i_samples_per_unit, job->arate );
199 SetDWLE( &h.i_default_len, 1 );
200 SetDWLE( &h.i_buffer_size, 30 * 1024 );
201 SetWLE ( &h.i_bits_per_sample, 0 );
203 SetDWLE( &h.header.audio.i_channels, 2 );
204 SetDWLE( &h.header.audio.i_block_align, 0 );
205 SetDWLE( &h.header.audio.i_avgbytespersec,
206 job->abitrate / 8 );
208 op.packet = (unsigned char*) &h;
209 op.bytes = sizeof( ogg_stream_header_t );
210 op.b_o_s = 1;
211 op.e_o_s = 0;
212 op.granulepos = 0;
213 op.packetno = mux_data->i_packet_no++;
214 ogg_stream_packetin( &mux_data->os, &op );
215 break;
217 case HB_ACODEC_VORBIS:
219 memcpy( &op, audio->config.vorbis.headers[0],
220 sizeof( ogg_packet ) );
221 op.packet = audio->config.vorbis.headers[0] +
222 sizeof( ogg_packet );
223 ogg_stream_packetin( &mux_data->os, &op );
224 break;
226 default:
227 hb_log( "muxogm: unhandled codec" );
228 break;
230 OGMFlush( m, mux_data );
233 /* second pass: all non b_o_s packets */
234 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
236 audio = hb_list_item( title->list_audio, i );
237 if( job->acodec == HB_ACODEC_VORBIS )
239 int j;
240 mux_data = audio->mux_data;
242 for( j = 1; j < 3; j++ )
244 memcpy( &op, audio->config.vorbis.headers[j],
245 sizeof( ogg_packet ) );
246 op.packet = audio->config.vorbis.headers[j] +
247 sizeof( ogg_packet );
248 ogg_stream_packetin( &mux_data->os, &op );
250 OGMFlush( m, mux_data );
254 hb_log( "muxogm: headers written" );
256 return 0;
259 static int OGMMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
260 hb_buffer_t * buf )
262 ogg_packet op;
264 switch( mux_data->codec )
266 case HB_VCODEC_FFMPEG:
267 case HB_VCODEC_XVID:
268 case HB_VCODEC_X264:
269 op.bytes = buf->size + 1;
270 op.packet = malloc( op.bytes );
271 op.packet[0] = (buf->frametype & HB_FRAME_KEY) ? 0x08 : 0x00;
272 memcpy( &op.packet[1], buf->data, buf->size );
273 op.b_o_s = 0;
274 op.e_o_s = 0;
275 op.granulepos = mux_data->i_packet_no;
276 op.packetno = mux_data->i_packet_no++;
277 break;
278 case HB_ACODEC_LAME:
279 op.bytes = buf->size + 1;
280 op.packet = malloc( op.bytes );
281 op.packet[0] = 0x08;
282 memcpy( &op.packet[1], buf->data, buf->size );
283 op.b_o_s = 0;
284 op.e_o_s = 0;
285 op.granulepos = mux_data->i_packet_no * 1152;
286 op.packetno = mux_data->i_packet_no++;
287 break;
288 case HB_ACODEC_VORBIS:
289 memcpy( &op, buf->data, sizeof( ogg_packet ) );
290 op.packet = malloc( op.bytes );
291 memcpy( op.packet, buf->data + sizeof( ogg_packet ), op.bytes );
292 break;
294 default:
295 hb_log( "muxogm: unhandled codec" );
296 op.bytes = 0;
297 op.packet = NULL;
298 break;
301 if( op.packet )
303 ogg_stream_packetin( &mux_data->os, &op );
305 for( ;; )
307 ogg_page og;
308 if( ogg_stream_pageout( &mux_data->os, &og ) == 0 )
310 break;
313 if( fwrite( og.header, og.header_len, 1, m->file ) <= 0 ||
314 fwrite( og.body, og.body_len, 1, m->file ) <= 0 )
316 hb_log( "muxogm: write failed" );
317 break;
320 free( op.packet );
322 return 0;
325 static int OGMEnd( hb_mux_object_t * m )
327 hb_job_t * job = m->job;
329 hb_title_t * title = job->title;
330 hb_audio_t * audio;
331 hb_mux_data_t * mux_data;
332 int i;
334 mux_data = job->mux_data;
335 if( OGMFlush( m, mux_data ) < 0 )
337 return -1;
339 ogg_stream_clear( &mux_data->os );
341 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
343 audio = hb_list_item( title->list_audio, i );
344 mux_data = audio->mux_data;
345 if( OGMFlush( m, mux_data ) < 0 )
347 return -1;
349 ogg_stream_clear( &mux_data->os );
352 fclose( m->file );
353 hb_log( "muxogm: `%s' closed", job->file );
355 return 0;
358 hb_mux_object_t * hb_mux_ogm_init( hb_job_t * job )
360 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );
361 m->init = OGMInit;
362 m->mux = OGMMux;
363 m->end = OGMEnd;
364 m->job = job;
365 return m;