* ffmpeg.c: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: ffmpeg.c,v 1.17 2002/07/20 18:53:33 fenrir Exp $
+ * $Id: ffmpeg.c,v 1.21 2002/07/31 20:56:51 sam Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
/*
* Local prototypes
*/
-static int decoder_Probe ( u8 * );
-static int decoder_Run ( decoder_fifo_t * );
+static int OpenDecoder ( vlc_object_t * );
+static int RunDecoder ( decoder_fifo_t * );
static int InitThread ( videodec_thread_t * );
static void EndThread ( videodec_thread_t * );
static void DecodeThread ( videodec_thread_t * );
static int b_ffmpeginit = 0;
/*****************************************************************************
- * Capabilities
- *****************************************************************************/
-void _M( vdec_getfunctions )( function_list_t * p_function_list )
-{
- p_function_list->functions.dec.pf_probe = decoder_Probe;
- p_function_list->functions.dec.pf_run = decoder_Run;
-}
-
-/*****************************************************************************
- * Build configuration tree.
+ * Module descriptor
*****************************************************************************/
#define ERROR_RESILIENCE_LONGTEXT \
#define HURRY_UP_LONGTEXT \
"Allow the decoder to partially decode or skip frame(s) " \
"when there not enough time.\n It's usefull with low CPU power " \
- "but it could produce broken pictures (not yet implemented)"
+ "but it could produce broken pictures."
-MODULE_CONFIG_START
-ADD_CATEGORY_HINT( N_("Miscellaneous"), NULL )
+vlc_module_begin();
+ add_category_hint( N_("Miscellaneous"), NULL );
#if LIBAVCODEC_BUILD >= 4611
- ADD_INTEGER ( "ffmpeg-error-resilience", 0, NULL,
- "error resilience", ERROR_RESILIENCE_LONGTEXT )
- ADD_INTEGER ( "ffmpeg-workaround-bugs", 0, NULL,
- "workaround bugs", "0-99, seems to be for msmpeg v3\n" )
-#endif
-#if LIBAVCODEC_BUILD > 4603
- ADD_BOOL( "ffmpeg-hurry-up", 0, NULL, "hurry up", HURRY_UP_LONGTEXT )
+ add_integer ( "ffmpeg-error-resilience", 0, NULL,
+ "error resilience", ERROR_RESILIENCE_LONGTEXT );
+ add_integer ( "ffmpeg-workaround-bugs", 0, NULL,
+ "workaround bugs", "0-99, seems to be for msmpeg v3\n" );
#endif
-
-MODULE_CONFIG_STOP
-
-MODULE_INIT_START
- SET_DESCRIPTION( "ffmpeg video decoder(MS-MPEG4,MPEG4,SVQ1,H263,H263.I)" )
- ADD_CAPABILITY( DECODER, 70 )
-MODULE_INIT_STOP
-
-MODULE_ACTIVATE_START
- _M( vdec_getfunctions )( &p_module->p_functions->dec );
-MODULE_ACTIVATE_STOP
-
-MODULE_DEACTIVATE_START
-MODULE_DEACTIVATE_STOP
-
+ add_bool( "ffmpeg-hurry-up", 0, NULL, "hurry up", HURRY_UP_LONGTEXT );
+ set_description( _("ffmpeg video decoder((MS)MPEG4,SVQ1,H263)") );
+ set_capability( "decoder", 70 );
+ set_callbacks( OpenDecoder, NULL );
+vlc_module_end();
/*****************************************************************************
- * decoder_Probe: probe the decoder and return score
+ * OpenDecoder: probe the decoder and return score
*****************************************************************************
* Tries to launch a decoder and return score so that the interface is able
* to chose.
*****************************************************************************/
-static int decoder_Probe( u8 *pi_type )
+static int OpenDecoder( vlc_object_t *p_this )
{
- return( ffmpeg_GetFfmpegCodec( *pi_type, NULL, NULL ) ? 0 : -1 );
+ decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
+
+ if( ffmpeg_GetFfmpegCodec( p_fifo->i_fourcc, NULL, NULL ) )
+ {
+ p_fifo->pf_run = RunDecoder;
+ return VLC_SUCCESS;
+ }
+
+ return VLC_EGENERIC;
}
/*****************************************************************************
- * decoder_Run: this function is called just after the thread is created
+ * RunDecoder: this function is called just after the thread is created
*****************************************************************************/
-static int decoder_Run ( decoder_fifo_t * p_fifo )
+static int RunDecoder( decoder_fifo_t *p_fifo )
{
videodec_thread_t *p_vdec;
int b_error;
-
+
if ( !(p_vdec = (videodec_thread_t*)malloc( sizeof(videodec_thread_t))) )
{
msg_Err( p_fifo, "out of memory" );
( *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) + \
( *((u8*)(p)+2) << 16 ) + ( *((u8*)(p)+3) << 24 ) )
-static void __ParseBitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
+static void ffmpeg_ParseBitMapInfoHeader( bitmapinfoheader_t *p_bh,
+ u8 *p_data )
{
- h->i_size = GetDWLE( p_data );
- h->i_width = GetDWLE( p_data + 4 );
- h->i_height = GetDWLE( p_data + 8 );
- h->i_planes = GetWLE( p_data + 12 );
- h->i_bitcount = GetWLE( p_data + 14 );
- h->i_compression = GetDWLE( p_data + 16 );
- h->i_sizeimage = GetDWLE( p_data + 20 );
- h->i_xpelspermeter = GetDWLE( p_data + 24 );
- h->i_ypelspermeter = GetDWLE( p_data + 28 );
- h->i_clrused = GetDWLE( p_data + 32 );
- h->i_clrimportant = GetDWLE( p_data + 36 );
+ p_bh->i_size = GetDWLE( p_data );
+ p_bh->i_width = GetDWLE( p_data + 4 );
+ p_bh->i_height = GetDWLE( p_data + 8 );
+ p_bh->i_planes = GetWLE( p_data + 12 );
+ p_bh->i_bitcount = GetWLE( p_data + 14 );
+ p_bh->i_compression = GetDWLE( p_data + 16 );
+ p_bh->i_sizeimage = GetDWLE( p_data + 20 );
+ p_bh->i_xpelspermeter = GetDWLE( p_data + 24 );
+ p_bh->i_ypelspermeter = GetDWLE( p_data + 28 );
+ p_bh->i_clrused = GetDWLE( p_data + 32 );
+ p_bh->i_clrimportant = GetDWLE( p_data + 36 );
+
+ if( p_bh->i_size > 40 )
+ {
+ p_bh->i_data = p_bh->i_size - 40;
+ p_bh->p_data = malloc( p_bh->i_data );
+ memcpy( p_bh->p_data, p_data + 40, p_bh->i_data );
+ }
+ else
+ {
+ p_bh->i_data = 0;
+ p_bh->p_data = NULL;
+ }
+
}
/* get the first pes from fifo */
static pes_packet_t *__PES_GET( decoder_fifo_t *p_fifo )
PIX_FMT_RGB24, PIX_FMT_BGR24, PIX_FMT_YUV422P,
PIX_FMT_YUV444P, PIX_FMT_YUV410P */
- 0, FOURCC_I420, FOURCC_I420,
- FOURCC_RV24, 0, FOURCC_Y422,
- FOURCC_I444, 0
+ 0, VLC_FOURCC('I','4','2','0'), VLC_FOURCC('I','4','2','0'),
+ VLC_FOURCC('R','V','2','4'), 0, VLC_FOURCC('Y','4','2','2'),
+ VLC_FOURCC('I','4','4','4'), 0
};
static inline u32 ffmpeg_PixFmtToChroma( int i_ffmpegchroma )
}
if( !i_chroma )
{
- i_chroma = FOURCC_I420; /* we will try to make conversion */
+ /* we will try to make conversion */
+ i_chroma = VLC_FOURCC('I','4','2','0');
}
if( ( p_vout->render.i_width != i_width )||
if( !i_chroma )
{
- i_chroma = FOURCC_I420; /* we make conversion if possible*/
+ /* we make conversion if possible*/
+ i_chroma = VLC_FOURCC('I','4','2','0');
msg_Warn( p_vdec->p_fifo, "Internal chroma conversion (FIXME)");
/* It's mainly for I410 -> I420 conversion that I've made,
it's buggy and very slow */
return( p_vout );
}
-#if 0
-/* segfault some^Wevery times*/
-static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic,
- AVPicture *p_avpicture,
- videodec_thread_t *p_vdec )
-{
- int i_plane;
-
- int i_x, i_y;
- int i_x_max, i_y_max;
-
- int i_width;
- int i_height;
-
- int i_dst_stride;
- int i_src_stride;
-
- u8 *p_dest;
- u8 *p_src;
-
- i_width = p_vdec->p_context->width;
- i_height= p_vdec->p_context->height;
-
-
- p_dest = p_pic->p[0].p_pixels;
- p_src = p_avpicture->data[0];
-
- i_src_stride = p_avpicture->linesize[0];
- i_dst_stride = p_pic->p[0].i_pitch;
-
- if( i_src_stride == i_dst_stride )
- {
- p_vdec->p_fifo->p_vlc->pf_memcpy( p_dest, p_src, i_src_stride * i_height );
- }
- else
- {
- for( i_y = 0; i_y < i_height; i_y++ )
- {
- p_vdec->p_fifo->p_vlc->pf_memcpy( p_dest, p_src, i_width );
- p_dest += i_dst_stride;
- p_src += i_src_stride;
- }
- }
-
- for( i_plane = 1; i_plane < 3; i_plane++ )
- {
- i_y_max = p_pic->p[i_plane].i_lines;
-
- p_src = p_avpicture->data[i_plane];
- p_dest = p_pic->p[i_plane].p_pixels;
- i_dst_stride = p_pic->p[i_plane].i_pitch;
- i_src_stride = p_avpicture->linesize[i_plane];
-
- i_x_max = __MIN( i_dst_stride / 2, i_src_stride );
-
- for( i_y = 0; i_y <( i_y_max + 1 ) / 2 ; i_y++ )
- {
- for( i_x = 0; i_x < i_x_max - 1; i_x++ )
- {
- p_dest[2 * i_x ] = p_src[i_x];
- p_dest[2 * i_x + 1] = ( p_src[i_x] + p_src[i_x + 1] ) / 2;
- }
- p_dest[2 * i_x_max - 2] = p_src[i_x];
- p_dest[2 * i_x_max - 1] = p_src[i_x];
-
- p_dest += 2 * i_dst_stride;
- p_src += i_src_stride;
- }
-
- p_src = p_pic->p[i_plane].p_pixels;
- p_dest = p_src + i_dst_stride;
-
- for( i_y = 0; i_y < ( i_y_max + 1 ) / 2 ; i_y++ )
- {
- p_vdec->p_fifo->p_vlc->pf_memcpy( p_dest, p_src, i_dst_stride );
- p_dest += 2*i_dst_stride;
- p_src += 2*i_dst_stride;
- }
-
- }
-}
-#endif
-
/* FIXME FIXME FIXME this is a big shit
does someone want to rewrite this function ?
or said to me how write a better thing
/*****************************************************************************
* InitThread: initialize vdec output thread
*****************************************************************************
- * This function is called from decoder_Run and performs the second step
+ * This function is called from RunDecoderoder and performs the second step
* of the initialization. It returns 0 on success. Note that the thread's
* flag are not modified inside this function.
*****************************************************************************/
if( p_vdec->p_fifo->p_demux_data )
{
- __ParseBitMapInfoHeader( &p_vdec->format,
- (byte_t*)p_vdec->p_fifo->p_demux_data );
+ ffmpeg_ParseBitMapInfoHeader( &p_vdec->format,
+ (u8*)p_vdec->p_fifo->p_demux_data );
}
else
{
{
msg_Dbg( p_vdec->p_fifo, "library ffmpeg already initialized" );
}
- ffmpeg_GetFfmpegCodec( p_vdec->p_fifo->i_type,
+ ffmpeg_GetFfmpegCodec( p_vdec->p_fifo->i_fourcc,
&i_ffmpeg_codec,
&p_vdec->psz_namecodec );
p_vdec->p_codec =
msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
p_vdec->psz_namecodec );
}
-
+
+ /* first give init data */
+ if( p_vdec->format.i_data )
+ {
+ AVPicture avpicture;
+ int b_gotpicture;
+
+ switch( i_ffmpeg_codec )
+ {
+ case( CODEC_ID_MPEG4 ):
+ avcodec_decode_video( p_vdec->p_context, &avpicture,
+ &b_gotpicture,
+ p_vdec->format.p_data,
+ p_vdec->format.i_data );
+ break;
+ default:
+ break;
+ }
+ }
+
/* This will be created after the first decoded frame */
p_vdec->p_vout = NULL;
-
+
return( 0 );
}
static void DecodeThread( videodec_thread_t *p_vdec )
{
int i_status;
+ int b_drawpicture;
int b_gotpicture;
AVPicture avpicture; /* ffmpeg picture */
picture_t *p_pic; /* videolan picture */
give it to ffmpeg decoder
and send the image to the output */
+ /* TODO implement it in a better way */
+
+ if( ( config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up") )&&
+ ( p_vdec->i_frame_late > 4 ) )
+ {
+#if LIBAVCODEC_BUILD > 4603
+ b_drawpicture = 0;
+ if( p_vdec->i_frame_late < 8 )
+ {
+ p_vdec->p_context->hurry_up = 2;
+ }
+ else
+ {
+ /* too much late picture, won't decode
+ but break picture until a new I, and for mpeg4 ...*/
+ p_vdec->i_frame_late--; /* needed else it will never be decrease */
+ __PES_NEXT( p_vdec->p_fifo );
+ return;
+ }
+#else
+ if( p_vdec->i_frame_late < 8 )
+ {
+ b_drawpicture = 0; /* not really good but .. */
+ }
+ else
+ {
+ /* too much late picture, won't decode
+ but break picture until a new I, and for mpeg4 ...*/
+ p_vdec->i_frame_late--; /* needed else it will never be decrease */
+ __PES_NEXT( p_vdec->p_fifo );
+ return;
+ }
+#endif
+ }
+ else
+ {
+ b_drawpicture = 1;
+#if LIBAVCODEC_BUILD > 4603
+ p_vdec->p_context->hurry_up = 0;
+#endif
+ }
+
__GetFrame( p_vdec );
i_status = avcodec_decode_video( p_vdec->p_context,
p_vdec->i_frame_error++;
return;
}
- if( !b_gotpicture || avpicture.linesize[0] == 0 )
+ /* Update frame late count*/
+ /* I don't make statistic on decoding time */
+ if( p_vdec->i_pts <= mdate())
+ {
+ p_vdec->i_frame_late++;
+ }
+ else
+ {
+ p_vdec->i_frame_late = 0;
+ }
+
+ if( !b_gotpicture || avpicture.linesize[0] == 0 || !b_drawpicture)
{
return;
}
+
/* Check our vout */
if( !ffmpeg_CheckVout( p_vdec->p_vout,
p_vdec->p_context->width,
vlc_object_detach( p_vdec->p_vout, p_vdec->p_fifo );
vlc_object_attach( p_vdec->p_vout, p_vdec->p_fifo->p_vlc );
}
+
+ if( p_vdec->format.p_data != NULL)
+ {
+ free( p_vdec->format.p_data );
+ }
free( p_vdec );
}