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

icmstream.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2002 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 "wingdi.h"
00025 #include "winuser.h"
00026 #include "winerror.h"
00027 #include "mmsystem.h"
00028 #include "vfw.h"
00029 
00030 #include "avifile_private.h"
00031 
00032 #include "wine/debug.h"
00033 
00034 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
00035 
00036 #define MAX_FRAMESIZE       (16 * 1024 * 1024)
00037 #define MAX_FRAMESIZE_DIFF  512
00038 
00039 /***********************************************************************/
00040 
00041 typedef struct _IAVIStreamImpl {
00042   /* IUnknown stuff */
00043   IAVIStream         IAVIStream_iface;
00044   LONG               ref;
00045 
00046   /* IAVIStream stuff */
00047   PAVISTREAM         pStream;
00048   AVISTREAMINFOW     sInfo;
00049 
00050   PGETFRAME          pg;
00051   HIC                hic;
00052   DWORD              dwICMFlags;
00053 
00054   LONG               lCurrent;
00055   LONG               lLastKey;
00056   LONG               lKeyFrameEvery;
00057   DWORD              dwLastQuality;
00058   DWORD              dwBytesPerFrame;
00059   DWORD              dwUnusedBytes;
00060 
00061   LPBITMAPINFOHEADER lpbiCur;  /* current frame */
00062   LPVOID             lpCur;
00063   LPBITMAPINFOHEADER lpbiPrev; /* previous frame */
00064   LPVOID             lpPrev;
00065 
00066   LPBITMAPINFOHEADER lpbiOutput; /* output format of codec */
00067   LONG               cbOutput;
00068   LPBITMAPINFOHEADER lpbiInput;  /* input format for codec */
00069   LONG               cbInput;
00070 } IAVIStreamImpl;
00071 
00072 /***********************************************************************/
00073 
00074 static HRESULT AVIFILE_EncodeFrame(IAVIStreamImpl *This,
00075                    LPBITMAPINFOHEADER lpbi, LPVOID lpBits);
00076 static HRESULT AVIFILE_OpenGetFrame(IAVIStreamImpl *This);
00077 
00078 static inline IAVIStreamImpl *impl_from_IAVIStream(IAVIStream *iface)
00079 {
00080   return CONTAINING_RECORD(iface, IAVIStreamImpl, IAVIStream_iface);
00081 }
00082 
00083 static inline void AVIFILE_Reset(IAVIStreamImpl *This)
00084 {
00085   This->lCurrent      = -1;
00086   This->lLastKey      = 0;
00087   This->dwLastQuality = ICQUALITY_HIGH;
00088   This->dwUnusedBytes = 0;
00089 }
00090 
00091 static HRESULT WINAPI ICMStream_fnQueryInterface(IAVIStream *iface,
00092                           REFIID refiid, LPVOID *obj)
00093 {
00094   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00095 
00096   TRACE("(%p,%s,%p)\n", iface, debugstr_guid(refiid), obj);
00097 
00098   if (IsEqualGUID(&IID_IUnknown, refiid) ||
00099       IsEqualGUID(&IID_IAVIStream, refiid)) {
00100     *obj = This;
00101     IAVIStream_AddRef(iface);
00102 
00103     return S_OK;
00104   }
00105 
00106   return OLE_E_ENUM_NOMORE;
00107 }
00108 
00109 static ULONG WINAPI ICMStream_fnAddRef(IAVIStream *iface)
00110 {
00111   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00112   ULONG ref = InterlockedIncrement(&This->ref);
00113 
00114   TRACE("(%p) -> %d\n", iface, ref);
00115 
00116   /* also add reference to the nested stream */
00117   if (This->pStream != NULL)
00118     IAVIStream_AddRef(This->pStream);
00119 
00120   return ref;
00121 }
00122 
00123 static ULONG WINAPI ICMStream_fnRelease(IAVIStream* iface)
00124 {
00125   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00126   ULONG ref = InterlockedDecrement(&This->ref);
00127 
00128   TRACE("(%p) -> %d\n", iface, ref);
00129 
00130   if (ref == 0) {
00131     /* destruct */
00132     if (This->pg != NULL) {
00133       AVIStreamGetFrameClose(This->pg);
00134       This->pg = NULL;
00135     }
00136     if (This->pStream != NULL) {
00137       IAVIStream_Release(This->pStream);
00138       This->pStream = NULL;
00139     }
00140     if (This->hic != NULL) {
00141       if (This->lpbiPrev != NULL) {
00142     ICDecompressEnd(This->hic);
00143     HeapFree(GetProcessHeap(), 0, This->lpbiPrev);
00144     This->lpbiPrev = NULL;
00145     This->lpPrev   = NULL;
00146       }
00147       ICCompressEnd(This->hic);
00148       This->hic = NULL;
00149     }
00150     if (This->lpbiCur != NULL) {
00151       HeapFree(GetProcessHeap(), 0, This->lpbiCur);
00152       This->lpbiCur = NULL;
00153       This->lpCur   = NULL;
00154     }
00155     if (This->lpbiOutput != NULL) {
00156       HeapFree(GetProcessHeap(), 0, This->lpbiOutput);
00157       This->lpbiOutput = NULL;
00158       This->cbOutput   = 0;
00159     }
00160     if (This->lpbiInput != NULL) {
00161       HeapFree(GetProcessHeap(), 0, This->lpbiInput);
00162       This->lpbiInput = NULL;
00163       This->cbInput   = 0;
00164     }
00165 
00166     HeapFree(GetProcessHeap(), 0, This);
00167 
00168     return 0;
00169   }
00170 
00171   /* also release reference to the nested stream */
00172   if (This->pStream != NULL)
00173     IAVIStream_Release(This->pStream);
00174 
00175   return ref;
00176 }
00177 
00178 /* lParam1: PAVISTREAM
00179  * lParam2: LPAVICOMPRESSOPTIONS
00180  */
00181 static HRESULT WINAPI ICMStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
00182                       LPARAM lParam2)
00183 {
00184   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00185 
00186   ICINFO               icinfo;
00187   ICCOMPRESSFRAMES     icFrames;
00188   LPAVICOMPRESSOPTIONS pco = (LPAVICOMPRESSOPTIONS)lParam2;
00189 
00190   TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
00191 
00192   /* check parameter */
00193   if ((LPVOID)lParam1 == NULL)
00194     return AVIERR_BADPARAM;
00195 
00196   /* get infos from stream */
00197   IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
00198   if (This->sInfo.fccType != streamtypeVIDEO)
00199     return AVIERR_ERROR; /* error in registry or AVIMakeCompressedStream */
00200 
00201   /* add reference to the stream */
00202   This->pStream = (PAVISTREAM)lParam1;
00203   IAVIStream_AddRef(This->pStream);
00204 
00205   AVIFILE_Reset(This);
00206 
00207   if (pco != NULL && pco->fccHandler != comptypeDIB) {
00208     /* we should compress */
00209     This->sInfo.fccHandler = pco->fccHandler;
00210 
00211     This->hic = ICOpen(ICTYPE_VIDEO, pco->fccHandler, ICMODE_COMPRESS);
00212     if (This->hic == NULL)
00213       return AVIERR_NOCOMPRESSOR;
00214 
00215     /* restore saved state of codec */
00216     if (pco->cbParms > 0 && pco->lpParms != NULL) {
00217       ICSetState(This->hic, pco->lpParms, pco->cbParms);
00218     }
00219 
00220     /* set quality -- resolve default quality */
00221     This->sInfo.dwQuality = pco->dwQuality;
00222     if (pco->dwQuality == ICQUALITY_DEFAULT)
00223       This->sInfo.dwQuality = ICGetDefaultQuality(This->hic);
00224 
00225     /* get capabilities of codec */
00226     ICGetInfo(This->hic, &icinfo, sizeof(icinfo));
00227     This->dwICMFlags = icinfo.dwFlags;
00228 
00229     /* use keyframes? */
00230     if ((pco->dwFlags & AVICOMPRESSF_KEYFRAMES) &&
00231     (icinfo.dwFlags & (VIDCF_TEMPORAL|VIDCF_FASTTEMPORALC))) {
00232       This->lKeyFrameEvery = pco->dwKeyFrameEvery;
00233     } else
00234       This->lKeyFrameEvery = 1;
00235 
00236     /* use datarate? */
00237     if ((pco->dwFlags & AVICOMPRESSF_DATARATE)) {
00238       /* Do we have a chance to reduce size to desired one? */
00239       if ((icinfo.dwFlags & (VIDCF_CRUNCH|VIDCF_QUALITY)) == 0)
00240     return AVIERR_NOCOMPRESSOR;
00241 
00242       assert(This->sInfo.dwRate != 0);
00243 
00244       This->dwBytesPerFrame = MulDiv(pco->dwBytesPerSecond,
00245                      This->sInfo.dwScale, This->sInfo.dwRate);
00246     } else {
00247       pco->dwBytesPerSecond = 0;
00248       This->dwBytesPerFrame = 0;
00249     }
00250 
00251     if (icinfo.dwFlags & VIDCF_COMPRESSFRAMES) {
00252       memset(&icFrames, 0, sizeof(icFrames));
00253       icFrames.lpbiOutput  = This->lpbiOutput;
00254       icFrames.lpbiInput   = This->lpbiInput;
00255       icFrames.lFrameCount = This->sInfo.dwLength;
00256       icFrames.lQuality    = This->sInfo.dwQuality;
00257       icFrames.lDataRate   = pco->dwBytesPerSecond;
00258       icFrames.lKeyRate    = This->lKeyFrameEvery;
00259       icFrames.dwRate      = This->sInfo.dwRate;
00260       icFrames.dwScale     = This->sInfo.dwScale;
00261       ICSendMessage(This->hic, ICM_COMPRESS_FRAMES_INFO,
00262             (LPARAM)&icFrames, (LPARAM)sizeof(icFrames));
00263     }
00264   } else
00265     This->sInfo.fccHandler = comptypeDIB;
00266 
00267   return AVIERR_OK;
00268 }
00269 
00270 static HRESULT WINAPI ICMStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
00271                     LONG size)
00272 {
00273   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00274 
00275   TRACE("(%p,%p,%d)\n", iface, psi, size);
00276 
00277   if (psi == NULL)
00278     return AVIERR_BADPARAM;
00279   if (size < 0)
00280     return AVIERR_BADSIZE;
00281 
00282   memcpy(psi, &This->sInfo, min((DWORD)size, sizeof(This->sInfo)));
00283 
00284   if ((DWORD)size < sizeof(This->sInfo))
00285     return AVIERR_BUFFERTOOSMALL;
00286   return AVIERR_OK;
00287 }
00288 
00289 static LONG WINAPI ICMStream_fnFindSample(IAVIStream *iface, LONG pos,
00290                        LONG flags)
00291 {
00292   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00293 
00294   TRACE("(%p,%d,0x%08X)\n",iface,pos,flags);
00295 
00296   if (flags & FIND_FROM_START) {
00297     pos = This->sInfo.dwStart;
00298     flags &= ~(FIND_FROM_START|FIND_PREV);
00299     flags |= FIND_NEXT;
00300   }
00301 
00302   if (flags & FIND_RET)
00303     WARN(": FIND_RET flags will be ignored!\n");
00304 
00305   if (flags & FIND_KEY) {
00306     if (This->hic == NULL)
00307       return pos; /* we decompress so every frame is a keyframe */
00308 
00309     if (flags & FIND_PREV) {
00310       /* need to read old or new frames? */
00311       if (This->lLastKey <= pos || pos < This->lCurrent)
00312     IAVIStream_Read(iface, pos, 1, NULL, 0, NULL, NULL);
00313 
00314       return This->lLastKey;
00315     }
00316   } else if (flags & FIND_ANY) {
00317     return pos; /* We really don't know, reread is to expensive, so guess. */
00318   } else if (flags & FIND_FORMAT) {
00319     if (flags & FIND_PREV)
00320       return 0;
00321   }
00322 
00323   return -1;
00324 }
00325 
00326 static HRESULT WINAPI ICMStream_fnReadFormat(IAVIStream *iface, LONG pos,
00327                           LPVOID format, LONG *formatsize)
00328 {
00329   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00330 
00331   LPBITMAPINFOHEADER lpbi;
00332   HRESULT            hr;
00333 
00334   TRACE("(%p,%d,%p,%p)\n", iface, pos, format, formatsize);
00335 
00336   if (formatsize == NULL)
00337     return AVIERR_BADPARAM;
00338 
00339   if (This->pg == NULL) {
00340     hr = AVIFILE_OpenGetFrame(This);
00341 
00342     if (FAILED(hr))
00343       return hr;
00344   }
00345 
00346   lpbi = AVIStreamGetFrame(This->pg, pos);
00347   if (lpbi == NULL)
00348     return AVIERR_MEMORY;
00349 
00350   if (This->hic == NULL) {
00351     LONG size = lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD);
00352 
00353     if (size > 0) {
00354       if (This->sInfo.dwSuggestedBufferSize < lpbi->biSizeImage)
00355     This->sInfo.dwSuggestedBufferSize = lpbi->biSizeImage;
00356 
00357       This->cbOutput = size;
00358       if (format != NULL) {
00359     if (This->lpbiOutput != NULL)
00360       memcpy(format, This->lpbiOutput, min(*formatsize, This->cbOutput));
00361     else
00362       memcpy(format, lpbi, min(*formatsize, size));
00363       }
00364     }
00365   } else if (format != NULL)
00366     memcpy(format, This->lpbiOutput, min(*formatsize, This->cbOutput));
00367 
00368   if (*formatsize < This->cbOutput)
00369     hr = AVIERR_BUFFERTOOSMALL;
00370   else
00371     hr = AVIERR_OK;
00372 
00373   *formatsize = This->cbOutput;
00374   return hr;
00375 }
00376 
00377 static HRESULT WINAPI ICMStream_fnSetFormat(IAVIStream *iface, LONG pos,
00378                          LPVOID format, LONG formatsize)
00379 {
00380   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00381 
00382   TRACE("(%p,%d,%p,%d)\n", iface, pos, format, formatsize);
00383 
00384   /* check parameters */
00385   if (format == NULL || formatsize <= 0)
00386     return AVIERR_BADPARAM;
00387 
00388   /* We can only accept RGB data for writing */
00389   if (((LPBITMAPINFOHEADER)format)->biCompression != BI_RGB) {
00390     WARN(": need RGB data as input\n");
00391     return AVIERR_UNSUPPORTED;
00392   }
00393 
00394   /* Input format already known?
00395    * Changing of palette is supported, but be quiet if it's the same */
00396   if (This->lpbiInput != NULL) {
00397     if (This->cbInput != formatsize)
00398       return AVIERR_UNSUPPORTED;
00399 
00400     if (memcmp(format, This->lpbiInput, formatsize) == 0)
00401       return AVIERR_OK;
00402   }
00403 
00404   /* Does the nested stream support writing? */
00405   if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
00406     return AVIERR_READONLY;
00407 
00408   /* check if frame is already written */
00409   if (This->sInfo.dwLength + This->sInfo.dwStart > pos)
00410     return AVIERR_UNSUPPORTED;
00411 
00412   /* check if we should compress */
00413   if (This->sInfo.fccHandler == 0 ||
00414       This->sInfo.fccHandler == mmioFOURCC('N','O','N','E'))
00415     This->sInfo.fccHandler = comptypeDIB;
00416 
00417   /* only pass through? */
00418   if (This->sInfo.fccHandler == comptypeDIB)
00419     return IAVIStream_SetFormat(This->pStream, pos, format, formatsize);
00420 
00421   /* initial format setting? */
00422   if (This->lpbiInput == NULL) {
00423     ULONG size;
00424 
00425     assert(This->hic != NULL);
00426 
00427     /* get memory for input format */
00428     This->lpbiInput = HeapAlloc(GetProcessHeap(), 0, formatsize);
00429     if (This->lpbiInput == NULL)
00430       return AVIERR_MEMORY;
00431     This->cbInput = formatsize;
00432     memcpy(This->lpbiInput, format, formatsize);
00433 
00434     /* get output format */
00435     size = ICCompressGetFormatSize(This->hic, This->lpbiInput);
00436     if (size < sizeof(BITMAPINFOHEADER))
00437       return AVIERR_COMPRESSOR;
00438     This->lpbiOutput = HeapAlloc(GetProcessHeap(), 0, size);
00439     if (This->lpbiOutput == NULL)
00440       return AVIERR_MEMORY;
00441     This->cbOutput = size;
00442     if (ICCompressGetFormat(This->hic,This->lpbiInput,This->lpbiOutput) < S_OK)
00443       return AVIERR_COMPRESSOR;
00444 
00445     /* update AVISTREAMINFO structure */
00446     This->sInfo.rcFrame.right  =
00447       This->sInfo.rcFrame.left + This->lpbiOutput->biWidth;
00448     This->sInfo.rcFrame.bottom =
00449       This->sInfo.rcFrame.top  + This->lpbiOutput->biHeight;
00450 
00451     /* prepare codec for compression */
00452     if (ICCompressBegin(This->hic, This->lpbiInput, This->lpbiOutput) != S_OK)
00453       return AVIERR_COMPRESSOR;
00454 
00455     /* allocate memory for compressed frame */
00456     size = ICCompressGetSize(This->hic, This->lpbiInput, This->lpbiOutput);
00457     This->lpbiCur = HeapAlloc(GetProcessHeap(), 0, This->cbOutput + size);
00458     if (This->lpbiCur == NULL)
00459       return AVIERR_MEMORY;
00460     memcpy(This->lpbiCur, This->lpbiOutput, This->cbOutput);
00461     This->lpCur = DIBPTR(This->lpbiCur);
00462 
00463     /* allocate memory for last frame if needed */
00464     if (This->lKeyFrameEvery != 1 &&
00465     (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
00466       size = ICDecompressGetFormatSize(This->hic, This->lpbiOutput);
00467       This->lpbiPrev = HeapAlloc(GetProcessHeap(), 0, size);
00468       if (This->lpbiPrev == NULL)
00469     return AVIERR_MEMORY;
00470       if (ICDecompressGetFormat(This->hic, This->lpbiOutput, This->lpbiPrev) < S_OK)
00471     return AVIERR_COMPRESSOR;
00472 
00473       if (This->lpbiPrev->biSizeImage == 0) {
00474     This->lpbiPrev->biSizeImage =
00475       DIBWIDTHBYTES(*This->lpbiPrev) * This->lpbiPrev->biHeight;
00476       }
00477 
00478       /* get memory for format and picture */
00479       size += This->lpbiPrev->biSizeImage;
00480       This->lpbiPrev = HeapReAlloc(GetProcessHeap(), 0, This->lpbiPrev, size);
00481       if (This->lpbiPrev == NULL)
00482     return AVIERR_MEMORY;
00483       This->lpPrev = DIBPTR(This->lpbiPrev);
00484 
00485       /* prepare codec also for decompression */
00486       if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
00487     return AVIERR_COMPRESSOR;
00488     }
00489   } else {
00490     /* format change -- check that's only the palette */
00491     LPBITMAPINFOHEADER lpbi = format;
00492 
00493     if (lpbi->biSize != This->lpbiInput->biSize ||
00494     lpbi->biWidth != This->lpbiInput->biWidth ||
00495     lpbi->biHeight != This->lpbiInput->biHeight ||
00496     lpbi->biBitCount != This->lpbiInput->biBitCount ||
00497     lpbi->biPlanes != This->lpbiInput->biPlanes ||
00498     lpbi->biCompression != This->lpbiInput->biCompression ||
00499     lpbi->biClrUsed != This->lpbiInput->biClrUsed)
00500       return AVIERR_UNSUPPORTED;
00501 
00502     /* get new output format */
00503     if (ICCompressGetFormat(This->hic, lpbi, This->lpbiOutput) < S_OK)
00504       return AVIERR_BADFORMAT;
00505 
00506     /* restart compression */
00507     ICCompressEnd(This->hic);
00508     if (ICCompressBegin(This->hic, lpbi, This->lpbiOutput) != S_OK)
00509       return AVIERR_COMPRESSOR;
00510 
00511     /* check if we need to restart decompression also */
00512     if (This->lKeyFrameEvery != 1 &&
00513     (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
00514       ICDecompressEnd(This->hic);
00515       if (ICDecompressGetFormat(This->hic,This->lpbiOutput,This->lpbiPrev) < S_OK)
00516     return AVIERR_COMPRESSOR;
00517       if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
00518     return AVIERR_COMPRESSOR;
00519     }
00520   }
00521 
00522   /* tell nested stream the new format */
00523   return IAVIStream_SetFormat(This->pStream, pos,
00524                   This->lpbiOutput, This->cbOutput);
00525 }
00526 
00527 static HRESULT WINAPI ICMStream_fnRead(IAVIStream *iface, LONG start,
00528                     LONG samples, LPVOID buffer,
00529                     LONG buffersize, LPLONG bytesread,
00530                     LPLONG samplesread)
00531 {
00532   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00533 
00534   LPBITMAPINFOHEADER lpbi;
00535 
00536   TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", iface, start, samples, buffer,
00537     buffersize, bytesread, samplesread);
00538 
00539   /* clear return parameters if given */
00540   if (bytesread != NULL)
00541     *bytesread = 0;
00542   if (samplesread != NULL)
00543     *samplesread = 0;
00544 
00545   if (samples == 0)
00546     return AVIERR_OK;
00547 
00548   /* check parameters */
00549   if (samples != 1 && (bytesread == NULL && samplesread == NULL))
00550     return AVIERR_BADPARAM;
00551   if (samples == -1) /* read as much as we could */
00552     samples = 1;
00553 
00554   if (This->pg == NULL) {
00555     HRESULT hr = AVIFILE_OpenGetFrame(This);
00556 
00557     if (FAILED(hr))
00558       return hr;
00559   }
00560 
00561   /* compress or decompress? */
00562   if (This->hic == NULL) {
00563     /* decompress */
00564     lpbi = AVIStreamGetFrame(This->pg, start);
00565     if (lpbi == NULL)
00566       return AVIERR_MEMORY;
00567 
00568     if (buffer != NULL && buffersize > 0) {
00569       /* check buffersize */
00570       if (buffersize < lpbi->biSizeImage)
00571     return AVIERR_BUFFERTOOSMALL;
00572 
00573       memcpy(buffer, DIBPTR(lpbi), lpbi->biSizeImage);
00574     }
00575 
00576     /* fill out return parameters if given */
00577     if (bytesread != NULL)
00578       *bytesread = lpbi->biSizeImage;
00579   } else {
00580     /* compress */
00581     if (This->lCurrent > start)
00582       AVIFILE_Reset(This);
00583 
00584     while (start > This->lCurrent) {
00585       HRESULT hr;
00586 
00587       lpbi = AVIStreamGetFrame(This->pg, ++This->lCurrent);
00588       if (lpbi == NULL) {
00589     AVIFILE_Reset(This);
00590     return AVIERR_MEMORY;
00591       }
00592 
00593       hr = AVIFILE_EncodeFrame(This, lpbi, DIBPTR(lpbi));
00594       if (FAILED(hr)) {
00595     AVIFILE_Reset(This);
00596     return hr;
00597       }
00598     }
00599 
00600     if (buffer != NULL && buffersize > 0) {
00601       /* check buffersize */
00602       if (This->lpbiCur->biSizeImage > buffersize)
00603     return AVIERR_BUFFERTOOSMALL;
00604 
00605       memcpy(buffer, This->lpCur, This->lpbiCur->biSizeImage);
00606     }
00607 
00608     /* fill out return parameters if given */
00609     if (bytesread != NULL)
00610       *bytesread = This->lpbiCur->biSizeImage;
00611   }
00612 
00613   /* fill out return parameters if given */
00614   if (samplesread != NULL)
00615     *samplesread = 1;
00616 
00617   return AVIERR_OK;
00618 }
00619 
00620 static HRESULT WINAPI ICMStream_fnWrite(IAVIStream *iface, LONG start,
00621                      LONG samples, LPVOID buffer,
00622                      LONG buffersize, DWORD flags,
00623                      LPLONG sampwritten,
00624                      LPLONG byteswritten)
00625 {
00626   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00627 
00628   HRESULT hr;
00629 
00630   TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n", iface, start, samples,
00631     buffer, buffersize, flags, sampwritten, byteswritten);
00632 
00633   /* clear return parameters if given */
00634   if (sampwritten != NULL)
00635     *sampwritten = 0;
00636   if (byteswritten != NULL)
00637     *byteswritten = 0;
00638 
00639   /* check parameters */
00640   if (buffer == NULL && (buffersize > 0 || samples > 0))
00641     return AVIERR_BADPARAM;
00642 
00643   if (This->sInfo.fccHandler == comptypeDIB) {
00644     /* only pass through */
00645     flags |= AVIIF_KEYFRAME;
00646 
00647     return IAVIStream_Write(This->pStream, start, samples, buffer, buffersize,
00648                 flags, sampwritten, byteswritten);
00649   } else {
00650     /* compress data before writing to pStream */
00651     if (samples != 1 && (sampwritten == NULL && byteswritten == NULL))
00652       return AVIERR_UNSUPPORTED;
00653 
00654     This->lCurrent = start;
00655     hr = AVIFILE_EncodeFrame(This, This->lpbiInput, buffer);
00656     if (FAILED(hr))
00657       return hr;
00658 
00659     if (This->lLastKey == start)
00660       flags |= AVIIF_KEYFRAME;
00661 
00662     return IAVIStream_Write(This->pStream, start, samples, This->lpCur,
00663                 This->lpbiCur->biSizeImage, flags, byteswritten,
00664                 sampwritten);
00665   }
00666 }
00667 
00668 static HRESULT WINAPI ICMStream_fnDelete(IAVIStream *iface, LONG start,
00669                       LONG samples)
00670 {
00671   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00672 
00673   TRACE("(%p,%d,%d)\n", iface, start, samples);
00674 
00675   return IAVIStream_Delete(This->pStream, start, samples);
00676 }
00677 
00678 static HRESULT WINAPI ICMStream_fnReadData(IAVIStream *iface, DWORD fcc,
00679                         LPVOID lp, LPLONG lpread)
00680 {
00681   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00682 
00683   TRACE("(%p,0x%08X,%p,%p)\n", iface, fcc, lp, lpread);
00684 
00685   assert(This->pStream != NULL);
00686 
00687   return IAVIStream_ReadData(This->pStream, fcc, lp, lpread);
00688 }
00689 
00690 static HRESULT WINAPI ICMStream_fnWriteData(IAVIStream *iface, DWORD fcc,
00691                          LPVOID lp, LONG size)
00692 {
00693   IAVIStreamImpl *This = impl_from_IAVIStream(iface);
00694 
00695   TRACE("(%p,0x%08x,%p,%d)\n", iface, fcc, lp, size);
00696 
00697   assert(This->pStream != NULL);
00698 
00699   return IAVIStream_WriteData(This->pStream, fcc, lp, size);
00700 }
00701 
00702 static HRESULT WINAPI ICMStream_fnSetInfo(IAVIStream *iface,
00703                        LPAVISTREAMINFOW info, LONG infolen)
00704 {
00705   FIXME("(%p,%p,%d): stub\n", iface, info, infolen);
00706 
00707   return E_FAIL;
00708 }
00709 
00710 static const struct IAVIStreamVtbl iicmst = {
00711   ICMStream_fnQueryInterface,
00712   ICMStream_fnAddRef,
00713   ICMStream_fnRelease,
00714   ICMStream_fnCreate,
00715   ICMStream_fnInfo,
00716   ICMStream_fnFindSample,
00717   ICMStream_fnReadFormat,
00718   ICMStream_fnSetFormat,
00719   ICMStream_fnRead,
00720   ICMStream_fnWrite,
00721   ICMStream_fnDelete,
00722   ICMStream_fnReadData,
00723   ICMStream_fnWriteData,
00724   ICMStream_fnSetInfo
00725 };
00726 
00727 HRESULT AVIFILE_CreateICMStream(REFIID riid, LPVOID *ppv)
00728 {
00729   IAVIStreamImpl *pstream;
00730   HRESULT         hr;
00731 
00732   assert(riid != NULL && ppv != NULL);
00733 
00734   *ppv = NULL;
00735 
00736   pstream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIStreamImpl));
00737   if (pstream == NULL)
00738     return AVIERR_MEMORY;
00739 
00740   pstream->IAVIStream_iface.lpVtbl = &iicmst;
00741   AVIFILE_Reset(pstream);
00742 
00743   hr = IAVIStream_QueryInterface(&pstream->IAVIStream_iface, riid, ppv);
00744   if (FAILED(hr))
00745     HeapFree(GetProcessHeap(), 0, pstream);
00746 
00747   return hr;
00748 }
00749 
00750 /***********************************************************************/
00751 
00752 static HRESULT AVIFILE_EncodeFrame(IAVIStreamImpl *This,
00753                    LPBITMAPINFOHEADER lpbi, LPVOID lpBits)
00754 {
00755   DWORD dwMinQual, dwMaxQual, dwCurQual;
00756   DWORD dwRequest;
00757   DWORD icmFlags = 0;
00758   DWORD idxFlags = 0;
00759   BOOL  bDecreasedQual = FALSE;
00760   BOOL  doSizeCheck;
00761   BOOL  noPrev;
00762 
00763   /* make lKeyFrameEvery and at start a keyframe */
00764   if ((This->lKeyFrameEvery != 0 &&
00765        (This->lCurrent - This->lLastKey) >= This->lKeyFrameEvery) ||
00766       This->lCurrent == This->sInfo.dwStart) {
00767     idxFlags = AVIIF_KEYFRAME;
00768     icmFlags = ICCOMPRESS_KEYFRAME;
00769   }
00770 
00771   if (This->lKeyFrameEvery != 0) {
00772     if (This->lCurrent == This->sInfo.dwStart) {
00773       if (idxFlags & AVIIF_KEYFRAME) {
00774     /* for keyframes allow to consume all unused bytes */
00775     dwRequest = This->dwBytesPerFrame + This->dwUnusedBytes;
00776     This->dwUnusedBytes = 0;
00777       } else {
00778     /* for non-keyframes only allow something of the unused bytes to be consumed */
00779     DWORD tmp1 = 0;
00780     DWORD tmp2;
00781 
00782     if (This->dwBytesPerFrame >= This->dwUnusedBytes)
00783       tmp1 = This->dwBytesPerFrame / This->lKeyFrameEvery;
00784     tmp2 = (This->dwUnusedBytes + tmp1) / This->lKeyFrameEvery;
00785 
00786     dwRequest = This->dwBytesPerFrame - tmp1 + tmp2;
00787     This->dwUnusedBytes -= tmp2;
00788       }
00789     } else
00790       dwRequest = MAX_FRAMESIZE;
00791   } else {
00792     /* only one keyframe at start desired */
00793     if (This->lCurrent == This->sInfo.dwStart) {
00794       dwRequest = This->dwBytesPerFrame + This->dwUnusedBytes;
00795       This->dwUnusedBytes = 0;
00796     } else
00797       dwRequest = MAX_FRAMESIZE;
00798   }
00799 
00800   /* must we check for framesize to gain requested
00801    * datarate or could we trust codec? */
00802   doSizeCheck = (dwRequest != 0 && ((This->dwICMFlags & (VIDCF_CRUNCH|VIDCF_QUALITY)) == 0));
00803 
00804   dwMaxQual = dwCurQual = This->sInfo.dwQuality;
00805   dwMinQual = ICQUALITY_LOW;
00806 
00807   noPrev = TRUE;
00808   if ((icmFlags & ICCOMPRESS_KEYFRAME) == 0 && 
00809       (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0)
00810     noPrev = FALSE;
00811 
00812   do {
00813     DWORD   idxCkid = 0;
00814     DWORD   res;
00815 
00816     res = ICCompress(This->hic,icmFlags,This->lpbiCur,This->lpCur,lpbi,lpBits,
00817              &idxCkid, &idxFlags, This->lCurrent, dwRequest, dwCurQual,
00818              noPrev ? NULL:This->lpbiPrev, noPrev ? NULL:This->lpPrev);
00819     if (res == ICERR_NEWPALETTE) {
00820       FIXME(": codec has changed palette -- unhandled!\n");
00821     } else if (res != ICERR_OK)
00822       return AVIERR_COMPRESSOR;
00823 
00824     /* need to check for framesize */
00825     if (! doSizeCheck)
00826       break;
00827 
00828     if (dwRequest >= This->lpbiCur->biSizeImage) {
00829       /* frame is smaller -- try to maximize quality */
00830       if (dwMaxQual - dwCurQual > 10) {
00831     DWORD tmp = dwRequest / 8;
00832 
00833     if (tmp < MAX_FRAMESIZE_DIFF)
00834       tmp = MAX_FRAMESIZE_DIFF;
00835 
00836     if (tmp < dwRequest - This->lpbiCur->biSizeImage && bDecreasedQual) {
00837       tmp = dwCurQual;
00838       dwCurQual = (dwMinQual + dwMaxQual) / 2;
00839       dwMinQual = tmp;
00840       continue;
00841     }
00842       } else
00843     break;
00844     } else if (dwMaxQual - dwMinQual <= 1) {
00845       break;
00846     } else {
00847       dwMaxQual = dwCurQual;
00848 
00849       if (bDecreasedQual || dwCurQual == This->dwLastQuality)
00850     dwCurQual = (dwMinQual + dwMaxQual) / 2;
00851       else
00852     FIXME(": no new quality computed min=%u cur=%u max=%u last=%u\n",
00853           dwMinQual, dwCurQual, dwMaxQual, This->dwLastQuality);
00854 
00855       bDecreasedQual = TRUE;
00856     }
00857   } while (TRUE);
00858 
00859   /* remember some values */
00860   This->dwLastQuality = dwCurQual;
00861   This->dwUnusedBytes = dwRequest - This->lpbiCur->biSizeImage;
00862   if (icmFlags & ICCOMPRESS_KEYFRAME)
00863     This->lLastKey = This->lCurrent;
00864 
00865   /* Does we manage previous frame? */
00866   if (This->lpPrev != NULL && This->lKeyFrameEvery != 1)
00867     ICDecompress(This->hic, 0, This->lpbiCur, This->lpCur,
00868          This->lpbiPrev, This->lpPrev);
00869 
00870   return AVIERR_OK;
00871 }
00872 
00873 static HRESULT AVIFILE_OpenGetFrame(IAVIStreamImpl *This)
00874 {
00875   LPBITMAPINFOHEADER lpbi;
00876   DWORD              size;
00877 
00878   /* pre-conditions */
00879   assert(This != NULL);
00880   assert(This->pStream != NULL);
00881   assert(This->pg == NULL);
00882 
00883   This->pg = AVIStreamGetFrameOpen(This->pStream, NULL);
00884   if (This->pg == NULL)
00885     return AVIERR_ERROR;
00886 
00887   /* When we only decompress this is enough */
00888   if (This->sInfo.fccHandler == comptypeDIB)
00889     return AVIERR_OK;
00890 
00891   assert(This->hic != NULL);
00892   assert(This->lpbiOutput == NULL);
00893 
00894   /* get input format */
00895   lpbi = AVIStreamGetFrame(This->pg, This->sInfo.dwStart);
00896   if (lpbi == NULL)
00897     return AVIERR_MEMORY;
00898 
00899   /* get memory for output format */
00900   size = ICCompressGetFormatSize(This->hic, lpbi);
00901   if ((LONG)size < (LONG)sizeof(BITMAPINFOHEADER))
00902     return AVIERR_COMPRESSOR;
00903   This->lpbiOutput = HeapAlloc(GetProcessHeap(), 0, size);
00904   if (This->lpbiOutput == NULL)
00905     return AVIERR_MEMORY;
00906   This->cbOutput = size;
00907 
00908   if (ICCompressGetFormat(This->hic, lpbi, This->lpbiOutput) < S_OK)
00909     return AVIERR_BADFORMAT;
00910 
00911   /* update AVISTREAMINFO structure */
00912   This->sInfo.rcFrame.right  =
00913     This->sInfo.rcFrame.left + This->lpbiOutput->biWidth;
00914   This->sInfo.rcFrame.bottom =
00915     This->sInfo.rcFrame.top  + This->lpbiOutput->biHeight;
00916   This->sInfo.dwSuggestedBufferSize =
00917     ICCompressGetSize(This->hic, lpbi, This->lpbiOutput);
00918 
00919   /* prepare codec for compression */
00920   if (ICCompressBegin(This->hic, lpbi, This->lpbiOutput) != S_OK)
00921     return AVIERR_COMPRESSOR;
00922 
00923   /* allocate memory for current frame */
00924   size += This->sInfo.dwSuggestedBufferSize;
00925   This->lpbiCur = HeapAlloc(GetProcessHeap(), 0, size);
00926   if (This->lpbiCur == NULL)
00927     return AVIERR_MEMORY;
00928   memcpy(This->lpbiCur, This->lpbiOutput, This->cbOutput);
00929   This->lpCur = DIBPTR(This->lpbiCur);
00930 
00931   /* allocate memory for last frame if needed */
00932   if (This->lKeyFrameEvery != 1 &&
00933       (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
00934     size = ICDecompressGetFormatSize(This->hic, This->lpbiOutput);
00935     This->lpbiPrev = HeapAlloc(GetProcessHeap(), 0, size);
00936     if (This->lpbiPrev == NULL)
00937       return AVIERR_MEMORY;
00938     if (ICDecompressGetFormat(This->hic, This->lpbiOutput, This->lpbiPrev) < S_OK)
00939       return AVIERR_COMPRESSOR;
00940 
00941     if (This->lpbiPrev->biSizeImage == 0) {
00942       This->lpbiPrev->biSizeImage =
00943     DIBWIDTHBYTES(*This->lpbiPrev) * This->lpbiPrev->biHeight;
00944     }
00945 
00946     /* get memory for format and picture */
00947     size += This->lpbiPrev->biSizeImage;
00948     This->lpbiPrev = HeapReAlloc(GetProcessHeap(), 0, This->lpbiPrev, size );
00949     if (This->lpbiPrev == NULL)
00950       return AVIERR_MEMORY;
00951     This->lpPrev = DIBPTR(This->lpbiPrev);
00952 
00953     /* prepare codec also for decompression */
00954     if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
00955       return AVIERR_COMPRESSOR;
00956   }
00957 
00958   return AVIERR_OK;
00959 }

Generated on Fri May 25 2012 04:20:49 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.