视频

第三章 FFmpeg的介绍与使用

2021-01-31  本文已影响0人  路飞_Luck

FFmpeg名称中的mpeg来自视频编码标准MPEG,而前缀FF是Fast Forward的首字母缩写。

目录

一 FFmpeg的主体结构
二 FFmpeg命令行工具的使用
三 FFmpeg API的介绍与使用

一 FFmpeg的主体结构
image.png

默认的编译会生成4个可执行文件和8个静态库。可执行文件包括用于转码推流、Dump媒体文件的ffmpeg、用于播放媒体文件的ffplay、 用于获取媒体文件信息的ffprobe,以及作为简单流媒体服务器的ffserver

8个静态库其实就是FFmpeg的8个模块,具体包括如下内容。

比如AAC编码,常见的有两种封装格式

AACbit stream filter常常应用在编码的过程中。

与音频的AAC编码格式相对应的是视频中的H264编码,它也有两种封装格式

FFmpeg中也提供了对应的bit stream filter,称H264_mp4toannexb,可以将MP4封装格式的H264数据包转换为annexb封装格式的H264数据 (其实就是裸的H264的数据)包。

H264bit stream filter常常应用于视频解码过程中。

二 FFmpeg命令行工具的使用

ffmpeg是进行媒体文件转码的命令行工具
ffprobe是用于查看媒体 文件头信息的工具
ffplay则是用于播放媒体文件的工具

2.1 ffprobe

1.首先用ffprobe查看一个音频的文件

ffprobe ~/Desktop/32037.mp3

2.输出格式信息format_name、时间长度duration、文件 大小size、比特率bit_rate、流的数目nb_streams等。

ffprobe -show_format 32037.mp4

3.以JSON格式的形式输出具体每一个流最详细的信息

ffprobe -print_format json -show_streams 32037.mp4

4.显示帧信息的命令如下:

ffprobe -show_frames sample.mp4

5.查看包信息的命令如下:

ffprobe -show_packets sample.mp4
2.2 ffplay

ffplay是以FFmpeg框架为基础,外加渲染音视频 的库libSDL来构建的媒体文件播放器。

业界内开源的ijkPlayer其实就是基于ffplay进行改造的播放器,当然其做了硬件解码以及很多兼容性的工作。

音视频同步

在 ffplay中音画同步的实现方式其实有三种。分别是

并且在ffplay中默认的对齐方式也是以音频为基准进行对齐的。

首先要声明的是,播放器接收到的视频帧或者音频帧,内部都会有时间戳(PTS时钟)来标识它实际应该在什么时刻进行展示。

实际的对齐策略如下:比较视频当前的播放时间和音频当前的播放时间

  1. 如果视频播放过快,则通过加大延迟或者重复播放来降低视频播放速度;
  2. 如果视频播放慢了,则通过减小延迟或者丢帧来追赶音频播放的时间点。

关键就在于音视频时间的比较以及延迟的计算,当然在比较的过程中会设 置一个阈值(Threshold),若超过预设的阈值就应该做调整(丢帧渲染 或者重复渲染),这就是整个对齐策略。

2.3 ffmpeg

ffmpeg就是强大的媒体文件转换工具。它可以转换任何格式的媒体文件,并且还可以用自己的AudioFilter以及VideoFilter进行处理和编辑。

  1. 从MP4文件中抽取视频流导出为裸H264数据
ffmpeg -i output.mp4 -an -vcodec copy -bsf:v h264_mp4toannexb output.h264
  1. 使用AAC音频数据和H264的视频生成MP4文件
ffmpeg -i test.aac -i test.h264 -acodec copy -bsf:a aac_adtstoasc -vcodec copy -f mp4 output.mp4
  1. 从WAV音频文件中导出PCM裸数据
ffmpeg -i input.wav -acodec pcm_s16le -f s16le output.pcm
  1. 将两路声音进行合并,比如要给一段声音加上背景音乐
ffmpeg -i vocal.wav -i accompany.wav -filter_complex
           amix=inputs=2:duration=shortest output.wav
  1. 为视频增加水印效果
ffmpeg -i input.mp4 -i changba_icon.png -filter_complex
           '[0:v][1:v]overlay=main_w-overlay_w-10:10:1[out]' -map '[out]' output.mp4
  1. 将一个YUV格式表示的数据转换为JPEG格式的图片
ffmpeg -f rawvideo -pix_fmt yuv420p -s 480*480 -i texture.yuv -f image2-vcodec mjpeg output.jpg
三 FFmpeg API的介绍与使用
3.1 术语
3.2 名词介绍
3.3 实例

接下来介绍一个解码的实例,该实例实现的功能非常单一,就是把一个视频文件解码成单独的音频PCM文件和视频YUV文件。

  1. 引用头文件
  2. 注册协议、格式与编解码器
avformat_network_init();
av_register_all();
  1. 打开媒体文件源,并设置超时回调
  2. 寻找各个流,并且打开对应的解码器
  3. 初始化解码后数据的结构体
    分配出解码之后的数据所存放的内存空间,以及进行格式转换需要用到的对象
  4. 读取流内容并且解码
    打开了解码器之后,就可以读取一部分流中的数据(压缩数据),然后将压缩数据作为解码器的输入,解码器将其解码为原始数据(裸数据),之后就可以将原始数据写入文件了。
  5. 处理解码后的裸数据
    解码之后会得到裸数据,音频就是PCM数据,视频就是YUV数据
  6. 关闭所有资源
四 FFmpeg源码结构
4.1 libavformat
image.png

AVFormatContext是API层直接接触到的结构体,它会进行格式的封 装与解封装。

4.2 libavcodec
image.png

该结构体包含的就是与实际的编解码有关的部分。

3.3 FFmpeg通用API分析

3.3.1 av_register_all
所以该函数的内部实现会先调用avcodec_register_all来注册所有config.h里面开放的编解码器,然后会注册所有的MuxerDemuxer(也就是封装格式),最后注册所有的Protocol(即协议层的东西)。

3.3.2 av_find_codec
这里面其实包含了两部分的内容:一部分是寻找解码器,一部分是寻找编码器

3.3.3 avcodec_open2
该函数是打开编解码器(Codec)的函数,无论是编码过程还是解码过程,都会用到该函数。

3.4 调用FFmpeg解码时用到的函数分析

avformat_open_input
根据所提供的文件路径判断文件的格 式,其实就是通过这一步来决定使用的到底是哪一个Demuxer

avformat_find_stream_info
该方法的作用就是把所有StreamMetaData信息填充好。

av_read_frame
使用该方法读取出来的数据是AVPacket

对于音频流,一个AVPacket可能包含AVFrame,但是对于视频流,一个AVPacket只包含AVFrame,该函数最终只会返回一个AVPacket结构体。

avcodec_decode
该方法包含了两部分内容:一部分是解码视频,一部分是解码音频解码是会委托给对应的解码器来实施的。

avformat_close_input
该函数负责释放对应的资源。

3.5 调用FFmpeg编码时用到的函数分析

avformat_alloc_output_context2
该函数内部需要调用方法avformat_alloc_context来分配一个 AVFormatContext结构体。

avio_open2
编码的阶段了,开发者需要将手动封装好的AVFrame结构体,作为avcodec_encode_video方法的输入,将其编码成为AVPacket,然后调用av_write_frame方法输出到媒体文件中。


本文参考音视频开发进阶指南


项目源码地址 - FFmpegDecoder


上一篇 下一篇

猜你喜欢

热点阅读