iOS ijkplayer进阶:源码编译、RTSP/HTTPS协议支持与录制功能集成实战
2026/7/15 1:58:03 网站建设 项目流程

1. ijkplayer源码编译与环境准备

第一次接触ijkplayer的开发者可能会被它的编译过程吓到,但其实只要掌握几个关键步骤,整个过程就像搭积木一样简单。我最近在开发一款安防监控App时,就经历了从零开始编译ijkplayer的全过程,这里把踩过的坑和最佳实践都分享给你。

首先需要准备Mac开发环境,建议使用Xcode 12以上版本。打开终端执行以下命令安装基础工具:

# 安装Homebrew(如果尚未安装) /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # 安装编译依赖 brew install git yasm

接着克隆ijkplayer源码库,这里特别要注意使用0.8.8这个稳定版本分支:

git clone https://github.com/bilibili/ijkplayer.git ijkplayer-ios cd ijkplayer-ios git checkout -B latest k0.8.8

在编译前有个重要选择:默认配置为了减小体积禁用了很多编解码器,我们需要修改module-lite.sh来开启必要功能。进入config目录执行:

cd config # 删除默认软连接 rm module.sh # 使用lite配置 ln -s module-lite.sh module.sh

然后编辑module-lite.sh文件,找到协议相关配置,修改为以下内容:

# 启用RTSP相关协议 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=tcp" # 启用HTTPS支持 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-openssl"

接下来初始化子模块和编译环境:

cd .. ./init-ios.sh ./init-ios-openssl.sh

这里有个常见坑点:如果遇到"ERROR: openssl not found"错误,需要先确保本地安装了openssl:

brew install openssl

2. 解决编译过程中的常见问题

实际编译时可能会遇到各种环境问题,我在M1芯片的MacBook Pro上就遇到了几个典型错误。首先是架构兼容性问题,需要修改compile-ffmpeg.sh:

# 修改前 FF_ALL_ARCHS_IOS8_SDK="armv7 arm64 i386 x86_64" # 修改后(移除armv7) FF_ALL_ARCHS_IOS8_SDK="arm64 i386 x86_64"

另一个常见错误是bitcode兼容性问题,解决方法是在compile-ffmpeg.sh中找到CFLAGS参数,添加:

CFLAGS+=" -Wno-error=incompatible-function-pointer-types" CFLAGS+=" -Wno-error=incompatible-pointer-to-integer-type"

开始正式编译前,建议先清理之前的编译结果:

./compile-ffmpeg.sh clean

然后分步编译openssl和ffmpeg:

# 编译openssl ./compile-openssl.sh all # 编译ffmpeg(耗时较长) ./compile-ffmpeg.sh all

编译过程中如果出现文件缺失错误,可能是缓存问题,需要完全清理后重新编译:

./compile-ffmpeg.sh clean ./compile-openssl.sh clean rm -rf ios/build

3. 集成RTSP与HTTPS协议支持

要让ijkplayer支持RTSP流,除了前面修改的编译配置外,还需要在代码层面进行适配。在iOS项目中使用时,需要设置额外的格式选项:

IJKFFOptions *options = [IJKFFOptions optionsByDefault]; // 强制使用TCP传输(避免UDP被防火墙拦截) [options setFormatOptionValue:@"tcp" forKey:@"rtsp_transport"]; // 设置超时时间(单位微秒) [options setFormatOptionIntValue:10000000 forKey:@"timeout"];

对于HTTPS流媒体,需要确保编译时已启用openssl支持。可以通过以下代码检查:

// 检查协议支持情况 NSLog(@"支持协议: %@", [IJKFFMoviePlayerController supportedProtocols]);

在测试RTSP流时,我发现有些摄像头使用特殊的分辨率会导致花屏,这时需要调整解码器参数:

// 设置解码器缓冲大小 [options setPlayerOptionIntValue:256 forKey:@"vol"]; [options setPlayerOptionIntValue:1 forKey:@"videotoolbox"];

一个实用的调试技巧是开启ffmpeg的日志输出:

// 设置日志级别 [options setCodecOptionIntValue:IJK_AV_LOG_DEBUG forKey:@"loglevel"];

4. 实现视频录制功能

在安防监控场景中,本地录制是刚需功能。我通过修改ijkplayer源码实现了这个功能,下面是关键实现步骤:

首先在ff_ffplay.h中添加函数声明:

// 录制控制接口 int ffp_start_record(FFPlayer *ffp, const char *file_name); int ffp_stop_record(FFPlayer *ffp); int ffp_record_file(FFPlayer *ffp, AVPacket *packet);

然后在ff_ffplay.c中实现核心逻辑。关键点是处理时间戳同步:

