wgl: Fix wglGetProcAddress bug.
[wine/hacks.git] / dlls / avifil32 / editstream.c
blobd275390443b2967edfdedff9db76f472812fdcd5
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <assert.h>
20 #include <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winuser.h"
25 #include "wingdi.h"
26 #include "winnls.h"
27 #include "winerror.h"
28 #include "mmsystem.h"
29 #include "vfw.h"
31 #include "avifile_private.h"
32 #include "extrachunk.h"
34 #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 typedef struct _EditStreamTable {
43 PAVISTREAM pStream; /* stream which contains the data */
44 DWORD dwStart; /* where starts the part which is also our */
45 DWORD dwLength; /* how many is also in this stream */
46 } EditStreamTable;
48 #define INTERFACE IEditStreamInternal
49 DECLARE_INTERFACE_(IEditStreamInternal,IUnknown)
51 /*** IUnknown methods ***/
52 STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
53 STDMETHOD_(ULONG,AddRef)(THIS) PURE;
54 STDMETHOD_(ULONG,Release)(THIS) PURE;
55 /*** IEditStreamInternal methods ***/
56 STDMETHOD(GetEditStreamImpl)(THIS_ LPVOID*) PURE;
58 #undef INTERFACE
60 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
61 (This)->pStreams[streamNr].dwLength)
63 /***********************************************************************/
65 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj);
66 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface);
67 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface);
68 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
69 LONG*plLength,PAVISTREAM*ppResult);
70 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
71 LONG*plLength,PAVISTREAM*ppResult);
72 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
73 LONG*plLength,PAVISTREAM pSource,
74 LONG lStart,LONG lEnd);
75 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
76 PAVISTREAM*ppResult);
77 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
78 LPAVISTREAMINFOW asi,LONG size);
80 static const struct IAVIEditStreamVtbl ieditstream = {
81 IAVIEditStream_fnQueryInterface,
82 IAVIEditStream_fnAddRef,
83 IAVIEditStream_fnRelease,
84 IAVIEditStream_fnCut,
85 IAVIEditStream_fnCopy,
86 IAVIEditStream_fnPaste,
87 IAVIEditStream_fnClone,
88 IAVIEditStream_fnSetInfo
91 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID*obj);
92 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface);
93 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface);
94 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
95 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
96 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
97 LONG flags);
98 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG*formatsize);
99 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
100 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
101 LONG samples,LPVOID buffer,
102 LONG buffersize,LONG*bytesread,
103 LONG*samplesread);
104 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
105 LONG samples,LPVOID buffer,
106 LONG buffersize,DWORD flags,
107 LONG*sampwritten,LONG*byteswritten);
108 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
109 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
110 LPVOID lp,LONG *lpread);
111 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
112 LPVOID lp,LONG size);
113 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
115 static const struct IAVIStreamVtbl ieditstast = {
116 IEditAVIStream_fnQueryInterface,
117 IEditAVIStream_fnAddRef,
118 IEditAVIStream_fnRelease,
119 IEditAVIStream_fnCreate,
120 IEditAVIStream_fnInfo,
121 IEditAVIStream_fnFindSample,
122 IEditAVIStream_fnReadFormat,
123 IEditAVIStream_fnSetFormat,
124 IEditAVIStream_fnRead,
125 IEditAVIStream_fnWrite,
126 IEditAVIStream_fnDelete,
127 IEditAVIStream_fnReadData,
128 IEditAVIStream_fnWriteData,
129 IEditAVIStream_fnSetInfo
132 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj);
133 static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface);
134 static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface);
135 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl);
137 static const struct IEditStreamInternalVtbl ieditstreaminternal = {
138 IEditStreamInternal_fnQueryInterface,
139 IEditStreamInternal_fnAddRef,
140 IEditStreamInternal_fnRelease,
141 IEditStreamInternal_fnGetEditStreamImpl
144 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
146 typedef struct _IEditAVIStreamImpl {
147 /* IUnknown stuff */
148 const IAVIStreamVtbl *lpVtbl;
150 /* IAVIStream stuff */
151 IAVIEditStreamImpl *pae;
152 } IEditAVIStreamImpl;
154 typedef struct _IEditStreamInternalImpl {
155 /* IUnknown stuff */
156 const IEditStreamInternalVtbl *lpVtbl;
158 /* IEditStreamInternal stuff */
159 IAVIEditStreamImpl *pae;
160 } IEditStreamInternalImpl;
162 struct _IAVIEditStreamImpl {
163 /* IUnknown stuff */
164 const IAVIEditStreamVtbl *lpVtbl;
165 LONG ref;
167 /* IAVIEditStream stuff */
168 IEditAVIStreamImpl iAVIStream;
169 IEditStreamInternalImpl iEditStreamInternal;
171 AVISTREAMINFOW sInfo;
173 EditStreamTable *pStreams;
174 DWORD nStreams; /* current fill level of pStreams table */
175 DWORD nTableSize; /* size of pStreams table */
177 BOOL bDecompress;
178 PAVISTREAM pCurStream;
179 PGETFRAME pg; /* IGetFrame for pCurStream */
180 LPBITMAPINFOHEADER lpFrame; /* frame of pCurStream */
183 /***********************************************************************/
185 PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream)
187 IAVIEditStreamImpl *pedit = NULL;
189 pedit = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIEditStreamImpl));
190 if (pedit == NULL)
191 return NULL;
193 pedit->lpVtbl = &ieditstream;
194 pedit->iAVIStream.lpVtbl = &ieditstast;
195 pedit->iAVIStream.pae = pedit;
196 pedit->iEditStreamInternal.lpVtbl = &ieditstreaminternal;
197 pedit->iEditStreamInternal.pae = pedit;
198 pedit->ref = 1;
200 IAVIStream_Create((PAVISTREAM)&pedit->iAVIStream,(LPARAM)pstream,0);
202 return (PAVIEDITSTREAM)pedit;
205 static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
206 DWORD pos,PAVISTREAM *ppStream,
207 DWORD* streamPos,
208 DWORD* streamNr,BOOL bFindSample)
210 DWORD n;
212 TRACE("(%p,%u,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
213 streamNr,bFindSample);
215 if (pos < This->sInfo.dwStart)
216 return AVIERR_BADPARAM;
218 pos -= This->sInfo.dwStart;
219 for (n = 0; n < This->nStreams; n++) {
220 if (pos < This->pStreams[n].dwLength) {
221 *ppStream = This->pStreams[n].pStream;
222 *streamPos = This->pStreams[n].dwStart + pos;
223 if (streamNr != NULL)
224 *streamNr = n;
226 return AVIERR_OK;
228 pos -= This->pStreams[n].dwLength;
230 if (pos == 0 && bFindSample) {
231 *ppStream = This->pStreams[--n].pStream;
232 *streamPos = EditStreamEnd(This, n);
233 if (streamNr != NULL)
234 *streamNr = n;
236 TRACE(" -- pos=0 && b=1 -> (%p,%u,%u)\n",*ppStream, *streamPos, n);
237 return AVIERR_OK;
238 } else {
239 *ppStream = NULL;
240 *streamPos = 0;
241 if (streamNr != NULL)
242 *streamNr = 0;
244 TRACE(" -> ERROR (NULL,0,0)\n");
245 return AVIERR_BADPARAM;
249 static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
250 PAVISTREAM pstream, LONG pos)
252 PGETFRAME pg;
254 TRACE("(%p,%p,%d)\n",This,pstream,pos);
256 if (pstream == NULL)
257 return NULL;
259 /* if stream changes make sure that only palette changes */
260 if (This->pCurStream != pstream) {
261 pg = AVIStreamGetFrameOpen(pstream, NULL);
262 if (pg == NULL)
263 return NULL;
264 if (This->pg != NULL) {
265 if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1)) {
266 AVIStreamGetFrameClose(pg);
267 ERR(": IGetFrame_SetFormat failed\n");
268 return NULL;
270 AVIStreamGetFrameClose(This->pg);
272 This->pg = pg;
273 This->pCurStream = pstream;
276 /* now get the decompressed frame */
277 This->lpFrame = AVIStreamGetFrame(This->pg, pos);
278 if (This->lpFrame != NULL)
279 This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage;
281 return This->lpFrame;
284 static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
286 assert(This != NULL);
287 assert(nr < This->nStreams);
289 /* remove part nr */
290 IAVIStream_Release(This->pStreams[nr].pStream);
291 This->nStreams--;
292 if (This->nStreams - nr > 0) {
293 memmove(This->pStreams + nr, This->pStreams + nr + 1,
294 (This->nStreams - nr) * sizeof(EditStreamTable));
296 This->pStreams[This->nStreams].pStream = NULL;
297 This->pStreams[This->nStreams].dwStart = 0;
298 This->pStreams[This->nStreams].dwLength = 0;
300 /* try to merge the part before the deleted one and the one after it */
301 if (0 < nr && 0 < This->nStreams &&
302 This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) {
303 if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) {
304 This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength;
305 return AVIFILE_RemoveStream(This, nr);
309 return AVIERR_OK;
312 static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
314 LPVOID fmt1 = NULL, fmt2 = NULL;
315 LONG size1, size2, start1, start2;
316 BOOL status = FALSE;
318 assert(avi1 != NULL && avi2 != NULL);
320 /* get stream starts and check format sizes */
321 start1 = AVIStreamStart(avi1);
322 start2 = AVIStreamStart(avi2);
323 if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
324 return FALSE;
325 if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
326 return FALSE;
327 if (size1 != size2)
328 return FALSE;
330 /* sizes match, now get formats and compare them */
331 fmt1 = HeapAlloc(GetProcessHeap(), 0, size1);
332 if (fmt1 == NULL)
333 return FALSE;
334 if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
335 fmt2 = HeapAlloc(GetProcessHeap(), 0, size1);
336 if (fmt2 != NULL) {
337 if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
338 status = (memcmp(fmt1, fmt2, size1) == 0);
342 HeapFree(GetProcessHeap(), 0, fmt2);
343 HeapFree(GetProcessHeap(), 0, fmt1);
345 return status;
348 /***********************************************************************/
350 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
352 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
354 TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
356 if (IsEqualGUID(&IID_IUnknown, refiid) ||
357 IsEqualGUID(&IID_IAVIEditStream, refiid)) {
358 *obj = iface;
359 IAVIEditStream_AddRef(iface);
361 return S_OK;
362 } else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
363 *obj = &This->iAVIStream;
364 IAVIEditStream_AddRef(iface);
366 return S_OK;
367 } else if (IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
368 *obj = &This->iEditStreamInternal;
369 IAVIEditStream_AddRef(iface);
371 return S_OK;
374 return OLE_E_ENUM_NOMORE;
377 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
379 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
380 ULONG ref = InterlockedIncrement(&This->ref);
382 TRACE("(%p) -> %d\n", iface, ref);
384 return ref;
387 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
389 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
390 DWORD i;
391 ULONG ref = InterlockedDecrement(&This->ref);
393 TRACE("(%p) -> %d\n", iface, ref);
395 if (!ref) {
396 /* release memory */
397 if (This->pg != NULL)
398 AVIStreamGetFrameClose(This->pg);
399 if (This->pStreams != NULL) {
400 for (i = 0; i < This->nStreams; i++) {
401 if (This->pStreams[i].pStream != NULL)
402 IAVIStream_Release(This->pStreams[i].pStream);
404 HeapFree(GetProcessHeap(), 0, This->pStreams);
407 HeapFree(GetProcessHeap(), 0, This);
408 return 0;
410 return ref;
413 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
414 LONG*plLength,PAVISTREAM*ppResult)
416 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
417 PAVISTREAM stream;
418 DWORD start, len, streamPos, streamNr;
419 HRESULT hr;
421 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
423 if (ppResult != NULL)
424 *ppResult = NULL;
425 if (plStart == NULL || plLength == NULL || *plStart < 0)
426 return AVIERR_BADPARAM;
428 /* if asked for cutted part copy it before deleting */
429 if (ppResult != NULL) {
430 hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
431 if (FAILED(hr))
432 return hr;
435 start = *plStart;
436 len = *plLength;
438 /* now delete the requested part */
439 while (len > 0) {
440 hr = AVIFILE_FindStreamInTable(This, start, &stream,
441 &streamPos, &streamNr, FALSE);
442 if (FAILED(hr))
443 return hr;
444 if (This->pStreams[streamNr].dwStart == streamPos) {
445 /* deleting from start of part */
446 if (len < This->pStreams[streamNr].dwLength) {
447 start += len;
448 This->pStreams[streamNr].dwStart += len;
449 This->pStreams[streamNr].dwLength -= len;
450 This->sInfo.dwLength -= len;
451 len = 0;
453 /* we must return decompressed data now */
454 This->bDecompress = TRUE;
455 } else {
456 /* deleting hole part */
457 len -= This->pStreams[streamNr].dwLength;
458 AVIFILE_RemoveStream(This,streamNr);
460 } else if (EditStreamEnd(This, streamNr) <= streamPos + len) {
461 /* deleting at end of a part */
462 DWORD count = EditStreamEnd(This, streamNr) - streamPos;
463 This->sInfo.dwLength -= count;
464 len -= count;
465 This->pStreams[streamNr].dwLength =
466 streamPos - This->pStreams[streamNr].dwStart;
467 } else {
468 /* splitting */
469 if (This->nStreams + 1 >= This->nTableSize) {
470 This->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pStreams,
471 (This->nTableSize + 32) * sizeof(EditStreamTable));
472 if (This->pStreams == NULL)
473 return AVIERR_MEMORY;
474 This->nTableSize += 32;
476 memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
477 (This->nStreams - streamNr) * sizeof(EditStreamTable));
478 This->nStreams++;
480 IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream);
481 This->pStreams[streamNr + 1].dwStart = streamPos + len;
482 This->pStreams[streamNr + 1].dwLength =
483 EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart;
485 This->pStreams[streamNr].dwLength =
486 streamPos - This->pStreams[streamNr].dwStart;
487 This->sInfo.dwLength -= len;
488 len = 0;
492 This->sInfo.dwEditCount++;
494 return AVIERR_OK;
497 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
498 LONG*plLength,PAVISTREAM*ppResult)
500 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
501 IAVIEditStreamImpl* pEdit;
502 HRESULT hr;
503 LONG start = 0;
505 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
507 if (ppResult == NULL)
508 return AVIERR_BADPARAM;
509 *ppResult = NULL;
510 if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
511 return AVIERR_BADPARAM;
513 /* check bounds */
514 if (*(LPDWORD)plLength > This->sInfo.dwLength)
515 *(LPDWORD)plLength = This->sInfo.dwLength;
516 if (*(LPDWORD)plStart < This->sInfo.dwStart) {
517 *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart;
518 *(LPDWORD)plStart = This->sInfo.dwStart;
519 if (*plLength < 0)
520 return AVIERR_BADPARAM;
522 if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
523 *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
524 *(LPDWORD)plStart;
526 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
527 if (pEdit == NULL)
528 return AVIERR_MEMORY;
530 hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength,
531 (PAVISTREAM)&This->iAVIStream,*plStart,
532 *plStart + *plLength);
533 *plStart = start;
534 if (FAILED(hr))
535 IAVIEditStream_Release((PAVIEDITSTREAM)pEdit);
536 else
537 *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
539 return hr;
542 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
543 LONG*plLength,PAVISTREAM pSource,
544 LONG lStart,LONG lLength)
546 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
547 AVISTREAMINFOW srcInfo;
548 IEditStreamInternal*pInternal = NULL;
549 IAVIEditStreamImpl *pEdit = NULL;
550 PAVISTREAM pStream;
551 DWORD startPos, endPos, streamNr, nStreams;
552 ULONG n;
554 TRACE("(%p,%p,%p,%p,%d,%d)\n",iface,plStart,plLength,
555 pSource,lStart,lLength);
557 if (pSource == NULL)
558 return AVIERR_BADHANDLE;
559 if (plStart == NULL || *plStart < 0)
560 return AVIERR_BADPARAM;
561 if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart)
562 return AVIERR_BADPARAM; /* Can't paste with holes */
563 if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo))))
564 return AVIERR_ERROR;
565 if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength)
566 return AVIERR_BADPARAM;
567 if (This->sInfo.fccType == 0) {
568 /* This stream is empty */
569 IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo));
570 This->sInfo.dwStart = *plStart;
571 This->sInfo.dwLength = 0;
573 if (This->sInfo.fccType != srcInfo.fccType)
574 return AVIERR_UNSUPPORTED; /* different stream types */
575 if (lLength == -1) /* Copy the hole stream */
576 lLength = srcInfo.dwLength;
577 if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength)
578 lLength = srcInfo.dwStart + srcInfo.dwLength - lStart;
579 if (lLength + *plStart >= 0x80000000)
580 return AVIERR_MEMORY;
582 /* streamtype specific tests */
583 if (srcInfo.fccType == streamtypeVIDEO) {
584 LONG size;
586 size = srcInfo.rcFrame.right - srcInfo.rcFrame.left;
587 if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left)
588 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
589 size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top;
590 if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top)
591 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
592 } else if (srcInfo.fccType == streamtypeAUDIO) {
593 if (! AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))
594 return AVIERR_UNSUPPORTED;
595 } else {
596 /* FIXME: streamtypeMIDI and streamtypeTEXT */
597 return AVIERR_UNSUPPORTED;
600 /* try to get an IEditStreamInternal interface */
601 if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal,
602 (LPVOID*)&pInternal))) {
603 pInternal->lpVtbl->GetEditStreamImpl(pInternal, (LPVOID*)&pEdit);
604 pInternal->lpVtbl->Release(pInternal);
607 /* for video must check for change of format */
608 if (This->sInfo.fccType == streamtypeVIDEO) {
609 if (! This->bDecompress) {
610 /* Need to decompress if any of the following conditions matches:
611 * - pSource is an editable stream which decompresses
612 * - the nearest keyframe of pSource isn't lStart
613 * - the nearest keyframe of this stream isn't *plStart
614 * - the format of pSource doesn't match this one
616 if ((pEdit != NULL && pEdit->bDecompress) ||
617 AVIStreamNearestKeyFrame(pSource, lStart) != lStart ||
618 AVIStreamNearestKeyFrame((PAVISTREAM)&This->iAVIStream, *plStart) != *plStart ||
619 (This->nStreams > 0 && !AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))) {
620 /* Use first stream part to get format to convert everything to */
621 AVIFILE_ReadFrame(This, This->pStreams[0].pStream,
622 This->pStreams[0].dwStart);
624 /* Check if we could convert the source streams to the disired format... */
625 if (pEdit != NULL) {
626 if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
627 &startPos, &streamNr, TRUE)))
628 return AVIERR_INTERNAL;
629 for (n = lStart; n < lStart + lLength; streamNr++) {
630 if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL)
631 return AVIERR_BADFORMAT;
632 startPos = pEdit->pStreams[streamNr].dwStart;
633 n += pEdit->pStreams[streamNr].dwLength;
635 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
636 return AVIERR_BADFORMAT;
638 This->bDecompress = TRUE;
639 This->sInfo.fccHandler = 0;
641 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
642 return AVIERR_BADFORMAT; /* Can't convert source to own format */
643 } /* FIXME: something special for the other formats? */
645 /* Make sure we have enough memory for parts */
646 if (pEdit != NULL) {
647 DWORD nLastStream;
649 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
650 &endPos, &nLastStream, TRUE);
651 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
652 &startPos, &streamNr, FALSE);
653 if (nLastStream == streamNr)
654 nLastStream++;
656 nStreams = nLastStream - streamNr;
657 } else
658 nStreams = 1;
659 if (This->nStreams + nStreams + 1 > This->nTableSize) {
660 n = This->nStreams + nStreams + 33;
662 This->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pStreams, n * sizeof(EditStreamTable));
663 if (This->pStreams == NULL)
664 return AVIERR_MEMORY;
665 This->nTableSize = n;
668 if (plLength != NULL)
669 *plLength = lLength;
671 /* now do the real work */
672 if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) {
673 AVIFILE_FindStreamInTable(This, *plStart, &pStream,
674 &startPos, &streamNr, FALSE);
675 if (startPos != This->pStreams[streamNr].dwStart) {
676 /* split stream streamNr at startPos */
677 memmove(This->pStreams + streamNr + nStreams + 1,
678 This->pStreams + streamNr,
679 (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable));
681 This->pStreams[streamNr + 2].dwLength =
682 EditStreamEnd(This, streamNr + 2) - startPos;
683 This->pStreams[streamNr + 2].dwStart = startPos;
684 This->pStreams[streamNr].dwLength =
685 startPos - This->pStreams[streamNr].dwStart;
686 IAVIStream_AddRef(This->pStreams[streamNr].pStream);
687 streamNr++;
688 } else {
689 /* insert before stream at streamNr */
690 memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
691 (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
693 } else /* append the streams */
694 streamNr = This->nStreams;
696 if (pEdit != NULL) {
697 /* insert the parts of the editable stream instead of itself */
698 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
699 &endPos, NULL, FALSE);
700 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE);
702 memcpy(This->pStreams + streamNr, pEdit->pStreams + n,
703 nStreams * sizeof(EditStreamTable));
704 if (This->pStreams[streamNr].dwStart < startPos) {
705 This->pStreams[streamNr].dwLength =
706 EditStreamEnd(This, streamNr) - startPos;
707 This->pStreams[streamNr].dwStart = startPos;
709 if (endPos < EditStreamEnd(This, streamNr + nStreams))
710 This->pStreams[streamNr + nStreams].dwLength =
711 endPos - This->pStreams[streamNr + nStreams].dwStart;
712 } else {
713 /* a simple stream */
714 This->pStreams[streamNr].pStream = pSource;
715 This->pStreams[streamNr].dwStart = lStart;
716 This->pStreams[streamNr].dwLength = lLength;
719 for (n = 0; n < nStreams; n++) {
720 IAVIStream_AddRef(This->pStreams[streamNr + n].pStream);
721 if (0 < streamNr + n &&
722 This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) {
723 This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
724 This->sInfo.dwFormatChangeCount++;
727 This->sInfo.dwEditCount++;
728 This->sInfo.dwLength += lLength;
729 This->nStreams += nStreams;
731 return AVIERR_OK;
734 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
735 PAVISTREAM*ppResult)
737 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
738 IAVIEditStreamImpl* pEdit;
739 DWORD i;
741 TRACE("(%p,%p)\n",iface,ppResult);
743 if (ppResult == NULL)
744 return AVIERR_BADPARAM;
745 *ppResult = NULL;
747 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
748 if (pEdit == NULL)
749 return AVIERR_MEMORY;
750 if (This->nStreams > pEdit->nTableSize) {
751 pEdit->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pEdit->pStreams,
752 This->nStreams * sizeof(EditStreamTable));
753 if (pEdit->pStreams == NULL)
754 return AVIERR_MEMORY;
755 pEdit->nTableSize = This->nStreams;
757 pEdit->nStreams = This->nStreams;
758 memcpy(pEdit->pStreams, This->pStreams,
759 This->nStreams * sizeof(EditStreamTable));
760 memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo));
761 for (i = 0; i < This->nStreams; i++) {
762 if (pEdit->pStreams[i].pStream != NULL)
763 IAVIStream_AddRef(pEdit->pStreams[i].pStream);
766 *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
768 return AVIERR_OK;
771 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
772 LPAVISTREAMINFOW asi,LONG size)
774 IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
776 TRACE("(%p,%p,%d)\n",iface,asi,size);
778 /* check parameters */
779 if (asi == NULL)
780 return AVIERR_BADPARAM;
781 if (size != sizeof(AVISTREAMINFOW))
782 return AVIERR_BADSIZE;
783 if (asi->dwScale == 0 || asi->dwRate == 0 || (LONG)asi->dwQuality < -1 ||
784 asi->dwQuality > ICQUALITY_HIGH)
785 return AVIERR_ERROR;
787 This->sInfo.wLanguage = asi->wLanguage;
788 This->sInfo.wPriority = asi->wPriority;
789 This->sInfo.dwStart = asi->dwStart;
790 if (asi->dwRate != 0)
791 This->sInfo.dwRate = asi->dwRate;
792 if (asi->dwScale != 0)
793 This->sInfo.dwScale = asi->dwScale;
794 if (asi->dwQuality <= ICQUALITY_HIGH)
795 This->sInfo.dwQuality = ICQUALITY_HIGH;
796 CopyRect(&This->sInfo.rcFrame, &asi->rcFrame);
797 memcpy(&This->sInfo.szName, &asi->szName, sizeof(asi->szName));
798 This->sInfo.dwEditCount++;
800 return AVIERR_OK;
803 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
804 REFIID refiid,LPVOID*obj)
806 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
808 assert(This->pae != NULL);
810 return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae,refiid,obj);
813 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface)
815 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
817 assert(This->pae != NULL);
819 return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
822 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface)
824 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
826 assert(This->pae != NULL);
828 return IAVIEditStream_Release((IAVIEditStream*)This->pae);
831 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,
832 LPARAM lParam1,LPARAM lParam2)
834 IAVIEditStreamImpl *This = ((IEditAVIStreamImpl*)iface)->pae;
836 if (lParam2 != 0)
837 return AVIERR_ERROR;
839 if (This->pStreams == NULL) {
840 This->pStreams = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256 * sizeof(EditStreamTable));
841 if (This->pStreams == NULL)
842 return AVIERR_MEMORY;
843 This->nTableSize = 256;
846 if (lParam1 != 0) {
847 IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
848 IAVIStream_AddRef((PAVISTREAM)lParam1);
849 This->pStreams[0].pStream = (PAVISTREAM)lParam1;
850 This->pStreams[0].dwStart = This->sInfo.dwStart;
851 This->pStreams[0].dwLength = This->sInfo.dwLength;
852 This->nStreams = 1;
854 return AVIERR_OK;
857 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,
858 AVISTREAMINFOW *psi,LONG size)
860 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
862 TRACE("(%p,%p,%d)\n",iface,psi,size);
864 assert(This->pae != NULL);
866 if (psi == NULL)
867 return AVIERR_BADPARAM;
868 if (size < 0)
869 return AVIERR_BADSIZE;
871 if (This->pae->bDecompress)
872 This->pae->sInfo.fccHandler = 0;
874 memcpy(psi, &This->pae->sInfo, min((DWORD)size, sizeof(This->pae->sInfo)));
876 if ((DWORD)size < sizeof(This->pae->sInfo))
877 return AVIERR_BUFFERTOOSMALL;
878 return AVIERR_OK;
881 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
882 LONG flags)
884 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
885 PAVISTREAM stream;
886 DWORD streamPos, streamNr;
888 TRACE("(%p,%d,0x%08X)\n",iface,pos,flags);
890 if (flags & FIND_FROM_START)
891 pos = (LONG)This->sInfo.dwStart;
893 /* outside of stream? */
894 if (pos < (LONG)This->sInfo.dwStart ||
895 (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos)
896 return -1;
898 /* map our position to a stream and position in it */
899 if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos,
900 &streamNr, TRUE))
901 return -1; /* doesn't exist */
903 if (This->bDecompress) {
904 /* only one stream -- format changes only at start */
905 if (flags & FIND_FORMAT)
906 return (flags & FIND_NEXT ? -1 : 0);
908 /* FIXME: map positions back to us */
909 return IAVIStream_FindSample(stream, streamPos, flags);
910 } else {
911 /* assume change of format every frame */
912 return pos;
916 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,
917 LPVOID format,LONG*fmtsize)
919 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
920 LPBITMAPINFOHEADER lp;
921 PAVISTREAM stream;
922 DWORD n;
923 HRESULT hr;
925 TRACE("(%p,%d,%p,%p)\n",iface,pos,format,fmtsize);
927 if (fmtsize == NULL || pos < This->sInfo.dwStart ||
928 This->sInfo.dwStart + This->sInfo.dwLength <= pos)
929 return AVIERR_BADPARAM;
931 /* find stream corresponding to position */
932 hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE);
933 if (FAILED(hr))
934 return hr;
936 if (! This->bDecompress)
937 return IAVIStream_ReadFormat(stream, n, format, fmtsize);
939 lp = (LPBITMAPINFOHEADER)AVIFILE_ReadFrame(This, stream, n);
940 if (lp == NULL)
941 return AVIERR_ERROR;
942 if (lp->biBitCount <= 8) {
943 n = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount);
944 n *= sizeof(RGBQUAD);
945 } else
946 n = 0;
947 n += lp->biSize;
949 memcpy(format, lp, min((LONG)n, *fmtsize));
950 hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK);
951 *fmtsize = n;
953 return hr;
956 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,
957 LPVOID format,LONG formatsize)
959 TRACE("(%p,%d,%p,%d)\n",iface,pos,format,formatsize);
961 return AVIERR_UNSUPPORTED;
964 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
965 LONG samples,LPVOID buffer,
966 LONG buffersize,LONG*bytesread,
967 LONG*samplesread)
969 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
970 PAVISTREAM stream;
971 DWORD streamPos, streamNr;
972 LONG readBytes, readSamples, count;
973 HRESULT hr;
975 TRACE("(%p,%d,%d,%p,%d,%p,%p) -- 0x%08X\n",iface,start,samples,
976 buffer,buffersize,bytesread,samplesread,This->sInfo.fccType);
978 /* check parameters */
979 if (bytesread != NULL)
980 *bytesread = 0;
981 if (samplesread != NULL)
982 *samplesread = 0;
983 if (buffersize < 0)
984 return AVIERR_BADSIZE;
985 if ((DWORD)start < This->sInfo.dwStart ||
986 This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
987 return AVIERR_BADPARAM;
989 if (! This->bDecompress) {
990 /* audio like data -- sample-based */
991 do {
992 if (samples == 0)
993 return AVIERR_OK; /* nothing at all or already done */
995 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
996 &streamPos, &streamNr, FALSE)))
997 return AVIERR_ERROR;
999 /* limit to end of the stream */
1000 count = samples;
1001 if (streamPos + count > EditStreamEnd(This, streamNr))
1002 count = EditStreamEnd(This, streamNr) - streamPos;
1004 hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize,
1005 &readBytes, &readSamples);
1006 if (FAILED(hr))
1007 return hr;
1008 if (readBytes == 0 && readSamples == 0 && count != 0)
1009 return AVIERR_FILEREAD; /* for bad stream implementations */
1011 if (samplesread != NULL)
1012 *samplesread += readSamples;
1013 if (bytesread != NULL)
1014 *bytesread += readBytes;
1015 if (buffer != NULL) {
1016 buffer = ((LPBYTE)buffer)+readBytes;
1017 buffersize -= readBytes;
1019 start += count;
1020 samples -= count;
1021 } while (This->sInfo.dwStart + This->sInfo.dwLength > start);
1022 } else {
1023 /* video like data -- frame-based */
1024 LPBITMAPINFOHEADER lp;
1026 if (samples == 0)
1027 return AVIERR_OK;
1029 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
1030 &streamPos, &streamNr, FALSE)))
1031 return AVIERR_ERROR;
1033 lp = AVIFILE_ReadFrame(This, stream, streamPos);
1034 if (lp == NULL)
1035 return AVIERR_ERROR;
1037 if (buffer != NULL) {
1038 /* need size of format to skip */
1039 if (lp->biBitCount <= 8) {
1040 count = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount;
1041 count *= sizeof(RGBQUAD);
1042 } else
1043 count = 0;
1044 count += lp->biSize;
1046 if (buffersize < lp->biSizeImage)
1047 return AVIERR_BUFFERTOOSMALL;
1048 memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage);
1051 if (bytesread != NULL)
1052 *bytesread = lp->biSizeImage;
1053 if (samplesread != NULL)
1054 *samplesread = 1;
1057 return AVIERR_OK;
1060 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
1061 LONG samples,LPVOID buffer,
1062 LONG buffersize,DWORD flags,
1063 LONG*sampwritten,LONG*byteswritten)
1065 TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n",iface,start,samples,buffer,
1066 buffersize,flags,sampwritten,byteswritten);
1068 /* be sure return parameters have correct values */
1069 if (sampwritten != NULL)
1070 *sampwritten = 0;
1071 if (byteswritten != NULL)
1072 *byteswritten = 0;
1074 return AVIERR_UNSUPPORTED;
1077 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,
1078 LONG samples)
1080 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1082 TRACE("(%p,%d,%d)\n",iface,start,samples);
1084 return IAVIEditStream_Cut((IAVIEditStream*)This->pae,&start,&samples,NULL);
1087 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
1088 LPVOID lp,LONG *lpread)
1090 IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
1091 DWORD n;
1093 TRACE("(%p,0x%08X,%p,%p)\n",iface,fcc,lp,lpread);
1095 /* check parameters */
1096 if (lp == NULL || lpread == NULL)
1097 return AVIERR_BADPARAM;
1099 /* simply ask every stream and return the first block found */
1100 for (n = 0; n < This->nStreams; n++) {
1101 HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread);
1103 if (SUCCEEDED(hr))
1104 return hr;
1107 *lpread = 0;
1108 return AVIERR_NODATA;
1111 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
1112 LPVOID lp,LONG size)
1114 TRACE("(%p,0x%08X,%p,%d)\n",iface,fcc,lp,size);
1116 return AVIERR_UNSUPPORTED;
1119 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,
1120 AVISTREAMINFOW*info,LONG len)
1122 IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1124 TRACE("(%p,%p,%d)\n",iface,info,len);
1126 return IAVIEditStream_SetInfo((IAVIEditStream*)This->pae,info,len);
1129 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj)
1131 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1133 assert(This->pae != NULL);
1135 return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae, refiid, obj);
1138 static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface)
1140 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1142 assert(This->pae != NULL);
1144 return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
1147 static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface)
1149 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1151 assert(This->pae != NULL);
1153 return IAVIEditStream_Release((IAVIEditStream*)This->pae);
1156 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl)
1158 IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1160 TRACE("(%p,%p) -> %p\n", iface, ppimpl, This->pae);
1162 assert(This->pae != NULL);
1163 assert(ppimpl != NULL);
1165 *ppimpl = This->pae;
1166 return AVIERR_OK;