[QUARTZ] Add FFMpeg video wrapper filter (take 2)

Christian Costa titan.costa at wanadoo.fr
Fri Jun 10 16:12:38 CDT 2005


Hi,

Removed #ifdefs. If libavcodec is not present, creating the wrapper just 
fail.

Changelog:
Added FFMpeg video wrapper filter.

Christian Costa   titan.costa at wanadoo.fr

-------------- next part --------------
Index: configure.ac
===================================================================
RCS file: /home/wine/wine/configure.ac,v
retrieving revision 1.362
diff -u -r1.362 configure.ac
--- configure.ac	9 Jun 2005 10:21:31 -0000	1.362
+++ configure.ac	10 Jun 2005 20:01:02 -0000
@@ -541,6 +541,14 @@
 AC_SUBST(FREETYPELIBS)
 AC_SUBST(FREETYPEINCL)
 
+dnl **** Check for avcodec lib ****
+AVCODECLIBS=""
+    AC_CHECK_HEADERS(ffmpeg/avcodec.h,
+      [AC_CHECK_LIB(avcodec,avcodec_open,
+          [AC_DEFINE(HAVE_LIBAVCODEC, 1, [Define if you have the avcodec library (-lavcodec)])
+           AVCODECLIBS="-lavcodec -lz -lm"],,-lz -lm)])
+AC_SUBST(AVCODECLIBS)
+
 dnl Only build the fonts dir if we have both freetype and fontforge
 if test "$FONTFORGE" != "false" -a -n "$FREETYPELIBS"
 then
Index: dlls/quartz/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/quartz/Makefile.in,v
retrieving revision 1.45
diff -u -r1.45 Makefile.in
--- dlls/quartz/Makefile.in	9 May 2005 14:42:32 -0000	1.45
+++ dlls/quartz/Makefile.in	10 Jun 2005 20:01:04 -0000
@@ -5,7 +5,7 @@
 MODULE    = quartz.dll
 IMPORTLIB = libquartz.$(IMPLIBEXT)
 IMPORTS   = dsound ddraw msacm32 msvfw32 ole32 oleaut32 user32 advapi32 kernel32
-EXTRALIBS = -lstrmiids -luuid $(LIBUNICODE)
+EXTRALIBS = -lstrmiids -luuid $(LIBUNICODE) @AVCODECLIBS@
 
 C_SRCS = \
 	acmwrapper.c \
@@ -18,6 +18,7 @@
 	enummoniker.c \
 	enumpins.c \
 	enumregfilters.c \
+	ffmpeg_video_wrapper.c \
 	filesource.c \
 	filtergraph.c \
 	filtermapper.c \
Index: dlls/quartz/quartz_private.h
===================================================================
RCS file: /home/wine/wine/dlls/quartz/quartz_private.h,v
retrieving revision 1.24
diff -u -r1.24 quartz_private.h
--- dlls/quartz/quartz_private.h	6 May 2005 14:34:02 -0000	1.24
+++ dlls/quartz/quartz_private.h	10 Jun 2005 20:01:05 -0000
@@ -53,6 +53,7 @@
 HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv);
 HRESULT ACMWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv);
 HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv);
+HRESULT FFMpegVideoWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv);
 
 HRESULT EnumMonikerImpl_Create(IMoniker ** ppMoniker, ULONG nMonikerCount, IEnumMoniker ** ppEnum);
 
@@ -81,5 +82,7 @@
 void DeleteMediaType(AM_MEDIA_TYPE * pmt);
 BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards);
 void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt);
+
+extern CLSID CLSID_FFMpegVideoWrapper;
 
 #endif /* __QUARTZ_PRIVATE_INCLUDED__ */
Index: dlls/quartz/regsvr.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/regsvr.c,v
retrieving revision 1.21
diff -u -r1.21 regsvr.c
--- dlls/quartz/regsvr.c	17 May 2005 14:41:37 -0000	1.21
+++ dlls/quartz/regsvr.c	10 Jun 2005 20:01:08 -0000
@@ -18,10 +18,15 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include "config.h"
+
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
 #define COBJMACROS
 #define COM_NO_WINDOWS_H
+
+#include "quartz_private.h"
+
 #include <stdarg.h>
 #include <string.h>
 
