ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

editstream.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.