2a7246bf7909df7cc5089c57f20a040514f97d47
[vlc.git] / 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.13 2003/07/15 13:12:00 gbazin 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 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <fcntl.h>
37
38 #include <vlc/vlc.h>
39 #include <vlc/input.h>
40 #include <vlc/sout.h>
41
42 #ifdef HAVE_UNISTD_H
43 #   include <unistd.h>
44 #endif
45
46 #include "codecs.h"
47 #include "bits.h"
48 #include "pes.h"
49
50 /*****************************************************************************
51  * Exported prototypes
52  *****************************************************************************/
53 static int     Open   ( vlc_object_t * );
54 static void    Close  ( vlc_object_t * );
55
56 static int Capability(sout_mux_t *, int, void *, void * );
57 static int AddStream( sout_mux_t *, sout_input_t * );
58 static int DelStream( sout_mux_t *, sout_input_t * );
59 static int Mux      ( sout_mux_t * );
60
61 static void SetWBE ( uint8_t *p, uint16_t v )
62 {
63     p[0] = ( v >> 8 )&0xff;
64     p[1] = v&0xff;
65 }
66 static void SetDWBE( uint8_t *p, uint32_t v )
67 {
68     SetWBE( p,    ( v >> 16 )&0xffff );
69     SetWBE( p + 2,  v & 0xffff );
70 }
71 #define ADD_DWBE( p_buff, v ) \
72     SetDWBE( (p_buff)->p_buffer + i_buffer, (v) ); \
73     i_buffer +=4;
74
75 /*****************************************************************************
76  * Module descriptor
77  *****************************************************************************/
78 vlc_module_begin();
79     set_description( _("PS muxer") );
80     set_capability( "sout mux", 50 );
81     add_shortcut( "ps" );
82     add_shortcut( "mpeg1" );
83     set_callbacks( Open, Close );
84 vlc_module_end();
85
86 typedef struct ps_stream_s
87 {
88     int             i_ok;
89
90     int             i_stream_id;
91
92 } ps_stream_t;
93
94 struct sout_mux_sys_t
95 {
96     int         i_stream_id_mpga;
97     int         i_stream_id_mpgv;
98     int         i_stream_id_a52;
99
100     int         i_audio_bound;
101     int         i_video_bound;
102
103     int         i_pes_count;
104
105     int         i_system_header;
106
107     vlc_bool_t  b_mpeg2;
108 };
109
110 /*****************************************************************************
111  * Open:
112  *****************************************************************************/
113 static int Open( vlc_object_t *p_this )
114 {
115     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
116     sout_mux_sys_t  *p_sys;
117
118     msg_Info( p_mux, "Open" );
119
120     p_sys = malloc( sizeof( sout_mux_sys_t ) );
121
122     p_mux->pf_capacity  = Capability;
123     p_mux->pf_addstream = AddStream;
124     p_mux->pf_delstream = DelStream;
125     p_mux->pf_mux       = Mux;
126     p_mux->p_sys        = p_sys;
127     p_mux->i_preheader  = 30; // really enough for a pes header
128
129     p_sys->i_stream_id_mpga = 0xc0;
130     p_sys->i_stream_id_a52  = 0x80;
131     p_sys->i_stream_id_mpgv = 0xe0;
132     p_sys->i_audio_bound = 0;
133     p_sys->i_video_bound = 0;
134     p_sys->i_system_header = 0;
135     p_sys->i_pes_count = 0;
136
137     p_sys->b_mpeg2 = !(p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mpeg1" ));
138
139     return VLC_SUCCESS;
140 }
141
142 /*****************************************************************************
143  * Close:
144  *****************************************************************************/
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     sout_buffer_t   *p_end;
152
153     msg_Info( p_mux, "Close" );
154
155     p_end = sout_BufferNew( p_mux->p_sout, 4 );
156     SetDWBE( p_end->p_buffer, 0x01b9 );
157
158     sout_AccessOutWrite( p_mux->p_access, p_end );
159
160     free( p_sys );
161 }
162
163 static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
164                        void *p_answer )
165 {
166    switch( i_query )
167    {
168         case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
169             *(vlc_bool_t*)p_answer = VLC_TRUE;
170             return( SOUT_MUX_CAP_ERR_OK );
171         default:
172             return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
173    }
174 }
175
176 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
177 {
178     sout_mux_sys_t  *p_sys = p_mux->p_sys;
179     ps_stream_t         *p_stream;
180
181     msg_Dbg( p_mux, "adding input" );
182     p_input->p_sys = (void*)p_stream = malloc( sizeof( ps_stream_t ) );
183     p_stream->i_ok = 0;
184     switch( p_input->p_fmt->i_cat )
185     {
186         case VIDEO_ES:
187             switch( p_input->p_fmt->i_fourcc )
188             {
189                 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
190                     p_stream->i_stream_id = p_sys->i_stream_id_mpgv;
191                     p_sys->i_stream_id_mpgv++;
192                     p_sys->i_video_bound++;
193                     break;
194                 default:
195                     return( -1 );
196             }
197             break;
198
199         case AUDIO_ES:
200             switch( p_input->p_fmt->i_fourcc )
201             {
202                 case VLC_FOURCC( 'a', '5', '2', ' ' ):
203                 case VLC_FOURCC( 'a', '5', '2', 'b' ):
204                     p_stream->i_stream_id = p_sys->i_stream_id_a52 |
205                                             ( 0xbd << 8 );
206                     p_sys->i_stream_id_a52++;
207                     p_sys->i_audio_bound++;
208                     break;
209                 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
210                     p_stream->i_stream_id = p_sys->i_stream_id_mpga;
211                     p_sys->i_stream_id_mpga++;
212                     p_sys->i_audio_bound++;
213                     break;
214                 default:
215                     return( -1 );
216             }
217             break;
218         default:
219             return( -1 );
220     }
221
222     p_stream->i_ok = 1;
223     msg_Dbg( p_mux, "adding input stream_id:0x%x [OK]",
224              p_stream->i_stream_id );
225
226     return( 0 );
227 }
228
229 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
230 {
231     ps_stream_t *p_stream =(ps_stream_t*)p_input->p_sys;
232
233     msg_Dbg( p_mux, "removing input" );
234     if( p_stream )
235     {
236         free( p_stream );
237     }
238     return( VLC_SUCCESS );
239 }
240
241 static int MuxWritePackHeader( sout_mux_t *p_mux, mtime_t i_dts )
242 {
243     sout_buffer_t   *p_hdr;
244     bits_buffer_t   bits;
245     mtime_t         i_src;
246
247     i_src = i_dts * 9 / 100;
248
249     p_hdr = sout_BufferNew( p_mux->p_sout, 18 );
250     bits_initwrite( &bits, 14, p_hdr->p_buffer );
251     bits_write( &bits, 32, 0x01ba );
252
253     if( p_mux->p_sys->b_mpeg2 )
254         bits_write( &bits, 2, 0x01 );
255     else
256         bits_write( &bits, 4, 0x02 );
257
258     bits_write( &bits, 3, ( i_src >> 30 )&0x07 );
259     bits_write( &bits, 1,  1 );
260     bits_write( &bits, 15, ( i_src >> 15 )&0x7fff );
261     bits_write( &bits, 1,  1 );
262     bits_write( &bits, 15, i_src&0x7fff );
263     bits_write( &bits, 1,  1 );
264
265     if( p_mux->p_sys->b_mpeg2 )
266     {
267         bits_write( &bits, 9,  0 ); // src extention
268     }
269     bits_write( &bits, 1,  1 );
270
271     bits_write( &bits, 22,  1000/8/50); // FIXME mux rate
272     bits_write( &bits, 1,  1 );
273
274     if( p_mux->p_sys->b_mpeg2 )
275     {
276         bits_write( &bits, 1,  1 );
277         bits_write( &bits, 5,  0x1f );  // FIXME reserved
278         bits_write( &bits, 3,  0 );     // stuffing bytes
279     }
280
281     if( p_mux->p_sys->b_mpeg2 )
282         p_hdr->i_size = 14;
283     else
284         p_hdr->i_size = 12;
285
286     sout_AccessOutWrite( p_mux->p_access, p_hdr );
287
288     return( 0 );
289 }
290
291 static int MuxWriteSystemHeader( sout_mux_t *p_mux )
292 {
293     sout_mux_sys_t  *p_sys = p_mux->p_sys;
294     sout_buffer_t   *p_hdr;
295     bits_buffer_t   bits;
296     int i;
297
298     p_hdr = sout_BufferNew( p_mux->p_sout, 12 + p_mux->i_nb_inputs * 3 );
299
300     bits_initwrite( &bits, 12 + p_mux->i_nb_inputs * 3, p_hdr->p_buffer );
301     bits_write( &bits, 32, 0x01bb );
302     bits_write( &bits, 16, 12 - 6 + p_mux->i_nb_inputs * 3 );
303     bits_write( &bits, 1,  1 );
304     bits_write( &bits, 22, 0 ); // FIXME rate bound
305     bits_write( &bits, 1,  1 );
306
307     bits_write( &bits, 6,  p_sys->i_audio_bound );
308     bits_write( &bits, 1,  0 ); // fixed flag
309     bits_write( &bits, 1,  0 ); // CSPS flag
310     bits_write( &bits, 1,  0 ); // system audio lock flag
311     bits_write( &bits, 1,  0 ); // system video lock flag
312
313     bits_write( &bits, 1,  1 ); // marker bit
314
315     bits_write( &bits, 5,  p_sys->i_video_bound );
316     bits_write( &bits, 1,  1 ); // packet rate restriction flag (1 for mpeg1)
317     bits_write( &bits, 7,  0xff ); // reserved bits
318
319     /* stream_id table */
320     for( i = 0; i < p_mux->i_nb_inputs; i++ )
321     {
322         ps_stream_t *p_stream = (ps_stream_t *)p_mux->pp_inputs[i]->p_sys;
323
324         if( p_stream->i_stream_id < 0xc0 )
325         {
326             /* FIXME */
327         }
328         bits_write( &bits, 8, p_stream->i_stream_id ); // stream ID
329         bits_write( &bits, 2, 0x03 );
330         if( p_stream->i_stream_id < 0xe0 ) /* FIXME */
331         {
332             /* audio */
333             bits_write( &bits, 1, 0 );
334             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 128 );
335         } else {
336             /* video */
337             bits_write( &bits, 1, 1 );
338             bits_write( &bits, 13, /* stream->max_buffer_size */ 0 / 1024 );
339         }
340     }
341
342     sout_AccessOutWrite( p_mux->p_access, p_hdr );
343
344     return( 0 );
345 }
346
347 /* return stream number to be muxed */
348 static int MuxGetStream( sout_mux_t *p_mux, 
349                          int        *pi_stream, 
350                          mtime_t    *pi_dts )
351 {
352     mtime_t i_dts;
353     int     i_stream;
354     int     i;
355
356     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
357     {
358         sout_fifo_t  *p_fifo;
359
360         p_fifo = p_mux->pp_inputs[i]->p_fifo;
361
362         if( p_fifo->i_depth > 1 )
363         {
364             sout_buffer_t *p_buf;
365
366             p_buf = sout_FifoShow( p_fifo );
367             if( i_stream < 0 || p_buf->i_dts < i_dts )
368             {
369                 i_dts = p_buf->i_dts;
370                 i_stream = i;
371             }
372         }
373         else
374         {
375             return( -1 ); // wait that all fifo have at least 2 packets
376         }
377     }
378
379     if( pi_stream )
380     {
381         *pi_stream = i_stream;
382     }
383     if( pi_dts )
384     {
385         *pi_dts = i_dts;
386     }
387
388     return( i_stream );
389 }
390
391 static int Mux( sout_mux_t *p_mux )
392 {
393     sout_mux_sys_t *p_sys = p_mux->p_sys;
394     mtime_t        i_dts;
395     int            i_stream;
396
397     for( ;; )
398     {
399         sout_input_t *p_input;
400         ps_stream_t *p_stream;
401         sout_fifo_t  *p_fifo;
402         sout_buffer_t *p_data;
403
404         if( MuxGetStream( p_mux, &i_stream, &i_dts ) < 0 )
405         {
406             return( VLC_SUCCESS );
407         }
408
409         p_input = p_mux->pp_inputs[i_stream];
410         p_fifo = p_input->p_fifo;
411         p_stream = (ps_stream_t*)p_input->p_sys;
412
413         if( p_sys->i_pes_count % 30 == 0)
414         {
415             MuxWritePackHeader( p_mux, i_dts );
416         }
417
418         if( p_sys->i_pes_count % 300 == 0 )
419         {
420             MuxWriteSystemHeader( p_mux );
421         }
422
423         p_data = sout_FifoGet( p_fifo );
424         E_( EStoPES )( p_mux->p_sout, &p_data, p_data, p_stream->i_stream_id,
425                        p_mux->p_sys->b_mpeg2 );
426         sout_AccessOutWrite( p_mux->p_access, p_data );
427
428         p_sys->i_pes_count++;
429
430     }
431     return( 0 );
432 }