1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VideoLAN
5 * $Id: copy.c,v 1.16 2003/09/02 20:19:26 gbazin Exp $
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Eric Petit <titer@videolan.org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
31 #include <vlc/decoder.h>
32 #include <vlc/input.h>
37 /*****************************************************************************
39 *****************************************************************************/
40 static int Open ( vlc_object_t * );
43 set_description( _("Copy packetizer") );
44 set_capability( "packetizer", 1 );
45 set_callbacks( Open, NULL );
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Run ( decoder_fifo_t * );
53 typedef struct packetizer_thread_s
55 /* Input properties */
56 decoder_fifo_t *p_fifo;
58 /* Output properties */
59 sout_packetizer_input_t *p_sout_input;
60 sout_format_t output_format;
62 void (*pf_packetize)( struct packetizer_thread_s * );
64 } packetizer_thread_t;
66 static int Init ( packetizer_thread_t * );
67 static void PacketizeStd( packetizer_thread_t * );
68 static void PacketizeSPU( packetizer_thread_t * );
69 static void End ( packetizer_thread_t * );
72 static void AppendPEStoSoutBuffer( sout_instance_t *,sout_buffer_t **,pes_packet_t *);
73 static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes );
75 /*****************************************************************************
76 * Open: probe the packetizer and return score
77 *****************************************************************************
78 * Tries to launch a decoder and return score so that the interface is able
80 *****************************************************************************/
81 static int Open( vlc_object_t *p_this )
83 decoder_t *p_dec = (decoder_t*)p_this;
90 /*****************************************************************************
91 * Run: this function is called just after the thread is created
92 *****************************************************************************/
93 static int Run( decoder_fifo_t *p_fifo )
95 packetizer_thread_t *p_pack;
98 msg_Dbg( p_fifo, "Running copy packetizer (fcc=%4.4s)",
99 (char*)&p_fifo->i_fourcc );
101 p_pack = malloc( sizeof( packetizer_thread_t ) );
102 memset( p_pack, 0, sizeof( packetizer_thread_t ) );
104 p_pack->p_fifo = p_fifo;
108 DecoderError( p_fifo );
112 while( !p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error )
114 p_pack->pf_packetize( p_pack );
117 if( p_pack->p_fifo->b_error )
119 DecoderError( p_pack->p_fifo );
122 i_ret = p_pack->p_fifo->b_error ? VLC_EGENERIC : VLC_SUCCESS;
128 /*****************************************************************************
129 * Init: initialize data before entering main loop
130 *****************************************************************************/
131 static int Init( packetizer_thread_t *p_pack )
134 p_pack->pf_packetize = PacketizeStd;
136 switch( p_pack->p_fifo->i_fourcc )
139 case VLC_FOURCC( 'm', '4', 's', '2'):
140 case VLC_FOURCC( 'M', '4', 'S', '2'):
141 case VLC_FOURCC( 'm', 'p', '4', 's'):
142 case VLC_FOURCC( 'M', 'P', '4', 'S'):
143 case VLC_FOURCC( 'm', 'p', '4', 'v'):
144 case VLC_FOURCC( 'D', 'I', 'V', 'X'):
145 case VLC_FOURCC( 'd', 'i', 'v', 'x'):
146 case VLC_FOURCC( 'X', 'V', 'I', 'D'):
147 case VLC_FOURCC( 'X', 'v', 'i', 'D'):
148 case VLC_FOURCC( 'x', 'v', 'i', 'd'):
149 case VLC_FOURCC( 'D', 'X', '5', '0'):
150 case VLC_FOURCC( 0x04, 0, 0, 0):
151 case VLC_FOURCC( '3', 'I', 'V', '2'):
152 p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v');
153 p_pack->output_format.i_cat = VIDEO_ES;
155 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
156 case VLC_FOURCC( 'm', 'p', 'g', '1' ):
157 case VLC_FOURCC( 'm', 'p', 'g', '2' ):
158 case VLC_FOURCC( 'm', 'p', '1', 'v' ):
159 case VLC_FOURCC( 'm', 'p', '2', 'v' ):
160 p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'v' );
161 p_pack->output_format.i_cat = VIDEO_ES;
164 case VLC_FOURCC( 'd', 'i', 'v', '1' ):
165 case VLC_FOURCC( 'D', 'I', 'V', '1' ):
166 case VLC_FOURCC( 'M', 'P', 'G', '4' ):
167 case VLC_FOURCC( 'm', 'p', 'g', '4' ):
168 p_pack->output_format.i_fourcc = VLC_FOURCC( 'D', 'I', 'V', '1' );
169 p_pack->output_format.i_cat = VIDEO_ES;
171 case VLC_FOURCC( 'd', 'i', 'v', '2' ):
172 case VLC_FOURCC( 'D', 'I', 'V', '2' ):
173 case VLC_FOURCC( 'M', 'P', '4', '2' ):
174 case VLC_FOURCC( 'm', 'p', '4', '2' ):
175 p_pack->output_format.i_fourcc = VLC_FOURCC( 'D', 'I', 'V', '2' );
176 p_pack->output_format.i_cat = VIDEO_ES;
178 case VLC_FOURCC( 'd', 'i', 'v', '3' ):
179 case VLC_FOURCC( 'D', 'I', 'V', '3' ):
180 case VLC_FOURCC( 'd', 'i', 'v', '4' ):
181 case VLC_FOURCC( 'D', 'I', 'V', '4' ):
182 case VLC_FOURCC( 'd', 'i', 'v', '5' ):
183 case VLC_FOURCC( 'D', 'I', 'V', '5' ):
184 case VLC_FOURCC( 'd', 'i', 'v', '6' ):
185 case VLC_FOURCC( 'D', 'I', 'V', '6' ):
186 case VLC_FOURCC( 'M', 'P', '4', '3' ):
187 case VLC_FOURCC( 'm', 'p', '4', '3' ):
188 case VLC_FOURCC( 'm', 'p', 'g', '3' ):
189 case VLC_FOURCC( 'M', 'P', 'G', '3' ):
190 case VLC_FOURCC( 'A', 'P', '4', '1' ):
191 p_pack->output_format.i_fourcc = VLC_FOURCC( 'D', 'I', 'V', '3' );
192 p_pack->output_format.i_cat = VIDEO_ES;
194 case VLC_FOURCC( 'H', '2', '6', '3' ):
195 case VLC_FOURCC( 'h', '2', '6', '3' ):
196 case VLC_FOURCC( 'U', '2', '6', '3' ):
197 case VLC_FOURCC( 'u', '2', '6', '3' ):
198 p_pack->output_format.i_fourcc = VLC_FOURCC( 'H', '2', '6', '3' );
199 p_pack->output_format.i_cat = VIDEO_ES;
201 case VLC_FOURCC( 'I', '2', '6', '3' ):
202 case VLC_FOURCC( 'i', '2', '6', '3' ):
203 p_pack->output_format.i_fourcc = VLC_FOURCC( 'I', '2', '6', '3' );
204 p_pack->output_format.i_cat = VIDEO_ES;
206 case VLC_FOURCC( 'W', 'M', 'V', '1' ):
207 p_pack->output_format.i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '1' );
208 p_pack->output_format.i_cat = VIDEO_ES;
210 case VLC_FOURCC( 'W', 'M', 'V', '2' ):
211 p_pack->output_format.i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '2' );
212 p_pack->output_format.i_cat = VIDEO_ES;
214 case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
215 case VLC_FOURCC( 'm', 'j', 'p', 'g' ):
216 case VLC_FOURCC( 'm', 'j', 'p', 'a' ):
217 case VLC_FOURCC( 'j', 'p', 'e', 'g' ):
218 case VLC_FOURCC( 'J', 'P', 'E', 'G' ):
219 case VLC_FOURCC( 'J', 'F', 'I', 'F' ):
220 p_pack->output_format.i_fourcc = VLC_FOURCC( 'M', 'J', 'P', 'G' );
221 p_pack->output_format.i_cat = VIDEO_ES;
223 case VLC_FOURCC( 'm', 'j', 'p', 'b' ):
224 p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'j', 'p', 'b' );
225 p_pack->output_format.i_cat = VIDEO_ES;
227 case VLC_FOURCC( 'd', 'v', 's', 'l' ):
228 case VLC_FOURCC( 'd', 'v', 's', 'd' ):
229 case VLC_FOURCC( 'D', 'V', 'S', 'D' ):
230 case VLC_FOURCC( 'd', 'v', 'h', 'd' ):
231 p_pack->output_format.i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'l' );
232 p_pack->output_format.i_cat = VIDEO_ES;
234 case VLC_FOURCC( 'S', 'V', 'Q', '1' ):
235 p_pack->output_format.i_fourcc = VLC_FOURCC( 'S', 'V', 'Q', '1' );
236 p_pack->output_format.i_cat = VIDEO_ES;
238 case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
239 p_pack->output_format.i_fourcc = VLC_FOURCC( 'S', 'V', 'Q', '3' );
240 p_pack->output_format.i_cat = VIDEO_ES;
243 case VLC_FOURCC( 'I', '4', '2', '0' ):
244 p_pack->output_format.i_fourcc = VLC_FOURCC( 'I', '4', '2', '0' );
245 p_pack->output_format.i_cat = VIDEO_ES;
247 case VLC_FOURCC( 'I', '4', '2', '2' ):
248 p_pack->output_format.i_fourcc = VLC_FOURCC( 'I', '4', '2', '2' );
249 p_pack->output_format.i_cat = VIDEO_ES;
251 case VLC_FOURCC( 'R', 'V', '1', '5' ):
252 p_pack->output_format.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
253 p_pack->output_format.i_cat = VIDEO_ES;
255 case VLC_FOURCC( 'R', 'V', '1', '6' ):
256 p_pack->output_format.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
257 p_pack->output_format.i_cat = VIDEO_ES;
259 case VLC_FOURCC( 'R', 'V', '2', '4' ):
260 p_pack->output_format.i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
261 p_pack->output_format.i_cat = VIDEO_ES;
263 case VLC_FOURCC( 'R', 'V', '3', '2' ):
264 p_pack->output_format.i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
265 p_pack->output_format.i_cat = VIDEO_ES;
267 case VLC_FOURCC( 'G', 'R', 'E', 'Y' ):
268 p_pack->output_format.i_fourcc = VLC_FOURCC( 'G', 'R', 'E', 'Y' );
269 p_pack->output_format.i_cat = VIDEO_ES;
273 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
274 p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'a' );
275 p_pack->output_format.i_cat = AUDIO_ES;
277 case VLC_FOURCC( 'w', 'm', 'a', '1' ):
278 p_pack->output_format.i_fourcc = VLC_FOURCC( 'w', 'm', 'a', '1' );
279 p_pack->output_format.i_cat = AUDIO_ES;
281 case VLC_FOURCC( 'w', 'm', 'a', '2' ):
282 p_pack->output_format.i_fourcc = VLC_FOURCC( 'w', 'm', 'a', '2' );
283 p_pack->output_format.i_cat = AUDIO_ES;
285 case VLC_FOURCC( 'a', 'r', 'a', 'w' ):
287 WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
290 switch( ( p_wf->wBitsPerSample + 7 ) / 8 )
293 p_pack->output_format.i_fourcc = VLC_FOURCC('u','8',' ',' ');
296 p_pack->output_format.i_fourcc = VLC_FOURCC('s','1','6','l');
299 p_pack->output_format.i_fourcc = VLC_FOURCC('s','2','4','l');
302 p_pack->output_format.i_fourcc = VLC_FOURCC('s','3','2','l');
305 msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
311 msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
314 p_pack->output_format.i_cat = AUDIO_ES;
317 case VLC_FOURCC( 't', 'w', 'o', 's' ):
319 WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
322 switch( ( p_wf->wBitsPerSample + 7 ) / 8 )
325 p_pack->output_format.i_fourcc = VLC_FOURCC('s','8',' ',' ');
328 p_pack->output_format.i_fourcc = VLC_FOURCC('s','1','6','b');
331 p_pack->output_format.i_fourcc = VLC_FOURCC('s','2','4','b');
334 p_pack->output_format.i_fourcc = VLC_FOURCC('s','3','2','b');
337 msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
343 msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
346 p_pack->output_format.i_cat = AUDIO_ES;
349 case VLC_FOURCC( 's', 'o', 'w', 't' ):
351 WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
354 switch( ( p_wf->wBitsPerSample + 7 ) / 8 )
357 p_pack->output_format.i_fourcc = VLC_FOURCC('s','8',' ',' ');
360 p_pack->output_format.i_fourcc = VLC_FOURCC('s','1','6','l');
363 p_pack->output_format.i_fourcc = VLC_FOURCC('s','2','4','l');
366 p_pack->output_format.i_fourcc = VLC_FOURCC('s','3','2','l');
369 msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
375 msg_Err( p_pack->p_fifo, "unknown raw audio sample size !!" );
378 p_pack->output_format.i_cat = AUDIO_ES;
383 case VLC_FOURCC( 's', 'p', 'u', ' ' ): /* DVD */
384 case VLC_FOURCC( 's', 'p', 'u', 'b' ):
385 p_pack->output_format.i_fourcc = VLC_FOURCC( 's', 'p', 'u', ' ' );
386 p_pack->output_format.i_cat = SPU_ES;
387 p_pack->pf_packetize = PacketizeSPU;
390 msg_Err( p_pack->p_fifo, "unknown es type !!" );
394 switch( p_pack->output_format.i_cat )
398 WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
401 p_pack->output_format.i_sample_rate = p_wf->nSamplesPerSec;
402 p_pack->output_format.i_channels = p_wf->nChannels;
403 p_pack->output_format.i_block_align = p_wf->nBlockAlign;
404 p_pack->output_format.i_bitrate = p_wf->nAvgBytesPerSec * 8;
405 p_pack->output_format.i_extra_data = p_wf->cbSize;
406 if( p_wf->cbSize > 0 )
408 p_pack->output_format.p_extra_data =
409 malloc( p_pack->output_format.i_extra_data );
410 memcpy( p_pack->output_format.p_extra_data,
412 p_pack->output_format.i_extra_data );
416 p_pack->output_format.p_extra_data = NULL;
421 p_pack->output_format.i_sample_rate = 0;
422 p_pack->output_format.i_channels = 0;
423 p_pack->output_format.i_block_align = 0;
424 p_pack->output_format.i_bitrate = 0;
425 p_pack->output_format.i_extra_data = 0;
426 p_pack->output_format.p_extra_data = NULL;
433 BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)p_pack->p_fifo->p_bitmapinfoheader;
435 p_pack->output_format.i_bitrate = 0;
438 p_pack->output_format.i_width = p_bih->biWidth;
439 p_pack->output_format.i_height = p_bih->biHeight;
440 p_pack->output_format.i_extra_data = p_bih->biSize - sizeof( BITMAPINFOHEADER );
441 if( p_pack->output_format.i_extra_data > 0 )
443 p_pack->output_format.p_extra_data =
444 malloc( p_pack->output_format.i_extra_data );
445 memcpy( p_pack->output_format.p_extra_data,
447 p_pack->output_format.i_extra_data );
452 p_pack->output_format.i_width = 0;
453 p_pack->output_format.i_height = 0;
454 p_pack->output_format.i_extra_data = 0;
455 p_pack->output_format.p_extra_data = NULL;
461 p_pack->output_format.i_extra_data = 0;
462 p_pack->output_format.p_extra_data = NULL;
469 p_pack->p_sout_input =
470 sout_InputNew( p_pack->p_fifo,
471 &p_pack->output_format );
473 if( !p_pack->p_sout_input )
475 msg_Err( p_pack->p_fifo, "cannot add a new stream" );
479 return( VLC_SUCCESS );
482 /*****************************************************************************
483 * PacketizeStd: packetize an unit (here copy a complete pes)
484 *****************************************************************************/
485 static void PacketizeStd( packetizer_thread_t *p_pack )
487 sout_buffer_t *p_out = NULL;
490 input_ExtractPES( p_pack->p_fifo, &p_pes );
493 p_pack->p_fifo->b_error = 1;
497 msg_Dbg( p_pack->p_fifo, "pes size:%d dts="I64Fd" pts="I64Fd,
498 p_pes->i_pes_size, p_pes->i_dts, p_pes->i_pts );
501 if( p_pes->i_pts <= 0 )
503 msg_Dbg( p_pack->p_fifo, "need pts != 0" );
504 input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
508 if( p_pes->i_pes_size > 0 )
510 pes_packet_t *p_next;
512 AppendPEStoSoutBuffer( p_pack->p_sout_input->p_sout, &p_out, p_pes );
514 input_ShowPES( p_pack->p_fifo, &p_next );
515 if( p_next && p_next->i_pts > 0 )
517 p_out->i_length = p_next->i_pts - p_pes->i_pts;
520 sout_InputSendBuffer( p_pack->p_sout_input,
524 input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
527 /*****************************************************************************
528 * PacketizeSPU: packetize an SPU unit (so gather all PES of one subtitle)
529 *****************************************************************************/
530 static void PacketizeSPU( packetizer_thread_t *p_pack )
532 sout_buffer_t *p_out = NULL;
539 input_ExtractPES( p_pack->p_fifo, &p_pes );
542 p_pack->p_fifo->b_error = 1;
546 msg_Dbg( p_pack->p_fifo, "pes size:%d dts="I64Fd" pts="I64Fd,
547 p_pes->i_pes_size, p_pes->i_dts, p_pes->i_pts );
551 ( p_pes->i_pts <= 0 || p_pes->i_pes_size < 4 ) )
553 msg_Dbg( p_pack->p_fifo, "invalid starting packet (size < 4 or pts <=0)" );
554 input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
558 if( p_pes->i_pes_size > 0 )
560 AppendPEStoSoutBuffer( p_pack->p_sout_input->p_sout, &p_out, p_pes );
562 if( i_spu_size <= 0 )
565 i_spu_size = ( p_out->p_buffer[0] << 8 )| p_out->p_buffer[1];
566 i_rle = ( ( p_out->p_buffer[2] << 8 )| p_out->p_buffer[3] ) - 4;
568 msg_Dbg( p_pack->p_fifo, "i_spu_size=%d i_rle=%d", i_spu_size, i_rle );
569 if( i_spu_size == 0 || i_rle >= i_spu_size )
571 sout_BufferDelete( p_pack->p_sout_input->p_sout, p_out );
572 input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
578 input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
580 if( (int)p_out->i_size >= i_spu_size )
585 msg_Dbg( p_pack->p_fifo,
586 "SPU packets size=%d should be %d",
587 p_out->i_size, i_spu_size );
589 sout_InputSendBuffer( p_pack->p_sout_input, p_out );
593 /*****************************************************************************
594 * End : packetizer thread destruction
595 *****************************************************************************/
596 static void End ( packetizer_thread_t *p_pack)
598 if( p_pack->p_sout_input )
600 sout_InputDelete( p_pack->p_sout_input );
605 /*****************************************************************************
606 * AppendPEStoSoutBuffer: copy/cat one pes into a sout_buffer_t.
607 *****************************************************************************/
608 static void AppendPEStoSoutBuffer( sout_instance_t *p_sout,
609 sout_buffer_t **pp_out,
610 pes_packet_t *p_pes )
612 sout_buffer_t *p_out = *pp_out;
615 data_packet_t *p_data;
620 p_out = *pp_out = sout_BufferNew( p_sout, p_pes->i_pes_size );
621 p_out->i_dts = p_pes->i_pts;
622 p_out->i_pts = p_pes->i_pts;
626 i_out = p_out->i_size;
627 sout_BufferRealloc( p_sout, p_out, i_out + p_pes->i_pes_size );
629 p_out->i_size = i_out + p_pes->i_pes_size;
631 for( p_data = p_pes->p_first; p_data != NULL; p_data = p_data->p_next)
635 i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
636 p_out->i_size - i_out );
639 memcpy( &p_out->p_buffer[i_out],
640 p_data->p_payload_start,
645 p_out->i_size = i_out;
648 /*****************************************************************************
649 * input_ShowPES: Show the next PES in the fifo
650 *****************************************************************************/
651 static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
653 vlc_mutex_lock( &p_fifo->data_lock );
655 if( p_fifo->p_first == NULL )
659 vlc_mutex_unlock( &p_fifo->data_lock );
664 /* Signal the input thread we're waiting. This is only
665 * needed in case of slave clock (ES plug-in) but it won't
667 vlc_cond_signal( &p_fifo->data_wait );
669 /* Wait for the input to tell us when we received a packet. */
670 vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
672 *pp_pes = p_fifo->p_first;
673 vlc_mutex_unlock( &p_fifo->data_lock );