72edad3f019aa08e0009bb644836d67533bf4ef4
[vlc.git] / modules / mux / mpeg / ps.c
1 /*****************************************************************************
2  * ps.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: ps.c,v 1.10 2003/03/03 14:21:08 gbazin 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_instance_t *, int, void *, void * );
55 static int AddStream( sout_instance_t *, sout_input_t * );
56 static int DelStream( sout_instance_t *, sout_input_t * );
57 static int Mux      ( sout_instance_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 typedef struct sout_mux_s
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 } sout_mux_t;
105
106 /*****************************************************************************
107  * Open:
108  *****************************************************************************/
109 static int Open( vlc_object_t *p_this )
110 {
111     sout_instance_t     *p_sout = (sout_instance_t*)p_this;
112     sout_mux_t          *p_mux;
113
114     msg_Info( p_sout, "Open" );
115
116     p_mux = malloc( sizeof( sout_mux_t ) );
117
118     p_sout->pf_mux_capacity  = Capability;
119     p_sout->pf_mux_addstream = AddStream;
120     p_sout->pf_mux_delstream = DelStream;
121     p_sout->pf_mux           = Mux;
122     p_sout->p_mux_data       = (void*)p_mux;
123     p_sout->i_mux_preheader  = 30; // really enough for a pes header
124
125     p_mux->i_stream_id_mpga = 0xc0;
126     p_mux->i_stream_id_a52  = 0x80;
127     p_mux->i_stream_id_mpgv = 0xe0;
128     p_mux->i_audio_bound = 0;
129     p_mux->i_video_bound = 0;
130     p_mux->i_system_header = 0;
131     p_mux->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_instance_t     *p_sout = (sout_instance_t*)p_this;
143     sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
144     sout_buffer_t       *p_end;
145
146     msg_Info( p_sout, "Close" );
147
148     p_end = sout_BufferNew( p_sout, 4 );
149     SetDWBE( p_end->p_buffer, 0x01b9 );
150
151     sout_AccessOutWrite( p_sout->p_access, p_end );
152
153     free( p_mux );
154
155     p_sout->p_mux_data = NULL;
156 }
157
158 static int Capability( sout_instance_t *p_sout, int i_query, void *p_args, void *p_answer )
159 {
160    switch( i_query )
161    {
162         case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
163             *(vlc_bool_t*)p_answer = VLC_TRUE;
164             return( SOUT_MUX_CAP_ERR_OK );
165         default:
166             return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
167    }
168 }
169
170 static int AddStream( sout_instance_t *p_sout, sout_input_t *p_input )
171 {
172     sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
173     ps_stream_t         *p_stream;
174
175     msg_Dbg( p_sout, "adding input" );
176     p_input->p_mux_data = (void*)p_stream = malloc( sizeof( ps_stream_t ) );
177     p_stream->i_ok = 0;
178     switch( p_input->input_format.i_cat )
179     {
180         case VIDEO_ES:
181
182             switch( p_input->input_format.i_fourcc )
183             {
184                 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
185                     p_stream->i_stream_id = p_mux->i_stream_id_mpgv;
186                     p_mux->i_stream_id_mpgv++;
187                     p_mux->i_video_bound++;
188                     break;
189                 default:
190                     return( -1 );
191             }
192             break;
193         case AUDIO_ES:
194             switch( p_input->input_format.i_fourcc )
195             {
196                 case VLC_FOURCC( 'a', '5', '2', ' ' ):
197                 case VLC_FOURCC( 'a', '5', '2', 'b' ):
198                     p_stream->i_stream_id = p_mux->i_stream_id_a52 | ( 0xbd << 8 );
199                     p_mux->i_stream_id_a52++;
200                     p_mux->i_audio_bound++;
201                     break;
202                 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
203                     p_stream->i_stream_id = p_mux->i_stream_id_mpga;
204                     p_mux->i_stream_id_mpga++;
205                     p_mux->i_audio_bound++;
206                     break;
207                 default:
208                     return( -1 );
209             }
210             break;
211         default:
212             return( -1 );
213     }
214
215     p_stream->i_ok = 1;
216     msg_Dbg( p_sout, "adding input stream_id:0x%x [OK]", p_stream->i_stream_id );
217     return( 0 );
218 }
219
220 static int DelStream( sout_instance_t *p_sout, sout_input_t *p_input )
221 {
222     ps_stream_t         *p_stream =(ps_stream_t*)p_input->p_mux_data;
223
224     msg_Dbg( p_sout, "removing input" );
225     if( p_stream )
226     {
227         free( p_stream );
228     }
229     return( 0 );
230 }
231
232 static int MuxWritePackHeader( sout_instance_t *p_sout,
233                                mtime_t         i_dts )
234 {
235     sout_buffer_t   *p_hdr;
236     bits_buffer_t   bits;
237     mtime_t         i_src;
238
239     i_src = i_dts * 9 / 100;
240
241     p_hdr = sout_BufferNew( p_sout, 18 );
242     bits_initwrite( &bits, 14, p_hdr->p_buffer );
243     bits_write( &bits, 32, 0x01ba );
244     bits_write( &bits, 2, 0x01 );       // FIXME ??
245     bits_write( &bits, 3, ( i_src >> 30 )&0x07 );
246     bits_write( &bits, 1,  1 );
247     bits_write( &bits, 15, ( i_src >> 15 )&0x7fff );
248     bits_write( &bits, 1,  1 );
249     bits_write( &bits, 15, i_src&0x7fff );
250     bits_write( &bits, 1,  1 );
251
252     bits_write( &bits, 9,  0 ); // src extention
253     bits_write( &bits, 1,  1 );
254
255     bits_write( &bits, 22,  0/8/50); // FIXME
256     bits_write( &bits, 1,  1 );
257     bits_write( &bits, 1,  1 );
258     bits_write( &bits, 5,  0x1f );  // FIXME reserved
259     bits_write( &bits, 3,  0 );     // stuffing bytes
260     p_hdr->i_size = 14;
261     sout_AccessOutWrite( p_sout->p_access, p_hdr );
262
263     return( 0 );
264 }
265
266 static int MuxWriteSystemHeader( sout_instance_t *p_sout )
267 {
268     sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
269     sout_buffer_t   *p_hdr;
270     bits_buffer_t   bits;
271
272     p_hdr = sout_BufferNew( p_sout, 12 );
273
274     bits_initwrite( &bits, 12, p_hdr->p_buffer );
275     bits_write( &bits, 32, 0x01bb );
276     bits_write( &bits, 16, 12 - 6);
277     bits_write( &bits, 1,  1 );
278     bits_write( &bits, 22, 0 ); // FIXME rate bound
279     bits_write( &bits, 1,  1 );
280
281     bits_write( &bits, 6,  p_mux->i_audio_bound );
282     bits_write( &bits, 1,  0 ); // fixed flag
283     bits_write( &bits, 1,  0 ); // CSPS flag
284     bits_write( &bits, 1,  0 ); // system audio lock flag
285     bits_write( &bits, 1,  0 ); // system video lock flag
286
287     bits_write( &bits, 1,  1 ); // marker bit
288
289     bits_write( &bits, 5,  p_mux->i_video_bound );
290     bits_write( &bits, 1,  0 ); // packet rate restriction flag
291     bits_write( &bits, 7,  0x7f ); // reserved bits
292
293     /* FIXME missing stream_id ... */
294
295     sout_AccessOutWrite( p_sout->p_access, p_hdr );
296
297     return( 0 );
298 }
299
300 /* return stream number to be muxed */
301 static int MuxGetStream( sout_instance_t *p_sout, 
302                          int        *pi_stream, 
303                          mtime_t    *pi_dts )
304 {
305     mtime_t i_dts;
306     int     i_stream;
307     int     i;
308
309     for( i = 0, i_dts = 0, i_stream = -1; i < p_sout->i_nb_inputs; i++ )
310     {
311         sout_fifo_t  *p_fifo;
312
313         p_fifo = p_sout->pp_inputs[i]->p_fifo;
314
315         if( p_fifo->i_depth > 1 )
316         {
317             sout_buffer_t *p_buf;
318
319             p_buf = sout_FifoShow( p_fifo );
320             if( i_stream < 0 || p_buf->i_dts < i_dts )
321             {
322                 i_dts = p_buf->i_dts;
323                 i_stream = i;
324             }
325         }
326         else
327         {
328             return( -1 ); // wait that all fifo have at least 2 packets
329         }
330     }
331
332     if( pi_stream )
333     {
334         *pi_stream = i_stream;
335     }
336     if( pi_dts )
337     {
338         *pi_dts = i_dts;
339     }
340
341     return( i_stream );
342 }
343
344
345 static int Mux      ( sout_instance_t *p_sout )
346 {
347     sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
348     mtime_t i_dts;
349     int     i_stream;
350
351     for( ;; )
352     {
353         sout_input_t *p_input;
354         ps_stream_t *p_stream;
355         sout_fifo_t  *p_fifo;
356         sout_buffer_t *p_data;
357
358         if( MuxGetStream( p_sout, &i_stream, &i_dts ) < 0 )
359         {
360             return( 0 );
361         }
362
363         p_input = p_sout->pp_inputs[i_stream];
364         p_fifo = p_input->p_fifo;
365         p_stream = (ps_stream_t*)p_input->p_mux_data;
366
367         if( p_mux->i_pes_count % 30 == 0)
368         {
369             MuxWritePackHeader( p_sout, i_dts );
370         }
371
372         if( p_mux->i_pes_count % 300 == 0 )
373         {
374 //            MuxWriteSystemHeader( p_sout );
375         }
376
377         p_data = sout_FifoGet( p_fifo );
378         E_( EStoPES )( p_sout, &p_data, p_data, p_stream->i_stream_id, 1);
379         sout_AccessOutWrite( p_sout->p_access, p_data );
380
381         p_mux->i_pes_count++;
382
383     }
384     return( 0 );
385 }
386