msvcr: Fix the event_wait() spec entries.
[wine.git] / dlls / wineqtdecoder / qtvdecoder.c
blob4e8278b773fb71446ae26dd3abfc20a97b7af4ca
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 GetCurrentProcess
71 #undef AnimatePalette
72 #undef EqualRgn
73 #undef FillRgn
74 #undef FrameRgn
75 #undef GetPixel
76 #undef InvertRgn
77 #undef LineTo
78 #undef OffsetRgn
79 #undef PaintRgn
80 #undef Polygon
81 #undef ResizePalette
82 #undef SetRectRgn
83 #undef CheckMenuItem
84 #undef DeleteMenu
85 #undef DrawMenuBar
86 #undef EnableMenuItem
87 #undef EqualRect
88 #undef FillRect
89 #undef FrameRect
90 #undef GetCursor
91 #undef GetMenu
92 #undef InvertRect
93 #undef IsWindowVisible
94 #undef MoveWindow
95 #undef OffsetRect
96 #undef PtInRect
97 #undef SetCursor
98 #undef SetRect
99 #undef ShowCursor
100 #undef ShowWindow
101 #undef UnionRect
103 #undef ULONG
104 #undef HRESULT
105 #undef STDMETHODCALLTYPE
107 #define COBJMACROS
109 #include "windef.h"
110 #include "winbase.h"
111 #include "wtypes.h"
112 #include "winuser.h"
113 #include "dshow.h"
115 #include "uuids.h"
116 #include "amvideo.h"
117 #include "strmif.h"
118 #include "vfwmsgs.h"
119 #include "vfw.h"
120 #include "dvdmedia.h"
122 #include <assert.h>
124 #include "wine/unicode.h"
125 #include "wine/debug.h"
126 #include "wine/strmbase.h"
128 #include "qtprivate.h"
130 extern CLSID CLSID_QTVDecoder;
132 WINE_DEFAULT_DEBUG_CHANNEL(qtdecoder);
134 typedef struct QTVDecoderImpl
136 TransformFilter tf;
138 ImageDescriptionHandle hImageDescription;
139 CFMutableDictionaryRef outputBufferAttributes;
140 ICMDecompressionSessionRef decompressionSession;
141 HRESULT decodeHR;
143 DWORD outputSize;
145 } QTVDecoderImpl;
147 static inline QTVDecoderImpl *impl_from_IBaseFilter( IBaseFilter *iface )
149 return CONTAINING_RECORD(iface, QTVDecoderImpl, tf.filter.IBaseFilter_iface);
152 static inline QTVDecoderImpl *impl_from_TransformFilter( TransformFilter *iface )
154 return CONTAINING_RECORD(iface, QTVDecoderImpl, tf.filter);
157 static void trackingCallback(
158 void *decompressionTrackingRefCon,
159 OSStatus result,
160 ICMDecompressionTrackingFlags decompressionTrackingFlags,
161 CVPixelBufferRef pixelBuffer,
162 TimeValue64 displayTime,
163 TimeValue64 displayDuration,
164 ICMValidTimeFlags validTimeFlags,
165 void *reserved,
166 void *sourceFrameRefCon )
168 QTVDecoderImpl *This = (QTVDecoderImpl*)decompressionTrackingRefCon;
169 IMediaSample *pSample = (IMediaSample*)sourceFrameRefCon;
170 HRESULT hr = S_OK;
171 IMediaSample* pOutSample = NULL;
172 LPBYTE pbDstStream;
173 DWORD cbDstStream;
175 if (result != noErr)
177 ERR("Error from Codec, no frame decompressed\n");
178 return;
181 if (!pixelBuffer)
183 ERR("No pixel buffer, no frame decompressed\n");
184 return;
187 EnterCriticalSection(&This->tf.csReceive);
188 hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->tf.ppPins[1], &pOutSample, NULL, NULL, 0);
189 if (FAILED(hr)) {
190 ERR("Unable to get delivery buffer (%x)\n", hr);
191 goto error;
194 hr = IMediaSample_SetActualDataLength(pOutSample, 0);
195 assert(hr == S_OK);
197 hr = IMediaSample_GetPointer(pOutSample, &pbDstStream);
198 if (FAILED(hr)) {
199 ERR("Unable to get pointer to buffer (%x)\n", hr);
200 goto error;
203 cbDstStream = IMediaSample_GetSize(pOutSample);
204 if (cbDstStream < This->outputSize) {
205 ERR("Sample size is too small %d < %d\n", cbDstStream, This->outputSize);
206 hr = E_FAIL;
207 goto error;
210 hr = AccessPixelBufferPixels(pixelBuffer, pbDstStream);
211 if (FAILED(hr))
212 goto error;
214 IMediaSample_SetActualDataLength(pOutSample, This->outputSize);
216 IMediaSample_SetPreroll(pOutSample, (IMediaSample_IsPreroll(pSample) == S_OK));
217 IMediaSample_SetDiscontinuity(pOutSample, (IMediaSample_IsDiscontinuity(pSample) == S_OK));
218 IMediaSample_SetSyncPoint(pOutSample, (IMediaSample_IsSyncPoint(pSample) == S_OK));
220 if (!validTimeFlags)
221 IMediaSample_SetTime(pOutSample, NULL, NULL);
222 else
224 LONGLONG tStart, tStop;
226 if (validTimeFlags & kICMValidTime_DisplayTimeStampIsValid)
227 tStart = displayTime;
228 else
229 tStart = 0;
230 if (validTimeFlags & kICMValidTime_DisplayDurationIsValid)
231 tStop = tStart + displayDuration;
232 else
233 tStop = tStart;
235 IMediaSample_SetTime(pOutSample, &tStart, &tStop);
238 LeaveCriticalSection(&This->tf.csReceive);
239 hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)This->tf.ppPins[1], pOutSample);
240 EnterCriticalSection(&This->tf.csReceive);
241 if (hr != S_OK && hr != VFW_E_NOT_CONNECTED)
242 ERR("Error sending sample (%x)\n", hr);
244 error:
245 LeaveCriticalSection(&This->tf.csReceive);
246 if (pOutSample)
247 IMediaSample_Release(pOutSample);
249 This->decodeHR = hr;
252 static HRESULT WINAPI QTVDecoder_StartStreaming(TransformFilter* pTransformFilter)
254 QTVDecoderImpl* This = impl_from_TransformFilter(pTransformFilter);
255 OSErr err = noErr;
256 ICMDecompressionSessionOptionsRef sessionOptions = NULL;
257 ICMDecompressionTrackingCallbackRecord trackingCallbackRecord;
259 TRACE("(%p)->()\n", This);
261 trackingCallbackRecord.decompressionTrackingCallback = trackingCallback;
262 trackingCallbackRecord.decompressionTrackingRefCon = (void*)This;
264 err = ICMDecompressionSessionCreate(NULL, This->hImageDescription, sessionOptions, This->outputBufferAttributes, &trackingCallbackRecord, &This->decompressionSession);
266 if (err != noErr)
268 ERR("Error with ICMDecompressionSessionCreate %i\n",err);
269 return E_FAIL;
272 return S_OK;
275 static HRESULT WINAPI QTVDecoder_Receive(TransformFilter *tf, IMediaSample *pSample)
277 QTVDecoderImpl* This = impl_from_TransformFilter(tf);
278 HRESULT hr;
279 DWORD cbSrcStream;
280 LPBYTE pbSrcStream;
282 ICMFrameTimeRecord frameTime = {{0}};
283 TimeValue time = 1;
284 TimeScale timeScale = 1;
285 OSStatus err = noErr;
286 LONGLONG tStart, tStop;
288 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
289 if (FAILED(hr))
291 ERR("Cannot get pointer to sample data (%x)\n", hr);
292 goto error;
295 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
297 if (IMediaSample_GetTime(pSample, &tStart, &tStop) != S_OK)
298 tStart = tStop = 0;
300 time = tStart;
302 frameTime.recordSize = sizeof(ICMFrameTimeRecord);
303 *(TimeValue64 *)&frameTime.value = tStart;
304 frameTime.scale = 1;
305 frameTime.rate = fixed1;
306 frameTime.duration = tStop - tStart;
307 frameTime.frameNumber = 0;
308 frameTime.flags = icmFrameTimeIsNonScheduledDisplayTime;
310 err = ICMDecompressionSessionDecodeFrame(This->decompressionSession,
311 (UInt8 *)pbSrcStream, cbSrcStream, NULL, &frameTime, pSample);
313 if (err != noErr)
315 ERR("Error with ICMDecompressionSessionDecodeFrame\n");
316 hr = E_FAIL;
317 goto error;
320 ICMDecompressionSessionSetNonScheduledDisplayTime(This->decompressionSession, time, timeScale, 0);
321 ICMDecompressionSessionFlush(This->decompressionSession);
322 hr = This->decodeHR;
324 error:
325 return hr;
328 static HRESULT WINAPI QTVDecoder_StopStreaming(TransformFilter* pTransformFilter)
330 QTVDecoderImpl* This = impl_from_TransformFilter(pTransformFilter);
332 TRACE("(%p)->()\n", This);
334 if (This->decompressionSession)
335 ICMDecompressionSessionRelease(This->decompressionSession);
336 This->decompressionSession = NULL;
338 return S_OK;
341 static HRESULT WINAPI QTVDecoder_SetMediaType(TransformFilter *tf, PIN_DIRECTION dir, const AM_MEDIA_TYPE * pmt)
343 QTVDecoderImpl* This = impl_from_TransformFilter(tf);
344 HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED;
345 OSErr err = noErr;
346 AM_MEDIA_TYPE *outpmt = &This->tf.pmt;
347 CFNumberRef n = NULL;
349 TRACE("(%p)->(%p)\n", This, pmt);
351 if (dir != PINDIR_INPUT)
352 return S_OK;
354 FreeMediaType(outpmt);
355 CopyMediaType(outpmt, pmt);
357 if (This->hImageDescription)
358 DisposeHandle((Handle)This->hImageDescription);
360 This->hImageDescription = (ImageDescriptionHandle)
361 NewHandleClear(sizeof(ImageDescription));
363 if (This->hImageDescription != NULL)
365 (**This->hImageDescription).idSize = sizeof(ImageDescription);
366 (**This->hImageDescription).spatialQuality = codecNormalQuality;
367 (**This->hImageDescription).frameCount = 1;
368 (**This->hImageDescription).clutID = -1;
370 else
372 ERR("Failed to create ImageDescription\n");
373 goto failed;
376 /* Check root (GUID w/o FOURCC) */
377 if ((IsEqualIID(&pmt->majortype, &MEDIATYPE_Video)) &&
378 (!memcmp(((const char *)&pmt->subtype)+4, ((const char *)&MEDIATYPE_Video)+4, sizeof(GUID)-4)))
380 VIDEOINFOHEADER *format1 = (VIDEOINFOHEADER *)outpmt->pbFormat;
381 VIDEOINFOHEADER2 *format2 = (VIDEOINFOHEADER2 *)outpmt->pbFormat;
382 BITMAPINFOHEADER *bmi;
383 OSType fourCC;
384 DecompressorComponent dc;
385 OSType format;
386 DWORD outputWidth, outputHeight, outputDepth;
388 if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
389 bmi = &format1->bmiHeader;
390 else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
391 bmi = &format2->bmiHeader;
392 else
393 goto failed;
395 TRACE("Fourcc: %s\n", debugstr_an((const char *)&pmt->subtype.Data1, 4));
396 fourCC = ((const char *)&pmt->subtype.Data1)[3] |
397 (((const char *)&pmt->subtype.Data1)[2]<<8) |
398 (((const char *)&pmt->subtype.Data1)[1]<<16) |
399 (((const char *)&pmt->subtype.Data1)[0]<<24);
401 err = FindCodec(fourCC,NULL,NULL,&dc);
402 if (err != noErr || dc == 0x0)
404 TRACE("Codec not found\n");
405 goto failed;
408 outputWidth = bmi->biWidth;
409 outputHeight = bmi->biHeight;
411 (**This->hImageDescription).cType = fourCC;
412 (**This->hImageDescription).width = outputWidth;
413 (**This->hImageDescription).height = outputHeight;
414 (**This->hImageDescription).depth = bmi->biBitCount;
415 (**This->hImageDescription).hRes = 72<<16;
416 (**This->hImageDescription).vRes = 72<<16;
418 if (This->outputBufferAttributes)
419 CFRelease(This->outputBufferAttributes);
421 This->outputBufferAttributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
422 if (!This->outputBufferAttributes)
424 ERR("Failed to create outputBufferAttributes\n");
425 goto failed;
428 n = CFNumberCreate(NULL, kCFNumberIntType, &outputWidth);
429 CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferWidthKey, n);
430 CFRelease(n);
432 n = CFNumberCreate(NULL, kCFNumberIntType, &outputHeight);
433 CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferHeightKey, n);
434 CFRelease(n);
436 /* yes this looks wrong. but 32ARGB is 24 RGB with an alpha channel */
437 format = k32ARGBPixelFormat;
438 n = CFNumberCreate(NULL, kCFNumberIntType, &format);
439 CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferPixelFormatTypeKey, n);
440 CFRelease(n);
442 CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferCGBitmapContextCompatibilityKey, kCFBooleanTrue);
443 CFDictionaryAddValue(This->outputBufferAttributes, kCVPixelBufferCGImageCompatibilityKey, kCFBooleanTrue);
445 outputDepth = 3;
446 This->outputSize = outputWidth * outputHeight * outputDepth;
447 bmi->biCompression = BI_RGB;
448 bmi->biBitCount = 24;
449 outpmt->subtype = MEDIASUBTYPE_RGB24;
451 return S_OK;
454 failed:
455 if (This->hImageDescription)
457 DisposeHandle((Handle)This->hImageDescription);
458 This->hImageDescription = NULL;
460 if (This->outputBufferAttributes)
462 CFRelease(This->outputBufferAttributes);
463 This->outputBufferAttributes = NULL;
466 TRACE("Connection refused\n");
467 return hr;
470 static HRESULT WINAPI QTVDecoder_BreakConnect(TransformFilter *tf, PIN_DIRECTION dir)
472 QTVDecoderImpl *This = impl_from_TransformFilter(tf);
474 TRACE("(%p)->()\n", This);
476 if (This->hImageDescription)
477 DisposeHandle((Handle)This->hImageDescription);
478 if (This->outputBufferAttributes)
479 CFRelease(This->outputBufferAttributes);
481 This->hImageDescription = NULL;
482 This->outputBufferAttributes = NULL;
484 return S_OK;
487 static HRESULT WINAPI QTVDecoder_DecideBufferSize(TransformFilter *tf, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
489 QTVDecoderImpl *This = impl_from_TransformFilter(tf);
490 ALLOCATOR_PROPERTIES actual;
492 TRACE("()\n");
494 if (!ppropInputRequest->cbAlign)
495 ppropInputRequest->cbAlign = 1;
497 if (ppropInputRequest->cbBuffer < This->outputSize)
498 ppropInputRequest->cbBuffer = This->outputSize + ppropInputRequest->cbAlign;
500 if (!ppropInputRequest->cBuffers)
501 ppropInputRequest->cBuffers = 1;
503 return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual);
506 static const TransformFilterFuncTable QTVDecoder_FuncsTable = {
507 QTVDecoder_DecideBufferSize,
508 QTVDecoder_StartStreaming,
509 QTVDecoder_Receive,
510 QTVDecoder_StopStreaming,
511 NULL,
512 QTVDecoder_SetMediaType,
513 NULL,
514 QTVDecoder_BreakConnect,
515 NULL,
516 NULL,
517 NULL,
518 NULL
521 IUnknown * CALLBACK QTVDecoder_create(IUnknown * pUnkOuter, HRESULT* phr)
523 HRESULT hr;
524 QTVDecoderImpl * This;
526 TRACE("(%p, %p)\n", pUnkOuter, phr);
528 *phr = S_OK;
530 if (pUnkOuter)
532 *phr = CLASS_E_NOAGGREGATION;
533 return NULL;
536 hr = TransformFilter_Construct(sizeof(QTVDecoderImpl), &CLSID_QTVDecoder,
537 &QTVDecoder_FuncsTable, (IBaseFilter **)&This);
539 if (FAILED(hr))
541 *phr = hr;
542 return NULL;
545 *phr = hr;
546 return (IUnknown*)This;