~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/avifil32/editstream.c

Version: ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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 "winerror.h"
 27 #include "mmsystem.h"
 28 #include "vfw.h"
 29 
 30 #include "avifile_private.h"
 31 #include "extrachunk.h"
 32 
 33 #include "wine/debug.h"
 34 
 35 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
 36 
 37 /***********************************************************************/
 38 
 39 /* internal interface to get access to table of stream in an editable stream */
 40 
 41 typedef struct _EditStreamTable {
 42   PAVISTREAM pStream;  /* stream which contains the data */
 43   DWORD      dwStart;  /* where starts the part which is also our */
 44   DWORD      dwLength; /* how many is also in this stream */
 45 } EditStreamTable;
 46 
 47 #define INTERFACE IEditStreamInternal
 48 DECLARE_INTERFACE_(IEditStreamInternal,IUnknown)
 49 {
 50     /*** IUnknown methods ***/
 51     STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
 52     STDMETHOD_(ULONG,AddRef)(THIS) PURE;
 53     STDMETHOD_(ULONG,Release)(THIS) PURE;
 54     /*** IEditStreamInternal methods ***/
 55     STDMETHOD(GetEditStreamImpl)(THIS_ LPVOID*) PURE;
 56 };
 57 #undef INTERFACE
 58 
 59 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
 60                                       (This)->pStreams[streamNr].dwLength)
 61 
 62 /***********************************************************************/
 63 
 64 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj);
 65 static ULONG   WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface);
 66 static ULONG   WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface);
 67 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
 68                                            LONG*plLength,PAVISTREAM*ppResult);
 69 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
 70                                             LONG*plLength,PAVISTREAM*ppResult);
 71 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
 72                                              LONG*plLength,PAVISTREAM pSource,
 73                                              LONG lStart,LONG lEnd);
 74 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
 75                                              PAVISTREAM*ppResult);
 76 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
 77                                                LPAVISTREAMINFOW asi,LONG size);
 78 
 79 static const struct IAVIEditStreamVtbl ieditstream = {
 80   IAVIEditStream_fnQueryInterface,
 81   IAVIEditStream_fnAddRef,
 82   IAVIEditStream_fnRelease,
 83   IAVIEditStream_fnCut,
 84   IAVIEditStream_fnCopy,
 85   IAVIEditStream_fnPaste,
 86   IAVIEditStream_fnClone,
 87   IAVIEditStream_fnSetInfo
 88 };
 89 
 90 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID*obj);
 91 static ULONG   WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface);
 92 static ULONG   WINAPI IEditAVIStream_fnRelease(IAVIStream*iface);
 93 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
 94 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
 95 static LONG    WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
 96                                                   LONG flags);
 97 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG*formatsize);
 98 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
 99 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
