Skip to content

Commit bedc1ac

Browse files
author
Sri Ramanujam
committed
Use libavcodec's VA-API decoding.
Leverages libavcodec's hw decode support to provide VA-API based hardware decoding. Depends on the local build of ffmpeg having hardware VA-API support compiled in and the appropriate libva drivers and libraries installed.
1 parent 6705739 commit bedc1ac

File tree

4 files changed

+131
-4
lines changed

4 files changed

+131
-4
lines changed

CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,10 @@ set(FFMPEG_FEATURE_TYPE "RECOMMENDED")
663663
set(FFMPEG_FEATURE_PURPOSE "multimedia")
664664
set(FFMPEG_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
665665

666+
set(VAAPI_FEATURE_TYPE "OPTIONAL")
667+
set(VAAPI_FEATURE_PURPOSE "multimedia")
668+
set(VAAPI_FEATURE_DESCRIPTION "VA-API hardware acceleration for video playback")
669+
666670
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
667671
set(GSTREAMER_0_10_FEATURE_PURPOSE "multimedia")
668672
set(GSTREAMER_0_10_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback, gstreamer 0.10 version")
@@ -706,6 +710,7 @@ if(WIN32)
706710
set(CUPS_FEATURE_TYPE "DISABLED")
707711
set(PCSC_FEATURE_TYPE "DISABLED")
708712
set(FFMPEG_FEATURE_TYPE "DISABLED")
713+
set(VAAPI_FEATURE_TYPE "DISABLED")
709714
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
710715
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
711716
set(OPENSLES_FEATURE_TYPE "DISABLED")
@@ -714,6 +719,7 @@ endif()
714719
if(APPLE)
715720
set(DIRECTFB_FEATURE_TYPE "DISABLED")
716721
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
722+
set(VAAPI_FEATURE_TYPE "DISABLED")
717723
set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL")
718724
set(X11_FEATURE_TYPE "OPTIONAL")
719725
set(WAYLAND_FEATURE_TYPE "DISABLED")
@@ -755,6 +761,7 @@ if(ANDROID)
755761
set(CUPS_FEATURE_TYPE "DISABLED")
756762
set(PCSC_FEATURE_TYPE "DISABLED")
757763
set(FFMPEG_FEATURE_TYPE "DISABLED")
764+
set(VAAPI_FEATURE_TYPE "DISABLED")
758765
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
759766
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
760767
set(OPENSLES_FEATURE_TYPE "REQUIRED")

config.h.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
#cmakedefine WITH_X264
5959
#cmakedefine WITH_MEDIA_FOUNDATION
6060

61+
#cmakedefine WITH_VAAPI
62+
6163
/* Plugins */
6264
#cmakedefine BUILTIN_CHANNELS
6365
#cmakedefine WITH_RDPDR

include/freerdp/codec/h264.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ struct _H264_CONTEXT
7575
void* pSystemData;
7676
H264_CONTEXT_SUBSYSTEM* subsystem;
7777
};
78-
7978
#ifdef __cplusplus
8079
extern "C" {
8180
#endif

libfreerdp/codec/h264_ffmpeg.c

Lines changed: 122 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,22 @@
1818
* See the License for the specific language governing permissions and
1919
* limitations under the License.
2020
*/
21+
#ifdef HAVE_CONFIG_H
22+
#include "config.h"
23+
#endif
24+
2125
#include <winpr/wlog.h>
2226
#include <freerdp/log.h>
2327
#include <freerdp/codec/h264.h>
2428
#include <libavcodec/avcodec.h>
25-
#include <libavutil/avutil.h>
2629
#include <libavutil/opt.h>
27-
#include <libavutil/mem.h>
30+
31+
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 9, 0)
32+
#include <libavutil/hwcontext.h>
33+
#else
34+
#pragma warning You have asked for VA-API decoding, but your version of libavutil is too old! Disabling.
35+
#undef WITH_VAAPI
36+
#endif
2837

2938
#define TAG FREERDP_TAG("codec")
3039

@@ -56,6 +65,10 @@ static inline char* error_string(char* errbuf, size_t errbuf_size, int errnum)
5665
error_string((char[64]){0}, 64, errnum)
5766
#endif
5867

68+
#ifdef WITH_VAAPI
69+
#define VAAPI_DEVICE "/dev/dri/renderD128"
70+
#endif
71+
5972
struct _H264_CONTEXT_LIBAVCODEC
6073
{
6174
AVCodec* codecDecoder;
@@ -65,6 +78,11 @@ struct _H264_CONTEXT_LIBAVCODEC
6578
AVCodecParserContext* codecParser;
6679
AVFrame* videoFrame;
6780
AVPacket packet;
81+
#ifdef WITH_VAAPI
82+
AVBufferRef* hwctx;
83+
AVFrame* hwVideoFrame;
84+
enum AVPixelFormat hw_pix_fmt;
85+
#endif
6886
};
6987
typedef struct _H264_CONTEXT_LIBAVCODEC H264_CONTEXT_LIBAVCODEC;
7088

@@ -197,20 +215,31 @@ static int libavcodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData,
197215

198216
if (status < 0)
199217
{
200-
WLog_ERR(TAG, "Failed to decode video frame (status=%d)", status);
218+
WLog_ERR(TAG, "Failed to decode video frame (%s)", av_err2str(status));
201219
return -1;
202220
}
203221

222+
sys->videoFrame->format = AV_PIX_FMT_YUV420P;
223+
204224
do
205225
{
226+
#ifdef WITH_VAAPI
227+
status = avcodec_receive_frame(sys->codecDecoderContext, sys->hwVideoFrame);
228+
#else
206229
status = avcodec_receive_frame(sys->codecDecoderContext, sys->videoFrame);
230+
#endif
207231
}
208232
while (status == AVERROR(EAGAIN));
209233

210234
gotFrame = (status == 0);
235+
#else
236+
#ifdef WITH_VAAPI
237+
status = avcodec_decode_video2(sys->codecDecoderContext, sys->hwVideoFrame, &gotFrame,
238+
&sys->packet);
211239
#else
212240
status = avcodec_decode_video2(sys->codecDecoderContext, sys->videoFrame, &gotFrame,
213241
&sys->packet);
242+
#endif
214243
#endif
215244

216245
if (status < 0)
@@ -219,6 +248,28 @@ static int libavcodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData,
219248
return -1;
220249
}
221250

