2 * Copyright 2003 Michael Günnewig
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "avifile_private.h"
31 #include "extrachunk.h"
33 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
38 /***********************************************************************/
40 /* internal interface to get access to table of stream in an editable stream */
42 DEFINE_AVIGUID(IID_IEditStreamInternal, 0x0002000A,0,0);
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 EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
51 (This)->pStreams[streamNr].dwLength)
53 /***********************************************************************/
55 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj);
56 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface);
57 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface);
58 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
59 LONG*plLength,PAVISTREAM*ppResult);
60 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
61 LONG*plLength,PAVISTREAM*ppResult);
62 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
63 LONG*plLength,PAVISTREAM pSource,
64 LONG lStart,LONG lEnd);
65 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
67 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
68 LPAVISTREAMINFOW asi,LONG size);
70 static const struct IAVIEditStreamVtbl ieditstream = {
71 IAVIEditStream_fnQueryInterface,
72 IAVIEditStream_fnAddRef,
73 IAVIEditStream_fnRelease,
75 IAVIEditStream_fnCopy,
76 IAVIEditStream_fnPaste,
77 IAVIEditStream_fnClone,
78 IAVIEditStream_fnSetInfo
81 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID*obj);
82 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface);
83 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface);
84 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
85 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
86 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
88 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG*formatsize);
89 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
90 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
91 LONG samples,LPVOID buffer,
92 LONG buffersize,LONG*bytesread,
94 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
95 LONG samples,LPVOID buffer,
96 LONG buffersize,DWORD flags,
97 LONG*sampwritten,LONG*byteswritten);
98 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
99 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
100 LPVOID lp,LONG *lpread);
101 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
102 LPVOID lp,LONG size);
103 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
105 static const struct IAVIStreamVtbl ieditstast = {
106 IEditAVIStream_fnQueryInterface,
107 IEditAVIStream_fnAddRef,
108 IEditAVIStream_fnRelease,
109 IEditAVIStream_fnCreate,
110 IEditAVIStream_fnInfo,
111 IEditAVIStream_fnFindSample,
112 IEditAVIStream_fnReadFormat,
113 IEditAVIStream_fnSetFormat,
114 IEditAVIStream_fnRead,
115 IEditAVIStream_fnWrite,
116 IEditAVIStream_fnDelete,
117 IEditAVIStream_fnReadData,
118 IEditAVIStream_fnWriteData,
119 IEditAVIStream_fnSetInfo
122 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
124 struct _IAVIEditStreamImpl {
126 const IAVIEditStreamVtbl *lpVtbl;
127 const IAVIStreamVtbl *lpVtblAVIStream;
131 AVISTREAMINFOW sInfo;
133 EditStreamTable *pStreams;
134 DWORD nStreams; /* current fill level of pStreams table */
135 DWORD nTableSize; /* size of pStreams table */
138 PAVISTREAM pCurStream;
139 PGETFRAME pg; /* IGetFrame for pCurStream */
140 LPBITMAPINFOHEADER lpFrame; /* frame of pCurStream */
143 static inline IAVIEditStreamImpl *impl_from_IAVIStream( IAVIStream *iface )
145 return (IAVIEditStreamImpl *)((char*)iface - FIELD_OFFSET(IAVIEditStreamImpl, lpVtblAVIStream));
148 static inline IAVIStream *IAVIStream_from_impl( IAVIEditStreamImpl *impl )
150 return (IAVIStream *)&impl->lpVtblAVIStream;
153 /***********************************************************************/
155 PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream)
157 IAVIEditStreamImpl *pedit = NULL;
159 pedit = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIEditStreamImpl));
163 pedit->lpVtbl = &ieditstream;
164 pedit->lpVtblAVIStream = &ieditstast;
167 IAVIStream_Create( IAVIStream_from_impl( pedit ),(LPARAM)pstream,0);
169 return (PAVIEDITSTREAM)pedit;
172 static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
173 DWORD pos,PAVISTREAM *ppStream,
175 DWORD* streamNr,BOOL bFindSample)
179 TRACE("(%p,%u,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
180 streamNr,bFindSample);
182 if (pos < This->sInfo.dwStart)
183 return AVIERR_BADPARAM;
185 pos -= This->sInfo.dwStart;
186 for (n = 0; n < This->nStreams; n++) {
187 if (pos < This->pStreams[n].dwLength) {
188 *ppStream = This->pStreams[n].pStream;
189 *streamPos = This->pStreams[n].dwStart + pos;
190 if (streamNr != NULL)
195 pos -= This->pStreams[n].dwLength;
197 if (pos == 0 && bFindSample) {
198 *ppStream = This->pStreams[--n].pStream;
199 *streamPos = EditStreamEnd(This, n);
200 if (streamNr != NULL)
203 TRACE(" -- pos=0 && b=1 -> (%p,%u,%u)\n",*ppStream, *streamPos, n);
208 if (streamNr != NULL)
211 TRACE(" -> ERROR (NULL,0,0)\n");
212 return AVIERR_BADPARAM;
216 static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
217 PAVISTREAM pstream, LONG pos)
221 TRACE("(%p,%p,%d)\n",This,pstream,pos);
226 /* if stream changes make sure that only palette changes */
227 if (This->pCurStream != pstream) {
228 pg = AVIStreamGetFrameOpen(pstream, NULL);
231 if (This->pg != NULL) {
232 if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1) != S_OK) {
233 AVIStreamGetFrameClose(pg);
234 ERR(": IGetFrame_SetFormat failed\n");
237 AVIStreamGetFrameClose(This->pg);
240 This->pCurStream = pstream;
243 /* now get the decompressed frame */
244 This->lpFrame = AVIStreamGetFrame(This->pg, pos);
245 if (This->lpFrame != NULL)
246 This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage;
248 return This->lpFrame;
251 static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
253 assert(This != NULL);
254 assert(nr < This->nStreams);
257 IAVIStream_Release(This->pStreams[nr].pStream);
259 if (This->nStreams - nr > 0) {
260 memmove(This->pStreams + nr, This->pStreams + nr + 1,
261 (This->nStreams - nr) * sizeof(EditStreamTable));
263 This->pStreams[This->nStreams].pStream = NULL;
264 This->pStreams[This->nStreams].dwStart = 0;
265 This->pStreams[This->nStreams].dwLength = 0;
267 /* try to merge the part before the deleted one and the one after it */
268 if (0 < nr && 0 < This->nStreams &&
269 This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) {
270 if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) {
271 This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength;
272 return AVIFILE_RemoveStream(This, nr);
279 static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
281 LPVOID fmt1 = NULL, fmt2 = NULL;
282 LONG size1, size2, start1, start2;
285 assert(avi1 != NULL && avi2 != NULL);
287 /* get stream starts and check format sizes */
288 start1 = AVIStreamStart(avi1);
289 start2 = AVIStreamStart(avi2);
290 if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
292 if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
297 /* sizes match, now get formats and compare them */
298 fmt1 = HeapAlloc(GetProcessHeap(), 0, size1);
301 if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
302 fmt2 = HeapAlloc(GetProcessHeap(), 0, size1);
304 if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
305 status = (memcmp(fmt1, fmt2, size1) == 0);
309 HeapFree(GetProcessHeap(), 0, fmt2);
310 HeapFree(GetProcessHeap(), 0, fmt1);
315 /***********************************************************************/
317 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
319 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
321 TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
323 if (IsEqualGUID(&IID_IUnknown, refiid) ||
324 IsEqualGUID(&IID_IAVIEditStream, refiid) ||
325 IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
327 IAVIEditStream_AddRef(iface);
330 } else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
331 *obj = IAVIStream_from_impl( This );
332 IAVIEditStream_AddRef(iface);
337 return E_NOINTERFACE;
340 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
342 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
343 ULONG ref = InterlockedIncrement(&This->ref);
345 TRACE("(%p) -> %d\n", iface, ref);
350 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
352 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
354 ULONG ref = InterlockedDecrement(&This->ref);
356 TRACE("(%p) -> %d\n", iface, ref);
360 if (This->pg != NULL)
361 AVIStreamGetFrameClose(This->pg);
362 if (This->pStreams != NULL) {
363 for (i = 0; i < This->nStreams; i++) {
364 if (This->pStreams[i].pStream != NULL)
365 IAVIStream_Release(This->pStreams[i].pStream);
367 HeapFree(GetProcessHeap(), 0, This->pStreams);
370 HeapFree(GetProcessHeap(), 0, This);
376 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
377 LONG*plLength,PAVISTREAM*ppResult)
379 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
381 DWORD start, len, streamPos, streamNr;
384 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
386 if (ppResult != NULL)
388 if (plStart == NULL || plLength == NULL || *plStart < 0)
389 return AVIERR_BADPARAM;
391 /* if asked for cut part copy it before deleting */
392 if (ppResult != NULL) {
393 hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
401 /* now delete the requested part */
403 hr = AVIFILE_FindStreamInTable(This, start, &stream,
404 &streamPos, &streamNr, FALSE);
407 if (This->pStreams[streamNr].dwStart == streamPos) {
408 /* deleting from start of part */
409 if (len < This->pStreams[streamNr].dwLength) {
411 This->pStreams[streamNr].dwStart += len;
412 This->pStreams[streamNr].dwLength -= len;
413 This->sInfo.dwLength -= len;
416 /* we must return decompressed data now */
417 This->bDecompress = TRUE;
419 /* deleting hole part */
420 len -= This->pStreams[streamNr].dwLength;
421 AVIFILE_RemoveStream(This,streamNr);
423 } else if (EditStreamEnd(This, streamNr) <= streamPos + len) {
424 /* deleting at end of a part */
425 DWORD count = EditStreamEnd(This, streamNr) - streamPos;
426 This->sInfo.dwLength -= count;
428 This->pStreams[streamNr].dwLength =
429 streamPos - This->pStreams[streamNr].dwStart;
432 if (This->nStreams + 1 >= This->nTableSize) {
433 This->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pStreams,
434 (This->nTableSize + 32) * sizeof(EditStreamTable));
435 if (This->pStreams == NULL)
436 return AVIERR_MEMORY;
437 This->nTableSize += 32;
439 memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
440 (This->nStreams - streamNr) * sizeof(EditStreamTable));
443 IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream);
444 This->pStreams[streamNr + 1].dwStart = streamPos + len;
445 This->pStreams[streamNr + 1].dwLength =
446 EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart;
448 This->pStreams[streamNr].dwLength =
449 streamPos - This->pStreams[streamNr].dwStart;
450 This->sInfo.dwLength -= len;
455 This->sInfo.dwEditCount++;
460 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
461 LONG*plLength,PAVISTREAM*ppResult)
463 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
464 IAVIEditStreamImpl* pEdit;
468 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
470 if (ppResult == NULL)
471 return AVIERR_BADPARAM;
473 if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
474 return AVIERR_BADPARAM;
477 if (*(LPDWORD)plLength > This->sInfo.dwLength)
478 *(LPDWORD)plLength = This->sInfo.dwLength;
479 if (*(LPDWORD)plStart < This->sInfo.dwStart) {
480 *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart;
481 *(LPDWORD)plStart = This->sInfo.dwStart;
483 return AVIERR_BADPARAM;
485 if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
486 *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
489 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
491 return AVIERR_MEMORY;
493 hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength,
494 IAVIStream_from_impl( This ),*plStart,
495 *plStart + *plLength);
498 IAVIEditStream_Release((PAVIEDITSTREAM)pEdit);
500 *ppResult = IAVIStream_from_impl( This );
505 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
506 LONG*plLength,PAVISTREAM pSource,
507 LONG lStart,LONG lLength)
509 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
510 AVISTREAMINFOW srcInfo;
511 IAVIEditStreamImpl *pEdit = NULL;
513 DWORD startPos, endPos, streamNr, nStreams;
516 TRACE("(%p,%p,%p,%p,%d,%d)\n",iface,plStart,plLength,
517 pSource,lStart,lLength);
520 return AVIERR_BADHANDLE;
521 if (plStart == NULL || *plStart < 0)
522 return AVIERR_BADPARAM;
523 if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart)
524 return AVIERR_BADPARAM; /* Can't paste with holes */
525 if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo))))
527 if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength)
528 return AVIERR_BADPARAM;
529 if (This->sInfo.fccType == 0) {
530 /* This stream is empty */
531 IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo));
532 This->sInfo.dwStart = *plStart;
533 This->sInfo.dwLength = 0;
535 if (This->sInfo.fccType != srcInfo.fccType)
536 return AVIERR_UNSUPPORTED; /* different stream types */
537 if (lLength == -1) /* Copy the hole stream */
538 lLength = srcInfo.dwLength;
539 if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength)
540 lLength = srcInfo.dwStart + srcInfo.dwLength - lStart;
541 if (lLength + *plStart >= 0x80000000)
542 return AVIERR_MEMORY;
544 /* streamtype specific tests */
545 if (srcInfo.fccType == streamtypeVIDEO) {
548 size = srcInfo.rcFrame.right - srcInfo.rcFrame.left;
549 if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left)
550 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
551 size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top;
552 if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top)
553 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
554 } else if (srcInfo.fccType == streamtypeAUDIO) {
555 if (! AVIFILE_FormatsEqual(IAVIStream_from_impl( This ), pSource))
556 return AVIERR_UNSUPPORTED;
558 /* FIXME: streamtypeMIDI and streamtypeTEXT */
559 return AVIERR_UNSUPPORTED;
562 /* try to get an IEditStreamInternal interface */
563 if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal, (LPVOID*)&pEdit)))
564 IAVIEditStream_Release( (IAVIEditStream *)pEdit ); /* pSource holds a reference */
566 /* for video must check for change of format */
567 if (This->sInfo.fccType == streamtypeVIDEO) {
568 if (! This->bDecompress) {
569 /* Need to decompress if any of the following conditions matches:
570 * - pSource is an editable stream which decompresses
571 * - the nearest keyframe of pSource isn't lStart
572 * - the nearest keyframe of this stream isn't *plStart
573 * - the format of pSource doesn't match this one
575 if ((pEdit != NULL && pEdit->bDecompress) ||
576 AVIStreamNearestKeyFrame(pSource, lStart) != lStart ||
577 AVIStreamNearestKeyFrame(IAVIStream_from_impl( This ), *plStart) != *plStart ||
578 (This->nStreams > 0 && !AVIFILE_FormatsEqual(IAVIStream_from_impl( This ), pSource))) {
579 /* Use first stream part to get format to convert everything to */
580 AVIFILE_ReadFrame(This, This->pStreams[0].pStream,
581 This->pStreams[0].dwStart);
583 /* Check if we could convert the source streams to the desired format... */
585 if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
586 &startPos, &streamNr, TRUE)))
587 return AVIERR_INTERNAL;
588 for (n = lStart; n < lStart + lLength; streamNr++) {
589 if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL)
590 return AVIERR_BADFORMAT;
591 startPos = pEdit->pStreams[streamNr].dwStart;
592 n += pEdit->pStreams[streamNr].dwLength;
594 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
595 return AVIERR_BADFORMAT;
597 This->bDecompress = TRUE;
598 This->sInfo.fccHandler = 0;
600 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
601 return AVIERR_BADFORMAT; /* Can't convert source to own format */
602 } /* FIXME: something special for the other formats? */
604 /* Make sure we have enough memory for parts */
608 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
609 &endPos, &nLastStream, TRUE);
610 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
611 &startPos, &streamNr, FALSE);
612 if (nLastStream == streamNr)
615 nStreams = nLastStream - streamNr;
618 if (This->nStreams + nStreams + 1 > This->nTableSize) {
619 n = This->nStreams + nStreams + 33;
621 This->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pStreams, n * sizeof(EditStreamTable));
622 if (This->pStreams == NULL)
623 return AVIERR_MEMORY;
624 This->nTableSize = n;
627 if (plLength != NULL)
630 /* now do the real work */
631 if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) {
632 AVIFILE_FindStreamInTable(This, *plStart, &pStream,
633 &startPos, &streamNr, FALSE);
634 if (startPos != This->pStreams[streamNr].dwStart) {
635 /* split stream streamNr at startPos */
636 memmove(This->pStreams + streamNr + nStreams + 1,
637 This->pStreams + streamNr,
638 (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable));
640 This->pStreams[streamNr + 2].dwLength =
641 EditStreamEnd(This, streamNr + 2) - startPos;
642 This->pStreams[streamNr + 2].dwStart = startPos;
643 This->pStreams[streamNr].dwLength =
644 startPos - This->pStreams[streamNr].dwStart;
645 IAVIStream_AddRef(This->pStreams[streamNr].pStream);
648 /* insert before stream at streamNr */
649 memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
650 (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
652 } else /* append the streams */
653 streamNr = This->nStreams;
656 /* insert the parts of the editable stream instead of itself */
657 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
658 &endPos, NULL, FALSE);
659 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE);
661 memcpy(This->pStreams + streamNr, pEdit->pStreams + n,
662 nStreams * sizeof(EditStreamTable));
663 if (This->pStreams[streamNr].dwStart < startPos) {
664 This->pStreams[streamNr].dwLength =
665 EditStreamEnd(This, streamNr) - startPos;
666 This->pStreams[streamNr].dwStart = startPos;
668 if (endPos < EditStreamEnd(This, streamNr + nStreams))
669 This->pStreams[streamNr + nStreams].dwLength =
670 endPos - This->pStreams[streamNr + nStreams].dwStart;
672 /* a simple stream */
673 This->pStreams[streamNr].pStream = pSource;
674 This->pStreams[streamNr].dwStart = lStart;
675 This->pStreams[streamNr].dwLength = lLength;
678 for (n = 0; n < nStreams; n++) {
679 IAVIStream_AddRef(This->pStreams[streamNr + n].pStream);
680 if (0 < streamNr + n &&
681 This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) {
682 This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
683 This->sInfo.dwFormatChangeCount++;
686 This->sInfo.dwEditCount++;
687 This->sInfo.dwLength += lLength;
688 This->nStreams += nStreams;
693 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
696 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
697 IAVIEditStreamImpl* pEdit;
700 TRACE("(%p,%p)\n",iface,ppResult);
702 if (ppResult == NULL)
703 return AVIERR_BADPARAM;
706 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
708 return AVIERR_MEMORY;
709 if (This->nStreams > pEdit->nTableSize) {
710 pEdit->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pEdit->pStreams,
711 This->nStreams * sizeof(EditStreamTable));
712 if (pEdit->pStreams == NULL)
713 return AVIERR_MEMORY;
714 pEdit->nTableSize = This->nStreams;
716 pEdit->nStreams = This->nStreams;
717 memcpy(pEdit->pStreams, This->pStreams,
718 This->nStreams * sizeof(EditStreamTable));
719 memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo));
720 for (i = 0; i < This->nStreams; i++) {
721 if (pEdit->pStreams[i].pStream != NULL)
722 IAVIStream_AddRef(pEdit->pStreams[i].pStream);
725 *ppResult = IAVIStream_from_impl( This );
730 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
731 LPAVISTREAMINFOW asi,LONG size)
733 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
735 TRACE("(%p,%p,%d)\n",iface,asi,size);
737 /* check parameters */
738 if (size >= 0 && size < sizeof(AVISTREAMINFOW))
739 return AVIERR_BADSIZE;
741 This->sInfo.wLanguage = asi->wLanguage;
742 This->sInfo.wPriority = asi->wPriority;
743 This->sInfo.dwStart = asi->dwStart;
744 This->sInfo.dwRate = asi->dwRate;
745 This->sInfo.dwScale = asi->dwScale;
746 This->sInfo.dwQuality = asi->dwQuality;
747 CopyRect(&This->sInfo.rcFrame, &asi->rcFrame);
748 memcpy(This->sInfo.szName, asi->szName, sizeof(asi->szName));
749 This->sInfo.dwEditCount++;
754 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
755 REFIID refiid,LPVOID*obj)
757 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
758 return IAVIEditStream_QueryInterface((IAVIEditStream *)This,refiid,obj);
761 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface)
763 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
764 return IAVIEditStream_AddRef((IAVIEditStream*)This);
767 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface)
769 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
770 return IAVIEditStream_Release((IAVIEditStream*)This);
773 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,
774 LPARAM lParam1,LPARAM lParam2)
776 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
781 if (This->pStreams == NULL) {
782 This->pStreams = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256 * sizeof(EditStreamTable));
783 if (This->pStreams == NULL)
784 return AVIERR_MEMORY;
785 This->nTableSize = 256;
789 IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
790 IAVIStream_AddRef((PAVISTREAM)lParam1);
791 This->pStreams[0].pStream = (PAVISTREAM)lParam1;
792 This->pStreams[0].dwStart = This->sInfo.dwStart;
793 This->pStreams[0].dwLength = This->sInfo.dwLength;
799 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,
800 AVISTREAMINFOW *psi,LONG size)
802 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
804 TRACE("(%p,%p,%d)\n",iface,psi,size);
807 return AVIERR_BADPARAM;
809 return AVIERR_BADSIZE;
811 if (This->bDecompress)
812 This->sInfo.fccHandler = 0;
814 memcpy(psi, &This->sInfo, min((DWORD)size, sizeof(This->sInfo)));
816 if ((DWORD)size < sizeof(This->sInfo))
817 return AVIERR_BUFFERTOOSMALL;
821 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
824 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
826 DWORD streamPos, streamNr;
828 TRACE("(%p,%d,0x%08X)\n",iface,pos,flags);
830 if (flags & FIND_FROM_START)
831 pos = (LONG)This->sInfo.dwStart;
833 /* outside of stream? */
834 if (pos < (LONG)This->sInfo.dwStart ||
835 (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos)
838 /* map our position to a stream and position in it */
839 if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos,
840 &streamNr, TRUE) != S_OK)
841 return -1; /* doesn't exist */
843 if (This->bDecompress) {
844 /* only one stream -- format changes only at start */
845 if (flags & FIND_FORMAT)
846 return (flags & FIND_NEXT ? -1 : 0);
848 /* FIXME: map positions back to us */
849 return IAVIStream_FindSample(stream, streamPos, flags);
851 /* assume change of format every frame */
856 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,
857 LPVOID format,LONG*fmtsize)
859 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
860 LPBITMAPINFOHEADER lp;
865 TRACE("(%p,%d,%p,%p)\n",iface,pos,format,fmtsize);
867 if (fmtsize == NULL || pos < This->sInfo.dwStart ||
868 This->sInfo.dwStart + This->sInfo.dwLength <= pos)
869 return AVIERR_BADPARAM;
871 /* find stream corresponding to position */
872 hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE);
876 if (! This->bDecompress)
877 return IAVIStream_ReadFormat(stream, n, format, fmtsize);
879 lp = AVIFILE_ReadFrame(This, stream, n);
882 if (lp->biBitCount <= 8) {
883 n = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount);
884 n *= sizeof(RGBQUAD);
889 memcpy(format, lp, min((LONG)n, *fmtsize));
890 hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK);
896 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,
897 LPVOID format,LONG formatsize)
899 TRACE("(%p,%d,%p,%d)\n",iface,pos,format,formatsize);
901 return AVIERR_UNSUPPORTED;
904 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
905 LONG samples,LPVOID buffer,
906 LONG buffersize,LONG*bytesread,
909 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
911 DWORD streamPos, streamNr;
912 LONG readBytes, readSamples, count;
915 TRACE("(%p,%d,%d,%p,%d,%p,%p) -- 0x%08X\n",iface,start,samples,
916 buffer,buffersize,bytesread,samplesread,This->sInfo.fccType);
918 /* check parameters */
919 if (bytesread != NULL)
921 if (samplesread != NULL)
924 return AVIERR_BADSIZE;
925 if ((DWORD)start < This->sInfo.dwStart ||
926 This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
927 return AVIERR_BADPARAM;
929 if (! This->bDecompress) {
930 /* audio like data -- sample-based */
933 return AVIERR_OK; /* nothing at all or already done */
935 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
936 &streamPos, &streamNr, FALSE)))
939 /* limit to end of the stream */
941 if (streamPos + count > EditStreamEnd(This, streamNr))
942 count = EditStreamEnd(This, streamNr) - streamPos;
944 hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize,
945 &readBytes, &readSamples);
948 if (readBytes == 0 && readSamples == 0 && count != 0)
949 return AVIERR_FILEREAD; /* for bad stream implementations */
951 if (samplesread != NULL)
952 *samplesread += readSamples;
953 if (bytesread != NULL)
954 *bytesread += readBytes;
955 if (buffer != NULL) {
956 buffer = ((LPBYTE)buffer)+readBytes;
957 buffersize -= readBytes;
961 } while (This->sInfo.dwStart + This->sInfo.dwLength > start);
963 /* video like data -- frame-based */
964 LPBITMAPINFOHEADER lp;
969 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
970 &streamPos, &streamNr, FALSE)))
973 lp = AVIFILE_ReadFrame(This, stream, streamPos);
977 if (buffer != NULL) {
978 /* need size of format to skip */
979 if (lp->biBitCount <= 8) {
980 count = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount;
981 count *= sizeof(RGBQUAD);
986 if (buffersize < lp->biSizeImage)
987 return AVIERR_BUFFERTOOSMALL;
988 memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage);
991 if (bytesread != NULL)
992 *bytesread = lp->biSizeImage;
993 if (samplesread != NULL)
1000 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
1001 LONG samples,LPVOID buffer,
1002 LONG buffersize,DWORD flags,
1003 LONG*sampwritten,LONG*byteswritten)
1005 TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n",iface,start,samples,buffer,
1006 buffersize,flags,sampwritten,byteswritten);
1008 /* be sure return parameters have correct values */
1009 if (sampwritten != NULL)
1011 if (byteswritten != NULL)
1014 return AVIERR_UNSUPPORTED;
1017 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,
1020 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
1022 TRACE("(%p,%d,%d)\n",iface,start,samples);
1024 return IAVIEditStream_Cut((IAVIEditStream*)This,&start,&samples,NULL);
1027 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
1028 LPVOID lp,LONG *lpread)
1030 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
1033 TRACE("(%p,0x%08X,%p,%p)\n",iface,fcc,lp,lpread);
1035 /* check parameters */
1036 if (lp == NULL || lpread == NULL)
1037 return AVIERR_BADPARAM;
1039 /* simply ask every stream and return the first block found */
1040 for (n = 0; n < This->nStreams; n++) {
1041 HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread);
1048 return AVIERR_NODATA;
1051 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
1052 LPVOID lp,LONG size)
1054 TRACE("(%p,0x%08X,%p,%d)\n",iface,fcc,lp,size);
1056 return AVIERR_UNSUPPORTED;
1059 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,
1060 AVISTREAMINFOW*info,LONG len)
1062 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
1064 TRACE("(%p,%p,%d)\n",iface,info,len);
1066 return IAVIEditStream_SetInfo((IAVIEditStream*)This,info,len);