Add X11 VAAPI decoder

This commit is contained in:
Iwan Timmer 2017-06-17 12:32:33 +02:00
parent 2c35e70cc0
commit 4415836579
9 changed files with 204 additions and 43 deletions

View File

@ -21,20 +21,26 @@ pkg_check_modules(SDL sdl2>=2.0.4)
pkg_check_modules(AVCODEC libavcodec)
pkg_check_modules(AVUTIL libavutil)
pkg_check_modules(XLIB x11)
pkg_check_modules(LIBVA vdpau)
pkg_check_modules(VDPAU vdpau)
pkg_check_modules(LIBVA libva)
pkg_check_modules(LIBVA_X11 libva-x11)
pkg_check_modules(PULSE libpulse-simple)
pkg_check_modules(CEC libcec>=3.0.0)
pkg_check_modules(EGL egl)
pkg_check_modules(GLES glesv2)
set(VDPAU_FOUND FALSE)
set(VDPAU_ACCEL_FOUND FALSE)
set(VA_ACCEL_FOUND FALSE)
set(SOFTWARE_FOUND FALSE)
if(AVCODEC_FOUND AND AVUTIL_FOUND)
if(EGL_FOUND AND GLES_FOUND AND XLIB_FOUND)
set(X11_FOUND TRUE)
if(XLIB_FOUND AND LIBVA_FOUND)
set(VDPAU_FOUND TRUE)
if(VDPAU_FOUND)
set(VDPAU_ACCEL_FOUND TRUE)
endif()
if (LIBVA_FOUND AND LIBVA_X11_FOUND)
set(VA_ACCEL_FOUND TRUE)
endif()
endif()
if(SDL_FOUND OR X11_FOUND)
@ -61,11 +67,16 @@ if (SOFTWARE_FOUND)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_X11)
list(APPEND MOONLIGHT_OPTIONS X11)
endif()
if(VDPAU_FOUND)
if(VDPAU_ACCEL_FOUND)
list(APPEND SRC_LIST ./src/video/ffmpeg_vdpau.c)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_VDPAU)
list(APPEND MOONLIGHT_OPTIONS VDPAU)
endif()
if(VA_ACCEL_FOUND)
list(APPEND SRC_LIST ./src/video/ffmpeg_vaapi.c)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_VAAPI)
list(APPEND MOONLIGHT_OPTIONS VAAPI)
endif()
endif()
if (AMLOGIC_FOUND OR BROADCOM_FOUND OR FREESCALE_FOUND OR X11_FOUND)
@ -147,9 +158,13 @@ endif()
if (SOFTWARE_FOUND)
target_include_directories(moonlight PRIVATE ${AVCODEC_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS})
target_link_libraries(moonlight ${AVCODEC_LIBRARIES} ${AVUTIL_LIBRARIES})
if(VDPAU_FOUND)
target_include_directories(moonlight PRIVATE ${XLIB_INCLUDE_DIRS} ${LIBVA_INCLUDE_DIRS})
target_link_libraries(moonlight ${XLIB_LIBRARIES} ${LIBVA_LIBRARIES})
if(VDPAU_ACCEL_FOUND)
target_include_directories(moonlight PRIVATE ${VDPAU_INCLUDE_DIRS})
target_link_libraries(moonlight ${VDPAU_LIBRARIES})
endif()
if(VA_ACCEL_FOUND)
target_include_directories(moonlight PRIVATE ${LIBVA_INCLUDE_DIRS} ${LIBVA_X11_INCLUDE_DIRS})
target_link_libraries(moonlight ${LIBVA_LIBRARIES} ${LIBVA_X11_LIBRARIES})
endif()
endif()

View File

