2 * Copyright 2003 Michael Günnewig
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.
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.
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
19 #define COM_NO_WINDOWS_H
32 #include "avifile_private.h"
33 #include "extrachunk.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
39 /***********************************************************************/
41 /* internal interface to get access to table of stream in an editable stream */
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 */
49 #define INTERFACE IEditStreamInternal
50 DECLARE_INTERFACE_(IEditStreamInternal,IUnknown)
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;
61 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
62 (This)->pStreams[streamNr].dwLength)
64 /***********************************************************************/
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,
78 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
79 LPAVISTREAMINFOW asi,LONG size);
81 static const struct IAVIEditStreamVtbl ieditstream = {
82 IAVIEditStream_fnQueryInterface,
83 IAVIEditStream_fnAddRef,
84 IAVIEditStream_fnRelease,
86 IAVIEditStream_fnCopy,
87 IAVIEditStream_fnPaste,
88 IAVIEditStream_fnClone,
89 IAVIEditStream_fnSetInfo
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,
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,
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);
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
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);
138 static const struct IEditStreamInternalVtbl ieditstreaminternal = {
139 IEditStreamInternal_fnQueryInterface,
140 IEditStreamInternal_fnAddRef,
141 IEditStreamInternal_fnRelease,
142 IEditStreamInternal_fnGetEditStreamImpl
145 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
147 typedef struct _IEditAVIStreamImpl {
149 const IAVIStreamVtbl *lpVtbl;
151 /* IAVIStream stuff */
152 IAVIEditStreamImpl *pae;
153 } IEditAVIStreamImpl;
155 typedef struct _IEditStreamInternalImpl {
157 const IEditStreamInternalVtbl *lpVtbl;
159 /* IEditStreamInternal stuff */
160 IAVIEditStreamImpl *pae;
161 } IEditStreamInternalImpl;
163 struct _IAVIEditStreamImpl {
165 const IAVIEditStreamVtbl *lpVtbl;
168 /* IAVIEditStream stuff */
169 IEditAVIStreamImpl iAVIStream;
170 IEditStreamInternalImpl iEditStreamInternal;
172 AVISTREAMINFOW sInfo;
174 EditStreamTable *pStreams;
175 DWORD nStreams; /* current fill level of pStreams table */
176 DWORD nTableSize; /* size of pStreams table */
179 PAVISTREAM pCurStream;
180 PGETFRAME pg; /* IGetFrame for pCurStream */
181 LPBITMAPINFOHEADER lpFrame; /* frame of pCurStream */
184 /***********************************************************************/
186 PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream)
188 IAVIEditStreamImpl *pedit = NULL;
190 pedit = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIEditStreamImpl));
194 pedit->lpVtbl = &ieditstream;
195 pedit->iAVIStream.lpVtbl = &ieditstast;
196 pedit->iAVIStream.pae = pedit;
197 pedit->iEditStreamInternal.lpVtbl = &ieditstreaminternal;
198 pedit->iEditStreamInternal.pae = pedit;
201 IAVIStream_Create((PAVISTREAM)&pedit->iAVIStream,(LPARAM)pstream,0);
203 return (PAVIEDITSTREAM)pedit;
206 static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
207 DWORD pos,PAVISTREAM *ppStream,
209 DWORD* streamNr,BOOL bFindSample)
213 TRACE("(%p,%lu,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
214 streamNr,bFindSample);
216 if (pos < This->sInfo.dwStart)
217 return AVIERR_BADPARAM;
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)
229 pos -= This->pStreams[n].dwLength;
231 if (pos == 0 && bFindSample) {
232 *ppStream = This->pStreams[--n].pStream;
233 *streamPos = EditStreamEnd(This, n);
234 if (streamNr != NULL)
237 TRACE(" -- pos=0 && b=1 -> (%p,%lu,%lu)\n",*ppStream, *streamPos, n);
242 if (streamNr != NULL)
245 TRACE(" -> ERROR (NULL,0,0)\n");
246 return AVIERR_BADPARAM;
250 static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
251 PAVISTREAM pstream, LONG pos)
255 TRACE("(%p,%p,%ld)\n",This,pstream,pos);
260 /* if stream changes make sure that only palette changes */
261 if (This->pCurStream != pstream) {
262 pg = AVIStreamGetFrameOpen(pstream, 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");
271 AVIStreamGetFrameClose(This->pg);
274 This->pCurStream = pstream;
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;
282 return This->lpFrame;
285 static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
287 assert(This != NULL);
288 assert(nr < This->nStreams);
291 IAVIStream_Release(This->pStreams[nr].pStream);
293 if (This->nStreams - nr > 0) {
294 memmove(This->pStreams + nr, This->pStreams + nr + 1,
295 (This->nStreams - nr) * sizeof(EditStreamTable));
297 This->pStreams[This->nStreams].pStream = NULL;
298 This->pStreams[This->nStreams].dwStart = 0;
299 This->pStreams[This->nStreams].dwLength = 0;
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);
313 static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
315 LPVOID fmt1 = NULL, fmt2 = NULL;
316 LONG size1, size2, start1, start2;
319 assert(avi1 != NULL && avi2 != NULL);
321 /* get stream starts and check format sizes */
322 start1 = AVIStreamStart(avi1);
323 start2 = AVIStreamStart(avi2);
324 if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
326 if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
331 /* sizes match, now get formats and compare them */
332 fmt1 = HeapAlloc(GetProcessHeap(), 0, size1);
335 if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
336 fmt2 = HeapAlloc(GetProcessHeap(), 0, size1);
338 if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
339 status = (memcmp(fmt1, fmt2, size1) == 0);
343 HeapFree(GetProcessHeap(), 0, fmt2);
344 HeapFree(GetProcessHeap(), 0, fmt1);
349 /***********************************************************************/
351 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
353 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
355 TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
357 if (IsEqualGUID(&IID_IUnknown, refiid) ||
358 IsEqualGUID(&IID_IAVIEditStream, refiid)) {
360 IAVIEditStream_AddRef(iface);
363 } else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
364 *obj = &This->iAVIStream;
365 IAVIEditStream_AddRef(iface);
368 } else if (IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
369 *obj = &This->iEditStreamInternal;
370 IAVIEditStream_AddRef(iface);
375 return OLE_E_ENUM_NOMORE;
378 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
380 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
381 ULONG ref = InterlockedIncrement(&This->ref);
383 TRACE("(%p) -> %ld\n", iface, ref);
388 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
390 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
392 ULONG ref = InterlockedDecrement(&This->ref);
394 TRACE("(%p) -> %ld\n", iface, ref);
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);
405 HeapFree(GetProcessHeap(), 0, This->pStreams);
408 HeapFree(GetProcessHeap(), 0, This);
414 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
415 LONG*plLength,PAVISTREAM*ppResult)
417 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
419 DWORD start, len, streamPos, streamNr;
422 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
424 if (ppResult != NULL)
426 if (plStart == NULL || plLength == NULL || *plStart < 0)
427 return AVIERR_BADPARAM;
429 /* if asked for cutted part copy it before deleting */
430 if (ppResult != NULL) {
431 hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
439 /* now delete the requested part */
441 hr = AVIFILE_FindStreamInTable(This, start, &stream,
442 &streamPos, &streamNr, FALSE);
445 if (This->pStreams[streamNr].dwStart == streamPos) {
446 /* deleting from start of part */
447 if (len < This->pStreams[streamNr].dwLength) {
449 This->pStreams[streamNr].dwStart += len;
450 This->pStreams[streamNr].dwLength -= len;
451 This->sInfo.dwLength -= len;
454 /* we must return decompressed data now */
455 This->bDecompress = TRUE;
457 /* deleting hole part */
458 len -= This->pStreams[streamNr].dwLength;
459 AVIFILE_RemoveStream(This,streamNr);
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;
466 This->pStreams[streamNr].dwLength =
467 streamPos - This->pStreams[streamNr].dwStart;
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;
477 memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
478 (This->nStreams - streamNr) * sizeof(EditStreamTable));
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;
486 This->pStreams[streamNr].dwLength =
487 streamPos - This->pStreams[streamNr].dwStart;
488 This->sInfo.dwLength -= len;
493 This->sInfo.dwEditCount++;
498 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
499 LONG*plLength,PAVISTREAM*ppResult)
501 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
502 IAVIEditStreamImpl* pEdit;
506 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
508 if (ppResult == NULL)
509 return AVIERR_BADPARAM;
511 if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
512 return AVIERR_BADPARAM;
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;
521 return AVIERR_BADPARAM;
523 if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
524 *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
527 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
529 return AVIERR_MEMORY;
531 hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength,
532 (PAVISTREAM)&This->iAVIStream,*plStart,
533 *plStart + *plLength);
536 IAVIEditStream_Release((PAVIEDITSTREAM)pEdit);
538 *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
543 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
544 LONG*plLength,PAVISTREAM pSource,
545 LONG lStart,LONG lLength)
547 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
548 AVISTREAMINFOW srcInfo;
549 IEditStreamInternal*pInternal = NULL;
550 IAVIEditStreamImpl *pEdit = NULL;
552 DWORD startPos, endPos, streamNr, nStreams;
555 TRACE("(%p,%p,%p,%p,%ld,%ld)\n",iface,plStart,plLength,
556 pSource,lStart,lLength);
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))))
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;
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;
583 /* streamtype specific tests */
584 if (srcInfo.fccType == streamtypeVIDEO) {
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;
597 /* FIXME: streamtypeMIDI and streamtypeTEXT */
598 return AVIERR_UNSUPPORTED;
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);
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
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);
625 /* Check if we could convert the source streams to the disired format... */
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;
636 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
637 return AVIERR_BADFORMAT;
639 This->bDecompress = TRUE;
640 This->sInfo.fccHandler = 0;
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? */
646 /* Make sure we have enough memory for parts */
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)
657 nStreams = nLastStream - streamNr;
660 if (This->nStreams + nStreams + 1 > This->nTableSize) {
661 n = This->nStreams + nStreams + 33;
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;
669 if (plLength != NULL)
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));
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);
690 /* insert before stream at streamNr */
691 memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
692 (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
694 } else /* append the streams */
695 streamNr = This->nStreams;
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);
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;
710 if (endPos < EditStreamEnd(This, streamNr + nStreams))
711 This->pStreams[streamNr + nStreams].dwLength =
712 endPos - This->pStreams[streamNr + nStreams].dwStart;
714 /* a simple stream */
715 This->pStreams[streamNr].pStream = pSource;
716 This->pStreams[streamNr].dwStart = lStart;
717 This->pStreams[streamNr].dwLength = lLength;
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++;
728 This->sInfo.dwEditCount++;
729 This->sInfo.dwLength += lLength;
730 This->nStreams += nStreams;
735 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
738 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
739 IAVIEditStreamImpl* pEdit;
742 TRACE("(%p,%p)\n",iface,ppResult);
744 if (ppResult == NULL)
745 return AVIERR_BADPARAM;
748 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(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;
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);
767 *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
772 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
773 LPAVISTREAMINFOW asi,LONG size)
775 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
777 TRACE("(%p,%p,%ld)\n",iface,asi,size);
779 /* check parameters */
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)
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++;
804 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
805 REFIID refiid,LPVOID*obj)
807 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
809 assert(This->pae != NULL);
811 return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae,refiid,obj);
814 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface)
816 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
818 assert(This->pae != NULL);
820 return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
823 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface)
825 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
827 assert(This->pae != NULL);
829 return IAVIEditStream_Release((IAVIEditStream*)This->pae);
832 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,
833 LPARAM lParam1,LPARAM lParam2)
835 IAVIEditStreamImpl *This = ((IEditAVIStreamImpl*)iface)->pae;
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;
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;
858 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,
859 AVISTREAMINFOW *psi,LONG size)
861 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
863 TRACE("(%p,%p,%ld)\n",iface,psi,size);
865 assert(This->pae != NULL);
868 return AVIERR_BADPARAM;
870 return AVIERR_BADSIZE;
872 if (This->pae->bDecompress)
873 This->pae->sInfo.fccHandler = 0;
875 memcpy(psi, &This->pae->sInfo, min((DWORD)size, sizeof(This->pae->sInfo)));
877 if ((DWORD)size < sizeof(This->pae->sInfo))
878 return AVIERR_BUFFERTOOSMALL;
882 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
885 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
887 DWORD streamPos, streamNr;
889 TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
891 if (flags & FIND_FROM_START)
892 pos = (LONG)This->sInfo.dwStart;
894 /* outside of stream? */
895 if (pos < (LONG)This->sInfo.dwStart ||
896 (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos)
899 /* map our position to a stream and position in it */
900 if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos,
902 return -1; /* doesn't exist */
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);
909 /* FIXME: map positions back to us */
910 return IAVIStream_FindSample(stream, streamPos, flags);
912 /* assume change of format every frame */
917 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,
918 LPVOID format,LONG*fmtsize)
920 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
921 LPBITMAPINFOHEADER lp;
926 TRACE("(%p,%ld,%p,%p)\n",iface,pos,format,fmtsize);
928 if (fmtsize == NULL || pos < This->sInfo.dwStart ||
929 This->sInfo.dwStart + This->sInfo.dwLength <= pos)
930 return AVIERR_BADPARAM;
932 /* find stream corresponding to position */
933 hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE);
937 if (! This->bDecompress)
938 return IAVIStream_ReadFormat(stream, n, format, fmtsize);
940 lp = (LPBITMAPINFOHEADER)AVIFILE_ReadFrame(This, stream, n);
943 if (lp->biBitCount <= 8) {
944 n = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount);
945 n *= sizeof(RGBQUAD);
950 memcpy(format, lp, min((LONG)n, *fmtsize));
951 hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK);
957 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,
958 LPVOID format,LONG formatsize)
960 TRACE("(%p,%ld,%p,%ld)\n",iface,pos,format,formatsize);
962 return AVIERR_UNSUPPORTED;
965 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
966 LONG samples,LPVOID buffer,
967 LONG buffersize,LONG*bytesread,
970 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
972 DWORD streamPos, streamNr;
973 LONG readBytes, readSamples, count;
976 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p) -- 0x%08lX\n",iface,start,samples,
977 buffer,buffersize,bytesread,samplesread,This->sInfo.fccType);
979 /* check parameters */
980 if (bytesread != NULL)
982 if (samplesread != NULL)
985 return AVIERR_BADSIZE;
986 if ((DWORD)start < This->sInfo.dwStart ||
987 This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
988 return AVIERR_BADPARAM;
990 if (! This->bDecompress) {
991 /* audio like data -- sample-based */
994 return AVIERR_OK; /* nothing at all or already done */
996 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
997 &streamPos, &streamNr, FALSE)))
1000 /* limit to end of the stream */
1002 if (streamPos + count > EditStreamEnd(This, streamNr))
1003 count = EditStreamEnd(This, streamNr) - streamPos;
1005 hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize,
1006 &readBytes, &readSamples);
1009 if (readBytes == 0 && readSamples == 0 && count != 0)
1010 return AVIERR_FILEREAD; /* for bad stream implementations */
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;
1022 } while (This->sInfo.dwStart + This->sInfo.dwLength > start);
1024 /* video like data -- frame-based */
1025 LPBITMAPINFOHEADER lp;
1030 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
1031 &streamPos, &streamNr, FALSE)))
1032 return AVIERR_ERROR;
1034 lp = AVIFILE_ReadFrame(This, stream, streamPos);
1036 return AVIERR_ERROR;
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);
1045 count += lp->biSize;
1047 if (buffersize < lp->biSizeImage)
1048 return AVIERR_BUFFERTOOSMALL;
1049 memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage);
1052 if (bytesread != NULL)
1053 *bytesread = lp->biSizeImage;
1054 if (samplesread != NULL)
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)
1066 TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n",iface,start,samples,buffer,
1067 buffersize,flags,sampwritten,byteswritten);
1069 /* be sure return parameters have correct values */
1070 if (sampwritten != NULL)
1072 if (byteswritten != NULL)
1075 return AVIERR_UNSUPPORTED;
1078 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,
1081 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1083 TRACE("(%p,%ld,%ld)\n",iface,start,samples);
1085 return IAVIEditStream_Cut((IAVIEditStream*)This->pae,&start,&samples,NULL);
1088 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
1089 LPVOID lp,LONG *lpread)
1091 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
1094 TRACE("(%p,0x%08lX,%p,%p)\n",iface,fcc,lp,lpread);
1096 /* check parameters */
1097 if (lp == NULL || lpread == NULL)
1098 return AVIERR_BADPARAM;
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);
1109 return AVIERR_NODATA;
1112 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
1113 LPVOID lp,LONG size)
1115 TRACE("(%p,0x%08lX,%p,%ld)\n",iface,fcc,lp,size);
1117 return AVIERR_UNSUPPORTED;
1120 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,
1121 AVISTREAMINFOW*info,LONG len)
1123 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1125 TRACE("(%p,%p,%ld)\n",iface,info,len);
1127 return IAVIEditStream_SetInfo((IAVIEditStream*)This->pae,info,len);
1130 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj)
1132 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1134 assert(This->pae != NULL);
1136 return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae, refiid, obj);
1139 static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface)
1141 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1143 assert(This->pae != NULL);
1145 return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
1148 static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface)
1150 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1152 assert(This->pae != NULL);
1154 return IAVIEditStream_Release((IAVIEditStream*)This->pae);
1157 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl)
1159 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1161 TRACE("(%p,%p) -> %p\n", iface, ppimpl, This->pae);
1163 assert(This->pae != NULL);
1164 assert(ppimpl != NULL);
1166 *ppimpl = This->pae;