Add openh264 encoder support.

This commit is contained in:
Vic Lee 2015-02-16 17:51:20 +08:00
parent 7db6a13b6c
commit 3c3c7068a0
4 changed files with 290 additions and 40 deletions

View File

@ -30,6 +30,7 @@ typedef BOOL (*pfnH264SubsystemInit)(H264_CONTEXT* h264);
typedef void (*pfnH264SubsystemUninit)(H264_CONTEXT* h264); typedef void (*pfnH264SubsystemUninit)(H264_CONTEXT* h264);
typedef int (*pfnH264SubsystemDecompress)(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize); typedef int (*pfnH264SubsystemDecompress)(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize);
typedef int (*pfnH264SubsystemCompress)(H264_CONTEXT* h264, UINT32 TargetFrameSizeInBits, BYTE** ppDstData, UINT32* pDstSize);
struct _H264_CONTEXT_SUBSYSTEM struct _H264_CONTEXT_SUBSYSTEM
{ {
@ -37,6 +38,7 @@ struct _H264_CONTEXT_SUBSYSTEM
pfnH264SubsystemInit Init; pfnH264SubsystemInit Init;
pfnH264SubsystemUninit Uninit; pfnH264SubsystemUninit Uninit;
pfnH264SubsystemDecompress Decompress; pfnH264SubsystemDecompress Decompress;
pfnH264SubsystemCompress Compress;
}; };
typedef struct _H264_CONTEXT_SUBSYSTEM H264_CONTEXT_SUBSYSTEM; typedef struct _H264_CONTEXT_SUBSYSTEM H264_CONTEXT_SUBSYSTEM;
@ -58,7 +60,9 @@ struct _H264_CONTEXT
extern "C" { extern "C" {
#endif #endif
FREERDP_API int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize); FREERDP_API int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, DWORD SrcFormat,
int nSrcStep, int nSrcWidth, int nSrcHeight, UINT32 TargetFrameSizeInBits,
BYTE** ppDstData, UINT32* pDstSize);
FREERDP_API int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, FREERDP_API int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize,
BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nDstWidth, int nDstHeight, BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nDstWidth, int nDstHeight,

View File

