mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2026-02-16 02:20:42 +00:00
Use VDPAU video output in X11
This commit is contained in:
@@ -40,14 +40,13 @@ static AVFrame** dec_frames;
|
||||
static int dec_frames_cnt;
|
||||
static int current_frame, next_frame;
|
||||
|
||||
enum decoders {SOFTWARE, VDPAU};
|
||||
enum decoders decoder_system;
|
||||
enum decoders ffmpeg_decoder;
|
||||
|
||||
#define BYTES_PER_PIXEL 4
|
||||
|
||||
// This function must be called before
|
||||
// any other decoding functions
|
||||
int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count) {
|
||||
int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count, void* context) {
|
||||
// Initialize the avcodec library and register codecs
|
||||
av_log_set_level(AV_LOG_QUIET);
|
||||
avcodec_register_all();
|
||||
@@ -66,12 +65,12 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer
|
||||
}
|
||||
|
||||
if (decoder != NULL)
|
||||
decoder_system = VDPAU;
|
||||
ffmpeg_decoder = VDPAU;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (decoder == NULL) {
|
||||
decoder_system = SOFTWARE;
|
||||
ffmpeg_decoder = SOFTWARE;
|
||||
switch (videoFormat) {
|
||||
case VIDEO_FORMAT_H264:
|
||||
decoder = avcodec_find_decoder_by_name("h264");
|
||||
@@ -133,8 +132,8 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer
|
||||
}
|
||||
|
||||
#ifdef HAVE_VDPAU
|
||||
if (decoder_system == VDPAU)
|
||||
vdpau_init(decoder_ctx, width, height);
|
||||
if (ffmpeg_decoder == VDPAU)
|
||||
vdpau_init(decoder_ctx, (Display*) context, width, height);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -156,16 +155,16 @@ void ffmpeg_destroy(void) {
|
||||
}
|
||||
}
|
||||
|
||||
AVFrame* ffmpeg_get_frame() {
|
||||
AVFrame* ffmpeg_get_frame(bool native_frame) {
|
||||
int err = avcodec_receive_frame(decoder_ctx, dec_frames[next_frame]);
|
||||
if (err == 0) {
|
||||
current_frame = next_frame;
|
||||
next_frame = (current_frame+1) % dec_frames_cnt;
|
||||
|
||||
if (decoder_system == SOFTWARE)
|
||||
if (ffmpeg_decoder == SOFTWARE || native_frame)
|
||||
return dec_frames[current_frame];
|
||||
#ifdef HAVE_VDPAU
|
||||
else if (decoder_system == VDPAU)
|
||||
else if (ffmpeg_decoder == VDPAU)
|
||||
return vdpau_get_frame(dec_frames[current_frame]);
|
||||
#endif
|
||||
} else if (err != AVERROR(EAGAIN)) {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
// Disables the deblocking filter at the cost of image quality
|
||||
@@ -34,9 +36,12 @@
|
||||
// Uses hardware acceleration
|
||||
#define HARDWARE_ACCELERATION 0x40
|
||||
|
||||
int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count);
|
||||
enum decoders {SOFTWARE, VDPAU};
|
||||
extern enum decoders ffmpeg_decoder;
|
||||
|
||||
int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count, void* context);
|
||||
void ffmpeg_destroy(void);
|
||||
|
||||
int ffmpeg_draw_frame(AVFrame *pict);
|
||||
AVFrame* ffmpeg_get_frame();
|
||||
AVFrame* ffmpeg_get_frame(bool native_frame);
|
||||
int ffmpeg_decode(unsigned char* indata, int inlen);
|
||||
|
||||
@@ -34,6 +34,9 @@ static AVFrame* cpu_frame;
|
||||
static VdpDevice vdp_device;
|
||||
static VdpDecoder vdp_decoder;
|
||||
static VdpVideoMixer vdp_mixer;
|
||||
static VdpPresentationQueue vdp_queue;
|
||||
static VdpPresentationQueueTarget vdp_queue_target;
|
||||
static VdpOutputSurface vdp_output;
|
||||
static struct vdpau_render_state* vdp_render_state[MAX_RENDER_STATES];
|
||||
static int vdp_render_states = 0;
|
||||
|
||||
@@ -43,8 +46,13 @@ static VdpDecoderRender* vdp_decoder_render;
|
||||
static VdpVideoSurfaceGetBitsYCbCr* vdp_video_surface_get_bits_y_cb_cr;
|
||||
static VdpVideoSurfaceCreate* vdp_video_surface_create;
|
||||
static VdpVideoMixerCreate* vdp_video_mixer_create;
|
||||
static VdpVideoMixerRender* vdp_video_mixer_render;
|
||||
static VdpOutputSurfaceCreate* vdp_output_surface_create;
|
||||
static VdpPresentationQueueCreate* vdp_presentation_queue_create;
|
||||
static VdpPresentationQueueDisplay* vdp_presentation_queue_display;
|
||||
static VdpPresentationQueueTargetCreateX11* vdp_presentation_queue_target_create_x11;
|
||||
|
||||
struct vdpau_render_state* vdp_get_free_render_state() {
|
||||
struct vdpau_render_state* vdp_get_free_render_state(int width, int height) {
|
||||
for (unsigned i = 0; i < vdp_render_states; i++) {
|
||||
struct vdpau_render_state* render_state = vdp_render_state[i];
|
||||
if (!render_state->state)
|
||||
@@ -60,7 +68,7 @@ struct vdpau_render_state* vdp_get_free_render_state() {
|
||||
vdp_render_states++;
|
||||
memset(render_state, 0, sizeof(struct vdpau_render_state));
|
||||
render_state->surface = VDP_INVALID_HANDLE;
|
||||
VdpStatus status = vdp_video_surface_create(vdp_device, VDP_CHROMA_TYPE_420, 1280, 720, &render_state->surface);
|
||||
VdpStatus status = vdp_video_surface_create(vdp_device, VDP_CHROMA_TYPE_420, width, height, &render_state->surface);
|
||||
return render_state;
|
||||
}
|
||||
|
||||
@@ -70,7 +78,7 @@ static void vdp_release_buffer(void* opaque, uint8_t *data) {
|
||||
}
|
||||
|
||||
static int vdp_get_buffer(AVCodecContext* context, AVFrame* frame, int flags) {
|
||||
struct vdpau_render_state* pRenderState = vdp_get_free_render_state();
|
||||
struct vdpau_render_state* pRenderState = vdp_get_free_render_state(frame->width, frame->height);
|
||||
frame->data[0] = (uint8_t*) pRenderState;
|
||||
frame->buf[0] = av_buffer_create(frame->data[0], 0, vdp_release_buffer, NULL, 0);
|
||||
|
||||
@@ -89,23 +97,27 @@ static void vdp_draw_horiz_band(struct AVCodecContext* context, const AVFrame* f
|
||||
status = vdp_decoder_render(vdp_decoder, render_state->surface, (VdpPictureInfo const*)&(render_state->info), render_state->bitstream_buffers_used, render_state->bitstream_buffers);
|
||||
}
|
||||
|
||||
int vdpau_init(AVCodecContext* decoder_ctx, int width, int height) {
|
||||
int vdpau_init(AVCodecContext* decoder_ctx, Display* display, int width, int height) {
|
||||
if (vdp_device)
|
||||
return vdp_device;
|
||||
|
||||
Display* xdisplay = XOpenDisplay(0);
|
||||
if (!xdisplay)
|
||||
return -1;
|
||||
if (!display)
|
||||
display = XOpenDisplay(NULL);
|
||||
|
||||
VdpStatus status = vdp_device_create_x11(xdisplay, DefaultScreen(xdisplay), &vdp_device, &vdp_get_proc_address);
|
||||
VdpStatus status = vdp_device_create_x11(display, DefaultScreen(display), &vdp_device, &vdp_get_proc_address);
|
||||
if (status != VDP_STATUS_OK)
|
||||
return -1;
|
||||
|
||||
vdp_get_proc_address(vdp_device, VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, (void**)&vdp_video_surface_get_bits_y_cb_cr);
|
||||
vdp_get_proc_address(vdp_device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE, (void**)&vdp_video_surface_create);
|
||||
vdp_get_proc_address(vdp_device, VDP_FUNC_ID_OUTPUT_SURFACE_CREATE, (void**)&vdp_output_surface_create);
|
||||
vdp_get_proc_address(vdp_device, VDP_FUNC_ID_DECODER_RENDER, (void**)&vdp_decoder_render);
|
||||
vdp_get_proc_address(vdp_device, VDP_FUNC_ID_DECODER_CREATE, (void**)&vdp_decoder_create);
|
||||
vdp_get_proc_address(vdp_device, VDP_FUNC_ID_VIDEO_MIXER_CREATE, (void**)&vdp_video_mixer_create);
|
||||
vdp_get_proc_address(vdp_device, VDP_FUNC_ID_VIDEO_MIXER_RENDER, (void**)&vdp_video_mixer_render);
|
||||
vdp_get_proc_address(vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE, (void**)&vdp_presentation_queue_create);
|
||||
vdp_get_proc_address(vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11, (void**)&vdp_presentation_queue_target_create_x11);
|
||||
vdp_get_proc_address(vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY, (void**)&vdp_presentation_queue_display);
|
||||
|
||||
decoder_ctx->get_buffer2 = vdp_get_buffer;
|
||||
decoder_ctx->draw_horiz_band = vdp_draw_horiz_band;
|
||||
@@ -153,6 +165,8 @@ int vdpau_init(AVCodecContext* decoder_ctx, int width, int height) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, width, height, &vdp_output);
|
||||
|
||||
return vdp_device;
|
||||
}
|
||||
|
||||
@@ -172,3 +186,21 @@ AVFrame* vdpau_get_frame(AVFrame* dec_frame) {
|
||||
VdpStatus status = vdp_video_surface_get_bits_y_cb_cr(render_state->surface, VDP_YCBCR_FORMAT_YV12, dest, pitches);
|
||||
return cpu_frame;
|
||||
}
|
||||
|
||||
int vdpau_init_queue(Drawable win) {
|
||||
if(vdp_presentation_queue_target_create_x11(vdp_device, win, &vdp_queue_target) != VDP_STATUS_OK)
|
||||
return -1;
|
||||
|
||||
if(vdp_presentation_queue_create(vdp_device, vdp_queue_target, &vdp_queue) != VDP_STATUS_OK)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vdpau_queue(AVFrame* dec_frame) {
|
||||
struct vdpau_render_state *render_state = (struct vdpau_render_state *)dec_frame->data[0];
|
||||
int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
|
||||
vdp_video_mixer_render(vdp_mixer, VDP_INVALID_HANDLE, 0, field, 0, (VdpVideoSurface*)VDP_INVALID_HANDLE, render_state->surface, 0,(VdpVideoSurface*)VDP_INVALID_HANDLE, NULL, vdp_output, NULL, NULL, 0, NULL);
|
||||
|
||||
vdp_presentation_queue_display(vdp_queue, vdp_output, 0, 0, 0);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
int vdpau_init(AVCodecContext* decoder_ctx, int width, int height);
|
||||
int vdpau_init(AVCodecContext* decoder_ctx, Display* display, int width, int height);
|
||||
AVFrame* vdpau_get_frame(AVFrame* dec_frame);
|
||||
int vdpau_init_queue(Drawable win);
|
||||
void vdpau_queue(AVFrame* dec_frame);
|
||||
|
||||
@@ -37,7 +37,7 @@ static int sdl_setup(int videoFormat, int width, int height, int redrawRate, voi
|
||||
if (drFlags & FORCE_HARDWARE_ACCELERATION)
|
||||
avc_flags |= HARDWARE_ACCELERATION;
|
||||
|
||||
if (ffmpeg_init(videoFormat, width, height, avc_flags, SDL_BUFFER_FRAMES, sysconf(_SC_NPROCESSORS_ONLN)) < 0) {
|
||||
if (ffmpeg_init(videoFormat, width, height, avc_flags, SDL_BUFFER_FRAMES, sysconf(_SC_NPROCESSORS_ONLN), NULL) < 0) {
|
||||
fprintf(stderr, "Couldn't initialize video decoding\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -68,7 +68,7 @@ static int sdl_submit_decode_unit(PDECODE_UNIT decodeUnit) {
|
||||
ffmpeg_decode(ffmpeg_buffer, length);
|
||||
|
||||
if (SDL_LockMutex(mutex) == 0) {
|
||||
AVFrame* frame = ffmpeg_get_frame();
|
||||
AVFrame* frame = ffmpeg_get_frame(false);
|
||||
if (frame != NULL) {
|
||||
sdlNextFrame++;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "video.h"
|
||||
#include "egl.h"
|
||||
#include "ffmpeg.h"
|
||||
#include "ffmpeg_vdpau.h"
|
||||
|
||||
#include "../input/x11.h"
|
||||
#include "../loop.h"
|
||||
@@ -54,11 +55,6 @@ int x11_setup(int videoFormat, int width, int height, int redrawRate, void* cont
|
||||
if (drFlags & FORCE_HARDWARE_ACCELERATION)
|
||||
avc_flags |= HARDWARE_ACCELERATION;
|
||||
|
||||
if (ffmpeg_init(videoFormat, width, height, avc_flags, 2, 2) < 0) {
|
||||
fprintf(stderr, "Couldn't initialize video decoding\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ffmpeg_buffer = malloc(DECODER_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (ffmpeg_buffer == NULL) {
|
||||
fprintf(stderr, "Not enough memory\n");
|
||||
@@ -95,7 +91,16 @@ int x11_setup(int videoFormat, int width, int height, int redrawRate, void* cont
|
||||
XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
|
||||
}
|
||||
|
||||
egl_init(display, window, width, height);
|
||||
if (ffmpeg_init(videoFormat, width, height, avc_flags, 2, 2, display) < 0) {
|
||||
fprintf(stderr, "Couldn't initialize video decoding\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ffmpeg_decoder == SOFTWARE)
|
||||
egl_init(display, window, width, height);
|
||||
else
|
||||
vdpau_init_queue(window);
|
||||
|
||||
x11_input_init(display, window);
|
||||
|
||||
if (pipe(pipefd) == -1) {
|
||||
@@ -123,10 +128,13 @@ int x11_submit_decode_unit(PDECODE_UNIT decodeUnit) {
|
||||
entry = entry->next;
|
||||
}
|
||||
ffmpeg_decode(ffmpeg_buffer, length);
|
||||
AVFrame* frame = ffmpeg_get_frame();
|
||||
AVFrame* frame = ffmpeg_get_frame(true);
|
||||
if (frame != NULL) {
|
||||
void* pointer = frame->data;
|
||||
write(pipefd[1], &pointer, sizeof(void*));
|
||||
if (ffmpeg_decoder == SOFTWARE) {
|
||||
void* pointer = frame->data;
|
||||
write(pipefd[1], &pointer, sizeof(void*));
|
||||
} else
|
||||
vdpau_queue(frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user