]> git.sesse.net Git - vlc/blob - modules/mux/mpeg/ps.c
* mux: sout_buffer_t -> block_t.
[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$
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 *, block_t **, mtime_t );
76 static void MuxWriteSystemHeader( sout_mux_t *, block_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->p_sys        = p_sys = malloc( sizeof( sout_mux_sys_t ) );
124
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 );
132
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;
137
138     p_sys->b_mpeg2 = !(p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mpeg1" ));
139
140     return VLC_SUCCESS;
141 }
142
143 /*****************************************************************************
144  * Close:
145  *****************************************************************************/
146 static void Close( vlc_object_t * p_this )
147 {
148     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
149     sout_mux_sys_t  *p_sys = p_mux->p_sys;
150
151     block_t   *p_end;
152
153     msg_Info( p_mux, "Close" );
154
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;
160
161     sout_AccessOutWrite( p_mux->p_access, p_end );
162
163     free( p_sys );
164 }
165
166 /*****************************************************************************
167  * Capability:
168  *****************************************************************************/
169 static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
170                        void *p_answer )
171 {
172    switch( i_query )
173    {
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 );
177         default:
178             return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
179    }
180 }
181
182 /*****************************************************************************
183  * AddStream:
184  *****************************************************************************/
185 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
186 {
187     sout_mux_sys_t  *p_sys = p_mux->p_sys;
188     ps_stream_t         *p_stream;
189
190     msg_Dbg( p_mux, "adding input codec=%4.4s", (char*)&p_input->p_fmt->i_codec );
191
192     p_input->p_sys = (void*)p_stream = malloc( sizeof( ps_stream_t ) );
193
194     /* Init this new stream */
195     switch( p_input->p_fmt->i_codec )
196     {
197         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
198             p_stream->i_stream_id = StreamIdGet( p_sys->stream_id_mpgv, 0xe0, 0xef );
199             break;
200         case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
201             p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_lpcm, 0xa0, 0xaf );
202             break;
203         case VLC_FOURCC( 'd', 't', 's', ' ' ):
204             p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_dts, 0x88, 0x8f );
205             break;
206         case VLC_FOURCC( 'a', '5', '2', ' ' ):
207             p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_a52, 0x80, 0x87 );
208             break;
209         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
210             p_stream->i_stream_id = StreamIdGet( p_sys->stream_id_mpga, 0xc0, 0xcf );
211             break;
212         case VLC_FOURCC( 's', 'p', 'u', ' ' ):
213             p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_spu, 0x20, 0x3f );
214             break;
215         default:
216             goto error;
217     }
218
219     if( p_stream->i_stream_id < 0 )
220     {
221         goto error;
222     }
223
224     if( p_input->p_fmt->i_cat == AUDIO_ES )
225     {
226         p_sys->i_audio_bound++;
227     }
228     else if( p_input->p_fmt->i_cat == VIDEO_ES )
229     {
230         p_sys->i_video_bound++;
231     }
232
233     return VLC_SUCCESS;
234
235 error:
236     free( p_stream );
237     return VLC_EGENERIC;
238 }
239
240 /*****************************************************************************
241  * DelStream:
242  *****************************************************************************/
243 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
244 {
245     sout_mux_sys_t  *p_sys = p_mux->p_sys;
246     ps_stream_t *p_stream =(ps_stream_t*)p_input->p_sys;
247
248     msg_Dbg( p_mux, "removing input" );
249     switch( p_input->p_fmt->i_codec )
250     {
251         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
252             StreamIdRelease( p_sys->stream_id_mpgv, 0xe0, p_stream->i_stream_id);
253             break;
254         case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
255             StreamIdRelease( p_sys->stream_id_lpcm, 0xa0, p_stream->i_stream_id&0xff );
256             break;
257         case VLC_FOURCC( 'd', 't', 's', ' ' ):
258             StreamIdRelease( p_sys->stream_id_dts, 0x88, p_stream->i_stream_id&0xff );
259             break;
260         case VLC_FOURCC( 'a', '5', '2', ' ' ):
261             StreamIdRelease( p_sys->stream_id_a52, 0x80, p_stream->i_stream_id&0xff );
262             break;
263         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
264             StreamIdRelease( p_sys->stream_id_mpga, 0xc0, p_stream->i_stream_id  );
265             break;
266         case VLC_FOURCC( 's', 'p', 'u', ' ' ):
267             StreamIdRelease( p_sys->stream_id_spu, 0x20, p_stream->i_stream_id&0xff );
268             break;
269         default:
270             /* Never reached */
271             break;
272     }
273
274     if( p_input->p_fmt->i_cat == AUDIO_ES )
275     {
276         p_sys->i_audio_bound--;
277     }
278     else if( p_input->p_fmt->i_cat == VIDEO_ES )
279     {
280         p_sys->i_video_bound--;
281     }
282
283     free( p_stream );
284     return VLC_SUCCESS;
285 }
286
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 )
291 {
292     sout_mux_sys_t *p_sys = p_mux->p_sys;
293
294     for( ;; )
295     {
296         sout_input_t *p_input;
297         ps_stream_t *p_stream;
298
299         block_t *p_ps, *p_data;
300
301         mtime_t        i_dts;
302         int            i_stream;
303
304         /* Choose which stream to mux */
305         if( MuxGetStream( p_mux, &i_stream, &i_dts ) )
306         {
307             return VLC_SUCCESS;
308         }
309         p_input  = p_mux->pp_inputs[i_stream];
310         p_stream = (ps_stream_t*)p_input->p_sys;
311         p_ps     = NULL;
312
313         /* Write regulary PackHeader */
314         if( p_sys->i_pes_count % 30 == 0)
315         {
316             MuxWritePackHeader( p_mux, &p_ps, i_dts );
317         }
318
319         /* Write regulary SystemHeader */
320         if( p_sys->i_pes_count % 300 == 0 )
321         {
322             block_t *p_pk;
323
324             MuxWriteSystemHeader( p_mux, &p_ps );
325
326             /* For MPEG1 streaming, set HEADER flag */
327             for( p_pk = p_ps; p_pk != NULL; p_pk = p_pk->p_next )
328             {
329                 p_pk->i_flags |= BLOCK_FLAG_HEADER;
330             }
331         }
332
333         /* Get and mux a packet */
334         p_data = block_FifoGet( p_input->p_fifo );
335         E_( EStoPES )( p_mux->p_sout,
336                        &p_data, p_data,
337                        p_stream->i_stream_id,
338                        p_mux->p_sys->b_mpeg2 );
339
340         block_ChainAppend( &p_ps, p_data );
341         sout_AccessOutWrite( p_mux->p_access, p_ps );
342
343         /* Increase counter */
344         p_sys->i_pes_count++;
345     }
346
347     return VLC_SUCCESS;
348 }
349
350
351 /*****************************************************************************
352  *
353  *****************************************************************************/
354 static void StreamIdInit   ( vlc_bool_t *id, int i_range )
355 {
356     int i;
357
358     for( i = 0; i < i_range; i++ )
359     {
360         id[i] = VLC_TRUE;
361     }
362 }
363 static int  StreamIdGet    ( vlc_bool_t *id, int i_id_min, int i_id_max )
364 {
365     int i;
366
367     for( i = 0; i <= i_id_max - i_id_min; i++ )
368     {
369         if( id[i] )
370         {
371             id[i] = VLC_FALSE;
372
373             return i_id_min + i;
374         }
375     }
376     return -1;
377 }
378 static void StreamIdRelease( vlc_bool_t *id, int i_id_min, int i_id )
379 {
380     id[i_id - i_id_min] = VLC_TRUE;
381 }
382
383 static void MuxWritePackHeader( sout_mux_t *p_mux, block_t **p_buf,
384                                mtime_t i_dts )
385 {
386     block_t   *p_hdr;
387     bits_buffer_t   bits;
388     mtime_t         i_src;
389
390     i_src = i_dts * 9 / 100;
391
392     p_hdr = block_New( p_mux, 18 );
393     bits_initwrite( &bits, 14, p_hdr->p_buffer );
394     bits_write( &bits, 32, 0x01ba );
395
396     if( p_mux->p_sys->b_mpeg2 )
397     {
398         bits_write( &bits, 2, 0x01 );
399     }
400     else
401     {
402         bits_write( &bits, 4, 0x02 );
403     }
404
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 );
411
412     if( p_mux->p_sys->b_mpeg2 )
413     {
414         bits_write( &bits, 9,  0 ); // src extention
415     }
416     bits_write( &bits, 1,  1 );
417
418     bits_write( &bits, 22,  1000/8/50); // FIXME mux rate
419     bits_write( &bits, 1,  1 );
420
421     if( p_mux->p_sys->b_mpeg2 )
422     {
423         bits_write( &bits, 1,  1 );
424         bits_write( &bits, 5,  0x1f );  // FIXME reserved
425         bits_write( &bits, 3,  0 );     // stuffing bytes
426     }
427
428     p_hdr->i_buffer = p_mux->p_sys->b_mpeg2 ? 14: 12;
429
430     block_ChainAppend( p_buf, p_hdr );
431 }
432
433 static void MuxWriteSystemHeader( sout_mux_t *p_mux, block_t **p_buf )
434 {
435     sout_mux_sys_t  *p_sys = p_mux->p_sys;
436     block_t   *p_hdr;
437     bits_buffer_t   bits;
438     vlc_bool_t      b_private;
439     int             i_nb_private, i_nb_stream;
440     int i;
441
442     /* Count the number of private stream */
443     for( i = 0, i_nb_private = 0; i < p_mux->i_nb_inputs; i++ )
444     {
445         ps_stream_t *p_stream;
446
447         p_stream = (ps_stream_t*)p_mux->pp_inputs[i]->p_sys;
448
449         if( ( p_stream->i_stream_id&0xff00 ) == 0xbd00 )
450         {
451             i_nb_private++;
452         }
453     }
454
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 );
457
458     p_hdr = block_New( p_mux, 12 + i_nb_stream * 3 );
459
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 );
466
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
472
473     bits_write( &bits, 1,  1 ); // marker bit
474
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
478
479     /* stream_id table */
480     for( i = 0, b_private = VLC_FALSE; i < p_mux->i_nb_inputs; i++ )
481     {
482         sout_input_t *p_input;
483         ps_stream_t *p_stream;
484
485         p_input = p_mux->pp_inputs[i];
486         p_stream = (ps_stream_t *)p_input->p_sys;
487
488         if( ( p_stream->i_stream_id&0xff00 ) == 0xbd00 )
489         {
490             if( b_private )
491             {
492                 continue;
493             }
494             b_private = VLC_TRUE;
495             /* Write stream id */
496             bits_write( &bits, 8, 0xbd );
497         }
498         else
499         {
500             /* Write stream id */
501             bits_write( &bits, 8, p_stream->i_stream_id&0xff );
502         }
503         bits_write( &bits, 2, 0x03 );
504         if( p_input->p_fmt->i_cat == AUDIO_ES )
505         {
506             bits_write( &bits, 1, 0 );
507             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 128 );
508         }
509         else if( p_input->p_fmt->i_cat == VIDEO_ES )
510         {
511             bits_write( &bits, 1, 1 );
512             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 1024);
513         }
514         else
515         {
516             /* FIXME */
517             bits_write( &bits, 1, 0 );
518             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 );
519         }
520     }
521
522     block_ChainAppend( p_buf, p_hdr );
523 }
524
525 /*
526  * Find stream to be muxed.
527  */
528 static int MuxGetStream( sout_mux_t *p_mux,
529                          int        *pi_stream,
530                          mtime_t    *pi_dts )
531 {
532     mtime_t i_dts;
533     int     i_stream;
534     int     i;
535
536     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
537     {
538         sout_input_t  *p_input = p_mux->pp_inputs[i];
539         block_t *p_data;
540
541         if( p_input->p_fifo->i_depth <= 0 )
542         {
543             if( p_input->p_fmt->i_cat == AUDIO_ES ||
544                 p_input->p_fmt->i_cat == VIDEO_ES )
545             {
546                 /* We need that audio+video fifo contain at least 1 packet */
547                 return VLC_EGENERIC;
548             }
549             /* SPU */
550             continue;
551         }
552
553         p_data = block_FifoShow( p_input->p_fifo );
554         if( i_stream == -1 ||
555             p_data->i_dts < i_dts )
556         {
557             i_stream = i;
558             i_dts    = p_data->i_dts;
559         }
560     }
561
562     *pi_stream = i_stream;
563     *pi_dts = i_dts;
564
565     return VLC_SUCCESS;
566 }
567