Esempio n. 1
0
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;
  }
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}