前言
本文是继iOS编译FFmpeg的第二部分
集成到工程
找到对应文件
将Appdelegate.m后缀改为.mm,开启混编模式。command+B,如果没有报错,则表明编译成功。
在ffmpeg中找到fftools
在scratch中找到config
到iOS工程中
解决集成报错(4.2.3版本)
增加库
ffmpeg.h注释
#include "libavutil/thread.h"
ffmpeg_fliter.c注释
#include "libavresample/avresample.h"
cmdutils.c注释
#include "compat/va_copy.h"
#include "libavresample/avresample.h"
#include "libpostproc/postprocess.h"
#include "libavutil/libm.h"
#include "libavformat/network.h"
PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);
PRINT_LIB_INFO(postproc, POSTPROC, flags, level);
ffmpeg.c注释
include "libavutil/internal.h"
#include "libavutil/libm.h"
#include "libavutil/thread.h"
#include "libavcodec/mathops.h"
#include "libavformat/os_support.h"
nb0_frames = nb_frames = mid_pred(ost->last_nb0_frames[0],
ost->last_nb0_frames[1],
ost->last_nb0_frames[2]);
ff_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n",
ost->forced_keyframes_expr_const_values[FKF_N],
ost->forced_keyframes_expr_const_values[FKF_N_FORCED],
ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N],
ost->forced_keyframes_expr_const_values[FKF_T],
ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T],
res);
ffmpeg.c头部导入
#include "pthread.h"
ffmpeg.h添加
int ffmpeg_main(int argc, char **argv);
将ffmpeg.c中的main
改为ffmpeg_main
优化集成后的问题
计数器置零问题 (ffmpeg.c的代码中会访问空属性导致程序崩溃)
找到ffmpeg.c
中的ffmpeg_cleanup
函数改成如下
nb_filtergraphs=0;
nb_output_files=0;
nb_output_streams=0;
nb_input_files=0;
nb_input_streams=0;
命令执行结束崩溃问题
第一种方法(推荐)
- FFmpeg 默认执行完会执行
exit_program
方法结束进程,而iOS下只能启动一个进程,如果默认不做处理,执行完一条命令后app就自动退出了,所以需要处理下。 - 在
ffmpeg.c
的ffmpeg_main
函数中,把所有调用exit_program
函数 ,改为调用ffmpeg_cleanup
函数就可以了。到这一步就可以使用FFmpeg给我们提供的命令啦(〃'▽'〃)
第二种方法
- 此方法需要2个文件
在cmdutils.c
中的exit_program
函数改成如下
void exit_program(int ret)
{
if (program_exit)
program_exit(ret);
//标记为转换完成
stopRuning();
//这个是结束进程的方法,让ffmpeg进行完转码以后不至于退出程序
// exit(ret);
// 所以将退出进程的方法改造为退出线程
pthread_exit(NULL);
}
运行
编写OC调用
#import "FFmpegTools.h"
#import "ffmpeg.h"
@implementation FFmpegTools
///执行ffmpeg指令," "为分割标记符
+ (void)runCmd:(NSString *)commandStr completionBlock:(void(^)(int result))completionBlock {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 根据 " " 将指令分割为指令数组
NSArray *argv_array = [commandStr componentsSeparatedByString:(@" ")];
// 将OC对象转换为对应的C对象
int argc = (int)argv_array.count;
char** argv = (char**)malloc(sizeof(char*)*argc);
for(int i=0; i < argc; i++) {
argv[i] = (char*)malloc(sizeof(char)*1024);
strcpy(argv[i],[[argv_array objectAtIndex:i] UTF8String]);
}
// ffmpeg_main
// 传入指令数及指令数组,result==0表示成功
int result = ffmpeg_main(argc,argv);
NSLog(@"执行FFmpeg命令:%@,result = %d",commandStr,result);
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(result);
});
});
}
@end
运行代码
NSString *inputPath = [[NSBundle mainBundle] pathForResource:@"123.ts" ofType:nil];
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *outputPath = [docDir stringByAppendingPathComponent:@"videoConver2.mov"];
NSString *commandStr = [NSString stringWithFormat:@"ffmpeg -i %@ -b:v 2000K -y %@", inputPath, outputPath];
NSLog(@"执行1");
[FFmpegTools runCmd:commandStr completionBlock:^(int result) {
// 0表示成功
NSLog(@"结果%d",result);
}];
NSLog(@"执行2");
★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。
见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