int ffp_start_record(FFPlayer *ffp, const char *file_name) { // 创建输出上下文 avformat_alloc_output_context2(&ffp->m_ofmt_ctx, NULL, NULL, file_name); // 复制流信息 for (int i = 0; i < is->ic->nb_streams; i++) { AVStream *out_stream = avformat_new_stream(ffp->m_ofmt_ctx, NULL); avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar); } // 写入文件头 avformat_write_header(ffp->m_ofmt_ctx, NULL); ffp->is_record = 1; }

录制过程中需要特别注意线程安全,我使用了pthread_mutex_t来保护写操作:

int ffp_record_file(FFPlayer *ffp, AVPacket *packet) { pthread_mutex_lock(&ffp->record_mutex); // 调整时间戳 pkt->pts = av_rescale_q_rnd(pkt->pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF); // 写入数据包 av_interleaved_write_frame(ffp->m_ofmt_ctx, pkt); pthread_mutex_unlock(&ffp->record_mutex); }

在Objective-C层封装接口:

- (void)startRecordWithFileName:(NSString *)fileName { const char *path = [fileName UTF8String]; ijkmp_start_record(_mediaPlayer, path); } - (void)stopRecord { ijkmp_stop_record(_mediaPlayer); }

5. 打包Framework与项目集成

编译完成后,我们需要将ijkplayer打包成可集成的Framework。首先用Xcode打开IJKMediaPlayer工程:

  1. 选择IJKMediaFramework Scheme
  2. 修改Build Configuration为Release
  3. 分别选择Generic iOS Device和模拟器各编译一次

然后使用lipo工具合并二进制文件:

lipo -create \ Release-iphoneos/IJKMediaFramework.framework/IJKMediaFramework \ Release-iphonesimulator/IJKMediaFramework.framework/IJKMediaFramework \ -output IJKMediaFramework

合并后需要处理依赖库问题。在项目配置中需要添加以下依赖:

  • 必需框架:

    • AudioToolbox.framework
    • VideoToolbox.framework
    • CoreMedia.framework
    • CoreVideo.framework
  • 动态库:

    • libz.tbd
    • libbz2.tbd
    • libc++.tbd

集成到项目后,可以通过这个简单示例测试播放器:

// 初始化播放器 IJKFFOptions *options = [IJKFFOptions optionsByDefault]; NSURL *url = [NSURL URLWithString:@"rtsp://example.com/live.stream"]; _player = [[IJKFFMoviePlayerController alloc] initWithContentURL:url withOptions:options]; // 设置视图 UIView *playerView = [_player view]; playerView.frame = self.view.bounds; [self.view addSubview:playerView]; // 开始播放 [_player prepareToPlay];

6. 录制功能的高级应用

在实现基础录制功能后,我又针对安防场景做了些优化。首先是分段录制功能:

// 每5分钟分段录制一次 [NSTimer scheduledTimerWithTimeInterval:300 repeats:YES block:^(NSTimer * _Nonnull timer) { if (_isRecording) { [self stopCurrentRecording]; [self startNewRecording]; } }];

然后是视频存储管理,自动清理旧文件:

- (void)cleanOldRecordings { NSFileManager *fm = [NSFileManager defaultManager]; NSArray *files = [fm contentsOfDirectoryAtPath:_recordDirectory error:nil]; for (NSString *file in files) { NSString *path = [_recordDirectory stringByAppendingPathComponent:file]; NSDictionary *attrs = [fm attributesOfItemAtPath:path error:nil]; NSDate *createDate = [attrs objectForKey:NSFileCreationDate]; if ([createDate timeIntervalSinceNow] < -86400) { // 超过1天 [fm removeItemAtPath:path error:nil]; } } }

对于视频质量,可以通过参数控制:

// 设置录制参数 [options setPlayerOptionIntValue:2000000 forKey:@"video-bitrate"]; // 2Mbps [options setPlayerOptionIntValue:30 forKey:@"fps"]; [options setPlayerOptionIntValue:1 forKey:@"vf"];

7. 性能优化与调试技巧

在实际使用中,我发现几个提升ijkplayer性能的关键点。首先是内存管理:

// 设置最大缓冲大小(单位MB) [options setPlayerOptionIntValue:15 forKey:@"max-buffer-size"]; [options setPlayerOptionIntValue:1 forKey:@"infbuf"];

对于直播流,建议开启低延迟模式:

[options setPlayerOptionIntValue:1 forKey:@"framedrop"]; [options setPlayerOptionIntValue:0 forKey:@"packet-buffering"];

调试时可以通过监听状态变化来排查问题:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerStateDidChange:) name:IJKMPMoviePlayerLoadStateDidChangeNotification object:_player];

遇到播放卡顿时,可以检查以下指标:

NSLog(@"缓冲长度: %f", _player.playableDuration); NSLog(@"网络速度: %f kbps", _player.tcpSpeed);

最后分享一个实用技巧 - 在控制台查看ffmpeg日志:

// 设置日志回调 ijkmp_set_log_level(IJK_LOG_DEBUG); ijkmp_set_log_handler(^(IJKLogLevel level, NSString *tag, NSString *msg){ NSLog(@"%@: %@", tag, msg); });

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询