ReactOS  0.4.14-dev-50-g13bb5e2
avifile.c
Go to the documentation of this file.
1 /*
2  * Copyright 1999 Marcus Meissner
3  * Copyright 2002-2003 Michael G├╝nnewig
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 /* TODO:
21  * - IAVIStreaming interface is missing for the IAVIStreamImpl
22  * - IAVIStream_fnFindSample: FIND_INDEX isn't supported.
23  * - IAVIStream_fnReadFormat: formatchanges aren't read in.
24  * - IAVIStream_fnDelete: a stub.
25  * - IAVIStream_fnSetInfo: a stub.
26  * - make thread safe
27  *
28  * KNOWN Bugs:
29  * - native version can hangup when reading a file generated with this DLL.
30  * When index is missing it works, but index seems to be okay.
31  */
32 
33 #define COBJMACROS
34 #include <assert.h>
35 #include <stdarg.h>
36 
37 #include "windef.h"
38 #include "winbase.h"
39 #include "wingdi.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "winerror.h"
43 #include "mmsystem.h"
44 #include "vfw.h"
45 
46 #include "avifile_private.h"
47 #include "extrachunk.h"
48 
49 #include "wine/unicode.h"
50 #include "wine/debug.h"
51 
53 
54 #ifndef IDX_PER_BLOCK
55 #define IDX_PER_BLOCK 2730
56 #endif
57 
58 typedef struct _IAVIFileImpl IAVIFileImpl;
59 
60 typedef struct _IAVIStreamImpl {
62  LONG ref;
63 
65  DWORD nStream; /* the n-th stream in file */
67 
70 
73 
75 
77  DWORD cbBuffer; /* size of lpBuffer */
78  DWORD dwCurrentFrame; /* frame/block currently in lpBuffer */
79 
80  LONG lLastFrame; /* last correct index in idxFrames */
82  DWORD nIdxFrames; /* upper index limit of idxFrames */
84  DWORD nIdxFmtChanges; /* upper index limit of idxFmtChanges */
86 
88 {
89  return CONTAINING_RECORD(iface, IAVIStreamImpl, IAVIStream_iface);
90 }
91 
92 struct _IAVIFileImpl {
98 
101 
103 
104  DWORD dwMoviChunkPos; /* some stuff for saving ... */
108 
110  AVIINDEXENTRY *idxRecords; /* won't be updated while loading */
111  DWORD nIdxRecords; /* current fill level */
112  DWORD cbIdxRecords; /* size of idxRecords */
113 
114  /* IPersistFile stuff ... */
115  HMMIO hmmio;
119 };
120 
122 {
123  return CONTAINING_RECORD(iface, IAVIFileImpl, IUnknown_inner);
124 }
125 
127 {
128  return CONTAINING_RECORD(iface, IAVIFileImpl, IAVIFile_iface);
129 }
130 
132 {
133  return CONTAINING_RECORD(iface, IAVIFileImpl, IPersistFile_iface);
134 }
135 
136 /***********************************************************************/
137 
143  const AVISTREAMINFOW *asi);
148  LONG count, DWORD pos, BOOL *bAbsolute);
152  LPLONG offset);
155 static ULONG AVIFILE_SearchStream(const IAVIFileImpl *This, DWORD fccType,
156  LONG lSkip);
157 static void AVIFILE_UpdateInfo(IAVIFileImpl *This);
160  LONG size);
161 
163 {
165 
166  TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
167 
168  if (!ppv) {
169  WARN("invalid parameter\n");
170  return E_INVALIDARG;
171  }
172  *ppv = NULL;
173 
175  *ppv = &This->IUnknown_inner;
176  else if (IsEqualIID(riid, &IID_IAVIFile))
177  *ppv = &This->IAVIFile_iface;
178  else if (IsEqualGUID(riid, &IID_IPersistFile))
179  *ppv = &This->IPersistFile_iface;
180  else {
181  WARN("unknown IID %s\n", debugstr_guid(riid));
182  return E_NOINTERFACE;
183  }
184 
185  /* Violation of the COM aggregation ref counting rule */
186  IUnknown_AddRef(&This->IUnknown_inner);
187  return S_OK;
188 }
189 
191 {
194 
195  TRACE("(%p) ref=%d\n", This, ref);
196 
197  return ref;
198 }
199 
201 {
204  UINT i;
205 
206  TRACE("(%p) ref=%d\n", This, ref);
207 
208  if (!ref) {
209  if (This->fDirty)
211 
212  for (i = 0; i < This->fInfo.dwStreams; i++) {
213  if (This->ppStreams[i] != NULL) {
214  if (This->ppStreams[i]->ref != 0)
215  ERR(": someone has still %u reference to stream %u (%p)!\n",
216  This->ppStreams[i]->ref, i, This->ppStreams[i]);
217  AVIFILE_DestructAVIStream(This->ppStreams[i]);
218  HeapFree(GetProcessHeap(), 0, This->ppStreams[i]);
219  This->ppStreams[i] = NULL;
220  }
221  }
222 
223  if (This->idxRecords != NULL) {
224  HeapFree(GetProcessHeap(), 0, This->idxRecords);
225  This->idxRecords = NULL;
226  This->nIdxRecords = 0;
227  }
228 
229  if (This->fileextra.lp != NULL) {
230  HeapFree(GetProcessHeap(), 0, This->fileextra.lp);
231  This->fileextra.lp = NULL;
232  This->fileextra.cb = 0;
233  }
234 
235  HeapFree(GetProcessHeap(), 0, This->szFileName);
236  This->szFileName = NULL;
237 
238  if (This->hmmio != NULL) {
239  mmioClose(This->hmmio, 0);
240  This->hmmio = NULL;
241  }
242 
244  }
245  return ref;
246 }
247 
248 static const IUnknownVtbl unk_vtbl =
249 {
253 };
254 
256 {
258 
259  return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
260 }
261 
263 {
265 
266  return IUnknown_AddRef(This->outer_unk);
267 }
268 
270 {
272 
273  return IUnknown_Release(This->outer_unk);
274 }
275 
277 {
279 
280  TRACE("(%p,%p,%d)\n",iface,afi,size);
281 
282  if (afi == NULL)
283  return AVIERR_BADPARAM;
284  if (size < 0)
285  return AVIERR_BADSIZE;
286 
288 
289  memcpy(afi, &This->fInfo, min((DWORD)size, sizeof(This->fInfo)));
290 
291  if ((DWORD)size < sizeof(This->fInfo))
292  return AVIERR_BUFFERTOOSMALL;
293  return AVIERR_OK;
294 }
295 
297  LONG lParam)
298 {
300  ULONG nStream;
301 
302  TRACE("(%p,%p,0x%08X,%d)\n", iface, avis, fccType, lParam);
303 
304  if (avis == NULL || lParam < 0)
305  return AVIERR_BADPARAM;
306 
307  nStream = AVIFILE_SearchStream(This, fccType, lParam);
308 
309  /* Does the requested stream exist? */
310  if (nStream < This->fInfo.dwStreams &&
311  This->ppStreams[nStream] != NULL) {
312  *avis = &This->ppStreams[nStream]->IAVIStream_iface;
313  IAVIStream_AddRef(*avis);
314 
315  return AVIERR_OK;
316  }
317 
318  /* Sorry, but the specified stream doesn't exist */
319  *avis = NULL;
320  return AVIERR_NODATA;
321 }
322 
324  AVISTREAMINFOW *asi)
325 {
327  DWORD n;
328 
329  TRACE("(%p,%p,%p)\n", iface, avis, asi);
330 
331  /* check parameters */
332  if (avis == NULL || asi == NULL)
333  return AVIERR_BADPARAM;
334 
335  *avis = NULL;
336 
337  /* Does the user have write permission? */
338  if ((This->uMode & MMIO_RWMODE) == 0)
339  return AVIERR_READONLY;
340 
341  /* Can we add another stream? */
342  n = This->fInfo.dwStreams;
343  if (n >= MAX_AVISTREAMS || This->dwMoviChunkPos != 0) {
344  /* already reached max nr of streams
345  * or have already written frames to disk */
346  return AVIERR_UNSUPPORTED;
347  }
348 
349  /* check AVISTREAMINFO for some really needed things */
350  if (asi->fccType == 0 || asi->dwScale == 0 || asi->dwRate == 0)
351  return AVIERR_BADFORMAT;
352 
353  /* now it seems to be save to add the stream */
354  assert(This->ppStreams[n] == NULL);
356  sizeof(IAVIStreamImpl));
357  if (This->ppStreams[n] == NULL)
358  return AVIERR_MEMORY;
359 
360  /* initialize the new allocated stream */
362 
363  This->fInfo.dwStreams++;
364  This->fDirty = TRUE;
365 
366  /* update our AVIFILEINFO structure */
368 
369  /* return it */
370  *avis = &This->ppStreams[n]->IAVIStream_iface;
371  IAVIStream_AddRef(*avis);
372 
373  return AVIERR_OK;
374 }
375 
376 static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile *iface, DWORD ckid, void *lpData, LONG size)
377 {
379 
380  TRACE("(%p,0x%08X,%p,%d)\n", iface, ckid, lpData, size);
381 
382  /* check parameters */
383  if (lpData == NULL)
384  return AVIERR_BADPARAM;
385  if (size < 0)
386  return AVIERR_BADSIZE;
387 
388  /* Do we have write permission? */
389  if ((This->uMode & MMIO_RWMODE) == 0)
390  return AVIERR_READONLY;
391 
392  This->fDirty = TRUE;
393 
394  return WriteExtraChunk(&This->fileextra, ckid, lpData, size);
395 }
396 
397 static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile *iface, DWORD ckid, void *lpData, LONG *size)
398 {
400 
401  TRACE("(%p,0x%08X,%p,%p)\n", iface, ckid, lpData, size);
402 
403  return ReadExtraChunk(&This->fileextra, ckid, lpData, size);
404 }
405 
407 {
409 
410  TRACE("(%p)\n",iface);
411 
412  if ((This->uMode & MMIO_RWMODE) == 0)
413  return AVIERR_READONLY;
414 
415  This->fDirty = TRUE;
416 
417  /* no frames written to any stream? -- compute start of 'movi'-chunk */
418  if (This->dwMoviChunkPos == 0)
420 
421  This->fInfo.dwFlags |= AVIFILEINFO_ISINTERLEAVED;
422 
423  /* already written frames to any stream, ... */
424  if (This->ckLastRecord.dwFlags & MMIO_DIRTY) {
425  /* close last record */
426  if (mmioAscend(This->hmmio, &This->ckLastRecord, 0) != 0)
427  return AVIERR_FILEWRITE;
428 
430 
431  if (This->fInfo.dwSuggestedBufferSize < This->ckLastRecord.cksize + 3 * sizeof(DWORD))
432  This->fInfo.dwSuggestedBufferSize = This->ckLastRecord.cksize + 3 * sizeof(DWORD);
433  }
434 
435  /* write out a new record into file, but don't close it */
436  This->ckLastRecord.cksize = 0;
437  This->ckLastRecord.fccType = listtypeAVIRECORD;
438  if (mmioSeek(This->hmmio, This->dwNextFramePos, SEEK_SET) == -1)
439  return AVIERR_FILEWRITE;
440  if (mmioCreateChunk(This->hmmio, &This->ckLastRecord, MMIO_CREATELIST) != 0)
441  return AVIERR_FILEWRITE;
442  This->dwNextFramePos += 3 * sizeof(DWORD);
443 
444  return AVIERR_OK;
445 }
446 
448 {
450  ULONG nStream;
451 
452  TRACE("(%p,0x%08X,%d)\n", iface, fccType, lParam);
453 
454  /* check parameter */
455  if (lParam < 0)
456  return AVIERR_BADPARAM;
457 
458  /* Have user write permissions? */
459  if ((This->uMode & MMIO_RWMODE) == 0)
460  return AVIERR_READONLY;
461 
462  nStream = AVIFILE_SearchStream(This, fccType, lParam);
463 
464  /* Does the requested stream exist? */
465  if (nStream < This->fInfo.dwStreams &&
466  This->ppStreams[nStream] != NULL) {
467  /* ... so delete it now */
468  HeapFree(GetProcessHeap(), 0, This->ppStreams[nStream]);
469  This->fInfo.dwStreams--;
470  if (nStream < This->fInfo.dwStreams)
471  memmove(&This->ppStreams[nStream], &This->ppStreams[nStream + 1],
472  (This->fInfo.dwStreams - nStream) * sizeof(This->ppStreams[0]));
473 
474  This->ppStreams[This->fInfo.dwStreams] = NULL;
475  This->fDirty = TRUE;
476 
477  /* This->fInfo will be updated further when asked for */
478  return AVIERR_OK;
479  } else
480  return AVIERR_NODATA;
481 }
482 
483 static const struct IAVIFileVtbl avif_vt = {
494 };
495 
496 
498 {
500 
501  return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
502 }
503 
505 {
507 
508  return IUnknown_AddRef(This->outer_unk);
509 }
510 
512 {
514 
515  return IUnknown_Release(This->outer_unk);
516 }
517 
519 {
520  TRACE("(%p,%p)\n", iface, pClassID);
521 
522  if (pClassID == NULL)
523  return AVIERR_BADPARAM;
524 
525  *pClassID = CLSID_AVIFile;
526 
527  return AVIERR_OK;
528 }
529 
531 {
533 
534  TRACE("(%p)\n", iface);
535 
536  return (This->fDirty ? S_OK : S_FALSE);
537 }
538 
540 {
542  int len;
543 
544  TRACE("(%p,%s,0x%08X)\n", iface, debugstr_w(pszFileName), dwMode);
545 
546  /* check parameter */
547  if (pszFileName == NULL)
548  return AVIERR_BADPARAM;
549 
550  if (This->hmmio != NULL)
551  return AVIERR_ERROR; /* No reuse of this object for another file! */
552 
553  /* remember mode and name */
554  This->uMode = dwMode;
555 
556  len = lstrlenW(pszFileName) + 1;
557  This->szFileName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
558  if (This->szFileName == NULL)
559  return AVIERR_MEMORY;
560  lstrcpyW(This->szFileName, pszFileName);
561 
562  /* try to open the file */
563  This->hmmio = mmioOpenW(This->szFileName, NULL, MMIO_ALLOCBUF | dwMode);
564  if (This->hmmio == NULL) {
565  /* mmioOpenW not in native DLLs of Win9x -- try mmioOpenA */
566  LPSTR szFileName;
567 
568  len = WideCharToMultiByte(CP_ACP, 0, This->szFileName, -1, NULL, 0, NULL, NULL);
569  szFileName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR));
570  if (szFileName == NULL)
571  return AVIERR_MEMORY;
572 
573  WideCharToMultiByte(CP_ACP, 0, This->szFileName, -1, szFileName, len, NULL, NULL);
574 
575  This->hmmio = mmioOpenA(szFileName, NULL, MMIO_ALLOCBUF | dwMode);
576  HeapFree(GetProcessHeap(), 0, szFileName);
577  if (This->hmmio == NULL)
578  return AVIERR_FILEOPEN;
579  }
580 
581  /* should we create a new file? */
582  if (dwMode & OF_CREATE) {
583  memset(& This->fInfo, 0, sizeof(This->fInfo));
585 
586  return AVIERR_OK;
587  } else
588  return AVIFILE_LoadFile(This);
589 }
590 
592  BOOL fRemember)
593 {
594  TRACE("(%p,%s,%d)\n", iface, debugstr_w(pszFileName), fRemember);
595 
596  /* We write directly to disk, so nothing to do. */
597 
598  return AVIERR_OK;
599 }
600 
602 {
603  TRACE("(%p,%s)\n", iface, debugstr_w(pszFileName));
604 
605  /* We write directly to disk, so nothing to do. */
606 
607  return AVIERR_OK;
608 }
609 
611 {
613 
614  TRACE("(%p,%p)\n", iface, ppszFileName);
615 
616  if (ppszFileName == NULL)
617  return AVIERR_BADPARAM;
618 
619  *ppszFileName = NULL;
620 
621  if (This->szFileName != NULL) {
622  int len = lstrlenW(This->szFileName) + 1;
623 
624  *ppszFileName = CoTaskMemAlloc(len * sizeof(WCHAR));
625  if (*ppszFileName == NULL)
626  return AVIERR_MEMORY;
627 
628  strcpyW(*ppszFileName, This->szFileName);
629  }
630 
631  return AVIERR_OK;
632 }
633 
634 static const struct IPersistFileVtbl pf_vt = {
644 };
645 
647 {
648  IAVIFileImpl *obj;
649  HRESULT hr;
650 
651  *ppv = NULL;
653  if (!obj)
654  return AVIERR_MEMORY;
655 
656  obj->IUnknown_inner.lpVtbl = &unk_vtbl;
657  obj->IAVIFile_iface.lpVtbl = &avif_vt;
658  obj->IPersistFile_iface.lpVtbl = &pf_vt;
659  obj->ref = 1;
660  if (pUnkOuter)
661  obj->outer_unk = pUnkOuter;
662  else
663  obj->outer_unk = &obj->IUnknown_inner;
664 
665  hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
666  IUnknown_Release(&obj->IUnknown_inner);
667 
668  return hr;
669 }
670 
671 
673 {
675 
676  TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
677 
678  if (!ppv) {
679  WARN("invalid parameter\n");
680  return E_INVALIDARG;
681  }
682  *ppv = NULL;
683 
684  if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IAVIStream, riid)) {
685  *ppv = iface;
686  IAVIStream_AddRef(iface);
687 
688  return S_OK;
689  }
690  /* FIXME: IAVIStreaming interface */
691 
692  return E_NOINTERFACE;
693 }
694 
696 {
699 
700  TRACE("(%p) ref=%d\n", This, ref);
701 
702  /* also add ref to parent, so that it doesn't kill us */
703  if (This->paf != NULL)
704  IAVIFile_AddRef(&This->paf->IAVIFile_iface);
705 
706  return ref;
707 }
708 
710 {
713 
714  TRACE("(%p) ref=%d\n", This, ref);
715 
716  if (This->paf != NULL)
717  IAVIFile_Release(&This->paf->IAVIFile_iface);
718 
719  return ref;
720 }
721 
722 static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream *iface, LPARAM lParam1, LPARAM lParam2)
723 {
724  TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
725 
726  /* This IAVIStream interface needs an AVIFile */
727  return AVIERR_UNSUPPORTED;
728 }
729 
731 {
733 
734  TRACE("(%p,%p,%d)\n", iface, psi, size);
735 
736  if (psi == NULL)
737  return AVIERR_BADPARAM;
738  if (size < 0)
739  return AVIERR_BADSIZE;
740 
741  memcpy(psi, &This->sInfo, min((DWORD)size, sizeof(This->sInfo)));
742 
743  if ((DWORD)size < sizeof(This->sInfo))
744  return AVIERR_BUFFERTOOSMALL;
745  return AVIERR_OK;
746 }
747 
749 {
751  LONG offset = 0;
752 
753  TRACE("(%p,%d,0x%08X)\n",iface,pos,flags);
754 
755  if (flags & FIND_FROM_START) {
756  pos = This->sInfo.dwStart;
758  flags |= FIND_NEXT;
759  }
760 
761  if (This->sInfo.dwSampleSize != 0) {
762  /* convert samples into block number with offset */
764  }
765 
766  if (flags & FIND_TYPE) {
767  if (flags & FIND_KEY) {
768  while (0 <= pos && pos <= This->lLastFrame) {
769  if (This->idxFrames[pos].dwFlags & AVIIF_KEYFRAME)
770  goto RETURN_FOUND;
771 
772  if (flags & FIND_NEXT)
773  pos++;
774  else
775  pos--;
776  };
777  } else if (flags & FIND_ANY) {
778  while (0 <= pos && pos <= This->lLastFrame) {
779  if (This->idxFrames[pos].dwChunkLength > 0)
780  goto RETURN_FOUND;
781 
782  if (flags & FIND_NEXT)
783  pos++;
784  else
785  pos--;
786 
787  };
788  } else if ((flags & FIND_FORMAT) && This->idxFmtChanges != NULL &&
789  This->sInfo.fccType == streamtypeVIDEO) {
790  if (flags & FIND_NEXT) {
791  ULONG n;
792 
793  for (n = 0; n < This->sInfo.dwFormatChangeCount; n++)
794  if (This->idxFmtChanges[n].ckid >= pos) {
795  pos = This->idxFmtChanges[n].ckid;
796  goto RETURN_FOUND;
797  }
798  } else {
799  LONG n;
800 
801  for (n = (LONG)This->sInfo.dwFormatChangeCount; n >= 0; n--) {
802  if (This->idxFmtChanges[n].ckid <= pos) {
803  pos = This->idxFmtChanges[n].ckid;
804  goto RETURN_FOUND;
805  }
806  }
807 
808  if (pos > (LONG)This->sInfo.dwStart)
809  return 0; /* format changes always for first frame */
810  }
811  }
812 
813  return -1;
814  }
815 
816  RETURN_FOUND:
817  if (pos < (LONG)This->sInfo.dwStart)
818  return -1;
819 
820  switch (flags & FIND_RET) {
821  case FIND_LENGTH:
822  /* physical size */
823  pos = This->idxFrames[pos].dwChunkLength;
824  break;
825  case FIND_OFFSET:
826  /* physical position */
827  pos = This->idxFrames[pos].dwChunkOffset + 2 * sizeof(DWORD)
828  + offset * This->sInfo.dwSampleSize;
829  break;
830  case FIND_SIZE:
831  /* logical size */
832  if (This->sInfo.dwSampleSize)
833  pos = This->sInfo.dwSampleSize;
834  else
835  pos = 1;
836  break;
837  case FIND_INDEX:
838  FIXME(": FIND_INDEX flag is not supported!\n");
839  /* This is an index in the index-table on disc. */
840  break;
841  }; /* else logical position */
842 
843  return pos;
844 }
845 
847  LONG *formatsize)
848 {
850 
851  TRACE("(%p,%d,%p,%p)\n", iface, pos, format, formatsize);
852 
853  if (formatsize == NULL)
854  return AVIERR_BADPARAM;
855 
856  /* only interested in needed buffersize? */
857  if (format == NULL || *formatsize <= 0) {
858  *formatsize = This->cbFormat;
859 
860  return AVIERR_OK;
861  }
862 
863  /* copy initial format (only as much as will fit) */
864  memcpy(format, This->lpFormat, min(*(DWORD*)formatsize, This->cbFormat));
865  if (*(DWORD*)formatsize < This->cbFormat) {
866  *formatsize = This->cbFormat;
867  return AVIERR_BUFFERTOOSMALL;
868  }
869 
870  /* Could format change? When yes will it change? */
871  if ((This->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
872  pos > This->sInfo.dwStart) {
873  LONG lLastFmt;
874 
875  lLastFmt = IAVIStream_fnFindSample(iface, pos, FIND_FORMAT|FIND_PREV);
876  if (lLastFmt > 0) {
877  FIXME(": need to read formatchange for %d -- unimplemented!\n",lLastFmt);
878  }
879  }
880 
881  *formatsize = This->cbFormat;
882  return AVIERR_OK;
883 }
884 
886  LONG formatsize)
887 {
889  BITMAPINFOHEADER *lpbiNew = format;
890 
891  TRACE("(%p,%d,%p,%d)\n", iface, pos, format, formatsize);
892 
893  /* check parameters */
894  if (format == NULL || formatsize <= 0)
895  return AVIERR_BADPARAM;
896 
897  /* Do we have write permission? */
898  if ((This->paf->uMode & MMIO_RWMODE) == 0)
899  return AVIERR_READONLY;
900 
901  /* can only set format before frame is written! */
902  if (This->lLastFrame > pos)
903  return AVIERR_UNSUPPORTED;
904 
905  /* initial format or a formatchange? */
906  if (This->lpFormat == NULL) {
907  /* initial format */
908  if (This->paf->dwMoviChunkPos != 0)
909  return AVIERR_ERROR; /* user has used API in wrong sequence! */
910 
911  This->lpFormat = HeapAlloc(GetProcessHeap(), 0, formatsize);
912  if (This->lpFormat == NULL)
913  return AVIERR_MEMORY;
914  This->cbFormat = formatsize;
915 
916  memcpy(This->lpFormat, format, formatsize);
917 
918  /* update some infos about stream */
919  if (This->sInfo.fccType == streamtypeVIDEO) {
920  LONG lDim;
921 
922  lDim = This->sInfo.rcFrame.right - This->sInfo.rcFrame.left;
923  if (lDim < lpbiNew->biWidth)
924  This->sInfo.rcFrame.right = This->sInfo.rcFrame.left + lpbiNew->biWidth;
925  lDim = This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top;
926  if (lDim < lpbiNew->biHeight)
927  This->sInfo.rcFrame.bottom = This->sInfo.rcFrame.top + lpbiNew->biHeight;
928  } else if (This->sInfo.fccType == streamtypeAUDIO)
929  This->sInfo.dwSampleSize = ((LPWAVEFORMATEX)This->lpFormat)->nBlockAlign;
930 
931  return AVIERR_OK;
932  } else {
933  MMCKINFO ck;
934  LPBITMAPINFOHEADER lpbiOld = This->lpFormat;
935  RGBQUAD *rgbNew = (RGBQUAD*)((LPBYTE)lpbiNew + lpbiNew->biSize);
936  AVIPALCHANGE *lppc = NULL;
937  UINT n;
938 
939  /* perhaps format change, check it ... */
940  if (This->cbFormat != formatsize)
941  return AVIERR_UNSUPPORTED;
942 
943  /* no format change, only the initial one */
944  if (memcmp(This->lpFormat, format, formatsize) == 0)
945  return AVIERR_OK;
946 
947  /* check that's only the palette, which changes */
948  if (lpbiOld->biSize != lpbiNew->biSize ||
949  lpbiOld->biWidth != lpbiNew->biWidth ||
950  lpbiOld->biHeight != lpbiNew->biHeight ||
951  lpbiOld->biPlanes != lpbiNew->biPlanes ||
952  lpbiOld->biBitCount != lpbiNew->biBitCount ||
953  lpbiOld->biCompression != lpbiNew->biCompression ||
954  lpbiOld->biClrUsed != lpbiNew->biClrUsed)
955  return AVIERR_UNSUPPORTED;
956 
957  This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
958 
959  /* simply say all colors have changed */
960  ck.ckid = MAKEAVICKID(cktypePALchange, This->nStream);
961  ck.cksize = 2 * sizeof(WORD) + lpbiOld->biClrUsed * sizeof(PALETTEENTRY);
962  lppc = HeapAlloc(GetProcessHeap(), 0, ck.cksize);
963  if (lppc == NULL)
964  return AVIERR_MEMORY;
965 
966  lppc->bFirstEntry = 0;
967  lppc->bNumEntries = (lpbiOld->biClrUsed < 256 ? lpbiOld->biClrUsed : 0);
968  lppc->wFlags = 0;
969  for (n = 0; n < lpbiOld->biClrUsed; n++) {
970  lppc->peNew[n].peRed = rgbNew[n].rgbRed;
971  lppc->peNew[n].peGreen = rgbNew[n].rgbGreen;
972  lppc->peNew[n].peBlue = rgbNew[n].rgbBlue;
973  lppc->peNew[n].peFlags = 0;
974  }
975 
976  if (mmioSeek(This->paf->hmmio, This->paf->dwNextFramePos, SEEK_SET) == -1 ||
977  mmioCreateChunk(This->paf->hmmio, &ck, 0) != S_OK ||
978  mmioWrite(This->paf->hmmio, (HPSTR)lppc, ck.cksize) != ck.cksize ||
979  mmioAscend(This->paf->hmmio, &ck, 0) != S_OK)
980  {
981  HeapFree(GetProcessHeap(), 0, lppc);
982  return AVIERR_FILEWRITE;
983  }
984 
985  This->paf->dwNextFramePos += ck.cksize + 2 * sizeof(DWORD);
986 
987  HeapFree(GetProcessHeap(), 0, lppc);
988 
990  }
991 }
992 
994  LONG buffersize, LONG *bytesread, LONG *samplesread)
995 {
997  DWORD size;
998  HRESULT hr;
999 
1000  TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", iface, start, samples, buffer,
1001  buffersize, bytesread, samplesread);
1002 
1003  /* clear return parameters if given */
1004  if (bytesread != NULL)
1005  *bytesread = 0;
1006  if (samplesread != NULL)
1007  *samplesread = 0;
1008 
1009  /* check parameters */
1010  if ((LONG)This->sInfo.dwStart > start)
1011  return AVIERR_NODATA; /* couldn't read before start of stream */
1012  if (This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
1013  return AVIERR_NODATA; /* start is past end of stream */
1014 
1015  /* should we read as much as possible? */
1016  if (samples == -1) {
1017  /* User should know how much we have read */
1018  if (bytesread == NULL && samplesread == NULL)
1019  return AVIERR_BADPARAM;
1020 
1021  if (This->sInfo.dwSampleSize != 0)
1022  samples = buffersize / This->sInfo.dwSampleSize;
1023  else
1024  samples = 1;
1025  }
1026 
1027  /* limit to end of stream */
1028  if ((LONG)This->sInfo.dwLength < samples)
1029  samples = This->sInfo.dwLength;
1030  if ((start - This->sInfo.dwStart) > (This->sInfo.dwLength - samples))
1031  samples = This->sInfo.dwLength - (start - This->sInfo.dwStart);
1032 
1033  /* nothing to read? Then leave ... */
1034  if (samples == 0)
1035  return AVIERR_OK;
1036 
1037  if (This->sInfo.dwSampleSize != 0) {
1038  /* fixed samplesize -- we can read over frame/block boundaries */
1039  LONG block = start;
1040  LONG offset = 0;
1041 
1042  if (!buffer)
1043  {
1044  if (bytesread)
1045  *bytesread = samples*This->sInfo.dwSampleSize;
1046  if (samplesread)
1047  *samplesread = samples;
1048  return AVIERR_OK;
1049  }
1050 
1051  /* convert start sample to block,offset pair */
1053 
1054  /* convert samples to bytes */
1055  samples *= This->sInfo.dwSampleSize;
1056 
1057  while (samples > 0 && buffersize > 0) {
1058  LONG blocksize;
1059  if (block != This->dwCurrentFrame) {
1061  if (FAILED(hr))
1062  return hr;
1063  }
1064 
1065  size = min((DWORD)samples, (DWORD)buffersize);
1066  blocksize = This->lpBuffer[1];
1067  TRACE("blocksize = %u\n",blocksize);
1068  size = min(size, blocksize - offset);
1069  memcpy(buffer, ((BYTE*)&This->lpBuffer[2]) + offset, size);
1070 
1071  block++;
1072  offset = 0;
1073  buffer = ((LPBYTE)buffer)+size;
1074  samples -= size;
1075  buffersize -= size;
1076 
1077  /* fill out return parameters if given */
1078  if (bytesread != NULL)
1079  *bytesread += size;
1080  if (samplesread != NULL)
1081  *samplesread += size / This->sInfo.dwSampleSize;
1082  }
1083 
1084  if (samples == 0)
1085  return AVIERR_OK;
1086  else
1087  return AVIERR_BUFFERTOOSMALL;
1088  } else {
1089  /* variable samplesize -- we can only read one full frame/block */
1090  if (samples > 1)
1091  samples = 1;
1092 
1093  assert(start <= This->lLastFrame);
1094  size = This->idxFrames[start].dwChunkLength;
1095  if (buffer != NULL && buffersize >= size) {
1097  if (FAILED(hr))
1098  return hr;
1099  } else if (buffer != NULL)
1100  return AVIERR_BUFFERTOOSMALL;
1101 
1102  /* fill out return parameters if given */
1103  if (bytesread != NULL)
1104  *bytesread = size;
1105  if (samplesread != NULL)
1106  *samplesread = samples;
1107 
1108  return AVIERR_OK;
1109  }
1110 }
1111 
1113  LONG buffersize, DWORD flags, LONG *sampwritten, LONG *byteswritten)
1114 {
1116  FOURCC ckid;
1117  HRESULT hr;
1118 
1119  TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n", iface, start, samples,
1120  buffer, buffersize, flags, sampwritten, byteswritten);
1121 
1122  /* clear return parameters if given */
1123  if (sampwritten != NULL)
1124  *sampwritten = 0;
1125  if (byteswritten != NULL)
1126  *byteswritten = 0;
1127 
1128  /* check parameters */
1129  if (buffer == NULL && (buffersize > 0 || samples > 0))
1130  return AVIERR_BADPARAM;
1131 
1132  /* Have we write permission? */
1133  if ((This->paf->uMode & MMIO_RWMODE) == 0)
1134  return AVIERR_READONLY;
1135 
1136  switch (This->sInfo.fccType) {
1137  case streamtypeAUDIO:
1138  ckid = MAKEAVICKID(cktypeWAVEbytes, This->nStream);
1139  break;
1140  default:
1141  if ((flags & AVIIF_KEYFRAME) && buffersize != 0)
1142  ckid = MAKEAVICKID(cktypeDIBbits, This->nStream);
1143  else
1144  ckid = MAKEAVICKID(cktypeDIBcompressed, This->nStream);
1145  break;
1146  };
1147 
1148  /* append to end of stream? */
1149  if (start == -1) {
1150  if (This->lLastFrame == -1)
1151  start = This->sInfo.dwStart;
1152  else
1153  start = This->sInfo.dwLength;
1154  } else if (This->lLastFrame == -1)
1155  This->sInfo.dwStart = start;
1156 
1157  if (This->sInfo.dwSampleSize != 0) {
1158  /* fixed sample size -- audio like */
1159  if (samples * This->sInfo.dwSampleSize != buffersize)
1160  return AVIERR_BADPARAM;
1161 
1162  /* Couldn't skip audio-like data -- User must supply appropriate silence */
1163  if (This->sInfo.dwLength != start)
1164  return AVIERR_UNSUPPORTED;
1165 
1166  /* Convert position to frame/block */
1167  start = This->lLastFrame + 1;
1168 
1169  if ((This->paf->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) == 0) {
1170  FIXME(": not interleaved, could collect audio data!\n");
1171  }
1172  } else {
1173  /* variable sample size -- video like */
1174  if (samples > 1)
1175  return AVIERR_UNSUPPORTED;
1176 
1177  /* must we fill up with empty frames? */
1178  if (This->lLastFrame != -1) {
1179  FOURCC ckid2 = MAKEAVICKID(cktypeDIBcompressed, This->nStream);
1180 
1181  while (start > This->lLastFrame + 1) {
1182  hr = AVIFILE_WriteBlock(This, This->lLastFrame + 1, ckid2, 0, NULL, 0);
1183  if (FAILED(hr))
1184  return hr;
1185  }
1186  }
1187  }
1188 
1189  /* write the block now */
1190  hr = AVIFILE_WriteBlock(This, start, ckid, flags, buffer, buffersize);
1191  if (SUCCEEDED(hr)) {
1192  /* fill out return parameters if given */
1193  if (sampwritten != NULL)
1194  *sampwritten = samples;
1195  if (byteswritten != NULL)
1196  *byteswritten = buffersize;
1197  }
1198 
1199  return hr;
1200 }
1201 
1203 {
1205 
1206  FIXME("(%p,%d,%d): stub\n", iface, start, samples);
1207 
1208  /* check parameters */
1209  if (start < 0 || samples < 0)
1210  return AVIERR_BADPARAM;
1211 
1212  /* Delete before start of stream? */
1213  if (start + samples < This->sInfo.dwStart)
1214  return AVIERR_OK;
1215 
1216  /* Delete after end of stream? */
1217  if (start > This->sInfo.dwLength)
1218  return AVIERR_OK;
1219 
1220  /* For the rest we need write permissions */
1221  if ((This->paf->uMode & MMIO_RWMODE) == 0)
1222  return AVIERR_READONLY;
1223 
1224  /* 1. overwrite the data with JUNK
1225  *
1226  * if ISINTERLEAVED {
1227  * 2. concat all neighboured JUNK-blocks in this record to one
1228  * 3. if this record only contains JUNK and is at end set dwNextFramePos
1229  * to start of this record, repeat this.
1230  * } else {
1231  * 2. concat all neighboured JUNK-blocks.
1232  * 3. if the JUNK block is at the end, then set dwNextFramePos to
1233  * start of this block.
1234  * }
1235  */
1236 
1237  return AVIERR_UNSUPPORTED;
1238 }
1239 
1240 static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream *iface, DWORD fcc, void *lp, LONG *lpread)
1241 {
1243 
1244  TRACE("(%p,0x%08X,%p,%p)\n", iface, fcc, lp, lpread);
1245 
1246  if (fcc == ckidSTREAMHANDLERDATA) {
1247  if (This->lpHandlerData != NULL && This->cbHandlerData > 0) {
1248  if (lp == NULL || *lpread <= 0) {
1249  *lpread = This->cbHandlerData;
1250  return AVIERR_OK;
1251  }
1252 
1253  memcpy(lp, This->lpHandlerData, min(This->cbHandlerData, *lpread));
1254  if (*lpread < This->cbHandlerData)
1255  return AVIERR_BUFFERTOOSMALL;
1256  return AVIERR_OK;
1257  } else
1258  return AVIERR_NODATA;
1259  } else
1260  return ReadExtraChunk(&This->extra, fcc, lp, lpread);
1261 }
1262 
1264 {
1266 
1267  TRACE("(%p,0x%08x,%p,%d)\n", iface, fcc, lp, size);
1268 
1269  /* check parameters */
1270  if (lp == NULL)
1271  return AVIERR_BADPARAM;
1272  if (size <= 0)
1273  return AVIERR_BADSIZE;
1274 
1275  /* need write permission */
1276  if ((This->paf->uMode & MMIO_RWMODE) == 0)
1277  return AVIERR_READONLY;
1278 
1279  /* already written something to this file? */
1280  if (This->paf->dwMoviChunkPos != 0) {
1281  /* the data will be inserted before the 'movi' chunk, so check for
1282  * enough space */
1283  DWORD dwPos = AVIFILE_ComputeMoviStart(This->paf);
1284 
1285  /* ckid,size => 2 * sizeof(DWORD) */
1286  dwPos += 2 * sizeof(DWORD) + size;
1287  if (dwPos >= This->paf->dwMoviChunkPos - 2 * sizeof(DWORD))
1288  return AVIERR_UNSUPPORTED; /* not enough space left */
1289  }
1290 
1291  This->paf->fDirty = TRUE;
1292 
1293  if (fcc == ckidSTREAMHANDLERDATA) {
1294  if (This->lpHandlerData != NULL) {
1295  FIXME(": handler data already set -- overwrite?\n");
1296  return AVIERR_UNSUPPORTED;
1297  }
1298 
1299  This->lpHandlerData = HeapAlloc(GetProcessHeap(), 0, size);
1300  if (This->lpHandlerData == NULL)
1301  return AVIERR_MEMORY;
1302  This->cbHandlerData = size;
1303  memcpy(This->lpHandlerData, lp, size);
1304 
1305  return AVIERR_OK;
1306  } else
1307  return WriteExtraChunk(&This->extra, fcc, lp, size);
1308 }
1309 
1311 {
1312  FIXME("(%p,%p,%d): stub\n", iface, info, infolen);
1313 
1314  return E_FAIL;
1315 }
1316 
1317 static const struct IAVIStreamVtbl avist_vt = {
1332 };
1333 
1334 
1336 {
1337  UINT n;
1338 
1339  /* pre-conditions */
1340  assert(This != NULL);
1341 
1342  switch (TWOCCFromFOURCC(ckid)) {
1343  case cktypeDIBbits:
1344  if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
1345  flags |= AVIIF_KEYFRAME;
1346  break;
1347  case cktypeDIBcompressed:
1348  if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
1349  flags &= ~AVIIF_KEYFRAME;
1350  break;
1351  case cktypePALchange:
1352  if (This->sInfo.fccType != streamtypeVIDEO) {
1353  ERR(": found palette change in non-video stream!\n");
1354  return AVIERR_BADFORMAT;
1355  }
1356 
1357  if (This->idxFmtChanges == NULL || This->nIdxFmtChanges <= This->sInfo.dwFormatChangeCount) {
1358  DWORD new_count = This->nIdxFmtChanges + 16;
1359  void *new_buffer;
1360 
1361  if (This->idxFmtChanges == NULL) {
1362  This->idxFmtChanges =
1363  HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(AVIINDEXENTRY));
1364  if (!This->idxFmtChanges) return AVIERR_MEMORY;
1365  } else {
1366  new_buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->idxFmtChanges,
1367  new_count * sizeof(AVIINDEXENTRY));
1368  if (!new_buffer) return AVIERR_MEMORY;
1369  This->idxFmtChanges = new_buffer;
1370  }
1371  This->nIdxFmtChanges = new_count;
1372  }
1373 
1374  This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
1375  n = ++This->sInfo.dwFormatChangeCount;
1376  This->idxFmtChanges[n].ckid = This->lLastFrame;
1377  This->idxFmtChanges[n].dwFlags = 0;
1378  This->idxFmtChanges[n].dwChunkOffset = offset;
1379  This->idxFmtChanges[n].dwChunkLength = size;
1380 
1381  return AVIERR_OK;
1382  case cktypeWAVEbytes:
1383  if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
1384  flags |= AVIIF_KEYFRAME;
1385  break;
1386  default:
1387  WARN(": unknown TWOCC 0x%04X found\n", TWOCCFromFOURCC(ckid));
1388  break;
1389  };
1390 
1391  /* first frame is always a keyframe */
1392  if (This->lLastFrame == -1)
1393  flags |= AVIIF_KEYFRAME;
1394 
1395  if (This->sInfo.dwSuggestedBufferSize < size)
1396  This->sInfo.dwSuggestedBufferSize = size;
1397 
1398  /* get memory for index */
1399  if (This->idxFrames == NULL || This->lLastFrame + 1 >= This->nIdxFrames) {
1400  This->nIdxFrames += 512;
1401  if (This->idxFrames == NULL)
1402  This->idxFrames = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->nIdxFrames * sizeof(AVIINDEXENTRY));
1403  else
1404  This->idxFrames = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->idxFrames,
1405  This->nIdxFrames * sizeof(AVIINDEXENTRY));
1406  if (This->idxFrames == NULL)
1407  return AVIERR_MEMORY;
1408  }
1409 
1410  This->lLastFrame++;
1411  This->idxFrames[This->lLastFrame].ckid = ckid;
1412  This->idxFrames[This->lLastFrame].dwFlags = flags;
1413  This->idxFrames[This->lLastFrame].dwChunkOffset = offset;
1414  This->idxFrames[This->lLastFrame].dwChunkLength = size;
1415 
1416  /* update AVISTREAMINFO structure if necessary */
1417  if (This->sInfo.dwLength <= This->lLastFrame)
1418  This->sInfo.dwLength = This->lLastFrame + 1;
1419 
1420  return AVIERR_OK;
1421 }
1422 
1424 {
1425  /* pre-conditions */
1426  assert(This != NULL && This->ppStreams[0] != NULL);
1427 
1428  if (This->idxRecords == NULL || This->cbIdxRecords / sizeof(AVIINDEXENTRY) <= This->nIdxRecords) {
1429  DWORD new_count = This->cbIdxRecords + 1024 * sizeof(AVIINDEXENTRY);
1430  void *mem;
1431  if (!This->idxRecords)
1432  mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, new_count);
1433  else
1434  mem = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->idxRecords, new_count);
1435  if (mem) {
1436  This->cbIdxRecords = new_count;
1437  This->idxRecords = mem;
1438  } else {
1439  HeapFree(GetProcessHeap(), 0, This->idxRecords);
1440  This->idxRecords = NULL;
1441  return AVIERR_MEMORY;
1442  }
1443  }
1444 
1445  assert(This->nIdxRecords < This->cbIdxRecords/sizeof(AVIINDEXENTRY));
1446 
1447  This->idxRecords[This->nIdxRecords].ckid = listtypeAVIRECORD;
1448  This->idxRecords[This->nIdxRecords].dwFlags = AVIIF_LIST;
1449  This->idxRecords[This->nIdxRecords].dwChunkOffset =
1450  This->ckLastRecord.dwDataOffset - 2 * sizeof(DWORD);
1451  This->idxRecords[This->nIdxRecords].dwChunkLength =
1452  This->ckLastRecord.cksize;
1453  This->nIdxRecords++;
1454 
1455  return AVIERR_OK;
1456 }
1457 
1459 {
1460  DWORD dwPos;
1461  DWORD nStream;
1462 
1463  /* RIFF,hdrl,movi,avih => (3 * 3 + 2) * sizeof(DWORD) = 11 * sizeof(DWORD) */
1464  dwPos = 11 * sizeof(DWORD) + sizeof(MainAVIHeader);
1465 
1466  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
1467  IAVIStreamImpl *pStream = This->ppStreams[nStream];
1468 
1469  /* strl,strh,strf => (3 + 2 * 2) * sizeof(DWORD) = 7 * sizeof(DWORD) */
1470  dwPos += 7 * sizeof(DWORD) + sizeof(AVIStreamHeader);
1471  dwPos += ((pStream->cbFormat + 1) & ~1U);
1472  if (pStream->lpHandlerData != NULL && pStream->cbHandlerData > 0)
1473  dwPos += 2 * sizeof(DWORD) + ((pStream->cbHandlerData + 1) & ~1U);
1474  if (pStream->sInfo.szName[0])
1475  dwPos += 2 * sizeof(DWORD) + ((lstrlenW(pStream->sInfo.szName) + 1) & ~1U);
1476  }
1477 
1478  if (This->dwMoviChunkPos == 0) {
1479  This->dwNextFramePos = dwPos;
1480 
1481  /* pad to multiple of AVI_HEADERSIZE only if we are more than 8 bytes away from it */
1482  if (((dwPos + AVI_HEADERSIZE) & ~(AVI_HEADERSIZE - 1)) - dwPos > 2 * sizeof(DWORD))
1483  This->dwNextFramePos = (dwPos + AVI_HEADERSIZE) & ~(AVI_HEADERSIZE - 1);
1484 
1485  This->dwMoviChunkPos = This->dwNextFramePos - sizeof(DWORD);
1486  }
1487 
1488  return dwPos;
1489 }
1490 
1492 {
1493  IAVIStreamImpl *pstream;
1494 
1495  /* pre-conditions */
1496  assert(paf != NULL);
1498  assert(paf->ppStreams[nr] != NULL);
1499 
1500  pstream = paf->ppStreams[nr];
1501 
1502  pstream->IAVIStream_iface.lpVtbl = &avist_vt;
1503  pstream->ref = 0;
1504  pstream->paf = paf;
1505  pstream->nStream = nr;
1506  pstream->dwCurrentFrame = (DWORD)-1;
1507  pstream->lLastFrame = -1;
1508 
1509  if (asi != NULL) {
1510  memcpy(&pstream->sInfo, asi, sizeof(pstream->sInfo));
1511 
1512  if (asi->dwLength > 0) {
1513  /* pre-allocate mem for frame-index structure */
1514  pstream->idxFrames =
1516  if (pstream->idxFrames != NULL)
1517  pstream->nIdxFrames = asi->dwLength;
1518  }
1519  if (asi->dwFormatChangeCount > 0) {
1520  /* pre-allocate mem for formatchange-index structure */
1521  pstream->idxFmtChanges =
1523  if (pstream->idxFmtChanges != NULL)
1524  pstream->nIdxFmtChanges = asi->dwFormatChangeCount;
1525  }
1526 
1527  /* These values will be computed */
1528  pstream->sInfo.dwLength = 0;
1529  pstream->sInfo.dwSuggestedBufferSize = 0;
1530  pstream->sInfo.dwFormatChangeCount = 0;
1531  pstream->sInfo.dwEditCount = 1;
1532  if (pstream->sInfo.dwSampleSize > 0)
1533  SetRectEmpty(&pstream->sInfo.rcFrame);
1534  }
1535 
1537 }
1538 
1540 {
1541  /* pre-conditions */
1542  assert(This != NULL);
1543 
1544  This->dwCurrentFrame = (DWORD)-1;
1545  This->lLastFrame = -1;
1546  This->paf = NULL;
1547  if (This->idxFrames != NULL) {
1548  HeapFree(GetProcessHeap(), 0, This->idxFrames);
1549  This->idxFrames = NULL;
1550  This->nIdxFrames = 0;
1551  }
1552  HeapFree(GetProcessHeap(), 0, This->idxFmtChanges);
1553  This->idxFmtChanges = NULL;
1554  if (This->lpBuffer != NULL) {
1555  HeapFree(GetProcessHeap(), 0, This->lpBuffer);
1556  This->lpBuffer = NULL;
1557  This->cbBuffer = 0;
1558  }
1559  if (This->lpHandlerData != NULL) {
1560  HeapFree(GetProcessHeap(), 0, This->lpHandlerData);
1561  This->lpHandlerData = NULL;
1562  This->cbHandlerData = 0;
1563  }
1564  if (This->extra.lp != NULL) {
1565  HeapFree(GetProcessHeap(), 0, This->extra.lp);
1566  This->extra.lp = NULL;
1567  This->extra.cb = 0;
1568  }
1569  if (This->lpFormat != NULL) {
1570  HeapFree(GetProcessHeap(), 0, This->lpFormat);
1571  This->lpFormat = NULL;
1572  This->cbFormat = 0;
1573  }
1574 }
1575 
1577 {
1578  MainAVIHeader MainAVIHdr;
1579  MMCKINFO ckRIFF;
1580  MMCKINFO ckLIST1;
1581  MMCKINFO ckLIST2;
1582  MMCKINFO ck;
1583  IAVIStreamImpl *pStream;
1584  DWORD nStream;
1585  HRESULT hr;
1586 
1587  if (This->hmmio == NULL)
1588  return AVIERR_FILEOPEN;
1589 
1590  /* initialize stream ptr's */
1591  memset(This->ppStreams, 0, sizeof(This->ppStreams));
1592 
1593  /* try to get "RIFF" chunk -- must not be at beginning of file! */
1594  ckRIFF.fccType = formtypeAVI;
1595  if (mmioDescend(This->hmmio, &ckRIFF, NULL, MMIO_FINDRIFF) != S_OK) {
1596  ERR(": not an AVI!\n");
1597  return AVIERR_FILEREAD;
1598  }
1599 
1600  /* get "LIST" "hdrl" */
1601  ckLIST1.fccType = listtypeAVIHEADER;
1602  hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ckLIST1, &ckRIFF, MMIO_FINDLIST);
1603  if (FAILED(hr))
1604  return hr;
1605 
1606  /* get "avih" chunk */
1607  ck.ckid = ckidAVIMAINHDR;
1608  hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckLIST1, MMIO_FINDCHUNK);
1609  if (FAILED(hr))
1610  return hr;
1611 
1612  if (ck.cksize != sizeof(MainAVIHdr)) {
1613  ERR(": invalid size of %d for MainAVIHeader!\n", ck.cksize);
1614  return AVIERR_BADFORMAT;
1615  }
1616  if (mmioRead(This->hmmio, (HPSTR)&MainAVIHdr, ck.cksize) != ck.cksize)
1617  return AVIERR_FILEREAD;
1618 
1619  /* check for MAX_AVISTREAMS limit */
1620  if (MainAVIHdr.dwStreams > MAX_AVISTREAMS) {
1621  WARN("file contains %u streams, but only supports %d -- change MAX_AVISTREAMS!\n", MainAVIHdr.dwStreams, MAX_AVISTREAMS);
1622  return AVIERR_UNSUPPORTED;
1623  }
1624 
1625  /* adjust permissions if copyrighted material in file */
1626  if (MainAVIHdr.dwFlags & AVIFILEINFO_COPYRIGHTED) {
1627  This->uMode &= ~MMIO_RWMODE;
1628  This->uMode |= MMIO_READ;
1629  }
1630 
1631  /* convert MainAVIHeader into AVIFILINFOW */
1632  memset(&This->fInfo, 0, sizeof(This->fInfo));
1633  This->fInfo.dwRate = MainAVIHdr.dwMicroSecPerFrame;
1634  This->fInfo.dwScale = 1000000;
1635  This->fInfo.dwMaxBytesPerSec = MainAVIHdr.dwMaxBytesPerSec;
1636  This->fInfo.dwFlags = MainAVIHdr.dwFlags;
1638  This->fInfo.dwLength = MainAVIHdr.dwTotalFrames;
1639  This->fInfo.dwStreams = MainAVIHdr.dwStreams;
1640  This->fInfo.dwSuggestedBufferSize = 0;
1641  This->fInfo.dwWidth = MainAVIHdr.dwWidth;
1642  This->fInfo.dwHeight = MainAVIHdr.dwHeight;
1643  LoadStringW(AVIFILE_hModule, IDS_AVIFILETYPE, This->fInfo.szFileType,
1644  ARRAY_SIZE(This->fInfo.szFileType));
1645 
1646  /* go back to into header list */
1647  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
1648  return AVIERR_FILEREAD;
1649 
1650  /* foreach stream exists a "LIST","strl" chunk */
1651  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
1652  /* get next nested chunk in this "LIST","strl" */
1653  if (mmioDescend(This->hmmio, &ckLIST2, &ckLIST1, 0) != S_OK)
1654  return AVIERR_FILEREAD;
1655 
1656  /* nested chunk must be of type "LIST","strl" -- when not normally JUNK */
1657  if (ckLIST2.ckid == FOURCC_LIST &&
1658  ckLIST2.fccType == listtypeSTREAMHEADER) {
1659  pStream = This->ppStreams[nStream] =
1661  if (pStream == NULL)
1662  return AVIERR_MEMORY;
1664 
1665  ck.ckid = 0;
1666  while (mmioDescend(This->hmmio, &ck, &ckLIST2, 0) == S_OK) {
1667  switch (ck.ckid) {
1668  case ckidSTREAMHANDLERDATA:
1669  if (pStream->lpHandlerData != NULL)
1670  return AVIERR_BADFORMAT;
1671  pStream->lpHandlerData = HeapAlloc(GetProcessHeap(), 0, ck.cksize);
1672  if (pStream->lpHandlerData == NULL)
1673  return AVIERR_MEMORY;
1674  pStream->cbHandlerData = ck.cksize;
1675 
1676  if (mmioRead(This->hmmio, pStream->lpHandlerData, ck.cksize) != ck.cksize)
1677  return AVIERR_FILEREAD;
1678  break;
1679  case ckidSTREAMFORMAT:
1680  if (pStream->lpFormat != NULL)
1681  return AVIERR_BADFORMAT;
1682  if (ck.cksize == 0)
1683  break;
1684 
1685  pStream->lpFormat = HeapAlloc(GetProcessHeap(), 0, ck.cksize);
1686  if (pStream->lpFormat == NULL)
1687  return AVIERR_MEMORY;
1688  pStream->cbFormat = ck.cksize;
1689 
1690  if (mmioRead(This->hmmio, pStream->lpFormat, ck.cksize) != ck.cksize)
1691  return AVIERR_FILEREAD;
1692 
1693  if (pStream->sInfo.fccType == streamtypeVIDEO) {
1694  LPBITMAPINFOHEADER lpbi = pStream->lpFormat;
1695 
1696  /* some corrections to the video format */
1697  if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
1698  lpbi->biClrUsed = 1u << lpbi->biBitCount;
1699  if (lpbi->biCompression == BI_RGB && lpbi->biSizeImage == 0)
1700  lpbi->biSizeImage = DIBWIDTHBYTES(*lpbi) * lpbi->biHeight;
1701  if (lpbi->biCompression != BI_RGB && lpbi->biBitCount == 8) {
1702  if (pStream->sInfo.fccHandler == mmioFOURCC('R','L','E','0') ||
1703  pStream->sInfo.fccHandler == mmioFOURCC('R','L','E',' '))
1704  lpbi->biCompression = BI_RLE8;
1705  }
1706  if (lpbi->biCompression == BI_RGB &&
1707  (pStream->sInfo.fccHandler == 0 ||
1708  pStream->sInfo.fccHandler == mmioFOURCC('N','O','N','E')))
1709  pStream->sInfo.fccHandler = comptypeDIB;
1710 
1711  /* init rcFrame if it's empty */
1712  if (IsRectEmpty(&pStream->sInfo.rcFrame))
1713  SetRect(&pStream->sInfo.rcFrame, 0, 0, lpbi->biWidth, lpbi->biHeight);
1714  }
1715  break;
1716  case ckidSTREAMHEADER:
1717  {
1718  static const WCHAR streamTypeFmt[] = {'%','4','.','4','h','s',0};
1719  static const WCHAR streamNameFmt[] = {'%','s',' ','%','s',' ','#','%','d',0};
1720 
1721  AVIStreamHeader streamHdr;
1722  WCHAR szType[25];
1723  UINT count;
1724  LONG n = ck.cksize;
1725 
1726  if (ck.cksize > sizeof(streamHdr))
1727  n = sizeof(streamHdr);
1728 
1729  if (mmioRead(This->hmmio, (HPSTR)&streamHdr, n) != n)
1730  return AVIERR_FILEREAD;
1731 
1732  pStream->sInfo.fccType = streamHdr.fccType;
1733  pStream->sInfo.fccHandler = streamHdr.fccHandler;
1734  pStream->sInfo.dwFlags = streamHdr.dwFlags;
1735  pStream->sInfo.wPriority = streamHdr.wPriority;
1736  pStream->sInfo.wLanguage = streamHdr.wLanguage;
1737  pStream->sInfo.dwInitialFrames = streamHdr.dwInitialFrames;
1738  pStream->sInfo.dwScale = streamHdr.dwScale;
1739  pStream->sInfo.dwRate = streamHdr.dwRate;
1740  pStream->sInfo.dwStart = streamHdr.dwStart;
1741  pStream->sInfo.dwLength = streamHdr.dwLength;
1742  pStream->sInfo.dwSuggestedBufferSize = 0;
1743  pStream->sInfo.dwQuality = streamHdr.dwQuality;
1744  pStream->sInfo.dwSampleSize = streamHdr.dwSampleSize;
1745  pStream->sInfo.rcFrame.left = streamHdr.rcFrame.left;
1746  pStream->sInfo.rcFrame.top = streamHdr.rcFrame.top;
1747  pStream->sInfo.rcFrame.right = streamHdr.rcFrame.right;
1748  pStream->sInfo.rcFrame.bottom = streamHdr.rcFrame.bottom;
1749  pStream->sInfo.dwEditCount = 0;
1750  pStream->sInfo.dwFormatChangeCount = 0;
1751 
1752  /* generate description for stream like "filename.avi Type #n" */
1753  if (streamHdr.fccType == streamtypeVIDEO)
1755  else if (streamHdr.fccType == streamtypeAUDIO)
1757  else
1758  wsprintfW(szType, streamTypeFmt, (char*)&streamHdr.fccType);
1759 
1760  /* get count of this streamtype up to this stream */
1761  count = 0;
1762  for (n = nStream; 0 <= n; n--) {
1763  if (This->ppStreams[n]->sInfo.fccHandler == streamHdr.fccType)
1764  count++;
1765  }
1766 
1767  memset(pStream->sInfo.szName, 0, sizeof(pStream->sInfo.szName));
1768 
1769  /* FIXME: avoid overflow -- better use wsnprintfW, which doesn't exists ! */
1770  wsprintfW(pStream->sInfo.szName, streamNameFmt,
1771  AVIFILE_BasenameW(This->szFileName), szType, count);
1772  }
1773  break;
1774  case ckidSTREAMNAME:
1775  { /* streamname will be saved as ASCII string */
1776  LPSTR str = HeapAlloc(GetProcessHeap(), 0, ck.cksize);
1777  if (str == NULL)
1778  return AVIERR_MEMORY;
1779 
1780  if (mmioRead(This->hmmio, str, ck.cksize) != ck.cksize)
1781  {
1782  HeapFree(GetProcessHeap(), 0, str);
1783  return AVIERR_FILEREAD;
1784  }
1785 
1786  MultiByteToWideChar(CP_ACP, 0, str, -1, pStream->sInfo.szName,
1787  ARRAY_SIZE(pStream->sInfo.szName));
1788 
1789  HeapFree(GetProcessHeap(), 0, str);
1790  }
1791  break;
1792  case ckidAVIPADDING:
1793  case mmioFOURCC('p','a','d','d'):
1794  break;
1795  default:
1796  WARN(": found extra chunk 0x%08X\n", ck.ckid);
1797  hr = ReadChunkIntoExtra(&pStream->extra, This->hmmio, &ck);
1798  if (FAILED(hr))
1799  return hr;
1800  };
1801  if (pStream->lpFormat != NULL && pStream->sInfo.fccType == streamtypeAUDIO)
1802  {
1803  WAVEFORMATEX *wfx = pStream->lpFormat; /* wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8; could be added */
1804  pStream->sInfo.dwSampleSize = wfx->nBlockAlign; /* to deal with corrupt wfx->nBlockAlign but Windows doesn't do this */
1805  TRACE("Block size reset to %u, chan=%u bpp=%u\n", wfx->nBlockAlign, wfx->nChannels, wfx->wBitsPerSample);
1806  pStream->sInfo.dwScale = 1;
1807  pStream->sInfo.dwRate = wfx->nSamplesPerSec;
1808  }
1809  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
1810  return AVIERR_FILEREAD;
1811  }
1812  } else {
1813  /* nested chunks in "LIST","hdrl" which are not of type "LIST","strl" */
1814  hr = ReadChunkIntoExtra(&This->fileextra, This->hmmio, &ckLIST2);
1815  if (FAILED(hr))
1816  return hr;
1817  }
1818  if (mmioAscend(This->hmmio, &ckLIST2, 0) != S_OK)
1819  return AVIERR_FILEREAD;
1820  }
1821 
1822  /* read any extra headers in "LIST","hdrl" */
1823  FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckLIST1, 0);
1824  if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
1825  return AVIERR_FILEREAD;
1826 
1827  /* search "LIST","movi" chunk in "RIFF","AVI " */
1828  ckLIST1.fccType = listtypeAVIMOVIE;
1829  hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ckLIST1, &ckRIFF,
1830  MMIO_FINDLIST);
1831  if (FAILED(hr))
1832  return hr;
1833 
1834  This->dwMoviChunkPos = ckLIST1.dwDataOffset;
1835  This->dwIdxChunkPos = ckLIST1.cksize + ckLIST1.dwDataOffset;
1836  if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
1837  return AVIERR_FILEREAD;
1838 
1839  /* try to find an index */
1840  ck.ckid = ckidAVINEWINDEX;
1841  hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio,
1842  &ck, &ckRIFF, MMIO_FINDCHUNK);
1843  if (SUCCEEDED(hr) && ck.cksize > 0) {
1844  if (FAILED(AVIFILE_LoadIndex(This, ck.cksize, ckLIST1.dwDataOffset)))
1845  This->fInfo.dwFlags &= ~AVIFILEINFO_HASINDEX;
1846  }
1847 
1848  /* when we haven't found an index or it's bad, then build one
1849  * by parsing 'movi' chunk */
1850  if ((This->fInfo.dwFlags & AVIFILEINFO_HASINDEX) == 0) {
1851  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++)
1852  This->ppStreams[nStream]->lLastFrame = -1;
1853 
1854  if (mmioSeek(This->hmmio, ckLIST1.dwDataOffset + sizeof(DWORD), SEEK_SET) == -1) {
1855  ERR(": Oops, can't seek back to 'movi' chunk!\n");
1856  return AVIERR_FILEREAD;
1857  }
1858 
1859  /* seek through the 'movi' list until end */
1860  while (mmioDescend(This->hmmio, &ck, &ckLIST1, 0) == S_OK) {
1861  if (ck.ckid != FOURCC_LIST) {
1862  if (mmioAscend(This->hmmio, &ck, 0) == S_OK) {
1863  nStream = StreamFromFOURCC(ck.ckid);
1864 
1865  if (nStream > This->fInfo.dwStreams)
1866  return AVIERR_BADFORMAT;
1867 
1868  AVIFILE_AddFrame(This->ppStreams[nStream], ck.ckid, ck.cksize,
1869  ck.dwDataOffset - 2 * sizeof(DWORD), 0);
1870  } else {
1871  nStream = StreamFromFOURCC(ck.ckid);
1872  WARN(": file seems to be truncated!\n");
1873  if (nStream <= This->fInfo.dwStreams &&
1874  This->ppStreams[nStream]->sInfo.dwSampleSize > 0) {
1875  ck.cksize = mmioSeek(This->hmmio, 0, SEEK_END);
1876  if (ck.cksize != -1) {
1877  ck.cksize -= ck.dwDataOffset;
1878  ck.cksize &= ~(This->ppStreams[nStream]->sInfo.dwSampleSize - 1);
1879 
1880  AVIFILE_AddFrame(This->ppStreams[nStream], ck.ckid, ck.cksize,
1881  ck.dwDataOffset - 2 * sizeof(DWORD), 0);
1882  }
1883  }
1884  }
1885  }
1886  }
1887  }
1888 
1889  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++)
1890  {
1891  DWORD sugbuf = This->ppStreams[nStream]->sInfo.dwSuggestedBufferSize;
1892  if (This->fInfo.dwSuggestedBufferSize < sugbuf)
1893  This->fInfo.dwSuggestedBufferSize = sugbuf;
1894  }
1895 
1896  /* find other chunks */
1897  FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckRIFF, 0);
1898 
1899  return AVIERR_OK;
1900 }
1901 
1903 {
1904  AVIINDEXENTRY *lp;
1905  DWORD pos, n;
1906  HRESULT hr = AVIERR_OK;
1907  BOOL bAbsolute = TRUE;
1908 
1909  lp = HeapAlloc(GetProcessHeap(), 0, IDX_PER_BLOCK * sizeof(AVIINDEXENTRY));
1910  if (lp == NULL)
1911  return AVIERR_MEMORY;
1912 
1913  /* adjust limits for index tables, so that inserting will be faster */
1914  for (n = 0; n < This->fInfo.dwStreams; n++) {
1915  IAVIStreamImpl *pStream = This->ppStreams[n];
1916 
1917  pStream->lLastFrame = -1;
1918 
1919  if (pStream->idxFrames != NULL) {
1920  HeapFree(GetProcessHeap(), 0, pStream->idxFrames);
1921  pStream->idxFrames = NULL;
1922  pStream->nIdxFrames = 0;
1923  }
1924 
1925  if (pStream->sInfo.dwSampleSize != 0) {
1926  if (n > 0 && This->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) {
1927  pStream->nIdxFrames = This->ppStreams[0]->nIdxFrames;
1928  } else if (pStream->sInfo.dwSuggestedBufferSize) {
1929  pStream->nIdxFrames =
1930  pStream->sInfo.dwLength / pStream->sInfo.dwSuggestedBufferSize;
1931  }
1932  } else
1933  pStream->nIdxFrames = pStream->sInfo.dwLength;
1934 
1935  pStream->idxFrames =
1937  if (pStream->idxFrames == NULL && pStream->nIdxFrames > 0) {
1938  pStream->nIdxFrames = 0;
1939  HeapFree(GetProcessHeap(), 0, lp);
1940  return AVIERR_MEMORY;
1941  }
1942  }
1943 
1944  pos = (DWORD)-1;
1945  while (size != 0) {
1946  LONG read = min(IDX_PER_BLOCK * sizeof(AVIINDEXENTRY), size);
1947 
1948  if (mmioRead(This->hmmio, (HPSTR)lp, read) != read) {
1949  hr = AVIERR_FILEREAD;
1950  break;
1951  }
1952  size -= read;
1953 
1954  if (pos == (DWORD)-1)
1955  pos = offset - lp->dwChunkOffset + sizeof(DWORD);
1956 
1957  AVIFILE_ParseIndex(This, lp, read / sizeof(AVIINDEXENTRY),
1958  pos, &bAbsolute);
1959  }
1960 
1961  HeapFree(GetProcessHeap(), 0, lp);
1962 
1963  /* checking ... */
1964  for (n = 0; n < This->fInfo.dwStreams; n++) {
1965  IAVIStreamImpl *pStream = This->ppStreams[n];
1966 
1967  if (pStream->sInfo.dwSampleSize == 0 &&
1968  pStream->sInfo.dwLength != pStream->lLastFrame+1)
1969  ERR("stream %u length mismatch: dwLength=%u found=%d\n",
1970  n, pStream->sInfo.dwLength, pStream->lLastFrame);
1971  }
1972 
1973  return hr;
1974 }
1975 
1977  LONG count, DWORD pos, BOOL *bAbsolute)
1978 {
1979  if (lp == NULL)
1980  return AVIERR_BADPARAM;
1981 
1982  for (; count > 0; count--, lp++) {
1983  WORD nStream = StreamFromFOURCC(lp->ckid);
1984 
1985  if (lp->ckid == listtypeAVIRECORD || nStream == 0x7F)
1986  continue; /* skip these */
1987 
1988  if (nStream > This->fInfo.dwStreams)
1989  return AVIERR_BADFORMAT;
1990 
1991  /* Video frames can be either indexed in a relative position to the
1992  * "movi" chunk or in a absolute position in the file. If the index
1993  * is relative the frame offset will always be so small that it will
1994  * virtually never reach the "movi" offset so we can detect if the
1995  * video is relative very fast.
1996  */
1997  if (*bAbsolute && lp->dwChunkOffset < This->dwMoviChunkPos)
1998  *bAbsolute = FALSE;
1999 
2000  if (!*bAbsolute)
2001  lp->dwChunkOffset += pos; /* make the offset absolute */
2002 
2003  if (FAILED(AVIFILE_AddFrame(This->ppStreams[nStream], lp->ckid, lp->dwChunkLength, lp->dwChunkOffset, lp->dwFlags)))
2004  return AVIERR_MEMORY;
2005  }
2006 
2007  return AVIERR_OK;
2008 }
2009 
2012 {
2013  /* pre-conditions */
2014  assert(This != NULL);
2015  assert(This->paf != NULL);
2016  assert(This->paf->hmmio != NULL);
2017  assert(This->sInfo.dwStart <= pos && pos < This->sInfo.dwLength);
2018  assert(pos <= This->lLastFrame);
2019 
2020  /* should we read as much as block gives us? */
2021  if (size == 0 || size > This->idxFrames[pos].dwChunkLength)
2022  size = This->idxFrames[pos].dwChunkLength;
2023 
2024  /* read into out own buffer or given one? */
2025  if (buffer == NULL) {
2026  /* we also read the chunk */
2027  size += 2 * sizeof(DWORD);
2028 
2029  /* check that buffer is big enough -- don't trust dwSuggestedBufferSize */
2030  if (This->lpBuffer == NULL || This->cbBuffer < size) {
2031  DWORD maxSize = max(size, This->sInfo.dwSuggestedBufferSize);
2032 
2033  if (This->lpBuffer == NULL) {
2034  This->lpBuffer = HeapAlloc(GetProcessHeap(), 0, maxSize);
2035  if (!This->lpBuffer) return AVIERR_MEMORY;
2036  } else {
2037  void *new_buffer = HeapReAlloc(GetProcessHeap(), 0, This->lpBuffer, maxSize);
2038  if (!new_buffer) return AVIERR_MEMORY;
2039  This->lpBuffer = new_buffer;
2040  }
2041  This->cbBuffer = maxSize;
2042  }
2043 
2044  /* now read the complete chunk into our buffer */
2045  if (mmioSeek(This->paf->hmmio, This->idxFrames[pos].dwChunkOffset, SEEK_SET) == -1)
2046  return AVIERR_FILEREAD;
2047  if (mmioRead(This->paf->hmmio, (HPSTR)This->lpBuffer, size) != size)
2048  return AVIERR_FILEREAD;
2049 
2050  /* check if it was the correct block which we have read */
2051  if (This->lpBuffer[0] != This->idxFrames[pos].ckid ||
2052  This->lpBuffer[1] != This->idxFrames[pos].dwChunkLength) {
2053  ERR(": block %d not found at 0x%08X\n", pos, This->idxFrames[pos].dwChunkOffset);
2054  ERR(": Index says: '%4.4s'(0x%08X) size 0x%08X\n",
2055  (char*)&This->idxFrames[pos].ckid, This->idxFrames[pos].ckid,
2056  This->idxFrames[pos].dwChunkLength);
2057  ERR(": Data says: '%4.4s'(0x%08X) size 0x%08X\n",
2058  (char*)&This->lpBuffer[0], This->lpBuffer[0], This->lpBuffer[1]);
2059  return AVIERR_FILEREAD;
2060  }
2061  } else {
2062  if (mmioSeek(This->paf->hmmio, This->idxFrames[pos].dwChunkOffset + 2 * sizeof(DWORD), SEEK_SET) == -1)
2063  return AVIERR_FILEREAD;
2064  if (mmioRead(This->paf->hmmio, buffer, size) != size)
2065  return AVIERR_FILEREAD;
2066  }
2067 
2068  return AVIERR_OK;
2069 }
2070 
2072 {
2073  LONG block;
2074 
2075  /* pre-conditions */
2076  assert(This != NULL);
2077  assert(pos != NULL);
2078  assert(offset != NULL);
2079  assert(This->sInfo.dwSampleSize != 0);
2080  assert(*pos >= This->sInfo.dwStart);
2081 
2082  /* convert start sample to start bytes */
2083  (*offset) = (*pos) - This->sInfo.dwStart;
2084  (*offset) *= This->sInfo.dwSampleSize;
2085 
2086  /* convert bytes to block number */
2087  for (block = 0; block <= This->lLastFrame; block++) {
2088  if (This->idxFrames[block].dwChunkLength <= *offset)
2089  (*offset) -= This->idxFrames[block].dwChunkLength;
2090  else
2091  break;
2092  }
2093 
2094  *pos = block;
2095 }
2096 
2098 {
2099  MainAVIHeader MainAVIHdr;
2100  IAVIStreamImpl* pStream;
2101  MMCKINFO ckRIFF;
2102  MMCKINFO ckLIST1;
2103  MMCKINFO ckLIST2;
2104  MMCKINFO ck;
2105  DWORD nStream;
2106  DWORD dwPos;
2107  HRESULT hr;
2108 
2109  /* initialize some things */
2110  if (This->dwMoviChunkPos == 0)
2112 
2113  /* written one record too much? */
2114  if (This->ckLastRecord.dwFlags & MMIO_DIRTY) {
2115  This->dwNextFramePos -= 3 * sizeof(DWORD);
2116  if (This->nIdxRecords > 0)
2117  This->nIdxRecords--;
2118  }
2119 
2121 
2122  assert(This->fInfo.dwScale != 0);
2123 
2124  memset(&MainAVIHdr, 0, sizeof(MainAVIHdr));
2125  MainAVIHdr.dwMicroSecPerFrame = MulDiv(This->fInfo.dwRate, 1000000,
2126  This->fInfo.dwScale);
2127  MainAVIHdr.dwMaxBytesPerSec = This->fInfo.dwMaxBytesPerSec;
2128  MainAVIHdr.dwPaddingGranularity = AVI_HEADERSIZE;
2129  MainAVIHdr.dwFlags = This->fInfo.dwFlags;
2130  MainAVIHdr.dwTotalFrames = This->fInfo.dwLength;
2131  MainAVIHdr.dwInitialFrames = 0;
2132  MainAVIHdr.dwStreams = This->fInfo.dwStreams;
2133  MainAVIHdr.dwSuggestedBufferSize = This->fInfo.dwSuggestedBufferSize;
2134  MainAVIHdr.dwWidth = This->fInfo.dwWidth;
2135  MainAVIHdr.dwHeight = This->fInfo.dwHeight;
2136  MainAVIHdr.dwInitialFrames = This->dwInitialFrames;
2137 
2138  /* now begin writing ... */
2139  mmioSeek(This->hmmio, 0, SEEK_SET);
2140 
2141  /* RIFF chunk */
2142  ckRIFF.cksize = 0;
2143  ckRIFF.fccType = formtypeAVI;
2144  if (mmioCreateChunk(This->hmmio, &ckRIFF, MMIO_CREATERIFF) != S_OK)
2145  return AVIERR_FILEWRITE;
2146 
2147  /* AVI headerlist */
2148  ckLIST1.cksize = 0;
2149  ckLIST1.fccType = listtypeAVIHEADER;
2150  if (mmioCreateChunk(This->hmmio, &ckLIST1, MMIO_CREATELIST) != S_OK)
2151  return AVIERR_FILEWRITE;
2152 
2153  /* MainAVIHeader */
2154  ck.ckid = ckidAVIMAINHDR;
2155  ck.cksize = sizeof(MainAVIHdr);
2156  ck.fccType = 0;
2157  if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
2158  return AVIERR_FILEWRITE;
2159  if (mmioWrite(This->hmmio, (HPSTR)&MainAVIHdr, ck.cksize) != ck.cksize)
2160  return AVIERR_FILEWRITE;
2161  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
2162  return AVIERR_FILEWRITE;
2163 
2164  /* write the headers of each stream into a separate streamheader list */
2165  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
2166  AVIStreamHeader strHdr;
2167 
2168  pStream = This->ppStreams[nStream];
2169 
2170  /* begin the new streamheader list */
2171  ckLIST2.cksize = 0;
2172  ckLIST2.fccType = listtypeSTREAMHEADER;
2173  if (mmioCreateChunk(This->hmmio, &ckLIST2, MMIO_CREATELIST) != S_OK)
2174  return AVIERR_FILEWRITE;
2175 
2176  /* create an AVIStreamHeader from the AVSTREAMINFO */
2177  strHdr.fccType = pStream->sInfo.fccType;
2178  strHdr.fccHandler = pStream->sInfo.fccHandler;
2179  strHdr.dwFlags = pStream->sInfo.dwFlags;
2180  strHdr.wPriority = pStream->sInfo.wPriority;
2181  strHdr.wLanguage = pStream->sInfo.wLanguage;
2182  strHdr.dwInitialFrames = pStream->sInfo.dwInitialFrames;
2183  strHdr.dwScale = pStream->sInfo.dwScale;
2184  strHdr.dwRate = pStream->sInfo.dwRate;
2185  strHdr.dwStart = pStream->sInfo.dwStart;
2186  strHdr.dwLength = pStream->sInfo.dwLength;
2188  strHdr.dwQuality = pStream->sInfo.dwQuality;
2189  strHdr.dwSampleSize = pStream->sInfo.dwSampleSize;
2190  strHdr.rcFrame.left = pStream->sInfo.rcFrame.left;
2191  strHdr.rcFrame.top = pStream->sInfo.rcFrame.top;
2192  strHdr.rcFrame.right = pStream->sInfo.rcFrame.right;
2193  strHdr.rcFrame.bottom = pStream->sInfo.rcFrame.bottom;
2194 
2195  /* now write the AVIStreamHeader */
2196  ck.ckid = ckidSTREAMHEADER;
2197  ck.cksize = sizeof(strHdr);
2198  if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
2199  return AVIERR_FILEWRITE;
2200  if (mmioWrite(This->hmmio, (HPSTR)&strHdr, ck.cksize) != ck.cksize)
2201  return AVIERR_FILEWRITE;
2202  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
2203  return AVIERR_FILEWRITE;
2204 
2205  /* ... the hopefully ever present streamformat ... */
2206  ck.ckid = ckidSTREAMFORMAT;
2207  ck.cksize = pStream->cbFormat;
2208  if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
2209  return AVIERR_FILEWRITE;
2210  if (pStream->lpFormat != NULL && ck.cksize > 0) {
2211  if (mmioWrite(This->hmmio, pStream->lpFormat, ck.cksize) != ck.cksize)
2212  return AVIERR_FILEWRITE;
2213  }
2214  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
2215  return AVIERR_FILEWRITE;
2216 
2217  /* ... some optional existing handler data ... */
2218  if (pStream->lpHandlerData != NULL && pStream->cbHandlerData > 0) {
2220  ck.cksize = pStream->cbHandlerData;
2221  if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
2222  return AVIERR_FILEWRITE;
2223  if (mmioWrite(This->hmmio, pStream->lpHandlerData, ck.cksize) != ck.cksize)
2224  return AVIERR_FILEWRITE;
2225  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
2226  return AVIERR_FILEWRITE;
2227  }
2228 
2229  /* ... some optional additional extra chunk for this stream ... */
2230  if (pStream->extra.lp != NULL && pStream->extra.cb > 0) {
2231  /* the chunk header(s) are already in the structure */
2232  if (mmioWrite(This->hmmio, pStream->extra.lp, pStream->extra.cb) != pStream->extra.cb)
2233  return AVIERR_FILEWRITE;
2234  }
2235 
2236  /* ... an optional name for this stream ... */
2237  if (pStream->sInfo.szName[0]) {
2238  LPSTR str;
2239 
2240  ck.ckid = ckidSTREAMNAME;
2241  ck.cksize = lstrlenW(pStream->sInfo.szName) + 1;
2242  if (ck.cksize & 1) /* align */
2243  ck.cksize++;
2244  if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
2245  return AVIERR_FILEWRITE;
2246 
2247  /* the streamname must be saved in ASCII not Unicode */
2248  str = HeapAlloc(GetProcessHeap(), 0, ck.cksize);
2249  if (str == NULL)
2250  return AVIERR_MEMORY;
2251  WideCharToMultiByte(CP_ACP, 0, pStream->sInfo.szName, -1, str,
2252  ck.cksize, NULL, NULL);
2253 
2254  if (mmioWrite(This->hmmio, str, ck.cksize) != ck.cksize) {
2255  HeapFree(GetProcessHeap(), 0, str);
2256  return AVIERR_FILEWRITE;
2257  }
2258 
2259  HeapFree(GetProcessHeap(), 0, str);
2260  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
2261  return AVIERR_FILEWRITE;
2262  }
2263 
2264  /* close streamheader list for this stream */
2265  if (mmioAscend(This->hmmio, &ckLIST2, 0) != S_OK)
2266  return AVIERR_FILEWRITE;
2267  } /* for (0 <= nStream < MainAVIHdr.dwStreams) */
2268 
2269  /* close the aviheader list */
2270  if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
2271  return AVIERR_FILEWRITE;
2272 
2273  /* check for padding to pre-guessed 'movi'-chunk position */
2274  dwPos = ckLIST1.dwDataOffset + ckLIST1.cksize;
2275  if (This->dwMoviChunkPos - 2 * sizeof(DWORD) > dwPos) {
2276  ck.ckid = ckidAVIPADDING;
2277  ck.cksize = This->dwMoviChunkPos - dwPos - 4 * sizeof(DWORD);
2278  assert((LONG)ck.cksize >= 0);
2279 
2280  if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
2281  return AVIERR_FILEWRITE;
2282  if (mmioSeek(This->hmmio, ck.cksize, SEEK_CUR) == -1)
2283  return AVIERR_FILEWRITE;
2284  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
2285  return AVIERR_FILEWRITE;
2286  }
2287 
2288  /* now write the 'movi' chunk */
2289  mmioSeek(This->hmmio, This->dwMoviChunkPos - 2 * sizeof(DWORD), SEEK_SET);
2290  ckLIST1.cksize = 0;
2291  ckLIST1.fccType = listtypeAVIMOVIE;
2292  if (mmioCreateChunk(This->hmmio, &ckLIST1, MMIO_CREATELIST) != S_OK)
2293  return AVIERR_FILEWRITE;
2294  if (mmioSeek(This->hmmio, This->dwNextFramePos, SEEK_SET) == -1)
2295  return AVIERR_FILEWRITE;
2296  if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
2297  return AVIERR_FILEWRITE;
2298 
2299  /* write 'idx1' chunk */
2301  if (FAILED(hr))
2302  return hr;
2303 
2304  /* write optional extra file chunks */
2305  if (This->fileextra.lp != NULL && This->fileextra.cb > 0) {
2306  /* as for the streams, are the chunk header(s) in the structure */
2307  if (mmioWrite(This->hmmio, This->fileextra.lp, This->fileextra.cb) != This->fileextra.cb)
2308  return AVIERR_FILEWRITE;
2309  }
2310 
2311  /* close RIFF chunk */
2312  if (mmioAscend(This->hmmio, &ckRIFF, 0) != S_OK)
2313  return AVIERR_FILEWRITE;
2314 
2315  /* add some JUNK at end for bad parsers */
2316  memset(&ckRIFF, 0, sizeof(ckRIFF));
2317  mmioWrite(This->hmmio, (HPSTR)&ckRIFF, sizeof(ckRIFF));
2318  mmioFlush(This->hmmio, 0);
2319 
2320  return AVIERR_OK;
2321 }
2322 
2324 {
2325  IAVIStreamImpl *pStream;
2327  MMCKINFO ck;
2328  DWORD nStream;
2329  LONG n;
2330 
2331  ck.ckid = ckidAVINEWINDEX;
2332  ck.cksize = 0;
2333  if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
2334  return AVIERR_FILEWRITE;
2335 
2336  if (This->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) {
2337  /* is interleaved -- write block of corresponding frames */
2338  LONG lInitialFrames = 0;
2339  LONG stepsize;
2340  LONG i;
2341 
2342  if (This->ppStreams[0]->sInfo.dwSampleSize == 0)
2343  stepsize = 1;
2344  else
2345  stepsize = AVIStreamTimeToSample(&This->ppStreams[0]->IAVIStream_iface, 1000000);
2346 
2347  assert(stepsize > 0);
2348 
2349  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
2350  if (lInitialFrames < This->ppStreams[nStream]->sInfo.dwInitialFrames)
2351  lInitialFrames = This->ppStreams[nStream]->sInfo.dwInitialFrames;
2352  }
2353 
2354  for (i = -lInitialFrames; i < (LONG)This->fInfo.dwLength - lInitialFrames;
2355  i += stepsize) {
2356  DWORD nFrame = lInitialFrames + i;
2357 
2358  assert(nFrame < This->nIdxRecords);
2359 
2360  idx.ckid = listtypeAVIRECORD;
2361  idx.dwFlags = AVIIF_LIST;
2362  idx.dwChunkLength = This->idxRecords[nFrame].dwChunkLength;
2363  idx.dwChunkOffset = This->idxRecords[nFrame].dwChunkOffset
2364  - This->dwMoviChunkPos;
2365  if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
2366  return AVIERR_FILEWRITE;
2367 
2368  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
2369  pStream = This->ppStreams[nStream];
2370 
2371  /* heave we reached start of this stream? */
2372  if (-(LONG)pStream->sInfo.dwInitialFrames > i)
2373  continue;
2374 
2375  if (pStream->sInfo.dwInitialFrames < lInitialFrames)
2376  nFrame -= (lInitialFrames - pStream->sInfo.dwInitialFrames);
2377 
2378  /* reached end of this stream? */
2379  if (pStream->lLastFrame <= nFrame)
2380  continue;
2381 
2382  if ((pStream->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
2383  pStream->sInfo.dwFormatChangeCount != 0 &&
2384  pStream->idxFmtChanges != NULL) {
2385  DWORD pos;
2386 
2387  for (pos = 0; pos < pStream->sInfo.dwFormatChangeCount; pos++) {
2388  if (pStream->idxFmtChanges[pos].ckid == nFrame) {
2389  idx.dwFlags = AVIIF_NOTIME;
2390  idx.ckid = MAKEAVICKID(cktypePALchange, pStream->nStream);
2391  idx.dwChunkLength = pStream->idxFmtChanges[pos].dwChunkLength;
2392  idx.dwChunkOffset = pStream->idxFmtChanges[pos].dwChunkOffset
2393  - This->dwMoviChunkPos;
2394 
2395  if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
2396  return AVIERR_FILEWRITE;
2397  break;
2398  }
2399  }
2400  } /* if have formatchanges */
2401 
2402  idx.ckid = pStream->idxFrames[nFrame].ckid;
2403  idx.dwFlags = pStream->idxFrames[nFrame].dwFlags;
2404  idx.dwChunkLength = pStream->idxFrames[nFrame].dwChunkLength;
2405  idx.dwChunkOffset = pStream->idxFrames[nFrame].dwChunkOffset
2406  - This->dwMoviChunkPos;
2407  if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
2408  return AVIERR_FILEWRITE;
2409  }
2410  }
2411  } else {
2412  /* not interleaved -- write index for each stream at once */
2413  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
2414  pStream = This->ppStreams[nStream];
2415 
2416  for (n = 0; n <= pStream->lLastFrame; n++) {
2417  if ((pStream->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
2418  (pStream->sInfo.dwFormatChangeCount != 0)) {
2419  DWORD pos;
2420 
2421  for (pos = 0; pos < pStream->sInfo.dwFormatChangeCount; pos++) {
2422  if (pStream->idxFmtChanges[pos].ckid == n) {
2423  idx.dwFlags = AVIIF_NOTIME;
2424  idx.ckid = MAKEAVICKID(cktypePALchange, pStream->nStream);
2425  idx.dwChunkLength = pStream->idxFmtChanges[pos].dwChunkLength;
2426  idx.dwChunkOffset =
2427  pStream->idxFmtChanges[pos].dwChunkOffset - This->dwMoviChunkPos;
2428  if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
2429  return AVIERR_FILEWRITE;
2430  break;
2431  }
2432  }
2433  } /* if have formatchanges */
2434 
2435  idx.ckid = pStream->idxFrames[n].ckid;
2436  idx.dwFlags = pStream->idxFrames[n].dwFlags;
2437  idx.dwChunkLength = pStream->idxFrames[n].dwChunkLength;
2438  idx.dwChunkOffset = pStream->idxFrames[n].dwChunkOffset
2439  - This->dwMoviChunkPos;
2440 
2441  if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
2442  return AVIERR_FILEWRITE;
2443  }
2444  }
2445  } /* if not interleaved */
2446 
2447  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
2448  return AVIERR_FILEWRITE;
2449 
2450  return AVIERR_OK;
2451 }
2452 
2454 {
2455  UINT i;
2456  UINT nStream;
2457 
2458  /* pre-condition */
2459  assert(lSkip >= 0);
2460 
2461  if (fcc != 0) {
2462  /* search the number of the specified stream */
2463  nStream = (ULONG)-1;
2464  for (i = 0; i < This->fInfo.dwStreams; i++) {
2465  assert(This->ppStreams[i] != NULL);
2466 
2467  if (This->ppStreams[i]->sInfo.fccType == fcc) {
2468  if (lSkip == 0) {
2469  nStream = i;
2470  break;
2471  } else
2472  lSkip--;
2473  }
2474  }
2475  } else
2476  nStream = lSkip;
2477 
2478  return nStream;
2479 }
2480 
2482 {
2483  UINT i;
2484 
2485  /* pre-conditions */
2486  assert(This != NULL);
2487 
2488  This->fInfo.dwMaxBytesPerSec = 0;
2490  This->fInfo.dwSuggestedBufferSize = 0;
2491  This->fInfo.dwWidth = 0;
2492  This->fInfo.dwHeight = 0;
2493  This->fInfo.dwScale = 0;
2494  This->fInfo.dwRate = 0;
2495  This->fInfo.dwLength = 0;
2496  This->dwInitialFrames = 0;
2497 
2498  for (i = 0; i < This->fInfo.dwStreams; i++) {
2499  AVISTREAMINFOW *psi;
2500  DWORD n;
2501 
2502  /* pre-conditions */
2503  assert(This->ppStreams[i] != NULL);
2504 
2505  psi = &This->ppStreams[i]->sInfo;
2506  assert(psi->dwScale != 0);
2507  assert(psi->dwRate != 0);
2508 
2509  if (i == 0) {
2510  /* use first stream timings as base */
2511  This->fInfo.dwScale = psi->dwScale;
2512  This->fInfo.dwRate = psi->dwRate;
2513  This->fInfo.dwLength = psi->dwLength;
2514  } else {
2515  n = AVIStreamSampleToSample(&This->ppStreams[0]->IAVIStream_iface,
2516  &This->ppStreams[i]->IAVIStream_iface, psi->dwLength);
2517  if (This->fInfo.dwLength < n)
2518  This->fInfo.dwLength = n;
2519  }
2520 
2521  if (This->dwInitialFrames < psi->dwInitialFrames)
2522  This->dwInitialFrames = psi->dwInitialFrames;
2523 
2524  if (This->fInfo.dwSuggestedBufferSize < psi->dwSuggestedBufferSize)
2525  This->fInfo.dwSuggestedBufferSize = psi->dwSuggestedBufferSize;
2526 
2527  if (psi->dwSampleSize != 0) {
2528  /* fixed sample size -- exact computation */
2529  This->fInfo.dwMaxBytesPerSec += MulDiv(psi->dwSampleSize, psi->dwRate,
2530  psi->dwScale);
2531  } else {
2532  /* variable sample size -- only upper limit */
2533  This->fInfo.dwMaxBytesPerSec += MulDiv(psi->dwSuggestedBufferSize,
2534  psi->dwRate, psi->dwScale);
2535 
2536  /* update dimensions */
2537  n = psi->rcFrame.right - psi->rcFrame.left;
2538  if (This->fInfo.dwWidth < n)
2539  This->fInfo.dwWidth = n;
2540  n = psi->rcFrame.bottom - psi->rcFrame.top;
2541  if (This->fInfo.dwHeight < n)
2542  This->fInfo.dwHeight = n;
2543  }
2544  }
2545 }
2546 
2548  FOURCC ckid, DWORD flags, LPCVOID buffer,
2549  LONG size)
2550 {
2551  MMCKINFO ck;
2552 
2553  ck.ckid = ckid;
2554  ck.cksize = size;
2555  ck.fccType = 0;
2556 
2557  /* if no frame/block is already written, we must compute start of movi chunk */
2558  if (This->paf->dwMoviChunkPos == 0)
2560 
2561  if (mmioSeek(This->paf->hmmio, This->paf->dwNextFramePos, SEEK_SET) == -1)
2562  return AVIERR_FILEWRITE;
2563 
2564  if (mmioCreateChunk(This->paf->hmmio, &ck, 0) != S_OK)
2565  return AVIERR_FILEWRITE;
2566  if (buffer != NULL && size > 0) {
2567  if (mmioWrite(This->paf->hmmio, buffer, size) != size)
2568  return AVIERR_FILEWRITE;
2569  }
2570  if (mmioAscend(This->paf->hmmio, &ck, 0) != S_OK)
2571  return AVIERR_FILEWRITE;
2572 
2573  This->paf->fDirty = TRUE;
2574  This->paf->dwNextFramePos = mmioSeek(This->paf->hmmio, 0, SEEK_CUR);
2575 
2576  return AVIFILE_AddFrame(This, ckid, size,
2577  ck.dwDataOffset - 2 * sizeof(DWORD), flags);
2578 }
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
int WINAPIV wsprintfW(_Out_ LPWSTR, _In_ _Printf_format_string_ LPCWSTR,...)
static unsigned int block
Definition: xmlmemory.c:118
DWORD dwFlags
Definition: vfw.h:944
#define MMIO_ALLOCBUF
Definition: mmsystem.h:532
DWORD dwInitialFrames
Definition: vfw.h:964
MMRESULT WINAPI mmioFlush(HMMIO hmmio, UINT uFlags)
Definition: mmio.c:960
GLsizei samples
Definition: glext.h:7006
#define SEEK_CUR
Definition: util.h:63
LPWSTR szFileName
Definition: avifile.c:116
struct _AVIINDEXENTRY AVIINDEXENTRY
#define AVIIF_LIST
Definition: aviriff.h:130
#define AVIFILEINFO_HASINDEX
Definition: vfw.h:1052
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define max(a, b)
Definition: svc.c:63
DWORD dwSampleSize
Definition: avifil32.idl:42
IAVIFileImpl * paf
Definition: avifile.c:64
static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface)
Definition: avifile.c:262
#define REFIID
Definition: guiddef.h:118
#define TRUE
Definition: types.h:120
#define E_NOINTERFACE
Definition: winerror.h:2364
#define ckidSTREAMFORMAT
Definition: aviriff.h:125
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile *iface, DWORD ckid, void *lpData, LONG size)
Definition: avifile.c:376
#define MMIO_RWMODE
Definition: mmsystem.h:526
#define FIND_ANY
Definition: vfw.h:1124
#define cktypeDIBcompressed
Definition: vfw.h:911
#define AVIERR_NODATA
Definition: vfw.h:1757
struct _IAVIStreamImpl IAVIStreamImpl
static IAVIFileImpl * impl_from_IPersistFile(IPersistFile *iface)
Definition: avifile.c:131
#define listtypeSTREAMHEADER
Definition: vfw.h:892
#define WideCharToMultiByte
Definition: compat.h:101
static ULONG WINAPI IAVIStream_fnRelease(IAVIStream *iface)
Definition: avifile.c:709
HRESULT hr
Definition: shlfolder.c:183
#define IDX_PER_BLOCK
Definition: avifile.c:55
DWORD dwSuggestedBufferSize
Definition: avifil32.idl:40
PALETTEENTRY peNew[1]
Definition: vfw.h:996
ULONG nr
Definition: thread.c:7
WINE_DEFAULT_DEBUG_CHANNEL(avifile)
HMODULE AVIFILE_hModule
Definition: factory.c:39
LONG lLastFrame
Definition: avifile.c:80
#define ckidAVIPADDING
Definition: vfw.h:916
DWORD nIdxFmtChanges
Definition: avifile.c:84
#define AVIFILEINFO_TRUSTCKTYPE
Definition: vfw.h:1055
#define MMIO_CREATELIST
Definition: mmsystem.h:555
REFIID riid
Definition: precomp.h:44
#define FIND_RET
Definition: vfw.h:1127
DWORD dwInitialFrames
Definition: vfw.h:946
#define listtypeAVIHEADER
Definition: vfw.h:890
#define CP_ACP
Definition: compat.h:99
struct AVIStreamHeader::@3137 rcFrame
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define AVIFILECAPS_CANREAD
Definition: vfw.h:1060
HMMIO hmmio
Definition: avifile.c:115
MMRESULT WINAPI mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT uFlags)
Definition: mmio.c:1204
char CHAR
Definition: xmlstorage.h:175
DWORD dwLength
Definition: vfw.h:968
DWORD dwChunkOffset
Definition: vfw.h:988
#define WARN(fmt,...)
Definition: debug.h:111
#define U(x)
Definition: wordpad.c:44
DWORD dwDataOffset
Definition: mmsystem.h:1510
HRESULT ReadChunkIntoExtra(LPEXTRACHUNKS extra, HMMIO hmmio, const MMCKINFO *lpck)
Definition: extrachunk.c:102
#define cktypeDIBbits
Definition: vfw.h:910
GLintptr offset
Definition: glext.h:5920
REFIID LPVOID * ppv
Definition: atlbase.h:39
static DWORD AVIFILE_ComputeMoviStart(IAVIFileImpl *This)
Definition: avifile.c:1458
GLdouble n
Definition: glext.h:7729
LONG top
Definition: windef.h:292
#define AVIIF_KEYFRAME
Definition: aviriff.h:131
HRESULT AVIFILE_CreateAVIFile(IUnknown *pUnkOuter, REFIID riid, void **ppv)
Definition: avifile.c:646
#define assert(x)
Definition: debug.h:53
MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags)
Definition: mmio.c:701
GLuint buffer
Definition: glext.h:5915
#define FIND_OFFSET
Definition: vfw.h:1130
DWORD dwStart
Definition: vfw.h:967
static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile *iface, REFIID riid, void **ppv)
Definition: avifile.c:497
#define ckidSTREAMHEADER
Definition: aviriff.h:88
HRESULT WriteExtraChunk(LPEXTRACHUNKS extra, FOURCC ckid, LPCVOID lpData, LONG size)
Definition: extrachunk.c:70
LPDWORD lpBuffer
Definition: avifile.c:76
HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO *lpmmioinfo, DWORD dwOpenFlags)
Definition: mmio.c:669
LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
Definition: api.c:928
DWORD cbFormat
Definition: avifile.c:69
LONG left
Definition: windef.h:291
static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile *iface, LPCOLESTR pszFileName)
Definition: avifile.c:601
DWORD dwFlags
Definition: vfw.h:961
char * LPSTR
Definition: xmlstorage.h:182
static HRESULT WINAPI IAVIStream_fnRead(IAVIStream *iface, LONG start, LONG samples, void *buffer, LONG buffersize, LONG *bytesread, LONG *samplesread)
Definition: avifile.c:993
static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream *iface, LONG start, LONG samples, void *buffer, LONG buffersize, DWORD flags, LONG *sampwritten, LONG *byteswritten)
Definition: avifile.c:1112
static LPOLESTR
Definition: stg_prop.c:27
LONG right
Definition: windef.h:293
#define lstrlenW
Definition: compat.h:407
static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream *iface, DWORD fcc, void *lp, LONG *lpread)
Definition: avifile.c:1240
#define E_FAIL
Definition: ddrawi.h:102
HMMIO WINAPI mmioOpenA(LPSTR szFileName, MMIOINFO *lpmmioinfo, DWORD dwOpenFlags)
Definition: mmio.c:692
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
#define DWORD
Definition: nt_native.h:44
Definition: send.c:47
LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin)
Definition: mmio.c:835
AVISTREAMINFOW sInfo
Definition: acmstream.c:46
static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream *iface, LONG pos, void *format, LONG *formatsize)
Definition: avifile.c:846
UCHAR rgbBlue
Definition: inbv.c:170
static const WCHAR avifile[]
Definition: avisplitter.c:273
DWORD dwMicroSecPerFrame
Definition: vfw.h:941
#define IAVIFile_AddRef(p)
Definition: vfw.h:1603
IUnknown IUnknown_inner
Definition: avifile.c:93
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
static IAVIFileImpl * impl_from_IAVIFile(IAVIFile *iface)
Definition: avifile.c:126
static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile *iface, IAVIStream **avis, AVISTREAMINFOW *asi)
Definition: avifile.c:323
static HRESULT AVIFILE_ReadBlock(IAVIStreamImpl *This, DWORD start, LPVOID buffer, DWORD size)
Definition: avifile.c:2010
GLsizei GLsizei GLuint * obj
Definition: glext.h:6042
static ULONG WINAPI IPersistFile_fnRelease(IPersistFile *iface)
Definition: avifile.c:511
static ULONG AVIFILE_SearchStream(const IAVIFileImpl *This, DWORD fccType, LONG lSkip)
Definition: avifile.c:2453
static HRESULT AVIFILE_ParseIndex(const IAVIFileImpl *This, AVIINDEXENTRY *lp, LONG count, DWORD pos, BOOL *bAbsolute)
Definition: avifile.c:1976
UCHAR rgbGreen
Definition: inbv.c:171
DWORD dwIdxChunkPos
Definition: avifile.c:105
UCHAR rgbRed
Definition: inbv.c:172
#define FIND_INDEX
Definition: vfw.h:1132
static HRESULT WINAPI IPersistFile_fnSave(IPersistFile *iface, LPCOLESTR pszFileName, BOOL fRemember)
Definition: avifile.c:591
#define FIND_NEXT
Definition: vfw.h:1118
#define AVIIF_NOTIME
Definition: vfw.h:982
FOURCC fccHandler
Definition: vfw.h:960
#define AVIERR_MEMORY
Definition: vfw.h:1745
static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream *iface, LPARAM lParam1, LPARAM lParam2)
Definition: avifile.c:722
#define comptypeDIB
Definition: vfw.h:147
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define DIBWIDTHBYTES(bi)
unsigned char * LPBYTE
Definition: typedefs.h:52
#define FIND_PREV
Definition: vfw.h:1119
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
#define TWOCCFromFOURCC(fcc)
Definition: avisplit.c:49
static const struct IAVIFileVtbl avif_vt
Definition: avifile.c:483
#define debugstr_w
Definition: kernel32.h:32
GLenum GLint ref
Definition: glext.h:6028
static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This)
Definition: avifile.c:1576
#define FIXME(fmt,...)
Definition: debug.h:110
WORD wBitsPerSample
Definition: audioclient.idl:45
DWORD biCompression
Definition: amvideo.idl:35
WORD WORD PSZ PSZ pszFileName
Definition: vdmdbg.h:41
#define IAVIStream_AddRef(p)
Definition: vfw.h:1176
unsigned int idx
Definition: utils.c:41
#define S_FALSE
Definition: winerror.h:2357
struct _WAVEFORMATEX * LPWAVEFORMATEX
LONG WINAPI mmioWrite(HMMIO hmmio, HPCSTR pch, LONG cch)
Definition: mmio.c:781
BOOL WINAPI IsRectEmpty(_In_ LPCRECT)
#define E_INVALIDARG
Definition: ddrawi.h:101
const WCHAR * str
static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream *iface, LONG start, LONG samples)
Definition: avifile.c:1202
static LONG WINAPI IAVIStream_fnFindSample(IAVIStream *iface, LONG pos, LONG flags)
Definition: avifile.c:748
static ULONG WINAPI IUnknown_fnAddRef(IUnknown *iface)
Definition: avifile.c:190
LPVOID lpFormat
Definition: avifile.c:68
DWORD dwInitialFrames
Definition: avifil32.idl:39
smooth NULL
Definition: ftsmooth.c:416
static void AVIFILE_ConstructAVIStream(IAVIFileImpl *paf, DWORD nr, const AVISTREAMINFOW *asi)
Definition: avifile.c:1491
LONG_PTR LPARAM
Definition: windef.h:208
#define MMIO_FINDCHUNK
Definition: mmsystem.h:551
BOOL fDirty
Definition: avifile.c:118
static const struct IPersistFileVtbl pf_vt
Definition: avifile.c:634
FOURCC fccType
Definition: vfw.h:959
FOURCC fccType
Definition: mmsystem.h:1509
#define debugstr_guid
Definition: kernel32.h:35
static const struct IAVIStreamVtbl avist_vt
Definition: avifile.c:1317
static IAVIFileImpl * impl_from_IUnknown(IUnknown *iface)
Definition: avifile.c:121
#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
DWORD dwNextFramePos
Definition: avifile.c:106
DWORD dwStreams
Definition: vfw.h:947
#define FIND_KEY
Definition: vfw.h:1123
DWORD nSamplesPerSec
Definition: audioclient.idl:42
LPVOID lp
Definition: extrachunk.h:33
#define AVIERR_BADPARAM
Definition: vfw.h:1748
#define AVIERR_UNSUPPORTED
Definition: vfw.h:1743
#define MMIO_READ
Definition: mmsystem.h:535
#define MAX_AVISTREAMS
BYTE bFirstEntry
Definition: vfw.h:993
#define FIND_LENGTH
Definition: vfw.h:1129
WORD wPriority
Definition: vfw.h:962
#define SEEK_SET
Definition: jmemansi.c:26
DWORD dwChunkLength
Definition: vfw.h:989
#define MMIO_DIRTY
Definition: mmsystem.h:534
IAVIFile IAVIFile_iface
Definition: avifile.c:94
#define TRACE(s)
Definition: solgame.cpp:4
GLsizeiptr size
Definition: glext.h:5919
static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile *iface)
Definition: avifile.c:504
#define GetProcessHeap()
Definition: compat.h:395
#define FOURCC_LIST
Definition: mmsystem.h:565
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define ckidAVINEWINDEX
Definition: vfw.h:901
if(!(yy_init))
Definition: macro.lex.yy.c:714
static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream *iface, AVISTREAMINFOW *info, LONG infolen)
Definition: avifile.c:1310
static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile *iface, REFIID riid, void **ppv)
Definition: avifile.c:255
#define ckidSTREAMHANDLERDATA
Definition: vfw.h:895
__wchar_t WCHAR
Definition: xmlstorage.h:180
BYTE bNumEntries
Definition: vfw.h:994
LONG HRESULT
Definition: typedefs.h:77
DWORD nIdxFrames
Definition: avifile.c:82
const GUID IID_IUnknown
#define AVIERR_BADSIZE
Definition: vfw.h:1749
static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile *iface, IAVIStream **avis, DWORD fccType, LONG lParam)
Definition: avifile.c:296
DWORD dwEditCount
Definition: avifil32.idl:44
DWORD dwSuggestedBufferSize
Definition: vfw.h:969
#define WINAPI
Definition: msvc.h:8
AVIINDEXENTRY * idxFmtChanges
Definition: avifile.c:83
DWORD dwCurrentFrame
Definition: avifile.c:78
static HRESULT AVIFILE_WriteBlock(IAVIStreamImpl *This, DWORD block, FOURCC ckid, DWORD flags, LPCVOID buffer, LONG size)
Definition: avifile.c:2547
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
DWORD biSizeImage
Definition: amvideo.idl:36
static HRESULT AVIFILE_AddRecord(IAVIFileImpl *This)
Definition: avifile.c:1423
#define listtypeAVIRECORD
Definition: vfw.h:899
DWORD cksize
Definition: mmsystem.h:1508
DWORD dwMaxBytesPerSec
Definition: vfw.h:942
#define AVIFILEINFO_COPYRIGHTED
Definition: vfw.h:1057
static HRESULT AVIFILE_SaveIndex(const IAVIFileImpl *This)
Definition: avifile.c:2323
WORD wFlags
Definition: vfw.h:995
GLbitfield flags
Definition: glext.h:7161
static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface)
Definition: avifile.c:406
#define AVIERR_FILEWRITE
Definition: vfw.h:1752
static ULONG WINAPI IUnknown_fnRelease(IUnknown *iface)
Definition: avifile.c:200
HRESULT ReadExtraChunk(const EXTRACHUNKS *extra, FOURCC ckid, LPVOID lpData, LPLONG size)
Definition: extrachunk.c:32
static void AVIFILE_SamplesToBlock(const IAVIStreamImpl *This, LPLONG pos, LPLONG offset)
Definition: avifile.c:2071
char * HPSTR
Definition: mmsystem.h:1477
DWORD dwQuality
Definition: vfw.h:970
#define IDS_VIDEO
IPersistFile IPersistFile_iface
Definition: avifile.c:95
#define InterlockedDecrement
Definition: armddk.h:52
MMRESULT WINAPI mmioCreateChunk(HMMIO hmmio, MMCKINFO *lpck, UINT uFlags)
Definition: mmio.c:1238
MMCKINFO ckLastRecord
Definition: avifile.c:109
#define mmioFOURCC(c0, c1, c2, c3)
Definition: mmsystem.h:38
static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile *iface, AVIFILEINFOW *afi, LONG size)
Definition: avifile.c:276
DWORD dwSampleSize
Definition: vfw.h:971
#define streamtypeAUDIO
Definition: aviriff.h:93
static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile *iface, LPOLESTR *ppszFileName)
Definition: avifile.c:610
#define FIND_TYPE
Definition: vfw.h:1122
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
#define MAKEAVICKID(tcc, stream)
Definition: vfw.h:923
unsigned char BYTE
Definition: mem.h:68
DWORD dwTotalFrames
Definition: vfw.h:945
IAVIStream IAVIStream_iface
Definition: acmstream.c:41
static void AVIFILE_UpdateInfo(IAVIFileImpl *This)
Definition: avifile.c:2481
BOOL WINAPI SetRectEmpty(_Out_ LPRECT)
DWORD cbHandlerData
Definition: avifile.c:72
DWORD nStream
Definition: avifile.c:65
DWORD cbIdxRecords
Definition: avifile.c:112
DWORD dwSuggestedBufferSize
Definition: vfw.h:948
#define AVIStreamSampleToSample(pavi1, pavi2, samp2)
Definition: vfw.h:1442
#define AVIFILEINFO_ISINTERLEAVED
Definition: vfw.h:1054
DWORD FOURCC
Definition: dmdls.h:25
IUnknown * outer_unk
Definition: avifile.c:96
AVIFILEINFOW fInfo
Definition: avifile.c:99
#define AVIERR_OK
Definition: vfw.h:1740
DWORD cbBuffer
Definition: avifile.c:77
#define MMIO_CREATERIFF
Definition: mmsystem.h:554
IAVIStreamImpl * ppStreams[MAX_AVISTREAMS]
Definition: avifile.c:100
EXTRACHUNKS extra
Definition: avifile.c:74
#define streamtypeVIDEO
Definition: aviriff.h:92
#define FIND_FROM_START
Definition: vfw.h:1120
#define ERR(fmt,...)
Definition: debug.h:109
static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size, DWORD offset, DWORD flags)
Definition: avifile.c:1335
BOOL WINAPI SetRect(_Out_ LPRECT, _In_ int, _In_ int, _In_ int, _In_ int)
#define S_OK
Definition: intsafe.h:59
int32_t * LPLONG
Definition: typedefs.h:56
WINE_UNICODE_INLINE WCHAR * strcpyW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:219
static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile *iface, DWORD ckid, void *lpData, LONG *size)
Definition: avifile.c:397
AVIINDEXENTRY * idxRecords
Definition: avifile.c:110
#define InterlockedIncrement
Definition: armddk.h:53
#define lstrcpyW
Definition: compat.h:406
LPVOID lpHandlerData
Definition: avifile.c:71
static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream *iface)
Definition: avifile.c:695
FOURCC ckid
Definition: mmsystem.h:1507
static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile *iface, LPCOLESTR pszFileName, DWORD dwMode)
Definition: avifile.c:539
static IAVIStreamImpl * impl_from_IAVIStream(IAVIStream *iface)
Definition: avifile.c:87
GLuint start
Definition: gl.h:1545
#define ARRAY_SIZE(a)
Definition: main.h:24
MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, const MMCKINFO *lpckParent, UINT uFlags)
Definition: mmio.c:1106
#define formtypeAVI
Definition: vfw.h:889
#define HeapReAlloc
Definition: compat.h:393
AVIINDEXENTRY * idxFrames
Definition: avifile.c:81
#define listtypeAVIMOVIE
Definition: vfw.h:898
DWORD dwWidth
Definition: vfw.h:949
EXTRACHUNKS fileextra
Definition: avifile.c:102
DWORD fccHandler
Definition: avifil32.idl:30
DWORD dwScale
Definition: vfw.h:965
#define min(a, b)
Definition: monoChain.cc:55
DWORD dwMoviChunkPos
Definition: avifile.c:104
WCHAR szName[64]
Definition: avifil32.idl:46
unsigned int UINT
Definition: ndis.h:50
BOOL WINAPI IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
Definition: compobj.c:4021
DWORD dwFlags
Definition: vfw.h:987
static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This)
Definition: avifile.c:2097
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
#define MultiByteToWideChar
Definition: compat.h:100
static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc, void *lp, LONG size)
Definition: avifile.c:1263
DWORD ckid
Definition: vfw.h:986
#define AVI_HEADERSIZE
Definition: vfw.h:935
#define MMIO_FINDRIFF
Definition: mmsystem.h:552
static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface)
Definition: avifile.c:269
Definition: mem.c:156
CONST void * LPCVOID
Definition: windef.h:191
#define AVIERR_FILEOPEN
Definition: vfw.h:1753
static HRESULT AVIFILE_LoadIndex(const IAVIFileImpl *This, DWORD size, DWORD offset)
Definition: avifile.c:1902
#define ckidAVIMAINHDR
Definition: vfw.h:891
const GUID IID_IPersistFile
static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream *iface, REFIID riid, void **ppv)
Definition: avifile.c:672
#define FIND_SIZE
Definition: vfw.h:1131
#define FIND_FORMAT
Definition: vfw.h:1125
#define OF_CREATE
Definition: winbase.h:125
uint32_t * LPDWORD
Definition: typedefs.h:57
#define IAVIFile_Release(p)
Definition: vfw.h:1604
#define ckidSTREAMNAME
Definition: vfw.h:896
#define IDS_AVIFILETYPE
#define AVISTREAMINFO_FORMATCHANGES
Definition: vfw.h:1049
unsigned int ULONG
Definition: retypes.h:1
#define SEEK_END
Definition: cabinet.c:27
#define AVIERR_FILEREAD
Definition: vfw.h:1751
LONG bottom
Definition: windef.h:294
LPCWSTR AVIFILE_BasenameW(LPCWSTR szFileName) DECLSPEC_HIDDEN
Definition: factory.c:162
static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile *iface, DWORD fccType, LONG lParam)
Definition: avifile.c:447
#define StreamFromFOURCC(fcc)
Definition: vfw.h:919
DWORD dwFormatChangeCount
Definition: avifil32.idl:45
static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream *iface, LONG pos, void *format, LONG formatsize)
Definition: avifile.c:885
DWORD dwPaddingGranularity
Definition: vfw.h:943
#define MMIO_FINDLIST
Definition: mmsystem.h:553
static void AVIFILE_DestructAVIStream(IAVIStreamImpl *This)
Definition: avifile.c:1539
#define AVIERR_READONLY
Definition: vfw.h:1756
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define AVIERR_BADFORMAT
Definition: vfw.h:1744
DWORD dwInitialFrames
Definition: avifile.c:107
UINT uMode
Definition: avifile.c:117
#define BI_RLE8
Definition: wingdi.h:35
#define memset(x, y, z)
Definition: compat.h:39
DWORD nIdxRecords
Definition: avifile.c:111
DWORD dwHeight
Definition: vfw.h:950
LONG ref
Definition: avifile.c:97
WORD wLanguage
Definition: vfw.h:963
#define BI_RGB
Definition: precomp.h:34
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: ifs.c:406
LPARAM lParam
Definition: combotst.c:139
static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown *iface, REFIID riid, void **ppv)
Definition: avifile.c:162
#define HeapFree(x, y, z)
Definition: compat.h:394
#define cktypePALchange
Definition: vfw.h:912
#define MulDiv(x, y, z)
Definition: gdifloat.h:86
#define AVIERR_ERROR
Definition: vfw.h:1761
static const WCHAR szType[]
Definition: table.c:81
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream *iface, AVISTREAMINFOW *psi, LONG size)
Definition: avifile.c:730
DWORD dwRate
Definition: vfw.h:966
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
#define SUCCEEDED(hr)
Definition: intsafe.h:57
static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile *iface)
Definition: avifile.c:530
LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch)
Definition: mmio.c:732
HRESULT FindChunkAndKeepExtras(LPEXTRACHUNKS extra, HMMIO hmmio, MMCKINFO *lpck, MMCKINFO *lpckParent, UINT flags)
Definition: extrachunk.c:143
#define cktypeWAVEbytes
Definition: vfw.h:913
static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile *iface, LPCLSID pClassID)
Definition: avifile.c:518
static const IUnknownVtbl unk_vtbl
Definition: avifile.c:248
#define IDS_AUDIO