static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame *iface, LPBITMAPINFOHEADER lpbiWanted, LPVOID lpBits, INT x, INT y, INT dx, INT dy) { IGetFrameImpl *This = impl_from_IGetFrame(iface); AVISTREAMINFOW sInfo; LPBITMAPINFOHEADER lpbi = lpbiWanted; BOOL bBestDisplay = FALSE; TRACE("(%p,%p,%p,%d,%d,%d,%d)\n", iface, lpbiWanted, lpBits, x, y, dx, dy); if (This->pStream == NULL) return AVIERR_ERROR; if (lpbiWanted == (LPBITMAPINFOHEADER)AVIGETFRAMEF_BESTDISPLAYFMT) { lpbi = NULL; bBestDisplay = TRUE; } IAVIStream_Info(This->pStream, &sInfo, sizeof(sInfo)); if (sInfo.fccType != streamtypeVIDEO) return AVIERR_UNSUPPORTED; This->bFormatChanges = (sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) != 0; This->dwFormatChangeCount = sInfo.dwFormatChangeCount; This->dwEditCount = sInfo.dwEditCount; This->lCurrentFrame = -1; /* get input format from stream */ if (This->lpInFormat == NULL) { HRESULT hr; This->cbInBuffer = (LONG)sInfo.dwSuggestedBufferSize; if (This->cbInBuffer == 0) This->cbInBuffer = 1024; IAVIStream_ReadFormat(This->pStream, sInfo.dwStart, NULL, &This->cbInFormat); This->lpInFormat = HeapAlloc(GetProcessHeap(), 0, This->cbInFormat + This->cbInBuffer); if (This->lpInFormat == NULL) { AVIFILE_CloseCompressor(This); return AVIERR_MEMORY; } hr = IAVIStream_ReadFormat(This->pStream, sInfo.dwStart, This->lpInFormat, &This->cbInFormat); if (FAILED(hr)) { AVIFILE_CloseCompressor(This); return hr; } This->lpInBuffer = ((LPBYTE)This->lpInFormat) + This->cbInFormat; } /* check input format */ if (This->lpInFormat->biClrUsed == 0 && This->lpInFormat->biBitCount <= 8) This->lpInFormat->biClrUsed = 1u << This->lpInFormat->biBitCount; if (This->lpInFormat->biSizeImage == 0 && This->lpInFormat->biCompression == BI_RGB) { This->lpInFormat->biSizeImage = DIBWIDTHBYTES(*This->lpInFormat) * This->lpInFormat->biHeight; } /* only to pass through? */ if (This->lpInFormat->biCompression == BI_RGB && lpBits == NULL) { if (lpbi == NULL || (lpbi->biCompression == BI_RGB && lpbi->biWidth == This->lpInFormat->biWidth && lpbi->biHeight == This->lpInFormat->biHeight && lpbi->biBitCount == This->lpInFormat->biBitCount)) { This->lpOutFormat = This->lpInFormat; This->lpOutBuffer = DIBPTR(This->lpInFormat); return AVIERR_OK; } } /* need memory for output format? */ if (This->lpOutFormat == NULL) { This->lpOutFormat = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); if (This->lpOutFormat == NULL) { AVIFILE_CloseCompressor(This); return AVIERR_MEMORY; } } /* need handle to video compressor */ if (This->hic == NULL) { FOURCC fccHandler; if (This->lpInFormat->biCompression == BI_RGB) fccHandler = comptypeDIB; else if (This->lpInFormat->biCompression == BI_RLE8) fccHandler = mmioFOURCC('R','L','E',' '); else fccHandler = sInfo.fccHandler; if (lpbi != NULL) { if (lpbi->biWidth == 0) lpbi->biWidth = This->lpInFormat->biWidth; if (lpbi->biHeight == 0) lpbi->biHeight = This->lpInFormat->biHeight; } This->hic = ICLocate(ICTYPE_VIDEO, fccHandler, This->lpInFormat, lpbi, ICMODE_DECOMPRESS); if (This->hic == NULL) { AVIFILE_CloseCompressor(This); return AVIERR_NOCOMPRESSOR; } } /* output format given? */ if (lpbi != NULL) { /* check the given output format ... */ if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8) lpbi->biClrUsed = 1u << lpbi->biBitCount; /* ... and remember it */ memcpy(This->lpOutFormat, lpbi, lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD)); if (lpbi->biBitCount <= 8) ICDecompressGetPalette(This->hic, This->lpInFormat, This->lpOutFormat); return AVIERR_OK; } else { if (bBestDisplay) { ICGetDisplayFormat(This->hic, This->lpInFormat, This->lpOutFormat, 0, dx, dy); } else if (ICDecompressGetFormat(This->hic, This->lpInFormat, This->lpOutFormat) < 0) { AVIFILE_CloseCompressor(This); return AVIERR_NOCOMPRESSOR; } /* check output format */ if (This->lpOutFormat->biClrUsed == 0 && This->lpOutFormat->biBitCount <= 8) This->lpOutFormat->biClrUsed = 1u << This->lpOutFormat->biBitCount; if (This->lpOutFormat->biSizeImage == 0 && This->lpOutFormat->biCompression == BI_RGB) { This->lpOutFormat->biSizeImage = DIBWIDTHBYTES(*This->lpOutFormat) * This->lpOutFormat->biHeight; } if (lpBits == NULL) { DWORD size = This->lpOutFormat->biClrUsed * sizeof(RGBQUAD); size += This->lpOutFormat->biSize + This->lpOutFormat->biSizeImage; This->lpOutFormat = HeapReAlloc(GetProcessHeap(), 0, This->lpOutFormat, size); if (This->lpOutFormat == NULL) { AVIFILE_CloseCompressor(This); return AVIERR_MEMORY; } This->lpOutBuffer = DIBPTR(This->lpOutFormat); } else This->lpOutBuffer = lpBits; /* for user size was irrelevant */ if (dx == -1) dx = This->lpOutFormat->biWidth; if (dy == -1) dy = This->lpOutFormat->biHeight; /* need to resize? */ if (x != 0 || y != 0) { if (dy == This->lpOutFormat->biHeight && dx == This->lpOutFormat->biWidth) This->bResize = FALSE; else This->bResize = TRUE; } if (This->bResize) { This->x = x; This->y = y; This->dx = dx; This->dy = dy; if (ICDecompressExBegin(This->hic,0,This->lpInFormat,This->lpInBuffer,0, 0,This->lpInFormat->biWidth, This->lpInFormat->biHeight,This->lpOutFormat, This->lpOutBuffer, x, y, dx, dy) == ICERR_OK) return AVIERR_OK; } else if (ICDecompressBegin(This->hic, This->lpInFormat, This->lpOutFormat) == ICERR_OK) return AVIERR_OK; AVIFILE_CloseCompressor(This); return AVIERR_COMPRESSOR; } }
static HRESULT WINAPI ICMStream_fnSetFormat(IAVIStream *iface, LONG pos, LPVOID format, LONG formatsize) { IAVIStreamImpl *This = impl_from_IAVIStream(iface); TRACE("(%p,%d,%p,%d)\n", iface, pos, format, formatsize); /* check parameters */ if (format == NULL || formatsize <= 0) return AVIERR_BADPARAM; /* We can only accept RGB data for writing */ if (((LPBITMAPINFOHEADER)format)->biCompression != BI_RGB) { WARN(": need RGB data as input\n"); return AVIERR_UNSUPPORTED; } /* Input format already known? * Changing of palette is supported, but be quiet if it's the same */ if (This->lpbiInput != NULL) { if (This->cbInput != formatsize) return AVIERR_UNSUPPORTED; if (memcmp(format, This->lpbiInput, formatsize) == 0) return AVIERR_OK; } /* Does the nested stream support writing? */ if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0) return AVIERR_READONLY; /* check if frame is already written */ if (This->sInfo.dwLength + This->sInfo.dwStart > pos) return AVIERR_UNSUPPORTED; /* check if we should compress */ if (This->sInfo.fccHandler == 0 || This->sInfo.fccHandler == mmioFOURCC('N','O','N','E')) This->sInfo.fccHandler = comptypeDIB; /* only pass through? */ if (This->sInfo.fccHandler == comptypeDIB) return IAVIStream_SetFormat(This->pStream, pos, format, formatsize); /* initial format setting? */ if (This->lpbiInput == NULL) { ULONG size; assert(This->hic != NULL); /* get memory for input format */ This->lpbiInput = HeapAlloc(GetProcessHeap(), 0, formatsize); if (This->lpbiInput == NULL) return AVIERR_MEMORY; This->cbInput = formatsize; memcpy(This->lpbiInput, format, formatsize); /* get output format */ size = ICCompressGetFormatSize(This->hic, This->lpbiInput); if (size < sizeof(BITMAPINFOHEADER)) return AVIERR_COMPRESSOR; This->lpbiOutput = HeapAlloc(GetProcessHeap(), 0, size); if (This->lpbiOutput == NULL) return AVIERR_MEMORY; This->cbOutput = size; if (ICCompressGetFormat(This->hic,This->lpbiInput,This->lpbiOutput) < S_OK) return AVIERR_COMPRESSOR; /* update AVISTREAMINFO structure */ This->sInfo.rcFrame.right = This->sInfo.rcFrame.left + This->lpbiOutput->biWidth; This->sInfo.rcFrame.bottom = This->sInfo.rcFrame.top + This->lpbiOutput->biHeight; /* prepare codec for compression */ if (ICCompressBegin(This->hic, This->lpbiInput, This->lpbiOutput) != S_OK) return AVIERR_COMPRESSOR; /* allocate memory for compressed frame */ size = ICCompressGetSize(This->hic, This->lpbiInput, This->lpbiOutput); This->lpbiCur = HeapAlloc(GetProcessHeap(), 0, This->cbOutput + size); if (This->lpbiCur == NULL) return AVIERR_MEMORY; memcpy(This->lpbiCur, This->lpbiOutput, This->cbOutput); This->lpCur = DIBPTR(This->lpbiCur); /* allocate memory for last frame if needed */ if (This->lKeyFrameEvery != 1 && (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) { size = ICDecompressGetFormatSize(This->hic, This->lpbiOutput); This->lpbiPrev = HeapAlloc(GetProcessHeap(), 0, size); if (This->lpbiPrev == NULL) return AVIERR_MEMORY; if (ICDecompressGetFormat(This->hic, This->lpbiOutput, This->lpbiPrev) < S_OK) return AVIERR_COMPRESSOR; if (This->lpbiPrev->biSizeImage == 0) { This->lpbiPrev->biSizeImage = DIBWIDTHBYTES(*This->lpbiPrev) * This->lpbiPrev->biHeight; } /* get memory for format and picture */ size += This->lpbiPrev->biSizeImage; This->lpbiPrev = HeapReAlloc(GetProcessHeap(), 0, This->lpbiPrev, size); if (This->lpbiPrev == NULL) return AVIERR_MEMORY; This->lpPrev = DIBPTR(This->lpbiPrev); /* prepare codec also for decompression */ if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK) return AVIERR_COMPRESSOR; } } else { /* format change -- check that's only the palette */ LPBITMAPINFOHEADER lpbi = format; if (lpbi->biSize != This->lpbiInput->biSize || lpbi->biWidth != This->lpbiInput->biWidth || lpbi->biHeight != This->lpbiInput->biHeight || lpbi->biBitCount != This->lpbiInput->biBitCount || lpbi->biPlanes != This->lpbiInput->biPlanes || lpbi->biCompression != This->lpbiInput->biCompression || lpbi->biClrUsed != This->lpbiInput->biClrUsed) return AVIERR_UNSUPPORTED; /* get new output format */ if (ICCompressGetFormat(This->hic, lpbi, This->lpbiOutput) < S_OK) return AVIERR_BADFORMAT; /* restart compression */ ICCompressEnd(This->hic); if (ICCompressBegin(This->hic, lpbi, This->lpbiOutput) != S_OK) return AVIERR_COMPRESSOR; /* check if we need to restart decompression also */ if (This->lKeyFrameEvery != 1 && (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) { ICDecompressEnd(This->hic); if (ICDecompressGetFormat(This->hic,This->lpbiOutput,This->lpbiPrev) < S_OK) return AVIERR_COMPRESSOR; if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK) return AVIERR_COMPRESSOR; } } /* tell nested stream the new format */ return IAVIStream_SetFormat(This->pStream, pos, This->lpbiOutput, This->cbOutput); }
static HRESULT AVIFILE_OpenGetFrame(IAVIStreamImpl *This) { LPBITMAPINFOHEADER lpbi; DWORD size; /* pre-conditions */ assert(This != NULL); assert(This->pStream != NULL); assert(This->pg == NULL); This->pg = AVIStreamGetFrameOpen(This->pStream, NULL); if (This->pg == NULL) return AVIERR_ERROR; /* When we only decompress this is enough */ if (This->sInfo.fccHandler == comptypeDIB) return AVIERR_OK; assert(This->hic != NULL); assert(This->lpbiOutput == NULL); /* get input format */ lpbi = AVIStreamGetFrame(This->pg, This->sInfo.dwStart); if (lpbi == NULL) return AVIERR_MEMORY; /* get memory for output format */ size = ICCompressGetFormatSize(This->hic, lpbi); if ((LONG)size < (LONG)sizeof(BITMAPINFOHEADER)) return AVIERR_COMPRESSOR; This->lpbiOutput = HeapAlloc(GetProcessHeap(), 0, size); if (This->lpbiOutput == NULL) return AVIERR_MEMORY; This->cbOutput = size; if (ICCompressGetFormat(This->hic, lpbi, This->lpbiOutput) < S_OK) return AVIERR_BADFORMAT; /* update AVISTREAMINFO structure */ This->sInfo.rcFrame.right = This->sInfo.rcFrame.left + This->lpbiOutput->biWidth; This->sInfo.rcFrame.bottom = This->sInfo.rcFrame.top + This->lpbiOutput->biHeight; This->sInfo.dwSuggestedBufferSize = ICCompressGetSize(This->hic, lpbi, This->lpbiOutput); /* prepare codec for compression */ if (ICCompressBegin(This->hic, lpbi, This->lpbiOutput) != S_OK) return AVIERR_COMPRESSOR; /* allocate memory for current frame */ size += This->sInfo.dwSuggestedBufferSize; This->lpbiCur = HeapAlloc(GetProcessHeap(), 0, size); if (This->lpbiCur == NULL) return AVIERR_MEMORY; memcpy(This->lpbiCur, This->lpbiOutput, This->cbOutput); This->lpCur = DIBPTR(This->lpbiCur); /* allocate memory for last frame if needed */ if (This->lKeyFrameEvery != 1 && (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) { size = ICDecompressGetFormatSize(This->hic, This->lpbiOutput); This->lpbiPrev = HeapAlloc(GetProcessHeap(), 0, size); if (This->lpbiPrev == NULL) return AVIERR_MEMORY; if (ICDecompressGetFormat(This->hic, This->lpbiOutput, This->lpbiPrev) < S_OK) return AVIERR_COMPRESSOR; if (This->lpbiPrev->biSizeImage == 0) { This->lpbiPrev->biSizeImage = DIBWIDTHBYTES(*This->lpbiPrev) * This->lpbiPrev->biHeight; } /* get memory for format and picture */ size += This->lpbiPrev->biSizeImage; This->lpbiPrev = HeapReAlloc(GetProcessHeap(), 0, This->lpbiPrev, size ); if (This->lpbiPrev == NULL) return AVIERR_MEMORY; This->lpPrev = DIBPTR(This->lpbiPrev); /* prepare codec also for decompression */ if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK) return AVIERR_COMPRESSOR; } return AVIERR_OK; }
static HRESULT FFMVWrapper_ProcessReceive( CTransformBaseImpl* pImpl, IMediaSample* pSampIn ) { CFFMVWrapperImpl* This = pImpl->m_pUserData; BYTE* pDataIn = NULL; LONG lDataInLen; IMediaSample* pSampOut = NULL; BYTE* pOutBuf; HRESULT hr; AVFrame tmp_pic; AVPicture dst_pic; int nOut, got_pic; LONG width, height; REFERENCE_TIME rtStart, rtStop, rtNow; BOOL skip; TRACE("(%p)\n",This); if ( This == NULL || !This->ctx.codec || This->m_pbiIn == NULL || This->m_pbiOut == NULL ) return E_UNEXPECTED; hr = IMediaSample_GetPointer( pSampIn, &pDataIn ); if ( FAILED(hr) ) return hr; lDataInLen = IMediaSample_GetActualDataLength( pSampIn ); if ( lDataInLen < 0 ) return E_FAIL; EnterCriticalSection( &This->m_cs ); if ( !This->ctx.codec ) { hr = E_UNEXPECTED; goto failed; } if ( IMediaSample_IsDiscontinuity( pSampIn ) == S_OK ) avcodec_flush_buffers( &This->ctx ); width = This->m_pbiIn->bmiHeader.biWidth; height = (This->m_pbiIn->bmiHeader.biHeight < 0) ? -This->m_pbiIn->bmiHeader.biHeight : This->m_pbiIn->bmiHeader.biHeight; while ( TRUE ) { nOut = avcodec_decode_video( &This->ctx, &tmp_pic, &got_pic, (void*)pDataIn, lDataInLen ); if ( nOut < 0 ) { TRACE("decoding error\n"); goto fail; } TRACE("used %d of %d bytes\n", nOut, lDataInLen); if ( nOut > lDataInLen ) { WARN("arrgh - FFmpeg read too much\n"); nOut = lDataInLen; } pDataIn += nOut; lDataInLen -= nOut; if (!got_pic) { TRACE("no frame decoded\n"); if (lDataInLen) continue; LeaveCriticalSection( &This->m_cs ); return S_OK; } TRACE("frame decoded\n"); This->rtInternal ++; hr = IMediaSample_GetTime( pSampIn, &rtStart, &rtStop ); if ( hr == S_OK ) { /* if the parser gives us a timestamp, the data * we got from it should be a single frame */ if ( lDataInLen ) { ERR("excessive data in compressed frame\n"); lDataInLen = 0; } } else { /* compute our own timestamp */ rtStart = This->rtCur; This->rtCur = This->rtInternal * (REFERENCE_TIME)QUARTZ_TIMEUNITS * This->ctx.frame_rate_base / This->ctx.frame_rate; rtStop = This->rtCur; } TRACE("frame start=%lld, stop=%lld\n", rtStart, rtStop); skip = FALSE; hr = IReferenceClock_GetTime(pImpl->basefilter.pClock, &rtNow); if (SUCCEEDED(hr)) { rtNow -= pImpl->basefilter.rtStart; TRACE("time=%lld\n", rtNow); if (rtStart < rtNow + SKIP_TIME) { skip = TRUE; if ( ++This->skipFrames >= MAX_SKIP ) { This->skipFrames = 0; TRACE("frame late, but max skip exceeded\n"); skip = FALSE; } } } if (skip) { TRACE("skipping late frame\n"); if ( lDataInLen == 0 ) { LeaveCriticalSection( &This->m_cs ); return S_OK; } } else { /* process frame */ hr = IMemAllocator_GetBuffer( pImpl->m_pOutPinAllocator, &pSampOut, &rtStart, &rtStop, 0 ); if ( FAILED(hr) ) goto failed; hr = IMediaSample_GetPointer( pSampOut, &pOutBuf ); if ( FAILED(hr) ) goto failed; dst_pic.data[0] = ( This->m_pOutBuf != NULL ) ? This->m_pOutBuf : pOutBuf; dst_pic.linesize[0] = DIBWIDTHBYTES(This->m_pbiOut->bmiHeader); /* convert to RGB (or BGR) */ switch (This->m_pbiOut->bmiHeader.biBitCount) { case 24: img_convert( &dst_pic, PIX_FMT_BGR24, (AVPicture*)&tmp_pic, This->ctx.pix_fmt, width, height ); break; case 32: /* RGBA32 is misnamed (is actually cpu-endian ARGB, which means BGRA on x86), * might get renamed in future ffmpeg snapshots */ img_convert( &dst_pic, PIX_FMT_RGBA32, (AVPicture*)&tmp_pic, This->ctx.pix_fmt, width, height ); break; default: TRACE("bad bpp\n"); goto fail; } if ( This->m_pOutBuf != NULL ) memcpy( pOutBuf, This->m_pOutBuf, This->m_pbiOut->bmiHeader.biSizeImage ); IMediaSample_SetActualDataLength( pSampOut, This->m_pbiOut->bmiHeader.biSizeImage ); /* FIXME: discontinuity and sync point */ LeaveCriticalSection( &This->m_cs ); hr = CPinBaseImpl_SendSample( &pImpl->pOutPin->pin, pSampOut ); if ( FAILED(hr) ) return hr; IMediaSample_Release( pSampOut ); pSampOut = NULL; if ( lDataInLen == 0 ) return S_OK; EnterCriticalSection( &This->m_cs ); if ( !This->ctx.codec ) { hr = E_UNEXPECTED; goto failed; } } } fail: hr = E_FAIL; failed: LeaveCriticalSection( &This->m_cs ); return hr; }