wined3d: Move the resource map count field up to wined3d_resource.
[wine/multimedia.git] / dlls / wineqtdecoder / qtvdecoder.c
blob3dfece837479af04624674951e5ec78b4af1d0ee
1 /*
2 * QuickTime Toolkit decoder filter for video
4 * Copyright 2010 Aric Stewart, CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #define ULONG CoreFoundation_ULONG
24 #define HRESULT CoreFoundation_HRESULT
26 #define LoadResource __carbon_LoadResource
27 #define CompareString __carbon_CompareString
28 #define GetCurrentThread __carbon_GetCurrentThread
29 #define GetCurrentProcess __carbon_GetCurrentProcess
30 #define AnimatePalette __carbon_AnimatePalette
31 #define EqualRgn __carbon_EqualRgn
32 #define FillRgn __carbon_FillRgn
33 #define FrameRgn __carbon_FrameRgn
34 #define GetPixel __carbon_GetPixel
35 #define InvertRgn __carbon_InvertRgn
36 #define LineTo __carbon_LineTo
37 #define OffsetRgn __carbon_OffsetRgn
38 #define PaintRgn __carbon_PaintRgn
39 #define Polygon __carbon_Polygon
40 #define ResizePalette __carbon_ResizePalette
41 #define SetRectRgn __carbon_SetRectRgn
43 #define CheckMenuItem __carbon_CheckMenuItem
44 #define DeleteMenu __carbon_DeleteMenu
45 #define DrawMenuBar __carbon_DrawMenuBar
46 #define EnableMenuItem __carbon_EnableMenuItem
47 #define EqualRect __carbon_EqualRect
48 #define FillRect __carbon_FillRect
49 #define FrameRect __carbon_FrameRect
50 #define GetCursor __carbon_GetCursor
51 #define GetMenu __carbon_GetMenu
52 #define InvertRect __carbon_InvertRect
53 #define IsWindowVisible __carbon_IsWindowVisible
54 #define MoveWindow __carbon_MoveWindow
55 #define OffsetRect __carbon_OffsetRect
56 #define PtInRect __carbon_PtInRect
57 #define SetCursor __carbon_SetCursor
58 #define SetRect __carbon_SetRect
59 #define ShowCursor __carbon_ShowCursor
60 #define ShowWindow __carbon_ShowWindow
61 #define UnionRect __carbon_UnionRect
63 #include <QuickTime/ImageCompression.h>
64 #include <CoreVideo/CVPixelBuffer.h>
66 #undef LoadResource
67 #undef CompareString
68 #undef GetCurrentThread
69 #undef _CDECL
70 #undef DPRINTF
71 #undef GetCurrentProcess
72 #undef AnimatePalette
73 #undef EqualRgn
74 #undef FillRgn
75 #undef FrameRgn
76 #undef GetPixel
77 #undef InvertRgn
78 #undef LineTo
79 #undef OffsetRgn
80 #undef PaintRgn
81 #undef Polygon
82 #undef ResizePalette
83 #undef SetRectRgn
84 #undef CheckMenuItem
85 #undef DeleteMenu
86 #undef DrawMenuBar
87 #undef EnableMenuItem
88 #undef EqualRect
89 #undef FillRect
90 #undef FrameRect
91 #undef GetCursor
92 #undef GetMenu
93 #undef InvertRect
94 #undef IsWindowVisible
95 #undef MoveWindow
96 #undef OffsetRect
97 #undef PtInRect
98 #undef SetCursor
99 #undef SetRect
100 #undef ShowCursor
101 #undef ShowWindow
102 #undef UnionRect
104 #undef ULONG
105 #undef HRESULT
106 #undef DPRINTF
107 #undef STDMETHODCALLTYPE
109 #define COBJMACROS
111 #include "windef.h"
112 #include "winbase.h"
113 #include "wtypes.h"
114 #include "winuser.h"
115 #include "dshow.h"
117 #include "uuids.h"
118 #include "amvideo.h"
119 #include "strmif.h"
120 #include "vfwmsgs.h"
121 #include "vfw.h"
122 #include "dvdmedia.h"
124 #include <assert.h>
126 #include "wine/unicode.h"
127 #include "wine/debug.h"
128 #include "wine/strmbase.h"
130 #include "qtprivate.h"
132 extern CLSID CLSID_QTVDecoder;
134 WINE_DEFAULT_DEBUG_CHANNEL(qtdecoder);
136 typedef struct QTVDecoderImpl
138 TransformFilter tf;
139 IUnknown *seekthru_unk;
141 ImageDescriptionHandle hImageDescription;
142 CFMutableDictionaryRef outputBufferAttributes;
143 ICMDecompressionSessionRef decompressionSession;
144 HRESULT decodeHR;
146 DWORD outputSize;
148 } QTVDecoderImpl;
150 static inline QTVDecoderImpl *impl_from_IBaseFilter( IBaseFilter *iface )
152 return CONTAINING_RECORD(iface, QTVDecoderImpl, tf.filter.IBaseFilter_iface);
155 static inline QTVDecoderImpl *impl_from_TransformFilter( TransformFilter *iface )
157 return CONTAINING_RECORD(iface, QTVDecoderImpl, tf.filter);
160 static const IBaseFilterVtbl QTVDecoder_Vtbl;
162 static void trackingCallback(
163 void *decompressionTrackingRefCon,
164 OSStatus result,
165 ICMDecompressionTrackingFlags decompressionTrackingFlags,
166 CVPixelBufferRef pixelBuffer,
167 TimeValue64 displayTime,
168 TimeValue64 displayDuration,
169 ICMValidTimeFlags validTimeFlags,
170 void *reserved,
171 void *sourceFrameRefCon )
173 QTVDecoderImpl *This = (QTVDecoderImpl*)decompressionTrackingRefCon;
174 IMediaSample *pSample = (IMediaSample*)sourceFrameRefCon;
175 HRESULT hr = S_OK;
176 IMediaSample* pOutSample = NULL;
177 LPBYTE pbDstStream;
178 DWORD cbDstStream;
180 if (result != noErr)
182 ERR("Error from Codec, no frame decompressed\n");
183 return;
186 if (!pixelBuffer)
188 ERR("No pixel buffer, no frame decompressed\n");
189 return;
192 EnterCriticalSection(&This->tf.csReceive);
193 hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->tf.ppPins[1], &pOutSample, NULL, NULL, 0);
194 if (FAILED(hr)) {
195 ERR("Unable to get delivery buffer (%x)\n", hr);
196 goto error;
199 hr = IMediaSample_SetActualDataLength(pOutSample, 0);
200 assert(hr == S_OK);
202 hr = IMediaSample_GetPointer(pOutSample, &pbDstStream);
203 if (FAILED(hr)) {
204 ERR("Unable to get pointer to buffer (%x)\n", hr);
205 goto error;
208 cbDstStream = IMediaSample_GetSize(pOutSample);
209 if (cbDstStream < This->outputSize) {
210 ERR("Sample size is too small %d < %d\n", cbDstStream, This->outputSize);
211 hr = E_FAIL;
212 goto error;
215 hr = AccessPixelBufferPixels(pixelBuffer, pbDstStream);
216 if (FAILED(hr))
217 goto error;
219 IMediaSample_SetActualDataLength(pOutSample, This->outputSize);
221 IMediaSample_SetPreroll(pOutSample, (IMediaSample_IsPreroll(pSample) == S_OK));
222 IMediaSample_SetDiscontinuity(pOutSample, (IMediaSample_IsDiscontinuity(pSample) == S_OK));
223 IMediaSample_SetSyncPoint(pOutSample, (IMediaSample_IsSyncPoint(pSample) == S_OK));
225 if (!validTimeFlags)
226 IMediaSample_SetTime(pOutSample, NULL, NULL);
227 else
229 LONGLONG tStart, tStop;
231 if (validTimeFlags & kICMValidTime_DisplayTimeStampIsValid)
232 tStart = displayTime;
233 else
234 tStart = 0;
235 if (validTimeFlags & kICMValidTime_DisplayDurationIsValid)
236 tStop = tStart + displayDuration;
237 else
238 tStop = tStart;
240 IMediaSample_SetTime(pOutSample, &tStart, &tStop);
243 LeaveCriticalSection(&This->tf.csReceive);
244 hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)This->tf.ppPins[1], pOutSample);
245 EnterCriticalSection(&This->tf.csReceive);
246 if (hr != S_OK && hr != VFW_E_NOT_CONNECTED)
247 ERR("Error sending sample (%x)\n", hr);
249 error:
250 LeaveCriticalSection(&This->tf.csReceive);
251 if (pOutSample)
252 IMediaSample_Release(pOutSample);
254 This->decodeHR = hr;
257 static HRESULT WINAPI QTVDecoder_StartStreaming(TransformFilter* pTransformFilter)
259 QTVDecoderImpl* This = impl_from_TransformFilter(pTransformFilter);
260 OSErr err = noErr;
261 ICMDecompressionSessionOptionsRef sessionOptions = NULL;
262 ICMDecompressionTrackingCallbackRecord trackingCallbackRecord;
264 TRACE("(%p)->()\n", This);
266 trackingCallbackRecord.decompressionTrackingCallback = trackingCallback;
267 trackingCallbackRecord.decompressionTrackingRefCon = (void*)This;
269 err = ICMDecompressionSessionCreate(NULL, This->hImageDescription, sessionOptions, This->outputBufferAttributes, &trackingCallbackRecord, &This->decompressionSession);
271 if (err != noErr)
273 ERR("Error with ICMDecompressionSessionCreate %i\n",err);
274 return E_FAIL;
277 return S_OK;
280 static HRESULT WINAPI QTVDecoder_Receive(TransformFilter *tf, IMediaSample *pSample)
282 QTVDecoderImpl* This = impl_from_TransformFilter(tf);
283 HRESULT hr;
284 DWORD cbSrcStream;
285 LPBYTE pbSrcStream;
287 ICMFrameTimeRecord frameTime = {{0}};
288 TimeValue time = 1;
289 TimeScale timeScale = 1;
290 OSStatus err = noErr;
291 LONGLONG tStart, tStop;
293 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
294 if (FAILED(hr))
296 ERR("Cannot get pointer to sample data (%x)\n", hr);
297 goto error;
300 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
302 if (IMediaSample_GetTime(pSample, &tStart, &tStop) != S_OK)
303 tStart = tStop = 0;
305 time = tStart;
307 frameTime.recordSize = sizeof(ICMFrameTimeRecord);
308 *(TimeValue64 *)&frameTime.value = tStart;
309 frameTime.scale = 1;
310 frameTime.rate = fixed1;
311 frameTime.duration = tStop - tStart;
312 frameTime.frameNumber = 0;
313 frameTime.flags = icmFrameTimeIsNonScheduledDisplayTime;
315 err = ICMDecompressionSessionDecodeFrame(This->decompressionSession,
316 (UInt8 *)pbSrcStream, cbSrcStream, NULL, &frameTime, pSample);
318 if (err != noErr)
320 ERR("Error with ICMDecompressionSessionDecodeFrame\n");
321 hr = E_FAIL;
322 goto error;
325 ICMDecompressionSessionSetNonScheduledDisplayTime(This->decompressionSession, time, timeScale, 0);
326 ICMDecompressionSessionFlush(This->decompressionSession);
327 hr = This->decodeHR;
329 error:
330 return hr;
333 static HRESULT WINAPI QTVDecoder_StopStreaming(TransformFilter* pTransformFilter)
335 QTVDecoderImpl* This = impl_from_TransformFilter(pTransformFilter);
337 TRACE("(%p)->()\n", This);
339 if (This->decompressionSession)
340 ICMDecompressionSessionRelease(This->decompressionSession);
341 This->decompressionSession = NULL;
343 return S_OK;
346 static HRESULT WINAPI QTVDecoder_SetMediaType(TransformFilter *tf, PIN_DIRECTION dir, const AM_MEDIA_TYPE * pmt)
348 QTVDecoderImpl* This = impl_from_TransformFilter(tf);
349 HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED;
350 OSErr err = noErr;
351 AM_MEDIA_TYPE *outpmt = &This->tf.pmt;
352 CFNumberRef n = NULL;
354 TRACE("(%p)->(%p)\n", This, pmt);
356 if (dir != PINDIR_INPUT)
357 return S_OK;
359 FreeMediaType(outpmt);
360 CopyMediaType(outpmt, pmt);
362 if (This->hImageDescription)
363 DisposeHandle((Handle)This->hImageDescription);
365 This->hImageDescription = (ImageDescriptionHandle)
366 NewHandleClear(sizeof(ImageDescription));
368 if (This->hImageDescription != NULL)
370 (**This->hImageDescription).idSize = sizeof(ImageDescription);
371 (**This->hImageDescription).spatialQuality = codecNormalQuality;
372 (**This->hImageDescription).frameCount = 1;
373 (**This->hImageDescription).clutID = -1;
375 else
377 ERR("Failed to create ImageDescription\n");
378 goto failed;
381 /* Check root (GUID w/o FOURCC) */
382 if ((IsEqualIID(&pmt->majortype, &MEDIATYPE_Video)) &&
383 (!memcmp(((const char *)&pmt->subtype)+4, ((const char *)&MEDIATYPE_Video)+4, sizeof(GUID)-4)))
385 VIDEOINFOHEADER *format1 = (VIDEOINFOHEADER *)outpmt->pbFormat;
386 VIDEOINFOHEADER2 *format2 = (VIDEOINFOHEADER2 *)outpmt->pbFormat;
387 BITMAPINFOHEADER *bmi;
388 OSType fourCC;
389 DecompressorComponent dc;
390 OSType format;
391 DWORD outputWidth, outputHeight, outputDepth;
393 if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
394 bmi = &format1->bmiHeader;
395 else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
396 bmi = &format2->bmiHeader;
397 else
398 goto failed;
400 TRACE("Fourcc: %s\n", debugstr_an((const char *)&pmt->subtype.Data1, 4));
401 fourCC = ((const char *)&pmt->subtype.Data1)[3] |
402 (((const char *)&pmt->subtype.Data1)[2]<<8) |
403 (((const char *)&pmt->subtype.Data1)[1]<<16) |
404 (((const char *)&pmt->subtype.Data1)[0]<<24);
406 err = FindCodec(fourCC,NULL,NULL,&dc);
407 if (err != noErr || dc == 0x0)
409 TRACE("Codec not found\n");
410 goto failed;
413 outputWidth = bmi->biWidth;
414 outputHeight = bmi->biHeight;
416 (**This->hImageDescription).cType = fourCC;
417 (**This->hImageDescription).width = outputWidth;
418 (**This->hImageDescription).height = outputHeight;
419 (**This->hImageDescription).depth = bmi->biBitCount;
420 (**This->hImageDescription).hRes = 72<<16;
421 (**This->hImageDescription).vRes = 72<<16;
423 if (This->outputBufferAttributes)
424 CFRelease(This->outputBufferAttributes);
426 This->outputBufferAttributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
427 if (!This->outputBufferAttributes)
429 ERR("Failed to create outputBufferAttributes\n");
430 goto failed;
433 n = CFNumberCreate(NULL, kCFNumberIntType, &outputWidth);
434 CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferWidthKey, n);
435 CFRelease(n);
437 n = CFNumberCreate(NULL, kCFNumberIntType, &outputHeight);
438 CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferHeightKey, n);
439 CFRelease(n);
441 /* yes this looks wrong. but 32ARGB is 24 RGB with an alpha channel */
442 format = k32ARGBPixelFormat;
443 n = CFNumberCreate(NULL, kCFNumberIntType, &format);
444 CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferPixelFormatTypeKey, n);
445 CFRelease(n);
447 CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferCGBitmapContextCompatibilityKey, kCFBooleanTrue);
448 CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferCGImageCompatibilityKey, kCFBooleanTrue);
450 outputDepth = 3;
451 This->outputSize = outputWidth * outputHeight * outputDepth;
452 bmi->biCompression = BI_RGB;
453 bmi->biBitCount = 24;
454 outpmt->subtype = MEDIASUBTYPE_RGB24;
456 return S_OK;
459 failed:
460 if (This->hImageDescription)
462 DisposeHandle((Handle)This->hImageDescription);
463 This->hImageDescription = NULL;
465 if (This->outputBufferAttributes)
467 CFRelease(This->outputBufferAttributes);
468 This->outputBufferAttributes = NULL;
471 TRACE("Connection refused\n");
472 return hr;
475 static HRESULT WINAPI QTVDecoder_BreakConnect(TransformFilter *tf, PIN_DIRECTION dir)
477 QTVDecoderImpl *This = impl_from_TransformFilter(tf);
479 TRACE("(%p)->()\n", This);
481 if (This->hImageDescription)
482 DisposeHandle((Handle)This->hImageDescription);
483 if (This->outputBufferAttributes)
484 CFRelease(This->outputBufferAttributes);
486 This->hImageDescription = NULL;
487 This->outputBufferAttributes = NULL;
489 return S_OK;
492 static HRESULT WINAPI QTVDecoder_DecideBufferSize(TransformFilter *tf, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
494 QTVDecoderImpl *This = impl_from_TransformFilter(tf);
495 ALLOCATOR_PROPERTIES actual;
497 TRACE("()\n");
499 if (!ppropInputRequest->cbAlign)
500 ppropInputRequest->cbAlign = 1;
502 if (ppropInputRequest->cbBuffer < This->outputSize)
503 ppropInputRequest->cbBuffer = This->outputSize + ppropInputRequest->cbAlign;
505 if (!ppropInputRequest->cBuffers)
506 ppropInputRequest->cBuffers = 1;
508 return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual);
511 static const TransformFilterFuncTable QTVDecoder_FuncsTable = {
512 QTVDecoder_DecideBufferSize,
513 QTVDecoder_StartStreaming,
514 QTVDecoder_Receive,
515 QTVDecoder_StopStreaming,
516 NULL,
517 QTVDecoder_SetMediaType,
518 NULL,
519 QTVDecoder_BreakConnect,
520 NULL,
521 NULL,
522 NULL,
523 NULL
526 IUnknown * CALLBACK QTVDecoder_create(IUnknown * pUnkOuter, HRESULT* phr)
528 HRESULT hr;
529 QTVDecoderImpl * This;
531 TRACE("(%p, %p)\n", pUnkOuter, phr);
533 *phr = S_OK;
535 if (pUnkOuter)
537 *phr = CLASS_E_NOAGGREGATION;
538 return NULL;
541 hr = TransformFilter_Construct(&QTVDecoder_Vtbl, sizeof(QTVDecoderImpl), &CLSID_QTVDecoder, &QTVDecoder_FuncsTable, (IBaseFilter**)&This);
543 if (FAILED(hr))
545 *phr = hr;
546 return NULL;
548 else
550 ISeekingPassThru *passthru;
551 hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)This, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&This->seekthru_unk);
552 IUnknown_QueryInterface(This->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
553 ISeekingPassThru_Init(passthru, FALSE, This->tf.ppPins[0]);
554 ISeekingPassThru_Release(passthru);
557 *phr = hr;
558 return (IUnknown*)This;
561 HRESULT WINAPI QTVDecoder_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
563 HRESULT hr;
564 QTVDecoderImpl *This = impl_from_IBaseFilter(iface);
565 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
567 if (IsEqualIID(riid, &IID_IMediaSeeking) || IsEqualIID(riid, &IID_IMediaPosition))
568 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
570 hr = TransformFilterImpl_QueryInterface(iface, riid, ppv);
572 return hr;
575 static const IBaseFilterVtbl QTVDecoder_Vtbl =
577 QTVDecoder_QueryInterface,
578 BaseFilterImpl_AddRef,
579 TransformFilterImpl_Release,
580 BaseFilterImpl_GetClassID,
581 TransformFilterImpl_Stop,
582 TransformFilterImpl_Pause,
583 TransformFilterImpl_Run,
584 BaseFilterImpl_GetState,
585 BaseFilterImpl_SetSyncSource,
586 BaseFilterImpl_GetSyncSource,
587 BaseFilterImpl_EnumPins,
588 TransformFilterImpl_FindPin,
589 BaseFilterImpl_QueryFilterInfo,
590 BaseFilterImpl_JoinFilterGraph,
591 BaseFilterImpl_QueryVendorInfo