Skip to content

Commit 750893c

Browse files
committed
update ffmpeg part
1 parent 4bdc2a2 commit 750893c

6 files changed

Lines changed: 369 additions & 31 deletions

File tree

VideoDevelopment/.DS_Store

-6 KB
Binary file not shown.

VideoDevelopment/FFmpeg/1.FFmpeg简介.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
1.FFmpeg简介
22
===
33

4-
FFmpeg是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多codec都是从头开发的。
4+
[FFmpeg](https://ffmpeg.org/)是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多codec都是从头开发的。
55

66
FFmpeg框架的基本组成包含:
77
- AVFormat
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
## 开发环境配置
2+
3+
### Mac下安装FFmpeg
4+
5+
FFmpeg的学习看其源代码时需要下载他的仓库,直接读源码,其他场景下的编译都是自己根据自己的需求进行编译的,但是在Mac 中不需要进行编译就可以学习FFmpeg的各个API:
6+
```
7+
brew install ffmpeg
8+
```
9+
通过brew安装之后,ffmpeg需要的头文件和lib文件都会安装到/usr/local/X的位置,我的为:
10+
```
11+
/usr/local/Cellar/ffmpeg/6.0
12+
```
13+
### xcode
14+
15+
Xcode 创建一个Commond Line Tools 项目,选择C++/C都可
16+
#### 配置Header、Library路径
17+
18+
![Image](https://raw.githubusercontent.com/CharonChui/Pictures/master/xcode_ffmpeg_1.png?raw=true)
19+
#### 添加动态链接库
20+
![Image](https://raw.githubusercontent.com/CharonChui/Pictures/master/xcode_ffmpeg_2.png?raw=true)
21+
22+
#### main.cpp测试代码
23+
```c++
24+
#if defined(__cplusplus)
25+
extern "C"
26+
{
27+
#endif
28+
#include "libavcodec/avcodec.h"
29+
#if defined(__cplusplus)
30+
}
31+
#endif
32+
33+
#include <iostream>
34+
35+
using namespace std;
36+
37+
#include <iostream>
38+
39+
40+
int main(int argc, const char * argv[]) {
41+
// insert code here...
42+
std::cout << "Hello, World!\n";
43+
cout << "avcodec_configuration : " << avcodec_configuration() << endl;
44+
return 0;
45+
}
46+
```
47+
运行结果:
48+
```
49+
Hello, World!
50+
avcodec_configuration : --prefix=/usr/local/Cellar/ffmpeg/6.0 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox
51+
Program ended with exit code: 0
52+
```
53+
54+
### Android Studio配置FFmpeg开发环境
55+
### 下载ffmpeg源码
56+
下载ffmpeg的源码
57+
官网地址:http://www.ffmpeg.org/download.html
58+
里面有Linux、macOS、Windows系统的版本,根据自己的需要下载对应的版本。下载完成后把源码放在你喜欢的路径,如:/Users/ccc/ffmpeg
59+
60+
### 修改FFmpeg目录下的configuration配置文件:
61+
62+
![Image](https://raw.githubusercontent.com/CharonChui/Pictures/master/ffmpeg_source_code_1.png?raw=true)
63+
64+
然后搜索Toolchain options部分,增加:
65+
```
66+
--cross-prefix-clang=PREFIX use PREFIX for compilation tools [$cross_prefix_clang]
67+
```
68+
![Image](https://raw.githubusercontent.com/CharonChui/Pictures/master/ffmpeg_source_code_2.png?raw=true)
69+
70+
再搜索CMDLINE_SET,也增加上面的自定义参数配置:
71+
72+
![Image](https://raw.githubusercontent.com/CharonChui/Pictures/master/ffmpeg_sourcecode_3.png?raw=true)
73+
74+
最后再搜索set_default target_os,进行一下修改:
75+
```
76+
4436 set_default target_os
77+
4437 if test "$target_os" = android; then
78+
4438 cc_default="clang"
79+
4439 # 增长这一行
80+
4440 cxx_default="clang++"
81+
4441 fi
82+
4442
83+
4443 ar_default="${cross_prefix}${ar_default}"
84+
4444 # 修改这一行
85+
4445 cc_default="${cross_prefix_clang}${cc_default}"
86+
4446 # 修改这一行
87+
4447 cxx_default="${cross_prefix_clang}${cxx_default}"
88+
4448 nm_default="${cross_prefix}${nm_default}"
89+
```
90+
91+
这样修改之后咱们在编译时就可使用咱们新增的cross_prefix_clang参数了,而后其余的如nm,ar,ranlib,strip则继续使用cross_prefix参数。
92+
93+
为什么要这样改?
94+
首先,需要先了解编译库的流程。
95+
①编写自定义的编译脚本
96+
②脚本根据各个配置项,去寻找对应的库工具路径
97+
③生成动态链接库
98+
而上面的修改,目的就是为了第二步能正常找到对应的库工具。配置中的nm,ar,ranlib,strip这些的前缀,是arm-linux-androideabi-,而cc,cxx这两个是arm-linux-androideabi21-这样的前缀,而且他们放的位置也不一样。所以增加一个自定义的配置项,用于指向不同的目录。
99+
100+
#### 编写编译脚本
101+
在ffmepg的文件夹中新建一个文件夹build-android,里面再新建一个build-android.sh文件。
102+
103+
```shell
104+
#!/bin/bash
105+
#NDK路径
106+
export NDK=/Users/xxxx/Library/Android/sdk/ndk/21.0.6113669
107+
#CPU类型
108+
export CPU=armv8-a
109+
# 目标Android版本
110+
API=21
111+
#架构类型
112+
export ARCH=arm
113+
export SYSROOT=$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot
114+
#交叉编译工具链
115+
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
116+
#编译成功后,存放的路径
117+
export PREFIX=./build-android/dist
118+
119+
cd .. #回到ffmpeg根目录
120+
121+
echo "start configure"
122+
./configure \
123+
--prefix=$PREFIX \
124+
--enable-shared \
125+
--enable-cross-compile \
126+
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
127+
--cross-prefix-clang=$TOOLCHAIN/bin/armv7a-linux-androideabi21- \
128+
--target-os=android --arch=$ARCH --cpu=$CPU \
129+
--enable-gpl --enable-version3 \
130+
--disable-programs --disable-ffmpeg --disable-ffplay --disable-ffprobe \
131+
--disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages \
132+
--disable-postproc \
133+
--disable-debug \
134+
--sysroot=$SYSROOT \
135+
--extra-cflags="-I$SYSROOT/usr/include" \
136+
--extra-ldflags="-L$SYSROOT/usr/lib" \
137+
--enable-small \
138+
--enable-jni \
139+
--enable-mediacodec
140+
--disable-everything \
141+
--enable-decoder=hevc --enable-decoder=h264 --enable-decoder=aac \
142+
--enable-parser=h264 --enable-parser=hevc --enable-parser=aac \
143+
--enable-demuxer=flv --enable-demuxer=mov --enable-demuxer=avi --enable-demuxer=mpegts \
144+
--enable-protocol=file --enable-protocol=hls
145+
146+
echo "make clean start"
147+
make clean
148+
echo "make start"
149+
make -j4
150+
echo "make finished"
151+
make install
152+
echo "make install finished"
153+
```
154+
155+
cd到ffmpeg一级目录,然后执行以下的命令
156+
```
157+
chmod 777 build_android.sh //改变脚本权限,使其能够运行,然后
158+
159+
./build_android.sh //运行脚本
160+
```
161+
162+
等编译完成后,进入目录就能看到生成的库:
163+
![Image](https://raw.githubusercontent.com/CharonChui/Pictures/master/ffmpeg_sourcecode_5.png?raw=true)
164+
165+
166+
167+
还有一个问题,就是能不能不修改configure文件?
168+
其实也是可以,只需要明确指定cc和cxx的路径就行。
169+
170+
--cc=$TOOLCHAIN/bin/armv7a-linux-androideabi21-clang \
171+
--cxx=$TOOLCHAIN/bin/armv7a-linux-androideabi21-clang++ \
172+
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
173+
脚本部分配置项解释
174+
1.—prefix:指定编译输出的文件路径
175+
2.—target-os:指定目标操作系统
176+
3.--disable-static:禁止生成静态库
177+
4.—disable-programs:禁止生成ffplay、ffmpeg等可执行文件
178+
5.—disable-doc:禁止生成文档
179+
6.—enable-shared:生成动态链接库
180+
7.enable-cross-compile:开启交叉编译(跨平台编译)
181+
8.make -j12:定义用几个CPU编译
182+
183+
184+
到这里为止,就已经编译出我们需要的so库了,之后就是怎么在android项目中使用了。
185+
186+
### Android编译方式2
187+
188+
[ffmpeg-android-maker](https://github.com/Javernaut/ffmpeg-android-maker)项目已经把下载、编译都给写好了,我们要做的就是下载下来后,
189+
环境变量中配置ANDROID_SDK_HOME和ANDROID_NDK_HOME:
190+
```
191+
export ANDROID_SDK_HOME=/Users/xuchuanren/Library/Android/sdk
192+
export ANDROID_NDK_HOME=/Users/xuchuanren/Library/Android/sdk/ndk/23.1.77796 20
193+
```
194+
然后运行进入目录执行:
195+
```
196+
sh ffmpeg-android-maker.sh
197+
```
198+
它会自动下载并编译android上可用的so,结果为:
199+
![Image](https://raw.githubusercontent.com/CharonChui/Pictures/master/ffmpeg_source_generate_2.png?raw=true)
200+
201+
#### 项目集成
202+
新建项目,增加C++支持。手动创建jniLibs文件夹
203+
然后将上一步生成的所有文件(库文件和头文件)复制到jniLibs文件夹下面
204+
最终目录结构:
205+
206+
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
## 5. FFmpeg核心功能
2+
3+
FFmpeg共有8个可信开发库:
4+
5+
- avutil
6+
包含一些公共的工具函数,主要有数学函数、字符串操作、内存管理相关、数据结构相关、错误码及错误处理、日志输出、其他复制信息比如密钥、哈希值、宏、库版本、常量等。
7+
8+
- avformat
9+
用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能,包含demuxers和muxer库
10+
- avcodec
11+
用于各种类型声音/图像编解码
12+
- avfilter
13+
在多媒体处理中,filter的意思是被编码到输出文件之前用来修改输入文件内容的一个软件工具
14+
- avdevice
15+
FFmpeg中有一个和多媒体设备交互的类库:Libavdevice。使用这个库可以读取电脑(或其他设备) 的多媒体设备的数据,或者输出数据到指定的多媒体设备上
16+
- postproc
17+
用于后期效果处理
18+
- swresample
19+
libswresample库功能主要包括高度优化的音频重采样、rematrixing和样本格式转换操作
20+
- swscale
21+
用于视频场景比例缩放、色彩映射转换
22+
23+
24+
### FFmpeg重要结构体
25+
26+
![Image](https://raw.githubusercontent.com/CharonChui/Pictures/master/ffmpeg_struct_import.png?raw=true)
27+
28+
29+
FFmpeg中的结构体有非常多,其中重要的结构体大概可以分以下几类:
30+
31+
###### 1.解协议(http,rtsp,rtmp,mms,file,tcp,udp ...)
32+
33+
AVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。(注意:FFMPEG中文件也被当做一种协议“file”)。
34+
35+
###### 2.解封装(flv,rmvb,mp4)
36+
37+
AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。
38+
39+
###### 3.解码(h264,mpeg2,aac,mp3)
40+
41+
每个AVStream存储一个视频/音频流的相关数据;每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。
42+
43+
###### 4.存数据
44+
45+
视频的话,每个结构一般是存一帧;音频可能有好几帧
46+
47+
解码前数据:AVPacket
48+
49+
解码后数据:AVFrame
50+
51+
### FFmpeg 4.x解码流程
52+
![Image](https://raw.githubusercontent.com/CharonChui/Pictures/master/ffmpeg_stream_11.png?raw=true)
53+
54+
55+
FFMpeg 中主要数据结构存在包含关系,如下标题显示的就是包含层级的关系。
56+
57+
AVFormatContext ->AVStream-> AVCodecContext -> AVCodec,其中后者是前者的数据成员。
58+
AVFormatContext 是一个贯穿始终的数据结构,很多函数都用到它作为参数,是输入输
59+
出相关信息的一个容器。
60+
主要成员如下:
61+
1. AVInputFormat 和AVOutputFormat,同一时间只能存在一个。当播放视频时AVInputFormat
62+
生效,录制视频时则AVOutputFormat 生效。
63+
2. AVStream 是继AVFormatContext 之后第二个贯穿始终的数据结构,它保存于数据流相关
64+
的编解码器、数据段等信息,还包含“流”这个概念中的一些信息。
65+
66+
- AVCodecContext 保存AVCodec 指针和与codec 相关的数据。
67+
68+
在AVStream 初始化后,AVCodecContext 的初始化时Codec 使用中最重要的一环。
69+
AVCodecContext 中的codec_type,codec_id 二个变量对于encoder/decoder 的匹配来说,
70+
最为重要。
71+
AVCodecContext 中有两个成员:AVCodec,AVFrame。
72+
73+
- AVCodec 记录了所要使用的Codec 的信息并有5 个函数:init,encoder,close,decode,flush
74+
来完成编解码工作。
75+
- AVFrame 中主要包饭了编码后的帧信息。
76+
```
77+
typedef struct AVFrame {
78+
FF_COMMON_FRAME
79+
} AVFrame;
80+
```
81+
其中FF_COMMON_FRAME 是以宏出现的,由于编码过程中AVFrame 中的数据是要经常存取
82+
的,为了加速,采取这样的代码手段。
83+
84+
85+
### API介绍
86+
87+
FFmpeg中奖编码帧及未编码帧均称作frame,这里为了方便,将编码帧称为packet,未编码帧称为frame。
88+
原始图片(yuv、rgb)或声音(pcm流)都是未压缩的,未编码的。
89+
H264/H265, aac/ac3/mp3:都是压缩的,编码的。
90+
91+
- avformat_open_input()
92+
这个函数会打开输入媒体文件,读取文件头,将文件格式信息存储在第一个参数AVFormatContext中。
93+
94+
- avformat_find_stream_info()
95+
这个函数会读取一段视频文件数据并尝试解码,将取到的流信息填入AVFormatContext.streams中。
96+
AVFormatContext.streams是一个指针数组,熟读大小是AVFormatContext.nb_streams。
97+
98+
- av_read_frame
99+
本函数用于解复用过程。
100+
本函数将存储在输入文件中的数据分割为多个packet,每次调用将得到一个packet。packet
101+
可能是视频帧、音频帧或其他数据,解码器只会解码视频帧或音频帧,非音视频数据并不会
102+
被扔掉、从而能向解码器提供尽可能多的信息。
103+
对于视频来说,一个packet 只包含一个视频帧;
104+
105+
对于音频来说,若是帧长固定的格式则一个packet 可包含整数个音频帧,若是帧长可
106+
变的格式则一个packet 只包含一个音频帧。
107+
读取到的packet 每次使用完之后应调用av_packet_unref(AVPacket *pkt)清空packet。否则会
108+
造成内存泄露。
109+
110+
- av_write_frame()
111+
本函数用于复用过程,将packet 写入输出媒体。
112+
packet 交织是指:不同流的packet 在输出媒体文件中应严格按照packet 中dts 递增的顺序交
113+
错存放。
114+
本函数直接将packet 写入复用器(muxer),不会缓存或记录任何packet。本函数不负责不同
115+
流的packet 交织问题。由调用者负责。
116+
如果调用者不愿处理packet 交织问题,应调用av_interleaved_write_frame()替代本函数。
117+
- av_interleaved_write_frame()
118+
本函数用于复用过程,将packet 写入输出媒体。
119+
本函数将按需在内部缓存packet,从而确保输出媒体中不同流的packet 能按照dts 增长的顺
120+
序正确交织。
121+
- avio_open()
122+
创建并初始化一个AVIOContext,用于访问输出媒体文件。
123+
- avformat_write_header()
124+
向输出文件写入文件头信息。
125+
- av_write_trailer()
126+
向输出文件写入文件尾信息。
127+
128+
129+
### 解封装demuxer
130+
1.分配解复用器上下文avformat_alloc_context
131+
2.根据url 打开本地文件或网络流avformat_open_input
132+
3.读取媒体的部分数据包以获取码流信息avformat_find_stream_info
133+
4.读取码流信息:循环处理
134+
4.1 从文件中读取数据包av_read_frame
135+
4.2 定位文件avformat_seek_file 或av_seek_frame
136+
5.关闭解复用器avformat_close_input
137+
138+
139+
140+
### 转封装
141+
从一种视频容器转成另一种视频容器
142+
所谓的封装格式转换, 就是在AVI , FLV , MKV , MP4 这些格式之间转换( 对
143+
应.avi,.flv,.mkv,.mp4 文件)。需要注意的是,本程序并不进行视音频的编码和解码工作。
144+
而是直接将视音频压缩码流从一种封装格式文件中获取出来然后打包成另外一种封装格式
145+
的文件。

VideoDevelopment/FFmpeg/AAC.md

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)