@ -172,6 +172,10 @@ typedef pstatus_t (*__YUV420ToRGB_8u_P3AC4R_t)(
const BYTE* pSrc[3], INT32 srcStep[3], const BYTE* pSrc[3], INT32 srcStep[3],
BYTE* pDst, INT32 dstStep, BYTE* pDst, INT32 dstStep,
const prim_size_t* roi); const prim_size_t* roi);
typedef pstatus_t (*__RGBToYUV420_8u_P3AC4R_t)(
const BYTE* pSrc, INT32 srcStep,
BYTE* pDst[3], INT32 dstStep[3],
const prim_size_t* roi);
typedef pstatus_t (*__andC_32u_t)( typedef pstatus_t (*__andC_32u_t)(
const UINT32 *pSrc, const UINT32 *pSrc,
UINT32 val, UINT32 val,
@ -219,6 +223,7 @@ typedef struct
__YCoCgToRGB_8u_AC4R_t YCoCgToRGB_8u_AC4R; __YCoCgToRGB_8u_AC4R_t YCoCgToRGB_8u_AC4R;
__RGB565ToARGB_16u32u_C3C4_t RGB565ToARGB_16u32u_C3C4; __RGB565ToARGB_16u32u_C3C4_t RGB565ToARGB_16u32u_C3C4;
__YUV420ToRGB_8u_P3AC4R_t YUV420ToRGB_8u_P3AC4R; __YUV420ToRGB_8u_P3AC4R_t YUV420ToRGB_8u_P3AC4R;
__RGBToYUV420_8u_P3AC4R_t RGBToYUV420_8u_P3AC4R;
} primitives_t; } primitives_t;
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -70,6 +70,8 @@ static H264_CONTEXT_SUBSYSTEM g_Subsystem_dummy =
struct _H264_CONTEXT_OPENH264 struct _H264_CONTEXT_OPENH264
{ {
ISVCDecoder* pDecoder; ISVCDecoder* pDecoder;
ISVCEncoder* pEncoder;
SEncParamBase EncParamBase;
}; };
typedef struct _H264_CONTEXT_OPENH264 H264_CONTEXT_OPENH264; typedef struct _H264_CONTEXT_OPENH264 H264_CONTEXT_OPENH264;
@ -148,6 +150,86 @@ static int openh264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSiz
return 1; return 1;
} }
static int openh264_compress(H264_CONTEXT* h264, UINT32 TargetFrameSizeInBits, BYTE** ppDstData, UINT32* pDstSize)
{
int i, j;
int status;
SFrameBSInfo info;
SSourcePicture pic;
SBitrateInfo bitrate;
H264_CONTEXT_OPENH264* sys = (H264_CONTEXT_OPENH264*) h264->pSystemData;
if (!sys->pEncoder)
return -1;
if (!h264->pYUVData[0] || !h264->pYUVData[1] || !h264->pYUVData[2])
return -1;
if (sys->EncParamBase.iPicWidth != h264->width ||
sys->EncParamBase.iPicHeight != h264->height)
{
sys->EncParamBase.iUsageType = SCREEN_CONTENT_REAL_TIME;
sys->EncParamBase.iPicWidth = h264->width;
sys->EncParamBase.iPicHeight = h264->height;
sys->EncParamBase.iTargetBitrate = TargetFrameSizeInBits * 30;
sys->EncParamBase.iRCMode = RC_BITRATE_MODE;
sys->EncParamBase.fMaxFrameRate = 30.0f;
status = (*sys->pEncoder)->Initialize(sys->pEncoder, &sys->EncParamBase);
if (status < 0)
{
WLog_ERR(TAG, "Failed to initialize OpenH264 encoder (status=%ld)", status);
return status;
}
}
else if (sys->EncParamBase.iTargetBitrate != TargetFrameSizeInBits * 30)
{
sys->EncParamBase.iTargetBitrate = TargetFrameSizeInBits * 30;
bitrate.iLayer = SPATIAL_LAYER_ALL;
bitrate.iBitrate = TargetFrameSizeInBits * 30;
status = (*sys->pEncoder)->SetOption(sys->pEncoder, ENCODER_OPTION_BITRATE, &bitrate);
if (status < 0)
{
WLog_ERR(TAG, "Failed to set encoder bitrate (status=%ld)", status);
return status;
}
}
memset(&info, 0, sizeof(SFrameBSInfo));
memset(&pic, 0, sizeof(SSourcePicture));
pic.iPicWidth = h264->width;
pic.iPicHeight = h264->height;
pic.iColorFormat = videoFormatI420;
pic.iStride[0] = h264->iStride[0];
pic.iStride[1] = h264->iStride[1];
pic.iStride[2] = h264->iStride[2];
pic.pData[0] = h264->pYUVData[0];
pic.pData[1] = h264->pYUVData[1];
pic.pData[2] = h264->pYUVData[2];
status = (*sys->pEncoder)->EncodeFrame(sys->pEncoder, &pic, &info);
if (status < 0)
{
WLog_ERR(TAG, "Failed to encode frame (status=%ld)", status);
return status;
}
*ppDstData = info.sLayerInfo[0].pBsBuf;
*pDstSize = 0;
for (i = 0; i < info.iLayerNum; i++)
{
for (j = 0; j < info.sLayerInfo[i].iNalCount; j++)
{
*pDstSize += info.sLayerInfo[i].pNalLengthInByte[j];
}
}
return 1;
}
static void openh264_uninit(H264_CONTEXT* h264) static void openh264_uninit(H264_CONTEXT* h264)
{ {
H264_CONTEXT_OPENH264* sys = (H264_CONTEXT_OPENH264*) h264->pSystemData; H264_CONTEXT_OPENH264* sys = (H264_CONTEXT_OPENH264*) h264->pSystemData;
@ -161,6 +243,13 @@ static void openh264_uninit(H264_CONTEXT* h264)
sys->pDecoder = NULL; sys->pDecoder = NULL;
} }
if (sys->pEncoder)
{
(*sys->pEncoder)->Uninitialize(sys->pEncoder);
WelsDestroySVCEncoder(sys->pEncoder);
sys->pEncoder = NULL;
}
free(sys); free(sys);
h264->pSystemData = NULL; h264->pSystemData = NULL;
} }
@ -184,55 +273,68 @@ static BOOL openh264_init(H264_CONTEXT* h264)
h264->pSystemData = (void*) sys; h264->pSystemData = (void*) sys;
WelsCreateDecoder(&sys->pDecoder); if (h264->Compressor)
if (!sys->pDecoder)
{ {
WLog_ERR(TAG, "Failed to create OpenH264 decoder"); WelsCreateSVCEncoder(&sys->pEncoder);
goto EXCEPTION;
}
ZeroMemory(&sDecParam, sizeof(sDecParam)); if (!sys->pEncoder)
sDecParam.eOutputColorFormat = videoFormatI420;
sDecParam.eEcActiveIdc = ERROR_CON_FRAME_COPY;
sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
status = (*sys->pDecoder)->Initialize(sys->pDecoder, &sDecParam);
if (status != 0)
{
WLog_ERR(TAG, "Failed to initialize OpenH264 decoder (status=%ld)", status);
goto EXCEPTION;
}
status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_DATAFORMAT, &videoFormat);
if (status != 0)
{
WLog_ERR(TAG, "Failed to set data format option on OpenH264 decoder (status=%ld)", status);
}
if (g_openh264_trace_enabled)
{
status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_LEVEL, &traceLevel);
if (status != 0)
{ {
WLog_ERR(TAG, "Failed to set trace level option on OpenH264 decoder (status=%ld)", status); WLog_ERR(TAG, "Failed to create OpenH264 encoder");
goto EXCEPTION;
}
}
else
{
WelsCreateDecoder(&sys->pDecoder);
if (!sys->pDecoder)
{
WLog_ERR(TAG, "Failed to create OpenH264 decoder");
goto EXCEPTION;
} }
status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK, &traceCallback); ZeroMemory(&sDecParam, sizeof(sDecParam));
sDecParam.eOutputColorFormat = videoFormatI420;
sDecParam.eEcActiveIdc = ERROR_CON_FRAME_COPY;
sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
status = (*sys->pDecoder)->Initialize(sys->pDecoder, &sDecParam);
if (status != 0) if (status != 0)
{ {
WLog_ERR(TAG, "Failed to set trace callback option on OpenH264 decoder (status=%ld)", status); WLog_ERR(TAG, "Failed to initialize OpenH264 decoder (status=%ld)", status);
goto EXCEPTION;
} }
status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK_CONTEXT, &h264); status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_DATAFORMAT, &videoFormat);
if (status != 0) if (status != 0)
{ {
WLog_ERR(TAG, "Failed to set trace callback context option on OpenH264 decoder (status=%ld)", status); WLog_ERR(TAG, "Failed to set data format option on OpenH264 decoder (status=%ld)", status);
}
if (g_openh264_trace_enabled)
{
status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_LEVEL, &traceLevel);
if (status != 0)
{
WLog_ERR(TAG, "Failed to set trace level option on OpenH264 decoder (status=%ld)", status);
}
status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK, &traceCallback);
if (status != 0)
{
WLog_ERR(TAG, "Failed to set trace callback option on OpenH264 decoder (status=%ld)", status);
}
status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK_CONTEXT, &h264);
if (status != 0)
{
WLog_ERR(TAG, "Failed to set trace callback context option on OpenH264 decoder (status=%ld)", status);
}
} }
} }
@ -249,7 +351,8 @@ static H264_CONTEXT_SUBSYSTEM g_Subsystem_OpenH264 =
"OpenH264", "OpenH264",
openh264_init, openh264_init,
openh264_uninit, openh264_uninit,
openh264_decompress openh264_decompress,
openh264_compress
}; };
#endif #endif
@ -494,9 +597,45 @@ int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize,
return 1; return 1;
} }
int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize) int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, DWORD SrcFormat,
int nSrcStep, int nSrcWidth, int nSrcHeight, UINT32 TargetFrameSizeInBits,
BYTE** ppDstData, UINT32* pDstSize)
{ {
return 1; int status;
prim_size_t roi;
int nWidth, nHeight;
primitives_t *prims = primitives_get();
if (!h264)
return -1;
if (!h264->subsystem->Compress)
return -1;
nWidth = (nSrcWidth + 1) & ~1;
nHeight = (nSrcHeight + 1) & ~1;
h264->pYUVData[0] = (BYTE*) malloc(nWidth * nHeight);
h264->iStride[0] = nWidth;
h264->pYUVData[1] = (BYTE*) malloc(nWidth * nHeight / 4);
h264->iStride[1] = nWidth / 2;
h264->pYUVData[2] = (BYTE*) malloc(nWidth * nHeight / 4);
h264->iStride[2] = nWidth / 2;
h264->width = nWidth;
h264->height = nHeight;
roi.width = nSrcWidth;
roi.height = nSrcHeight;
prims->RGBToYUV420_8u_P3AC4R(pSrcData, nSrcStep, h264->pYUVData, h264->iStride, &roi);
status = h264->subsystem->Compress(h264, TargetFrameSizeInBits, ppDstData, pDstSize);
free(h264->pYUVData[0]);
free(h264->pYUVData[1]);
free(h264->pYUVData[2]);
h264->pYUVData[0] = NULL;
h264->pYUVData[1] = NULL;
h264->pYUVData[2] = NULL;
return status;
} }
BOOL h264_context_init(H264_CONTEXT* h264) BOOL h264_context_init(H264_CONTEXT* h264)

