From 78a02b302488decc3b4f7977e160ddb8f2ef08ec Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Tue, 27 Oct 2026 21:32:16 +0800 Subject: [PATCH] feat(encoder): enable VAAPI hardware encode for ZY NL60R MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gate the VAAPI hardware encoder behind the hwEncodeStatus DConfig key so the X11 backend fallback and thread-safe Xlib init apply only to the ZY NL60R customization; other models stay software. 将 VAAPI 硬编改为由 hwEncodeStatus 配置门控,X11 后端回退与 Xlib 线程安全仅对卓怡 NL60R 定制生效,其他机型保持软件编码。 Log: 新增卓怡NL60R硬编定制,按配置启用VAAPI PMS: TASK-397321 Influence: 仅卓怡NL60R开启硬编,其他机型软编行为不变。 --- libcam/libcam/camview.c | 12 +++++++ libcam/libcam/camview.h | 24 +++++++++++++ libcam/libcam_encoder/encoder.c | 44 +++++++++++++++--------- src/CMakeLists.txt | 1 + src/assets/org.deepin.camera.encode.json | 10 ++++++ src/main.cpp | 19 ++++++++++ 6 files changed, 94 insertions(+), 16 deletions(-) diff --git a/libcam/libcam/camview.c b/libcam/libcam/camview.c index f52bda77..85f623a2 100644 --- a/libcam/libcam/camview.c +++ b/libcam/libcam/camview.c @@ -110,6 +110,8 @@ static int statusForceGles = 0; //forceGles 1,强走GLES static int is_pgux = 0; //是否是pugx +static int hw_encode_status = 0; //是否开启硬编(卓怡 NL60R 定制) + static char libva_driver_name[200]; static char libvdpau_driver_name[200]; @@ -1427,6 +1429,16 @@ int get_pugx_status() return is_pgux; } +void set_hw_encode_status(int status) +{ + hw_encode_status = status; +} + +int get_hw_encode_status() +{ + return hw_encode_status; +} + void set_project_id(const char *id) { if (id != NULL) { diff --git a/libcam/libcam/camview.h b/libcam/libcam/camview.h index 625f0b83..589949cc 100644 --- a/libcam/libcam/camview.h +++ b/libcam/libcam/camview.h @@ -436,6 +436,30 @@ void set_pugx_status(int status); int get_pugx_status(); +/* + * set hardware encode status (project customization, only for 卓怡 NL60R) + * args: + * status - 1 to enable VAAPI hardware encode, 0 to keep software encode + * + * asserts: + * none + * + * returns: none + */ +void set_hw_encode_status(int status); + +/* + * get hardware encode status + * args: + * none + * + * asserts: + * none + * + * returns: 1 if hardware encode enabled, 0 otherwise + */ +int get_hw_encode_status(); + void set_forceGles(int status); int is_forceGles(); diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index 32a8313b..2bccb713 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -46,6 +46,7 @@ #include #include +#include #include "cameraconfig.h" #include "core_time.h" @@ -2311,12 +2312,16 @@ static encoder_video_context_t *encoder_video_init_vaapi(encoder_context_t *enco int ret; is_vaapi = HW_VAAPI_OK; - if(!check_vaapi_support()) - { - is_vaapi = HW_VAAPI_FAIL1; + /* + * 仅对开启硬编的定制机型(卓怡 NL60R,DConfig: hwEncodeStatus=true)跳过 check_vaapi_support(): + * 该探测与下面的 av_hwdevice_ctx_create 重复,且部分 VA 驱动对 vaQueryConfigProfiles(NULL) + * 空列表处理不当会崩溃;其余机型完全保持原有逻辑:check_vaapi_support() 恒失败 -> 软编。 + */ + if (!get_hw_encode_status() && !check_vaapi_support()) { + is_vaapi = HW_VAAPI_FAIL1; fprintf(stderr, "no gpu card for vaapi\n"); return NULL; - } + } //assertions assert(encoder_ctx != NULL); @@ -2368,7 +2373,20 @@ static encoder_video_context_t *encoder_video_init_vaapi(encoder_context_t *enco } - int err = getAvutil()->m_av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0); + /* + * 先用 FFmpeg 默认后端(多数平台走 DRM),失败再回退 X11 后端 + * (部分 VA 驱动只实现了 X11 后端,DRM 会 init 失败)。 + */ + int err = getAvutil()->m_av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0); + if (err < 0) { + getAvutil()->m_av_buffer_unref(&hw_device_ctx); + AVDictionary *hwopts = NULL; + if (getAvutil()->m_av_dict_set) + getAvutil()->m_av_dict_set(&hwopts, "connection_type", "x11", 0); + err = getAvutil()->m_av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, NULL, hwopts, 0); + if (getAvutil()->m_av_dict_free) + getAvutil()->m_av_dict_free(&hwopts); + } if (err < 0) { fprintf(stderr, "Failed to create a VAAPI device. Error code: %s\n", vm_err22str(err)); is_vaapi = HW_VAAPI_FAIL5; @@ -2509,24 +2527,18 @@ static encoder_video_context_t *encoder_video_init_vaapi(encoder_context_t *enco /* open codec*/ if ((ret = getLoadLibsInstance()->m_avcodec_open2(video_codec_data->codec_context,video_codec_data->codec,&video_codec_data->private_options)) < 0){ - fprintf(stderr, "ENCODER: could not open video codec (%s): %i - using raw input\n", video_defaults->codec_name, ret); + /* VAAPI 编码器无法打开(例如该设备 VAAPI 只有解码、没有 H264 编码入口)。 + * 直接返回 NULL,由 encoder_init() 回退到软件编码(encoder_video_init),与 FAIL8 一致; + * 这里不能再调用 encoder_set_raw_video_input():它会把 video_codec_ind 置为 0(raw), + * 使回退退化成“raw 直通”,导致封装异常/崩溃。 */ + fprintf(stderr, "ENCODER: could not open VAAPI video codec: %i - fallback to software\n", ret); free(video_codec_data->codec_context); video_codec_data->codec_context = NULL; video_codec_data->codec = 0; - /*we will use raw data so free the codec data*/ free(video_codec_data); - video_defaults = encoder_get_video_codec_defaults(0); - encoder_set_raw_video_input(encoder_ctx, video_defaults); - - //alloc outbuf - if(enc_video_ctx->outbuf_size <= 0) - enc_video_ctx->outbuf_size = 240000;//1792 - if(enc_video_ctx->outbuf != NULL) - free(enc_video_ctx->outbuf); is_vaapi = HW_VAAPI_FAIL9; getAvutil()->m_av_buffer_unref(&hw_device_ctx); fprintf(stderr, "FAIL to encoder_video_init_vaapi:%d.\n", is_vaapi); - free(video_codec_data); return NULL; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 158114e2..f6c1533f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -122,6 +122,7 @@ pkg_check_modules(3rd_lib REQUIRED pciaccess libva libva-x11 + x11 # libv4l2 # libudev # libusb-1.0 diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index da1ab435..c0d08cb7 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -32,6 +32,16 @@ "permissions": "readwrite", "visibility": "private" }, + "hwEncodeStatus": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "enable hardware encode", + "name[zh_CN]": "启用硬件编码", + "description": "Whether to enable VAAPI hardware encoding (project customization, currently only for 卓怡 NL60R)", + "permissions": "readwrite", + "visibility": "private" + }, "libVaDriverName": { "value": "", "serial": 0, diff --git a/src/main.cpp b/src/main.cpp index b1f5f18d..8be92afc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,6 +37,7 @@ extern "C" { #include #include #include +#include #ifndef DEEPIN_CAMERA_PRO #include "config.h" @@ -111,6 +112,24 @@ static void handleSignal(int sig) int main(int argc, char *argv[]) { + // 硬编定制开关:仅卓怡 NL60R 通过 os-config 下发的 DConfig override 将其置为 true。 + // 只有开启时才尝试 VAAPI 硬编并开启 Xlib 线程安全;其余机型行为完全不变。 + bool hwEncodeEnabled = false; +#ifdef DTKCORE_CLASS_DConfigFile + { + DConfig *encodeCfg = DConfig::create("org.deepin.camera", "org.deepin.camera.encode"); + if (encodeCfg && encodeCfg->isValid() && encodeCfg->keyList().contains("hwEncodeStatus")) { + hwEncodeEnabled = encodeCfg->value("hwEncodeStatus").toBool(); + } + } +#endif + set_hw_encode_status(hwEncodeEnabled ? 1 : 0); + if (hwEncodeEnabled) { + // 编码子线程会经 libva-x11 调用 XOpenDisplay; + // 必须在任何 Xlib/Qt 使用之前开启 Xlib 线程安全,否则子线程里 XOpenDisplay 返回 NULL。 + XInitThreads(); + } + // 将日志配置提前,以确保所有日志没有遗漏 //qputenv("QT_LOGGING_RULES", "*.debug=true;*.info=true"); DLogManager::registerConsoleAppender();