e30264023252c468afec46dfc2dccaa27218275f
[vlc.git] / modules / packetizer / copy.c
1 /*****************************************************************************
2  * copy.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: copy.c,v 1.6 2003/03/31 03:46:11 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_packet_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
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_last_pts = 0;
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     ssize_t         i_size;
319     mtime_t         i_pts;
320
321     /* **** get samples count **** */
322     input_ExtractPES( p_pack->p_fifo, &p_pes );
323     if( !p_pes )
324     {
325         p_pack->p_fifo->b_error = 1;
326         return;
327     }
328     i_pts = p_pes->i_pts;
329
330     if( i_pts <= 0 ) //&& p_pack->i_last_pts <= 0 )
331     {
332         msg_Err( p_pack->p_fifo, "need pts != 0" );
333         input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
334         return;
335     }
336
337     i_size = p_pes->i_pes_size;
338
339 //    msg_Dbg( p_pack->p_fifo, "pes size:%d", i_size );
340     if( i_size > 0 )
341     {
342         pes_packet_t    *p_pes_next;
343         data_packet_t   *p_data;
344         ssize_t          i_buffer;
345
346         p_sout_buffer =
347             sout_BufferNew( p_pack->p_sout_input->p_sout, i_size );
348         if( !p_sout_buffer )
349         {
350             p_pack->p_fifo->b_error = 1;
351             input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
352             return;
353         }
354         /* TODO: memcpy of the pes packet */
355         for( i_buffer = 0, p_data = p_pes->p_first;
356              p_data != NULL && i_buffer < i_size;
357              p_data = p_data->p_next)
358         {
359             ssize_t i_copy;
360
361             i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
362                             i_size - i_buffer );
363             if( i_copy > 0 )
364             {
365                 p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer + i_buffer,
366                                                   p_data->p_payload_start,
367                                                   i_copy );
368             }
369             i_buffer += i_copy;
370         }
371         p_sout_buffer->i_length = 0;
372         p_sout_buffer->i_dts = i_pts; //p_pes->i_pts - p_pack->i_pts_start;
373         p_sout_buffer->i_pts = i_pts; //p_pes->i_pts - p_pack->i_pts_start;
374         p_sout_buffer->i_bitrate = 0;
375
376         input_ShowPES( p_pack->p_fifo, &p_pes_next );
377         if( p_pes_next )
378         {
379             p_sout_buffer->i_length = p_pes_next->i_pts - i_pts;
380         }
381         sout_InputSendBuffer( p_pack->p_sout_input,
382                                p_sout_buffer );
383     }
384
385     input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
386 }
387
388
389 /*****************************************************************************
390  * EndThread : packetizer thread destruction
391  *****************************************************************************/
392 static void EndThread ( packetizer_thread_t *p_pack)
393 {
394     if( p_pack->p_sout_input )
395     {
396         sout_InputDelete( p_pack->p_sout_input );
397     }
398 }
399
400 static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
401 {
402     pes_packet_t *p_pes;
403
404     vlc_mutex_lock( &p_fifo->data_lock );
405
406     if( p_fifo->p_first == NULL )
407     {
408         if( p_fifo->b_die )
409         {
410             vlc_mutex_unlock( &p_fifo->data_lock );
411             if( pp_pes ) *pp_pes = NULL;
412             return;
413         }
414
415         /* Signal the input thread we're waiting. This is only
416          * needed in case of slave clock (ES plug-in) but it won't
417          * harm. */
418         vlc_cond_signal( &p_fifo->data_wait );
419
420         /* Wait for the input to tell us when we received a packet. */
421         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
422     }
423     p_pes = p_fifo->p_first;
424     vlc_mutex_unlock( &p_fifo->data_lock );
425
426     if( pp_pes )
427     {
428         *pp_pes = p_pes;
429     }
430 }
431