音视频篇 - FFmpeg 的介绍和使用 (学习笔记)

本文章是阅读《音视频开发进阶指南基于android与ios平台的实践》一书的学习笔记。


目录:

  1. FFmpeg 的介绍
  2. FFmpeg Android 编译库
  3. FFmpeg 的结构
  4. FFmpeg 命令行工具的使用

 

1. FFmpeg 的介绍

音视频篇 - FFmpeg 的介绍和使用 (学习笔记)_第1张图片

http://ffmpeg.org

若要讲解音视频的开发,首先不得不提开源框架 FFmpeg。该开源框架为音视频开发者们提供了非常大的帮助,其也是全世界的音视频开发工程师都应该掌握的工具。

FFmpeg 是一套可以用来记录、处理数字音频、视频,并将其转换为流的开源框架,提供了录制、转换以及流化音视频的完整解决方案

它的可移植性或者说跨平台特性非常强大,可以用在 Linux 服务器、PC (包括 Windows、Mac OS X 等)、移动端设备 (Android、iOS 等移动设备) 等平台。

名称中的 mpeg 来自视频编码标准 MPEG,而前缀 FF 是 Fast Forward 的首字母缩写。本章会从编译开始讲解,然后介绍命令行工具的使用,接着会介绍 FFmpeg 在代码层面提供给开发者的 API,最后会从源码的角度分析一下整个 FFmpeg 框架。

 

 

2. FFmpeg Android 编译库

FFmpeg github 上已经有现成编译好的 android 库:https://github.com/xufuji456/FFmpegAndroid,简介如下:

android 端基于 FFmpeg 库的使用,添加编译 ffmpeg、shine、mp3lame、x264 源码的参考脚本,目前音视频相关处理:

  • 音频剪切、拼接
  • 音频混音
  • 音频转码
  • 音视频合成
  • 音频抽取
  • 音频解码播放
  • 音频编码
  • 视频抽取
  • 视频剪切
  • 视频转码
  • 视频截图
  • 视频降噪
  • 视频抽帧
  • 视频转 GIF 动图
  • 视频添加水印
  • 视频画面拼接
  • 视频反序倒播
  • 视频画中画
  • 图片合成视频
  • 视频解码播放
  • 本地直播推流
  • 实时直播推流
  • 音视频解码播放
  • FFmpeg 的 AVFilter 滤镜
  • 使用 mp3lame 库进行 mp3 转码
  • 视频拖动实时预览
  • moov 往前移动
  • ffprobe 检测多媒体格式
  • IjkPlayer 的 RTSP 超低延时直播

 

 

3. FFmpeg 的结构

音视频篇 - FFmpeg 的介绍和使用 (学习笔记)_第2张图片

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

  • AVUtil:核心工具库,该模块是最基础的模块之一,下面的许多其他模块都会依赖该库做一些基本的音视频处理操作。
  • AVFormat:文件格式和协议库,该模块是最重要的模块之一,封装了 Protocol 层和 Demuxer、Muxer 层,使得协议和格式对于开发者来说是透明的。
  • AVCodec:编解码库,该模块也是最重要的模块之一,封装了 Codec 层,但是有一些 Codec 是具备自己的 License 的,FFmpeg 是不会默认添加像 libx264、FDK-AAC、lame 等库的,但是 FFmpeg 就像一个平台一样,可以将其他的第三方的 Codec 以插件的方式添加进来,然后为开发者提供统一的接口。
  • AVFilter:音视频滤镜库,该模块提供了包括音频特效和视频特效的处理,在使用 FFmpeg 的 API 进行编解码的过程中,直接使用该模块为音视频数据做特效处理是非常方便同时也非常高效的一种方式。
  • AVDevice:输入输出设备库,比如,需要编译出播放声音或者视频的工具 ffplay,就需要确保该模块是打开的,同时也需要 libSDL的预先编译,因为该设备模块播放声音与播放视频使用的都是 libSDL 库。
  • SwrRessample:该模块可用于音频重采样,可以对数字音频进行声道数、数据格式、采样率等多种基本信息的转换。
  • SWScale:该模块是将图像进行格式转换的模块,比如,可以将 YUV 的数据转换为 RGB 的数据。
  • PostProc:该模块可用于进行后期处理,当我们使用 AVFilter 的时候需要打开该模块的开关,因为 Filter中 会使用到该模块的一些基础函数。

