/*
* $Id$
*
* (C) 2003-2006 Gabest
* (C) 2006-2010 see AUTHORS
*
* This file is part of mplayerc.
*
* Mplayerc is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Mplayerc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "stdafx.h"
#include "DeinterlacerFilter.h"
#include "../../DSUtil/MediaTypes.h"
#include
CDeinterlacerFilter::CDeinterlacerFilter(LPUNKNOWN punk, HRESULT* phr)
: CTransformFilter(NAME("CDeinterlacerFilter"), punk, __uuidof(CDeinterlacerFilter))
{
if(phr) {
*phr = S_OK;
}
}
HRESULT CDeinterlacerFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
{
return GetCLSID(pPin) == __uuidof(*this) ? E_FAIL : S_OK;
}
HRESULT CDeinterlacerFilter::CheckInputType(const CMediaType* mtIn)
{
BITMAPINFOHEADER bih;
if(!ExtractBIH(mtIn, &bih) /*|| bih.biHeight <= 0*/ || bih.biHeight <= 288) {
return E_FAIL;
}
return mtIn->subtype == MEDIASUBTYPE_YUY2 || mtIn->subtype == MEDIASUBTYPE_UYVY
|| mtIn->subtype == MEDIASUBTYPE_I420 || mtIn->subtype == MEDIASUBTYPE_YV12 || mtIn->subtype == MEDIASUBTYPE_IYUV
? S_OK
: E_FAIL;
}
HRESULT CDeinterlacerFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
{
return mtIn->subtype == mtOut->subtype ? S_OK : E_FAIL;
}
HRESULT CDeinterlacerFilter::Transform(IMediaSample* pIn, IMediaSample* pOut)
{
HRESULT hr;
AM_MEDIA_TYPE* pmt = NULL;
if(SUCCEEDED(pOut->GetMediaType(&pmt)) && pmt) {
CMediaType mt = *pmt;
m_pOutput->SetMediaType(&mt);
DeleteMediaType(pmt);
}
BYTE* pDataIn = NULL;
if(FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn) {
return S_FALSE;
}
BYTE* pDataOut = NULL;
if(FAILED(hr = pOut->GetPointer(&pDataOut)) || !pDataOut) {
return hr;
}
const CMediaType& mtIn = m_pInput->CurrentMediaType();
const CMediaType& mtOut = m_pOutput->CurrentMediaType();
BITMAPINFOHEADER bihIn, bihOut;
ExtractBIH(&mtIn, &bihIn);
ExtractBIH(&mtOut, &bihOut);
bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3;
bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3;
bool fFlip = fInputFlipped != fOutputFlipped;
int bppIn = !(bihIn.biBitCount&7) ? bihIn.biBitCount : 8;
int bppOut = !(bihOut.biBitCount&7) ? bihOut.biBitCount : 8;
int pitchIn = bihIn.biWidth*bppIn>>3;
int pitchOut = bihOut.biWidth*bppOut>>3;
BYTE* pDataOut2 = pDataOut;
if(fFlip) {
pDataOut2 += pitchOut*(bihIn.biHeight-1);
pitchOut = -pitchOut;
}
if(mtIn.subtype == MEDIASUBTYPE_YUY2 || mtIn.subtype == MEDIASUBTYPE_UYVY) {
DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn);
} else if(mtIn.subtype == MEDIASUBTYPE_I420 || mtIn.subtype == MEDIASUBTYPE_YV12 || mtIn.subtype == MEDIASUBTYPE_IYUV) {
DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn);
int sizeIn = bihIn.biHeight*pitchIn, sizeOut = abs(bihOut.biHeight)*pitchOut;
pitchIn /= 2;
pitchOut /= 2;
bihIn.biHeight /= 2;
pDataIn += sizeIn;
pDataOut += sizeOut;
DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn);
pDataIn += sizeIn/4;
pDataOut += sizeOut/4;
DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn);
}
return S_OK;
}
HRESULT CDeinterlacerFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
{
if(m_pInput->IsConnected() == FALSE) {
return E_UNEXPECTED;
}
BITMAPINFOHEADER bih;
ExtractBIH(&m_pOutput->CurrentMediaType(), &bih);
pProperties->cBuffers = 1;
pProperties->cbBuffer = bih.biSizeImage;
pProperties->cbAlign = 1;
pProperties->cbPrefix = 0;
HRESULT hr;
ALLOCATOR_PROPERTIES Actual;
if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) {
return hr;
}
return pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
? E_FAIL
: NOERROR;
}
HRESULT CDeinterlacerFilter::GetMediaType(int iPosition, CMediaType* pmt)
{
if(m_pInput->IsConnected() == FALSE) {
return E_UNEXPECTED;
}
if(iPosition < 0) {
return E_INVALIDARG;
}
if(iPosition > 0) {
return VFW_S_NO_MORE_ITEMS;
}
*pmt = m_pInput->CurrentMediaType();
CorrectMediaType(pmt);
return S_OK;
}