From f8f2e1fd41b6f8cde6940db3f9c65ca4a329d499 Mon Sep 17 00:00:00 2001 From: GloriousEggroll Date: Sat, 1 Apr 2023 16:57:18 -0600 Subject: [PATCH] remove ffmpeg vaapi encoder (we replace it with obs-vaapi plugin which uses gstreamer) --- plugins/obs-ffmpeg/CMakeLists.txt | 2 +- plugins/obs-ffmpeg/cmake/legacy.cmake | 2 +- plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c | 1009 ------------------------- plugins/obs-ffmpeg/obs-ffmpeg.c | 59 -- 4 files changed, 2 insertions(+), 1070 deletions(-) delete mode 100644 plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c diff --git a/plugins/obs-ffmpeg/CMakeLists.txt b/plugins/obs-ffmpeg/CMakeLists.txt index 2d07960..0632896 100644 --- a/plugins/obs-ffmpeg/CMakeLists.txt +++ b/plugins/obs-ffmpeg/CMakeLists.txt @@ -114,7 +114,7 @@ elseif(OS_LINUX OR OS_FREEBSD) find_package(Libpci REQUIRED) find_package(Vulkan REQUIRED) - target_sources(obs-ffmpeg PRIVATE obs-ffmpeg-vaapi.c vaapi-utils.c vaapi-utils.h texture-amf.cpp) + target_sources(obs-ffmpeg PRIVATE vaapi-utils.c vaapi-utils.h texture-amf.cpp) target_link_libraries(obs-ffmpeg PRIVATE Libva::va Libva::drm Libpci::pci Vulkan::Vulkan) endif() diff --git a/plugins/obs-ffmpeg/cmake/legacy.cmake b/plugins/obs-ffmpeg/cmake/legacy.cmake index b29eef6..4b92825 100644 --- a/plugins/obs-ffmpeg/cmake/legacy.cmake +++ b/plugins/obs-ffmpeg/cmake/legacy.cmake @@ -110,7 +110,7 @@ elseif(OS_POSIX AND NOT OS_MACOS) find_package(Libva REQUIRED) find_package(Libpci REQUIRED) find_package(Vulkan REQUIRED) - target_sources(obs-ffmpeg PRIVATE obs-ffmpeg-vaapi.c vaapi-utils.c vaapi-utils.h texture-amf.cpp) + target_sources(obs-ffmpeg PRIVATE vaapi-utils.c vaapi-utils.h texture-amf.cpp) target_link_libraries(obs-ffmpeg PRIVATE Libva::va Libva::drm LIBPCI::LIBPCI Vulkan::Vulkan) endif() diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c deleted file mode 100644 index 79c7f3f..0000000 --- a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c +++ /dev/null @@ -1,1009 +0,0 @@ -/****************************************************************************** - Copyright (C) 2016 by Hugh Bailey - - This program 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 2 of the License, or - (at your option) any later version. - - This program 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 this program. If not, see . -******************************************************************************/ - -#include - -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 27, 100) - -#include -#include -#include -#include -#include -#include -#include -#ifdef ENABLE_HEVC -#include -#endif - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "vaapi-utils.h" -#include "obs-ffmpeg-formats.h" - -#define do_log(level, format, ...) \ - blog(level, "[FFmpeg VAAPI encoder: '%s'] " format, \ - obs_encoder_get_name(enc->encoder), ##__VA_ARGS__) - -#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) -#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__) -#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__) - -struct vaapi_encoder { - obs_encoder_t *encoder; - - AVBufferRef *vadevice_ref; - AVBufferRef *vaframes_ref; - - const AVCodec *vaapi; - AVCodecContext *context; - - AVPacket *packet; - - AVFrame *vframe; - - DARRAY(uint8_t) buffer; - - uint8_t *header; - size_t header_size; - - uint8_t *sei; - size_t sei_size; - - int height; - bool first_packet; - bool initialized; -}; - -static const char *h264_vaapi_getname(void *unused) -{ - UNUSED_PARAMETER(unused); - return "FFmpeg VAAPI H.264"; -} - -#ifdef ENABLE_HEVC -static const char *hevc_vaapi_getname(void *unused) -{ - UNUSED_PARAMETER(unused); - return "FFmpeg VAAPI HEVC"; -} -#endif - -static inline bool h264_valid_format(enum video_format format) -{ - return format == VIDEO_FORMAT_NV12; -} - -#ifdef ENABLE_HEVC -static inline bool hevc_valid_format(enum video_format format) -{ - return (format == VIDEO_FORMAT_NV12) || (format == VIDEO_FORMAT_P010); -} -#endif - -static void h264_vaapi_video_info(void *data, struct video_scale_info *info) -{ - struct vaapi_encoder *enc = data; - enum video_format pref_format; - - pref_format = obs_encoder_get_preferred_video_format(enc->encoder); - - if (!h264_valid_format(pref_format)) { - pref_format = h264_valid_format(info->format) - ? info->format - : VIDEO_FORMAT_NV12; - } - - info->format = pref_format; -} - -#ifdef ENABLE_HEVC -static void hevc_vaapi_video_info(void *data, struct video_scale_info *info) -{ - struct vaapi_encoder *enc = data; - enum video_format pref_format; - - pref_format = obs_encoder_get_preferred_video_format(enc->encoder); - - if (!hevc_valid_format(pref_format)) { - pref_format = hevc_valid_format(info->format) - ? info->format - : VIDEO_FORMAT_NV12; - } - - info->format = pref_format; -} -#endif - -static bool vaapi_init_codec(struct vaapi_encoder *enc, const char *path) -{ - int ret; - - ret = av_hwdevice_ctx_create(&enc->vadevice_ref, AV_HWDEVICE_TYPE_VAAPI, - path, NULL, 0); - if (ret < 0) { - warn("Failed to create VAAPI device context: %s", - av_err2str(ret)); - return false; - } - - enc->vaframes_ref = av_hwframe_ctx_alloc(enc->vadevice_ref); - if (!enc->vaframes_ref) { - warn("Failed to alloc HW frames context"); - return false; - } - - AVHWFramesContext *frames_ctx = - (AVHWFramesContext *)enc->vaframes_ref->data; - frames_ctx->format = AV_PIX_FMT_VAAPI; - frames_ctx->sw_format = enc->context->pix_fmt; - frames_ctx->width = enc->context->width; - frames_ctx->height = enc->context->height; - frames_ctx->initial_pool_size = 20; - - ret = av_hwframe_ctx_init(enc->vaframes_ref); - if (ret < 0) { - warn("Failed to init HW frames context: %s", av_err2str(ret)); - return false; - } - - /* 2. Create software frame and picture */ - enc->vframe = av_frame_alloc(); - if (!enc->vframe) { - warn("Failed to allocate video frame"); - return false; - } - - enc->vframe->format = enc->context->pix_fmt; - enc->vframe->width = enc->context->width; - enc->vframe->height = enc->context->height; - enc->vframe->colorspace = enc->context->colorspace; - enc->vframe->color_range = enc->context->color_range; - enc->vframe->chroma_location = enc->context->chroma_sample_location; - - ret = av_frame_get_buffer(enc->vframe, base_get_alignment()); - if (ret < 0) { - warn("Failed to allocate vframe: %s", av_err2str(ret)); - return false; - } - - /* 3. set up codec */ - enc->context->pix_fmt = AV_PIX_FMT_VAAPI; - enc->context->hw_frames_ctx = av_buffer_ref(enc->vaframes_ref); - - ret = avcodec_open2(enc->context, enc->vaapi, NULL); - if (ret < 0) { - warn("Failed to open VAAPI codec: %s", av_err2str(ret)); - return false; - } - - enc->packet = av_packet_alloc(); - - enc->initialized = true; - return true; -} - -/* "Allowed" options per Rate Control - * See FFMPEG libavcodec/vaapi_encode.c (vaapi_encode_rc_modes) - */ -typedef struct { - const char *name; - bool qp; - bool bitrate; - bool maxrate; -} rc_mode_t; - -static const rc_mode_t *get_rc_mode(const char *name) -{ - /* Set "allowed" options per Rate Control */ - static const rc_mode_t RC_MODES[] = { - {.name = "CBR", .qp = false, .bitrate = true, .maxrate = false}, - {.name = "CQP", .qp = true, .bitrate = false, .maxrate = false}, - {.name = "VBR", .qp = false, .bitrate = true, .maxrate = true}, - {0}}; - - const rc_mode_t *rc_mode = RC_MODES; - - while (!!rc_mode->name && strcmp(rc_mode->name, name) != 0) - rc_mode++; - - return rc_mode ? rc_mode : RC_MODES; -} - -static bool vaapi_update(void *data, obs_data_t *settings, bool hevc) -{ - struct vaapi_encoder *enc = data; - - const char *device = obs_data_get_string(settings, "vaapi_device"); - - const char *rate_control = - obs_data_get_string(settings, "rate_control"); - const rc_mode_t *rc_mode = get_rc_mode(rate_control); - bool cbr = strcmp(rc_mode->name, "CBR") == 0; - - int profile = (int)obs_data_get_int(settings, "profile"); - int bf = (int)obs_data_get_int(settings, "bf"); - int qp = rc_mode->qp ? (int)obs_data_get_int(settings, "qp") : 0; - - av_opt_set_int(enc->context->priv_data, "qp", qp, 0); - - int level = (int)obs_data_get_int(settings, "level"); - int bitrate = rc_mode->bitrate - ? (int)obs_data_get_int(settings, "bitrate") - : 0; - int maxrate = rc_mode->maxrate - ? (int)obs_data_get_int(settings, "maxrate") - : 0; - int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); - - /* For Rate Control which allows maxrate, FFMPEG will give - * an error if maxrate > bitrate. To prevent that set maxrate - * to 0. - * For CBR, maxrate = bitrate - */ - if (cbr) - maxrate = bitrate; - else if (rc_mode->maxrate && maxrate && maxrate < bitrate) - maxrate = 0; - - video_t *video = obs_encoder_video(enc->encoder); - const struct video_output_info *voi = video_output_get_info(video); - struct video_scale_info info; - - info.format = voi->format; - info.colorspace = voi->colorspace; - info.range = voi->range; - -#ifdef ENABLE_HEVC - if (hevc) { - if ((profile == FF_PROFILE_HEVC_MAIN) && - (info.format == VIDEO_FORMAT_P010)) { - warn("Forcing Main10 for P010"); - profile = FF_PROFILE_HEVC_MAIN_10; - } - - hevc_vaapi_video_info(enc, &info); - } else -#endif - { - h264_vaapi_video_info(enc, &info); - } - - enc->context->profile = profile; - enc->context->max_b_frames = bf; - enc->context->level = level; - enc->context->bit_rate = bitrate * 1000; - enc->context->rc_max_rate = maxrate * 1000; - - enc->context->width = obs_encoder_get_width(enc->encoder); - enc->context->height = obs_encoder_get_height(enc->encoder); - - enc->context->time_base = (AVRational){voi->fps_den, voi->fps_num}; - const enum AVPixelFormat pix_fmt = - obs_to_ffmpeg_video_format(info.format); - enc->context->pix_fmt = pix_fmt; - enc->context->color_range = info.range == VIDEO_RANGE_FULL - ? AVCOL_RANGE_JPEG - : AVCOL_RANGE_MPEG; - - enum AVColorSpace colorspace = AVCOL_SPC_UNSPECIFIED; - switch (info.colorspace) { - case VIDEO_CS_601: - enc->context->color_primaries = AVCOL_PRI_SMPTE170M; - enc->context->color_trc = AVCOL_TRC_SMPTE170M; - colorspace = AVCOL_SPC_SMPTE170M; - break; - case VIDEO_CS_DEFAULT: - case VIDEO_CS_709: - enc->context->color_primaries = AVCOL_PRI_BT709; - enc->context->color_trc = AVCOL_TRC_BT709; - colorspace = AVCOL_SPC_BT709; - break; - case VIDEO_CS_SRGB: - enc->context->color_primaries = AVCOL_PRI_BT709; - enc->context->color_trc = AVCOL_TRC_IEC61966_2_1; - colorspace = AVCOL_SPC_BT709; - break; - case VIDEO_CS_2100_PQ: - enc->context->color_primaries = AVCOL_PRI_BT2020; - enc->context->color_trc = AVCOL_TRC_SMPTE2084; - colorspace = AVCOL_SPC_BT2020_NCL; - break; - case VIDEO_CS_2100_HLG: - enc->context->color_primaries = AVCOL_PRI_BT2020; - enc->context->color_trc = AVCOL_TRC_ARIB_STD_B67; - colorspace = AVCOL_SPC_BT2020_NCL; - break; - default: - break; - } - - enc->context->colorspace = colorspace; - enc->context->chroma_sample_location = - determine_chroma_location(pix_fmt, colorspace); - - if (keyint_sec > 0) { - enc->context->gop_size = - keyint_sec * voi->fps_num / voi->fps_den; - } else { - enc->context->gop_size = 120; - } - - enc->height = enc->context->height; - - info("settings:\n" - "\tdevice: %s\n" - "\trate_control: %s\n" - "\tprofile: %d\n" - "\tlevel: %d\n" - "\tqp: %d\n" - "\tbitrate: %d\n" - "\tmaxrate: %d\n" - "\tkeyint: %d\n" - "\twidth: %d\n" - "\theight: %d\n" - "\tb-frames: %d\n", - device, rate_control, profile, level, qp, bitrate, maxrate, - enc->context->gop_size, enc->context->width, enc->context->height, - enc->context->max_b_frames); - - return vaapi_init_codec(enc, device); -} - -static inline void flush_remaining_packets(struct vaapi_encoder *enc) -{ - int r_pkt = 1; - - while (r_pkt) { -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101) - if (avcodec_receive_packet(enc->context, enc->packet) < 0) - break; -#else - if (avcodec_encode_video2(enc->context, enc->packet, NULL, - &r_pkt) < 0) - break; -#endif - - if (r_pkt) - av_packet_unref(enc->packet); - } -} - -static void vaapi_destroy(void *data) -{ - struct vaapi_encoder *enc = data; - - if (enc->initialized) - flush_remaining_packets(enc); - - av_packet_free(&enc->packet); - avcodec_free_context(&enc->context); - av_frame_unref(enc->vframe); - av_frame_free(&enc->vframe); - av_buffer_unref(&enc->vaframes_ref); - av_buffer_unref(&enc->vadevice_ref); - da_free(enc->buffer); - bfree(enc->header); - bfree(enc->sei); - - bfree(enc); -} - -static void *vaapi_create_internal(obs_data_t *settings, obs_encoder_t *encoder, - bool hevc) -{ - struct vaapi_encoder *enc; -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100) - avcodec_register_all(); -#endif - - enc = bzalloc(sizeof(*enc)); - enc->encoder = encoder; - - const char *const name = hevc ? "hevc_vaapi" : "h264_vaapi"; - enc->vaapi = avcodec_find_encoder_by_name(name); - - enc->first_packet = true; - - blog(LOG_INFO, "---------------------------------"); - - if (!enc->vaapi) { - warn("Couldn't find encoder"); - goto fail; - } - - enc->context = avcodec_alloc_context3(enc->vaapi); - if (!enc->context) { - warn("Failed to create codec context"); - goto fail; - } - - if (!vaapi_update(enc, settings, hevc)) - goto fail; - - return enc; - -fail: - vaapi_destroy(enc); - return NULL; -} - -static void *h264_vaapi_create(obs_data_t *settings, obs_encoder_t *encoder) -{ - return vaapi_create_internal(settings, encoder, false); -} - -#ifdef ENABLE_HEVC -static void *hevc_vaapi_create(obs_data_t *settings, obs_encoder_t *encoder) -{ - return vaapi_create_internal(settings, encoder, true); -} -#endif - -static inline void copy_data(AVFrame *pic, const struct encoder_frame *frame, - int height, enum AVPixelFormat format) -{ - int h_chroma_shift, v_chroma_shift; - av_pix_fmt_get_chroma_sub_sample(format, &h_chroma_shift, - &v_chroma_shift); - for (int plane = 0; plane < MAX_AV_PLANES; plane++) { - if (!frame->data[plane]) - continue; - - int frame_rowsize = (int)frame->linesize[plane]; - int pic_rowsize = pic->linesize[plane]; - int bytes = frame_rowsize < pic_rowsize ? frame_rowsize - : pic_rowsize; - int plane_height = height >> (plane ? v_chroma_shift : 0); - - for (int y = 0; y < plane_height; y++) { - int pos_frame = y * frame_rowsize; - int pos_pic = y * pic_rowsize; - - memcpy(pic->data[plane] + pos_pic, - frame->data[plane] + pos_frame, bytes); - } - } -} - -static bool vaapi_encode_internal(void *data, struct encoder_frame *frame, - struct encoder_packet *packet, - bool *received_packet, bool hevc) -{ - struct vaapi_encoder *enc = data; - AVFrame *hwframe = NULL; - int got_packet; - int ret; - - hwframe = av_frame_alloc(); - if (!hwframe) { - warn("vaapi_encode: failed to allocate hw frame"); - return false; - } - - ret = av_hwframe_get_buffer(enc->vaframes_ref, hwframe, 0); - if (ret < 0) { - warn("vaapi_encode: failed to get buffer for hw frame: %s", - av_err2str(ret)); - goto fail; - } - - copy_data(enc->vframe, frame, enc->height, enc->context->pix_fmt); - - enc->vframe->pts = frame->pts; - hwframe->pts = frame->pts; - hwframe->width = enc->vframe->width; - hwframe->height = enc->vframe->height; - - ret = av_hwframe_transfer_data(hwframe, enc->vframe, 0); - if (ret < 0) { - warn("vaapi_encode: failed to upload hw frame: %s", - av_err2str(ret)); - goto fail; - } - - ret = av_frame_copy_props(hwframe, enc->vframe); - if (ret < 0) { - warn("vaapi_encode: failed to copy props to hw frame: %s", - av_err2str(ret)); - goto fail; - } - -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101) - ret = avcodec_send_frame(enc->context, hwframe); - if (ret == 0) - ret = avcodec_receive_packet(enc->context, enc->packet); - - got_packet = (ret == 0); - - if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) - ret = 0; -#else - ret = avcodec_encode_video2(enc->context, enc->packet, hwframe, - &got_packet); -#endif - if (ret < 0) { - warn("vaapi_encode: Error encoding: %s", av_err2str(ret)); - goto fail; - } - - if (got_packet && enc->packet->size) { - if (enc->first_packet) { - uint8_t *new_packet; - size_t size; - - enc->first_packet = false; -#ifdef ENABLE_HEVC - if (hevc) { - obs_extract_hevc_headers( - enc->packet->data, enc->packet->size, - &new_packet, &size, &enc->header, - &enc->header_size, &enc->sei, - &enc->sei_size); - } else -#endif - { - obs_extract_avc_headers( - enc->packet->data, enc->packet->size, - &new_packet, &size, &enc->header, - &enc->header_size, &enc->sei, - &enc->sei_size); - } - - da_copy_array(enc->buffer, new_packet, size); - bfree(new_packet); - } else { - da_copy_array(enc->buffer, enc->packet->data, - enc->packet->size); - } - - packet->pts = enc->packet->pts; - packet->dts = enc->packet->dts; - packet->data = enc->buffer.array; - packet->size = enc->buffer.num; - packet->type = OBS_ENCODER_VIDEO; -#ifdef ENABLE_HEVC - if (hevc) { - packet->keyframe = - obs_hevc_keyframe(packet->data, packet->size); - } else -#endif - { - packet->keyframe = - obs_avc_keyframe(packet->data, packet->size); - } - *received_packet = true; - } else { - *received_packet = false; - } - - av_packet_unref(enc->packet); - av_frame_free(&hwframe); - return true; - -fail: - av_frame_free(&hwframe); - return false; -} - -static bool h264_vaapi_encode(void *data, struct encoder_frame *frame, - struct encoder_packet *packet, - bool *received_packet) -{ - return vaapi_encode_internal(data, frame, packet, received_packet, - false); -} - -#ifdef ENABLE_HEVC -static bool hevc_vaapi_encode(void *data, struct encoder_frame *frame, - struct encoder_packet *packet, - bool *received_packet) -{ - return vaapi_encode_internal(data, frame, packet, received_packet, - true); -} -#endif - -static void set_visible(obs_properties_t *ppts, const char *name, bool visible) -{ - obs_property_t *p = obs_properties_get(ppts, name); - obs_property_set_visible(p, visible); -} - -static void vaapi_defaults_internal(obs_data_t *settings, bool hevc) -{ -#ifdef ENABLE_HEVC - const char *device = hevc ? vaapi_get_hevc_default_device() - : vaapi_get_h264_default_device(); -#else - const char *const device = vaapi_get_h264_default_device(); -#endif - - obs_data_set_default_string(settings, "vaapi_device", device); -#ifdef ENABLE_HEVC - if (hevc) { - obs_data_set_default_int(settings, "profile", - FF_PROFILE_HEVC_MAIN); - - } else -#endif - { - obs_data_set_default_int(settings, "profile", - FF_PROFILE_H264_CONSTRAINED_BASELINE); - } - obs_data_set_default_int(settings, "level", 40); - obs_data_set_default_int(settings, "bitrate", 2500); - obs_data_set_default_int(settings, "keyint_sec", 0); - obs_data_set_default_int(settings, "bf", 0); - obs_data_set_default_int(settings, "rendermode", 0); - obs_data_set_default_int(settings, "qp", 20); - obs_data_set_default_int(settings, "maxrate", 0); - - int drm_fd = -1; - VADisplay va_dpy = vaapi_open_device(&drm_fd, device, "vaapi_defaults"); - if (!va_dpy) - return; - -#ifdef ENABLE_HEVC - const VAProfile profile = hevc ? VAProfileHEVCMain - : VAProfileH264ConstrainedBaseline; -#else - const VAProfile profile = VAProfileH264ConstrainedBaseline; -#endif - if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_CBR, device)) - obs_data_set_default_string(settings, "rate_control", "CBR"); - else if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_VBR, device)) - obs_data_set_default_string(settings, "rate_control", "VBR"); - else - obs_data_set_default_string(settings, "rate_control", "CQP"); - - vaapi_close_device(&drm_fd, va_dpy); -} - -static void h264_vaapi_defaults(obs_data_t *settings) -{ - vaapi_defaults_internal(settings, false); -} - -static void hevc_vaapi_defaults(obs_data_t *settings) -{ - vaapi_defaults_internal(settings, true); -} - -static bool vaapi_device_modified(obs_properties_t *ppts, obs_property_t *p, - obs_data_t *settings) -{ - UNUSED_PARAMETER(p); - - const char *device = obs_data_get_string(settings, "vaapi_device"); - int drm_fd = -1; - VADisplay va_dpy = - vaapi_open_device(&drm_fd, device, "vaapi_device_modified"); - int profile = obs_data_get_int(settings, "profile"); - obs_property_t *rc_p = obs_properties_get(ppts, "rate_control"); - - obs_property_list_clear(rc_p); - - if (!va_dpy) - goto fail; - - switch (profile) { - case FF_PROFILE_H264_CONSTRAINED_BASELINE: - if (!vaapi_display_h264_supported(va_dpy, device)) - goto fail; - profile = VAProfileH264ConstrainedBaseline; - break; - case FF_PROFILE_H264_MAIN: - if (!vaapi_display_h264_supported(va_dpy, device)) - goto fail; - profile = VAProfileH264Main; - break; - case FF_PROFILE_H264_HIGH: - if (!vaapi_display_h264_supported(va_dpy, device)) - goto fail; - profile = VAProfileH264High; - break; -#ifdef ENABLE_HEVC - case FF_PROFILE_HEVC_MAIN: - if (!vaapi_display_hevc_supported(va_dpy, device)) - goto fail; - profile = VAProfileHEVCMain; - break; - case FF_PROFILE_HEVC_MAIN_10: - if (!vaapi_display_hevc_supported(va_dpy, device)) - goto fail; - profile = VAProfileHEVCMain10; - break; -#endif - } - - if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_CBR, device)) - obs_property_list_add_string(rc_p, "CBR (default)", "CBR"); - - if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_VBR, device)) - obs_property_list_add_string(rc_p, "VBR", "VBR"); - - if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_CQP, device)) - obs_property_list_add_string(rc_p, "CQP", "CQP"); - -fail: - vaapi_close_device(&drm_fd, va_dpy); - return true; -} - -static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p, - obs_data_t *settings) -{ - UNUSED_PARAMETER(p); - - const char *rate_control = - obs_data_get_string(settings, "rate_control"); - - const rc_mode_t *rc_mode = get_rc_mode(rate_control); - - /* Set options visibility per Rate Control */ - set_visible(ppts, "qp", rc_mode->qp); - set_visible(ppts, "bitrate", rc_mode->bitrate); - set_visible(ppts, "maxrate", rc_mode->maxrate); - - return true; -} - -static bool get_device_name_from_pci(struct pci_access *pacc, char *pci_slot, - char *buf, int size) -{ - struct pci_filter filter; - struct pci_dev *dev; - char *name; - - pci_filter_init(pacc, &filter); - if (pci_filter_parse_slot(&filter, pci_slot)) - return false; - - pci_scan_bus(pacc); - for (dev = pacc->devices; dev; dev = dev->next) { - if (pci_filter_match(&filter, dev)) { - pci_fill_info(dev, PCI_FILL_IDENT); - name = pci_lookup_name(pacc, buf, size, - PCI_LOOKUP_DEVICE, - dev->vendor_id, dev->device_id); - strcpy(buf, name); - return true; - } - } - return false; -} - -static obs_properties_t *vaapi_properties_internal(bool hevc) -{ - obs_properties_t *props = obs_properties_create(); - obs_property_t *list; - - list = obs_properties_add_list(props, "vaapi_device", - obs_module_text("VAAPI.Device"), - OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_STRING); - if (os_file_exists("/dev/dri/by-path")) { - os_dir_t *by_path_dir = os_opendir("/dev/dri/by-path"); - struct pci_access *pacc = pci_alloc(); - struct os_dirent *file; - char namebuf[1024]; - char pci_slot[13]; - char *type; - - pci_init(pacc); - while ((file = os_readdir(by_path_dir)) != NULL) { - // file_name pattern: pci-- - char *file_name = file->d_name; - if (strcmp(file_name, ".") == 0 || - strcmp(file_name, "..") == 0) - continue; - - char path[64] = {0}; - - // Use the return value of snprintf to prevent truncation warning. - int written = snprintf(path, 64, "/dev/dri/by-path/%s", - file_name); - if (written >= 64) - blog(LOG_DEBUG, - "obs-ffmpeg-vaapi: A format truncation may have occurred." - " This can be ignored since it is quite improbable."); - - type = strrchr(file_name, '-'); - if (type == NULL) - continue; - else - type++; - - if (strcmp(type, "render") == 0) { - strncpy(pci_slot, file_name + 4, 12); - pci_slot[12] = 0; - bool name_found = get_device_name_from_pci( - pacc, pci_slot, namebuf, - sizeof(namebuf)); - - if (!vaapi_device_h264_supported(path)) - continue; - - if (!name_found) - obs_property_list_add_string(list, path, - path); - else - obs_property_list_add_string( - list, namebuf, path); - } - } - pci_cleanup(pacc); - os_closedir(by_path_dir); - } - if (obs_property_list_item_count(list) == 0) { - char path[32]; - for (int i = 28;; i++) { - snprintf(path, sizeof(path), "/dev/dri/renderD1%d", i); - if (access(path, F_OK) == 0) { - char card[128]; - int ret = snprintf(card, sizeof(card), - "Card%d: %s", i - 28, path); - if (ret >= (int)sizeof(card)) - blog(LOG_DEBUG, - "obs-ffmpeg-vaapi: A format truncation may have occurred." - " This can be ignored since it is quite improbable."); - - if (!vaapi_device_h264_supported(path)) - continue; - - obs_property_list_add_string(list, card, path); - } else { - break; - } - } - } - - obs_property_set_modified_callback(list, vaapi_device_modified); - - list = obs_properties_add_list(props, "profile", - obs_module_text("Profile"), - OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_INT); - if (hevc) { - obs_property_list_add_int(list, "Main", FF_PROFILE_HEVC_MAIN); - obs_property_list_add_int(list, "Main10", - FF_PROFILE_HEVC_MAIN_10); - } else { - obs_property_list_add_int(list, - "Constrained Baseline (default)", - FF_PROFILE_H264_CONSTRAINED_BASELINE); - obs_property_list_add_int(list, "Main", FF_PROFILE_H264_MAIN); - obs_property_list_add_int(list, "High", FF_PROFILE_H264_HIGH); - } - - obs_property_set_modified_callback(list, vaapi_device_modified); - - list = obs_properties_add_list(props, "level", obs_module_text("Level"), - OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_INT); - obs_property_list_add_int(list, "Auto", FF_LEVEL_UNKNOWN); - obs_property_list_add_int(list, "3.0", 30); - obs_property_list_add_int(list, "3.1", 31); - obs_property_list_add_int(list, "4.0 (default) (Compatibility mode)", - 40); - obs_property_list_add_int(list, "4.1", 41); - obs_property_list_add_int(list, "4.2", 42); - obs_property_list_add_int(list, "5.0", 50); - obs_property_list_add_int(list, "5.1", 51); - obs_property_list_add_int(list, "5.2", 52); - - list = obs_properties_add_list(props, "rate_control", - obs_module_text("RateControl"), - OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_STRING); - - obs_property_set_modified_callback(list, rate_control_modified); - - obs_property_t *p; - p = obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"), - 0, 300000, 50); - obs_property_int_set_suffix(p, " Kbps"); - - p = obs_properties_add_int( - props, "maxrate", obs_module_text("MaxBitrate"), 0, 300000, 50); - obs_property_int_set_suffix(p, " Kbps"); - - obs_properties_add_int(props, "qp", "QP", 0, 51, 1); - - p = obs_properties_add_int(props, "keyint_sec", - obs_module_text("KeyframeIntervalSec"), 0, - 20, 1); - obs_property_int_set_suffix(p, " s"); - - return props; -} - -static obs_properties_t *h264_vaapi_properties(void *unused) -{ - UNUSED_PARAMETER(unused); - return vaapi_properties_internal(false); -} - -#ifdef ENABLE_HEVC -static obs_properties_t *hevc_vaapi_properties(void *unused) -{ - UNUSED_PARAMETER(unused); - return vaapi_properties_internal(true); -} -#endif - -static bool vaapi_extra_data(void *data, uint8_t **extra_data, size_t *size) -{ - struct vaapi_encoder *enc = data; - - *extra_data = enc->header; - *size = enc->header_size; - return true; -} - -static bool vaapi_sei_data(void *data, uint8_t **extra_data, size_t *size) -{ - struct vaapi_encoder *enc = data; - - *extra_data = enc->sei; - *size = enc->sei_size; - return true; -} - -struct obs_encoder_info h264_vaapi_encoder_info = { - .id = "ffmpeg_vaapi", - .type = OBS_ENCODER_VIDEO, - .codec = "h264", - .get_name = h264_vaapi_getname, - .create = h264_vaapi_create, - .destroy = vaapi_destroy, - .encode = h264_vaapi_encode, - .get_defaults = h264_vaapi_defaults, - .get_properties = h264_vaapi_properties, - .get_extra_data = vaapi_extra_data, - .get_sei_data = vaapi_sei_data, - .get_video_info = h264_vaapi_video_info, -}; - -#ifdef ENABLE_HEVC -struct obs_encoder_info hevc_vaapi_encoder_info = { - .id = "hevc_ffmpeg_vaapi", - .type = OBS_ENCODER_VIDEO, - .codec = "hevc", - .get_name = hevc_vaapi_getname, - .create = hevc_vaapi_create, - .destroy = vaapi_destroy, - .encode = hevc_vaapi_encode, - .get_defaults = hevc_vaapi_defaults, - .get_properties = hevc_vaapi_properties, - .get_extra_data = vaapi_extra_data, - .get_sei_data = vaapi_sei_data, - .get_video_info = hevc_vaapi_video_info, -}; -#endif - -#endif diff --git a/plugins/obs-ffmpeg/obs-ffmpeg.c b/plugins/obs-ffmpeg/obs-ffmpeg.c index 92421c6..6a20937 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg.c @@ -16,7 +16,6 @@ LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 27, 100) #include "vaapi-utils.h" -#define LIBAVUTIL_VAAPI_AVAILABLE #endif OBS_DECLARE_MODULE() @@ -46,13 +45,6 @@ extern struct obs_encoder_info hevc_nvenc_encoder_info; extern struct obs_encoder_info svt_av1_encoder_info; extern struct obs_encoder_info aom_av1_encoder_info; -#ifdef LIBAVUTIL_VAAPI_AVAILABLE -extern struct obs_encoder_info h264_vaapi_encoder_info; -#ifdef ENABLE_HEVC -extern struct obs_encoder_info hevc_vaapi_encoder_info; -#endif -#endif - #ifndef __APPLE__ static const char *nvenc_check_name = "nvenc_check"; @@ -330,33 +322,6 @@ static bool nvenc_supported(bool *out_h264, bool *out_hevc, bool *out_av1) #endif -#ifdef LIBAVUTIL_VAAPI_AVAILABLE -static bool h264_vaapi_supported(void) -{ - const AVCodec *vaenc = avcodec_find_encoder_by_name("h264_vaapi"); - - if (!vaenc) - return false; - - /* NOTE: If default device is NULL, it means there is no device - * that support H264. */ - return vaapi_get_h264_default_device() != NULL; -} -#ifdef ENABLE_HEVC -static bool hevc_vaapi_supported(void) -{ - const AVCodec *vaenc = avcodec_find_encoder_by_name("hevc_vaapi"); - - if (!vaenc) - return false; - - /* NOTE: If default device is NULL, it means there is no device - * that support HEVC. */ - return vaapi_get_hevc_default_device() != NULL; -} -#endif -#endif - #ifdef _WIN32 extern void jim_nvenc_load(bool h264, bool hevc, bool av1); extern void jim_nvenc_unload(void); @@ -440,30 +405,6 @@ bool obs_module_load(void) #if defined(_WIN32) || defined(__linux__) amf_load(); #endif - -#ifdef LIBAVUTIL_VAAPI_AVAILABLE - const char *libva_env = getenv("LIBVA_DRIVER_NAME"); - if (!!libva_env) - blog(LOG_WARNING, - "LIBVA_DRIVER_NAME variable is set," - " this could prevent FFmpeg VAAPI from working correctly"); - - if (h264_vaapi_supported()) { - blog(LOG_INFO, "FFmpeg VAAPI H264 encoding supported"); - obs_register_encoder(&h264_vaapi_encoder_info); - } else { - blog(LOG_INFO, "FFmpeg VAAPI H264 encoding not supported"); - } - -#ifdef ENABLE_HEVC - if (hevc_vaapi_supported()) { - blog(LOG_INFO, "FFmpeg VAAPI HEVC encoding supported"); - obs_register_encoder(&hevc_vaapi_encoder_info); - } else { - blog(LOG_INFO, "FFmpeg VAAPI HEVC encoding not supported"); - } -#endif -#endif #endif #if ENABLE_FFMPEG_LOGGING -- 2.39.2