Handle a number as a parameter for custom action 19.
[wine] / dlls / quartz / avidec.c
1 /*
2  * AVI Decompressor (VFW decompressors wrapper)
3  *
4  * Copyright 2004-2005 Christian Costa
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "quartz_private.h"
24 #include "control_private.h"
25 #include "pin.h"
26
27 #include "uuids.h"
28 #include "aviriff.h"
29 #include "mmreg.h"
30 #include "vfwmsgs.h"
31 #include "amvideo.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "dshow.h"
35 #include "strmif.h"
36 #include "vfwmsgs.h"
37 #include "evcode.h"
38 #include "vfw.h"
39
40 #include <assert.h>
41
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
44
45 #include "transform.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
48
49 typedef struct AVIDecImpl
50 {
51     TransformFilterImpl tf;
52     HIC hvid;
53     BITMAPINFOHEADER* pBihIn;
54     BITMAPINFOHEADER* pBihOut;
55 } AVIDecImpl;
56
57 static DWORD AVIDec_SendSampleData(TransformFilterImpl* pTransformFilter, LPBYTE data, DWORD size)
58 {
59     AVIDecImpl* This = (AVIDecImpl*)pTransformFilter;
60     VIDEOINFOHEADER* format;
61     AM_MEDIA_TYPE amt;
62     HRESULT hr;
63     DWORD res;
64     IMediaSample* pSample = NULL;
65     DWORD cbDstStream;
66     LPBYTE pbDstStream;
67
68     TRACE("(%p)->(%p,%ld)\n", This, data, size);
69     
70     hr = IPin_ConnectionMediaType(This->tf.ppPins[0], &amt);
71     if (FAILED(hr)) {
72         ERR("Unable to retrieve media type\n");
73         goto error;
74     }
75     format = (VIDEOINFOHEADER*)amt.pbFormat;
76
77     /* Update input size to match sample size */
78     This->pBihIn->biSizeImage = size;
79
80     hr = OutputPin_GetDeliveryBuffer((OutputPin*)This->tf.ppPins[1], &pSample, NULL, NULL, 0);
81     if (FAILED(hr)) {
82         ERR("Unable to get delivery buffer (%lx)\n", hr);
83         goto error;
84     }
85
86     hr = IMediaSample_SetActualDataLength(pSample, 0);
87     assert(hr == S_OK);
88
89     hr = IMediaSample_GetPointer(pSample, &pbDstStream);
90     if (FAILED(hr)) {
91         ERR("Unable to get pointer to buffer (%lx)\n", hr);
92         goto error;
93     }
94     cbDstStream = IMediaSample_GetSize(pSample);
95     if (cbDstStream < This->pBihOut->biSizeImage) {
96         ERR("Sample size is too small %ld < %ld\n", cbDstStream, This->pBihOut->biSizeImage);
97         hr = E_FAIL;
98         goto error;
99     }
100
101     res = ICDecompress(This->hvid, 0, This->pBihIn, data, This->pBihOut, pbDstStream);
102     if (res != ICERR_OK)
103         ERR("Error occurred during the decompression (%lx)\n", res);
104
105     hr = OutputPin_SendSample((OutputPin*)This->tf.ppPins[1], pSample);
106     if (hr != S_OK && hr != VFW_E_NOT_CONNECTED) {
107         ERR("Error sending sample (%lx)\n", hr);
108         goto error;
109     }
110
111 error:
112     if (pSample)
113         IMediaSample_Release(pSample);
114
115     return hr;
116 }
117
118 static HRESULT AVIDec_ConnectInput(TransformFilterImpl* pTransformFilter, const AM_MEDIA_TYPE * pmt)
119 {
120     AVIDecImpl* This = (AVIDecImpl*)pTransformFilter;
121
122     TRACE("(%p)->(%p)\n", This, pmt);
123
124     if ((IsEqualIID(&pmt->majortype, &MEDIATYPE_Video)) &&
125         (!memcmp(((char*)&pmt->subtype)+4, ((char*)&MEDIATYPE_Video)+4, sizeof(GUID)-4)) && /* Check root (GUID w/o FOURCC) */
126         (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)))
127     {
128         HIC drv;
129         VIDEOINFOHEADER* format = (VIDEOINFOHEADER*)pmt->pbFormat;
130
131         drv = ICLocate(pmt->majortype.Data1, pmt->subtype.Data1, &format->bmiHeader, NULL, ICMODE_DECOMPRESS);
132         if (drv)
133         {
134             AM_MEDIA_TYPE* outpmt = &((OutputPin*)This->tf.ppPins[1])->pin.mtCurrent;
135             const CLSID* outsubtype;
136             DWORD bih_size;
137
138             switch(format->bmiHeader.biBitCount)
139             {
140                 case 32: outsubtype = &MEDIASUBTYPE_RGB32; break;
141                 case 24: outsubtype = &MEDIASUBTYPE_RGB24; break;
142                 case 16: outsubtype = &MEDIASUBTYPE_RGB565; break;
143                 case 8:  outsubtype = &MEDIASUBTYPE_RGB8; break;
144                 default:
145                     FIXME("Depth %d not supported\n", format->bmiHeader.biBitCount);
146                     ICClose(drv);
147                     return S_FALSE;
148             }
149             CopyMediaType(outpmt, pmt);
150             outpmt->subtype = *outsubtype;
151             This->hvid = drv;
152
153             /* Copy bitmap header from media type to 1 for input and 1 for output */
154             if (This->pBihIn) {
155                 CoTaskMemFree(This->pBihIn);
156                 CoTaskMemFree(This->pBihOut);
157             }
158             bih_size = format->bmiHeader.biSize + format->bmiHeader.biClrUsed * 4;
159             This->pBihIn = (BITMAPINFOHEADER*)CoTaskMemAlloc(bih_size);
160             if (!This->pBihIn)
161             {
162                 ICClose(drv);
163                 return E_OUTOFMEMORY;
164             }
165             This->pBihOut = (BITMAPINFOHEADER*)CoTaskMemAlloc(bih_size);
166             if (!This->pBihOut)
167             {
168                 CoTaskMemFree(This->pBihIn);
169                 This->pBihIn = NULL;
170                 ICClose(drv);
171                 return E_OUTOFMEMORY;
172             }
173             memcpy(This->pBihIn, &format->bmiHeader, bih_size);
174             memcpy(This->pBihOut, &format->bmiHeader, bih_size);
175
176             /* Update output format as non compressed bitmap */
177             This->pBihOut->biCompression = 0;
178             This->pBihOut->biSizeImage = This->pBihOut->biWidth * This->pBihOut->biHeight * This->pBihOut->biBitCount / 8;
179
180             /* Update buffer size of media samples in output */
181             ((OutputPin*)This->tf.ppPins[1])->allocProps.cbBuffer = This->pBihOut->biSizeImage;
182
183             TRACE("Connection accepted\n");
184             return S_OK;
185         }
186         TRACE("Unable to find a suitable VFW decompressor\n");
187     }
188
189     TRACE("Connection refused\n");
190     return S_FALSE;
191 }
192
193 static HRESULT AVIDec_Cleanup(TransformFilterImpl* pTransformFilter)
194 {
195     AVIDecImpl* This = (AVIDecImpl*)pTransformFilter;
196
197     TRACE("(%p)->()\n", This);
198     
199     if (This->hvid)
200         ICClose(This->hvid);
201
202     if (This->pBihIn) {
203         CoTaskMemFree(This->pBihIn);
204         CoTaskMemFree(This->pBihOut);
205     }
206
207     This->hvid = NULL;
208     This->pBihIn = NULL;
209
210     return S_OK;
211 }
212
213 HRESULT AVIDec_create(IUnknown * pUnkOuter, LPVOID * ppv)
214 {
215     HRESULT hr;
216     AVIDecImpl * This;
217
218     TRACE("(%p, %p)\n", pUnkOuter, ppv);
219
220     *ppv = NULL;
221
222     if (pUnkOuter)
223         return CLASS_E_NOAGGREGATION;
224
225     /* Note: This memory is managed by the transform filter once created */
226     This = CoTaskMemAlloc(sizeof(AVIDecImpl));
227
228     This->hvid = NULL;
229     This->pBihIn = NULL;
230
231     hr = TransformFilter_Create(&(This->tf), &CLSID_AVIDec, AVIDec_SendSampleData, AVIDec_ConnectInput, AVIDec_Cleanup);
232
233     if (FAILED(hr))
234         return hr;
235
236     *ppv = (LPVOID)This;
237
238     return hr;
239 }