21 #include <freerdp/config.h>
23 #include <winpr/winpr.h>
24 #include <winpr/library.h>
25 #include <winpr/assert.h>
26 #include <winpr/cast.h>
28 #include <freerdp/log.h>
29 #include <freerdp/codec/h264.h>
31 #include <wels/codec_def.h>
32 #include <wels/codec_api.h>
33 #include <wels/codec_ver.h>
37 typedef void (*pWelsGetCodecVersionEx)(OpenH264Version* pVersion);
39 typedef long (*pWelsCreateDecoder)(ISVCDecoder** ppDecoder);
40 typedef void (*pWelsDestroyDecoder)(ISVCDecoder* pDecoder);
42 typedef int (*pWelsCreateSVCEncoder)(ISVCEncoder** ppEncoder);
43 typedef void (*pWelsDestroySVCEncoder)(ISVCEncoder* pEncoder);
47 #if defined(WITH_OPENH264_LOADING)
49 OpenH264Version version;
51 pWelsGetCodecVersionEx WelsGetCodecVersionEx;
52 pWelsCreateDecoder WelsCreateDecoder;
53 pWelsDestroyDecoder WelsDestroyDecoder;
54 pWelsCreateSVCEncoder WelsCreateSVCEncoder;
55 pWelsDestroySVCEncoder WelsDestroySVCEncoder;
56 ISVCDecoder* pDecoder;
57 ISVCEncoder* pEncoder;
58 SEncParamExt EncParamExt;
59 } H264_CONTEXT_OPENH264;
61 #if defined(WITH_OPENH264_LOADING)
62 static const char* openh264_library_names[] = {
65 #elif defined(__APPLE__)
73 static void openh264_trace_callback(
void* ctx,
int level,
const char* message)
75 H264_CONTEXT* h264 = ctx;
77 WLog_Print(h264->log, WLOG_TRACE,
"%d - %s", level, message);
80 static int openh264_decompress(H264_CONTEXT* WINPR_RESTRICT h264,
81 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize)
83 DECODING_STATE state = dsInvalidArgument;
84 SBufferInfo sBufferInfo = { 0 };
85 SSysMEMBuffer* pSystemBuffer = NULL;
86 H264_CONTEXT_OPENH264* sys = NULL;
87 UINT32* iStride = NULL;
88 BYTE** pYUVData = NULL;
91 WINPR_ASSERT(pSrcData || (SrcSize == 0));
93 sys = (H264_CONTEXT_OPENH264*)h264->pSystemData;
96 iStride = h264->iStride;
97 WINPR_ASSERT(iStride);
99 pYUVData = h264->pYUVData;
100 WINPR_ASSERT(pYUVData);
112 WINPR_ASSERT(sys->pDecoder);
113 state = (*sys->pDecoder)
114 ->DecodeFrame2(sys->pDecoder, pSrcData, WINPR_ASSERTING_INT_CAST(
int, SrcSize),
115 pYUVData, &sBufferInfo);
117 if (sBufferInfo.iBufferStatus != 1)
119 if (state == dsNoParamSets)
122 state = (*sys->pDecoder)->DecodeFrame2(sys->pDecoder, NULL, 0, pYUVData, &sBufferInfo);
124 else if (state == dsErrorFree)
127 state = (*sys->pDecoder)->DecodeFrame2(sys->pDecoder, NULL, 0, pYUVData, &sBufferInfo);
131 WLog_Print(h264->log, WLOG_WARN,
"DecodeFrame2 state: 0x%04X iBufferStatus: %d", state,
132 sBufferInfo.iBufferStatus);
137 if (state != dsErrorFree)
139 WLog_Print(h264->log, WLOG_WARN,
"DecodeFrame2 state: 0x%02X", state);
143 #if OPENH264_MAJOR >= 2
144 state = (*sys->pDecoder)->FlushFrame(sys->pDecoder, pYUVData, &sBufferInfo);
145 if (state != dsErrorFree)
147 WLog_Print(h264->log, WLOG_WARN,
"FlushFrame state: 0x%02X", state);
152 pSystemBuffer = &sBufferInfo.UsrData.sSystemBuffer;
153 iStride[0] = pSystemBuffer->iStride[0];
154 iStride[1] = pSystemBuffer->iStride[1];
155 iStride[2] = pSystemBuffer->iStride[1];
157 if (sBufferInfo.iBufferStatus != 1)
159 WLog_Print(h264->log, WLOG_WARN,
"DecodeFrame2 iBufferStatus: %d",
160 sBufferInfo.iBufferStatus);
164 if (state != dsErrorFree)
166 WLog_Print(h264->log, WLOG_WARN,
"DecodeFrame2 state: 0x%02X", state);
171 WLog_Print(h264->log, WLOG_INFO,
172 "h264_decompress: state=%u, pYUVData=[%p,%p,%p], bufferStatus=%d, width=%d, height=%d, format=%d, stride=[%d,%d]",
173 state, (
void*) pYUVData[0], (
void*) pYUVData[1], (
void*) pYUVData[2], sBufferInfo.iBufferStatus,
174 pSystemBuffer->iWidth, pSystemBuffer->iHeight, pSystemBuffer->iFormat,
175 pSystemBuffer->iStride[0], pSystemBuffer->iStride[1]);
178 if (pSystemBuffer->iFormat != videoFormatI420)
181 if (!pYUVData[0] || !pYUVData[1] || !pYUVData[2])
187 static int openh264_compress(H264_CONTEXT* WINPR_RESTRICT h264,
188 const BYTE** WINPR_RESTRICT pYUVData,
189 const UINT32* WINPR_RESTRICT iStride, BYTE** WINPR_RESTRICT ppDstData,
190 UINT32* WINPR_RESTRICT pDstSize)
193 SFrameBSInfo info = { 0 };
194 SSourcePicture pic = { 0 };
196 H264_CONTEXT_OPENH264* sys = NULL;
199 WINPR_ASSERT(pYUVData);
200 WINPR_ASSERT(iStride);
201 WINPR_ASSERT(ppDstData);
202 WINPR_ASSERT(pDstSize);
204 sys = &((H264_CONTEXT_OPENH264*)h264->pSystemData)[0];
210 if (!pYUVData[0] || !pYUVData[1] || !pYUVData[2])
213 if ((h264->width > INT_MAX) || (h264->height > INT_MAX))
216 if ((h264->FrameRate > INT_MAX) || (h264->NumberOfThreads > INT_MAX) ||
217 (h264->BitRate > INT_MAX) || (h264->QP > INT_MAX))
220 WINPR_ASSERT(sys->pEncoder);
221 if ((sys->EncParamExt.iPicWidth != (
int)h264->width) ||
222 (sys->EncParamExt.iPicHeight != (
int)h264->height))
224 WINPR_ASSERT((*sys->pEncoder)->GetDefaultParams);
225 status = (*sys->pEncoder)->GetDefaultParams(sys->pEncoder, &sys->EncParamExt);
229 WLog_Print(h264->log, WLOG_ERROR,
230 "Failed to get OpenH264 default parameters (status=%d)", status);
234 EUsageType usageType = SCREEN_CONTENT_REAL_TIME;
236 switch (h264->UsageType)
238 case H264_CAMERA_VIDEO_NON_REAL_TIME:
239 usageType = CAMERA_VIDEO_NON_REAL_TIME;
241 case H264_CAMERA_VIDEO_REAL_TIME:
242 usageType = CAMERA_VIDEO_REAL_TIME;
244 case H264_SCREEN_CONTENT_NON_REAL_TIME:
245 usageType = SCREEN_CONTENT_NON_REAL_TIME;
247 case H264_SCREEN_CONTENT_REAL_TIME:
252 sys->EncParamExt.iUsageType = usageType;
253 sys->EncParamExt.iPicWidth = WINPR_ASSERTING_INT_CAST(
int, h264->width);
254 sys->EncParamExt.iPicHeight = WINPR_ASSERTING_INT_CAST(
int, h264->height);
255 sys->EncParamExt.fMaxFrameRate = WINPR_ASSERTING_INT_CAST(
int, h264->FrameRate);
256 sys->EncParamExt.iMaxBitrate = UNSPECIFIED_BIT_RATE;
257 sys->EncParamExt.bEnableDenoise = 0;
258 sys->EncParamExt.bEnableLongTermReference = 0;
259 sys->EncParamExt.iSpatialLayerNum = 1;
260 sys->EncParamExt.iMultipleThreadIdc = (int)h264->NumberOfThreads;
261 sys->EncParamExt.sSpatialLayers[0].fFrameRate = h264->FrameRate;
262 sys->EncParamExt.sSpatialLayers[0].iVideoWidth = sys->EncParamExt.iPicWidth;
263 sys->EncParamExt.sSpatialLayers[0].iVideoHeight = sys->EncParamExt.iPicHeight;
264 sys->EncParamExt.sSpatialLayers[0].iMaxSpatialBitrate = sys->EncParamExt.iMaxBitrate;
266 switch (h264->RateControlMode)
268 case H264_RATECONTROL_VBR:
269 sys->EncParamExt.iRCMode = RC_BITRATE_MODE;
270 sys->EncParamExt.iTargetBitrate = (int)h264->BitRate;
271 sys->EncParamExt.sSpatialLayers[0].iSpatialBitrate =
272 sys->EncParamExt.iTargetBitrate;
273 sys->EncParamExt.bEnableFrameSkip = 1;
276 case H264_RATECONTROL_CQP:
277 sys->EncParamExt.iRCMode = RC_OFF_MODE;
278 sys->EncParamExt.sSpatialLayers[0].iDLayerQp = (
int)h264->QP;
279 sys->EncParamExt.bEnableFrameSkip = 0;
283 if (sys->EncParamExt.iMultipleThreadIdc > 1)
285 #if (OPENH264_MAJOR == 1) && (OPENH264_MINOR <= 5)
286 sys->EncParamExt.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_AUTO_SLICE;
288 sys->EncParamExt.sSpatialLayers[0].sSliceArgument.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
292 WINPR_ASSERT((*sys->pEncoder)->InitializeExt);
293 status = (*sys->pEncoder)->InitializeExt(sys->pEncoder, &sys->EncParamExt);
297 WLog_Print(h264->log, WLOG_ERROR,
"Failed to initialize OpenH264 encoder (status=%d)",
302 WINPR_ASSERT((*sys->pEncoder)->GetOption);
305 ->GetOption(sys->pEncoder, ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sys->EncParamExt);
309 WLog_Print(h264->log, WLOG_ERROR,
310 "Failed to get initial OpenH264 encoder parameters (status=%d)", status);
316 switch (h264->RateControlMode)
318 case H264_RATECONTROL_VBR:
319 if (sys->EncParamExt.iTargetBitrate != (
int)h264->BitRate)
321 SBitrateInfo bitrate = { 0 };
323 sys->EncParamExt.iTargetBitrate = (int)h264->BitRate;
324 bitrate.iLayer = SPATIAL_LAYER_ALL;
325 bitrate.iBitrate = (
int)h264->BitRate;
327 WINPR_ASSERT((*sys->pEncoder)->SetOption);
328 status = (*sys->pEncoder)
329 ->SetOption(sys->pEncoder, ENCODER_OPTION_BITRATE, &bitrate);
333 WLog_Print(h264->log, WLOG_ERROR,
334 "Failed to set encoder bitrate (status=%d)", status);
339 if (sys->EncParamExt.fMaxFrameRate != (
int)h264->FrameRate)
341 sys->EncParamExt.fMaxFrameRate = (int)h264->FrameRate;
343 WINPR_ASSERT((*sys->pEncoder)->SetOption);
344 status = (*sys->pEncoder)
345 ->SetOption(sys->pEncoder, ENCODER_OPTION_FRAME_RATE,
346 &sys->EncParamExt.fMaxFrameRate);
350 WLog_Print(h264->log, WLOG_ERROR,
351 "Failed to set encoder framerate (status=%d)", status);
358 case H264_RATECONTROL_CQP:
359 if (sys->EncParamExt.sSpatialLayers[0].iDLayerQp != (
int)h264->QP)
361 sys->EncParamExt.sSpatialLayers[0].iDLayerQp = (int)h264->QP;
363 WINPR_ASSERT((*sys->pEncoder)->SetOption);
364 status = (*sys->pEncoder)
365 ->SetOption(sys->pEncoder, ENCODER_OPTION_SVC_ENCODE_PARAM_EXT,
370 WLog_Print(h264->log, WLOG_ERROR,
371 "Failed to set encoder parameters (status=%d)", status);
380 pic.iPicWidth = (int)h264->width;
381 pic.iPicHeight = (
int)h264->height;
382 pic.iColorFormat = videoFormatI420;
383 pic.iStride[0] = (int)iStride[0];
384 pic.iStride[1] = (int)iStride[1];
385 pic.iStride[2] = (int)iStride[2];
386 pic.pData[0] = WINPR_CAST_CONST_PTR_AWAY(pYUVData[0], BYTE*);
387 pic.pData[1] = WINPR_CAST_CONST_PTR_AWAY(pYUVData[1], BYTE*);
388 pic.pData[2] = WINPR_CAST_CONST_PTR_AWAY(pYUVData[2], BYTE*);
390 WINPR_ASSERT((*sys->pEncoder)->EncodeFrame);
391 status = (*sys->pEncoder)->EncodeFrame(sys->pEncoder, &pic, &info);
395 WLog_Print(h264->log, WLOG_ERROR,
"Failed to encode frame (status=%d)", status);
399 *ppDstData = info.sLayerInfo[0].pBsBuf;
402 for (
int i = 0; i < info.iLayerNum; i++)
404 for (
int j = 0; j < info.sLayerInfo[i].iNalCount; j++)
406 *pDstSize += info.sLayerInfo[i].pNalLengthInByte[j];
413 static void openh264_uninit(H264_CONTEXT* h264)
415 H264_CONTEXT_OPENH264* sysContexts = NULL;
419 sysContexts = (H264_CONTEXT_OPENH264*)h264->pSystemData;
423 for (UINT32 x = 0; x < h264->numSystemData; x++)
425 H264_CONTEXT_OPENH264* sys = &sysContexts[x];
429 (*sys->pDecoder)->Uninitialize(sys->pDecoder);
430 sysContexts->WelsDestroyDecoder(sys->pDecoder);
431 sys->pDecoder = NULL;
436 (*sys->pEncoder)->Uninitialize(sys->pEncoder);
437 sysContexts->WelsDestroySVCEncoder(sys->pEncoder);
438 sys->pEncoder = NULL;
442 #if defined(WITH_OPENH264_LOADING)
443 if (sysContexts->lib)
444 FreeLibrary(sysContexts->lib);
446 free(h264->pSystemData);
447 h264->pSystemData = NULL;
451 #if defined(WITH_OPENH264_LOADING)
452 static BOOL openh264_load_functionpointers(H264_CONTEXT* h264,
const char* name)
454 H264_CONTEXT_OPENH264* sysContexts;
461 sysContexts = h264->pSystemData;
466 sysContexts->lib = LoadLibraryA(name);
468 if (!sysContexts->lib)
471 sysContexts->WelsGetCodecVersionEx =
472 GetProcAddressAs(sysContexts->lib,
"WelsGetCodecVersionEx", pWelsGetCodecVersionEx);
473 sysContexts->WelsCreateDecoder =
474 GetProcAddressAs(sysContexts->lib,
"WelsCreateDecoder", pWelsCreateDecoder);
475 sysContexts->WelsDestroyDecoder =
476 GetProcAddressAs(sysContexts->lib,
"WelsDestroyDecoder", pWelsDestroyDecoder);
477 sysContexts->WelsCreateSVCEncoder =
478 GetProcAddressAs(sysContexts->lib,
"WelsCreateSVCEncoder", pWelsCreateSVCEncoder);
479 sysContexts->WelsDestroySVCEncoder =
480 GetProcAddressAs(sysContexts->lib,
"WelsDestroySVCEncoder", pWelsDestroySVCEncoder);
482 if (!sysContexts->WelsCreateDecoder || !sysContexts->WelsDestroyDecoder ||
483 !sysContexts->WelsCreateSVCEncoder || !sysContexts->WelsDestroySVCEncoder ||
484 !sysContexts->WelsGetCodecVersionEx)
486 FreeLibrary(sysContexts->lib);
487 sysContexts->lib = NULL;
491 sysContexts->WelsGetCodecVersionEx(&sysContexts->version);
492 WLog_Print(h264->log, WLOG_INFO,
"loaded %s %d.%d.%d", name, sysContexts->version.uMajor,
493 sysContexts->version.uMinor, sysContexts->version.uRevision);
495 if ((sysContexts->version.uMajor < 1) ||
496 ((sysContexts->version.uMajor == 1) && (sysContexts->version.uMinor < 6)))
499 h264->log, WLOG_ERROR,
500 "OpenH264 %s %d.%d.%d is too old, need at least version 1.6.0 for dynamic loading",
501 name, sysContexts->version.uMajor, sysContexts->version.uMinor,
502 sysContexts->version.uRevision);
503 FreeLibrary(sysContexts->lib);
504 sysContexts->lib = NULL;
512 static BOOL openh264_init(H264_CONTEXT* h264)
514 #if defined(WITH_OPENH264_LOADING)
515 BOOL success = FALSE;
518 H264_CONTEXT_OPENH264* sysContexts = NULL;
519 static int traceLevel = WELS_LOG_DEBUG;
520 #if (OPENH264_MAJOR == 1) && (OPENH264_MINOR <= 5)
521 static EVideoFormatType videoFormat = videoFormatI420;
523 static WelsTraceCallback traceCallback = openh264_trace_callback;
527 h264->numSystemData = 1;
529 (H264_CONTEXT_OPENH264*)calloc(h264->numSystemData,
sizeof(H264_CONTEXT_OPENH264));
534 h264->pSystemData = (
void*)sysContexts;
535 #if defined(WITH_OPENH264_LOADING)
537 for (
size_t i = 0; i < ARRAYSIZE(openh264_library_names); i++)
539 const char* current = openh264_library_names[i];
540 success = openh264_load_functionpointers(h264, current);
550 sysContexts->WelsGetCodecVersionEx = WelsGetCodecVersionEx;
551 sysContexts->WelsCreateDecoder = WelsCreateDecoder;
552 sysContexts->WelsDestroyDecoder = WelsDestroyDecoder;
553 sysContexts->WelsCreateSVCEncoder = WelsCreateSVCEncoder;
554 sysContexts->WelsDestroySVCEncoder = WelsDestroySVCEncoder;
557 for (UINT32 x = 0; x < h264->numSystemData; x++)
559 SDecodingParam sDecParam = { 0 };
560 H264_CONTEXT_OPENH264* sys = &sysContexts[x];
562 if (h264->Compressor)
564 sysContexts->WelsCreateSVCEncoder(&sys->pEncoder);
568 WLog_Print(h264->log, WLOG_ERROR,
"Failed to create OpenH264 encoder");
574 sysContexts->WelsCreateDecoder(&sys->pDecoder);
578 WLog_Print(h264->log, WLOG_ERROR,
"Failed to create OpenH264 decoder");
582 #if (OPENH264_MAJOR == 1) && (OPENH264_MINOR <= 5)
583 sDecParam.eOutputColorFormat = videoFormatI420;
585 sDecParam.eEcActiveIdc = ERROR_CON_FRAME_COPY;
586 sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_AVC;
587 status = (*sys->pDecoder)->Initialize(sys->pDecoder, &sDecParam);
591 WLog_Print(h264->log, WLOG_ERROR,
592 "Failed to initialize OpenH264 decoder (status=%ld)", status);
596 #if (OPENH264_MAJOR == 1) && (OPENH264_MINOR <= 5)
598 (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_DATAFORMAT, &videoFormat);
603 WLog_Print(h264->log, WLOG_ERROR,
604 "Failed to set data format option on OpenH264 decoder (status=%ld)",
609 if (WLog_GetLogLevel(h264->log) == WLOG_TRACE)
611 status = (*sys->pDecoder)
612 ->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_LEVEL, &traceLevel);
616 WLog_Print(h264->log, WLOG_ERROR,
617 "Failed to set trace level option on OpenH264 decoder (status=%ld)",
624 ->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK_CONTEXT, h264);
628 WLog_Print(h264->log, WLOG_ERROR,
629 "Failed to set trace callback context option on OpenH264 decoder "
637 ->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK, traceCallback);
642 h264->log, WLOG_ERROR,
643 "Failed to set trace callback option on OpenH264 decoder (status=%ld)",
653 openh264_uninit(h264);
657 const H264_CONTEXT_SUBSYSTEM g_Subsystem_OpenH264 = {
"OpenH264", openh264_init, openh264_uninit,
658 openh264_decompress, openh264_compress };