]> git.sesse.net Git - vlc/blob - modules/mux/mpeg/ps.c
* modules/mux/mpeg: for video ES, always put the pts and dts in the pes header when...
[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@videolan.org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <stdlib.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/input.h>
34 #include <vlc/sout.h>
35
36 #include "codecs.h"
37 #include "bits.h"
38 #include "pes.h"
39
40 /*****************************************************************************
41  * Module descriptor
42  *****************************************************************************/
43 #define DTS_TEXT N_("DTS delay (ms)")
44 #define DTS_LONGTEXT N_("This option will delay the DTS (decoding time " \
45   "stamps) and PTS (presentation timestamps) of the data in the " \
46   "stream, compared to the SCRs. This allows for some buffering inside " \
47   "the client decoder.")
48
49 static int     Open   ( vlc_object_t * );
50 static void    Close  ( vlc_object_t * );
51
52 #define SOUT_CFG_PREFIX "sout-ps-"
53
54 vlc_module_begin();
55     set_description( _("PS muxer") );
56     set_capability( "sout mux", 50 );
57     add_shortcut( "ps" );
58     add_shortcut( "mpeg1" );
59     add_shortcut( "dvd" );
60     set_callbacks( Open, Close );
61
62     add_integer( SOUT_CFG_PREFIX "dts-delay", 200, NULL, DTS_TEXT,
63                  DTS_LONGTEXT, VLC_TRUE );
64 vlc_module_end();
65
66 /*****************************************************************************
67  * Exported prototypes
68  *****************************************************************************/
69 static int Control  ( sout_mux_t *, int, va_list );
70 static int AddStream( sout_mux_t *, sout_input_t * );
71 static int DelStream( sout_mux_t *, sout_input_t * );
72 static int Mux      ( sout_mux_t * );
73
74 /*****************************************************************************
75  * Local prototypes
76  *****************************************************************************/
77 static int  MuxGetStream        ( sout_mux_t *, int *, mtime_t * );
78
79 static void MuxWritePackHeader  ( sout_mux_t *, block_t **, mtime_t );
80 static void MuxWriteSystemHeader( sout_mux_t *, block_t **, mtime_t );
81
82 static void StreamIdInit        ( vlc_bool_t *id, int i_range );
83 static int  StreamIdGet         ( vlc_bool_t *id, int i_id_min, int i_id_max );
84 static void StreamIdRelease     ( vlc_bool_t *id, int i_id_min, int i_id );
85
86 typedef struct ps_stream_s
87 {
88     int             i_stream_id;
89
90 } ps_stream_t;
91
92 struct sout_mux_sys_t
93 {
94     /* Which id are unused */
95     vlc_bool_t  stream_id_mpga[16]; /* 0xc0 -> 0xcf */
96     vlc_bool_t  stream_id_mpgv[16]; /* 0xe0 -> 0xef */
97     vlc_bool_t  stream_id_a52[8];   /* 0x80 -> 0x87 <- FIXME I'm not sure */
98     vlc_bool_t  stream_id_spu[32];  /* 0x20 -> 0x3f */
99     vlc_bool_t  stream_id_dts[8];   /* 0x88 -> 0x8f */
100     vlc_bool_t  stream_id_lpcm[16]; /* 0xa0 -> 0xaf */
101
102     int i_audio_bound;
103     int i_video_bound;
104     int i_pes_count;
105     int i_system_header;
106     int i_dts_delay;
107
108     vlc_bool_t b_mpeg2;
109 };
110
111 static const char *ppsz_sout_options[] = {
112     "dts-delay", NULL
113 };
114
115 /*****************************************************************************
116  * Open:
117  *****************************************************************************/
118 static int Open( vlc_object_t *p_this )
119 {
120     sout_mux_t *p_mux = (sout_mux_t*)p_this;
121     sout_mux_sys_t *p_sys;
122     vlc_value_t val;
123
124     msg_Info( p_mux, "Open" );
125     sout_CfgParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
126
127     p_mux->pf_control   = Control;
128     p_mux->pf_addstream = AddStream;
129     p_mux->pf_delstream = DelStream;
130     p_mux->pf_mux       = Mux;
131     p_mux->p_sys        = p_sys = malloc( sizeof( sout_mux_sys_t ) );
132
133     /* Init free stream id */
134     StreamIdInit( p_sys->stream_id_a52,  8  );
135     StreamIdInit( p_sys->stream_id_dts,  8  );
136     StreamIdInit( p_sys->stream_id_mpga, 16 );
137     StreamIdInit( p_sys->stream_id_mpgv, 16 );
138     StreamIdInit( p_sys->stream_id_lpcm, 16 );
139     StreamIdInit( p_sys->stream_id_spu,  32 );
140
141     p_sys->i_audio_bound   = 0;
142     p_sys->i_video_bound   = 0;
143     p_sys->i_system_header = 0;
144     p_sys->i_pes_count     = 0;
145
146     p_sys->b_mpeg2 = !(p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mpeg1" ));
147
148     var_Get( p_mux, SOUT_CFG_PREFIX "dts-delay", &val );
149     p_sys->i_dts_delay = (int64_t)val.i_int * 1000;
150
151     return VLC_SUCCESS;
152 }
153
154 /*****************************************************************************
155  * Close:
156  *****************************************************************************/
157 static void Close( vlc_object_t * p_this )
158 {
159     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
160     sout_mux_sys_t  *p_sys = p_mux->p_sys;
161
162     block_t   *p_end;
163
164     msg_Info( p_mux, "Close" );
165
166     p_end = block_New( p_mux, 4 );
167     p_end->p_buffer[0] = 0x00;
168     p_end->p_buffer[1] = 0x00;
169     p_end->p_buffer[2] = 0x01;
170     p_end->p_buffer[3] = 0xb9;
171
172     sout_AccessOutWrite( p_mux->p_access, p_end );
173
174     free( p_sys );
175 }
176
177 /*****************************************************************************
178  * Control:
179  *****************************************************************************/
180 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
181 {
182     vlc_bool_t *pb_bool;
183     char **ppsz;
184
185    switch( i_query )
186    {
187        case MUX_CAN_ADD_STREAM_WHILE_MUXING:
188            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
189            *pb_bool = VLC_TRUE;
190            return VLC_SUCCESS;
191
192        case MUX_GET_ADD_STREAM_WAIT:
193            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
194            *pb_bool = VLC_FALSE;
195            return VLC_SUCCESS;
196
197        case MUX_GET_MIME:
198            ppsz = (char**)va_arg( args, char ** );
199            *ppsz = strdup( "video/mpeg" );
200            return VLC_SUCCESS;
201
202         default:
203             return VLC_EGENERIC;
204    }
205 }
206
207 /*****************************************************************************
208  * AddStream:
209  *****************************************************************************/
210 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
211 {
212     sout_mux_sys_t  *p_sys = p_mux->p_sys;
213     ps_stream_t *p_stream;
214
215     msg_Dbg( p_mux, "adding input codec=%4.4s",
216              (char*)&p_input->p_fmt->i_codec );
217
218     p_input->p_sys = p_stream = malloc( sizeof( ps_stream_t ) );
219
220     /* Init this new stream */
221     switch( p_input->p_fmt->i_codec )
222     {
223         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
224             p_stream->i_stream_id =
225                 StreamIdGet( p_sys->stream_id_mpgv, 0xe0, 0xef );
226             break;
227         case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
228             p_stream->i_stream_id =
229                 0xbd00 | StreamIdGet( p_sys->stream_id_lpcm, 0xa0, 0xaf );
230             break;
231         case VLC_FOURCC( 'd', 't', 's', ' ' ):
232             p_stream->i_stream_id =
233                 0xbd00 | StreamIdGet( p_sys->stream_id_dts, 0x88, 0x8f );
234             break;
235         case VLC_FOURCC( 'a', '5', '2', ' ' ):
236             p_stream->i_stream_id =
237                 0xbd00 | StreamIdGet( p_sys->stream_id_a52, 0x80, 0x87 );
238             break;
239         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
240             p_stream->i_stream_id =
241                 StreamIdGet( p_sys->stream_id_mpga, 0xc0, 0xcf );
242             break;
243         case VLC_FOURCC( 's', 'p', 'u', ' ' ):
244             p_stream->i_stream_id =
245                 0xbd00 | StreamIdGet( p_sys->stream_id_spu, 0x20, 0x3f );
246             break;
247         default:
248             goto error;
249     }
250
251     if( p_stream->i_stream_id < 0 )
252     {
253         goto error;
254     }
255
256     if( p_input->p_fmt->i_cat == AUDIO_ES )
257     {
258         p_sys->i_audio_bound++;
259     }
260     else if( p_input->p_fmt->i_cat == VIDEO_ES )
261     {
262         p_sys->i_video_bound++;
263     }
264
265     return VLC_SUCCESS;
266
267 error:
268     free( p_stream );
269     return VLC_EGENERIC;
270 }
271
272 /*****************************************************************************
273  * DelStream:
274  *****************************************************************************/
275 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
276 {
277     sout_mux_sys_t *p_sys = p_mux->p_sys;
278     ps_stream_t *p_stream =(ps_stream_t*)p_input->p_sys;
279
280     msg_Dbg( p_mux, "removing input" );
281     switch( p_input->p_fmt->i_codec )
282     {
283         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
284             StreamIdRelease( p_sys->stream_id_mpgv, 0xe0,
285                              p_stream->i_stream_id );
286             break;
287         case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
288             StreamIdRelease( p_sys->stream_id_lpcm, 0xa0,
289                              p_stream->i_stream_id&0xff );
290             break;
291         case VLC_FOURCC( 'd', 't', 's', ' ' ):
292             StreamIdRelease( p_sys->stream_id_dts, 0x88,
293                              p_stream->i_stream_id&0xff );
294             break;
295         case VLC_FOURCC( 'a', '5', '2', ' ' ):
296             StreamIdRelease( p_sys->stream_id_a52, 0x80,
297                              p_stream->i_stream_id&0xff );
298             break;
299         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
300             StreamIdRelease( p_sys->stream_id_mpga, 0xc0,
301                              p_stream->i_stream_id  );
302             break;
303         case VLC_FOURCC( 's', 'p', 'u', ' ' ):
304             StreamIdRelease( p_sys->stream_id_spu, 0x20,
305                              p_stream->i_stream_id&0xff );
306             break;
307         default:
308             /* Never reached */
309             break;
310     }
311
312     if( p_input->p_fmt->i_cat == AUDIO_ES )
313     {
314         p_sys->i_audio_bound--;
315     }
316     else if( p_input->p_fmt->i_cat == VIDEO_ES )
317     {
318         p_sys->i_video_bound--;
319     }
320
321     free( p_stream );
322     return VLC_SUCCESS;
323 }
324
325 /*****************************************************************************
326  * Mux: Call each time there is new data for at least one stream
327  *****************************************************************************/
328 static int Mux( sout_mux_t *p_mux )
329 {
330     sout_mux_sys_t *p_sys = p_mux->p_sys;
331
332     for( ;; )
333     {
334         sout_input_t *p_input;
335         ps_stream_t *p_stream;
336
337         block_t *p_ps, *p_data;
338
339         mtime_t        i_dts;
340         int            i_stream;
341
342         /* Choose which stream to mux */
343         if( MuxGetStream( p_mux, &i_stream, &i_dts ) )
344         {
345             return VLC_SUCCESS;
346         }
347
348         p_input  = p_mux->pp_inputs[i_stream];
349         p_stream = (ps_stream_t*)p_input->p_sys;
350         p_ps     = NULL;
351
352         /* Write regulary PackHeader */
353         if( p_sys->i_pes_count % 30 == 0)
354         {
355             MuxWritePackHeader( p_mux, &p_ps, i_dts );
356         }
357
358         /* Write regulary SystemHeader */
359         if( p_sys->i_pes_count % 300 == 0 )
360         {
361             block_t *p_pk;
362
363             MuxWriteSystemHeader( p_mux, &p_ps, i_dts );
364
365             /* For MPEG1 streaming, set HEADER flag */
366             for( p_pk = p_ps; p_pk != NULL; p_pk = p_pk->p_next )
367             {
368                 p_pk->i_flags |= BLOCK_FLAG_HEADER;
369             }
370         }
371
372         /* Get and mux a packet */
373         p_data = block_FifoGet( p_input->p_fifo );
374         E_( EStoPES )( p_mux->p_sout, &p_data, p_data,
375                        p_input->p_fmt, p_stream->i_stream_id,
376                        p_mux->p_sys->b_mpeg2, 0, 0 );
377
378         block_ChainAppend( &p_ps, p_data );
379
380         sout_AccessOutWrite( p_mux->p_access, p_ps );
381
382         /* Increase counter */
383         p_sys->i_pes_count++;
384     }
385
386     return VLC_SUCCESS;
387 }
388
389 /*****************************************************************************
390  *
391  *****************************************************************************/
392 static void StreamIdInit( vlc_bool_t *id, int i_range )
393 {
394     int i;
395
396     for( i = 0; i < i_range; i++ )
397     {
398         id[i] = VLC_TRUE;
399     }
400 }
401 static int StreamIdGet( vlc_bool_t *id, int i_id_min, int i_id_max )
402 {
403     int i;
404
405     for( i = 0; i <= i_id_max - i_id_min; i++ )
406     {
407         if( id[i] )
408         {
409             id[i] = VLC_FALSE;
410
411             return i_id_min + i;
412         }
413     }
414     return -1;
415 }
416 static void StreamIdRelease( vlc_bool_t *id, int i_id_min, int i_id )
417 {
418     id[i_id - i_id_min] = VLC_TRUE;
419 }
420
421 static void MuxWritePackHeader( sout_mux_t *p_mux, block_t **p_buf,
422                                 mtime_t i_dts )
423 {
424     sout_mux_sys_t *p_sys = p_mux->p_sys;
425     bits_buffer_t bits;
426     block_t *p_hdr;
427     mtime_t i_scr;
428
429     i_scr = (i_dts - p_sys->i_dts_delay) * 9 / 100;
430
431     p_hdr = block_New( p_mux, 18 );
432     p_hdr->i_pts = p_hdr->i_dts = i_dts;
433     bits_initwrite( &bits, 14, p_hdr->p_buffer );
434     bits_write( &bits, 32, 0x01ba );
435
436     if( p_sys->b_mpeg2 )
437     {
438         bits_write( &bits, 2, 0x01 );
439     }
440     else
441     {
442         bits_write( &bits, 4, 0x02 );
443     }
444
445     bits_write( &bits, 3, ( i_scr >> 30 )&0x07 );
446     bits_write( &bits, 1,  1 );
447     bits_write( &bits, 15, ( i_scr >> 15 )&0x7fff );
448     bits_write( &bits, 1,  1 );
449     bits_write( &bits, 15, i_scr&0x7fff );
450     bits_write( &bits, 1,  1 );
451
452     if( p_sys->b_mpeg2 )
453     {
454         bits_write( &bits, 9,  0 ); // src extention
455     }
456     bits_write( &bits, 1,  1 );
457
458     bits_write( &bits, 22,  1000/8/50); // FIXME mux rate
459     bits_write( &bits, 1,  1 );
460
461     if( p_sys->b_mpeg2 )
462     {
463         bits_write( &bits, 1,  1 );
464         bits_write( &bits, 5,  0x1f );  // FIXME reserved
465         bits_write( &bits, 3,  0 );     // stuffing bytes
466     }
467
468     p_hdr->i_buffer = p_sys->b_mpeg2 ? 14: 12;
469
470     block_ChainAppend( p_buf, p_hdr );
471 }
472
473 static void MuxWriteSystemHeader( sout_mux_t *p_mux, block_t **p_buf,
474                                   mtime_t i_dts )
475 {
476     sout_mux_sys_t  *p_sys = p_mux->p_sys;
477     block_t   *p_hdr;
478     bits_buffer_t   bits;
479     vlc_bool_t      b_private;
480     int             i_nb_private, i_nb_stream;
481     int i;
482
483     /* Count the number of private stream */
484     for( i = 0, i_nb_private = 0; i < p_mux->i_nb_inputs; i++ )
485     {
486         ps_stream_t *p_stream;
487
488         p_stream = (ps_stream_t*)p_mux->pp_inputs[i]->p_sys;
489
490         if( ( p_stream->i_stream_id&0xff00 ) == 0xbd00 )
491         {
492             i_nb_private++;
493         }
494     }
495
496     /* Private stream are declared only one time */
497     i_nb_stream = p_mux->i_nb_inputs -
498         ( i_nb_private > 0 ? i_nb_private - 1 : 0 );
499
500     p_hdr = block_New( p_mux, 12 + i_nb_stream * 3 );
501     p_hdr->i_dts = p_hdr->i_pts = i_dts;
502
503     bits_initwrite( &bits, 12 + i_nb_stream * 3, p_hdr->p_buffer );
504     bits_write( &bits, 32, 0x01bb );
505     bits_write( &bits, 16, 12 - 6 + i_nb_stream * 3 );
506     bits_write( &bits, 1,  1 );
507     bits_write( &bits, 22, 0 ); // FIXME rate bound
508     bits_write( &bits, 1,  1 );
509
510     bits_write( &bits, 6,  p_sys->i_audio_bound );
511     bits_write( &bits, 1,  0 ); // fixed flag
512     bits_write( &bits, 1,  0 ); // CSPS flag
513     bits_write( &bits, 1,  0 ); // system audio lock flag
514     bits_write( &bits, 1,  0 ); // system video lock flag
515
516     bits_write( &bits, 1,  1 ); // marker bit
517
518     bits_write( &bits, 5,  p_sys->i_video_bound );
519     bits_write( &bits, 1,  1 ); // packet rate restriction flag (1 for mpeg1)
520     bits_write( &bits, 7,  0xff ); // reserved bits
521
522     /* stream_id table */
523     for( i = 0, b_private = VLC_FALSE; i < p_mux->i_nb_inputs; i++ )
524     {
525         sout_input_t *p_input;
526         ps_stream_t *p_stream;
527
528         p_input = p_mux->pp_inputs[i];
529         p_stream = (ps_stream_t *)p_input->p_sys;
530
531         if( ( p_stream->i_stream_id&0xff00 ) == 0xbd00 )
532         {
533             if( b_private )
534             {
535                 continue;
536             }
537             b_private = VLC_TRUE;
538             /* Write stream id */
539             bits_write( &bits, 8, 0xbd );
540         }
541         else
542         {
543             /* Write stream id */
544             bits_write( &bits, 8, p_stream->i_stream_id&0xff );
545         }
546         bits_write( &bits, 2, 0x03 );
547         if( p_input->p_fmt->i_cat == AUDIO_ES )
548         {
549             bits_write( &bits, 1, 0 );
550             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 128 );
551         }
552         else if( p_input->p_fmt->i_cat == VIDEO_ES )
553         {
554             bits_write( &bits, 1, 1 );
555             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 1024);
556         }
557         else
558         {
559             /* FIXME */
560             bits_write( &bits, 1, 0 );
561             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 );
562         }
563     }
564
565     block_ChainAppend( p_buf, p_hdr );
566 }
567
568 /*
569  * Find stream to be muxed.
570  */
571 static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
572 {
573     mtime_t i_dts;
574     int     i_stream;
575     int     i;
576
577     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
578     {
579         sout_input_t *p_input = p_mux->pp_inputs[i];
580         block_t *p_data;
581
582         if( p_input->p_fifo->i_depth <= 0 )
583         {
584             if( p_input->p_fmt->i_cat == AUDIO_ES ||
585                 p_input->p_fmt->i_cat == VIDEO_ES )
586             {
587                 /* We need that audio+video fifo contain at least 1 packet */
588                 return VLC_EGENERIC;
589             }
590
591             /* SPU */
592             continue;
593         }
594
595         p_data = block_FifoShow( p_input->p_fifo );
596         if( i_stream == -1 || p_data->i_dts < i_dts )
597         {
598             i_stream = i;
599             i_dts    = p_data->i_dts;
600         }
601     }
602
603     *pi_stream = i_stream;
604     *pi_dts = i_dts;
605
606     return VLC_SUCCESS;
607 }