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