Assorted spelling fixes.
[wine] / dlls / avifil32 / editstream.c
1 /*
2  * Copyright 2003 Michael Günnewig
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <assert.h>
20 #include <stdarg.h>
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winuser.h"
25 #include "wingdi.h"
26 #include "winnls.h"
27 #include "winerror.h"
28 #include "mmsystem.h"
29 #include "vfw.h"
30
31 #include "avifile_private.h"
32 #include "extrachunk.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
37
38 /***********************************************************************/
39
40 /* internal interface to get access to table of stream in an editable stream */
41
42 typedef struct _EditStreamTable {
43   PAVISTREAM pStream;  /* stream which contains the data */
44   DWORD      dwStart;  /* where starts the part which is also our */
45   DWORD      dwLength; /* how many is also in this stream */
46 } EditStreamTable;
47
48 #define INTERFACE IEditStreamInternal
49 DECLARE_INTERFACE_(IEditStreamInternal,IUnknown)
50 {
51     /*** IUnknown methods ***/
52     STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
53     STDMETHOD_(ULONG,AddRef)(THIS) PURE;
54     STDMETHOD_(ULONG,Release)(THIS) PURE;
55     /*** IEditStreamInternal methods ***/
56     STDMETHOD(GetEditStreamImpl)(THIS_ LPVOID*) PURE;
57 };
58 #undef INTERFACE
59
60 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
61                                       (This)->pStreams[streamNr].dwLength)
62
63 /***********************************************************************/
64
65 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj);
66 static ULONG   WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface);
67 static ULONG   WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface);
68 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
69                                            LONG*plLength,PAVISTREAM*ppResult);
70 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
71                                             LONG*plLength,PAVISTREAM*ppResult);
72 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
73                                              LONG*plLength,PAVISTREAM pSource,
74                                              LONG lStart,LONG lEnd);
75 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
76                                              PAVISTREAM*ppResult);
77 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
78                                                LPAVISTREAMINFOW asi,LONG size);
79
80 static const struct IAVIEditStreamVtbl ieditstream = {
81   IAVIEditStream_fnQueryInterface,
82   IAVIEditStream_fnAddRef,
83   IAVIEditStream_fnRelease,
84   IAVIEditStream_fnCut,
85   IAVIEditStream_fnCopy,
86   IAVIEditStream_fnPaste,
87   IAVIEditStream_fnClone,
88   IAVIEditStream_fnSetInfo
89 };
90
91 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID*obj);
92 static ULONG   WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface);
93 static ULONG   WINAPI IEditAVIStream_fnRelease(IAVIStream*iface);
94 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
95 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
96 static LONG    WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
97                                                   LONG flags);
98 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG*formatsize);
99 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
100 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
101                                             LONG samples,LPVOID buffer,
102                                             LONG buffersize,LONG*bytesread,
103                                             LONG*samplesread);
104 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
105                                              LONG samples,LPVOID buffer,
106                                              LONG buffersize,DWORD flags,
107                                              LONG*sampwritten,LONG*byteswritten);
108 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
109 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
110                                                 LPVOID lp,LONG *lpread);
111 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
112                                                  LPVOID lp,LONG size);
113 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
114
115 static const struct IAVIStreamVtbl ieditstast = {
116   IEditAVIStream_fnQueryInterface,
117   IEditAVIStream_fnAddRef,
118   IEditAVIStream_fnRelease,
119   IEditAVIStream_fnCreate,
120   IEditAVIStream_fnInfo,
121   IEditAVIStream_fnFindSample,
122   IEditAVIStream_fnReadFormat,
123   IEditAVIStream_fnSetFormat,
124   IEditAVIStream_fnRead,
125   IEditAVIStream_fnWrite,
126   IEditAVIStream_fnDelete,
127   IEditAVIStream_fnReadData,
128   IEditAVIStream_fnWriteData,
129   IEditAVIStream_fnSetInfo
130 };
131
132 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj);
133 static ULONG   WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface);
134 static ULONG   WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface);
135 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl);
136
137 static const struct IEditStreamInternalVtbl ieditstreaminternal = {
138   IEditStreamInternal_fnQueryInterface,
139   IEditStreamInternal_fnAddRef,
140   IEditStreamInternal_fnRelease,
141   IEditStreamInternal_fnGetEditStreamImpl
142 };
143
144 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
145
146 typedef struct _IEditAVIStreamImpl {
147   /* IUnknown stuff */
148   const IAVIStreamVtbl *lpVtbl;
149
150   /* IAVIStream stuff */
151   IAVIEditStreamImpl *pae;
152 } IEditAVIStreamImpl;
153
154 typedef struct _IEditStreamInternalImpl {
155   /* IUnknown stuff */
156   const IEditStreamInternalVtbl *lpVtbl;
157
158   /* IEditStreamInternal stuff */
159   IAVIEditStreamImpl *pae;
160 } IEditStreamInternalImpl;
161
162 struct _IAVIEditStreamImpl {
163   /* IUnknown stuff */
164   const IAVIEditStreamVtbl *lpVtbl;
165   LONG  ref;
166
167   /* IAVIEditStream stuff */
168   IEditAVIStreamImpl      iAVIStream;
169   IEditStreamInternalImpl iEditStreamInternal;
170
171   AVISTREAMINFOW       sInfo;
172
173   EditStreamTable     *pStreams;
174   DWORD                nStreams;   /* current fill level of pStreams table */
175   DWORD                nTableSize; /* size of pStreams table */
176
177   BOOL                 bDecompress;
178   PAVISTREAM           pCurStream;
179   PGETFRAME            pg;         /* IGetFrame for pCurStream */
180   LPBITMAPINFOHEADER   lpFrame;    /* frame of pCurStream */
181 };
182
183 /***********************************************************************/
184
185 PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream)
186 {
187   IAVIEditStreamImpl *pedit = NULL;
188
189   pedit = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIEditStreamImpl));
190   if (pedit == NULL)
191     return NULL;
192
193   pedit->lpVtbl            = &ieditstream;
194   pedit->iAVIStream.lpVtbl = &ieditstast;
195   pedit->iAVIStream.pae    = pedit;
196   pedit->iEditStreamInternal.lpVtbl = &ieditstreaminternal;
197   pedit->iEditStreamInternal.pae    = pedit;
198   pedit->ref = 1;
199
200   IAVIStream_Create((PAVISTREAM)&pedit->iAVIStream,(LPARAM)pstream,0);
201
202   return (PAVIEDITSTREAM)pedit;
203 }
204
205 static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
206                                          DWORD pos,PAVISTREAM *ppStream,
207                                          DWORD* streamPos,
208                                          DWORD* streamNr,BOOL bFindSample)
209 {
210   DWORD n;
211
212   TRACE("(%p,%u,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
213         streamNr,bFindSample);
214
215   if (pos < This->sInfo.dwStart)
216     return AVIERR_BADPARAM;
217
218   pos -= This->sInfo.dwStart;
219   for (n = 0; n < This->nStreams; n++) {
220     if (pos < This->pStreams[n].dwLength) {
221       *ppStream  = This->pStreams[n].pStream;
222       *streamPos = This->pStreams[n].dwStart + pos;
223       if (streamNr != NULL)
224         *streamNr = n;
225
226       return AVIERR_OK;
227     }
228     pos -= This->pStreams[n].dwLength;
229   }
230   if (pos == 0 && bFindSample) {
231     *ppStream  = This->pStreams[--n].pStream;
232     *streamPos = EditStreamEnd(This, n);
233     if (streamNr != NULL)
234       *streamNr = n;
235
236     TRACE(" -- pos=0 && b=1 -> (%p,%u,%u)\n",*ppStream, *streamPos, n);
237     return AVIERR_OK;
238   } else {
239     *ppStream = NULL;
240     *streamPos = 0;
241     if (streamNr != NULL)
242       *streamNr = 0;
243
244     TRACE(" -> ERROR (NULL,0,0)\n");
245     return AVIERR_BADPARAM;
246   }
247 }
248
249 static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
250                                 PAVISTREAM pstream, LONG pos)
251 {
252   PGETFRAME pg;
253
254   TRACE("(%p,%p,%d)\n",This,pstream,pos);
255
256   if (pstream == NULL)
257     return NULL;
258
259   /* if stream changes make sure that only palette changes */
260   if (This->pCurStream != pstream) {
261     pg = AVIStreamGetFrameOpen(pstream, NULL);
262     if (pg == NULL)
263       return NULL;
264     if (This->pg != NULL) {
265       if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1)) {
266         AVIStreamGetFrameClose(pg);
267         ERR(": IGetFrame_SetFormat failed\n");
268         return NULL;
269       }
270       AVIStreamGetFrameClose(This->pg);
271     }
272     This->pg         = pg;
273     This->pCurStream = pstream;
274   }
275
276   /* now get the decompressed frame */
277   This->lpFrame = AVIStreamGetFrame(This->pg, pos);
278   if (This->lpFrame != NULL)
279     This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage;
280
281   return This->lpFrame;
282 }
283
284 static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
285 {
286   assert(This != NULL);
287   assert(nr < This->nStreams);
288
289   /* remove part nr */
290   IAVIStream_Release(This->pStreams[nr].pStream);
291   This->nStreams--;
292   if (This->nStreams - nr > 0) {
293     memmove(This->pStreams + nr, This->pStreams + nr + 1,
294             (This->nStreams - nr) * sizeof(EditStreamTable));
295   }
296   This->pStreams[This->nStreams].pStream  = NULL;
297   This->pStreams[This->nStreams].dwStart  = 0;
298   This->pStreams[This->nStreams].dwLength = 0;
299
300   /* try to merge the part before the deleted one and the one after it */
301   if (0 < nr && 0 < This->nStreams &&
302       This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) {
303     if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) {
304       This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength;
305       return AVIFILE_RemoveStream(This, nr);
306     }
307   }
308
309   return AVIERR_OK;
310 }
311
312 static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
313 {
314   LPVOID fmt1 = NULL, fmt2 = NULL;
315   LONG size1, size2, start1, start2;
316   BOOL status = FALSE;
317
318   assert(avi1 != NULL && avi2 != NULL);
319
320   /* get stream starts and check format sizes */
321   start1 = AVIStreamStart(avi1);
322   start2 = AVIStreamStart(avi2);
323   if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
324     return FALSE;
325   if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
326     return FALSE;
327   if (size1 != size2)
328     return FALSE;
329
330   /* sizes match, now get formats and compare them */
331   fmt1 = HeapAlloc(GetProcessHeap(), 0, size1);
332   if (fmt1 == NULL)
333     return FALSE;
334   if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
335     fmt2 = HeapAlloc(GetProcessHeap(), 0, size1);
336     if (fmt2 != NULL) {
337       if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
338         status = (memcmp(fmt1, fmt2, size1) == 0);
339     }
340   }
341
342   HeapFree(GetProcessHeap(), 0, fmt2);
343   HeapFree(GetProcessHeap(), 0, fmt1);
344
345   return status;
346 }
347
348 /***********************************************************************/
349
350 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
351 {
352   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
353
354   TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
355
356   if (IsEqualGUID(&IID_IUnknown, refiid) ||
357       IsEqualGUID(&IID_IAVIEditStream, refiid)) {
358     *obj = iface;
359     IAVIEditStream_AddRef(iface);
360
361     return S_OK;
362   } else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
363     *obj = &This->iAVIStream;
364     IAVIEditStream_AddRef(iface);
365
366     return S_OK;
367   } else if (IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
368     *obj = &This->iEditStreamInternal;
369     IAVIEditStream_AddRef(iface);
370
371     return S_OK;
372   }
373
374   return OLE_E_ENUM_NOMORE;
375 }
376
377 static ULONG   WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
378 {
379   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
380   ULONG ref = InterlockedIncrement(&This->ref);
381
382   TRACE("(%p) -> %d\n", iface, ref);
383
384   return ref;
385 }
386
387 static ULONG   WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
388 {
389   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
390   DWORD i;
391   ULONG ref = InterlockedDecrement(&This->ref);
392
393   TRACE("(%p) -> %d\n", iface, ref);
394
395   if (!ref) {
396     /* release memory */
397     if (This->pg != NULL)
398       AVIStreamGetFrameClose(This->pg);
399     if (This->pStreams != NULL) {
400       for (i = 0; i < This->nStreams; i++) {
401         if (This->pStreams[i].pStream != NULL)
402           IAVIStream_Release(This->pStreams[i].pStream);
403       }
404       HeapFree(GetProcessHeap(), 0, This->pStreams);
405     }
406
407     HeapFree(GetProcessHeap(), 0, This);
408     return 0;
409   }
410   return ref;
411 }
412
413 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
414                                            LONG*plLength,PAVISTREAM*ppResult)
415 {
416   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
417   PAVISTREAM stream;
418   DWORD      start, len, streamPos, streamNr;
419   HRESULT    hr;
420
421   TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
422
423   if (ppResult != NULL)
424     *ppResult = NULL;
425   if (plStart == NULL || plLength == NULL || *plStart < 0)
426     return AVIERR_BADPARAM;
427
428   /* if asked for cutted part copy it before deleting */
429   if (ppResult != NULL) {
430     hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
431     if (FAILED(hr))
432       return hr;
433   }
434
435   start = *plStart;
436   len   = *plLength;
437
438   /* now delete the requested part */
439   while (len > 0) {
440     hr = AVIFILE_FindStreamInTable(This, start, &stream,
441                                    &streamPos, &streamNr, FALSE);
442     if (FAILED(hr))
443       return hr;
444     if (This->pStreams[streamNr].dwStart == streamPos) {
445       /* deleting from start of part */
446       if (len < This->pStreams[streamNr].dwLength) {
447         start += len;
448         This->pStreams[streamNr].dwStart  += len;
449         This->pStreams[streamNr].dwLength -= len;
450         This->sInfo.dwLength -= len;
451         len = 0;
452
453         /* we must return decompressed data now */
454         This->bDecompress = TRUE;
455       } else {
456         /* deleting hole part */
457         len -= This->pStreams[streamNr].dwLength;
458         AVIFILE_RemoveStream(This,streamNr);
459       }
460     } else if (EditStreamEnd(This, streamNr) <= streamPos + len) {
461       /* deleting at end of a part */
462       DWORD count = EditStreamEnd(This, streamNr) - streamPos;
463       This->sInfo.dwLength -= count;
464       len                  -= count;
465       This->pStreams[streamNr].dwLength =
466         streamPos - This->pStreams[streamNr].dwStart;
467     } else {
468       /* splitting */
469       if (This->nStreams + 1 >= This->nTableSize) {
470         This->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pStreams,
471                                      (This->nTableSize + 32) * sizeof(EditStreamTable));
472         if (This->pStreams == NULL)
473           return AVIERR_MEMORY;
474         This->nTableSize += 32;
475       }
476       memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
477               (This->nStreams - streamNr) * sizeof(EditStreamTable));
478       This->nStreams++;
479
480       IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream);
481       This->pStreams[streamNr + 1].dwStart  = streamPos + len;
482       This->pStreams[streamNr + 1].dwLength =
483         EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart;
484
485       This->pStreams[streamNr].dwLength =
486         streamPos - This->pStreams[streamNr].dwStart;
487       This->sInfo.dwLength -= len;
488       len = 0;
489     }
490   }
491
492   This->sInfo.dwEditCount++;
493
494   return AVIERR_OK;
495 }
496
497 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
498                                             LONG*plLength,PAVISTREAM*ppResult)
499 {
500   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
501   IAVIEditStreamImpl* pEdit;
502   HRESULT hr;
503   LONG start = 0;
504
505   TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
506
507   if (ppResult == NULL)
508     return AVIERR_BADPARAM;
509   *ppResult = NULL;
510   if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
511     return AVIERR_BADPARAM;
512
513   /* check bounds */
514   if (*(LPDWORD)plLength > This->sInfo.dwLength)
515     *(LPDWORD)plLength = This->sInfo.dwLength;
516   if (*(LPDWORD)plStart < This->sInfo.dwStart) {
517     *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart;
518     *(LPDWORD)plStart   = This->sInfo.dwStart;
519     if (*plLength < 0)
520       return AVIERR_BADPARAM;
521   }
522   if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
523     *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
524       *(LPDWORD)plStart;
525
526   pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
527   if (pEdit == NULL)
528     return AVIERR_MEMORY;
529
530   hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength,
531                             (PAVISTREAM)&This->iAVIStream,*plStart,
532                             *plStart + *plLength);
533   *plStart = start;
534   if (FAILED(hr))
535     IAVIEditStream_Release((PAVIEDITSTREAM)pEdit);
536   else
537     *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
538
539   return hr;
540 }
541
542 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
543                                              LONG*plLength,PAVISTREAM pSource,
544                                              LONG lStart,LONG lLength)
545 {
546   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
547   AVISTREAMINFOW      srcInfo;
548   IEditStreamInternal*pInternal = NULL;
549   IAVIEditStreamImpl *pEdit = NULL;
550   PAVISTREAM          pStream;
551   DWORD               startPos, endPos, streamNr, nStreams;
552   ULONG               n;
553
554   TRACE("(%p,%p,%p,%p,%d,%d)\n",iface,plStart,plLength,
555         pSource,lStart,lLength);
556
557   if (pSource == NULL)
558     return AVIERR_BADHANDLE;
559   if (plStart == NULL || *plStart < 0)
560     return AVIERR_BADPARAM;
561   if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart)
562     return AVIERR_BADPARAM; /* Can't paste with holes */
563   if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo))))
564     return AVIERR_ERROR;
565   if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength)
566     return AVIERR_BADPARAM;
567   if (This->sInfo.fccType == 0) {
568     /* This stream is empty */
569     IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo));
570     This->sInfo.dwStart  = *plStart;
571     This->sInfo.dwLength = 0;
572   }
573   if (This->sInfo.fccType != srcInfo.fccType)
574     return AVIERR_UNSUPPORTED; /* different stream types */
575   if (lLength == -1) /* Copy the hole stream */
576     lLength = srcInfo.dwLength;
577   if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength)
578     lLength = srcInfo.dwStart + srcInfo.dwLength - lStart;
579   if (lLength + *plStart >= 0x80000000)
580     return AVIERR_MEMORY;
581
582   /* streamtype specific tests */
583   if (srcInfo.fccType == streamtypeVIDEO) {
584     LONG size;
585
586     size = srcInfo.rcFrame.right - srcInfo.rcFrame.left;
587     if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left)
588       return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
589     size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top;
590     if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top)
591       return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
592   } else if (srcInfo.fccType == streamtypeAUDIO) {
593     if (! AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))
594       return AVIERR_UNSUPPORTED;
595   } else {
596     /* FIXME: streamtypeMIDI and streamtypeTEXT */
597     return AVIERR_UNSUPPORTED;
598   }
599
600   /* try to get an IEditStreamInternal interface */
601   if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal,
602                                           (LPVOID*)&pInternal))) {
603     pInternal->lpVtbl->GetEditStreamImpl(pInternal, (LPVOID*)&pEdit);
604     pInternal->lpVtbl->Release(pInternal);
605   }
606
607   /* for video must check for change of format */
608   if (This->sInfo.fccType == streamtypeVIDEO) {
609     if (! This->bDecompress) {
610       /* Need to decompress if any of the following conditions matches:
611        *  - pSource is an editable stream which decompresses
612        *  - the nearest keyframe of pSource isn't lStart
613        *  - the nearest keyframe of this stream isn't *plStart
614        *  - the format of pSource doesn't match this one
615        */
616       if ((pEdit != NULL && pEdit->bDecompress) ||
617           AVIStreamNearestKeyFrame(pSource, lStart) != lStart ||
618           AVIStreamNearestKeyFrame((PAVISTREAM)&This->iAVIStream, *plStart) != *plStart ||
619           (This->nStreams > 0 && !AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))) {
620         /* Use first stream part to get format to convert everything to */
621         AVIFILE_ReadFrame(This, This->pStreams[0].pStream,
622                           This->pStreams[0].dwStart);
623
624         /* Check if we could convert the source streams to the disired format... */
625         if (pEdit != NULL) {
626           if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
627                                                &startPos, &streamNr, TRUE)))
628             return AVIERR_INTERNAL;
629           for (n = lStart; n < lStart + lLength; streamNr++) {
630             if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL)
631               return AVIERR_BADFORMAT;
632             startPos = pEdit->pStreams[streamNr].dwStart;
633             n += pEdit->pStreams[streamNr].dwLength;
634           }
635         } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
636           return AVIERR_BADFORMAT;
637
638         This->bDecompress      = TRUE;
639         This->sInfo.fccHandler = 0;
640       }
641     } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
642       return AVIERR_BADFORMAT; /* Can't convert source to own format */
643   } /* FIXME: something special for the other formats? */
644
645   /* Make sure we have enough memory for parts */
646   if (pEdit != NULL) {
647     DWORD nLastStream;
648
649     AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
650                               &endPos, &nLastStream, TRUE);
651     AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
652                               &startPos, &streamNr, FALSE);
653     if (nLastStream == streamNr)
654       nLastStream++;
655
656     nStreams = nLastStream - streamNr;
657   } else 
658     nStreams = 1;
659   if (This->nStreams + nStreams + 1 > This->nTableSize) {
660     n = This->nStreams + nStreams + 33;
661
662     This->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pStreams, n * sizeof(EditStreamTable));
663     if (This->pStreams == NULL)
664       return AVIERR_MEMORY;
665     This->nTableSize = n;
666   }
667
668   if (plLength != NULL)
669     *plLength = lLength;
670
671   /* now do the real work */
672   if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) {
673     AVIFILE_FindStreamInTable(This, *plStart, &pStream,
674                               &startPos, &streamNr, FALSE);
675     if (startPos != This->pStreams[streamNr].dwStart) {
676       /* split stream streamNr at startPos */
677       memmove(This->pStreams + streamNr + nStreams + 1,
678               This->pStreams + streamNr,
679               (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable));
680
681       This->pStreams[streamNr + 2].dwLength =
682         EditStreamEnd(This, streamNr + 2) - startPos;
683       This->pStreams[streamNr + 2].dwStart = startPos;
684       This->pStreams[streamNr].dwLength =
685         startPos - This->pStreams[streamNr].dwStart;
686       IAVIStream_AddRef(This->pStreams[streamNr].pStream);
687       streamNr++;
688     } else {
689       /* insert before stream at streamNr */
690       memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
691               (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
692     }
693   } else /* append the streams */
694     streamNr = This->nStreams;
695
696   if (pEdit != NULL) {
697     /* insert the parts of the editable stream instead of itself */
698     AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
699                               &endPos, NULL, FALSE);
700     AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE);
701
702     memcpy(This->pStreams + streamNr, pEdit->pStreams + n,
703            nStreams * sizeof(EditStreamTable));
704     if (This->pStreams[streamNr].dwStart < startPos) {
705       This->pStreams[streamNr].dwLength =
706         EditStreamEnd(This, streamNr) - startPos;
707       This->pStreams[streamNr].dwStart  = startPos;
708     }
709     if (endPos < EditStreamEnd(This, streamNr + nStreams))
710       This->pStreams[streamNr + nStreams].dwLength =
711         endPos - This->pStreams[streamNr + nStreams].dwStart;
712   } else {
713     /* a simple stream */
714     This->pStreams[streamNr].pStream  = pSource;
715     This->pStreams[streamNr].dwStart  = lStart;
716     This->pStreams[streamNr].dwLength = lLength;
717   }
718
719   for (n = 0; n < nStreams; n++) {
720     IAVIStream_AddRef(This->pStreams[streamNr + n].pStream);
721     if (0 < streamNr + n &&
722         This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) {
723       This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
724       This->sInfo.dwFormatChangeCount++;
725     }
726   }
727   This->sInfo.dwEditCount++;
728   This->sInfo.dwLength += lLength;
729   This->nStreams += nStreams;
730
731   return AVIERR_OK;
732 }
733
734 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
735                                              PAVISTREAM*ppResult)
736 {
737   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
738   IAVIEditStreamImpl* pEdit;
739   DWORD i;
740
741   TRACE("(%p,%p)\n",iface,ppResult);
742
743   if (ppResult == NULL)
744     return AVIERR_BADPARAM;
745   *ppResult = NULL;
746
747   pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
748   if (pEdit == NULL)
749     return AVIERR_MEMORY;
750   if (This->nStreams > pEdit->nTableSize) {
751     pEdit->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pEdit->pStreams,
752                                   This->nStreams * sizeof(EditStreamTable));
753     if (pEdit->pStreams == NULL)
754       return AVIERR_MEMORY;
755     pEdit->nTableSize = This->nStreams;
756   }
757   pEdit->nStreams = This->nStreams;
758   memcpy(pEdit->pStreams, This->pStreams,
759          This->nStreams * sizeof(EditStreamTable));
760   memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo));
761   for (i = 0; i < This->nStreams; i++) {
762     if (pEdit->pStreams[i].pStream != NULL)
763       IAVIStream_AddRef(pEdit->pStreams[i].pStream);
764   }
765
766   *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
767
768   return AVIERR_OK;
769 }
770
771 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
772                                                LPAVISTREAMINFOW asi,LONG size)
773 {
774   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
775
776   TRACE("(%p,%p,%d)\n",iface,asi,size);
777
778   /* check parameters */
779   if (asi == NULL)
780     return AVIERR_BADPARAM;
781   if (size != sizeof(AVISTREAMINFOW))
782     return AVIERR_BADSIZE;
783   if (asi->dwScale == 0 || asi->dwRate == 0 || (LONG)asi->dwQuality < -1 ||
784       asi->dwQuality > ICQUALITY_HIGH)
785     return AVIERR_ERROR;
786
787   This->sInfo.wLanguage = asi->wLanguage;
788   This->sInfo.wPriority = asi->wPriority;
789   This->sInfo.dwStart   = asi->dwStart;
790   if (asi->dwRate != 0)
791     This->sInfo.dwRate  = asi->dwRate;
792   if (asi->dwScale != 0)
793     This->sInfo.dwScale = asi->dwScale;
794   if (asi->dwQuality <= ICQUALITY_HIGH)
795     This->sInfo.dwQuality = ICQUALITY_HIGH;
796   CopyRect(&This->sInfo.rcFrame, &asi->rcFrame);
797   memcpy(&This->sInfo.szName, &asi->szName, sizeof(asi->szName));
798   This->sInfo.dwEditCount++;
799
800   return AVIERR_OK;
801 }
802
803 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
804                                                       REFIID refiid,LPVOID*obj)
805 {
806   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
807
808   assert(This->pae != NULL);
809
810   return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae,refiid,obj);
811 }
812
813 static ULONG   WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface)
814 {
815   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
816
817   assert(This->pae != NULL);
818
819   return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
820 }
821
822 static ULONG   WINAPI IEditAVIStream_fnRelease(IAVIStream*iface)
823 {
824   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
825
826   assert(This->pae != NULL);
827
828   return IAVIEditStream_Release((IAVIEditStream*)This->pae);
829 }
830
831 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,
832                                               LPARAM lParam1,LPARAM lParam2)
833 {
834   IAVIEditStreamImpl *This = ((IEditAVIStreamImpl*)iface)->pae;
835
836   if (lParam2 != 0)
837     return AVIERR_ERROR;
838
839   if (This->pStreams == NULL) {
840     This->pStreams = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256 * sizeof(EditStreamTable));
841     if (This->pStreams == NULL)
842       return AVIERR_MEMORY;
843     This->nTableSize = 256;
844   }
845
846   if (lParam1 != 0) {
847     IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
848     IAVIStream_AddRef((PAVISTREAM)lParam1);
849     This->pStreams[0].pStream  = (PAVISTREAM)lParam1;
850     This->pStreams[0].dwStart  = This->sInfo.dwStart;
851     This->pStreams[0].dwLength = This->sInfo.dwLength;
852     This->nStreams = 1;
853   }
854   return AVIERR_OK;
855 }
856
857 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,
858                                             AVISTREAMINFOW *psi,LONG size)
859 {
860   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
861
862   TRACE("(%p,%p,%d)\n",iface,psi,size);
863
864   assert(This->pae != NULL);
865
866   if (psi == NULL)
867     return AVIERR_BADPARAM;
868   if (size < 0)
869     return AVIERR_BADSIZE;
870
871   if (This->pae->bDecompress)
872     This->pae->sInfo.fccHandler = 0;
873
874   memcpy(psi, &This->pae->sInfo, min((DWORD)size, sizeof(This->pae->sInfo)));
875
876   if ((DWORD)size < sizeof(This->pae->sInfo))
877     return AVIERR_BUFFERTOOSMALL;
878   return AVIERR_OK;
879 }
880
881 static LONG    WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
882                                                   LONG flags)
883 {
884   IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
885   PAVISTREAM stream;
886   DWORD      streamPos, streamNr;
887
888   TRACE("(%p,%d,0x%08X)\n",iface,pos,flags);
889
890   if (flags & FIND_FROM_START)
891     pos = (LONG)This->sInfo.dwStart;
892
893   /* outside of stream? */
894   if (pos < (LONG)This->sInfo.dwStart ||
895       (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos)
896     return -1;
897
898   /* map our position to a stream and position in it */
899   if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos,
900                                 &streamNr, TRUE))
901     return -1; /* doesn't exist */
902
903   if (This->bDecompress) {
904     /* only one stream -- format changes only at start */
905     if (flags & FIND_FORMAT)
906       return (flags & FIND_NEXT ? -1 : 0);
907
908     /* FIXME: map positions back to us */
909     return IAVIStream_FindSample(stream, streamPos, flags);
910   } else {
911     /* assume change of format every frame */
912     return pos;
913   }
914 }
915
916 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,
917                                                   LPVOID format,LONG*fmtsize)
918 {
919   IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
920   LPBITMAPINFOHEADER  lp;
921   PAVISTREAM          stream;
922   DWORD               n;
923   HRESULT             hr;
924
925   TRACE("(%p,%d,%p,%p)\n",iface,pos,format,fmtsize);
926
927   if (fmtsize == NULL || pos < This->sInfo.dwStart ||
928       This->sInfo.dwStart + This->sInfo.dwLength <= pos)
929     return AVIERR_BADPARAM;
930
931   /* find stream corresponding to position */
932   hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE);
933   if (FAILED(hr))
934     return hr;
935
936   if (! This->bDecompress)
937     return IAVIStream_ReadFormat(stream, n, format, fmtsize);
938
939   lp = (LPBITMAPINFOHEADER)AVIFILE_ReadFrame(This, stream, n);
940   if (lp == NULL)
941     return AVIERR_ERROR;
942   if (lp->biBitCount <= 8) {
943     n  = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount);
944     n *= sizeof(RGBQUAD);
945   } else
946     n = 0;
947   n += lp->biSize;
948   
949   memcpy(format, lp, min((LONG)n, *fmtsize));
950   hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK);
951   *fmtsize = n;
952
953   return hr;
954 }
955
956 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,
957                                                  LPVOID format,LONG formatsize)
958 {
959   TRACE("(%p,%d,%p,%d)\n",iface,pos,format,formatsize);
960
961   return AVIERR_UNSUPPORTED;
962 }
963
964 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
965                                             LONG samples,LPVOID buffer,
966                                             LONG buffersize,LONG*bytesread,
967                                             LONG*samplesread)
968 {
969   IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
970   PAVISTREAM stream;
971   DWORD   streamPos, streamNr;
972   LONG    readBytes, readSamples, count;
973   HRESULT hr;
974
975   TRACE("(%p,%d,%d,%p,%d,%p,%p) -- 0x%08X\n",iface,start,samples,
976         buffer,buffersize,bytesread,samplesread,This->sInfo.fccType);
977
978   /* check parameters */
979   if (bytesread != NULL)
980     *bytesread = 0;
981   if (samplesread != NULL)
982     *samplesread = 0;
983   if (buffersize < 0)
984     return AVIERR_BADSIZE;
985   if ((DWORD)start < This->sInfo.dwStart ||
986       This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
987     return AVIERR_BADPARAM;
988
989   if (! This->bDecompress) {
990     /* audio like data -- sample-based */
991     do {
992       if (samples == 0)
993         return AVIERR_OK; /* nothing at all or already done */
994
995       if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
996                                            &streamPos, &streamNr, FALSE)))
997         return AVIERR_ERROR;
998
999       /* limit to end of the stream */
1000       count = samples;
1001       if (streamPos + count > EditStreamEnd(This, streamNr))
1002         count = EditStreamEnd(This, streamNr) - streamPos;
1003
1004       hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize,
1005                            &readBytes, &readSamples);
1006       if (FAILED(hr))
1007         return hr;
1008       if (readBytes == 0 && readSamples == 0 && count != 0)
1009         return AVIERR_FILEREAD; /* for bad stream implementations */
1010
1011       if (samplesread != NULL)
1012         *samplesread += readSamples;
1013       if (bytesread != NULL)
1014         *bytesread += readBytes;
1015       if (buffer != NULL) {
1016         buffer = ((LPBYTE)buffer)+readBytes;
1017         buffersize     -= readBytes;
1018       }
1019       start   += count;
1020       samples -= count;
1021     } while (This->sInfo.dwStart + This->sInfo.dwLength > start);
1022   } else {
1023     /* video like data -- frame-based */
1024     LPBITMAPINFOHEADER lp;
1025
1026     if (samples == 0)
1027       return AVIERR_OK;
1028
1029     if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
1030                                          &streamPos, &streamNr, FALSE)))
1031       return AVIERR_ERROR;
1032
1033     lp = AVIFILE_ReadFrame(This, stream, streamPos);
1034     if (lp == NULL)
1035       return AVIERR_ERROR;
1036
1037     if (buffer != NULL) {
1038       /* need size of format to skip */
1039       if (lp->biBitCount <= 8) {
1040         count  = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount;
1041         count *= sizeof(RGBQUAD);
1042       } else
1043         count = 0;
1044       count += lp->biSize;
1045
1046       if (buffersize < lp->biSizeImage)
1047         return AVIERR_BUFFERTOOSMALL;
1048       memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage);
1049     }
1050
1051     if (bytesread != NULL)
1052       *bytesread = lp->biSizeImage;
1053     if (samplesread != NULL)
1054       *samplesread = 1;
1055   }
1056
1057   return AVIERR_OK;
1058 }
1059
1060 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
1061                                              LONG samples,LPVOID buffer,
1062                                              LONG buffersize,DWORD flags,
1063                                              LONG*sampwritten,LONG*byteswritten)
1064 {
1065   TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n",iface,start,samples,buffer,
1066         buffersize,flags,sampwritten,byteswritten);
1067
1068   /* be sure return parameters have correct values */
1069   if (sampwritten != NULL)
1070     *sampwritten = 0;
1071   if (byteswritten != NULL)
1072     *byteswritten = 0;
1073
1074   return AVIERR_UNSUPPORTED;
1075 }
1076
1077 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,
1078                                               LONG samples)
1079 {
1080   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1081
1082   TRACE("(%p,%d,%d)\n",iface,start,samples);
1083
1084   return IAVIEditStream_Cut((IAVIEditStream*)This->pae,&start,&samples,NULL);
1085 }
1086
1087 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
1088                                                 LPVOID lp,LONG *lpread)
1089 {
1090   IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
1091   DWORD n;
1092
1093   TRACE("(%p,0x%08X,%p,%p)\n",iface,fcc,lp,lpread);
1094
1095   /* check parameters */
1096   if (lp == NULL || lpread == NULL)
1097     return AVIERR_BADPARAM;
1098
1099   /* simply ask every stream and return the first block found */
1100   for (n = 0; n < This->nStreams; n++) {
1101     HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread);
1102
1103     if (SUCCEEDED(hr))
1104       return hr;
1105   }
1106
1107   *lpread = 0;
1108   return AVIERR_NODATA;
1109 }
1110
1111 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
1112                                                  LPVOID lp,LONG size)
1113 {
1114   TRACE("(%p,0x%08X,%p,%d)\n",iface,fcc,lp,size);
1115
1116   return AVIERR_UNSUPPORTED;
1117 }
1118
1119 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,
1120                                                AVISTREAMINFOW*info,LONG len)
1121 {
1122   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1123
1124   TRACE("(%p,%p,%d)\n",iface,info,len);
1125
1126   return IAVIEditStream_SetInfo((IAVIEditStream*)This->pae,info,len);
1127 }
1128
1129 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj)
1130 {
1131   IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1132
1133   assert(This->pae != NULL);
1134
1135   return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae, refiid, obj);
1136 }
1137
1138 static ULONG   WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface)
1139 {
1140   IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1141
1142   assert(This->pae != NULL);
1143
1144   return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
1145 }
1146
1147 static ULONG   WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface)
1148 {
1149   IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1150
1151   assert(This->pae != NULL);
1152
1153   return IAVIEditStream_Release((IAVIEditStream*)This->pae);
1154 }
1155
1156 static HRESULT  WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl)
1157 {
1158   IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1159
1160   TRACE("(%p,%p) -> %p\n", iface, ppimpl, This->pae);
1161
1162   assert(This->pae != NULL);
1163   assert(ppimpl != NULL);
1164
1165   *ppimpl = This->pae;
1166   return AVIERR_OK;
1167 }