mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-09-13 02:54:26 +08:00
feat: 支持高通 iris v4l2m2m 硬件编码器
- 新增高通平台检测,避免 Amlogic v4l2m2m 检测误判 - 对高通 Iris 编码器调整 GOP 和 capture buffers - 强制关键帧仅在高通 Iris 之外启用
This commit is contained in:
@@ -146,6 +146,67 @@ int linux_support_v4l2m2m() {
|
||||
return false;
|
||||
};
|
||||
|
||||
auto is_qcom_platform = [&]() -> bool {
|
||||
const char *platform_hints[] = {
|
||||
"qcom",
|
||||
"qualcomm",
|
||||
"venus",
|
||||
"iris",
|
||||
"sc7280",
|
||||
"qcm6490",
|
||||
"qcs6490",
|
||||
};
|
||||
|
||||
const char *platform_files[] = {
|
||||
"/proc/device-tree/compatible",
|
||||
"/proc/device-tree/model",
|
||||
"/sys/firmware/devicetree/base/compatible",
|
||||
"/sys/firmware/devicetree/base/model",
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(platform_files) / sizeof(platform_files[0]); i++) {
|
||||
std::string value;
|
||||
if (read_text_file(platform_files[i], &value) &&
|
||||
contains_any(to_lower(value), platform_hints,
|
||||
sizeof(platform_hints) / sizeof(platform_hints[0]))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *video_nodes[] = {
|
||||
"video0",
|
||||
"video1",
|
||||
"video2",
|
||||
"video3",
|
||||
"video10",
|
||||
"video11",
|
||||
"video32",
|
||||
};
|
||||
const char *video_hints[] = {
|
||||
"qcom-iris",
|
||||
"qcom,",
|
||||
"venus",
|
||||
"iris",
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(video_nodes) / sizeof(video_nodes[0]); i++) {
|
||||
std::string name;
|
||||
std::string modalias;
|
||||
const std::string base = std::string("/sys/class/video4linux/") + video_nodes[i];
|
||||
if (read_text_file((base + "/name").c_str(), &name) &&
|
||||
contains_any(to_lower(name), video_hints, sizeof(video_hints) / sizeof(video_hints[0]))) {
|
||||
return true;
|
||||
}
|
||||
if (read_text_file((base + "/device/modalias").c_str(), &modalias) &&
|
||||
contains_any(to_lower(modalias), video_hints,
|
||||
sizeof(video_hints) / sizeof(video_hints[0]))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto is_amlogic_platform = [&]() -> bool {
|
||||
const char *platform_hints[] = {
|
||||
"amlogic",
|
||||
@@ -210,7 +271,8 @@ int linux_support_v4l2m2m() {
|
||||
return false;
|
||||
};
|
||||
|
||||
const bool amlogic_platform = is_amlogic_platform();
|
||||
const bool qcom_platform = is_qcom_platform();
|
||||
const bool amlogic_platform = !qcom_platform && is_amlogic_platform();
|
||||
if (amlogic_platform && !v4l2m2m_allowed()) {
|
||||
LOG_WARN(std::string(
|
||||
"V4L2 M2M: skipped probe on Amlogic platform; set ONE_KVM_V4L2M2M_ALLOW=1 to enable"));
|
||||
|
||||
@@ -4,6 +4,9 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include "util.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <string.h>
|
||||
@@ -45,17 +48,46 @@ bool is_software_hevc(const std::string &name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_qcom_iris_driver() {
|
||||
const char *driver_path = "/sys/class/video4linux/video1/name";
|
||||
std::ifstream file(driver_path);
|
||||
if (!file.is_open()) return false;
|
||||
|
||||
std::string value;
|
||||
std::getline(file, value, '\0');
|
||||
std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) {
|
||||
return static_cast<char>(std::tolower(c));
|
||||
});
|
||||
return value.find("qcom-iris") != std::string::npos ||
|
||||
value.find("iris-encoder") != std::string::npos ||
|
||||
value.find("iris") != std::string::npos;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace util_encode {
|
||||
|
||||
bool is_qcom_iris_platform() {
|
||||
return is_qcom_iris_driver();
|
||||
}
|
||||
|
||||
bool supports_forced_keyframe(const std::string &name) {
|
||||
if (name.find("v4l2m2m") != std::string::npos && is_qcom_iris_platform()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_av_codec_ctx(AVCodecContext *c, const std::string &name, int kbs,
|
||||
int gop, int fps, int thread_count) {
|
||||
c->has_b_frames = 0;
|
||||
c->max_b_frames = 0;
|
||||
if (gop > 0 && gop < std::numeric_limits<int16_t>::max()) {
|
||||
c->gop_size = gop;
|
||||
c->keyint_min = gop; // Match keyint_min to gop for consistent keyframe interval
|
||||
const bool qcom_iris_v4l2 =
|
||||
name.find("v4l2m2m") != std::string::npos && is_qcom_iris_platform();
|
||||
const int effective_gop = qcom_iris_v4l2 ? std::max(5, fps / 3) : gop;
|
||||
if (effective_gop > 0 && effective_gop < std::numeric_limits<int16_t>::max()) {
|
||||
c->gop_size = effective_gop;
|
||||
c->keyint_min = effective_gop; // Match keyint_min to gop for consistent keyframe interval
|
||||
} else if (name.find("vaapi") != std::string::npos) {
|
||||
c->gop_size = fps > 0 ? fps : 30; // Default to 1 second keyframe interval
|
||||
c->keyint_min = c->gop_size;
|
||||
@@ -153,7 +185,8 @@ bool set_lantency_free(void *priv_data, const std::string &name) {
|
||||
av_err2str(ret));
|
||||
// Not fatal
|
||||
}
|
||||
if ((ret = av_opt_set_int(priv_data, "num_capture_buffers", 4, 0)) < 0) {
|
||||
const int capture_buffers = is_qcom_iris_driver() ? 12 : 8;
|
||||
if ((ret = av_opt_set_int(priv_data, "num_capture_buffers", capture_buffers, 0)) < 0) {
|
||||
LOG_DEBUG(std::string("v4l2m2m num_capture_buffers option is unavailable, ret = ") +
|
||||
av_err2str(ret));
|
||||
// Not fatal
|
||||
|
||||
@@ -9,6 +9,9 @@ extern "C" {
|
||||
|
||||
namespace util_encode {
|
||||
|
||||
bool is_qcom_iris_platform();
|
||||
bool supports_forced_keyframe(const std::string &name);
|
||||
|
||||
void set_av_codec_ctx(AVCodecContext *c, const std::string &name, int kbs,
|
||||
int gop, int fps, int thread_count);
|
||||
bool set_lantency_free(void *priv_data, const std::string &name);
|
||||
|
||||
@@ -379,12 +379,12 @@ private:
|
||||
frame->pts = ms;
|
||||
|
||||
// Force keyframe if requested
|
||||
if (force_keyframe_) {
|
||||
if (force_keyframe_ && util_encode::supports_forced_keyframe(name_)) {
|
||||
frame->pict_type = AV_PICTURE_TYPE_I;
|
||||
force_keyframe_ = false;
|
||||
} else {
|
||||
frame->pict_type = AV_PICTURE_TYPE_NONE;
|
||||
}
|
||||
force_keyframe_ = false;
|
||||
|
||||
ret = avcodec_send_frame(c_, frame);
|
||||
if (ret == AVERROR(EAGAIN)) {
|
||||
|
||||
Reference in New Issue
Block a user