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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #define COM_NO_WINDOWS_H
33 #include "avifile_private.h"
34 #include "extrachunk.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
40 /***********************************************************************/
42 /* internal interface to get access to table of stream in an editable stream */
44 typedef struct _EditStreamTable {
45 PAVISTREAM pStream; /* stream which contains the data */
46 DWORD dwStart; /* where starts the part which is also our */
47 DWORD dwLength; /* how many is also in this stream */
50 #define INTERFACE IEditStreamInternal
51 DECLARE_INTERFACE_(IEditStreamInternal,IUnknown)
53 /*** IUnknown methods ***/
54 STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
55 STDMETHOD_(ULONG,AddRef)(THIS) PURE;
56 STDMETHOD_(ULONG,Release)(THIS) PURE;
57 /*** IEditStreamInternal methods ***/
58 STDMETHOD(GetEditStreamImpl)(THIS_ LPVOID*) PURE;
62 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
63 (This)->pStreams[streamNr].dwLength)
65 /***********************************************************************/
67 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj);
68 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface);
69 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface);
70 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
71 LONG*plLength,PAVISTREAM*ppResult);
72 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
73 LONG*plLength,PAVISTREAM*ppResult);
74 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
75 LONG*plLength,PAVISTREAM pSource,
76 LONG lStart,LONG lEnd);
77 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
79 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
80 LPAVISTREAMINFOW asi,LONG size);
82 static const struct IAVIEditStreamVtbl ieditstream = {
83 IAVIEditStream_fnQueryInterface,
84 IAVIEditStream_fnAddRef,
85 IAVIEditStream_fnRelease,
87 IAVIEditStream_fnCopy,
88 IAVIEditStream_fnPaste,
89 IAVIEditStream_fnClone,
90 IAVIEditStream_fnSetInfo
93 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID*obj);
94 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface);
95 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface);
96 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
97 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
98 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
100 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG*formatsize);
101 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
102 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
103 LONG samples,LPVOID buffer,
104 LONG buffersize,LONG*bytesread,
106 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
107 LONG samples,LPVOID buffer,
108 LONG buffersize,DWORD flags,
109 LONG*sampwritten,LONG*byteswritten);
110 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
111 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
112 LPVOID lp,LONG *lpread);
113 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
114 LPVOID lp,LONG size);
115 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
117 static const struct IAVIStreamVtbl ieditstast = {
118 IEditAVIStream_fnQueryInterface,
119 IEditAVIStream_fnAddRef,
120 IEditAVIStream_fnRelease,
121 IEditAVIStream_fnCreate,
122 IEditAVIStream_fnInfo,
123 IEditAVIStream_fnFindSample,
124 IEditAVIStream_fnReadFormat,
125 IEditAVIStream_fnSetFormat,
126 IEditAVIStream_fnRead,
127 IEditAVIStream_fnWrite,
128 IEditAVIStream_fnDelete,
129 IEditAVIStream_fnReadData,
130 IEditAVIStream_fnWriteData,
131 IEditAVIStream_fnSetInfo
134 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj);
135 static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface);
136 static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface);
137 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl);
139 static const struct IEditStreamInternalVtbl ieditstreaminternal = {
140 IEditStreamInternal_fnQueryInterface,
141 IEditStreamInternal_fnAddRef,
142 IEditStreamInternal_fnRelease,
143 IEditStreamInternal_fnGetEditStreamImpl
146 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
148 typedef struct _IEditAVIStreamImpl {
150 const IAVIStreamVtbl *lpVtbl;
152 /* IAVIStream stuff */
153 IAVIEditStreamImpl *pae;
154 } IEditAVIStreamImpl;
156 typedef struct _IEditStreamInternalImpl {
158 const IEditStreamInternalVtbl *lpVtbl;
160 /* IEditStreamInternal stuff */
161 IAVIEditStreamImpl *pae;
162 } IEditStreamInternalImpl;
164 struct _IAVIEditStreamImpl {
166 const IAVIEditStreamVtbl *lpVtbl;
169 /* IAVIEditStream stuff */
170 IEditAVIStreamImpl iAVIStream;
171 IEditStreamInternalImpl iEditStreamInternal;
173 AVISTREAMINFOW sInfo;
175 EditStreamTable *pStreams;
176 DWORD nStreams; /* current fill level of pStreams table */
177 DWORD nTableSize; /* size of pStreams table */
180 PAVISTREAM pCurStream;
181 PGETFRAME pg; /* IGetFrame for pCurStream */
182 LPBITMAPINFOHEADER lpFrame; /* frame of pCurStream */
185 /***********************************************************************/
187 PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream)
189 IAVIEditStreamImpl *pedit = NULL;
191 pedit = (IAVIEditStreamImpl*)LocalAlloc(LPTR,sizeof(IAVIEditStreamImpl));
195 pedit->lpVtbl = &ieditstream;
196 pedit->iAVIStream.lpVtbl = &ieditstast;
197 pedit->iAVIStream.pae = pedit;
198 pedit->iEditStreamInternal.lpVtbl = &ieditstreaminternal;
199 pedit->iEditStreamInternal.pae = pedit;
202 IAVIStream_Create((PAVISTREAM)&pedit->iAVIStream,(LPARAM)pstream,0);
204 return (PAVIEDITSTREAM)pedit;
207 static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
208 DWORD pos,PAVISTREAM *ppStream,
210 DWORD* streamNr,BOOL bFindSample)
214 TRACE("(%p,%lu,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
215 streamNr,bFindSample);
217 if (pos < This->sInfo.dwStart)
218 return AVIERR_BADPARAM;
220 pos -= This->sInfo.dwStart;
221 for (n = 0; n < This->nStreams; n++) {
222 if (pos < This->pStreams[n].dwLength) {
223 *ppStream = This->pStreams[n].pStream;
224 *streamPos = This->pStreams[n].dwStart + pos;
225 if (streamNr != NULL)
230 pos -= This->pStreams[n].dwLength;
232 if (pos == 0 && bFindSample) {
233 *ppStream = This->pStreams[--n].pStream;
234 *streamPos = EditStreamEnd(This, n);
235 if (streamNr != NULL)
238 TRACE(" -- pos=0 && b=1 -> (%p,%lu,%lu)\n",*ppStream, *streamPos, n);
243 if (streamNr != NULL)
246 TRACE(" -> ERROR (NULL,0,0)\n");
247 return AVIERR_BADPARAM;
251 static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
252 PAVISTREAM pstream, LONG pos)
256 TRACE("(%p,%p,%ld)\n",This,pstream,pos);
261 /* if stream changes make sure that only palette changes */
262 if (This->pCurStream != pstream) {
263 pg = AVIStreamGetFrameOpen(pstream, NULL);
266 if (This->pg != NULL) {
267 if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1)) {
268 AVIStreamGetFrameClose(pg);
269 ERR(": IGetFrame_SetFormat failed\n");
272 AVIStreamGetFrameClose(This->pg);
275 This->pCurStream = pstream;
278 /* now get the decompressed frame */
279 This->lpFrame = AVIStreamGetFrame(This->pg, pos);
280 if (This->lpFrame != NULL)
281 This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage;
283 return This->lpFrame;
286 static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
288 assert(This != NULL);
289 assert(nr < This->nStreams);
292 IAVIStream_Release(This->pStreams[nr].pStream);
294 if (This->nStreams - nr > 0) {
295 memmove(This->pStreams + nr, This->pStreams + nr + 1,
296 (This->nStreams - nr) * sizeof(EditStreamTable));
298 This->pStreams[This->nStreams].pStream = NULL;
299 This->pStreams[This->nStreams].dwStart = 0;
300 This->pStreams[This->nStreams].dwLength = 0;
302 /* try to merge the part before the deleted one and the one after it */
303 if (0 < nr && 0 < This->nStreams &&
304 This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) {
305 if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) {
306 This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength;
307 return AVIFILE_RemoveStream(This, nr);
314 static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
316 LPVOID fmt1 = NULL, fmt2 = NULL;
317 LONG size1, size2, start1, start2;
320 assert(avi1 != NULL && avi2 != NULL);
322 /* get stream starts and check format sizes */
323 start1 = AVIStreamStart(avi1);
324 start2 = AVIStreamStart(avi2);
325 if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
327 if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
332 /* sizes match, now get formats and compare them */
333 fmt1 = GlobalAllocPtr(GHND, size1);
336 if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
337 fmt2 = GlobalAllocPtr(GHND, size1);
339 if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
340 status = (memcmp(fmt1, fmt2, size1) == 0);
351 /***********************************************************************/
353 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
355 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
357 TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
359 if (IsEqualGUID(&IID_IUnknown, refiid) ||
360 IsEqualGUID(&IID_IAVIEditStream, refiid)) {
362 IAVIEditStream_AddRef(iface);
365 } else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
366 *obj = &This->iAVIStream;
367 IAVIEditStream_AddRef(iface);
370 } else if (IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
371 *obj = &This->iEditStreamInternal;
372 IAVIEditStream_AddRef(iface);
377 return OLE_E_ENUM_NOMORE;
380 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
382 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
383 ULONG ref = InterlockedIncrement(&This->ref);
385 TRACE("(%p) -> %ld\n", iface, ref);
390 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
392 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
394 ULONG ref = InterlockedDecrement(&This->ref);
396 TRACE("(%p) -> %ld\n", iface, ref);
400 if (This->pg != NULL)
401 AVIStreamGetFrameClose(This->pg);
402 if (This->pStreams != NULL) {
403 for (i = 0; i < This->nStreams; i++) {
404 if (This->pStreams[i].pStream != NULL)
405 IAVIStream_Release(This->pStreams[i].pStream);
407 GlobalFreePtr(This->pStreams);
410 LocalFree((HLOCAL)This);
416 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
417 LONG*plLength,PAVISTREAM*ppResult)
419 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
421 DWORD start, len, streamPos, streamNr;
424 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
426 if (ppResult != NULL)
428 if (plStart == NULL || plLength == NULL || *plStart < 0)
429 return AVIERR_BADPARAM;
431 /* if asked for cutted part copy it before deleting */
432 if (ppResult != NULL) {
433 hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
441 /* now delete the requested part */
443 hr = AVIFILE_FindStreamInTable(This, start, &stream,
444 &streamPos, &streamNr, FALSE);
447 if (This->pStreams[streamNr].dwStart == streamPos) {
448 /* deleting from start of part */
449 if (len < This->pStreams[streamNr].dwLength) {
451 This->pStreams[streamNr].dwStart += len;
452 This->pStreams[streamNr].dwLength -= len;
453 This->sInfo.dwLength -= len;
456 /* we must return decompressed data now */
457 This->bDecompress = TRUE;
459 /* deleting hole part */
460 len -= This->pStreams[streamNr].dwLength;
461 AVIFILE_RemoveStream(This,streamNr);
463 } else if (EditStreamEnd(This, streamNr) <= streamPos + len) {
464 /* deleting at end of a part */
465 DWORD count = EditStreamEnd(This, streamNr) - streamPos;
466 This->sInfo.dwLength -= count;
468 This->pStreams[streamNr].dwLength =
469 streamPos - This->pStreams[streamNr].dwStart;
472 if (This->nStreams + 1 >= This->nTableSize) {
474 GlobalReAllocPtr(This->pStreams, (This->nTableSize + 32) * sizeof(EditStreamTable), GMEM_SHARE|GHND);
475 if (This->pStreams == NULL)
476 return AVIERR_MEMORY;
477 This->nTableSize += 32;
479 memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
480 (This->nStreams - streamNr) * sizeof(EditStreamTable));
483 IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream);
484 This->pStreams[streamNr + 1].dwStart = streamPos + len;
485 This->pStreams[streamNr + 1].dwLength =
486 EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart;
488 This->pStreams[streamNr].dwLength =
489 streamPos - This->pStreams[streamNr].dwStart;
490 This->sInfo.dwLength -= len;
495 This->sInfo.dwEditCount++;
500 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
501 LONG*plLength,PAVISTREAM*ppResult)
503 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
504 IAVIEditStreamImpl* pEdit;
508 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
510 if (ppResult == NULL)
511 return AVIERR_BADPARAM;
513 if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
514 return AVIERR_BADPARAM;
517 if (*(LPDWORD)plLength > This->sInfo.dwLength)
518 *(LPDWORD)plLength = This->sInfo.dwLength;
519 if (*(LPDWORD)plStart < This->sInfo.dwStart) {
520 *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart;
521 *(LPDWORD)plStart = This->sInfo.dwStart;
523 return AVIERR_BADPARAM;
525 if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
526 *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
529 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
531 return AVIERR_MEMORY;
533 hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength,
534 (PAVISTREAM)&This->iAVIStream,*plStart,
535 *plStart + *plLength);
538 IAVIEditStream_Release((PAVIEDITSTREAM)pEdit);
540 *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
545 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
546 LONG*plLength,PAVISTREAM pSource,
547 LONG lStart,LONG lLength)
549 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
550 AVISTREAMINFOW srcInfo;
551 IEditStreamInternal*pInternal = NULL;
552 IAVIEditStreamImpl *pEdit = NULL;
554 DWORD startPos, endPos, streamNr, nStreams;
557 TRACE("(%p,%p,%p,%p,%ld,%ld)\n",iface,plStart,plLength,
558 pSource,lStart,lLength);
561 return AVIERR_BADHANDLE;
562 if (plStart == NULL || *plStart < 0)
563 return AVIERR_BADPARAM;
564 if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart)
565 return AVIERR_BADPARAM; /* Can't paste with holes */
566 if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo))))
568 if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength)
569 return AVIERR_BADPARAM;
570 if (This->sInfo.fccType == 0) {
571 /* This stream is empty */
572 IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo));
573 This->sInfo.dwStart = *plStart;
574 This->sInfo.dwLength = 0;
576 if (This->sInfo.fccType != srcInfo.fccType)
577 return AVIERR_UNSUPPORTED; /* different stream types */
578 if (lLength == -1) /* Copy the hole stream */
579 lLength = srcInfo.dwLength;
580 if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength)
581 lLength = srcInfo.dwStart + srcInfo.dwLength - lStart;
582 if (lLength + *plStart >= 0x80000000)
583 return AVIERR_MEMORY;
585 /* streamtype specific tests */
586 if (srcInfo.fccType == streamtypeVIDEO) {
589 size = srcInfo.rcFrame.right - srcInfo.rcFrame.left;
590 if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left)
591 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
592 size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top;
593 if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top)
594 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
595 } else if (srcInfo.fccType == streamtypeAUDIO) {
596 if (! AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))
597 return AVIERR_UNSUPPORTED;
599 /* FIXME: streamtypeMIDI and streamtypeTEXT */
600 return AVIERR_UNSUPPORTED;
603 /* try to get an IEditStreamInternal interface */
604 if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal,
605 (LPVOID*)&pInternal))) {
606 pInternal->lpVtbl->GetEditStreamImpl(pInternal, (LPVOID*)&pEdit);
607 pInternal->lpVtbl->Release(pInternal);
610 /* for video must check for change of format */
611 if (This->sInfo.fccType == streamtypeVIDEO) {
612 if (! This->bDecompress) {
613 /* Need to decompress if any of the following conditions matches:
614 * - pSource is an editable stream which decompresses
615 * - the nearest keyframe of pSource isn't lStart
616 * - the nearest keyframe of this stream isn't *plStart
617 * - the format of pSource doesn't match this one
619 if ((pEdit != NULL && pEdit->bDecompress) ||
620 AVIStreamNearestKeyFrame(pSource, lStart) != lStart ||
621 AVIStreamNearestKeyFrame((PAVISTREAM)&This->iAVIStream, *plStart) != *plStart ||
622 (This->nStreams > 0 && !AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))) {
623 /* Use first stream part to get format to convert everything to */
624 AVIFILE_ReadFrame(This, This->pStreams[0].pStream,
625 This->pStreams[0].dwStart);
627 /* Check if we could convert the source streams to the disired format... */
629 if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
630 &startPos, &streamNr, TRUE)))
631 return AVIERR_INTERNAL;
632 for (n = lStart; n < lStart + lLength; streamNr++) {
633 if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL)
634 return AVIERR_BADFORMAT;
635 startPos = pEdit->pStreams[streamNr].dwStart;
636 n += pEdit->pStreams[streamNr].dwLength;
638 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
639 return AVIERR_BADFORMAT;
641 This->bDecompress = TRUE;
642 This->sInfo.fccHandler = 0;
644 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
645 return AVIERR_BADFORMAT; /* Can't convert source to own format */
646 } /* FIXME: something special for the other formats? */
648 /* Make sure we have enough memory for parts */
652 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
653 &endPos, &nLastStream, TRUE);
654 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
655 &startPos, &streamNr, FALSE);
656 if (nLastStream == streamNr)
659 nStreams = nLastStream - streamNr;
662 if (This->nStreams + nStreams + 1 > This->nTableSize) {
663 n = This->nStreams + nStreams + 33;
666 GlobalReAllocPtr(This->pStreams, n * sizeof(EditStreamTable), GMEM_SHARE|GHND);
667 if (This->pStreams == NULL)
668 return AVIERR_MEMORY;
669 This->nTableSize = n;
672 if (plLength != NULL)
675 /* now do the real work */
676 if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) {
677 AVIFILE_FindStreamInTable(This, *plStart, &pStream,
678 &startPos, &streamNr, FALSE);
679 if (startPos != This->pStreams[streamNr].dwStart) {
680 /* split stream streamNr at startPos */
681 memmove(This->pStreams + streamNr + nStreams + 1,
682 This->pStreams + streamNr,
683 (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable));
685 This->pStreams[streamNr + 2].dwLength =
686 EditStreamEnd(This, streamNr + 2) - startPos;
687 This->pStreams[streamNr + 2].dwStart = startPos;
688 This->pStreams[streamNr].dwLength =
689 startPos - This->pStreams[streamNr].dwStart;
690 IAVIStream_AddRef(This->pStreams[streamNr].pStream);
693 /* insert before stream at streamNr */
694 memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
695 (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
697 } else /* append the streams */
698 streamNr = This->nStreams;
701 /* insert the parts of the editable stream instead of itself */
702 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
703 &endPos, NULL, FALSE);
704 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE);
706 memcpy(This->pStreams + streamNr, pEdit->pStreams + n,
707 nStreams * sizeof(EditStreamTable));
708 if (This->pStreams[streamNr].dwStart < startPos) {
709 This->pStreams[streamNr].dwLength =
710 EditStreamEnd(This, streamNr) - startPos;
711 This->pStreams[streamNr].dwStart = startPos;
713 if (endPos < EditStreamEnd(This, streamNr + nStreams))
714 This->pStreams[streamNr + nStreams].dwLength =
715 endPos - This->pStreams[streamNr + nStreams].dwStart;
717 /* a simple stream */
718 This->pStreams[streamNr].pStream = pSource;
719 This->pStreams[streamNr].dwStart = lStart;
720 This->pStreams[streamNr].dwLength = lLength;
723 for (n = 0; n < nStreams; n++) {
724 IAVIStream_AddRef(This->pStreams[streamNr + n].pStream);
725 if (0 < streamNr + n &&
726 This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) {
727 This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
728 This->sInfo.dwFormatChangeCount++;
731 This->sInfo.dwEditCount++;
732 This->sInfo.dwLength += lLength;
733 This->nStreams += nStreams;
738 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
741 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
742 IAVIEditStreamImpl* pEdit;
745 TRACE("(%p,%p)\n",iface,ppResult);
747 if (ppResult == NULL)
748 return AVIERR_BADPARAM;
751 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
753 return AVIERR_MEMORY;
754 if (This->nStreams > pEdit->nTableSize) {
755 pEdit->pStreams = GlobalReAllocPtr(pEdit->pStreams, This->nStreams * sizeof(EditStreamTable),GMEM_SHARE|GHND);
756 if (pEdit->pStreams == NULL)
757 return AVIERR_MEMORY;
758 pEdit->nTableSize = This->nStreams;
760 pEdit->nStreams = This->nStreams;
761 memcpy(pEdit->pStreams, This->pStreams,
762 This->nStreams * sizeof(EditStreamTable));
763 memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo));
764 for (i = 0; i < This->nStreams; i++) {
765 if (pEdit->pStreams[i].pStream != NULL)
766 IAVIStream_AddRef(pEdit->pStreams[i].pStream);
769 *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
774 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
775 LPAVISTREAMINFOW asi,LONG size)
777 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
779 TRACE("(%p,%p,%ld)\n",iface,asi,size);
781 /* check parameters */
783 return AVIERR_BADPARAM;
784 if (size != sizeof(AVISTREAMINFOW))
785 return AVIERR_BADSIZE;
786 if (asi->dwScale == 0 || asi->dwRate == 0 || (LONG)asi->dwQuality < -1 ||
787 asi->dwQuality > ICQUALITY_HIGH)
790 This->sInfo.wLanguage = asi->wLanguage;
791 This->sInfo.wPriority = asi->wPriority;
792 This->sInfo.dwStart = asi->dwStart;
793 if (asi->dwRate != 0)
794 This->sInfo.dwRate = asi->dwRate;
795 if (asi->dwScale != 0)
796 This->sInfo.dwScale = asi->dwScale;
797 if (asi->dwQuality <= ICQUALITY_HIGH)
798 This->sInfo.dwQuality = ICQUALITY_HIGH;
799 CopyRect(&This->sInfo.rcFrame, &asi->rcFrame);
800 memcpy(&This->sInfo.szName, &asi->szName, sizeof(asi->szName));
801 This->sInfo.dwEditCount++;
806 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
807 REFIID refiid,LPVOID*obj)
809 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
811 assert(This->pae != NULL);
813 return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae,refiid,obj);
816 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface)
818 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
820 assert(This->pae != NULL);
822 return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
825 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface)
827 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
829 assert(This->pae != NULL);
831 return IAVIEditStream_Release((IAVIEditStream*)This->pae);
834 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,
835 LPARAM lParam1,LPARAM lParam2)
837 IAVIEditStreamImpl *This = ((IEditAVIStreamImpl*)iface)->pae;
842 if (This->pStreams == NULL) {
844 GlobalAllocPtr(GMEM_SHARE|GHND, 256 * sizeof(EditStreamTable));
845 if (This->pStreams == NULL)
846 return AVIERR_MEMORY;
847 This->nTableSize = 256;
851 IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
852 IAVIStream_AddRef((PAVISTREAM)lParam1);
853 This->pStreams[0].pStream = (PAVISTREAM)lParam1;
854 This->pStreams[0].dwStart = This->sInfo.dwStart;
855 This->pStreams[0].dwLength = This->sInfo.dwLength;
861 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,
862 AVISTREAMINFOW *psi,LONG size)
864 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
866 TRACE("(%p,%p,%ld)\n",iface,psi,size);
868 assert(This->pae != NULL);
871 return AVIERR_BADPARAM;
873 return AVIERR_BADSIZE;
875 if (This->pae->bDecompress)
876 This->pae->sInfo.fccHandler = 0;
878 memcpy(psi, &This->pae->sInfo, min((DWORD)size, sizeof(This->pae->sInfo)));
880 if ((DWORD)size < sizeof(This->pae->sInfo))
881 return AVIERR_BUFFERTOOSMALL;
885 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
888 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
890 DWORD streamPos, streamNr;
892 TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
894 if (flags & FIND_FROM_START)
895 pos = (LONG)This->sInfo.dwStart;
897 /* outside of stream? */
898 if (pos < (LONG)This->sInfo.dwStart ||
899 (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos)
902 /* map our position to a stream and position in it */
903 if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos,
905 return -1; /* doesn't exist */
907 if (This->bDecompress) {
908 /* only one stream -- format changes only at start */
909 if (flags & FIND_FORMAT)
910 return (flags & FIND_NEXT ? -1 : 0);
912 /* FIXME: map positions back to us */
913 return IAVIStream_FindSample(stream, streamPos, flags);
915 /* assume change of format every frame */
920 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,
921 LPVOID format,LONG*fmtsize)
923 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
924 LPBITMAPINFOHEADER lp;
929 TRACE("(%p,%ld,%p,%p)\n",iface,pos,format,fmtsize);
931 if (fmtsize == NULL || pos < This->sInfo.dwStart ||
932 This->sInfo.dwStart + This->sInfo.dwLength <= pos)
933 return AVIERR_BADPARAM;
935 /* find stream corresponding to position */
936 hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE);
940 if (! This->bDecompress)
941 return IAVIStream_ReadFormat(stream, n, format, fmtsize);
943 lp = (LPBITMAPINFOHEADER)AVIFILE_ReadFrame(This, stream, n);
946 if (lp->biBitCount <= 8) {
947 n = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount);
948 n *= sizeof(RGBQUAD);
953 memcpy(format, lp, min((LONG)n, *fmtsize));
954 hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK);
960 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,
961 LPVOID format,LONG formatsize)
963 TRACE("(%p,%ld,%p,%ld)\n",iface,pos,format,formatsize);
965 return AVIERR_UNSUPPORTED;
968 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
969 LONG samples,LPVOID buffer,
970 LONG buffersize,LONG*bytesread,
973 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
975 DWORD streamPos, streamNr;
976 LONG readBytes, readSamples, count;
979 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p) -- 0x%08lX\n",iface,start,samples,
980 buffer,buffersize,bytesread,samplesread,This->sInfo.fccType);
982 /* check parameters */
983 if (bytesread != NULL)
985 if (samplesread != NULL)
988 return AVIERR_BADSIZE;
989 if ((DWORD)start < This->sInfo.dwStart ||
990 This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
991 return AVIERR_BADPARAM;
993 if (! This->bDecompress) {
994 /* audio like data -- sample-based */
997 return AVIERR_OK; /* nothing at all or already done */
999 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
1000 &streamPos, &streamNr, FALSE)))
1001 return AVIERR_ERROR;
1003 /* limit to end of the stream */
1005 if (streamPos + count > EditStreamEnd(This, streamNr))
1006 count = EditStreamEnd(This, streamNr) - streamPos;
1008 hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize,
1009 &readBytes, &readSamples);
1012 if (readBytes == 0 && readSamples == 0 && count != 0)
1013 return AVIERR_FILEREAD; /* for bad stream implementations */
1015 if (samplesread != NULL)
1016 *samplesread += readSamples;
1017 if (bytesread != NULL)
1018 *bytesread += readBytes;
1019 if (buffer != NULL) {
1020 buffer = ((LPBYTE)buffer)+readBytes;
1021 buffersize -= readBytes;
1025 } while (This->sInfo.dwStart + This->sInfo.dwLength > start);
1027 /* video like data -- frame-based */
1028 LPBITMAPINFOHEADER lp;
1033 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
1034 &streamPos, &streamNr, FALSE)))
1035 return AVIERR_ERROR;
1037 lp = AVIFILE_ReadFrame(This, stream, streamPos);
1039 return AVIERR_ERROR;
1041 if (buffer != NULL) {
1042 /* need size of format to skip */
1043 if (lp->biBitCount <= 8) {
1044 count = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount;
1045 count *= sizeof(RGBQUAD);
1048 count += lp->biSize;
1050 if (buffersize < lp->biSizeImage)
1051 return AVIERR_BUFFERTOOSMALL;
1052 memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage);
1055 if (bytesread != NULL)
1056 *bytesread = lp->biSizeImage;
1057 if (samplesread != NULL)
1064 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
1065 LONG samples,LPVOID buffer,
1066 LONG buffersize,DWORD flags,
1067 LONG*sampwritten,LONG*byteswritten)
1069 TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n",iface,start,samples,buffer,
1070 buffersize,flags,sampwritten,byteswritten);
1072 /* be sure return parameters have correct values */
1073 if (sampwritten != NULL)
1075 if (byteswritten != NULL)
1078 return AVIERR_UNSUPPORTED;
1081 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,
1084 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1086 TRACE("(%p,%ld,%ld)\n",iface,start,samples);
1088 return IAVIEditStream_Cut((IAVIEditStream*)This->pae,&start,&samples,NULL);
1091 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
1092 LPVOID lp,LONG *lpread)
1094 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
1097 TRACE("(%p,0x%08lX,%p,%p)\n",iface,fcc,lp,lpread);
1099 /* check parameters */
1100 if (lp == NULL || lpread == NULL)
1101 return AVIERR_BADPARAM;
1103 /* simply ask every stream and return the first block found */
1104 for (n = 0; n < This->nStreams; n++) {
1105 HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread);
1112 return AVIERR_NODATA;
1115 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
1116 LPVOID lp,LONG size)
1118 TRACE("(%p,0x%08lX,%p,%ld)\n",iface,fcc,lp,size);
1120 return AVIERR_UNSUPPORTED;
1123 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,
1124 AVISTREAMINFOW*info,LONG len)
1126 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1128 TRACE("(%p,%p,%ld)\n",iface,info,len);
1130 return IAVIEditStream_SetInfo((IAVIEditStream*)This->pae,info,len);
1133 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj)
1135 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1137 assert(This->pae != NULL);
1139 return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae, refiid, obj);
1142 static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface)
1144 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1146 assert(This->pae != NULL);
1148 return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
1151 static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface)
1153 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1155 assert(This->pae != NULL);
1157 return IAVIEditStream_Release((IAVIEditStream*)This->pae);
1160 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl)
1162 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1164 TRACE("(%p,%p) -> %p\n", iface, ppimpl, This->pae);
1166 assert(This->pae != NULL);
1167 assert(ppimpl != NULL);
1169 *ppimpl = This->pae;