aboutsummaryrefslogtreecommitdiff
path: root/src/encoder/video/vaapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/encoder/video/vaapi.c')
-rw-r--r--src/encoder/video/vaapi.c108
1 files changed, 68 insertions, 40 deletions
diff --git a/src/encoder/video/vaapi.c b/src/encoder/video/vaapi.c
index 2df140d..d558785 100644
--- a/src/encoder/video/vaapi.c
+++ b/src/encoder/video/vaapi.c
@@ -4,17 +4,20 @@
#include <libavcodec/avcodec.h>
#include <libavutil/hwcontext_vaapi.h>
+#include <libavutil/intreadwrite.h>
#include <va/va_drmcommon.h>
#include <stdlib.h>
#include <unistd.h>
+#include <fcntl.h>
typedef struct {
gsr_video_encoder_vaapi_params params;
unsigned int target_textures[2];
+ AVBufferRef *device_ctx;
VADisplay va_dpy;
VADRMPRIMESurfaceDescriptor prime;
} gsr_video_encoder_vaapi;
@@ -26,43 +29,40 @@ static bool gsr_video_encoder_vaapi_setup_context(gsr_video_encoder_vaapi *self,
return false;
}
- AVBufferRef *device_ctx;
- if(av_hwdevice_ctx_create(&device_ctx, AV_HWDEVICE_TYPE_VAAPI, render_path, NULL, 0) < 0) {
+ if(av_hwdevice_ctx_create(&self->device_ctx, AV_HWDEVICE_TYPE_VAAPI, render_path, NULL, 0) < 0) {
fprintf(stderr, "gsr error: gsr_video_encoder_vaapi_setup_context: failed to create hardware device context\n");
return false;
}
- AVBufferRef *frame_context = av_hwframe_ctx_alloc(device_ctx);
+ AVBufferRef *frame_context = av_hwframe_ctx_alloc(self->device_ctx);
if(!frame_context) {
fprintf(stderr, "gsr error: gsr_video_encoder_vaapi_setup_context: failed to create hwframe context\n");
- av_buffer_unref(&device_ctx);
+ av_buffer_unref(&self->device_ctx);
return false;
}
- AVHWFramesContext *hw_frame_context =
- (AVHWFramesContext *)frame_context->data;
+ AVHWFramesContext *hw_frame_context = (AVHWFramesContext*)frame_context->data;
hw_frame_context->width = video_codec_context->width;
hw_frame_context->height = video_codec_context->height;
- hw_frame_context->sw_format = self->params.hdr ? AV_PIX_FMT_P010LE : AV_PIX_FMT_NV12;
+ hw_frame_context->sw_format = self->params.color_depth == GSR_COLOR_DEPTH_10_BITS ? AV_PIX_FMT_P010LE : AV_PIX_FMT_NV12;
hw_frame_context->format = video_codec_context->pix_fmt;
- hw_frame_context->device_ref = device_ctx;
- hw_frame_context->device_ctx = (AVHWDeviceContext*)device_ctx->data;
+ hw_frame_context->device_ctx = (AVHWDeviceContext*)self->device_ctx->data;
//hw_frame_context->initial_pool_size = 20;
- AVVAAPIDeviceContext *vactx =((AVHWDeviceContext*)device_ctx->data)->hwctx;
+ AVVAAPIDeviceContext *vactx = ((AVHWDeviceContext*)self->device_ctx->data)->hwctx;
self->va_dpy = vactx->display;
if (av_hwframe_ctx_init(frame_context) < 0) {
fprintf(stderr, "gsr error: gsr_video_encoder_vaapi_setup_context: failed to initialize hardware frame context "
"(note: ffmpeg version needs to be > 4.0)\n");
- av_buffer_unref(&device_ctx);
+ av_buffer_unref(&self->device_ctx);
//av_buffer_unref(&frame_context);
return false;
}
- video_codec_context->hw_device_ctx = av_buffer_ref(device_ctx);
video_codec_context->hw_frames_ctx = av_buffer_ref(frame_context);
+ av_buffer_unref(&frame_context);
return true;
}
@@ -96,20 +96,22 @@ static bool gsr_video_encoder_vaapi_setup_textures(gsr_video_encoder_vaapi *self
self->params.egl->glGenTextures(2, self->target_textures);
for(int i = 0; i < 2; ++i) {
const int layer = i;
- const int plane = 0;
-
- const uint64_t modifier = self->prime.objects[self->prime.layers[layer].object_index[plane]].drm_format_modifier;
- const intptr_t img_attr[] = {
- EGL_LINUX_DRM_FOURCC_EXT, formats[i],
- EGL_WIDTH, self->prime.width / div[i],
- EGL_HEIGHT, self->prime.height / div[i],
- EGL_DMA_BUF_PLANE0_FD_EXT, self->prime.objects[self->prime.layers[layer].object_index[plane]].fd,
- EGL_DMA_BUF_PLANE0_OFFSET_EXT, self->prime.layers[layer].offset[plane],
- EGL_DMA_BUF_PLANE0_PITCH_EXT, self->prime.layers[layer].pitch[plane],
- EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, modifier & 0xFFFFFFFFULL,
- EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, modifier >> 32ULL,
- EGL_NONE
- };
+
+ int fds[4];
+ uint32_t offsets[4];
+ uint32_t pitches[4];
+ uint64_t modifiers[4];
+ for(uint32_t j = 0; j < self->prime.layers[layer].num_planes; ++j) {
+ // TODO: Close these? in _stop, using self->prime
+ fds[j] = self->prime.objects[self->prime.layers[layer].object_index[j]].fd;
+ offsets[j] = self->prime.layers[layer].offset[j];
+ pitches[j] = self->prime.layers[layer].pitch[j];
+ modifiers[j] = self->prime.objects[self->prime.layers[layer].object_index[j]].drm_format_modifier;
+ }
+
+ intptr_t img_attr[44];
+ setup_dma_buf_attrs(img_attr, formats[i], self->prime.width / div[i], self->prime.height / div[i],
+ fds, offsets, pitches, modifiers, self->prime.layers[layer].num_planes, true);
while(self->params.egl->eglGetError() != EGL_SUCCESS){}
EGLImage image = self->params.egl->eglCreateImage(self->params.egl->egl_display, 0, EGL_LINUX_DMA_BUF_EXT, NULL, img_attr);
@@ -149,13 +151,13 @@ static bool gsr_video_encoder_vaapi_setup_textures(gsr_video_encoder_vaapi *self
static void gsr_video_encoder_vaapi_stop(gsr_video_encoder_vaapi *self, AVCodecContext *video_codec_context);
static bool gsr_video_encoder_vaapi_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) {
- gsr_video_encoder_vaapi *encoder_vaapi = encoder->priv;
+ gsr_video_encoder_vaapi *self = encoder->priv;
- if(encoder_vaapi->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_AMD && video_codec_context->codec_id == AV_CODEC_ID_HEVC) {
+ if(self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_AMD && video_codec_context->codec_id == AV_CODEC_ID_HEVC) {
// TODO: dont do this if using ffmpeg reports that this is not needed (AMD driver bug that was fixed recently)
video_codec_context->width = FFALIGN(video_codec_context->width, 64);
video_codec_context->height = FFALIGN(video_codec_context->height, 16);
- } else if(encoder_vaapi->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_AMD && video_codec_context->codec_id == AV_CODEC_ID_AV1) {
+ } else if(self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_AMD && video_codec_context->codec_id == AV_CODEC_ID_AV1) {
// TODO: Dont do this for VCN 5 and forward which should fix this hardware bug
video_codec_context->width = FFALIGN(video_codec_context->width, 64);
// AMD driver has special case handling for 1080 height to set it to 1082 instead of 1088 (1080 aligned to 16).
@@ -167,13 +169,40 @@ static bool gsr_video_encoder_vaapi_start(gsr_video_encoder *encoder, AVCodecCon
}
}
- if(!gsr_video_encoder_vaapi_setup_context(encoder_vaapi, video_codec_context)) {
- gsr_video_encoder_vaapi_stop(encoder_vaapi, video_codec_context);
+ const int crop_top = (video_codec_context->height - frame->height) / 2;
+ const int crop_left = (video_codec_context->width - frame->width) / 2;
+ if(crop_top != 0 || crop_left != 0) {
+ fprintf(stderr, "gsr warning: gsr_video_encoder_vaapi_start: black bars have been added to the video because of a bug in AMD drivers/hardware. Record with h264 codec instead (-k h264) to get around this issue\n");
+#if 0
+ #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 10, 100)
+ const int crop_bottom = crop_top;
+ const int crop_right = crop_left;
+ fprintf(stderr, "gsr info: cropping metadata has been added to the file to try and workaround this issue. Video players that support this will remove the black bars when the video is playing\n");
+ const int frame_cropping_data_size = 4 * sizeof(uint32_t);
+ uint8_t *frame_cropping = av_malloc(frame_cropping_data_size);
+ if(frame_cropping) {
+ AV_WL32(frame_cropping + 0, crop_top);
+ AV_WL32(frame_cropping + 4, crop_bottom);
+ AV_WL32(frame_cropping + 8, crop_left);
+ AV_WL32(frame_cropping + 12, crop_right);
+ const bool sidedata_added = av_packet_side_data_add(&video_stream->codecpar->coded_side_data, &video_stream->codecpar->nb_coded_side_data, AV_PKT_DATA_FRAME_CROPPING, frame_cropping, frame_cropping_data_size, 0) != NULL;
+ if(!sidedata_added)
+ av_free(frame_cropping);
+ }
+ #endif
+#endif
+ }
+
+ frame->width = video_codec_context->width;
+ frame->height = video_codec_context->height;
+
+ if(!gsr_video_encoder_vaapi_setup_context(self, video_codec_context)) {
+ gsr_video_encoder_vaapi_stop(self, video_codec_context);
return false;
}
- if(!gsr_video_encoder_vaapi_setup_textures(encoder_vaapi, video_codec_context, frame)) {
- gsr_video_encoder_vaapi_stop(encoder_vaapi, video_codec_context);
+ if(!gsr_video_encoder_vaapi_setup_textures(self, video_codec_context, frame)) {
+ gsr_video_encoder_vaapi_stop(self, video_codec_context);
return false;
}
@@ -185,10 +214,10 @@ void gsr_video_encoder_vaapi_stop(gsr_video_encoder_vaapi *self, AVCodecContext
self->target_textures[0] = 0;
self->target_textures[1] = 0;
- if(video_codec_context->hw_device_ctx)
- av_buffer_unref(&video_codec_context->hw_device_ctx);
if(video_codec_context->hw_frames_ctx)
av_buffer_unref(&video_codec_context->hw_frames_ctx);
+ if(self->device_ctx)
+ av_buffer_unref(&self->device_ctx);
for(uint32_t i = 0; i < self->prime.num_objects; ++i) {
if(self->prime.objects[i].fd > 0) {
@@ -199,11 +228,11 @@ void gsr_video_encoder_vaapi_stop(gsr_video_encoder_vaapi *self, AVCodecContext
}
static void gsr_video_encoder_vaapi_get_textures(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color) {
- gsr_video_encoder_vaapi *encoder_vaapi = encoder->priv;
- textures[0] = encoder_vaapi->target_textures[0];
- textures[1] = encoder_vaapi->target_textures[1];
+ gsr_video_encoder_vaapi *self = encoder->priv;
+ textures[0] = self->target_textures[0];
+ textures[1] = self->target_textures[1];
*num_textures = 2;
- *destination_color = encoder_vaapi->params.hdr ? GSR_DESTINATION_COLOR_P010 : GSR_DESTINATION_COLOR_NV12;
+ *destination_color = self->params.color_depth == GSR_COLOR_DEPTH_10_BITS ? GSR_DESTINATION_COLOR_P010 : GSR_DESTINATION_COLOR_NV12;
}
static void gsr_video_encoder_vaapi_destroy(gsr_video_encoder *encoder, AVCodecContext *video_codec_context) {
@@ -227,7 +256,6 @@ gsr_video_encoder* gsr_video_encoder_vaapi_create(const gsr_video_encoder_vaapi_
*encoder = (gsr_video_encoder) {
.start = gsr_video_encoder_vaapi_start,
- .copy_textures_to_frame = NULL,
.get_textures = gsr_video_encoder_vaapi_get_textures,
.destroy = gsr_video_encoder_vaapi_destroy,
.priv = encoder_vaapi