FFmpeg代码结构:
一:日志系统
初学者可能不理解为什么打印日志,还要设置这么多级别,但如果参与过实际项目,可能就会发现,如果不控制日志级别,全部打印出来,茫茫多的日志,很难管理。
例子:
```c
include <libavutil/log.h> //包含库
av_log_set_level(AV_LOG_DEBUG) //日志级别,debug级是最低级别的日志了。
av_log(NULL, AV_LOG_INFO, "...%s\n", op) //使用INFO级别,打印一条日志。
二:文件
1:文件的基本操作
ffmpeg对操作系统的文件接口进行了封装,操作更加简便。
#include <iostream>
#include "string.h"
extern "C"{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libavutil/log.h>
}
using namespace std;
int add(int a,int b,int c=0,int d=0){
return 0;
}
int main(int argc, const char * argv[]) {
av_log_set_level(AV_LOG_DEBUG);
av_log(NULL, AV_LOG_INFO, "hello world!");
int ret = 0;
// 文件
avpriv_io_move("/Users/heyutang/Desktop/1.mp4", "/Users/heyutang/Desktop/2.mp4"); //重命名
ret = avpriv_io_delete("/Users/heyutang/Desktop/2.mp4"); //删除
if (ret < 0) {
av_log(NULL, AV_LOG_INFO, "delete fial!");
return -1;
}
//目录
AVIODirContext* ctx = NULL;
ret = avio_open_dir(&ctx, "/Users/heyutang/Desktop", NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "can't open dir");
return -1;
}
AVIODirEntry* entry;
while (1) {
ret = avio_read_dir(ctx, &entry); //读取目录中的文件
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "can't read file");
goto __fail;
}
if (!entry) {
break;
}
av_log(NULL, AV_LOG_INFO, "%s:%lld\n",entry->name,entry->size);
avio_free_directory_entry(&entry);
}
avio_close_dir(&ctx); //关闭目录
return 0;
//使用goto语句对错误进行统一处理。
__fail:
avio_close_dir(&ctx);
return -1;
}
2:多媒体文件的基本概念和打印
总的来说就是: 流 包 帧
- 多媒体文件本质是一个容器。
- 在容器里有多个流(stream/track)。
- 每种流是由不同的编码器进行编码的,比如音频用mp3,视频用h264等。
- 从流中读取的数据,我们称之为 包。
- 包解码后,就变成了一个或一组数据帧,视频帧就是一幅幅图,音频帧就是离散的采样点了。
这些概念所对应的结构体如下:
AVFormatContext:格式上下文,即连接多个api的一个桥梁。
AVStream:流
AVPacket:包
基本流程如下:
举个?:打印音视频信息
几个基本api
av_registr_all(