]> git.sesse.net Git - vlc/commitdiff
* ./modules/codec/xvid.c: beginning of a video decoder using the Xvid codec
authorSam Hocevar <sam@videolan.org>
Tue, 5 Nov 2002 22:53:21 +0000 (22:53 +0000)
committerSam Hocevar <sam@videolan.org>
Tue, 5 Nov 2002 22:53:21 +0000 (22:53 +0000)
    from xvid.org; compile with --enable-xvid --with-xvid-tree=..., run with
    --codec xvid,any (the priority is lower than ffmpeg's for the now).

    todo list: direct rendering, better buffer handling, see why only I frames
               are rendered OK here... probably more.

configure.ac.in
modules/codec/Modules.am
modules/codec/xvid.c [new file with mode: 0644]

index 76362230337bbfe2e909ad2f7318a9778f24b972..5c6954d77db0168b65811f6e441037003e36d9a5 100644 (file)
@@ -1274,6 +1274,61 @@ then
 fi
 
 
+dnl
+dnl  xvid decoder plugin
+dnl
+AC_ARG_ENABLE(xvid,
+[  --enable-xvid           xvid codec (default disabled)])
+if test "x${enable_xvid}" = "xyes"
+then
+  AC_ARG_WITH(xvid,
+    [    --with-xvid=PATH      path to xvid installation],[],[])
+  if test "x${with_xvid}" != "xno" -a "x${with_xvid}" != "x"
+  then
+    CPPFLAGS_xvid="${CPPFLAGS_xvid} -I${with_xvid}/include"
+    LDFLAGS_xvid="${LDFLAGS_xvid} -L${with_xvid}/lib"
+  fi
+  LDFLAGS_xvid="${LDFLAGS_xvid}"
+
+  AC_ARG_WITH(xvid-tree,
+  [    --with-xvid-tree=PATH xvid tree for static linking])
+  if test "x${with_xvid_tree}" != "x"
+  then
+    AC_MSG_CHECKING(for libxvidcore.a in ${with_xvid_tree})
+    real_xvid_tree="`cd ${with_xvid_tree} 2>/dev/null && pwd`"
+    if test "x${real_xvid_tree}" = x
+    then
+      dnl  The given directory can't be found
+      AC_MSG_RESULT(no)
+      AC_MSG_ERROR([cannot cd to ${with_xvid_tree}])
+    fi
+    if test -f "${real_xvid_tree}/build/generic/libxvidcore.a"
+    then
+      dnl  Use a custom xvid
+      AC_MSG_RESULT(${real_xvid_tree}/build/generic/libxvidcore.a)
+      BUILTINS="${BUILTINS} xvid"
+      LDFLAGS_xvid="${LDFLAGS_xvid} ${real_xvid_tree}/build/generic/libxvidcore.a"
+      CPPFLAGS_xvid="${CPPFLAGS_xvid} -I${real_xvid_tree}/src"
+    else
+      dnl  The given libxvidcore wasn't built
+      AC_MSG_RESULT(no)
+      AC_MSG_ERROR([cannot find ${real_xvid_tree}/build/generic/libxvidcore.a, make sure you compiled libxvidcore in ${with_xvid_tree}])
+    fi
+  else
+    CPPFLAGS="${CPPFLAGS_save} ${CPPFLAGS_xvid}"
+    LDFLAGS="${LDFLAGS_save} ${LDFLAGS_xvid}"
+    AC_CHECK_HEADERS(xvid.h, ,
+      [ AC_MSG_ERROR([Cannot find development headers for libxvidcore...]) ])
+    AC_CHECK_LIB(xvid, xvid_init, [
+      PLUGINS="${PLUGINS} xvid"
+      LDFLAGS_xvid="${LDFLAGS_xvid} -lxvid" ],
+      [ AC_MSG_ERROR([Cannot find libxvidcore library...]) ])
+    LDFLAGS="${LDFLAGS_save}"
+    CPPFLAGS="${CPPFLAGS_save}"
+  fi
+fi
+
+
 
 dnl
 dnl MP4 module
index 90449fec04ba04263e1ab28a739584162d45ba69..aa309e8d79910eea393b4737af2dc214dd436c56 100644 (file)
@@ -3,4 +3,4 @@ SOURCES_lpcm = modules/codec/lpcm.c
 SOURCES_araw = modules/codec/araw.c
 SOURCES_vorbis = modules/codec/vorbis.c
 SOURCES_dv = modules/codec/dv.c
-#SOURCES_xvid = modules/codec/xvid.c
+SOURCES_xvid = modules/codec/xvid.c
diff --git a/modules/codec/xvid.c b/modules/codec/xvid.c
new file mode 100644 (file)
index 0000000..fa8b798
--- /dev/null
@@ -0,0 +1,286 @@
+/*****************************************************************************
+ * xvid.c: a decoder for libxvidcore, the Xvid video codec
+ *****************************************************************************
+ * Copyright (C) 2002 VideoLAN
+ * $Id: xvid.c,v 1.1 2002/11/05 22:53:21 sam Exp $
+ *
+ * Authors: Samuel Hocevar <sam@zoy.org>
+ *      
+ * This program is free software; you can redistribute it and/or modify
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <vlc/vlc.h>
+#include <vlc/vout.h>
+#include <vlc/input.h>
+#include <vlc/decoder.h>
+
+#include <stdlib.h>
+
+#include "codecs.h"
+
+#include <xvid.h>
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int RunDecoder  ( decoder_fifo_t * );
+static int OpenDecoder ( vlc_object_t * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("Xvid video decoder") );
+    set_capability( "decoder", 50 );
+    set_callbacks( OpenDecoder, NULL );
+vlc_module_end();
+
+/*****************************************************************************
+ * OpenDecoder: probe the decoder and return score
+ *****************************************************************************
+ * The fourcc format for DV is "dvsd"
+ *****************************************************************************/
+static int OpenDecoder ( vlc_object_t *p_this )
+{
+    decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
+
+    if( p_fifo->i_fourcc != VLC_FOURCC('x','v','i','d')
+         && p_fifo->i_fourcc != VLC_FOURCC('X','V','I','D')
+         && p_fifo->i_fourcc != VLC_FOURCC('D','I','V','X') )
+    {
+        return VLC_EGENERIC;
+    }
+
+    p_fifo->pf_run = RunDecoder;
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * RunDecoder: this function is called just after the thread is created
+ *****************************************************************************/
+static int RunDecoder ( decoder_fifo_t *p_fifo )
+{
+    XVID_INIT_PARAM    xinit;
+    XVID_DEC_PARAM     xparam;
+    BITMAPINFOHEADER * p_format;
+    void *             p_xvid;
+
+    pes_packet_t *     p_pes = NULL;
+    bit_stream_t       bit_stream;
+    vout_thread_t *    p_vout;
+
+    uint8_t *  p_buffer, * p_image;
+    int        i_ret;
+    int        i_width, i_height, i_chroma, i_aspect;
+    int        i_size, i_offset;
+
+    if( InitBitstream( &bit_stream, p_fifo, NULL, NULL ) != VLC_SUCCESS )
+    {
+        msg_Err( p_fifo, "cannot initialise bitstream" );
+        p_fifo->b_error = VLC_TRUE;
+        DecoderError( p_fifo );
+        return VLC_EGENERIC;
+    }
+
+    p_format = (BITMAPINFOHEADER *)p_fifo->p_demux_data;
+
+    /* Guess picture properties from the BIH */
+    i_width = p_format->biWidth;
+    i_height = p_format->biHeight;
+    i_chroma = VLC_FOURCC('Y','V','1','2');
+    i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
+
+    /* XXX: Completely arbitrary buffer size */
+    i_size = i_width * i_height / 4;
+    i_offset = 0;
+    p_buffer = malloc( i_size + 4 * i_width * i_height );
+    p_image = p_buffer + 4 * i_width * i_height;
+
+    if( !p_buffer )
+    {
+        msg_Err( p_fifo, "out of memory" );
+        p_fifo->b_error = VLC_TRUE;
+        CloseBitstream( &bit_stream );
+        DecoderError( p_fifo );
+        return VLC_EGENERIC;
+    }
+
+    xinit.cpu_flags = 0;
+    xvid_init( NULL, 0, &xinit, NULL );
+
+    xparam.width = i_width;
+    xparam.height = i_height;
+    i_ret = xvid_decore( NULL, XVID_DEC_CREATE, &xparam, NULL );
+
+    if( i_ret )
+    {
+        msg_Err( p_fifo, "cannot create xvid decoder" );
+        p_fifo->b_error = VLC_TRUE;
+        free( p_buffer );
+        CloseBitstream( &bit_stream );
+        DecoderError( p_fifo );
+        return VLC_EGENERIC;
+    }
+
+    p_xvid = xparam.handle;
+
+    /* Spawn a video output if there is none. First we look amongst our
+     * children, then we look for any other vout that might be available */
+    p_vout = vlc_object_find( p_fifo, VLC_OBJECT_VOUT, FIND_CHILD );
+    if( !p_vout ) 
+    {
+        p_vout = vlc_object_find( p_fifo, VLC_OBJECT_VOUT, FIND_ANYWHERE );
+    }
+
+    if( p_vout )
+    {
+        if( p_vout->render.i_width != i_width
+         || p_vout->render.i_height != i_height
+         || p_vout->render.i_chroma != i_chroma
+         || p_vout->render.i_aspect != i_aspect )
+        {
+            /* We are not interested in this format, close this vout */
+            vlc_object_detach( p_vout );
+            vlc_object_release( p_vout );
+            vout_DestroyThread( p_vout );
+            p_vout = NULL;
+        }
+        else
+        {
+            /* This video output is cool! Hijack it. */
+            vlc_object_detach( p_vout );
+            vlc_object_attach( p_vout, p_fifo );
+            vlc_object_release( p_vout );
+        }
+    }
+
+    if( !p_vout )
+    {
+        msg_Dbg( p_fifo, "no vout present, spawning one" );
+
+        p_vout = vout_CreateThread( p_fifo,
+                                    i_width, i_height,
+                                    i_chroma, i_aspect );
+        if( !p_vout )
+        {
+            msg_Err( p_fifo, "could not spawn vout" );
+            p_fifo->b_error = VLC_TRUE;
+            xvid_decore( p_xvid, XVID_DEC_DESTROY, NULL, NULL );
+            free( p_buffer );
+            CloseBitstream( &bit_stream );
+            DecoderError( p_fifo );
+            return VLC_EGENERIC;
+        }
+    }
+
+    /* Main loop */
+    while( !p_fifo->b_die && !p_fifo->b_error )
+    {
+        XVID_DEC_FRAME xframe;
+        mtime_t i_pts = 0;
+
+        GetChunk( &bit_stream, p_buffer + i_offset, i_size - i_offset );
+
+        if( p_pes )
+        {
+            input_DeletePES( p_fifo->p_packets_mgt, p_pes );
+        }
+
+        input_ExtractPES( p_fifo, &p_pes );
+        if( p_pes )
+        {
+            /* Don't trust the sucker */
+            //i_pts = p_pes->i_pts + DEFAULT_PTS_DELAY;
+            i_pts = mdate() + DEFAULT_PTS_DELAY;
+        }
+
+        if( p_fifo->b_die || p_fifo->b_error )
+        {
+            break;
+        }
+
+        /* Decode the stuff */
+        xframe.bitstream = p_buffer;
+        xframe.length = i_size;
+        xframe.image = p_image;
+        xframe.stride = i_width;
+        xframe.colorspace = XVID_CSP_YV12;
+        i_ret = xvid_decore( p_xvid, XVID_DEC_DECODE, &xframe, NULL );
+        /* FIXME: check i_ret */
+
+        if( p_vout )
+        {
+            picture_t *p_pic;
+
+            while( !(p_pic = vout_CreatePicture( p_vout, 0, 0, 0 ) ) )
+            {
+                if( p_fifo->b_die || p_fifo->b_error )
+                {
+                    break;
+                } 
+                msleep( VOUT_OUTMEM_SLEEP );
+            }
+
+            if( !p_pic )
+            {
+                break;
+            }
+
+            /* TODO: use pf_memcpy when this is stable. */
+            memcpy( p_pic->p[0].p_pixels,
+                    p_image,
+                    i_width * i_height );
+            memcpy( p_pic->p[2].p_pixels,
+                    p_image + i_width * i_height,
+                    i_width * i_height / 4 );
+            memcpy( p_pic->p[1].p_pixels,
+                    p_image + i_width * i_height + i_width * i_height / 4,
+                    i_width * i_height / 4 );
+
+            vout_DatePicture( p_vout, p_pic, i_pts );
+            vout_DisplayPicture( p_vout, p_pic );
+        }
+
+        /* Move the remaining data. TODO: only do this when necessary. */
+        memmove( p_buffer, p_buffer + xframe.length, i_size - xframe.length );
+        i_offset = i_size - xframe.length;
+    }
+
+    /* Clean up everything */
+    vlc_object_detach( p_vout );
+    vout_DestroyThread( p_vout );
+
+    xvid_decore( p_xvid, XVID_DEC_DESTROY, NULL, NULL );
+
+    if( p_pes )
+    {
+        input_DeletePES( p_fifo->p_packets_mgt, p_pes );
+    }
+
+    free( p_buffer );
+    CloseBitstream( &bit_stream );
+
+    if( p_fifo->b_error )
+    {
+        DecoderError( p_fifo );
+        return VLC_EGENERIC;
+    }
+
+    return VLC_SUCCESS;
+}
+