killapp/Assets/Plugins/iOS/FFmpegKitIOS.mm
“虞渠成” 52a3e9f06c feat(video,ios): 接入 iOS 端 ffmpeg-kit 转码桥
- 新增 Assets/Plugins/iOS/FFmpegKitIOS.mm: ObjC++ extern C 桥,调 ffmpeg-kit executeWithArguments 做 libx264 重编码

- FFmpegKitBridge.cs 新增 UNITY_IOS 分支,经 DllImport(__Internal) 后台线程调用,参数与 Android 一致

- 新增 Assets/Plugins/iOS/FFmpegKit/README: 说明需放入的 ffmpegkit.xcframework 及构建来源

- 注: xcframework 需 macOS 自编译(arthenica ffmpeg-kit ios.sh --full --enable-gpl -x),放好前 .mm 链接头文件编译期报错属预期
2026-09-08 14:10:41 +08:00

65 lines
2.5 KiB
Plaintext

//
// FFmpegKitIOS.mm
// iOS 端 .264 -> .mp4 转码桥(extern "C"),供 C# 经 [DllImport("__Internal")] 调用。
//
// 原理: 调用 native ffmpeg-kit(ffmpegkit.framework)的 executeWithArguments,用 libx264
// 重编码重新生成干净的 SPS/PPS + 时间戳,修复设备(OPPO/MTK 等)产出裸流坏 PPS 导致的
// 解码卡死("non-existing PPS 0 referenced")。
//
// 依赖: 需将 ffmpeg-kit iOS full-gpl 的 .xcframework(含 ffmpegkit.framework)放进
// Assets/Plugins/iOS/FFmpegKit/(Unity 会在构建 Xcode 工程时自动链接)。
// 版本需与本项目 Android 端一致: dev.ffmpegkit-maintained:ffmpeg-kit-full-gpl:6.0.3
// (FFmpeg n6.1.6,含 libx264)。缺少该 framework 时本文件编译期即报错找不到头文件,属预期。
//
#import <ffmpegkit/FFmpegKit.h>
#import <ffmpegkit/FFmpegKitConfig.h>
#import <Foundation/Foundation.h>
#import <signal.h>
static BOOL ffmpegKitConfigured = NO;
// 一次性配置:忽略 Unity/IL2CPP 运行时可能被 ffmpeg-kit 信号处理干扰的信号
static void FFmpegKitConfigureOnce(void) {
if (ffmpegKitConfigured) return;
ffmpegKitConfigured = YES;
[FFmpegKitConfig ignoreSignal:SIGXCPU];
[FFmpegKitConfig ignoreSignal:SIGPIPE];
}
extern "C" {
/// 执行 ffmpeg 转码。
/// @param argv 参数数组(C# string[] 会作为 UTF-8 char** 传入)
/// @param argc 参数个数
/// @return 0=成功;否则为 ffmpeg 退出码;-1=参数或内部错误
int FFmpegKitExecuteWithArguments(char **argv, int argc) {
@autoreleasepool {
FFmpegKitConfigureOnce();
if (argv == NULL || argc <= 0) {
NSLog(@"[FFmpegKitIOS] bad args argv=%p argc=%d", argv, argc);
return -1;
}
NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:(NSUInteger)argc];
for (int i = 0; i < argc; i++) {
if (argv[i] == NULL) continue;
[arguments addObject:[NSString stringWithUTF8String:argv[i]]];
}
NSLog(@"[FFmpegKitIOS] execute: %@", [arguments componentsJoinedByString:@" "]);
FFmpegSession *session = [FFmpegKit executeWithArguments:arguments];
ReturnCode *returnCode = [session getReturnCode];
if ([ReturnCode isSuccess:returnCode]) {
return 0;
}
if (returnCode == nil) {
NSLog(@"[FFmpegKitIOS] returnCode nil, treat as failure.");
return -1;
}
return (int)[returnCode getValue];
}
}
}