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