# Technical Documentation: xufuji456/FFmpegAndroid

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/xufuji456/FFmpegAndroid)

### Overview (`README.md`)

# FFmpegAndroid

### [FFmpeg官方文档](https://ffmpeg.org/)
### [FFmpeg编译流程](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/FFmpeg_compile_shell.md)
### [FFmpeg常用命令行](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/FFmpeg_command_line.md)
### [FFmpeg源码分析](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/FFmpeg_sourcecode.md)
### [JNI与NDK开发](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/JNI_develop_practice.md)
### [音视频知识汇总](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/multimedia_knowledge.md)
### [ijkplayer播放器架构](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/player_framework.md)

----------------------------------------------------------------------------------------------------

常见的流媒体传输协议包括：RTP、RTMP、RTCP、RTSP，流媒体应用协议有HLS、DASH，</br>
WebRTC设计传输协议有SDP、ICE、NAT、STUN等，常用视频编码协议有H264、HEVC、VVC，</br>
常用的视频封装格式有mp4，关于C/C++语言标准有C11、C20++等，书籍包括音视频编解码等。</br>
详细列表可以查阅：[多媒体协议与书籍](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/multimedia_protocol.md)

音视频工作方向包括:直播、短视频、流媒体传输、视频播放器、音乐播放器、音视频算法、</br>
流媒体后端、音视频编辑、图像处理(个人概括，具体方向不限于此)。</br>
详情可查阅：[音视频工作方向](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/multimedia_work.md)

### 音视频基础知识:


### 音视频进阶成长:


### 音视频开源库:


### Joining the group to learn FFmpeg:

---

### Doc FFmpeg Command Line (`doc/FFmpeg_command_line.md`)

