2 * Copyright 2001 Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
4 * FIXME - implements color space(depth) converter.
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,
37 IGetFrame_fnSetFormat,
40 typedef struct IGetFrameImpl
42 ICOM_VFIELD(IGetFrame);
53 DWORD dwICInDataBufSize;
58 static HRESULT IGetFrame_Construct( IGetFrameImpl* This,
60 LPBITMAPINFOHEADER lpbi );
61 static void IGetFrame_Destruct( IGetFrameImpl* This );
66 static LPVOID AVIFILE_IGetFrame_DecodeFrame(IGetFrameImpl* This,LONG lPos)
74 if ( This->hIC == (HIC)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 );
84 TRACE( "frame length = %ld\n", lFrameLength );
86 if ( This->dwICInDataBufSize < lFrameLength )
90 if ( This->pvICInDataBuf == NULL )
93 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
99 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
100 This->pvICInDataBuf,lFrameLength );
104 ERR( "out of memory!\n" );
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 );
120 This->pbiICIn->bmiHeader.biSizeImage = lFrameLength;
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 )
135 ERR( "ICDecompress failed!\n" );
139 This->lCachedFrame = lPos;
141 return This->pvICOutBits;
144 /****************************************************************************/
146 HRESULT AVIFILE_CreateIGetFrame(void** ppobj,
147 IAVIStream* pstr,LPBITMAPINFOHEADER lpbi)
153 This = (IGetFrameImpl*)HeapAlloc(AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
154 sizeof(IGetFrameImpl));
156 ICOM_VTBL(This) = &igetfrm;
157 hr = IGetFrame_Construct( This, pstr, lpbi );
160 IGetFrame_Destruct( This );
164 *ppobj = (LPVOID)This;
169 /****************************************************************************
173 static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame* iface,REFIID refiid,LPVOID *obj)
175 ICOM_THIS(IGetFrameImpl,iface);
177 TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj);
178 if ( IsEqualGUID(&IID_IUnknown,refiid) ||
179 IsEqualGUID(&IID_IGetFrame,refiid) )
181 IGetFrame_AddRef(iface);
186 return OLE_E_ENUM_NOMORE;
189 static ULONG WINAPI IGetFrame_fnAddRef(IGetFrame* iface)
191 ICOM_THIS(IGetFrameImpl,iface);
193 TRACE("(%p)->AddRef()\n",iface);
194 return ++(This->ref);
197 static ULONG WINAPI IGetFrame_fnRelease(IGetFrame* iface)
199 ICOM_THIS(IGetFrameImpl,iface);
201 TRACE("(%p)->Release()\n",iface);
202 if ((--(This->ref)) > 0 )
204 IGetFrame_Destruct(This);
205 if ( This->pas != NULL )
206 IAVIStream_Release( This->pas );
208 HeapFree(AVIFILE_data.hHeap,0,iface);
212 /****************************************************************************
213 * IGetFrrame interface
216 static LPVOID WINAPI IGetFrame_fnGetFrame(IGetFrame* iface,LONG lPos)
218 ICOM_THIS(IGetFrameImpl,iface);
222 TRACE( "(%p)->(%ld)\n", This, lPos );
227 if ( This->lCachedFrame == lPos )
228 return This->pvICOutBits;
229 if ( (This->lCachedFrame+1) != lPos )
231 lKeyFrame = IAVIStream_FindSample( This->pas, lPos,
232 FIND_KEY | FIND_PREV );
233 if ( lKeyFrame < 0 || lKeyFrame > lPos )
235 while ( ++lKeyFrame < lPos )
237 lpv = AVIFILE_IGetFrame_DecodeFrame(This, lKeyFrame);
243 lpv = AVIFILE_IGetFrame_DecodeFrame(This, lPos);
244 TRACE( "lpv = %p\n",lpv );
251 static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame* iface,LONG lStart,LONG lEnd,LONG lRate)
253 ICOM_THIS(IGetFrameImpl,iface);
255 TRACE( "(%p)->(%ld,%ld,%ld)\n", This, lStart, lEnd, lRate );
257 if ( This->hIC == (HIC)NULL )
260 if ( ICDecompressBegin( This->hIC,
262 This->pbiICOut ) != ICERR_OK )
268 static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame* iface)
270 ICOM_THIS(IGetFrameImpl,iface);
272 TRACE( "(%p)->()\n", This );
274 if ( This->hIC == (HIC)NULL )
277 if ( ICDecompressEnd( This->hIC ) != ICERR_OK )
283 static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame* iface,LPBITMAPINFOHEADER lpbi,LPVOID lpBits,INT x,INT y,INT dx,INT dy)
285 ICOM_THIS(IGetFrameImpl,iface);
288 BITMAPINFOHEADER biTemp;
291 FIXME( "(%p)->(%p,%p,%d,%d,%d,%d)\n",This,lpbi,lpBits,x,y,dx,dy );
293 IGetFrame_Destruct(This);
295 hr = IAVIStream_ReadFormat(This->pas,0,NULL,&fmtlen);
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);
305 This->pbiICIn = (LPBITMAPINFO)This->pvICInFmtBuf;
307 This->hIC = (HIC)ICOpen( ICTYPE_VIDEO,
308 This->pbiICIn->bmiHeader.biCompression,
310 if ( This->hIC == (HIC)NULL )
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 );
320 if ( lpbi == NULL || lpbi == ((LPBITMAPINFOHEADER)1) )
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;
327 biTemp.biBitCount = 24;
328 biTemp.biCompression = 0;
332 if ( lpbi->biPlanes != 1 || lpbi->biCompression != 0 )
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+
342 if ( This->pvICOutBuf == NULL )
343 return AVIERR_MEMORY;
345 This->pbiICOut = (BITMAPINFO*)This->pvICOutBuf;
346 This->pvICOutBits = (LPVOID)( (BYTE*)This->pvICOutBuf +
347 sizeof(BITMAPINFO) + sizeof(RGBQUAD)*256 );
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) );
360 static HRESULT IGetFrame_Construct( IGetFrameImpl* This,
362 LPBITMAPINFOHEADER lpbi )
366 TRACE( "(%p)->(%p,%p)\n",This,pstr,lpbi );
368 IAVIStream_AddRef( 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;
379 hr = IGetFrame_SetFormat((IGetFrame*)This,lpbi,NULL,0,0,0,0);
386 static void IGetFrame_Destruct( IGetFrameImpl* This )
388 if ( This->hIC != (HIC)NULL )
390 ICClose( This->hIC );
391 This->hIC = (HIC)NULL;
393 if ( This->pvICInFmtBuf != NULL )
395 HeapFree( AVIFILE_data.hHeap, 0, This->pvICInFmtBuf );
396 This->pvICInFmtBuf = NULL;
398 if ( This->pvICInDataBuf != NULL )
400 HeapFree( AVIFILE_data.hHeap, 0, This->pvICInDataBuf );
401 This->pvICInDataBuf = NULL;
403 if ( This->pvICOutBuf != NULL )
405 HeapFree( AVIFILE_data.hHeap, 0, This->pvICOutBuf );
406 This->pvICOutBuf = NULL;
409 This->lCachedFrame = -1L;
410 This->pbiICIn = NULL;
411 This->pbiICOut = NULL;
412 This->dwICInDataBufSize = 0;