@@ -928,6 +933,12 @@
 	"quartz.dll",
 	"Both"
     },
+    {   &CLSID_FFMpegVideoWrapper,
+	"FFMpeg Video Wrapper",
+	NULL,
+	"quartz.dll",
+	"Both"
+    },
     { NULL }			/* list terminator */
 };
 
@@ -1112,6 +1123,24 @@
 	    },
 	    {   REG_PINFLAG_B_OUTPUT,
 		{   { &MEDIATYPE_Audio, &GUID_NULL },
+		    { NULL }
+		},
+	    },
+	    { 0xFFFFFFFF },
+	}
+    },
+    /* Wine specific filters */
+    {   &CLSID_FFMpegVideoWrapper,
+	&CLSID_LegacyAmFilterCategory,
+	{'F','F','M','p','e','g',' ','V','i','d','e','o',' ','W','r','a','p','p','e','r',0},
+	0x5FFFFF, /* Just below AVIDec */
+	{   {   0,
+		{   { &MEDIATYPE_Video, &GUID_NULL },
+		    { NULL }
+		},
+	    },
+	    {   REG_PINFLAG_B_OUTPUT,
+		{   { &MEDIATYPE_Video, &GUID_NULL },
 		    { NULL }
 		},
 	    },
Index: dlls/quartz/main.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/main.c,v
retrieving revision 1.47
diff -u -r1.47 main.c
--- dlls/quartz/main.c	6 Jun 2005 19:50:36 -0000	1.47
+++ dlls/quartz/main.c	10 Jun 2005 20:01:10 -0000
@@ -72,7 +72,8 @@
     { &CLSID_AVIDec, AVIDec_create },
     { &CLSID_SystemClock, &QUARTZ_CreateSystemClock },
     { &CLSID_ACMWrapper, &ACMWrapper_create },
-    { &CLSID_WAVEParser, &WAVEParser_create }
+    { &CLSID_WAVEParser, &WAVEParser_create },
+    { &CLSID_FFMpegVideoWrapper, &FFMpegVideoWrapper_create }
 };
 
 static HRESULT WINAPI
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ dlls/quartz/ffmpeg_video_wrapper.c	2005-06-10 21:37:48.000000000 +0100
@@ -0,0 +1,386 @@
+/*
+ * FFMpeg Video Decompressor (libavcodec video wrapper)
+ *
+ * Copyright 2004-2005 Christian Costa
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+
+#include "quartz_private.h"
+#include "control_private.h"
+#include "pin.h"
+
+#include "uuids.h"
+#include "aviriff.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "vfwmsgs.h"
+#include "evcode.h"
+#include "vfw.h"
+/* #include "fourcc.h" */
+#include <ffmpeg/avcodec.h>
+
+#include <assert.h>
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+#include "transform.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+
+CLSID CLSID_FFMpegVideoWrapper = { 0x30355649, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x72 } };
+
+#ifdef HAVE_LIBAVCODEC
+
+#define MAKE_FOURCC(a,b,c,d) ((a<<0)|(b<<8)|(c<<16)|(d<<24))
+
+struct toto {
+    DWORD fourcc;
+    int codec_id;
+};
+
+struct toto list[] = {
+    { MAKE_FOURCC('R','L','E',' '), CODEC_ID_MSRLE },
+    { 1, CODEC_ID_MSRLE },
+    { MAKE_FOURCC('m','s','v','c'), CODEC_ID_MSVIDEO1 },
+    { MAKE_FOURCC('C','R','A','M'), CODEC_ID_MSVIDEO1 },
+    { MAKE_FOURCC('i','v','3','2'), CODEC_ID_INDEO3 },
+    { MAKE_FOURCC('I','V','3','2'), CODEC_ID_INDEO3 },
+    { MAKE_FOURCC('c','v','i','d'), CODEC_ID_CINEPAK },
+    { MAKE_FOURCC('D','I','V','3'), CODEC_ID_MSMPEG4V3 },
+    { MAKE_FOURCC('M','J','P','G'), CODEC_ID_MJPEG },
+    { MAKE_FOURCC('m','j','p','g'), CODEC_ID_MJPEG }
+};
+
+typedef struct FFMpegVideoWrapperImpl
+{
+    TransformFilterImpl tf;
+    BITMAPINFOHEADER* pBihIn;
+    BITMAPINFOHEADER* pBihOut;
+    AVCodec* codec;
+    AVCodecContext* ctx;
+    AVFrame* tmp_pic;
+    AVPaletteControl palctrl;
+    int init;
+} FFMpegVideoWrapperImpl;
+
+static HRESULT FFMpegVideoWrapper_ProcessSampleData(TransformFilterImpl* pTransformFilter, LPBYTE data, DWORD size)
+{
+    FFMpegVideoWrapperImpl* This = (FFMpegVideoWrapperImpl*)pTransformFilter;
+    VIDEOINFOHEADER* format;
+    AM_MEDIA_TYPE amt;
+    HRESULT hr;
+    IMediaSample* pSample = NULL;
+    DWORD cbDstStream;
+    LPBYTE pbDstStream;
+    int nOut, got_pic;
+    int i;
+    AVPicture dst_pic;
+    int ret;
+    BYTE* tmp;
+    int fmt;
+
+    hr = IPin_ConnectionMediaType(This->tf.ppPins[0], &amt);
+    if (FAILED(hr))
+    {
+	ERR("Unable to retrieve media type\n");
+	goto error;
+    }
+    format = (VIDEOINFOHEADER*)amt.pbFormat;
+
+    /* Update input size to match sample size */
+    This->pBihIn->biSizeImage = size;
+
+    hr = OutputPin_GetDeliveryBuffer((OutputPin*)This->tf.ppPins[1], &pSample, NULL, NULL, 0);
+    if (FAILED(hr))
+    {
+	ERR("Unable to get delivery buffer (%lx)\n", hr);
+	goto error;
+    }
+    
+    hr = IMediaSample_SetActualDataLength(pSample, 0);
+    assert(hr == S_OK);
+
+    hr = IMediaSample_GetPointer(pSample, &pbDstStream);
+    if (FAILED(hr))
+    {
+	ERR("Unable to get pointer to buffer (%lx)\n", hr);
+	goto error;
+    }
+    cbDstStream = IMediaSample_GetSize(pSample);
+    if (cbDstStream < This->pBihOut->biSizeImage)
+    {
+        ERR("Sample size is too small %ld < %ld\n", cbDstStream, This->pBihOut->biSizeImage);
+	hr = E_FAIL;
+	goto error;
+    }
+
+    This->ctx->width = This->pBihIn->biWidth;
+    This->ctx->height = This->pBihIn->biHeight;
+    This->ctx->bits_per_sample = This->pBihIn->biBitCount;
+
+    TRACE("Decode %d %d\n", This->tmp_pic->linesize[0], This->pBihOut->biBitCount);
+
+    nOut = avcodec_decode_video( This->ctx, This->tmp_pic, &got_pic, (void*)data, size );
+
+    TRACE("End decode %d\n", This->tmp_pic->linesize[0]);
+
+    if (nOut < 0)
+    {
+	ERR("Decoding error\n");
+	hr = E_FAIL;
+	goto error;
+    }
+    if (!got_pic)
+    {
+	ERR("No pic!!!\n");
+	hr = E_FAIL;
+	goto error;
+    }
+
+    TRACE("used %d,%ld size %d x %d\n", nOut, size, This->ctx->width, This->ctx->height);
+
+    switch(This->pBihOut->biBitCount)
+    {
+        case 32: fmt = PIX_FMT_RGBA32; break;
+        case 24: fmt = PIX_FMT_BGR24; break;
+        case 16: fmt = PIX_FMT_RGB565; break;
+        case 8:  fmt = PIX_FMT_PAL8; break;
+        default: FIXME("Bad depth\n"); fmt = PIX_FMT_RGBA32; break;
+    }
+
+    if (This->pBihOut->biBitCount != 8)
+    {
+        tmp = CoTaskMemAlloc(This->ctx->width*3*This->ctx->height);
+        dst_pic.data[0] = tmp;
+        dst_pic.linesize[0] = This->ctx->width*3;
+        ret = img_convert(&dst_pic, fmt, (AVPicture*)This->tmp_pic, This->ctx->pix_fmt, This->ctx->width, This->ctx->height);
+        if (ret != 0)
+        {
+	    ERR("Cannot convert img!\n");
+            CoTaskMemFree(tmp);
+	    hr = E_FAIL;
+	    goto error;
+        }
+
+        for(i = 0; i < This->ctx->height; i++)
+    	    memcpy(pbDstStream + (This->ctx->height-i-1) * This->ctx->width*This->pBihOut->biBitCount/8,
+                   dst_pic.data[0] + i * dst_pic.linesize[0], This->ctx->width*This->pBihOut->biBitCount/8);
+
+        CoTaskMemFree(tmp);
+    }
+    else
+    {
+        for(i = 0; i < This->ctx->height; i++)
+    	    memcpy(pbDstStream + (This->ctx->height-i-1) * This->ctx->width,
+                   This->tmp_pic->data[0] + i * This->tmp_pic->linesize[0], This->ctx->width);
+    }
+
+    hr = OutputPin_SendSample((OutputPin*)This->tf.ppPins[1], pSample);
+    if (hr != S_OK && hr != VFW_E_NOT_CONNECTED)
+    {
+        ERR("Error sending sample (%lx)\n", hr);
+	goto error;
+    }
+
+error:
+    if (pSample)
+        IMediaSample_Release(pSample);
+
+    return hr;
+}
+
+static HRESULT FFMpegVideoWrapper_ConnectInput(TransformFilterImpl* pTransformFilter, const AM_MEDIA_TYPE * pmt)
+{
+    FFMpegVideoWrapperImpl* This = (FFMpegVideoWrapperImpl*)pTransformFilter;
+    int i;
+
+    TRACE("(%p)->(%p)\n", This, pmt);
+    
+    if ((IsEqualIID(&pmt->majortype, &MEDIATYPE_Video)) &&
+        (!memcmp(((char*)&pmt->subtype)+4, ((char*)&MEDIATYPE_Video)+4, sizeof(GUID)-4)) && /* Check root (GUID w/o FOURCC) */
+        (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)))
+    {
+        VIDEOINFOHEADER* format = (VIDEOINFOHEADER*)pmt->pbFormat;
+        AM_MEDIA_TYPE* outpmt = &((OutputPin*)This->tf.ppPins[1])->pin.mtCurrent;
+        const CLSID* outsubtype;
+        DWORD bih_size;
+        DWORD output_depth = format->bmiHeader.biBitCount;
+        int codec_id = CODEC_ID_NONE;
+
+        switch(format->bmiHeader.biBitCount)
+        {
+            case 32: outsubtype = &MEDIASUBTYPE_RGB32; break;
+            case 24: outsubtype = &MEDIASUBTYPE_RGB24; break;
+            case 16: outsubtype = &MEDIASUBTYPE_RGB565; break;
+            case 8:  outsubtype = &MEDIASUBTYPE_RGB8; break;
+            default:
+                TRACE("Non standard input depth %d, forced ouptut depth to 32\n", format->bmiHeader.biBitCount);
+                outsubtype = &MEDIASUBTYPE_RGB32;
+                output_depth = 32;
+                break;
+        }
+
+        /* Copy bitmap header from media type to 1 for input and 1 for output */
+        if (This->pBihIn)
+        {
+            CoTaskMemFree(This->pBihIn);
+            CoTaskMemFree(This->pBihOut);
+        }
+
+        bih_size = format->bmiHeader.biSize + format->bmiHeader.biClrUsed * 4;
+        This->pBihIn = (BITMAPINFOHEADER*)CoTaskMemAlloc(bih_size);
+        if (!This->pBihIn)
+            return E_OUTOFMEMORY;
+        This->pBihOut = (BITMAPINFOHEADER*)CoTaskMemAlloc(bih_size);
+        if (!This->pBihOut)
+        {
+            CoTaskMemFree(This->pBihIn);
+            This->pBihIn = NULL;
+            return E_OUTOFMEMORY;
+        }
+        memcpy(This->pBihIn, &format->bmiHeader, bih_size);
+        memcpy(This->pBihOut, &format->bmiHeader, bih_size);
+
+        /* Update output format as non compressed bitmap */
+        This->pBihOut->biCompression = 0;
+        This->pBihOut->biBitCount = output_depth;
+        This->pBihOut->biSizeImage = This->pBihOut->biWidth * This->pBihOut->biHeight * This->pBihOut->biBitCount / 8;
+
+        /* Update buffer size of media samples in output */
+        ((OutputPin*)This->tf.ppPins[1])->allocProps.cbBuffer = This->pBihOut->biSizeImage;
+
+        TRACE("FMT %.04s %ld %.04s\n", (LPCSTR)&pmt->subtype.Data1, pmt->subtype.Data1, (LPCSTR)&list[0].fourcc);
+
+        for(i = 0; i < sizeof(list)/sizeof(list[0]); i++)
+            if (pmt->subtype.Data1 == list[i].fourcc)
+            {
+                codec_id = list[i].codec_id;
+                break;
+            }
+        if (codec_id == CODEC_ID_NONE)
+        {
+            TRACE("Codec not supported yet\n");
+	    goto skip;
+        }
+
+        This->codec = avcodec_find_decoder(codec_id);
+        if (!This->codec)
+        {
+            TRACE("Couldn't find codec\n");
+            goto skip;
+        }
+
+        This->ctx = avcodec_alloc_context();
+        This->tmp_pic = avcodec_alloc_frame();
+
+        if (format->bmiHeader.biClrUsed)
+        {
+            This->ctx->palctrl = &This->palctrl;
+            CopyMemory(This->ctx->palctrl->palette, ((LPBYTE)This->pBihIn) + format->bmiHeader.biSize, format->bmiHeader.biClrUsed * 4);
+        }
+
+        if (avcodec_open( This->ctx, This->codec) < 0)
+        {
+            ERR("Couldn't open codec\n");
+            goto skip;
+        }
+
+        /* Update output media type */
+        CopyMediaType(outpmt, pmt);
+        outpmt->subtype = *outsubtype;
+        memcpy(&(((VIDEOINFOHEADER*)outpmt->pbFormat)->bmiHeader), This->pBihOut, This->pBihOut->biSize);
+
+        This->init = 1;
+        TRACE("Connection accepted\n");
+        return S_OK;
+
+skip:
+        TRACE("Unable to find a suitable FFMpeg video decompressor\n");
+    }
+    
+    TRACE("Connection refused\n");
+    return S_FALSE;
+}
+
+static HRESULT FFMpegVideoWrapper_Cleanup(TransformFilterImpl* pTransformFilter)
+{
+    FFMpegVideoWrapperImpl* This = (FFMpegVideoWrapperImpl*)pTransformFilter;
+
+    TRACE("(%p)->()\n", This);
+    
+    return S_OK;
+}
+
+TransformFuncsTable FFMpegVideoWrapper_FuncsTable = {
+    NULL,
+    FFMpegVideoWrapper_ProcessSampleData,
+    NULL,
+    FFMpegVideoWrapper_ConnectInput,
+    FFMpegVideoWrapper_Cleanup
+};
+
+HRESULT FFMpegVideoWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv)
+{
+    HRESULT hr;
+    FFMpegVideoWrapperImpl * This;
+
+    TRACE("(%p, %p)\n", pUnkOuter, ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter)
+        return CLASS_E_NOAGGREGATION;
+
+    /* Note: This memory is managed by the transform filter once created */
+    This = CoTaskMemAlloc(sizeof(FFMpegVideoWrapperImpl));
+
+    This->pBihIn = NULL;
+    This->pBihOut = NULL;
+
+    hr = TransformFilter_Create(&(This->tf), &CLSID_FFMpegVideoWrapper, &FFMpegVideoWrapper_FuncsTable);
+
+    if (FAILED(hr))
+        return hr;
+
+    avcodec_init();
+    avcodec_register_all();
+    
+    *ppv = (LPVOID)This;
+
+    return hr;
+}
+
+#else
+
+HRESULT FFMpegVideoWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv)
+{
+    TRACE("(%p, %p) Failed! No libavcodec support!\n", pUnkOuter, ppv);
+
+    *ppv = NULL;
+
+    return E_FAIL;
+}
+
+#endif /* HAVE_LIBAVCODEC */
+


More information about the wine-patches mailing list