* ffmpeg.c: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: ffmpeg.c,v 1.7 2002/05/10 02:04:17 fenrir Exp $
+ * $Id: ffmpeg.c,v 1.8 2002/05/12 06:51:08 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
MODULE_CONFIG_STOP
MODULE_INIT_START
- SET_DESCRIPTION( "ffmpeg video decoder module (MSMPEG4,MPEG4)" )
- ADD_CAPABILITY( DECODER, 50 )
+ SET_DESCRIPTION( "ffmpeg video decoder (MSMPEG4v3,MPEG4)" )
+ ADD_CAPABILITY( DECODER, 70 )
ADD_SHORTCUT( "ffmpeg" )
MODULE_INIT_STOP
{
switch( *pi_type )
{
-/* case( MPEG1_VIDEO_ES ): marche pas pr le moment
- case( MPEG2_VIDEO_ES ): */
case( MSMPEG4_VIDEO_ES ):
case( MPEG4_VIDEO_ES ):
return( 0 );
p_pes = p_fifo->p_first;
vlc_mutex_unlock( &p_fifo->data_lock );
-
+
return( p_pes );
}
/* free the first pes and go to next */
vlc_mutex_unlock( &p_fifo->data_lock );
}
-static void __PACKET_REINIT( videodec_thread_t *p_vdec )
+static __inline__ void __GetFrame( videodec_thread_t *p_vdec )
{
- pes_packet_t *p_pes;
+ pes_packet_t *p_pes;
+ data_packet_t *p_data;
+ byte_t *p_buffer;
p_pes = __PES_GET( p_vdec->p_fifo );
- if( p_vdec->p_fifo->b_die )
+ p_vdec->i_pts = p_pes->i_pts;
+
+ while( ( !p_pes->i_nb_data )||( !p_pes->i_pes_size ) )
{
- return;
+ __PES_NEXT( p_vdec->p_fifo );
+ p_pes = __PES_GET( p_vdec->p_fifo );
}
- p_vdec->p_data = p_pes->p_first;
- p_vdec->p_buff = p_vdec->p_data->p_payload_start;
- p_vdec->i_data_size = p_vdec->p_data->p_payload_end -
- p_vdec->p_data->p_payload_start;
-}
-
-static void __PACKET_NEXT( videodec_thread_t *p_vdec )
-{
+ p_vdec->i_framesize = p_pes->i_pes_size;
+ if( p_pes->i_nb_data == 1 )
+ {
+ p_vdec->p_framedata = p_pes->p_first->p_payload_start;
+ return;
+ }
+ /* get a buffer and gather all data packet */
+ p_vdec->p_framedata = p_buffer = malloc( p_pes->i_pes_size );
+ p_data = p_pes->p_first;
do
{
- p_vdec->p_data = p_vdec->p_data->p_next;
- if( !p_vdec->p_data )
- {
- __PES_NEXT( p_vdec->p_fifo );
- if( p_vdec->p_fifo->b_die )
- {
- return;
- }
- __PACKET_REINIT( p_vdec );
- }
- else
- {
- p_vdec->p_buff = p_vdec->p_data->p_payload_start;
- p_vdec->i_data_size = p_vdec->p_data->p_payload_end -
- p_vdec->p_data->p_payload_start;
- }
-
- } while( ( p_vdec->i_data_size <= 0 )
- ||( p_vdec->p_data->b_discard_payload ) );
+ FAST_MEMCPY( p_buffer,
+ p_data->p_payload_start,
+ p_data->p_payload_end - p_data->p_payload_start );
+ p_buffer += p_data->p_payload_end - p_data->p_payload_start;
+ p_data = p_data->p_next;
+ } while( p_data );
}
-static void __PACKET_FILL( videodec_thread_t *p_vdec )
-{
- if( p_vdec->i_data_size <= 0 )
- {
- __PACKET_NEXT( p_vdec );
- }
-}
-/* call only two times so inline for faster */
-static __inline__ void __ConvertAVPictureToPicture( AVPicture *p_avpicture,
- picture_t *p_picture )
+static __inline__ void __NextFrame( videodec_thread_t *p_vdec )
{
- int i_plane, i_line, i_inc;
- u8 *p_dest,*p_src;
-
- for( i_plane = 0; i_plane < __MIN(p_picture->i_planes, 3); i_plane++ )
+ pes_packet_t *p_pes;
+
+ p_pes = __PES_GET( p_vdec->p_fifo );
+ if( p_pes->i_nb_data != 1 )
{
- p_dest = p_picture->p[i_plane].p_pixels;
- p_src = p_avpicture->data[i_plane];
- if( ( !p_dest )||( !p_src ))
- {
- return;
- }
- i_inc = __MIN( p_picture->p[i_plane].i_pitch,
- p_avpicture->linesize[i_plane] );
- for( i_line = 0; i_line < p_picture->p[i_plane].i_lines; i_line++ )
- {
- FAST_MEMCPY( p_dest,
- p_src,
- i_inc );
- p_dest += p_picture->p[i_plane].i_pitch;
- p_src += p_avpicture->linesize[i_plane];
- }
+ free( p_vdec->p_framedata ); /* FIXME keep this buffer */
}
+ __PES_NEXT( p_vdec->p_fifo );
}
-static __inline__ u32 __FfmpegChromaToFourCC( int i_ffmpegchroma )
-{
- switch( i_ffmpegchroma )
- {
- case( PIX_FMT_YUV420P ):
- case( PIX_FMT_YUV422 ):
- return FOURCC_I420;
- case( PIX_FMT_RGB24 ):
- return FOURCC_RV24;
- case( PIX_FMT_YUV422P ):
- return FOURCC_Y422;
- case( PIX_FMT_YUV444P ):
- case( PIX_FMT_BGR24 ):
- default:
- return( 0 );
- }
-}
+
/*****************************************************************************
* decoder_Run: this function is called just after the thread is created
*****************************************************************************/
}
else
{
- memset( &p_vdec->format, 0, sizeof( bitmapinfoheader_t ) );
+ intf_ErrMsg( "vdec error: cannot get informations" );
+ return( -1 );
}
- /* some codec need to have height and width initialized (msmepg4,mpeg4) */
- /* we cannot create vout because we don't know what chroma */
/*init ffmpeg */
- /* TODO: add a global variable to know if init was already done
- in case we use it also for audio */
if( !b_ffmpeginit )
{
avcodec_init();
switch( p_vdec->p_config->i_type)
{
- case( MPEG1_VIDEO_ES ): /* marche pas pr le moment */
- case( MPEG2_VIDEO_ES ):
- p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MPEG1VIDEO );
- p_vdec->psz_namecodec = "MPEG-1";
- break;
case( MSMPEG4_VIDEO_ES):
p_vdec->p_codec = avcodec_find_decoder( CODEC_ID_MSMPEG4 );
p_vdec->psz_namecodec = "MS MPEG-4/divx";
p_vdec->p_context->width = p_vdec->format.i_width;
p_vdec->p_context->height = p_vdec->format.i_height;
- p_vdec->p_context->pix_fmt = PIX_FMT_YUV420P;
+ p_vdec->p_context->pix_fmt = PIX_FMT_YUV420P; /* I420 */
if (avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0)
{
intf_WarnMsg( 1, "vdec info: ffmpeg codec (%s) started",
p_vdec->psz_namecodec );
}
- /* destroy each p_vout */
+ /* create vout */
+
+ p_vdec->p_vout = vout_CreateThread(
+ NULL,
+ p_vdec->format.i_width,
+ p_vdec->format.i_height,
+ FOURCC_I420,
+ VOUT_ASPECT_FACTOR * p_vdec->format.i_width /
+ p_vdec->format.i_height );
+
+ if( !p_vdec->p_vout )
+ {
+ intf_ErrMsg( "vdec error: can't open vout, aborting" );
+ avcodec_close( p_vdec->p_context );
+ intf_WarnMsg(1, "vdec info: ffmpeg codec (%s) stopped",
+ p_vdec->psz_namecodec);
+ return( -1 );
+ }
+
vlc_mutex_lock( &p_vout_bank->lock );
if( p_vout_bank->i_count != 0 )
{
vlc_mutex_unlock( &p_vout_bank->lock );
vout_DestroyThread( p_vout_bank->pp_vout[ 0 ], NULL );
vlc_mutex_lock( &p_vout_bank->lock );
- p_vout_bank->i_count--;
- p_vout_bank->pp_vout[ 0 ] = NULL;
+ p_vout_bank->i_count--;
}
+ p_vout_bank->i_count++;
+ p_vout_bank->pp_vout[0] = p_vdec->p_vout;
vlc_mutex_unlock( &p_vout_bank->lock );
- __PACKET_REINIT( p_vdec );
+
return( 0 );
}
static void DecodeThread( videodec_thread_t *p_vdec )
{
- int i_len;
+ int i_plane;
+ int i_status;
int b_gotpicture;
- int b_convert;
- mtime_t i_pts;
AVPicture avpicture; /* ffmpeg picture */
- u32 i_chroma;
- picture_t *p_picture; /* videolan picture */
+ picture_t *p_pic; /* videolan picture */
/* we have to get a frame stored in a pes
give it to ffmpeg decoder
and send the image to the output */
- /* when we have the first image we create the video output */
- i_pts = 0 ;
- do
- {
- __PACKET_FILL( p_vdec );
- if( (p_vdec->p_fifo->b_die)||(p_vdec->p_fifo->b_error) )
- {
- return;
- }
- /* save pts */
- if( !i_pts ) {i_pts = __PES_GET( p_vdec->p_fifo )->i_pts;}
-
- i_len = avcodec_decode_video( p_vdec->p_context,
- &avpicture,
- &b_gotpicture,
- p_vdec->p_buff,
- p_vdec->i_data_size);
-
- if( i_len < 0 )
- {
- intf_WarnMsg( 3, "vdec error: cannot decode one frame (%d bytes)",
- p_vdec->i_data_size );
- __PES_NEXT( p_vdec->p_fifo );
- __PACKET_REINIT( p_vdec );
- return;
- }
- p_vdec->i_data_size -= i_len;
- p_vdec->p_buff += i_len;
- } while( !b_gotpicture );
+ __GetFrame( p_vdec );
- if( !(i_chroma =__FfmpegChromaToFourCC( p_vdec->p_context->pix_fmt ) ) )
+ i_status = avcodec_decode_video( p_vdec->p_context,
+ &avpicture,
+ &b_gotpicture,
+ p_vdec->p_framedata,
+ p_vdec->i_framesize);
+ __NextFrame( p_vdec );
+
+ if( i_status < 0 )
{
- b_convert = 1;
- i_chroma = FOURCC_I420;
+ intf_WarnMsg( 2, "vdec error: cannot decode one frame (%d bytes)",
+ p_vdec->i_framesize );
+ return;
}
- else
+ if( !b_gotpicture )
{
- b_convert = 0;
- }
-
- /* Send decoded frame to vout */
- if( !p_vdec->p_vout )
- {
- /* create vout */
-
- /* ffmpeg set it for us with some codec */
- if( (!p_vdec->format.i_width )||(!p_vdec->format.i_height) )
- {
- p_vdec->format.i_width = p_vdec->p_context->width;
- p_vdec->format.i_height = p_vdec->p_context->height;
- }
- /* calculate i_aspect */
- p_vdec->i_aspect = VOUT_ASPECT_FACTOR * p_vdec->format.i_width /
- p_vdec->format.i_height;
- p_vdec->i_chroma = i_chroma;
-
- p_vdec->p_vout = vout_CreateThread(
- NULL,
- p_vdec->format.i_width,
- p_vdec->format.i_height,
- p_vdec->i_chroma,
- p_vdec->i_aspect );
-
+ return;
+ }
- if( !p_vdec->p_vout )
- {
- intf_ErrMsg( "vdec error: can't open vout, aborting" );
- p_vdec->p_fifo->b_error = 1;
- return;
- }
- vlc_mutex_lock( &p_vout_bank->lock );
- p_vout_bank->pp_vout[ 0 ] = p_vdec->p_vout;
- p_vout_bank->i_count++;
- vlc_mutex_unlock( &p_vout_bank->lock );
- }
+ /* Send decoded frame to vout */
- while( (p_picture = vout_CreatePicture( p_vdec->p_vout,
- 0, /* ??? */
- 0, /* ??? */
- 0) ) /* ??? */
- == NULL )
+ while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
{
if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
{
msleep( VOUT_OUTMEM_SLEEP );
}
- if( b_convert )
- {
- /* we convert in a supported format */
- int i_status;
- u8 *p_buff;
- AVPicture avpicture_tmp;
-
- p_buff = malloc( avpicture_get_size( PIX_FMT_YUV420P,
- p_vdec->p_context->width,
- p_vdec->p_context->height) );
- avpicture_fill( &avpicture_tmp,
- p_buff,
- PIX_FMT_YUV420P,
- p_vdec->p_context->width,
- p_vdec->p_context->height );
-
- i_status = img_convert( &avpicture_tmp,
- PIX_FMT_YUV420P,
- &avpicture,
- p_vdec->p_context->pix_fmt,
- p_vdec->p_context->width,
- p_vdec->p_context->height );
- if( i_status < 0 )
- {
- intf_ErrMsg( "vdec error: cannot convert picture in known chroma" );
- return;
- }
- __ConvertAVPictureToPicture( &avpicture_tmp, p_picture );
- free( p_buff ); /* FIXME try to alloc only one time */
- }
- else
+ for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
{
- __ConvertAVPictureToPicture( &avpicture, p_picture );
+ int i_size;
+ int i_line;
+ byte_t *p_dest = p_pic->p[i_plane].p_pixels;
+ byte_t *p_src = avpicture.data[i_plane];
+ if( ( !p_dest )||( !p_src ))
+ {
+ break;
+ }
+ i_size = __MIN( p_pic->p[i_plane].i_pitch,
+ avpicture.linesize[i_plane] );
+ for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
+ {
+ FAST_MEMCPY( p_dest, p_src, i_size );
+ p_dest += p_pic->p[i_plane].i_pitch;
+ p_src += avpicture.linesize[i_plane];
+ }
}
- vout_DatePicture( p_vdec->p_vout, p_picture, i_pts );
- vout_DisplayPicture( p_vdec->p_vout, p_picture );
+ vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->i_pts);
+ vout_DisplayPicture( p_vdec->p_vout, p_pic );
return;
}