Added mappings for a few messages.
[wine] / dlls / avifil32 / igframe.c
1 /*
2  * Copyright 2001 Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
3  *
4  * FIXME - implements color space(depth) converter.
5  */
6
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10
11 #include "winbase.h"
12 #include "winnls.h"
13 #include "mmsystem.h"
14 #include "winerror.h"
15 #include "vfw.h"
16 #include "debugtools.h"
17 #include "avifile_private.h"
18
19 DEFAULT_DEBUG_CHANNEL(avifile);
20
21 static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame* iface,REFIID refiid,LPVOID *obj);
22 static ULONG WINAPI IGetFrame_fnAddRef(IGetFrame* iface);
23 static ULONG WINAPI IGetFrame_fnRelease(IGetFrame* iface);
24 static LPVOID WINAPI IGetFrame_fnGetFrame(IGetFrame* iface,LONG lPos);
25 static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame* iface,LONG lStart,LONG lEnd,LONG lRate);
26 static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame* iface);
27 static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame* iface,LPBITMAPINFOHEADER lpbi,LPVOID lpBits,INT x,INT y,INT dx,INT dy);
28
29 struct ICOM_VTABLE(IGetFrame) igetfrm = {
30     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
31         IGetFrame_fnQueryInterface,
32         IGetFrame_fnAddRef,
33         IGetFrame_fnRelease,
34         IGetFrame_fnGetFrame,
35         IGetFrame_fnBegin,
36         IGetFrame_fnEnd,
37         IGetFrame_fnSetFormat,
38 };
39
40 typedef struct IGetFrameImpl
41 {
42         ICOM_VFIELD(IGetFrame);
43         /* IUnknown stuff */
44         DWORD                   ref;
45         /* IGetFrame stuff */
46         IAVIStream*             pas;
47         HIC                     hIC;
48         LONG                    lCachedFrame;
49         BITMAPINFO*             pbiICIn;
50         BITMAPINFO*             pbiICOut;
51         LPVOID                  pvICOutBits;
52         LPVOID                  pvICInFmtBuf;
53         DWORD                   dwICInDataBufSize;
54         LPVOID                  pvICInDataBuf;
55         LPVOID                  pvICOutBuf;
56 } IGetFrameImpl;
57
58 static HRESULT IGetFrame_Construct( IGetFrameImpl* This,
59                                     IAVIStream* pstr,
60                                     LPBITMAPINFOHEADER lpbi );
61 static void IGetFrame_Destruct( IGetFrameImpl* This );
62
63
64
65
66 static LPVOID AVIFILE_IGetFrame_DecodeFrame(IGetFrameImpl* This,LONG lPos)
67 {
68         HRESULT hr;
69         DWORD   dwRes;
70         LONG    lFrameLength;
71         LONG    lSampleCount;
72         ICDECOMPRESS    icd;
73
74         if ( This->hIC == (HIC)NULL )
75                 return NULL;
76
77         hr = IAVIStream_Read(This->pas,lPos,1,NULL,0,
78                              &lFrameLength,&lSampleCount);
79         if ( hr != S_OK || lSampleCount <= 0 )
80         {
81                 FIXME( "IAVIStream_Read failed! res = %08lx\n", hr );
82                 return NULL;
83         }
84         TRACE( "frame length = %ld\n", lFrameLength );
85
86         if ( This->dwICInDataBufSize < lFrameLength )
87         {
88                 LPVOID  lpv;
89
90                 if ( This->pvICInDataBuf == NULL )
91                 {
92                         lpv = HeapAlloc(
93                                 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
94                                 lFrameLength );
95                 }
96                 else
97                 {
98                         lpv = HeapReAlloc(
99                                 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
100                                 This->pvICInDataBuf,lFrameLength );
101                 }
102                 if ( lpv == NULL )
103                 {
104                         ERR( "out of memory!\n" );
105                         return NULL;
106                 }
107                 This->pvICInDataBuf = lpv;
108                 This->dwICInDataBufSize = lFrameLength;
109         }
110
111         hr = IAVIStream_Read(This->pas,lPos,1,
112                              This->pvICInDataBuf,This->dwICInDataBufSize,
113                              &lFrameLength,&lSampleCount);
114         if ( hr != S_OK || lSampleCount <= 0 )
115         {
116                 FIXME( "IAVIStream_Read to buffer failed! res = %08lx\n", hr );
117                 return NULL;
118         }
119
120         This->pbiICIn->bmiHeader.biSizeImage = lFrameLength;
121
122         TRACE( "call ICM_DECOMPRESS\n" );
123         icd.dwFlags = (*(BYTE*)This->pvICInDataBuf) == 'c' ?
124                                       ICDECOMPRESS_NOTKEYFRAME : 0;
125         icd.lpbiInput = &This->pbiICIn->bmiHeader;
126         icd.lpInput = (BYTE*)This->pvICInDataBuf + 8;
127         icd.lpbiOutput = &This->pbiICOut->bmiHeader;
128         icd.lpOutput = This->pvICOutBits;
129         icd.ckid = *((DWORD*)This->pvICInDataBuf);
130         dwRes = ICSendMessage(This->hIC,ICM_DECOMPRESS,
131                               (DWORD)(&icd),sizeof(ICDECOMPRESS) );
132         TRACE( "returned from ICM_DECOMPRESS\n" );
133         if ( dwRes != ICERR_OK )
134         {
135                 ERR( "ICDecompress failed!\n" );
136                 return NULL;
137         }
138
139         This->lCachedFrame = lPos;
140
141         return This->pvICOutBits;
142 }
143
144 /****************************************************************************/
145
146 HRESULT AVIFILE_CreateIGetFrame(void** ppobj,
147                                 IAVIStream* pstr,LPBITMAPINFOHEADER lpbi)
148 {
149         IGetFrameImpl   *This;
150         HRESULT         hr;
151
152         *ppobj = NULL;
153         This = (IGetFrameImpl*)HeapAlloc(AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
154                                           sizeof(IGetFrameImpl));
155         This->ref = 1;
156         ICOM_VTBL(This) = &igetfrm;
157         hr = IGetFrame_Construct( This, pstr, lpbi );
158         if ( hr != S_OK )
159         {
160                 IGetFrame_Destruct( This );
161                 return hr;
162         }
163
164         *ppobj = (LPVOID)This;
165
166         return S_OK;
167 }
168
169 /****************************************************************************
170  * IUnknown interface
171  */
172
173 static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame* iface,REFIID refiid,LPVOID *obj)
174 {
175         ICOM_THIS(IGetFrameImpl,iface);
176
177         TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj);
178         if ( IsEqualGUID(&IID_IUnknown,refiid) ||
179              IsEqualGUID(&IID_IGetFrame,refiid) )
180         {
181                 IGetFrame_AddRef(iface);
182                 *obj = iface;
183                 return S_OK;
184         }
185
186         return OLE_E_ENUM_NOMORE;
187 }
188
189 static ULONG WINAPI IGetFrame_fnAddRef(IGetFrame* iface)
190 {
191         ICOM_THIS(IGetFrameImpl,iface);
192
193         TRACE("(%p)->AddRef()\n",iface);
194         return ++(This->ref);
195 }
196
197 static ULONG WINAPI IGetFrame_fnRelease(IGetFrame* iface)
198 {
199         ICOM_THIS(IGetFrameImpl,iface);
200
201         TRACE("(%p)->Release()\n",iface);
202         if ((--(This->ref)) > 0 )
203                 return This->ref;
204         IGetFrame_Destruct(This);
205         if ( This->pas != NULL )
206                 IAVIStream_Release( This->pas );
207
208         HeapFree(AVIFILE_data.hHeap,0,iface);
209         return 0;
210 }
211
212 /****************************************************************************
213  * IGetFrrame interface
214  */
215
216 static LPVOID WINAPI IGetFrame_fnGetFrame(IGetFrame* iface,LONG lPos)
217 {
218         ICOM_THIS(IGetFrameImpl,iface);
219         LPVOID  lpv;
220         LONG    lKeyFrame;
221
222         TRACE( "(%p)->(%ld)\n", This, lPos );
223
224         if ( lPos < 0 )
225                 return NULL;
226
227         if ( This->lCachedFrame == lPos )
228                 return This->pvICOutBits;
229         if ( (This->lCachedFrame+1) != lPos )
230         {
231                 lKeyFrame = IAVIStream_FindSample( This->pas, lPos,
232                                                    FIND_KEY | FIND_PREV );
233                 if ( lKeyFrame < 0 || lKeyFrame > lPos )
234                         return NULL;
235                 while ( ++lKeyFrame < lPos )
236                 {
237                         lpv = AVIFILE_IGetFrame_DecodeFrame(This, lKeyFrame);
238                         if ( lpv == NULL )
239                                 return NULL;
240                 }
241         }
242
243         lpv = AVIFILE_IGetFrame_DecodeFrame(This, lPos);
244         TRACE( "lpv = %p\n",lpv );
245         if ( lpv == NULL )
246                 return NULL;
247
248         return lpv;
249 }
250
251 static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame* iface,LONG lStart,LONG lEnd,LONG lRate)
252 {
253         ICOM_THIS(IGetFrameImpl,iface);
254
255         TRACE( "(%p)->(%ld,%ld,%ld)\n", This, lStart, lEnd, lRate );
256
257         if ( This->hIC == (HIC)NULL )
258                 return E_UNEXPECTED;
259
260         if ( ICDecompressBegin( This->hIC,
261                                 This->pbiICIn,
262                                 This->pbiICOut ) != ICERR_OK )
263                 return E_FAIL;
264
265         return S_OK;
266 }
267
268 static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame* iface)
269 {
270         ICOM_THIS(IGetFrameImpl,iface);
271
272         TRACE( "(%p)->()\n", This );
273
274         if ( This->hIC == (HIC)NULL )
275                 return E_UNEXPECTED;
276
277         if ( ICDecompressEnd( This->hIC ) != ICERR_OK )
278                 return E_FAIL;
279
280         return S_OK;
281 }
282
283 static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame* iface,LPBITMAPINFOHEADER lpbi,LPVOID lpBits,INT x,INT y,INT dx,INT dy)
284 {
285         ICOM_THIS(IGetFrameImpl,iface);
286         HRESULT hr;
287         LONG    fmtlen;
288         BITMAPINFOHEADER        biTemp;
289         DWORD   dwSizeImage;
290
291         FIXME( "(%p)->(%p,%p,%d,%d,%d,%d)\n",This,lpbi,lpBits,x,y,dx,dy );
292
293         IGetFrame_Destruct(This);
294
295         hr = IAVIStream_ReadFormat(This->pas,0,NULL,&fmtlen);
296         if ( hr != S_OK )
297                 return hr;
298         This->pvICInFmtBuf = HeapAlloc(
299                 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,fmtlen);
300         if ( This->pvICInFmtBuf == NULL )
301                 return AVIERR_MEMORY;
302         hr = IAVIStream_ReadFormat(This->pas,0,This->pvICInFmtBuf,&fmtlen);
303         if ( hr != S_OK )
304                 return hr;
305         This->pbiICIn = (LPBITMAPINFO)This->pvICInFmtBuf;
306
307         This->hIC = (HIC)ICOpen( ICTYPE_VIDEO,
308                                  This->pbiICIn->bmiHeader.biCompression,
309                                  ICMODE_DECOMPRESS );
310         if ( This->hIC == (HIC)NULL )
311         {
312                 ERR( "no AVI decompressor for %c%c%c%c.\n",
313                      (int)(This->pbiICIn->bmiHeader.biCompression>> 0)&0xff,
314                      (int)(This->pbiICIn->bmiHeader.biCompression>> 8)&0xff,
315                      (int)(This->pbiICIn->bmiHeader.biCompression>>16)&0xff,
316                      (int)(This->pbiICIn->bmiHeader.biCompression>>24)&0xff );
317                 return E_FAIL;
318         }
319
320         if ( lpbi == NULL || lpbi == ((LPBITMAPINFOHEADER)1) )
321         {
322                 memset( &biTemp, 0, sizeof(biTemp) );
323                 biTemp.biSize = sizeof(BITMAPINFOHEADER);
324                 biTemp.biWidth = This->pbiICIn->bmiHeader.biWidth;
325                 biTemp.biHeight = This->pbiICIn->bmiHeader.biHeight;
326                 biTemp.biPlanes = 1;
327                 biTemp.biBitCount = 24;
328                 biTemp.biCompression = 0;
329                 lpbi = &biTemp;
330         }
331
332         if ( lpbi->biPlanes != 1 || lpbi->biCompression != 0 )
333                 return E_FAIL;
334
335         dwSizeImage =
336                 ((This->pbiICIn->bmiHeader.biWidth*lpbi->biBitCount+7)/8)*
337                                         This->pbiICIn->bmiHeader.biHeight;
338         This->pvICOutBuf = HeapAlloc(
339                 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
340                 (sizeof(BITMAPINFO)+sizeof(RGBQUAD)*256)*2+
341                 dwSizeImage );
342         if ( This->pvICOutBuf == NULL )
343                 return AVIERR_MEMORY;
344
345         This->pbiICOut = (BITMAPINFO*)This->pvICOutBuf;
346         This->pvICOutBits = (LPVOID)( (BYTE*)This->pvICOutBuf +
347                                 sizeof(BITMAPINFO) + sizeof(RGBQUAD)*256 );
348
349         This->pbiICOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
350         This->pbiICOut->bmiHeader.biWidth = This->pbiICIn->bmiHeader.biWidth;
351         This->pbiICOut->bmiHeader.biHeight = This->pbiICIn->bmiHeader.biHeight;
352         This->pbiICOut->bmiHeader.biPlanes = 1;
353         This->pbiICOut->bmiHeader.biBitCount = lpbi->biBitCount;
354         This->pbiICOut->bmiHeader.biSizeImage = dwSizeImage;
355         memcpy( This->pvICOutBits, This->pbiICOut, sizeof(BITMAPINFOHEADER) );
356
357         return S_OK;
358 }
359
360 static HRESULT IGetFrame_Construct( IGetFrameImpl* This,
361                                     IAVIStream* pstr,
362                                     LPBITMAPINFOHEADER lpbi )
363 {
364         HRESULT hr;
365
366         TRACE( "(%p)->(%p,%p)\n",This,pstr,lpbi );
367
368         IAVIStream_AddRef( pstr );
369         This->pas = pstr;
370         This->hIC = (HIC)NULL;
371         This->lCachedFrame = -1L;
372         This->pbiICIn = NULL;
373         This->pbiICOut = NULL;
374         This->pvICInFmtBuf = NULL;
375         This->pvICInDataBuf = NULL;
376         This->dwICInDataBufSize = 0;
377         This->pvICOutBuf = NULL;
378
379         hr = IGetFrame_SetFormat((IGetFrame*)This,lpbi,NULL,0,0,0,0);
380         if ( hr != S_OK )
381                 return hr;
382
383         return S_OK;
384 }
385
386 static void IGetFrame_Destruct( IGetFrameImpl* This )
387 {
388         if ( This->hIC != (HIC)NULL )
389         {
390                 ICClose( This->hIC );
391                 This->hIC = (HIC)NULL;
392         }
393         if ( This->pvICInFmtBuf != NULL )
394         {
395                 HeapFree( AVIFILE_data.hHeap, 0, This->pvICInFmtBuf );
396                 This->pvICInFmtBuf = NULL;
397         }
398         if ( This->pvICInDataBuf != NULL )
399         {
400                 HeapFree( AVIFILE_data.hHeap, 0, This->pvICInDataBuf );
401                 This->pvICInDataBuf = NULL;
402         }
403         if ( This->pvICOutBuf != NULL )
404         {
405                 HeapFree( AVIFILE_data.hHeap, 0, This->pvICOutBuf );
406                 This->pvICOutBuf = NULL;
407         }
408
409         This->lCachedFrame = -1L;
410         This->pbiICIn = NULL;
411         This->pbiICOut = NULL;
412         This->dwICInDataBufSize = 0;
413 }