# 前言
FFmpeg多媒体库支持的命令行调用分为三个模块：ffmpeg、ffprobe、ffplay。<br>
其中ffmpeg命令行常用于音视频剪切、转码、滤镜、拼接、混音、截图等；<br>
ffprobe用于检测多媒体流格式；ffplay用于播放视频,包括本地与网络视频。<br>
详情可查阅FFmpeg官方文档：[ffmpeg Documentation](https://ffmpeg.org/documentation.html)<br>
更详细命令行处理可查看博客：[FFmpeg命令行汇总](https://blog.csdn.net/u011686167/article/details/120879467)<br>

# 一、ffmpeg命令行
## 1、命令行参数介绍

 | Print help/info:   | Description                    |
 |:-------------------|:-------------------------------|
 | --help topic       | show help                      |
 | -version           | show version                   |
 | -formats           | show available formats         |
 | -muxers            | show available muxers          |
 | -demuxers          | show available demuxers        |
 | -devices           | show available devices         |
 | -codecs            | show available codecs          |
 | -decoders          | show available decoders        |
 | -encoders          | show available encoders        |
 | -protocols         | show available protocols       |
 | -filters           | show available filters         |
 | -pix_fmts          | show available pixel formats   |
 | -sample_fmts       | show available sample formats  |
 | -hwaccels          | show available HW acceleration |

 | Global options:    | Description                    |
 |:-------------------|:-------------------------------|
 | -v loglevel        | set logging level              |
 | -y                 | overwrite output files         |
 | -n                 | never overwrite output files   |
 | -filter_threads    | number of filter threads       |
 | -vol volume        | change audio volume(256=normal)|

 | main options:      | Description                    |
 |:-------------------|:-------------------------------|
 | -f fmt             | force format                   |
 | -c codec           | codec name                     |
 | -codec codec       | codec name                     |
 | -t duration        | duration seconds of audio/video|
 | -to time_stop      | record or transcode stop time  |
 | -ss time_off       | set the start time offset      |
 | -frames number     | set the number of frames       |
 | -discard           | discard                        |
 | -disposition       | disposition                    |

 | Video options:     | Description                    |
 |:-------------------|:-------------------------------|
 | -vframes number    | set the number of video frames |
 | -r rate            | set frame rate (Hz value)      |
 | -s size            | set frame size                 |
 | -aspect aspect     | set aspect ratio (4:3, 16:9)   |
 | -vn                | disable video                  |
 | -vcodec codec      | force video codec              |
 | -vf filter_graph   | set video filters              |
 | -ab bitrate        | audio bitrate (please use -b:a)|
 | -b bitrate         | video bitrate (please use -b:v)|

 | Audio options:     | Description                    |
 |:-------------------|:-------------------------------|
 | -aframes number    | set the number of audio frames |
 | -aq quality        | set audio quality              |
 | -ar rate           | set audio sampling rate (in Hz)|
 | -ac channels       | set number of audio channels   |
 | -an                | disable audio                  |
 | -acodec codec      | force audio codec              |
 | -vol volume        | change audio volume(256=normal)|
 | -af filter_graph   | set audio filters              |

命令行整体格式：以ffmpeg开头，参数之间用空格隔开，每个参数key以"-"开头，后面跟着参数value，输出文件放在命令行最后。<br>

## 2、音频常见操作
### 2.1 音频转码
直接转码：<br>
ffmpeg -i input.mp3 output.m4a<br>
指定编码器、采样率、声道数转码：<br>
ffmpeg -i input.mp3 -acodec aac -ac 2 -ar 44100 output.m4a<br>

### 2.2 音频剪切
-ss 10指定从第10秒开始，-t 20代表剪切20秒<br>
ffmpeg -i input.mp3 -ss 10 -t 20 cut.mp3<br>

### 2.3 音频拼接
ffmpeg -i concat:"hello.mp3|world.mp3" -acodec copy -vn concat.mp3<br>

### 2.4 音频混音
使用amix，参数inputs代表输入流个数，duration有longest、shortest、first三种模式，weights设置每条流音量权重占比：<br>
ffmpeg -i hello.mp3 -i world.mp3 -filter_complex amix=inputs=2:duration=first -vn mix.mp3<br>
使用amerge，合并成多声道输出：<br>
ffmpeg -i hello.mp3 -i world.mp3 -filter_complex [0:a][1:a]amerge=inputs=2[aout] -map [aout] merge.mp3<br>

### 2.5 空灵音效
aecho接收4个参数：in_gain (0, 1]；out_gain (0, 1]；delays (0 - 90000]；decays (0 - 1.0]<br>
ffmpeg -i input.mp3 -af aecho=0.8:0.8:1000:0.5 echo.mp3<br>

### 2.6 惊悚音效
tremolo接收2个参数：frequency [0.1, 20000.0]；depth (0, 1]<br>
ffmpeg -i input.mp3 -af tremolo=5:0.9 tremolo.mp3<br>

### 2.7 搞笑音效
搞笑音效通过调节音速实现，使用atempo：<br>
ffmpeg -i input.mp3 -filter_complex atempo=0.5 atempo.mp3<br>

### 2.8 静音检测
ffmpeg -i input.mp3 -af silencedetect=noise=0.0001 -f null -<br>

### 2.9 修改音量
ffmpeg -i input.mp3 -af volume=0.5 volume.mp3<br>

### 2.10 抽取音频
从视频抽取音频，直接disable视频流：<br>
ffmpeg -i input.mp4 -vn out.mp3<br>
从视频抽取音频，disable视频流，音频进行转码：<br>
ffmpeg -i input.mp4 -acodec aac -vn out.m4a<br>
从视频抽取音频，如果存在多音轨，可指定某个音轨：<br>
ffmpeg -i input.mp4 -map 0:1 -vn out.mp3<br>

## 3、视频常见操作
### 3.1 视频剪切
基本剪切，指定起始时间、剪切时长：<br>
ffmpeg -i input.mp4 -ss 10 -t 20 -codec copy cut.mp4<br>
精确剪切，包含多音轨，-map 0代表所有track流进行剪切，-accurate_seek代表精确seek：<br>
ffmpeg -i input.mp4 -ss 10 -accurate_seek -t 20 -map 0 -codec copy cut.mp4<br>

### 3.2 视频转码
使用-vcodec指定视频编码，-acodec指定音频编码，-s 640x480指定视频分辨率，<br>
-b 200k指定码率，-r 20指定帧率，这样达到视频压缩效果：<br>
ffmpeg -i input.mp4 -vcodec libx264 -acodec aac -s 640x480 -b 200k -r 20 transcode.mp4<br>

### 3.3 视频截图
使用-vframes指定截图数量，-ss指定起始时间放在-i前面，这样保证先seek到指定位置再截图。<br>
如果是先-i指定输入文件再-ss，是从时间0开始解码，直到指定时间再截图，这样效率太低：<br>
ffmpeg -ss 10 -i input.mp4 -f image2 -vframes 1 -an screenshot.jpg<br>

### 3.4 图片水印
使用-filter_complex指定位置overlay=x:y，如下所示：<br>
ffmpeg -i input.mp4 -i logo.png -filter_complex overlay=10:20 pic_watermark.mp4<br>
如果要灵活设置左上角、右上角、左下角、右下角位置，可以使用case语句，其中main_w代表视频宽度，<br>
main_h代表视频高度，overlay_w代表水印宽度，overlay_h代表水印高度：<br>
```
public static String obtainOverlay(int offsetX, int offsetY, int location) {
    switch (location) {
        case 2:
            return "overlay='(main_w-overlay_w)-" + offsetX + ":" + offsetY + "'";
        case 3:
            return "overlay='" + offsetX + ":(main_h-overlay_h)-" + offsetY + "'";
        case 4:
            return "overlay='(main_w-overlay_w)-" + offsetX + ":(main_h-overlay_h)-" + offsetY + "'";
        case 1:
        default:
            return "overlay=" + offsetX + ":" + offsetY;
    }
}

public static String[] addWaterMarkImg(String inputPath, String imgPath, int location,
                                           int offsetXY, String outputPath) {
    String overlay = obtainOverlay(offsetXY, offsetXY, location);
    String waterMarkCmd = "ffmpeg -i %s -i %s -filter_complex %s -preset:v superfast %s";
    waterMarkCmd = String.format(waterMarkCmd, inputPath, imgPath, overlay, outputPath);
    return waterMarkCmd.split(" ");
}
```
### 3.5 GIF水印
使用-ignore_loop 0代表GIF循环显示，其他操作与图片水印一致：<br>
ffmpeg -i input.mp4 -ignore_loop 0 -i logo.gif -filter_complex overlay=10:20 gif_mark.mp4<br>

### 3.6 去除水印
使用delogo命令，然后指定水印位置：<br>
ffmpeg -i input.mp4 -filter_complex delogo=x=10:y=20:w=90:h=30 delogo.mp4<br>

### 3.7 视频拼接
视频拼接分为垂直拼接、水平拼接，还有前后拼接，这里主要介绍垂直与水平拼接，其中使用hstack做水平拼接，vstack做垂直拼接：<br>
ffmpeg -i input1.mp4 -i input2.mp4 -filter_complex hstack out.mp4<br>

### 3.8 视频翻转
使用reverse实现视频翻转，但是处理比较耗时：<br>
ffmpeg -i input.mp4 -vf reverse -an output.mp4<br>

### 3.9 视频降噪
使用-nr代表noise reduction，进行视频降噪：<br>
ffmpeg -i in.mp4 -nr 500 out.mp4<br>

### 3.10 视频抽帧
ffmpeg -ss 20 -accurate_seek -t 10 -i input.mp4 -an -r 5 %3d.jpg<br>

### 3.11 播放速度
使用setpts设置视频速度，atempo设置音频速度：<br>
ffmpeg -i in.mp4 -filter_complex [0:v]setpts=%.2f*PTS[v];[0:a]atempo=%.2f[a] -map [v] -map [a] out.mp4<br>

### 3.12 黑白视频
ffmpeg -i in.mp4 -vf lutyuv='u=128:v=128' out.mp4

# 二、ffplay命令行
ffplay主要用于播放视频，也可以播放网络流，示例如下：<br>
ffplay -i beyond.mp4<br>

# 三、ffprobe命令行
ffprobe主要用于检测多媒体信息，包括时长、视频分辨率、帧率、音频采样率、声道数、每个stream流信息等等。<br>
支持显示形式包括：json和xml，例如-print_format json<br>
ffprobe -i input.mp4 -show_streams -show_format -print_format json<br>

如果要显示每帧数据信息，使用-show_frames可以显示pts、packet_size、duration、frame_type等信息：<br>
ffprobe -i input.mp4 -show_frames<br>

如果只要显示视频流，使用-select_streams v。其中v代表video，a代表audio，s代表subtitle。<br>
ffprobe -i input.mp4 -show_frames -select_streams v<br>

---

### Doc FFmpeg Compile Shell (`doc/FFmpeg_compile_shell.md`)

# 前言
FFmpeg是一个跨平台的多媒体库，也是目前音视频领域应用最广泛的库。包括libavcodec、libavformat、libavutil、</br>
libavdevice、libavfilter、libswscale、libswresample、libpostproc等模块。其中avcodec用于编解码，</br>
avformat用于解封装，avutil是提供工具类，avdevice用于各平台的设备接入，avfilter提供滤镜操作，</br>
swscale提供图像缩放与像素格式转换，swresample提供音频重采样，postproc提供高级处理。</br>
更详细编译脚本可查看博客：[FFmpeg编译脚本分析](https://blog.csdn.net/u011686167/article/details/120390739)<br>

# 一、准备工作
## 1、下载ffmpeg源码
使用git命令：git clone https://github.com/FFmpeg/FFmpeg.git。

## 2、下载ndk源码
在Android开发者文档可以下载到ndk源码，[ndk下载链接](https://developer.android.com/ndk/downloads)。
根据实际需求选择对应ndk版本，建议下载ndk-r20b稳定版。mac电脑配置ndk系统环境变量步骤如下：
(1)、在命令行输入vim ~/.bash_profile
(2)、输入i进行编辑模式
(3)、编写export NDK_PATH=xxx/xxx/android-ndk-r20b
(4)、按下esc退出编辑模式，输入:wq保存并退出

# 二、编译ffmpeg源码
## 1、分析configure结构
在FFmpeg源码目录有个configure配置脚本，使用./configure --help进行查看，可以看到如下结构的编译选项：</br>

 | Help options:           | Description                 |
 |:------------------------|:----------------------------|
 | --help                  | print this message          |
 | --list-decoders         | show all available decoders |
 | --list-encoders         | show all available encoders |
 | --list-hwaccels         | show all available hardware |
 | --list-demuxers         | show all available demuxers |
 | --list-muxers           | show all available muxers   |
 | --list-parsers          | show all available parsers  |
 | --list-protocols        | show all available protocols|
 | --list-filters          | show all available filters  |

 | Licensing options:      | Description                 |
 |:------------------------|:----------------------------|
 | --enable-gpl            | allow use of GPL code       |
 | --enable-version3       | upgrade (L)GPL to version 3 |
 | --enable-nonfree        | allow use of nonfree code   |

 | Configuration options:  | Description                 |
 |:------------------------|:----------------------------|
 | --prefix=PREFIX         | install in PREFIX           |
 | --disable-static        | do not build static libs    |
 | --enable-shared         | build shared libraries [no] |
 | --enable-small          | optimize for size           |
 | --disable-all           | disable components, libs    |
 | --disable-autodetect    | disable detect external libs|

 | Program options:        | Description                 |
 |:------------------------|:----------------------------|
 | --disable-programs      | don't build command line    |
 | --disable-ffmpeg        | disable ffmpeg build        |
 | --disable-ffplay        | disable ffplay build        |
 | --disable-ffprobe       | disable ffprobe build       |

 | Component options:      | Description                 |
 |:------------------------|:----------------------------|
 | --disable-avdevice      | disable libavdevice build   |
 | --disable-avcodec       | disable libavcodec build    |
 | --disable-avformat      | disable libavformat build   |
 | --disable-swresample    | disable libswresample build |
 | --disable-swscale       | disable libswscale build    |
 | --disable-postproc      | disable libpostproc build   |
 | --disable-avfilter      | disable libavfilter build   |
 | --disable-pthreads      | disable pthreads            |
 | --disable-network       | disable network support     |

 | Individual component:   | Description                 |
 |:------------------------|:----------------------------|
 | --disable-everything    | disable all components      |
 | --disable-encoder=NAME  | disable encoder NAME        |
 | --enable-encoder=NAME   | enable encoder NAME         |
 | --disable-encoders      | disable all encoders        |
 | --disable-decoder=NAME  | disable decoder NAME        |
 | --enable-decoder=NAME   | enable decoder NAME         |
 | --disable-decoders      | disable all decoders        |
 | --disable-muxer=NAME    | disable muxer NAME          |
 | --enable-muxer=NAME     | enable muxer NAME           |
 | --disable-muxers        | disable all muxers          |
 | --disable-demuxer=NAME  | disable demuxer NAME        |
 | --enable-demuxer=NAME   | enable demuxer NAME         |
 | --disable-demuxers      | disable all demuxers        |
 | --enable-parser=NAME    | enable parser NAME          |
 | --disable-parser=NAME   | disable parser NAME         |
 | --disable-parsers       | disable all parsers         |
 | --enable-protocol=NAME  | enable protocol NAME        |
 | --disable-protocol=NAME | disable protocol NAME       |
 | --disable-protocols     | disable all protocols       |
 | --enable-filter=NAME    | enable filter NAME          |
 | --disable-filter=NAME   | disable filter NAME         |
 | --disable-filters       | disable all filters         |

 | External library:       | Description                              |
 |:------------------------|:-----------------------------------------|
 | --disable-avfoundation  | disable Apple AVFoundation framework     |
 | --enable-jni            | enable JNI support [no]                  |
 | --enable-libaom         | enable AV1 video codec via libaom [no]   |
 | --enable-libass         | enable libass subtitles rendering [no]   |
 | --enable-libdav1d       | enable AV1 decoding via libdav1d [no]    |
 | --enable-libfdk-aac     | enable AAC de/encoding via libfdk-aac    |
 | --enable-libfontconfig  | enable libfontconfig [no]                |
 | --enable-libfreetype    | enable libfreetype, needed for drawtext  |
 | --enable-libfribidi     | enable libfribidi, improves drawtext     |
 | --enable-libmp3lame     | enable MP3 encoding via libmp3lame [no]  |
 | --enable-libopencv      | enable video filtering via libopencv [no]|
 | --enable-libopenh264    | enable H.264 encoding via OpenH264 [no]  |
 | --enable-libopus        | enable Opus de/encoding via libopus [no] |
 | --enable-librtmp        | enable RTMP[E] support via librtmp [no]  |
 | --enable-libshine       | enable fixed-point MP3 encoding          |
 | --enable-libsoxr        | enable Include libsoxr resampling [no]   |
 | --enable-libspeex       | enable Speex de/encoding via libspeex    |
 | --enable-libtensorflow  | enable TensorFlow as a DNN module [no]   |
 | --enable-libvorbis      | enable Vorbis en/decoding via libvorbis  |
 | --enable-libvpx         | enable VP8 and VP9 de/encoding via libvpx|
 | --enable-libx264        | enable H.264 encoding via x264 [no]      |
 | --enable-libx265        | enable HEVC encoding via x265 [no]       |
 | --enable-mediacodec     | enable Android MediaCodec support [no]   |
 | --enable-opengl         | enable OpenGL rendering [no]             |
 | --enable-openssl        | enable openssl, needed for https support |

 | Toolchain options:      | Description                 |
 |:------------------------|:----------------------------|
 | --arch=ARCH             | select architecture         |
 | --cpu=CPU               | select the minimum CPU      |
 | --cross-prefix=PREFIX   | use PREFIX for compile tool |
 | --enable-cross-compile  | assume a cross-compiler     |
 | --sysroot=PATH          | root of cross-build tree    |
 | --target-os=OS          | compiler targets OS         |
 | --toolchain=NAME        | set tool according to name  |
 | --nm=NM                 | use nm tool NM [nm -g]      |
 | --ar=AR                 | use archive tool AR [ar]    |
 | --as=AS                 | use assembler AS            |
 | --strip=STRIP           | use strip tool STRIP [strip]|
 | --cc=CC                 | use C compiler CC [gcc]     |
 | --cxx=CXX               | use C compiler CXX [g++]    |
 | --ld=LD                 | use linker LD               |
 | --host-cc=HOSTCC        | use host C compiler HOSTCC  |
 | --host-cflags=HCFLAGS   | use HCFLAGS when compiling  |
 | --host-ld=HOSTLD        | use host linker HOSTLD      |
 | --host-ldflags=HLDFLAGS | use HLDFLAGS when linking   |
 | --host-extralibs=HLIBS  | use libs HLIBS when linking |
 | --host-os=OS            | compiler host OS            |
 | --extra-cflags=ECFLAGS  | add ECFLAGS to CFLAGS       |
 | --extra-cxxflags=ECFLAGS| add ECFLAGS to CXXFLAGS     |
 | --extra-ldflags=ELDFLAGS| add ELDFLAGS to LDFLAGS     |

## 2、修改so后缀
默认编译出来的so库包括avcodec、avformat、avutil、avdevice、avfilter、swscale、</br>
avresample、swresample、postproc，编译出来so是个软链接，真正so名字后缀带有一长串主版本号与子版本号，</br>
这样的so名字在Adnroid平台无法识别。所以我们需要修改一下，打开该文件并搜索SLIBNAME，找到如下命令行：</br>
```
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'

LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'

SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'

SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'
```
替换为：
```
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'

LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'

SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'

SLIB_INSTALL_LINKS='$(SLIBNAME)'
```
## 3、修改hevc_mvs.c
在linux或者mac平台交叉编译过程中，可能在libavcodec/hevc_mvs.c报错：
```
libavcodec/hevc_mvs.c: In function 'derive_spatial_merge_candidates':
libavcodec/hevc_mvs.c:208:15: error: 'y0000000' undeclared (first use in this function)
((y ## v) >> s->ps.sps->log2_min_pu_size))
^
libavcodec/hevc_mvs.c:204:14: note: in definition of macro 'TAB_MVF'
tab_mvf[(y) * min_pu_width + x]
^
libavcodec/hevc_mvs.c:274:16: note: in expansion of macro 'TAB_MVF_PU'
(cand && !(TAB_MVF_PU(v).pred_flag == PF_INTRA))
^
libavcodec/hevc_mvs.c:368:23: note: in expansion of macro 'AVAILABLE'
is_available_b0 = AVAILABLE(cand_up_right, B0) &&
^
libavcodec/hevc_mvs.c:208:15: note: each undeclared identifier is reported only once for each function it appears in
((y ## v) >> s->ps.sps->log2_min_pu_size))
^
libavcodec/hevc_mvs.c:204:14: note: in definition of macro 'TAB_MVF'
tab_mvf[(y) * min_pu_width + x]
^
libavcodec/hevc_mvs.c:274:16: note: in expansion of macro 'TAB_MVF_PU'
(cand && !(TAB_MVF_PU(v).pred_flag == PF_INTRA))
```
原因是hevc_mvs.c会引用libavutil/timer.h文件(参考：ijkplayer#issues#4093)
```
#if CONFIG_LINUX_PERF
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <sys/ioctl.h>
#include <asm/unistd.h>
#include <linux/perf_event.h>
#endif
```
在sys/ioctl.h中最终会引用asm/termbits .h文件有#define B0 0000000，导致与hevc_mvs.c的B0命名冲突。</br>
解决方法有2种：把B0改为b0、xB0改为xb0、yB0改为yb0。</br>
或者在脚本添加：export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-linux-perf"</br>

## 4、编译脚本
在ffmpeg源码根目录创建一个shell脚本，比如命名为build_ffmpeg.sh，以mac编译环境为例，</br>
ndk旧版本已经过时，google官方放弃了gcc交叉编译工具链，转而使用clang编译工具链，因为clang编译速度快、效率高。</br>
下面例子是采用ndk新版的clang进行编译(如果是使用虚拟机在linux环境交叉编译FFmpeg，下面的darwin改为linux)。具体如下：</br>
```
/* Detailed source-code truncated for AI context efficiency. */
```
按照上面shell脚本分为4段。第一段make clean清除缓存，set -e设置编译出错后马上退出，archbit=xx指定cpu架构是32位还是64位。</br>
第二段if...else...fi用来条件编译不同cpu架构对应字段的值。第三段用export关键字声明宏定义，其中PREFIX是指定输出文件路径。</br>
第四段是一个执行函数，按照ffmpeg的configure规范进行编写。函数里面的enable代表开启，disable代表关闭，也就是对ffmpeg进行剪裁，</br>
根据我们需要的功能进行enable。make命令是执行编译，make install命令是执行安装。最后的build_android是执行函数。</br>
初次执行shell脚本，需要修改脚本权限，使用linux命令：chmod 777 build_ffmpeg.sh。执行脚本只需要一行命令，</br>
即在命令行输入./build_ffmpeg.sh。编译过程中，命令行会不断打印编译日志，等待命令行输出INSTALL xxx关键字代表编译完成。</br>

## 5、编译问题分析
编译过程中，可能会出现这样那样的问题，比如ndk配置不对、脚本语法不对。但不用慌，编译输出窗口会描述出错原因，</br>
在ffbuild/config.log会告诉你问题的具体原因所在，顺着思路一般可以找到问题的答案。</br>

# 三、so库剪裁
ffmpeg强大之处在于支持按需编译，进行弹性剪裁。可以使用--disable-everything关闭所有模块，</br>
可以使用enable/disable来开启关闭某个模块，或者某个编解码器、某个封装器、某个协议。</br>

## 1、encoders与decoders
encoder和decoder在libavcodec模块，可以用./configure --list-encoders或者ffmpeg --encoders查看支持的编码器。</br>
同样地，可以用./configure --list-decoders或者ffmpeg --decoders查看支持的解码器。我们可以先--disable-encoders，</br>
--enable-encoder=aac,h264 其中lib开头的表示第三方库。</br>

## 2、muxers与demuxers
muxer和demuxer在libavformat模块，可用./configure --list-muxers或者ffmpeg --muxers查看支持的封装器。</br>
同样地，可用./configure --list-demuxers或者ffmpeg --demuxers查看支持的解封装器。先--disable-muxers，再--enable-muxer=mp3</br>

## 3、protocols
protocol也是在libavformat模块中，./configure --list-protocols或者ffmpeg --protocols查看支持的协议，</br>

## 4、parsers
parser在libavfilter模块中，提供各种filter，比如音频：amix、atempo，视频：rotate、hflip，</br>
我们可以根据需求--enable-parser来开启，可使用./configure --list-parsers查看具体列表。</br>

# 四、编译过程分析
编译过程包括：预编译、编译、汇编、链接。详细可以查阅书籍<程序员的自我修养>

## 1、预编译
预编译处理(.c/.cpp->.i)，对源文件的伪指令进行处理。
伪指令包括：宏定义(#define)、条件编译指令(#ifdef #elseif #endif)、头文件包含指令(#include)

## 2、编译
编译(.i->.s)，对经过预编译处理文件进行语法分析，编译为汇编文件。

## 3、汇编
汇编(.i->.o)，把汇编代码翻译为机器码，也就是二进制的目标文件。

## 4、链接
链接(.o->.so/.a/.lib)，把所有目标文件链接成动态库、静态库文件。

## 5、FFmpeg的makefile分析
makefile主要发生在汇编阶段，把所有依赖的目标文件添加进去。以FFmpeg的AVFilter模块makefile为例(有省略)：
```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Doc FFmpeg Sourcecode (`doc/FFmpeg_sourcecode.md`)

# 前言
FFmpeg是一个跨平台的多媒体库，也是目前音视频领域应用最广泛的库。包括libavcodec、libavformat、libavutil、</br>
libavdevice、libavfilter、libswscale、libswresample、libpostproc等模块。其中avcodec用于编解码，</br>
avformat用于解封装，avutil是提供工具类，avdevice用于各平台的设备接入，avfilter提供滤镜操作，</br>
swscale提供图像缩放与像素格式转换，swresample提供音频重采样，postproc提供高级处理。</br>
在这里，按照每个模块功能进行分析，如有错漏不当之处，敬请指出。</br>

### 1：AVIOContext、IO模型与协议
[AVIOContext结构体](https://blog.csdn.net/u011686167/article/details/121452343)

### 2：AVFormatContext连接FFmpeg的桥梁
[AVFormatContext](https://blog.csdn.net/u011686167/article/details/121483584)

### 3：AVCodecContext编解码器上下文
[AVCodecContext](https://blog.csdn.net/u011686167/article/details/121506335)

### 4：AVStream码流
[码流数组](https://blog.csdn.net/u011686167/article/details/121528354)

### 5：AVFrame与AVPacket
[AVFrame与AVPacket](https://blog.csdn.net/u011686167/article/details/121551041)

### 6：avformat_open_input()打开媒体流
[打开媒体流](https://blog.csdn.net/u011686167/article/details/121578185)

### 7：avformat_find_stream_info分析码流信息
[分析码流信息](https://blog.csdn.net/u011686167/article/details/121630969)

### 8：av_read_frame()读取音视频帧
[读取音视频帧](https://blog.csdn.net/u011686167/article/details/121642861)

### 9：av_parser_parse2()解析数据包
[解析数据包](https://blog.csdn.net/u011686167/article/details/121667755)

### 10：av_register_all()注册封装器与解封装器
[注册封装器与解封装器](https://blog.csdn.net/u011686167/article/details/121691245)

### 11：avdevice_register_all()注册设备
[注册设备](https://blog.csdn.net/u011686167/article/details/121716973)

### 12：avfilter_register_all()注册AVFilter
[注册AVFilter](https://blog.csdn.net/u011686167/article/details/121721099)

### 13：avcodec_register_all()注册编解码器
[注册编解码器](https://blog.csdn.net/u011686167/article/details/121723790)

### 14：avcodec_find_decoder()查找编解码器
[查找编解码器](https://blog.csdn.net/u011686167/article/details/121726609)

### 15：log日志系统分析
[log日志系统](https://blog.csdn.net/u011686167/article/details/121758769)

### 16：内存管理系统
[内存管理系统](https://blog.csdn.net/u011686167/article/details/121781824)

### 17：图像常用操作
[图像常用操作](https://blog.csdn.net/u011686167/article/details/121758769)

### 18：SwsContext图像转换上下文
[SwsContext](https://blog.csdn.net/u011686167/article/details/121875305)

### 19：sws_scale图像缩放与图像转换
[sws_scale](https://blog.csdn.net/u011686167/article/details/121879397)

### 20：音频采样格式相关API
[音频采样格式](https://blog.csdn.net/u011686167/article/details/121917453)

---

### Doc JNI Develop Practice (`doc/JNI_develop_practice.md`)

# 前言
JNI是Java本地接口，定义Android从应用代码(以Java或kotlin编程语言编写)到本地代码(C/C++编写)交互编译成字节码的一种方式。</br>
文档[Java Native Interface Specification](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html)</br>

### NDK编译脚本
[Android.mk与CMake编译](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/NDK_compile_shell.md)

### 相关介绍文章如下：
[NDK编译脚本](https://blog.csdn.net/u011686167/article/details/106458899)</br>
[JNI开发规范](https://blog.csdn.net/u011686167/article/details/81784979)</br>
[JNI全面介绍与最佳实践](https://blog.csdn.net/u011686167/article/details/124132719)</br>

---

### Doc NDK Compile Shell (`doc/NDK_compile_shell.md`)

# 前言
Android NDK以前默认使用Android.mk与Application.mk进行构建，但是在Android Studio2.2之后推荐使用CMake进行编译。</br>
CMake是跨平台编译工具，全称为cross platform make，内建c、c++、java自动相依性分析功能。NDK通过工具链支持CMake，</br>
工具链文件是用于自定义交叉编译工具链的CMake文件。用于NDK的工具链位于<NDK>/build/cmake/android.toolchain.cmake，</br>
关于CMake更多详情请参考官网：[cmake官网](https://cmake.org/documentation/)。下面对比下Android.mk与CMakeLists.txt的语法。</br>
更详细脚本分析可查看博客：[NDK编译脚本分析](https://blog.csdn.net/u011686167/article/details/106458899)<br>

# 一、Android.mk语法
以动态库编译hello模块为例，完整脚本如下：
```
WORKING_DIR := $(call my-dir)
LOCAL_PATH := $(WORKING_DIR)

include $(CLEAR_VARS)
LOCAL_ARM_MODE  := arm
LOCAL_MODULE    := libffmpeg
LOCAL_SRC_FILES := $(LOCAL_PATH)/ffmpeg/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_ARM_MODE  := arm
#模块名称
LOCAL_MODULE    := hello
#源文件
LOCAL_SRC_FILES := hello.c
#头文件路径
LOCAL_C_INCLUDES := $(LOCAL_PATH)
#系统库依赖
LOCAL_LDLIBS    := -llog -lz -lm -landroid
#第三方动态库
LOCAL_SHARED_LIBRARIES := libffmpeg
#以动态库形式编译
include $(BUILD_SHARED_LIBRARY)
```
## 1、LOCAL_MODULE
声明模块名称，例如这里编译出来的动态库名称为libhello.so。

## 2、LOCAL_SRC_FILES
声明源文件列表，文件之间用空格分开，需要换行时使用'\'换行符。

## 3、LOCAL_C_INCLUDES
声明头文件路径，例如$(LOCAL_PATH)/xxx

## 4、LOCAL_CPP_EXTENSION
指定C++源文件除.cpp以外的文件扩展名，例如这样LOCAL_CPP_EXTENSION := .cpp .cxx .cc

## 5、LOCAL_CPP_FEATURES
指定依赖c++的某些功能，例如RTTI(运行时类型信息)：
LOCAL_CPP_FEATURES := rtti
使用c++异常检测：
LOCAL_CPP_FEATURES := exceptions

## 6、LOCAL_CFLAGS
在编译c和c++源文件时编译系统要传递的编译器标记，即指定额外的宏定义或编译选项。
LOCAL_CFLAGS += -I<path>

## 7、LOCAL_STATIC_LIBRARIES
共享静态库，作为第三方库被引用
LOCAL_STATIC_LIBRARIES := libavcodec libavutil libavformat libavfilter

## 8、LOCAL_SHARED_LIBRARIES
共享动态库，与共享静态库一样作为第三方库被引用
LOCAL_SHARED_LIBRARIES := libffmpeg

## 9、LOCAL_LDLIBS
额外链接器，一般为系统库，使用-l来引用
LOCAL_LDLIBS := -lz -lm

## 10、 LOCAL_ARM_MODE
ndk默认使用thumb模式来生成目标二进制文件，每条指令为16位宽。也可以指定为ARM模式，来生成32位ARM的目标文件：</br>
LOCAL_ARM_MODE := arm

## 11、LOCAL_ARM_NEON
用于开启NEON指令加速，仅对armeabi-v7a平台有效。为模块开启NEON：
LOCAL_ARM_NEON := true
为单独源文件开启NEON：
LOCAL_SRC_FILES := hello.c.neon

## 12、TARGET_ARCH
用于指向CPU架构，包括x86、x86_64、armeabi-v7a、 arm64-v8a

## 13、TARGET_PLATFORM
目标平台，对应Android API级别号，例如Android5.0系统镜像对应Android API级别21：android-21

## 14、打印信息
可用warning、debug、info、error级别来打印信息，如果是打印error信息，会终止编译。以warning为例：
$(warning 'This is a test')

## 15、if条件判断
采用ifeq关键字，然后左右变量放在括号体内，用逗号分隔：
```
ifeq($(TARGET_ABI), arm64-v8a)
$(debug 'This is arm64-v8a')
endif
```
# 二、Application.mk语法
Android.mk依赖Application.mk文件进行编译，一般Application.mk脚本如下所示：</br>
```
APP_STL      := c++_static
APP_DEBUG    := false
APP_OPTIM    := release
APP_CPPFLAGS := -frtti
APP_PLATFORM := android-16
APP_ABI      := armeabi-v7a arm64-v8a
```
## 1、APP_ABI
与Android.mk的TARGET_ABI对应，包括CPU架构有：x86、x86_64、armeabi-v7a、arm64-v8a，支持所有平台这样表示：</br>
APP_ABI := all

## 2、APP_BUILD_SCRIPT
指向编译脚本的路径，一般Android.mk和Application.mk都位于jni目录，默认指向jni/Android.mk路径，如果是其他路径，</br>
需要使用此变量来指定绝对路径：
APP_BUILD_SCRIPT := /xx/xx/Android.mk

## 3、APP_OPTIM
编译优化选项，调试模式为debug，发布模式为release。在调试模式下，会保留symbol符号表；在发布模式下，会开启优化，去掉symbol符号表。

## 4、APP_PLATFORM
指定编译平台，面向于Android API级别，对应gradle声明的minSdkVersion。如果不声明，默认为ndk支持的最低API版本

## 5、APP_STL
声明使用c++的标准库，默认为system STL。其他选项包括c++_static、c++_shared和none

# 三、CMakeLists.txt语法

以编译hello模块以及依赖ffmpeg模块为例：
```
cmake_minimum_required(VERSION 3.4.1)
#添加动态库，包含源文件路径
add_library( hello
             SHARED
             src/main/jni/hello.c)
#添加第三方动态库
add_library( ffmpeg
             SHARED
             IMPORTED )
#指定第三方库路径
set_target_properties( ffmpeg
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/${CMAKE_ANDROID_ARCH_ABI}/libffmpeg.so )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
#指定头文件路径
include_directories(src/main/cpp)
if(${CMAKE_ANDROID_ARCH_ABI} MATCHES "armeabi-v7a")
    include_directories(src/main/cpp/include/armeabi-v7a)
    message("This is armeabi-v7a")
elseif(${CMAKE_ANDROID_ARCH_ABI} MATCHES "arm64-v8a")
    include_directories(src/main/cpp/include/arm64-v8a)
    message("This is arm64-v8a")
endif()
#查找系统库
find_library( # Sets the name of the path variable.
              log-lib
              log )
#链接目标库
target_link_libraries( hello
                       ffmpeg
                       ${log-lib} )
```
## 1、add_library
传递三个参数，第一个参数是模块名称，第二个参数是SHARED或者STATIC。如果是源文件模块，第三个参数是源文件列表；</br>
如果是第三方库，第三个参数是IMPORTED。

## 2、set_target_properties
用于指定第三方库路径，IMPORT_LOCATION一般是指向src/main/cpp目录

## 3、include_directories
用于指定头文件路径，头文件路径可以有多个

## 4、find_library
用于查找系统库，比如Android系统的log日志库

## 5、target_link_libraries
链接目标库，把依赖库都链接到目标库中

## 6、if条件判断
与Android.mk稍有差异，CMake采用if...MATCHES形式，例如：
if(${CMAKE_ANDROID_ARCH_ABI} MATCHES "armeabi-v7a")
......
endif()

## 7、打印日志
与Android.mk不同的是，CMake采用message函数来打印日志，括号体传入msg内容
message("hello, cmake")

## 8、命令行参数
命令行参数前面统一加上-D，常用的参数：

* -DANRDOID_ABI :android的ABI架构平台

* -DANDROID_NDK :ndk路径

* -DANDROID_ARM_MODE :arm模式/thumb模式

* -DANDROID_ARM_NEON :是否开启arm neon加速，针对armeabi-v7a平台

* -DANDROID_TOOLCHAIN :编译工具链

* -DANDROID_NATIVE_API_LEVEL :与ANDROID_PLATFORM相同，对应minSdkVersion

* -DCMAKE_BUILD_TYPE :编译类型，debug或release

* -DCMAKE_MAKE_PROGRAM :编译程序

* -DCMAKE_TOOLCHAIN_FILE :编译文件

## 9、命令行编译
以cmake作为关键字，后面带着指定参数，示例如下：
```
    cmake \
    -DANDROID_ABI=armeabi-v7a \
    -DANDROID_NDK=${HOME}/Android/Sdk/ndk-bundle \
    -DCMAKE_BUILD_TYPE=Debug \
    -DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.6.3155560/bin/ninja \
    -DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake \
    -DANDROID_NATIVE_API_LEVEL=23 \
    -DANDROID_TOOLCHAIN=clang
```
# 四、ndk编译配置
## 1、Android.mk方式配置
在gradle的defaultConfig配置ndk：
```
defaultConfig {
    ......
    ndk {
        moduleName "hello"
        abiFilters "armeabi-v7a", "arm64-v8a"
    }
}
```
然后配置jni源文件路径：
```
sourceSets {
    main {
        jniLibs.srcDir 'src/main/libs' // Enable to use libs
        jni.srcDirs 'src/main/jni' // Enable the automatic ndk-build
    }
}
```
另外配置Android.mk文件绝对路径：
```
externalNativeBuild {
    ndkBuild {
        "src/main/jni/Android.mk"
    }
}
```
## 2、CMake方式配置
前两步与Android.mk方式一样，配置脚本路径稍有差异：
```
externalNativeBuild {
    cmake {
        path "CMakeLists.txt"
    }
}
```
另外在defaultConfig设置cppFlags:
```
externalNativeBuild {
    cmake {
        cppFlags ""
    }
}
```
# 五、ndk编译过程
## 1、ndk-build编译
在命令行输入ndk-build后，会根据声明所支持的平台依次编译。首先是armeabi-v7a平台架构，把hello.c源文件编译成hello</br>
目标文件，然后链接成libhello.so动态库，最终安装到libs/armeabi-v7a目录下。

## 2、cmake在Gradle中编译
编译arm64-v8a平台架构的hello模块。首先把hello.c源文件编译成hello.c.o目标文件，然后链接成libhello.so动态库。</br>
生成的debug模式动态库在/build/intermediates/cmake/debug/obj/arm64-v8a目录下。

---

### Doc Multimedia Knowledge (`doc/multimedia_knowledge.md`)

# 前言
音视频多媒体涉及语音信号处理、数字图像处理、信息论、封装协议、编解码、渲染、网络传输、视频特效、音频特效等等。在特定场景，</br>
还会结合AI、机器学习ML、计算机视觉CV、自然语言理解NLP。比如AI智能编码，抽取视频帧用计算机视觉做人脸识别，用NLP做语音理解。</br>

### 1、音视频基本概念
[基本概念](https://blog.csdn.net/u011686167/article/details/108314078)

### 2、视频封装格式
[视频封装](https://blog.csdn.net/u011686167/article/details/108426708)

### 3、音频封装格式
[音频封装](https://blog.csdn.net/u011686167/article/details/108565360)

### 4、音视频编码
[编码器介绍](https://blog.csdn.net/u011686167/article/details/108590762)

### 5、音视频解码
[解码解码器介绍](https://blog.csdn.net/u011686167/article/details/108743947)

### 6、音效(均衡器、混响、重低音)
[基本音效](https://blog.csdn.net/u011686167/article/details/109191399)

### 7、杜比音效AC3与AC4
[杜比音效](https://blog.csdn.net/u011686167/article/details/113576628)

### 8、杜比视觉Dolby-Vision与HDR
[杜比视觉](https://blog.csdn.net/u011686167/article/details/113624068)

### 9、Matroska封装格式
[Matroska封装格式上](https://blog.csdn.net/u011686167/article/details/113791392)
[Matroska封装格式下](https://blog.csdn.net/u011686167/article/details/113796271)

### 10、新一代视频AV1编码器
[AV1编码器](https://blog.csdn.net/u011686167/article/details/113806322)

### 11、Android图像渲染框架
[Android图像渲染](https://blog.csdn.net/u011686167/article/details/118035545)

---

### Doc Multimedia Protocol (`doc/multimedia_protocol.md`)

## 多媒体协议与书籍
多媒体开发涉及非常多的多媒体协议，在这里整理一些常用的多媒体协议与多媒体书籍，</br>
欢迎大家补充其他相关协议与书籍，共同维护良好的开源社区。</br>

### 多媒体协议
常见的流媒体传输协议包括：RTP、SRTP、RTMP、RTCP、RTSP，流媒体应用协议有HLS、DASH，</br>
WebRTC网络传输协议有SDP、ICE、NAT、STUN、TURN等，常用视频编码协议有H264，</br>
常用的视频封装格式有mp4，关于C语言标准有C11、C17等，详细列表如下：
 |    protocol     |          download                               |     password    |
 |:----------------|:------------------------------------------------|:----------------|
 | H264            | https://pan.baidu.com/s/1I1Sfw0y8g_XQmylzWBnV6A |       vm5i      |
 | HLS             | https://pan.baidu.com/s/1cDl8FdJfioviWasApObVcg |       w5vh      |
 | RTP             | https://pan.baidu.com/s/13K1ZHXytq8_k-TT1Nu7P7g |       eg3s      |
 | SRTP            | https://pan.baidu.com/s/1fw3deX0GC3AYtzMt7RosWg |       v87w      |
 | SDP             | https://pan.baidu.com/s/10mCBI93awj4FkSOFy3_hbQ |       ks6g      |
 | RTCP            | https://pan.baidu.com/s/1Q5ZQS5Mh_D3g9JfNQ7J9sg |       c046      |
 | RTMP            | https://pan.baidu.com/s/1Vm4mi2KOdaelLcx9t426Mw |       c1wu      |
 | RTSP            | https://pan.baidu.com/s/1mxEwMaXjL4ml3jixmdr2lw |       n6hx      |
 | RTP(WebRTC)     | https://pan.baidu.com/s/1saXyutLmuBiiCRbzkmzyyQ |       8gvc      |
 | HTTP2           | https://pan.baidu.com/s/1a2LE3vkjhBpGfLALTk0YRA |       fwxk      |
 | STUN            | https://pan.baidu.com/s/1o6G80R6880rT4My6fVXtEg |       933a      |
 | ICE             | https://pan.baidu.com/s/1AEJxzf1Nflg98u35Eg3Yyg |       1u1w      |
 | NAT             | https://pan.baidu.com/s/1Kcup8UZhnF15lqgSIkNAWw |       w3oz      |
 | C11             | https://pan.baidu.com/s/1AH7-cT6jPpgkN-fcsxZiqQ |       p0ay      |
 | C++20           | https://pan.baidu.com/s/1Alsm2Ve8hiMb_UhYMnGPYg |       79ej      |
 | MP4             | https://pan.baidu.com/s/13WrU60CYPCRshPrmLOTtKA |       fa0f      |
 | DASH            | https://pan.baidu.com/s/1-38Erd4a9mtEUKzD3GMaig |       ctz7      |
 | DASH(ISO)       | https://pan.baidu.com/s/1UnxkaPeKVIsmddaYIrADdw |       buav      |
 | H265(ITU-T)     | https://pan.baidu.com/s/1SypB6m9cQbB-IYyUy4EvFg |       n8tz      |

### 多媒体书籍
音频开发书籍包括：音乐理论、音频信号处理与编码、DSP语音降噪、3D声音环绕，</br>
视频开发书籍包括：数字图像与视频处理、视频编码全角度详解，</br>
渲染方面是OpenGL，硬件加速指令有neon，详细列表如下：
 |    book         |          download                               |     password    |
 |:----------------|:------------------------------------------------|:----------------|
 | OpenGL          | https://pan.baidu.com/s/1j8_UD217vNeV6SWi5G3ySw |       snvo      |
 | Theory of Music | https://pan.baidu.com/s/1pDpChcrhqOUBL8Dl9xq8UQ |       b38b      |
 | neon guide      | https://pan.baidu.com/s/1mOTnhIyulNASN90IAzHzdA |       f2bw      |
 | CodingForNeon   | https://pan.baidu.com/s/1R-Lf94AnHk_hUwZQyLuxSQ |       5iyj      |
 | HybridReverb    | https://pan.baidu.com/s/19LV36iTBKPGFDQZkoCosiw |       jjlq      |
 | 数字图像与视频处理 | https://pan.baidu.com/s/1oBAtwAFU0pfnhf_cQUs6dg |       pi17      |
 | 视频编码全角度详解 | https://pan.baidu.com/s/1WBdEFF4MWcZDnheeR4XvCA |       vyfo      |
 | 音频信号处理与编码 | https://pan.baidu.com/s/1qwSrRrcs1eipph9QLxrEXg |       q9xc      |
 | DSP语音降噪       | https://pan.baidu.com/s/1z2i6vXf9xn_Uq2_T6TE8rA |       h7a1      |
 | 3D声音环绕        | https://pan.baidu.com/s/1URAnDx_eNXJhsQUSUVLKDA |       u8n0      |
 | 音视频开发进阶指南 |                      /                          |         /       |
 | HEVC算法与架构    | https://pan.baidu.com/s/1l8IwSACejk4ZZe10Dh6OdQ |       kgfg      |
 | A Tour of C++    | https://pan.baidu.com/s/16mg_1aafhcM68-NYHT6XhQ |       ycvm      |
 | C++标准库         | https://pan.baidu.com/s/1QPXbjnYArNmwZY4TCZ5aWA |       3xyv      |
 | C程序语言         | https://pan.baidu.com/s/132cTecL7RArkx2eaGGZOmw |       wzrj      |
 | C++程序语言       | https://pan.baidu.com/s/1joKa0qt_xl57QdRRL7Ud9g |       br5q      |

---

### Doc Multimedia Work (`doc/multimedia_work.md`)

### 音视频工作方向概要
音视频工作方向包括:直播、短视频、流媒体传输、视频播放器、音乐播放器、音视频算法、</br>
流媒体后端、音视频编辑、图像处理(个人概括，具体方向不限于此)。</br>

---

### Doc Player Framework (`doc/player_framework.md`)

# 前言
ijkplayer是一款跨平台的播放器，支持Android与iOS端，核心部分基于ffmpeg，</br>
支持Android的mediacodec硬解与iOS的videotoolbox硬解，视频图像采用OpenGL进行渲染。</br>
许多主流播放器都使用ijkplayer作为播放方案。</br>

## 1、ijkplayer的API详细介绍
[API介绍](https://blog.csdn.net/u011686167/article/details/121317933)

## 2、ijkplayer的时序图与状态图分析
[时序图与状态图](https://blog.csdn.net/u011686167/article/details/121322757)

## 3、ijkplayer自定义协议播放加密视频
[自定义协议](https://blog.csdn.net/u011686167/article/details/121341461)

## 4、ijkplayer音频解码播放架构分析
[音频解码播放](https://blog.csdn.net/u011686167/article/details/121411150)

## 5、ijkplayer视频解码播放架构分析
[视频解码播放](https://blog.csdn.net/u011686167/article/details/121432094)

## 6、ijkplayer播放器架构从原型到升级
[播放器整体架构](https://blog.csdn.net/u011686167/article/details/121440104)

## 7、ijkplayer音视频同步策略分析
[音视频同步](https://blog.csdn.net/u011686167/article/details/121446345)

---

--- METRICS ---
- Files Extracted: 10
- Estimated Token Budget: ~9495 tokens
- Canonical Reference: https://codewiki.google/github.com/xufuji456/FFmpegAndroid
