]> git.sesse.net Git - vlc/blobdiff - plugins/ffmpeg/ffmpeg.c
* ALL: new module API. Makes a few things a lot simpler, and we gain
[vlc] / plugins / ffmpeg / ffmpeg.c
index 6019791134670b9414d51534cff6d49764caa369..8a6d7d7cc0f15802ec0040537f36666b2250decc 100644 (file)
@@ -2,7 +2,7 @@
  * 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>
  *
@@ -49,8 +49,8 @@
 /*
  * 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 * );
@@ -59,16 +59,7 @@ 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 \
@@ -80,54 +71,49 @@ void _M( vdec_getfunctions )( function_list_t * p_function_list )
 #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" );
@@ -176,19 +162,33 @@ static int decoder_Run ( decoder_fifo_t * p_fifo )
     (  *(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 )
@@ -292,9 +292,9 @@ static int i_ffmpeg_PixFmtToChroma[] =
    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 )
@@ -337,7 +337,8 @@ static int ffmpeg_CheckVout( vout_thread_t *p_vout,
     }
     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 )||
@@ -371,7 +372,8 @@ static vout_thread_t *ffmpeg_CreateVout( videodec_thread_t *p_vdec,
 
     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 */
@@ -423,89 +425,6 @@ static vout_thread_t *ffmpeg_CreateVout( videodec_thread_t *p_vdec,
     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
@@ -667,7 +586,7 @@ static void ffmpeg_ConvertPicture( picture_t *p_pic,
 /*****************************************************************************
  * 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.
  *****************************************************************************/
@@ -679,8 +598,8 @@ static int InitThread( videodec_thread_t *p_vdec )
     
     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
     {
@@ -699,7 +618,7 @@ static int InitThread( videodec_thread_t *p_vdec )
     {
         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 = 
@@ -755,10 +674,29 @@ static int InitThread( videodec_thread_t *p_vdec )
         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 );
 }
 
@@ -768,6 +706,7 @@ static int InitThread( videodec_thread_t *p_vdec )
 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 */
@@ -775,6 +714,48 @@ static void  DecodeThread( videodec_thread_t *p_vdec )
        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,
@@ -792,10 +773,22 @@ static void  DecodeThread( videodec_thread_t *p_vdec )
         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,
@@ -866,6 +859,11 @@ static void EndThread( videodec_thread_t *p_vdec )
         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 );
 }