* ffmpeg.c: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: ffmpeg.c,v 1.13 2002/10/28 22:23:23 gbazin Exp $
+ * $Id: ffmpeg.c,v 1.49 2003/09/02 20:19:25 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#include <vlc/decoder.h>
#include <vlc/input.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* getpid() */
-#endif
-
-#include <errno.h>
#include <string.h>
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
-#include "avcodec.h" /* ffmpeg */
+/* ffmpeg header */
+#ifdef HAVE_FFMPEG_AVCODEC_H
+# include <ffmpeg/avcodec.h>
+#else
+# include <avcodec.h>
+#endif
+
+#if LIBAVCODEC_BUILD < 4655
+# error You must have a libavcodec >= 4655 (get CVS)
+#endif
-#include "postprocessing/postprocessing.h"
#include "ffmpeg.h"
+
+#ifdef LIBAVCODEC_PP
+# ifdef HAVE_POSTPROC_POSTPROCESS_H
+# include <postproc/postprocess.h>
+# else
+# include <libpostproc/postprocess.h>
+# endif
+#endif
+
#include "video.h" // video ffmpeg specific
#include "audio.h" // audio ffmpeg specific
/*
* Local prototypes
*/
+int E_(OpenChroma) ( vlc_object_t * );
static int OpenDecoder ( vlc_object_t * );
static int RunDecoder ( decoder_fifo_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
+#define DR_TEXT N_("Direct rendering")
-#define ERROR_RESILIENCE_LONGTEXT \
- "ffmpeg can make errors resiliences. \n"\
- "Nevertheless, with buggy encoder (like ISO MPEG-4 encoder from M$) " \
+#define ERROR_TEXT N_("Error resilience")
+#define ERROR_LONGTEXT N_( \
+ "ffmpeg can make errors resiliences. \n" \
+ "Nevertheless, with a buggy encoder (like ISO MPEG-4 encoder from M$) " \
"this will produce a lot of errors.\n" \
- "Valid range is -1 to 99 (-1 disable all errors resiliences)."
+ "Valid range is -1 to 99 (-1 disables all errors resiliences).")
-#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."
-
-#define POSTPROCESSING_Q_LONGTEXT \
- "Quality of post processing\n"\
- "Valid range is 0 to 6\n" \
- "( Overridden by others setting)"
-
-#define POSTPROCESSING_AQ_LONGTEXT \
- "Post processing quality is selected upon time left" \
- "but no more than requested quality\n" \
- "Not yet implemented !"
-
-#define WORAROUND_BUG_LONGTEXT \
+#define BUGS_TEXT N_("Workaround bugs")
+#define BUGS_LONGTEXT N_( \
"Try to fix some bugs\n" \
"1 autodetect\n" \
"2 old msmpeg4\n" \
"4 xvid interlaced\n" \
"8 ump4 \n" \
"16 no padding\n" \
- "32 ac vlc" \
- "64 Qpel chroma"
+ "32 ac vlc\n" \
+ "64 Qpel chroma")
+
+#define HURRYUP_TEXT N_("Hurry up")
+#define HURRYUP_LONGTEXT N_( \
+ "Allow the decoder to partially decode or skip frame(s) " \
+ "when there is not enough time. It's useful with low CPU power " \
+ "but it can produce distorted pictures.")
+
+#define TRUNC_TEXT N_("Truncated stream")
+#define TRUNC_LONGTEXT N_("truncated stream -1:auto,0:disable,:1:enable")
+
+#define PP_Q_TEXT N_("Post processing quality")
+#define PP_Q_LONGTEXT N_( \
+ "Quality of post processing. Valid range is 0 to 6\n" \
+ "Higher levels require considerable more CPU power, but produce " \
+ "better looking pictures." )
+
+#define LIBAVCODEC_PP_TEXT N_("Ffmpeg postproc filter chains")
+/* FIXME (cut/past from ffmpeg */
+#define LIBAVCODEC_PP_LONGTEXT \
+"<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n" \
+"long form example:\n" \
+"vdeblock:autoq/hdeblock:autoq/linblenddeint default,-vdeblock\n" \
+"short form example:\n" \
+"vb:a/hb:a/lb de,-vb\n" \
+"more examples:\n" \
+"tn:64:128:256\n" \
+"Filters Options\n" \
+"short long name short long option Description\n" \
+"* * a autoq cpu power dependant enabler\n" \
+" c chrom chrominance filtring enabled\n" \
+" y nochrom chrominance filtring disabled\n" \
+"hb hdeblock (2 Threshold) horizontal deblocking filter\n" \
+" 1. difference factor: default=64, higher -> more deblocking\n" \
+" 2. flatness threshold: default=40, lower -> more deblocking\n" \
+" the h & v deblocking filters share these\n" \
+" so u cant set different thresholds for h / v\n" \
+"vb vdeblock (2 Threshold) vertical deblocking filter\n" \
+"h1 x1hdeblock Experimental h deblock filter 1\n" \
+"v1 x1vdeblock Experimental v deblock filter 1\n" \
+"dr dering Deringing filter\n" \
+"al autolevels automatic brightness / contrast\n" \
+" f fullyrange stretch luminance to (0..255)\n" \
+"lb linblenddeint linear blend deinterlacer\n" \
+"li linipoldeint linear interpolating deinterlace\n" \
+"ci cubicipoldeint cubic interpolating deinterlacer\n" \
+"md mediandeint median deinterlacer\n" \
+"fd ffmpegdeint ffmpeg deinterlacer\n" \
+"de default hb:a,vb:a,dr:a,al\n" \
+"fa fast h1:a,v1:a,dr:a,al\n" \
+"tn tmpnoise (3 Thresholds) Temporal Noise Reducer\n" \
+" 1. <= 2. <= 3. larger -> stronger filtering\n" \
+"fq forceQuant <quantizer> Force quantizer\n"
vlc_module_begin();
- add_category_hint( N_("Ffmpeg"), NULL );
-#if LIBAVCODEC_BUILD >= 4611
- add_integer ( "ffmpeg-error-resilience", -1, NULL,
- "error resilience", ERROR_RESILIENCE_LONGTEXT );
- add_integer ( "ffmpeg-workaround-bugs", 0, NULL,
- "workaround bugs", WORAROUND_BUG_LONGTEXT );
-#endif
- add_bool( "ffmpeg-hurry-up", 0, NULL, "hurry up", HURRY_UP_LONGTEXT );
-
- add_category_hint( N_("Post processing"), NULL );
- add_module( "ffmpeg-pp", "postprocessing",NULL, NULL,
- N_( "ffmpeg postprocessing module" ), NULL );
- add_integer( "ffmpeg-pp-q", 0, NULL,
- "post processing quality", POSTPROCESSING_Q_LONGTEXT );
- add_bool( "ffmpeg-pp-auto", 0, NULL,
- "auto-level Post processing quality", POSTPROCESSING_AQ_LONGTEXT );
- add_bool( "ffmpeg-db-yv", 0, NULL,
- "force vertical luminance deblocking",
- "force vertical luminance deblocking (override other settings)" );
- add_bool( "ffmpeg-db-yh", 0, NULL,
- "force horizontal luminance deblocking",
- "force horizontal luminance deblocking (override other settings)" );
- add_bool( "ffmpeg-db-cv", 0, NULL,
- "force vertical chrominance deblocking",
- "force vertical chrominance deblocking (override other settings)" );
- add_bool( "ffmpeg-db-ch", 0, NULL,
- "force horizontal chrominance deblocking",
- "force horizontal chrominance deblocking (override other settings) " );
- add_bool( "ffmpeg-dr-y", 0, NULL,
- "force luminance deringing",
- "force luminance deringing (override other settings)" );
- add_bool( "ffmpeg-dr-c", 0, NULL,
- "force chrominance deringing",
- "force chrominance deringing (override other settings)" );
-
- set_description( _("ffmpeg audio/video decoder((MS)MPEG4,SVQ1,H263,WMV,WMA)") );
+ add_category_hint( N_("ffmpeg"), NULL, VLC_FALSE );
set_capability( "decoder", 70 );
set_callbacks( OpenDecoder, NULL );
+ set_description( _("ffmpeg audio/video decoder((MS)MPEG4,SVQ1,H263,WMV,WMA)") );
+
+ add_bool( "ffmpeg-dr", 1, NULL, DR_TEXT, DR_TEXT, VLC_TRUE );
+ add_integer ( "ffmpeg-error-resilience", -1, NULL, ERROR_TEXT, ERROR_LONGTEXT, VLC_TRUE );
+ add_integer ( "ffmpeg-workaround-bugs", 1, NULL, BUGS_TEXT, BUGS_LONGTEXT, VLC_FALSE );
+ add_bool( "ffmpeg-hurry-up", 0, NULL, HURRYUP_TEXT, HURRYUP_LONGTEXT, VLC_FALSE );
+ add_integer( "ffmpeg-truncated", -1, NULL, TRUNC_TEXT, TRUNC_LONGTEXT, VLC_FALSE );
+
+ add_category_hint( N_("Post processing"), NULL, VLC_FALSE );
+
+ add_integer( "ffmpeg-pp-q", 0, NULL, PP_Q_TEXT, PP_Q_LONGTEXT, VLC_FALSE );
+#ifdef LIBAVCODEC_PP
+ add_string( "ffmpeg-pp-name", "default", NULL, LIBAVCODEC_PP_TEXT, LIBAVCODEC_PP_LONGTEXT, VLC_TRUE );
+#endif
+
+ /* chroma conversion submodule */
+ add_submodule();
+ set_capability( "chroma", 50 );
+ set_callbacks( E_(OpenChroma), NULL );
+ set_description( _("ffmpeg chroma conversion") );
+
+ var_Create( p_module->p_libvlc, "avcodec", VLC_VAR_MUTEX );
vlc_module_end();
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************
- * Tries to launch a decoder and return score so that the interface is able
+ * Tries to launch a decoder and return score so that the interface is able
* to chose.
*****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
- decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
+ decoder_t *p_dec = (decoder_t*) p_this;
- if( ffmpeg_GetFfmpegCodec( p_fifo->i_fourcc, NULL, NULL, NULL ) )
+ if( !ffmpeg_GetFfmpegCodec( p_dec->p_fifo->i_fourcc, NULL, NULL, NULL ) )
{
- p_fifo->pf_run = RunDecoder;
- return VLC_SUCCESS;
+ return VLC_EGENERIC;
}
- return VLC_EGENERIC;
+ p_dec->pf_run = RunDecoder;
+
+ return VLC_SUCCESS;
}
typedef union decoder_thread_u
} decoder_thread_t;
-
/*****************************************************************************
* RunDecoder: this function is called just after the thread is created
*****************************************************************************/
DecoderError( p_fifo );
return( -1 );
}
-
+
while( (!p_decoder->p_fifo->b_die) && (!p_decoder->p_fifo->b_error) )
{
switch( p_decoder->i_cat )
{
return( -1 );
}
-
+
return( 0 );
-}
+}
/*****************************************************************************
*
/*****************************************************************************
* InitThread: initialize vdec output thread
*****************************************************************************
- * This function is called from decoder_Run and performs the second step
- * of the initialization. It returns 0 on success. Note that the thread's
+ * This function is called from decoder_Run 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.
*
* ffmpeg codec will be open, some memory allocated. But Vout is not yet
static int InitThread( generic_thread_t *p_decoder )
{
int i_result;
-
+ vlc_value_t lockval;
+
+
+ var_Get( p_decoder->p_fifo->p_libvlc, "avcodec", &lockval );
+ vlc_mutex_lock( lockval.p_address );
+
/* *** init ffmpeg library (libavcodec) *** */
if( !b_ffmpeginit )
{
+
avcodec_init();
avcodec_register_all();
b_ffmpeginit = 1;
- msg_Dbg( p_decoder->p_fifo, "library ffmpeg initialized" );
+ msg_Dbg( p_decoder->p_fifo, "libavcodec initialized (interface "
+ LIBAVCODEC_BUILD_STR ")" );
}
else
{
- msg_Dbg( p_decoder->p_fifo, "library ffmpeg already initialized" );
+ msg_Dbg( p_decoder->p_fifo, "libavcodec already initialized" );
}
+ vlc_mutex_unlock( lockval.p_address );
/* *** determine codec type *** */
ffmpeg_GetFfmpegCodec( p_decoder->p_fifo->i_fourcc,
&p_decoder->i_cat,
&p_decoder->i_codec_id,
&p_decoder->psz_namecodec );
-
+
/* *** ask ffmpeg for a decoder *** */
- if( !( p_decoder->p_codec =
+ if( !( p_decoder->p_codec =
avcodec_find_decoder( p_decoder->i_codec_id ) ) )
{
- msg_Err( p_decoder->p_fifo,
+ msg_Err( p_decoder->p_fifo,
"codec not found (%s)",
p_decoder->psz_namecodec );
return( -1 );
}
/* *** Get a p_context *** */
-#if LIBAVCODEC_BUILD >= 4624
p_decoder->p_context = avcodec_alloc_context();
-#else
- p_decoder->p_context = malloc( sizeof( AVCodecContext ) );
- memset( p_decoder->p_context, 0, sizeof( AVCodecContext ) );
-#endif
-
+
switch( p_decoder->i_cat )
{
case VIDEO_ES:
default:
i_result = -1;
}
-
+
p_decoder->pts = 0;
+ p_decoder->p_buffer = NULL;
+ p_decoder->i_buffer = 0;
+ p_decoder->i_buffer_size = 0;
+
return( i_result );
}
*****************************************************************************/
static void EndThread( generic_thread_t *p_decoder )
{
-
+
if( !p_decoder )
{
return;
}
-
+
if( p_decoder->p_context != NULL)
{
- FREE( p_decoder->p_context->quant_store );
FREE( p_decoder->p_context->extradata );
avcodec_close( p_decoder->p_context );
- msg_Dbg( p_decoder->p_fifo,
+ msg_Dbg( p_decoder->p_fifo,
"ffmpeg codec (%s) stopped",
p_decoder->psz_namecodec );
free( p_decoder->p_context );
E_( EndThread_Video )( (vdec_thread_t*)p_decoder );
break;
}
-
+
free( p_decoder );
}
* locales Functions
*****************************************************************************/
-void E_( GetPESData )( u8 *p_buf, int i_max, pes_packet_t *p_pes )
-{
- int i_copy;
+int E_( GetPESData )( u8 *p_buf, int i_max, pes_packet_t *p_pes )
+{
+ int i_copy;
int i_count;
data_packet_t *p_data;
while( p_data != NULL && i_count < i_max )
{
- i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
+ i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
i_max - i_count );
if( i_copy > 0 )
{
memset( p_buf, 0, i_max - i_count );
}
+ return( i_count );
}
switch( i_fourcc )
{
-#if LIBAVCODEC_BUILD >= 4608
+ case FOURCC_mpgv:
+ i_cat = VIDEO_ES;
+ i_codec = CODEC_ID_MPEG1VIDEO;
+ psz_name = "MPEG-1/2 Video";
+ break;
+
case FOURCC_DIV1:
case FOURCC_div1:
case FOURCC_MPG4:
i_codec = CODEC_ID_MSMPEG4V2;
psz_name = "MS MPEG-4 v2";
break;
-#endif
case FOURCC_MPG3:
case FOURCC_mpg3:
case FOURCC_DIV6:
case FOURCC_div6:
case FOURCC_AP41:
- case FOURCC_3IV1:
+ case FOURCC_3VID:
+ case FOURCC_3vid:
+ case FOURCC_3IVD:
+ case FOURCC_3ivd:
i_cat = VIDEO_ES;
-#if LIBAVCODEC_BUILD >= 4608
i_codec = CODEC_ID_MSMPEG4V3;
-#else
- i_codec = CODEC_ID_MSMPEG4;
-#endif
psz_name = "MS MPEG-4 v3";
break;
-#if LIBAVCODEC_BUILD >= 4615
case FOURCC_SVQ1:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_SVQ1;
psz_name = "SVQ-1 (Sorenson Video v1)";
break;
+#if LIBAVCODEC_BUILD >= 4666
+ case FOURCC_SVQ3:
+ i_cat = VIDEO_ES;
+ i_codec = CODEC_ID_SVQ3;
+ psz_name = "SVQ-3 (Sorenson Video v3)";
+ break;
#endif
case FOURCC_DIVX:
case FOURCC_DX50:
case FOURCC_mp4v:
case FOURCC_4:
+ case FOURCC_m4cc:
+ case FOURCC_M4CC:
+ /* 3iv1 is unsupported by ffmpeg
+ putting it here gives extreme distorted images
+ case FOURCC_3IV1:
+ case FOURCC_3iv1:
+ */
case FOURCC_3IV2:
+ case FOURCC_3iv2:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_MPEG4;
psz_name = "MPEG-4";
psz_name ="Windows Media Video 1";
break;
case FOURCC_WMV2:
+ case FOURCC_MSS1:
i_cat = VIDEO_ES;
i_codec = CODEC_ID_WMV2;
psz_name ="Windows Media Video 2";
break;
+ case FOURCC_MJPG:
+ case FOURCC_mjpg:
+ case FOURCC_mjpa:
+ case FOURCC_jpeg:
+ case FOURCC_JPEG:
+ case FOURCC_JFIF:
+ i_cat = VIDEO_ES;
+ i_codec = CODEC_ID_MJPEG;
+ psz_name = "Motion JPEG";
+ break;
+ case FOURCC_mjpb:
+ i_cat = VIDEO_ES;
+ i_codec = CODEC_ID_MJPEGB;
+ psz_name = "Motion JPEG B";
+ break;
+ case FOURCC_dvsl:
+ case FOURCC_dvsd:
+ case FOURCC_DVSD:
+ case FOURCC_dvhd:
+ case FOURCC_dvc:
+ case FOURCC_dvp:
+ case FOURCC_CDVC:
+ i_cat = VIDEO_ES;
+ i_codec = CODEC_ID_DVVIDEO;
+ psz_name = "DV video";
+ break;
+
+ case FOURCC_MAC3:
+ i_cat = AUDIO_ES;
+ i_codec = CODEC_ID_MACE3;
+ psz_name = "MACE-3 audio";
+ break;
+ case FOURCC_MAC6:
+ i_cat = AUDIO_ES;
+ i_codec = CODEC_ID_MACE6;
+ psz_name = "MACE-6 audio";
+ break;
+ case FOURCC_dvau:
+ i_cat = AUDIO_ES;
+ i_codec = CODEC_ID_DVAUDIO;
+ psz_name = "DV audio";
+ break;
-#if LIBAVCODEC_BUILD >= 4632
case FOURCC_WMA1:
case FOURCC_wma1:
i_cat = AUDIO_ES;
i_codec = CODEC_ID_WMAV2;
psz_name ="Windows Media Audio 2";
break;
+
+#if( ( LIBAVCODEC_BUILD >= 4663 ) && ( !defined( WORDS_BIGENDIAN ) ) )
+ /* Quality of this decoder on ppc is not good */
+ case FOURCC_IV31:
+ case FOURCC_iv31:
+ case FOURCC_IV32:
+ case FOURCC_iv32:
+ i_cat = VIDEO_ES;
+ i_codec = CODEC_ID_INDEO3;
+ psz_name = "Indeo v3";
+ break;
+#endif
+
+#if LIBAVCODEC_BUILD >= 4668
+ /* Not yet finished
+ case FOURCC_vp31:
+ case FOURCC_VP31:
+ i_cat = VIDEO_ES;
+ i_codec = CODEC_ID_VP3;
+ psz_name = "On2's VP3 Video";
+ break;
+
+ case FOURCC_asv1:
+ case FOURCC_ASV1:
+ i_cat = VIDEO_ES;
+ i_codec = CODEC_ID_ASV1;
+ psz_name = "Asus V1";
+ break; */
#endif
default:
return( VLC_FALSE );
}
-
-
-