[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