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