ReactOS  0.4.15-dev-499-g1f31905
icmstream.c
Go to the documentation of this file.
1 /*
2  * Copyright 2002 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 <assert.h>
20 #include <stdarg.h>
21 
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "winuser.h"
26 #include "winerror.h"
27 #include "mmsystem.h"
28 #include "vfw.h"
29 
30 #include "avifile_private.h"
31 
32 #include "wine/debug.h"
33 
35 
36 #define MAX_FRAMESIZE (16 * 1024 * 1024)
37 #define MAX_FRAMESIZE_DIFF 512
38 
39 /***********************************************************************/
40 
41 typedef struct _IAVIStreamImpl {
42  /* IUnknown stuff */
44  LONG ref;
45 
46  /* IAVIStream stuff */
49 
51  HIC hic;
53 
60 
61  LPBITMAPINFOHEADER lpbiCur; /* current frame */
63  LPBITMAPINFOHEADER lpbiPrev; /* previous frame */
65 
66  LPBITMAPINFOHEADER lpbiOutput; /* output format of codec */
68  LPBITMAPINFOHEADER lpbiInput; /* input format for codec */
71 
72 /***********************************************************************/
73 
75  LPBITMAPINFOHEADER lpbi, LPVOID lpBits);
77 
79 {
80  return CONTAINING_RECORD(iface, IAVIStreamImpl, IAVIStream_iface);
81 }
82 
83 static inline void AVIFILE_Reset(IAVIStreamImpl *This)
84 {
85  This->lCurrent = -1;
86  This->lLastKey = 0;
87  This->dwLastQuality = ICQUALITY_HIGH;
88  This->dwUnusedBytes = 0;
89 }
90 
92  REFIID refiid, LPVOID *obj)
93 {
95 
96  TRACE("(%p,%s,%p)\n", iface, debugstr_guid(refiid), obj);
97 
98  if (IsEqualGUID(&IID_IUnknown, refiid) ||
99  IsEqualGUID(&IID_IAVIStream, refiid)) {
100  *obj = &This->IAVIStream_iface;
101  IAVIStream_AddRef(iface);
102 
103  return S_OK;
104  }
105 
106  return OLE_E_ENUM_NOMORE;
107 }
108 
110 {
113 
114  TRACE("(%p) -> %d\n", iface, ref);
115 
116  /* also add reference to the nested stream */
117  if (This->pStream != NULL)
118  IAVIStream_AddRef(This->pStream);
119 
120  return ref;
121 }
122 
124 {
127 
128  TRACE("(%p) -> %d\n", iface, ref);
129 
130  if (ref == 0) {
131  /* destruct */
132  if (This->pg != NULL) {
134  This->pg = NULL;
135  }
136  if (This->pStream != NULL) {
137  IAVIStream_Release(This->pStream);
138  This->pStream = NULL;
139  }
140  if (This->hic != NULL) {
141  if (This->lpbiPrev != NULL) {
142  ICDecompressEnd(This->hic);
143  HeapFree(GetProcessHeap(), 0, This->lpbiPrev);
144  This->lpbiPrev = NULL;
145  This->lpPrev = NULL;
146  }
147  ICCompressEnd(This->hic);
148  This->hic = NULL;
149  }
150  if (This->lpbiCur != NULL) {
151  HeapFree(GetProcessHeap(), 0, This->lpbiCur);
152  This->lpbiCur = NULL;
153  This->lpCur = NULL;
154  }
155  if (This->lpbiOutput != NULL) {
156  HeapFree(GetProcessHeap(), 0, This->lpbiOutput);
157  This->lpbiOutput = NULL;
158  This->cbOutput = 0;
159  }
160  if (This->lpbiInput != NULL) {
161  HeapFree(GetProcessHeap(), 0, This->lpbiInput);
162  This->lpbiInput = NULL;
163  This->cbInput = 0;
164  }
165 
167 
168  return 0;
169  }
170 
171  /* also release reference to the nested stream */
172  if (This->pStream != NULL)
173  IAVIStream_Release(This->pStream);
174 
175  return ref;
176 }
177 
178 /* lParam1: PAVISTREAM
179  * lParam2: LPAVICOMPRESSOPTIONS
180  */
182  LPARAM lParam2)
183 {
185 
186  ICINFO icinfo;
187  ICCOMPRESSFRAMES icFrames;
189 
190  TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
191 
192  /* check parameter */
193  if ((LPVOID)lParam1 == NULL)
194  return AVIERR_BADPARAM;
195 
196  /* get infos from stream */
197  IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
198  if (This->sInfo.fccType != streamtypeVIDEO)
199  return AVIERR_ERROR; /* error in registry or AVIMakeCompressedStream */
200 
201  /* add reference to the stream */
202  This->pStream = (PAVISTREAM)lParam1;
203  IAVIStream_AddRef(This->pStream);
204 
206 
207  if (pco != NULL && pco->fccHandler != comptypeDIB) {
208  /* we should compress */
209  This->sInfo.fccHandler = pco->fccHandler;
210 
211  This->hic = ICOpen(ICTYPE_VIDEO, pco->fccHandler, ICMODE_COMPRESS);
212  if (This->hic == NULL)
213  return AVIERR_NOCOMPRESSOR;
214 
215  /* restore saved state of codec */
216  if (pco->cbParms > 0 && pco->lpParms != NULL) {
217  ICSetState(This->hic, pco->lpParms, pco->cbParms);
218  }
219 
220  /* set quality -- resolve default quality */
221  This->sInfo.dwQuality = pco->dwQuality;
222  if (pco->dwQuality == ICQUALITY_DEFAULT)
223  This->sInfo.dwQuality = ICGetDefaultQuality(This->hic);
224 
225  /* get capabilities of codec */
226  ICGetInfo(This->hic, &icinfo, sizeof(icinfo));
227  This->dwICMFlags = icinfo.dwFlags;
228 
229  /* use keyframes? */
230  if ((pco->dwFlags & AVICOMPRESSF_KEYFRAMES) &&
232  This->lKeyFrameEvery = pco->dwKeyFrameEvery;
233  } else
234  This->lKeyFrameEvery = 1;
235 
236  /* use datarate? */
237  if ((pco->dwFlags & AVICOMPRESSF_DATARATE)) {
238  /* Do we have a chance to reduce size to desired one? */
239  if ((icinfo.dwFlags & (VIDCF_CRUNCH|VIDCF_QUALITY)) == 0)
240  return AVIERR_NOCOMPRESSOR;
241 
242  assert(This->sInfo.dwRate != 0);
243 
244  This->dwBytesPerFrame = MulDiv(pco->dwBytesPerSecond,
245  This->sInfo.dwScale, This->sInfo.dwRate);
246  } else {
247  pco->dwBytesPerSecond = 0;
248  This->dwBytesPerFrame = 0;
249  }
250 
251  if (icinfo.dwFlags & VIDCF_COMPRESSFRAMES) {
252  memset(&icFrames, 0, sizeof(icFrames));
253  icFrames.lpbiOutput = This->lpbiOutput;
254  icFrames.lpbiInput = This->lpbiInput;
255  icFrames.lFrameCount = This->sInfo.dwLength;
256  icFrames.lQuality = This->sInfo.dwQuality;
257  icFrames.lDataRate = pco->dwBytesPerSecond;
258  icFrames.lKeyRate = This->lKeyFrameEvery;
259  icFrames.dwRate = This->sInfo.dwRate;
260  icFrames.dwScale = This->sInfo.dwScale;
262  (LPARAM)&icFrames, (LPARAM)sizeof(icFrames));
263  }
264  } else
265  This->sInfo.fccHandler = comptypeDIB;
266 
267  return AVIERR_OK;
268 }
269 
271  LONG size)
272 {
274 
275  TRACE("(%p,%p,%d)\n", iface, psi, size);
276 
277  if (psi == NULL)
278  return AVIERR_BADPARAM;
279  if (size < 0)
280  return AVIERR_BADSIZE;
281 
282  memcpy(psi, &This->sInfo, min((DWORD)size, sizeof(This->sInfo)));
283 
284  if ((DWORD)size < sizeof(This->sInfo))
285  return AVIERR_BUFFERTOOSMALL;
286  return AVIERR_OK;
287 }
288 
290  LONG flags)
291 {
293 
294  TRACE("(%p,%d,0x%08X)\n",iface,pos,flags);
295 
296  if (flags & FIND_FROM_START) {
297  pos = This->sInfo.dwStart;
299  flags |= FIND_NEXT;
300  }
301 
302  if (flags & FIND_RET)
303  WARN(": FIND_RET flags will be ignored!\n");
304 
305  if (flags & FIND_KEY) {
306  if (This->hic == NULL)
307  return pos; /* we decompress so every frame is a keyframe */
308 
309  if (flags & FIND_PREV) {
310  /* need to read old or new frames? */
311  if (This->lLastKey <= pos || pos < This->lCurrent)
312  IAVIStream_Read(iface, pos, 1, NULL, 0, NULL, NULL);
313 
314  return This->lLastKey;
315  }
316  } else if (flags & FIND_ANY) {
317  return pos; /* We really don't know, reread is too expensive, so guess. */
318  } else if (flags & FIND_FORMAT) {
319  if (flags & FIND_PREV)
320  return 0;
321  }
322 
323  return -1;
324 }
325 
327  LPVOID format, LONG *formatsize)
328 {
330 
331  LPBITMAPINFOHEADER lpbi;
332  HRESULT hr;
333 
334  TRACE("(%p,%d,%p,%p)\n", iface, pos, format, formatsize);
335 
336  if (formatsize == NULL)
337  return AVIERR_BADPARAM;
338 
339  if (This->pg == NULL) {
341 
342  if (FAILED(hr))
343  return hr;
344  }
345 
346  lpbi = AVIStreamGetFrame(This->pg, pos);
347  if (lpbi == NULL)
348  return AVIERR_MEMORY;
349 
350  if (This->hic == NULL) {
351  LONG size = lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD);
352 
353  if (size > 0) {
354  if (This->sInfo.dwSuggestedBufferSize < lpbi->biSizeImage)
355  This->sInfo.dwSuggestedBufferSize = lpbi->biSizeImage;
356 
357  This->cbOutput = size;
358  if (format != NULL) {
359  if (This->lpbiOutput != NULL)
360  memcpy(format, This->lpbiOutput, min(*formatsize, This->cbOutput));
361  else
362  memcpy(format, lpbi, min(*formatsize, size));
363  }
364  }
365  } else if (format != NULL)
366  memcpy(format, This->lpbiOutput, min(*formatsize, This->cbOutput));
367 
368  if (*formatsize < This->cbOutput)
370  else
371  hr = AVIERR_OK;
372 
373  *formatsize = This->cbOutput;
374  return hr;
375 }
376 
378  LPVOID format, LONG formatsize)
379 {
381 
382  TRACE("(%p,%d,%p,%d)\n", iface, pos, format, formatsize);
383 
384  /* check parameters */
385  if (format == NULL || formatsize <= 0)
386  return AVIERR_BADPARAM;
387 
388  /* We can only accept RGB data for writing */
389  if (((LPBITMAPINFOHEADER)format)->biCompression != BI_RGB) {
390  WARN(": need RGB data as input\n");
391  return AVIERR_UNSUPPORTED;
392  }
393 
394  /* Input format already known?
395  * Changing of palette is supported, but be quiet if it's the same */
396  if (This->lpbiInput != NULL) {
397  if (This->cbInput != formatsize)
398  return AVIERR_UNSUPPORTED;
399 
400  if (memcmp(format, This->lpbiInput, formatsize) == 0)
401  return AVIERR_OK;
402  }
403 
404  /* Does the nested stream support writing? */
405  if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
406  return AVIERR_READONLY;
407 
408  /* check if frame is already written */
409  if (This->sInfo.dwLength + This->sInfo.dwStart > pos)
410  return AVIERR_UNSUPPORTED;
411 
412  /* check if we should compress */
413  if (This->sInfo.fccHandler == 0 ||
414  This->sInfo.fccHandler == mmioFOURCC('N','O','N','E'))
415  This->sInfo.fccHandler = comptypeDIB;
416 
417  /* only pass through? */
418  if (This->sInfo.fccHandler == comptypeDIB)
419  return IAVIStream_SetFormat(This->pStream, pos, format, formatsize);
420 
421  /* initial format setting? */
422  if (This->lpbiInput == NULL) {
423  ULONG size;
424 
425  assert(This->hic != NULL);
426 
427  /* get memory for input format */
428  This->lpbiInput = HeapAlloc(GetProcessHeap(), 0, formatsize);
429  if (This->lpbiInput == NULL)
430  return AVIERR_MEMORY;
431  This->cbInput = formatsize;
432  memcpy(This->lpbiInput, format, formatsize);
433 
434  /* get output format */
435  size = ICCompressGetFormatSize(This->hic, This->lpbiInput);
436  if (size < sizeof(BITMAPINFOHEADER))
437  return AVIERR_COMPRESSOR;
438  This->lpbiOutput = HeapAlloc(GetProcessHeap(), 0, size);
439  if (This->lpbiOutput == NULL)
440  return AVIERR_MEMORY;
441  This->cbOutput = size;
442  if (ICCompressGetFormat(This->hic,This->lpbiInput,This->lpbiOutput) < S_OK)
443  return AVIERR_COMPRESSOR;
444 
445  /* update AVISTREAMINFO structure */
446  This->sInfo.rcFrame.right =
447  This->sInfo.rcFrame.left + This->lpbiOutput->biWidth;
448  This->sInfo.rcFrame.bottom =
449  This->sInfo.rcFrame.top + This->lpbiOutput->biHeight;
450 
451  /* prepare codec for compression */
452  if (ICCompressBegin(This->hic, This->lpbiInput, This->lpbiOutput) != S_OK)
453  return AVIERR_COMPRESSOR;
454 
455  /* allocate memory for compressed frame */
456  size = ICCompressGetSize(This->hic, This->lpbiInput, This->lpbiOutput);
457  This->lpbiCur = HeapAlloc(GetProcessHeap(), 0, This->cbOutput + size);
458  if (This->lpbiCur == NULL)
459  return AVIERR_MEMORY;
460  memcpy(This->lpbiCur, This->lpbiOutput, This->cbOutput);
461  This->lpCur = DIBPTR(This->lpbiCur);
462 
463  /* allocate memory for last frame if needed */
464  if (This->lKeyFrameEvery != 1 &&
465  (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
466  size = ICDecompressGetFormatSize(This->hic, This->lpbiOutput);
467  This->lpbiPrev = HeapAlloc(GetProcessHeap(), 0, size);
468  if (This->lpbiPrev == NULL)
469  return AVIERR_MEMORY;
470  if (ICDecompressGetFormat(This->hic, This->lpbiOutput, This->lpbiPrev) < S_OK)
471  return AVIERR_COMPRESSOR;
472 
473  if (This->lpbiPrev->biSizeImage == 0) {
474  This->lpbiPrev->biSizeImage =
475  DIBWIDTHBYTES(*This->lpbiPrev) * This->lpbiPrev->biHeight;
476  }
477 
478  /* get memory for format and picture */
479  size += This->lpbiPrev->biSizeImage;
480  This->lpbiPrev = HeapReAlloc(GetProcessHeap(), 0, This->lpbiPrev, size);
481  if (This->lpbiPrev == NULL)
482  return AVIERR_MEMORY;
483  This->lpPrev = DIBPTR(This->lpbiPrev);
484 
485  /* prepare codec also for decompression */
486  if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
487  return AVIERR_COMPRESSOR;
488  }
489  } else {
490  /* format change -- check that's only the palette */
491  LPBITMAPINFOHEADER lpbi = format;
492 
493  if (lpbi->biSize != This->lpbiInput->biSize ||
494  lpbi->biWidth != This->lpbiInput->biWidth ||
495  lpbi->biHeight != This->lpbiInput->biHeight ||
496  lpbi->biBitCount != This->lpbiInput->biBitCount ||
497  lpbi->biPlanes != This->lpbiInput->biPlanes ||
498  lpbi->biCompression != This->lpbiInput->biCompression ||
499  lpbi->biClrUsed != This->lpbiInput->biClrUsed)
500  return AVIERR_UNSUPPORTED;
501 
502  /* get new output format */
503  if (ICCompressGetFormat(This->hic, lpbi, This->lpbiOutput) < S_OK)
504  return AVIERR_BADFORMAT;
505 
506  /* restart compression */
507  ICCompressEnd(This->hic);
508  if (ICCompressBegin(This->hic, lpbi, This->lpbiOutput) != S_OK)
509  return AVIERR_COMPRESSOR;
510 
511  /* check if we need to restart decompression also */
512  if (This->lKeyFrameEvery != 1 &&
513  (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
514  ICDecompressEnd(This->hic);
515  if (ICDecompressGetFormat(This->hic,This->lpbiOutput,This->lpbiPrev) < S_OK)
516  return AVIERR_COMPRESSOR;
517  if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
518  return AVIERR_COMPRESSOR;
519  }
520  }
521 
522  /* tell nested stream the new format */
523  return IAVIStream_SetFormat(This->pStream, pos,
524  This->lpbiOutput, This->cbOutput);
525 }
526 
529  LONG buffersize, LPLONG bytesread,
530  LPLONG samplesread)
531 {
533 
534  LPBITMAPINFOHEADER lpbi;
535 
536  TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", iface, start, samples, buffer,
537  buffersize, bytesread, samplesread);
538 
539  /* clear return parameters if given */
540  if (bytesread != NULL)
541  *bytesread = 0;
542  if (samplesread != NULL)
543  *samplesread = 0;
544 
545  if (samples == 0)
546  return AVIERR_OK;
547 
548  /* check parameters */
549  if (samples != 1 && (bytesread == NULL && samplesread == NULL))
550  return AVIERR_BADPARAM;
551  if (samples == -1) /* read as much as we could */
552  samples = 1;
553 
554  if (This->pg == NULL) {
556 
557  if (FAILED(hr))
558  return hr;
559  }
560 
561  /* compress or decompress? */
562  if (This->hic == NULL) {
563  /* decompress */
564  lpbi = AVIStreamGetFrame(This->pg, start);
565  if (lpbi == NULL)
566  return AVIERR_MEMORY;
567 
568  if (buffer != NULL && buffersize > 0) {
569  /* check buffersize */
570  if (buffersize < lpbi->biSizeImage)
571  return AVIERR_BUFFERTOOSMALL;
572 
573  memcpy(buffer, DIBPTR(lpbi), lpbi->biSizeImage);
574  }
575 
576  /* fill out return parameters if given */
577  if (bytesread != NULL)
578  *bytesread = lpbi->biSizeImage;
579  } else {
580  /* compress */
581  if (This->lCurrent > start)
583 
584  while (start > This->lCurrent) {
585  HRESULT hr;
586 
587  lpbi = AVIStreamGetFrame(This->pg, ++This->lCurrent);
588  if (lpbi == NULL) {
590  return AVIERR_MEMORY;
591  }
592 
593  hr = AVIFILE_EncodeFrame(This, lpbi, DIBPTR(lpbi));
594  if (FAILED(hr)) {
596  return hr;
597  }
598  }
599 
600  if (buffer != NULL && buffersize > 0) {
601  /* check buffersize */
602  if (This->lpbiCur->biSizeImage > buffersize)
603  return AVIERR_BUFFERTOOSMALL;
604 
605  memcpy(buffer, This->lpCur, This->lpbiCur->biSizeImage);
606  }
607 
608  /* fill out return parameters if given */
609  if (bytesread != NULL)
610  *bytesread = This->lpbiCur->biSizeImage;
611  }
612 
613  /* fill out return parameters if given */
614  if (samplesread != NULL)
615  *samplesread = 1;
616 
617  return AVIERR_OK;
618 }
619 
622  LONG buffersize, DWORD flags,
623  LPLONG sampwritten,
624  LPLONG byteswritten)
625 {
627 
628  HRESULT hr;
629 
630  TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n", iface, start, samples,
631  buffer, buffersize, flags, sampwritten, byteswritten);
632 
633  /* clear return parameters if given */
634  if (sampwritten != NULL)
635  *sampwritten = 0;
636  if (byteswritten != NULL)
637  *byteswritten = 0;
638 
639  /* check parameters */
640  if (buffer == NULL && (buffersize > 0 || samples > 0))
641  return AVIERR_BADPARAM;
642 
643  if (This->sInfo.fccHandler == comptypeDIB) {
644  /* only pass through */
646 
647  return IAVIStream_Write(This->pStream, start, samples, buffer, buffersize,
648  flags, sampwritten, byteswritten);
649  } else {
650  /* compress data before writing to pStream */
651  if (samples != 1 && (sampwritten == NULL && byteswritten == NULL))
652  return AVIERR_UNSUPPORTED;
653 
654  This->lCurrent = start;
655  hr = AVIFILE_EncodeFrame(This, This->lpbiInput, buffer);
656  if (FAILED(hr))
657  return hr;
658 
659  if (This->lLastKey == start)
661 
662  return IAVIStream_Write(This->pStream, start, samples, This->lpCur,
663  This->lpbiCur->biSizeImage, flags, byteswritten,
664  sampwritten);
665  }
666 }
667 
669  LONG samples)
670 {
672 
673  TRACE("(%p,%d,%d)\n", iface, start, samples);
674 
675  return IAVIStream_Delete(This->pStream, start, samples);
676 }
677 
679  LPVOID lp, LPLONG lpread)
680 {
682 
683  TRACE("(%p,0x%08X,%p,%p)\n", iface, fcc, lp, lpread);
684 
685  assert(This->pStream != NULL);
686 
687  return IAVIStream_ReadData(This->pStream, fcc, lp, lpread);
688 }
689 
691  LPVOID lp, LONG size)
692 {
694 
695  TRACE("(%p,0x%08x,%p,%d)\n", iface, fcc, lp, size);
696 
697  assert(This->pStream != NULL);
698 
699  return IAVIStream_WriteData(This->pStream, fcc, lp, size);
700 }
701 
703  LPAVISTREAMINFOW info, LONG infolen)
704 {
705  FIXME("(%p,%p,%d): stub\n", iface, info, infolen);
706 
707  return E_FAIL;
708 }
709 
710 static const struct IAVIStreamVtbl iicmst = {
725 };
726 
728 {
729  IAVIStreamImpl *pstream;
730  HRESULT hr;
731 
732  assert(riid != NULL && ppv != NULL);
733 
734  *ppv = NULL;
735 
737  if (pstream == NULL)
738  return AVIERR_MEMORY;
739 
740  pstream->IAVIStream_iface.lpVtbl = &iicmst;
741  AVIFILE_Reset(pstream);
742 
744  if (FAILED(hr))
745  HeapFree(GetProcessHeap(), 0, pstream);
746 
747  return hr;
748 }
749 
750 /***********************************************************************/
751 
753  LPBITMAPINFOHEADER lpbi, LPVOID lpBits)
754 {
755  DWORD dwMinQual, dwMaxQual, dwCurQual;
756  DWORD dwRequest;
757  DWORD icmFlags = 0;
758  DWORD idxFlags = 0;
759  BOOL bDecreasedQual = FALSE;
760  BOOL doSizeCheck;
761  BOOL noPrev;
762 
763  /* make lKeyFrameEvery and at start a keyframe */
764  if ((This->lKeyFrameEvery != 0 &&
765  (This->lCurrent - This->lLastKey) >= This->lKeyFrameEvery) ||
766  This->lCurrent == This->sInfo.dwStart) {
767  idxFlags = AVIIF_KEYFRAME;
768  icmFlags = ICCOMPRESS_KEYFRAME;
769  }
770 
771  if (This->lKeyFrameEvery != 0) {
772  if (This->lCurrent == This->sInfo.dwStart) {
773  if (idxFlags & AVIIF_KEYFRAME) {
774  /* allow keyframes to consume all unused bytes */
775  dwRequest = This->dwBytesPerFrame + This->dwUnusedBytes;
776  This->dwUnusedBytes = 0;
777  } else {
778  /* for non-keyframes only allow some of the unused bytes to be consumed */
779  DWORD tmp1 = 0;
780  DWORD tmp2;
781 
782  if (This->dwBytesPerFrame >= This->dwUnusedBytes)
783  tmp1 = This->dwBytesPerFrame / This->lKeyFrameEvery;
784  tmp2 = (This->dwUnusedBytes + tmp1) / This->lKeyFrameEvery;
785 
786  dwRequest = This->dwBytesPerFrame - tmp1 + tmp2;
787  This->dwUnusedBytes -= tmp2;
788  }
789  } else
790  dwRequest = MAX_FRAMESIZE;
791  } else {
792  /* only one keyframe at start desired */
793  if (This->lCurrent == This->sInfo.dwStart) {
794  dwRequest = This->dwBytesPerFrame + This->dwUnusedBytes;
795  This->dwUnusedBytes = 0;
796  } else
797  dwRequest = MAX_FRAMESIZE;
798  }
799 
800  /* must we check for frame size to gain the requested
801  * data rate or can we trust the codec? */
802  doSizeCheck = (dwRequest != 0 && ((This->dwICMFlags & (VIDCF_CRUNCH|VIDCF_QUALITY)) == 0));
803 
804  dwMaxQual = dwCurQual = This->sInfo.dwQuality;
805  dwMinQual = ICQUALITY_LOW;
806 
807  noPrev = TRUE;
808  if ((icmFlags & ICCOMPRESS_KEYFRAME) == 0 &&
809  (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0)
810  noPrev = FALSE;
811 
812  do {
813  DWORD idxCkid = 0;
814  DWORD res;
815 
816  res = ICCompress(This->hic,icmFlags,This->lpbiCur,This->lpCur,lpbi,lpBits,
817  &idxCkid, &idxFlags, This->lCurrent, dwRequest, dwCurQual,
818  noPrev ? NULL:This->lpbiPrev, noPrev ? NULL:This->lpPrev);
819  if (res == ICERR_NEWPALETTE) {
820  FIXME(": codec has changed palette -- unhandled!\n");
821  } else if (res != ICERR_OK)
822  return AVIERR_COMPRESSOR;
823 
824  /* need to check for framesize */
825  if (! doSizeCheck)
826  break;
827 
828  if (dwRequest >= This->lpbiCur->biSizeImage) {
829  /* frame is smaller -- try to maximize quality */
830  if (dwMaxQual - dwCurQual > 10) {
831  DWORD tmp = dwRequest / 8;
832 
833  if (tmp < MAX_FRAMESIZE_DIFF)
834  tmp = MAX_FRAMESIZE_DIFF;
835 
836  if (tmp < dwRequest - This->lpbiCur->biSizeImage && bDecreasedQual) {
837  tmp = dwCurQual;
838  dwCurQual = (dwMinQual + dwMaxQual) / 2;
839  dwMinQual = tmp;
840  continue;
841  }
842  } else
843  break;
844  } else if (dwMaxQual - dwMinQual <= 1) {
845  break;
846  } else {
847  dwMaxQual = dwCurQual;
848 
849  if (bDecreasedQual || dwCurQual == This->dwLastQuality)
850  dwCurQual = (dwMinQual + dwMaxQual) / 2;
851  else
852  FIXME(": no new quality computed min=%u cur=%u max=%u last=%u\n",
853  dwMinQual, dwCurQual, dwMaxQual, This->dwLastQuality);
854 
855  bDecreasedQual = TRUE;
856  }
857  } while (TRUE);
858 
859  /* remember some values */
860  This->dwLastQuality = dwCurQual;
861  This->dwUnusedBytes = dwRequest - This->lpbiCur->biSizeImage;
862  if (icmFlags & ICCOMPRESS_KEYFRAME)
863  This->lLastKey = This->lCurrent;
864 
865  /* Does we manage previous frame? */
866  if (This->lpPrev != NULL && This->lKeyFrameEvery != 1)
867  ICDecompress(This->hic, 0, This->lpbiCur, This->lpCur,
868  This->lpbiPrev, This->lpPrev);
869 
870  return AVIERR_OK;
871 }
872 
874 {
875  LPBITMAPINFOHEADER lpbi;
876  DWORD size;
877 
878  /* pre-conditions */
879  assert(This != NULL);
880  assert(This->pStream != NULL);
881  assert(This->pg == NULL);
882 
883  This->pg = AVIStreamGetFrameOpen(This->pStream, NULL);
884  if (This->pg == NULL)
885  return AVIERR_ERROR;
886 
887  /* When we only decompress this is enough */
888  if (This->sInfo.fccHandler == comptypeDIB)
889  return AVIERR_OK;
890 
891  assert(This->hic != NULL);
892  assert(This->lpbiOutput == NULL);
893 
894  /* get input format */
895  lpbi = AVIStreamGetFrame(This->pg, This->sInfo.dwStart);
896  if (lpbi == NULL)
897  return AVIERR_MEMORY;
898 
899  /* get memory for output format */
900  size = ICCompressGetFormatSize(This->hic, lpbi);
901  if ((LONG)size < (LONG)sizeof(BITMAPINFOHEADER))
902  return AVIERR_COMPRESSOR;
903  This->lpbiOutput = HeapAlloc(GetProcessHeap(), 0, size);
904  if (This->lpbiOutput == NULL)
905  return AVIERR_MEMORY;
906  This->cbOutput = size;
907 
908  if (ICCompressGetFormat(This->hic, lpbi, This->lpbiOutput) < S_OK)
909  return AVIERR_BADFORMAT;
910 
911  /* update AVISTREAMINFO structure */
912  This->sInfo.rcFrame.right =
913  This->sInfo.rcFrame.left + This->lpbiOutput->biWidth;
914  This->sInfo.rcFrame.bottom =
915  This->sInfo.rcFrame.top + This->lpbiOutput->biHeight;
916  This->sInfo.dwSuggestedBufferSize =
917  ICCompressGetSize(This->hic, lpbi, This->lpbiOutput);
918 
919  /* prepare codec for compression */
920  if (ICCompressBegin(This->hic, lpbi, This->lpbiOutput) != S_OK)
921  return AVIERR_COMPRESSOR;
922 
923  /* allocate memory for current frame */
924  size += This->sInfo.dwSuggestedBufferSize;
925  This->lpbiCur = HeapAlloc(GetProcessHeap(), 0, size);
926  if (This->lpbiCur == NULL)
927  return AVIERR_MEMORY;
928  memcpy(This->lpbiCur, This->lpbiOutput, This->cbOutput);
929  This->lpCur = DIBPTR(This->lpbiCur);
930 
931  /* allocate memory for last frame if needed */
932  if (This->lKeyFrameEvery != 1 &&
933  (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
934  size = ICDecompressGetFormatSize(This->hic, This->lpbiOutput);
935  This->lpbiPrev = HeapAlloc(GetProcessHeap(), 0, size);
936  if (This->lpbiPrev == NULL)
937  return AVIERR_MEMORY;
938  if (ICDecompressGetFormat(This->hic, This->lpbiOutput, This->lpbiPrev) < S_OK)
939  return AVIERR_COMPRESSOR;
940 
941  if (This->lpbiPrev->biSizeImage == 0) {
942  This->lpbiPrev->biSizeImage =
943  DIBWIDTHBYTES(*This->lpbiPrev) * This->lpbiPrev->biHeight;
944  }
945 
946  /* get memory for format and picture */
947  size += This->lpbiPrev->biSizeImage;
948  This->lpbiPrev = HeapReAlloc(GetProcessHeap(), 0, This->lpbiPrev, size );
949  if (This->lpbiPrev == NULL)
950  return AVIERR_MEMORY;
951  This->lpPrev = DIBPTR(This->lpbiPrev);
952 
953  /* prepare codec also for decompression */
954  if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
955  return AVIERR_COMPRESSOR;
956  }
957 
958  return AVIERR_OK;
959 }
#define AVICOMPRESSF_DATARATE
Definition: vfw.h:1099
#define ICDecompressEnd(hic)
Definition: vfw.h:404
#define AVIERR_NOCOMPRESSOR
Definition: vfw.h:1755
GLsizei samples
Definition: glext.h:7006
static HRESULT WINAPI ICMStream_fnDelete(IAVIStream *iface, LONG start, LONG samples)
Definition: icmstream.c:668
#define REFIID
Definition: guiddef.h:118
#define TRUE
Definition: types.h:120
HIC VFWAPI ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode)
Definition: msvideo_main.c:441
LONG lKeyFrameEvery
Definition: icmstream.c:56
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define FIND_ANY
Definition: vfw.h:1124
#define ICQUALITY_LOW
Definition: vfw.h:276
#define ICCompressGetSize(hic, lpbiInput, lpbiOutput)
Definition: vfw.h:218
HRESULT hr
Definition: shlfolder.c:183
DWORD dwFlags
Definition: vfw.h:284
#define ICCOMPRESS_KEYFRAME
Definition: vfw.h:170
LRESULT VFWAPI ICSendMessage(HIC hic, UINT msg, DWORD_PTR lParam1, DWORD_PTR lParam2)
REFIID riid
Definition: precomp.h:44
#define AVIERR_COMPRESSOR
Definition: vfw.h:1754
#define FIND_RET
Definition: vfw.h:1127
#define IAVIStream_Info(p, a, b)
Definition: vfw.h:1180
static HRESULT WINAPI ICMStream_fnWrite(IAVIStream *iface, LONG start, LONG samples, LPVOID buffer, LONG buffersize, DWORD flags, LPLONG sampwritten, LPLONG byteswritten)
Definition: icmstream.c:620
#define WARN(fmt,...)
Definition: debug.h:112
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define AVIIF_KEYFRAME
Definition: aviriff.h:131
#define IAVIStream_Release(p)
Definition: vfw.h:1177
#define assert(x)
Definition: debug.h:53
GLuint buffer
Definition: glext.h:5915
#define MAX_FRAMESIZE_DIFF
Definition: icmstream.c:37
static HRESULT WINAPI ICMStream_fnRead(IAVIStream *iface, LONG start, LONG samples, LPVOID buffer, LONG buffersize, LPLONG bytesread, LPLONG samplesread)
Definition: icmstream.c:527
struct IGetFrame * PGETFRAME
Definition: vfw.h:40
#define VIDCF_TEMPORAL
Definition: vfw.h:299
#define ICERR_OK
Definition: vfw.h:50
#define ICDecompressGetFormat(hic, lpbiInput, lpbiOutput)
Definition: vfw.h:383
#define OLE_E_ENUM_NOMORE
Definition: winerror.h:2616
#define E_FAIL
Definition: ddrawi.h:102
LPBITMAPINFOHEADER lpbiInput
Definition: vfw.h:238
#define IAVIStream_ReadData(p, a, b, c)
Definition: vfw.h:1187
Definition: send.c:48
AVISTREAMINFOW sInfo
Definition: acmstream.c:46
DWORD dwUnusedBytes
Definition: icmstream.c:59
static const WCHAR avifile[]
Definition: avisplitter.c:273
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
#define ICCompressGetFormat(hic, lpbiInput, lpbiOutput)
Definition: vfw.h:204
static LONG WINAPI ICMStream_fnFindSample(IAVIStream *iface, LONG pos, LONG flags)
Definition: icmstream.c:289
#define ICCompressBegin(hic, lpbiInput, lpbiOutput)
Definition: vfw.h:212
#define VIDCF_CRUNCH
Definition: vfw.h:298
static ULONG WINAPI ICMStream_fnRelease(IAVIStream *iface)
Definition: icmstream.c:123
LONG lDataRate
Definition: vfw.h:243
static HRESULT WINAPI ICMStream_fnReadFormat(IAVIStream *iface, LONG pos, LPVOID format, LONG *formatsize)
Definition: icmstream.c:326
#define FIND_NEXT
Definition: vfw.h:1118
static HRESULT WINAPI ICMStream_fnReadData(IAVIStream *iface, DWORD fcc, LPVOID lp, LPLONG lpread)
Definition: icmstream.c:678
#define AVIERR_MEMORY
Definition: vfw.h:1745
#define comptypeDIB
Definition: vfw.h:147
#define DIBWIDTHBYTES(bi)
#define VIDCF_COMPRESSFRAMES
Definition: vfw.h:300
#define FIND_PREV
Definition: vfw.h:1119
DWORD VFWAPIV ICDecompress(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiFormat, LPVOID lpData, LPBITMAPINFOHEADER lpbi, LPVOID lpBits)
Definition: msvideo_main.c:827
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
#define ICQUALITY_DEFAULT
Definition: vfw.h:278
DWORD dwScale
Definition: vfw.h:246
LPBITMAPINFOHEADER lpbiInput
Definition: icmstream.c:68
#define ICM_COMPRESS_FRAMES_INFO
Definition: vfw.h:143
GLenum GLint ref
Definition: glext.h:6028
#define FIXME(fmt,...)
Definition: debug.h:111
#define AVICOMPRESSF_KEYFRAMES
Definition: vfw.h:1100
DWORD biCompression
Definition: amvideo.idl:35
#define IAVIStream_AddRef(p)
Definition: vfw.h:1176
static HRESULT WINAPI ICMStream_fnWriteData(IAVIStream *iface, DWORD fcc, LPVOID lp, LONG size)
Definition: icmstream.c:690
#define ICSetState(hic, pv, cb)
Definition: vfw.h:632
smooth NULL
Definition: ftsmooth.c:416
struct IAVIStream * PAVISTREAM
Definition: vfw.h:38
LONG_PTR LPARAM
Definition: windef.h:208
#define DIBPTR(lp)
DWORD VFWAPIV ICCompress(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiOutput, LPVOID lpData, LPBITMAPINFOHEADER lpbiInput, LPVOID lpBits, LPDWORD lpckid, LPDWORD lpdwFlags, LONG lFrameNum, DWORD dwFrameSize, DWORD dwQuality, LPBITMAPINFOHEADER lpbiPrev, LPVOID lpPrev)
Definition: msvideo_main.c:797
#define debugstr_guid
Definition: kernel32.h:35
#define AVIFILECAPS_CANWRITE
Definition: vfw.h:1061
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define AVIERR_BUFFERTOOSMALL
Definition: vfw.h:1758
#define FIND_KEY
Definition: vfw.h:1123
#define ICCompressGetFormatSize(hic, lpbi)
Definition: vfw.h:210
#define AVIERR_BADPARAM
Definition: vfw.h:1748
#define AVIERR_UNSUPPORTED
Definition: vfw.h:1743
#define ICCompressEnd(hic)
Definition: vfw.h:230
#define IAVIStream_Write(p, a, b, c, d, e, f, g)
Definition: vfw.h:1185
static HRESULT AVIFILE_EncodeFrame(IAVIStreamImpl *This, LPBITMAPINFOHEADER lpbi, LPVOID lpBits)
Definition: icmstream.c:752
LRESULT VFWAPI ICGetInfo(HIC hic, ICINFO *picinfo, DWORD cb)
Definition: msvideo_main.c:594
#define TRACE(s)
Definition: solgame.cpp:4
#define IAVIStream_Read(p, a, b, c, d, e, f)
Definition: vfw.h:1184
GLsizeiptr size
Definition: glext.h:5919
static HRESULT WINAPI ICMStream_fnSetInfo(IAVIStream *iface, LPAVISTREAMINFOW info, LONG infolen)
Definition: icmstream.c:702
#define GetProcessHeap()
Definition: compat.h:404
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
ULONG RGBQUAD
Definition: precomp.h:50
#define IAVIStream_SetFormat(p, a, b, c)
Definition: vfw.h:1183
LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
Definition: api.c:664
LONG HRESULT
Definition: typedefs.h:78
const GUID IID_IUnknown
#define AVIERR_BADSIZE
Definition: vfw.h:1749
#define ICTYPE_VIDEO
Definition: mmreg.h:531
#define WINAPI
Definition: msvc.h:6
LONG lFrameCount
Definition: vfw.h:241
WINE_DEFAULT_DEBUG_CHANNEL(avifile)
DWORD dwLastQuality
Definition: icmstream.c:57
unsigned long DWORD
Definition: ntddk_ex.h:95
#define VIDCF_QUALITY
Definition: vfw.h:297
DWORD biSizeImage
Definition: amvideo.idl:36
#define MAX_FRAMESIZE
Definition: icmstream.c:36
#define VIDCF_FASTTEMPORALC
Definition: vfw.h:302
GLbitfield flags
Definition: glext.h:7161
struct AVICOMPRESSOPTIONS * LPAVICOMPRESSOPTIONS
struct _IAVIStreamImpl IAVIStreamImpl
static void AVIFILE_Reset(IAVIStreamImpl *This)
Definition: icmstream.c:83
#define InterlockedDecrement
Definition: armddk.h:52
#define IAVIStream_WriteData(p, a, b, c)
Definition: vfw.h:1188
#define ICDecompressGetFormatSize(hic, lpbi)
Definition: vfw.h:389
#define mmioFOURCC(c0, c1, c2, c3)
Definition: mmsystem.h:38
PGETFRAME pg
Definition: icmstream.c:50
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
_In_ SURFOBJ _In_ CLIPOBJ * pco
Definition: winddi.h:3414
IAVIStream IAVIStream_iface
Definition: acmstream.c:41
#define IAVIStream_QueryInterface(p, a, b)
Definition: vfw.h:1175
LPVOID lpCur
Definition: icmstream.c:62
#define ICDecompressBegin(hic, lpbiInput, lpbiOutput)
Definition: vfw.h:371
#define AVIERR_OK
Definition: vfw.h:1740
LPBITMAPINFOHEADER lpbiCur
Definition: icmstream.c:61
static ULONG WINAPI ICMStream_fnAddRef(IAVIStream *iface)
Definition: icmstream.c:109
#define streamtypeVIDEO
Definition: aviriff.h:92
#define FIND_FROM_START
Definition: vfw.h:1120
DWORD dwRate
Definition: vfw.h:245
Definition: vfw.h:280
#define ICMODE_COMPRESS
Definition: vfw.h:268
#define ICERR_NEWPALETTE
Definition: vfw.h:52
LONG lQuality
Definition: vfw.h:242
#define S_OK
Definition: intsafe.h:59
int32_t * LPLONG
Definition: typedefs.h:57
#define InterlockedIncrement
Definition: armddk.h:53
HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
Definition: api.c:677
GLuint start
Definition: gl.h:1545
static HRESULT WINAPI ICMStream_fnInfo(IAVIStream *iface, LPAVISTREAMINFOW psi, LONG size)
Definition: icmstream.c:270
#define HeapReAlloc
Definition: compat.h:402
#define IAVIStream_Delete(p, a, b)
Definition: vfw.h:1186
LPBITMAPINFOHEADER lpbiOutput
Definition: vfw.h:236
#define min(a, b)
Definition: monoChain.cc:55
DWORD dwBytesPerFrame
Definition: icmstream.c:58
BOOL WINAPI IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
Definition: compobj.c:4112
static HRESULT WINAPI ICMStream_fnQueryInterface(IAVIStream *iface, REFIID refiid, LPVOID *obj)
Definition: icmstream.c:91
static HRESULT AVIFILE_OpenGetFrame(IAVIStreamImpl *This)
Definition: icmstream.c:873
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
HRESULT AVIFILE_CreateICMStream(REFIID riid, LPVOID *ppv)
Definition: icmstream.c:727
static HRESULT WINAPI ICMStream_fnCreate(IAVIStream *iface, LPARAM lParam1, LPARAM lParam2)
Definition: icmstream.c:181
PAVISTREAM pStream
Definition: acmstream.c:45
LPVOID lpPrev
Definition: icmstream.c:64
GLuint res
Definition: glext.h:9613
LONG lKeyRate
Definition: vfw.h:244
#define FIND_FORMAT
Definition: vfw.h:1125
unsigned int ULONG
Definition: retypes.h:1
static IAVIStreamImpl * impl_from_IAVIStream(IAVIStream *iface)
Definition: icmstream.c:78
LPBITMAPINFOHEADER lpbiOutput
Definition: icmstream.c:66
static HRESULT WINAPI ICMStream_fnSetFormat(IAVIStream *iface, LONG pos, LPVOID format, LONG formatsize)
Definition: icmstream.c:377
#define AVIERR_READONLY
Definition: vfw.h:1756
static const struct IAVIStreamVtbl iicmst
Definition: icmstream.c:710
#define ICQUALITY_HIGH
Definition: vfw.h:277
#define AVIERR_BADFORMAT
Definition: vfw.h:1744
#define memset(x, y, z)
Definition: compat.h:39
#define BI_RGB
Definition: precomp.h:47
#define HeapFree(x, y, z)
Definition: compat.h:403
#define MulDiv(x, y, z)
Definition: gdifloat.h:86
#define AVIERR_ERROR
Definition: vfw.h:1761
static DWORD ICGetDefaultQuality(HIC hic)
Definition: vfw.h:637
LPBITMAPINFOHEADER lpbiPrev
Definition: icmstream.c:63
PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream, LPBITMAPINFOHEADER lpbiWanted)
Definition: api.c:639
DWORD dwICMFlags
Definition: icmstream.c:52