欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

ffmpeg 基础知识入门

最编程 2024-04-27 07:04:57
...

关于ffmpeg

关于ffmpeg,我们首先需要知道它是什么,ffmpeg官网对ffmpeg进行了定义:

image.png

一个针对音视频的录制/转换/串流传输的跨平台解决方案。

image.png

当然,在about页面介绍得更加详细,可以说ffmpeg是针对音视频领域的全能操作框架。在现如今的互联网世界中,关于音视频的操作处理,或直接或间接都会依赖到这个框架(当然也有其他音视频框架)。

怎样使用ffmpeg

ffmpeg有两种使用方法:

  • 自定义开发使用
  • 命令行使用

因为ffmpeg的音视频处理能力都封装在对应的库文件中,因此我们再可以在自己的代码工程中嵌入对应的库文件,然后就可以调用它的基础能力,通过各种组合实现我们想要的功能,这就是自定义开发使用。

而且ffmpeg自身也会把这些功能库统一封装并套壳,打包成一个可执行文件,可以接受各种输入命令,比如在windows上就是ffmpeg.exe文件,我们可以下载这个可执行文件,然后再命令行窗口执行对应的命令行代码。

命令行

我们以windows平台为例,在官网下载最新的可执行文件,不出意外,你会下载到三个可执行文件,分别是:

  • ffmpeg,用于音视频进行修改(录制,采集,裁剪,转换等)处理的能力
  • ffprobe,用于分析音视频文件的相关信息
  • ffplay,发播放音视频

把文件所在路径添加到系统路径即可在命令行窗口进行调用。

比如查看媒体文件的一些信息

ffprobe -show_streams sample.mp4 // 显示sample.mp4内部的流的信息

比如视频文件的格式转换

// mp4转换为avi
ffmpeg -i sample.mp4 -c copy output.avi

命令行的参数和组合形式非常多,具体可以参考官网 Command Line Tools Documentation

也可以先看看阮一峰 FFmpeg 视频处理入门教程,我认为他的教程都非常详细且易懂

自定义开发

自定义开发则是撇开了ffmpeg的壳,只获取其内部功能实现的库文件,把库文件集成到我们工程中,通过调用ffmpeg提供的API来实现我们自己的功能,这个会涉及到了c/cpp开发。

关于自定义开发更多细节就不举例了,这不是本文的重点,而且后面会专门在ffmpeg的基础上进行功能开发。

小结

相对而言命令行的方式更简单一些,因为命令行相当于已经提前封装了一些功能实现的逻辑代码,自定义开发的使用复杂的多,因为自定义开发则需要自己实现逻辑。但是自定义开发比较灵活,而且更适合精细化的,自定义程度较高的那些需求,而且更容易让我们理解音视频处理的一些过程。

其实这两种使用方式没有本质区别,命令行在library之上增加了中间层,把一些功能实现凝结为几个命令参数以达到简化开发的目的。而自定义则直接拿开中间层,直接接触library。

image.png

ffmpeg的功能模块

image.png

  • libavcodec 提供音视频的编解码能力

  • libavformat 提供处理各种音视频容器格式的能力,比如封装,解封装

  • libavutil 提供一些实用的功能函数

  • libavfilter 提供音视频流的滤镜效果

  • libavdevice 提供操作输入和输出设备的能力。例如,从摄像头获取视频数据以及将视频数据输出到屏幕

  • libswresample 实现音频混合和重采样能力

  • libswscale 实现视频帧的颜色转换和缩放能力

如果使用命令行模式,一般会把上述的库全部打包起来,而如果是自定义开发则是按需使用,比如如果不涉及设备操作可以不要libavdevice,不需要滤镜功能可以不要libavfilter...

这些支持库都是跨平台的,既可以是动态库也可以是静态库,

ffmpeg的一些基础概念

time_scale

time_scale 可以称作时间刻度,具体的含义是把一秒钟分为多少个刻度

time_scale = 10 // 表示把一秒钟分为10份,10个刻度,每个刻度代表1/10time_scale = 1000 // 表示把一秒钟分为1000份,1000个刻度,每个刻度代表1/1000

