Fixed a few more headers dependency issues.
[wine] / dlls / avifil32 / getframe.c
1 /*
2  * Copyright 2002-2003 Michael Günnewig
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #define COM_NO_WINDOWS_H
20 #include <assert.h>
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "windowsx.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "vfw.h"
30
31 #include "avifile_private.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
36
37 #ifndef DIBPTR
38 #define DIBPTR(lp)      ((LPBYTE)(lp) + (lp)->biSize + \
39                          (lp)->biClrUsed * sizeof(RGBQUAD))
40 #endif
41
42 /***********************************************************************/
43
44 static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame *iface,
45                                                  REFIID refiid, LPVOID *obj);
46 static ULONG   WINAPI IGetFrame_fnAddRef(IGetFrame *iface);
47 static ULONG   WINAPI IGetFrame_fnRelease(IGetFrame *iface);
48 static LPVOID  WINAPI IGetFrame_fnGetFrame(IGetFrame *iface, LONG lPos);
49 static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame *iface, LONG lStart,
50                                         LONG lEnd, LONG lRate);
51 static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame *iface);
52 static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame *iface,
53                                             LPBITMAPINFOHEADER lpbi,
54                                             LPVOID lpBits, INT x, INT y,
55                                             INT dx, INT dy);
56
57 struct ICOM_VTABLE(IGetFrame) igetframeVtbl = {
58   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
59   IGetFrame_fnQueryInterface,
60   IGetFrame_fnAddRef,
61   IGetFrame_fnRelease,
62   IGetFrame_fnGetFrame,
63   IGetFrame_fnBegin,
64   IGetFrame_fnEnd,
65   IGetFrame_fnSetFormat
66 };
67
68 typedef struct _IGetFrameImpl {
69   /* IUnknown stuff */
70   ICOM_VFIELD(IGetFrame);
71   DWORD              ref;
72
73   /* IGetFrame stuff */
74   BOOL               bFixedStream;
75   PAVISTREAM         pStream;
76
77   LPVOID             lpInBuffer;
78   LONG               cbInBuffer;
79   LPBITMAPINFOHEADER lpInFormat;
80   LONG               cbInFormat;
81
82   LONG               lCurrentFrame;
83   LPBITMAPINFOHEADER lpOutFormat;
84   LPVOID             lpOutBuffer;
85
86   HIC                hic;
87   BOOL               bResize;
88   DWORD              x;
89   DWORD              y;
90   DWORD              dx;
91   DWORD              dy;
92
93   BOOL               bFormatChanges;
94   DWORD              dwFormatChangeCount;
95   DWORD              dwEditCount;
96 } IGetFrameImpl;
97
98 /***********************************************************************/
99
100 static void AVIFILE_CloseCompressor(IGetFrameImpl *This)
101 {
102   if (This->lpOutFormat != NULL && This->lpInFormat != This->lpOutFormat) {
103     GlobalFreePtr(This->lpOutFormat);
104     This->lpOutFormat = NULL;
105   }
106   if (This->lpInFormat != NULL) {
107     GlobalFreePtr(This->lpInFormat);
108     This->lpInFormat = NULL;
109   }
110   if (This->hic != NULL) {
111     if (This->bResize)
112       ICDecompressExEnd(This->hic);
113     else
114       ICDecompressEnd(This->hic);
115     ICClose(This->hic);
116     This->hic = NULL;
117   }
118 }
119
120 PGETFRAME AVIFILE_CreateGetFrame(PAVISTREAM pStream)
121 {
122   IGetFrameImpl *pg;
123
124   /* check parameter */
125   if (pStream == NULL)
126     return NULL;
127
128   pg = (IGetFrameImpl*)LocalAlloc(LPTR, sizeof(IGetFrameImpl));
129   if (pg != NULL) {
130     pg->lpVtbl        = &igetframeVtbl;
131     pg->ref           = 1;
132     pg->lCurrentFrame = -1;
133     pg->pStream       = pStream;
134     IAVIStream_AddRef(pStream);
135   }
136
137   return (PGETFRAME)pg;
138 }
139
140 static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame *iface,
141                                                  REFIID refiid, LPVOID *obj)
142 {
143   ICOM_THIS(IGetFrameImpl,iface);
144
145   TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
146
147   if (IsEqualGUID(&IID_IUnknown, refiid) ||
148       IsEqualGUID(&IID_IGetFrame, refiid)) {
149     *obj = iface;
150     return S_OK;
151   }
152
153   return OLE_E_ENUM_NOMORE;
154 }
155
156 static ULONG   WINAPI IGetFrame_fnAddRef(IGetFrame *iface)
157 {
158   ICOM_THIS(IGetFrameImpl,iface);
159
160   TRACE("(%p)\n", iface);
161
162   return ++(This->ref);
163 }
164
165 static ULONG   WINAPI IGetFrame_fnRelease(IGetFrame *iface)
166 {
167   ICOM_THIS(IGetFrameImpl,iface);
168
169   TRACE("(%p)\n", iface);
170
171   if (!--(This->ref)) {
172     AVIFILE_CloseCompressor(This);
173     if (This->pStream != NULL) {
174       AVIStreamRelease(This->pStream);
175       This->pStream = NULL;
176     }
177
178     LocalFree((HLOCAL)iface);
179     return 0;
180   }
181
182   return This->ref;
183 }
184
185 static LPVOID  WINAPI IGetFrame_fnGetFrame(IGetFrame *iface, LONG lPos)
186 {
187   ICOM_THIS(IGetFrameImpl,iface);
188
189   LONG readBytes;
190   LONG readSamples;
191
192   TRACE("(%p,%ld)\n", iface, lPos);
193
194   /* check state */
195   if (This->pStream == NULL)
196     return NULL;
197   if (This->lpInFormat == NULL)
198     return NULL;
199
200   /* Could stream have changed? */
201   if (! This->bFixedStream) {
202     AVISTREAMINFOW sInfo;
203
204     IAVIStream_Info(This->pStream, &sInfo, sizeof(sInfo));
205
206     if (sInfo.dwEditCount != This->dwEditCount) {
207       This->dwEditCount   = sInfo.dwEditCount;
208       This->lCurrentFrame = -1;
209     }
210
211     if (sInfo.dwFormatChangeCount != This->dwFormatChangeCount) {
212       /* stream has changed */
213       if (This->lpOutFormat != NULL) {
214         BITMAPINFOHEADER bi;
215
216         memcpy(&bi, This->lpOutFormat, sizeof(bi));
217         AVIFILE_CloseCompressor(This);
218
219         if (FAILED(IGetFrame_SetFormat(iface, &bi, NULL, 0, 0, -1, -1))) {
220           if (FAILED(IGetFrame_SetFormat(iface, NULL, NULL, 0, 0, -1, -1)))
221             return NULL;
222         }
223       } else if (FAILED(IGetFrame_SetFormat(iface, NULL, NULL, 0, 0, -1, -1)))
224         return NULL;
225     }
226   }
227
228   if (lPos != This->lCurrentFrame) {
229     LONG lNext = AVIStreamFindSample(This->pStream, lPos, FIND_KEY|FIND_PREV);
230
231     if (lNext == -1)
232       return NULL;
233     if (lNext <= This->lCurrentFrame && This->lCurrentFrame < lPos)
234       lNext = This->lCurrentFrame + 1;
235
236     for (; lNext <= lPos; lNext++) {
237       /* new format for this frame? */
238       if (This->bFormatChanges) {
239         AVIStreamReadFormat(This->pStream, lNext, This->lpInFormat, &This->cbInFormat);
240         if (This->lpOutFormat != NULL) {
241           if (This->lpOutFormat->biBitCount <= 8)
242             ICDecompressGetPalette(This->hic, This->lpInFormat,
243                                    This->lpOutFormat);
244         }
245       }
246
247       /* read input frame */
248       while (FAILED(AVIStreamRead(This->pStream, lNext, 1, This->lpInBuffer,
249                                   This->cbInBuffer, &readBytes, &readSamples))) {
250         /* not enough memory for input buffer? */
251         readBytes = 0;
252         if (FAILED(AVIStreamSampleSize(This->pStream, lNext, &readBytes)))
253           return NULL;
254         if (This->cbInBuffer >= readBytes)
255           break;
256         This->lpInFormat = GlobalReAllocPtr(This->lpInFormat, This->cbInFormat + readBytes, 0);
257         if (This->lpInFormat == NULL)
258           return NULL;
259         This->lpInBuffer = (BYTE*)This->lpInFormat + This->cbInFormat;
260       }
261
262       if (readSamples != 1)
263         return NULL;
264       if (readBytes != 0) {
265         This->lpInFormat->biSizeImage = readBytes;
266
267         /* nothing to decompress? */
268         if (This->hic == NULL) {
269           This->lCurrentFrame = lPos;
270           return This->lpInFormat;
271         }
272
273         if (This->bResize) {
274           ICDecompressEx(This->hic,0,This->lpInFormat,This->lpInBuffer,0,0,
275                          This->lpInFormat->biWidth,This->lpInFormat->biHeight,
276                          This->lpOutFormat,This->lpOutBuffer,This->x,This->y,
277                          This->dx,This->dy);
278         } else {
279           ICDecompress(This->hic, 0, This->lpInFormat, This->lpInBuffer,
280                        This->lpOutFormat, This->lpOutBuffer);
281         }
282       }
283     } /* for (lNext < lPos) */
284   } /* if (This->lCurrentFrame != lPos) */
285
286   return (This->hic == NULL ? This->lpInFormat : This->lpOutFormat);
287 }
288
289 static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame *iface, LONG lStart,
290                                         LONG lEnd, LONG lRate)
291 {
292   ICOM_THIS(IGetFrameImpl,iface);
293
294   TRACE("(%p,%ld,%ld,%ld)\n", iface, lStart, lEnd, lRate);
295
296   This->bFixedStream = TRUE;
297
298   return (IGetFrame_GetFrame(iface, lStart) ? AVIERR_OK : AVIERR_ERROR);
299 }
300
301 static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame *iface)
302 {
303   ICOM_THIS(IGetFrameImpl,iface);
304
305   TRACE("(%p)\n", iface);
306
307   This->bFixedStream = FALSE;
308
309   return AVIERR_OK;
310 }
311
312 static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame *iface,
313                                             LPBITMAPINFOHEADER lpbiWanted,
314                                             LPVOID lpBits, INT x, INT y,
315                                             INT dx, INT dy)
316 {
317   ICOM_THIS(IGetFrameImpl,iface);
318
319   AVISTREAMINFOW     sInfo;
320   LPBITMAPINFOHEADER lpbi         = lpbiWanted;
321   BOOL               bBestDisplay = FALSE;
322
323   TRACE("(%p,%p,%p,%d,%d,%d,%d)\n", iface, lpbiWanted, lpBits,
324         x, y, dx, dy);
325
326   if (This->pStream == NULL)
327     return AVIERR_ERROR;
328
329   if ((LONG)lpbiWanted == AVIGETFRAMEF_BESTDISPLAYFMT) {
330     lpbi = NULL;
331     bBestDisplay = TRUE;
332   }
333
334   IAVIStream_Info(This->pStream, &sInfo, sizeof(sInfo));
335   if (sInfo.fccType != streamtypeVIDEO)
336     return AVIERR_UNSUPPORTED;
337
338   This->bFormatChanges =
339     (sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES ? TRUE : FALSE );
340   This->dwFormatChangeCount = sInfo.dwFormatChangeCount;
341   This->dwEditCount         = sInfo.dwEditCount;
342   This->lCurrentFrame       = -1;
343
344   /* get input format from stream */
345   if (This->lpInFormat == NULL) {
346     HRESULT hr;
347
348     This->cbInBuffer = (LONG)sInfo.dwSuggestedBufferSize;
349     if (This->cbInBuffer == 0)
350       This->cbInBuffer = 1024;
351
352     AVIStreamFormatSize(This->pStream, sInfo.dwStart, &This->cbInFormat);
353
354     This->lpInFormat =
355       (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, This->cbInFormat + This->cbInBuffer);
356     if (This->lpInFormat == NULL) {
357       AVIFILE_CloseCompressor(This);
358       return AVIERR_MEMORY;
359     }
360
361     hr = AVIStreamReadFormat(This->pStream, sInfo.dwStart, This->lpInFormat, &This->cbInFormat);
362     if (FAILED(hr)) {
363       AVIFILE_CloseCompressor(This);
364       return hr;
365     }
366
367     This->lpInBuffer = ((LPBYTE)This->lpInFormat) + This->cbInFormat;
368   }
369
370   /* check input format */
371   if (This->lpInFormat->biClrUsed == 0 && This->lpInFormat->biBitCount <= 8)
372     This->lpInFormat->biClrUsed = 1u << This->lpInFormat->biBitCount;
373   if (This->lpInFormat->biSizeImage == 0 &&
374       This->lpInFormat->biCompression == BI_RGB) {
375     This->lpInFormat->biSizeImage =
376       DIBWIDTHBYTES(*This->lpInFormat) * This->lpInFormat->biHeight;
377   }
378
379   /* only to pass through? */
380   if (This->lpInFormat->biCompression == BI_RGB && lpBits == NULL) {
381     if (lpbi == NULL || 
382         (lpbi->biCompression == BI_RGB &&
383          lpbi->biWidth == This->lpInFormat->biWidth &&
384          lpbi->biHeight == This->lpInFormat->biHeight &&
385          lpbi->biBitCount == This->lpInFormat->biBitCount)) {
386       This->lpOutFormat = This->lpInFormat;
387       This->lpOutBuffer = DIBPTR(This->lpInFormat);
388       return AVIERR_OK;
389     }
390   }
391
392   /* need memory for output format? */
393   if (This->lpOutFormat == NULL) {
394     This->lpOutFormat =
395       (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, sizeof(BITMAPINFOHEADER)
396                                          + 256 * sizeof(RGBQUAD));
397     if (This->lpOutFormat == NULL) {
398       AVIFILE_CloseCompressor(This);
399       return AVIERR_MEMORY;
400     }
401   }
402
403   /* need handle to video compressor */
404   if (This->hic == NULL) {
405     FOURCC fccHandler;
406
407     if (This->lpInFormat->biCompression == BI_RGB)
408       fccHandler = comptypeDIB;
409     else if (This->lpInFormat->biCompression == BI_RLE8)
410       fccHandler = mmioFOURCC('R','L','E',' ');
411     else
412       fccHandler = sInfo.fccHandler;
413
414     if (lpbi != NULL) {
415       if (lpbi->biWidth == 0)
416         lpbi->biWidth = This->lpInFormat->biWidth;
417       if (lpbi->biHeight == 0)
418         lpbi->biHeight = This->lpInFormat->biHeight;
419     }
420
421     This->hic = ICLocate(ICTYPE_VIDEO, fccHandler, This->lpInFormat, lpbi, ICMODE_DECOMPRESS);
422     if (This->hic == NULL) {
423       AVIFILE_CloseCompressor(This);
424       return AVIERR_NOCOMPRESSOR;
425     }
426   }
427
428   /* output format given? */
429   if (lpbi != NULL) {
430     /* check the given output format ... */
431     if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
432       lpbi->biClrUsed = 1u << lpbi->biBitCount;
433
434     /* ... and remember it */
435     memcpy(This->lpOutFormat, lpbi,
436            lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD));
437     if (lpbi->biBitCount <= 8)
438       ICDecompressGetPalette(This->hic, This->lpInFormat, This->lpOutFormat);
439
440     return AVIERR_OK;
441   } else {
442     if (bBestDisplay) {
443       ICGetDisplayFormat(This->hic, This->lpInFormat,
444                          This->lpOutFormat, 0, dx, dy);
445     } else if (ICDecompressGetFormat(This->hic, This->lpInFormat,
446                                      This->lpOutFormat) < 0) {
447       AVIFILE_CloseCompressor(This);
448       return AVIERR_NOCOMPRESSOR;
449     }
450
451     /* check output format */
452     if (This->lpOutFormat->biClrUsed == 0 &&
453         This->lpOutFormat->biBitCount <= 8)
454       This->lpOutFormat->biClrUsed = 1u << This->lpOutFormat->biBitCount;
455     if (This->lpOutFormat->biSizeImage == 0 &&
456         This->lpOutFormat->biCompression == BI_RGB) {
457       This->lpOutFormat->biSizeImage =
458         DIBWIDTHBYTES(*This->lpOutFormat) * This->lpOutFormat->biHeight;
459     }
460
461     if (lpBits == NULL) {
462       register DWORD size = This->lpOutFormat->biClrUsed * sizeof(RGBQUAD);
463
464       size += This->lpOutFormat->biSize + This->lpOutFormat->biSizeImage;
465       This->lpOutFormat =
466         (LPBITMAPINFOHEADER)GlobalReAllocPtr(This->lpOutFormat, size, GMEM_MOVEABLE);
467       if (This->lpOutFormat == NULL) {
468         AVIFILE_CloseCompressor(This);
469         return AVIERR_MEMORY;
470       }
471       This->lpOutBuffer = DIBPTR(This->lpOutFormat);
472     } else
473       This->lpOutBuffer = lpBits;
474
475     /* for user size was irrelevant */
476     if (dx == -1)
477       dx = This->lpOutFormat->biWidth;
478     if (dy == -1)
479       dy = This->lpOutFormat->biHeight;
480
481     /* need to resize? */
482     if (x != 0 || y != 0) {
483       if (dy == This->lpOutFormat->biHeight &&
484           dx == This->lpOutFormat->biWidth)
485         This->bResize = FALSE;
486       else
487         This->bResize = TRUE;
488     }
489
490     if (This->bResize) {
491       This->x  = x;
492       This->y  = y;
493       This->dx = dx;
494       This->dy = dy;
495
496       if (ICDecompressExBegin(This->hic,0,This->lpInFormat,This->lpInBuffer,0,
497                               0,This->lpInFormat->biWidth,
498                               This->lpInFormat->biHeight,This->lpOutFormat,
499                               This->lpOutBuffer, x, y, dx, dy) == ICERR_OK)
500         return AVIERR_OK;
501     } else if (ICDecompressBegin(This->hic, This->lpInFormat,
502                                  This->lpOutFormat) == ICERR_OK)
503       return AVIERR_OK;
504
505     AVIFILE_CloseCompressor(This);
506
507     return AVIERR_COMPRESSOR;
508   }
509 }
510
511 /***********************************************************************/