Files
core/ASCMediaCore3/ASCVideoFrameTransform.h

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"));
}
};