mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-10-27 16:00:49 +08:00
build: 启用显式 RKMPP 构建
This commit is contained in:
@@ -11,6 +11,7 @@ categories = ["embedded", "network-programming"]
|
||||
|
||||
[features]
|
||||
default = ["desktop"]
|
||||
rkmpp = ["hwcodec/rkmpp"]
|
||||
desktop = [
|
||||
"dep:tokio",
|
||||
"dep:tokio-util",
|
||||
|
||||
@@ -18,6 +18,10 @@ ARCH_MAP=(
|
||||
# Build for specific architecture using cross
|
||||
build_arch() {
|
||||
local rust_target="$1"
|
||||
local feature_args=()
|
||||
case "$rust_target" in
|
||||
aarch64-*|armv7-*) feature_args=(--features rkmpp) ;;
|
||||
esac
|
||||
|
||||
case "${CHINAMIRRO:-}" in
|
||||
1|true|TRUE|yes|YES|on|ON)
|
||||
@@ -40,13 +44,13 @@ build_arch() {
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI=true \
|
||||
RUSTUP_DIST_SERVER="$rust_dist" \
|
||||
RUSTUP_UPDATE_ROOT="$rust_root" \
|
||||
cross build --release --target "$rust_target"
|
||||
cross build --release --target "$rust_target" "${feature_args[@]}"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "=== Building: $rust_target (via cross with custom Dockerfile) ==="
|
||||
cross build --release --target "$rust_target"
|
||||
cross build --release --target "$rust_target" "${feature_args[@]}"
|
||||
}
|
||||
|
||||
# Main
|
||||
|
||||
@@ -268,14 +268,18 @@ build_for_platform() {
|
||||
if [ "$BUILD_BINARY" = true ]; then
|
||||
echo_info "Building binary with cross..."
|
||||
cd "$PROJECT_ROOT"
|
||||
cross build --release --target "$target"
|
||||
local feature_args=()
|
||||
case "$target" in
|
||||
aarch64-*|armv7-*) feature_args=(--features rkmpp) ;;
|
||||
esac
|
||||
cross build --release --target "$target" "${feature_args[@]}"
|
||||
fi
|
||||
|
||||
# Check binary exists
|
||||
local binary="$PROJECT_ROOT/target/$target/release/one-kvm"
|
||||
if [ ! -f "$binary" ]; then
|
||||
echo_error "Binary not found: $binary"
|
||||
echo_error "Build it first: cross build --release --target $target"
|
||||
echo_error "Build it first: ./build/build-images.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ mod ffmpeg {
|
||||
let include_dir = Path::new(&custom_lib_path).join("include");
|
||||
let avcodec_lib = lib_dir.join("libavcodec.a");
|
||||
|
||||
if avcodec_lib.exists() {
|
||||
if avcodec_lib.exists() && use_static {
|
||||
println!("cargo:info=Using custom FFmpeg from {}", custom_lib_path);
|
||||
println!("cargo:rustc-link-search=native={}", lib_dir.display());
|
||||
builder.include(&include_dir);
|
||||
@@ -171,7 +171,7 @@ mod ffmpeg {
|
||||
println!("cargo:rustc-link-lib=va-drm");
|
||||
println!("cargo:rustc-link-lib=va-x11"); // Required for vaGetDisplay
|
||||
println!("cargo:rustc-link-lib=mfx");
|
||||
} else {
|
||||
} else if std::env::var_os("CARGO_FEATURE_RKMPP").is_some() {
|
||||
for lib in ["rockchip_mpp", "rga"] {
|
||||
if !lib_dir.join(format!("lib{lib}.a")).exists() {
|
||||
panic!("missing static library: lib{lib}.a");
|
||||
@@ -400,8 +400,7 @@ mod ffmpeg {
|
||||
// RKMPP decode only exists on ARM builds where FFmpeg is compiled with RKMPP support.
|
||||
// Avoid compiling this file on x86/x64 where `AV_HWDEVICE_TYPE_RKMPP` doesn't exist.
|
||||
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
|
||||
let enable_rkmpp = matches!(target_arch.as_str(), "aarch64" | "arm")
|
||||
|| std::env::var_os("CARGO_FEATURE_RKMPP").is_some();
|
||||
let enable_rkmpp = std::env::var_os("CARGO_FEATURE_RKMPP").is_some();
|
||||
if enable_rkmpp {
|
||||
builder.file(ffmpeg_ram_dir.join("ffmpeg_ram_decode.cpp"));
|
||||
if enable_rkmpp {
|
||||
@@ -459,8 +458,7 @@ mod ffmpeg {
|
||||
.unwrap();
|
||||
|
||||
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
|
||||
let enable_rkmpp = matches!(target_arch.as_str(), "aarch64" | "arm")
|
||||
|| std::env::var_os("CARGO_FEATURE_RKMPP").is_some();
|
||||
let enable_rkmpp = std::env::var_os("CARGO_FEATURE_RKMPP").is_some();
|
||||
if enable_rkmpp {
|
||||
// Include RGA headers for NV16->NV12 conversion (RGA im2d API)
|
||||
let rga_sys_dirs = [
|
||||
|
||||
@@ -9,12 +9,12 @@ use std::ffi::c_int;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/ffmpeg_ram_ffi.rs"));
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm", feature = "rkmpp"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
pub mod decode;
|
||||
|
||||
// Provide a small stub on non-ARM builds so dependents can still compile, but decoder
|
||||
// construction will fail (since the C++ RKMPP decoder isn't built/linked).
|
||||
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm", feature = "rkmpp")))]
|
||||
#[cfg(not(feature = "rkmpp"))]
|
||||
pub mod decode {
|
||||
use crate::ffmpeg::AVPixelFormat;
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
pub mod capture;
|
||||
pub mod common;
|
||||
pub mod ffmpeg;
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm", feature = "rkmpp"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
pub mod ffmpeg_hw;
|
||||
pub mod ffmpeg_ram;
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(target_arch = "aarch64", target_arch = "arm", feature = "rkmpp")
|
||||
feature = "rkmpp"
|
||||
))]
|
||||
pub mod rkmpp_dmabuf;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::os::fd::AsFd;
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
use std::os::fd::OwnedFd;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -31,7 +31,7 @@ use crate::video::device::VideoControlMode;
|
||||
use crate::video::format::{PixelFormat, Resolution};
|
||||
use crate::video::signal::SignalStatus;
|
||||
|
||||
#[cfg(any(test, target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(any(test, feature = "rkmpp"))]
|
||||
#[path = "dmabuf_layout.rs"]
|
||||
mod dmabuf_layout;
|
||||
|
||||
@@ -79,7 +79,7 @@ pub struct CaptureStream {
|
||||
bridge_kind: Option<CsiBridgeKind>,
|
||||
native_hdmirx_state: Option<NativeHdmirxState>,
|
||||
native_hdmirx_next_state_check: Option<Instant>,
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
dma_layout_bytes: Option<usize>,
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ impl CaptureStream {
|
||||
mappings.push(plane_maps);
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
let dma_layout_bytes = PixelFormat::from_v4l2r(actual_fmt.pixelformat).and_then(|format| {
|
||||
dmabuf_layout::DmaCaptureLayout {
|
||||
native_hdmi: is_native_hdmirx,
|
||||
@@ -364,7 +364,7 @@ impl CaptureStream {
|
||||
bridge_kind: bridge.kind,
|
||||
native_hdmirx_state,
|
||||
native_hdmirx_next_state_check,
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
dma_layout_bytes,
|
||||
};
|
||||
|
||||
@@ -491,7 +491,7 @@ impl CaptureStream {
|
||||
|
||||
/// Native HDMI NV12/BGR24 and single-planar USB UVC YUYV/NV12/RGB24/MJPEG.
|
||||
/// Actual EXPBUF/import support is probed separately; failure retains copy.
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
pub(crate) fn supports_rkmpp_dmabuf(&self) -> bool {
|
||||
self.dma_layout_bytes.is_some_and(|minimum| {
|
||||
(2..=16).contains(&self.mappings.len())
|
||||
@@ -502,7 +502,7 @@ impl CaptureStream {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
pub(crate) fn export_dmabufs(&self) -> io::Result<Vec<(OwnedFd, usize)>> {
|
||||
if !self.supports_rkmpp_dmabuf() {
|
||||
return Err(io::Error::new(
|
||||
@@ -524,7 +524,7 @@ impl CaptureStream {
|
||||
/// Run a synchronous consumer while a buffer is dequeued. QBUF occurs only
|
||||
/// after the callback returns, including its error path. Consumers must end
|
||||
/// hardware access before returning; see hwcodec::rkmpp_dmabuf::encode.
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
pub(crate) fn with_next_dmabuf<T>(
|
||||
&mut self,
|
||||
consume: impl FnOnce(usize, usize, Option<OwnedFd>) -> T,
|
||||
@@ -843,17 +843,17 @@ impl CaptureStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(any(test, feature = "rkmpp"))]
|
||||
struct BufferReturn<F: FnOnce() -> io::Result<()>>(Option<F>);
|
||||
|
||||
#[cfg(any(test, target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(any(test, feature = "rkmpp"))]
|
||||
impl<F: FnOnce() -> io::Result<()>> BufferReturn<F> {
|
||||
fn finish(mut self) -> io::Result<()> {
|
||||
self.0.take().expect("capture lease already returned")()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(any(test, feature = "rkmpp"))]
|
||||
impl<F: FnOnce() -> io::Result<()>> Drop for BufferReturn<F> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(return_buffer) = self.0.take() {
|
||||
|
||||
@@ -4,14 +4,14 @@ use std::io;
|
||||
|
||||
#[cfg(any(
|
||||
test,
|
||||
all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm"))
|
||||
all(target_os = "linux", feature = "rkmpp")
|
||||
))]
|
||||
use crate::video::device::VideoControlMode;
|
||||
use crate::video::signal::SignalStatus;
|
||||
|
||||
#[cfg(any(
|
||||
test,
|
||||
all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm"))
|
||||
all(target_os = "linux", feature = "rkmpp")
|
||||
))]
|
||||
pub(crate) fn capture_recovery_status(
|
||||
control_mode: VideoControlMode,
|
||||
|
||||
@@ -17,7 +17,7 @@ pub mod video_codec;
|
||||
pub mod vp8;
|
||||
pub mod vp9;
|
||||
|
||||
#[cfg(all(feature = "desktop", any(target_arch = "aarch64", target_arch = "arm")))]
|
||||
#[cfg(all(feature = "desktop", feature = "rkmpp"))]
|
||||
pub mod mjpeg_rkmpp;
|
||||
|
||||
pub use convert::{MjpegToNv12Decoder, PixelConverter, Yuv420pBuffer};
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::video::codec::vp8::{VP8Config, VP8Encoder};
|
||||
use crate::video::codec::vp9::{VP9Config, VP9Encoder};
|
||||
use crate::video::format::{PixelFormat, Resolution};
|
||||
use bytes::Bytes;
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
use hwcodec::ffmpeg_hw::{
|
||||
last_error_message as ffmpeg_hw_last_error, HwMjpegH26xConfig, HwMjpegH26xPipeline,
|
||||
};
|
||||
@@ -22,9 +22,9 @@ pub(super) struct EncoderThreadState {
|
||||
pub(super) nv12_converter: Option<Nv12Converter>,
|
||||
pub(super) yuv420p_converter: Option<PixelConverter>,
|
||||
pub(super) encoder_needs_yuv420p: bool,
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
pub(super) ffmpeg_hw_pipeline: Option<HwMjpegH26xPipeline>,
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
pub(super) ffmpeg_hw_enabled: bool,
|
||||
pub(super) fps: u32,
|
||||
pub(super) codec: VideoEncoderType,
|
||||
@@ -347,9 +347,9 @@ pub(super) fn build_encoder_state(
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
let is_rkmpp_encoder = selected_codec_name.contains("rkmpp");
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
if needs_mjpeg_decode
|
||||
&& is_rkmpp_encoder
|
||||
&& matches!(
|
||||
@@ -389,9 +389,9 @@ pub(super) fn build_encoder_state(
|
||||
nv12_converter: None,
|
||||
yuv420p_converter: None,
|
||||
encoder_needs_yuv420p: false,
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
ffmpeg_hw_pipeline: Some(pipeline),
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
ffmpeg_hw_enabled: true,
|
||||
fps: config.fps,
|
||||
codec: config.output_codec,
|
||||
@@ -573,9 +573,9 @@ pub(super) fn build_encoder_state(
|
||||
nv12_converter,
|
||||
yuv420p_converter,
|
||||
encoder_needs_yuv420p: needs_yuv420p,
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
ffmpeg_hw_pipeline: None,
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
ffmpeg_hw_enabled: false,
|
||||
fps: config.fps,
|
||||
codec: config.output_codec,
|
||||
|
||||
@@ -35,13 +35,13 @@ use super::encoder_state::{build_encoder_state, should_parallel_decode_mjpeg, En
|
||||
use super::frame_mailbox::{FrameMailbox, PublishResult};
|
||||
use super::mjpeg_admission::{MjpegAdmissionPolicy, MjpegAdmissionStage, MjpegDropReason};
|
||||
|
||||
#[cfg(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm")))]
|
||||
#[cfg(all(target_os = "linux", feature = "rkmpp"))]
|
||||
#[path = "dmabuf.rs"]
|
||||
mod dmabuf;
|
||||
|
||||
#[cfg(any(
|
||||
test,
|
||||
all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm"))
|
||||
all(target_os = "linux", feature = "rkmpp")
|
||||
))]
|
||||
fn rkmpp_dma_eligible(
|
||||
backend: Option<EncoderBackend>,
|
||||
@@ -269,7 +269,7 @@ fn spawn_mjpeg_decode_workers(
|
||||
senders
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
use hwcodec::ffmpeg_hw::last_error_message as ffmpeg_hw_last_error;
|
||||
|
||||
/// Encoded video frame for distribution
|
||||
@@ -726,7 +726,7 @@ impl SharedVideoPipeline {
|
||||
match cmd {
|
||||
PipelineCmd::SetBitrate { preset } => {
|
||||
let bitrate_kbps = preset.bitrate_kbps();
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
if state.ffmpeg_hw_enabled {
|
||||
if let Some(ref mut pipeline) = state.ffmpeg_hw_pipeline {
|
||||
pipeline
|
||||
@@ -1154,7 +1154,7 @@ impl SharedVideoPipeline {
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
#[cfg(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm")))]
|
||||
#[cfg(all(target_os = "linux", feature = "rkmpp"))]
|
||||
if dmabuf::eligible(&config) {
|
||||
if let Some(stream) = preopened.as_ref().filter(|s| s.supports_rkmpp_dmabuf()) {
|
||||
match dmabuf::prepare(stream, &config) {
|
||||
@@ -1817,7 +1817,7 @@ impl SharedVideoPipeline {
|
||||
|
||||
let pts_ms = self.pts_ms();
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
if state.ffmpeg_hw_enabled {
|
||||
if input_format != PixelFormat::Mjpeg {
|
||||
return Err(AppError::VideoError(
|
||||
@@ -2527,9 +2527,9 @@ mod tests {
|
||||
nv12_converter: None,
|
||||
yuv420p_converter: None,
|
||||
encoder_needs_yuv420p: false,
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
ffmpeg_hw_pipeline: None,
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
||||
#[cfg(feature = "rkmpp")]
|
||||
ffmpeg_hw_enabled: false,
|
||||
fps: 30,
|
||||
codec: VideoEncoderType::H264,
|
||||
|
||||
Reference in New Issue
Block a user