Fix some DPA functions so they pass the new tests.
[wine/multimedia.git] / dlls / avifil32 / editstream.c
blob091cda8c9b78a66e5a5f73ada9737c7602b4c578
1 /*
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
20 #include <assert.h>
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "wingdi.h"
27 #include "winnls.h"
28 #include "winerror.h"
29 #include "windowsx.h"
30 #include "mmsystem.h"
31 #include "vfw.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 */
43 typedef struct IEditStreamInternal IEditStreamInternal;
45 typedef struct _EditStreamTable {
46 PAVISTREAM pStream; /* stream which contains the data */
47 DWORD dwStart; /* where starts the part which is also our */
48 DWORD dwLength; /* how many is also in this stream */
49 } EditStreamTable;
51 #define INTERFACE IEditStreamInternal
52 DECLARE_INTERFACE_(IEditStreamInternal,IUnknown)
54 /*** IUnknown methods ***/
55 STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
56 STDMETHOD_(ULONG,AddRef)(THIS) PURE;
57 STDMETHOD_(ULONG,Release)(THIS) PURE;
58 /*** IEditStreamInternal methods ***/
59 STDMETHOD(GetEditStreamImpl)(THIS_ LPVOID*) PURE;
61 #undef INTERFACE
63 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
64 (This)->pStreams[streamNr].dwLength)
66 /***********************************************************************/
68 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj);
69 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface);
70 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface);
71 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
72 LONG*plLength,PAVISTREAM*ppResult);
73 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
74 LONG*plLength,PAVISTREAM*ppResult);
75 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
76 LONG*plLength,PAVISTREAM pSource,
77 LONG lStart,LONG lEnd);
78 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
79 PAVISTREAM*ppResult);
80 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
81 LPAVISTREAMINFOW asi,LONG size);
83 static const struct IAVIEditStreamVtbl ieditstream = {
84 IAVIEditStream_fnQueryInterface,
85 IAVIEditStream_fnAddRef,
86 IAVIEditStream_fnRelease,
87 IAVIEditStream_fnCut,
88 IAVIEditStream_fnCopy,
89 IAVIEditStream_fnPaste,
90 IAVIEditStream_fnClone,
91 IAVIEditStream_fnSetInfo
94 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID*obj);
95 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface);
96 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface);
97 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
98 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
99 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
100 LONG flags);
101 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG*formatsize);
102 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
103 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
104 LONG samples,LPVOID buffer,
105 LONG buffersize,LONG*bytesread,
106 LONG*samplesread);
107 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
108 LONG samples,LPVOID buffer,
109 LONG buffersize,DWORD flags,
110 LONG*sampwritten,LONG*byteswritten);
111 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
112 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
113 LPVOID lp,LONG *lpread);
114 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
115 LPVOID lp,LONG size);
116 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
118 static const struct IAVIStreamVtbl ieditstast = {
119 IEditAVIStream_fnQueryInterface,
120 IEditAVIStream_fnAddRef,
121 IEditAVIStream_fnRelease,
122 IEditAVIStream_fnCreate,
123 IEditAVIStream_fnInfo,
124 IEditAVIStream_fnFindSample,
125 IEditAVIStream_fnReadFormat,
126 IEditAVIStream_fnSetFormat,
127 IEditAVIStream_fnRead,
128 IEditAVIStream_fnWrite,
129 IEditAVIStream_fnDelete,
130 IEditAVIStream_fnReadData,
131 IEditAVIStream_fnWriteData,
132 IEditAVIStream_fnSetInfo
135 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj);
136 static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface);
137 static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface);
138 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl);
140 static const struct IEditStreamInternalVtbl ieditstreaminternal = {
141 IEditStreamInternal_fnQueryInterface,
142 IEditStreamInternal_fnAddRef,
143 IEditStreamInternal_fnRelease,
144 IEditStreamInternal_fnGetEditStreamImpl
147 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
149 typedef struct _IEditAVIStreamImpl {
150 /* IUnknown stuff */
151 const IAVIStreamVtbl *lpVtbl;
153 /* IAVIStream stuff */
154 IAVIEditStreamImpl *pae;
155 } IEditAVIStreamImpl;
157 typedef struct _IEditStreamInternalImpl {
158 /* IUnknown stuff */
159 const IEditStreamInternalVtbl *lpVtbl;
161 /* IEditStreamInternal stuff */
162 IAVIEditStreamImpl *pae;
163 } IEditStreamInternalImpl;
165 struct _IAVIEditStreamImpl {
166 /* IUnknown stuff */
167 const IAVIEditStreamVtbl *lpVtbl;
168 LONG ref;
170 /* IAVIEditStream stuff */
171 IEditAVIStreamImpl iAVIStream;
172 IEditStreamInternalImpl iEditStreamInternal;
174 AVISTREAMINFOW sInfo;
176 EditStreamTable *pStreams;
177 DWORD nStreams; /* current fill level of pStreams table */
178 DWORD nTableSize; /* size of pStreams table */
180 BOOL bDecompress;
181 PAVISTREAM pCurStream;
182 PGETFRAME pg; /* IGetFrame for pCurStream */
183 LPBITMAPINFOHEADER lpFrame; /* frame of pCurStream */
186 /***********************************************************************/
188 PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream)
190 IAVIEditStreamImpl *pedit = NULL;
192 pedit = (IAVIEditStreamImpl*)LocalAlloc(LPTR,sizeof(IAVIEditStreamImpl));
193 if (pedit == NULL)
194 return NULL;
196 pedit->lpVtbl = &ieditstream;
197 pedit->iAVIStream.lpVtbl = &ieditstast;
198 pedit->iAVIStream.pae = pedit;
199 pedit->iEditStreamInternal.lpVtbl = &ieditstreaminternal;
200 pedit->iEditStreamInternal.pae = pedit;
201 pedit->ref = 1;
203 IAVIStream_Create((PAVISTREAM)&pedit->iAVIStream,(LPARAM)pstream,0);
205 return (PAVIEDITSTREAM)pedit;
208 static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
209 DWORD pos,PAVISTREAM *ppStream,
210 DWORD* streamPos,
211 DWORD* streamNr,BOOL bFindSample)
213 DWORD n;
215 TRACE("(%p,%lu,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
216 streamNr,bFindSample);
218 if (pos < This->sInfo.dwStart)
219 return AVIERR_BADPARAM;
221 pos -= This->sInfo.dwStart;
222 for (n = 0; n < This->nStreams; n++) {
223 if (pos < This->pStreams[n].dwLength) {
224 *ppStream = This->pStreams[n].pStream;
225 *streamPos = This->pStreams[n].dwStart + pos;
226 if (streamNr != NULL)
227 *streamNr = n;
229 return AVIERR_OK;
231 pos -= This->pStreams[n].dwLength;
233 if (pos == 0 && bFindSample) {
234 *ppStream = This->pStreams[--n].pStream;
235 *streamPos = EditStreamEnd(This, n);
236 if (streamNr != NULL)
237 *streamNr = n;
239 TRACE(" -- pos=0 && b=1 -> (%p,%lu,%lu)\n",*ppStream, *streamPos, n);
240 return AVIERR_OK;
241 } else {
242 *ppStream = NULL;
243 *streamPos = 0;
244 if (streamNr != NULL)
245 *streamNr = 0;
247 TRACE(" -> ERROR (NULL,0,0)\n");
248 return AVIERR_BADPARAM;
252 static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
253 PAVISTREAM pstream, LONG pos)
255 PGETFRAME pg;
257 TRACE("(%p,%p,%ld)\n",This,pstream,pos);
259 if (pstream == NULL)
260 return NULL;
262 /* if stream changes make sure that only palette changes */
263 if (This->pCurStream != pstream) {
264 pg = AVIStreamGetFrameOpen(pstream, NULL);
265 if (pg == NULL)
266 return NULL;
267 if (This->pg != NULL) {
268 if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1)) {
269 AVIStreamGetFrameClose(pg);
270 ERR(": IGetFrame_SetFormat failed\n");
271 return NULL;
273 AVIStreamGetFrameClose(This->pg);
275 This->pg = pg;
276 This->pCurStream = pstream;
279 /* now get the decompressed frame */
280 This->lpFrame = AVIStreamGetFrame(This->pg, pos);
281 if (This->lpFrame != NULL)
282 This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage;
284 return This->lpFrame;
287 static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
289 assert(This != NULL);
290 assert(nr < This->nStreams);
292 /* remove part nr */
293 IAVIStream_Release(This->pStreams[nr].pStream);
294 This->nStreams--;
295 if (This->nStreams - nr > 0) {
296 memmove(This->pStreams + nr, This->pStreams + nr + 1,
297 (This->nStreams - nr) * sizeof(EditStreamTable));
299 This->pStreams[This->nStreams].pStream = NULL;
300 This->pStreams[This->nStreams].dwStart = 0;
301 This->pStreams[This->nStreams].dwLength = 0;
303 /* try to merge the part before the deleted one and the one after it */
304 if (0 < nr && 0 < This->nStreams &&
305 This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) {
306 if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) {
307 This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength;
308 return AVIFILE_RemoveStream(This, nr);
312 return AVIERR_OK;
315 static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
317 LPVOID fmt1 = NULL, fmt2 = NULL;
318 LONG size1, size2, start1, start2;
319 BOOL status = FALSE;
321 assert(avi1 != NULL && avi2 != NULL);
323 /* get stream starts and check format sizes */
324 start1 = AVIStreamStart(avi1);
325 start2 = AVIStreamStart(avi2);
326 if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
327 return FALSE;
328 if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
329 return FALSE;
330 if (size1 != size2)
331 return FALSE;
333 /* sizes match, now get formats and compare them */
334 fmt1 = GlobalAllocPtr(GHND, size1);
335 if (fmt1 == NULL)
336 return FALSE;
337 if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
338 fmt2 = GlobalAllocPtr(GHND, size1);
339 if (fmt2 != NULL) {
340 if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
341 status = (memcmp(fmt1, fmt2, size1) == 0);
345 if (fmt2 != NULL)
346 GlobalFreePtr(fmt2);
347 GlobalFreePtr(fmt1);
349 return status;
352 /***********************************************************************/
354 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
356 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
358 TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
360 if (IsEqualGUID(&IID_IUnknown, refiid) ||
361 IsEqualGUID(&IID_IAVIEditStream, refiid)) {
362 *obj = iface;
363 IAVIEditStream_AddRef(iface);
365 return S_OK;
366 } else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
367 *obj = &This->iAVIStream;
368 IAVIEditStream_AddRef(iface);
370 return S_OK;
371 } else if (IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
372 *obj = &This->iEditStreamInternal;
373 IAVIEditStream_AddRef(iface);
375 return S_OK;
378 return OLE_E_ENUM_NOMORE;
381 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
383 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
384 ULONG ref = InterlockedIncrement(&This->ref);
386 TRACE("(%p) -> %ld\n", iface, ref);
388 return ref;
391 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
393 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
394 DWORD i;
395 ULONG ref = InterlockedDecrement(&This->ref);
397 TRACE("(%p) -> %ld\n", iface, ref);
399 if (!ref) {
400 /* release memory */
401 if (This->pg != NULL)
402 AVIStreamGetFrameClose(This->pg);
403 if (This->pStreams != NULL) {
404 for (i = 0; i < This->nStreams; i++) {
405 if (This->pStreams[i].pStream != NULL)
406 IAVIStream_Release(This->pStreams[i].pStream);
408 GlobalFreePtr(This->pStreams);
411 LocalFree((HLOCAL)This);
412 return 0;
414 return ref;
417 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
418 LONG*plLength,PAVISTREAM*ppResult)
420 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
421 PAVISTREAM stream;
422 DWORD start, len, streamPos, streamNr;
423 HRESULT hr;
425 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
427 if (ppResult != NULL)
428 *ppResult = NULL;
429 if (plStart == NULL || plLength == NULL || *plStart < 0)
430 return AVIERR_BADPARAM;
432 /* if asked for cutted part copy it before deleting */
433 if (ppResult != NULL) {
434 hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
435 if (FAILED(hr))
436 return hr;
439 start = *plStart;
440 len = *plLength;
442 /* now delete the requested part */
443 while (len > 0) {
444 hr = AVIFILE_FindStreamInTable(This, start, &stream,
445 &streamPos, &streamNr, FALSE);
446 if (FAILED(hr))
447 return hr;
448 if (This->pStreams[streamNr].dwStart == streamPos) {
449 /* deleting from start of part */
450 if (len < This->pStreams[streamNr].dwLength) {
451 start += len;
452 This->pStreams[streamNr].dwStart += len;
453 This->pStreams[streamNr].dwLength -= len;
454 This->sInfo.dwLength -= len;
455 len = 0;
457 /* we must return decompressed data now */
458 This->bDecompress = TRUE;
459 } else {
460 /* deleting hole part */
461 len -= This->pStreams[streamNr].dwLength;
462 AVIFILE_RemoveStream(This,streamNr);
464 } else if (EditStreamEnd(This, streamNr) <= streamPos + len) {
465 /* deleting at end of a part */
466 DWORD count = EditStreamEnd(This, streamNr) - streamPos;
467 This->sInfo.dwLength -= count;
468 len -= count;
469 This->pStreams[streamNr].dwLength =
470 streamPos - This->pStreams[streamNr].dwStart;
471 } else {
472 /* splitting */
473 if (This->nStreams + 1 >= This->nTableSize) {
474 This->pStreams =
475 GlobalReAllocPtr(This->pStreams, (This->nTableSize + 32) * sizeof(EditStreamTable), GMEM_SHARE|GHND);
476 if (This->pStreams == NULL)
477 return AVIERR_MEMORY;
478 This->nTableSize += 32;
480 memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
481 (This->nStreams - streamNr) * sizeof(EditStreamTable));
482 This->nStreams++;
484 IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream);
485 This->pStreams[streamNr + 1].dwStart = streamPos + len;
486 This->pStreams[streamNr + 1].dwLength =
487 EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart;
489 This->pStreams[streamNr].dwLength =
490 streamPos - This->pStreams[streamNr].dwStart;
491 This->sInfo.dwLength -= len;
492 len = 0;
496 This->sInfo.dwEditCount++;
498 return AVIERR_OK;
501 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
502 LONG*plLength,PAVISTREAM*ppResult)
504 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
505 IAVIEditStreamImpl* pEdit;
506 HRESULT hr;
507 LONG start = 0;
509 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
511 if (ppResult == NULL)
512 return AVIERR_BADPARAM;
513 *ppResult = NULL;
514 if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
515 return AVIERR_BADPARAM;
517 /* check bounds */
518 if (*(LPDWORD)plLength > This->sInfo.dwLength)
519 *(LPDWORD)plLength = This->sInfo.dwLength;
520 if (*(LPDWORD)plStart < This->sInfo.dwStart) {
521 *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart;
522 *(LPDWORD)plStart = This->sInfo.dwStart;
523 if (*plLength < 0)
524 return AVIERR_BADPARAM;
526 if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
527 *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
528 *(LPDWORD)plStart;
530 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
531 if (pEdit == NULL)
532 return AVIERR_MEMORY;
534 hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength,
535 (PAVISTREAM)&This->iAVIStream,*plStart,
536 *plStart + *plLength);
537 *plStart = start;
538 if (FAILED(hr))
539 IAVIEditStream_Release((PAVIEDITSTREAM)pEdit);
540 else
541 *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
543 return hr;
546 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
547 LONG*plLength,PAVISTREAM pSource,
548 LONG lStart,LONG lLength)
550 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
551 AVISTREAMINFOW srcInfo;
552 IEditStreamInternal*pInternal = NULL;
553 IAVIEditStreamImpl *pEdit = NULL;
554 PAVISTREAM pStream;
555 DWORD startPos, endPos, streamNr, nStreams;
556 LONG n;
558 TRACE("(%p,%p,%p,%p,%ld,%ld)\n",iface,plStart,plLength,
559 pSource,lStart,lLength);
561 if (pSource == NULL)
562 return AVIERR_BADHANDLE;
563 if (plStart == NULL || *plStart < 0)
564 return AVIERR_BADPARAM;
565 if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart)
566 return AVIERR_BADPARAM; /* Can't paste with holes */
567 if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo))))
568 return AVIERR_ERROR;
569 if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength)
570 return AVIERR_BADPARAM;
571 if (This->sInfo.fccType == 0) {
572 /* This stream is empty */
573 IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo));
574 This->sInfo.dwStart = *plStart;
575 This->sInfo.dwLength = 0;
577 if (This->sInfo.fccType != srcInfo.fccType)
578 return AVIERR_UNSUPPORTED; /* different stream types */
579 if (lLength == -1) /* Copy the hole stream */
580 lLength = srcInfo.dwLength;
581 if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength)
582 lLength = srcInfo.dwStart + srcInfo.dwLength - lStart;
583 if (lLength + *plStart >= 0x80000000)
584 return AVIERR_MEMORY;
586 /* streamtype specific tests */
587 if (srcInfo.fccType == streamtypeVIDEO) {
588 LONG size;
590 size = srcInfo.rcFrame.right - srcInfo.rcFrame.left;
591 if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left)
592 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
593 size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top;
594 if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top)
595 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
596 } else if (srcInfo.fccType == streamtypeAUDIO) {
597 if (! AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))
598 return AVIERR_UNSUPPORTED;
599 } else {
600 /* FIXME: streamtypeMIDI and streamtypeTEXT */
601 return AVIERR_UNSUPPORTED;
604 /* try to get an IEditStreamInternal interface */
605 if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal,
606 (LPVOID*)&pInternal))) {
607 pInternal->lpVtbl->GetEditStreamImpl(pInternal, (LPVOID*)&pEdit);
608 pInternal->lpVtbl->Release(pInternal);
611 /* for video must check for change of format */
612 if (This->sInfo.fccType == streamtypeVIDEO) {
613 if (! This->bDecompress) {
614 /* Need to decompress if any of the following conditions matches:
615 * - pSource is an editable stream which decompresses
616 * - the nearest keyframe of pSource isn't lStart
617 * - the nearest keyframe of this stream isn't *plStart
618 * - the format of pSource doesn't match this one
620 if ((pEdit != NULL && pEdit->bDecompress) ||
621 AVIStreamNearestKeyFrame(pSource, lStart) != lStart ||
622 AVIStreamNearestKeyFrame((PAVISTREAM)&This->iAVIStream, *plStart) != *plStart ||
623 (This->nStreams > 0 && !AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))) {
624 /* Use first stream part to get format to convert everything to */
625 AVIFILE_ReadFrame(This, This->pStreams[0].pStream,
626 This->pStreams[0].dwStart);
628 /* Check if we could convert the source streams to the disired format... */
629 if (pEdit != NULL) {
630 if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
631 &startPos, &streamNr, TRUE)))
632 return AVIERR_INTERNAL;
633 for (n = lStart; n < lStart + lLength; streamNr++) {
634 if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL)
635 return AVIERR_BADFORMAT;
636 startPos = pEdit->pStreams[streamNr].dwStart;
637 n += pEdit->pStreams[streamNr].dwLength;
639 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
640 return AVIERR_BADFORMAT;
642 This->bDecompress = TRUE;
643 This->sInfo.fccHandler = 0;
645 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
646 return AVIERR_BADFORMAT; /* Can't convert source to own format */
647 } /* FIXME: something special for the other formats? */
649 /* Make sure we have enough memory for parts */
650 if (pEdit != NULL) {
651 DWORD nLastStream;
653 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
654 &endPos, &nLastStream, TRUE);
655 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
656 &startPos, &streamNr, FALSE);
657 if (nLastStream == streamNr)
658 nLastStream++;
660 nStreams = nLastStream - streamNr;
661 } else
662 nStreams = 1;
663 if (This->nStreams + nStreams + 1 > This->nTableSize) {
664 n = This->nStreams + nStreams + 33;
666 This->pStreams =
667 GlobalReAllocPtr(This->pStreams, n * sizeof(EditStreamTable), GMEM_SHARE|GHND);
668 if (This->pStreams == NULL)
669 return AVIERR_MEMORY;
670 This->nTableSize = n;
673 if (plLength != NULL)
674 *plLength = lLength;
676 /* now do the real work */
677 if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) {
678 AVIFILE_FindStreamInTable(This, *plStart, &pStream,
679 &startPos, &streamNr, FALSE);
680 if (startPos != This->pStreams[streamNr].dwStart) {
681 /* split stream streamNr at startPos */
682 memmove(This->pStreams + streamNr + nStreams + 1,
683 This->pStreams + streamNr,
684 (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable));
686 This->pStreams[streamNr + 2].dwLength =
687 EditStreamEnd(This, streamNr + 2) - startPos;
688 This->pStreams[streamNr + 2].dwStart = startPos;
689 This->pStreams[streamNr].dwLength =
690 startPos - This->pStreams[streamNr].dwStart;
691 IAVIStream_AddRef(This->pStreams[streamNr].pStream);
692 streamNr++;
693 } else {
694 /* insert before stream at streamNr */
695 memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
696 (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
698 } else /* append the streams */
699 streamNr = This->nStreams;
701 if (pEdit != NULL) {
702 /* insert the parts of the editable stream instead of itself */
703 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
704 &endPos, NULL, FALSE);
705 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE);
707 memcpy(This->pStreams + streamNr, pEdit->pStreams + n,
708 nStreams * sizeof(EditStreamTable));
709 if (This->pStreams[streamNr].dwStart < startPos) {
710 This->pStreams[streamNr].dwLength =
711 EditStreamEnd(This, streamNr) - startPos;
712 This->pStreams[streamNr].dwStart = startPos;
714 if (endPos < EditStreamEnd(This, streamNr + nStreams))
715 This->pStreams[streamNr + nStreams].dwLength =
716 endPos - This->pStreams[streamNr + nStreams].dwStart;
717 } else {
718 /* a simple stream */
719 This->pStreams[streamNr].pStream = pSource;
720 This->pStreams[streamNr].dwStart = lStart;
721 This->pStreams[streamNr].dwLength = lLength;
724 for (n = 0; n < nStreams; n++) {
725 IAVIStream_AddRef(This->pStreams[streamNr + n].pStream);
726 if (0 < streamNr + n &&
727 This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) {
728 This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
729 This->sInfo.dwFormatChangeCount++;
732 This->sInfo.dwEditCount++;
733 This->sInfo.dwLength += lLength;
734 This->nStreams += nStreams;
736 return AVIERR_OK;
739 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
740 PAVISTREAM*ppResult)
742 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
743 IAVIEditStreamImpl* pEdit;
744 DWORD i;
746 TRACE("(%p,%p)\n",iface,ppResult);
748 if (ppResult == NULL)
749 return AVIERR_BADPARAM;
750 *ppResult = NULL;
752 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
753 if (pEdit == NULL)
754 return AVIERR_MEMORY;
755 if (This->nStreams > pEdit->nTableSize) {
756 pEdit->pStreams = GlobalReAllocPtr(pEdit->pStreams, This->nStreams * sizeof(EditStreamTable),GMEM_SHARE|GHND);
757 if (pEdit->pStreams == NULL)
758 return AVIERR_MEMORY;
759 pEdit->nTableSize = This->nStreams;
761 pEdit->nStreams = This->nStreams;
762 memcpy(pEdit->pStreams, This->pStreams,
763 This->nStreams * sizeof(EditStreamTable));
764 memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo));
765 for (i = 0; i < This->nStreams; i++) {
766 if (pEdit->pStreams[i].pStream != NULL)
767 IAVIStream_AddRef(pEdit->pStreams[i].pStream);
770 *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
772 return AVIERR_OK;
775 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
776 LPAVISTREAMINFOW asi,LONG size)
778 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
780 TRACE("(%p,%p,%ld)\n",iface,asi,size);
782 /* check parameters */
783 if (asi == NULL)
784 return AVIERR_BADPARAM;
785 if (size != sizeof(AVISTREAMINFOW))
786 return AVIERR_BADSIZE;
787 if (asi->dwScale == 0 || asi->dwRate == 0 || (LONG)asi->dwQuality < -1 ||
788 asi->dwQuality > ICQUALITY_HIGH)
789 return AVIERR_ERROR;
791 This->sInfo.wLanguage = asi->wLanguage;
792 This->sInfo.wPriority = asi->wPriority;
793 This->sInfo.dwStart = asi->dwStart;
794 if (asi->dwRate != 0)
795 This->sInfo.dwRate = asi->dwRate;
796 if (asi->dwScale != 0)
797 This->sInfo.dwScale = asi->dwScale;
798 if (asi->dwQuality <= ICQUALITY_HIGH)
799 This->sInfo.dwQuality = ICQUALITY_HIGH;
800 CopyRect(&This->sInfo.rcFrame, &asi->rcFrame);
801 memcpy(&This->sInfo.szName, &asi->szName, sizeof(asi->szName));
802 This->sInfo.dwEditCount++;
804 return AVIERR_OK;
807 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
808 REFIID refiid,LPVOID*obj)
810 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
812 assert(This->pae != NULL);
814 return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae,refiid,obj);
817 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface)
819 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
821 assert(This->pae != NULL);
823 return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
826 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface)
828 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
830 assert(This->pae != NULL);
832 return IAVIEditStream_Release((IAVIEditStream*)This->pae);
835 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,
836 LPARAM lParam1,LPARAM lParam2)
838 IAVIEditStreamImpl *This = ((IEditAVIStreamImpl*)iface)->pae;
840 if (lParam2 != 0)
841 return AVIERR_ERROR;
843 if (This->pStreams == NULL) {
844 This->pStreams =
845 GlobalAllocPtr(GMEM_SHARE|GHND, 256 * sizeof(EditStreamTable));
846 if (This->pStreams == NULL)
847 return AVIERR_MEMORY;
848 This->nTableSize = 256;
851 if (lParam1 != 0) {
852 IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
853 IAVIStream_AddRef((PAVISTREAM)lParam1);
854 This->pStreams[0].pStream = (PAVISTREAM)lParam1;
855 This->pStreams[0].dwStart = This->sInfo.dwStart;
856 This->pStreams[0].dwLength = This->sInfo.dwLength;
857 This->nStreams = 1;
859 return AVIERR_OK;
862 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,
863 AVISTREAMINFOW *psi,LONG size)
865 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
867 TRACE("(%p,%p,%ld)\n",iface,psi,size);
869 assert(This->pae != NULL);
871 if (psi == NULL)
872 return AVIERR_BADPARAM;
873 if (size < 0)
874 return AVIERR_BADSIZE;
876 if (This->pae->bDecompress)
877 This->pae->sInfo.fccHandler = 0;
879 memcpy(psi, &This->pae->sInfo, min((DWORD)size, sizeof(This->pae->sInfo)));
881 if ((DWORD)size < sizeof(This->pae->sInfo))
882 return AVIERR_BUFFERTOOSMALL;
883 return AVIERR_OK;
886 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
887 LONG flags)
889 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
890 PAVISTREAM stream;
891 DWORD streamPos, streamNr;
893 TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
895 if (flags & FIND_FROM_START)
896 pos = (LONG)This->sInfo.dwStart;
898 /* outside of stream? */
899 if (pos < (LONG)This->sInfo.dwStart ||
900 (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos)
901 return -1;
903 /* map our position to a stream and position in it */
904 if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos,
905 &streamNr, TRUE))
906 return -1; /* doesn't exist */
908 if (This->bDecompress) {
909 /* only one stream -- format changes only at start */
910 if (flags & FIND_FORMAT)
911 return (flags & FIND_NEXT ? -1 : 0);
913 /* FIXME: map positions back to us */
914 return IAVIStream_FindSample(stream, streamPos, flags);
915 } else {
916 /* assume change of format every frame */
917 return pos;
921 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,
922 LPVOID format,LONG*fmtsize)
924 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
925 LPBITMAPINFOHEADER lp;
926 PAVISTREAM stream;
927 DWORD n;
928 HRESULT hr;
930 TRACE("(%p,%ld,%p,%p)\n",iface,pos,format,fmtsize);
932 if (fmtsize == NULL || pos < This->sInfo.dwStart ||
933 This->sInfo.dwStart + This->sInfo.dwLength <= pos)
934 return AVIERR_BADPARAM;
936 /* find stream corresponding to position */
937 hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE);
938 if (FAILED(hr))
939 return hr;
941 if (! This->bDecompress)
942 return IAVIStream_ReadFormat(stream, n, format, fmtsize);
944 lp = (LPBITMAPINFOHEADER)AVIFILE_ReadFrame(This, stream, n);
945 if (lp == NULL)
946 return AVIERR_ERROR;
947 if (lp->biBitCount <= 8) {
948 n = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount);
949 n *= sizeof(RGBQUAD);
950 } else
951 n = 0;
952 n += lp->biSize;
954 memcpy(format, lp, min((LONG)n, *fmtsize));
955 hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK);
956 *fmtsize = n;
958 return hr;
961 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,
962 LPVOID format,LONG formatsize)
964 TRACE("(%p,%ld,%p,%ld)\n",iface,pos,format,formatsize);
966 return AVIERR_UNSUPPORTED;
969 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
970 LONG samples,LPVOID buffer,
971 LONG buffersize,LONG*bytesread,
972 LONG*samplesread)
974 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
975 PAVISTREAM stream;
976 DWORD streamPos, streamNr;
977 LONG readBytes, readSamples, count;
978 HRESULT hr;
980 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p) -- 0x%08lX\n",iface,start,samples,
981 buffer,buffersize,bytesread,samplesread,This->sInfo.fccType);
983 /* check parameters */
984 if (bytesread != NULL)
985 *bytesread = 0;
986 if (samplesread != NULL)
987 *samplesread = 0;
988 if (buffersize < 0)
989 return AVIERR_BADSIZE;
990 if ((DWORD)start < This->sInfo.dwStart ||
991 This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
992 return AVIERR_BADPARAM;
994 if (! This->bDecompress) {
995 /* audio like data -- sample-based */
996 do {
997 if (samples == 0)
998 return AVIERR_OK; /* nothing at all or already done */
1000 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
1001 &streamPos, &streamNr, FALSE)))
1002 return AVIERR_ERROR;
1004 /* limit to end of the stream */
1005 count = samples;
1006 if (streamPos + count > EditStreamEnd(This, streamNr))
1007 count = EditStreamEnd(This, streamNr) - streamPos;
1009 hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize,
1010 &readBytes, &readSamples);
1011 if (FAILED(hr))
1012 return hr;
1013 if (readBytes == 0 && readSamples == 0 && count != 0)
1014 return AVIERR_FILEREAD; /* for bad stream implementations */
1016 if (samplesread != NULL)
1017 *samplesread += readSamples;
1018 if (bytesread != NULL)
1019 *bytesread += readBytes;
1020 if (buffer != NULL) {
1021 buffer = ((LPBYTE)buffer)+readBytes;
1022 buffersize -= readBytes;
1024 start += count;
1025 samples -= count;
1026 } while (This->sInfo.dwStart + This->sInfo.dwLength > start);
1027 } else {
1028 /* video like data -- frame-based */
1029 LPBITMAPINFOHEADER lp;
1031 if (samples == 0)
1032 return AVIERR_OK;
1034 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
1035 &streamPos, &streamNr, FALSE)))
1036 return AVIERR_ERROR;
1038 lp = AVIFILE_ReadFrame(This, stream, streamPos);
1039 if (lp == NULL)
1040 return AVIERR_ERROR;
1042 if (buffer != NULL) {
1043 /* need size of format to skip */
1044 if (lp->biBitCount <= 8) {
1045 count = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount;
1046 count *= sizeof(RGBQUAD);
1047 } else
1048 count = 0;
1049 count += lp->biSize;
1051 if (buffersize < lp->biSizeImage)
1052 return AVIERR_BUFFERTOOSMALL;
1053 memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage);
1056 if (bytesread != NULL)
1057 *bytesread = lp->biSizeImage;
1058 if (samplesread != NULL)
1059 *samplesread = 1;
1062 return AVIERR_OK;
1065 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
1066 LONG samples,LPVOID buffer,
1067 LONG buffersize,DWORD flags,
1068 LONG*sampwritten,LONG*byteswritten)
1070 TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n",iface,start,samples,buffer,
1071 buffersize,flags,sampwritten,byteswritten);
1073 /* be sure return parameters have correct values */
1074 if (sampwritten != NULL)
1075 *sampwritten = 0;
1076 if (byteswritten != NULL)
1077 *byteswritten = 0;
1079 return AVIERR_UNSUPPORTED;
1082 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,
1083 LONG samples)
1085 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1087 TRACE("(%p,%ld,%ld)\n",iface,start,samples);
1089 return IAVIEditStream_Cut((IAVIEditStream*)This->pae,&start,&samples,NULL);
1092 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
1093 LPVOID lp,LONG *lpread)
1095 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
1096 DWORD n;
1098 TRACE("(%p,0x%08lX,%p,%p)\n",iface,fcc,lp,lpread);
1100 /* check parameters */
1101 if (lp == NULL || lpread == NULL)
1102 return AVIERR_BADPARAM;
1104 /* simply ask every stream and return the first block found */
1105 for (n = 0; n < This->nStreams; n++) {
1106 HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread);
1108 if (SUCCEEDED(hr))
1109 return hr;
1112 *lpread = 0;
1113 return AVIERR_NODATA;
1116 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
1117 LPVOID lp,LONG size)
1119 TRACE("(%p,0x%08lX,%p,%ld)\n",iface,fcc,lp,size);
1121 return AVIERR_UNSUPPORTED;
1124 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,
1125 AVISTREAMINFOW*info,LONG len)
1127 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1129 TRACE("(%p,%p,%ld)\n",iface,info,len);
1131 return IAVIEditStream_SetInfo((IAVIEditStream*)This->pae,info,len);
1134 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj)
1136 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1138 assert(This->pae != NULL);
1140 return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae, refiid, obj);
1143 static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface)
1145 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1147 assert(This->pae != NULL);
1149 return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
1152 static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface)
1154 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1156 assert(This->pae != NULL);
1158 return IAVIEditStream_Release((IAVIEditStream*)This->pae);
1161 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl)
1163 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1165 TRACE("(%p,%p) -> %p\n", iface, ppimpl, This->pae);
1167 assert(This->pae != NULL);
1168 assert(ppimpl != NULL);
1170 *ppimpl = This->pae;
1171 return AVIERR_OK;