]> git.sesse.net Git - vlc/blob - modules/packetizer/copy.c
* all: new sout scheme. Now a chain of module are created that can
[vlc] / modules / packetizer / copy.c
1 /*****************************************************************************
2  * copy.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: copy.c,v 1.7 2003/04/13 20:00:21 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Eric Petit <titer@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <vlc/vlc.h>
29 #include <vlc/aout.h>
30 #include <vlc/decoder.h>
31 #include <vlc/input.h>
32 #include <vlc/sout.h>
33
34 #include <stdlib.h>                                      /* malloc(), free() */
35 #include <string.h>                                              /* strdup() */
36
37 #include "codecs.h"
38 /*****************************************************************************
39  * Local prototypes
40  *****************************************************************************/
41 typedef struct packetizer_thread_s
42 {
43     /* Input properties */
44     decoder_fifo_t          *p_fifo;
45
46     /* Output properties */
47     sout_packetizer_input_t *p_sout_input;
48     sout_format_t           output_format;
49
50 //    mtime_t i_last_pts;
51
52 } packetizer_thread_t;
53
54 static int  Open    ( vlc_object_t * );
55 static int  Run     ( decoder_fifo_t * );
56
57 static int  InitThread     ( packetizer_thread_t * );
58 static void PacketizeThread   ( packetizer_thread_t * );
59 static void EndThread      ( packetizer_thread_t * );
60
61
62 static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes );
63
64 /*****************************************************************************
65  * Module descriptor
66  *****************************************************************************/
67
68 vlc_module_begin();
69     set_description( _("Copy packetizer") );
70     set_capability( "packetizer", 1 );
71     set_callbacks( Open, NULL );
72 vlc_module_end();
73
74
75 /*****************************************************************************
76  * OpenDecoder: probe the packetizer and return score
77  *****************************************************************************
78  * Tries to launch a decoder and return score so that the interface is able
79  * to choose.
80  *****************************************************************************/
81 static int Open( vlc_object_t *p_this )
82 {
83     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
84
85     p_fifo->pf_run = Run;
86
87     return VLC_SUCCESS;
88 }
89
90 /*****************************************************************************
91  * RunDecoder: this function is called just after the thread is created
92  *****************************************************************************/
93 static int Run( decoder_fifo_t *p_fifo )
94 {
95     packetizer_thread_t *p_pack;
96     int b_error;
97
98     msg_Info( p_fifo, "Running copy packetizer" );
99     if( !( p_pack = malloc( sizeof( packetizer_thread_t ) ) ) )
100     {
101         msg_Err( p_fifo, "out of memory" );
102         DecoderError( p_fifo );
103         return( -1 );
104     }
105     memset( p_pack, 0, sizeof( packetizer_thread_t ) );
106
107     p_pack->p_fifo = p_fifo;
108
109     if( InitThread( p_pack ) != 0 )
110     {
111         DecoderError( p_fifo );
112         return( -1 );
113     }
114
115     while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
116     {
117         PacketizeThread( p_pack );
118     }
119
120
121     if( ( b_error = p_pack->p_fifo->b_error ) )
122     {
123         DecoderError( p_pack->p_fifo );
124     }
125
126     EndThread( p_pack );
127     if( b_error )
128     {
129         return( -1 );
130     }
131
132     return( 0 );
133 }
134
135
136 #define FREE( p ) if( p ) free( p ); p = NULL
137
138 /*****************************************************************************
139  * InitThread: initialize data before entering main loop
140  *****************************************************************************/
141
142 static int InitThread( packetizer_thread_t *p_pack )
143 {
144
145     switch( p_pack->p_fifo->i_fourcc )
146     {
147         case VLC_FOURCC( 'm', '4', 's', '2'):
148         case VLC_FOURCC( 'M', '4', 'S', '2'):
149         case VLC_FOURCC( 'm', 'p', '4', 's'):
150         case VLC_FOURCC( 'M', 'P', '4', 'S'):
151         case VLC_FOURCC( 'm', 'p', '4', 'v'):
152         case VLC_FOURCC( 'D', 'I', 'V', 'X'):
153         case VLC_FOURCC( 'd', 'i', 'v', 'x'):
154         case VLC_FOURCC( 'X', 'V', 'I', 'D'):
155         case VLC_FOURCC( 'X', 'v', 'i', 'D'):
156         case VLC_FOURCC( 'x', 'v', 'i', 'd'):
157         case VLC_FOURCC( 'D', 'X', '5', '0'):
158         case VLC_FOURCC( 0x04, 0,   0,   0):
159         case VLC_FOURCC( '3', 'I', 'V', '2'):
160             p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v');
161             p_pack->output_format.i_cat = VIDEO_ES;
162             break;
163         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
164         case VLC_FOURCC( 'm', 'p', 'g', '1' ):
165         case VLC_FOURCC( 'm', 'p', 'g', '2' ):
166         case VLC_FOURCC( 'm', 'p', '1', 'v' ):
167         case VLC_FOURCC( 'm', 'p', '2', 'v' ):
168             p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'v' );
169             p_pack->output_format.i_cat = VIDEO_ES;
170             break;
171         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
172             p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'a' );
173             p_pack->output_format.i_cat = AUDIO_ES;
174             break;
175
176         case VLC_FOURCC( 'd', 'i', 'v', '1' ):
177         case VLC_FOURCC( 'D', 'I', 'V', '1' ):
178         case VLC_FOURCC( 'M', 'P', 'G', '4' ):
179         case VLC_FOURCC( 'm', 'p', 'g', '4' ):
180             p_pack->output_format.i_fourcc = VLC_FOURCC( 'D', 'I', 'V', '1' );
181             p_pack->output_format.i_cat = VIDEO_ES;
182             break;
183         case VLC_FOURCC( 'd', 'i', 'v', '2' ):
184         case VLC_FOURCC( 'D', 'I', 'V', '2' ):
185         case VLC_FOURCC( 'M', 'P', '4', '2' ):
186         case VLC_FOURCC( 'm', 'p', '4', '2' ):
187             p_pack->output_format.i_fourcc = VLC_FOURCC( 'D', 'I', 'V', '2' );
188             p_pack->output_format.i_cat = VIDEO_ES;
189             break;
190         case VLC_FOURCC( 'd', 'i', 'v', '3' ):
191         case VLC_FOURCC( 'D', 'I', 'V', '3' ):
192         case VLC_FOURCC( 'd', 'i', 'v', '4' ):
193         case VLC_FOURCC( 'D', 'I', 'V', '4' ):
194         case VLC_FOURCC( 'd', 'i', 'v', '5' ):
195         case VLC_FOURCC( 'D', 'I', 'V', '5' ):
196         case VLC_FOURCC( 'd', 'i', 'v', '6' ):
197         case VLC_FOURCC( 'D', 'I', 'V', '6' ):
198         case VLC_FOURCC( 'M', 'P', '4', '3' ):
199         case VLC_FOURCC( 'm', 'p', '4', '3' ):
200         case VLC_FOURCC( 'm', 'p', 'g', '3' ):
201         case VLC_FOURCC( 'M', 'P', 'G', '3' ):
202         case VLC_FOURCC( 'A', 'P', '4', '1' ):
203             p_pack->output_format.i_fourcc = VLC_FOURCC( 'D', 'I', 'V', '3' );
204             p_pack->output_format.i_cat = VIDEO_ES;
205             break;
206         case VLC_FOURCC( 'H', '2', '6', '3' ):
207         case VLC_FOURCC( 'h', '2', '6', '3' ):
208         case VLC_FOURCC( 'U', '2', '6', '3' ):
209         case VLC_FOURCC( 'u', '2', '6', '3' ):
210             p_pack->output_format.i_fourcc = VLC_FOURCC( 'H', '2', '6', '3' );
211             p_pack->output_format.i_cat = VIDEO_ES;
212             break;
213         case VLC_FOURCC( 'I', '2', '6', '3' ):
214         case VLC_FOURCC( 'i', '2', '6', '3' ):
215             p_pack->output_format.i_fourcc = VLC_FOURCC( 'I', '2', '6', '3' );
216             p_pack->output_format.i_cat = VIDEO_ES;
217             break;
218         case VLC_FOURCC( 'W', 'M', 'V', '1' ):
219             p_pack->output_format.i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '1' );
220             p_pack->output_format.i_cat = VIDEO_ES;
221             break;
222         case VLC_FOURCC( 'W', 'M', 'V', '2' ):
223             p_pack->output_format.i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '2' );
224             p_pack->output_format.i_cat = VIDEO_ES;
225             break;
226         case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
227         case VLC_FOURCC( 'm', 'j', 'p', 'g' ):
228         case VLC_FOURCC( 'm', 'j', 'p', 'a' ):
229         case VLC_FOURCC( 'j', 'p', 'e', 'g' ):
230         case VLC_FOURCC( 'J', 'P', 'E', 'G' ):
231         case VLC_FOURCC( 'J', 'F', 'I', 'F' ):
232             p_pack->output_format.i_fourcc = VLC_FOURCC( 'M', 'J', 'P', 'G' );
233             p_pack->output_format.i_cat = VIDEO_ES;
234             break;
235         case VLC_FOURCC( 'm', 'j', 'p', 'b' ):
236             p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'j', 'p', 'b' );
237             p_pack->output_format.i_cat = VIDEO_ES;
238             break;
239         case VLC_FOURCC( 'd', 'v', 's', 'l' ):
240         case VLC_FOURCC( 'd', 'v', 's', 'd' ):
241         case VLC_FOURCC( 'D', 'V', 'S', 'D' ):
242         case VLC_FOURCC( 'd', 'v', 'h', 'd' ):
243             p_pack->output_format.i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'l' );
244             p_pack->output_format.i_cat = VIDEO_ES;
245             break;
246         case VLC_FOURCC( 'S', 'V', 'Q', '1' ):
247             p_pack->output_format.i_fourcc = VLC_FOURCC( 'S', 'V', 'Q', '1' );
248             p_pack->output_format.i_cat = VIDEO_ES;
249             break;
250
251         case VLC_FOURCC( 'w', 'm', 'a', '1' ):
252             p_pack->output_format.i_fourcc = VLC_FOURCC( 'w', 'm', 'a', '1' );
253             p_pack->output_format.i_cat = AUDIO_ES;
254             break;
255         case VLC_FOURCC( 'w', 'm', 'a', '2' ):
256             p_pack->output_format.i_fourcc = VLC_FOURCC( 'w', 'm', 'a', '2' );
257             p_pack->output_format.i_cat = AUDIO_ES;
258             break;
259
260         default:
261             msg_Err( p_pack->p_fifo, "unknown es type !!" );
262             return VLC_EGENERIC;
263             //p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc;
264             //p_pack->output_format.i_cat = UNKNOWN_ES;
265             //break;
266     }
267
268     switch( p_pack->output_format.i_cat )
269     {
270         case AUDIO_ES:
271             {
272                 WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
273                 if( p_wf )
274                 {
275                     p_pack->output_format.i_sample_rate = p_wf->nSamplesPerSec;
276                     p_pack->output_format.i_channels    = p_wf->nChannels;
277                     p_pack->output_format.i_block_align = p_wf->nBlockAlign;
278                     p_pack->output_format.i_bitrate     = p_wf->nAvgBytesPerSec * 8;
279                     p_pack->output_format.i_extra_data  = p_wf->cbSize;
280                     if( p_wf->cbSize  > 0 )
281                     {
282                         p_pack->output_format.p_extra_data =
283                             malloc( p_pack->output_format.i_extra_data );
284                         memcpy( p_pack->output_format.p_extra_data,
285                                 &p_wf[1],
286                                 p_pack->output_format.i_extra_data );
287                     }
288                     else
289                     {
290                         p_pack->output_format.p_extra_data = NULL;
291                     }
292                 }
293                 else
294                 {
295                     p_pack->output_format.i_sample_rate = 0;
296                     p_pack->output_format.i_channels    = 0;
297                     p_pack->output_format.i_block_align = 0;
298                     p_pack->output_format.i_bitrate     = 0;
299                     p_pack->output_format.i_extra_data  = 0;
300                     p_pack->output_format.p_extra_data  = NULL;
301                 }
302             }
303             break;
304
305         case VIDEO_ES:
306             {
307                 BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)p_pack->p_fifo->p_bitmapinfoheader;
308
309                 p_pack->output_format.i_bitrate = 0;
310                 if( p_bih )
311                 {
312                     p_pack->output_format.i_width  = p_bih->biWidth;
313                     p_pack->output_format.i_height = p_bih->biHeight;
314                     p_pack->output_format.i_extra_data  = p_bih->biSize - sizeof( BITMAPINFOHEADER );
315                     if( p_pack->output_format.i_extra_data > 0 )
316                     {
317                         p_pack->output_format.p_extra_data =
318                             malloc( p_pack->output_format.i_extra_data );
319                         memcpy( p_pack->output_format.p_extra_data,
320                                 &p_bih[1],
321                                 p_pack->output_format.i_extra_data );
322                     }
323                 }
324                 else
325                 {
326                     p_pack->output_format.i_width  = 0;
327                     p_pack->output_format.i_height = 0;
328                     p_pack->output_format.i_extra_data  = 0;
329                     p_pack->output_format.p_extra_data  = NULL;
330                 }
331             }
332             break;
333
334         default:
335             return VLC_EGENERIC;
336     }
337
338     p_pack->p_sout_input =
339         sout_InputNew( p_pack->p_fifo,
340                        &p_pack->output_format );
341
342     if( !p_pack->p_sout_input )
343     {
344         msg_Err( p_pack->p_fifo, "cannot add a new stream" );
345         return VLC_EGENERIC;
346     }
347 //    p_pack->i_last_pts = 0;
348     return( VLC_SUCCESS );
349 }
350
351 /*****************************************************************************
352  * PacketizeThread: packetize an unit (here copy a complete pes)
353  *****************************************************************************/
354 static void PacketizeThread( packetizer_thread_t *p_pack )
355 {
356     sout_buffer_t   *p_sout_buffer;
357     pes_packet_t    *p_pes;
358     ssize_t         i_size;
359     mtime_t         i_pts;
360
361     /* **** get samples count **** */
362     input_ExtractPES( p_pack->p_fifo, &p_pes );
363     if( !p_pes )
364     {
365         p_pack->p_fifo->b_error = 1;
366         return;
367     }
368     i_pts = p_pes->i_pts;
369
370     if( i_pts <= 0 ) //&& p_pack->i_last_pts <= 0 )
371     {
372         msg_Dbg( p_pack->p_fifo, "need pts != 0" );
373         input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
374         return;
375     }
376
377     i_size = p_pes->i_pes_size;
378
379 //    msg_Dbg( p_pack->p_fifo, "pes size:%d", i_size );
380     if( i_size > 0 )
381     {
382         pes_packet_t    *p_pes_next;
383         data_packet_t   *p_data;
384         ssize_t          i_buffer;
385
386         p_sout_buffer =
387             sout_BufferNew( p_pack->p_sout_input->p_sout, i_size );
388         if( !p_sout_buffer )
389         {
390             p_pack->p_fifo->b_error = 1;
391             input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
392             return;
393         }
394         /* TODO: memcpy of the pes packet */
395         for( i_buffer = 0, p_data = p_pes->p_first;
396              p_data != NULL && i_buffer < i_size;
397              p_data = p_data->p_next)
398         {
399             ssize_t i_copy;
400
401             i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
402                             i_size - i_buffer );
403             if( i_copy > 0 )
404             {
405                 p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer + i_buffer,
406                                                   p_data->p_payload_start,
407                                                   i_copy );
408             }
409             i_buffer += i_copy;
410         }
411         p_sout_buffer->i_length = 0;
412         p_sout_buffer->i_dts = i_pts; //p_pes->i_pts - p_pack->i_pts_start;
413         p_sout_buffer->i_pts = i_pts; //p_pes->i_pts - p_pack->i_pts_start;
414         p_sout_buffer->i_bitrate = 0;
415
416         input_ShowPES( p_pack->p_fifo, &p_pes_next );
417         if( p_pes_next )
418         {
419             p_sout_buffer->i_length = p_pes_next->i_pts - i_pts;
420         }
421         sout_InputSendBuffer( p_pack->p_sout_input,
422                                p_sout_buffer );
423     }
424
425     input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
426 }
427
428
429 /*****************************************************************************
430  * EndThread : packetizer thread destruction
431  *****************************************************************************/
432 static void EndThread ( packetizer_thread_t *p_pack)
433 {
434     if( p_pack->p_sout_input )
435     {
436         sout_InputDelete( p_pack->p_sout_input );
437     }
438 }
439
440 static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
441 {
442     pes_packet_t *p_pes;
443
444     vlc_mutex_lock( &p_fifo->data_lock );
445
446     if( p_fifo->p_first == NULL )
447     {
448         if( p_fifo->b_die )
449         {
450             vlc_mutex_unlock( &p_fifo->data_lock );
451             if( pp_pes ) *pp_pes = NULL;
452             return;
453         }
454
455         /* Signal the input thread we're waiting. This is only
456          * needed in case of slave clock (ES plug-in) but it won't
457          * harm. */
458         vlc_cond_signal( &p_fifo->data_wait );
459
460         /* Wait for the input to tell us when we received a packet. */
461         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
462     }
463     p_pes = p_fifo->p_first;
464     vlc_mutex_unlock( &p_fifo->data_lock );
465
466     if( pp_pes )
467     {
468         *pp_pes = p_pes;
469     }
470 }
471