21#include <freerdp/config.h>
23#include <winpr/wlog.h>
24#include <freerdp/log.h>
25#include <freerdp/codec/h264.h>
26#include <libavcodec/avcodec.h>
27#include <libavutil/opt.h>
32#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 9, 0)
33#include <libavutil/hwcontext.h>
35#pragma warning You have asked for VA - API decoding, \
36 but your version of libavutil is too old !Disabling.
42#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100)
43#define AV_CODEC_ID_H264 CODEC_ID_H264
46#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(56, 34, 2)
47#define AV_CODEC_FLAG_LOOP_FILTER CODEC_FLAG_LOOP_FILTER
48#define AV_CODEC_CAP_TRUNCATED CODEC_CAP_TRUNCATED
49#define AV_CODEC_FLAG_TRUNCATED CODEC_FLAG_TRUNCATED
52#if LIBAVUTIL_VERSION_MAJOR < 52
53#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
58#if !defined(av_err2str)
59static inline char* error_string(
char* errbuf,
size_t errbuf_size,
int errnum)
61 av_strerror(errnum, errbuf, errbuf_size);
65#define av_err2str(errnum) error_string((char[64]){ 0 }, 64, errnum)
68#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
69#define VAAPI_DEVICE "/dev/dri/renderD128"
74 const AVCodec* codecDecoder;
75 AVCodecContext* codecDecoderContext;
76 const AVCodec* codecEncoder;
77 AVCodecContext* codecEncoderContext;
78 AVCodecParserContext* codecParser;
80#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
81 AVPacket bufferpacket;
84#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
86 AVFrame* hwVideoFrame;
87 enum AVPixelFormat hw_pix_fmt;
88#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
89 AVBufferRef* hw_frames_ctx;
92} H264_CONTEXT_LIBAVCODEC;
94static void libavcodec_destroy_encoder_context(H264_CONTEXT* WINPR_RESTRICT h264)
96 H264_CONTEXT_LIBAVCODEC* sys = NULL;
98 if (!h264 || !h264->subsystem)
101 sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
103 if (sys->codecEncoderContext)
105#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 69, 100)
106 avcodec_free_context(&sys->codecEncoderContext);
108 avcodec_close(sys->codecEncoderContext);
109 av_free(sys->codecEncoderContext);
113 sys->codecEncoderContext = NULL;
116#ifdef WITH_VAAPI_H264_ENCODING
117static int set_hw_frames_ctx(H264_CONTEXT* WINPR_RESTRICT h264)
119 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
120 AVBufferRef* hw_frames_ref = NULL;
121 AVHWFramesContext* frames_ctx = NULL;
124 if (!(hw_frames_ref = av_hwframe_ctx_alloc(sys->hwctx)))
126 WLog_Print(h264->log, WLOG_ERROR,
"Failed to create VAAPI frame context");
129 frames_ctx = (AVHWFramesContext*)(hw_frames_ref->data);
130 frames_ctx->format = AV_PIX_FMT_VAAPI;
131 frames_ctx->sw_format = AV_PIX_FMT_NV12;
132 frames_ctx->width = sys->codecEncoderContext->width;
133 frames_ctx->height = sys->codecEncoderContext->height;
134 frames_ctx->initial_pool_size = 20;
135 if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0)
137 WLog_Print(h264->log, WLOG_ERROR,
138 "Failed to initialize VAAPI frame context."
141 av_buffer_unref(&hw_frames_ref);
144 sys->codecEncoderContext->hw_frames_ctx = av_buffer_ref(hw_frames_ref);
145 if (!sys->codecEncoderContext->hw_frames_ctx)
146 err = AVERROR(ENOMEM);
148 av_buffer_unref(&hw_frames_ref);
153static BOOL libavcodec_create_encoder_context(H264_CONTEXT* WINPR_RESTRICT h264)
155 BOOL recreate = FALSE;
156 H264_CONTEXT_LIBAVCODEC* sys = NULL;
158 if (!h264 || !h264->subsystem)
161 if ((h264->width > INT_MAX) || (h264->height > INT_MAX))
164 sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
165 if (!sys || !sys->codecEncoder)
168 recreate = !sys->codecEncoderContext;
170 if (sys->codecEncoderContext)
172 if ((sys->codecEncoderContext->width != (
int)h264->width) ||
173 (sys->codecEncoderContext->height != (
int)h264->height))
180 libavcodec_destroy_encoder_context(h264);
182 sys->codecEncoderContext = avcodec_alloc_context3(sys->codecEncoder);
184 if (!sys->codecEncoderContext)
187 switch (h264->RateControlMode)
189 case H264_RATECONTROL_VBR:
190 sys->codecEncoderContext->bit_rate = h264->BitRate;
193 case H264_RATECONTROL_CQP:
194 if (av_opt_set_int(sys->codecEncoderContext,
"qp", h264->QP, AV_OPT_SEARCH_CHILDREN) <
197 WLog_Print(h264->log, WLOG_ERROR,
"av_opt_set_int failed");
205 sys->codecEncoderContext->width = (int)MIN(INT32_MAX, h264->width);
206 sys->codecEncoderContext->height = (int)MIN(INT32_MAX, h264->height);
207 sys->codecEncoderContext->delay = 0;
208#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 13, 100)
209 sys->codecEncoderContext->framerate =
210 (AVRational){ WINPR_ASSERTING_INT_CAST(
int, h264->FrameRate), 1 };
212 sys->codecEncoderContext->time_base =
213 (AVRational){ 1, WINPR_ASSERTING_INT_CAST(
int, h264->FrameRate) };
214 av_opt_set(sys->codecEncoderContext,
"tune",
"zerolatency", AV_OPT_SEARCH_CHILDREN);
216 sys->codecEncoderContext->flags |= AV_CODEC_FLAG_LOOP_FILTER;
218#ifdef WITH_VAAPI_H264_ENCODING
221 av_opt_set(sys->codecEncoderContext,
"preset",
"veryslow", AV_OPT_SEARCH_CHILDREN);
223 sys->codecEncoderContext->pix_fmt = AV_PIX_FMT_VAAPI;
225 if (set_hw_frames_ctx(h264) < 0)
231 av_opt_set(sys->codecEncoderContext,
"preset",
"medium", AV_OPT_SEARCH_CHILDREN);
232 sys->codecEncoderContext->pix_fmt = AV_PIX_FMT_YUV420P;
235 if (avcodec_open2(sys->codecEncoderContext, sys->codecEncoder, NULL) < 0)
240 libavcodec_destroy_encoder_context(h264);
244static int libavcodec_decompress(H264_CONTEXT* WINPR_RESTRICT h264,
245 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize)
255 AVPacket* packet = NULL;
258 WINPR_ASSERT(pSrcData || (SrcSize == 0));
260 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
261 BYTE** pYUVData = h264->pYUVData;
262 UINT32* iStride = h264->iStride;
266#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
267 packet = &sys->bufferpacket;
268 WINPR_ASSERT(packet);
269 av_init_packet(packet);
271 packet = av_packet_alloc();
275 WLog_Print(h264->log, WLOG_ERROR,
"Failed to allocate AVPacket");
280 packet->data = cnv.pv;
281 packet->size = (int)MIN(SrcSize, INT32_MAX);
283 WINPR_ASSERT(sys->codecDecoderContext);
285#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
286 status = avcodec_send_packet(sys->codecDecoderContext, packet);
290 WLog_Print(h264->log, WLOG_ERROR,
"Failed to decode video frame (status=%d)", status);
294 sys->videoFrame->format = AV_PIX_FMT_YUV420P;
297 status = avcodec_receive_frame(sys->codecDecoderContext,
298 sys->hwctx ? sys->hwVideoFrame : sys->videoFrame);
300 status = avcodec_receive_frame(sys->codecDecoderContext, sys->videoFrame);
302 if (status == AVERROR(EAGAIN))
308 gotFrame = (status == 0);
312 avcodec_decode_video2(sys->codecDecoderContext,
313 sys->hwctx ? sys->hwVideoFrame : sys->videoFrame, &gotFrame, packet);
315 status = avcodec_decode_video2(sys->codecDecoderContext, sys->videoFrame, &gotFrame, packet);
320 WLog_Print(h264->log, WLOG_ERROR,
"Failed to decode video frame (status=%d)", status);
328 if (sys->hwVideoFrame->format == sys->hw_pix_fmt)
330 sys->videoFrame->width = sys->hwVideoFrame->width;
331 sys->videoFrame->height = sys->hwVideoFrame->height;
332 status = av_hwframe_transfer_data(sys->videoFrame, sys->hwVideoFrame, 0);
336 status = av_frame_copy(sys->videoFrame, sys->hwVideoFrame);
340 gotFrame = (status == 0);
344 WLog_Print(h264->log, WLOG_ERROR,
"Failed to transfer video frame (status=%d) (%s)", status,
353 WINPR_ASSERT(sys->videoFrame);
355 pYUVData[0] = sys->videoFrame->data[0];
356 pYUVData[1] = sys->videoFrame->data[1];
357 pYUVData[2] = sys->videoFrame->data[2];
358 iStride[0] = (UINT32)MAX(0, sys->videoFrame->linesize[0]);
359 iStride[1] = (UINT32)MAX(0, sys->videoFrame->linesize[1]);
360 iStride[2] = (UINT32)MAX(0, sys->videoFrame->linesize[2]);
368#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
369 av_packet_unref(packet);
371 av_packet_free(&packet);
377static int libavcodec_compress(H264_CONTEXT* WINPR_RESTRICT h264,
378 const BYTE** WINPR_RESTRICT pSrcYuv,
379 const UINT32* WINPR_RESTRICT pStride,
380 BYTE** WINPR_RESTRICT ppDstData, UINT32* WINPR_RESTRICT pDstSize)
393 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
396 if (!libavcodec_create_encoder_context(h264))
399#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
400 sys->packet = &sys->bufferpacket;
401 av_packet_unref(sys->packet);
402 av_init_packet(sys->packet);
404 av_packet_free(&sys->packet);
405 sys->packet = av_packet_alloc();
409 WLog_Print(h264->log, WLOG_ERROR,
"Failed to allocate AVPacket");
413 WINPR_ASSERT(sys->packet);
414 sys->packet->data = NULL;
415 sys->packet->size = 0;
417 WINPR_ASSERT(sys->videoFrame);
418 WINPR_ASSERT(sys->codecEncoderContext);
419 sys->videoFrame->format = AV_PIX_FMT_YUV420P;
420 sys->videoFrame->width = sys->codecEncoderContext->width;
421 sys->videoFrame->height = sys->codecEncoderContext->height;
422#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 48, 100)
423 sys->videoFrame->colorspace = AVCOL_SPC_BT709;
425#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 92, 100)
426 sys->videoFrame->chroma_location = AVCHROMA_LOC_LEFT;
428 cnv.cpv = pSrcYuv[0];
429 sys->videoFrame->data[0] = cnv.pv;
431 cnv.cpv = pSrcYuv[1];
432 sys->videoFrame->data[1] = cnv.pv;
434 cnv.cpv = pSrcYuv[2];
435 sys->videoFrame->data[2] = cnv.pv;
437 sys->videoFrame->linesize[0] = (int)pStride[0];
438 sys->videoFrame->linesize[1] = (int)pStride[1];
439 sys->videoFrame->linesize[2] = (int)pStride[2];
440 sys->videoFrame->pts++;
442#ifdef WITH_VAAPI_H264_ENCODING
445 av_frame_unref(sys->hwVideoFrame);
446 if ((status = av_hwframe_get_buffer(sys->codecEncoderContext->hw_frames_ctx,
447 sys->hwVideoFrame, 0)) < 0 ||
448 !sys->hwVideoFrame->hw_frames_ctx)
450 WLog_Print(h264->log, WLOG_ERROR,
"av_hwframe_get_buffer failed (%s [%d])",
451 av_err2str(status), status);
454 sys->videoFrame->format = AV_PIX_FMT_NV12;
455 if ((status = av_hwframe_transfer_data(sys->hwVideoFrame, sys->videoFrame, 0)) < 0)
457 WLog_Print(h264->log, WLOG_ERROR,
"av_hwframe_transfer_data failed (%s [%d])",
458 av_err2str(status), status);
465#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
466#ifdef WITH_VAAPI_H264_ENCODING
467 status = avcodec_send_frame(sys->codecEncoderContext,
468 sys->hwctx ? sys->hwVideoFrame : sys->videoFrame);
470 status = avcodec_send_frame(sys->codecEncoderContext, sys->videoFrame);
475 WLog_Print(h264->log, WLOG_ERROR,
"Failed to encode video frame (%s [%d])",
476 av_err2str(status), status);
480 status = avcodec_receive_packet(sys->codecEncoderContext, sys->packet);
484 WLog_Print(h264->log, WLOG_ERROR,
"Failed to encode video frame (%s [%d])",
485 av_err2str(status), status);
489 gotFrame = (status == 0);
490#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 59, 100)
494 status = avcodec_encode_video2(sys->codecEncoderContext, sys->packet, sys->videoFrame,
496 }
while ((status >= 0) && (gotFrame == 0));
500 avpicture_get_size(sys->codecDecoderContext->pix_fmt, sys->codecDecoderContext->width,
501 sys->codecDecoderContext->height);
502 sys->packet->data = av_malloc(sys->packet->size);
504 if (!sys->packet->data)
508 status = avcodec_encode_video(sys->codecDecoderContext, sys->packet->data,
509 sys->packet->size, sys->videoFrame);
516 WLog_Print(h264->log, WLOG_ERROR,
"Failed to encode video frame (%s [%d])",
517 av_err2str(status), status);
521 WINPR_ASSERT(sys->packet);
522 *ppDstData = sys->packet->data;
523 *pDstSize = (UINT32)MAX(0, sys->packet->size);
527 WLog_Print(h264->log, WLOG_ERROR,
"Did not get frame! (%s [%d])", av_err2str(status),
537static void libavcodec_uninit(H264_CONTEXT* h264)
541 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
548#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
549 av_packet_unref(sys->packet);
551 av_packet_free(&sys->packet);
557#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
558 av_frame_free(&sys->videoFrame);
560 av_free(sys->videoFrame);
564#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
565 if (sys->hwVideoFrame)
567#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
568 av_frame_free(&sys->hwVideoFrame);
570 av_free(sys->hwVideoFrame);
575 av_buffer_unref(&sys->hwctx);
577#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
579 if (sys->hw_frames_ctx)
580 av_buffer_unref(&sys->hw_frames_ctx);
586 if (sys->codecParser)
587 av_parser_close(sys->codecParser);
589 if (sys->codecDecoderContext)
591#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 69, 100)
592 avcodec_free_context(&sys->codecDecoderContext);
594 avcodec_close(sys->codecDecoderContext);
595 av_free(sys->codecDecoderContext);
599 libavcodec_destroy_encoder_context(h264);
601 h264->pSystemData = NULL;
605static enum AVPixelFormat libavcodec_get_format(
struct AVCodecContext* ctx,
606 const enum AVPixelFormat* fmts)
610 H264_CONTEXT* h264 = (H264_CONTEXT*)ctx->opaque;
613 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
616 for (
const enum AVPixelFormat* p = fmts; *p != AV_PIX_FMT_NONE; p++)
618 if (*p == sys->hw_pix_fmt)
620#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
621 sys->hw_frames_ctx = av_hwframe_ctx_alloc(sys->hwctx);
623 if (!sys->hw_frames_ctx)
625 return AV_PIX_FMT_NONE;
628 sys->codecDecoderContext->pix_fmt = *p;
629 AVHWFramesContext* frames = (AVHWFramesContext*)sys->hw_frames_ctx->data;
631 frames->height = sys->codecDecoderContext->coded_height;
632 frames->width = sys->codecDecoderContext->coded_width;
634 (sys->codecDecoderContext->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? AV_PIX_FMT_P010
636 frames->initial_pool_size = 20;
638 if (sys->codecDecoderContext->active_thread_type & FF_THREAD_FRAME)
639 frames->initial_pool_size += sys->codecDecoderContext->thread_count;
641 int err = av_hwframe_ctx_init(sys->hw_frames_ctx);
645 WLog_Print(h264->log, WLOG_ERROR,
"Could not init hwframes context: %s",
647 return AV_PIX_FMT_NONE;
650 sys->codecDecoderContext->hw_frames_ctx = av_buffer_ref(sys->hw_frames_ctx);
656 return AV_PIX_FMT_NONE;
660static BOOL libavcodec_init(H264_CONTEXT* h264)
662 H264_CONTEXT_LIBAVCODEC* sys = NULL;
665 sys = (H264_CONTEXT_LIBAVCODEC*)calloc(1,
sizeof(H264_CONTEXT_LIBAVCODEC));
672 h264->pSystemData = (
void*)sys;
674#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
675 avcodec_register_all();
678 if (!h264->Compressor)
680 sys->codecDecoder = avcodec_find_decoder(AV_CODEC_ID_H264);
682 if (!sys->codecDecoder)
684 WLog_Print(h264->log, WLOG_ERROR,
"Failed to find libav H.264 codec");
688 sys->codecDecoderContext = avcodec_alloc_context3(sys->codecDecoder);
690 if (!sys->codecDecoderContext)
692 WLog_Print(h264->log, WLOG_ERROR,
"Failed to allocate libav codec context");
696#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 18, 100)
697 if (sys->codecDecoder->capabilities & AV_CODEC_CAP_TRUNCATED)
699 sys->codecDecoderContext->flags |= AV_CODEC_FLAG_TRUNCATED;
708 av_hwdevice_ctx_create(&sys->hwctx, AV_HWDEVICE_TYPE_VAAPI, VAAPI_DEVICE, NULL, 0);
712 WLog_Print(h264->log, WLOG_ERROR,
713 "Could not initialize hardware decoder, falling back to software: %s",
716 goto fail_hwdevice_create;
719 WLog_Print(h264->log, WLOG_INFO,
"Using VAAPI for accelerated H264 decoding");
721 sys->codecDecoderContext->get_format = libavcodec_get_format;
722 sys->hw_pix_fmt = AV_PIX_FMT_VAAPI;
723#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 80, 100)
724 sys->codecDecoderContext->hw_device_ctx = av_buffer_ref(sys->hwctx);
726 sys->codecDecoderContext->opaque = (
void*)h264;
727 fail_hwdevice_create:
730 if (avcodec_open2(sys->codecDecoderContext, sys->codecDecoder, NULL) < 0)
732 WLog_Print(h264->log, WLOG_ERROR,
"Failed to open libav codec");
736 sys->codecParser = av_parser_init(AV_CODEC_ID_H264);
738 if (!sys->codecParser)
740 WLog_Print(h264->log, WLOG_ERROR,
"Failed to initialize libav parser");
746#ifdef WITH_VAAPI_H264_ENCODING
749 sys->codecEncoder = avcodec_find_encoder_by_name(
"h264_vaapi");
750 if (!sys->codecEncoder)
752 WLog_Print(h264->log, WLOG_ERROR,
"H264 VAAPI encoder not found");
754 else if (av_hwdevice_ctx_create(&sys->hwctx, AV_HWDEVICE_TYPE_VAAPI, VAAPI_DEVICE, NULL,
757 WLog_Print(h264->log, WLOG_ERROR,
"av_hwdevice_ctx_create failed");
758 sys->codecEncoder = NULL;
763 WLog_Print(h264->log, WLOG_INFO,
"Using VAAPI for accelerated H264 encoding");
767 if (!sys->codecEncoder)
769 sys->codecEncoder = avcodec_find_encoder(AV_CODEC_ID_H264);
770 h264->hwAccel = FALSE;
773 if (!sys->codecEncoder)
775 WLog_Print(h264->log, WLOG_ERROR,
"Failed to initialize H264 encoder");
780#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
781 sys->videoFrame = av_frame_alloc();
782#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
783 sys->hwVideoFrame = av_frame_alloc();
786 sys->videoFrame = avcodec_alloc_frame();
789 if (!sys->videoFrame)
791 WLog_Print(h264->log, WLOG_ERROR,
"Failed to allocate libav frame");
795#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
796 if (!sys->hwVideoFrame)
798 WLog_Print(h264->log, WLOG_ERROR,
"Failed to allocate libav hw frame");
803 sys->videoFrame->pts = 0;
806 libavcodec_uninit(h264);
810const H264_CONTEXT_SUBSYSTEM g_Subsystem_libavcodec = {
"libavcodec", libavcodec_init,
811 libavcodec_uninit, libavcodec_decompress,
812 libavcodec_compress };