From eefe6f65c1ba208e32e9dad836c885347cda7e17 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Fri, 3 Dec 2010 07:33:08 -0600 Subject: [PATCH] wineqtdecoder: Initial version of the video decoder using Mac OS/X QuickTime Framework. --- configure | 6 + configure.ac | 4 + dlls/wineqtdecoder/Makefile.in | 9 + dlls/wineqtdecoder/main.c | 135 ++++++ dlls/wineqtdecoder/qtvdecoder.c | 609 ++++++++++++++++++++++++++ dlls/wineqtdecoder/wineqtdecoder.spec | 4 + 6 files changed, 767 insertions(+) create mode 100644 dlls/wineqtdecoder/Makefile.in create mode 100644 dlls/wineqtdecoder/main.c create mode 100644 dlls/wineqtdecoder/qtvdecoder.c create mode 100644 dlls/wineqtdecoder/wineqtdecoder.spec diff --git a/configure b/configure index 5abdaacce77..503c8387cf6 100755 --- a/configure +++ b/configure @@ -657,6 +657,7 @@ FRAMEWORK_OPENAL COREAUDIO DISKARBITRATIONLIB LDEXECFLAGS +QUICKTIMELIB IOKITLIB COREFOUNDATIONLIB SECURITYLIB @@ -6518,6 +6519,8 @@ fi IOKITLIB="-framework IOKit -framework CoreFoundation" + QUICKTIMELIB="-framework QuickTime -framework ApplicationServices -framework CoreVideo" + LDEXECFLAGS="-image_base 0x7bf00000 -Wl,-segaddr,WINE_DOS,0x00000000,-segaddr,WINE_SHAREDHEAP,0x7f000000" if test "$ac_cv_header_DiskArbitration_DiskArbitration_h" = "yes" @@ -6564,6 +6567,7 @@ done LIBS="$ac_save_LIBS" fi + enable_wineqtdecoder=${enable_wineqtdecoder:-yes} case $host_cpu in *powerpc*) LDDLLFLAGS="$LDDLLFLAGS -read_only_relocs warning" ;; @@ -7031,6 +7035,7 @@ $as_echo "$ac_cv_c_dll_hpux" >&6; } ;; esac +enable_wineqtdecoder=${enable_wineqtdecoder:-no} enable_winequartz_drv=${enable_winequartz_drv:-no} if test "$LIBEXT" = "a"; then @@ -15270,6 +15275,7 @@ wine_fn_config_dll winenas.drv enable_winenas_drv wine_fn_config_dll wineoss.drv enable_wineoss_drv wine_fn_config_dll wineps.drv enable_wineps_drv wine_fn_config_dll wineps16.drv16 enable_win16 +wine_fn_config_dll wineqtdecoder enable_wineqtdecoder wine_fn_config_dll winequartz.drv enable_winequartz_drv wine_fn_config_dll winex11.drv enable_winex11_drv wine_fn_config_dll wing.dll16 enable_win16 diff --git a/configure.ac b/configure.ac index 2431c7febdc..2dd58311cb9 100644 --- a/configure.ac +++ b/configure.ac @@ -702,6 +702,7 @@ case $host_os in AC_SUBST(SECURITYLIB,"-framework Security -framework CoreFoundation") AC_SUBST(COREFOUNDATIONLIB,"-framework CoreFoundation") AC_SUBST(IOKITLIB,"-framework IOKit -framework CoreFoundation") + AC_SUBST(QUICKTIMELIB,"-framework QuickTime -framework ApplicationServices -framework CoreVideo") AC_SUBST(LDEXECFLAGS,["-image_base 0x7bf00000 -Wl,-segaddr,WINE_DOS,0x00000000,-segaddr,WINE_SHAREDHEAP,0x7f000000"]) if test "$ac_cv_header_DiskArbitration_DiskArbitration_h" = "yes" then @@ -731,6 +732,7 @@ case $host_os in AC_CHECK_FUNCS(IOHIDManagerCreate) LIBS="$ac_save_LIBS" fi + enable_wineqtdecoder=${enable_wineqtdecoder:-yes} case $host_cpu in *powerpc*) LDDLLFLAGS="$LDDLLFLAGS -read_only_relocs warning" dnl FIXME @@ -838,6 +840,7 @@ case $host_os in ;; esac +enable_wineqtdecoder=${enable_wineqtdecoder:-no} enable_winequartz_drv=${enable_winequartz_drv:-no} if test "$LIBEXT" = "a"; then @@ -2794,6 +2797,7 @@ WINE_CONFIG_DLL(winenas.drv) WINE_CONFIG_DLL(wineoss.drv) WINE_CONFIG_DLL(wineps.drv) WINE_CONFIG_DLL(wineps16.drv16,enable_win16) +WINE_CONFIG_DLL(wineqtdecoder) WINE_CONFIG_DLL(winequartz.drv) WINE_CONFIG_DLL(winex11.drv) WINE_CONFIG_DLL(wing.dll16,enable_win16) diff --git a/dlls/wineqtdecoder/Makefile.in b/dlls/wineqtdecoder/Makefile.in new file mode 100644 index 00000000000..57436b5bcf1 --- /dev/null +++ b/dlls/wineqtdecoder/Makefile.in @@ -0,0 +1,9 @@ +MODULE = wineqtdecoder.dll +IMPORTS = strmiids strmbase uuid ole32 advapi32 +EXTRALIBS = @QUICKTIMELIB@ + +C_SRCS = \ + main.c \ + qtvdecoder.c + +@MAKE_DLL_RULES@ diff --git a/dlls/wineqtdecoder/main.c b/dlls/wineqtdecoder/main.c new file mode 100644 index 00000000000..e36101394be --- /dev/null +++ b/dlls/wineqtdecoder/main.c @@ -0,0 +1,135 @@ +/* + * Directshow filter for Quicktime Toolkit on mac OS/X + * + * Copyright (C) 2010 Aric Stewart, CodeWeavers + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include "config.h" + +#include +#include +#include + +#define COBJMACROS +#define NONAMELESSSTRUCT +#define NONAMELESSUNION + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winerror.h" +#include "objbase.h" +#include "uuids.h" +#include "strmif.h" + +#include "wine/unicode.h" +#include "wine/debug.h" +#include "wine/strmbase.h" + +#include "initguid.h" +DEFINE_GUID(CLSID_QTVDecoder, 0x683DDACB, 0x4354, 0x490C, 0xA0,0x58, 0xE0,0x5A,0xD0,0xF2,0x05,0x37); + +WINE_DEFAULT_DEBUG_CHANNEL(qtdecoder); + +extern IUnknown * CALLBACK QTVDecoder_create(IUnknown * pUnkOuter, HRESULT* phr); + +static const WCHAR wQTVName[] = +{'Q','T',' ','V','i','d','e','o',' ','D','e','c','o','d','e','r',0}; +static WCHAR wNull[] = {'\0'}; + +static const AMOVIESETUP_MEDIATYPE amfMTvideo[] = +{ { &MEDIATYPE_Video, &MEDIASUBTYPE_NULL } }; + +static const AMOVIESETUP_PIN amfQTVPin[] = +{ { wNull, + FALSE, FALSE, FALSE, FALSE, + &GUID_NULL, + NULL, + 1, + amfMTvideo + }, + { + wNull, + FALSE, TRUE, FALSE, FALSE, + &GUID_NULL, + NULL, + 1, + amfMTvideo + }, +}; + +static const AMOVIESETUP_FILTER amfQTV = +{ &CLSID_QTVDecoder, + wQTVName, + MERIT_NORMAL, + 2, + amfQTVPin +}; + +FactoryTemplate const g_Templates[] = { + { + wQTVName, + &CLSID_QTVDecoder, + QTVDecoder_create, + NULL, + &amfQTV, + } +}; + +int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); + +/*********************************************************************** + * Dll EntryPoint (wineqtdecoder.@) + */ +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) +{ + return STRMBASE_DllMain(hInstDLL,fdwReason,lpv); +} + +/*********************************************************************** + * DllGetClassObject + */ +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + return STRMBASE_DllGetClassObject( rclsid, riid, ppv ); +} + +/*********************************************************************** + * DllRegisterServer (wineqtdecoder.@) + */ +HRESULT WINAPI DllRegisterServer(void) +{ + TRACE("()\n"); + return AMovieDllRegisterServer2(TRUE); +} + +/*********************************************************************** + * DllUnregisterServer (wineqtdecoder.@) + */ +HRESULT WINAPI DllUnregisterServer(void) +{ + TRACE("\n"); + return AMovieDllRegisterServer2(FALSE); +} + +/*********************************************************************** + * DllCanUnloadNow (wineqtdecoder.@) + */ +HRESULT WINAPI DllCanUnloadNow(void) +{ + TRACE("\n"); + return STRMBASE_DllCanUnloadNow(); +} diff --git a/dlls/wineqtdecoder/qtvdecoder.c b/dlls/wineqtdecoder/qtvdecoder.c new file mode 100644 index 00000000000..b0cf12882ad --- /dev/null +++ b/dlls/wineqtdecoder/qtvdecoder.c @@ -0,0 +1,609 @@ +/* + * QuickTime Toolkit decoder filter for video + * + * Copyright 2010 Aric Stewart, CodeWeavers + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#define ULONG CoreFoundation_ULONG +#define HRESULT CoreFoundation_HRESULT + +#define LoadResource __carbon_LoadResource +#define CompareString __carbon_CompareString +#define GetCurrentThread __carbon_GetCurrentThread +#define GetCurrentProcess __carbon_GetCurrentProcess +#define AnimatePalette __carbon_AnimatePalette +#define EqualRgn __carbon_EqualRgn +#define FillRgn __carbon_FillRgn +#define FrameRgn __carbon_FrameRgn +#define GetPixel __carbon_GetPixel +#define InvertRgn __carbon_InvertRgn +#define LineTo __carbon_LineTo +#define OffsetRgn __carbon_OffsetRgn +#define PaintRgn __carbon_PaintRgn +#define Polygon __carbon_Polygon +#define ResizePalette __carbon_ResizePalette +#define SetRectRgn __carbon_SetRectRgn + +#define CheckMenuItem __carbon_CheckMenuItem +#define DeleteMenu __carbon_DeleteMenu +#define DrawMenuBar __carbon_DrawMenuBar +#define EnableMenuItem __carbon_EnableMenuItem +#define EqualRect __carbon_EqualRect +#define FillRect __carbon_FillRect +#define FrameRect __carbon_FrameRect +#define GetCursor __carbon_GetCursor +#define GetMenu __carbon_GetMenu +#define InvertRect __carbon_InvertRect +#define IsWindowVisible __carbon_IsWindowVisible +#define MoveWindow __carbon_MoveWindow +#define OffsetRect __carbon_OffsetRect +#define PtInRect __carbon_PtInRect +#define SetCursor __carbon_SetCursor +#define SetRect __carbon_SetRect +#define ShowCursor __carbon_ShowCursor +#define ShowWindow __carbon_ShowWindow +#define UnionRect __carbon_UnionRect + +#include +#include + +#undef LoadResource +#undef CompareString +#undef GetCurrentThread +#undef _CDECL +#undef DPRINTF +#undef GetCurrentProcess +#undef AnimatePalette +#undef EqualRgn +#undef FillRgn +#undef FrameRgn +#undef GetPixel +#undef InvertRgn +#undef LineTo +#undef OffsetRgn +#undef PaintRgn +#undef Polygon +#undef ResizePalette +#undef SetRectRgn +#undef CheckMenuItem +#undef DeleteMenu +#undef DrawMenuBar +#undef EnableMenuItem +#undef EqualRect +#undef FillRect +#undef FrameRect +#undef GetCursor +#undef GetMenu +#undef InvertRect +#undef IsWindowVisible +#undef MoveWindow +#undef OffsetRect +#undef PtInRect +#undef SetCursor +#undef SetRect +#undef ShowCursor +#undef ShowWindow +#undef UnionRect + +#undef ULONG +#undef HRESULT +#undef DPRINTF +#undef STDMETHODCALLTYPE + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "wtypes.h" +#include "winuser.h" +#include "dshow.h" + +#include "uuids.h" +#include "amvideo.h" +#include "strmif.h" +#include "vfwmsgs.h" +#include "vfw.h" +#include "dvdmedia.h" + +#include + +#include "wine/unicode.h" +#include "wine/debug.h" +#include "wine/strmbase.h" + +extern CLSID CLSID_QTVDecoder; + +WINE_DEFAULT_DEBUG_CHANNEL(qtdecoder); + +typedef struct QTVDecoderImpl +{ + TransformFilter tf; + IUnknown *seekthru_unk; + + ImageDescriptionHandle hImageDescription; + CFMutableDictionaryRef outputBufferAttributes; + ICMDecompressionSessionRef decompressionSession; + HRESULT decodeHR; + + DWORD outputSize; + DWORD outputWidth, outputHeight, outputDepth; + +} QTVDecoderImpl; + +typedef struct { + UInt8 a; /* Alpha Channel */ + UInt8 r; /* red component */ + UInt8 g; /* green component */ + UInt8 b; /* blue component */ +} ARGBPixelRecord, *ARGBPixelPtr, **ARGBPixelHdl; + +static const IBaseFilterVtbl QTVDecoder_Vtbl; + +static void trackingCallback( + void *decompressionTrackingRefCon, + OSStatus result, + ICMDecompressionTrackingFlags decompressionTrackingFlags, + CVPixelBufferRef pixelBuffer, + TimeValue64 displayTime, + TimeValue64 displayDuration, + ICMValidTimeFlags validTimeFlags, + void *reserved, + void *sourceFrameRefCon ) +{ + QTVDecoderImpl *This = (QTVDecoderImpl*)decompressionTrackingRefCon; + IMediaSample *pSample = (IMediaSample*)sourceFrameRefCon; + HRESULT hr = S_OK; + IMediaSample* pOutSample = NULL; + LPBYTE pbDstStream; + DWORD cbDstStream; + LPBYTE pPixels = NULL; + LPBYTE out = NULL; + size_t bytesPerRow = 0; + + int i; + + if (result != noErr) + { + ERR("Error from Codec, no frame decompressed\n"); + return; + } + + if (!pixelBuffer) + { + ERR("No pixel buffer, no frame decompressed\n"); + return; + } + + EnterCriticalSection(&This->tf.filter.csFilter); + hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->tf.ppPins[1], &pOutSample, NULL, NULL, 0); + if (FAILED(hr)) { + ERR("Unable to get delivery buffer (%x)\n", hr); + goto error; + } + + hr = IMediaSample_SetActualDataLength(pOutSample, 0); + assert(hr == S_OK); + + hr = IMediaSample_GetPointer(pOutSample, &pbDstStream); + if (FAILED(hr)) { + ERR("Unable to get pointer to buffer (%x)\n", hr); + goto error; + } + + cbDstStream = IMediaSample_GetSize(pOutSample); + if (cbDstStream < This->outputSize) { + ERR("Sample size is too small %d < %d\n", cbDstStream, This->outputSize); + hr = E_FAIL; + goto error; + } + + /* ACCESS THE PIXELS */ + CVPixelBufferLockBaseAddress(pixelBuffer,0); + pPixels = (LPBYTE)CVPixelBufferGetBaseAddress(pixelBuffer); + bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer); + + for (out = pbDstStream, i = 0; i < This->outputHeight; i++) + { + int j; + for (j = 0; j < This->outputWidth; j++) + { + *((DWORD*)out) = (((ARGBPixelPtr)pPixels)[j].r) << 16 + | (((ARGBPixelPtr)pPixels)[j].g) << 8 + | (((ARGBPixelPtr)pPixels)[j].b); + out+=This->outputDepth; + } + pPixels += bytesPerRow; + } + CVPixelBufferUnlockBaseAddress(pixelBuffer,0); + + IMediaSample_SetActualDataLength(pOutSample, This->outputSize); + + IMediaSample_SetPreroll(pOutSample, (IMediaSample_IsPreroll(pSample) == S_OK)); + IMediaSample_SetDiscontinuity(pOutSample, (IMediaSample_IsDiscontinuity(pSample) == S_OK)); + IMediaSample_SetSyncPoint(pOutSample, (IMediaSample_IsSyncPoint(pSample) == S_OK)); + + if (!validTimeFlags) + IMediaSample_SetTime(pOutSample, NULL, NULL); + else + { + LONGLONG tStart, tStop; + + if (validTimeFlags & kICMValidTime_DisplayTimeStampIsValid) + tStart = displayTime; + else + tStart = 0; + if (validTimeFlags & kICMValidTime_DisplayDurationIsValid) + tStop = tStart + displayDuration; + else + tStop = tStart; + + IMediaSample_SetTime(pOutSample, &tStart, &tStop); + } + + LeaveCriticalSection(&This->tf.filter.csFilter); + hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)This->tf.ppPins[1], pOutSample); + if (hr != S_OK && hr != VFW_E_NOT_CONNECTED) + ERR("Error sending sample (%x)\n", hr); + +error: + if (pOutSample) + IMediaSample_Release(pOutSample); + + This->decodeHR = hr; +} + +static HRESULT WINAPI QTVDecoder_StartStreaming(TransformFilter* pTransformFilter) +{ + QTVDecoderImpl* This = (QTVDecoderImpl*)pTransformFilter; + OSErr err = noErr; + ICMDecompressionSessionOptionsRef sessionOptions = NULL; + ICMDecompressionTrackingCallbackRecord trackingCallbackRecord; + + TRACE("(%p)->()\n", This); + + trackingCallbackRecord.decompressionTrackingCallback = trackingCallback; + trackingCallbackRecord.decompressionTrackingRefCon = (void*)This; + + err = ICMDecompressionSessionCreate(NULL, This->hImageDescription, sessionOptions, This->outputBufferAttributes, &trackingCallbackRecord, &This->decompressionSession); + + if (err != noErr) + { + ERR("Error with ICMDecompressionSessionCreate %i\n",err); + return E_FAIL; + } + + return S_OK; +} + +static HRESULT WINAPI QTVDecoder_Receive(TransformFilter *tf, IMediaSample *pSample) +{ + QTVDecoderImpl* This = (QTVDecoderImpl *)tf; + HRESULT hr; + DWORD cbSrcStream; + LPBYTE pbSrcStream; + + ICMFrameTimeRecord frameTime = {{0}}; + TimeValue time = 1; + TimeScale timeScale = 1; + OSStatus err = noErr; + LONGLONG tStart, tStop; + + EnterCriticalSection(&This->tf.filter.csFilter); + hr = IMediaSample_GetPointer(pSample, &pbSrcStream); + if (FAILED(hr)) + { + ERR("Cannot get pointer to sample data (%x)\n", hr); + goto error; + } + + cbSrcStream = IMediaSample_GetActualDataLength(pSample); + + if (IMediaSample_GetTime(pSample, &tStart, &tStop) != S_OK) + tStart = tStop = 0; + + time = tStart; + + frameTime.recordSize = sizeof(ICMFrameTimeRecord); + *(TimeValue64 *)&frameTime.value = tStart; + frameTime.scale = 1; + frameTime.rate = fixed1; + frameTime.duration = tStop - tStart; + frameTime.frameNumber = 0; + frameTime.flags = icmFrameTimeIsNonScheduledDisplayTime; + + err = ICMDecompressionSessionDecodeFrame(This->decompressionSession, + (UInt8 *)pbSrcStream, cbSrcStream, NULL, &frameTime, pSample); + + if (err != noErr) + { + ERR("Error with ICMDecompressionSessionDecodeFrame\n"); + hr = E_FAIL; + goto error; + } + + ICMDecompressionSessionSetNonScheduledDisplayTime(This->decompressionSession, time, timeScale, 0); + ICMDecompressionSessionFlush(This->decompressionSession); + hr = This->decodeHR; + +error: + LeaveCriticalSection(&This->tf.filter.csFilter); + return hr; +} + +static HRESULT WINAPI QTVDecoder_StopStreaming(TransformFilter* pTransformFilter) +{ + QTVDecoderImpl* This = (QTVDecoderImpl*)pTransformFilter; + + TRACE("(%p)->()\n", This); + + if (This->decompressionSession) + ICMDecompressionSessionRelease(This->decompressionSession); + This->decompressionSession = NULL; + + return S_OK; +} + +static HRESULT WINAPI QTVDecoder_SetMediaType(TransformFilter *tf, PIN_DIRECTION dir, const AM_MEDIA_TYPE * pmt) +{ + QTVDecoderImpl* This = (QTVDecoderImpl*)tf; + HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED; + OSErr err = noErr; + AM_MEDIA_TYPE *outpmt = &This->tf.pmt; + CFNumberRef n = NULL; + + TRACE("(%p)->(%p)\n", This, pmt); + + if (dir != PINDIR_INPUT) + return S_OK; + + FreeMediaType(outpmt); + CopyMediaType(outpmt, pmt); + + if (This->hImageDescription) + DisposeHandle((Handle)This->hImageDescription); + + This->hImageDescription = (ImageDescriptionHandle) + NewHandleClear(sizeof(ImageDescription)); + + if (This->hImageDescription != NULL) + { + (**This->hImageDescription).idSize = sizeof(ImageDescription); + (**This->hImageDescription).spatialQuality = codecNormalQuality; + (**This->hImageDescription).frameCount = 1; + (**This->hImageDescription).clutID = -1; + } + else + { + ERR("Failed to create ImageDescription\n"); + goto failed; + } + + /* Check root (GUID w/o FOURCC) */ + if ((IsEqualIID(&pmt->majortype, &MEDIATYPE_Video)) && + (!memcmp(((const char *)&pmt->subtype)+4, ((const char *)&MEDIATYPE_Video)+4, sizeof(GUID)-4))) + { + VIDEOINFOHEADER *format1 = (VIDEOINFOHEADER *)outpmt->pbFormat; + VIDEOINFOHEADER2 *format2 = (VIDEOINFOHEADER2 *)outpmt->pbFormat; + BITMAPINFOHEADER *bmi; + OSType fourCC; + DecompressorComponent dc; + OSType format; + + if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) + bmi = &format1->bmiHeader; + else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) + bmi = &format2->bmiHeader; + else + goto failed; + + TRACE("Fourcc: %s\n", debugstr_an((const char *)&pmt->subtype.Data1, 4)); + fourCC = ((const char *)&pmt->subtype.Data1)[0] | + (((const char *)&pmt->subtype.Data1)[1]<<8) | + (((const char *)&pmt->subtype.Data1)[2]<<16) | + (((const char *)&pmt->subtype.Data1)[3]<<24); + + err = FindCodec(fourCC,NULL,NULL,&dc); + if (err != noErr || dc == 0x0) + { + TRACE("Codec not found\n"); + goto failed; + } + + This->outputWidth = bmi->biWidth; + This->outputHeight = bmi->biHeight; + + (**This->hImageDescription).cType = fourCC; + (**This->hImageDescription).width = This->outputWidth; + (**This->hImageDescription).height = This->outputHeight; + (**This->hImageDescription).depth = bmi->biBitCount; + (**This->hImageDescription).hRes = 72<<16; + (**This->hImageDescription).vRes = 72<<16; + + if (This->outputBufferAttributes) + CFRelease(This->outputBufferAttributes); + + This->outputBufferAttributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!This->outputBufferAttributes) + { + ERR("Failed to create outputBufferAttributes\n"); + goto failed; + } + + n = CFNumberCreate(NULL, kCFNumberIntType, &This->outputWidth); + CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferWidthKey, n); + CFRelease(n); + + n = CFNumberCreate(NULL, kCFNumberIntType, &This->outputHeight); + CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferHeightKey, n); + CFRelease(n); + + /* yes this looks wrong. but 32ARGB is 24 RGB with an alpha channel */ + format = k32ARGBPixelFormat; + n = CFNumberCreate(NULL, kCFNumberIntType, &format); + CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferPixelFormatTypeKey, n); + CFRelease(n); + + CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferCGBitmapContextCompatibilityKey, kCFBooleanTrue); + CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferCGImageCompatibilityKey, kCFBooleanTrue); + + This->outputDepth = 3; + This->outputSize = This->outputWidth * This->outputHeight * This->outputDepth; + bmi->biCompression = BI_RGB; + bmi->biBitCount = 24; + outpmt->subtype = MEDIASUBTYPE_RGB24; + if (bmi->biHeight > 0) + bmi->biHeight = -bmi->biHeight; + + return S_OK; + } + +failed: + if (This->hImageDescription) + { + DisposeHandle((Handle)This->hImageDescription); + This->hImageDescription = NULL; + } + if (This->outputBufferAttributes) + { + CFRelease(This->outputBufferAttributes); + This->outputBufferAttributes = NULL; + } + + TRACE("Connection refused\n"); + return hr; +} + +static HRESULT WINAPI QTVDecoder_BreakConnect(TransformFilter *tf, PIN_DIRECTION dir) +{ + QTVDecoderImpl *This = (QTVDecoderImpl *)tf; + + TRACE("(%p)->()\n", This); + + if (This->hImageDescription) + DisposeHandle((Handle)This->hImageDescription); + if (This->outputBufferAttributes) + CFRelease(This->outputBufferAttributes); + + This->hImageDescription = NULL; + This->outputBufferAttributes = NULL; + + return S_OK; +} + +static HRESULT WINAPI QTVDecoder_DecideBufferSize(TransformFilter *tf, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) +{ + QTVDecoderImpl *This = (QTVDecoderImpl*)tf; + ALLOCATOR_PROPERTIES actual; + + TRACE("()\n"); + + if (!ppropInputRequest->cbAlign) + ppropInputRequest->cbAlign = 1; + + if (ppropInputRequest->cbBuffer < This->outputSize) + ppropInputRequest->cbBuffer = This->outputSize; + + if (!ppropInputRequest->cBuffers) + ppropInputRequest->cBuffers = 1; + + return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual); +} + +static const TransformFilterFuncTable QTVDecoder_FuncsTable = { + QTVDecoder_DecideBufferSize, + QTVDecoder_StartStreaming, + QTVDecoder_Receive, + QTVDecoder_StopStreaming, + NULL, + QTVDecoder_SetMediaType, + NULL, + QTVDecoder_BreakConnect, + NULL, + NULL, + NULL, + NULL +}; + +IUnknown * CALLBACK QTVDecoder_create(IUnknown * pUnkOuter, HRESULT* phr) +{ + HRESULT hr; + QTVDecoderImpl * This; + + TRACE("(%p, %p)\n", pUnkOuter, phr); + + *phr = S_OK; + + if (pUnkOuter) + { + *phr = CLASS_E_NOAGGREGATION; + return NULL; + } + + hr = TransformFilter_Construct(&QTVDecoder_Vtbl, sizeof(QTVDecoderImpl), &CLSID_QTVDecoder, &QTVDecoder_FuncsTable, (IBaseFilter**)&This); + + if (FAILED(hr)) + { + *phr = hr; + return NULL; + } + else + { + ISeekingPassThru *passthru; + hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)This, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&This->seekthru_unk); + IUnknown_QueryInterface(This->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru); + ISeekingPassThru_Init(passthru, FALSE, (IPin*)This->tf.ppPins[0]); + ISeekingPassThru_Release(passthru); + } + + *phr = hr; + return (IUnknown*)This; +} + +HRESULT WINAPI QTVDecoder_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) +{ + HRESULT hr; + QTVDecoderImpl *This = (QTVDecoderImpl *)iface; + TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv); + + if (IsEqualIID(riid, &IID_IMediaSeeking)) + return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv); + + hr = TransformFilterImpl_QueryInterface(iface, riid, ppv); + + return hr; +} + +static const IBaseFilterVtbl QTVDecoder_Vtbl = +{ + QTVDecoder_QueryInterface, + BaseFilterImpl_AddRef, + TransformFilterImpl_Release, + BaseFilterImpl_GetClassID, + TransformFilterImpl_Stop, + TransformFilterImpl_Pause, + TransformFilterImpl_Run, + BaseFilterImpl_GetState, + BaseFilterImpl_SetSyncSource, + BaseFilterImpl_GetSyncSource, + BaseFilterImpl_EnumPins, + TransformFilterImpl_FindPin, + BaseFilterImpl_QueryFilterInfo, + BaseFilterImpl_JoinFilterGraph, + BaseFilterImpl_QueryVendorInfo +}; diff --git a/dlls/wineqtdecoder/wineqtdecoder.spec b/dlls/wineqtdecoder/wineqtdecoder.spec new file mode 100644 index 00000000000..b16365d0c9f --- /dev/null +++ b/dlls/wineqtdecoder/wineqtdecoder.spec @@ -0,0 +1,4 @@ +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer()