ffmpeg入门

ffmpeg入------安装

Fmpeg地址

FFmpeg源码地址:https://github.com/FFmpeg/FFmpeg

FFmpeg可执行文件地址:https://ffmpeg.org/download.html

Windows平台

Windows平台下载解压后如图所示(文件名称以-share结尾的是开发库)

FFmpeg库介绍

◆ ffmpeg.exe:用于音视频转码, 也可以从url/现场音频/视频源抓取输入源。

◆ ffplay.exe:一个非常简单和可移植的媒体播放器,使用FFmpeg库和SDL库。

◆ ffprobe.exe:查看多媒体文件的信息

将FFmpeg可执行文件加入系统环境变量,如下图所示:

Linux

ffmpeg官方 GitHub - FFmpeg/FFmpeg: Mirror of https://git.ffmpeg.org/ffmpeg.git

下载压缩包 或者 直接clone

  1. 直接clone:git clone https://github.com/FFmpeg/FFmpeg.git![](https://file.jishuzhan.net/article/1781211365344546818/2f5876dd7b5bbdc73519b3a0100c85aa.webp)![](https://file.jishuzhan.net/article/1781211365344546818/b642ff01c30bc463711b56e5026ff786.webp)
  2. 下载完成,执行./configure

如果出现了错误 nasm/yasm not found or too old. Use --disable-x86asm for a crippled build.

这是因为 FFMPEG为了提高编译速度,使用了汇编指令,如MMX和SSE等。如果系统中没有yasm指令的话,就会该错误。

1)下载:wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz

2)解压:tar zxvf yasm-1.3.0.tar.gz

3)切换路径: cd yasm-1.3.0

4)执行配置: ./configure

5)编译:make

6)安装:make install

3.make && sudo make install

测试代码:

cpp 复制代码
#include<stdio.h>
#include<libavutil/log.h>


int main()
{
	av_log_set_level(AV_LOG_DEBUG);            //设置日志等级
	av_log(NULL, AV_LOG_INFO, "Hello~~~\n");       // INFO等级,输出hello

	return 0;
}

编译链接: gcc -o ff_log ff_log.c -lavutil

或者 gcc -o ff_log ff_log.c `pkg-config --cflags --libs libavutil`

("pk g-config 工具:1)会检查库的版本号。如果所需要的库的版本不满足要求,它会打印出错误信息,避免链接错误版本的库文件;2)会获得编译预处理参数,如宏定义,头文件的位置。3)还会获得链接参数,如库及依赖的其它库的位置,文件名及其它一些连接参数

选项*--cflags** 它是用来指定程序在编译时所需要头文件所在的目录, 选项 --libs则是指定程序在链接时所需要的动态链接库的目录。*

ffmpeg------log日志系统

log日志位于libavutil模块,log level的声明位于log.h

日志级别:

cpp 复制代码
// 静默模式,不打印日志
#define AV_LOG_QUIET    -8
 
// 立即崩溃,退出程序
#define AV_LOG_PANIC     0
 
// 严重出错,无法修复
#define AV_LOG_FATAL     8
 
// 程序出错
#define AV_LOG_ERROR    16
 
// 警告
#define AV_LOG_WARNING  24
 
// 信息
#define AV_LOG_INFO     32
 
// 详细信息
#define AV_LOG_VERBOSE  40
 
// 调试日志
#define AV_LOG_DEBUG    48
 
// 跟踪日志
#define AV_LOG_TRACE    56

设置日志等级的方法set_log_level()位于log.c,其中av_log_level是个静态全局变量,具体如下

cpp 复制代码
static int av_log_level = AV_LOG_INFO;
 
void av_log_set_level(int level)
{
    av_log_level = level;
}

常用的打印日志方法av_log(),声明位于log.h:

cpp 复制代码
/** 
 * 发送特定消息到小于等于当前等级的日志,默认全部发送到stderr
 *
 * @param avcl  指向任意结构体的指针,结构体第一个变量为AVClass或NULL
 * @param level 日志等级
 * @param fmt   字符串格式
 */
void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4);

ffmpeg------文件的删除与重命名

  • avpriv_io_delete() //删除
  • avpriv_io_move() //重命名

编译链接: gcc xxx.c -o xxx -lavformat -lavutil

cpp 复制代码
#include <libavformat/avformat.h>
 
int main(int argc,char *argv[])
{
        int ret;
        set_av_log_level(AV_LOG_DEBUG);
        ret = avpriv_io_move("111.txt","222.txt");
        if(ret < 0)
        {
                av_log(NULL,AV_LOG_ERROR,"Failed to move file:%s\n","111.txt");
                return -1;
        }
 
        

        ret = avpriv_io_delete("./mytestfile.txt");
        if(ret < 0)
        {
                av_log(NULL,AV_LOG_ERROR,"Failed to delete file:%s\n","mytestfile.txt");
                return -1;
        }
 
        av_log(NULL,AV_LOG_DEBUG,"Success to delete file:%s\n","mytestfile.txt");
 
        return 0;
}

ffmpeg------目录操作

重要结构体:

AVIODirContext 操作目录的上下文(记录avio_open_dir打开目录信息)

AVIODirEntry 目录项。用于存放文件名,文件大小等信息

操作目录API:

  • avio_open_dir()
  • avio_read_dir()//读取目录中每一个文件的属性
  • avio_close_dir()

编译链接: gcc xxx.c -o xxx -lavformat -lavutil

cpp 复制代码
// 实现简单的ls命令

#include <libavutil/log.h>
#include <libavformat/avformat.h>
 
int main(int argc,char* argv[])
{
        int ret;
        AVIODirContext *ctx = NULL;
        AVIODirEntry *entry = NULL;
        av_log_set_level(AV_LOG_INFO);
 
        ret = avio_open_dir(&ctx,"./",NULL);
        if(ret < 0){
                av_log(NULL,AV_LOG_ERROR,"Cant open dir:%s\n",av_err2str(ret));
                return -1;
        }
 
        while(1){
                ret = avio_read_dir(ctx,&entry);//malloc entry
                if(ret < 0){
                        av_log(NULL,AV_LOG_ERROR,"Cant read dir:%s\n",av_err2str(ret));
                        avio_close_dir(&ctx);
                        return -1;
                }
                if(!entry){
                        //the end
                        break;
                }
 
                av_log(NULL,AV_LOG_INFO,"%12"PRId64" %s\n",
                        entry->size,
                        entry->name);
 
                avio_free_directory_entry(&entry);//free entry
        }
 
        avio_close_dir(&ctx);
        return 0;
}

ffmpeg------重要的结构体

  • AVIOContext(I/O上下文) // 实现文件或者流的I/O操作
  • AVFormatContext(封装格式上下文) // 管理媒体文件的格式和封装信息
  • AVCodecContext(编解码器上下文) // 控制和配置音视频编解码器的行为
  • AVStream(音视频流) // 描述音视频流的属性
  • AVPacket (数据包) // 用于在媒体文件、流之间传递数据
  • AVFrame(帧) // 存储和传递音视频数据
  • AVDictionary(字典) // 存储配置选项和元数据
  • AVFilterContext(滤镜上下文) // 处理音视频数据,应用滤镜效果。
  • SwsContext(图像转换上下文) // 进行图像处理和转换
  • SwrContext(音频重采样上下文) // 进行音频处理和转换

AVIOContext结构体,用于管理媒体文件或者网络流的输入和输出操作

AVCodecContext结构体,包含了音频和视频编解码器的配置信息,如编码参数、解码参数、码率控制等。部分字段说明:

