Fixes for compatibility.
[wine/multimedia.git] / dlls / avifil32 / igframe.c
blob4964ec7005c2a1d86fc1ae365743b6e1ae5854ca
1 /*
2 * Copyright 2001 Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
4 * FIXME - implements color space(depth) converter.
5 */
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
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"
19 DEFAULT_DEBUG_CHANNEL(avifile);
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);
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,
40 typedef struct IGetFrameImpl
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;
58 static HRESULT IGetFrame_Construct( IGetFrameImpl* This,
59 IAVIStream* pstr,
60 LPBITMAPINFOHEADER lpbi );
61 static void IGetFrame_Destruct( IGetFrameImpl* This );
66 static LPVOID AVIFILE_IGetFrame_DecodeFrame(IGetFrameImpl* This,LONG lPos)
68 HRESULT hr;
69 DWORD dwRes;
70 LONG lFrameLength;
71 LONG lSampleCount;
72 ICDECOMPRESS icd;
74 if ( This->hIC == (HIC)NULL )
75 return NULL;
77 hr = IAVIStream_Read(This->pas,lPos,1,NULL,0,
78 &lFrameLength,&lSampleCount);
79 if ( hr != S_OK || lSampleCount <= 0 )
81 FIXME( "IAVIStream_Read failed! res = %08lx\n", hr );
82 return NULL;
84 TRACE( "frame length = %ld\n", lFrameLength );
86 if ( This->dwICInDataBufSize < lFrameLength )
88 LPVOID lpv;
90 if ( This->pvICInDataBuf == NULL )
92 lpv = HeapAlloc(
93 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
94 lFrameLength );
96 else
98 lpv = HeapReAlloc(
99 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
100 This->pvICInDataBuf,lFrameLength );
102 if ( lpv == NULL )
104 ERR( "out of memory!\n" );
105 return NULL;
107 This->pvICInDataBuf = lpv;
108 This->dwICInDataBufSize = lFrameLength;
111 hr = IAVIStream_Read(This->pas,lPos,1,
112 This->pvICInDataBuf,This->dwICInDataBufSize,
113 &lFrameLength,&lSampleCount);
114 if ( hr != S_OK || lSampleCount <= 0 )
116 FIXME( "IAVIStream_Read to buffer failed! res = %08lx\n", hr );
117 return NULL;
120 This->pbiICIn->bmiHeader.biSizeImage = lFrameLength;
122 TRACE( "call ICM_DECOMPRESS\n" );
123 icd.dwFlags = 0;
124 if ( IAVIStream_FindSample(This->pas,lPos,FIND_PREV|FIND_KEY) != lPos )
125 icd.dwFlags = ICDECOMPRESS_NOTKEYFRAME;
126 icd.lpbiInput = &This->pbiICIn->bmiHeader;
127 icd.lpInput = (BYTE*)This->pvICInDataBuf;
128 icd.lpbiOutput = &This->pbiICOut->bmiHeader;
129 icd.lpOutput = This->pvICOutBits;
130 icd.ckid = *((DWORD*)This->pvICInDataBuf);
131 dwRes = ICSendMessage(This->hIC,ICM_DECOMPRESS,
132 (DWORD)(&icd),sizeof(ICDECOMPRESS) );
133 TRACE( "returned from ICM_DECOMPRESS\n" );
134 if ( dwRes != ICERR_OK )
136 ERR( "ICDecompress failed!\n" );
137 return NULL;
140 This->lCachedFrame = lPos;
142 return This->pvICOutBits;
145 /****************************************************************************/
147 HRESULT AVIFILE_CreateIGetFrame(void** ppobj,
148 IAVIStream* pstr,LPBITMAPINFOHEADER lpbi)
150 IGetFrameImpl *This;
151 HRESULT hr;
153 *ppobj = NULL;
154 This = (IGetFrameImpl*)HeapAlloc(AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
155 sizeof(IGetFrameImpl));
156 This->ref = 1;
157 ICOM_VTBL(This) = &igetfrm;
158 hr = IGetFrame_Construct( This, pstr, lpbi );
159 if ( hr != S_OK )
161 IGetFrame_Destruct( This );
162 return hr;
165 *ppobj = (LPVOID)This;
167 return S_OK;
170 /****************************************************************************
171 * IUnknown interface
174 static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame* iface,REFIID refiid,LPVOID *obj)
176 ICOM_THIS(IGetFrameImpl,iface);
178 TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj);
179 if ( IsEqualGUID(&IID_IUnknown,refiid) ||
180 IsEqualGUID(&IID_IGetFrame,refiid) )
182 IGetFrame_AddRef(iface);
183 *obj = iface;
184 return S_OK;
187 return OLE_E_ENUM_NOMORE;
190 static ULONG WINAPI IGetFrame_fnAddRef(IGetFrame* iface)
192 ICOM_THIS(IGetFrameImpl,iface);
194 TRACE("(%p)->AddRef()\n",iface);
195 return ++(This->ref);
198 static ULONG WINAPI IGetFrame_fnRelease(IGetFrame* iface)
200 ICOM_THIS(IGetFrameImpl,iface);
202 TRACE("(%p)->Release()\n",iface);
203 if ((--(This->ref)) > 0 )
204 return This->ref;
205 IGetFrame_Destruct(This);
206 if ( This->pas != NULL )
207 IAVIStream_Release( This->pas );
209 HeapFree(AVIFILE_data.hHeap,0,iface);
210 return 0;
213 /****************************************************************************
214 * IGetFrrame interface
217 static LPVOID WINAPI IGetFrame_fnGetFrame(IGetFrame* iface,LONG lPos)
219 ICOM_THIS(IGetFrameImpl,iface);
220 LPVOID lpv;
221 LONG lKeyFrame;
223 TRACE( "(%p)->(%ld)\n", This, lPos );
225 if ( lPos < 0 )
226 return NULL;
228 if ( This->lCachedFrame == lPos )
229 return This->pvICOutBits;
230 if ( (This->lCachedFrame+1) != lPos )
232 lKeyFrame = IAVIStream_FindSample( This->pas, lPos,
233 FIND_KEY | FIND_PREV );
234 if ( lKeyFrame < 0 || lKeyFrame > lPos )
235 return NULL;
236 while ( ++lKeyFrame < lPos )
238 lpv = AVIFILE_IGetFrame_DecodeFrame(This, lKeyFrame);
239 if ( lpv == NULL )
240 return NULL;
244 lpv = AVIFILE_IGetFrame_DecodeFrame(This, lPos);
245 TRACE( "lpv = %p\n",lpv );
246 if ( lpv == NULL )
247 return NULL;
249 return lpv;
252 static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame* iface,LONG lStart,LONG lEnd,LONG lRate)
254 ICOM_THIS(IGetFrameImpl,iface);
256 TRACE( "(%p)->(%ld,%ld,%ld)\n", This, lStart, lEnd, lRate );
258 if ( This->hIC == (HIC)NULL )
259 return E_UNEXPECTED;
261 if ( ICDecompressBegin( This->hIC,
262 This->pbiICIn,
263 This->pbiICOut ) != ICERR_OK )
264 return E_FAIL;
266 return S_OK;
269 static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame* iface)
271 ICOM_THIS(IGetFrameImpl,iface);
273 TRACE( "(%p)->()\n", This );
275 if ( This->hIC == (HIC)NULL )
276 return E_UNEXPECTED;
278 if ( ICDecompressEnd( This->hIC ) != ICERR_OK )
279 return E_FAIL;
281 return S_OK;
284 static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame* iface,LPBITMAPINFOHEADER lpbi,LPVOID lpBits,INT x,INT y,INT dx,INT dy)
286 ICOM_THIS(IGetFrameImpl,iface);
287 HRESULT hr;
288 LONG fmtlen;
289 BITMAPINFOHEADER biTemp;
290 DWORD dwSizeImage;
292 FIXME( "(%p)->(%p,%p,%d,%d,%d,%d)\n",This,lpbi,lpBits,x,y,dx,dy );
294 IGetFrame_Destruct(This);
296 hr = IAVIStream_ReadFormat(This->pas,0,NULL,&fmtlen);
297 if ( hr != S_OK )
298 return hr;
299 This->pvICInFmtBuf = HeapAlloc(
300 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,fmtlen);
301 if ( This->pvICInFmtBuf == NULL )
302 return AVIERR_MEMORY;
303 hr = IAVIStream_ReadFormat(This->pas,0,This->pvICInFmtBuf,&fmtlen);
304 if ( hr != S_OK )
305 return hr;
306 This->pbiICIn = (LPBITMAPINFO)This->pvICInFmtBuf;
308 This->hIC = (HIC)ICOpen( ICTYPE_VIDEO,
309 This->pbiICIn->bmiHeader.biCompression,
310 ICMODE_DECOMPRESS );
311 if ( This->hIC == (HIC)NULL )
313 ERR( "no AVI decompressor for %c%c%c%c.\n",
314 (int)(This->pbiICIn->bmiHeader.biCompression>> 0)&0xff,
315 (int)(This->pbiICIn->bmiHeader.biCompression>> 8)&0xff,
316 (int)(This->pbiICIn->bmiHeader.biCompression>>16)&0xff,
317 (int)(This->pbiICIn->bmiHeader.biCompression>>24)&0xff );
318 return E_FAIL;
321 if ( lpbi == NULL || lpbi == ((LPBITMAPINFOHEADER)1) )
323 memset( &biTemp, 0, sizeof(biTemp) );
324 biTemp.biSize = sizeof(BITMAPINFOHEADER);
325 biTemp.biWidth = This->pbiICIn->bmiHeader.biWidth;
326 biTemp.biHeight = This->pbiICIn->bmiHeader.biHeight;
327 biTemp.biPlanes = 1;
328 biTemp.biBitCount = 24;
329 biTemp.biCompression = 0;
330 lpbi = &biTemp;
333 if ( lpbi->biPlanes != 1 || lpbi->biCompression != 0 )
334 return E_FAIL;
336 dwSizeImage =
337 ((This->pbiICIn->bmiHeader.biWidth*lpbi->biBitCount+7)/8)*
338 This->pbiICIn->bmiHeader.biHeight;
339 This->pvICOutBuf = HeapAlloc(
340 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
341 (sizeof(BITMAPINFO)+sizeof(RGBQUAD)*256)*2+
342 dwSizeImage );
343 if ( This->pvICOutBuf == NULL )
344 return AVIERR_MEMORY;
346 This->pbiICOut = (BITMAPINFO*)This->pvICOutBuf;
347 This->pvICOutBits = (LPVOID)( (BYTE*)This->pvICOutBuf +
348 sizeof(BITMAPINFO) + sizeof(RGBQUAD)*256 );
350 This->pbiICOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
351 This->pbiICOut->bmiHeader.biWidth = This->pbiICIn->bmiHeader.biWidth;
352 This->pbiICOut->bmiHeader.biHeight = This->pbiICIn->bmiHeader.biHeight;
353 This->pbiICOut->bmiHeader.biPlanes = 1;
354 This->pbiICOut->bmiHeader.biBitCount = lpbi->biBitCount;
355 This->pbiICOut->bmiHeader.biSizeImage = dwSizeImage;
356 memcpy( This->pvICOutBits, This->pbiICOut, sizeof(BITMAPINFOHEADER) );
358 return S_OK;
361 static HRESULT IGetFrame_Construct( IGetFrameImpl* This,
362 IAVIStream* pstr,
363 LPBITMAPINFOHEADER lpbi )
365 HRESULT hr;
367 TRACE( "(%p)->(%p,%p)\n",This,pstr,lpbi );
369 IAVIStream_AddRef( pstr );
370 This->pas = pstr;
371 This->hIC = (HIC)NULL;
372 This->lCachedFrame = -1L;
373 This->pbiICIn = NULL;
374 This->pbiICOut = NULL;
375 This->pvICInFmtBuf = NULL;
376 This->pvICInDataBuf = NULL;
377 This->dwICInDataBufSize = 0;
378 This->pvICOutBuf = NULL;
380 hr = IGetFrame_SetFormat((IGetFrame*)This,lpbi,NULL,0,0,0,0);
381 if ( hr != S_OK )
382 return hr;
384 return S_OK;
387 static void IGetFrame_Destruct( IGetFrameImpl* This )
389 if ( This->hIC != (HIC)NULL )
391 ICClose( This->hIC );
392 This->hIC = (HIC)NULL;
394 if ( This->pvICInFmtBuf != NULL )
396 HeapFree( AVIFILE_data.hHeap, 0, This->pvICInFmtBuf );
397 This->pvICInFmtBuf = NULL;
399 if ( This->pvICInDataBuf != NULL )
401 HeapFree( AVIFILE_data.hHeap, 0, This->pvICInDataBuf );
402 This->pvICInDataBuf = NULL;
404 if ( This->pvICOutBuf != NULL )
406 HeapFree( AVIFILE_data.hHeap, 0, This->pvICOutBuf );
407 This->pvICOutBuf = NULL;
410 This->lCachedFrame = -1L;
411 This->pbiICIn = NULL;
412 This->pbiICOut = NULL;
413 This->dwICInDataBufSize = 0;