1 /*****************************************************************************
2 * ps.c: MPEG PS (ISO/IEC 13818-1) / MPEG SYSTEM (ISO/IEC 1172-1)
3 * multiplexer module for vlc
4 *****************************************************************************
5 * Copyright (C) 2001, 2002 VideoLAN
8 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * Eric Petit <titer@videolan.org>
10 * Gildas Bazin <gbazin@netcourrier.com>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
34 #include <vlc/input.h>
42 * - test support of DTS, LPCM
46 /*****************************************************************************
48 *****************************************************************************/
49 static int Open ( vlc_object_t * );
50 static void Close ( vlc_object_t * );
53 set_description( _("PS muxer") );
54 set_capability( "sout mux", 50 );
56 add_shortcut( "mpeg1" );
57 set_callbacks( Open, Close );
61 /*****************************************************************************
63 *****************************************************************************/
64 static int Capability(sout_mux_t *, int, void *, void * );
65 static int AddStream( sout_mux_t *, sout_input_t * );
66 static int DelStream( sout_mux_t *, sout_input_t * );
67 static int Mux ( sout_mux_t * );
70 /*****************************************************************************
72 *****************************************************************************/
73 static int MuxGetStream ( sout_mux_t *, int *, mtime_t * );
75 static void MuxWritePackHeader ( sout_mux_t *, block_t **, mtime_t );
76 static void MuxWriteSystemHeader( sout_mux_t *, block_t ** );
78 static void StreamIdInit ( vlc_bool_t *id, int i_range );
79 static int StreamIdGet ( vlc_bool_t *id, int i_id_min, int i_id_max );
80 static void StreamIdRelease ( vlc_bool_t *id, int i_id_min, int i_id );
82 typedef struct ps_stream_s
90 /* Which id are unused */
91 vlc_bool_t stream_id_mpga[16]; /* 0xc0 -> 0xcf */
92 vlc_bool_t stream_id_mpgv[16]; /* 0xe0 -> 0xef */
93 vlc_bool_t stream_id_a52[8]; /* 0x80 -> 0x87 <- FIXME I'm not sure */
94 vlc_bool_t stream_id_spu[32]; /* 0x20 -> 0x3f */
95 vlc_bool_t stream_id_dts[8]; /* 0x88 -> 0x8f */
96 vlc_bool_t stream_id_lpcm[16]; /* 0xa0 -> 0xaf */
109 /*****************************************************************************
111 *****************************************************************************/
112 static int Open( vlc_object_t *p_this )
114 sout_mux_t *p_mux = (sout_mux_t*)p_this;
115 sout_mux_sys_t *p_sys;
117 msg_Info( p_mux, "Open" );
119 p_mux->pf_capacity = Capability;
120 p_mux->pf_addstream = AddStream;
121 p_mux->pf_delstream = DelStream;
123 p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
125 /* Init free stream id */
126 StreamIdInit( p_sys->stream_id_a52, 8 );
127 StreamIdInit( p_sys->stream_id_dts, 8 );
128 StreamIdInit( p_sys->stream_id_mpga, 16 );
129 StreamIdInit( p_sys->stream_id_mpgv, 16 );
130 StreamIdInit( p_sys->stream_id_lpcm, 16 );
131 StreamIdInit( p_sys->stream_id_spu, 32 );
133 p_sys->i_audio_bound = 0;
134 p_sys->i_video_bound = 0;
135 p_sys->i_system_header = 0;
136 p_sys->i_pes_count = 0;
138 p_sys->b_mpeg2 = !(p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mpeg1" ));
143 /*****************************************************************************
145 *****************************************************************************/
146 static void Close( vlc_object_t * p_this )
148 sout_mux_t *p_mux = (sout_mux_t*)p_this;
149 sout_mux_sys_t *p_sys = p_mux->p_sys;
153 msg_Info( p_mux, "Close" );
155 p_end = block_New( p_mux, 4 );
156 p_end->p_buffer[0] = 0x00;
157 p_end->p_buffer[1] = 0x00;
158 p_end->p_buffer[2] = 0x01;
159 p_end->p_buffer[3] = 0xb9;
161 sout_AccessOutWrite( p_mux->p_access, p_end );
166 /*****************************************************************************
168 *****************************************************************************/
169 static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
174 case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
175 *(vlc_bool_t*)p_answer = VLC_TRUE;
176 return( SOUT_MUX_CAP_ERR_OK );
178 return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
182 /*****************************************************************************
184 *****************************************************************************/
185 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
187 sout_mux_sys_t *p_sys = p_mux->p_sys;
188 ps_stream_t *p_stream;
190 msg_Dbg( p_mux, "adding input codec=%4.4s", (char*)&p_input->p_fmt->i_codec );
192 p_input->p_sys = (void*)p_stream = malloc( sizeof( ps_stream_t ) );
194 /* Init this new stream */
195 switch( p_input->p_fmt->i_codec )
197 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
198 p_stream->i_stream_id = StreamIdGet( p_sys->stream_id_mpgv, 0xe0, 0xef );
200 case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
201 p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_lpcm, 0xa0, 0xaf );
203 case VLC_FOURCC( 'd', 't', 's', ' ' ):
204 p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_dts, 0x88, 0x8f );
206 case VLC_FOURCC( 'a', '5', '2', ' ' ):
207 p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_a52, 0x80, 0x87 );
209 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
210 p_stream->i_stream_id = StreamIdGet( p_sys->stream_id_mpga, 0xc0, 0xcf );
212 case VLC_FOURCC( 's', 'p', 'u', ' ' ):
213 p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_spu, 0x20, 0x3f );
219 if( p_stream->i_stream_id < 0 )
224 if( p_input->p_fmt->i_cat == AUDIO_ES )
226 p_sys->i_audio_bound++;
228 else if( p_input->p_fmt->i_cat == VIDEO_ES )
230 p_sys->i_video_bound++;
240 /*****************************************************************************
242 *****************************************************************************/
243 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
245 sout_mux_sys_t *p_sys = p_mux->p_sys;
246 ps_stream_t *p_stream =(ps_stream_t*)p_input->p_sys;
248 msg_Dbg( p_mux, "removing input" );
249 switch( p_input->p_fmt->i_codec )
251 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
252 StreamIdRelease( p_sys->stream_id_mpgv, 0xe0, p_stream->i_stream_id);
254 case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
255 StreamIdRelease( p_sys->stream_id_lpcm, 0xa0, p_stream->i_stream_id&0xff );
257 case VLC_FOURCC( 'd', 't', 's', ' ' ):
258 StreamIdRelease( p_sys->stream_id_dts, 0x88, p_stream->i_stream_id&0xff );
260 case VLC_FOURCC( 'a', '5', '2', ' ' ):
261 StreamIdRelease( p_sys->stream_id_a52, 0x80, p_stream->i_stream_id&0xff );
263 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
264 StreamIdRelease( p_sys->stream_id_mpga, 0xc0, p_stream->i_stream_id );
266 case VLC_FOURCC( 's', 'p', 'u', ' ' ):
267 StreamIdRelease( p_sys->stream_id_spu, 0x20, p_stream->i_stream_id&0xff );
274 if( p_input->p_fmt->i_cat == AUDIO_ES )
276 p_sys->i_audio_bound--;
278 else if( p_input->p_fmt->i_cat == VIDEO_ES )
280 p_sys->i_video_bound--;
287 /*****************************************************************************
288 * Mux: Call each time there is new data for at least one stream
289 *****************************************************************************/
290 static int Mux( sout_mux_t *p_mux )
292 sout_mux_sys_t *p_sys = p_mux->p_sys;
296 sout_input_t *p_input;
297 ps_stream_t *p_stream;
299 block_t *p_ps, *p_data;
304 /* Choose which stream to mux */
305 if( MuxGetStream( p_mux, &i_stream, &i_dts ) )
309 p_input = p_mux->pp_inputs[i_stream];
310 p_stream = (ps_stream_t*)p_input->p_sys;
313 /* Write regulary PackHeader */
314 if( p_sys->i_pes_count % 30 == 0)
316 MuxWritePackHeader( p_mux, &p_ps, i_dts );
319 /* Write regulary SystemHeader */
320 if( p_sys->i_pes_count % 300 == 0 )
324 MuxWriteSystemHeader( p_mux, &p_ps );
326 /* For MPEG1 streaming, set HEADER flag */
327 for( p_pk = p_ps; p_pk != NULL; p_pk = p_pk->p_next )
329 p_pk->i_flags |= BLOCK_FLAG_HEADER;
333 /* Get and mux a packet */
334 p_data = block_FifoGet( p_input->p_fifo );
335 E_( EStoPES )( p_mux->p_sout,
337 p_stream->i_stream_id,
338 p_mux->p_sys->b_mpeg2 );
340 block_ChainAppend( &p_ps, p_data );
341 sout_AccessOutWrite( p_mux->p_access, p_ps );
343 /* Increase counter */
344 p_sys->i_pes_count++;
351 /*****************************************************************************
353 *****************************************************************************/
354 static void StreamIdInit ( vlc_bool_t *id, int i_range )
358 for( i = 0; i < i_range; i++ )
363 static int StreamIdGet ( vlc_bool_t *id, int i_id_min, int i_id_max )
367 for( i = 0; i <= i_id_max - i_id_min; i++ )
378 static void StreamIdRelease( vlc_bool_t *id, int i_id_min, int i_id )
380 id[i_id - i_id_min] = VLC_TRUE;
383 static void MuxWritePackHeader( sout_mux_t *p_mux, block_t **p_buf,
390 i_src = i_dts * 9 / 100;
392 p_hdr = block_New( p_mux, 18 );
393 bits_initwrite( &bits, 14, p_hdr->p_buffer );
394 bits_write( &bits, 32, 0x01ba );
396 if( p_mux->p_sys->b_mpeg2 )
398 bits_write( &bits, 2, 0x01 );
402 bits_write( &bits, 4, 0x02 );
405 bits_write( &bits, 3, ( i_src >> 30 )&0x07 );
406 bits_write( &bits, 1, 1 );
407 bits_write( &bits, 15, ( i_src >> 15 )&0x7fff );
408 bits_write( &bits, 1, 1 );
409 bits_write( &bits, 15, i_src&0x7fff );
410 bits_write( &bits, 1, 1 );
412 if( p_mux->p_sys->b_mpeg2 )
414 bits_write( &bits, 9, 0 ); // src extention
416 bits_write( &bits, 1, 1 );
418 bits_write( &bits, 22, 1000/8/50); // FIXME mux rate
419 bits_write( &bits, 1, 1 );
421 if( p_mux->p_sys->b_mpeg2 )
423 bits_write( &bits, 1, 1 );
424 bits_write( &bits, 5, 0x1f ); // FIXME reserved
425 bits_write( &bits, 3, 0 ); // stuffing bytes
428 p_hdr->i_buffer = p_mux->p_sys->b_mpeg2 ? 14: 12;
430 block_ChainAppend( p_buf, p_hdr );
433 static void MuxWriteSystemHeader( sout_mux_t *p_mux, block_t **p_buf )
435 sout_mux_sys_t *p_sys = p_mux->p_sys;
438 vlc_bool_t b_private;
439 int i_nb_private, i_nb_stream;
442 /* Count the number of private stream */
443 for( i = 0, i_nb_private = 0; i < p_mux->i_nb_inputs; i++ )
445 ps_stream_t *p_stream;
447 p_stream = (ps_stream_t*)p_mux->pp_inputs[i]->p_sys;
449 if( ( p_stream->i_stream_id&0xff00 ) == 0xbd00 )
455 /* Private stream are declared only one time */
456 i_nb_stream = p_mux->i_nb_inputs - ( i_nb_private > 0 ? i_nb_private - 1 : 0 );
458 p_hdr = block_New( p_mux, 12 + i_nb_stream * 3 );
460 bits_initwrite( &bits, 12 + i_nb_stream * 3, p_hdr->p_buffer );
461 bits_write( &bits, 32, 0x01bb );
462 bits_write( &bits, 16, 12 - 6 + i_nb_stream * 3 );
463 bits_write( &bits, 1, 1 );
464 bits_write( &bits, 22, 0 ); // FIXME rate bound
465 bits_write( &bits, 1, 1 );
467 bits_write( &bits, 6, p_sys->i_audio_bound );
468 bits_write( &bits, 1, 0 ); // fixed flag
469 bits_write( &bits, 1, 0 ); // CSPS flag
470 bits_write( &bits, 1, 0 ); // system audio lock flag
471 bits_write( &bits, 1, 0 ); // system video lock flag
473 bits_write( &bits, 1, 1 ); // marker bit
475 bits_write( &bits, 5, p_sys->i_video_bound );
476 bits_write( &bits, 1, 1 ); // packet rate restriction flag (1 for mpeg1)
477 bits_write( &bits, 7, 0xff ); // reserved bits
479 /* stream_id table */
480 for( i = 0, b_private = VLC_FALSE; i < p_mux->i_nb_inputs; i++ )
482 sout_input_t *p_input;
483 ps_stream_t *p_stream;
485 p_input = p_mux->pp_inputs[i];
486 p_stream = (ps_stream_t *)p_input->p_sys;
488 if( ( p_stream->i_stream_id&0xff00 ) == 0xbd00 )
494 b_private = VLC_TRUE;
495 /* Write stream id */
496 bits_write( &bits, 8, 0xbd );
500 /* Write stream id */
501 bits_write( &bits, 8, p_stream->i_stream_id&0xff );
503 bits_write( &bits, 2, 0x03 );
504 if( p_input->p_fmt->i_cat == AUDIO_ES )
506 bits_write( &bits, 1, 0 );
507 bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 128 );
509 else if( p_input->p_fmt->i_cat == VIDEO_ES )
511 bits_write( &bits, 1, 1 );
512 bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 1024);
517 bits_write( &bits, 1, 0 );
518 bits_write( &bits, 13, /* stream->max_buffer_size */ 0 );
522 block_ChainAppend( p_buf, p_hdr );
526 * Find stream to be muxed.
528 static int MuxGetStream( sout_mux_t *p_mux,
536 for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
538 sout_input_t *p_input = p_mux->pp_inputs[i];
541 if( p_input->p_fifo->i_depth <= 0 )
543 if( p_input->p_fmt->i_cat == AUDIO_ES ||
544 p_input->p_fmt->i_cat == VIDEO_ES )
546 /* We need that audio+video fifo contain at least 1 packet */
553 p_data = block_FifoShow( p_input->p_fifo );
554 if( i_stream == -1 ||
555 p_data->i_dts < i_dts )
558 i_dts = p_data->i_dts;
562 *pi_stream = i_stream;