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
6 * $Id: ps.c,v 1.16 2003/11/21 15:32:08 fenrir Exp $
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 *, sout_buffer_t **, mtime_t );
76 static void MuxWriteSystemHeader( sout_mux_t *, sout_buffer_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->i_preheader = 30; // really enough for a pes header
124 p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
126 /* Init free stream id */
127 StreamIdInit( p_sys->stream_id_a52, 8 );
128 StreamIdInit( p_sys->stream_id_dts, 8 );
129 StreamIdInit( p_sys->stream_id_mpga, 16 );
130 StreamIdInit( p_sys->stream_id_mpgv, 16 );
131 StreamIdInit( p_sys->stream_id_lpcm, 16 );
132 StreamIdInit( p_sys->stream_id_spu, 32 );
134 p_sys->i_audio_bound = 0;
135 p_sys->i_video_bound = 0;
136 p_sys->i_system_header = 0;
137 p_sys->i_pes_count = 0;
139 p_sys->b_mpeg2 = !(p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mpeg1" ));
144 /*****************************************************************************
146 *****************************************************************************/
147 static void Close( vlc_object_t * p_this )
149 sout_mux_t *p_mux = (sout_mux_t*)p_this;
150 sout_mux_sys_t *p_sys = p_mux->p_sys;
152 sout_buffer_t *p_end;
154 msg_Info( p_mux, "Close" );
156 p_end = sout_BufferNew( p_mux->p_sout, 4 );
157 p_end->p_buffer[0] = 0x00;
158 p_end->p_buffer[1] = 0x00;
159 p_end->p_buffer[2] = 0x01;
160 p_end->p_buffer[3] = 0xb9;
162 sout_AccessOutWrite( p_mux->p_access, p_end );
167 /*****************************************************************************
169 *****************************************************************************/
170 static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
175 case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
176 *(vlc_bool_t*)p_answer = VLC_TRUE;
177 return( SOUT_MUX_CAP_ERR_OK );
179 return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
183 /*****************************************************************************
185 *****************************************************************************/
186 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
188 sout_mux_sys_t *p_sys = p_mux->p_sys;
189 ps_stream_t *p_stream;
191 msg_Dbg( p_mux, "adding input codec=%4.4s", (char*)&p_input->p_fmt->i_codec );
193 p_input->p_sys = (void*)p_stream = malloc( sizeof( ps_stream_t ) );
195 /* Init this new stream */
196 switch( p_input->p_fmt->i_codec )
198 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
199 p_stream->i_stream_id = StreamIdGet( p_sys->stream_id_mpgv, 0xe0, 0xef );
201 case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
202 p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_lpcm, 0xa0, 0xaf );
204 case VLC_FOURCC( 'd', 't', 's', ' ' ):
205 p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_dts, 0x88, 0x8f );
207 case VLC_FOURCC( 'a', '5', '2', ' ' ):
208 p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_a52, 0x80, 0x87 );
210 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
211 p_stream->i_stream_id = StreamIdGet( p_sys->stream_id_mpga, 0xc0, 0xcf );
213 case VLC_FOURCC( 's', 'p', 'u', ' ' ):
214 p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_spu, 0x20, 0x3f );
220 if( p_stream->i_stream_id < 0 )
225 if( p_input->p_fmt->i_cat == AUDIO_ES )
227 p_sys->i_audio_bound++;
229 else if( p_input->p_fmt->i_cat == VIDEO_ES )
231 p_sys->i_video_bound++;
241 /*****************************************************************************
243 *****************************************************************************/
244 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
246 sout_mux_sys_t *p_sys = p_mux->p_sys;
247 ps_stream_t *p_stream =(ps_stream_t*)p_input->p_sys;
249 msg_Dbg( p_mux, "removing input" );
250 switch( p_input->p_fmt->i_codec )
252 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
253 StreamIdRelease( p_sys->stream_id_mpgv, 0xe0, p_stream->i_stream_id);
255 case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
256 StreamIdRelease( p_sys->stream_id_lpcm, 0xa0, p_stream->i_stream_id&0xff );
258 case VLC_FOURCC( 'd', 't', 's', ' ' ):
259 StreamIdRelease( p_sys->stream_id_dts, 0x88, p_stream->i_stream_id&0xff );
261 case VLC_FOURCC( 'a', '5', '2', ' ' ):
262 StreamIdRelease( p_sys->stream_id_a52, 0x80, p_stream->i_stream_id&0xff );
264 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
265 StreamIdRelease( p_sys->stream_id_mpga, 0xc0, p_stream->i_stream_id );
267 case VLC_FOURCC( 's', 'p', 'u', ' ' ):
268 StreamIdRelease( p_sys->stream_id_spu, 0x20, p_stream->i_stream_id&0xff );
275 if( p_input->p_fmt->i_cat == AUDIO_ES )
277 p_sys->i_audio_bound--;
279 else if( p_input->p_fmt->i_cat == VIDEO_ES )
281 p_sys->i_video_bound--;
288 /*****************************************************************************
289 * Mux: Call each time there is new data for at least one stream
290 *****************************************************************************/
291 static int Mux( sout_mux_t *p_mux )
293 sout_mux_sys_t *p_sys = p_mux->p_sys;
297 sout_input_t *p_input;
298 ps_stream_t *p_stream;
300 sout_buffer_t *p_ps, *p_data;
305 /* Choose which stream to mux */
306 if( MuxGetStream( p_mux, &i_stream, &i_dts ) )
310 p_input = p_mux->pp_inputs[i_stream];
311 p_stream = (ps_stream_t*)p_input->p_sys;
314 /* Write regulary PackHeader */
315 if( p_sys->i_pes_count % 30 == 0)
317 MuxWritePackHeader( p_mux, &p_ps, i_dts );
320 /* Write regulary SystemHeader */
321 if( p_sys->i_pes_count % 300 == 0 )
325 MuxWriteSystemHeader( p_mux, &p_ps );
327 /* For MPEG1 streaming, set HEADER flag */
328 for( p_pk = p_ps; p_pk != NULL; p_pk = p_pk->p_next )
330 p_pk->i_flags |= SOUT_BUFFER_FLAGS_HEADER;
334 /* Get and mux a packet */
335 p_data = sout_FifoGet( p_input->p_fifo );
336 E_( EStoPES )( p_mux->p_sout,
338 p_stream->i_stream_id,
339 p_mux->p_sys->b_mpeg2 );
341 sout_BufferChain( &p_ps, p_data );
342 sout_AccessOutWrite( p_mux->p_access, p_ps );
344 /* Increase counter */
345 p_sys->i_pes_count++;
352 /*****************************************************************************
354 *****************************************************************************/
355 static void StreamIdInit ( vlc_bool_t *id, int i_range )
359 for( i = 0; i < i_range; i++ )
364 static int StreamIdGet ( vlc_bool_t *id, int i_id_min, int i_id_max )
368 for( i = 0; i <= i_id_max - i_id_min; i++ )
379 static void StreamIdRelease( vlc_bool_t *id, int i_id_min, int i_id )
381 id[i_id - i_id_min] = VLC_TRUE;
384 static void MuxWritePackHeader( sout_mux_t *p_mux, sout_buffer_t **p_buf,
387 sout_buffer_t *p_hdr;
391 i_src = i_dts * 9 / 100;
393 p_hdr = sout_BufferNew( p_mux->p_sout, 18 );
394 bits_initwrite( &bits, 14, p_hdr->p_buffer );
395 bits_write( &bits, 32, 0x01ba );
397 if( p_mux->p_sys->b_mpeg2 )
399 bits_write( &bits, 2, 0x01 );
403 bits_write( &bits, 4, 0x02 );
406 bits_write( &bits, 3, ( i_src >> 30 )&0x07 );
407 bits_write( &bits, 1, 1 );
408 bits_write( &bits, 15, ( i_src >> 15 )&0x7fff );
409 bits_write( &bits, 1, 1 );
410 bits_write( &bits, 15, i_src&0x7fff );
411 bits_write( &bits, 1, 1 );
413 if( p_mux->p_sys->b_mpeg2 )
415 bits_write( &bits, 9, 0 ); // src extention
417 bits_write( &bits, 1, 1 );
419 bits_write( &bits, 22, 1000/8/50); // FIXME mux rate
420 bits_write( &bits, 1, 1 );
422 if( p_mux->p_sys->b_mpeg2 )
424 bits_write( &bits, 1, 1 );
425 bits_write( &bits, 5, 0x1f ); // FIXME reserved
426 bits_write( &bits, 3, 0 ); // stuffing bytes
429 p_hdr->i_size = p_mux->p_sys->b_mpeg2 ? 14: 12;
431 sout_BufferChain( p_buf, p_hdr );
434 static void MuxWriteSystemHeader( sout_mux_t *p_mux, sout_buffer_t **p_buf )
436 sout_mux_sys_t *p_sys = p_mux->p_sys;
437 sout_buffer_t *p_hdr;
439 vlc_bool_t b_private;
440 int i_nb_private, i_nb_stream;
443 /* Count the number of private stream */
444 for( i = 0, i_nb_private = 0; i < p_mux->i_nb_inputs; i++ )
446 ps_stream_t *p_stream;
448 p_stream = (ps_stream_t*)p_mux->pp_inputs[i]->p_sys;
450 if( ( p_stream->i_stream_id&0xff00 ) == 0xbd00 )
456 /* Private stream are declared only one time */
457 i_nb_stream = p_mux->i_nb_inputs - ( i_nb_private > 0 ? i_nb_private - 1 : 0 );
459 p_hdr = sout_BufferNew( p_mux->p_sout, 12 + i_nb_stream * 3 );
461 bits_initwrite( &bits, 12 + i_nb_stream * 3, p_hdr->p_buffer );
462 bits_write( &bits, 32, 0x01bb );
463 bits_write( &bits, 16, 12 - 6 + i_nb_stream * 3 );
464 bits_write( &bits, 1, 1 );
465 bits_write( &bits, 22, 0 ); // FIXME rate bound
466 bits_write( &bits, 1, 1 );
468 bits_write( &bits, 6, p_sys->i_audio_bound );
469 bits_write( &bits, 1, 0 ); // fixed flag
470 bits_write( &bits, 1, 0 ); // CSPS flag
471 bits_write( &bits, 1, 0 ); // system audio lock flag
472 bits_write( &bits, 1, 0 ); // system video lock flag
474 bits_write( &bits, 1, 1 ); // marker bit
476 bits_write( &bits, 5, p_sys->i_video_bound );
477 bits_write( &bits, 1, 1 ); // packet rate restriction flag (1 for mpeg1)
478 bits_write( &bits, 7, 0xff ); // reserved bits
480 /* stream_id table */
481 for( i = 0, b_private = VLC_FALSE; i < p_mux->i_nb_inputs; i++ )
483 sout_input_t *p_input;
484 ps_stream_t *p_stream;
486 p_input = p_mux->pp_inputs[i];
487 p_stream = (ps_stream_t *)p_input->p_sys;
489 if( ( p_stream->i_stream_id&0xff00 ) == 0xbd00 )
495 b_private = VLC_TRUE;
496 /* Write stream id */
497 bits_write( &bits, 8, 0xbd );
501 /* Write stream id */
502 bits_write( &bits, 8, p_stream->i_stream_id&0xff );
504 bits_write( &bits, 2, 0x03 );
505 if( p_input->p_fmt->i_cat == AUDIO_ES )
507 bits_write( &bits, 1, 0 );
508 bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 128 );
510 else if( p_input->p_fmt->i_cat == VIDEO_ES )
512 bits_write( &bits, 1, 1 );
513 bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 1024);
518 bits_write( &bits, 1, 0 );
519 bits_write( &bits, 13, /* stream->max_buffer_size */ 0 );
523 sout_BufferChain( p_buf, p_hdr );
527 * Find stream to be muxed.
529 static int MuxGetStream( sout_mux_t *p_mux,
537 for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
539 sout_input_t *p_input = p_mux->pp_inputs[i];
540 sout_buffer_t *p_data;
542 if( p_input->p_fifo->i_depth <= 0 )
544 if( p_input->p_fmt->i_cat == AUDIO_ES ||
545 p_input->p_fmt->i_cat == VIDEO_ES )
547 /* We need that audio+video fifo contain at least 1 packet */
554 p_data = sout_FifoShow( p_input->p_fifo );
555 if( i_stream == -1 ||
556 p_data->i_dts < i_dts )
559 i_dts = p_data->i_dts;
563 *pi_stream = i_stream;