]> git.sesse.net Git - vlc/blob - modules/mux/mpeg/ps.c
7adcd7e2a556e52972a224d604d2ec47cccb8477
[vlc] / modules / mux / mpeg / ps.c
1 /*****************************************************************************
2  * ps.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: ps.c,v 1.3 2002/12/18 14:17:11 sam 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 #elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
43 #   include <io.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 AddStream( sout_instance_t *, sout_input_t * );
57 static int DelStream( sout_instance_t *, sout_input_t * );
58 static int Mux      ( sout_instance_t * );
59
60 static void SetWBE ( uint8_t *p, uint16_t v )
61 {
62     p[0] = ( v >> 8 )&0xff;
63     p[1] = v&0xff;
64 }
65 static void SetDWBE( uint8_t *p, uint32_t v )
66 {
67     SetWBE( p,    ( v >> 16 )&0xffff );
68     SetWBE( p + 2,  v & 0xffff );
69 }
70 #define ADD_DWBE( p_buff, v ) \
71     SetDWBE( (p_buff)->p_buffer + i_buffer, (v) ); \
72     i_buffer +=4;
73
74 /*****************************************************************************
75  * Module descriptor
76  *****************************************************************************/
77 vlc_module_begin();
78     set_description( _("PS muxer") );
79     set_capability( "sout mux", 50 );
80     add_shortcut( "ps" );
81     set_callbacks( Open, Close );
82 vlc_module_end();
83
84 typedef struct ps_stream_s
85 {
86     int             i_ok;
87
88     int             i_stream_id;
89
90 } ps_stream_t;
91
92 typedef struct sout_mux_s
93 {
94
95     int         i_stream_id_mpga;
96     int         i_stream_id_mpgv;
97     int         i_stream_id_a52;
98
99     int         i_audio_bound;
100     int         i_video_bound;
101
102     int         i_pes_count;
103
104     int         i_system_header;
105 } sout_mux_t;
106
107 /*****************************************************************************
108  * Open:
109  *****************************************************************************/
110 static int Open( vlc_object_t *p_this )
111 {
112     sout_instance_t     *p_sout = (sout_instance_t*)p_this;
113     sout_mux_t          *p_mux;
114
115     msg_Info( p_sout, "Open" );
116
117     p_mux = malloc( sizeof( sout_mux_t ) );
118
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
124     p_mux->i_stream_id_mpga = 0xc0;
125     p_mux->i_stream_id_a52  = 0x80;
126     p_mux->i_stream_id_mpgv = 0xe0;
127     p_mux->i_audio_bound = 0;
128     p_mux->i_video_bound = 0;
129     p_mux->i_system_header = 0;
130     p_mux->i_pes_count = 0;
131
132     return VLC_SUCCESS;
133 }
134
135 /*****************************************************************************
136  * Close:
137  *****************************************************************************/
138
139 static void Close( vlc_object_t * p_this )
140 {
141     sout_instance_t     *p_sout = (sout_instance_t*)p_this;
142     sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
143     sout_buffer_t       *p_end;
144
145     msg_Info( p_sout, "Close" );
146
147     p_end = sout_BufferNew( p_sout, 4 );
148     SetDWBE( p_end->p_buffer, 0x01b9 );
149
150     p_sout->pf_write( p_sout, p_end );
151
152     free( p_mux );
153
154     p_sout->p_mux_data = NULL;
155 }
156
157
158 static int AddStream( sout_instance_t *p_sout, sout_input_t *p_input )
159 {
160     sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
161     ps_stream_t         *p_stream;
162
163     msg_Dbg( p_sout, "adding input" );
164     p_input->p_mux_data = (void*)p_stream = malloc( sizeof( ps_stream_t ) );
165     p_stream->i_ok = 0;
166     switch( p_input->input_format.i_cat )
167     {
168         case VIDEO_ES:
169             p_stream->i_stream_id = p_mux->i_stream_id_mpgv;
170             p_mux->i_stream_id_mpgv++;
171             p_mux->i_video_bound++;
172             break;
173         case AUDIO_ES:
174             if( p_input->input_format.i_fourcc == VLC_FOURCC( 'a', '5', '2', ' ' ) )
175             {
176                 p_stream->i_stream_id = p_mux->i_stream_id_a52;
177                 p_mux->i_stream_id_a52++;
178             }
179             else
180             {
181                 p_stream->i_stream_id = p_mux->i_stream_id_mpga;
182                 p_mux->i_stream_id_mpga++;
183             }
184             p_mux->i_audio_bound++;
185             break;
186         default:
187             return( -1 );
188     }
189
190     p_stream->i_ok = 1;
191     msg_Dbg( p_sout, "adding input stream_id:0x%x [OK]", p_stream->i_stream_id );
192     return( 0 );
193 }
194
195 static int DelStream( sout_instance_t *p_sout, sout_input_t *p_input )
196 {
197     ps_stream_t         *p_stream =(ps_stream_t*)p_input->p_mux_data;
198
199     msg_Dbg( p_sout, "removing input" );
200     if( p_stream )
201     {
202         free( p_stream );
203     }
204     return( 0 );
205 }
206
207 static int MuxWritePackHeader( sout_instance_t *p_sout,
208                                mtime_t         i_dts )
209 {
210     sout_buffer_t   *p_hdr;
211     bits_buffer_t   bits;
212     mtime_t         i_src;
213
214     i_src = i_dts * 9 / 100;
215
216     p_hdr = sout_BufferNew( p_sout, 18 );
217     bits_initwrite( &bits, 14, p_hdr->p_buffer );
218     bits_write( &bits, 32, 0x01ba );
219     bits_write( &bits, 2, 0x01 );       // FIXME ??
220     bits_write( &bits, 3, ( i_src >> 30 )&0x07 );
221     bits_write( &bits, 1,  1 );
222     bits_write( &bits, 15, ( i_src >> 15 )&0x7fff );
223     bits_write( &bits, 1,  1 );
224     bits_write( &bits, 15, i_src&0x7fff );
225     bits_write( &bits, 1,  1 );
226
227     bits_write( &bits, 9,  0 ); // src extention
228     bits_write( &bits, 1,  1 );
229
230     bits_write( &bits, 22,  0/8/50); // FIXME
231     bits_write( &bits, 1,  1 );
232     bits_write( &bits, 1,  1 );
233     bits_write( &bits, 5,  0x1f );  // FIXME reserved
234     bits_write( &bits, 3,  0 );     // stuffing bytes
235     p_hdr->i_size = 14;
236     p_sout->pf_write( p_sout, p_hdr );
237
238     return( 0 );
239 }
240
241 static int MuxWriteSystemHeader( sout_instance_t *p_sout )
242 {
243     sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
244     sout_buffer_t   *p_hdr;
245     bits_buffer_t   bits;
246
247     p_hdr = sout_BufferNew( p_sout, 12 );
248
249     bits_initwrite( &bits, 12, p_hdr->p_buffer );
250     bits_write( &bits, 32, 0x01bb );
251     bits_write( &bits, 16, 12 - 6);
252     bits_write( &bits, 1,  1 );
253     bits_write( &bits, 22, 0 ); // FIXME rate bound
254     bits_write( &bits, 1,  1 );
255
256     bits_write( &bits, 6,  p_mux->i_audio_bound );
257     bits_write( &bits, 1,  0 ); // fixed flag
258     bits_write( &bits, 1,  0 ); // CSPS flag
259     bits_write( &bits, 1,  0 ); // system audio lock flag
260     bits_write( &bits, 1,  0 ); // system video lock flag
261
262     bits_write( &bits, 1,  1 ); // marker bit
263
264     bits_write( &bits, 5,  p_mux->i_video_bound );
265     bits_write( &bits, 1,  0 ); // packet rate restriction flag
266     bits_write( &bits, 7,  0x7f ); // reserved bits
267
268     /* FIXME missing stream_id ... */
269
270     p_sout->pf_write( p_sout, p_hdr );
271
272     return( 0 );
273 }
274
275 /* return stream number to be muxed */
276 static int MuxGetStream( sout_instance_t *p_sout, 
277                          int        *pi_stream, 
278                          mtime_t    *pi_dts )
279 {
280     mtime_t i_dts;
281     int     i_stream;
282     int     i;
283
284     for( i = 0, i_dts = 0, i_stream = -1; i < p_sout->i_nb_inputs; i++ )
285     {
286         sout_fifo_t  *p_fifo;
287
288         p_fifo = p_sout->pp_inputs[i]->p_fifo;
289
290         if( p_fifo->i_depth > 1 )
291         {
292             sout_buffer_t *p_buf;
293
294             p_buf = sout_FifoShow( p_fifo );
295             if( i_stream < 0 || p_buf->i_dts < i_dts )
296             {
297                 i_dts = p_buf->i_dts;
298                 i_stream = i;
299             }
300         }
301         else
302         {
303             return( -1 ); // wait that all fifo have at least 2 packets
304         }
305     }
306
307     if( pi_stream )
308     {
309         *pi_stream = i_stream;
310     }
311     if( pi_dts )
312     {
313         *pi_dts = i_dts;
314     }
315
316     return( i_stream );
317 }
318
319
320 static int Mux      ( sout_instance_t *p_sout )
321 {
322     sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
323     mtime_t i_dts;
324     int     i_stream;
325
326     for( ;; )
327     {
328         sout_input_t *p_input;
329         ps_stream_t *p_stream;
330         sout_fifo_t  *p_fifo;
331         sout_buffer_t *p_data;
332
333         if( MuxGetStream( p_sout, &i_stream, &i_dts ) < 0 )
334         {
335             return( 0 );
336         }
337
338         p_input = p_sout->pp_inputs[i_stream];
339         p_fifo = p_input->p_fifo;
340         p_stream = (ps_stream_t*)p_input->p_mux_data;
341
342         if( p_mux->i_pes_count % 30 == 0)
343         {
344             MuxWritePackHeader( p_sout, i_dts );
345         }
346
347         if( p_mux->i_pes_count % 300 == 0 )
348         {
349 //            MuxWriteSystemHeader( p_sout );
350         }
351
352         p_data = sout_FifoGet( p_fifo );
353         E_( EStoPES )( p_sout, &p_data, p_data, p_stream->i_stream_id, 1);
354         p_sout->pf_write( p_sout, p_data );
355
356         p_mux->i_pes_count++;
357
358     }
359     return( 0 );
360 }
361