21#include <freerdp/config.h>
24#include <winpr/print.h>
25#include <winpr/library.h>
26#include <winpr/bitstream.h>
27#include <winpr/synch.h>
29#include <freerdp/primitives.h>
30#include <freerdp/codec/h264.h>
31#include <freerdp/codec/yuv.h>
32#include <freerdp/log.h>
33#include <freerdp/codec/region.h>
37#define TAG FREERDP_TAG("codec")
39static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight);
41static BOOL yuv_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT32 height)
44 UINT32 pheight = height;
53 stride += 16 - stride % 16;
55 if (pheight % 16 != 0)
56 pheight += 16 - pheight % 16;
58 const size_t nPlanes = h264->hwAccel ? 2 : 3;
60 for (
size_t x = 0; x < nPlanes; x++)
62 if (!h264->pYUVData[x] || !h264->pOldYUVData[x])
71 if (isNull || (width != h264->width) || (height != h264->height) ||
72 (stride != h264->iStride[0]))
76 h264->iStride[0] = stride;
77 h264->iStride[1] = stride;
82 h264->iStride[0] = stride;
83 h264->iStride[1] = (stride + 1) / 2;
84 h264->iStride[2] = (stride + 1) / 2;
87 for (
size_t x = 0; x < nPlanes; x++)
89 BYTE* tmp1 = winpr_aligned_recalloc(h264->pYUVData[x], h264->iStride[x], pheight, 16);
91 winpr_aligned_recalloc(h264->pOldYUVData[x], h264->iStride[x], pheight, 16);
93 h264->pYUVData[x] = tmp1;
95 h264->pOldYUVData[x] = tmp2;
100 h264->height = height;
106BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT32 height)
108 return yuv_ensure_buffer(h264, stride, width, height);
111static BOOL isRectValid(UINT32 width, UINT32 height,
const RECTANGLE_16* rect)
114 if (rect->left > width)
116 if (rect->right > width)
118 if (rect->left >= rect->right)
120 if (rect->top > height)
122 if (rect->bottom > height)
124 if (rect->top >= rect->bottom)
129static BOOL areRectsValid(wLog* log, UINT32 width, UINT32 height,
const RECTANGLE_16* rects,
132 WINPR_ASSERT(rects || (count == 0));
133 for (
size_t x = 0; x < count; x++)
136 if (!isRectValid(width, height, rect))
138 char buffer[64] = WINPR_C_ARRAY_INIT;
139 WLog_Print(log, WLOG_WARN,
140 "Rectangle %" PRIuz
" %s outside of bounding frame %" PRIu32
"x%" PRIu32, x,
141 rectangle_to_string(rect, buffer,
sizeof(buffer)), width, height);
148static int log_decompress(H264_CONTEXT* h264,
const BYTE* pSrcData, UINT32 SrcSize,
151 const int status = h264->subsystem->Decompress(h264, pSrcData, SrcSize);
154 WLog_Print(h264->log, WLOG_WARN,
"H264 decompress failed with %d", status);
165 if (h264->YUVHeight > h264->height)
167 WLog_Print(h264->log, WLOG_WARN,
168 "H264 decompress: frame %" PRIu32
"x%" PRIu32
" exceeds buffer size %" PRIu32
170 h264->YUVWidth, h264->YUVHeight, h264->width, h264->height);
175 if (!areRectsValid(h264->log, h264->YUVWidth, h264->YUVHeight, rects, nrRects))
180INT32 avc420_decompress(H264_CONTEXT* h264,
const BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData,
181 DWORD DstFormat, UINT32 nDstStep, WINPR_ATTR_UNUSED UINT32 nDstWidth,
182 WINPR_ATTR_UNUSED UINT32 nDstHeight,
const RECTANGLE_16* regionRects,
183 UINT32 numRegionRects)
186 const BYTE* pYUVData[3];
188 if (!h264 || h264->Compressor)
191 if (!areRectsValid(h264->log, nDstWidth, nDstHeight, regionRects, numRegionRects))
194 status = log_decompress(h264, pSrcData, SrcSize, regionRects, numRegionRects);
202 pYUVData[0] = h264->pYUVData[0];
203 pYUVData[1] = h264->pYUVData[1];
204 pYUVData[2] = h264->pYUVData[2];
205 if (!yuv420_context_decode(h264->yuv, pYUVData, h264->iStride, h264->YUVHeight, DstFormat,
206 pDstData, nDstStep, regionRects, numRegionRects))
212static BOOL allocate_h264_metablock(UINT32 QP,
RECTANGLE_16* rectangles,
216 if (!meta || (QP > UINT8_MAX))
222 meta->regionRects = rectangles;
226 if (count > UINT32_MAX)
231 if (!meta->quantQualityVals || !meta->regionRects)
233 meta->numRegionRects = (UINT32)count;
234 for (
size_t x = 0; x < count; x++)
241 cur->qualityVal = 100 - (QP & 0x3F);
246static inline BOOL diff_tile(
const RECTANGLE_16* regionRect, BYTE* pYUVData[3],
247 BYTE* pOldYUVData[3], UINT32
const iStride[3])
251 if (!regionRect || !pYUVData || !pOldYUVData || !iStride)
253 size = regionRect->right - regionRect->left;
254 if (regionRect->right > iStride[0])
256 if (regionRect->right / 2u > iStride[1])
258 if (regionRect->right / 2u > iStride[2])
261 for (
size_t y = regionRect->top; y < regionRect->bottom; y++)
263 const BYTE* cur0 = &pYUVData[0][y * iStride[0]];
264 const BYTE* cur1 = &pYUVData[1][y * iStride[1]];
265 const BYTE* cur2 = &pYUVData[2][y * iStride[2]];
266 const BYTE* old0 = &pOldYUVData[0][y * iStride[0]];
267 const BYTE* old1 = &pOldYUVData[1][y * iStride[1]];
268 const BYTE* old2 = &pOldYUVData[2][y * iStride[2]];
270 if (memcmp(&cur0[regionRect->left], &old0[regionRect->left], size) != 0)
272 if (memcmp(&cur1[regionRect->left / 2], &old1[regionRect->left / 2], size / 2) != 0)
274 if (memcmp(&cur2[regionRect->left / 2], &old2[regionRect->left / 2], size / 2) != 0)
280static BOOL detect_changes(BOOL firstFrameDone,
const UINT32 QP,
const RECTANGLE_16* regionRect,
281 BYTE* pYUVData[3], BYTE* pOldYUVData[3], UINT32
const iStride[3],
289 if (!regionRect || !pYUVData || !pOldYUVData || !iStride || !meta)
292 wc = (regionRect->right - regionRect->left) / 64 + 1;
293 hc = (regionRect->bottom - regionRect->top) / 64 + 1;
299 rectangles[0] = *regionRect;
304 for (
size_t y = regionRect->top; y < regionRect->bottom; y += 64)
306 for (
size_t x = regionRect->left; x < regionRect->right; x += 64)
309 rect.left = (UINT16)MIN(UINT16_MAX, regionRect->left + x);
310 rect.top = (UINT16)MIN(UINT16_MAX, regionRect->top + y);
312 (UINT16)MIN(UINT16_MAX, MIN(regionRect->left + x + 64, regionRect->right));
314 (UINT16)MIN(UINT16_MAX, MIN(regionRect->top + y + 64, regionRect->bottom));
315 if (diff_tile(&rect, pYUVData, pOldYUVData, iStride))
316 rectangles[count++] = rect;
320 if (!allocate_h264_metablock(QP, rectangles, meta, count))
325INT32 h264_get_yuv_buffer(H264_CONTEXT* h264, UINT32 nSrcStride, UINT32 nSrcWidth,
326 UINT32 nSrcHeight, BYTE* YUVData[3], UINT32 stride[3])
328 if (!h264 || !h264->Compressor || !h264->subsystem || !h264->subsystem->Compress)
331 if (!yuv_ensure_buffer(h264, nSrcStride, nSrcWidth, nSrcHeight))
334 for (
size_t x = 0; x < 3; x++)
336 YUVData[x] = h264->pYUVData[x];
337 stride[x] = h264->iStride[x];
343INT32 h264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize)
345 if (!h264 || !h264->Compressor || !h264->subsystem || !h264->subsystem->Compress)
348 const BYTE* pcYUVData[3] = { h264->pYUVData[0], h264->pYUVData[1], h264->pYUVData[2] };
350 return h264->subsystem->Compress(h264, pcYUVData, h264->iStride, ppDstData, pDstSize);
353INT32 avc420_compress(H264_CONTEXT* h264,
const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep,
354 UINT32 nSrcWidth, UINT32 nSrcHeight,
const RECTANGLE_16* regionRect,
358 BYTE* pYUVData[3] = WINPR_C_ARRAY_INIT;
359 const BYTE* pcYUVData[3] = WINPR_C_ARRAY_INIT;
360 BYTE* pOldYUVData[3] = WINPR_C_ARRAY_INIT;
362 if (!h264 || !regionRect || !meta || !h264->Compressor)
365 if (!h264->subsystem->Compress)
368 if (!avc420_ensure_buffer(h264, nSrcStep, nSrcWidth, nSrcHeight))
371 if (h264->encodingBuffer)
373 for (
size_t x = 0; x < 3; x++)
375 pYUVData[x] = h264->pYUVData[x];
376 pOldYUVData[x] = h264->pOldYUVData[x];
381 for (
size_t x = 0; x < 3; x++)
383 pYUVData[x] = h264->pOldYUVData[x];
384 pOldYUVData[x] = h264->pYUVData[x];
387 h264->encodingBuffer = !h264->encodingBuffer;
389 if (!yuv420_context_encode(h264->yuv, pSrcData, nSrcStep, SrcFormat, h264->iStride, pYUVData,
393 if (!detect_changes(h264->firstLumaFrameDone, h264->QP, regionRect, pYUVData, pOldYUVData,
394 h264->iStride, meta))
397 if (meta->numRegionRects == 0)
403 for (
size_t x = 0; x < 3; x++)
404 pcYUVData[x] = pYUVData[x];
406 rc = h264->subsystem->Compress(h264, pcYUVData, h264->iStride, ppDstData, pDstSize);
408 h264->firstLumaFrameDone = TRUE;
412 free_h264_metablock(meta);
416INT32 avc444_compress(H264_CONTEXT* h264,
const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep,
417 UINT32 nSrcWidth, UINT32 nSrcHeight, BYTE version,
const RECTANGLE_16* region,
418 BYTE* op, BYTE** ppDstData, UINT32* pDstSize, BYTE** ppAuxDstData,
423 BYTE* coded =
nullptr;
424 UINT32 codedSize = 0;
425 BYTE** pYUV444Data =
nullptr;
426 BYTE** pOldYUV444Data =
nullptr;
427 BYTE** pYUVData =
nullptr;
428 BYTE** pOldYUVData =
nullptr;
430 if (!h264 || !h264->Compressor)
433 if (!h264->subsystem->Compress)
436 if (!avc420_ensure_buffer(h264, nSrcStep, nSrcWidth, nSrcHeight))
439 if (!avc444_ensure_buffer(h264, nSrcHeight))
442 if (h264->encodingBuffer)
444 pYUV444Data = h264->pOldYUV444Data;
445 pOldYUV444Data = h264->pYUV444Data;
446 pYUVData = h264->pOldYUVData;
447 pOldYUVData = h264->pYUVData;
451 pYUV444Data = h264->pYUV444Data;
452 pOldYUV444Data = h264->pOldYUV444Data;
453 pYUVData = h264->pYUVData;
454 pOldYUVData = h264->pOldYUVData;
456 h264->encodingBuffer = !h264->encodingBuffer;
458 if (!yuv444_context_encode(h264->yuv, version, pSrcData, nSrcStep, SrcFormat, h264->iStride,
459 pYUV444Data, pYUVData, region, 1))
462 if (!detect_changes(h264->firstLumaFrameDone, h264->QP, region, pYUV444Data, pOldYUV444Data,
463 h264->iStride, meta))
465 if (!detect_changes(h264->firstChromaFrameDone, h264->QP, region, pYUVData, pOldYUVData,
466 h264->iStride, auxMeta))
475 if ((meta->numRegionRects > 0) && (auxMeta->numRegionRects > 0))
477 else if (meta->numRegionRects > 0)
479 else if (auxMeta->numRegionRects > 0)
483 WLog_Print(h264->log, WLOG_TRACE,
"no changes detected for luma or chroma frame");
488 if ((*op == 0) || (*op == 1))
490 const BYTE* pcYUV444Data[3] = { pYUV444Data[0], pYUV444Data[1], pYUV444Data[2] };
492 if (h264->subsystem->Compress(h264, pcYUV444Data, h264->iStride, &coded, &codedSize) < 0)
494 h264->firstLumaFrameDone = TRUE;
495 memcpy(h264->lumaData, coded, codedSize);
496 *ppDstData = h264->lumaData;
497 *pDstSize = codedSize;
500 if ((*op == 0) || (*op == 2))
502 const BYTE* pcYUVData[3] = { pYUVData[0], pYUVData[1], pYUVData[2] };
504 if (h264->subsystem->Compress(h264, pcYUVData, h264->iStride, &coded, &codedSize) < 0)
506 h264->firstChromaFrameDone = TRUE;
507 *ppAuxDstData = coded;
508 *pAuxDstSize = codedSize;
515 free_h264_metablock(meta);
516 free_h264_metablock(auxMeta);
521static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight)
525 const UINT32* piMainStride = h264->iStride;
526 UINT32* piDstSize = h264->iYUV444Size;
527 UINT32* piDstStride = h264->iYUV444Stride;
528 BYTE** ppYUVDstData = h264->pYUV444Data;
529 BYTE** ppOldYUVDstData = h264->pOldYUV444Data;
531 nDstHeight = MAX(h264->height, nDstHeight);
532 const UINT32 pad = nDstHeight % 16;
533 UINT32 padDstHeight = nDstHeight;
536 padDstHeight += 16 - pad;
538 if ((piMainStride[0] == 0) || (padDstHeight == 0))
541 const uint64_t dstsize = 1ull * piMainStride[0] * padDstHeight;
542 if (dstsize > UINT32_MAX)
545 if ((piMainStride[0] != piDstStride[0]) || (piDstSize[0] != dstsize))
547 for (UINT32 x = 0; x < 3; x++)
549 piDstStride[x] = piMainStride[0];
551 const uint64_t dstride = 1ull * piDstStride[x] * padDstHeight;
552 if (dstride > UINT32_MAX)
555 piDstSize[x] = WINPR_ASSERTING_INT_CAST(UINT32, dstride);
556 if (piDstSize[x] == 0)
559 BYTE* tmp1 = winpr_aligned_recalloc(ppYUVDstData[x], piDstSize[x], 1, 16);
562 ppYUVDstData[x] = tmp1;
563 BYTE* tmp2 = winpr_aligned_recalloc(ppOldYUVDstData[x], piDstSize[x], 1, 16);
566 ppOldYUVDstData[x] = tmp2;
570 BYTE* tmp = winpr_aligned_recalloc(h264->lumaData, piDstSize[0], 4, 16);
573 h264->lumaData = tmp;
577 for (UINT32 x = 0; x < 3; x++)
579 if (!ppOldYUVDstData[x] || !ppYUVDstData[x] || (piDstSize[x] == 0) || (piDstStride[x] == 0))
581 WLog_Print(h264->log, WLOG_ERROR,
582 "YUV buffer not initialized! check your decoder settings");
595static BOOL avc444_process_rects(H264_CONTEXT* h264,
const BYTE* pSrcData, UINT32 SrcSize,
596 BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep,
597 WINPR_ATTR_UNUSED UINT32 nDstWidth, UINT32 nDstHeight,
598 const RECTANGLE_16* rects, UINT32 nrRects, avc444_frame_type type)
600 const BYTE* pYUVData[3] = WINPR_C_ARRAY_INIT;
601 BYTE* pYUVDstData[3] = WINPR_C_ARRAY_INIT;
602 UINT32* piDstStride = h264->iYUV444Stride;
603 BYTE** ppYUVDstData = h264->pYUV444Data;
604 const UINT32* piStride = h264->iStride;
606 if (log_decompress(h264, pSrcData, SrcSize, rects, nrRects) < 0)
609 pYUVData[0] = h264->pYUVData[0];
610 pYUVData[1] = h264->pYUVData[1];
611 pYUVData[2] = h264->pYUVData[2];
612 if (!avc444_ensure_buffer(h264, nDstHeight))
615 pYUVDstData[0] = ppYUVDstData[0];
616 pYUVDstData[1] = ppYUVDstData[1];
617 pYUVDstData[2] = ppYUVDstData[2];
618 return (yuv444_context_decode(h264->yuv, (BYTE)type, pYUVData, piStride, h264->YUVHeight,
619 pYUVDstData, piDstStride, DstFormat, pDstData, nDstStep, rects,
623#if defined(AVC444_FRAME_STAT)
624static UINT64 op1 = 0;
625static double op1sum = 0;
626static UINT64 op2 = 0;
627static double op2sum = 0;
628static UINT64 op3 = 0;
629static double op3sum = 0;
630static double avg(UINT64* count,
double old,
double size)
632 double tmp = size + *count * old;
639INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op,
const RECTANGLE_16* regionRects,
640 UINT32 numRegionRects,
const BYTE* pSrcData, UINT32 SrcSize,
641 const RECTANGLE_16* auxRegionRects, UINT32 numAuxRegionRect,
642 const BYTE* pAuxSrcData, UINT32 AuxSrcSize, BYTE* pDstData, DWORD DstFormat,
643 UINT32 nDstStep, UINT32 nDstWidth, UINT32 nDstHeight, UINT32 codecId)
646 avc444_frame_type chroma =
647 (codecId == RDPGFX_CODECID_AVC444) ? AVC444_CHROMAv1 : AVC444_CHROMAv2;
649 if (!h264 || !regionRects || !pSrcData || !pDstData || h264->Compressor)
652 if (!areRectsValid(h264->log, nDstWidth, nDstHeight, regionRects, numRegionRects))
654 if (!areRectsValid(h264->log, nDstWidth, nDstHeight, auxRegionRects, numAuxRegionRect))
661 if (!avc444_process_rects(h264, pSrcData, SrcSize, pDstData, DstFormat, nDstStep,
662 nDstWidth, nDstHeight, regionRects, numRegionRects,
665 else if (!avc444_process_rects(h264, pAuxSrcData, AuxSrcSize, pDstData, DstFormat,
666 nDstStep, nDstWidth, nDstHeight, auxRegionRects,
667 numAuxRegionRect, chroma))
675 if (!avc444_process_rects(h264, pSrcData, SrcSize, pDstData, DstFormat, nDstStep,
676 nDstWidth, nDstHeight, regionRects, numRegionRects, chroma))
684 if (!avc444_process_rects(h264, pSrcData, SrcSize, pDstData, DstFormat, nDstStep,
685 nDstWidth, nDstHeight, regionRects, numRegionRects,
697#if defined(AVC444_FRAME_STAT)
702 op1sum = avg(&op1, op1sum, SrcSize + AuxSrcSize);
706 op2sum = avg(&op2, op2sum, SrcSize);
710 op3sum = avg(&op3, op3sum, SrcSize);
717 WLog_Print(h264->log, WLOG_INFO,
718 "luma=%" PRIu64
" [avg=%lf] chroma=%" PRIu64
" [avg=%lf] combined=%" PRIu64
720 op1, op1sum, op2, op2sum, op3, op3sum);
725#define MAX_SUBSYSTEMS 10
726static INIT_ONCE subsystems_once = INIT_ONCE_STATIC_INIT;
727static const H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS] = WINPR_C_ARRAY_INIT;
729static BOOL CALLBACK h264_register_subsystems(WINPR_ATTR_UNUSED
PINIT_ONCE once,
730 WINPR_ATTR_UNUSED PVOID param,
731 WINPR_ATTR_UNUSED PVOID* context)
735#ifdef WITH_MEDIACODEC
737 subSystems[i] = &g_Subsystem_mediacodec;
741#if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION)
743 subSystems[i] = &g_Subsystem_MF;
749 subSystems[i] = &g_Subsystem_OpenH264;
753#ifdef WITH_VIDEO_FFMPEG
755 subSystems[i] = &g_Subsystem_libavcodec;
762static BOOL h264_context_init(H264_CONTEXT* h264)
767 h264->subsystem =
nullptr;
768 if (!InitOnceExecuteOnce(&subsystems_once, h264_register_subsystems,
nullptr,
nullptr))
771 for (
size_t i = 0; i < MAX_SUBSYSTEMS; i++)
773 const H264_CONTEXT_SUBSYSTEM* subsystem = subSystems[i];
775 if (!subsystem || !subsystem->Init)
778 if (subsystem->Init(h264))
780 h264->subsystem = subsystem;
788BOOL h264_context_reset(H264_CONTEXT* h264, UINT32 width, UINT32 height)
794 h264->height = height;
796 if (h264->subsystem && h264->subsystem->Uninit)
797 h264->subsystem->Uninit(h264);
798 if (!h264_context_init(h264))
801 return yuv_context_reset(h264->yuv, width, height);
804H264_CONTEXT* h264_context_new(BOOL Compressor)
806 H264_CONTEXT* h264 = (H264_CONTEXT*)calloc(1,
sizeof(H264_CONTEXT));
810 h264->log = WLog_Get(TAG);
815 h264->Compressor = Compressor;
819 h264->BitRate = 1000000;
820 h264->FrameRate = 30;
823 if (!h264_context_init(h264))
826 h264->yuv = yuv_context_new(Compressor, 0);
833 WINPR_PRAGMA_DIAG_PUSH
834 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
835 h264_context_free(h264);
836 WINPR_PRAGMA_DIAG_POP
840void h264_context_free(H264_CONTEXT* h264)
846 WINPR_ASSERT(h264->subsystem->Uninit);
847 h264->subsystem->Uninit(h264);
850 for (
size_t x = 0; x < 3; x++)
852 if (h264->Compressor)
854 winpr_aligned_free(h264->pYUVData[x]);
855 winpr_aligned_free(h264->pOldYUVData[x]);
857 winpr_aligned_free(h264->pYUV444Data[x]);
858 winpr_aligned_free(h264->pOldYUV444Data[x]);
860 winpr_aligned_free(h264->lumaData);
862 yuv_context_free(h264->yuv);
872 free(meta->quantQualityVals);
873 free(meta->regionRects);
877BOOL h264_context_set_option(H264_CONTEXT* h264, H264_CONTEXT_OPTION option, UINT32 value)
882 case H264_CONTEXT_OPTION_BITRATE:
883 h264->BitRate = value;
885 case H264_CONTEXT_OPTION_FRAMERATE:
886 h264->FrameRate = value;
888 case H264_CONTEXT_OPTION_RATECONTROL:
892 case H264_RATECONTROL_VBR:
893 h264->RateControlMode = H264_RATECONTROL_VBR;
895 case H264_RATECONTROL_CQP:
896 h264->RateControlMode = H264_RATECONTROL_CQP;
899 WLog_Print(h264->log, WLOG_WARN,
900 "Unknown H264_CONTEXT_OPTION_RATECONTROL value [0x%08" PRIx32
"]",
906 case H264_CONTEXT_OPTION_QP:
909 case H264_CONTEXT_OPTION_USAGETYPE:
910 h264->UsageType = value;
912 case H264_CONTEXT_OPTION_HW_ACCEL:
913 h264->hwAccel = (value);
916 WLog_Print(h264->log, WLOG_WARN,
"Unknown H264_CONTEXT_OPTION[0x%08" PRIx32
"]",
922UINT32 h264_context_get_option(H264_CONTEXT* h264, H264_CONTEXT_OPTION option)
927 case H264_CONTEXT_OPTION_BITRATE:
928 return h264->BitRate;
929 case H264_CONTEXT_OPTION_FRAMERATE:
930 return h264->FrameRate;
931 case H264_CONTEXT_OPTION_RATECONTROL:
932 return h264->RateControlMode;
933 case H264_CONTEXT_OPTION_QP:
935 case H264_CONTEXT_OPTION_USAGETYPE:
936 return h264->UsageType;
937 case H264_CONTEXT_OPTION_HW_ACCEL:
938 return h264->hwAccel;
940 WLog_Print(h264->log, WLOG_WARN,
"Unknown H264_CONTEXT_OPTION[0x%08" PRIx32
"]",