|---------------|----------------------------------------------|
| codec | 编解码器的AVCodec,比如指向AVCodec ff_aac_latm_decoder |
| width, height | 图像的宽高(只针对视频) |
| pix_fmt | 像素格式(只针对视频) |
| sample_rate | 采样率(只针对音频) |
| channels | 声道数(只针对音频) |
| sample_fmt | 采样格式(只针对音频 |

AVFormatContext结构体,是与多媒体文件格式相关的结构体,用于打开、读取和写入媒体文件。它包含了文件的格式信息、音视频流、文件I/O操作等。部分字段说明:

|--------------------------------|---------------------------------------------------------------|
| struct AVInputFormat* iformat | 输入媒体的AVInputFormat(输入数据的封装格式),比如指向AVInputFormatff_flv_demuxer |
| AVIOContext *pb | 输入数据的缓存 |
| unsigned int nb_streams; | 输出数据封装格式 |
| unsigned int nb_streams | 输入媒体的AVStream 个数 |
| AVStream** streams | 输入媒体的AVStream []数组 |
| int64_t duration | 输入媒体的时长(以微秒为单位),计算方式可以参考av_dump_format()函数 |
| int bit_rate | 输入媒体的码率 |

AVStream结构体,代表了音频或视频流,包括编解码参数、时间基准、时间戳等信息。部分字段说明

|----------------|--------------------------------|
| index | 标识该视频/音频流 |
| time_base | 该流的时基, PTS*time_base=真正的时间(秒) |
| avg_frame_rate | 该流的帧率 |
| duration | 该视频/音频流长度 |
| codecpar | 编解码器参数属性 |

AVPacket结构体,用于存储音频或视频数据包,包括编码后的数据和时间戳。部分字段说明:

|--------------|-------------|
| pts | 显示时间戳 |
| dts | 解码时间戳 |
| data | 压缩编码数据 |
| size | 压缩编码数据大小 |
| pos | 数据的偏移地址 |
| stream_index | 所属的AVStream |

AVFrame结构体,用于存储音频或视频帧的数据。它包括像素数据、采样数据、时间戳等。部分字段说明:

|---------------|---------------------------------|
| data | 解码后的图像像素数据(音频采样数据) |
| linesize | 对视频来说是图像中一行像素的大小;对音频来说是整个音频帧的大小 |
| width, height | 图像的宽高(只针对视频) |
| key_frame | 是否为关键帧(只针对视频) |
| pict_type | 帧类型(只针对视频) 。例如I, P, B |
| sample_rate | 音频采样率(只针对音频) |
| nb_samples | 音频每通道采样数(只针对音频) |
| pts | 显示时间戳 |

AVDictionary结构体,用于存储键值对,通常用于配置选项的传递和存储。

SwrContext结构体,用于音频重采样,支持不同采样率、通道数之间的转换

SwsContext结构体,用于图像转换,支持不同的像素格式和大小之间的转换

AVFilterContext结构体,用于配置和管理滤镜,包括音频滤镜和视频滤镜。

ffmpeg------多媒体文件

多媒体文件是一个容器(也可以理解为包装盒,常见的mp4、flv、mkv都是不同的包装盒 ),可以存放很多数据,最常见的有字幕数据、视频数据、音频数据。

容器中有很多流(Stream/Track),流媒体文件中不同的流之数据不会相交的,比如音频流和视频流就是各自独立的。

**每种流是由不同的编码器编码的,**每条流数据在多媒体文件中是经过压缩的,但是其使用压缩的编码器都是不一样的。比如音频有可能是MP3,有可能是AAC,视频常见的压缩器有可能是H264或者H265。

从流中读出的数据称为包,在一个包中包含着一个或者多个帧。

ffmpeg操作流数据的基本步骤:

API:

打开读取输入流报头:

cpp 复制代码
/* 打开一个输入流并读取报头。编解码器没有打开。流必须用avformat_close_input()关闭。


参数:
    @param ps指向用户提供的AVFormatContext(由avformat_alloc_context)。可能是指向NULL的指针,在这种情况下,AVFormatContext由this分配函数并写入ps。注意,用户提供的AVFormatContext将被释放失败。

    @param url打开的流的url。

    @param fmt如果非null,该参数强制使用特定的输入格式。否则格式自动检测。

    @param options一个由AVFormatContext和demuxer-private填充的字典选项。返回时,此参数将被销毁并替换为包含未找到的选项的字典。可能为NULL。


成功时返回0,失败时返回负AVERROR。
*/

int avformat open input(AVFormatContext *ps, 
                        const char *url, 
                        const AVinputFormat *fmt,
                        AVDictionary **options)
cpp 复制代码
/*
    在文件中找到"最佳"流。最佳流是根据各种启发式确定的,因为最可能是用户期望的。如果decoder参数非null, av_find_best_stream将为流的编解码器找到默认的解码器;找不到解码器的流将被忽略。


参数:

    *  @param ic                 媒体文件句柄
    * @param type                 视频,音频,字幕等
    * @param wanted_stream_nb    用户请求的流编号或-1为自动选择
    * @param related_stream    尝试找到一个流相关(例如:在同一个程序中)到这个,如果没有,则为-1
    * @param decoder_ret       如果非null,返回所选流的解码器
    * @param flags             当前没有定义


@return
    如果成功,返回非负的流号,如果没有找到请求类型的流,返回AVERROR_STREAM_NOT_FOUND,如果找到流但没有解码器,返回AVERROR_DECODER_NOT_FOUND

@note
如果av_find_best_stream返回成功并且decoder_ret不是NULL,那么*decoder_ret保证被设置为有效的AVCodec。

*/
int av_find_best_stream(AVFormatContext *ic,
                        enum AVMediaType type,
                        int wanted_stream_nb,
                        int related_stream,
                        const AVCodec **decoder_ret,
                        int flags);
cpp 复制代码
//分配一个AVFormatContext。
// avformat_free_context()可以用来释放上下文和框架在其中分配的所有内容。

AVFormatContext *avformat_alloc_context(void);
cpp 复制代码
/*返回与所提供参数最匹配的已注册输出格式列表中的输出格式,如果没有匹配则返回NULL。

@param short_name    if non-NULL检查short_name是否与注册格式的名称匹配
@param filename     if non-NULL检查filename是否以注册格式的扩展名结束
@param mime_type     if non-NULL检查mime_type是否与注册格式的MIME类型匹配

*/

const AVOutputFormat *av_guess_format(const char *short_name,
                                      const char *filename,
                                      const char *mime_type);
cpp 复制代码
/*向媒体文件添加新的流。
    在解模时,由read_header()中的解模器调用。如果标志AVFMTCTX_NOHEADER在s.ctx_flags中设置,那么它也可以在read_packet()中被调用

    当复用时,应该在avformat_write_header()之前由用户调用。
    用户需要调用avformat_free_context()来清理分配,由avformat_new_stream()。

参数:
    @param s  媒体文件句柄
    @param c  未使用,不做任何事情

@return 新创建的流,错误时返回NULL。

*/

AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c);
相关推荐
cuijiecheng20183 小时前
音视频入门基础:FLV专题(13)——FFmpeg源码中,解析任意Type值的SCRIPTDATAVALUE类型的实现
ffmpeg·音视频
小神.Chen1 天前
YouTube音视频合并批处理基于 FFmpeg的
ffmpeg·音视频
昱禹2 天前
记一次因视频编码无法在浏览器播放、编码视频报错问题
linux·python·opencv·ffmpeg·音视频
寻找09之夏3 天前
【FFmpeg 深度解析】:全方位视频合成
ffmpeg·音视频
zanglengyu3 天前
ffmpeg取rtsp流音频数据保存声音为wav文件
ffmpeg·音视频
cuijiecheng20183 天前
音视频入门基础:FLV专题(11)——FFmpeg源码中,解析SCRIPTDATASTRING类型的ScriptDataValue的实现
ffmpeg·音视频
汪子熙3 天前
什么是 LDAC、SBC 和 AAC 音频编码技术
ffmpeg·音视频·aac
cpp_learners3 天前
Windows环境 源码编译 FFmpeg
windows·ffmpeg·源码编译·ffmpeg源码编译
cuijiecheng20183 天前
音视频入门基础:FLV专题(8)——FFmpeg源码中,解码Tag header的实现
ffmpeg·音视频
职场人参4 天前
如何改变音频声音大小?关于改变音频大小的方法介绍
android·ffmpeg