20#include <freerdp/config.h>
24#include <winpr/assert.h>
25#include <winpr/wlog.h>
26#include <winpr/stream.h>
27#include <freerdp/log.h>
29#include <freerdp/codec/video.h>
30#include <freerdp/codec/h264.h>
32#define VTAG FREERDP_TAG("codec.video")
34#if defined(WITH_SWSCALE) || defined(WITH_MEDIACODEC) || defined(WITH_APPLE_VIDEOTOOLBOX)
35static UINT32 video_get_h264_bitrate(wLog* log, UINT32 height)
42 { 1080, 2700 }, { 720, 1250 }, { 480, 700 }, { 360, 400 },
43 { 240, 170 }, { 180, 140 }, { 0, 100 },
45 const size_t nBitrates = ARRAYSIZE(bitrates);
47 for (
size_t i = 0; i < nBitrates; i++)
49 if (height >= bitrates[i].height)
51 UINT32 bitrate = bitrates[i].bitrate;
52 WLog_Print(log, WLOG_DEBUG,
"Auto-calculated H.264 bitrate: %u kbps", bitrate);
53 return bitrate * 1000;
62#if defined(WITH_SWSCALE)
65static BOOL freerdp_video_fill_plane_info(wLog* log, BYTE* data[4],
int lineSize[4],
66 FREERDP_VIDEO_FORMAT format, UINT32 width, UINT32 height,
69#include "image_ffmpeg.h"
72#if defined(WITH_VIDEO_FFMPEG) && !defined(WITH_SWSCALE_LOADING)
73#define WITH_MJPEG_DECODER
74#include <libavcodec/avcodec.h>
77struct s_FREERDP_VIDEO_CONTEXT
81 struct SwsContext* sws;
83#if defined(WITH_MJPEG_DECODER)
84 AVCodecContext* mjpegDecoder;
85 AVPacket* mjpegPacket;
100static enum AVPixelFormat video_format_to_av(wLog* log, FREERDP_VIDEO_FORMAT format)
105 case FREERDP_VIDEO_FORMAT_MJPEG:
106 case FREERDP_VIDEO_FORMAT_H264:
107 return AV_PIX_FMT_NONE;
110 case FREERDP_VIDEO_FORMAT_YUV420P:
111 return AV_PIX_FMT_YUV420P;
112 case FREERDP_VIDEO_FORMAT_NV12:
113 return AV_PIX_FMT_NV12;
116 case FREERDP_VIDEO_FORMAT_YUYV422:
117 return AV_PIX_FMT_YUYV422;
120 case FREERDP_VIDEO_FORMAT_RGB24:
121 return AV_PIX_FMT_RGB24;
122 case FREERDP_VIDEO_FORMAT_RGB32:
123 return AV_PIX_FMT_RGB32;
125 case FREERDP_VIDEO_FORMAT_NONE:
127 WLog_Print(log, WLOG_WARN,
"Could not map FREERDP_VIDEO_FORMAT %s [0x%08" PRIx32
"]",
128 freerdp_video_format_string(format), format);
129 return AV_PIX_FMT_NONE;
133BOOL freerdp_video_available(
void)
135 return freerdp_swscale_available() && freerdp_avutil_available();
138FREERDP_VIDEO_CONTEXT* freerdp_video_context_new(UINT32 width, UINT32 height)
140 FREERDP_VIDEO_CONTEXT* context =
nullptr;
142 wLog* log = WLog_Get(VTAG);
143 if (!freerdp_video_available())
145 WLog_Print(log, WLOG_ERROR,
"Video codecs not available - FFmpeg not loaded");
149 context = (FREERDP_VIDEO_CONTEXT*)calloc(1,
sizeof(FREERDP_VIDEO_CONTEXT));
154 context->width = width;
155 context->height = height;
157#if defined(WITH_MJPEG_DECODER)
159 const AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
162 WLog_Print(context->log, WLOG_ERROR,
"avcodec_find_decoder failed to find MJPEG codec");
166 context->mjpegDecoder = avcodec_alloc_context3(codec);
167 if (!context->mjpegDecoder)
169 WLog_Print(context->log, WLOG_ERROR,
"avcodec_alloc_context3 failed");
173 context->mjpegDecoder->width = (int)width;
174 context->mjpegDecoder->height = (int)height;
176 context->mjpegDecoder->err_recognition |= AV_EF_EXPLODE;
178 if (avcodec_open2(context->mjpegDecoder, codec,
nullptr) < 0)
180 WLog_Print(context->log, WLOG_ERROR,
"avcodec_open2 failed");
184 context->mjpegPacket = av_packet_alloc();
185 if (!context->mjpegPacket)
187 WLog_Print(context->log, WLOG_ERROR,
"av_packet_alloc failed");
191 context->mjpegFrame = av_frame_alloc();
192 if (!context->mjpegFrame)
194 WLog_Print(context->log, WLOG_ERROR,
"av_frame_alloc failed");
201#if defined(WITH_MJPEG_DECODER)
203 freerdp_video_context_free(context);
208void freerdp_video_context_free(FREERDP_VIDEO_CONTEXT* context)
215 freerdp_sws_freeContext(context->sws);
216 context->sws =
nullptr;
219#if defined(WITH_MJPEG_DECODER)
220 if (context->mjpegFrame)
221 av_frame_free(&context->mjpegFrame);
223 if (context->mjpegPacket)
225 context->mjpegPacket->data =
nullptr;
226 context->mjpegPacket->size = 0;
227 av_packet_free(&context->mjpegPacket);
230 if (context->mjpegDecoder)
231 avcodec_free_context(&context->mjpegDecoder);
236 h264_context_free(context->h264);
237 context->h264 =
nullptr;
243BOOL freerdp_video_context_reconfigure(FREERDP_VIDEO_CONTEXT* context, UINT32 width, UINT32 height,
244 UINT32 framerate, UINT32 bitrate, UINT32 usageType)
246 WINPR_ASSERT(context);
248 if (width == 0 || height == 0)
250 WLog_Print(context->log, WLOG_ERROR,
"Invalid dimensions: %ux%u", width, height);
255 bitrate = video_get_h264_bitrate(context->log, height);
259 context->h264 = h264_context_new(TRUE);
262 WLog_Print(context->log, WLOG_ERROR,
"h264_context_new failed");
267 if (!h264_context_set_option(context->h264, H264_CONTEXT_OPTION_USAGETYPE, usageType))
270 if (!h264_context_set_option(context->h264, H264_CONTEXT_OPTION_FRAMERATE, framerate))
273 if (!h264_context_set_option(context->h264, H264_CONTEXT_OPTION_BITRATE, bitrate))
276 if (!h264_context_set_option(context->h264, H264_CONTEXT_OPTION_RATECONTROL,
277 H264_RATECONTROL_CQP))
280 if (!h264_context_set_option(context->h264, H264_CONTEXT_OPTION_QP, 26))
283 if (!h264_context_set_option(context->h264, H264_CONTEXT_OPTION_HW_ACCEL, FALSE))
286 if (!context->h264Configured || (context->width != width) || (context->height != height))
288 if (!h264_context_reset(context->h264, width, height))
290 WLog_Print(context->log, WLOG_ERROR,
"h264_context_reset failed");
295 context->h264Framerate = framerate;
296 context->h264Bitrate = bitrate;
297 context->h264UsageType = usageType;
298 context->h264Configured = TRUE;
299 context->width = width;
300 context->height = height;
307 h264_context_free(context->h264);
308 context->h264 =
nullptr;
313static BOOL freerdp_video_decode_mjpeg(FREERDP_VIDEO_CONTEXT* context,
const BYTE* srcData,
314 size_t srcSize, BYTE* dstData[4],
int dstLineSize[4],
315 enum AVPixelFormat* dstFormat);
317static BOOL freerdp_video_convert_to_yuv(FREERDP_VIDEO_CONTEXT* context,
const BYTE* srcData[4],
318 const int srcLineSize[4],
enum AVPixelFormat srcFormat,
319 BYTE* dstData[3],
const int dstLineSize[3],
320 FREERDP_VIDEO_FORMAT dstFormat, UINT32 width,
323BOOL freerdp_video_sample_convert(FREERDP_VIDEO_CONTEXT* context, FREERDP_VIDEO_FORMAT srcFormat,
324 const void* srcSampleData,
size_t srcSampleLength,
325 FREERDP_VIDEO_FORMAT dstFormat,
wStream* output)
327 WINPR_ASSERT(context);
328 WINPR_ASSERT(srcSampleData);
329 WINPR_ASSERT(output);
331 if (srcFormat == dstFormat)
333 if (!Stream_EnsureRemainingCapacity(output, srcSampleLength))
335 Stream_Write(output, srcSampleData, srcSampleLength);
339 if (!freerdp_video_available())
341 WLog_Print(context->log, WLOG_ERROR,
"Video codecs not available");
345 if (srcSampleLength == 0)
347 WLog_Print(context->log, WLOG_ERROR,
"Invalid source sample length: 0");
351 if (!freerdp_video_conversion_supported(srcFormat, dstFormat))
353 WLog_Print(context->log, WLOG_ERROR,
"Conversion from format %u to %u not supported",
354 srcFormat, dstFormat);
358 const BOOL srcCompressed =
359 (srcFormat == FREERDP_VIDEO_FORMAT_MJPEG || srcFormat == FREERDP_VIDEO_FORMAT_H264);
360 const BOOL dstCompressed =
361 (dstFormat == FREERDP_VIDEO_FORMAT_MJPEG || dstFormat == FREERDP_VIDEO_FORMAT_H264);
363 BYTE* intermediate_data[4] = WINPR_C_ARRAY_INIT;
364 int intermediate_linesize[4] = WINPR_C_ARRAY_INIT;
365 enum AVPixelFormat intermediate_format = AV_PIX_FMT_NONE;
369 if (srcFormat == FREERDP_VIDEO_FORMAT_MJPEG)
371 if (!freerdp_video_decode_mjpeg(context, (
const BYTE*)srcSampleData, srcSampleLength,
372 intermediate_data, intermediate_linesize,
373 &intermediate_format))
375 WLog_Print(context->log, WLOG_ERROR,
"MJPEG decoding failed");
379 else if (srcFormat == FREERDP_VIDEO_FORMAT_H264)
381 WLog_Print(context->log, WLOG_ERROR,
"H264 decoding not supported");
387 intermediate_format = video_format_to_av(context->log, srcFormat);
390 if (dstFormat == FREERDP_VIDEO_FORMAT_H264)
392 if (!context->h264Configured)
394 WLog_Print(context->log, WLOG_ERROR,
"H264 encoder not configured");
398 const UINT32 hwAccel = h264_context_get_option(context->h264, H264_CONTEXT_OPTION_HW_ACCEL);
399 const FREERDP_VIDEO_FORMAT yuvFormat =
400 hwAccel ? FREERDP_VIDEO_FORMAT_NV12 : FREERDP_VIDEO_FORMAT_YUV420P;
402 BYTE* yuvData[3] = WINPR_C_ARRAY_INIT;
403 UINT32 yuvStrides[3] = WINPR_C_ARRAY_INIT;
405 if (h264_get_yuv_buffer(context->h264, 0, context->width, context->height, yuvData,
408 WLog_Print(context->log, WLOG_ERROR,
"h264_get_yuv_buffer failed");
412 int yuvLineSizes[4] = { (int)yuvStrides[0], (
int)yuvStrides[1], (int)yuvStrides[2], 0 };
416 const BYTE* cIntermediateData[4] = { intermediate_data[0], intermediate_data[1],
417 intermediate_data[2], intermediate_data[3] };
418 if (!freerdp_video_convert_to_yuv(context, cIntermediateData, intermediate_linesize,
419 intermediate_format, yuvData, yuvLineSizes, yuvFormat,
420 context->width, context->height))
422 WLog_Print(context->log, WLOG_ERROR,
"YUV conversion failed");
428 BYTE* srcPlanes[4] = WINPR_C_ARRAY_INIT;
429 int srcStrides[4] = WINPR_C_ARRAY_INIT;
431 if (!freerdp_video_fill_plane_info(context->log, srcPlanes, srcStrides, srcFormat,
432 context->width, context->height,
433 (
const BYTE*)srcSampleData))
435 WLog_Print(context->log, WLOG_ERROR,
"Failed to fill plane info");
439 const BYTE* cSrcPlanes[4] = { srcPlanes[0], srcPlanes[1], srcPlanes[2], srcPlanes[3] };
440 if (!freerdp_video_convert_to_yuv(
441 context, cSrcPlanes, srcStrides, video_format_to_av(context->log, srcFormat),
442 yuvData, yuvLineSizes, yuvFormat, context->width, context->height))
444 WLog_Print(context->log, WLOG_ERROR,
"YUV conversion failed");
449 BYTE* h264Data =
nullptr;
452 if (h264_compress(context->h264, &h264Data, &h264Size) < 0)
454 WLog_Print(context->log, WLOG_ERROR,
"H264 compression failed");
458 if (!Stream_EnsureRemainingCapacity(output, h264Size))
460 WLog_Print(context->log, WLOG_ERROR,
"Failed to ensure stream capacity");
464 Stream_Write(output, h264Data, h264Size);
467 else if (dstCompressed)
469 WLog_Print(context->log, WLOG_ERROR,
"Only H264 encoding is supported");
473 WLog_Print(context->log, WLOG_ERROR,
"Raw format output not yet implemented");
477static BOOL freerdp_video_decode_mjpeg(FREERDP_VIDEO_CONTEXT* context,
const BYTE* srcData,
478 size_t srcSize, BYTE* dstData[4],
int dstLineSize[4],
479 enum AVPixelFormat* dstFormat)
481#if defined(WITH_MJPEG_DECODER)
482 WINPR_ASSERT(context);
483 WINPR_ASSERT(srcData);
484 WINPR_ASSERT(dstData);
485 WINPR_ASSERT(dstLineSize);
486 WINPR_ASSERT(dstFormat);
488 if (!context->mjpegDecoder)
490 WLog_Print(context->log, WLOG_ERROR,
"MJPEG decoder not initialized");
494 context->mjpegPacket->data = WINPR_CAST_CONST_PTR_AWAY(srcData, uint8_t*);
495 WINPR_ASSERT(srcSize <= INT32_MAX);
496 context->mjpegPacket->size = (int)srcSize;
498 if (avcodec_send_packet(context->mjpegDecoder, context->mjpegPacket) < 0)
500 WLog_Print(context->log, WLOG_ERROR,
"avcodec_send_packet failed");
504 if (avcodec_receive_frame(context->mjpegDecoder, context->mjpegFrame) < 0)
506 WLog_Print(context->log, WLOG_ERROR,
"avcodec_receive_frame failed");
511 for (
size_t i = 0; i < 4; i++)
513 dstData[i] = context->mjpegFrame->data[i];
514 dstLineSize[i] = context->mjpegFrame->linesize[i];
518 *dstFormat = context->mjpegDecoder->pix_fmt;
522 WINPR_UNUSED(context);
523 WINPR_UNUSED(srcData);
524 WINPR_UNUSED(srcSize);
525 WINPR_UNUSED(dstData);
526 WINPR_UNUSED(dstLineSize);
527 WINPR_UNUSED(dstFormat);
528 WLog_Print(context->log, WLOG_ERROR,
529 "MJPEG decoder not available (requires direct FFmpeg linking)");
534static BOOL freerdp_video_convert_to_yuv(FREERDP_VIDEO_CONTEXT* context,
const BYTE* srcData[4],
535 const int srcLineSize[4],
enum AVPixelFormat srcFormat,
536 BYTE* dstData[3],
const int dstLineSize[3],
537 FREERDP_VIDEO_FORMAT dstFormat, UINT32 width,
540 WINPR_ASSERT(context);
541 WINPR_ASSERT(srcData);
542 WINPR_ASSERT(srcLineSize);
543 WINPR_ASSERT(dstData);
544 WINPR_ASSERT(dstLineSize);
546 if (!freerdp_swscale_available())
548 WLog_Print(context->log, WLOG_ERROR,
549 "swscale not available - install FFmpeg to enable video processing");
553 enum AVPixelFormat srcPixFmt = srcFormat;
554 enum AVPixelFormat dstPixFmt = video_format_to_av(context->log, dstFormat);
556 if (srcPixFmt == AV_PIX_FMT_NONE || dstPixFmt == AV_PIX_FMT_NONE)
558 WLog_Print(context->log, WLOG_ERROR,
"Unsupported pixel format");
563 struct SwsContext* sws =
nullptr;
564 BOOL needFree = FALSE;
566 if (context && context->sws)
572 sws = freerdp_sws_getContext((
int)width, (
int)height, srcPixFmt, (
int)width, (
int)height,
573 dstPixFmt, 0,
nullptr,
nullptr,
nullptr);
576 WLog_Print(context->log, WLOG_ERROR,
"sws_getContext failed");
587 const BYTE* cSrcData[4] = { srcData[0], srcData[1], srcData[2], srcData[3] };
590 uint8_t* localDstData[4] = { dstData[0], dstData[1], dstData[2],
nullptr };
591 int localDstLineSize[4] = { dstLineSize[0], dstLineSize[1], dstLineSize[2], 0 };
593 const int result = freerdp_sws_scale(sws, cSrcData, srcLineSize, 0, (
int)height, localDstData,
598 freerdp_sws_freeContext(sws);
604static BOOL freerdp_video_fill_plane_info(wLog* log, BYTE* data[4],
int lineSize[4],
605 FREERDP_VIDEO_FORMAT format, UINT32 width, UINT32 height,
609 WINPR_ASSERT(lineSize);
611 enum AVPixelFormat pixFmt = video_format_to_av(log, format);
612 if (pixFmt == AV_PIX_FMT_NONE)
614 WLog_Print(log, WLOG_ERROR,
"Unsupported pixel format");
618 if (!freerdp_avutil_available())
620 WLog_Print(log, WLOG_ERROR,
"avutil not available");
624 if (freerdp_av_image_fill_linesizes(lineSize, pixFmt, (
int)width) < 0)
626 WLog_Print(log, WLOG_ERROR,
"av_image_fill_linesizes failed");
630 if (freerdp_av_image_fill_pointers(data, pixFmt, (
int)height,
631 WINPR_CAST_CONST_PTR_AWAY(buffer, BYTE*), lineSize) < 0)
633 WLog_Print(log, WLOG_ERROR,
"av_image_fill_pointers failed");
640BOOL freerdp_video_conversion_supported(FREERDP_VIDEO_FORMAT srcFormat,
641 FREERDP_VIDEO_FORMAT dstFormat)
643 if (srcFormat == dstFormat)
646 if (!freerdp_video_available())
649 if (srcFormat == FREERDP_VIDEO_FORMAT_MJPEG)
651#if !defined(WITH_MJPEG_DECODER)
655 else if (srcFormat == FREERDP_VIDEO_FORMAT_H264)
660 if (dstFormat == FREERDP_VIDEO_FORMAT_MJPEG)
664 else if (dstFormat == FREERDP_VIDEO_FORMAT_H264)
666#if !defined(WITH_OPENH264) && !defined(WITH_VIDEO_FFMPEG) && !defined(WITH_MEDIA_FOUNDATION) && \
667 !defined(WITH_MEDIACODEC) && !defined(WITH_APPLE_VIDEOTOOLBOX)
675#elif defined(WITH_MEDIACODEC) || defined(WITH_APPLE_VIDEOTOOLBOX)
688#define VIDEO_NV12_MAX_DIMENSION 16384
690struct s_FREERDP_VIDEO_CONTEXT
699BOOL freerdp_video_available(
void)
705FREERDP_VIDEO_CONTEXT* freerdp_video_context_new(UINT32 width, UINT32 height)
707 FREERDP_VIDEO_CONTEXT* context =
708 (FREERDP_VIDEO_CONTEXT*)calloc(1,
sizeof(FREERDP_VIDEO_CONTEXT));
712 context->log = WLog_Get(VTAG);
713 context->width = width;
714 context->height = height;
718void freerdp_video_context_free(FREERDP_VIDEO_CONTEXT* context)
723 h264_context_free(context->h264);
727BOOL freerdp_video_conversion_supported(FREERDP_VIDEO_FORMAT srcFormat,
728 FREERDP_VIDEO_FORMAT dstFormat)
730 if (srcFormat == dstFormat)
733 return (srcFormat == FREERDP_VIDEO_FORMAT_NV12) && (dstFormat == FREERDP_VIDEO_FORMAT_H264);
736BOOL freerdp_video_context_reconfigure(FREERDP_VIDEO_CONTEXT* context, UINT32 width, UINT32 height,
737 UINT32 framerate, UINT32 bitrate, UINT32 usageType)
743 if ((width == 0) || (height == 0) || ((width % 2) != 0) || ((height % 2) != 0) ||
744 (width > VIDEO_NV12_MAX_DIMENSION) || (height > VIDEO_NV12_MAX_DIMENSION))
746 WLog_Print(context->log, WLOG_ERROR,
"Invalid dimensions: %" PRIu32
"x%" PRIu32, width,
752 bitrate = video_get_h264_bitrate(context->log, height);
761 !context->h264Configured || (context->width != width) || (context->height != height);
764 h264_context_free(context->h264);
765 context->h264 =
nullptr;
766 context->h264Configured = FALSE;
771 context->h264 = h264_context_new(TRUE);
774 WLog_Print(context->log, WLOG_ERROR,
"h264_context_new failed");
781 if (!h264_context_set_option(context->h264, H264_CONTEXT_OPTION_USAGETYPE, usageType) ||
782 !h264_context_set_option(context->h264, H264_CONTEXT_OPTION_FRAMERATE, framerate) ||
783 !h264_context_set_option(context->h264, H264_CONTEXT_OPTION_BITRATE, bitrate) ||
784 !h264_context_set_option(context->h264, H264_CONTEXT_OPTION_RATECONTROL,
785 H264_RATECONTROL_CQP) ||
786 !h264_context_set_option(context->h264, H264_CONTEXT_OPTION_QP, 26) ||
787 !h264_context_set_option(context->h264, H264_CONTEXT_OPTION_HW_ACCEL, FALSE))
792 if (!h264_context_reset(context->h264, width, height))
794 WLog_Print(context->log, WLOG_ERROR,
"h264_context_reset failed");
798 WLog_Print(context->log, WLOG_INFO,
799 "camera frames encoded to H.264: %" PRIu32
"x%" PRIu32
", %" PRIu32
800 " fps, %" PRIu32
" bps",
801 width, height, framerate, bitrate);
804 context->h264Configured = TRUE;
805 context->width = width;
806 context->height = height;
810 h264_context_free(context->h264);
811 context->h264 =
nullptr;
812 context->h264Configured = FALSE;
817static void freerdp_video_nv12_to_i420(
const BYTE* nv12, UINT32 width, UINT32 height, BYTE* yuv[3],
818 const UINT32 strides[3])
820 for (UINT32 y = 0; y < height; y++)
821 memcpy(&yuv[0][(
size_t)y * strides[0]], &nv12[(
size_t)y * width], width);
823 const BYTE* uv = &nv12[(size_t)width * height];
824 for (UINT32 y = 0; y < height / 2; y++)
826 const BYTE* src = &uv[(size_t)y * width];
827 BYTE* u = &yuv[1][(size_t)y * strides[1]];
828 BYTE* v = &yuv[2][(size_t)y * strides[2]];
829 for (UINT32 x = 0; x < width / 2; x++)
831 u[x] = src[2 * (size_t)x];
832 v[x] = src[2 * (size_t)x + 1];
837BOOL freerdp_video_sample_convert(FREERDP_VIDEO_CONTEXT* context, FREERDP_VIDEO_FORMAT srcFormat,
838 const void* srcSampleData,
size_t srcSampleLength,
839 FREERDP_VIDEO_FORMAT dstFormat,
wStream* output)
841 if (!context || !srcSampleData || !output)
844 if (srcFormat == dstFormat)
846 if (!Stream_EnsureRemainingCapacity(output, srcSampleLength))
849 Stream_Write(output, srcSampleData, srcSampleLength);
853 if (!freerdp_video_conversion_supported(srcFormat, dstFormat))
855 WLog_Print(context->log, WLOG_ERROR,
"Conversion from %s to %s not supported",
856 freerdp_video_format_string(srcFormat), freerdp_video_format_string(dstFormat));
860 if (!context->h264Configured || !context->h264)
862 WLog_Print(context->log, WLOG_ERROR,
"H264 encoder not configured");
867 const size_t frameSize = (size_t)context->width * context->height * 3 / 2;
868 if (srcSampleLength < frameSize)
870 WLog_Print(context->log, WLOG_ERROR,
871 "NV12 sample of %" PRIuz
" bytes, %" PRIuz
" expected for %" PRIu32
"x%" PRIu32,
872 srcSampleLength, frameSize, context->width, context->height);
877 BYTE* yuvData[3] = WINPR_C_ARRAY_INIT;
878 UINT32 yuvStrides[3] = WINPR_C_ARRAY_INIT;
879 if ((h264_get_yuv_buffer(context->h264, context->width, context->width, context->height,
880 yuvData, yuvStrides) < 0) ||
881 !yuvData[0] || !yuvData[1] || !yuvData[2] || (yuvStrides[0] < context->width) ||
882 (yuvStrides[1] < context->width / 2) || (yuvStrides[2] < context->width / 2))
884 WLog_Print(context->log, WLOG_ERROR,
"h264_get_yuv_buffer failed");
888 freerdp_video_nv12_to_i420((
const BYTE*)srcSampleData, context->width, context->height, yuvData,
891 BYTE* h264Data =
nullptr;
893 if ((h264_compress(context->h264, &h264Data, &h264Size) < 0) || !h264Data || (h264Size == 0))
896 WLog_Print(context->log, WLOG_DEBUG,
"No H.264 frame out of this NV12 sample");
900 if (!Stream_EnsureRemainingCapacity(output, h264Size))
903 Stream_Write(output, h264Data, h264Size);
911BOOL freerdp_video_available(
void)
916FREERDP_VIDEO_CONTEXT* freerdp_video_context_new(WINPR_ATTR_UNUSED UINT32 width,
917 WINPR_ATTR_UNUSED UINT32 height)
920 WINPR_UNUSED(height);
921 return calloc(1,
sizeof(
char));
924void freerdp_video_context_free(FREERDP_VIDEO_CONTEXT* context)
929BOOL freerdp_video_conversion_supported(FREERDP_VIDEO_FORMAT srcFormat,
930 FREERDP_VIDEO_FORMAT dstFormat)
932 if (srcFormat == dstFormat)
937BOOL freerdp_video_context_reconfigure(WINPR_ATTR_UNUSED FREERDP_VIDEO_CONTEXT* context,
938 WINPR_ATTR_UNUSED UINT32 width,
939 WINPR_ATTR_UNUSED UINT32 height,
940 WINPR_ATTR_UNUSED UINT32 framerate,
941 WINPR_ATTR_UNUSED UINT32 bitrate,
942 WINPR_ATTR_UNUSED UINT32 usageType)
947BOOL freerdp_video_sample_convert(WINPR_ATTR_UNUSED FREERDP_VIDEO_CONTEXT* context,
948 FREERDP_VIDEO_FORMAT srcFormat,
const void* srcSampleData,
949 size_t srcSampleLength, FREERDP_VIDEO_FORMAT dstFormat,
952 if (srcFormat == dstFormat)
954 if (!Stream_EnsureRemainingCapacity(output, srcSampleLength))
957 Stream_Write(output, srcSampleData, srcSampleLength);
966const char* freerdp_video_format_string(UINT32 format)
974 EVCASE(FREERDP_VIDEO_FORMAT_NONE);
975 EVCASE(FREERDP_VIDEO_FORMAT_MJPEG);
976 EVCASE(FREERDP_VIDEO_FORMAT_H264);
977 EVCASE(FREERDP_VIDEO_FORMAT_YUV420P);
978 EVCASE(FREERDP_VIDEO_FORMAT_NV12);
979 EVCASE(FREERDP_VIDEO_FORMAT_YUYV422);
980 EVCASE(FREERDP_VIDEO_FORMAT_RGB24);
981 EVCASE(FREERDP_VIDEO_FORMAT_RGB32);
983 return "FREERDP_VIDEO_FORMAT_UNKNOWN";