time_base

time_base是ffmpeg中一个非常重要的概念,一般称作时间基,或者可以说是ffmpeg中的时间基础单位。

现实世界所使用的时间基础单位一般是是秒,因为秒对于普通人而言已经足够精确了,使用毫秒或者微秒毫无必要,但是在ffmpeg中不是以秒为基础单位,而是把秒分为若干份,以一份作为ffmpeg中的时间基础单位。

time_base = 1/24   //表示把1s分为24份,以1/24作为ffmpeg的时间的基础单位。

time_base = 1/1000   //表示把1s分为1000份,以1/1000作为ffmpeg的时间的基础单位。

ffmpeg中大量的时间表示(AVStram,AVPacket,AVFrame中的PTS,DTS),都是以time_base作为基础单位的,而不是现实时间。

PTS/DTS/pts_time

  • DTS(Decoding Time Stamp,解码时间戳)

    • 指示解码器应该在什么时间点开始解码该帧(解码顺序)
  • PTS(Presentation Time Stamp,显示时间戳)

    • 指示帧应该在什么时间点被呈现给用户。PTS 是在解码后确定的时间戳,用于视频帧或音频帧的渲染或播放顺序。
  • pts_time

    • 当前媒体帧的显示时间,单位为秒

DTS,PTS一般都是以time_base为单位的。

关于pts,pts_time,time_base之间的计算方式

time_base = 1/75; 
 Frame        pts           pts_time
   0          0          0 x 1/75 = 0.00  (表示该帧在第0秒显示)
   1          3          3 x 1/75 = 0.04  (表示该帧在第0.04秒显示)
   2          6          6 x 1/75 = 0.08  (表示该帧在第0.08秒显示)
   3          9          9 x 1/75 = 0.12  (表示该帧在第0.12秒显示)

AVStream

在ffmpeg中,读取或者写入视频文件时,内部会构建一个数据结构AVFormatContext,这个结构中包含了视频的相关信息,其中一个信息就是AVStram数组,每一个AVStream都包含了一种数据,比如音频和视频分别代表一个AVStram结构,我们可以从中获取比如时长,帧数,编解码器信息,time_base等

image.png

一旦我们获取了AVStream,我们就可以读取该Stream所代表的数据。

AVPacket

在ffmpeg中,在视频文件读取到基本信息之后,就可以读取正式数据内容用于解码,而这个用于解码的数据格式就是AVPacket.

AVPakcet内部包括待一段解码的数据data,size,pts,dts,time_base,stream_id(表示packet读取自哪个AVStream)等。

image.png

AVFrame

AVFrame则是解码后的原始数据,表示一个可以被使用帧,注意这并不一定是视频帧,也可能是音频帧,因为视频和音频都使用AVFrame的数据结构。

AVFrame内包含可播放数据,宽,高(视频),帧类型(视频),采样数(音频),音频格式,PTS等

一般如果是视频,AVFrame表示得是YUV或者RGB图片;如果是音频,则AVFrame表示得是PCM数据。

image.png

此时的得到的数据可以直接被播放。

音视频同步

在获得了可用的音频或者视频帧之后,也并不是直接发送到对应的设备进行播放即可,一般需要我们进行音视频同步控制,因为会出现音频和视频因为各种差异导致获得可用帧的速度差别很大,比如视频很快播放完,但是音频才播了一点点。因此我们需要通过PTS和time_base来控制每一帧的播放速度。

至于同步方法,一般是需要建立一个时间坐标系作为参考,然后计算每一帧的显示时间戳是否对应了正确的时间,否则就等待。

逻辑流程与数据格式转换

根据上面的对一些数据类型的简单介绍,我们已经可以得到一个音频文件播放过程的逻辑流程了

image.png

同样的,把可播放的原始数据保存成文件则是这个过程的逆过程,大同小异。

总结

本文主要对ffmpeg使用方法,核心模块,ffmpeg中的一些基本概念做了介绍,后面将会站在自定义开发的角度上,分析ffmpeg的数据结构的详情,和一个视频被播放的完整过程实现,最终会讲讲在Android平台的使用方式。