如何为 FFmpeg 平台引入第三方编解码库呢?下面就以最常用的 LAME、X264、FDK-AAC 进行举例。前面的章节中已经介绍了这三个库在 Android 和 iOS 平台上的交叉编译,现在就假设已经交叉编译出了 LAME、X264、FDK-AAC 的静态库与头文件,并且在 FFmpeg 的源码目录下建立了 external-libs 目录,还在其中建立了 LAME、X264、FDK-AAC 三个目录,每个目录中的结构都包含了 include 和 lib两个目录,并且将编译出来的头文件和静态库文件分别都放到了这两个目录下面。

现在修改编译脚本如下:

新增 X264 编码器需要新增以下脚本:

--enable-muxer=h264 \
--enable-encoder=libx264 \
--enable-libx264 \
--extra-cflags=”-Iexternal-libs/x264/include” \
--extra-ldflags=”-Lexternal-libs/x264/lib” \


新增 LAME 编码器需要新增以下脚本:

--enable-muxer=mp3 \
--enable-encoder=libmp3lame \
--enable-libmp3lame \
--extra-cflags=”-Iexternal-libs/lame/include” \
--extra-ldflags=”-Lexternal-libs/lame/lib” \


新增FDK-AAC编码器需要新增以下脚本:

--enable-encoder=libfdk_aac \
--enable-libfdk_aac \
--extra-cflags=”-Iexternal-libs/fdk-aac/include” \
--extra-ldflags=”-Lexternal-libs/fdk-aac/lib” \


可以按照自己的应用场景,把需要编译进来的第三方库以修改脚本文件的方式进行编译,然后以命令行模式或者以API调用的方式进行使用。

 

 

4. FFmpeg 命令行工具的使用

FFmpeg 中有 ffmpeg、ffprobe、ffplay以及 ffserver 等命令行工具,这边将重点介绍 ffmpeg、ffprobe 与 ffplay 这三个命令行工具,而ffserver 则是作为简单的流媒体服务器存在的,与客户端开发关系不大。

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

 

4.1 ffprobe

先来测试一个音频文件:

ffprobe /Users/kuangzhongwen/Desktop/my\ documents/kuang\ Music/繁星-阿文.mp3

输出:

# 时长 03:51.80,开始播放时间为 0,比特率是 128 kb/s
Duration: 00:03:51.80, start: 0.000000, bitrate: 128 kb/s

# 第一个流是音频流,编码格式是 mp3,采样率为 44100,声道是立体声,采样表示格式是 fltp,路流比特了是 128 kb/s
Stream #0:0: Audio: mp3, 44100 Hz, stereo, fltp, 128 kb/s

再来测试一个视频文件:

ffprobe /Users/kuangzhongwen/Desktop/my\ documents/视频/女生节.mpg 

输出:

 # 时长,开始播放时间,比特率
 Duration: 00:04:47.48, start: 0.220000, bitrate: 8381 kb/s
 Stream #0:0[0x1bf]: Data: dvd_nav_packet
 # stream,视频流,格式为 mpeg2video,每一帧的数据表示为 yuv420P,分辨率为 720x576,fps 为 25
 Stream #0:1[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, top first), 720x576 [SAR 64:45 DAR 16:9], 25 fps, 25 tbr, 90k tbn, 50 tbc
 # stream 音频流,格式为 pcm_dvd,采样率为 48000 Hz,2 个声道,音频流比特率为 1536 kb/s
 Stream #0:2[0xa0]: Audio: pcm_dvd, 48000 Hz, 2 channels, s16, 1536 kb/s

格式化输出:

ffprobe -show_format /Users/kuangzhongwen/Desktop/my\ documents/视频/女生节.mpg

输出:

[FORMAT]
filename=/Users/kuangzhongwen/Desktop/my documents/视频/女生节.mpg
nb_streams=3
nb_programs=0
format_name=mpeg
format_long_name=MPEG-PS (MPEG-2 Program Stream)
start_time=0.220000
duration=287.480000
size=301199360
bit_rate=8381782
probe_score=26
[/FORMAT]

JSON 格式输出:

ffprobe -print_format json -show_streams /Users/kuangzhongwen/Desktop/my\ documents/视频/女生节.mpg

输出:

