mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
840 lines
26 KiB
C++
840 lines
26 KiB
C++
// AVSVideoFrameTransform.h : Declaration of the CAVSVideoFrameTransform
|
|
|
|
#pragma once
|
|
#include "resource.h" // main symbols
|
|
#include "ASCUncompressedVideoFrame.h"
|
|
#include "./VideoFrameTransformLib/BaseTransform.h"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// IAVSVideoFrameTransform
|
|
[object, uuid("DEA8B89A-6350-49E0-890A-84377006633C"), dual, pointer_default(unique)]
|
|
__interface IAVSVideoFrameTransform : IDispatch
|
|
{
|
|
[id(204000 + 1)] HRESULT SetVideoFormat([in]IUnknown* pVideoFormat);
|
|
|
|
//ñì. "MediaDataDefine.h" êîíñòàíòû ñ ïðåôèêñîì RESIZE_MODE_
|
|
[id(204000 + 2), propget] HRESULT ResizeMode([out, retval] long* pVal);
|
|
[id(204000 + 2), propput] HRESULT ResizeMode([in] long newVal);
|
|
[id(204000 + 3), propget] HRESULT DeinterlaceEnabled([out, retval] VARIANT_BOOL* pVal);
|
|
[id(204000 + 3), propput] HRESULT DeinterlaceEnabled([in] VARIANT_BOOL newVal);
|
|
//ñì. "MediaDataDefine.h" êîíñòàíòû ñ ïðåôèêñîì DEINTERLACE_METHOD
|
|
[id(204000 + 4), propget] HRESULT DeinterlaceMethod([out, retval] long* pVal);
|
|
[id(204000 + 4), propput] HRESULT DeinterlaceMethod([in] long newVal);
|
|
[id(204000 + 5), propget] HRESULT CropScale([out, retval] long* pVal);
|
|
[id(204000 + 5), propput] HRESULT CropScale([in] long newVal);
|
|
[id(204000 + 6), propget] HRESULT DstBorderGrayScale([out, retval] ULONG* pVal);
|
|
[id(204000 + 6), propput] HRESULT DstBorderGrayScale([in] ULONG newVal);
|
|
|
|
[id(204000 + 7)] HRESULT SetAdditionalParam([in] BSTR ParamName, [in] VARIANT ParamValue);
|
|
[id(204000 + 8)] HRESULT GetAdditionalParam([in] BSTR ParamName, [out,retval] VARIANT* ParamValue);
|
|
[id(204000 + 9)] HRESULT TransformFrame([in] IUnknown* pInpFrame, [out,retval] IUnknown** pOutFrame);
|
|
[id(204000 + 10)] HRESULT ReleaseBuffers(void);
|
|
|
|
};
|
|
// CAVSVideoFrameTransform
|
|
[coclass, uuid("E093D454-88E3-44B2-84DC-F4270861298D"), threading(apartment), vi_progid("AVSMediaCore3.AVSVideoFrameTransform"), progid("AVSMediaCore3.AVSVideoFrameTransform.1"), version(1.0)]
|
|
class ATL_NO_VTABLE CAVSVideoFrameTransform
|
|
: public IAVSVideoFrameTransform
|
|
, public CBaseTransform
|
|
{
|
|
public:
|
|
CAVSVideoFrameTransform()
|
|
{
|
|
ReleaseBuffers();
|
|
//ATLTRACE("CAVSVideoFrameTransform::Constructor 0x%08X\n", this);
|
|
|
|
GetDeinterlaceMethodeFromRegistry();
|
|
|
|
}
|
|
~CAVSVideoFrameTransform()
|
|
{
|
|
ReleaseBuffers();
|
|
//ATLTRACE("CAVSVideoFrameTransform::Destructor 0x%08X\n", this);
|
|
}
|
|
STDMETHOD(SetVideoFormat)(IUnknown* pVideoFormat)
|
|
{
|
|
if (NULL==pVideoFormat)
|
|
return S_OK;
|
|
|
|
MediaFormat::IAVSVideoFormat *pFormat = NULL;
|
|
pVideoFormat->QueryInterface(MediaFormat::IID_IAVSVideoFormat, (void**)&pFormat);
|
|
if (NULL==pFormat)
|
|
return S_OK;
|
|
|
|
long lWidth, lHeight, lColorSpace, lAspectRatioX, lAspectRatioY;
|
|
pFormat->get_Width(&lWidth);
|
|
pFormat->get_Height(&lHeight);
|
|
pFormat->get_ColorSpace(&lColorSpace);
|
|
pFormat->get_AspectRatioX(&lAspectRatioX);
|
|
pFormat->get_AspectRatioY(&lAspectRatioY);
|
|
pFormat->Release();
|
|
ATLTRACE("Format: Width: %d, Height: %d, ColorSpace: 0x%08X\n", lWidth, lHeight, lColorSpace);
|
|
memset(&m_oDstFormat, 0, sizeof(SUncompressedVideoFrame));
|
|
m_oDstFormat.Width = lWidth;
|
|
m_oDstFormat.Height = lHeight;
|
|
m_oDstFormat.ColorSpace = lColorSpace;
|
|
m_oDstFormat.AspectX = lAspectRatioX;
|
|
m_oDstFormat.AspectY = lAspectRatioY;
|
|
m_oDstFormat.Interlaced = FALSE;
|
|
m_oDstFormat.kx = 1.0;
|
|
m_oDstFormat.ky = 1.0;
|
|
SetDefaultStride(&m_oDstFormat);
|
|
|
|
m_bIsNeedAplly = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHOD(get_ResizeMode)(long* pVal)
|
|
{
|
|
*pVal = m_lResizeMode;
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(put_ResizeMode)(long newVal)
|
|
{
|
|
if ((newVal<0)||(newVal>=RESIZE_MODE_COUNT))
|
|
return S_OK;
|
|
m_lResizeMode = newVal;
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(get_DeinterlaceEnabled)(VARIANT_BOOL* pVal)
|
|
{
|
|
*pVal = m_bDeinterlaceEnabled ? VARIANT_TRUE : VARIANT_FALSE;
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(put_DeinterlaceEnabled)(VARIANT_BOOL newVal)
|
|
{
|
|
m_bDeinterlaceEnabled = (VARIANT_FALSE!=newVal);
|
|
m_bIsNeedAplly = TRUE;
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(get_DeinterlaceMethod)(long* pVal)
|
|
{
|
|
*pVal = m_lDeinterlaceMethod;
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(put_DeinterlaceMethod)(long newVal)
|
|
{
|
|
if ((newVal<0)||(newVal>=DEINTERLACE_METHOD_COUNT))
|
|
return S_OK;
|
|
m_lDeinterlaceMethod = newVal;
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(get_CropScale)(long* pVal)
|
|
{
|
|
*pVal = m_lCropScale;
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(put_CropScale)(long newVal)
|
|
{
|
|
if ((newVal<0)||(newVal>100))
|
|
return S_OK;
|
|
m_bIsNeedAplly = true;
|
|
m_lCropScale = newVal;
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(get_DstBorderGrayScale)(ULONG* pVal)
|
|
{
|
|
//*pVal = m_nRGBDstBorderGrayScale;
|
|
*pVal = m_dwBGRDstBorderColor;
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(put_DstBorderGrayScale)(ULONG newVal)
|
|
{
|
|
//m_nRGBDstBorderGrayScale = (BYTE)newVal;
|
|
//m_nYDstBorderGrayScale = m_nRGBDstBorderGrayScale;
|
|
//m_nUDstBorderGrayScale = 0x80;
|
|
//m_nVDstBorderGrayScale = 0x80;
|
|
|
|
m_dwBGRDstBorderColor = newVal;
|
|
BYTE nRColor = (BYTE)(0xFF & m_dwBGRDstBorderColor);
|
|
BYTE nGColor = (BYTE)(0xFF & (m_dwBGRDstBorderColor >> 8));
|
|
BYTE nBColor = (BYTE)(0xFF & (m_dwBGRDstBorderColor >> 16));
|
|
|
|
m_nYDstBorderColor = 0.299*nRColor + 0.587*nGColor + 0.114*nBColor;
|
|
m_nUDstBorderColor = 0.565*(nBColor - m_nYDstBorderColor) + 0x80;
|
|
m_nVDstBorderColor = 0.713*(nRColor - m_nYDstBorderColor) + 0x80;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHOD(SetAdditionalParam)(BSTR ParamName, VARIANT ParamValue)
|
|
{
|
|
CString sParamName = ParamName;
|
|
|
|
if (sParamName == _T("RotateAngle"))
|
|
{
|
|
//0,90,180,270 - íà îñòàëüíûå ïîêà çàáèëè
|
|
m_lRotateAngle = ParamValue.lVal;
|
|
}
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(GetAdditionalParam)(BSTR ParamName, VARIANT* ParamValue)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHOD(TransformFrame)(IUnknown* pInpFrame, IUnknown** pOutFrame)
|
|
{
|
|
//ATLTRACE("CAVSVideoFrameTransform::TransformFrame begin 0x%08X\n", this);
|
|
|
|
if ((NULL == pInpFrame)||(NULL == pOutFrame))
|
|
return INVALIDOPERATION;
|
|
|
|
IAVSUncompressedVideoFrame *piInpFrame = NULL;
|
|
pInpFrame->QueryInterface(__uuidof(IAVSUncompressedVideoFrame), (void **)&piInpFrame);
|
|
if (NULL==piInpFrame)
|
|
return INVALIDOPERATION;
|
|
|
|
CAVSUncompressedVideoFrame* pInpVideoFrame=(CAVSUncompressedVideoFrame*)piInpFrame;
|
|
if (IsChangeArrayFormat(pInpVideoFrame))
|
|
{
|
|
m_oSrcFormat = pInpVideoFrame->m_oVideoFrame;
|
|
m_bIsNeedAplly=true;
|
|
}
|
|
if (m_bIsNeedAplly)
|
|
ApplySettings();
|
|
|
|
if (m_bIsNeedTransform)
|
|
{
|
|
//YV12 è I420 îòëè÷àþòñÿ òîëüêî ïîðÿäêîì U è V ïëîñêîñòåé
|
|
//YV12 - Y V U
|
|
//I420 - Y U V
|
|
//Èñïîëüçóåì äëÿ íèõ ÎÄÍÎ È ÒÎÆÅ ÏÐÅÎÁÐÀÇÎÂÀÍÈÅ (ðàáîòàþùèå ñ Y U V ïîðÿäêîì ïëîñêîñòåé),
|
|
//äëÿ YV12 ìåíÿåì ìåñòàìè ññûëêè íà U è V ïëîñêîñòè â m_oSrcFormat èëè m_oDstFormat
|
|
m_oSrcFormat.Plane[0] = pInpVideoFrame->m_oVideoFrame.Plane[0];
|
|
m_oSrcFormat.Plane[1] = pInpVideoFrame->m_oVideoFrame.Plane[1];
|
|
m_oSrcFormat.Plane[2] = pInpVideoFrame->m_oVideoFrame.Plane[2];
|
|
m_oSrcFormat.Plane[3] = pInpVideoFrame->m_oVideoFrame.Plane[3];
|
|
if (CSP_YV12 == (m_oSrcFormat.ColorSpace & CSP_COLOR_MASK))
|
|
{
|
|
m_oSrcFormat.Plane[1] = pInpVideoFrame->m_oVideoFrame.Plane[2];
|
|
m_oSrcFormat.Plane[2] = pInpVideoFrame->m_oVideoFrame.Plane[1];
|
|
}
|
|
IAVSUncompressedVideoFrame* piOutVideoFrame=NULL;
|
|
CoCreateInstance(__uuidof(CAVSUncompressedVideoFrame), NULL, CLSCTX_ALL, __uuidof(IAVSUncompressedVideoFrame), (void**)&piOutVideoFrame);
|
|
if (NULL==piOutVideoFrame)
|
|
return MEMORY;
|
|
|
|
VARIANT_BOOL vbTemp;
|
|
piInpFrame->get_IsDiscontinuity(&vbTemp);
|
|
piOutVideoFrame->put_IsDiscontinuity(vbTemp);
|
|
piInpFrame->get_IsTimeStampExist(&vbTemp);
|
|
if (VARIANT_FALSE!=vbTemp)
|
|
{
|
|
double dTimeStamp;
|
|
piInpFrame->get_TimeStamp(&dTimeStamp);
|
|
piOutVideoFrame->put_TimeStamp(dTimeStamp);
|
|
}
|
|
piInpFrame->get_IsDurationExist(&vbTemp);
|
|
if (VARIANT_FALSE!=vbTemp)
|
|
{
|
|
double dDuration;
|
|
piInpFrame->get_Duration(&dDuration);
|
|
piOutVideoFrame->put_Duration(dDuration);
|
|
}
|
|
|
|
CAVSUncompressedVideoFrame* pcOutVideoFrame=(CAVSUncompressedVideoFrame*)piOutVideoFrame;
|
|
pcOutVideoFrame->m_oVideoFrame = m_oDstFormat;
|
|
if ((0==m_oDstFormat.AspectX)||(0==m_oDstFormat.AspectY))
|
|
{
|
|
pcOutVideoFrame->m_oVideoFrame.AspectX = m_oSrcFormat.AspectX;
|
|
pcOutVideoFrame->m_oVideoFrame.AspectY = m_oSrcFormat.AspectY;
|
|
}
|
|
pcOutVideoFrame->AllocateBuffer(-1);
|
|
|
|
m_oDstFormat.Plane[0] = pcOutVideoFrame->m_oVideoFrame.Plane[0];
|
|
m_oDstFormat.Plane[1] = pcOutVideoFrame->m_oVideoFrame.Plane[1];
|
|
m_oDstFormat.Plane[2] = pcOutVideoFrame->m_oVideoFrame.Plane[2];
|
|
m_oDstFormat.Plane[3] = pcOutVideoFrame->m_oVideoFrame.Plane[3];
|
|
if (CSP_YV12 == (m_oDstFormat.ColorSpace & CSP_COLOR_MASK))
|
|
{
|
|
m_oDstFormat.Plane[1] = pcOutVideoFrame->m_oVideoFrame.Plane[2];
|
|
m_oDstFormat.Plane[2] = pcOutVideoFrame->m_oVideoFrame.Plane[1];
|
|
}
|
|
|
|
switch(m_nTransformType)
|
|
{
|
|
case ttErrorTransform:
|
|
ErrorTransform();
|
|
break;
|
|
case ttSimpleTransform:
|
|
SimpleTransform();
|
|
break;
|
|
case ttResizeTransform:
|
|
ResizeTransform();
|
|
break;
|
|
case ttDeinterlaceTransform:
|
|
DeinterlaceTransform();
|
|
break;
|
|
case ttResizeDeinterlaceTransform:
|
|
ResizeDeinterlaceTransform();
|
|
break;
|
|
}
|
|
|
|
if ((CSP_BGRA != (m_oSrcFormat.ColorSpace & CSP_COLOR_MASK)) &&
|
|
(CSP_BGRA == (m_oDstFormat.ColorSpace & CSP_COLOR_MASK)))
|
|
{
|
|
long lWidth = m_oDstFormat.Width;
|
|
long lHeight = m_oDstFormat.Height;
|
|
long lstride = m_oDstFormat.Stride[0] - 4*m_oDstFormat.Width;
|
|
LPBYTE ptrBuffer = m_oDstFormat.Plane[0] + 3;
|
|
for (long lRow = 0; lRow < lHeight; lRow++)
|
|
{
|
|
for (long lCol=0; lCol < lWidth; lCol++, ptrBuffer+=4)
|
|
{
|
|
*ptrBuffer = 255;
|
|
}
|
|
ptrBuffer += lstride;
|
|
}
|
|
}
|
|
piOutVideoFrame->QueryInterface(__uuidof(IAVSUncompressedVideoFrame), (void**)pOutFrame);
|
|
piOutVideoFrame->Release();
|
|
}
|
|
else
|
|
{
|
|
piInpFrame->QueryInterface(__uuidof(IAVSUncompressedVideoFrame), (void**)pOutFrame);
|
|
}
|
|
if (m_lRotateAngle == 90 || m_lRotateAngle == 180 || m_lRotateAngle == 270)
|
|
{
|
|
IAVSUncompressedVideoFrame* pOutFrameRotate = NULL;
|
|
HRESULT hr = RotateFrame((IAVSUncompressedVideoFrame*)(*pOutFrame),&pOutFrameRotate);
|
|
if (pOutFrameRotate)
|
|
{
|
|
(*pOutFrame)->Release();
|
|
pOutFrameRotate->QueryInterface(__uuidof(IAVSUncompressedVideoFrame), (void**)pOutFrame);
|
|
pOutFrameRotate->Release();
|
|
}
|
|
}
|
|
piInpFrame->Release();
|
|
//ATLTRACE("CAVSVideoFrameTransform::TransformFrame end 0x%08X\n", this);
|
|
return S_OK;
|
|
}
|
|
HRESULT RotateFrame (IAVSUncompressedVideoFrame* pInpFrame, IAVSUncompressedVideoFrame** ppOutFrame)
|
|
{
|
|
if ( !(m_oDstFormat.ColorSpace & CSP_YV12 || m_oDstFormat.ColorSpace & CSP_I420))
|
|
{
|
|
//äëÿ îñòàëüíûõ êîëîð ñïéñîâ ïîêà íå ðåàëèçîâàíî
|
|
pInpFrame->CreateDuplicate(DUBLICATE_TYPE_COPY,(IAVSMediaData**)ppOutFrame);
|
|
return S_OK;
|
|
}
|
|
SUncompressedVideoFrame m_oDstFormatRotate = m_oDstFormat;
|
|
if (m_lRotateAngle == 90 || m_lRotateAngle == 270)
|
|
{
|
|
//ïîâîðîò êàðòèíêè äåëàåòñÿ ÏÎÑËÅ âñåõ îñòàëüíûõ ïðåîáðàîâàíèé
|
|
//îí çàäàåòñÿ òîëüêî óãëîì ïîâîðîòà, à íå ôîðìàòîì
|
|
|
|
m_oDstFormatRotate.AspectX = m_oDstFormat.AspectY;
|
|
m_oDstFormatRotate.AspectY = m_oDstFormat.AspectX;
|
|
|
|
m_oDstFormatRotate.Width = m_oDstFormat.Height;
|
|
m_oDstFormatRotate.Height = m_oDstFormat.Width;
|
|
}
|
|
|
|
*ppOutFrame=NULL;
|
|
CoCreateInstance(__uuidof(CAVSUncompressedVideoFrame), NULL, CLSCTX_ALL, __uuidof(IAVSUncompressedVideoFrame), (void**)ppOutFrame);
|
|
if (NULL==(*ppOutFrame))
|
|
return MEMORY;
|
|
|
|
VARIANT_BOOL vbTemp;
|
|
pInpFrame->get_IsDiscontinuity(&vbTemp);
|
|
(*ppOutFrame)->put_IsDiscontinuity(vbTemp);
|
|
pInpFrame->get_IsTimeStampExist(&vbTemp);
|
|
if (VARIANT_FALSE!=vbTemp)
|
|
{
|
|
double dTimeStamp;
|
|
pInpFrame->get_TimeStamp(&dTimeStamp);
|
|
(*ppOutFrame)->put_TimeStamp(dTimeStamp);
|
|
}
|
|
pInpFrame->get_IsDurationExist(&vbTemp);
|
|
if (VARIANT_FALSE!=vbTemp)
|
|
{
|
|
double dDuration;
|
|
pInpFrame->get_Duration(&dDuration);
|
|
(*ppOutFrame)->put_Duration(dDuration);
|
|
}
|
|
CAVSUncompressedVideoFrame* pcInpFrame=(CAVSUncompressedVideoFrame*)(pInpFrame);
|
|
CAVSUncompressedVideoFrame* pcOutFrame=(CAVSUncompressedVideoFrame*)(*ppOutFrame);
|
|
pcOutFrame->m_oVideoFrame = m_oDstFormatRotate;
|
|
|
|
pcOutFrame->AllocateBuffer(-1);
|
|
|
|
int tmpColorSpace = m_oDstFormat.ColorSpace & CSP_COLOR_MASK;
|
|
if (CSP_YV12 == tmpColorSpace)
|
|
{
|
|
int res = I420Rotate(
|
|
pcInpFrame->m_oVideoFrame.Plane[0],pcInpFrame->m_oVideoFrame.Stride[0],
|
|
pcInpFrame->m_oVideoFrame.Plane[2],pcInpFrame->m_oVideoFrame.Stride[2],
|
|
pcInpFrame->m_oVideoFrame.Plane[1],pcInpFrame->m_oVideoFrame.Stride[1],
|
|
|
|
pcOutFrame->m_oVideoFrame.Plane[0],pcOutFrame->m_oVideoFrame.Stride[0],
|
|
pcOutFrame->m_oVideoFrame.Plane[2],pcOutFrame->m_oVideoFrame.Stride[2],
|
|
pcOutFrame->m_oVideoFrame.Plane[1],pcOutFrame->m_oVideoFrame.Stride[1],
|
|
|
|
pcInpFrame->m_oVideoFrame.Width,
|
|
pcInpFrame->m_oVideoFrame.Height,
|
|
|
|
m_lRotateAngle);
|
|
}
|
|
else if (CSP_I420 == tmpColorSpace)
|
|
{
|
|
int res = I420Rotate(
|
|
pcInpFrame->m_oVideoFrame.Plane[0],pcInpFrame->m_oVideoFrame.Stride[0],
|
|
pcInpFrame->m_oVideoFrame.Plane[1],pcInpFrame->m_oVideoFrame.Stride[1],
|
|
pcInpFrame->m_oVideoFrame.Plane[2],pcInpFrame->m_oVideoFrame.Stride[2],
|
|
|
|
pcOutFrame->m_oVideoFrame.Plane[0],pcOutFrame->m_oVideoFrame.Stride[0],
|
|
pcOutFrame->m_oVideoFrame.Plane[1],pcOutFrame->m_oVideoFrame.Stride[1],
|
|
pcOutFrame->m_oVideoFrame.Plane[2],pcOutFrame->m_oVideoFrame.Stride[2],
|
|
|
|
pcInpFrame->m_oVideoFrame.Width,
|
|
pcInpFrame->m_oVideoFrame.Height,
|
|
|
|
m_lRotateAngle);
|
|
}
|
|
else if (CSP_BGRA == tmpColorSpace || CSP_RGBA == tmpColorSpace || CSP_ABGR == tmpColorSpace)
|
|
{
|
|
fastconvert_RGB32CopyMem(&pcInpFrame->m_oVideoFrame, &pcOutFrame->m_oVideoFrame, m_bMirror);
|
|
}
|
|
else if (CSP_BGR == tmpColorSpace)
|
|
{
|
|
fastconvert_RGB24CopyMem(&pcInpFrame->m_oVideoFrame, &pcOutFrame->m_oVideoFrame, m_bMirror);
|
|
}
|
|
else if (CSP_YUY2 == tmpColorSpace)
|
|
{
|
|
fastconvert_YUY2CopyMem(&pcInpFrame->m_oVideoFrame, &pcOutFrame->m_oVideoFrame, m_bMirror);
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHOD(ReleaseBuffers)(void)
|
|
{
|
|
FreeBuffers();
|
|
|
|
memset(&m_oSrcFormat, 0, sizeof(SUncompressedVideoFrame));
|
|
memset(&m_oDstFormat, 0, sizeof(SUncompressedVideoFrame));
|
|
|
|
m_lResizeMode = 0;
|
|
m_bDeinterlaceEnabled = TRUE;
|
|
m_bRealNeedDeinterlace = FALSE;
|
|
m_lDeinterlaceMethod = 0;
|
|
|
|
m_lCropScale = 0;
|
|
//m_nRGBDstBorderGrayScale = 0x00;
|
|
//m_nYDstBorderGrayScale = 0x00;
|
|
//m_nUDstBorderGrayScale = 0x80;
|
|
//m_nVDstBorderGrayScale = 0x80;
|
|
|
|
m_dwBGRDstBorderColor = 0x00;
|
|
m_nYDstBorderColor = 0x00;
|
|
m_nUDstBorderColor = 0x80;
|
|
m_nVDstBorderColor = 0x80;
|
|
|
|
m_arlResizeModes[0] = IPPI_INTER_NN;
|
|
m_arlResizeModes[1] = IPPI_INTER_LINEAR;
|
|
m_arlResizeModes[2] = IPPI_INTER_CUBIC;
|
|
m_arlResizeModes[3] = IPPI_INTER_SUPER;
|
|
|
|
m_bFillBackground = FALSE;
|
|
|
|
m_nTransformType = ttErrorTransform;
|
|
|
|
m_bIsNeedTransform=false;
|
|
m_bIsNeedAplly=true;
|
|
|
|
m_lInpColorSpace = CSP_I420;
|
|
m_lOutColorSpace = CSP_I420;
|
|
m_bMirror = FALSE;
|
|
|
|
m_lRotateAngle = 0;
|
|
return S_OK;
|
|
}
|
|
protected:
|
|
enum TransformType
|
|
{
|
|
ttErrorTransform = 0,
|
|
ttSimpleTransform = 1,
|
|
ttResizeTransform = 2,
|
|
ttDeinterlaceTransform = 3,
|
|
ttResizeDeinterlaceTransform = 4,
|
|
};
|
|
int m_nTransformType;
|
|
|
|
BOOL __fastcall IsChangeArrayFormat(CAVSUncompressedVideoFrame* pVideoFrame);
|
|
void __fastcall ApplySettings();
|
|
|
|
void __fastcall FillBuffer(SUncompressedVideoFrame* pVideoFrame, BYTE* pBuffer);
|
|
void __fastcall AllocBuffer(SUncompressedVideoFrame* pVideoFrame, SUncompressedVideoFrame* pFrame, long lColorSpace);
|
|
void __fastcall FreeBuffer(SUncompressedVideoFrame *pVideoFrame);
|
|
void __fastcall FreeBuffers();
|
|
void __fastcall SetDefaultStride(SUncompressedVideoFrame *pVideoFrame);
|
|
|
|
void ResizeDeinterlaceTransform();
|
|
void DeinterlaceTransform();
|
|
void ResizeTransform();
|
|
void SimpleTransform();
|
|
void ErrorTransform();
|
|
|
|
void ResizeDeinterlaceAlloc();
|
|
void DeinterlaceAlloc();
|
|
void ResizeAlloc();
|
|
void SimpleAlloc();
|
|
void ErrorAlloc();
|
|
|
|
void __fastcall RGB32Resize(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame);
|
|
void __fastcall RGB24Resize(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame);
|
|
void __fastcall YV12Resize(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame);
|
|
void __fastcall YUY2Resize(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame);
|
|
|
|
void __fastcall RGB32ToRGB24(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame, bool Mirror);
|
|
void __fastcall RGB24ToRGB32(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame, bool Mirror);
|
|
|
|
void __fastcall RGB8ToRGB24(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame, bool Mirror);
|
|
void __fastcall RGB8ToRGB32(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame, bool Mirror);
|
|
|
|
void __fastcall RGB32Deinterlace(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame);
|
|
void __fastcall RGB24Deinterlace(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame);
|
|
void __fastcall YV12Deinterlace(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame);
|
|
void __fastcall YUY2Deinterlace(SUncompressedVideoFrame* InpFrame, SUncompressedVideoFrame* OutFrame);
|
|
|
|
long m_arlResizeModes[4];
|
|
long m_lResizeMode;
|
|
BOOL m_bDeinterlaceEnabled;
|
|
BOOL m_bRealNeedDeinterlace;
|
|
long m_lDeinterlaceMethod;
|
|
long m_lCropScale;
|
|
|
|
//BYTE m_nRGBDstBorderGrayScale;
|
|
//BYTE m_nYDstBorderGrayScale;
|
|
//BYTE m_nUDstBorderGrayScale;
|
|
//BYTE m_nVDstBorderGrayScale;
|
|
|
|
DWORD m_dwBGRDstBorderColor;
|
|
BYTE m_nYDstBorderColor;
|
|
BYTE m_nUDstBorderColor;
|
|
BYTE m_nVDstBorderColor;
|
|
|
|
BOOL m_bIsNeedAplly;
|
|
|
|
SUncompressedVideoFrame m_oSrcFormat;
|
|
SUncompressedVideoFrame m_oDstFormat;
|
|
|
|
SUncompressedVideoFrame m_oVideoBuffer1;
|
|
SUncompressedVideoFrame m_oVideoBuffer2;
|
|
SUncompressedVideoFrame m_oVideoBuffer3;
|
|
|
|
BOOL m_bFillBackground;
|
|
BOOL m_bIsNeedTransform;
|
|
|
|
long m_lInpColorSpace;
|
|
long m_lOutColorSpace;
|
|
bool m_bMirror;
|
|
|
|
long m_lRotateAngle;
|
|
|
|
private:
|
|
|
|
#define kMaxStride (2560 * 4)
|
|
|
|
#if defined(_MSC_VER) && !defined(__CLR_VER)
|
|
#define SIMD_ALIGNED(var) __declspec(align(16)) var
|
|
#endif
|
|
int I420Rotate(const BYTE* src_y, int src_stride_y,
|
|
const BYTE* src_u, int src_stride_u,
|
|
const BYTE* src_v, int src_stride_v,
|
|
BYTE* dst_y, int dst_stride_y,
|
|
BYTE* dst_u, int dst_stride_u,
|
|
BYTE* dst_v, int dst_stride_v,
|
|
int width, int height,
|
|
int mode)
|
|
{
|
|
if (!src_y || !src_u || !src_v || width <= 0 || height == 0 ||
|
|
!dst_y || !dst_u || !dst_v)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int halfwidth = (width + 1) >> 1;
|
|
int halfheight = (height + 1) >> 1;
|
|
|
|
// Negative height means invert the image.
|
|
if (height < 0)
|
|
{
|
|
height = -height;
|
|
halfheight = (height + 1) >> 1;
|
|
src_y = src_y + (height - 1) * src_stride_y;
|
|
src_u = src_u + (halfheight - 1) * src_stride_u;
|
|
src_v = src_v + (halfheight - 1) * src_stride_v;
|
|
src_stride_y = -src_stride_y;
|
|
src_stride_u = -src_stride_u;
|
|
src_stride_v = -src_stride_v;
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case 90:
|
|
RotatePlane90(src_y, src_stride_y,
|
|
dst_y, dst_stride_y,
|
|
width, height);
|
|
RotatePlane90(src_u, src_stride_u,
|
|
dst_u, dst_stride_u,
|
|
halfwidth, halfheight);
|
|
RotatePlane90(src_v, src_stride_v,
|
|
dst_v, dst_stride_v,
|
|
halfwidth, halfheight);
|
|
return 0;
|
|
case 270:
|
|
RotatePlane270(src_y, src_stride_y,
|
|
dst_y, dst_stride_y,
|
|
width, height);
|
|
RotatePlane270(src_u, src_stride_u,
|
|
dst_u, dst_stride_u,
|
|
halfwidth, halfheight);
|
|
RotatePlane270(src_v, src_stride_v,
|
|
dst_v, dst_stride_v,
|
|
halfwidth, halfheight);
|
|
return 0;
|
|
case 180:
|
|
RotatePlane180(src_y, src_stride_y,
|
|
dst_y, dst_stride_y,
|
|
width, height);
|
|
RotatePlane180(src_u, src_stride_u,
|
|
dst_u, dst_stride_u,
|
|
halfwidth, halfheight);
|
|
RotatePlane180(src_v, src_stride_v,
|
|
dst_v, dst_stride_v,
|
|
halfwidth, halfheight);
|
|
return 0;
|
|
default:
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
void RotatePlane90(const BYTE* src, int src_stride,
|
|
BYTE* dst, int dst_stride,
|
|
int width, int height)
|
|
{
|
|
// Rotate by 90 is a transpose with the source read
|
|
// from bottom to top. So set the source pointer to the end
|
|
// of the buffer and flip the sign of the source stride.
|
|
src += src_stride * (height - 1);
|
|
src_stride = -src_stride;
|
|
TransposePlane(src, src_stride, dst, dst_stride, width, height);
|
|
}
|
|
|
|
void RotatePlane270(const BYTE* src, int src_stride,
|
|
BYTE* dst, int dst_stride,
|
|
int width, int height)
|
|
{
|
|
// Rotate by 270 is a transpose with the destination written
|
|
// from bottom to top. So set the destination pointer to the end
|
|
// of the buffer and flip the sign of the destination stride.
|
|
dst += dst_stride * (width - 1);
|
|
dst_stride = -dst_stride;
|
|
TransposePlane(src, src_stride, dst, dst_stride, width, height);
|
|
}
|
|
|
|
void RotatePlane180(const BYTE* src, int src_stride,
|
|
BYTE* dst, int dst_stride,
|
|
int width, int height)
|
|
{
|
|
// â áóäóùåì ìîæíî ñäåëàòü
|
|
|
|
// void (*MirrorRow)(const BYTE* src, BYTE* dst, int width) = MirrorRow_C;
|
|
//#if defined(HAS_MIRRORROW_SSE2)
|
|
// if (TestCpuFlag(kCpuHasSSE2) &&
|
|
// IS_ALIGNED(width, 16) &&
|
|
// IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16) &&
|
|
// IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
|
|
// MirrorRow = MirrorRow_SSE2;
|
|
// }
|
|
//#endif
|
|
//#if defined(HAS_MIRRORROW_SSSE3)
|
|
// if (TestCpuFlag(kCpuHasSSSE3) &&
|
|
// IS_ALIGNED(width, 16) &&
|
|
// IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16) &&
|
|
// IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
|
|
// MirrorRow = MirrorRow_SSSE3;
|
|
// }
|
|
//#endif
|
|
// void (*CopyRow)(const BYTE* src, BYTE* dst, int width) = CopyRow_C;
|
|
//#if defined(HAS_COPYROW_X86)
|
|
// if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
|
|
// CopyRow = CopyRow_X86;
|
|
// }
|
|
//#endif
|
|
//#if defined(HAS_COPYROW_SSE2)
|
|
// if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
|
|
// IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16) &&
|
|
// IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
|
|
// CopyRow = CopyRow_SSE2;
|
|
// }
|
|
//#endif
|
|
if (width > kMaxStride)
|
|
{
|
|
return;
|
|
}
|
|
// Swap first and last row and mirror the content. Uses a temporary row.
|
|
SIMD_ALIGNED(BYTE row[kMaxStride]);
|
|
const BYTE* src_bot = src + src_stride * (height - 1);
|
|
BYTE* dst_bot = dst + dst_stride * (height - 1);
|
|
int half_height = (height + 1) >> 1;
|
|
// Odd height will harmlessly mirror the middle row twice.
|
|
for (int y = 0; y < half_height; ++y)
|
|
{
|
|
MirrorRow(src, row, width); // Mirror first row into a buffer
|
|
src += src_stride;
|
|
MirrorRow(src_bot, dst, width); // Mirror last row into first row
|
|
dst += dst_stride;
|
|
CopyRow(row, dst_bot, width); // Copy first mirrored row into last
|
|
src_bot -= src_stride;
|
|
dst_bot -= dst_stride;
|
|
}
|
|
}
|
|
|
|
void MirrorRow(const BYTE* src, BYTE* dst, int width)
|
|
{
|
|
src += width - 1;
|
|
for (int x = 0; x < width - 1; x += 2) {
|
|
dst[x] = src[0];
|
|
dst[x + 1] = src[-1];
|
|
src -= 2;
|
|
}
|
|
if (width & 1)
|
|
{
|
|
dst[width - 1] = src[0];
|
|
}
|
|
}
|
|
|
|
void CopyRow(const BYTE* src, BYTE* dst, int count)
|
|
{
|
|
memcpy(dst, src, count);
|
|
}
|
|
|
|
void TransposePlane(const BYTE* src, int src_stride,
|
|
BYTE* dst, int dst_stride,
|
|
int width, int height)
|
|
{
|
|
//void (*TransposeWx8)(const BYTE* src, int src_stride,
|
|
// BYTE* dst, int dst_stride,
|
|
// int width) = TransposeWx8_C;
|
|
|
|
//#if defined(HAS_TRANSPOSE_WX8_SSSE3)
|
|
// if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8)) {
|
|
// TransposeWx8 = TransposeWx8_SSSE3;
|
|
// }
|
|
//#endif
|
|
//#if defined(HAS_TRANSPOSE_WX8_FAST_SSSE3)
|
|
// if (TestCpuFlag(kCpuHasSSSE3) &&
|
|
// IS_ALIGNED(width, 16) &&
|
|
// IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16)) {
|
|
// TransposeWx8 = TransposeWx8_FAST_SSSE3;
|
|
// }
|
|
//#endif
|
|
|
|
// Work across the source in 8x8 tiles
|
|
int i = height;
|
|
while (i >= 8)
|
|
{
|
|
TransposeWx8(src, src_stride, dst, dst_stride, width);
|
|
src += 8 * src_stride; // Go down 8 rows.
|
|
dst += 8; // Move over 8 columns.
|
|
i -= 8;
|
|
}
|
|
|
|
TransposeWxH(src, src_stride, dst, dst_stride, width, i);
|
|
}
|
|
|
|
static void TransposeWx8(const BYTE* src, int src_stride,
|
|
BYTE* dst, int dst_stride,
|
|
int width)
|
|
{
|
|
for (int i = 0; i < width; ++i)
|
|
{
|
|
dst[0] = src[0 * src_stride];
|
|
dst[1] = src[1 * src_stride];
|
|
dst[2] = src[2 * src_stride];
|
|
dst[3] = src[3 * src_stride];
|
|
dst[4] = src[4 * src_stride];
|
|
dst[5] = src[5 * src_stride];
|
|
dst[6] = src[6 * src_stride];
|
|
dst[7] = src[7 * src_stride];
|
|
++src;
|
|
dst += dst_stride;
|
|
}
|
|
}
|
|
|
|
static void TransposeWxH(const BYTE* src, int src_stride,
|
|
BYTE* dst, int dst_stride,
|
|
int width, int height)
|
|
{
|
|
for (int i = 0; i < width; ++i)
|
|
{
|
|
for (int j = 0; j < height; ++j)
|
|
{
|
|
dst[i * dst_stride + j] = src[j * src_stride + i];
|
|
}
|
|
}
|
|
}
|
|
|
|
#define AVS_COMMON _T("SOFTWARE\\AVS4YOU\\Common")
|
|
|
|
void GetDeinterlaceMethodeFromRegistry()
|
|
{
|
|
m_lDeinterlaceMethod = 0; // default
|
|
|
|
bool bGotValidValue = false;
|
|
|
|
HKEY keyHandle;
|
|
LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, AVS_COMMON, 0, KEY_QUERY_VALUE, &keyHandle);
|
|
if( ERROR_SUCCESS == result )
|
|
{
|
|
long nMode;
|
|
DWORD size1=sizeof(nMode);
|
|
DWORD Type;
|
|
if ( ERROR_SUCCESS == RegQueryValueEx( keyHandle, _T("DeinterlaceMethod"), NULL, &Type,
|
|
(LPBYTE)&nMode,&size1) )
|
|
{
|
|
if ( DEINTERLACE_METHOD_BLEND == nMode ||
|
|
DEINTERLACE_METHOD_MIDDLE == nMode )
|
|
{
|
|
m_lDeinterlaceMethod = nMode;
|
|
bGotValidValue = true;
|
|
}
|
|
else
|
|
{
|
|
ATLTRACE2("Invalid impl mode got from registry: %d\n", nMode);
|
|
}
|
|
}
|
|
}
|
|
RegCloseKey(keyHandle);
|
|
|
|
if ( !bGotValidValue )
|
|
{
|
|
// failed to get valid mode from registry, let's update it (with MFX_IMPL_AUTO)
|
|
UpdateDeinterlaceMethodToRegistry();
|
|
}
|
|
}
|
|
void UpdateDeinterlaceMethodToRegistry()
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwDisposition;
|
|
LONG result = RegCreateKeyEx(HKEY_CURRENT_USER, AVS_COMMON, 0, NULL, 0, KEY_CREATE_SUB_KEY|KEY_SET_VALUE, NULL, &hkey, &dwDisposition);
|
|
if ( ERROR_SUCCESS == result )
|
|
{
|
|
long nVal = m_lDeinterlaceMethod;
|
|
result = RegSetValueEx(hkey, _T("DeinterlaceMethod"), 0, REG_DWORD, (PBYTE)&nVal, sizeof(DWORD));
|
|
if ( ERROR_SUCCESS != result )
|
|
ATLTRACE2(_T("Cannot update registry key value.\n"));
|
|
RegCloseKey(hkey);
|
|
}
|
|
else
|
|
ATLTRACE2(_T("Cannot open registry key for writing.\n"));
|
|
}
|
|
};
|
|
|