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. */
11 struct hb_mux_object_s
27 typedef struct __attribute__((__packed__
))
29 uint8_t i_packet_type
;
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
54 int16_t i_block_align
;
55 int32_t i_avgbytespersec
;
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;
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;
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
)
88 if( ogg_stream_flush( &mux_data
->os
, &og
) == 0 )
92 if( fwrite( og
.header
, og
.header_len
, 1, m
->file
) <= 0 ||
93 fwrite( og
.body
, og
.body_len
, 1, m
->file
) <= 0 )
101 /**********************************************************************
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
;
112 hb_mux_data_t
* mux_data
;
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
);
124 hb_log( "muxogm: `%s' opened", job
->file
);
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 );
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 */
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 );
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
);
178 op
.packetno
= mux_data
->i_packet_no
++;
179 ogg_stream_packetin( &mux_data
->os
, &op
);
180 OGMFlush( m
, mux_data
);
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
)
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
,
208 op
.packet
= (unsigned char*) &h
;
209 op
.bytes
= sizeof( ogg_stream_header_t
);
213 op
.packetno
= mux_data
->i_packet_no
++;
214 ogg_stream_packetin( &mux_data
->os
, &op
);
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
);
227 hb_log( "muxogm: unhandled codec" );
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
)
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" );
259 static int OGMMux( hb_mux_object_t
* m
, hb_mux_data_t
* mux_data
,
264 switch( mux_data
->codec
)
266 case HB_VCODEC_FFMPEG
:
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
);
275 op
.granulepos
= mux_data
->i_packet_no
;
276 op
.packetno
= mux_data
->i_packet_no
++;
279 op
.bytes
= buf
->size
+ 1;
280 op
.packet
= malloc( op
.bytes
);
282 memcpy( &op
.packet
[1], buf
->data
, buf
->size
);
285 op
.granulepos
= mux_data
->i_packet_no
* 1152;
286 op
.packetno
= mux_data
->i_packet_no
++;
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
);
295 hb_log( "muxogm: unhandled codec" );
303 ogg_stream_packetin( &mux_data
->os
, &op
);
308 if( ogg_stream_pageout( &mux_data
->os
, &og
) == 0 )
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" );
325 static int OGMEnd( hb_mux_object_t
* m
)
327 hb_job_t
* job
= m
->job
;
329 hb_title_t
* title
= job
->title
;
331 hb_mux_data_t
* mux_data
;
334 mux_data
= job
->mux_data
;
335 if( OGMFlush( m
, mux_data
) < 0 )
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 )
349 ogg_stream_clear( &mux_data
->os
);
353 hb_log( "muxogm: `%s' closed", job
->file
);
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 );