Use Interlocked* functions in AddRef and Release.
[wine.git] / dlls / avifil32 / editstream.c
blob4a974a67c6bfa248a494a2d5abf37209684f4995
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 #define IEditStreamInternal_METHODS \
53 IUnknown_METHODS \
54 STDMETHOD(GetEditStreamImpl)(THIS_ LPVOID*) PURE;
55 DECLARE_INTERFACE_(IEditStreamInternal, IUnknown) { IEditStreamInternal_METHODS };
56 #undef INTERFACE
58 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
59 (This)->pStreams[streamNr].dwLength)
61 /***********************************************************************/
63 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj);
64 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface);
65 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface);
66 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
67 LONG*plLength,PAVISTREAM*ppResult);
68 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
69 LONG*plLength,PAVISTREAM*ppResult);
70 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
71 LONG*plLength,PAVISTREAM pSource,
72 LONG lStart,LONG lEnd);
73 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
74 PAVISTREAM*ppResult);
75 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
76 LPAVISTREAMINFOW asi,LONG size);
78 struct IAVIEditStreamVtbl ieditstream = {
79 IAVIEditStream_fnQueryInterface,
80 IAVIEditStream_fnAddRef,
81 IAVIEditStream_fnRelease,
82 IAVIEditStream_fnCut,
83 IAVIEditStream_fnCopy,
84 IAVIEditStream_fnPaste,
85 IAVIEditStream_fnClone,
86 IAVIEditStream_fnSetInfo
89 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID*obj);
90 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface);
91 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface);
92 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
93 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
94 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
95 LONG flags);
96 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG*formatsize);
97 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
98 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
99 LONG samples,LPVOID buffer,
100 LONG buffersize,LONG*bytesread,
101 LONG*samplesread);
102 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
103 LONG samples,LPVOID buffer,
104 LONG buffersize,DWORD flags,
105 LONG*sampwritten,LONG*byteswritten);
106 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
107 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
108 LPVOID lp,LONG *lpread);
109 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
110 LPVOID lp,LONG size);
111 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
113 struct IAVIStreamVtbl ieditstast = {
114 IEditAVIStream_fnQueryInterface,
115 IEditAVIStream_fnAddRef,
116 IEditAVIStream_fnRelease,
117 IEditAVIStream_fnCreate,
118 IEditAVIStream_fnInfo,
119 IEditAVIStream_fnFindSample,
120 IEditAVIStream_fnReadFormat,
121 IEditAVIStream_fnSetFormat,
122 IEditAVIStream_fnRead,
123 IEditAVIStream_fnWrite,
124 IEditAVIStream_fnDelete,
125 IEditAVIStream_fnReadData,
126 IEditAVIStream_fnWriteData,
127 IEditAVIStream_fnSetInfo
130 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj);
131 static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface);
132 static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface);
133 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl);
135 struct IEditStreamInternalVtbl ieditstreaminternal = {
136 IEditStreamInternal_fnQueryInterface,
137 IEditStreamInternal_fnAddRef,
138 IEditStreamInternal_fnRelease,
139 IEditStreamInternal_fnGetEditStreamImpl
142 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
144 typedef struct _IEditAVIStreamImpl {
145 /* IUnknown stuff */
146 IAVIStreamVtbl *lpVtbl;
148 /* IAVIStream stuff */
149 IAVIEditStreamImpl *pae;
150 } IEditAVIStreamImpl;
152 typedef struct _IEditStreamInternalImpl {
153 /* IUnknown stuff */
154 IEditStreamInternalVtbl *lpVtbl;
156 /* IEditStreamInternal stuff */
157 IAVIEditStreamImpl *pae;
158 } IEditStreamInternalImpl;
160 struct _IAVIEditStreamImpl {
161 /* IUnknown stuff */
162 IAVIEditStreamVtbl *lpVtbl;
163 DWORD ref;
165 /* IAVIEditStream stuff */
166 IEditAVIStreamImpl iAVIStream;
167 IEditStreamInternalImpl iEditStreamInternal;
169 AVISTREAMINFOW sInfo;
171 EditStreamTable *pStreams;
172 DWORD nStreams; /* current fill level of pStreams table */
173 DWORD nTableSize; /* size of pStreams table */
175 BOOL bDecompress;
176 PAVISTREAM pCurStream;
177 PGETFRAME pg; /* IGetFrame for pCurStream */
178 LPBITMAPINFOHEADER lpFrame; /* frame of pCurStream */
181 /***********************************************************************/
183 PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream)
185 IAVIEditStreamImpl *pedit = NULL;
187 pedit = (IAVIEditStreamImpl*)LocalAlloc(LPTR,sizeof(IAVIEditStreamImpl));
188 if (pedit == NULL)
189 return NULL;
191 pedit->lpVtbl = &ieditstream;
192 pedit->iAVIStream.lpVtbl = &ieditstast;
193 pedit->iAVIStream.pae = pedit;
194 pedit->iEditStreamInternal.lpVtbl = &ieditstreaminternal;
195 pedit->iEditStreamInternal.pae = pedit;
196 pedit->ref = 1;
198 IAVIStream_Create((PAVISTREAM)&pedit->iAVIStream,(LPARAM)pstream,0);
200 return (PAVIEDITSTREAM)pedit;
203 static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
204 DWORD pos,PAVISTREAM *ppStream,
205 DWORD* streamPos,
206 DWORD* streamNr,BOOL bFindSample)
208 DWORD n;
210 TRACE("(%p,%lu,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
211 streamNr,bFindSample);
213 if (pos < This->sInfo.dwStart)
214 return AVIERR_BADPARAM;
216 pos -= This->sInfo.dwStart;
217 for (n = 0; n < This->nStreams; n++) {
218 if (pos < This->pStreams[n].dwLength) {
219 *ppStream = This->pStreams[n].pStream;
220 *streamPos = This->pStreams[n].dwStart + pos;
221 if (streamNr != NULL)
222 *streamNr = n;
224 return AVIERR_OK;
226 pos -= This->pStreams[n].dwLength;
228 if (pos == 0 && bFindSample) {
229 *ppStream = This->pStreams[--n].pStream;
230 *streamPos = EditStreamEnd(This, n);
231 if (streamNr != NULL)
232 *streamNr = n;
234 TRACE(" -- pos=0 && b=1 -> (%p,%lu,%lu)\n",*ppStream, *streamPos, n);
235 return AVIERR_OK;
236 } else {
237 *ppStream = NULL;
238 *streamPos = 0;
239 if (streamNr != NULL)
240 *streamNr = 0;
242 TRACE(" -> ERROR (NULL,0,0)\n");
243 return AVIERR_BADPARAM;
247 static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
248 PAVISTREAM pstream, LONG pos)
250 PGETFRAME pg;
252 TRACE("(%p,%p,%ld)\n",This,pstream,pos);
254 if (pstream == NULL)
255 return NULL;
257 /* if stream changes make sure that only palette changes */
258 if (This->pCurStream != pstream) {
259 pg = AVIStreamGetFrameOpen(pstream, NULL);
260 if (pg == NULL)
261 return NULL;
262 if (This->pg != NULL) {
263 if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1)) {
264 AVIStreamGetFrameClose(pg);
265 ERR(": IGetFrame_SetFormat failed\n");
266 return NULL;
268 AVIStreamGetFrameClose(This->pg);
270 This->pg = pg;
271 This->pCurStream = pstream;
274 /* now get the decompressed frame */
275 This->lpFrame = AVIStreamGetFrame(This->pg, pos);
276 if (This->lpFrame != NULL)
277 This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage;
279 return This->lpFrame;
282 static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
284 assert(This != NULL);
285 assert(nr < This->nStreams);
287 /* remove part nr */
288 IAVIStream_Release(This->pStreams[nr].pStream);
289 This->nStreams--;
290 if (This->nStreams - nr > 0) {
291 memmove(This->pStreams + nr, This->pStreams + nr + 1,
292 (This->nStreams - nr) * sizeof(EditStreamTable));
294 This->pStreams[This->nStreams].pStream = NULL;
295 This->pStreams[This->nStreams].dwStart = 0;
296 This->pStreams[This->nStreams].dwLength = 0;
298 /* try to merge the part before the deleted one and the one after it */
299 if (0 < nr && 0 < This->nStreams &&
300 This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) {
301 if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) {
302 This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength;
303 return AVIFILE_RemoveStream(This, nr);
307 return AVIERR_OK;
310 static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
312 LPVOID fmt1 = NULL, fmt2 = NULL;
313 LONG size1, size2, start1, start2;
314 BOOL status = FALSE;
316 assert(avi1 != NULL && avi2 != NULL);
318 /* get stream starts and check format sizes */
319 start1 = AVIStreamStart(avi1);
320 start2 = AVIStreamStart(avi2);
321 if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
322 return FALSE;
323 if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
324 return FALSE;
325 if (size1 != size2)
326 return FALSE;
328 /* sizes match, now get formats and compare them */
329 fmt1 = GlobalAllocPtr(GHND, size1);
330 if (fmt1 == NULL)
331 return FALSE;
332 if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
333 fmt2 = GlobalAllocPtr(GHND, size1);
334 if (fmt2 != NULL) {
335 if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
336 status = (memcmp(fmt1, fmt2, size1) == 0);
340 if (fmt2 != NULL)
341 GlobalFreePtr(fmt2);
342 GlobalFreePtr(fmt1);
344 return status;
347 /***********************************************************************/
349 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
351 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
353 TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
355 if (IsEqualGUID(&IID_IUnknown, refiid) ||
356 IsEqualGUID(&IID_IAVIEditStream, refiid)) {
357 *obj = iface;
358 IAVIEditStream_AddRef(iface);
360 return S_OK;
361 } else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
362 *obj = &This->iAVIStream;
363 IAVIEditStream_AddRef(iface);
365 return S_OK;
366 } else if (IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
367 *obj = &This->iEditStreamInternal;
368 IAVIEditStream_AddRef(iface);
370 return S_OK;
373 return OLE_E_ENUM_NOMORE;
376 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
378 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
380 TRACE("(%p) -> %ld\n", iface, This->ref + 1);
381 return ++(This->ref);
384 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
386 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
387 DWORD i;
389 TRACE("(%p) -> %ld\n", iface, This->ref - 1);
391 if (!--(This->ref)) {
392 /* releaase memory */
393 if (This->pg != NULL)
394 AVIStreamGetFrameClose(This->pg);
395 if (This->pStreams != NULL) {
396 for (i = 0; i < This->nStreams; i++) {
397 if (This->pStreams[i].pStream != NULL)
398 IAVIStream_Release(This->pStreams[i].pStream);
400 GlobalFreePtr(This->pStreams);
403 LocalFree((HLOCAL)This);
404 return 0;
406 return This->ref;
409 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
410 LONG*plLength,PAVISTREAM*ppResult)
412 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
413 PAVISTREAM stream;
414 DWORD start, len, streamPos, streamNr;
415 HRESULT hr;
417 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
419 if (ppResult != NULL)
420 *ppResult = NULL;
421 if (plStart == NULL || plLength == NULL || *plStart < 0)
422 return AVIERR_BADPARAM;
424 /* if asked for cutted part copy it before deleting */
425 if (ppResult != NULL) {
426 hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
427 if (FAILED(hr))
428 return hr;
431 start = *plStart;
432 len = *plLength;
434 /* now delete the requested part */
435 while (len > 0) {
436 hr = AVIFILE_FindStreamInTable(This, start, &stream,
437 &streamPos, &streamNr, FALSE);
438 if (FAILED(hr))
439 return hr;
440 if (This->pStreams[streamNr].dwStart == streamPos) {
441 /* deleting from start of part */
442 if (len < This->pStreams[streamNr].dwLength) {
443 start += len;
444 This->pStreams[streamNr].dwStart += len;
445 This->pStreams[streamNr].dwLength -= len;
446 This->sInfo.dwLength -= len;
447 len = 0;
449 /* we must return decompressed data now */
450 This->bDecompress = TRUE;
451 } else {
452 /* deleting hole part */
453 len -= This->pStreams[streamNr].dwLength;
454 AVIFILE_RemoveStream(This,streamNr);
456 } else if (EditStreamEnd(This, streamNr) <= streamPos + len) {
457 /* deleting at end of a part */
458 DWORD count = EditStreamEnd(This, streamNr) - streamPos;
459 This->sInfo.dwLength -= count;
460 len -= count;
461 This->pStreams[streamNr].dwLength =
462 streamPos - This->pStreams[streamNr].dwStart;
463 } else {
464 /* splitting */
465 if (This->nStreams + 1 >= This->nTableSize) {
466 This->pStreams =
467 GlobalReAllocPtr(This->pStreams, (This->nTableSize + 32) * sizeof(EditStreamTable), GMEM_SHARE|GHND);
468 if (This->pStreams == NULL)
469 return AVIERR_MEMORY;
470 This->nTableSize += 32;
472 memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
473 (This->nStreams - streamNr) * sizeof(EditStreamTable));
474 This->nStreams++;
476 IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream);
477 This->pStreams[streamNr + 1].dwStart = streamPos + len;
478 This->pStreams[streamNr + 1].dwLength =
479 EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart;
481 This->pStreams[streamNr].dwLength =
482 streamPos - This->pStreams[streamNr].dwStart;
483 This->sInfo.dwLength -= len;
484 len = 0;
488 This->sInfo.dwEditCount++;
490 return AVIERR_OK;
493 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
494 LONG*plLength,PAVISTREAM*ppResult)
496 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
497 IAVIEditStreamImpl* pEdit;
498 HRESULT hr;
499 LONG start = 0;
501 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
503 if (ppResult == NULL)
504 return AVIERR_BADPARAM;
505 *ppResult = NULL;
506 if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
507 return AVIERR_BADPARAM;
509 /* check bounds */
510 if (*(LPDWORD)plLength > This->sInfo.dwLength)
511 *(LPDWORD)plLength = This->sInfo.dwLength;
512 if (*(LPDWORD)plStart < This->sInfo.dwStart) {
513 *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart;
514 *(LPDWORD)plStart = This->sInfo.dwStart;
515 if (*plLength < 0)
516 return AVIERR_BADPARAM;
518 if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
519 *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
520 *(LPDWORD)plStart;
522 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
523 if (pEdit == NULL)
524 return AVIERR_MEMORY;
526 hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength,
527 (PAVISTREAM)&This->iAVIStream,*plStart,
528 *plStart + *plLength);
529 *plStart = start;
530 if (FAILED(hr))
531 IAVIEditStream_Release((PAVIEDITSTREAM)pEdit);
532 else
533 *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
535 return hr;
538 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
539 LONG*plLength,PAVISTREAM pSource,
540 LONG lStart,LONG lLength)
542 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
543 AVISTREAMINFOW srcInfo;
544 IEditStreamInternal*pInternal = NULL;
545 IAVIEditStreamImpl *pEdit = NULL;
546 PAVISTREAM pStream;
547 DWORD startPos, endPos, streamNr, nStreams;
548 LONG n;
550 TRACE("(%p,%p,%p,%p,%ld,%ld)\n",iface,plStart,plLength,
551 pSource,lStart,lLength);
553 if (pSource == NULL)
554 return AVIERR_BADHANDLE;
555 if (plStart == NULL || *plStart < 0)
556 return AVIERR_BADPARAM;
557 if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart)
558 return AVIERR_BADPARAM; /* Can't paste with holes */
559 if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo))))
560 return AVIERR_ERROR;
561 if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength)
562 return AVIERR_BADPARAM;
563 if (This->sInfo.fccType == 0) {
564 /* This stream is empty */
565 IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo));
566 This->sInfo.dwStart = *plStart;
567 This->sInfo.dwLength = 0;
569 if (This->sInfo.fccType != srcInfo.fccType)
570 return AVIERR_UNSUPPORTED; /* different stream types */
571 if (lLength == -1) /* Copy the hole stream */
572 lLength = srcInfo.dwLength;
573 if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength)
574 lLength = srcInfo.dwStart + srcInfo.dwLength - lStart;
575 if (lLength + *plStart >= 0x80000000)
576 return AVIERR_MEMORY;
578 /* streamtype specific tests */
579 if (srcInfo.fccType == streamtypeVIDEO) {
580 LONG size;
582 size = srcInfo.rcFrame.right - srcInfo.rcFrame.left;
583 if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left)
584 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
585 size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top;
586 if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top)
587 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
588 } else if (srcInfo.fccType == streamtypeAUDIO) {
589 if (! AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))
590 return AVIERR_UNSUPPORTED;
591 } else {
592 /* FIXME: streamtypeMIDI and streamtypeTEXT */
593 return AVIERR_UNSUPPORTED;
596 /* try to get an IEditStreamInternal interface */
597 if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal,
598 (LPVOID*)&pInternal))) {
599 pInternal->lpVtbl->GetEditStreamImpl(pInternal, (LPVOID*)&pEdit);
600 pInternal->lpVtbl->Release(pInternal);
603 /* for video must check for change of format */
604 if (This->sInfo.fccType == streamtypeVIDEO) {
605 if (! This->bDecompress) {
606 /* Need to decompress if any of the following conditions matches:
607 * - pSource is an editable stream which decompresses
608 * - the nearest keyframe of pSource isn't lStart
609 * - the nearest keyframe of this stream isn't *plStart
610 * - the format of pSource doesn't match this one
612 if ((pEdit != NULL && pEdit->bDecompress) ||
613 AVIStreamNearestKeyFrame(pSource, lStart) != lStart ||
614 AVIStreamNearestKeyFrame((PAVISTREAM)&This->iAVIStream, *plStart) != *plStart ||
615 (This->nStreams > 0 && !AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))) {
616 /* Use first stream part to get format to convert everything to */
617 AVIFILE_ReadFrame(This, This->pStreams[0].pStream,
618 This->pStreams[0].dwStart);
620 /* Check if we could convert the source streams to the disired format... */
621 if (pEdit != NULL) {
622 if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
623 &startPos, &streamNr, TRUE)))
624 return AVIERR_INTERNAL;
625 for (n = lStart; n < lStart + lLength; streamNr++) {
626 if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL)
627 return AVIERR_BADFORMAT;
628 startPos = pEdit->pStreams[streamNr].dwStart;
629 n += pEdit->pStreams[streamNr].dwLength;
631 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
632 return AVIERR_BADFORMAT;
634 This->bDecompress = TRUE;
635 This->sInfo.fccHandler = 0;
637 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
638 return AVIERR_BADFORMAT; /* Can't convert source to own format */
639 } /* FIXME: something special for the other formats? */
641 /* Make sure we have enough memory for parts */
642 if (pEdit != NULL) {
643 DWORD nLastStream;
645 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
646 &endPos, &nLastStream, TRUE);
647 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
648 &startPos, &streamNr, FALSE);
649 if (nLastStream == streamNr)
650 nLastStream++;
652 nStreams = nLastStream - streamNr;
653 } else
654 nStreams = 1;
655 if (This->nStreams + nStreams + 1 > This->nTableSize) {
656 n = This->nStreams + nStreams + 33;
658 This->pStreams =
659 GlobalReAllocPtr(This->pStreams, n * sizeof(EditStreamTable), GMEM_SHARE|GHND);
660 if (This->pStreams == NULL)
661 return AVIERR_MEMORY;
662 This->nTableSize = n;
665 if (plLength != NULL)
666 *plLength = lLength;
668 /* now do the real work */
669 if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) {
670 AVIFILE_FindStreamInTable(This, *plStart, &pStream,
671 &startPos, &streamNr, FALSE);
672 if (startPos != This->pStreams[streamNr].dwStart) {
673 /* split stream streamNr at startPos */
674 memmove(This->pStreams + streamNr + nStreams + 1,
675 This->pStreams + streamNr,
676 (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable));
678 This->pStreams[streamNr + 2].dwLength =
679 EditStreamEnd(This, streamNr + 2) - startPos;
680 This->pStreams[streamNr + 2].dwStart = startPos;
681 This->pStreams[streamNr].dwLength =
682 startPos - This->pStreams[streamNr].dwStart;
683 IAVIStream_AddRef(This->pStreams[streamNr].pStream);
684 streamNr++;
685 } else {
686 /* insert before stream at streamNr */
687 memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
688 (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
690 } else /* append the streams */
691 streamNr = This->nStreams;
693 if (pEdit != NULL) {
694 /* insert the parts of the editable stream instead of itself */
695 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
696 &endPos, NULL, FALSE);
697 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE);
699 memcpy(This->pStreams + streamNr, pEdit->pStreams + n,
700 nStreams * sizeof(EditStreamTable));
701 if (This->pStreams[streamNr].dwStart < startPos) {
702 This->pStreams[streamNr].dwLength =
703 EditStreamEnd(This, streamNr) - startPos;
704 This->pStreams[streamNr].dwStart = startPos;
706 if (endPos < EditStreamEnd(This, streamNr + nStreams))
707 This->pStreams[streamNr + nStreams].dwLength =
708 endPos - This->pStreams[streamNr + nStreams].dwStart;
709 } else {
710 /* a simple stream */
711 This->pStreams[streamNr].pStream = pSource;
712 This->pStreams[streamNr].dwStart = lStart;
713 This->pStreams[streamNr].dwLength = lLength;
716 for (n = 0; n < nStreams; n++) {
717 IAVIStream_AddRef(This->pStreams[streamNr + n].pStream);
718 if (0 < streamNr + n &&
719 This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) {
720 This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
721 This->sInfo.dwFormatChangeCount++;
724 This->sInfo.dwEditCount++;
725 This->sInfo.dwLength += lLength;
726 This->nStreams += nStreams;
728 return AVIERR_OK;
731 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
732 PAVISTREAM*ppResult)
734 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
735 IAVIEditStreamImpl* pEdit;
736 DWORD i;
738 TRACE("(%p,%p)\n",iface,ppResult);
740 if (ppResult == NULL)
741 return AVIERR_BADPARAM;
742 *ppResult = NULL;
744 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
745 if (pEdit == NULL)
746 return AVIERR_MEMORY;
747 if (This->nStreams > pEdit->nTableSize) {
748 pEdit->pStreams = GlobalReAllocPtr(pEdit->pStreams, This->nStreams * sizeof(EditStreamTable),GMEM_SHARE|GHND);
749 if (pEdit->pStreams == NULL)
750 return AVIERR_MEMORY;
751 pEdit->nTableSize = This->nStreams;
753 pEdit->nStreams = This->nStreams;
754 memcpy(pEdit->pStreams, This->pStreams,
755 This->nStreams * sizeof(EditStreamTable));
756 memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo));
757 for (i = 0; i < This->nStreams; i++) {
758 if (pEdit->pStreams[i].pStream != NULL)
759 IAVIStream_AddRef(pEdit->pStreams[i].pStream);
762 *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
764 return AVIERR_OK;
767 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
768 LPAVISTREAMINFOW asi,LONG size)
770 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
772 TRACE("(%p,%p,%ld)\n",iface,asi,size);
774 /* check parameters */
775 if (asi == NULL)
776 return AVIERR_BADPARAM;
777 if (size != sizeof(AVISTREAMINFOW))
778 return AVIERR_BADSIZE;
779 if (asi->dwScale == 0 || asi->dwRate == 0 || (LONG)asi->dwQuality < -1 ||
780 asi->dwQuality > ICQUALITY_HIGH)
781 return AVIERR_ERROR;
783 This->sInfo.wLanguage = asi->wLanguage;
784 This->sInfo.wPriority = asi->wPriority;
785 This->sInfo.dwStart = asi->dwStart;
786 if (asi->dwRate != 0)
787 This->sInfo.dwRate = asi->dwRate;
788 if (asi->dwScale != 0)
789 This->sInfo.dwScale = asi->dwScale;
790 if (asi->dwQuality <= ICQUALITY_HIGH)
791 This->sInfo.dwQuality = ICQUALITY_HIGH;
792 CopyRect(&This->sInfo.rcFrame, &asi->rcFrame);
793 memcpy(&This->sInfo.szName, &asi->szName, sizeof(asi->szName));
794 This->sInfo.dwEditCount++;
796 return AVIERR_OK;
799 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
800 REFIID refiid,LPVOID*obj)
802 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
804 assert(This->pae != NULL);
806 return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae,refiid,obj);
809 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface)
811 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
813 assert(This->pae != NULL);
815 return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
818 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface)
820 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
822 assert(This->pae != NULL);
824 return IAVIEditStream_Release((IAVIEditStream*)This->pae);
827 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,
828 LPARAM lParam1,LPARAM lParam2)
830 IAVIEditStreamImpl *This = ((IEditAVIStreamImpl*)iface)->pae;
832 if (lParam2 != 0)
833 return AVIERR_ERROR;
835 if (This->pStreams == NULL) {
836 This->pStreams =
837 GlobalAllocPtr(GMEM_SHARE|GHND, 256 * sizeof(EditStreamTable));
838 if (This->pStreams == NULL)
839 return AVIERR_MEMORY;
840 This->nTableSize = 256;
843 if (lParam1 != 0) {
844 IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
845 IAVIStream_AddRef((PAVISTREAM)lParam1);
846 This->pStreams[0].pStream = (PAVISTREAM)lParam1;
847 This->pStreams[0].dwStart = This->sInfo.dwStart;
848 This->pStreams[0].dwLength = This->sInfo.dwLength;
849 This->nStreams = 1;
851 return AVIERR_OK;
854 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,
855 AVISTREAMINFOW *psi,LONG size)
857 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
859 TRACE("(%p,%p,%ld)\n",iface,psi,size);
861 assert(This->pae != NULL);
863 if (psi == NULL)
864 return AVIERR_BADPARAM;
865 if (size < 0)
866 return AVIERR_BADSIZE;
868 if (This->pae->bDecompress)
869 This->pae->sInfo.fccHandler = 0;
871 memcpy(psi, &This->pae->sInfo, min((DWORD)size, sizeof(This->pae->sInfo)));
873 if ((DWORD)size < sizeof(This->pae->sInfo))
874 return AVIERR_BUFFERTOOSMALL;
875 return AVIERR_OK;
878 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
879 LONG flags)
881 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
882 PAVISTREAM stream;
883 DWORD streamPos, streamNr;
885 TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
887 if (flags & FIND_FROM_START)
888 pos = (LONG)This->sInfo.dwStart;
890 /* outside of stream? */
891 if (pos < (LONG)This->sInfo.dwStart ||
892 (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos)
893 return -1;
895 /* map our position to a stream and position in it */
896 if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos,
897 &streamNr, TRUE))
898 return -1; /* doesn't exist */
900 if (This->bDecompress) {
901 /* only one stream -- format changes only at start */
902 if (flags & FIND_FORMAT)
903 return (flags & FIND_NEXT ? -1 : 0);
905 /* FIXME: map positions back to us */
906 return IAVIStream_FindSample(stream, streamPos, flags);
907 } else {
908 /* assume change of format every frame */
909 return pos;
913 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,
914 LPVOID format,LONG*fmtsize)
916 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
917 LPBITMAPINFOHEADER lp;
918 PAVISTREAM stream;
919 DWORD n;
920 HRESULT hr;
922 TRACE("(%p,%ld,%p,%p)\n",iface,pos,format,fmtsize);
924 if (fmtsize == NULL || pos < This->sInfo.dwStart ||
925 This->sInfo.dwStart + This->sInfo.dwLength <= pos)
926 return AVIERR_BADPARAM;
928 /* find stream corresponding to position */
929 hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE);
930 if (FAILED(hr))
931 return hr;
933 if (! This->bDecompress)
934 return IAVIStream_ReadFormat(stream, n, format, fmtsize);
936 lp = (LPBITMAPINFOHEADER)AVIFILE_ReadFrame(This, stream, n);
937 if (lp == NULL)
938 return AVIERR_ERROR;
939 if (lp->biBitCount <= 8) {
940 n = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount);
941 n *= sizeof(RGBQUAD);
942 } else
943 n = 0;
944 n += lp->biSize;
946 memcpy(format, lp, min((LONG)n, *fmtsize));
947 hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK);
948 *fmtsize = n;
950 return hr;
953 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,
954 LPVOID format,LONG formatsize)
956 TRACE("(%p,%ld,%p,%ld)\n",iface,pos,format,formatsize);
958 return AVIERR_UNSUPPORTED;
961 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
962 LONG samples,LPVOID buffer,
963 LONG buffersize,LONG*bytesread,
964 LONG*samplesread)
966 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
967 PAVISTREAM stream;
968 DWORD streamPos, streamNr;
969 LONG readBytes, readSamples, count;
970 HRESULT hr;
972 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p) -- 0x%08lX\n",iface,start,samples,
973 buffer,buffersize,bytesread,samplesread,This->sInfo.fccType);
975 /* check parameters */
976 if (bytesread != NULL)
977 *bytesread = 0;
978 if (samplesread != NULL)
979 *samplesread = 0;
980 if (buffersize < 0)
981 return AVIERR_BADSIZE;
982 if ((DWORD)start < This->sInfo.dwStart ||
983 This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
984 return AVIERR_BADPARAM;
986 if (! This->bDecompress) {
987 /* audio like data -- sample-based */
988 do {
989 if (samples == 0)
990 return AVIERR_OK; /* nothing at all or already done */
992 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
993 &streamPos, &streamNr, FALSE)))
994 return AVIERR_ERROR;
996 /* limit to end of the stream */
997 count = samples;
998 if (streamPos + count > EditStreamEnd(This, streamNr))
999 count = EditStreamEnd(This, streamNr) - streamPos;
1001 hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize,
1002 &readBytes, &readSamples);
1003 if (FAILED(hr))
1004 return hr;
1005 if (readBytes == 0 && readSamples == 0 && count != 0)
1006 return AVIERR_FILEREAD; /* for bad stream implementations */
1008 if (samplesread != NULL)
1009 *samplesread += readSamples;
1010 if (bytesread != NULL)
1011 *bytesread += readBytes;
1012 if (buffer != NULL) {
1013 buffer = ((LPBYTE)buffer)+readBytes;
1014 buffersize -= readBytes;
1016 start += count;
1017 samples -= count;
1018 } while (This->sInfo.dwStart + This->sInfo.dwLength > start);
1019 } else {
1020 /* video like data -- frame-based */
1021 LPBITMAPINFOHEADER lp;
1023 if (samples == 0)
1024 return AVIERR_OK;
1026 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
1027 &streamPos, &streamNr, FALSE)))
1028 return AVIERR_ERROR;
1030 lp = AVIFILE_ReadFrame(This, stream, streamPos);
1031 if (lp == NULL)
1032 return AVIERR_ERROR;
1034 if (buffer != NULL) {
1035 /* need size of format to skip */
1036 if (lp->biBitCount <= 8) {
1037 count = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount;
1038 count *= sizeof(RGBQUAD);
1039 } else
1040 count = 0;
1041 count += lp->biSize;
1043 if (buffersize < lp->biSizeImage)
1044 return AVIERR_BUFFERTOOSMALL;
1045 memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage);
1048 if (bytesread != NULL)
1049 *bytesread = lp->biSizeImage;
1050 if (samplesread != NULL)
1051 *samplesread = 1;
1054 return AVIERR_OK;
1057 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
1058 LONG samples,LPVOID buffer,
1059 LONG buffersize,DWORD flags,
1060 LONG*sampwritten,LONG*byteswritten)
1062 TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n",iface,start,samples,buffer,
1063 buffersize,flags,sampwritten,byteswritten);
1065 /* be sure return parameters have correct values */
1066 if (sampwritten != NULL)
1067 *sampwritten = 0;
1068 if (byteswritten != NULL)
1069 *byteswritten = 0;
1071 return AVIERR_UNSUPPORTED;
1074 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,
1075 LONG samples)
1077 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1079 TRACE("(%p,%ld,%ld)\n",iface,start,samples);
1081 return IAVIEditStream_Cut((IAVIEditStream*)This->pae,&start,&samples,NULL);
1084 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
1085 LPVOID lp,LONG *lpread)
1087 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
1088 DWORD n;
1090 TRACE("(%p,0x%08lX,%p,%p)\n",iface,fcc,lp,lpread);
1092 /* check parameters */
1093 if (lp == NULL || lpread == NULL)
1094 return AVIERR_BADPARAM;
1096 /* simply ask every stream and return the first block found */
1097 for (n = 0; n < This->nStreams; n++) {
1098 HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread);
1100 if (SUCCEEDED(hr))
1101 return hr;
1104 *lpread = 0;
1105 return AVIERR_NODATA;
1108 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
1109 LPVOID lp,LONG size)
1111 TRACE("(%p,0x%08lX,%p,%ld)\n",iface,fcc,lp,size);
1113 return AVIERR_UNSUPPORTED;
1116 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,
1117 AVISTREAMINFOW*info,LONG len)
1119 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1121 TRACE("(%p,%p,%ld)\n",iface,info,len);
1123 return IAVIEditStream_SetInfo((IAVIEditStream*)This->pae,info,len);
1126 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj)
1128 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1130 assert(This->pae != NULL);
1132 return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae, refiid, obj);
1135 static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface)
1137 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1139 assert(This->pae != NULL);
1141 return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
1144 static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface)
1146 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1148 assert(This->pae != NULL);
1150 return IAVIEditStream_Release((IAVIEditStream*)This->pae);
1153 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl)
1155 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1157 TRACE("(%p,%p) -> %p\n", iface, ppimpl, This->pae);
1159 assert(This->pae != NULL);
1160 assert(ppimpl != NULL);
1162 *ppimpl = This->pae;
1163 return AVIERR_OK;