| /* | |
| * Copyright 2003 Michael Günnewig | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #define COM_NO_WINDOWS_H | |
| #include <assert.h> | |
| #include <stdarg.h> | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winuser.h" | |
| #include "wingdi.h" | |
| #include "winnls.h" | |
| #include "winerror.h" | |
| #include "windowsx.h" | |
| #include "mmsystem.h" | |
| #include "vfw.h" | |
| #include "avifile_private.h" | |
| #include "extrachunk.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(avifile); | |
| /***********************************************************************/ | |
| /* internal interface to get access to table of stream in an editable stream */ | |
| typedef struct IEditStreamInternal IEditStreamInternal; | |
| typedef struct _EditStreamTable { | |
| PAVISTREAM pStream; /* stream which contains the data */ | |
| DWORD dwStart; /* where starts the part which is also our */ | |
| DWORD dwLength; /* how many is also in this stream */ | |
| } EditStreamTable; | |
| #define INTERFACE IEditStreamInternal | |
| DECLARE_INTERFACE_(IEditStreamInternal,IUnknown) | |
| { | |
| /*** IUnknown methods ***/ | |
| STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; | |
| STDMETHOD_(ULONG,AddRef)(THIS) PURE; | |
| STDMETHOD_(ULONG,Release)(THIS) PURE; | |
| /*** IEditStreamInternal methods ***/ | |
| STDMETHOD(GetEditStreamImpl)(THIS_ LPVOID*) PURE; | |
| }; | |
| #undef INTERFACE | |
| #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \ | |
| (This)->pStreams[streamNr].dwLength) | |
| /***********************************************************************/ | |
| static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj); | |
| static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface); | |
| static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface); | |
| static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart, | |
| LONG*plLength,PAVISTREAM*ppResult); | |
| static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart, | |
| LONG*plLength,PAVISTREAM*ppResult); | |
| static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart, | |
| LONG*plLength,PAVISTREAM pSource, | |
| LONG lStart,LONG lEnd); | |
| static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface, | |
| PAVISTREAM*ppResult); | |
| static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface, | |
| LPAVISTREAMINFOW asi,LONG size); | |
| struct IAVIEditStreamVtbl ieditstream = { | |
| IAVIEditStream_fnQueryInterface, | |
| IAVIEditStream_fnAddRef, | |
| IAVIEditStream_fnRelease, | |
| IAVIEditStream_fnCut, | |
| IAVIEditStream_fnCopy, | |
| IAVIEditStream_fnPaste, | |
| IAVIEditStream_fnClone, | |
| IAVIEditStream_fnSetInfo | |
| }; | |
| static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID*obj); | |
| static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface); | |
| static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface); | |
| static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2); | |
| static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size); | |
| static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos, | |
| LONG flags); | |
| static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG*formatsize); | |
| static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize); | |
| static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start, | |
| LONG samples,LPVOID buffer, | |
| LONG buffersize,LONG*bytesread, | |
| LONG*samplesread); | |
| static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start, | |
| LONG samples,LPVOID buffer, | |
| LONG buffersize,DWORD flags, | |
| LONG*sampwritten,LONG*byteswritten); | |
| static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples); | |
| static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc, | |
| LPVOID lp,LONG *lpread); | |
| static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc, | |
| LPVOID lp,LONG size); | |
| static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen); | |
| struct IAVIStreamVtbl ieditstast = { | |
| IEditAVIStream_fnQueryInterface, | |
| IEditAVIStream_fnAddRef, | |
| IEditAVIStream_fnRelease, | |
| IEditAVIStream_fnCreate, | |
| IEditAVIStream_fnInfo, | |
| IEditAVIStream_fnFindSample, | |
| IEditAVIStream_fnReadFormat, | |
| IEditAVIStream_fnSetFormat, | |
| IEditAVIStream_fnRead, | |
| IEditAVIStream_fnWrite, | |
| IEditAVIStream_fnDelete, | |
| IEditAVIStream_fnReadData, | |
| IEditAVIStream_fnWriteData, | |
| IEditAVIStream_fnSetInfo | |
| }; | |
| static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj); | |
| static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface); | |
| static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface); | |
| static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl); | |
| struct IEditStreamInternalVtbl ieditstreaminternal = { | |
| IEditStreamInternal_fnQueryInterface, | |
| IEditStreamInternal_fnAddRef, | |
| IEditStreamInternal_fnRelease, | |
| IEditStreamInternal_fnGetEditStreamImpl | |
| }; | |
| typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl; | |
| typedef struct _IEditAVIStreamImpl { | |
| /* IUnknown stuff */ | |
| IAVIStreamVtbl *lpVtbl; | |
| /* IAVIStream stuff */ | |
| IAVIEditStreamImpl *pae; | |
| } IEditAVIStreamImpl; | |
| typedef struct _IEditStreamInternalImpl { | |
| /* IUnknown stuff */ | |
| IEditStreamInternalVtbl *lpVtbl; | |
| /* IEditStreamInternal stuff */ | |
| IAVIEditStreamImpl *pae; | |
| } IEditStreamInternalImpl; | |
| struct _IAVIEditStreamImpl { | |
| /* IUnknown stuff */ | |
| IAVIEditStreamVtbl *lpVtbl; | |
| DWORD ref; | |
| /* IAVIEditStream stuff */ | |
| IEditAVIStreamImpl iAVIStream; | |
| IEditStreamInternalImpl iEditStreamInternal; | |
| AVISTREAMINFOW sInfo; | |
| EditStreamTable *pStreams; | |
| DWORD nStreams; /* current fill level of pStreams table */ | |
| DWORD nTableSize; /* size of pStreams table */ | |
| BOOL bDecompress; | |
| PAVISTREAM pCurStream; | |
| PGETFRAME pg; /* IGetFrame for pCurStream */ | |
| LPBITMAPINFOHEADER lpFrame; /* frame of pCurStream */ | |
| }; | |
| /***********************************************************************/ | |
| PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream) | |
| { | |
| IAVIEditStreamImpl *pedit = NULL; | |
| pedit = (IAVIEditStreamImpl*)LocalAlloc(LPTR,sizeof(IAVIEditStreamImpl)); | |
| if (pedit == NULL) | |
| return NULL; | |
| pedit->lpVtbl = &ieditstream; | |
| pedit->iAVIStream.lpVtbl = &ieditstast; | |
| pedit->iAVIStream.pae = pedit; | |
| pedit->iEditStreamInternal.lpVtbl = &ieditstreaminternal; | |
| pedit->iEditStreamInternal.pae = pedit; | |
| pedit->ref = 1; | |
| IAVIStream_Create((PAVISTREAM)&pedit->iAVIStream,(LPARAM)pstream,0); | |
| return (PAVIEDITSTREAM)pedit; | |
| } | |
| static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This, | |
| DWORD pos,PAVISTREAM *ppStream, | |
| DWORD* streamPos, | |
| DWORD* streamNr,BOOL bFindSample) | |
| { | |
| DWORD n; | |
| TRACE("(%p,%lu,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos, | |
| streamNr,bFindSample); | |
| if (pos < This->sInfo.dwStart) | |
| return AVIERR_BADPARAM; | |
| pos -= This->sInfo.dwStart; | |
| for (n = 0; n < This->nStreams; n++) { | |
| if (pos < This->pStreams[n].dwLength) { | |
| *ppStream = This->pStreams[n].pStream; | |
| *streamPos = This->pStreams[n].dwStart + pos; | |
| if (streamNr != NULL) | |
| *streamNr = n; | |
| return AVIERR_OK; | |
| } | |
| pos -= This->pStreams[n].dwLength; | |
| } | |
| if (pos == 0 && bFindSample) { | |
| *ppStream = This->pStreams[--n].pStream; | |
| *streamPos = EditStreamEnd(This, n); | |
| if (streamNr != NULL) | |
| *streamNr = n; | |
| TRACE(" -- pos=0 && b=1 -> (%p,%lu,%lu)\n",*ppStream, *streamPos, n); | |
| return AVIERR_OK; | |
| } else { | |
| *ppStream = NULL; | |
| *streamPos = 0; | |
| if (streamNr != NULL) | |
| *streamNr = 0; | |
| TRACE(" -> ERROR (NULL,0,0)\n"); | |
| return AVIERR_BADPARAM; | |
| } | |
| } | |
| static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This, | |
| PAVISTREAM pstream, LONG pos) | |
| { | |
| PGETFRAME pg; | |
| TRACE("(%p,%p,%ld)\n",This,pstream,pos); | |
| if (pstream == NULL) | |
| return NULL; | |
| /* if stream changes make sure that only palette changes */ | |
| if (This->pCurStream != pstream) { | |
| pg = AVIStreamGetFrameOpen(pstream, NULL); | |
| if (pg == NULL) | |
| return NULL; | |
| if (This->pg != NULL) { | |
| if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1)) { | |
| AVIStreamGetFrameClose(pg); | |
| ERR(": IGetFrame_SetFormat failed\n"); | |
| return NULL; | |
| } | |
| AVIStreamGetFrameClose(This->pg); | |
| } | |
| This->pg = pg; | |
| This->pCurStream = pstream; | |
| } | |
| /* now get the decompressed frame */ | |
| This->lpFrame = AVIStreamGetFrame(This->pg, pos); | |
| if (This->lpFrame != NULL) | |
| This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage; | |
| return This->lpFrame; | |
| } | |
| static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr) | |
| { | |
| assert(This != NULL); | |
| assert(nr < This->nStreams); | |
| /* remove part nr */ | |
| IAVIStream_Release(This->pStreams[nr].pStream); | |
| This->nStreams--; | |
| if (This->nStreams - nr > 0) { | |
| memmove(This->pStreams + nr, This->pStreams + nr + 1, | |
| (This->nStreams - nr) * sizeof(EditStreamTable)); | |
| } | |
| This->pStreams[This->nStreams].pStream = NULL; | |
| This->pStreams[This->nStreams].dwStart = 0; | |
| This->pStreams[This->nStreams].dwLength = 0; | |
| /* try to merge the part before the deleted one and the one after it */ | |
| if (0 < nr && 0 < This->nStreams && | |
| This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) { | |
| if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) { | |
| This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength; | |
| return AVIFILE_RemoveStream(This, nr); | |
| } | |
| } | |
| return AVIERR_OK; | |
| } | |
| static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2) | |
| { | |
| LPVOID fmt1 = NULL, fmt2 = NULL; | |
| LONG size1, size2, start1, start2; | |
| BOOL status = FALSE; | |
| assert(avi1 != NULL && avi2 != NULL); | |
| /* get stream starts and check format sizes */ | |
| start1 = AVIStreamStart(avi1); | |
| start2 = AVIStreamStart(avi2); | |
| if (FAILED(AVIStreamFormatSize(avi1, start1, &size1))) | |
| return FALSE; | |
| if (FAILED(AVIStreamFormatSize(avi2, start2, &size2))) | |
| return FALSE; | |
| if (size1 != size2) | |
| return FALSE; | |
| /* sizes match, now get formats and compare them */ | |
| fmt1 = GlobalAllocPtr(GHND, size1); | |
| if (fmt1 == NULL) | |
| return FALSE; | |
| if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) { | |
| fmt2 = GlobalAllocPtr(GHND, size1); | |
| if (fmt2 != NULL) { | |
| if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1))) | |
| status = (memcmp(fmt1, fmt2, size1) == 0); | |
| } | |
| } | |
| if (fmt2 != NULL) | |
| GlobalFreePtr(fmt2); | |
| GlobalFreePtr(fmt1); | |
| return status; | |
| } | |
| /***********************************************************************/ | |
| static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj) | |
| { | |
| IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface; | |
| TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj); | |
| if (IsEqualGUID(&IID_IUnknown, refiid) || | |
| IsEqualGUID(&IID_IAVIEditStream, refiid)) { | |
| *obj = iface; | |
| IAVIEditStream_AddRef(iface); | |
| return S_OK; | |
| } else if (IsEqualGUID(&IID_IAVIStream, refiid)) { | |
| *obj = &This->iAVIStream; | |
| IAVIEditStream_AddRef(iface); | |
| return S_OK; | |
| } else if (IsEqualGUID(&IID_IEditStreamInternal, refiid)) { | |
| *obj = &This->iEditStreamInternal; | |
| IAVIEditStream_AddRef(iface); | |
| return S_OK; | |
| } | |
| return OLE_E_ENUM_NOMORE; | |
| } | |
| static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface) | |
| { | |
| IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface; | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) -> %ld\n", iface, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface) | |
| { | |
| IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface; | |
| DWORD i; | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p) -> %ld\n", iface, ref); | |
| if (!ref) { | |
| /* release memory */ | |
| if (This->pg != NULL) | |
| AVIStreamGetFrameClose(This->pg); | |
| if (This->pStreams != NULL) { | |
| for (i = 0; i < This->nStreams; i++) { | |
| if (This->pStreams[i].pStream != NULL) | |
| IAVIStream_Release(This->pStreams[i].pStream); | |
| } | |
| GlobalFreePtr(This->pStreams); | |
| } | |
| LocalFree((HLOCAL)This); | |
| return 0; | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart, | |
| LONG*plLength,PAVISTREAM*ppResult) | |
| { | |
| IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface; | |
| PAVISTREAM stream; | |
| DWORD start, len, streamPos, streamNr; | |
| HRESULT hr; | |
| TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult); | |
| if (ppResult != NULL) | |
| *ppResult = NULL; | |
| if (plStart == NULL || plLength == NULL || *plStart < 0) | |
| return AVIERR_BADPARAM; | |
| /* if asked for cutted part copy it before deleting */ | |
| if (ppResult != NULL) { | |
| hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult); | |
| if (FAILED(hr)) | |
| return hr; | |
| } | |
| start = *plStart; | |
| len = *plLength; | |
| /* now delete the requested part */ | |
| while (len > 0) { | |
| hr = AVIFILE_FindStreamInTable(This, start, &stream, | |
| &streamPos, &streamNr, FALSE); | |
| if (FAILED(hr)) | |
| return hr; | |
| if (This->pStreams[streamNr].dwStart == streamPos) { | |
| /* deleting from start of part */ | |
| if (len < This->pStreams[streamNr].dwLength) { | |
| start += len; | |
| This->pStreams[streamNr].dwStart += len; | |
| This->pStreams[streamNr].dwLength -= len; | |
| This->sInfo.dwLength -= len; | |
| len = 0; | |
| /* we must return decompressed data now */ | |
| This->bDecompress = TRUE; | |
| } else { | |
| /* deleting hole part */ | |
| len -= This->pStreams[streamNr].dwLength; | |
| AVIFILE_RemoveStream(This,streamNr); | |
| } | |
| } else if (EditStreamEnd(This, streamNr) <= streamPos + len) { | |
| /* deleting at end of a part */ | |
| DWORD count = EditStreamEnd(This, streamNr) - streamPos; | |
| This->sInfo.dwLength -= count; | |
| len -= count; | |
| This->pStreams[streamNr].dwLength = | |
| streamPos - This->pStreams[streamNr].dwStart; | |
| } else { | |
| /* splitting */ | |
| if (This->nStreams + 1 >= This->nTableSize) { | |
| This->pStreams = | |
| GlobalReAllocPtr(This->pStreams, (This->nTableSize + 32) * sizeof(EditStreamTable), GMEM_SHARE|GHND); | |
| if (This->pStreams == NULL) | |
| return AVIERR_MEMORY; | |
| This->nTableSize += 32; | |
| } | |
| memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr, | |
| (This->nStreams - streamNr) * sizeof(EditStreamTable)); | |
| This->nStreams++; | |
| IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream); | |
| This->pStreams[streamNr + 1].dwStart = streamPos + len; | |
| This->pStreams[streamNr + 1].dwLength = | |
| EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart; | |
| This->pStreams[streamNr].dwLength = | |
| streamPos - This->pStreams[streamNr].dwStart; | |
| This->sInfo.dwLength -= len; | |
| len = 0; | |
| } | |
| } | |
| This->sInfo.dwEditCount++; | |
| return AVIERR_OK; | |
| } | |
| static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart, | |
| LONG*plLength,PAVISTREAM*ppResult) | |
| { | |
| IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface; | |
| IAVIEditStreamImpl* pEdit; | |
| HRESULT hr; | |
| LONG start = 0; | |
| TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult); | |
| if (ppResult == NULL) | |
| return AVIERR_BADPARAM; | |
| *ppResult = NULL; | |
| if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0) | |
| return AVIERR_BADPARAM; | |
| /* check bounds */ | |
| if (*(LPDWORD)plLength > This->sInfo.dwLength) | |
| *(LPDWORD)plLength = This->sInfo.dwLength; | |
| if (*(LPDWORD)plStart < This->sInfo.dwStart) { | |
| *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart; | |
| *(LPDWORD)plStart = This->sInfo.dwStart; | |
| if (*plLength < 0) | |
| return AVIERR_BADPARAM; | |
| } | |
| if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength) | |
| *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength - | |
| *(LPDWORD)plStart; | |
| pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL); | |
| if (pEdit == NULL) | |
| return AVIERR_MEMORY; | |
| hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength, | |
| (PAVISTREAM)&This->iAVIStream,*plStart, | |
| *plStart + *plLength); | |
| *plStart = start; | |
| if (FAILED(hr)) | |
| IAVIEditStream_Release((PAVIEDITSTREAM)pEdit); | |
| else | |
| *ppResult = (PAVISTREAM)&pEdit->iAVIStream; | |
| return hr; | |
| } | |
| static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart, | |
| LONG*plLength,PAVISTREAM pSource, | |
| LONG lStart,LONG lLength) | |
| { | |
| IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface; | |
| AVISTREAMINFOW srcInfo; | |
| IEditStreamInternal*pInternal = NULL; | |
| IAVIEditStreamImpl *pEdit = NULL; | |
| PAVISTREAM pStream; | |
| DWORD startPos, endPos, streamNr, nStreams; | |
| LONG n; | |
| TRACE("(%p,%p,%p,%p,%ld,%ld)\n",iface,plStart,plLength, | |
| pSource,lStart,lLength); | |
| if (pSource == NULL) | |
| return AVIERR_BADHANDLE; | |
| if (plStart == NULL || *plStart < 0) | |
| return AVIERR_BADPARAM; | |
| if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart) | |
| return AVIERR_BADPARAM; /* Can't paste with holes */ | |
| if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo)))) | |
| return AVIERR_ERROR; | |
| if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength) | |
| return AVIERR_BADPARAM; | |
| if (This->sInfo.fccType == 0) { | |
| /* This stream is empty */ | |
| IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo)); | |
| This->sInfo.dwStart = *plStart; | |
| This->sInfo.dwLength = 0; | |
| } | |
| if (This->sInfo.fccType != srcInfo.fccType) | |
| return AVIERR_UNSUPPORTED; /* different stream types */ | |
| if (lLength == -1) /* Copy the hole stream */ | |
| lLength = srcInfo.dwLength; | |
| if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength) | |
| lLength = srcInfo.dwStart + srcInfo.dwLength - lStart; | |
| if (lLength + *plStart >= 0x80000000) | |
| return AVIERR_MEMORY; | |
| /* streamtype specific tests */ | |
| if (srcInfo.fccType == streamtypeVIDEO) { | |
| LONG size; | |
| size = srcInfo.rcFrame.right - srcInfo.rcFrame.left; | |
| if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left) | |
| return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */ | |
| size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top; | |
| if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top) | |
| return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */ | |
| } else if (srcInfo.fccType == streamtypeAUDIO) { | |
| if (! AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource)) | |
| return AVIERR_UNSUPPORTED; | |
| } else { | |
| /* FIXME: streamtypeMIDI and streamtypeTEXT */ | |
| return AVIERR_UNSUPPORTED; | |
| } | |
| /* try to get an IEditStreamInternal interface */ | |
| if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal, | |
| (LPVOID*)&pInternal))) { | |
| pInternal->lpVtbl->GetEditStreamImpl(pInternal, (LPVOID*)&pEdit); | |
| pInternal->lpVtbl->Release(pInternal); | |
| } | |
| /* for video must check for change of format */ | |
| if (This->sInfo.fccType == streamtypeVIDEO) { | |
| if (! This->bDecompress) { | |
| /* Need to decompress if any of the following conditions matches: | |
| * - pSource is an editable stream which decompresses | |
| * - the nearest keyframe of pSource isn't lStart | |
| * - the nearest keyframe of this stream isn't *plStart | |
| * - the format of pSource doesn't match this one | |
| */ | |
| if ((pEdit != NULL && pEdit->bDecompress) || | |
| AVIStreamNearestKeyFrame(pSource, lStart) != lStart || | |
| AVIStreamNearestKeyFrame((PAVISTREAM)&This->iAVIStream, *plStart) != *plStart || | |
| (This->nStreams > 0 && !AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))) { | |
| /* Use first stream part to get format to convert everything to */ | |
| AVIFILE_ReadFrame(This, This->pStreams[0].pStream, | |
| This->pStreams[0].dwStart); | |
| /* Check if we could convert the source streams to the disired format... */ | |
| if (pEdit != NULL) { | |
| if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, | |
| &startPos, &streamNr, TRUE))) | |
| return AVIERR_INTERNAL; | |
| for (n = lStart; n < lStart + lLength; streamNr++) { | |
| if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL) | |
| return AVIERR_BADFORMAT; | |
| startPos = pEdit->pStreams[streamNr].dwStart; | |
| n += pEdit->pStreams[streamNr].dwLength; | |
| } | |
| } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL) | |
| return AVIERR_BADFORMAT; | |
| This->bDecompress = TRUE; | |
| This->sInfo.fccHandler = 0; | |
| } | |
| } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL) | |
| return AVIERR_BADFORMAT; /* Can't convert source to own format */ | |
| } /* FIXME: something special for the other formats? */ | |
| /* Make sure we have enough memory for parts */ | |
| if (pEdit != NULL) { | |
| DWORD nLastStream; | |
| AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream, | |
| &endPos, &nLastStream, TRUE); | |
| AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, | |
| &startPos, &streamNr, FALSE); | |
| if (nLastStream == streamNr) | |
| nLastStream++; | |
| nStreams = nLastStream - streamNr; | |
| } else | |
| nStreams = 1; | |
| if (This->nStreams + nStreams + 1 > This->nTableSize) { | |
| n = This->nStreams + nStreams + 33; | |
| This->pStreams = | |
| GlobalReAllocPtr(This->pStreams, n * sizeof(EditStreamTable), GMEM_SHARE|GHND); | |
| if (This->pStreams == NULL) | |
| return AVIERR_MEMORY; | |
| This->nTableSize = n; | |
| } | |
| if (plLength != NULL) | |
| *plLength = lLength; | |
| /* now do the real work */ | |
| if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) { | |
| AVIFILE_FindStreamInTable(This, *plStart, &pStream, | |
| &startPos, &streamNr, FALSE); | |
| if (startPos != This->pStreams[streamNr].dwStart) { | |
| /* split stream streamNr at startPos */ | |
| memmove(This->pStreams + streamNr + nStreams + 1, | |
| This->pStreams + streamNr, | |
| (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable)); | |
| This->pStreams[streamNr + 2].dwLength = | |
| EditStreamEnd(This, streamNr + 2) - startPos; | |
| This->pStreams[streamNr + 2].dwStart = startPos; | |
| This->pStreams[streamNr].dwLength = | |
| startPos - This->pStreams[streamNr].dwStart; | |
| IAVIStream_AddRef(This->pStreams[streamNr].pStream); | |
| streamNr++; | |
| } else { | |
| /* insert before stream at streamNr */ | |
| memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr, | |
| (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable)); | |
| } | |
| } else /* append the streams */ | |
| streamNr = This->nStreams; | |
| if (pEdit != NULL) { | |
| /* insert the parts of the editable stream instead of itself */ | |
| AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream, | |
| &endPos, NULL, FALSE); | |
| AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE); | |
| memcpy(This->pStreams + streamNr, pEdit->pStreams + n, | |
| nStreams * sizeof(EditStreamTable)); | |
| if (This->pStreams[streamNr].dwStart < startPos) { | |
| This->pStreams[streamNr].dwLength = | |
| EditStreamEnd(This, streamNr) - startPos; | |
| This->pStreams[streamNr].dwStart = startPos; | |
| } | |
| if (endPos < EditStreamEnd(This, streamNr + nStreams)) | |
| This->pStreams[streamNr + nStreams].dwLength = | |
| endPos - This->pStreams[streamNr + nStreams].dwStart; | |
| } else { | |
| /* a simple stream */ | |
| This->pStreams[streamNr].pStream = pSource; | |
| This->pStreams[streamNr].dwStart = lStart; | |
| This->pStreams[streamNr].dwLength = lLength; | |
| } | |
| for (n = 0; n < nStreams; n++) { | |
| IAVIStream_AddRef(This->pStreams[streamNr + n].pStream); | |
| if (0 < streamNr + n && | |
| This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) { | |
| This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES; | |
| This->sInfo.dwFormatChangeCount++; | |
| } | |
| } | |
| This->sInfo.dwEditCount++; | |
| This->sInfo.dwLength += lLength; | |
| This->nStreams += nStreams; | |
| return AVIERR_OK; | |
| } | |
| static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface, | |
| PAVISTREAM*ppResult) | |
| { | |
| IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface; | |
| IAVIEditStreamImpl* pEdit; | |
| DWORD i; | |
| TRACE("(%p,%p)\n",iface,ppResult); | |
| if (ppResult == NULL) | |
| return AVIERR_BADPARAM; | |
| *ppResult = NULL; | |
| pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL); | |
| if (pEdit == NULL) | |
| return AVIERR_MEMORY; | |
| if (This->nStreams > pEdit->nTableSize) { | |
| pEdit->pStreams = GlobalReAllocPtr(pEdit->pStreams, This->nStreams * sizeof(EditStreamTable),GMEM_SHARE|GHND); | |
| if (pEdit->pStreams == NULL) | |
| return AVIERR_MEMORY; | |
| pEdit->nTableSize = This->nStreams; | |
| } | |
| pEdit->nStreams = This->nStreams; | |
| memcpy(pEdit->pStreams, This->pStreams, | |
| This->nStreams * sizeof(EditStreamTable)); | |
| memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo)); | |
| for (i = 0; i < This->nStreams; i++) { | |
| if (pEdit->pStreams[i].pStream != NULL) | |
| IAVIStream_AddRef(pEdit->pStreams[i].pStream); | |
| } | |
| *ppResult = (PAVISTREAM)&pEdit->iAVIStream; | |
| return AVIERR_OK; | |
| } | |
| static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface, | |
| LPAVISTREAMINFOW asi,LONG size) | |
| { | |
| IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface; | |
| TRACE("(%p,%p,%ld)\n",iface,asi,size); | |
| /* check parameters */ | |
| if (asi == NULL) | |
| return AVIERR_BADPARAM; | |
| if (size != sizeof(AVISTREAMINFOW)) | |
| return AVIERR_BADSIZE; | |
| if (asi->dwScale == 0 || asi->dwRate == 0 || (LONG)asi->dwQuality < -1 || | |
| asi->dwQuality > ICQUALITY_HIGH) | |
| return AVIERR_ERROR; | |
| This->sInfo.wLanguage = asi->wLanguage; | |
| This->sInfo.wPriority = asi->wPriority; | |
| This->sInfo.dwStart = asi->dwStart; | |
| if (asi->dwRate != 0) | |
| This->sInfo.dwRate = asi->dwRate; | |
| if (asi->dwScale != 0) | |
| This->sInfo.dwScale = asi->dwScale; | |
| if (asi->dwQuality <= ICQUALITY_HIGH) | |
| This->sInfo.dwQuality = ICQUALITY_HIGH; | |
| CopyRect(&This->sInfo.rcFrame, &asi->rcFrame); | |
| memcpy(&This->sInfo.szName, &asi->szName, sizeof(asi->szName)); | |
| This->sInfo.dwEditCount++; | |
| return AVIERR_OK; | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface, | |
| REFIID refiid,LPVOID*obj) | |
| { | |
| IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface; | |
| assert(This->pae != NULL); | |
| return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae,refiid,obj); | |
| } | |
| static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface) | |
| { | |
| IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface; | |
| assert(This->pae != NULL); | |
| return IAVIEditStream_AddRef((IAVIEditStream*)This->pae); | |
| } | |
| static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface) | |
| { | |
| IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface; | |
| assert(This->pae != NULL); | |
| return IAVIEditStream_Release((IAVIEditStream*)This->pae); | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface, | |
| LPARAM lParam1,LPARAM lParam2) | |
| { | |
| IAVIEditStreamImpl *This = ((IEditAVIStreamImpl*)iface)->pae; | |
| if (lParam2 != 0) | |
| return AVIERR_ERROR; | |
| if (This->pStreams == NULL) { | |
| This->pStreams = | |
| GlobalAllocPtr(GMEM_SHARE|GHND, 256 * sizeof(EditStreamTable)); | |
| if (This->pStreams == NULL) | |
| return AVIERR_MEMORY; | |
| This->nTableSize = 256; | |
| } | |
| if (lParam1 != 0) { | |
| IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo)); | |
| IAVIStream_AddRef((PAVISTREAM)lParam1); | |
| This->pStreams[0].pStream = (PAVISTREAM)lParam1; | |
| This->pStreams[0].dwStart = This->sInfo.dwStart; | |
| This->pStreams[0].dwLength = This->sInfo.dwLength; | |
| This->nStreams = 1; | |
| } | |
| return AVIERR_OK; | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface, | |
| AVISTREAMINFOW *psi,LONG size) | |
| { | |
| IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface; | |
| TRACE("(%p,%p,%ld)\n",iface,psi,size); | |
| assert(This->pae != NULL); | |
| if (psi == NULL) | |
| return AVIERR_BADPARAM; | |
| if (size < 0) | |
| return AVIERR_BADSIZE; | |
| if (This->pae->bDecompress) | |
| This->pae->sInfo.fccHandler = 0; | |
| memcpy(psi, &This->pae->sInfo, min((DWORD)size, sizeof(This->pae->sInfo))); | |
| if ((DWORD)size < sizeof(This->pae->sInfo)) | |
| return AVIERR_BUFFERTOOSMALL; | |
| return AVIERR_OK; | |
| } | |
| static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos, | |
| LONG flags) | |
| { | |
| IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae; | |
| PAVISTREAM stream; | |
| DWORD streamPos, streamNr; | |
| TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags); | |
| if (flags & FIND_FROM_START) | |
| pos = (LONG)This->sInfo.dwStart; | |
| /* outside of stream? */ | |
| if (pos < (LONG)This->sInfo.dwStart || | |
| (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos) | |
| return -1; | |
| /* map our position to a stream and position in it */ | |
| if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos, | |
| &streamNr, TRUE)) | |
| return -1; /* doesn't exist */ | |
| if (This->bDecompress) { | |
| /* only one stream -- format changes only at start */ | |
| if (flags & FIND_FORMAT) | |
| return (flags & FIND_NEXT ? -1 : 0); | |
| /* FIXME: map positions back to us */ | |
| return IAVIStream_FindSample(stream, streamPos, flags); | |
| } else { | |
| /* assume change of format every frame */ | |
| return pos; | |
| } | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos, | |
| LPVOID format,LONG*fmtsize) | |
| { | |
| IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae; | |
| LPBITMAPINFOHEADER lp; | |
| PAVISTREAM stream; | |
| DWORD n; | |
| HRESULT hr; | |
| TRACE("(%p,%ld,%p,%p)\n",iface,pos,format,fmtsize); | |
| if (fmtsize == NULL || pos < This->sInfo.dwStart || | |
| This->sInfo.dwStart + This->sInfo.dwLength <= pos) | |
| return AVIERR_BADPARAM; | |
| /* find stream corresponding to position */ | |
| hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE); | |
| if (FAILED(hr)) | |
| return hr; | |
| if (! This->bDecompress) | |
| return IAVIStream_ReadFormat(stream, n, format, fmtsize); | |
| lp = (LPBITMAPINFOHEADER)AVIFILE_ReadFrame(This, stream, n); | |
| if (lp == NULL) | |
| return AVIERR_ERROR; | |
| if (lp->biBitCount <= 8) { | |
| n = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount); | |
| n *= sizeof(RGBQUAD); | |
| } else | |
| n = 0; | |
| n += lp->biSize; | |
| memcpy(format, lp, min((LONG)n, *fmtsize)); | |
| hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK); | |
| *fmtsize = n; | |
| return hr; | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos, | |
| LPVOID format,LONG formatsize) | |
| { | |
| TRACE("(%p,%ld,%p,%ld)\n",iface,pos,format,formatsize); | |
| return AVIERR_UNSUPPORTED; | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start, | |
| LONG samples,LPVOID buffer, | |
| LONG buffersize,LONG*bytesread, | |
| LONG*samplesread) | |
| { | |
| IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae; | |
| PAVISTREAM stream; | |
| DWORD streamPos, streamNr; | |
| LONG readBytes, readSamples, count; | |
| HRESULT hr; | |
| TRACE("(%p,%ld,%ld,%p,%ld,%p,%p) -- 0x%08lX\n",iface,start,samples, | |
| buffer,buffersize,bytesread,samplesread,This->sInfo.fccType); | |
| /* check parameters */ | |
| if (bytesread != NULL) | |
| *bytesread = 0; | |
| if (samplesread != NULL) | |
| *samplesread = 0; | |
| if (buffersize < 0) | |
| return AVIERR_BADSIZE; | |
| if ((DWORD)start < This->sInfo.dwStart || | |
| This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start) | |
| return AVIERR_BADPARAM; | |
| if (! This->bDecompress) { | |
| /* audio like data -- sample-based */ | |
| do { | |
| if (samples == 0) | |
| return AVIERR_OK; /* nothing at all or already done */ | |
| if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream, | |
| &streamPos, &streamNr, FALSE))) | |
| return AVIERR_ERROR; | |
| /* limit to end of the stream */ | |
| count = samples; | |
| if (streamPos + count > EditStreamEnd(This, streamNr)) | |
| count = EditStreamEnd(This, streamNr) - streamPos; | |
| hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize, | |
| &readBytes, &readSamples); | |
| if (FAILED(hr)) | |
| return hr; | |
| if (readBytes == 0 && readSamples == 0 && count != 0) | |
| return AVIERR_FILEREAD; /* for bad stream implementations */ | |
| if (samplesread != NULL) | |
| *samplesread += readSamples; | |
| if (bytesread != NULL) | |
| *bytesread += readBytes; | |
| if (buffer != NULL) { | |
| buffer = ((LPBYTE)buffer)+readBytes; | |
| buffersize -= readBytes; | |
| } | |
| start += count; | |
| samples -= count; | |
| } while (This->sInfo.dwStart + This->sInfo.dwLength > start); | |
| } else { | |
| /* video like data -- frame-based */ | |
| LPBITMAPINFOHEADER lp; | |
| if (samples == 0) | |
| return AVIERR_OK; | |
| if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream, | |
| &streamPos, &streamNr, FALSE))) | |
| return AVIERR_ERROR; | |
| lp = AVIFILE_ReadFrame(This, stream, streamPos); | |
| if (lp == NULL) | |
| return AVIERR_ERROR; | |
| if (buffer != NULL) { | |
| /* need size of format to skip */ | |
| if (lp->biBitCount <= 8) { | |
| count = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount; | |
| count *= sizeof(RGBQUAD); | |
| } else | |
| count = 0; | |
| count += lp->biSize; | |
| if (buffersize < lp->biSizeImage) | |
| return AVIERR_BUFFERTOOSMALL; | |
| memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage); | |
| } | |
| if (bytesread != NULL) | |
| *bytesread = lp->biSizeImage; | |
| if (samplesread != NULL) | |
| *samplesread = 1; | |
| } | |
| return AVIERR_OK; | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start, | |
| LONG samples,LPVOID buffer, | |
| LONG buffersize,DWORD flags, | |
| LONG*sampwritten,LONG*byteswritten) | |
| { | |
| TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n",iface,start,samples,buffer, | |
| buffersize,flags,sampwritten,byteswritten); | |
| /* be sure return parameters have correct values */ | |
| if (sampwritten != NULL) | |
| *sampwritten = 0; | |
| if (byteswritten != NULL) | |
| *byteswritten = 0; | |
| return AVIERR_UNSUPPORTED; | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start, | |
| LONG samples) | |
| { | |
| IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface; | |
| TRACE("(%p,%ld,%ld)\n",iface,start,samples); | |
| return IAVIEditStream_Cut((IAVIEditStream*)This->pae,&start,&samples,NULL); | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc, | |
| LPVOID lp,LONG *lpread) | |
| { | |
| IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae; | |
| DWORD n; | |
| TRACE("(%p,0x%08lX,%p,%p)\n",iface,fcc,lp,lpread); | |
| /* check parameters */ | |
| if (lp == NULL || lpread == NULL) | |
| return AVIERR_BADPARAM; | |
| /* simply ask every stream and return the first block found */ | |
| for (n = 0; n < This->nStreams; n++) { | |
| HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread); | |
| if (SUCCEEDED(hr)) | |
| return hr; | |
| } | |
| *lpread = 0; | |
| return AVIERR_NODATA; | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc, | |
| LPVOID lp,LONG size) | |
| { | |
| TRACE("(%p,0x%08lX,%p,%ld)\n",iface,fcc,lp,size); | |
| return AVIERR_UNSUPPORTED; | |
| } | |
| static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface, | |
| AVISTREAMINFOW*info,LONG len) | |
| { | |
| IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface; | |
| TRACE("(%p,%p,%ld)\n",iface,info,len); | |
| return IAVIEditStream_SetInfo((IAVIEditStream*)This->pae,info,len); | |
| } | |
| static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj) | |
| { | |
| IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface; | |
| assert(This->pae != NULL); | |
| return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae, refiid, obj); | |
| } | |
| static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface) | |
| { | |
| IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface; | |
| assert(This->pae != NULL); | |
| return IAVIEditStream_AddRef((IAVIEditStream*)This->pae); | |
| } | |
| static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface) | |
| { | |
| IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface; | |
| assert(This->pae != NULL); | |
| return IAVIEditStream_Release((IAVIEditStream*)This->pae); | |
| } | |
| static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl) | |
| { | |
| IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface; | |
| TRACE("(%p,%p) -> %p\n", iface, ppimpl, This->pae); | |
| assert(This->pae != NULL); | |
| assert(ppimpl != NULL); | |
| *ppimpl = This->pae; | |
| return AVIERR_OK; | |
| } |