* all: change the way fourcc are stored in bitmapinfoheader.
[vlc.git] / modules / packetizer / copy.c
1 /*****************************************************************************
2  * copy.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: copy.c,v 1.3 2003/01/19 08:27:28 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_input_t            *p_sout_input;
48     sout_packet_format_t    output_format;
49
50     mtime_t i_pts_start;
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
247         default:
248             p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc;
249             p_pack->output_format.i_cat = UNKNOWN_ES;
250             break;
251     }
252
253     switch( p_pack->output_format.i_cat )
254     {
255         case AUDIO_ES:
256             {
257                 WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
258                 if( p_wf )
259                 {
260                     p_pack->output_format.p_format = malloc( sizeof( WAVEFORMATEX ) + p_wf->cbSize );
261                     memcpy( p_pack->output_format.p_format, p_wf, sizeof( WAVEFORMATEX ) + p_wf->cbSize );
262                 }
263                 else
264                 {
265                     p_pack->output_format.p_format = NULL;
266                 }
267             }
268             break;
269
270         case VIDEO_ES:
271             {
272                 BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)p_pack->p_fifo->p_bitmapinfoheader;
273                 if( p_bih )
274                 {
275                     p_pack->output_format.p_format = malloc( p_bih->biSize );
276                     memcpy( p_pack->output_format.p_format, p_bih, p_bih->biSize );
277                     if( p_pack->output_format.i_fourcc == VLC_FOURCC( 'm', 'p', '4', 'v' ) )
278                     {
279                         p_bih->biCompression = VLC_FOURCC( 'd', 'i', 'v', 'x' );
280                     }
281                     else
282                     {
283                         p_bih->biCompression = p_pack->output_format.i_fourcc;
284                     }
285
286                 }
287                 else
288                 {
289                     p_pack->output_format.p_format = NULL;
290                 }
291             }
292             break;
293         default:
294             p_pack->output_format.p_format = NULL;
295             break;
296     }
297
298     p_pack->p_sout_input =
299         sout_InputNew( p_pack->p_fifo,
300                        &p_pack->output_format );
301
302     if( !p_pack->p_sout_input )
303     {
304         msg_Err( p_pack->p_fifo, "cannot add a new stream" );
305         return( -1 );
306     }
307     p_pack->i_pts_start = -1;
308     return( 0 );
309 }
310
311 /*****************************************************************************
312  * PacketizeThread: packetize an unit (here copy a complete pes)
313  *****************************************************************************/
314 static void PacketizeThread( packetizer_thread_t *p_pack )
315 {
316     sout_buffer_t   *p_sout_buffer;
317     pes_packet_t    *p_pes;
318     size_t          i_size;
319
320     /* **** get samples count **** */
321     input_ExtractPES( p_pack->p_fifo, &p_pes );
322     if( !p_pes )
323     {
324         p_pack->p_fifo->b_error = 1;
325         return;
326     }
327     if( p_pack->i_pts_start < 0 && p_pes->i_pts > 0 )
328     {
329         p_pack->i_pts_start = p_pes->i_pts;
330     }
331     i_size = p_pes->i_pes_size;
332 //    msg_Dbg( p_pack->p_fifo, "pes size:%d", i_size );
333     if( i_size > 0 )
334     {
335         pes_packet_t    *p_pes_next;
336         data_packet_t   *p_data;
337         size_t          i_buffer;
338
339         p_sout_buffer = 
340             sout_BufferNew( p_pack->p_sout_input->p_sout, i_size );
341         if( !p_sout_buffer )
342         {
343             p_pack->p_fifo->b_error = 1;
344             return;
345         }
346         /* TODO: memcpy of the pes packet */
347         for( i_buffer = 0, p_data = p_pes->p_first;
348              p_data != NULL && i_buffer < i_size;
349              p_data = p_data->p_next)
350         {
351             size_t          i_copy;
352
353             i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start, 
354                             i_size - i_buffer );
355             if( i_copy > 0 )
356             {
357                 p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer + i_buffer,
358                                                   p_data->p_payload_start,
359                                                   i_copy );
360             }
361             i_buffer += i_copy;
362         }
363         p_sout_buffer->i_length = 0;
364         p_sout_buffer->i_dts = p_pes->i_pts - p_pack->i_pts_start;
365         p_sout_buffer->i_pts = p_pes->i_pts - p_pack->i_pts_start;
366         p_sout_buffer->i_bitrate = 0;
367
368         input_ShowPES( p_pack->p_fifo, &p_pes_next );
369         if( p_pes_next )
370         {
371             p_sout_buffer->i_length = p_pes_next->i_pts - p_pes->i_pts;
372         }
373         sout_InputSendBuffer( p_pack->p_sout_input,
374                                p_sout_buffer );
375     }
376
377     input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
378 }
379
380
381 /*****************************************************************************
382  * EndThread : packetizer thread destruction
383  *****************************************************************************/
384 static void EndThread ( packetizer_thread_t *p_pack)
385 {
386     if( p_pack->p_sout_input )
387     {
388         sout_InputDelete( p_pack->p_sout_input );
389     }
390 }
391
392 static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
393 {
394     pes_packet_t *p_pes;
395
396     vlc_mutex_lock( &p_fifo->data_lock );
397
398     if( p_fifo->p_first == NULL )
399     {
400         if( p_fifo->b_die )
401         {
402             vlc_mutex_unlock( &p_fifo->data_lock );
403             if( pp_pes ) *pp_pes = NULL;
404             return;
405         }
406
407         /* Signal the input thread we're waiting. This is only
408          * needed in case of slave clock (ES plug-in) but it won't
409          * harm. */
410         vlc_cond_signal( &p_fifo->data_wait );
411
412         /* Wait for the input to tell us when we received a packet. */
413         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
414     }
415     p_pes = p_fifo->p_first;
416     vlc_mutex_unlock( &p_fifo->data_lock );
417
418     if( pp_pes )
419     {
420         *pp_pes = p_pes;
421     }
422 }
423