]> git.sesse.net Git - vlc/blob - modules/mux/mpeg/ps.c
* all: remove sout_format_t and use es_format_t instead.
[vlc] / modules / mux / mpeg / ps.c
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 $
7  *
8  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9  *          Eric Petit <titer@videolan.org>
10  *          Gildas Bazin <gbazin@netcourrier.com>
11  *
12  *
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.
17  *
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.
22  *
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  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <stdlib.h>
32
33 #include <vlc/vlc.h>
34 #include <vlc/input.h>
35 #include <vlc/sout.h>
36
37 #include "codecs.h"
38 #include "bits.h"
39 #include "pes.h"
40
41 /* TODO:
42  *  - test support of DTS, LPCM
43  *
44  */
45
46 /*****************************************************************************
47  * Module descriptor
48  *****************************************************************************/
49 static int     Open   ( vlc_object_t * );
50 static void    Close  ( vlc_object_t * );
51
52 vlc_module_begin();
53     set_description( _("PS muxer") );
54     set_capability( "sout mux", 50 );
55     add_shortcut( "ps" );
56     add_shortcut( "mpeg1" );
57     set_callbacks( Open, Close );
58 vlc_module_end();
59
60
61 /*****************************************************************************
62  * Exported prototypes
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 * );
68
69
70 /*****************************************************************************
71  * Local prototypes
72  *****************************************************************************/
73 static int  MuxGetStream        ( sout_mux_t *, int *, mtime_t * );
74
75 static void MuxWritePackHeader  ( sout_mux_t *, sout_buffer_t **, mtime_t );
76 static void MuxWriteSystemHeader( sout_mux_t *, sout_buffer_t ** );
77
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 );
81
82 typedef struct ps_stream_s
83 {
84     int             i_stream_id;
85
86 } ps_stream_t;
87
88 struct sout_mux_sys_t
89 {
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 */
97
98     int         i_audio_bound;
99     int         i_video_bound;
100
101     int         i_pes_count;
102
103     int         i_system_header;
104
105     vlc_bool_t  b_mpeg2;
106 };
107
108
109 /*****************************************************************************
110  * Open:
111  *****************************************************************************/
112 static int Open( vlc_object_t *p_this )
113 {
114     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
115     sout_mux_sys_t  *p_sys;
116
117     msg_Info( p_mux, "Open" );
118
119     p_mux->pf_capacity  = Capability;
120     p_mux->pf_addstream = AddStream;
121     p_mux->pf_delstream = DelStream;
122     p_mux->pf_mux       = Mux;
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 ) );
125
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 );
133
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;
138
139     p_sys->b_mpeg2 = !(p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mpeg1" ));
140
141     return VLC_SUCCESS;
142 }
143
144 /*****************************************************************************
145  * Close:
146  *****************************************************************************/
147 static void Close( vlc_object_t * p_this )
148 {
149     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
150     sout_mux_sys_t  *p_sys = p_mux->p_sys;
151
152     sout_buffer_t   *p_end;
153
154     msg_Info( p_mux, "Close" );
155
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;
161
162     sout_AccessOutWrite( p_mux->p_access, p_end );
163
164     free( p_sys );
165 }
166
167 /*****************************************************************************
168  * Capability:
169  *****************************************************************************/
170 static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
171                        void *p_answer )
172 {
173    switch( i_query )
174    {
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 );
178         default:
179             return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
180    }
181 }
182
183 /*****************************************************************************
184  * AddStream:
185  *****************************************************************************/
186 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
187 {
188     sout_mux_sys_t  *p_sys = p_mux->p_sys;
189     ps_stream_t         *p_stream;
190
191     msg_Dbg( p_mux, "adding input codec=%4.4s", (char*)&p_input->p_fmt->i_codec );
192
193     p_input->p_sys = (void*)p_stream = malloc( sizeof( ps_stream_t ) );
194
195     /* Init this new stream */
196     switch( p_input->p_fmt->i_codec )
197     {
198         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
199             p_stream->i_stream_id = StreamIdGet( p_sys->stream_id_mpgv, 0xe0, 0xef );
200             break;
201         case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
202             p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_lpcm, 0xa0, 0xaf );
203             break;
204         case VLC_FOURCC( 'd', 't', 's', ' ' ):
205             p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_dts, 0x88, 0x8f );
206             break;
207         case VLC_FOURCC( 'a', '5', '2', ' ' ):
208             p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_a52, 0x80, 0x87 );
209             break;
210         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
211             p_stream->i_stream_id = StreamIdGet( p_sys->stream_id_mpga, 0xc0, 0xcf );
212             break;
213         case VLC_FOURCC( 's', 'p', 'u', ' ' ):
214             p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_spu, 0x20, 0x3f );
215             break;
216         default:
217             goto error;
218     }
219
220     if( p_stream->i_stream_id < 0 )
221     {
222         goto error;
223     }
224
225     if( p_input->p_fmt->i_cat == AUDIO_ES )
226     {
227         p_sys->i_audio_bound++;
228     }
229     else if( p_input->p_fmt->i_cat == VIDEO_ES )
230     {
231         p_sys->i_video_bound++;
232     }
233
234     return VLC_SUCCESS;
235
236 error:
237     free( p_stream );
238     return VLC_EGENERIC;
239 }
240
241 /*****************************************************************************
242  * DelStream:
243  *****************************************************************************/
244 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
245 {
246     sout_mux_sys_t  *p_sys = p_mux->p_sys;
247     ps_stream_t *p_stream =(ps_stream_t*)p_input->p_sys;
248
249     msg_Dbg( p_mux, "removing input" );
250     switch( p_input->p_fmt->i_codec )
251     {
252         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
253             StreamIdRelease( p_sys->stream_id_mpgv, 0xe0, p_stream->i_stream_id);
254             break;
255         case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
256             StreamIdRelease( p_sys->stream_id_lpcm, 0xa0, p_stream->i_stream_id&0xff );
257             break;
258         case VLC_FOURCC( 'd', 't', 's', ' ' ):
259             StreamIdRelease( p_sys->stream_id_dts, 0x88, p_stream->i_stream_id&0xff );
260             break;
261         case VLC_FOURCC( 'a', '5', '2', ' ' ):
262             StreamIdRelease( p_sys->stream_id_a52, 0x80, p_stream->i_stream_id&0xff );
263             break;
264         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
265             StreamIdRelease( p_sys->stream_id_mpga, 0xc0, p_stream->i_stream_id  );
266             break;
267         case VLC_FOURCC( 's', 'p', 'u', ' ' ):
268             StreamIdRelease( p_sys->stream_id_spu, 0x20, p_stream->i_stream_id&0xff );
269             break;
270         default:
271             /* Never reached */
272             break;
273     }
274
275     if( p_input->p_fmt->i_cat == AUDIO_ES )
276     {
277         p_sys->i_audio_bound--;
278     }
279     else if( p_input->p_fmt->i_cat == VIDEO_ES )
280     {
281         p_sys->i_video_bound--;
282     }
283
284     free( p_stream );
285     return VLC_SUCCESS;
286 }
287
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 )
292 {
293     sout_mux_sys_t *p_sys = p_mux->p_sys;
294
295     for( ;; )
296     {
297         sout_input_t *p_input;
298         ps_stream_t *p_stream;
299
300         sout_buffer_t *p_ps, *p_data;
301
302         mtime_t        i_dts;
303         int            i_stream;
304
305         /* Choose which stream to mux */
306         if( MuxGetStream( p_mux, &i_stream, &i_dts ) )
307         {
308             return VLC_SUCCESS;
309         }
310         p_input  = p_mux->pp_inputs[i_stream];
311         p_stream = (ps_stream_t*)p_input->p_sys;
312         p_ps     = NULL;
313
314         /* Write regulary PackHeader */
315         if( p_sys->i_pes_count % 30 == 0)
316         {
317             MuxWritePackHeader( p_mux, &p_ps, i_dts );
318         }
319
320         /* Write regulary SystemHeader */
321         if( p_sys->i_pes_count % 300 == 0 )
322         {
323             sout_buffer_t *p_pk;
324
325             MuxWriteSystemHeader( p_mux, &p_ps );
326
327             /* For MPEG1 streaming, set HEADER flag */
328             for( p_pk = p_ps; p_pk != NULL; p_pk = p_pk->p_next )
329             {
330                 p_pk->i_flags |= SOUT_BUFFER_FLAGS_HEADER;
331             }
332         }
333
334         /* Get and mux a packet */
335         p_data = sout_FifoGet( p_input->p_fifo );
336         E_( EStoPES )( p_mux->p_sout,
337                        &p_data, p_data,
338                        p_stream->i_stream_id,
339                        p_mux->p_sys->b_mpeg2 );
340
341         sout_BufferChain( &p_ps, p_data );
342         sout_AccessOutWrite( p_mux->p_access, p_ps );
343
344         /* Increase counter */
345         p_sys->i_pes_count++;
346     }
347
348     return VLC_SUCCESS;
349 }
350
351
352 /*****************************************************************************
353  *
354  *****************************************************************************/
355 static void StreamIdInit   ( vlc_bool_t *id, int i_range )
356 {
357     int i;
358
359     for( i = 0; i < i_range; i++ )
360     {
361         id[i] = VLC_TRUE;
362     }
363 }
364 static int  StreamIdGet    ( vlc_bool_t *id, int i_id_min, int i_id_max )
365 {
366     int i;
367
368     for( i = 0; i <= i_id_max - i_id_min; i++ )
369     {
370         if( id[i] )
371         {
372             id[i] = VLC_FALSE;
373
374             return i_id_min + i;
375         }
376     }
377     return -1;
378 }
379 static void StreamIdRelease( vlc_bool_t *id, int i_id_min, int i_id )
380 {
381     id[i_id - i_id_min] = VLC_TRUE;
382 }
383
384 static void MuxWritePackHeader( sout_mux_t *p_mux, sout_buffer_t **p_buf,
385                                mtime_t i_dts )
386 {
387     sout_buffer_t   *p_hdr;
388     bits_buffer_t   bits;
389     mtime_t         i_src;
390
391     i_src = i_dts * 9 / 100;
392
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 );
396
397     if( p_mux->p_sys->b_mpeg2 )
398     {
399         bits_write( &bits, 2, 0x01 );
400     }
401     else
402     {
403         bits_write( &bits, 4, 0x02 );
404     }
405
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 );
412
413     if( p_mux->p_sys->b_mpeg2 )
414     {
415         bits_write( &bits, 9,  0 ); // src extention
416     }
417     bits_write( &bits, 1,  1 );
418
419     bits_write( &bits, 22,  1000/8/50); // FIXME mux rate
420     bits_write( &bits, 1,  1 );
421
422     if( p_mux->p_sys->b_mpeg2 )
423     {
424         bits_write( &bits, 1,  1 );
425         bits_write( &bits, 5,  0x1f );  // FIXME reserved
426         bits_write( &bits, 3,  0 );     // stuffing bytes
427     }
428
429     p_hdr->i_size = p_mux->p_sys->b_mpeg2 ? 14: 12;
430
431     sout_BufferChain( p_buf, p_hdr );
432 }
433
434 static void MuxWriteSystemHeader( sout_mux_t *p_mux, sout_buffer_t **p_buf )
435 {
436     sout_mux_sys_t  *p_sys = p_mux->p_sys;
437     sout_buffer_t   *p_hdr;
438     bits_buffer_t   bits;
439     vlc_bool_t      b_private;
440     int             i_nb_private, i_nb_stream;
441     int i;
442
443     /* Count the number of private stream */
444     for( i = 0, i_nb_private = 0; i < p_mux->i_nb_inputs; i++ )
445     {
446         ps_stream_t *p_stream;
447
448         p_stream = (ps_stream_t*)p_mux->pp_inputs[i]->p_sys;
449
450         if( ( p_stream->i_stream_id&0xff00 ) == 0xbd00 )
451         {
452             i_nb_private++;
453         }
454     }
455
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 );
458
459     p_hdr = sout_BufferNew( p_mux->p_sout, 12 + i_nb_stream * 3 );
460
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 );
467
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
473
474     bits_write( &bits, 1,  1 ); // marker bit
475
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
479
480     /* stream_id table */
481     for( i = 0, b_private = VLC_FALSE; i < p_mux->i_nb_inputs; i++ )
482     {
483         sout_input_t *p_input;
484         ps_stream_t *p_stream;
485
486         p_input = p_mux->pp_inputs[i];
487         p_stream = (ps_stream_t *)p_input->p_sys;
488
489         if( ( p_stream->i_stream_id&0xff00 ) == 0xbd00 )
490         {
491             if( b_private )
492             {
493                 continue;
494             }
495             b_private = VLC_TRUE;
496             /* Write stream id */
497             bits_write( &bits, 8, 0xbd );
498         }
499         else
500         {
501             /* Write stream id */
502             bits_write( &bits, 8, p_stream->i_stream_id&0xff );
503         }
504         bits_write( &bits, 2, 0x03 );
505         if( p_input->p_fmt->i_cat == AUDIO_ES )
506         {
507             bits_write( &bits, 1, 0 );
508             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 128 );
509         }
510         else if( p_input->p_fmt->i_cat == VIDEO_ES )
511         {
512             bits_write( &bits, 1, 1 );
513             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 1024);
514         }
515         else
516         {
517             /* FIXME */
518             bits_write( &bits, 1, 0 );
519             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 );
520         }
521     }
522
523     sout_BufferChain( p_buf, p_hdr );
524 }
525
526 /*
527  * Find stream to be muxed.
528  */
529 static int MuxGetStream( sout_mux_t *p_mux,
530                          int        *pi_stream,
531                          mtime_t    *pi_dts )
532 {
533     mtime_t i_dts;
534     int     i_stream;
535     int     i;
536
537     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
538     {
539         sout_input_t  *p_input = p_mux->pp_inputs[i];
540         sout_buffer_t *p_data;
541
542         if( p_input->p_fifo->i_depth <= 0 )
543         {
544             if( p_input->p_fmt->i_cat == AUDIO_ES ||
545                 p_input->p_fmt->i_cat == VIDEO_ES )
546             {
547                 /* We need that audio+video fifo contain at least 1 packet */
548                 return VLC_EGENERIC;
549             }
550             /* SPU */
551             continue;
552         }
553
554         p_data = sout_FifoShow( p_input->p_fifo );
555         if( i_stream == -1 ||
556             p_data->i_dts < i_dts )
557         {
558             i_stream = i;
559             i_dts    = p_data->i_dts;
560         }
561     }
562
563     *pi_stream = i_stream;
564     *pi_dts = i_dts;
565
566     return VLC_SUCCESS;
567 }
568