251+
#ifdef WITH_VAAPI
252+
253+
if (sys->hwctx)
254+
{
255+
if (sys->hwVideoFrame->format == sys->hw_pix_fmt)
256+
{
257+
sys->videoFrame->width = sys->hwVideoFrame->width;
258+
sys->videoFrame->height = sys->hwVideoFrame->height;
259+
status = av_hwframe_transfer_data(sys->videoFrame, sys->hwVideoFrame, 0);
260+
}
261+
else
262+
{
263+
status = av_frame_copy(sys->videoFrame, sys->hwVideoFrame);
264+
}
265+
}
266+
else
267+
{
268+
status = av_frame_copy(sys->videoFrame, sys->hwVideoFrame);
269+
}
270+
271+
gotFrame = (status == 0);
272+
#endif
222273
#if 0
223274
WLog_INFO(TAG,
224275
"libavcodec_decompress: frame decoded (status=%d, gotFrame=%d, width=%d, height=%d, Y=[%p,%d], U=[%p,%d], V=[%p,%d])",
@@ -361,6 +412,24 @@ static void libavcodec_uninit(H264_CONTEXT* h264)
361412
#endif
362413
}
363414

415+
#ifdef WITH_VAAPI
416+
417+
if (sys->hwVideoFrame)
418+
{
419+
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
420+
av_frame_free(&sys->hwVideoFrame);
421+
#else
422+
av_free(sys->hwVideoFrame);
423+
#endif
424+
}
425+
426+
if (sys->hwctx)
427+
{
428+
av_buffer_unref(&sys->hwctx);
429+
}
430+
431+
#endif
432+
364433
if (sys->codecParser)
365434
av_parser_close(sys->codecParser);
366435

@@ -379,6 +448,25 @@ static void libavcodec_uninit(H264_CONTEXT* h264)
379448
h264->pSystemData = NULL;
380449
}
381450

451+
#ifdef WITH_VAAPI
452+
static enum AVPixelFormat libavcodec_get_format(struct AVCodecContext* ctx,
453+
const enum AVPixelFormat* fmts)
454+
{
455+
H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*) ctx->opaque;
456+
const enum AVPixelFormat* p;
457+
458+
for (p = fmts; *p != AV_PIX_FMT_NONE; p++)
459+
{
460+
if (*p == sys->hw_pix_fmt)
461+
{
462+
return *p;
463+
}
464+
}
465+
466+
return AV_PIX_FMT_NONE;
467+
}
468+
#endif
469+
382470
static BOOL libavcodec_init(H264_CONTEXT* h264)
383471
{
384472
H264_CONTEXT_LIBAVCODEC* sys;
@@ -415,6 +503,25 @@ static BOOL libavcodec_init(H264_CONTEXT* h264)
415503
sys->codecDecoderContext->flags |= AV_CODEC_FLAG_TRUNCATED;
416504
}
417505

506+
#ifdef WITH_VAAPI
507+
508+
if (!sys->hwctx)
509+
{
510+
int ret = av_hwdevice_ctx_create(&sys->hwctx, AV_HWDEVICE_TYPE_VAAPI, VAAPI_DEVICE, NULL, 0);
511+
512+
if (ret < 0)
513+
{
514+
WLog_ERR(TAG, "Could not initialize hw decoder: %s", av_err2str(ret));
515+
goto EXCEPTION;
516+
}
517+
}
518+
519+
sys->codecDecoderContext->get_format = libavcodec_get_format;
520+
sys->hw_pix_fmt = AV_PIX_FMT_VAAPI;
521+
sys->codecDecoderContext->hw_device_ctx = av_buffer_ref(sys->hwctx);
522+
sys->codecDecoderContext->opaque = (void*) sys;
523+
#endif
524+
418525
if (avcodec_open2(sys->codecDecoderContext, sys->codecDecoder, NULL) < 0)
419526
{
420527
WLog_ERR(TAG, "Failed to open libav codec");
@@ -432,6 +539,9 @@ static BOOL libavcodec_init(H264_CONTEXT* h264)
432539

433540
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
434541
sys->videoFrame = av_frame_alloc();
542+
#ifdef WITH_VAAPI
543+
sys->hwVideoFrame = av_frame_alloc();
544+
#endif
435545
#else
436546
sys->videoFrame = avcodec_alloc_frame();
437547
#endif
@@ -442,6 +552,15 @@ static BOOL libavcodec_init(H264_CONTEXT* h264)
442552
goto EXCEPTION;
443553
}
444554

555+
#ifdef WITH_VAAPI
556+
557+
if (!sys->hwVideoFrame)
558+
{
559+
WLog_ERR(TAG, "Failed to allocate libav hw frame");
560+
goto EXCEPTION;
561+
}
562+
563+
#endif
445564
sys->videoFrame->pts = 0;
446565
return TRUE;
447566
EXCEPTION:

0 commit comments

Comments
 (0)