]> git.sesse.net Git - vlc/blob - modules/packetizer/copy.c
* copy: added raw audio/video support.
[vlc] / modules / packetizer / copy.c
1 /*****************************************************************************
2  * copy.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: copy.c,v 1.8 2003/05/02 00:33:42 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         /* video */
148         case VLC_FOURCC( 'm', '4', 's', '2'):
149         case VLC_FOURCC( 'M', '4', 'S', '2'):
150         case VLC_FOURCC( 'm', 'p', '4', 's'):
151         case VLC_FOURCC( 'M', 'P', '4', 'S'):
152         case VLC_FOURCC( 'm', 'p', '4', 'v'):
153         case VLC_FOURCC( 'D', 'I', 'V', 'X'):
154         case VLC_FOURCC( 'd', 'i', 'v', 'x'):
155         case VLC_FOURCC( 'X', 'V', 'I', 'D'):
156         case VLC_FOURCC( 'X', 'v', 'i', 'D'):
157         case VLC_FOURCC( 'x', 'v', 'i', 'd'):
158         case VLC_FOURCC( 'D', 'X', '5', '0'):
159         case VLC_FOURCC( 0x04, 0,   0,   0):
160         case VLC_FOURCC( '3', 'I', 'V', '2'):
161             p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v');
162             p_pack->output_format.i_cat = VIDEO_ES;
163             break;
164         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
165         case VLC_FOURCC( 'm', 'p', 'g', '1' ):
166         case VLC_FOURCC( 'm', 'p', 'g', '2' ):
167         case VLC_FOURCC( 'm', 'p', '1', 'v' ):
168         case VLC_FOURCC( 'm', 'p', '2', 'v' ):
169             p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'v' );
170             p_pack->output_format.i_cat = VIDEO_ES;
171             break;
172
173         case VLC_FOURCC( 'd', 'i', 'v', '1' ):
174         case VLC_FOURCC( 'D', 'I', 'V', '1' ):
175         case VLC_FOURCC( 'M', 'P', 'G', '4' ):
176         case VLC_FOURCC( 'm', 'p', 'g', '4' ):
177             p_pack->output_format.i_fourcc = VLC_FOURCC( 'D', 'I', 'V', '1' );
178             p_pack->output_format.i_cat = VIDEO_ES;
179             break;
180         case VLC_FOURCC( 'd', 'i', 'v', '2' ):
181         case VLC_FOURCC( 'D', 'I', 'V', '2' ):
182         case VLC_FOURCC( 'M', 'P', '4', '2' ):
183         case VLC_FOURCC( 'm', 'p', '4', '2' ):
184             p_pack->output_format.i_fourcc = VLC_FOURCC( 'D', 'I', 'V', '2' );
185             p_pack->output_format.i_cat = VIDEO_ES;
186             break;
187         case VLC_FOURCC( 'd', 'i', 'v', '3' ):
188         case VLC_FOURCC( 'D', 'I', 'V', '3' ):
189         case VLC_FOURCC( 'd', 'i', 'v', '4' ):
190         case VLC_FOURCC( 'D', 'I', 'V', '4' ):
191         case VLC_FOURCC( 'd', 'i', 'v', '5' ):
192         case VLC_FOURCC( 'D', 'I', 'V', '5' ):
193         case VLC_FOURCC( 'd', 'i', 'v', '6' ):
194         case VLC_FOURCC( 'D', 'I', 'V', '6' ):
195         case VLC_FOURCC( 'M', 'P', '4', '3' ):
196         case VLC_FOURCC( 'm', 'p', '4', '3' ):
197         case VLC_FOURCC( 'm', 'p', 'g', '3' ):
198         case VLC_FOURCC( 'M', 'P', 'G', '3' ):
199         case VLC_FOURCC( 'A', 'P', '4', '1' ):
200             p_pack->output_format.i_fourcc = VLC_FOURCC( 'D', 'I', 'V', '3' );
201             p_pack->output_format.i_cat = VIDEO_ES;
202             break;
203         case VLC_FOURCC( 'H', '2', '6', '3' ):
204         case VLC_FOURCC( 'h', '2', '6', '3' ):
205         case VLC_FOURCC( 'U', '2', '6', '3' ):
206         case VLC_FOURCC( 'u', '2', '6', '3' ):
207             p_pack->output_format.i_fourcc = VLC_FOURCC( 'H', '2', '6', '3' );
208             p_pack->output_format.i_cat = VIDEO_ES;
209             break;
210         case VLC_FOURCC( 'I', '2', '6', '3' ):
211         case VLC_FOURCC( 'i', '2', '6', '3' ):
212             p_pack->output_format.i_fourcc = VLC_FOURCC( 'I', '2', '6', '3' );
213             p_pack->output_format.i_cat = VIDEO_ES;
214             break;
215         case VLC_FOURCC( 'W', 'M', 'V', '1' ):
216             p_pack->output_format.i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '1' );
217             p_pack->output_format.i_cat = VIDEO_ES;
218             break;
219         case VLC_FOURCC( 'W', 'M', 'V', '2' ):
220             p_pack->output_format.i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '2' );
221             p_pack->output_format.i_cat = VIDEO_ES;
222             break;
223         case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
224         case VLC_FOURCC( 'm', 'j', 'p', 'g' ):
225         case VLC_FOURCC( 'm', 'j', 'p', 'a' ):
226         case VLC_FOURCC( 'j', 'p', 'e', 'g' ):
227         case VLC_FOURCC( 'J', 'P', 'E', 'G' ):
228         case VLC_FOURCC( 'J', 'F', 'I', 'F' ):
229             p_pack->output_format.i_fourcc = VLC_FOURCC( 'M', 'J', 'P', 'G' );
230             p_pack->output_format.i_cat = VIDEO_ES;
231             break;
232         case VLC_FOURCC( 'm', 'j', 'p', 'b' ):
233             p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'j', 'p', 'b' );
234             p_pack->output_format.i_cat = VIDEO_ES;
235             break;
236         case VLC_FOURCC( 'd', 'v', 's', 'l' ):
237         case VLC_FOURCC( 'd', 'v', 's', 'd' ):
238         case VLC_FOURCC( 'D', 'V', 'S', 'D' ):
239         case VLC_FOURCC( 'd', 'v', 'h', 'd' ):
240             p_pack->output_format.i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'l' );
241             p_pack->output_format.i_cat = VIDEO_ES;
242             break;
243         case VLC_FOURCC( 'S', 'V', 'Q', '1' ):
244             p_pack->output_format.i_fourcc = VLC_FOURCC( 'S', 'V', 'Q', '1' );
245             p_pack->output_format.i_cat = VIDEO_ES;
246             break;
247
248         case VLC_FOURCC( 'I', '4', '2', '0' ):
249             p_pack->output_format.i_fourcc = VLC_FOURCC( 'I', '4', '2', '0' );
250             p_pack->output_format.i_cat = VIDEO_ES;
251             break;
252         case VLC_FOURCC( 'I', '4', '2', '2' ):
253             p_pack->output_format.i_fourcc = VLC_FOURCC( 'I', '4', '2', '2' );
254             p_pack->output_format.i_cat = VIDEO_ES;
255             break;
256
257         /* audio */
258         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
259             p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'a' );
260             p_pack->output_format.i_cat = AUDIO_ES;
261             break;
262         case VLC_FOURCC( 'w', 'm', 'a', '1' ):
263             p_pack->output_format.i_fourcc = VLC_FOURCC( 'w', 'm', 'a', '1' );
264             p_pack->output_format.i_cat = AUDIO_ES;
265             break;
266         case VLC_FOURCC( 'w', 'm', 'a', '2' ):
267             p_pack->output_format.i_fourcc = VLC_FOURCC( 'w', 'm', 'a', '2' );
268             p_pack->output_format.i_cat = AUDIO_ES;
269             break;
270         case VLC_FOURCC( 'a', 'r', 'a', 'w' ):
271         {
272             WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
273             if( p_wf )
274             {
275                 switch( ( p_wf->wBitsPerSample + 7 ) / 8 )
276                 {
277                     case 1:
278                         p_pack->output_format.i_fourcc = VLC_FOURCC('u','8',' ',' ');
279                         break;
280                     case 2:
281                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','1','6','l');
282                         break;
283                     case 3:
284                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','2','4','l');
285                         break;
286                     case 4:
287                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','3','2','l');
288                         break;
289                     default:
290                         msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
291                         return VLC_EGENERIC;
292                 }
293             }
294             else
295             {
296                 msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
297                 return VLC_EGENERIC;
298             }
299             p_pack->output_format.i_cat = AUDIO_ES;
300             break;
301         }
302         case VLC_FOURCC( 't', 'w', 'o', 's' ):
303         {
304             WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
305             if( p_wf )
306             {
307                 switch( ( p_wf->wBitsPerSample + 7 ) / 8 )
308                 {
309                     case 1:
310                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','8',' ',' ');
311                         break;
312                     case 2:
313                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','1','6','b');
314                         break;
315                     case 3:
316                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','2','4','b');
317                         break;
318                     case 4:
319                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','3','2','b');
320                         break;
321                     default:
322                         msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
323                         return VLC_EGENERIC;
324                 }
325             }
326             else
327             {
328                 msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
329                 return VLC_EGENERIC;
330             }
331             p_pack->output_format.i_cat = AUDIO_ES;
332             break;
333         }
334         case VLC_FOURCC( 's', 'o', 'w', 't' ):
335         {
336             WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
337             if( p_wf )
338             {
339                 switch( ( p_wf->wBitsPerSample + 7 ) / 8 )
340                 {
341                     case 1:
342                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','8',' ',' ');
343                         break;
344                     case 2:
345                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','1','6','l');
346                         break;
347                     case 3:
348                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','2','4','l');
349                         break;
350                     case 4:
351                         p_pack->output_format.i_fourcc = VLC_FOURCC('s','3','2','l');
352                         break;
353                     default:
354                         msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
355                         return VLC_EGENERIC;
356                 }
357             }
358             else
359             {
360                 msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
361                 return VLC_EGENERIC;
362             }
363             p_pack->output_format.i_cat = AUDIO_ES;
364             break;
365         }
366
367         default:
368             msg_Err( p_pack->p_fifo, "unknown es type !!" );
369             return VLC_EGENERIC;
370             //p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc;
371             //p_pack->output_format.i_cat = UNKNOWN_ES;
372             //break;
373     }
374
375     switch( p_pack->output_format.i_cat )
376     {
377         case AUDIO_ES:
378             {
379                 WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
380                 if( p_wf )
381                 {
382                     p_pack->output_format.i_sample_rate = p_wf->nSamplesPerSec;
383                     p_pack->output_format.i_channels    = p_wf->nChannels;
384                     p_pack->output_format.i_block_align = p_wf->nBlockAlign;
385                     p_pack->output_format.i_bitrate     = p_wf->nAvgBytesPerSec * 8;
386                     p_pack->output_format.i_extra_data  = p_wf->cbSize;
387                     if( p_wf->cbSize  > 0 )
388                     {
389                         p_pack->output_format.p_extra_data =
390                             malloc( p_pack->output_format.i_extra_data );
391                         memcpy( p_pack->output_format.p_extra_data,
392                                 &p_wf[1],
393                                 p_pack->output_format.i_extra_data );
394                     }
395                     else
396                     {
397                         p_pack->output_format.p_extra_data = NULL;
398                     }
399                 }
400                 else
401                 {
402                     p_pack->output_format.i_sample_rate = 0;
403                     p_pack->output_format.i_channels    = 0;
404                     p_pack->output_format.i_block_align = 0;
405                     p_pack->output_format.i_bitrate     = 0;
406                     p_pack->output_format.i_extra_data  = 0;
407                     p_pack->output_format.p_extra_data  = NULL;
408                 }
409             }
410             break;
411
412         case VIDEO_ES:
413             {
414                 BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)p_pack->p_fifo->p_bitmapinfoheader;
415
416                 p_pack->output_format.i_bitrate = 0;
417                 if( p_bih )
418                 {
419                     p_pack->output_format.i_width  = p_bih->biWidth;
420                     p_pack->output_format.i_height = p_bih->biHeight;
421                     p_pack->output_format.i_extra_data  = p_bih->biSize - sizeof( BITMAPINFOHEADER );
422                     if( p_pack->output_format.i_extra_data > 0 )
423                     {
424                         p_pack->output_format.p_extra_data =
425                             malloc( p_pack->output_format.i_extra_data );
426                         memcpy( p_pack->output_format.p_extra_data,
427                                 &p_bih[1],
428                                 p_pack->output_format.i_extra_data );
429                     }
430                 }
431                 else
432                 {
433                     p_pack->output_format.i_width  = 0;
434                     p_pack->output_format.i_height = 0;
435                     p_pack->output_format.i_extra_data  = 0;
436                     p_pack->output_format.p_extra_data  = NULL;
437                 }
438             }
439             break;
440
441         default:
442             return VLC_EGENERIC;
443     }
444
445     p_pack->p_sout_input =
446         sout_InputNew( p_pack->p_fifo,
447                        &p_pack->output_format );
448
449     if( !p_pack->p_sout_input )
450     {
451         msg_Err( p_pack->p_fifo, "cannot add a new stream" );
452         return VLC_EGENERIC;
453     }
454 //    p_pack->i_last_pts = 0;
455     return( VLC_SUCCESS );
456 }
457
458 /*****************************************************************************
459  * PacketizeThread: packetize an unit (here copy a complete pes)
460  *****************************************************************************/
461 static void PacketizeThread( packetizer_thread_t *p_pack )
462 {
463     sout_buffer_t   *p_sout_buffer;
464     pes_packet_t    *p_pes;
465     ssize_t         i_size;
466     mtime_t         i_pts;
467
468     /* **** get samples count **** */
469     input_ExtractPES( p_pack->p_fifo, &p_pes );
470     if( !p_pes )
471     {
472         p_pack->p_fifo->b_error = 1;
473         return;
474     }
475     i_pts = p_pes->i_pts;
476
477     if( i_pts <= 0 ) //&& p_pack->i_last_pts <= 0 )
478     {
479         msg_Dbg( p_pack->p_fifo, "need pts != 0" );
480         input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
481         return;
482     }
483
484     i_size = p_pes->i_pes_size;
485
486 //    msg_Dbg( p_pack->p_fifo, "pes size:%d", i_size );
487     if( i_size > 0 )
488     {
489         pes_packet_t    *p_pes_next;
490         data_packet_t   *p_data;
491         ssize_t          i_buffer;
492
493         p_sout_buffer =
494             sout_BufferNew( p_pack->p_sout_input->p_sout, i_size );
495         if( !p_sout_buffer )
496         {
497             p_pack->p_fifo->b_error = 1;
498             input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
499             return;
500         }
501         /* TODO: memcpy of the pes packet */
502         for( i_buffer = 0, p_data = p_pes->p_first;
503              p_data != NULL && i_buffer < i_size;
504              p_data = p_data->p_next)
505         {
506             ssize_t i_copy;
507
508             i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
509                             i_size - i_buffer );
510             if( i_copy > 0 )
511             {
512                 p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer + i_buffer,
513                                                   p_data->p_payload_start,
514                                                   i_copy );
515             }
516             i_buffer += i_copy;
517         }
518         p_sout_buffer->i_length = 0;
519         p_sout_buffer->i_dts = i_pts; //p_pes->i_pts - p_pack->i_pts_start;
520         p_sout_buffer->i_pts = i_pts; //p_pes->i_pts - p_pack->i_pts_start;
521         p_sout_buffer->i_bitrate = 0;
522
523         input_ShowPES( p_pack->p_fifo, &p_pes_next );
524         if( p_pes_next )
525         {
526             p_sout_buffer->i_length = p_pes_next->i_pts - i_pts;
527         }
528         sout_InputSendBuffer( p_pack->p_sout_input,
529                                p_sout_buffer );
530     }
531
532     input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
533 }
534
535
536 /*****************************************************************************
537  * EndThread : packetizer thread destruction
538  *****************************************************************************/
539 static void EndThread ( packetizer_thread_t *p_pack)
540 {
541     if( p_pack->p_sout_input )
542     {
543         sout_InputDelete( p_pack->p_sout_input );
544     }
545 }
546
547 static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
548 {
549     pes_packet_t *p_pes;
550
551     vlc_mutex_lock( &p_fifo->data_lock );
552
553     if( p_fifo->p_first == NULL )
554     {
555         if( p_fifo->b_die )
556         {
557             vlc_mutex_unlock( &p_fifo->data_lock );
558             if( pp_pes ) *pp_pes = NULL;
559             return;
560         }
561
562         /* Signal the input thread we're waiting. This is only
563          * needed in case of slave clock (ES plug-in) but it won't
564          * harm. */
565         vlc_cond_signal( &p_fifo->data_wait );
566
567         /* Wait for the input to tell us when we received a packet. */
568         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
569     }
570     p_pes = p_fifo->p_first;
571     vlc_mutex_unlock( &p_fifo->data_lock );
572
573     if( pp_pes )
574     {
575         *pp_pes = p_pes;
576     }
577 }
578