2 * Copyright 2001 Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * FIXME - implements color space(depth) converter.
30 #include "wine/debug.h"
31 #include "avifile_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
35 static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame* iface,REFIID refiid,LPVOID *obj);
36 static ULONG WINAPI IGetFrame_fnAddRef(IGetFrame* iface);
37 static ULONG WINAPI IGetFrame_fnRelease(IGetFrame* iface);
38 static LPVOID WINAPI IGetFrame_fnGetFrame(IGetFrame* iface,LONG lPos);
39 static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame* iface,LONG lStart,LONG lEnd,LONG lRate);
40 static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame* iface);
41 static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame* iface,LPBITMAPINFOHEADER lpbi,LPVOID lpBits,INT x,INT y,INT dx,INT dy);
43 struct ICOM_VTABLE(IGetFrame) igetfrm = {
44 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
45 IGetFrame_fnQueryInterface,
51 IGetFrame_fnSetFormat,
54 typedef struct IGetFrameImpl
56 ICOM_VFIELD(IGetFrame);
67 DWORD dwICInDataBufSize;
72 static HRESULT IGetFrame_Construct( IGetFrameImpl* This,
74 LPBITMAPINFOHEADER lpbi );
75 static void IGetFrame_Destruct( IGetFrameImpl* This );
80 static LPVOID AVIFILE_IGetFrame_DecodeFrame(IGetFrameImpl* This,LONG lPos)
88 if ( This->hIC == (HIC)NULL )
91 hr = IAVIStream_Read(This->pas,lPos,1,NULL,0,
92 &lFrameLength,&lSampleCount);
93 if ( hr != S_OK || lSampleCount <= 0 )
95 FIXME( "IAVIStream_Read failed! res = %08lx\n", hr );
98 TRACE( "frame length = %ld\n", lFrameLength );
100 if ( This->dwICInDataBufSize < lFrameLength )
104 if ( This->pvICInDataBuf == NULL )
107 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
113 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
114 This->pvICInDataBuf,lFrameLength );
118 ERR( "out of memory!\n" );
121 This->pvICInDataBuf = lpv;
122 This->dwICInDataBufSize = lFrameLength;
125 hr = IAVIStream_Read(This->pas,lPos,1,
126 This->pvICInDataBuf,This->dwICInDataBufSize,
127 &lFrameLength,&lSampleCount);
128 if ( hr != S_OK || lSampleCount <= 0 )
130 FIXME( "IAVIStream_Read to buffer failed! res = %08lx\n", hr );
134 This->pbiICIn->bmiHeader.biSizeImage = lFrameLength;
136 TRACE( "call ICM_DECOMPRESS\n" );
138 if ( IAVIStream_FindSample(This->pas,lPos,FIND_PREV|FIND_KEY) != lPos )
139 icd.dwFlags = ICDECOMPRESS_NOTKEYFRAME;
140 icd.lpbiInput = &This->pbiICIn->bmiHeader;
141 icd.lpInput = (BYTE*)This->pvICInDataBuf;
142 icd.lpbiOutput = &This->pbiICOut->bmiHeader;
143 icd.lpOutput = This->pvICOutBits;
144 icd.ckid = *((DWORD*)This->pvICInDataBuf);
145 dwRes = ICSendMessage(This->hIC,ICM_DECOMPRESS,
146 (DWORD)(&icd),sizeof(ICDECOMPRESS) );
147 TRACE( "returned from ICM_DECOMPRESS\n" );
148 if ( dwRes != ICERR_OK )
150 ERR( "ICDecompress failed!\n" );
154 This->lCachedFrame = lPos;
156 return This->pvICOutBits;
159 /****************************************************************************/
161 HRESULT AVIFILE_CreateIGetFrame(void** ppobj,
162 IAVIStream* pstr,LPBITMAPINFOHEADER lpbi)
168 This = (IGetFrameImpl*)HeapAlloc(AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
169 sizeof(IGetFrameImpl));
171 ICOM_VTBL(This) = &igetfrm;
172 hr = IGetFrame_Construct( This, pstr, lpbi );
175 IGetFrame_Destruct( This );
179 *ppobj = (LPVOID)This;
184 /****************************************************************************
188 static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame* iface,REFIID refiid,LPVOID *obj)
190 ICOM_THIS(IGetFrameImpl,iface);
192 TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj);
193 if ( IsEqualGUID(&IID_IUnknown,refiid) ||
194 IsEqualGUID(&IID_IGetFrame,refiid) )
196 IGetFrame_AddRef(iface);
201 return OLE_E_ENUM_NOMORE;
204 static ULONG WINAPI IGetFrame_fnAddRef(IGetFrame* iface)
206 ICOM_THIS(IGetFrameImpl,iface);
208 TRACE("(%p)->AddRef()\n",iface);
209 return ++(This->ref);
212 static ULONG WINAPI IGetFrame_fnRelease(IGetFrame* iface)
214 ICOM_THIS(IGetFrameImpl,iface);
216 TRACE("(%p)->Release()\n",iface);
217 if ((--(This->ref)) > 0 )
219 IGetFrame_Destruct(This);
220 if ( This->pas != NULL )
221 IAVIStream_Release( This->pas );
223 HeapFree(AVIFILE_data.hHeap,0,iface);
227 /****************************************************************************
228 * IGetFrrame interface
231 static LPVOID WINAPI IGetFrame_fnGetFrame(IGetFrame* iface,LONG lPos)
233 ICOM_THIS(IGetFrameImpl,iface);
237 TRACE( "(%p)->(%ld)\n", This, lPos );
242 if ( This->lCachedFrame == lPos )
243 return This->pvICOutBits;
244 if ( (This->lCachedFrame+1) != lPos )
246 lKeyFrame = IAVIStream_FindSample( This->pas, lPos,
247 FIND_KEY | FIND_PREV );
248 if ( lKeyFrame < 0 || lKeyFrame > lPos )
250 while ( ++lKeyFrame < lPos )
252 lpv = AVIFILE_IGetFrame_DecodeFrame(This, lKeyFrame);
258 lpv = AVIFILE_IGetFrame_DecodeFrame(This, lPos);
259 TRACE( "lpv = %p\n",lpv );
266 static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame* iface,LONG lStart,LONG lEnd,LONG lRate)
268 ICOM_THIS(IGetFrameImpl,iface);
270 TRACE( "(%p)->(%ld,%ld,%ld)\n", This, lStart, lEnd, lRate );
272 if ( This->hIC == (HIC)NULL )
275 if ( ICDecompressBegin( This->hIC,
277 This->pbiICOut ) != ICERR_OK )
283 static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame* iface)
285 ICOM_THIS(IGetFrameImpl,iface);
287 TRACE( "(%p)->()\n", This );
289 if ( This->hIC == (HIC)NULL )
292 if ( ICDecompressEnd( This->hIC ) != ICERR_OK )
298 static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame* iface,LPBITMAPINFOHEADER lpbi,LPVOID lpBits,INT x,INT y,INT dx,INT dy)
300 ICOM_THIS(IGetFrameImpl,iface);
303 BITMAPINFOHEADER biTemp;
306 FIXME( "(%p)->(%p,%p,%d,%d,%d,%d)\n",This,lpbi,lpBits,x,y,dx,dy );
308 IGetFrame_Destruct(This);
310 hr = IAVIStream_ReadFormat(This->pas,0,NULL,&fmtlen);
313 This->pvICInFmtBuf = HeapAlloc(
314 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,fmtlen);
315 if ( This->pvICInFmtBuf == NULL )
316 return AVIERR_MEMORY;
317 hr = IAVIStream_ReadFormat(This->pas,0,This->pvICInFmtBuf,&fmtlen);
320 This->pbiICIn = (LPBITMAPINFO)This->pvICInFmtBuf;
322 This->hIC = (HIC)ICOpen( ICTYPE_VIDEO,
323 This->pbiICIn->bmiHeader.biCompression,
325 if ( This->hIC == (HIC)NULL )
327 ERR( "no AVI decompressor for %c%c%c%c.\n",
328 (int)(This->pbiICIn->bmiHeader.biCompression>> 0)&0xff,
329 (int)(This->pbiICIn->bmiHeader.biCompression>> 8)&0xff,
330 (int)(This->pbiICIn->bmiHeader.biCompression>>16)&0xff,
331 (int)(This->pbiICIn->bmiHeader.biCompression>>24)&0xff );
335 if ( lpbi == NULL || lpbi == ((LPBITMAPINFOHEADER)1) )
337 memset( &biTemp, 0, sizeof(biTemp) );
338 biTemp.biSize = sizeof(BITMAPINFOHEADER);
339 biTemp.biWidth = This->pbiICIn->bmiHeader.biWidth;
340 biTemp.biHeight = This->pbiICIn->bmiHeader.biHeight;
342 biTemp.biBitCount = 24;
343 biTemp.biCompression = 0;
347 if ( lpbi->biPlanes != 1 || lpbi->biCompression != 0 )
351 ((This->pbiICIn->bmiHeader.biWidth*lpbi->biBitCount+7)/8)*
352 This->pbiICIn->bmiHeader.biHeight;
353 This->pvICOutBuf = HeapAlloc(
354 AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
355 (sizeof(BITMAPINFO)+sizeof(RGBQUAD)*256)*2+
357 if ( This->pvICOutBuf == NULL )
358 return AVIERR_MEMORY;
360 This->pbiICOut = (BITMAPINFO*)This->pvICOutBuf;
361 This->pvICOutBits = (LPVOID)( (BYTE*)This->pvICOutBuf +
362 sizeof(BITMAPINFO) + sizeof(RGBQUAD)*256 );
364 This->pbiICOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
365 This->pbiICOut->bmiHeader.biWidth = This->pbiICIn->bmiHeader.biWidth;
366 This->pbiICOut->bmiHeader.biHeight = This->pbiICIn->bmiHeader.biHeight;
367 This->pbiICOut->bmiHeader.biPlanes = 1;
368 This->pbiICOut->bmiHeader.biBitCount = lpbi->biBitCount;
369 This->pbiICOut->bmiHeader.biSizeImage = dwSizeImage;
370 memcpy( This->pvICOutBits, This->pbiICOut, sizeof(BITMAPINFOHEADER) );
375 static HRESULT IGetFrame_Construct( IGetFrameImpl* This,
377 LPBITMAPINFOHEADER lpbi )
381 TRACE( "(%p)->(%p,%p)\n",This,pstr,lpbi );
383 IAVIStream_AddRef( pstr );
385 This->hIC = (HIC)NULL;
386 This->lCachedFrame = -1L;
387 This->pbiICIn = NULL;
388 This->pbiICOut = NULL;
389 This->pvICInFmtBuf = NULL;
390 This->pvICInDataBuf = NULL;
391 This->dwICInDataBufSize = 0;
392 This->pvICOutBuf = NULL;
394 hr = IGetFrame_SetFormat((IGetFrame*)This,lpbi,NULL,0,0,0,0);
401 static void IGetFrame_Destruct( IGetFrameImpl* This )
403 if ( This->hIC != (HIC)NULL )
405 ICClose( This->hIC );
406 This->hIC = (HIC)NULL;
408 if ( This->pvICInFmtBuf != NULL )
410 HeapFree( AVIFILE_data.hHeap, 0, This->pvICInFmtBuf );
411 This->pvICInFmtBuf = NULL;
413 if ( This->pvICInDataBuf != NULL )
415 HeapFree( AVIFILE_data.hHeap, 0, This->pvICInDataBuf );
416 This->pvICInDataBuf = NULL;
418 if ( This->pvICOutBuf != NULL )
420 HeapFree( AVIFILE_data.hHeap, 0, This->pvICOutBuf );
421 This->pvICOutBuf = NULL;
424 This->lCachedFrame = -1L;
425 This->pbiICIn = NULL;
426 This->pbiICOut = NULL;
427 This->dwICInDataBufSize = 0;