View File

@ -265,9 +265,111 @@ pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3],
return PRIMITIVES_SUCCESS; return PRIMITIVES_SUCCESS;
} }
pstatus_t general_RGBToYUV420_8u_P3AC4R(const BYTE* pSrc, INT32 srcStep,
BYTE* pDst[3], INT32 dstStep[3], const prim_size_t* roi)
{
int x, y;
int dstPad[3];
int halfWidth;
int halfHeight;
BYTE* pY;
BYTE* pU;
BYTE* pV;
int Y, U, V;
int R, G, B;
int Ra, Ga, Ba;
const BYTE* pRGB;
int nWidth, nHeight;
pU = pDst[1];
pV = pDst[2];
nWidth = (roi->width + 1) & ~0x0001;
nHeight = (roi->height + 1) & ~0x0001;
halfWidth = nWidth / 2;
halfHeight = nHeight / 2;
dstPad[0] = (dstStep[0] - nWidth);
dstPad[1] = (dstStep[1] - halfWidth);
dstPad[2] = (dstStep[2] - halfWidth);
for (y = 0; y < halfHeight; y++)
{
for (x = 0; x < halfWidth; x++)
{
/* 1st pixel */
pRGB = pSrc + y * 2 * srcStep + x * 2 * 4;
pY = pDst[0] + y * 2 * dstStep[0] + x * 2;
Ba = B = pRGB[0];
Ga = G = pRGB[1];
Ra = R = pRGB[2];
Y = (54 * R + 183 * G + 18 * B) >> 8;
pY[0] = (BYTE) Y;
if (x * 2 + 1 < roi->width)
{
/* 2nd pixel */
Ba += B = pRGB[4];
Ga += G = pRGB[5];
Ra += R = pRGB[6];
Y = (54 * R + 183 * G + 18 * B) >> 8;
pY[1] = (BYTE) Y;
}
if (y * 2 + 1 < roi->height)
{
/* 3rd pixel */
pRGB += srcStep;
pY += dstStep[0];
Ba += B = pRGB[0];
Ga += G = pRGB[1];
Ra += R = pRGB[2];
Y = (54 * R + 183 * G + 18 * B) >> 8;
pY[0] = (BYTE) Y;
if (x * 2 + 1 < roi->width)
{
/* 4th pixel */
Ba += B = pRGB[4];
Ga += G = pRGB[5];
Ra += R = pRGB[6];
Y = (54 * R + 183 * G + 18 * B) >> 8;
pY[1] = (BYTE) Y;
}
}
/* U */
Ba >>= 2;
Ga >>= 2;
Ra >>= 2;
U = ((-29 * Ra - 99 * Ga + 128 * Ba) >> 8) + 128;
if (U < 0)
U = 0;
else if (U > 255)
U = 255;
*pU++ = (BYTE) U;
/* V */
V = ((128 * Ra - 116 * Ga - 12 * Ba) >> 8) + 128;
if (V < 0)
V = 0;
else if (V > 255)
V = 255;
*pV++ = (BYTE) V;
}
pU += dstPad[1];
pV += dstPad[2];
}
return PRIMITIVES_SUCCESS;
}
void primitives_init_YUV(primitives_t* prims) void primitives_init_YUV(primitives_t* prims)
{ {
prims->YUV420ToRGB_8u_P3AC4R = general_YUV420ToRGB_8u_P3AC4R; prims->YUV420ToRGB_8u_P3AC4R = general_YUV420ToRGB_8u_P3AC4R;
prims->RGBToYUV420_8u_P3AC4R = general_RGBToYUV420_8u_P3AC4R;
primitives_init_YUV_opt(prims); primitives_init_YUV_opt(prims);
} }