1 /*****************************************************************************
2 * ffmpeg.c: video decoder using ffmpeg library
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: ffmpeg.c,v 1.6 2002/05/07 13:55:36 fenrir Exp $
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
29 #include <videolan/vlc.h>
32 #include <unistd.h> /* getpid() */
38 #ifdef HAVE_SYS_TIMES_H
39 # include <sys/times.h>
43 #include "video_output.h"
45 #include "stream_control.h"
46 #include "input_ext-dec.h"
47 #include "input_ext-intf.h"
48 #include "input_ext-plugins.h"
51 #include "vdec_ext-plugins.h"
52 #include "avcodec.h" /* ffmpeg */
58 static int decoder_Probe ( u8 * );
59 static int decoder_Run ( decoder_config_t * );
60 static int InitThread ( videodec_thread_t * );
61 static void EndThread ( videodec_thread_t * );
62 static void DecodeThread ( videodec_thread_t * );
64 /* FIXME make this variable global */
65 static int b_ffmpeginit = 0;
67 /*****************************************************************************
69 *****************************************************************************/
70 void _M( vdec_getfunctions )( function_list_t * p_function_list )
72 p_function_list->functions.dec.pf_probe = decoder_Probe;
73 p_function_list->functions.dec.pf_run = decoder_Run;
76 /*****************************************************************************
77 * Build configuration tree.
78 *****************************************************************************/
84 SET_DESCRIPTION( "ffmpeg video decoder module (MSMPEG4,MPEG4)" )
85 ADD_CAPABILITY( DECODER, 50 )
86 ADD_SHORTCUT( "ffmpeg" )
90 _M( vdec_getfunctions )( &p_module->p_functions->dec );
93 MODULE_DEACTIVATE_START
94 MODULE_DEACTIVATE_STOP
97 static __inline__ u16 __GetWordLittleEndianFromBuff( byte_t *p_buff )
100 i = (*p_buff) + ( *(p_buff + 1) <<8 );
104 static __inline__ u32 __GetDoubleWordLittleEndianFromBuff( byte_t *p_buff )
107 i = (*p_buff) + ( *(p_buff + 1) <<8 ) +
108 ( *(p_buff + 2) <<16 ) + ( *(p_buff + 3) <<24 );
112 /*****************************************************************************
113 * decoder_Probe: probe the decoder and return score
114 *****************************************************************************
115 * Tries to launch a decoder and return score so that the interface is able
117 *****************************************************************************/
118 static int decoder_Probe( u8 *pi_type )
122 /* case( MPEG1_VIDEO_ES ): marche pas pr le moment
123 case( MPEG2_VIDEO_ES ): */
124 case( MSMPEG4_VIDEO_ES ):
125 case( MPEG4_VIDEO_ES ):
132 /*****************************************************************************
134 *****************************************************************************/
136 static void __ParseBitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
138 h->i_size = __GetDoubleWordLittleEndianFromBuff( p_data );
139 h->i_width = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
140 h->i_height = __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
141 h->i_planes = __GetWordLittleEndianFromBuff( p_data + 12 );
142 h->i_bitcount = __GetWordLittleEndianFromBuff( p_data + 14 );
143 h->i_compression = __GetDoubleWordLittleEndianFromBuff( p_data + 16 );
144 h->i_sizeimage = __GetDoubleWordLittleEndianFromBuff( p_data + 20 );
145 h->i_xpelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 24 );
146 h->i_ypelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 28 );
147 h->i_clrused = __GetDoubleWordLittleEndianFromBuff( p_data + 32 );
148 h->i_clrimportant = __GetDoubleWordLittleEndianFromBuff( p_data + 36 );
150 /* get the first pes from fifo */
151 static pes_packet_t *__PES_GET( decoder_fifo_t *p_fifo )
155 vlc_mutex_lock( &p_fifo->data_lock );
157 /* if fifo is emty wait */
158 while( !p_fifo->p_first )
162 vlc_mutex_unlock( &p_fifo->data_lock );
165 vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
167 p_pes = p_fifo->p_first;
169 vlc_mutex_unlock( &p_fifo->data_lock );
173 /* free the first pes and go to next */
174 static void __PES_NEXT( decoder_fifo_t *p_fifo )
176 pes_packet_t *p_next;
178 vlc_mutex_lock( &p_fifo->data_lock );
180 p_next = p_fifo->p_first->p_next;
181 p_fifo->p_first->p_next = NULL;
182 input_DeletePES( p_fifo->p_packets_mgt, p_fifo->p_first );
183 p_fifo->p_first = p_next;
186 if( !p_fifo->p_first )
188 /* No PES in the fifo */
189 /* pp_last no longer valid */
190 p_fifo->pp_last = &p_fifo->p_first;
191 while( !p_fifo->p_first )
193 vlc_cond_signal( &p_fifo->data_wait );
194 vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
197 vlc_mutex_unlock( &p_fifo->data_lock );
200 static void __PACKET_REINIT( videodec_thread_t *p_vdec )
204 p_pes = __PES_GET( p_vdec->p_fifo );
205 if( p_vdec->p_fifo->b_die )
209 p_vdec->p_data = p_pes->p_first;
210 p_vdec->p_buff = p_vdec->p_data->p_payload_start;
211 p_vdec->i_data_size = p_vdec->p_data->p_payload_end -
212 p_vdec->p_data->p_payload_start;
215 static void __PACKET_NEXT( videodec_thread_t *p_vdec )
219 p_vdec->p_data = p_vdec->p_data->p_next;
220 if( !p_vdec->p_data )
222 __PES_NEXT( p_vdec->p_fifo );
223 if( p_vdec->p_fifo->b_die )
227 __PACKET_REINIT( p_vdec );
231 p_vdec->p_buff = p_vdec->p_data->p_payload_start;
232 p_vdec->i_data_size = p_vdec->p_data->p_payload_end -
233 p_vdec->p_data->p_payload_start;
236 } while( ( p_vdec->i_data_size <= 0 )
237 ||( p_vdec->p_data->b_discard_payload ) );
240 static void __PACKET_FILL( videodec_thread_t *p_vdec )
242 if( p_vdec->i_data_size <= 0 )
244 __PACKET_NEXT( p_vdec );
247 /* call only two times so inline for faster */
248 static __inline__ void __ConvertAVPictureToPicture( AVPicture *p_avpicture,
249 picture_t *p_picture )
251 int i_plane, i_line, i_inc;
254 for( i_plane = 0; i_plane < __MIN(p_picture->i_planes, 3); i_plane++ )
256 p_dest = p_picture->p[i_plane].p_pixels;
257 p_src = p_avpicture->data[i_plane];
258 if( ( !p_dest )||( !p_src ))
262 i_inc = __MIN( p_picture->p[i_plane].i_pitch,
263 p_avpicture->linesize[i_plane] );
264 for( i_line = 0; i_line < p_picture->p[i_plane].i_lines; i_line++ )
269 p_dest += p_picture->p[i_plane].i_pitch;
270 p_src += p_avpicture->linesize[i_plane];
275 static __inline__ u32 __FfmpegChromaToFourCC( int i_ffmpegchroma )
277 switch( i_ffmpegchroma )
279 case( PIX_FMT_YUV420P ):
280 case( PIX_FMT_YUV422 ):
282 case( PIX_FMT_RGB24 ):
284 case( PIX_FMT_YUV422P ):
286 case( PIX_FMT_YUV444P ):
287 case( PIX_FMT_BGR24 ):
293 /*****************************************************************************
294 * decoder_Run: this function is called just after the thread is created
295 *****************************************************************************/
296 static int decoder_Run ( decoder_config_t * p_config )
298 videodec_thread_t *p_vdec;
301 if ( (p_vdec = (videodec_thread_t*)malloc( sizeof(videodec_thread_t)))
304 intf_ErrMsg( "vdec error: not enough memory "
305 "for vdec_CreateThread() to create the new thread");
306 DecoderError( p_config->p_decoder_fifo );
309 memset( p_vdec, 0, sizeof( videodec_thread_t ) );
311 p_vdec->p_fifo = p_config->p_decoder_fifo;
312 p_vdec->p_config = p_config;
314 if( InitThread( p_vdec ) != 0 )
316 DecoderError( p_config->p_decoder_fifo );
320 while( (!p_vdec->p_fifo->b_die) && (!p_vdec->p_fifo->b_error) )
322 /* decode a picture */
323 DecodeThread( p_vdec );
326 if( ( b_error = p_vdec->p_fifo->b_error ) )
328 DecoderError( p_vdec->p_fifo );
341 /*****************************************************************************
342 * InitThread: initialize vdec output thread
343 *****************************************************************************
344 * This function is called from decoder_Run and performs the second step
345 * of the initialization. It returns 0 on success. Note that the thread's
346 * flag are not modified inside this function.
347 *****************************************************************************/
348 static int InitThread( videodec_thread_t *p_vdec )
351 if( p_vdec->p_config->p_demux_data != NULL )
353 __ParseBitMapInfoHeader( &p_vdec->format,
354 (byte_t*)p_vdec->p_config->p_demux_data );
358 memset( &p_vdec->format, 0, sizeof( bitmapinfoheader_t ) );
360 /* some codec need to have height and width initialized (msmepg4,mpeg4) */
361 /* we cannot create vout because we don't know what chroma */
364 /* TODO: add a global variable to know if init was already done
365 in case we use it also for audio */
369 avcodec_register_all();
371 intf_WarnMsg( 1, "vdec init: library ffmpeg initialised" );
375 intf_WarnMsg( 1, "vdec init: library ffmpeg already initialised" );
378 switch( p_vdec->p_config->i_type)
380 case( MPEG1_VIDEO_ES ): /* marche pas pr le moment */
381 case( MPEG2_VIDEO_ES ):
382 p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MPEG1VIDEO );
383 p_vdec->psz_namecodec = "MPEG-1";
385 case( MSMPEG4_VIDEO_ES):
386 p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MSMPEG4 );
387 p_vdec->psz_namecodec = "MS MPEG-4/divx";
389 case( MPEG4_VIDEO_ES):
390 p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MPEG4 );
391 p_vdec->psz_namecodec = "MPEG-4/opendivx";
394 p_vdec->p_codec = NULL;
395 p_vdec->psz_namecodec = "Unknown";
398 if( !p_vdec->p_codec )
400 intf_ErrMsg( "vdec error: codec not found (%s)",
401 p_vdec->psz_namecodec );
405 p_vdec->p_context = &p_vdec->context;
406 memset( p_vdec->p_context, 0, sizeof( AVCodecContext ) );
408 p_vdec->p_context->width = p_vdec->format.i_width;
409 p_vdec->p_context->height = p_vdec->format.i_height;
410 p_vdec->p_context->pix_fmt = PIX_FMT_YUV420P;
412 if (avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0)
414 intf_ErrMsg( "vdec error: cannot open codec (%s)",
415 p_vdec->psz_namecodec );
420 intf_WarnMsg( 1, "vdec info: ffmpeg codec (%s) started",
421 p_vdec->psz_namecodec );
423 /* destroy each p_vout */
424 vlc_mutex_lock( &p_vout_bank->lock );
425 if( p_vout_bank->i_count != 0 )
427 vlc_mutex_unlock( &p_vout_bank->lock );
428 vout_DestroyThread( p_vout_bank->pp_vout[ 0 ], NULL );
429 vlc_mutex_lock( &p_vout_bank->lock );
430 p_vout_bank->i_count--;
431 p_vout_bank->pp_vout[ 0 ] = NULL;
433 vlc_mutex_unlock( &p_vout_bank->lock );
434 __PACKET_REINIT( p_vdec );
438 /*****************************************************************************
439 * EndThread: thread destruction
440 *****************************************************************************
441 * This function is called when the thread ends after a sucessful
443 *****************************************************************************/
444 static void EndThread( videodec_thread_t *p_vdec )
448 intf_ErrMsg( "vdec error: cannot free structures" );
452 if( p_vdec->p_context != NULL)
454 avcodec_close( p_vdec->p_context );
455 intf_WarnMsg(1, "vdec info: ffmpeg codec (%s) stopped",
456 p_vdec->psz_namecodec);
459 vlc_mutex_lock( &p_vout_bank->lock );
460 if( p_vout_bank->i_count != 0 )
462 vlc_mutex_unlock( &p_vout_bank->lock );
463 vout_DestroyThread( p_vout_bank->pp_vout[ 0 ], NULL );
464 vlc_mutex_lock( &p_vout_bank->lock );
465 p_vout_bank->i_count--;
466 p_vout_bank->pp_vout[ 0 ] = NULL;
468 vlc_mutex_unlock( &p_vout_bank->lock );
473 static void DecodeThread( videodec_thread_t *p_vdec )
479 AVPicture avpicture; /* ffmpeg picture */
481 picture_t *p_picture; /* videolan picture */
482 /* we have to get a frame stored in a pes
483 give it to ffmpeg decoder
484 and send the image to the output */
485 /* when we have the first image we create the video output */
490 __PACKET_FILL( p_vdec );
491 if( (p_vdec->p_fifo->b_die)||(p_vdec->p_fifo->b_error) )
496 if( !i_pts ) {i_pts = __PES_GET( p_vdec->p_fifo )->i_pts;}
498 i_len = avcodec_decode_video( p_vdec->p_context,
502 p_vdec->i_data_size);
506 intf_WarnMsg( 3, "vdec error: cannot decode one frame (%d bytes)",
507 p_vdec->i_data_size );
508 __PES_NEXT( p_vdec->p_fifo );
509 __PACKET_REINIT( p_vdec );
512 p_vdec->i_data_size -= i_len;
513 p_vdec->p_buff += i_len;
514 } while( !b_gotpicture );
516 if( !(i_chroma =__FfmpegChromaToFourCC( p_vdec->p_context->pix_fmt ) ) )
519 i_chroma = FOURCC_I420;
526 /* Send decoded frame to vout */
527 if( !p_vdec->p_vout )
531 /* ffmpeg set it for us with some codec */
532 if( (!p_vdec->format.i_width )||(!p_vdec->format.i_height) )
534 p_vdec->format.i_width = p_vdec->p_context->width;
535 p_vdec->format.i_height = p_vdec->p_context->height;
537 /* calculate i_aspect */
538 p_vdec->i_aspect = VOUT_ASPECT_FACTOR * p_vdec->format.i_width /
539 p_vdec->format.i_height;
540 p_vdec->i_chroma = i_chroma;
542 p_vdec->p_vout = vout_CreateThread(
544 p_vdec->format.i_width,
545 p_vdec->format.i_height,
550 if( !p_vdec->p_vout )
552 intf_ErrMsg( "vdec error: can't open vout, aborting" );
553 p_vdec->p_fifo->b_error = 1;
556 vlc_mutex_lock( &p_vout_bank->lock );
557 p_vout_bank->pp_vout[ 0 ] = p_vdec->p_vout;
558 p_vout_bank->i_count++;
559 vlc_mutex_unlock( &p_vout_bank->lock );
562 while( (p_picture = vout_CreatePicture( p_vdec->p_vout,
568 if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
572 msleep( VOUT_OUTMEM_SLEEP );
577 /* we convert in a supported format */
580 AVPicture avpicture_tmp;
582 p_buff = malloc( avpicture_get_size( PIX_FMT_YUV420P,
583 p_vdec->p_context->width,
584 p_vdec->p_context->height) );
585 avpicture_fill( &avpicture_tmp,
588 p_vdec->p_context->width,
589 p_vdec->p_context->height );
591 i_status = img_convert( &avpicture_tmp,
594 p_vdec->p_context->pix_fmt,
595 p_vdec->p_context->width,
596 p_vdec->p_context->height );
599 intf_ErrMsg( "vdec error: cannot convert picture in known chroma" );
602 __ConvertAVPictureToPicture( &avpicture_tmp, p_picture );
603 free( p_buff ); /* FIXME try to alloc only one time */
607 __ConvertAVPictureToPicture( &avpicture, p_picture );
610 vout_DatePicture( p_vdec->p_vout, p_picture, i_pts );
611 vout_DisplayPicture( p_vdec->p_vout, p_picture );