* video.c: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: video.c,v 1.8 2002/11/28 17:35:00 sam Exp $
+ * $Id: video.c,v 1.9 2002/12/06 11:53:45 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
/*****************************************************************************
* Local prototypes
*****************************************************************************/
+#if LIBAVCODEC_BUILD >= 4641
+static void ffmpeg_CopyPicture( picture_t *, AVVideoFrame *, vdec_thread_t * );
+#else
static void ffmpeg_CopyPicture( picture_t *, AVPicture *, vdec_thread_t * );
+#endif
+
static void ffmpeg_PostProcPicture( vdec_thread_t *, picture_t * );
-static int ffmpeg_GetFrameBuf( struct AVCodecContext *, int, int, int );
-/* FIXME FIXME some of them are wrong */
-static int i_ffmpeg_PixFmtToChroma[] =
-{
- /* PIX_FMT_ANY = -1, PIX_FMT_YUV420P,
- PIX_FMT_YUV422, PIX_FMT_RGB24,
- PIX_FMT_BGR24, PIX_FMT_YUV422P,
- PIX_FMT_YUV444P, PIX_FMT_YUV410P
- */
- 0, VLC_FOURCC('I','4','2','0'),
- VLC_FOURCC('I','4','2','0'), VLC_FOURCC('R','V','2','4'),
- 0, VLC_FOURCC('I','4','2','2'),
- VLC_FOURCC('I','4','4','4'), 0
-};
+#if LIBAVCODEC_BUILD >= 4641
+static int ffmpeg_GetFrameBuf( struct AVCodecContext *, AVVideoFrame *);
+static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *, AVVideoFrame *);
+#endif
/*****************************************************************************
* Local Functions
*****************************************************************************/
-static inline u32 ffmpeg_PixFmtToChroma( int i_ffmpegchroma )
+static inline uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma )
{
- if( ++i_ffmpegchroma > 7 )
- {
- return( 0 );
- }
- else
- {
- return( i_ffmpeg_PixFmtToChroma[i_ffmpegchroma] );
- }
-}
-
-static inline int ffmpeg_FfAspect( int i_width, int i_height, int i_ffaspect )
-{
- switch( i_ffaspect )
- {
- case( FF_ASPECT_4_3_625 ):
- case( FF_ASPECT_4_3_525 ):
- return( VOUT_ASPECT_FACTOR * 4 / 3);
- case( FF_ASPECT_16_9_625 ):
- case( FF_ASPECT_16_9_525 ):
- return( VOUT_ASPECT_FACTOR * 16 / 9 );
- case( FF_ASPECT_SQUARE ):
+ /* FIXME FIXME some of them are wrong */
+ switch( i_ff_chroma )
+ {
+ case PIX_FMT_YUV420P:
+ case PIX_FMT_YUV422:
+ return( VLC_FOURCC('I','4','2','0') );
+ case PIX_FMT_RGB24:
+ return( VLC_FOURCC('R','V','2','4') );
+
+ case PIX_FMT_YUV422P:
+ return( VLC_FOURCC('I','4','2','2') );
+ case PIX_FMT_YUV444P:
+ return( VLC_FOURCC('I','4','4','4') );
+#if LIBAVCODEC_BUILD >= 4615
+ case PIX_FMT_YUV410P:
+#endif
+ case PIX_FMT_BGR24:
default:
- return( VOUT_ASPECT_FACTOR * i_width / i_height );
+ return( 0 );
}
}
/* It's mainly for I410 -> I420 conversion that I've made,
it's buggy and very slow */
}
-
#if LIBAVCODEC_BUILD >= 4640
- i_aspect = (int) ( VOUT_ASPECT_FACTOR * p_vdec->p_context->aspect_ratio );
-
- if( i_aspect == 0 )
+ if( ( i_aspect = (int) ( VOUT_ASPECT_FACTOR *
+ p_vdec->p_context->aspect_ratio ) ) == 0 )
{
i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
}
-
#else
switch( p_vdec->p_context->aspect_ratio_info )
{
case( FF_ASPECT_16_9_625 ):
case( FF_ASPECT_16_9_525 ):
i_aspect = VOUT_ASPECT_FACTOR * 16 / 9 ;
- break;
+ break;
case( FF_ASPECT_SQUARE ):
default:
- i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
+ i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
break;
- }
+ }
#endif
+
/* Spawn a video output if there is none. First we look for our children,
* then we look for any other vout that might be available. */
p_vout = vout_Request( p_vdec->p_fifo, NULL,
or said to me how write a better thing
FIXME FIXME FIXME
*/
+#if LIBAVCODEC_BUILD >= 4641
+static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic,
+ AVVideoFrame *p_ff_pic,
+ vdec_thread_t *p_vdec )
+#else
static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic,
- AVPicture *p_avpicture,
+ AVPicture *p_ff_pic,
vdec_thread_t *p_vdec )
+#endif
{
u8 *p_src, *p_dst;
u8 *p_plane[3];
i_width = p_vdec->p_context->width;
p_dst = p_pic->p[0].p_pixels;
- p_src = p_avpicture->data[0];
+ p_src = p_ff_pic->data[0];
/* copy first plane */
for( i_y = 0; i_y < i_height; i_y++ )
{
p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_width);
p_dst += p_pic->p[0].i_pitch;
- p_src += p_avpicture->linesize[0];
+ p_src += p_ff_pic->linesize[0];
}
/* process each plane in a temporary buffer */
for( i_plane = 1; i_plane < 3; i_plane++ )
{
- i_stride = p_avpicture->linesize[i_plane];
+ i_stride = p_ff_pic->linesize[i_plane];
i_lines = i_height / 4;
p_dst = p_plane[i_plane] = malloc( i_lines * i_stride * 2 * 2 );
- p_src = p_avpicture->data[i_plane];
+ p_src = p_ff_pic->data[i_plane];
/* for each source line */
for( i_y = 0; i_y < i_lines; i_y++ )
for( i_plane = 1; i_plane < 3; i_plane++ )
{
- i_stride = p_avpicture->linesize[i_plane];
+ i_stride = p_ff_pic->linesize[i_plane];
i_lines = i_height / 4;
p_dst = p_plane[i_plane] + 2*i_stride;
int E_( InitThread_Video )( vdec_thread_t *p_vdec )
{
int i_tmp;
+#if LIBAVCODEC_BUILD >= 4641
+ p_vdec->p_ff_pic = avcodec_alloc_picture();
+#else
+ p_vdec->p_ff_pic = &p_vdec->ff_pic;
+#endif
if( p_vdec->p_fifo->p_demux_data )
{
p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
- p_vdec->p_lastpic = NULL;
- p_vdec->p_secondlastpic = NULL;
p_vdec->b_direct_rendering = 0;
-#if LIBAVCODEC_BUILD > 4615
- if( (p_vdec->p_codec->capabilities & CODEC_CAP_DR1)
- && (p_vdec->p_context->pix_fmt != PIX_FMT_YUV410P) &&
- config_GetInt( p_vdec->p_fifo, "ffmpeg-dr" ) )
+
+#if LIBAVCODEC_BUILD >= 4641
+ if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr" ) &&
+ p_vdec->p_codec->capabilities & CODEC_CAP_DR1 &&
+ p_vdec->p_context->pix_fmt != PIX_FMT_YUV410P ) /* <- FIXME */
{
msg_Dbg( p_vdec->p_fifo, "using direct rendering" );
p_vdec->b_direct_rendering = 1;
- p_vdec->p_context->flags|= CODEC_FLAG_EMU_EDGE | CODEC_FLAG_DR1;
- p_vdec->p_context->get_buffer_callback = ffmpeg_GetFrameBuf;
+ p_vdec->p_context->flags|= CODEC_FLAG_EMU_EDGE;
+ p_vdec->p_context->get_buffer = ffmpeg_GetFrameBuf;
+ p_vdec->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
p_vdec->p_context->opaque = p_vdec;
+
}
#endif
if( p_vdec->p_format &&
p_vdec->p_format->biSize > sizeof(BITMAPINFOHEADER) )
{
- AVPicture avpicture;
int b_gotpicture;
switch( p_vdec->i_codec_id )
{
case( CODEC_ID_MPEG4 ):
- avcodec_decode_video( p_vdec->p_context, &avpicture,
+ avcodec_decode_video( p_vdec->p_context, p_vdec->p_ff_pic,
&b_gotpicture,
(void *)&p_vdec->p_format[1],
p_vdec->p_format->biSize
config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ),
config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )
);
-
- /* allocate table for postprocess */
-// p_vdec->p_context->quant_store =
-// malloc( sizeof( int ) * ( MBR + 1 ) * ( MBC + 1 ) );
-// p_vdec->p_context->qstride = MBC + 1;
}
#else
p_vdec->i_pp_mode = 0;
int i_used;
int b_drawpicture;
int b_gotpicture;
- AVPicture avpicture; /* ffmpeg picture */
picture_t *p_pic; /* videolan picture */
mtime_t i_pts;
/* A good idea could be to decode all I pictures and see for the other */
if( ( p_vdec->b_hurry_up )&& ( p_vdec->i_frame_late > 4 ) )
{
-#if LIBAVCODEC_BUILD > 4603
b_drawpicture = 0;
if( p_vdec->i_frame_late < 8 )
{
input_ExtractPES( p_vdec->p_fifo, NULL );
return;
}
-#else
- if( p_vdec->i_frame_late < 8 )
- {
- b_drawpicture = 0; /* not really good but .. UPGRADE FFMPEG !! */
- }
- 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 */
- input_ExtractPES( p_vdec->p_fifo, NULL );
- return;
- }
-#endif
}
else
{
b_drawpicture = 1;
-#if LIBAVCODEC_BUILD > 4603
p_vdec->p_context->hurry_up = 0;
-#endif
}
do
usenextdata:
i_used = avcodec_decode_video( p_vdec->p_context,
- &avpicture,
+ p_vdec->p_ff_pic,
&b_gotpicture,
p_vdec->p_buffer,
i_frame_size );
p_vdec->i_frame_late = 0;
}
- if( !b_gotpicture || avpicture.linesize[0] == 0 || !b_drawpicture )
+ if( !b_gotpicture || p_vdec->p_ff_pic->linesize[0] == 0 || !b_drawpicture )
{
return;
}
msleep( VOUT_OUTMEM_SLEEP );
}
- /* fill p_picture_t from avpicture, do I410->I420 if needed */
- ffmpeg_CopyPicture( p_pic, &avpicture, p_vdec );
+ /* fill p_picture_t from AVVideoFrame, do I410->I420 if needed */
+ ffmpeg_CopyPicture( p_pic, p_vdec->p_ff_pic, p_vdec );
}
else
{
-#if LIBAVCODEC_BUILD > 4615
- p_pic = (picture_t *)p_vdec->p_context->dr_opaque_frame;
+#if LIBAVCODEC_BUILD >= 4641
+ p_pic = (picture_t *)p_vdec->p_ff_pic->opaque;
+#else
+ p_pic = NULL; /* f**ck gcc warning */
#endif
}
/* Do post-processing if requested */
- ffmpeg_PostProcPicture( p_vdec, p_pic );
+ /* XXX: with dr it is not a good thing if the picture will be used as
+ reference... */
+ ffmpeg_PostProcPicture( p_vdec, p_pic );
- /* Send decoded frame to vout */
+ /* fix date calculation */
if( p_vdec->pts > 0 )
{
i_pts = p_vdec->pts;
p_pic,
i_pts );
+ /* Send decoded frame to vout */
vout_DisplayPicture( p_vdec->p_vout, p_pic );
if( i_frame_size > 0 )
{
- goto usenextdata;
+ goto usenextdata; /* try to use all data */
}
}
*****************************************************************************/
void E_( EndThread_Video )( vdec_thread_t *p_vdec )
{
- if( p_vdec->p_secondlastpic )
- vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_secondlastpic );
- if( p_vdec->p_lastpic )
- vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_lastpic );
if( p_vdec->p_pp )
{
p_vdec->p_pp = NULL;
}
+#if LIBAVCODEC_BUILD >= 4641
+ if( p_vdec->p_ff_pic )
+ {
+ free( p_vdec->p_ff_pic );
+ }
+#endif
+
/* We are about to die. Reattach video output to p_vlc. */
vout_Request( p_vdec->p_fifo, p_vdec->p_vout, 0, 0, 0, 0 );
}
* ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a
* picture_t structure (when not in direct rendering mode).
*****************************************************************************/
-static void ffmpeg_CopyPicture( picture_t *p_pic, AVPicture *p_avpicture,
+#if LIBAVCODEC_BUILD >= 4641
+static void ffmpeg_CopyPicture( picture_t *p_pic,
+ AVVideoFrame *p_ff_pic,
+ vdec_thread_t *p_vdec )
+#else
+static void ffmpeg_CopyPicture( picture_t *p_pic,
+ AVPicture *p_ff_pic,
vdec_thread_t *p_vdec )
+#endif
{
int i_plane;
int i_size;
{
for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
{
- p_src = p_avpicture->data[i_plane];
+ p_src = p_ff_pic->data[i_plane];
p_dst = p_pic->p[i_plane].p_pixels;
- i_src_stride = p_avpicture->linesize[i_plane];
+ i_src_stride = p_ff_pic->linesize[i_plane];
i_dst_stride = p_pic->p[i_plane].i_pitch;
i_size = __MIN( i_src_stride, i_dst_stride );
{
#if LIBAVCODEC_BUILD >= 4615
case( PIX_FMT_YUV410P ):
- ffmpeg_ConvertPictureI410toI420( p_pic, p_avpicture, p_vdec );
+ ffmpeg_ConvertPictureI410toI420( p_pic, p_ff_pic, p_vdec );
break;
#endif
default:
*****************************************************************************/
static void ffmpeg_PostProcPicture( vdec_thread_t *p_vdec, picture_t *p_pic )
{
-#if LIBAVCODEC_BUILD > 4313
if( ( p_vdec->i_pp_mode )&&
( ( p_vdec->p_vout->render.i_chroma ==
VLC_FOURCC( 'I','4','2','0' ) )||
( p_vdec->p_vout->render.i_chroma ==
VLC_FOURCC( 'Y','V','1','2' ) ) ) )
{
- /* Make postproc */
+#if LIBAVCODEC_BUILD >= 4641
+ /* Make postproc */
+ p_vdec->p_pp->pf_postprocess( p_pic,
+ p_vdec->p_ff_pic->qscale_table,
+ p_vdec->p_ff_pic->qstride,
+ p_vdec->i_pp_mode );
+#elif LIBAVCODEC_BUILD >= 4633
p_vdec->p_pp->pf_postprocess( p_pic,
p_vdec->p_context->display_qscale_table,
-// p_vdec->p_context->current_qscale_table,
p_vdec->p_context->qstride,
p_vdec->i_pp_mode );
- }
#endif
+ }
}
+#if LIBAVCODEC_BUILD >= 4641
/*****************************************************************************
* ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer.
* (used for direct rendering)
*****************************************************************************/
-static int ffmpeg_GetFrameBuf( struct AVCodecContext *avctx, int width,
- int height, int pict_type )
+
+static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
+ AVVideoFrame *p_ff_pic )
{
-#if LIBAVCODEC_BUILD > 4615
- vdec_thread_t *p_vdec = (vdec_thread_t *)avctx->opaque;
+ vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
picture_t *p_pic;
- /* Check our vout */
+ /* Check and (re)create if needed our vout */
p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
if( !p_vdec->p_vout )
{
p_vdec->p_fifo->b_error = 1; /* abort */
return -1;
}
+ p_vdec->p_vout->render.b_allow_modify_pics = 0;
/* Get a new picture */
while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
}
msleep( VOUT_OUTMEM_SLEEP );
}
+ p_vdec->p_context->draw_horiz_band= NULL;
+
+ p_ff_pic->opaque = (void*)p_pic;
+
+ p_ff_pic->data[0] = p_pic->p[0].p_pixels;
+ p_ff_pic->data[1] = p_pic->p[1].p_pixels;
+ p_ff_pic->data[2] = p_pic->p[2].p_pixels;
+ p_ff_pic->data[3] = NULL; /* alpha channel but I'm not sure */
+
+ p_ff_pic->linesize[0] = p_pic->p[0].i_pitch;
+ p_ff_pic->linesize[1] = p_pic->p[1].i_pitch;
+ p_ff_pic->linesize[2] = p_pic->p[2].i_pitch;
+ p_ff_pic->linesize[3] = 0;
+
+ if( p_ff_pic->reference != 0 )
+ {
+ vout_LinkPicture( p_vdec->p_vout, p_pic );
+ }
+ /* FIXME what is that, should give good value */
+ p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg
- /* FIXME: We keep the last picture linked until the current one is decoded,
- * this trick won't work with streams with B frames though. */
- vout_LinkPicture( p_vdec->p_vout, p_pic );
- if( p_vdec->p_secondlastpic )
- vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_secondlastpic );
- p_vdec->p_secondlastpic = p_vdec->p_lastpic;
- p_vdec->p_lastpic = p_pic;
+ return( 0 );
+}
+
+static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
+ AVVideoFrame *p_ff_pic )
+{
+ vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
+ picture_t *p_pic;
- avctx->draw_horiz_band= NULL;
- avctx->dr_buffer[0]= p_pic->p[0].p_pixels;
- avctx->dr_buffer[1]= p_pic->p[1].p_pixels;
- avctx->dr_buffer[2]= p_pic->p[2].p_pixels;
+ //msg_Dbg( p_vdec->p_fifo, "ffmpeg_ReleaseFrameBuf" );
+ p_pic = (picture_t*)p_ff_pic->opaque;
- avctx->dr_stride = p_pic->p[0].i_pitch;
- avctx->dr_uvstride = p_pic->p[1].i_pitch;
+ p_ff_pic->data[0] = NULL;
+ p_ff_pic->data[1] = NULL;
+ p_ff_pic->data[2] = NULL;
+ p_ff_pic->data[3] = NULL;
- avctx->dr_opaque_frame = p_pic;
+ vout_UnlinkPicture( p_vdec->p_vout, p_pic );
+}
- /* This variable is used to determine if a macro-block to be written
- * can be skipped. The idea behind this is that if a macro-block hasn't
- * changed and all the frame-buffers already have the value of this
- * macro-block, then we don't need to write it again. */
- avctx->dr_ip_buffer_count = p_vdec->p_vout->render.i_pictures;
- p_vdec->p_vout->render.b_allow_modify_pics = 0;
- return 0;
#endif
-}
+