Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygeneditstream.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2003 Michael Günnewig 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #include <assert.h> 00020 #include <stdarg.h> 00021 00022 #include "windef.h" 00023 #include "winbase.h" 00024 #include "winuser.h" 00025 #include "wingdi.h" 00026 #include "winerror.h" 00027 #include "mmsystem.h" 00028 #include "vfw.h" 00029 00030 #include "avifile_private.h" 00031 #include "extrachunk.h" 00032 00033 #include "wine/debug.h" 00034 #include "initguid.h" 00035 00036 WINE_DEFAULT_DEBUG_CHANNEL(avifile); 00037 00038 /***********************************************************************/ 00039 00040 /* internal interface to get access to table of stream in an editable stream */ 00041 00042 DEFINE_AVIGUID(IID_IEditStreamInternal, 0x0002000A,0,0); 00043 00044 typedef struct _EditStreamTable { 00045 PAVISTREAM pStream; /* stream which contains the data */ 00046 DWORD dwStart; /* where starts the part which is also our */ 00047 DWORD dwLength; /* how many is also in this stream */ 00048 } EditStreamTable; 00049 00050 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \ 00051 (This)->pStreams[streamNr].dwLength) 00052 00053 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl; 00054 00055 struct _IAVIEditStreamImpl { 00056 IAVIEditStream IAVIEditStream_iface; 00057 IAVIStream IAVIStream_iface; 00058 00059 LONG ref; 00060 00061 AVISTREAMINFOW sInfo; 00062 00063 EditStreamTable *pStreams; 00064 DWORD nStreams; /* current fill level of pStreams table */ 00065 DWORD nTableSize; /* size of pStreams table */ 00066 00067 BOOL bDecompress; 00068 PAVISTREAM pCurStream; 00069 PGETFRAME pg; /* IGetFrame for pCurStream */ 00070 LPBITMAPINFOHEADER lpFrame; /* frame of pCurStream */ 00071 }; 00072 00073 static inline IAVIEditStreamImpl *impl_from_IAVIEditStream(IAVIEditStream *iface) 00074 { 00075 return CONTAINING_RECORD(iface, IAVIEditStreamImpl, IAVIEditStream_iface); 00076 } 00077 00078 static inline IAVIEditStreamImpl *impl_from_IAVIStream(IAVIStream *iface) 00079 { 00080 return CONTAINING_RECORD(iface, IAVIEditStreamImpl, IAVIStream_iface); 00081 } 00082 00083 /***********************************************************************/ 00084 00085 static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This, 00086 DWORD pos,PAVISTREAM *ppStream, 00087 DWORD* streamPos, 00088 DWORD* streamNr,BOOL bFindSample) 00089 { 00090 DWORD n; 00091 00092 TRACE("(%p,%u,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos, 00093 streamNr,bFindSample); 00094 00095 if (pos < This->sInfo.dwStart) 00096 return AVIERR_BADPARAM; 00097 00098 pos -= This->sInfo.dwStart; 00099 for (n = 0; n < This->nStreams; n++) { 00100 if (pos < This->pStreams[n].dwLength) { 00101 *ppStream = This->pStreams[n].pStream; 00102 *streamPos = This->pStreams[n].dwStart + pos; 00103 if (streamNr != NULL) 00104 *streamNr = n; 00105 00106 return AVIERR_OK; 00107 } 00108 pos -= This->pStreams[n].dwLength; 00109 } 00110 if (pos == 0 && bFindSample) { 00111 *ppStream = This->pStreams[--n].pStream; 00112 *streamPos = EditStreamEnd(This, n); 00113 if (streamNr != NULL) 00114 *streamNr = n; 00115 00116 TRACE(" -- pos=0 && b=1 -> (%p,%u,%u)\n",*ppStream, *streamPos, n); 00117 return AVIERR_OK; 00118 } else { 00119 *ppStream = NULL; 00120 *streamPos = 0; 00121 if (streamNr != NULL) 00122 *streamNr = 0; 00123 00124 TRACE(" -> ERROR (NULL,0,0)\n"); 00125 return AVIERR_BADPARAM; 00126 } 00127 } 00128 00129 static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This, 00130 PAVISTREAM pstream, LONG pos) 00131 { 00132 PGETFRAME pg; 00133 00134 TRACE("(%p,%p,%d)\n",This,pstream,pos); 00135 00136 if (pstream == NULL) 00137 return NULL; 00138 00139 /* if stream changes make sure that only palette changes */ 00140 if (This->pCurStream != pstream) { 00141 pg = AVIStreamGetFrameOpen(pstream, NULL); 00142 if (pg == NULL) 00143 return NULL; 00144 if (This->pg != NULL) { 00145 if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1) != S_OK) { 00146 AVIStreamGetFrameClose(pg); 00147 ERR(": IGetFrame_SetFormat failed\n"); 00148 return NULL; 00149 } 00150 AVIStreamGetFrameClose(This->pg); 00151 } 00152 This->pg = pg; 00153 This->pCurStream = pstream; 00154 } 00155 00156 /* now get the decompressed frame */ 00157 This->lpFrame = AVIStreamGetFrame(This->pg, pos); 00158 if (This->lpFrame != NULL) 00159 This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage; 00160 00161 return This->lpFrame; 00162 } 00163 00164 static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr) 00165 { 00166 assert(This != NULL); 00167 assert(nr < This->nStreams); 00168 00169 /* remove part nr */ 00170 IAVIStream_Release(This->pStreams[nr].pStream); 00171 This->nStreams--; 00172 if (This->nStreams - nr > 0) { 00173 memmove(This->pStreams + nr, This->pStreams + nr + 1, 00174 (This->nStreams - nr) * sizeof(EditStreamTable)); 00175 } 00176 This->pStreams[This->nStreams].pStream = NULL; 00177 This->pStreams[This->nStreams].dwStart = 0; 00178 This->pStreams[This->nStreams].dwLength = 0; 00179 00180 /* try to merge the part before the deleted one and the one after it */ 00181 if (0 < nr && 0 < This->nStreams && 00182 This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) { 00183 if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) { 00184 This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength; 00185 return AVIFILE_RemoveStream(This, nr); 00186 } 00187 } 00188 00189 return AVIERR_OK; 00190 } 00191 00192 static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2) 00193 { 00194 LPVOID fmt1 = NULL, fmt2 = NULL; 00195 LONG size1, size2, start1, start2; 00196 BOOL status = FALSE; 00197 00198 assert(avi1 != NULL && avi2 != NULL); 00199 00200 /* get stream starts and check format sizes */ 00201 start1 = AVIStreamStart(avi1); 00202 start2 = AVIStreamStart(avi2); 00203 if (FAILED(AVIStreamFormatSize(avi1, start1, &size1))) 00204 return FALSE; 00205 if (FAILED(AVIStreamFormatSize(avi2, start2, &size2))) 00206 return FALSE; 00207 if (size1 != size2) 00208 return FALSE; 00209 00210 /* sizes match, now get formats and compare them */ 00211 fmt1 = HeapAlloc(GetProcessHeap(), 0, size1); 00212 if (fmt1 == NULL) 00213 return FALSE; 00214 if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) { 00215 fmt2 = HeapAlloc(GetProcessHeap(), 0, size1); 00216 if (fmt2 != NULL) { 00217 if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1))) 00218 status = (memcmp(fmt1, fmt2, size1) == 0); 00219 } 00220 } 00221 00222 HeapFree(GetProcessHeap(), 0, fmt2); 00223 HeapFree(GetProcessHeap(), 0, fmt1); 00224 00225 return status; 00226 } 00227 00228 /***********************************************************************/ 00229 00230 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj) 00231 { 00232 IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface); 00233 00234 TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj); 00235 00236 if (IsEqualGUID(&IID_IUnknown, refiid) || 00237 IsEqualGUID(&IID_IAVIEditStream, refiid) || 00238 IsEqualGUID(&IID_IEditStreamInternal, refiid)) { 00239 *obj = iface; 00240 IAVIEditStream_AddRef(iface); 00241 00242 return S_OK; 00243 } else if (IsEqualGUID(&IID_IAVIStream, refiid)) { 00244 *obj = &This->IAVIStream_iface; 00245 IAVIEditStream_AddRef(iface); 00246 00247 return S_OK; 00248 } 00249 00250 return E_NOINTERFACE; 00251 } 00252 00253 static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface) 00254 { 00255 IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface); 00256 ULONG ref = InterlockedIncrement(&This->ref); 00257 00258 TRACE("(%p) -> %d\n", iface, ref); 00259 00260 return ref; 00261 } 00262 00263 static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface) 00264 { 00265 IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface); 00266 DWORD i; 00267 ULONG ref = InterlockedDecrement(&This->ref); 00268 00269 TRACE("(%p) -> %d\n", iface, ref); 00270 00271 if (!ref) { 00272 /* release memory */ 00273 if (This->pg != NULL) 00274 AVIStreamGetFrameClose(This->pg); 00275 if (This->pStreams != NULL) { 00276 for (i = 0; i < This->nStreams; i++) { 00277 if (This->pStreams[i].pStream != NULL) 00278 IAVIStream_Release(This->pStreams[i].pStream); 00279 } 00280 HeapFree(GetProcessHeap(), 0, This->pStreams); 00281 } 00282 00283 HeapFree(GetProcessHeap(), 0, This); 00284 return 0; 00285 } 00286 return ref; 00287 } 00288 00289 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart, 00290 LONG*plLength,PAVISTREAM*ppResult) 00291 { 00292 IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface); 00293 PAVISTREAM stream; 00294 DWORD start, len, streamPos, streamNr; 00295 HRESULT hr; 00296 00297 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult); 00298 00299 if (ppResult != NULL) 00300 *ppResult = NULL; 00301 if (plStart == NULL || plLength == NULL || *plStart < 0) 00302 return AVIERR_BADPARAM; 00303 00304 /* if asked for cut part copy it before deleting */ 00305 if (ppResult != NULL) { 00306 hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult); 00307 if (FAILED(hr)) 00308 return hr; 00309 } 00310 00311 start = *plStart; 00312 len = *plLength; 00313 00314 /* now delete the requested part */ 00315 while (len > 0) { 00316 hr = AVIFILE_FindStreamInTable(This, start, &stream, 00317 &streamPos, &streamNr, FALSE); 00318 if (FAILED(hr)) 00319 return hr; 00320 if (This->pStreams[streamNr].dwStart == streamPos) { 00321 /* deleting from start of part */ 00322 if (len < This->pStreams[streamNr].dwLength) { 00323 start += len; 00324 This->pStreams[streamNr].dwStart += len; 00325 This->pStreams[streamNr].dwLength -= len; 00326 This->sInfo.dwLength -= len; 00327 len = 0; 00328 00329 /* we must return decompressed data now */ 00330 This->bDecompress = TRUE; 00331 } else { 00332 /* deleting hole part */ 00333 len -= This->pStreams[streamNr].dwLength; 00334 AVIFILE_RemoveStream(This,streamNr); 00335 } 00336 } else if (EditStreamEnd(This, streamNr) <= streamPos + len) { 00337 /* deleting at end of a part */ 00338 DWORD count = EditStreamEnd(This, streamNr) - streamPos; 00339 This->sInfo.dwLength -= count; 00340 len -= count; 00341 This->pStreams[streamNr].dwLength = 00342 streamPos - This->pStreams[streamNr].dwStart; 00343 } else { 00344 /* splitting */ 00345 if (This->nStreams + 1 >= This->nTableSize) { 00346 This->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pStreams, 00347 (This->nTableSize + 32) * sizeof(EditStreamTable)); 00348 if (This->pStreams == NULL) 00349 return AVIERR_MEMORY; 00350 This->nTableSize += 32; 00351 } 00352 memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr, 00353 (This->nStreams - streamNr) * sizeof(EditStreamTable)); 00354 This->nStreams++; 00355 00356 IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream); 00357 This->pStreams[streamNr + 1].dwStart = streamPos + len; 00358 This->pStreams[streamNr + 1].dwLength = 00359 EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart; 00360 00361 This->pStreams[streamNr].dwLength = 00362 streamPos - This->pStreams[streamNr].dwStart; 00363 This->sInfo.dwLength -= len; 00364 len = 0; 00365 } 00366 } 00367 00368 This->sInfo.dwEditCount++; 00369 00370 return AVIERR_OK; 00371 } 00372 00373 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart, 00374 LONG*plLength,PAVISTREAM*ppResult) 00375 { 00376 IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface); 00377 IAVIEditStreamImpl* pEdit; 00378 HRESULT hr; 00379 LONG start = 0; 00380 00381 TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult); 00382 00383 if (ppResult == NULL) 00384 return AVIERR_BADPARAM; 00385 *ppResult = NULL; 00386 if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0) 00387 return AVIERR_BADPARAM; 00388 00389 /* check bounds */ 00390 if (*(LPDWORD)plLength > This->sInfo.dwLength) 00391 *(LPDWORD)plLength = This->sInfo.dwLength; 00392 if (*(LPDWORD)plStart < This->sInfo.dwStart) { 00393 *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart; 00394 *(LPDWORD)plStart = This->sInfo.dwStart; 00395 if (*plLength < 0) 00396 return AVIERR_BADPARAM; 00397 } 00398 if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength) 00399 *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength - 00400 *(LPDWORD)plStart; 00401 00402 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL); 00403 if (pEdit == NULL) 00404 return AVIERR_MEMORY; 00405 00406 hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit, &start, plLength, &This->IAVIStream_iface, 00407 *plStart, *plStart + *plLength); 00408 *plStart = start; 00409 if (FAILED(hr)) 00410 IAVIEditStream_Release((PAVIEDITSTREAM)pEdit); 00411 else 00412 *ppResult = &This->IAVIStream_iface; 00413 00414 return hr; 00415 } 00416 00417 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart, 00418 LONG*plLength,PAVISTREAM pSource, 00419 LONG lStart,LONG lLength) 00420 { 00421 IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface); 00422 AVISTREAMINFOW srcInfo; 00423 IAVIEditStreamImpl *pEdit = NULL; 00424 PAVISTREAM pStream; 00425 DWORD startPos, endPos, streamNr, nStreams; 00426 ULONG n; 00427 00428 TRACE("(%p,%p,%p,%p,%d,%d)\n",iface,plStart,plLength, 00429 pSource,lStart,lLength); 00430 00431 if (pSource == NULL) 00432 return AVIERR_BADHANDLE; 00433 if (plStart == NULL || *plStart < 0) 00434 return AVIERR_BADPARAM; 00435 if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart) 00436 return AVIERR_BADPARAM; /* Can't paste with holes */ 00437 if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo)))) 00438 return AVIERR_ERROR; 00439 if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength) 00440 return AVIERR_BADPARAM; 00441 if (This->sInfo.fccType == 0) { 00442 /* This stream is empty */ 00443 IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo)); 00444 This->sInfo.dwStart = *plStart; 00445 This->sInfo.dwLength = 0; 00446 } 00447 if (This->sInfo.fccType != srcInfo.fccType) 00448 return AVIERR_UNSUPPORTED; /* different stream types */ 00449 if (lLength == -1) /* Copy the hole stream */ 00450 lLength = srcInfo.dwLength; 00451 if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength) 00452 lLength = srcInfo.dwStart + srcInfo.dwLength - lStart; 00453 if (lLength + *plStart >= 0x80000000) 00454 return AVIERR_MEMORY; 00455 00456 /* streamtype specific tests */ 00457 if (srcInfo.fccType == streamtypeVIDEO) { 00458 LONG size; 00459 00460 size = srcInfo.rcFrame.right - srcInfo.rcFrame.left; 00461 if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left) 00462 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */ 00463 size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top; 00464 if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top) 00465 return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */ 00466 } else if (srcInfo.fccType == streamtypeAUDIO) { 00467 if (!AVIFILE_FormatsEqual(&This->IAVIStream_iface, pSource)) 00468 return AVIERR_UNSUPPORTED; 00469 } else { 00470 /* FIXME: streamtypeMIDI and streamtypeTEXT */ 00471 return AVIERR_UNSUPPORTED; 00472 } 00473 00474 /* try to get an IEditStreamInternal interface */ 00475 if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal, (LPVOID*)&pEdit))) 00476 IAVIEditStream_Release(&pEdit->IAVIEditStream_iface); /* pSource holds a reference */ 00477 00478 /* for video must check for change of format */ 00479 if (This->sInfo.fccType == streamtypeVIDEO) { 00480 if (! This->bDecompress) { 00481 /* Need to decompress if any of the following conditions matches: 00482 * - pSource is an editable stream which decompresses 00483 * - the nearest keyframe of pSource isn't lStart 00484 * - the nearest keyframe of this stream isn't *plStart 00485 * - the format of pSource doesn't match this one 00486 */ 00487 if ((pEdit != NULL && pEdit->bDecompress) || 00488 AVIStreamNearestKeyFrame(pSource, lStart) != lStart || 00489 AVIStreamNearestKeyFrame(&This->IAVIStream_iface, *plStart) != *plStart || 00490 (This->nStreams > 0 && !AVIFILE_FormatsEqual(&This->IAVIStream_iface, pSource))) { 00491 /* Use first stream part to get format to convert everything to */ 00492 AVIFILE_ReadFrame(This, This->pStreams[0].pStream, 00493 This->pStreams[0].dwStart); 00494 00495 /* Check if we could convert the source streams to the desired format... */ 00496 if (pEdit != NULL) { 00497 if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, 00498 &startPos, &streamNr, TRUE))) 00499 return AVIERR_INTERNAL; 00500 for (n = lStart; n < lStart + lLength; streamNr++) { 00501 if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL) 00502 return AVIERR_BADFORMAT; 00503 startPos = pEdit->pStreams[streamNr].dwStart; 00504 n += pEdit->pStreams[streamNr].dwLength; 00505 } 00506 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL) 00507 return AVIERR_BADFORMAT; 00508 00509 This->bDecompress = TRUE; 00510 This->sInfo.fccHandler = 0; 00511 } 00512 } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL) 00513 return AVIERR_BADFORMAT; /* Can't convert source to own format */ 00514 } /* FIXME: something special for the other formats? */ 00515 00516 /* Make sure we have enough memory for parts */ 00517 if (pEdit != NULL) { 00518 DWORD nLastStream; 00519 00520 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream, 00521 &endPos, &nLastStream, TRUE); 00522 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, 00523 &startPos, &streamNr, FALSE); 00524 if (nLastStream == streamNr) 00525 nLastStream++; 00526 00527 nStreams = nLastStream - streamNr; 00528 } else 00529 nStreams = 1; 00530 if (This->nStreams + nStreams + 1 > This->nTableSize) { 00531 n = This->nStreams + nStreams + 33; 00532 00533 This->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pStreams, n * sizeof(EditStreamTable)); 00534 if (This->pStreams == NULL) 00535 return AVIERR_MEMORY; 00536 This->nTableSize = n; 00537 } 00538 00539 if (plLength != NULL) 00540 *plLength = lLength; 00541 00542 /* now do the real work */ 00543 if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) { 00544 AVIFILE_FindStreamInTable(This, *plStart, &pStream, 00545 &startPos, &streamNr, FALSE); 00546 if (startPos != This->pStreams[streamNr].dwStart) { 00547 /* split stream streamNr at startPos */ 00548 memmove(This->pStreams + streamNr + nStreams + 1, 00549 This->pStreams + streamNr, 00550 (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable)); 00551 00552 This->pStreams[streamNr + 2].dwLength = 00553 EditStreamEnd(This, streamNr + 2) - startPos; 00554 This->pStreams[streamNr + 2].dwStart = startPos; 00555 This->pStreams[streamNr].dwLength = 00556 startPos - This->pStreams[streamNr].dwStart; 00557 IAVIStream_AddRef(This->pStreams[streamNr].pStream); 00558 streamNr++; 00559 } else { 00560 /* insert before stream at streamNr */ 00561 memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr, 00562 (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable)); 00563 } 00564 } else /* append the streams */ 00565 streamNr = This->nStreams; 00566 00567 if (pEdit != NULL) { 00568 /* insert the parts of the editable stream instead of itself */ 00569 AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream, 00570 &endPos, NULL, FALSE); 00571 AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE); 00572 00573 memcpy(This->pStreams + streamNr, pEdit->pStreams + n, 00574 nStreams * sizeof(EditStreamTable)); 00575 if (This->pStreams[streamNr].dwStart < startPos) { 00576 This->pStreams[streamNr].dwLength = 00577 EditStreamEnd(This, streamNr) - startPos; 00578 This->pStreams[streamNr].dwStart = startPos; 00579 } 00580 if (endPos < EditStreamEnd(This, streamNr + nStreams)) 00581 This->pStreams[streamNr + nStreams].dwLength = 00582 endPos - This->pStreams[streamNr + nStreams].dwStart; 00583 } else { 00584 /* a simple stream */ 00585 This->pStreams[streamNr].pStream = pSource; 00586 This->pStreams[streamNr].dwStart = lStart; 00587 This->pStreams[streamNr].dwLength = lLength; 00588 } 00589 00590 for (n = 0; n < nStreams; n++) { 00591 IAVIStream_AddRef(This->pStreams[streamNr + n].pStream); 00592 if (0 < streamNr + n && 00593 This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) { 00594 This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES; 00595 This->sInfo.dwFormatChangeCount++; 00596 } 00597 } 00598 This->sInfo.dwEditCount++; 00599 This->sInfo.dwLength += lLength; 00600 This->nStreams += nStreams; 00601 00602 return AVIERR_OK; 00603 } 00604 00605 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface, 00606 PAVISTREAM*ppResult) 00607 { 00608 IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface); 00609 IAVIEditStreamImpl* pEdit; 00610 DWORD i; 00611 00612 TRACE("(%p,%p)\n",iface,ppResult); 00613 00614 if (ppResult == NULL) 00615 return AVIERR_BADPARAM; 00616 *ppResult = NULL; 00617 00618 pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL); 00619 if (pEdit == NULL) 00620 return AVIERR_MEMORY; 00621 if (This->nStreams > pEdit->nTableSize) { 00622 pEdit->pStreams = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pEdit->pStreams, 00623 This->nStreams * sizeof(EditStreamTable)); 00624 if (pEdit->pStreams == NULL) 00625 return AVIERR_MEMORY; 00626 pEdit->nTableSize = This->nStreams; 00627 } 00628 pEdit->nStreams = This->nStreams; 00629 memcpy(pEdit->pStreams, This->pStreams, 00630 This->nStreams * sizeof(EditStreamTable)); 00631 memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo)); 00632 for (i = 0; i < This->nStreams; i++) { 00633 if (pEdit->pStreams[i].pStream != NULL) 00634 IAVIStream_AddRef(pEdit->pStreams[i].pStream); 00635 } 00636 00637 *ppResult = &This->IAVIStream_iface; 00638 00639 return AVIERR_OK; 00640 } 00641 00642 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface, 00643 LPAVISTREAMINFOW asi,LONG size) 00644 { 00645 IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface); 00646 00647 TRACE("(%p,%p,%d)\n",iface,asi,size); 00648 00649 /* check parameters */ 00650 if (size >= 0 && size < sizeof(AVISTREAMINFOW)) 00651 return AVIERR_BADSIZE; 00652 00653 This->sInfo.wLanguage = asi->wLanguage; 00654 This->sInfo.wPriority = asi->wPriority; 00655 This->sInfo.dwStart = asi->dwStart; 00656 This->sInfo.dwRate = asi->dwRate; 00657 This->sInfo.dwScale = asi->dwScale; 00658 This->sInfo.dwQuality = asi->dwQuality; 00659 CopyRect(&This->sInfo.rcFrame, &asi->rcFrame); 00660 memcpy(This->sInfo.szName, asi->szName, sizeof(asi->szName)); 00661 This->sInfo.dwEditCount++; 00662 00663 return AVIERR_OK; 00664 } 00665 00666 static const struct IAVIEditStreamVtbl ieditstream = { 00667 IAVIEditStream_fnQueryInterface, 00668 IAVIEditStream_fnAddRef, 00669 IAVIEditStream_fnRelease, 00670 IAVIEditStream_fnCut, 00671 IAVIEditStream_fnCopy, 00672 IAVIEditStream_fnPaste, 00673 IAVIEditStream_fnClone, 00674 IAVIEditStream_fnSetInfo 00675 }; 00676 00677 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface, 00678 REFIID refiid,LPVOID*obj) 00679 { 00680 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00681 return IAVIEditStream_QueryInterface(&This->IAVIEditStream_iface,refiid,obj); 00682 } 00683 00684 static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface) 00685 { 00686 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00687 return IAVIEditStream_AddRef(&This->IAVIEditStream_iface); 00688 } 00689 00690 static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface) 00691 { 00692 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00693 return IAVIEditStream_Release(&This->IAVIEditStream_iface); 00694 } 00695 00696 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface, 00697 LPARAM lParam1,LPARAM lParam2) 00698 { 00699 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00700 00701 if (lParam2 != 0) 00702 return AVIERR_ERROR; 00703 00704 if (This->pStreams == NULL) { 00705 This->pStreams = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256 * sizeof(EditStreamTable)); 00706 if (This->pStreams == NULL) 00707 return AVIERR_MEMORY; 00708 This->nTableSize = 256; 00709 } 00710 00711 if (lParam1 != 0) { 00712 IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo)); 00713 IAVIStream_AddRef((PAVISTREAM)lParam1); 00714 This->pStreams[0].pStream = (PAVISTREAM)lParam1; 00715 This->pStreams[0].dwStart = This->sInfo.dwStart; 00716 This->pStreams[0].dwLength = This->sInfo.dwLength; 00717 This->nStreams = 1; 00718 } 00719 return AVIERR_OK; 00720 } 00721 00722 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface, 00723 AVISTREAMINFOW *psi,LONG size) 00724 { 00725 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00726 00727 TRACE("(%p,%p,%d)\n",iface,psi,size); 00728 00729 if (psi == NULL) 00730 return AVIERR_BADPARAM; 00731 if (size < 0) 00732 return AVIERR_BADSIZE; 00733 00734 if (This->bDecompress) 00735 This->sInfo.fccHandler = 0; 00736 00737 memcpy(psi, &This->sInfo, min((DWORD)size, sizeof(This->sInfo))); 00738 00739 if ((DWORD)size < sizeof(This->sInfo)) 00740 return AVIERR_BUFFERTOOSMALL; 00741 return AVIERR_OK; 00742 } 00743 00744 static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos, 00745 LONG flags) 00746 { 00747 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00748 PAVISTREAM stream; 00749 DWORD streamPos, streamNr; 00750 00751 TRACE("(%p,%d,0x%08X)\n",iface,pos,flags); 00752 00753 if (flags & FIND_FROM_START) 00754 pos = (LONG)This->sInfo.dwStart; 00755 00756 /* outside of stream? */ 00757 if (pos < (LONG)This->sInfo.dwStart || 00758 (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos) 00759 return -1; 00760 00761 /* map our position to a stream and position in it */ 00762 if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos, 00763 &streamNr, TRUE) != S_OK) 00764 return -1; /* doesn't exist */ 00765 00766 if (This->bDecompress) { 00767 /* only one stream -- format changes only at start */ 00768 if (flags & FIND_FORMAT) 00769 return (flags & FIND_NEXT ? -1 : 0); 00770 00771 /* FIXME: map positions back to us */ 00772 return IAVIStream_FindSample(stream, streamPos, flags); 00773 } else { 00774 /* assume change of format every frame */ 00775 return pos; 00776 } 00777 } 00778 00779 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos, 00780 LPVOID format,LONG*fmtsize) 00781 { 00782 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00783 LPBITMAPINFOHEADER lp; 00784 PAVISTREAM stream; 00785 DWORD n; 00786 HRESULT hr; 00787 00788 TRACE("(%p,%d,%p,%p)\n",iface,pos,format,fmtsize); 00789 00790 if (fmtsize == NULL || pos < This->sInfo.dwStart || 00791 This->sInfo.dwStart + This->sInfo.dwLength <= pos) 00792 return AVIERR_BADPARAM; 00793 00794 /* find stream corresponding to position */ 00795 hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE); 00796 if (FAILED(hr)) 00797 return hr; 00798 00799 if (! This->bDecompress) 00800 return IAVIStream_ReadFormat(stream, n, format, fmtsize); 00801 00802 lp = AVIFILE_ReadFrame(This, stream, n); 00803 if (lp == NULL) 00804 return AVIERR_ERROR; 00805 if (lp->biBitCount <= 8) { 00806 n = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount); 00807 n *= sizeof(RGBQUAD); 00808 } else 00809 n = 0; 00810 n += lp->biSize; 00811 00812 memcpy(format, lp, min((LONG)n, *fmtsize)); 00813 hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK); 00814 *fmtsize = n; 00815 00816 return hr; 00817 } 00818 00819 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos, 00820 LPVOID format,LONG formatsize) 00821 { 00822 TRACE("(%p,%d,%p,%d)\n",iface,pos,format,formatsize); 00823 00824 return AVIERR_UNSUPPORTED; 00825 } 00826 00827 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start, 00828 LONG samples,LPVOID buffer, 00829 LONG buffersize,LONG*bytesread, 00830 LONG*samplesread) 00831 { 00832 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00833 PAVISTREAM stream; 00834 DWORD streamPos, streamNr; 00835 LONG readBytes, readSamples, count; 00836 HRESULT hr; 00837 00838 TRACE("(%p,%d,%d,%p,%d,%p,%p) -- 0x%08X\n",iface,start,samples, 00839 buffer,buffersize,bytesread,samplesread,This->sInfo.fccType); 00840 00841 /* check parameters */ 00842 if (bytesread != NULL) 00843 *bytesread = 0; 00844 if (samplesread != NULL) 00845 *samplesread = 0; 00846 if (buffersize < 0) 00847 return AVIERR_BADSIZE; 00848 if ((DWORD)start < This->sInfo.dwStart || 00849 This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start) 00850 return AVIERR_BADPARAM; 00851 00852 if (! This->bDecompress) { 00853 /* audio like data -- sample-based */ 00854 do { 00855 if (samples == 0) 00856 return AVIERR_OK; /* nothing at all or already done */ 00857 00858 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream, 00859 &streamPos, &streamNr, FALSE))) 00860 return AVIERR_ERROR; 00861 00862 /* limit to end of the stream */ 00863 count = samples; 00864 if (streamPos + count > EditStreamEnd(This, streamNr)) 00865 count = EditStreamEnd(This, streamNr) - streamPos; 00866 00867 hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize, 00868 &readBytes, &readSamples); 00869 if (FAILED(hr)) 00870 return hr; 00871 if (readBytes == 0 && readSamples == 0 && count != 0) 00872 return AVIERR_FILEREAD; /* for bad stream implementations */ 00873 00874 if (samplesread != NULL) 00875 *samplesread += readSamples; 00876 if (bytesread != NULL) 00877 *bytesread += readBytes; 00878 if (buffer != NULL) { 00879 buffer = ((LPBYTE)buffer)+readBytes; 00880 buffersize -= readBytes; 00881 } 00882 start += count; 00883 samples -= count; 00884 } while (This->sInfo.dwStart + This->sInfo.dwLength > start); 00885 } else { 00886 /* video like data -- frame-based */ 00887 LPBITMAPINFOHEADER lp; 00888 00889 if (samples == 0) 00890 return AVIERR_OK; 00891 00892 if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream, 00893 &streamPos, &streamNr, FALSE))) 00894 return AVIERR_ERROR; 00895 00896 lp = AVIFILE_ReadFrame(This, stream, streamPos); 00897 if (lp == NULL) 00898 return AVIERR_ERROR; 00899 00900 if (buffer != NULL) { 00901 /* need size of format to skip */ 00902 if (lp->biBitCount <= 8) { 00903 count = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount; 00904 count *= sizeof(RGBQUAD); 00905 } else 00906 count = 0; 00907 count += lp->biSize; 00908 00909 if (buffersize < lp->biSizeImage) 00910 return AVIERR_BUFFERTOOSMALL; 00911 memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage); 00912 } 00913 00914 if (bytesread != NULL) 00915 *bytesread = lp->biSizeImage; 00916 if (samplesread != NULL) 00917 *samplesread = 1; 00918 } 00919 00920 return AVIERR_OK; 00921 } 00922 00923 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start, 00924 LONG samples,LPVOID buffer, 00925 LONG buffersize,DWORD flags, 00926 LONG*sampwritten,LONG*byteswritten) 00927 { 00928 TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n",iface,start,samples,buffer, 00929 buffersize,flags,sampwritten,byteswritten); 00930 00931 /* be sure return parameters have correct values */ 00932 if (sampwritten != NULL) 00933 *sampwritten = 0; 00934 if (byteswritten != NULL) 00935 *byteswritten = 0; 00936 00937 return AVIERR_UNSUPPORTED; 00938 } 00939 00940 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start, 00941 LONG samples) 00942 { 00943 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00944 00945 TRACE("(%p,%d,%d)\n",iface,start,samples); 00946 00947 return IAVIEditStream_Cut(&This->IAVIEditStream_iface,&start,&samples,NULL); 00948 } 00949 00950 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc, 00951 LPVOID lp,LONG *lpread) 00952 { 00953 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00954 DWORD n; 00955 00956 TRACE("(%p,0x%08X,%p,%p)\n",iface,fcc,lp,lpread); 00957 00958 /* check parameters */ 00959 if (lp == NULL || lpread == NULL) 00960 return AVIERR_BADPARAM; 00961 00962 /* simply ask every stream and return the first block found */ 00963 for (n = 0; n < This->nStreams; n++) { 00964 HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread); 00965 00966 if (SUCCEEDED(hr)) 00967 return hr; 00968 } 00969 00970 *lpread = 0; 00971 return AVIERR_NODATA; 00972 } 00973 00974 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc, 00975 LPVOID lp,LONG size) 00976 { 00977 TRACE("(%p,0x%08X,%p,%d)\n",iface,fcc,lp,size); 00978 00979 return AVIERR_UNSUPPORTED; 00980 } 00981 00982 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface, 00983 AVISTREAMINFOW*info,LONG len) 00984 { 00985 IAVIEditStreamImpl *This = impl_from_IAVIStream( iface ); 00986 00987 TRACE("(%p,%p,%d)\n",iface,info,len); 00988 00989 return IAVIEditStream_SetInfo(&This->IAVIEditStream_iface,info,len); 00990 } 00991 00992 static const struct IAVIStreamVtbl ieditstast = { 00993 IEditAVIStream_fnQueryInterface, 00994 IEditAVIStream_fnAddRef, 00995 IEditAVIStream_fnRelease, 00996 IEditAVIStream_fnCreate, 00997 IEditAVIStream_fnInfo, 00998 IEditAVIStream_fnFindSample, 00999 IEditAVIStream_fnReadFormat, 01000 IEditAVIStream_fnSetFormat, 01001 IEditAVIStream_fnRead, 01002 IEditAVIStream_fnWrite, 01003 IEditAVIStream_fnDelete, 01004 IEditAVIStream_fnReadData, 01005 IEditAVIStream_fnWriteData, 01006 IEditAVIStream_fnSetInfo 01007 }; 01008 01009 PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream) 01010 { 01011 IAVIEditStreamImpl *pedit = NULL; 01012 01013 pedit = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIEditStreamImpl)); 01014 if (pedit == NULL) 01015 return NULL; 01016 01017 pedit->IAVIEditStream_iface.lpVtbl = &ieditstream; 01018 pedit->IAVIStream_iface.lpVtbl = &ieditstast; 01019 pedit->ref = 1; 01020 01021 IAVIStream_Create(&pedit->IAVIStream_iface, (LPARAM)pstream, 0); 01022 01023 return (PAVIEDITSTREAM)pedit; 01024 } Generated on Sat May 26 2012 04:21:23 for ReactOS by
1.7.6.1
|