]> git.sesse.net Git - vlc/blobdiff - modules/codec/ffmpeg/ffmpeg.c
* ALL: Introduction of a new api for decoders.
[vlc] / modules / codec / ffmpeg / ffmpeg.c
index 793ce80cf34c87ffbb3e03deb5bcf40f6ef85877..db67bf8199edeba5dd6708221e5454bc04dacf05 100644 (file)
@@ -2,7 +2,7 @@
  * ffmpeg.c: video decoder using ffmpeg library
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: ffmpeg.c,v 1.20 2002/11/28 16:32:29 fenrir Exp $
+ * $Id: ffmpeg.c,v 1.49 2003/09/02 20:19:25 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
@@ -10,7 +10,7 @@
  * 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 <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 * );
 
@@ -63,101 +81,124 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t, int *, int *, char ** );
 /*****************************************************************************
  * 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 >= 4615
-    add_bool( "ffmpeg-dr", 0, NULL,
-              "direct rendering", 
-              "direct rendering" );
-#endif
-#if LIBAVCODEC_BUILD >= 4611
-    add_integer ( "ffmpeg-error-resilience", -1, NULL, 
-                  "error resilience", ERROR_RESILIENCE_LONGTEXT );
-    add_integer ( "ffmpeg-workaround-bugs", 1, 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
@@ -168,7 +209,6 @@ typedef union decoder_thread_u
 
 } decoder_thread_t;
 
-
 /*****************************************************************************
  * RunDecoder: this function is called just after the thread is created
  *****************************************************************************/
@@ -193,7 +233,7 @@ static int RunDecoder( decoder_fifo_t *p_fifo )
         DecoderError( p_fifo );
         return( -1 );
     }
-     
+
     while( (!p_decoder->p_fifo->b_die) && (!p_decoder->p_fifo->b_error) )
     {
         switch( p_decoder->i_cat )
@@ -218,9 +258,9 @@ static int RunDecoder( decoder_fifo_t *p_fifo )
     {
         return( -1 );
     }
-   
+
     return( 0 );
-} 
+}
 
 /*****************************************************************************
  *
@@ -231,8 +271,8 @@ static int RunDecoder( decoder_fifo_t *p_fifo )
 /*****************************************************************************
  * 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
@@ -242,45 +282,48 @@ static int RunDecoder( decoder_fifo_t *p_fifo )
 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:
@@ -292,7 +335,7 @@ static int InitThread( generic_thread_t *p_decoder )
         default:
             i_result = -1;
     }
-    
+
     p_decoder->pts = 0;
     p_decoder->p_buffer = NULL;
     p_decoder->i_buffer = 0;
@@ -309,17 +352,17 @@ static int InitThread( generic_thread_t *p_decoder )
  *****************************************************************************/
 static void EndThread( generic_thread_t *p_decoder )
 {
-    
+
     if( !p_decoder )
     {
         return;
     }
-    
+
     if( p_decoder->p_context != NULL)
     {
         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 );
@@ -336,7 +379,7 @@ static void EndThread( generic_thread_t *p_decoder )
             E_( EndThread_Video )( (vdec_thread_t*)p_decoder );
             break;
     }
-    
+
     free( p_decoder );
 }
 
@@ -345,8 +388,8 @@ static void EndThread( generic_thread_t *p_decoder )
  *****************************************************************************/
 
 int E_( GetPESData )( u8 *p_buf, int i_max, pes_packet_t *p_pes )
-{   
-    int i_copy; 
+{
+    int i_copy;
     int i_count;
 
     data_packet_t   *p_data;
@@ -356,7 +399,7 @@ int E_( GetPESData )( u8 *p_buf, int i_max, pes_packet_t *p_pes )
     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 )
@@ -390,15 +433,12 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
 
     switch( i_fourcc )
     {
-#if 0
-        /* XXX don't use it */
         case FOURCC_mpgv:
             i_cat = VIDEO_ES;
             i_codec = CODEC_ID_MPEG1VIDEO;
             psz_name = "MPEG-1/2 Video";
             break;
-#endif
-#if LIBAVCODEC_BUILD >= 4608 
+
         case FOURCC_DIV1:
         case FOURCC_div1:
         case FOURCC_MPG4:
@@ -416,7 +456,6 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
             i_codec = CODEC_ID_MSMPEG4V2;
             psz_name = "MS MPEG-4 v2";
             break;
-#endif
 
         case FOURCC_MPG3:
         case FOURCC_mpg3:
@@ -431,22 +470,26 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
         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:
@@ -461,7 +504,15 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
         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";
@@ -487,6 +538,7 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
             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";
@@ -501,15 +553,39 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
             i_codec = CODEC_ID_MJPEG;
             psz_name = "Motion JPEG";
             break;
-#if LIBAVCODEC_BUILD >= 4640
         case FOURCC_mjpb:
             i_cat = VIDEO_ES;
             i_codec = CODEC_ID_MJPEGB;
             psz_name = "Motion JPEG B";
             break;
-#endif
+        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;
@@ -522,6 +598,34 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
             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:
@@ -541,6 +645,3 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
 
     return( VLC_FALSE );
 }
-
-
-