00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdlib.h>
00029 #include <string.h>
00030
00031 #ifdef HAVE_TIME_H
00032 # include <time.h>
00033 #endif
00034
00035 #include <vlc/vlc.h>
00036 #include <vlc/input.h>
00037 #include <vlc/sout.h>
00038
00039 #include "codecs.h"
00040
00041 #include <ogg/ogg.h>
00042
00043
00044
00045
00046 static int Open ( vlc_object_t * );
00047 static void Close ( vlc_object_t * );
00048
00049 vlc_module_begin();
00050 set_description( _("Ogg/ogm muxer") );
00051 set_capability( "sout mux", 10 );
00052 set_category( CAT_SOUT );
00053 set_subcategory( SUBCAT_SOUT_MUX );
00054 add_shortcut( "ogg" );
00055 add_shortcut( "ogm" );
00056 set_callbacks( Open, Close );
00057 vlc_module_end();
00058
00059
00060
00061
00062
00063 static int Control ( sout_mux_t *, int, va_list );
00064 static int AddStream( sout_mux_t *, sout_input_t * );
00065 static int DelStream( sout_mux_t *, sout_input_t * );
00066 static int Mux ( sout_mux_t * );
00067 static int MuxBlock ( sout_mux_t *, sout_input_t * );
00068
00069 static block_t *OggCreateHeader( sout_mux_t *, mtime_t );
00070 static block_t *OggCreateFooter( sout_mux_t *, mtime_t );
00071
00072
00073
00074
00075 #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
00076
00077
00078
00079 #define PACKET_TYPE_HEADER 0x01
00080 #define PACKET_TYPE_COMMENT 0x03
00081 #define PACKET_IS_SYNCPOINT 0x08
00082
00083 typedef struct
00084 #ifdef HAVE_ATTRIBUTE_PACKED
00085 __attribute__((__packed__))
00086 #endif
00087 {
00088 int32_t i_width;
00089 int32_t i_height;
00090 } oggds_header_video_t;
00091
00092 typedef struct
00093 #ifdef HAVE_ATTRIBUTE_PACKED
00094 __attribute__((__packed__))
00095 #endif
00096 {
00097 int16_t i_channels;
00098 int16_t i_block_align;
00099 int32_t i_avgbytespersec;
00100 } oggds_header_audio_t;
00101
00102 typedef struct
00103 #ifdef HAVE_ATTRIBUTE_PACKED
00104 __attribute__((__packed__))
00105 #endif
00106 {
00107 uint8_t i_packet_type;
00108
00109 char stream_type[8];
00110 char sub_type[4];
00111
00112 int32_t i_size;
00113
00114 int64_t i_time_unit;
00115 int64_t i_samples_per_unit;
00116 int32_t i_default_len;
00117
00118 int32_t i_buffer_size;
00119 int16_t i_bits_per_sample;
00120
00121 int16_t i_padding_0;
00122
00123 union
00124 {
00125 oggds_header_video_t video;
00126 oggds_header_audio_t audio;
00127 } header;
00128
00129 int32_t i_padding_1;
00130
00131 } oggds_header_t;
00132
00133
00134
00135
00136 static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
00137 {
00138 mtime_t i_dts;
00139 int i_stream;
00140 int i;
00141
00142 for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
00143 {
00144 block_fifo_t *p_fifo;
00145
00146 p_fifo = p_mux->pp_inputs[i]->p_fifo;
00147
00148
00149 if( p_mux->pp_inputs[i]->p_fmt->i_cat == SPU_ES &&
00150 p_fifo->i_depth == 0 ) continue;
00151
00152 if( p_fifo->i_depth )
00153 {
00154 block_t *p_buf;
00155
00156 p_buf = block_FifoShow( p_fifo );
00157 if( i_stream < 0 || p_buf->i_dts < i_dts )
00158 {
00159 i_dts = p_buf->i_dts;
00160 i_stream = i;
00161 }
00162 }
00163 else return -1;
00164
00165 }
00166 if( pi_stream ) *pi_stream = i_stream;
00167 if( pi_dts ) *pi_dts = i_dts;
00168 return i_stream;
00169 }
00170
00171
00172
00173
00174 typedef struct
00175 {
00176 int i_cat;
00177 int i_fourcc;
00178
00179 int b_new;
00180
00181 mtime_t i_dts;
00182 mtime_t i_length;
00183 int i_packet_no;
00184 int i_serial_no;
00185 int i_keyframe_granule_shift;
00186 ogg_stream_state os;
00187
00188 oggds_header_t *p_oggds_header;
00189
00190 } ogg_stream_t;
00191
00192 struct sout_mux_sys_t
00193 {
00194 int i_streams;
00195
00196 mtime_t i_start_dts;
00197 int i_next_serial_no;
00198
00199
00200 int i_add_streams;
00201
00202
00203 int i_del_streams;
00204 ogg_stream_t **pp_del_streams;
00205 };
00206
00207 static void OggSetDate( block_t *, mtime_t , mtime_t );
00208 static block_t *OggStreamFlush( sout_mux_t *, ogg_stream_state *, mtime_t );
00209
00210
00211
00212
00213 static int Open( vlc_object_t *p_this )
00214 {
00215 sout_mux_t *p_mux = (sout_mux_t*)p_this;
00216 sout_mux_sys_t *p_sys;
00217
00218 msg_Info( p_mux, "Open" );
00219
00220 p_sys = malloc( sizeof( sout_mux_sys_t ) );
00221 p_sys->i_streams = 0;
00222 p_sys->i_add_streams = 0;
00223 p_sys->i_del_streams = 0;
00224 p_sys->pp_del_streams = 0;
00225
00226 p_mux->p_sys = p_sys;
00227 p_mux->pf_control = Control;
00228 p_mux->pf_addstream = AddStream;
00229 p_mux->pf_delstream = DelStream;
00230 p_mux->pf_mux = Mux;
00231
00232
00233
00234
00235 srand( (unsigned int)time( NULL ) );
00236 p_sys->i_next_serial_no = rand();
00237
00238 return VLC_SUCCESS;
00239 }
00240
00241
00242
00243
00244 static void Close( vlc_object_t * p_this )
00245 {
00246 sout_mux_t *p_mux = (sout_mux_t*)p_this;
00247 sout_mux_sys_t *p_sys = p_mux->p_sys;
00248
00249 msg_Info( p_mux, "Close" );
00250
00251 if( p_sys->i_del_streams )
00252 {
00253 block_t *p_og = NULL;
00254 mtime_t i_dts = -1;
00255 int i;
00256
00257
00258 msg_Dbg( p_mux, "writing footer" );
00259 block_ChainAppend( &p_og, OggCreateFooter( p_mux, 0 ) );
00260
00261
00262 for( i = 0; i < p_sys->i_del_streams; i++ )
00263 {
00264 i_dts = p_sys->pp_del_streams[i]->i_dts;
00265 ogg_stream_clear( &p_sys->pp_del_streams[i]->os );
00266 FREE( p_sys->pp_del_streams[i]->p_oggds_header );
00267 FREE( p_sys->pp_del_streams[i] );
00268 }
00269 FREE( p_sys->pp_del_streams );
00270 p_sys->i_streams -= p_sys->i_del_streams;
00271
00272
00273 OggSetDate( p_og, i_dts, 0 );
00274 sout_AccessOutWrite( p_mux->p_access, p_og );
00275 }
00276
00277 free( p_sys );
00278 }
00279
00280
00281
00282
00283 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
00284 {
00285 vlc_bool_t *pb_bool;
00286 char **ppsz;
00287
00288 switch( i_query )
00289 {
00290 case MUX_CAN_ADD_STREAM_WHILE_MUXING:
00291 pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00292 *pb_bool = VLC_TRUE;
00293 return VLC_SUCCESS;
00294
00295 case MUX_GET_ADD_STREAM_WAIT:
00296 pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00297 *pb_bool = VLC_TRUE;
00298 return VLC_SUCCESS;
00299
00300 case MUX_GET_MIME:
00301 ppsz = (char**)va_arg( args, char ** );
00302 *ppsz = strdup( "application/ogg" );
00303 return VLC_SUCCESS;
00304
00305 default:
00306 return VLC_EGENERIC;
00307 }
00308 }
00309
00310
00311
00312 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
00313 {
00314 sout_mux_sys_t *p_sys = p_mux->p_sys;
00315 ogg_stream_t *p_stream;
00316 uint16_t i_tag;
00317
00318 msg_Dbg( p_mux, "adding input" );
00319
00320 p_input->p_sys = p_stream = malloc( sizeof( ogg_stream_t ) );
00321
00322 p_stream->i_cat = p_input->p_fmt->i_cat;
00323 p_stream->i_fourcc = p_input->p_fmt->i_codec;
00324 p_stream->i_serial_no = p_sys->i_next_serial_no++;
00325 p_stream->i_packet_no = 0;
00326
00327 p_stream->p_oggds_header = 0;
00328
00329 switch( p_input->p_fmt->i_cat )
00330 {
00331 case VIDEO_ES:
00332 if( !p_input->p_fmt->video.i_frame_rate ||
00333 !p_input->p_fmt->video.i_frame_rate_base )
00334 {
00335 msg_Warn( p_mux, "Missing frame rate, assuming 25fps" );
00336 p_input->p_fmt->video.i_frame_rate = 25;
00337 p_input->p_fmt->video.i_frame_rate_base = 1;
00338 }
00339
00340 switch( p_stream->i_fourcc )
00341 {
00342 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
00343 case VLC_FOURCC( 'm', 'p', '4', 'v' ):
00344 case VLC_FOURCC( 'D', 'I', 'V', '3' ):
00345 case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
00346 case VLC_FOURCC( 'W', 'M', 'V', '1' ):
00347 case VLC_FOURCC( 'W', 'M', 'V', '2' ):
00348 case VLC_FOURCC( 'W', 'M', 'V', '3' ):
00349 case VLC_FOURCC( 'S', 'N', 'O', 'W' ):
00350 case VLC_FOURCC( 'd', 'r', 'a', 'c' ):
00351 p_stream->p_oggds_header = malloc( sizeof(oggds_header_t) );
00352 memset( p_stream->p_oggds_header, 0, sizeof(oggds_header_t) );
00353 p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
00354
00355 memcpy( p_stream->p_oggds_header->stream_type, "video", 5 );
00356 if( p_stream->i_fourcc == VLC_FOURCC( 'm', 'p', '4', 'v' ) )
00357 {
00358 memcpy( p_stream->p_oggds_header->sub_type, "XVID", 4 );
00359 }
00360 else if( p_stream->i_fourcc == VLC_FOURCC( 'D', 'I', 'V', '3' ) )
00361 {
00362 memcpy( p_stream->p_oggds_header->sub_type, "DIV3", 4 );
00363 }
00364 else
00365 {
00366 memcpy( p_stream->p_oggds_header->sub_type,
00367 &p_stream->i_fourcc, 4 );
00368 }
00369 SetDWLE( &p_stream->p_oggds_header->i_size,
00370 sizeof( oggds_header_t ) - 1 );
00371 SetQWLE( &p_stream->p_oggds_header->i_time_unit,
00372 I64C(10000000) * p_input->p_fmt->video.i_frame_rate_base /
00373 (int64_t)p_input->p_fmt->video.i_frame_rate );
00374 SetQWLE( &p_stream->p_oggds_header->i_samples_per_unit, 1 );
00375 SetDWLE( &p_stream->p_oggds_header->i_default_len, 1 );
00376 SetDWLE( &p_stream->p_oggds_header->i_buffer_size, 1024*1024 );
00377 SetWLE( &p_stream->p_oggds_header->i_bits_per_sample, 0 );
00378 SetDWLE( &p_stream->p_oggds_header->header.video.i_width,
00379 p_input->p_fmt->video.i_width );
00380 SetDWLE( &p_stream->p_oggds_header->header.video.i_height,
00381 p_input->p_fmt->video.i_height );
00382 msg_Dbg( p_mux, "%4.4s stream", (char *)&p_stream->i_fourcc );
00383 break;
00384
00385 case VLC_FOURCC( 't', 'h', 'e', 'o' ):
00386 msg_Dbg( p_mux, "theora stream" );
00387 break;
00388
00389 default:
00390 FREE( p_input->p_sys );
00391 return VLC_EGENERIC;
00392 }
00393 break;
00394
00395 case AUDIO_ES:
00396 switch( p_stream->i_fourcc )
00397 {
00398 case VLC_FOURCC( 'v', 'o', 'r', 'b' ):
00399 msg_Dbg( p_mux, "vorbis stream" );
00400 break;
00401
00402 case VLC_FOURCC( 's', 'p', 'x', ' ' ):
00403 msg_Dbg( p_mux, "speex stream" );
00404 break;
00405
00406 case VLC_FOURCC( 'f', 'l', 'a', 'c' ):
00407 msg_Dbg( p_mux, "flac stream" );
00408 break;
00409
00410 default:
00411 fourcc_to_wf_tag( p_stream->i_fourcc, &i_tag );
00412 if( i_tag == WAVE_FORMAT_UNKNOWN )
00413 {
00414 FREE( p_input->p_sys );
00415 return VLC_EGENERIC;
00416 }
00417
00418 p_stream->p_oggds_header =
00419 malloc( sizeof(oggds_header_t) + p_input->p_fmt->i_extra );
00420 memset( p_stream->p_oggds_header, 0, sizeof(oggds_header_t) );
00421 p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
00422
00423 SetDWLE( &p_stream->p_oggds_header->i_size,
00424 sizeof( oggds_header_t ) - 1 + p_input->p_fmt->i_extra );
00425
00426 if( p_input->p_fmt->i_extra )
00427 {
00428 memcpy( &p_stream->p_oggds_header[1],
00429 p_input->p_fmt->p_extra, p_input->p_fmt->i_extra );
00430 }
00431
00432 memcpy( p_stream->p_oggds_header->stream_type, "audio", 5 );
00433
00434 memset( p_stream->p_oggds_header->sub_type, 0, 4 );
00435 sprintf( p_stream->p_oggds_header->sub_type, "%-x", i_tag );
00436
00437 SetQWLE( &p_stream->p_oggds_header->i_time_unit, I64C(10000000) );
00438 SetDWLE( &p_stream->p_oggds_header->i_default_len, 1 );
00439 SetDWLE( &p_stream->p_oggds_header->i_buffer_size, 30*1024 );
00440 SetQWLE( &p_stream->p_oggds_header->i_samples_per_unit,
00441 p_input->p_fmt->audio.i_rate );
00442 SetWLE( &p_stream->p_oggds_header->i_bits_per_sample,
00443 p_input->p_fmt->audio.i_bitspersample );
00444 SetDWLE( &p_stream->p_oggds_header->header.audio.i_channels,
00445 p_input->p_fmt->audio.i_channels );
00446 SetDWLE( &p_stream->p_oggds_header->header.audio.i_block_align,
00447 p_input->p_fmt->audio.i_blockalign );
00448 SetDWLE( &p_stream->p_oggds_header->header.audio.i_avgbytespersec,
00449 p_input->p_fmt->i_bitrate / 8);
00450 msg_Dbg( p_mux, "%4.4s stream", (char *)&p_stream->i_fourcc );
00451 break;
00452 }
00453 break;
00454
00455 case SPU_ES:
00456 switch( p_stream->i_fourcc )
00457 {
00458 case VLC_FOURCC( 's', 'u','b', 't' ):
00459 p_stream->p_oggds_header = malloc( sizeof(oggds_header_t) );
00460 memset( p_stream->p_oggds_header, 0, sizeof(oggds_header_t) );
00461 p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
00462
00463 memcpy( p_stream->p_oggds_header->stream_type, "text", 4 );
00464 msg_Dbg( p_mux, "subtitles stream" );
00465 break;
00466
00467 default:
00468 FREE( p_input->p_sys );
00469 return VLC_EGENERIC;
00470 }
00471 break;
00472 default:
00473 FREE( p_input->p_sys );
00474 return VLC_EGENERIC;
00475 }
00476
00477 p_stream->b_new = VLC_TRUE;
00478
00479 p_sys->i_add_streams++;
00480
00481 return VLC_SUCCESS;
00482 }
00483
00484
00485
00486
00487 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
00488 {
00489 sout_mux_sys_t *p_sys = p_mux->p_sys;
00490 ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
00491 block_t *p_og;
00492
00493 msg_Dbg( p_mux, "removing input" );
00494
00495
00496 if( p_input->p_sys )
00497 {
00498 if( !p_stream->b_new )
00499 {
00500 while( p_input->p_fifo->i_depth ) MuxBlock( p_mux, p_input );
00501 }
00502
00503 if( !p_stream->b_new &&
00504 ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
00505 {
00506 OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
00507 sout_AccessOutWrite( p_mux->p_access, p_og );
00508 }
00509
00510
00511 if( !p_stream->b_new )
00512 {
00513 p_sys->pp_del_streams = realloc( p_sys->pp_del_streams,
00514 (p_sys->i_del_streams + 1) *
00515 sizeof(ogg_stream_t *) );
00516 p_sys->pp_del_streams[p_sys->i_del_streams++] = p_stream;
00517 }
00518 else
00519 {
00520
00521 FREE( p_stream->p_oggds_header );
00522 FREE( p_stream );
00523 p_sys->i_add_streams--;
00524 }
00525 }
00526
00527 p_input->p_sys = NULL;
00528
00529 return 0;
00530 }
00531
00532
00533
00534
00535 static block_t *OggStreamFlush( sout_mux_t *p_mux,
00536 ogg_stream_state *p_os, mtime_t i_pts )
00537 {
00538 block_t *p_og, *p_og_first = NULL;
00539 ogg_page og;
00540
00541 while( ogg_stream_flush( p_os, &og ) )
00542 {
00543
00544 p_og = block_New( p_mux, og.header_len + og.body_len );
00545
00546 memcpy( p_og->p_buffer, og.header, og.header_len );
00547 memcpy( p_og->p_buffer + og.header_len, og.body, og.body_len );
00548 p_og->i_dts = 0;
00549 p_og->i_pts = i_pts;
00550 p_og->i_length = 0;
00551
00552 i_pts = 0;
00553
00554 block_ChainAppend( &p_og_first, p_og );
00555 }
00556
00557 return p_og_first;
00558 }
00559
00560 static block_t *OggStreamPageOut( sout_mux_t *p_mux,
00561 ogg_stream_state *p_os, mtime_t i_pts )
00562 {
00563 block_t *p_og, *p_og_first = NULL;
00564 ogg_page og;
00565
00566 while( ogg_stream_pageout( p_os, &og ) )
00567 {
00568
00569 p_og = block_New( p_mux, og.header_len + og.body_len );
00570
00571 memcpy( p_og->p_buffer, og.header, og.header_len );
00572 memcpy( p_og->p_buffer + og.header_len, og.body, og.body_len );
00573 p_og->i_dts = 0;
00574 p_og->i_pts = i_pts;
00575 p_og->i_length = 0;
00576
00577 i_pts = 0;
00578
00579 block_ChainAppend( &p_og_first, p_og );
00580 }
00581
00582 return p_og_first;
00583 }
00584
00585 static block_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
00586 {
00587 block_t *p_hdr = NULL;
00588 block_t *p_og = NULL;
00589 ogg_packet op;
00590 uint8_t *p_extra;
00591 int i, i_extra;
00592
00593
00594
00595 for( i = 0; i < p_mux->i_nb_inputs; i++ )
00596 {
00597 sout_input_t *p_input = p_mux->pp_inputs[i];
00598 ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
00599 p_stream->b_new = VLC_FALSE;
00600
00601 msg_Dbg( p_mux, "creating header for %4.4s",
00602 (char *)&p_stream->i_fourcc );
00603
00604 ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
00605 p_stream->i_packet_no = 0;
00606
00607 if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
00608 p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) ||
00609 p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
00610 {
00611
00612 p_extra = p_input->p_fmt->p_extra;
00613 i_extra = p_input->p_fmt->i_extra;
00614
00615 op.bytes = *(p_extra++) << 8;
00616 op.bytes |= (*(p_extra++) & 0xFF);
00617 op.packet = p_extra;
00618 i_extra -= (op.bytes + 2);
00619 if( i_extra < 0 )
00620 {
00621 msg_Err( p_mux, "header data corrupted");
00622 op.bytes += i_extra;
00623 }
00624
00625 op.b_o_s = 1;
00626 op.e_o_s = 0;
00627 op.granulepos = 0;
00628 op.packetno = p_stream->i_packet_no++;
00629 ogg_stream_packetin( &p_stream->os, &op );
00630 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
00631
00632
00633 if( p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
00634 {
00635 int i_keyframe_frequency_force =
00636 1 << ((op.packet[40] << 6 >> 3) | (op.packet[41] >> 5));
00637
00638
00639 p_stream->i_keyframe_granule_shift = 0;
00640 i_keyframe_frequency_force--;
00641 while( i_keyframe_frequency_force )
00642 {
00643 p_stream->i_keyframe_granule_shift++;
00644 i_keyframe_frequency_force >>= 1;
00645 }
00646 }
00647 }
00648 else if( p_stream->i_fourcc == VLC_FOURCC( 'f', 'l', 'a', 'c' ) )
00649 {
00650
00651 op.packet = (unsigned char *)"fLaC";
00652 op.bytes = 4;
00653 op.b_o_s = 1;
00654 op.e_o_s = 0;
00655 op.granulepos = 0;
00656 op.packetno = p_stream->i_packet_no++;
00657 ogg_stream_packetin( &p_stream->os, &op );
00658 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
00659 }
00660 else if( p_stream->p_oggds_header )
00661 {
00662
00663 op.packet = (uint8_t*)p_stream->p_oggds_header;
00664 op.bytes = p_stream->p_oggds_header->i_size + 1;
00665 op.b_o_s = 1;
00666 op.e_o_s = 0;
00667 op.granulepos = 0;
00668 op.packetno = p_stream->i_packet_no++;
00669 ogg_stream_packetin( &p_stream->os, &op );
00670 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
00671 }
00672
00673 block_ChainAppend( &p_hdr, p_og );
00674 }
00675
00676
00677 for( i = 0; i < p_mux->i_nb_inputs; i++ )
00678 {
00679 sout_input_t *p_input = p_mux->pp_inputs[i];
00680 ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
00681
00682 if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
00683 p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) ||
00684 p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
00685 {
00686
00687
00688 int j = 2;
00689
00690 if( p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) ) j = 1;
00691
00692 p_extra = p_input->p_fmt->p_extra;
00693 i_extra = p_input->p_fmt->i_extra;
00694
00695
00696 op.bytes = *(p_extra++) << 8;
00697 op.bytes |= (*(p_extra++) & 0xFF);
00698 op.packet = p_extra;
00699 p_extra += op.bytes;
00700 i_extra -= (op.bytes + 2);
00701
00702 while( j-- )
00703 {
00704 op.bytes = *(p_extra++) << 8;
00705 op.bytes |= (*(p_extra++) & 0xFF);
00706 op.packet = p_extra;
00707 p_extra += op.bytes;
00708 i_extra -= (op.bytes + 2);
00709 if( i_extra < 0 )
00710 {
00711 msg_Err( p_mux, "header data corrupted");
00712 op.bytes += i_extra;
00713 }
00714
00715 op.b_o_s = 0;
00716 op.e_o_s = 0;
00717 op.granulepos = 0;
00718 op.packetno = p_stream->i_packet_no++;
00719 ogg_stream_packetin( &p_stream->os, &op );
00720
00721 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
00722 block_ChainAppend( &p_hdr, p_og );
00723 }
00724 }
00725 else if( p_stream->i_fourcc != VLC_FOURCC( 'f', 'l', 'a', 'c' ) )
00726 {
00727 uint8_t com[128];
00728 int i_com;
00729
00730
00731 com[0] = PACKET_TYPE_COMMENT;
00732 i_com = snprintf( (char *)(com+1), 127,
00733 PACKAGE_VERSION" stream output" )
00734 + 1;
00735 op.packet = com;
00736 op.bytes = i_com;
00737 op.b_o_s = 0;
00738 op.e_o_s = 0;
00739 op.granulepos = 0;
00740 op.packetno = p_stream->i_packet_no++;
00741 ogg_stream_packetin( &p_stream->os, &op );
00742 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
00743 block_ChainAppend( &p_hdr, p_og );
00744 }
00745
00746
00747 if( ( p_stream->i_fourcc == VLC_FOURCC( 'm', 'p', '4', 'v' ) ||
00748 p_stream->i_fourcc == VLC_FOURCC( 'f', 'l', 'a', 'c' ) ) &&
00749 p_input->p_fmt->i_extra )
00750 {
00751
00752
00753 msg_Dbg( p_mux, "writing extra data" );
00754 op.bytes = p_input->p_fmt->i_extra;
00755 op.packet = p_input->p_fmt->p_extra;
00756 if( p_stream->i_fourcc == VLC_FOURCC( 'f', 'l', 'a', 'c' ) )
00757 {
00758
00759 op.bytes -= 4;
00760 op.packet+= 4;
00761 }
00762 op.b_o_s = 0;
00763 op.e_o_s = 0;
00764 op.granulepos = 0;
00765 op.packetno = p_stream->i_packet_no++;
00766 ogg_stream_packetin( &p_stream->os, &op );
00767 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
00768 block_ChainAppend( &p_hdr, p_og );
00769 }
00770 }
00771
00772
00773 for( p_og = p_hdr; p_og != NULL; p_og = p_og->p_next )
00774 {
00775 p_og->i_flags |= BLOCK_FLAG_HEADER;
00776 }
00777 return p_hdr;
00778 }
00779
00780 static block_t *OggCreateFooter( sout_mux_t *p_mux, mtime_t i_dts )
00781 {
00782 sout_mux_sys_t *p_sys = p_mux->p_sys;
00783 block_t *p_hdr = NULL;
00784 block_t *p_og;
00785 ogg_packet op;
00786 int i;
00787
00788
00789 for( i = 0; i < p_mux->i_nb_inputs; i++ )
00790 {
00791 ogg_stream_t *p_stream = p_mux->pp_inputs[i]->p_sys;
00792
00793
00794 if( p_stream->b_new ) continue;
00795
00796 if( ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
00797 {
00798 OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
00799 sout_AccessOutWrite( p_mux->p_access, p_og );
00800 }
00801 }
00802
00803
00804 for( i = 0; i < p_mux->i_nb_inputs; i++ )
00805 {
00806 ogg_stream_t *p_stream = p_mux->pp_inputs[i]->p_sys;
00807
00808
00809 if( p_stream->b_new ) continue;
00810
00811 op.packet = NULL;
00812 op.bytes = 0;
00813 op.b_o_s = 0;
00814 op.e_o_s = 1;
00815 op.granulepos = -1;
00816 op.packetno = p_stream->i_packet_no++;
00817 ogg_stream_packetin( &p_stream->os, &op );
00818
00819 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
00820 block_ChainAppend( &p_hdr, p_og );
00821 ogg_stream_clear( &p_stream->os );
00822 }
00823
00824 for( i = 0; i < p_sys->i_del_streams; i++ )
00825 {
00826 op.packet = NULL;
00827 op.bytes = 0;
00828 op.b_o_s = 0;
00829 op.e_o_s = 1;
00830 op.granulepos = -1;
00831 op.packetno = p_sys->pp_del_streams[i]->i_packet_no++;
00832 ogg_stream_packetin( &p_sys->pp_del_streams[i]->os, &op );
00833
00834 p_og = OggStreamFlush( p_mux, &p_sys->pp_del_streams[i]->os, 0 );
00835 block_ChainAppend( &p_hdr, p_og );
00836 ogg_stream_clear( &p_sys->pp_del_streams[i]->os );
00837 }
00838
00839 return p_hdr;
00840 }
00841
00842 static void OggSetDate( block_t *p_og, mtime_t i_dts, mtime_t i_length )
00843 {
00844 int i_count;
00845 block_t *p_tmp;
00846 mtime_t i_delta;
00847
00848 for( p_tmp = p_og, i_count = 0; p_tmp != NULL; p_tmp = p_tmp->p_next )
00849 {
00850 i_count++;
00851 }
00852 i_delta = i_length / i_count;
00853
00854 for( p_tmp = p_og; p_tmp != NULL; p_tmp = p_tmp->p_next )
00855 {
00856 p_tmp->i_dts = i_dts;
00857 p_tmp->i_length = i_delta;
00858
00859 i_dts += i_delta;
00860 }
00861 }
00862
00863
00864
00865
00866 static int Mux( sout_mux_t *p_mux )
00867 {
00868 sout_mux_sys_t *p_sys = p_mux->p_sys;
00869 block_t *p_og = NULL;
00870 int i_stream;
00871 mtime_t i_dts;
00872
00873 if( p_sys->i_add_streams || p_sys->i_del_streams )
00874 {
00875
00876 if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 )
00877 {
00878 msg_Dbg( p_mux, "waiting for data..." );
00879 return VLC_SUCCESS;
00880 }
00881
00882 if( p_sys->i_streams )
00883 {
00884
00885 int i;
00886
00887 msg_Dbg( p_mux, "writing footer" );
00888 block_ChainAppend( &p_og, OggCreateFooter( p_mux, 0 ) );
00889
00890
00891 for( i = 0; i < p_sys->i_del_streams; i++ )
00892 {
00893 FREE( p_sys->pp_del_streams[i]->p_oggds_header );
00894 FREE( p_sys->pp_del_streams[i] );
00895 }
00896 FREE( p_sys->pp_del_streams );
00897 p_sys->i_streams = 0;
00898 }
00899
00900 msg_Dbg( p_mux, "writing header" );
00901 p_sys->i_start_dts = i_dts;
00902 p_sys->i_streams = p_mux->i_nb_inputs;
00903 p_sys->i_del_streams = 0;
00904 p_sys->i_add_streams = 0;
00905 block_ChainAppend( &p_og, OggCreateHeader( p_mux, i_dts ) );
00906
00907
00908 OggSetDate( p_og, i_dts, 0 );
00909 sout_AccessOutWrite( p_mux->p_access, p_og );
00910 p_og = NULL;
00911 }
00912
00913 for( ;; )
00914 {
00915 if( MuxGetStream( p_mux, &i_stream, 0 ) < 0 ) return VLC_SUCCESS;
00916 MuxBlock( p_mux, p_mux->pp_inputs[i_stream] );
00917 }
00918
00919 return VLC_SUCCESS;
00920 }
00921
00922 static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input )
00923 {
00924 sout_mux_sys_t *p_sys = p_mux->p_sys;
00925 ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
00926 block_t *p_data = block_FifoGet( p_input->p_fifo );
00927 block_t *p_og = NULL;
00928 ogg_packet op;
00929
00930 if( p_stream->i_fourcc != VLC_FOURCC( 'v', 'o', 'r', 'b' ) &&
00931 p_stream->i_fourcc != VLC_FOURCC( 'f', 'l', 'a', 'c' ) &&
00932 p_stream->i_fourcc != VLC_FOURCC( 's', 'p', 'x', ' ' ) &&
00933 p_stream->i_fourcc != VLC_FOURCC( 't', 'h', 'e', 'o' ) )
00934 {
00935 p_data = block_Realloc( p_data, 1, p_data->i_buffer );
00936 p_data->p_buffer[0] = PACKET_IS_SYNCPOINT;
00937 }
00938
00939 op.packet = p_data->p_buffer;
00940 op.bytes = p_data->i_buffer;
00941 op.b_o_s = 0;
00942 op.e_o_s = 0;
00943 op.packetno = p_stream->i_packet_no++;
00944
00945 if( p_stream->i_cat == AUDIO_ES )
00946 {
00947 if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
00948 p_stream->i_fourcc == VLC_FOURCC( 'f', 'l', 'a', 'c' ) ||
00949 p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) )
00950 {
00951
00952 op.granulepos =
00953 ( p_data->i_dts - p_sys->i_start_dts + p_data->i_length ) *
00954 (mtime_t)p_input->p_fmt->audio.i_rate / I64C(1000000);
00955 }
00956 else if( p_stream->p_oggds_header )
00957 {
00958
00959 op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) *
00960 p_stream->p_oggds_header->i_samples_per_unit / I64C(1000000);
00961 }
00962 }
00963 else if( p_stream->i_cat == VIDEO_ES )
00964 {
00965 if( p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
00966 {
00967
00968 op.granulepos = ( ( p_data->i_dts - p_sys->i_start_dts ) *
00969 p_input->p_fmt->video.i_frame_rate /
00970 p_input->p_fmt->video.i_frame_rate_base /
00971 I64C(1000000) ) << p_stream->i_keyframe_granule_shift;
00972 }
00973 else if( p_stream->p_oggds_header )
00974 op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) * I64C(10) /
00975 p_stream->p_oggds_header->i_time_unit;
00976 }
00977 else if( p_stream->i_cat == SPU_ES )
00978 {
00979
00980 op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) / 1000;
00981 }
00982
00983 ogg_stream_packetin( &p_stream->os, &op );
00984
00985 if( p_stream->i_cat == SPU_ES ||
00986 p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) )
00987 {
00988
00989
00990 p_og = OggStreamFlush( p_mux, &p_stream->os, p_data->i_dts );
00991 }
00992 else
00993 {
00994 p_og = OggStreamPageOut( p_mux, &p_stream->os, p_data->i_dts );
00995 }
00996
00997 if( p_og )
00998 {
00999 OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
01000 p_stream->i_dts = -1;
01001 p_stream->i_length = 0;
01002
01003 sout_AccessOutWrite( p_mux->p_access, p_og );
01004 }
01005 else
01006 {
01007 if( p_stream->i_dts < 0 )
01008 {
01009 p_stream->i_dts = p_data->i_dts;
01010 }
01011 p_stream->i_length += p_data->i_length;
01012 }
01013
01014 block_Release( p_data );
01015 return VLC_SUCCESS;
01016 }