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