@ -60,10 +60,17 @@ enum platform platform_check(char* name) {
}
#endif
#ifdef HAVE_X11
if (std || strcmp(name, "x11") == 0 || strcmp(name, "x11_vdpau") == 0) {
int x11 = x11_init(strcmp(name, "x11") != 0);
bool x11 = strcmp(name, "x11") == 0;
bool vdpau = strcmp(name, "x11_vdpau") == 0;
bool vaapi = strcmp(name, "x11_vaapi") == 0;
if (std || x11 || vdpau || vaapi) {
int init = x11_init(std || vdpau, std || vaapi);
#ifdef HAVE_VAAPI
if (init == INIT_VAAPI)
return X11_VAAPI;
#endif
#ifdef HAVE_VDPAU
if (strcmp(name, "x11") != 0 && x11 == 0)
if (init == INIT_VDPAU)
return X11_VDPAU;
#endif
return X11;
@ -182,6 +189,8 @@ char* platform_name(enum platform system) {
return "AMLogic VPU";
case X11:
return "X Window System (software decoding)";
case X11_VAAPI:
return "X Window System (VAAPI)";
case X11_VDPAU:
return "X Window System (VDPAU)";
case SDL:

View File

@ -26,7 +26,7 @@
#define IS_EMBEDDED(SYSTEM) SYSTEM != SDL
enum platform { NONE, SDL, X11, X11_VDPAU, PI, IMX, AML, FAKE };
enum platform { NONE, SDL, X11, X11_VDPAU, X11_VAAPI, PI, IMX, AML, FAKE };
enum platform platform_check(char*);
PDECODER_RENDERER_CALLBACKS platform_get_video(enum platform system);

View File

@ -22,6 +22,9 @@
#ifdef HAVE_VDPAU
#include "ffmpeg_vdpau.h"
#endif
#ifdef HAVE_VAAPI
#include "ffmpeg_vaapi.h"
#endif
#include <Limelight.h>
@ -53,8 +56,7 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer
av_init_packet(&pkt);
#ifdef HAVE_VDPAU
if (perf_lvl & HARDWARE_ACCELERATION) {
if (perf_lvl & VDPAU_ACCELERATION) {
switch (videoFormat) {
case VIDEO_FORMAT_H264:
decoder = avcodec_find_decoder_by_name("h264_vdpau");
@ -64,13 +66,9 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer
break;
}
if (decoder != NULL)
ffmpeg_decoder = VDPAU;
}
#endif
if (decoder == NULL) {
ffmpeg_decoder = SOFTWARE;
} else {
ffmpeg_decoder = perf_lvl & VAAPI_ACCELERATION ? VAAPI : SOFTWARE;
switch (videoFormat) {
case VIDEO_FORMAT_H264:
decoder = avcodec_find_decoder_by_name("h264");
@ -79,11 +77,12 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer
decoder = avcodec_find_decoder_by_name("hevc");
break;
}
}
if (decoder == NULL) {
printf("Couldn't find decoder\n");
return -1;
}
}
decoder_ctx = avcodec_alloc_context3(decoder);
if (decoder_ctx == NULL) {
@ -131,6 +130,11 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer
}
}
#ifdef HAVE_VAAPI
if (ffmpeg_decoder == VAAPI)
vaapi_init(decoder_ctx);
#endif
#ifdef HAVE_VDPAU
if (ffmpeg_decoder == VDPAU)
vdpau_init(decoder_ctx, width, height);

View File

@ -34,9 +34,10 @@
// Uses a faster bilinear filtering with lower image quality
#define FAST_BILINEAR_FILTERING 0x20
// Uses hardware acceleration
#define HARDWARE_ACCELERATION 0x40
#define VDPAU_ACCELERATION 0x40
#define VAAPI_ACCELERATION 0x80
enum decoders {SOFTWARE, VDPAU};
enum decoders {SOFTWARE, VDPAU, VAAPI};
extern enum decoders ffmpeg_decoder;
int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count);

75
src/video/ffmpeg_vaapi.c Normal file
View File

@ -0,0 +1,75 @@
/*
* This file is part of Moonlight Embedded.
*
* Copyright (C) 2017 Iwan Timmer
*
* Moonlight is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Moonlight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
*/
#include <va/va.h>
#include <va/va_x11.h>
#include <libavcodec/avcodec.h>
#include <libavutil/hwcontext.h>
#include <libavutil/hwcontext_vaapi.h>
#include <X11/Xlib.h>
#define MAX_SURFACES 16
static AVBufferRef* device_ref;
static enum AVPixelFormat va_get_format(AVCodecContext* context, const enum AVPixelFormat* pixel_format) {
AVBufferRef* hw_ctx = av_hwframe_ctx_alloc(device_ref);
if (hw_ctx == NULL) {
fprintf(stderr, "Failed to initialize Vaapi buffer\n");
return AV_PIX_FMT_NONE;
}
AVHWFramesContext* fr_ctx = (AVHWFramesContext*) hw_ctx->data;
fr_ctx->format = AV_PIX_FMT_VAAPI;
fr_ctx->sw_format = AV_PIX_FMT_NV12;
fr_ctx->width = context->coded_width;
fr_ctx->height = context->coded_height;
fr_ctx->initial_pool_size = MAX_SURFACES + 1;
if (av_hwframe_ctx_init(hw_ctx) < 0) {
fprintf(stderr, "Failed to initialize VAAPI frame context");
return AV_PIX_FMT_NONE;
}
context->pix_fmt = AV_PIX_FMT_VAAPI;
context->hw_device_ctx = device_ref;
context->hw_frames_ctx = hw_ctx;
context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
return AV_PIX_FMT_VAAPI;
}
static int va_get_buffer(AVCodecContext* context, AVFrame* frame, int flags) {
return av_hwframe_get_buffer(context->hw_frames_ctx, frame, 0);
}
int vaapi_init_lib() {
return av_hwdevice_ctx_create(&device_ref, AV_HWDEVICE_TYPE_VAAPI, ":0", NULL, 0);
}
int vaapi_init(AVCodecContext* decoder_ctx) {
decoder_ctx->get_format = va_get_format;
decoder_ctx->get_buffer2 = va_get_buffer;
}
void vaapi_queue(AVFrame* dec_frame, Window win, int width, int height) {
VASurfaceID surface = (VASurfaceID)(uintptr_t)dec_frame->data[3];
AVHWDeviceContext* device = (AVHWDeviceContext*) device_ref->data;
AVVAAPIDeviceContext *va_ctx = device->hwctx;
vaPutSurface(va_ctx->display, surface, win, 0, 0, dec_frame->width, dec_frame->height, 0, 0, width, height, NULL, 0, 0);
}

24
src/video/ffmpeg_vaapi.h Normal file
View File

@ -0,0 +1,24 @@
/*
* This file is part of Moonlight Embedded.
*
* Copyright (C) 2017 Iwan Timmer
*
* Moonlight is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Moonlight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
*/
#include <va/va.h>
int vaapi_init_lib();
int vaapi_init(AVCodecContext* decoder_ctx);
void vaapi_queue(AVFrame* dec_frame, Window win, int width, int height);

View File

@ -22,11 +22,19 @@
#include <stdbool.h>
#define DISPLAY_FULLSCREEN 1
#define ENABLE_HARDWARE_ACCELERATION 2
#define ENABLE_HARDWARE_ACCELERATION_1 2
#define ENABLE_HARDWARE_ACCELERATION_2 4
#define INIT_EGL 1
#define INIT_VDPAU 2
#define INIT_VAAPI 3
#ifdef HAVE_X11
int x11_init(bool vdpau);
int x11_init(bool vdpau, bool vaapi);
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_x11;
#ifdef HAVE_VAAPI
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_x11_vaapi;
#endif
#ifdef HAVE_VDPAU
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_x11_vdpau;
#endif

View File

@ -23,6 +23,9 @@
#ifdef HAVE_VDPAU
#include "ffmpeg_vdpau.h"
#endif
#ifdef HAVE_VAAPI
#include "ffmpeg_vaapi.h"
#endif
#include "../input/x11.h"
#include "../loop.h"
@ -36,13 +39,19 @@
#include <poll.h>
#define DECODER_BUFFER_SIZE 92*1024
#define X11_VDPAU_ACCELERATION ENABLE_HARDWARE_ACCELERATION_1
#define X11_VAAPI_ACCELERATION ENABLE_HARDWARE_ACCELERATION_2
static char* ffmpeg_buffer = NULL;
static Display *display = NULL;
static Window window;
static int pipefd[2];
static int display_width;
static int display_height;
static int frame_handle(int pipefd) {
AVFrame* frame = NULL;
while (read(pipefd, &frame, sizeof(void*)) > 0);
@ -52,18 +61,23 @@ static int frame_handle(int pipefd) {
return LOOP_OK;
}
int x11_init(bool vdpau) {
int x11_init(bool vdpau, bool vaapi) {
XInitThreads();
display = XOpenDisplay(NULL);
if (!display)
return -1;
return 0;
#ifdef HAVE_VDPAU
if (vdpau && vdpau_init_lib(display) != 0)
return -2;
#ifdef HAVE_VAAPI
if (vaapi && vaapi_init_lib(display) == 0)
return INIT_VAAPI;
#endif
return 0;
#ifdef HAVE_VDPAU
if (vdpau && vdpau_init_lib(display) == 0)
return INIT_VDPAU;
#endif
return INIT_EGL;
}
int x11_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
@ -78,8 +92,6 @@ int x11_setup(int videoFormat, int width, int height, int redrawRate, void* cont
return -1;
}
int display_width;
int display_height;
if (drFlags & DISPLAY_FULLSCREEN) {
Screen* screen = DefaultScreenOfDisplay(display);
display_width = WidthOfScreen(screen);
@ -91,7 +103,7 @@ int x11_setup(int videoFormat, int width, int height, int redrawRate, void* cont
Window root = DefaultRootWindow(display);
XSetWindowAttributes winattr = { .event_mask = PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask };
Window window = XCreateWindow(display, root, 0, 0, display_width, display_height, 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask, &winattr);
window = XCreateWindow(display, root, 0, 0, display_width, display_height, 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask, &winattr);
XMapWindow(display, window);
XStoreName(display, window, "Moonlight");
@ -113,10 +125,10 @@ int x11_setup(int videoFormat, int width, int height, int redrawRate, void* cont
XFlush(display);
int avc_flags = SLICE_THREADING;
#ifdef HAVE_VDPAU
if (drFlags & ENABLE_HARDWARE_ACCELERATION)
avc_flags |= HARDWARE_ACCELERATION;
#endif
if (drFlags & X11_VDPAU_ACCELERATION)
avc_flags |= VDPAU_ACCELERATION;
else if (drFlags & X11_VAAPI_ACCELERATION)
avc_flags |= VAAPI_ACCELERATION;
if (ffmpeg_init(videoFormat, width, height, avc_flags, 2, 2) < 0) {
fprintf(stderr, "Couldn't initialize video decoding\n");
@ -143,7 +155,11 @@ int x11_setup(int videoFormat, int width, int height, int redrawRate, void* cont
}
int x11_setup_vdpau(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
return x11_setup(videoFormat, width, height, redrawRate, context, drFlags | ENABLE_HARDWARE_ACCELERATION);
return x11_setup(videoFormat, width, height, redrawRate, context, drFlags | X11_VDPAU_ACCELERATION);
}
int x11_setup_vaapi(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
return x11_setup(videoFormat, width, height, redrawRate, context, drFlags | X11_VAAPI_ACCELERATION);
}
void x11_cleanup() {
@ -167,6 +183,8 @@ int x11_submit_decode_unit(PDECODE_UNIT decodeUnit) {
write(pipefd[1], &frame, sizeof(void*));
else if (ffmpeg_decoder == VDPAU)
vdpau_queue(frame);
else if (ffmpeg_decoder == VAAPI)
vaapi_queue(frame, window, display_width, display_height);
}
}
@ -186,3 +204,10 @@ DECODER_RENDERER_CALLBACKS decoder_callbacks_x11_vdpau = {
.submitDecodeUnit = x11_submit_decode_unit,
.capabilities = CAPABILITY_DIRECT_SUBMIT,
};
DECODER_RENDERER_CALLBACKS decoder_callbacks_x11_vaapi = {
.setup = x11_setup_vaapi,
.cleanup = x11_cleanup,
.submitDecodeUnit = x11_submit_decode_unit,
.capabilities = CAPABILITY_SLICES_PER_FRAME(4) | CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC | CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC | CAPABILITY_DIRECT_SUBMIT,
};