f3f6ebf92cb0cb0294f358b728d4b4d2c5a69463
[vlc.git] / modules / mux / mpeg / ps.c
1 /*****************************************************************************
2  * ps.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: ps.c,v 1.11 2003/03/11 19:02:30 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Eric Petit <titer@videolan.org>
9  *
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <fcntl.h>
35
36 #include <vlc/vlc.h>
37 #include <vlc/input.h>
38 #include <vlc/sout.h>
39
40 #ifdef HAVE_UNISTD_H
41 #   include <unistd.h>
42 #endif
43
44 #include "codecs.h"
45 #include "bits.h"
46 #include "pes.h"
47
48 /*****************************************************************************
49  * Exported prototypes
50  *****************************************************************************/
51 static int     Open   ( vlc_object_t * );
52 static void    Close  ( vlc_object_t * );
53
54 static int Capability(sout_mux_t *, int, void *, void * );
55 static int AddStream( sout_mux_t *, sout_input_t * );
56 static int DelStream( sout_mux_t *, sout_input_t * );
57 static int Mux      ( sout_mux_t * );
58
59 static void SetWBE ( uint8_t *p, uint16_t v )
60 {
61     p[0] = ( v >> 8 )&0xff;
62     p[1] = v&0xff;
63 }
64 static void SetDWBE( uint8_t *p, uint32_t v )
65 {
66     SetWBE( p,    ( v >> 16 )&0xffff );
67     SetWBE( p + 2,  v & 0xffff );
68 }
69 #define ADD_DWBE( p_buff, v ) \
70     SetDWBE( (p_buff)->p_buffer + i_buffer, (v) ); \
71     i_buffer +=4;
72
73 /*****************************************************************************
74  * Module descriptor
75  *****************************************************************************/
76 vlc_module_begin();
77     set_description( _("PS muxer") );
78     set_capability( "sout mux", 50 );
79     add_shortcut( "ps" );
80     set_callbacks( Open, Close );
81 vlc_module_end();
82
83 typedef struct ps_stream_s
84 {
85     int             i_ok;
86
87     int             i_stream_id;
88
89 } ps_stream_t;
90
91 struct sout_mux_sys_t
92 {
93
94     int         i_stream_id_mpga;
95     int         i_stream_id_mpgv;
96     int         i_stream_id_a52;
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
106 /*****************************************************************************
107  * Open:
108  *****************************************************************************/
109 static int Open( vlc_object_t *p_this )
110 {
111     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
112     sout_mux_sys_t  *p_sys;
113
114     msg_Info( p_mux, "Open" );
115
116     p_sys = malloc( sizeof( sout_mux_sys_t ) );
117
118     p_mux->pf_capacity  = Capability;
119     p_mux->pf_addstream = AddStream;
120     p_mux->pf_delstream = DelStream;
121     p_mux->pf_mux       = Mux;
122     p_mux->p_sys        = p_sys;
123     p_mux->i_preheader  = 30; // really enough for a pes header
124
125     p_sys->i_stream_id_mpga = 0xc0;
126     p_sys->i_stream_id_a52  = 0x80;
127     p_sys->i_stream_id_mpgv = 0xe0;
128     p_sys->i_audio_bound = 0;
129     p_sys->i_video_bound = 0;
130     p_sys->i_system_header = 0;
131     p_sys->i_pes_count = 0;
132
133     return VLC_SUCCESS;
134 }
135
136 /*****************************************************************************
137  * Close:
138  *****************************************************************************/
139
140 static void Close( vlc_object_t * p_this )
141 {
142     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
143     sout_mux_sys_t  *p_sys = p_mux->p_sys;
144
145     sout_buffer_t       *p_end;
146
147     msg_Info( p_mux, "Close" );
148
149     p_end = sout_BufferNew( p_mux->p_sout, 4 );
150     SetDWBE( p_end->p_buffer, 0x01b9 );
151
152     sout_AccessOutWrite( p_mux->p_access, p_end );
153
154     free( p_sys );
155 }
156
157 static int Capability( sout_mux_t *p_mux, int i_query, void *p_args, void *p_answer )
158 {
159    switch( i_query )
160    {
161         case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
162             *(vlc_bool_t*)p_answer = VLC_TRUE;
163             return( SOUT_MUX_CAP_ERR_OK );
164         default:
165             return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
166    }
167 }
168
169 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
170 {
171     sout_mux_sys_t  *p_sys = p_mux->p_sys;
172     ps_stream_t         *p_stream;
173
174     msg_Dbg( p_mux, "adding input" );
175     p_input->p_sys = (void*)p_stream = malloc( sizeof( ps_stream_t ) );
176     p_stream->i_ok = 0;
177     switch( p_input->input_format.i_cat )
178     {
179         case VIDEO_ES:
180
181             switch( p_input->input_format.i_fourcc )
182             {
183                 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
184                     p_stream->i_stream_id = p_sys->i_stream_id_mpgv;
185                     p_sys->i_stream_id_mpgv++;
186                     p_sys->i_video_bound++;
187                     break;
188                 default:
189                     return( -1 );
190             }
191             break;
192         case AUDIO_ES:
193             switch( p_input->input_format.i_fourcc )
194             {
195                 case VLC_FOURCC( 'a', '5', '2', ' ' ):
196                 case VLC_FOURCC( 'a', '5', '2', 'b' ):
197                     p_stream->i_stream_id = p_sys->i_stream_id_a52 | ( 0xbd << 8 );
198                     p_sys->i_stream_id_a52++;
199                     p_sys->i_audio_bound++;
200                     break;
201                 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
202                     p_stream->i_stream_id = p_sys->i_stream_id_mpga;
203                     p_sys->i_stream_id_mpga++;
204                     p_sys->i_audio_bound++;
205                     break;
206                 default:
207                     return( -1 );
208             }
209             break;
210         default:
211             return( -1 );
212     }
213
214     p_stream->i_ok = 1;
215     msg_Dbg( p_mux, "adding input stream_id:0x%x [OK]", p_stream->i_stream_id );
216     return( 0 );
217 }
218
219 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
220 {
221     ps_stream_t         *p_stream =(ps_stream_t*)p_input->p_sys;
222
223     msg_Dbg( p_mux, "removing input" );
224     if( p_stream )
225     {
226         free( p_stream );
227     }
228     return( VLC_SUCCESS );
229 }
230
231 static int MuxWritePackHeader( sout_mux_t *p_mux,
232                                mtime_t         i_dts )
233 {
234     sout_buffer_t   *p_hdr;
235     bits_buffer_t   bits;
236     mtime_t         i_src;
237
238     i_src = i_dts * 9 / 100;
239
240     p_hdr = sout_BufferNew( p_mux->p_sout, 18 );
241     bits_initwrite( &bits, 14, p_hdr->p_buffer );
242     bits_write( &bits, 32, 0x01ba );
243     bits_write( &bits, 2, 0x01 );       // FIXME ??
244     bits_write( &bits, 3, ( i_src >> 30 )&0x07 );
245     bits_write( &bits, 1,  1 );
246     bits_write( &bits, 15, ( i_src >> 15 )&0x7fff );
247     bits_write( &bits, 1,  1 );
248     bits_write( &bits, 15, i_src&0x7fff );
249     bits_write( &bits, 1,  1 );
250
251     bits_write( &bits, 9,  0 ); // src extention
252     bits_write( &bits, 1,  1 );
253
254     bits_write( &bits, 22,  0/8/50); // FIXME
255     bits_write( &bits, 1,  1 );
256     bits_write( &bits, 1,  1 );
257     bits_write( &bits, 5,  0x1f );  // FIXME reserved
258     bits_write( &bits, 3,  0 );     // stuffing bytes
259     p_hdr->i_size = 14;
260     sout_AccessOutWrite( p_mux->p_access, p_hdr );
261
262     return( 0 );
263 }
264
265 static int MuxWriteSystemHeader( sout_mux_t *p_mux )
266 {
267     sout_mux_sys_t  *p_sys = p_mux->p_sys;
268     sout_buffer_t   *p_hdr;
269     bits_buffer_t   bits;
270
271     p_hdr = sout_BufferNew( p_mux->p_sout, 12 );
272
273     bits_initwrite( &bits, 12, p_hdr->p_buffer );
274     bits_write( &bits, 32, 0x01bb );
275     bits_write( &bits, 16, 12 - 6);
276     bits_write( &bits, 1,  1 );
277     bits_write( &bits, 22, 0 ); // FIXME rate bound
278     bits_write( &bits, 1,  1 );
279
280     bits_write( &bits, 6,  p_sys->i_audio_bound );
281     bits_write( &bits, 1,  0 ); // fixed flag
282     bits_write( &bits, 1,  0 ); // CSPS flag
283     bits_write( &bits, 1,  0 ); // system audio lock flag
284     bits_write( &bits, 1,  0 ); // system video lock flag
285
286     bits_write( &bits, 1,  1 ); // marker bit
287
288     bits_write( &bits, 5,  p_sys->i_video_bound );
289     bits_write( &bits, 1,  0 ); // packet rate restriction flag
290     bits_write( &bits, 7,  0x7f ); // reserved bits
291
292     /* FIXME missing stream_id ... */
293
294     sout_AccessOutWrite( p_mux->p_access, p_hdr );
295
296     return( 0 );
297 }
298
299 /* return stream number to be muxed */
300 static int MuxGetStream( sout_mux_t *p_mux, 
301                          int        *pi_stream, 
302                          mtime_t    *pi_dts )
303 {
304     mtime_t i_dts;
305     int     i_stream;
306     int     i;
307
308     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
309     {
310         sout_fifo_t  *p_fifo;
311
312         p_fifo = p_mux->pp_inputs[i]->p_fifo;
313
314         if( p_fifo->i_depth > 1 )
315         {
316             sout_buffer_t *p_buf;
317
318             p_buf = sout_FifoShow( p_fifo );
319             if( i_stream < 0 || p_buf->i_dts < i_dts )
320             {
321                 i_dts = p_buf->i_dts;
322                 i_stream = i;
323             }
324         }
325         else
326         {
327             return( -1 ); // wait that all fifo have at least 2 packets
328         }
329     }
330
331     if( pi_stream )
332     {
333         *pi_stream = i_stream;
334     }
335     if( pi_dts )
336     {
337         *pi_dts = i_dts;
338     }
339
340     return( i_stream );
341 }
342
343
344 static int Mux      ( sout_mux_t *p_mux )
345 {
346     sout_mux_sys_t *p_sys = p_mux->p_sys;
347     mtime_t        i_dts;
348     int            i_stream;
349
350     for( ;; )
351     {
352         sout_input_t *p_input;
353         ps_stream_t *p_stream;
354         sout_fifo_t  *p_fifo;
355         sout_buffer_t *p_data;
356
357         if( MuxGetStream( p_mux, &i_stream, &i_dts ) < 0 )
358         {
359             return( VLC_SUCCESS );
360         }
361
362         p_input = p_mux->pp_inputs[i_stream];
363         p_fifo = p_input->p_fifo;
364         p_stream = (ps_stream_t*)p_input->p_sys;
365
366         if( p_sys->i_pes_count % 30 == 0)
367         {
368             MuxWritePackHeader( p_mux, i_dts );
369         }
370
371         if( p_sys->i_pes_count % 300 == 0 )
372         {
373 //            MuxWriteSystemHeader( p_sout );
374         }
375
376         p_data = sout_FifoGet( p_fifo );
377         E_( EStoPES )( p_mux->p_sout, &p_data, p_data, p_stream->i_stream_id, 1);
378         sout_AccessOutWrite( p_mux->p_access, p_data );
379
380         p_sys->i_pes_count++;
381
382     }
383     return( 0 );
384 }
385