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)
59 static 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)
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;
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;
94 static void libavcodec_destroy_encoder(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 avcodec_close(sys->codecEncoderContext);
106 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 69, 100)
107 avcodec_free_context(&sys->codecEncoderContext);
109 av_free(sys->codecEncoderContext);
113 sys->codecEncoder = NULL;
114 sys->codecEncoderContext = NULL;
117 static BOOL libavcodec_create_encoder(H264_CONTEXT* WINPR_RESTRICT h264)
119 BOOL recreate = FALSE;
120 H264_CONTEXT_LIBAVCODEC* sys = NULL;
122 if (!h264 || !h264->subsystem)
125 if ((h264->width > INT_MAX) || (h264->height > INT_MAX))
128 sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
131 recreate = !sys->codecEncoder || !sys->codecEncoderContext;
133 if (sys->codecEncoderContext)
135 if ((sys->codecEncoderContext->width != (
int)h264->width) ||
136 (sys->codecEncoderContext->height != (int)h264->height))
143 libavcodec_destroy_encoder(h264);
144 sys->codecEncoder = avcodec_find_encoder(AV_CODEC_ID_H264);
146 if (!sys->codecEncoder)
149 sys->codecEncoderContext = avcodec_alloc_context3(sys->codecEncoder);
151 if (!sys->codecEncoderContext)
154 switch (h264->RateControlMode)
156 case H264_RATECONTROL_VBR:
157 sys->codecEncoderContext->bit_rate = h264->BitRate;
160 case H264_RATECONTROL_CQP:
168 sys->codecEncoderContext->width = (int)MIN(INT32_MAX, h264->width);
169 sys->codecEncoderContext->height = (int)MIN(INT32_MAX, h264->height);
170 sys->codecEncoderContext->delay = 0;
171 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 13, 100)
172 sys->codecEncoderContext->framerate =
173 (AVRational){ WINPR_ASSERTING_INT_CAST(
int, h264->FrameRate), 1 };
175 sys->codecEncoderContext->time_base =
176 (AVRational){ 1, WINPR_ASSERTING_INT_CAST(
int, h264->FrameRate) };
177 av_opt_set(sys->codecEncoderContext,
"preset",
"medium", AV_OPT_SEARCH_CHILDREN);
178 av_opt_set(sys->codecEncoderContext,
"tune",
"zerolatency", AV_OPT_SEARCH_CHILDREN);
179 sys->codecEncoderContext->flags |= AV_CODEC_FLAG_LOOP_FILTER;
180 sys->codecEncoderContext->pix_fmt = AV_PIX_FMT_YUV420P;
182 if (avcodec_open2(sys->codecEncoderContext, sys->codecEncoder, NULL) < 0)
187 libavcodec_destroy_encoder(h264);
191 static int libavcodec_decompress(H264_CONTEXT* WINPR_RESTRICT h264,
192 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize)
202 AVPacket* packet = NULL;
205 WINPR_ASSERT(pSrcData || (SrcSize == 0));
207 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
208 BYTE** pYUVData = h264->pYUVData;
209 UINT32* iStride = h264->iStride;
213 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
214 packet = &sys->bufferpacket;
215 WINPR_ASSERT(packet);
216 av_init_packet(packet);
218 packet = av_packet_alloc();
222 WLog_Print(h264->log, WLOG_ERROR,
"Failed to allocate AVPacket");
227 packet->data = cnv.pv;
228 packet->size = (int)MIN(SrcSize, INT32_MAX);
230 WINPR_ASSERT(sys->codecDecoderContext);
232 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
233 status = avcodec_send_packet(sys->codecDecoderContext, packet);
237 WLog_Print(h264->log, WLOG_ERROR,
"Failed to decode video frame (status=%d)", status);
241 sys->videoFrame->format = AV_PIX_FMT_YUV420P;
246 status = avcodec_receive_frame(sys->codecDecoderContext,
247 sys->hwctx ? sys->hwVideoFrame : sys->videoFrame);
249 status = avcodec_receive_frame(sys->codecDecoderContext, sys->videoFrame);
251 }
while (status == AVERROR(EAGAIN));
253 gotFrame = (status == 0);
257 avcodec_decode_video2(sys->codecDecoderContext,
258 sys->hwctx ? sys->hwVideoFrame : sys->videoFrame, &gotFrame, packet);
260 status = avcodec_decode_video2(sys->codecDecoderContext, sys->videoFrame, &gotFrame, packet);
265 WLog_Print(h264->log, WLOG_ERROR,
"Failed to decode video frame (status=%d)", status);
273 if (sys->hwVideoFrame->format == sys->hw_pix_fmt)
275 sys->videoFrame->width = sys->hwVideoFrame->width;
276 sys->videoFrame->height = sys->hwVideoFrame->height;
277 status = av_hwframe_transfer_data(sys->videoFrame, sys->hwVideoFrame, 0);
281 status = av_frame_copy(sys->videoFrame, sys->hwVideoFrame);
285 gotFrame = (status == 0);
289 WLog_Print(h264->log, WLOG_ERROR,
"Failed to transfer video frame (status=%d) (%s)", status,
296 WLog_Print(h264->log, WLOG_INFO,
297 "libavcodec_decompress: frame decoded (status=%d, gotFrame=%d, width=%d, height=%d, Y=[%p,%d], U=[%p,%d], V=[%p,%d])",
298 status, gotFrame, sys->videoFrame->width, sys->videoFrame->height,
299 (
void*) sys->videoFrame->data[0], sys->videoFrame->linesize[0],
300 (
void*) sys->videoFrame->data[1], sys->videoFrame->linesize[1],
301 (
void*) sys->videoFrame->data[2], sys->videoFrame->linesize[2]);
306 WINPR_ASSERT(sys->videoFrame);
308 pYUVData[0] = sys->videoFrame->data[0];
309 pYUVData[1] = sys->videoFrame->data[1];
310 pYUVData[2] = sys->videoFrame->data[2];
311 iStride[0] = (UINT32)MAX(0, sys->videoFrame->linesize[0]);
312 iStride[1] = (UINT32)MAX(0, sys->videoFrame->linesize[1]);
313 iStride[2] = (UINT32)MAX(0, sys->videoFrame->linesize[2]);
321 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
322 av_packet_unref(packet);
324 av_packet_free(&packet);
330 static int libavcodec_compress(H264_CONTEXT* WINPR_RESTRICT h264,
331 const BYTE** WINPR_RESTRICT pSrcYuv,
332 const UINT32* WINPR_RESTRICT pStride,
333 BYTE** WINPR_RESTRICT ppDstData, UINT32* WINPR_RESTRICT pDstSize)
346 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
349 if (!libavcodec_create_encoder(h264))
352 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
353 sys->packet = &sys->bufferpacket;
354 av_packet_unref(sys->packet);
355 av_init_packet(sys->packet);
357 av_packet_free(&sys->packet);
358 sys->packet = av_packet_alloc();
362 WLog_Print(h264->log, WLOG_ERROR,
"Failed to allocate AVPacket");
366 WINPR_ASSERT(sys->packet);
367 sys->packet->data = NULL;
368 sys->packet->size = 0;
370 WINPR_ASSERT(sys->videoFrame);
371 WINPR_ASSERT(sys->codecEncoderContext);
372 sys->videoFrame->format = sys->codecEncoderContext->pix_fmt;
373 sys->videoFrame->width = sys->codecEncoderContext->width;
374 sys->videoFrame->height = sys->codecEncoderContext->height;
375 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 48, 100)
376 sys->videoFrame->colorspace = AVCOL_SPC_BT709;
378 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 92, 100)
379 sys->videoFrame->chroma_location = AVCHROMA_LOC_LEFT;
381 cnv.cpv = pSrcYuv[0];
382 sys->videoFrame->data[0] = cnv.pv;
384 cnv.cpv = pSrcYuv[1];
385 sys->videoFrame->data[1] = cnv.pv;
387 cnv.cpv = pSrcYuv[2];
388 sys->videoFrame->data[2] = cnv.pv;
390 sys->videoFrame->linesize[0] = (int)pStride[0];
391 sys->videoFrame->linesize[1] = (int)pStride[1];
392 sys->videoFrame->linesize[2] = (int)pStride[2];
393 sys->videoFrame->pts++;
395 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
396 status = avcodec_send_frame(sys->codecEncoderContext, sys->videoFrame);
400 WLog_Print(h264->log, WLOG_ERROR,
"Failed to encode video frame (%s [%d])",
401 av_err2str(status), status);
405 status = avcodec_receive_packet(sys->codecEncoderContext, sys->packet);
409 WLog_Print(h264->log, WLOG_ERROR,
"Failed to encode video frame (%s [%d])",
410 av_err2str(status), status);
414 gotFrame = (status == 0);
415 #elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 59, 100)
419 status = avcodec_encode_video2(sys->codecEncoderContext, sys->packet, sys->videoFrame,
421 }
while ((status >= 0) && (gotFrame == 0));
425 avpicture_get_size(sys->codecDecoderContext->pix_fmt, sys->codecDecoderContext->width,
426 sys->codecDecoderContext->height);
427 sys->packet->data = av_malloc(sys->packet->size);
429 if (!sys->packet->data)
433 status = avcodec_encode_video(sys->codecDecoderContext, sys->packet->data,
434 sys->packet->size, sys->videoFrame);
441 WLog_Print(h264->log, WLOG_ERROR,
"Failed to encode video frame (%s [%d])",
442 av_err2str(status), status);
446 WINPR_ASSERT(sys->packet);
447 *ppDstData = sys->packet->data;
448 *pDstSize = (UINT32)MAX(0, sys->packet->size);
452 WLog_Print(h264->log, WLOG_ERROR,
"Did not get frame! (%s [%d])", av_err2str(status),
462 static void libavcodec_uninit(H264_CONTEXT* h264)
466 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
473 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
474 av_packet_unref(sys->packet);
476 av_packet_free(&sys->packet);
482 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
483 av_frame_free(&sys->videoFrame);
485 av_free(sys->videoFrame);
491 if (sys->hwVideoFrame)
493 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
494 av_frame_free(&sys->hwVideoFrame);
496 av_free(sys->hwVideoFrame);
501 av_buffer_unref(&sys->hwctx);
503 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
505 if (sys->hw_frames_ctx)
506 av_buffer_unref(&sys->hw_frames_ctx);
511 if (sys->codecParser)
512 av_parser_close(sys->codecParser);
514 if (sys->codecDecoderContext)
516 avcodec_close(sys->codecDecoderContext);
517 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 69, 100)
518 avcodec_free_context(&sys->codecDecoderContext);
520 av_free(sys->codecDecoderContext);
524 libavcodec_destroy_encoder(h264);
526 h264->pSystemData = NULL;
530 static enum AVPixelFormat libavcodec_get_format(
struct AVCodecContext* ctx,
531 const enum AVPixelFormat* fmts)
535 H264_CONTEXT* h264 = (H264_CONTEXT*)ctx->opaque;
538 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
541 for (
const enum AVPixelFormat* p = fmts; *p != AV_PIX_FMT_NONE; p++)
543 if (*p == sys->hw_pix_fmt)
545 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
546 sys->hw_frames_ctx = av_hwframe_ctx_alloc(sys->hwctx);
548 if (!sys->hw_frames_ctx)
550 return AV_PIX_FMT_NONE;
553 sys->codecDecoderContext->pix_fmt = *p;
554 AVHWFramesContext* frames = (AVHWFramesContext*)sys->hw_frames_ctx->data;
556 frames->height = sys->codecDecoderContext->coded_height;
557 frames->width = sys->codecDecoderContext->coded_width;
559 (sys->codecDecoderContext->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? AV_PIX_FMT_P010
561 frames->initial_pool_size = 20;
563 if (sys->codecDecoderContext->active_thread_type & FF_THREAD_FRAME)
564 frames->initial_pool_size += sys->codecDecoderContext->thread_count;
566 int err = av_hwframe_ctx_init(sys->hw_frames_ctx);
570 WLog_Print(h264->log, WLOG_ERROR,
"Could not init hwframes context: %s",
572 return AV_PIX_FMT_NONE;
575 sys->codecDecoderContext->hw_frames_ctx = av_buffer_ref(sys->hw_frames_ctx);
581 return AV_PIX_FMT_NONE;
585 static BOOL libavcodec_init(H264_CONTEXT* h264)
587 H264_CONTEXT_LIBAVCODEC* sys = NULL;
590 sys = (H264_CONTEXT_LIBAVCODEC*)calloc(1,
sizeof(H264_CONTEXT_LIBAVCODEC));
597 h264->pSystemData = (
void*)sys;
599 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
600 avcodec_register_all();
603 if (!h264->Compressor)
605 sys->codecDecoder = avcodec_find_decoder(AV_CODEC_ID_H264);
607 if (!sys->codecDecoder)
609 WLog_Print(h264->log, WLOG_ERROR,
"Failed to find libav H.264 codec");
613 sys->codecDecoderContext = avcodec_alloc_context3(sys->codecDecoder);
615 if (!sys->codecDecoderContext)
617 WLog_Print(h264->log, WLOG_ERROR,
"Failed to allocate libav codec context");
621 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 18, 100)
622 if (sys->codecDecoder->capabilities & AV_CODEC_CAP_TRUNCATED)
624 sys->codecDecoderContext->flags |= AV_CODEC_FLAG_TRUNCATED;
633 av_hwdevice_ctx_create(&sys->hwctx, AV_HWDEVICE_TYPE_VAAPI, VAAPI_DEVICE, NULL, 0);
637 WLog_Print(h264->log, WLOG_ERROR,
638 "Could not initialize hardware decoder, falling back to software: %s",
641 goto fail_hwdevice_create;
644 WLog_Print(h264->log, WLOG_INFO,
"Using VAAPI for accelerated H264 decoding");
646 sys->codecDecoderContext->get_format = libavcodec_get_format;
647 sys->hw_pix_fmt = AV_PIX_FMT_VAAPI;
648 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 80, 100)
649 sys->codecDecoderContext->hw_device_ctx = av_buffer_ref(sys->hwctx);
651 sys->codecDecoderContext->opaque = (
void*)h264;
652 fail_hwdevice_create:
655 if (avcodec_open2(sys->codecDecoderContext, sys->codecDecoder, NULL) < 0)
657 WLog_Print(h264->log, WLOG_ERROR,
"Failed to open libav codec");
661 sys->codecParser = av_parser_init(AV_CODEC_ID_H264);
663 if (!sys->codecParser)
665 WLog_Print(h264->log, WLOG_ERROR,
"Failed to initialize libav parser");
670 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
671 sys->videoFrame = av_frame_alloc();
673 sys->hwVideoFrame = av_frame_alloc();
676 sys->videoFrame = avcodec_alloc_frame();
679 if (!sys->videoFrame)
681 WLog_Print(h264->log, WLOG_ERROR,
"Failed to allocate libav frame");
687 if (!sys->hwVideoFrame)
689 WLog_Print(h264->log, WLOG_ERROR,
"Failed to allocate libav hw frame");
694 sys->videoFrame->pts = 0;
697 libavcodec_uninit(h264);
701 const H264_CONTEXT_SUBSYSTEM g_Subsystem_libavcodec = {
"libavcodec", libavcodec_init,
702 libavcodec_uninit, libavcodec_decompress,
703 libavcodec_compress };