100                                             LONG samples,LPVOID buffer,
101                                             LONG buffersize,LONG*bytesread,
102                                             LONG*samplesread);
103 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
104                                              LONG samples,LPVOID buffer,
105                                              LONG buffersize,DWORD flags,
106                                              LONG*sampwritten,LONG*byteswritten);
107 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
108 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
109                                                 LPVOID lp,LONG *lpread);
110 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
111                                                  LPVOID lp,LONG size);
112 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
113 
114 static const struct IAVIStreamVtbl ieditstast = {
115   IEditAVIStream_fnQueryInterface,
116   IEditAVIStream_fnAddRef,
117   IEditAVIStream_fnRelease,
118   IEditAVIStream_fnCreate,
119   IEditAVIStream_fnInfo,
120   IEditAVIStream_fnFindSample,
121   IEditAVIStream_fnReadFormat,
122   IEditAVIStream_fnSetFormat,
123   IEditAVIStream_fnRead,
124   IEditAVIStream_fnWrite,
125   IEditAVIStream_fnDelete,
126   IEditAVIStream_fnReadData,
127   IEditAVIStream_fnWriteData,
128   IEditAVIStream_fnSetInfo
129 };
130 
131 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj);
132 static ULONG   WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface);
133 static ULONG   WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface);
134 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl);
135 
136 static const struct IEditStreamInternalVtbl ieditstreaminternal = {
137   IEditStreamInternal_fnQueryInterface,
138   IEditStreamInternal_fnAddRef,
139   IEditStreamInternal_fnRelease,
140   IEditStreamInternal_fnGetEditStreamImpl
141 };
142 
143 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
144 
145 typedef struct _IEditAVIStreamImpl {
146   /* IUnknown stuff */
147   const IAVIStreamVtbl *lpVtbl;
148 
149   /* IAVIStream stuff */
150   IAVIEditStreamImpl *pae;
151 } IEditAVIStreamImpl;
152 
153 typedef struct _IEditStreamInternalImpl {
154   /* IUnknown stuff */
155   const IEditStreamInternalVtbl *lpVtbl;
156 
157   /* IEditStreamInternal stuff */
158   IAVIEditStreamImpl *pae;
159 } IEditStreamInternalImpl;
160 
161 struct _IAVIEditStreamImpl {
162   /* IUnknown stuff */
163   const IAVIEditStreamVtbl *lpVtbl;
164   LONG  ref;
165 
166   /* IAVIEditStream stuff */
167   IEditAVIStreamImpl      iAVIStream;
168   IEditStreamInternalImpl iEditStreamInternal;
169 
170   AVISTREAMINFOW       sInfo;
171 
172   EditStreamTable     *pStreams;
173   DWORD                nStreams;   /* current fill level of pStreams table */
174   DWORD                nTableSize; /* size of pStreams table */
175 
176   BOOL                 bDecompress;
177   PAVISTREAM           pCurStream;
178   PGETFRAME            pg;         /* IGetFrame for pCurStream */
179   LPBITMAPINFOHEADER   lpFrame;    /* frame of pCurStream */
180 };
181 
182 /***********************************************************************/
183 
184 PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream)
185 {
186   IAVIEditStreamImpl *pedit = NULL;
187 
188   pedit = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIEditStreamImpl));
189   if (pedit == NULL)
190     return NULL;
191 
192   pedit->lpVtbl            = &ieditstream;
193   pedit->iAVIStream.lpVtbl = &ieditstast;
194   pedit->iAVIStream.pae    = pedit;
195   pedit->iEditStreamInternal.lpVtbl = &ieditstreaminternal;
196   pedit->iEditStreamInternal.pae    = pedit;
197   pedit->ref = 1;
198 
199   IAVIStream_Create((PAVISTREAM)&pedit->iAVIStream,(LPARAM)pstream,0);
200 
201   return (PAVIEDITSTREAM)pedit;
202 }
203 
204 static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
205                                          DWORD pos,PAVISTREAM *ppStream,
206                                          DWORD* streamPos,
207                                          DWORD* streamNr,BOOL bFindSample)
208 {
209   DWORD n;
210 
211   TRACE("(%p,%u,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
212         streamNr,bFindSample);
213 
214   if (pos < This->sInfo.dwStart)
215     return AVIERR_BADPARAM;
216 
217   pos -= This->sInfo.dwStart;
218   for (n = 0; n < This->nStreams; n++) {
219     if (pos < This->pStreams[n].dwLength) {
220       *ppStream  = This->pStreams[n].pStream;
221       *streamPos = This->pStreams[n].dwStart + pos;
222       if (streamNr != NULL)
223         *streamNr = n;
224 
225       return AVIERR_OK;
226     }
227     pos -= This->pStreams[n].dwLength;
228   }
229   if (pos == 0 && bFindSample) {
230     *ppStream  = This->pStreams[--n].pStream;
231     *streamPos = EditStreamEnd(This, n);
232     if (streamNr != NULL)
233       *streamNr = n;
234 
235     TRACE(" -- pos=0 && b=1 -> (%p,%u,%u)\n",*ppStream, *streamPos, n);
236     return AVIERR_OK;
237   } else {
238     *ppStream = NULL;
239     *streamPos = 0;
240     if (streamNr != NULL)
241       *streamNr = 0;
242 
243     TRACE(" -> ERROR (NULL,0,0)\n");
244     return AVIERR_BADPARAM;
245   }
246 }
247 
248 static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
249                                 PAVISTREAM pstream, LONG pos)
250 {
251   PGETFRAME pg;
252 
253   TRACE("(%p,%p,%d)\n",This,pstream,pos);
254 
255   if (pstream == NULL)
256     return NULL;
257 
258   /* if stream changes make sure that only palette changes */
259   if (This->pCurStream != pstream) {
260     pg = AVIStreamGetFrameOpen(pstream, NULL);
261     if (pg == NULL)
262       return NULL;
263     if (This->pg != NULL) {
264       if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1)) {
265         AVIStreamGetFrameClose(pg);
266         ERR(": IGetFrame_SetFormat failed\n");
267         return NULL;
268       }
269       AVIStreamGetFrameClose(This->pg);
270     }
271     This->pg         = pg;
272     This->pCurStream = pstream;
273   }
274 
275   /* now get the decompressed frame */
276   This->lpFrame = AVIStreamGetFrame(This->pg, pos);
277   if (This->lpFrame != NULL)
278     This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage;
279 
280   return This->lpFrame;
281 }
282 
283 static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
284 {
285   assert(This != NULL);
286   assert(nr < This->nStreams);
287 
288   /* remove part nr */
289   IAVIStream_Release(This->pStreams[nr].pStream);
290   This->nStreams--;
291   if (This->nStreams - nr > 0) {
292     memmove(This->pStreams + nr, This->pStreams + nr + 1,
293             (This->nStreams - nr) * sizeof(EditStreamTable));
294   }
295   This->pStreams[This->nStreams].pStream  = NULL;
296   This->pStreams[This->nStreams].dwStart  = 0;
297   This->pStreams[This->nStreams].dwLength = 0;
298 
299   /* try to merge the part before the deleted one and the one after it */
300   if (0 < nr && 0 < This->nStreams &&
301       This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) {
302     if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) {
303       This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength;
304       return AVIFILE_RemoveStream(This, nr);
305     }
306   }
307 
308   return AVIERR_OK;
309 }
310 
311 static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
312 {
313   LPVOID fmt1 = NULL, fmt2 = NULL;
314   LONG size1, size2, start1, start2;
315   BOOL status = FALSE;
316 
317   assert(avi1 != NULL && avi2 != NULL);
318 
319   /* get stream starts and check format sizes */
320   start1 = AVIStreamStart(avi1);
321   start2 = AVIStreamStart(avi2);
322   if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
323     return FALSE;
324   if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
325     return FALSE;
326   if (size1 != size2)
327     return FALSE;
328 
329   /* sizes match, now get formats and compare them */
330   fmt1 = HeapAlloc(GetProcessHeap(), 0, size1);
331   if (fmt1 == NULL)
332     return FALSE;
333   if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
334     fmt2 = HeapAlloc(GetProcessHeap(), 0, size1);
335     if (fmt2 != NULL) {
336       if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
337         status = (memcmp(fmt1, fmt2, size1) == 0);
338     }
339   }
340 
341   HeapFree(GetProcessHeap(), 0, fmt2);
342   HeapFree(GetProcessHeap(), 0, fmt1);
343 
344   return status;
345 }
346 
347 /***********************************************************************/
348 
349 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
350 {
351   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
352 
353   TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
354 
355   if (IsEqualGUID(&IID_IUnknown, refiid) ||
356       IsEqualGUID(&IID_IAVIEditStream, refiid)) {
357     *obj = iface;
358     IAVIEditStream_AddRef(iface);
359 
360     return S_OK;
361   } else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
362     *obj = &This->iAVIStream;
363     IAVIEditStream_AddRef(iface);
364 
365     return S_OK;
366   } else if (IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
367     *obj = &This->iEditStreamInternal;
368     IAVIEditStream_AddRef(iface);
369 
370     return S_OK;
371   }
372 
373   return OLE_E_ENUM_NOMORE;
374 }
375 
376 static ULONG   WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
377 {
378   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
379   ULONG ref = InterlockedIncrement(&This->ref);
380 
381   TRACE("(%p) -> %d\n", iface, ref);
382 
383   return ref;
384 }
385 
386 static ULONG   WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
387 {
388   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
389   DWORD i;
390   ULONG ref = InterlockedDecrement(&This->ref);
391 
392   TRACE("(%p) -> %d\n", iface, ref);
393 
394   if (!ref) {
395     /* release memory */
396     if (This->pg != NULL)
397       AVIStreamGetFrameClose(This->pg);
398     if (This->pStreams != NULL) {
399       for (i = 0; i < This->nStreams; i++) {
400         if (This->pStreams[i].pStream != NULL)
401           IAVIStream_Release(This->pStreams[i].pStream);
402       }
403       HeapFree(GetProcessHeap(), 0, This->pStreams);
404     }
405 
406     HeapFree(GetProcessHeap(), 0, This);
407     return 0;
408   }
409   return ref;
410 }
411 
412 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
413                                            LONG*plLength,PAVISTREAM*ppResult)
414 {
415   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
416   PAVISTREAM stream;
417   DWORD      start, len, streamPos, streamNr;
418   HRESULT    hr;
419 
420   TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
421 
422   if (ppResult != NULL)
423     *ppResult = NULL;
424   if (plStart == NULL || plLength == NULL || *plStart < 0)
425     return AVIERR_BADPARAM;
426 
427   /* if asked for cut part copy it before deleting */
428   if (ppResult != NULL) {
429     hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
430     if (FAILED(hr))
431       return hr;
432   }
433 
434   start = *plStart;
435   len   = *plLength;
436 
437   /* now delete the requested part */
438   while (len > 0) {
439     hr = AVIFILE_FindStreamInTable(This, start, &stream,
440                                    &streamPos, &streamNr, FALSE);
441     if (FAILED(hr))
442       return hr;
443     if (This->pStreams[streamNr].dwStart == streamPos) {
444       /* deleting from start of part */
445       if (len < This->pStreams[streamNr].dwLength) {
446         start += len;
447         This->pStreams[streamNr].dwStart  += len;
448         This->pStreams[streamNr].dwLength -= len;
449         This->sInfo.dwLength -= len;
450         len = 0;
451 
452         /* we must return decompressed data now */
453         This->bDecompress = TRUE;
454       } else {
455         /* deleting hole part */
456         len -= This->pStreams[streamNr].dwLength;
457         AVIFILE_RemoveStream(This,streamNr);
458       }
459     } else if (EditStreamEnd(This, streamNr) <= streamPos + len) {
460       /* deleting at end of a part */
461       DWORD count = EditStreamEnd(This, streamNr) - streamPos;
462       This->sInfo.dwLength -= count;
463       len                  -= count;
464       This->pStreams[streamNr].dwLength =
465         streamPos - This->pStreams[streamNr].dwStart;
466     } else {
467       /* splitting */
468       if (This->nStreams + 1 >= This->nTableSize) {
469         This->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pStreams,
470                                      (This->nTableSize + 32) * sizeof(EditStreamTable));
471         if (This->pStreams == NULL)
472           return AVIERR_MEMORY;
473         This->nTableSize += 32;
474       }
475       memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
476               (This->nStreams - streamNr) * sizeof(EditStreamTable));
477       This->nStreams++;
478 
479       IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream);
480       This->pStreams[streamNr + 1].dwStart  = streamPos + len;
481       This->pStreams[streamNr + 1].dwLength =
482         EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart;
483 
484       This->pStreams[streamNr].dwLength =
485         streamPos - This->pStreams[streamNr].dwStart;
486       This->sInfo.dwLength -= len;
487       len = 0;
488     }
489   }
490 
491   This->sInfo.dwEditCount++;
492 
493   return AVIERR_OK;
494 }
495 
496 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
497                                             LONG*plLength,PAVISTREAM*ppResult)
498 {
499   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
500   IAVIEditStreamImpl* pEdit;
501   HRESULT hr;
502   LONG start = 0;
503 
504   TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
505 
506   if (ppResult == NULL)
507     return AVIERR_BADPARAM;
508   *ppResult = NULL;
509   if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
510     return AVIERR_BADPARAM;
511 
512   /* check bounds */
513   if (*(LPDWORD)plLength > This->sInfo.dwLength)
514     *(LPDWORD)plLength = This->sInfo.dwLength;
515   if (*(LPDWORD)plStart < This->sInfo.dwStart) {
516     *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart;
517     *(LPDWORD)plStart   = This->sInfo.dwStart;
518     if (*plLength < 0)
519       return AVIERR_BADPARAM;
520   }
521   if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
522     *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
523       *(LPDWORD)plStart;
524 
525   pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
526   if (pEdit == NULL)
527     return AVIERR_MEMORY;
528 
529   hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength,
530                             (PAVISTREAM)&This->iAVIStream,*plStart,
531                             *plStart + *plLength);
532   *plStart = start;
533   if (FAILED(hr))
534     IAVIEditStream_Release((PAVIEDITSTREAM)pEdit);
535   else
536     *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
537 
538   return hr;
539 }
540 
541 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
542                                              LONG*plLength,PAVISTREAM pSource,
543                                              LONG lStart,LONG lLength)
544 {
545   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
546   AVISTREAMINFOW      srcInfo;
547   IEditStreamInternal*pInternal = NULL;
548   IAVIEditStreamImpl *pEdit = NULL;
549   PAVISTREAM          pStream;
550   DWORD               startPos, endPos, streamNr, nStreams;
551   ULONG               n;
552 
553   TRACE("(%p,%p,%p,%p,%d,%d)\n",iface,plStart,plLength,
554         pSource,lStart,lLength);
555 
556   if (pSource == NULL)
557     return AVIERR_BADHANDLE;
558   if (plStart == NULL || *plStart < 0)
559     return AVIERR_BADPARAM;
560   if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart)
561     return AVIERR_BADPARAM; /* Can't paste with holes */
562   if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo))))
563     return AVIERR_ERROR;
564   if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength)
565     return AVIERR_BADPARAM;
566   if (This->sInfo.fccType == 0) {
567     /* This stream is empty */
568     IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo));
569     This->sInfo.dwStart  = *plStart;
570     This->sInfo.dwLength = 0;
571   }
572   if (This->sInfo.fccType != srcInfo.fccType)
573     return AVIERR_UNSUPPORTED; /* different stream types */
574   if (lLength == -1) /* Copy the hole stream */
575     lLength = srcInfo.dwLength;
576   if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength)
577     lLength = srcInfo.dwStart + srcInfo.dwLength - lStart;
578   if (lLength + *plStart >= 0x80000000)
579     return AVIERR_MEMORY;
580 
581   /* streamtype specific tests */
582   if (srcInfo.fccType == streamtypeVIDEO) {
583     LONG size;
584 
585     size = srcInfo.rcFrame.right - srcInfo.rcFrame.left;
586     if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left)
587       return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
588     size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top;
589     if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top)
590       return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
591   } else if (srcInfo.fccType == streamtypeAUDIO) {
592     if (! AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))
593       return AVIERR_UNSUPPORTED;
594   } else {
595     /* FIXME: streamtypeMIDI and streamtypeTEXT */
596     return AVIERR_UNSUPPORTED;
597   }
598 
599   /* try to get an IEditStreamInternal interface */
600   if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal,
601                                           (LPVOID*)&pInternal))) {
602     pInternal->lpVtbl->GetEditStreamImpl(pInternal, (LPVOID*)&pEdit);
603     pInternal->lpVtbl->Release(pInternal);
604   }
605 
606   /* for video must check for change of format */
607   if (This->sInfo.fccType == streamtypeVIDEO) {
608     if (! This->bDecompress) {
609       /* Need to decompress if any of the following conditions matches:
610        *  - pSource is an editable stream which decompresses
611        *  - the nearest keyframe of pSource isn't lStart
612        *  - the nearest keyframe of this stream isn't *plStart
613        *  - the format of pSource doesn't match this one
614        */
615       if ((pEdit != NULL && pEdit->bDecompress) ||
616           AVIStreamNearestKeyFrame(pSource, lStart) != lStart ||
617           AVIStreamNearestKeyFrame((PAVISTREAM)&This->iAVIStream, *plStart) != *plStart ||
618           (This->nStreams > 0 && !AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))) {
619         /* Use first stream part to get format to convert everything to */
620         AVIFILE_ReadFrame(This, This->pStreams[0].pStream,
621                           This->pStreams[0].dwStart);
622 
623         /* Check if we could convert the source streams to the desired format... */
624         if (pEdit != NULL) {
625           if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
626                                                &startPos, &streamNr, TRUE)))
627             return AVIERR_INTERNAL;
628           for (n = lStart; n < lStart + lLength; streamNr++) {
629             if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL)
630               return AVIERR_BADFORMAT;
631             startPos = pEdit->pStreams[streamNr].dwStart;
632             n += pEdit->pStreams[streamNr].dwLength;
633           }
634         } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
635           return AVIERR_BADFORMAT;
636 
637         This->bDecompress      = TRUE;
638         This->sInfo.fccHandler = 0;
639       }
640     } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
641       return AVIERR_BADFORMAT; /* Can't convert source to own format */
642   } /* FIXME: something special for the other formats? */
643 
644   /* Make sure we have enough memory for parts */
645   if (pEdit != NULL) {
646     DWORD nLastStream;
647 
648     AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
649                               &endPos, &nLastStream, TRUE);
650     AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
651                               &startPos, &streamNr, FALSE);
652     if (nLastStream == streamNr)
653       nLastStream++;
654 
655     nStreams = nLastStream - streamNr;
656   } else 
657     nStreams = 1;
658   if (This->nStreams + nStreams + 1 > This->nTableSize) {
659     n = This->nStreams + nStreams + 33;
660 
661     This->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pStreams, n * sizeof(EditStreamTable));
662     if (This->pStreams == NULL)
663       return AVIERR_MEMORY;
664     This->nTableSize = n;
665   }
666 
667   if (plLength != NULL)
668     *plLength = lLength;
669 
670   /* now do the real work */
671   if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) {
672     AVIFILE_FindStreamInTable(This, *plStart, &pStream,
673                               &startPos, &streamNr, FALSE);
674     if (startPos != This->pStreams[streamNr].dwStart) {
675       /* split stream streamNr at startPos */
676       memmove(This->pStreams + streamNr + nStreams + 1,
677               This->pStreams + streamNr,
678               (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable));
679 
680       This->pStreams[streamNr + 2].dwLength =
681         EditStreamEnd(This, streamNr + 2) - startPos;
682       This->pStreams[streamNr + 2].dwStart = startPos;
683       This->pStreams[streamNr].dwLength =
684         startPos - This->pStreams[streamNr].dwStart;
685       IAVIStream_AddRef(This->pStreams[streamNr].pStream);
686       streamNr++;
687     } else {
688       /* insert before stream at streamNr */
689       memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
690               (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
691     }
692   } else /* append the streams */
693     streamNr = This->nStreams;
694 
695   if (pEdit != NULL) {
696     /* insert the parts of the editable stream instead of itself */
697     AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
698                               &endPos, NULL, FALSE);
699     AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE);
700 
701     memcpy(This->pStreams + streamNr, pEdit->pStreams + n,
702            nStreams * sizeof(EditStreamTable));
703     if (This->pStreams[streamNr].dwStart < startPos) {
704       This->pStreams[streamNr].dwLength =
705         EditStreamEnd(This, streamNr) - startPos;
706       This->pStreams[streamNr].dwStart  = startPos;
707     }
708     if (endPos < EditStreamEnd(This, streamNr + nStreams))
709       This->pStreams[streamNr + nStreams].dwLength =
710         endPos - This->pStreams[streamNr + nStreams].dwStart;
711   } else {
712     /* a simple stream */
713     This->pStreams[streamNr].pStream  = pSource;
714     This->pStreams[streamNr].dwStart  = lStart;
715     This->pStreams[streamNr].dwLength = lLength;
716   }
717 
718   for (n = 0; n < nStreams; n++) {
719     IAVIStream_AddRef(This->pStreams[streamNr + n].pStream);
720     if (0 < streamNr + n &&
721         This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) {
722       This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
723       This->sInfo.dwFormatChangeCount++;
724     }
725   }
726   This->sInfo.dwEditCount++;
727   This->sInfo.dwLength += lLength;
728   This->nStreams += nStreams;
729 
730   return AVIERR_OK;
731 }
732 
733 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
734                                              PAVISTREAM*ppResult)
735 {
736   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
737   IAVIEditStreamImpl* pEdit;
738   DWORD i;
739 
740   TRACE("(%p,%p)\n",iface,ppResult);
741 
742   if (ppResult == NULL)
743     return AVIERR_BADPARAM;
744   *ppResult = NULL;
745 
746   pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
747   if (pEdit == NULL)
748     return AVIERR_MEMORY;
749   if (This->nStreams > pEdit->nTableSize) {
750     pEdit->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pEdit->pStreams,
751                                   This->nStreams * sizeof(EditStreamTable));
752     if (pEdit->pStreams == NULL)
753       return AVIERR_MEMORY;
754     pEdit->nTableSize = This->nStreams;
755   }
756   pEdit->nStreams = This->nStreams;
757   memcpy(pEdit->pStreams, This->pStreams,
758          This->nStreams * sizeof(EditStreamTable));
759   memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo));
760   for (i = 0; i < This->nStreams; i++) {
761     if (pEdit->pStreams[i].pStream != NULL)
762       IAVIStream_AddRef(pEdit->pStreams[i].pStream);
763   }
764 
765   *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
766 
767   return AVIERR_OK;
768 }
769 
770 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
771                                                LPAVISTREAMINFOW asi,LONG size)
772 {
773   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
774 
775   TRACE("(%p,%p,%d)\n",iface,asi,size);
776 
777   /* check parameters */
778   if (asi == NULL)
779     return AVIERR_BADPARAM;
780   if (size != sizeof(AVISTREAMINFOW))
781     return AVIERR_BADSIZE;
782   if (asi->dwScale == 0 || asi->dwRate == 0 || (LONG)asi->dwQuality < -1 ||
783       asi->dwQuality > ICQUALITY_HIGH)
784     return AVIERR_ERROR;
785 
786   This->sInfo.wLanguage = asi->wLanguage;
787   This->sInfo.wPriority = asi->wPriority;
788   This->sInfo.dwStart   = asi->dwStart;
789   if (asi->dwRate != 0)
790     This->sInfo.dwRate  = asi->dwRate;
791   if (asi->dwScale != 0)
792     This->sInfo.dwScale = asi->dwScale;
793   if (asi->dwQuality <= ICQUALITY_HIGH)
794     This->sInfo.dwQuality = ICQUALITY_HIGH;
795   CopyRect(&This->sInfo.rcFrame, &asi->rcFrame);
796   memcpy(&This->sInfo.szName, &asi->szName, sizeof(asi->szName));
797   This->sInfo.dwEditCount++;
798 
799   return AVIERR_OK;
800 }
801 
802 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
803                                                       REFIID refiid,LPVOID*obj)
804 {
805   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
806 
807   assert(This->pae != NULL);
808 
809   return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae,refiid,obj);
810 }
811 
812 static ULONG   WINAPI IEditAVIStr