使用FFmpeg库抽取视频中的视频数据


1
2
3
//导入头文件
#import "avcodec.h"
#import "avutil.h"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
- (IBAction)extraVedioAction:(id)sender {

//需要处理的视频文件路径
NSString * path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"mp4"];
char srcChar [ 1024 ];
strcpy (srcChar ,( char *)[path UTF8String]);
// 处理好的文件存储路径
NSString * dstpath = [NSString stringWithFormat:@"%@/Library/Caches/1-1.mp4",NSHomeDirectory()];
char dstChar [ 1024 ];
strcpy (dstChar ,( char *)[dstpath UTF8String]);

char * argv[2];
argv[0] = srcChar;
argv[1] = dstChar;

NSLog(@"存储路径:%@", dstpath);

extraVideo(2, argv);
}

#pragma mark 抽取视频数据
void extraVideo(int argc, char* argv[]) {

int ret = -1;
int idx = -1;

//1. 处理一些参数;
char* src;
char* dst;

AVFormatContext *pFmtCtx = NULL;
AVFormatContext *oFmtCtx = NULL;

const AVOutputFormat *outFmt = NULL;
AVStream *outStream = NULL;
AVStream *inStream = NULL;

AVPacket pkt;

av_log_set_level(AV_LOG_DEBUG);
if(argc < 2){
av_log(NULL, AV_LOG_INFO, "arguments must be more than 2!\n");
exit(-1);
}

src = argv[0];
dst = argv[1];

//2. 打开多媒体文件
if((ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret));
exit(-1);
}

//3. 从多媒体文件中找到视频流
idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if(idx < 0) {
av_log(pFmtCtx, AV_LOG_ERROR, "Does not include audio stream!\n");
goto _ERROR;
}

//4. 打开目的文件的上下文
oFmtCtx = avformat_alloc_context();
if(!oFmtCtx){
av_log(NULL, AV_LOG_ERROR, "NO Memory!\n");
goto _ERROR;
}
outFmt = av_guess_format(NULL, dst, NULL);
oFmtCtx->oformat = outFmt;

//5. 为目的文件,创建一个新的视频流
outStream = avformat_new_stream(oFmtCtx, NULL);
//6. 设置输出视频参数
inStream = pFmtCtx->streams[idx];
avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);
outStream->codecpar->codec_tag = 0;

//绑定
ret = avio_open2(&oFmtCtx->pb, dst, AVIO_FLAG_WRITE, NULL, NULL);
if(ret < 0 ){
av_log(oFmtCtx, AV_LOG_ERROR, "%s", av_err2str(ret));
goto _ERROR;
}

//7. 写多媒体文件头到目的文件
ret = avformat_write_header(oFmtCtx, NULL);
if(ret < 0 ){
av_log(oFmtCtx, AV_LOG_ERROR, "%s", av_err2str(ret));
goto _ERROR;
}
//8. 从源多媒体文件中读到视频数据到目的文件中
while(av_read_frame(pFmtCtx, &pkt) >= 0) {
if(pkt.stream_index == idx) {
pkt.pts = av_rescale_q_rnd(pkt.pts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base);
pkt.stream_index = 0;
pkt.pos = -1;
av_interleaved_write_frame(oFmtCtx, &pkt);
av_packet_unref(&pkt);
}
}
//9. 写多媒体文件尾到文件中
av_write_trailer(oFmtCtx);

//10. 将申请的资源释放掉
_ERROR:
if(pFmtCtx){
avformat_close_input(&pFmtCtx);
pFmtCtx = NULL;
}
if(oFmtCtx->pb){
avio_close(oFmtCtx->pb);
}

if(oFmtCtx){
avformat_free_context(oFmtCtx);
oFmtCtx = NULL;
}
}

github上的示例代码