[fix] use VideoToolbox exclusively for iOS H.264

This commit is contained in:
dijunkun
2026-09-27 20:53:12 +08:00
parent 52f6f23f93
commit e65a30e969
7 changed files with 28 additions and 73 deletions
@@ -100,7 +100,6 @@ typedef NS_ENUM(NSInteger, CrossDeskVideoAdaptationPolicy) {
- (void)configureWithSignalHost:(NSString *)host - (void)configureWithSignalHost:(NSString *)host
signalPort:(NSInteger)signalPort; signalPort:(NSInteger)signalPort;
- (void)setHardwareAccelerationEnabled:(BOOL)enabled;
- (void)setVideoAdaptationPolicy:(CrossDeskVideoAdaptationPolicy)policy; - (void)setVideoAdaptationPolicy:(CrossDeskVideoAdaptationPolicy)policy;
- (void)requestPresenceForRemoteIDs:(NSArray<NSString *> *)remoteIDs - (void)requestPresenceForRemoteIDs:(NSArray<NSString *> *)remoteIDs
subscribe:(BOOL)subscribe subscribe:(BOOL)subscribe
@@ -75,7 +75,6 @@ struct RTCState {
CallbackContext controller_context; CallbackContext controller_context;
std::string signal_host; std::string signal_host;
int signal_port = 0; int signal_port = 0;
bool hardware_acceleration = true;
VideoDegradationPreference video_adaptation_policy = VideoDegradationPreference video_adaptation_policy =
VideoDegradationPreference::MaintainResolution; VideoDegradationPreference::MaintainResolution;
bool identity_ready = false; bool identity_ready = false;
@@ -332,7 +331,8 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
state.signal_host); state.signal_host);
params.signal_server_port = state.signal_port; params.signal_server_port = state.signal_port;
CopyCString(params.log_path, sizeof(params.log_path), state.log_path); CopyCString(params.log_path, sizeof(params.log_path), state.log_path);
params.hardware_acceleration = state.hardware_acceleration; // iOS H.264 is provided exclusively by VideoToolbox.
params.hardware_acceleration = true;
params.native_video_output = true; params.native_video_output = true;
params.av1_encoding = false; params.av1_encoding = false;
params.turn_mode = TurnMode::TurnAutoUdpTcp; params.turn_mode = TurnMode::TurnAutoUdpTcp;
@@ -495,12 +495,6 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
}); });
} }
- (void)setHardwareAccelerationEnabled:(BOOL)enabled {
dispatch_async(_rtcQueue, ^{
self->_state->hardware_acceleration = enabled;
});
}
- (void)setVideoAdaptationPolicy:(CrossDeskVideoAdaptationPolicy)policy { - (void)setVideoAdaptationPolicy:(CrossDeskVideoAdaptationPolicy)policy {
dispatch_async(_rtcQueue, ^{ dispatch_async(_rtcQueue, ^{
switch (policy) { switch (policy) {
@@ -686,22 +686,6 @@ private struct ServerSettingsView: View {
.font(.footnote) .font(.footnote)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} }
Section("视频编解码") {
Picker("处理方式", selection: $session.videoCodecMode) {
ForEach(VideoCodecMode.allCases) { mode in
Text(mode.title).tag(mode)
}
}
.pickerStyle(.segmented)
Text(session.videoCodecMode.detail)
.font(.footnote)
.foregroundStyle(.secondary)
Text("修改后从下一次连接开始生效。")
.font(.caption)
.foregroundStyle(.tertiary)
}
Section("画面偏好") { Section("画面偏好") {
Picker("偏好模式", selection: $session.videoAdaptationPolicy) { Picker("偏好模式", selection: $session.videoAdaptationPolicy) {
ForEach(VideoAdaptationPolicy.allCases) { policy in ForEach(VideoAdaptationPolicy.allCases) { policy in
@@ -42,43 +42,6 @@ enum MouseControlMode: String, CaseIterable, Identifiable {
} }
} }
enum VideoCodecMode: String, CaseIterable, Identifiable {
case hardware
case software
private static let defaultsKey = "crossdesk.mobile.video-codec-mode"
var id: String { rawValue }
var title: String {
switch self {
case .hardware: return "硬件"
case .software: return "软件"
}
}
var detail: String {
switch self {
case .hardware:
return "使用 VideoToolbox,延迟和耗电更低,推荐日常使用。"
case .software:
return "使用 OpenH264 软件编解码,适合兼容性测试。"
}
}
static var saved: VideoCodecMode {
guard let rawValue = UserDefaults.standard.string(forKey: defaultsKey),
let mode = VideoCodecMode(rawValue: rawValue) else {
return .hardware
}
return mode
}
func save() {
UserDefaults.standard.set(rawValue, forKey: Self.defaultsKey)
}
}
enum VideoAdaptationPolicy: String, CaseIterable, Identifiable { enum VideoAdaptationPolicy: String, CaseIterable, Identifiable {
case frameRatePriority case frameRatePriority
case qualityPriority case qualityPriority
@@ -361,9 +324,6 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe
@Published var mouseControlMode = MouseControlMode.saved { @Published var mouseControlMode = MouseControlMode.saved {
didSet { mouseControlMode.save() } didSet { mouseControlMode.save() }
} }
@Published var videoCodecMode = VideoCodecMode.saved {
didSet { videoCodecMode.save() }
}
@Published var videoAdaptationPolicy = VideoAdaptationPolicy.saved { @Published var videoAdaptationPolicy = VideoAdaptationPolicy.saved {
didSet { videoAdaptationPolicy.save() } didSet { videoAdaptationPolicy.save() }
} }
@@ -467,7 +427,6 @@ final class RemoteSessionModel: NSObject, ObservableObject, CrossDeskRTCBridgeDe
} else if signalConnected { } else if signalConnected {
signalStatus = "已连接服务器" signalStatus = "已连接服务器"
} }
bridge.setHardwareAccelerationEnabled(videoCodecMode == .hardware)
bridge.setVideoAdaptationPolicy(videoAdaptationPolicy.bridgeValue) bridge.setVideoAdaptationPolicy(videoAdaptationPolicy.bridgeValue)
bridge.configure(withSignalHost: host, bridge.configure(withSignalHost: host,
signalPort: signal) signalPort: signal)
+10 -5
View File
@@ -56,11 +56,16 @@ the desktop-compatible `DisplayN`, `control_audio`, `mouse`, `keyboard`,
## Video codecs ## Video codecs
Every iOS build includes VideoToolbox, OpenH264, dav1d, and SVT-AV1. H.264 uses Every iOS build includes VideoToolbox, dav1d, and SVT-AV1. H.264 uses
VideoToolbox by default; choose software processing under **设置 → 视频编解码 → VideoToolbox exclusively; OpenH264 is excluded from the iOS dependencies and
处理方式** (Settings → Video codec → Processing mode) to use OpenH264 for H.264. native archive. The hardware/software processing setting has been removed,
The change takes effect on the next connection. AV1 encoding uses SVT-AV1 and AV1 decoding and preferences saved by older versions are no longer read. H.264 codec
uses dav1d; VideoToolbox AV1 hardware decoding is currently unsupported. initialization failure is reported without a software fallback.
AV1 encoding uses SVT-AV1 and AV1 decoding uses dav1d; VideoToolbox AV1 hardware
decoding is currently unsupported. Desktop builds retain OpenH264.
The native build script checks the merged archive for OpenH264 entry points
and rejects a build if they are present, including in cached archives.
The unused libaom backends are excluded by default. To include them for development, The unused libaom backends are excluded by default. To include them for development,
set the `MINIRTC_ENABLE_AOM` environment variable (or Xcode user-defined build setting) set the `MINIRTC_ENABLE_AOM` environment variable (or Xcode user-defined build setting)
+15 -1
View File
@@ -152,7 +152,7 @@ REQUIRED_LINKS=(
nice glib-2.0 gobject-2.0 gmodule-2.0 gio-2.0 gthread-2.0 intl nice glib-2.0 gobject-2.0 gmodule-2.0 gio-2.0 gthread-2.0 intl
gupnp-igd-1.6 gupnp-1.6 gssdp-1.6 soup-3.0 nghttp2 sqlite3 psl xml2 gupnp-igd-1.6 gupnp-1.6 gssdp-1.6 soup-3.0 nghttp2 sqlite3 psl xml2
ffi pcre2-8 pcre2-posix z ssl crypto srtp2 openfec opus yuv kcp ffi pcre2-8 pcre2-posix z ssl crypto srtp2 openfec opus yuv kcp
datachannel usrsctp openh264 dav1d SvtAv1Enc datachannel usrsctp dav1d SvtAv1Enc
) )
if [[ "${MINIRTC_ENABLE_AOM}" == "true" ]]; then if [[ "${MINIRTC_ENABLE_AOM}" == "true" ]]; then
REQUIRED_LINKS+=(aom) REQUIRED_LINKS+=(aom)
@@ -180,12 +180,25 @@ MERGE_MANIFEST="${OUTPUT_LIBRARY}.inputs.sha256"
TEMP_MANIFEST="${MERGE_MANIFEST}.tmp" TEMP_MANIFEST="${MERGE_MANIFEST}.tmp"
trap 'rm -f "${TEMP_LIBRARY}" "${TEMP_MANIFEST}"' EXIT trap 'rm -f "${TEMP_LIBRARY}" "${TEMP_MANIFEST}"' EXIT
# Check the actual archive, including when reusing cached build products.
verify_no_openh264() {
local symbols
symbols="$(DEVELOPER_DIR="${XMAKE_DEVELOPER_DIR}" xcrun nm -g "$1")"
if [[ "${symbols}" == *WelsCreateDecoder* || \
"${symbols}" == *WelsCreateSVCEncoder* || \
"${symbols}" == *WelsGetCodecVersion* ]]; then
print -u2 "OpenH264 symbols must not be present in the iOS native archive: $1"
exit 65
fi
}
# Hash contents as well as paths so same-size archives replaced within the same # Hash contents as well as paths so same-size archives replaced within the same
# timestamp tick cannot leave a stale merged library. Preserve the output mtime # timestamp tick cannot leave a stale merged library. Preserve the output mtime
# on no-op builds to avoid relinking the Xcode app. # on no-op builds to avoid relinking the Xcode app.
shasum -a 256 "${SCRIPT_DIR}/build_minirtc_ios.sh" "${MINIRTC_LIBRARY}" \ shasum -a 256 "${SCRIPT_DIR}/build_minirtc_ios.sh" "${MINIRTC_LIBRARY}" \
"${DEPENDENCY_ARCHIVES[@]}" "${WIRE_LIBRARY}" > "${TEMP_MANIFEST}" "${DEPENDENCY_ARCHIVES[@]}" "${WIRE_LIBRARY}" > "${TEMP_MANIFEST}"
if [[ -f "${OUTPUT_LIBRARY}" ]] && cmp -s "${TEMP_MANIFEST}" "${MERGE_MANIFEST}"; then if [[ -f "${OUTPUT_LIBRARY}" ]] && cmp -s "${TEMP_MANIFEST}" "${MERGE_MANIFEST}"; then
verify_no_openh264 "${OUTPUT_LIBRARY}"
print "Up to date: ${OUTPUT_LIBRARY}" print "Up to date: ${OUTPUT_LIBRARY}"
exit 0 exit 0
fi fi
@@ -193,6 +206,7 @@ fi
/usr/bin/libtool -static -o "${TEMP_LIBRARY}" \ /usr/bin/libtool -static -o "${TEMP_LIBRARY}" \
"${MINIRTC_LIBRARY}" "${DEPENDENCY_ARCHIVES[@]}" \ "${MINIRTC_LIBRARY}" "${DEPENDENCY_ARCHIVES[@]}" \
"${WIRE_LIBRARY}" "${WIRE_LIBRARY}"
verify_no_openh264 "${TEMP_LIBRARY}"
mv -f "${TEMP_LIBRARY}" "${OUTPUT_LIBRARY}" mv -f "${TEMP_LIBRARY}" "${OUTPUT_LIBRARY}"
mv -f "${TEMP_MANIFEST}" "${MERGE_MANIFEST}" mv -f "${TEMP_MANIFEST}" "${MERGE_MANIFEST}"