mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-09-12 18:44:25 +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;
|
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 {
|
auto is_amlogic_platform = [&]() -> bool {
|
||||||
const char *platform_hints[] = {
|
const char *platform_hints[] = {
|
||||||
"amlogic",
|
"amlogic",
|
||||||
@@ -210,7 +271,8 @@ int linux_support_v4l2m2m() {
|
|||||||
return false;
|
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()) {
|
if (amlogic_platform && !v4l2m2m_allowed()) {
|
||||||
LOG_WARN(std::string(
|
LOG_WARN(std::string(
|
||||||
"V4L2 M2M: skipped probe on Amlogic platform; set ONE_KVM_V4L2M2M_ALLOW=1 to enable"));
|
"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 "util.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <fstream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -45,17 +48,46 @@ bool is_software_hevc(const std::string &name) {
|
|||||||
return true;
|
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
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace util_encode {
|
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,
|
void set_av_codec_ctx(AVCodecContext *c, const std::string &name, int kbs,
|
||||||
int gop, int fps, int thread_count) {
|
int gop, int fps, int thread_count) {
|
||||||
c->has_b_frames = 0;
|
c->has_b_frames = 0;
|
||||||
c->max_b_frames = 0;
|
c->max_b_frames = 0;
|
||||||
if (gop > 0 && gop < std::numeric_limits<int16_t>::max()) {
|
const bool qcom_iris_v4l2 =
|
||||||
c->gop_size = gop;
|
name.find("v4l2m2m") != std::string::npos && is_qcom_iris_platform();
|
||||||
c->keyint_min = gop; // Match keyint_min to gop for consistent keyframe interval
|
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) {
|
} else if (name.find("vaapi") != std::string::npos) {
|
||||||
c->gop_size = fps > 0 ? fps : 30; // Default to 1 second keyframe interval
|
c->gop_size = fps > 0 ? fps : 30; // Default to 1 second keyframe interval
|
||||||
c->keyint_min = c->gop_size;
|
c->keyint_min = c->gop_size;
|
||||||
@@ -153,7 +185,8 @@ bool set_lantency_free(void *priv_data, const std::string &name) {
|
|||||||
av_err2str(ret));
|
av_err2str(ret));
|
||||||
// Not fatal
|
// 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 = ") +
|
LOG_DEBUG(std::string("v4l2m2m num_capture_buffers option is unavailable, ret = ") +
|
||||||
av_err2str(ret));
|
av_err2str(ret));
|
||||||
// Not fatal
|
// Not fatal
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ extern "C" {
|
|||||||
|
|
||||||
namespace util_encode {
|
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,
|
void set_av_codec_ctx(AVCodecContext *c, const std::string &name, int kbs,
|
||||||
int gop, int fps, int thread_count);
|
int gop, int fps, int thread_count);
|
||||||
bool set_lantency_free(void *priv_data, const std::string &name);
|
bool set_lantency_free(void *priv_data, const std::string &name);
|
||||||
|
|||||||
@@ -379,12 +379,12 @@ private:
|
|||||||
frame->pts = ms;
|
frame->pts = ms;
|
||||||
|
|
||||||
// Force keyframe if requested
|
// Force keyframe if requested
|
||||||
if (force_keyframe_) {
|
if (force_keyframe_ && util_encode::supports_forced_keyframe(name_)) {
|
||||||
frame->pict_type = AV_PICTURE_TYPE_I;
|
frame->pict_type = AV_PICTURE_TYPE_I;
|
||||||
force_keyframe_ = false;
|
|
||||||
} else {
|
} else {
|
||||||
frame->pict_type = AV_PICTURE_TYPE_NONE;
|
frame->pict_type = AV_PICTURE_TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
force_keyframe_ = false;
|
||||||
|
|
||||||
ret = avcodec_send_frame(c_, frame);
|
ret = avcodec_send_frame(c_, frame);
|
||||||
if (ret == AVERROR(EAGAIN)) {
|
if (ret == AVERROR(EAGAIN)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user