Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenicmstream.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
1.7.6.1
|