{
Input #0, mpeg, from '/Users/kuangzhongwen/Desktop/my documents/视频/女生节.mpg':
  Duration: 00:04:47.48, start: 0.220000, bitrate: 8381 kb/s
    Stream #0:0[0x1bf]: Data: dvd_nav_packet
    Stream #0:1[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, top first), 720x576 [SAR 64:45 DAR 16:9], 25 fps, 25 tbr, 90k tbn, 50 tbc
    Stream #0:2[0xa0]: Audio: pcm_dvd, 48000 Hz, 2 channels, s16, 1536 kb/s
Unsupported codec with id 100357 for input stream 0
    "streams": [
        {
            "index": 0,
            "codec_name": "dvd_nav_packet",
            "codec_long_name": "DVD Nav packet",
            "codec_type": "data",
            "codec_tag_string": "[0][0][0][0]",
            "codec_tag": "0x0000",
            "id": "0x1bf",
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/90000",
            "start_pts": 19800,
            "start_time": "0.220000",
            "disposition": {
                "default": 0,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            }
        },
        {
            "index": 1,
            "codec_name": "mpeg2video",
            "codec_long_name": "MPEG-2 video",
            "profile": "Main",
            "codec_type": "video",
            "codec_time_base": "1/25",
            "codec_tag_string": "[0][0][0][0]",
            "codec_tag": "0x0000",
            "width": 720,
            "height": 576,
            "coded_width": 0,
            "coded_height": 0,
            "has_b_frames": 1,
            "sample_aspect_ratio": "64:45",
            "display_aspect_ratio": "16:9",
            "pix_fmt": "yuv420p",
            "level": 8,
            "color_range": "tv",
            "chroma_location": "left",
            "field_order": "tt",
            "refs": 1,
            "id": "0x1e0",
            "r_frame_rate": "25/1",
            "avg_frame_rate": "25/1",
            "time_base": "1/90000",
            "start_pts": 19800,
            "start_time": "0.220000",
            "duration_ts": 25873200,
            "duration": "287.480000",
            "disposition": {
                "default": 0,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            }
        },
        {
            "index": 2,
            "codec_name": "pcm_dvd",
            "codec_long_name": "PCM signed 20|24-bit big-endian",
            "codec_type": "audio",
            "codec_time_base": "1/48000",
            "codec_tag_string": "[0][0][0][0]",
            "codec_tag": "0x0000",
            "sample_fmt": "s16",
            "sample_rate": "48000",
            "channels": 2,
            "bits_per_sample": 0,
            "id": "0xa0",
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/90000",
            "start_pts": 19800,
            "start_time": "0.220000",
            "duration_ts": 25873091,
            "duration": "287.478789",
            "bit_rate": "1536000",
            "bits_per_raw_sample": "16",
            "disposition": {
                "default": 0,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            }
        }
    ]
}

显示帧信息的命令如下:

ffprobe -show_frames sample.mp4

查看包信息的命令如下:

ffprobe -show_packets sample.mp4

 

4.2 ffplay

ffplay 是以 FFmpeg 框架为基础,外加渲染音视频的库 libSDL 来构建的媒体文件播放器。它所依赖的 libSDL 是1.2版本的,所以在安装ffplay 之前也要安装对应版本的 libSDL 作为其依赖的组件。之后使用 ffplay 就非常简单了,比如我们要播放一个音频文件。

ffplay /Users/kuangzhongwen/Desktop/my\ documents/kuang\ Music/繁星-阿文.mp3

或者视频文件:

ffplay /Users/kuangzhongwen/Desktop/my\ documents/视频/女生节.mpg

会打开 ffmpeg 自带的播放器播放。

业界内开源的 ijkPlayer 其实就是基于 ffplay 进行改造的播放器,当然其做了硬件解码以及很多兼容性的工作。ijkPlayer 是一款非常优秀的播放器,作为开发者的我们需要很多优秀的开源项目。

 

4.3 ffmpeg

ffmpeg 其实是这三个命令行工具里最强大的一个工具,如果说 ffprobe 是用于探测媒体文件的格式以及详细信息,ffplay 是一个播放媒体文件的工具,那么 ffmpeg 就是强大的媒体文件转换工具。它可以转换任何格式的媒体文件,并且还可以用自己的 AudioFilter 以及VideoFilter 进行处理和编辑,总之一句话,有了它,进行离线处理视频时可以做任何你想做的事情了。

你可能感兴趣的:(音视频篇)