Showing preview only (1,424K chars total). Download the full file or copy to clipboard to get everything.
Repository: 0voice/ffmpeg_develop_doc
Branch: main
Commit: cf5d48aea3b6
Files: 147
Total size: 1.0 MB
Directory structure:
gitextract_9rzpuyiq/
├── 3个重点,20个函数分析,浅析FFmpeg转码过程.md
├── FFMpeg写MP4文件例子分析.c
├── FFmpeg source code structure AVPacket, AVPacketSideData, AVBufferRef and AVBuffer.md
├── FFmpeg 学习(一):FFmpeg 简介 .md
├── FFmpeg 学习(七):FFmpeg 学习整理总结.md
├── FFmpeg 学习(三):将 FFmpeg 移植到 Android平台.md
├── FFmpeg 学习(二):Mac下安装FFmpeg.md
├── FFmpeg 学习(五):FFmpeg 编解码 API 分析.md
├── FFmpeg 学习(六):FFmpeg 核心模块 libavformat 与 libavcodec 分析.md
├── FFmpeg 学习(四):FFmpeg API 介绍与通用 API 分析.md
├── FFmpeg 开发之 AVFilter 使用流程总结.md
├── FFmpeg 结构体学习(一): AVFormatContext 分析.md
├── FFmpeg 结构体学习(七): AVIOContext 分析.md
├── FFmpeg 结构体学习(三): AVPacket 分析.md
├── FFmpeg 结构体学习(二): AVStream 分析.md
├── FFmpeg 结构体学习(五): AVCodec 分析.md
├── FFmpeg 结构体学习(八):FFMPEG中重要结构体之间的关系.md
├── FFmpeg 结构体学习(六): AVCodecContext 分析.md
├── FFmpeg 结构体学习(四): AVFrame 分析.md
├── FFmpeg源码分析:内存管理系统.md
├── H.264视频解码优化及DSP实现.caj
├── Linux上的ffmpeg完全使用指南.md
├── README.md
├── case_interview/
│ ├── 001-README.md
│ └── 002-README.md
├── ffmpeg常用命令.md
├── ffmpeg源码example解析之decode_audio.md
├── ffmpeg源码example解析之decode_video.md
├── ffplay源码和书籍/
│ └── ffplay/
│ ├── Debug/
│ │ ├── allcodecs.obj
│ │ ├── allformats.obj
│ │ ├── avidec.obj
│ │ ├── avio.obj
│ │ ├── aviobuf.obj
│ │ ├── cutils.obj
│ │ ├── dsputil.obj
│ │ ├── ffplay.Build.CppClean.log
│ │ ├── ffplay.ilk
│ │ ├── ffplay.log
│ │ ├── ffplay.obj
│ │ ├── ffplay.pdb
│ │ ├── ffplay.tlog/
│ │ │ ├── CL.read.1.tlog
│ │ │ ├── CL.write.1.tlog
│ │ │ ├── cl.command.1.tlog
│ │ │ ├── ffplay.lastbuildstate
│ │ │ ├── link.command.1.tlog
│ │ │ ├── link.read.1.tlog
│ │ │ └── link.write.1.tlog
│ │ ├── file.obj
│ │ ├── imgconvert.obj
│ │ ├── msrle.obj
│ │ ├── truespeech.obj
│ │ ├── utils_codec.obj
│ │ ├── utils_format.obj
│ │ ├── vc120.idb
│ │ └── vc120.pdb
│ ├── berrno.h
│ ├── ffplay.c
│ ├── ffplay.dsp
│ ├── ffplay.vcxproj
│ ├── ffplay.vcxproj.filters
│ ├── libavcodec/
│ │ ├── allcodecs.c
│ │ ├── avcodec.h
│ │ ├── dsputil.c
│ │ ├── dsputil.h
│ │ ├── imgconvert.c
│ │ ├── imgconvert_template.h
│ │ ├── msrle.c
│ │ ├── truespeech.c
│ │ ├── truespeech_data.h
│ │ └── utils_codec.c
│ ├── libavformat/
│ │ ├── allformats.c
│ │ ├── avformat.h
│ │ ├── avidec.c
│ │ ├── avio.c
│ │ ├── avio.h
│ │ ├── aviobuf.c
│ │ ├── cutils.c
│ │ ├── file.c
│ │ └── utils_format.c
│ ├── libavutil/
│ │ ├── avutil.h
│ │ ├── bswap.h
│ │ ├── common.h
│ │ ├── mathematics.h
│ │ └── rational.h
│ └── update.txt
├── iOS资料/
│ ├── AVFoundation之视频捕捉.md
│ ├── IOS 剪辑编辑器.md
│ ├── IOS之多媒体API.md
│ ├── MACiOS利用FFmpeg解析音视频数据流.md
│ ├── iOS - 图形高级处理 (一、图片显示相关理论).md
│ ├── iOS AVDemo(5):音频解码.md
│ ├── iOS AVDemo(6):音频渲染.md
│ ├── iOS AVDemo(7):视频采集.md
│ ├── iOS AVDemo(8):视频编码,H.264 和 H.265 都支持.md
│ ├── iOS AVDemo(9):视频封装,采集编码 H.264H.265 并封装 MP4.md
│ ├── iOS AVDemo:音频封装,采集编码并封装为 M4A.md
│ ├── iOS AVDemo:音频编码,采集 PCM 数据编码为 AAC.md
│ ├── iOS AVDemo:音频解封装,从 MP4 中解封装出 AAC.md
│ ├── iOS AVDemo:音频采集.md
│ ├── iOS Runtime详解.md
│ ├── iOS 入门(2):管理第三方库.md
│ ├── iOS 离屏渲染探究.md
│ ├── iOS 系统架构及常用框架.md
│ ├── iOS-WebRTC静态库,framework下载、编译,使用.md
│ ├── iOSAVDemo(10):视频解封装,从 MP4 解出 H.264H.265.md
│ ├── iOS下 WebRTC 视频渲染.md
│ ├── iOS下的渲染框架.md
│ ├── iOS使用AVPlayer,播放本地,在线音频
│ ├── iOS动画系列之三:Core Animation.md
│ ├── iOS图像渲染及卡顿问题优化.md
│ ├── iOS学习音视频的过程.md
│ ├── iOS拉取SRS流媒体服务器的Rtc流.md
│ ├── iOS短视频篇:音视频编辑之音视频合成,添加水印及音视频导出.md
│ ├── iOS硬编解码相关知识.md
│ ├── iOS视图渲染与性能优化.md
│ ├── iOS视频开发:视频H264硬编码.md
│ ├── iOS视频推流、拉流原理.md
│ ├── iOS逆向 MachO文件.md
│ ├── iOS配置FFmpeg框架.md
│ ├── iOS音视频 -- AVFoundation捕捉.md
│ ├── iOS音视频同步探讨.md
│ ├── iOS音视频开发-了解编码及视频.md
│ ├── iOS音视频开发-代码实现视频编码.md
│ ├── iOS音视频开发-采集、编码、滤镜.md
│ ├── iOS音视频开发——FFmpeg库编译.md
│ ├── iOS音视频开发——视频采集.md
│ ├── iOS音视频开源框架WebRTC入门-AppRTCMobile.md
│ ├── iOS音视频的那些事儿:数据的采集和编码.md
│ ├── iOS音视频:OpenGL常用术语介绍.md
│ ├── iOS音频录制及合成,以及优化处理
│ ├── iOS音频视频开发.md
│ ├── iOS音频采集过程中的音效实现.md
│ ├── iOS项目集成OpenCV及踩过的坑.md
│ ├── iOS高级视频渲染.md
│ ├── macOS 下单步调试 WebRTC Android & iOS.md
│ ├── 【OpenGL入门】iOS 图像渲染原理.md
│ ├── 【如何快速的开发一个完整的iOS直播app】(美颜篇).md
│ ├── 关于iOS离屏渲染的深入研究.md
│ ├── 基于 AVFoundation 框架开发小视频功能的方案解析.md
│ ├── 最简单的基于FFmpeg的移动端例子:IOS HelloWorld.md
│ ├── 视频直播iOS端技术.md
│ ├── 资深程序员的Metal入门教程总结.md
│ └── 音视频学习--iOS适配H265实战踩坑记.md
├── paper/
│ └── README.md
├── teaching video/
│ └── video.md
├── 使用FFMpeg进行H264编码.c
└── 基于RTMP的高清流媒体直播点播封装技术的研究与实现.caj
================================================
FILE CONTENTS
================================================
================================================
FILE: 3个重点,20个函数分析,浅析FFmpeg转码过程.md
================================================
## **写在前面**
最近在做和转码有关的项目,接触到ffmpeg这个神器。从一开始简单的写脚本直接调用ffmpeg的可执行文件做些转码的工作,到后来需要写程序调用ffmpeg的API。虽然上网搜了别人的demo稍微改改顺利完成了工作,但是对于ffmpeg这个黑盒子,还是有些好奇心和担心(项目中使用不了解的代码总是不那么放心),于是抽空翻了翻ffmpeg的源码,整理成文章给大家分享分享。
由于我并非做音频出身,对于音频一窍不通。ffmpeg整个也非常庞大,所以这篇文章从ffmpeg提供的转码的demo开始,侧重于讲清楚整个输入->转码->输出的流程,并学习ffmpeg如何做到通用和可扩展性。
注:本文基于ffmpeg提供的transcode_aac.c样例。
## **三个重点**
转码的过程是怎么样的?简单来说就是从输入读取数据,解析原来的数据格式,转成目标数据格式,再将最终数据输出。这里就涉及到三个**点**:**数据输入和输出方式**,**数据的编码方式**及**数据的容器格式**(容器是用来区分不同文件的数据类型的,而编码格式则由音视频的压缩算法决定,一般所说的文件格式或者后缀名指的就是文件的容器。对于一种容器,可以包含不同编码格式的一种视频和音频)。
ffmpeg是一个非常非常通用的工具,支持非常广的数据输入和输出,包括:hls流,文件,内存等,支持各类数据编码格式,包括:aac,mp3等等,同时支持多种容器格式,包括ts,aac等。另外ffmpeg是通过C语言实现的,如果是C++,我们可以通过继承和多态来实现。定义一个IO的基类,一个Format的基类和一个Codec的基类,具体的输入输出协议继承IO基类实现各自的输入输出方法,具体的容器格式继承Format基类,具体的编码格式继承Codec基类。这篇文章也会简单讲解ffmpeg如何用C语言实现类似C++的继承和多态。
## **基本数据结构**
ffmpeg转码中最基本的结构为AVFormatContext和AVCodecContext。AVCodecContext负责编码,AVFormatContext负责IO和容器格式。
我从AVFormatContext类抽离出三个基本的成员iformat,oformat,pb。分别属于AVInputFormat,AVOutputFormat,AVIOContext类。iformat为输入的数据格式,oformat为输出的数据格式,pb则负责输入输出。

我把这三个类的定义抽离了出来简化了下,可以看出AVInputFormat声明了read_packet方法,AVOutputFormat声明了write_packet方法,AVIOContext声明了read_packet, write_packet方法。同时AVInputFormat和AVOutputFormat还有一个成员变量name用以标识该格式的后缀名。

下一节我们会看到Input/OutputForm的read/write packet方法和IOContext的关系。
## **输入函数调用图**
下面是初始化输入的整个过程的函数调用图。

首先从调用open_input_file开始,首先**解析输入的protocol**。avio_open2函数会调用一系列helper函数(ffurl_open,ffio_fdopen)分析输入的协议,设置AVFormatContext的pb变量的read_packet方法。而av_probe_input_buffer2函数则会**分析输入文件的格式**(从文件名解析或输入数据做判断),设置AVFormatContext的iformat的read_packet方法。

两个read_packet有什么关系呢?第二个函数调用图可以看出,iformat的read_packet最终会调用pb的read_packet方法。意思就是**数据本身由pb的read_packet方法来读取,而iformat则会在输入的数据上做些格式相关的解析操作**(比如解析输入数据的头部,提取出输入数据中真正的音频/视频数据,再加以转码)。
## **IO相关代码**
直接看上面的图不太直观,这一节我把源码中各个步骤截图下来进行分析。
转码开始步骤,调用open_input_file函数,传入文件名。

avformat_open_input函数会调用init_input()来处理输入文件。

init_input函数主要做两个事情,一是解析输入协议(如何读取数据?hls流?文件?内存?),二是解析输入数据的格式(输入数据为aac?ts?m4a?)

avio_open2函数首先调用ffurl_open函数,根据文件名来推断所属的输入协议(URLProtocol)。之后再调用ffio_fdopen设置pb的read_packet方法。



上面几段代码的逻辑为:根据文件名查找对应的URLProtocol->把该URLProtocol赋值给URLContext的prot成员变量->创建AVIOContext实例,赋值给AVFormatContext的pb成员变量。


这里设置了AVIOContext实例的read_packet为ffurl_read方法。

ffurl_read方法其实就是调用URLContext的prot(上面赋值的)的url_read方法。通过函数指针去调用具体的URLContext对象的prot成员变量的url_read方法。

接下来看看解析输入数据格式的代码。av_probe_input_buffer2函数调用av_probe_input_format2函数来推断数据数据的格式。从之前的图我们知道*fmt其实就是&s->iformat。因此这里设置了AVFormatContext的iformat成员变量。

至此AVFormatContext对象的iformat和pb成员变量就设置好了。接下来看看如何读取输入开始转码。
av_read_frame函数调用read_frame_internal函数开始读取数据。

read_frame_internal会调用ff_read_packet,后者最终调用的是iformat成员变量的read_packet方法。


拿aac举例,aac的read_packet方法实际上是ff_raw_read_partial_packet函数。

ff_raw_read_partial_packet会调用ffio_read_partial,后者最终调用的是AVFormatContext的pb成员变量的read_packet方法。而我们知道pb成员的read_packet其实就是ffurl_read,也就是具体输入URLProtocl的read_packet方法。


至此已经走完了整个输入的流程,输出也是类似的代码,这里就不再赘述。
## **转码函数调用图**
上面关于IO的介绍我从输入的角度进行分析。接下来的转码过程我则从输出的角度进行分析。下图是转码过程的函数调用图(做了简化)。load_encode_and_write调用encode_audio_frame, encode_audio_frame调用avcodec_encode_audio2来做实际的编码工作,最后调用av_write_frame将编码完的数据写入输出。

## **转码相关代码**
首先需要设置输出目标编码格式,下面的代码为设置编码格式(aac)的片段:

在这里设置了output_codec_context(AVCodecContext类对象)之后,从前面的函数调用图,我们知道是avcodec_encode_audio2函数执行的转码过程:

这里看到调用了avctx(AVCodecContext类对象)的codec(AVCodec类对象)成员变量的encode2方法去做编码操作。
转码这里专业性比较强,我并没有细读,因此这里简单带过。
## **总结**
可以看出ffmpeg大量使用函数指针来实现类似C++的继承/多态的效果。并且ffmpeg具有非常好的扩展性。如果我需要自定义一个新的输入协议,只需要自己定义一个新的URLProtocol对象,实现read_packet方法即可。如果需要自定义一个新的容器格式,只需要定义一个新的AVInputFormat对象,实现read_packet方法即可。如果需要自定义一个新的编码格式,只需要定义一个新的AVCodec对象,实现encode2方法即可。真是非常赞的代码架构设计!
================================================
FILE: FFMpeg写MP4文件例子分析.c
================================================
/**
这段时间看了FFMpeg提供的例子muxing.c,我略微修改了下源代码,使其生成一个MP4文件,音频使用AAC编码,视频使用H.264编码。代码很简单,我就不做说明了,代码如下。
以后我们继续写如何将DirectShow中采集的音视频数据编码并生成MP4文件。
*/
/* 5 seconds stream duration */
#define STREAM_DURATION 5.0
#define STREAM_FRAME_RATE 25 /* 25 images/s */
#define STREAM_NB_FRAMES ((int)(STREAM_DURATION * STREAM_FRAME_RATE))
#define STREAM_PIX_FMT PIX_FMT_YUV420P /* default pix_fmt */
static int sws_flags = SWS_BICUBIC;
/**************************************************************/
/* audio output */
static float t, tincr, tincr2;
static int16_t *samples;
static uint8_t *audio_outbuf;
static int audio_outbuf_size;
static int audio_input_frame_size;
/*
* add an audio output stream
*/
static AVStream *add_audio_stream(AVFormatContext *oc, enum CodecID codec_id)
{
AVCodecContext *c;
AVStream *st;
st = avformat_new_stream(oc, NULL);
if (!st) {
fprintf(stderr, "Could not alloc stream\n");
exit(1);
}
st->id = 1;
c = st->codec;
c->codec_id = codec_id;
c->codec_type = AVMEDIA_TYPE_AUDIO;
/* put sample parameters */
c->sample_fmt = AV_SAMPLE_FMT_S16;
c->bit_rate = 64000;
c->sample_rate = 44100;
c->channels = 2;
// some formats want stream headers to be separate
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
return st;
}
static void open_audio(AVFormatContext *oc, AVStream *st)
{
AVCodecContext *c;
AVCodec *codec;
c = st->codec;
/* find the audio encoder */
codec = avcodec_find_encoder(c->codec_id);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
/* init signal generator */
t = 0;
tincr = 2 * M_PI * 110.0 / c->sample_rate;
/* increment frequency by 110 Hz per second */
tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
audio_outbuf_size = 10000;
audio_outbuf = (uint8_t *)av_malloc(audio_outbuf_size);
/* ugly hack for PCM codecs (will be removed ASAP with new PCM
support to compute the input frame size in samples */
if (c->frame_size <= 1) {
audio_input_frame_size = audio_outbuf_size / c->channels;
switch(st->codec->codec_id) {
case CODEC_ID_PCM_S16LE:
case CODEC_ID_PCM_S16BE:
case CODEC_ID_PCM_U16LE:
case CODEC_ID_PCM_U16BE:
audio_input_frame_size >>= 1;
break;
default:
break;
}
} else {
audio_input_frame_size = c->frame_size;
}
samples = (int16_t *)av_malloc(audio_input_frame_size * 2 * c->channels);
}
/* prepare a 16 bit dummy audio frame of 'frame_size' samples and
'nb_channels' channels */
static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels)
{
int j, i, v;
int16_t *q;
q = samples;
for (j = 0; j < frame_size; j++) {
v = (int)(sin(t) * 10000);
for(i = 0; i < nb_channels; i++)
*q++ = v;
t += tincr;
tincr += tincr2;
}
}
static void write_audio_frame(AVFormatContext *oc, AVStream *st)
{
AVCodecContext *c;
AVPacket pkt;
av_init_packet(&pkt);
c = st->codec;
get_audio_frame(samples, audio_input_frame_size, c->channels);
pkt.size = avcodec_encode_audio(c, audio_outbuf, audio_outbuf_size, samples);
if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = st->index;
pkt.data = audio_outbuf;
/* write the compressed frame in the media file */
if (av_interleaved_write_frame(oc, &pkt) != 0) {
fprintf(stderr, "Error while writing audio frame\n");
exit(1);
}
}
static void close_audio(AVFormatContext *oc, AVStream *st)
{
avcodec_close(st->codec);
av_free(samples);
av_free(audio_outbuf);
}
/**************************************************************/
/* video output */
static AVFrame *picture, *tmp_picture;
static uint8_t *video_outbuf;
static int frame_count, video_outbuf_size;
/* add a video output stream */
static AVStream *add_video_stream(AVFormatContext *oc, enum CodecID codec_id)
{
AVCodecContext *c;
AVStream *st;
AVCodec *codec;
st = avformat_new_stream(oc, NULL);
if (!st) {
fprintf(stderr, "Could not alloc stream\n");
exit(1);
}
c = st->codec;
/* find the video encoder */
codec = avcodec_find_encoder(codec_id);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
avcodec_get_context_defaults3(c, codec);
c->codec_id = codec_id;
/* put sample parameters */
c->bit_rate = /*400000*/3000000;
/* resolution must be a multiple of two */
c->width = /*352*/640;
c->height = /*288*/480;
/* time base: this is the fundamental unit of time (in seconds) in terms
of which frame timestamps are represented. for fixed-fps content,
timebase should be 1/framerate and timestamp increments should be
identically 1. */
c->time_base.den = STREAM_FRAME_RATE;
c->time_base.num = 1;
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = STREAM_PIX_FMT;
if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
/* just for testing, we also add B frames */
c->max_b_frames = 2;
}
if (c->codec_id == CODEC_ID_MPEG1VIDEO){
/* Needed to avoid using macroblocks in which some coeffs overflow.
This does not happen with normal video, it just happens here as
the motion of the chroma plane does not match the luma plane. */
c->mb_decision=2;
}
// some formats want stream headers to be separate
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
return st;
}
static AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int height)
{
AVFrame *picture;
uint8_t *picture_buf;
int size;
picture = avcodec_alloc_frame();
if (!picture)
return NULL;
size = avpicture_get_size(pix_fmt, width, height);
picture_buf = (uint8_t *)av_malloc(size);
if (!picture_buf) {
av_free(picture);
return NULL;
}
avpicture_fill((AVPicture *)picture, picture_buf,
pix_fmt, width, height);
return picture;
}
static void open_video(AVFormatContext *oc, AVStream *st)
{
AVCodec *codec;
AVCodecContext *c;
c = st->codec;
/* find the video encoder */
codec = avcodec_find_encoder(c->codec_id);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
/* open the codec */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
video_outbuf = NULL;
if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
/* allocate output buffer */
/* XXX: API change will be done */
/* buffers passed into lav* can be allocated any way you prefer,
as long as they're aligned enough for the architecture, and
they're freed appropriately (such as using av_free for buffers
allocated with av_malloc) */
video_outbuf_size = 200000;
video_outbuf = (uint8_t *)av_malloc(video_outbuf_size);
}
/* allocate the encoded raw picture */
picture = alloc_picture(c->pix_fmt, c->width, c->height);
if (!picture) {
fprintf(stderr, "Could not allocate picture\n");
exit(1);
}
/* if the output format is not YUV420P, then a temporary YUV420P
picture is needed too. It is then converted to the required
output format */
tmp_picture = NULL;
if (c->pix_fmt != PIX_FMT_YUV420P) {
tmp_picture = alloc_picture(PIX_FMT_YUV420P, c->width, c->height);
if (!tmp_picture) {
fprintf(stderr, "Could not allocate temporary picture\n");
exit(1);
}
}
}
/* prepare a dummy image */
static void fill_yuv_image(AVFrame *pict, int frame_index, int width, int height)
{
int x, y, i;
i = frame_index;
/* Y */
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
}
}
/* Cb and Cr */
for (y = 0; y < height/2; y++) {
for (x = 0; x < width/2; x++) {
pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
}
}
}
static void write_video_frame(AVFormatContext *oc, AVStream *st)
{
int out_size, ret;
AVCodecContext *c;
static struct SwsContext *img_convert_ctx;
c = st->codec;
if (frame_count >= STREAM_NB_FRAMES) {
/* no more frame to compress. The codec has a latency of a few
frames if using B frames, so we get the last frames by
passing the same picture again */
} else {
if (c->pix_fmt != PIX_FMT_YUV420P) {
/* as we only generate a YUV420P picture, we must convert it
to the codec pixel format if needed */
if (img_convert_ctx == NULL) {
img_convert_ctx = sws_getContext(c->width, c->height,
PIX_FMT_YUV420P,
c->width, c->height,
c->pix_fmt,
sws_flags, NULL, NULL, NULL);
if (img_convert_ctx == NULL) {
fprintf(stderr, "Cannot initialize the conversion context\n");
exit(1);
}
}
fill_yuv_image(tmp_picture, frame_count, c->width, c->height);
sws_scale(img_convert_ctx, tmp_picture->data, tmp_picture->linesize,
0, c->height, picture->data, picture->linesize);
} else {
fill_yuv_image(picture, frame_count, c->width, c->height);
}
}
if (oc->oformat->flags & AVFMT_RAWPICTURE) {
/* raw video case. The API will change slightly in the near
future for that. */
AVPacket pkt;
av_init_packet(&pkt);
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = st->index;
pkt.data = (uint8_t *)picture;
pkt.size = sizeof(AVPicture);
ret = av_interleaved_write_frame(oc, &pkt);
} else {
/* encode the image */
out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);
/* if zero size, it means the image was buffered */
if (out_size > 0) {
AVPacket pkt;
av_init_packet(&pkt);
if (c->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
if(c->coded_frame->key_frame)
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = st->index;
pkt.data = video_outbuf;
pkt.size = out_size;
// printf("pts %d \n", c->coded_frame->pts);
/* write the compressed frame in the media file */
ret = av_interleaved_write_frame(oc, &pkt);
} else {
ret = 0;
}
}
if (ret != 0) {
fprintf(stderr, "Error while writing video frame\n");
exit(1);
}
frame_count++;
}
static void close_video(AVFormatContext *oc, AVStream *st)
{
avcodec_close(st->codec);
av_free(picture->data[0]);
av_free(picture);
if (tmp_picture) {
av_free(tmp_picture->data[0]);
av_free(tmp_picture);
}
av_free(video_outbuf);
}
/**************************************************************/
/* media file output */
int main(int argc, char **argv)
{
const char *filename;
AVOutputFormat *fmt;
AVFormatContext *oc;
AVStream *audio_st, *video_st;
double audio_pts, video_pts;
int i;
/* initialize libavcodec, and register all codecs and formats */
av_register_all();
#if 0
if (argc != 2) {
printf("usage: %s output_file\n"
"API example program to output a media file with libavformat.\n"
"The output format is automatically guessed according to the file extension.\n"
"Raw images can also be output by using '%%d' in the filename\n"
"\n", argv[0]);
return 1;
}
filename = argv[1];
#endif
//#define RTMP_STREAM
#ifdef RTMP_STREAM
filename = "rtmp://192.168.0.239/live/livestream";
#else
filename = "1.mp4";
#endif
/* allocate the output media context */
avformat_alloc_output_context2(&oc, NULL, NULL, filename);
if (!oc)
{
printf("Could not deduce output format from file extension: using MPEG.\n");
avformat_alloc_output_context2(&oc, NULL, /*"mpeg"*/"flv", filename);
}
if (!oc)
{
return 1;
}
// 强制指定 264 编码
oc->oformat->video_codec = CODEC_ID_H264;
oc->oformat->audio_codec = CODEC_ID_AAC;
fmt = oc->oformat;
/* add the audio and video streams using the default format codecs
and initialize the codecs */
video_st = NULL;
audio_st = NULL;
if (fmt->video_codec != CODEC_ID_NONE) {
video_st = add_video_stream(oc, fmt->video_codec);
}
if (fmt->audio_codec != CODEC_ID_NONE) {
audio_st = add_audio_stream(oc, fmt->audio_codec);
}
av_dump_format(oc, 0, filename, 1);
/* now that all the parameters are set, we can open the audio and
video codecs and allocate the necessary encode buffers */
if (video_st)
open_video(oc, video_st);
if (audio_st)
open_audio(oc, audio_st);
/* open the output file, if needed */
if (!(fmt->flags & AVFMT_NOFILE)) {
if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "Could not open '%s'\n", filename);
return 1;
}
}
/* write the stream header, if any */
avformat_write_header(oc, NULL);
picture->pts = 0;
for(;;)
{
/* compute current audio and video time */
if (audio_st)
audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;
else
audio_pts = 0.0;
if (video_st)
video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den;
else
video_pts = 0.0;
if ((!audio_st || audio_pts >= STREAM_DURATION) &&
(!video_st || video_pts >= STREAM_DURATION))
break;
/* write interleaved audio and video frames */
if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
write_audio_frame(oc, audio_st);
} else {
write_video_frame(oc, video_st);
picture->pts++;
}
}
/* write the trailer, if any. the trailer must be written
* before you close the CodecContexts open when you wrote the
* header; otherwise write_trailer may try to use memory that
* was freed on av_codec_close() */
av_write_trailer(oc);
/* close each codec */
if (video_st)
close_video(oc, video_st);
if (audio_st)
close_audio(oc, audio_st);
/* free the streams */
for(i = 0; i < oc->nb_streams; i++) {
av_freep(&oc->streams[i]->codec);
av_freep(&oc->streams[i]);
}
if (!(fmt->flags & AVFMT_NOFILE)) {
/* close the output file */
avio_close(oc->pb);
}
/* free the stream */
av_free(oc);
return 0;
}
================================================
FILE: FFmpeg source code structure AVPacket, AVPacketSideData, AVBufferRef and AVBuffer.md
================================================
AVPacket stores the encoded frame data, which is usually output by demuxer and then transferred to decoder as input, or received from encoder as output and then transferred to muxer.

For video, it should usually contain a compressed frame. For audio, it may contain several compressed frames. Encoders allow output of empty packets, no compressed data, and only side data (for example, updating some stream parameters at the end of encoding).
The semantics of data ownership depends on the buf field. If this value is set, the Packet data is dynamically allocated and valid indefinitely until it is used for AV_ Packet_ The call to unref() reduces the reference count to 0.
If the buf field is not set, av_packet_ref() will make a copy instead of increasing the reference count.
side data is always generated by av_malloc(), assigned by av_packet_ref() is copied by av_packet_unref() is released.
sizeof(AVPacket) has been abandoned as a part of public ABI. Once AV_ init_ The Packet() function is removed, and the new Packet can only be created by av_packet_alloc(), new fields may be added to the end of the structure.
Next, we will learn about AVPacket, and then we will lead out AVBufferRef and AVPacketSideData from AVPacket structure. Finally, we will lead out AVBuffer from AVBufferRef and AVPacketSideData from AVPacketSideData enumeration.
## 1, AVPacket
libavcodec/packet.h
```
typedef struct AVPacket {
/**
* A reference to the reference-counted buffer where the packet data is
* stored.
* May be NULL, then the packet data is not reference-counted.
*/
AVBufferRef *buf;
/**
* Presentation timestamp in AVStream->time_base units; the time at which
* the decompressed packet will be presented to the user.
* Can be AV_NOPTS_VALUE if it is not stored in the file.
* pts MUST be larger or equal to dts as presentation cannot happen before
* decompression, unless one wants to view hex dumps. Some formats misuse
* the terms dts and pts/cts to mean something different. Such timestamps
* must be converted to true pts/dts before they are stored in AVPacket.
*/
int64_t pts;
/**
* Decompression timestamp in AVStream->time_base units; the time at which
* the packet is decompressed.
* Can be AV_NOPTS_VALUE if it is not stored in the file.
*/
int64_t dts;
uint8_t *data;
int size;
int stream_index;
/**
* A combination of AV_PKT_FLAG values
*/
int flags;
/**
* Additional packet data that can be provided by the container.
* Packet can contain several types of side information.
*/
AVPacketSideData *side_data;
int side_data_elems;
/**
* Duration of this packet in AVStream->time_base units, 0 if unknown.
* Equals next_pts - this_pts in presentation order.
*/
int64_t duration;
int64_t pos; ///< byte position in stream, -1 if unknown
#if FF_API_CONVERGENCE_DURATION
/**
* @deprecated Same as the duration field, but as int64_t. This was required
* for Matroska subtitles, whose duration values could overflow when the
* duration field was still an int.
*/
attribute_deprecated
int64_t convergence_duration;
#endif
} AVPacket;
```
Here's what each field means.
| field | meaning |
| ---------------------------- | ------------------------------------------------------------ |
| AVBufferRef * buf | The reference to the reference count buffer that stores the packet data. |
| int64_t pts | Using avstream > time_ The time stamp displayed in the base time base is the time when the unpacked packet is presented to the user. |
| int64_t dts | Using avstream > time_ Base is the time stamp of unpacking, and the time when the packet is unpacked. |
| uint8_t * data | The actual data buffer of the packet. |
| int size | The actual data size of the packet. |
| int stream_index | The index of the stream. |
| int flags | AV_ PKT_ A combination of flag values. |
| AVPacketSideData * side_data | Additional data that the container can provide. |
| int side_data_elems | side_ The number of data elements. |
| int64_t duration | The duration of this packet is avstream > time_ Base, or 0 if unknown. |
| int64_t pos | The byte position in the stream, or - 1 if unknown. |
Here's AV_ PKT_ The combined values that flag can use.
libavcodec/packet.h
```
#define AV_PKT_FLAG_KEY 0x0001 / / key frame
#define AV_PKT_FLAG_CORRUPT 0x0002 / / corrupt data
#define AV_PKT_FLAG_DISCARD 0x0004 / / is used to discard packet s that need to remain in a valid decoder state but do not need to be output, and should be discarded after decoding.
#define AV_ PKT_ FLAG_ Trusted 0x0008 / / packet comes from a trusted source.
#define AV_PKT_FLAG_DISPOSABLE 0x0010 / / used to indicate a packet containing a frame that can be discarded by the decoder, that is, a non referenced frame.
```
## 2, AVBufferRef
A reference to a data buffer. The size of this structure is not part of the public ABI and is not intended to be allocated directly.
libavutil/buffer.h
```
typedef struct AVBufferRef {
AVBuffer *buffer;
/**
* The data buffer. It is considered writable if and only if
* this is the only reference to the buffer, in which case
* av_buffer_is_writable() returns 1.
*/
uint8_t *data;
/**
* Size of data in bytes.
*/
#if FF_API_BUFFER_SIZE_T
int size;
#else
size_t size;
#endif
} AVBufferRef;
```
| field | meaning |
| ----------------- | ------------------------------------------------------------ |
| AVBuffer *buffer | A reference count buffer type. It is opaque, which means to use it by reference (AVBufferRef). |
| uint8_t *data | Data buffer. If and only if this is the only reference to the buffer, it is considered writable, in which case av_buffer_is_writable() returns 1. |
| size_t / int size | The size of data in bytes. |
## 3, AVBuffer
A reference count buffer type. Defined in libavutil / buffer_ In internal. H. It is opaque, which means to use it by reference (AVBufferRef).
libavutil/buffer_internal.h
```
struct AVBuffer {
uint8_t *data; /**< data described by this buffer */
buffer_size_t size; /**< size of data in bytes */
/**
* number of existing AVBufferRef instances referring to this buffer
*/
atomic_uint refcount;
/**
* a callback for freeing the data
*/
void (*free)(void *opaque, uint8_t *data);
/**
* an opaque pointer, to be used by the freeing callback
*/
void *opaque;
/**
* A combination of AV_BUFFER_FLAG_*
*/
int flags;
/**
* A combination of BUFFER_FLAG_*
*/
int flags_internal;
};
```
| field | meaning |
| ----------------------------------------- | ------------------------------------------------------------ |
| uint8_t *data | The data described by the buffer. |
| buffer_size_t size | The size of data in bytes. |
| atomic_uint refcount | The number of existing AVBufferRef instances that reference this buffer. |
| void (*free)(void *opaque, uint8_t *data) | Callback used to release data. |
| void *opaque | An opaque pointer used by the release callback function. |
| int flags | AV_BUFFER_FLAG_ *The combination of the two. |
| int flags_internal | BUFFER_FLAG_ *The combination of the two. |
AVBuffer is an API for referencing count data buffers.
There are two core objects AVBuffer and AVBufferRef in this API. AVBuffer represents the data buffer itself; it is opaque and cannot be accessed directly by the caller, but only through AVBufferRef. However, the caller may compare two AVBuffer pointers to check whether two different references describe the same data buffer. AVBufferRef represents a single reference to AVBuffer, which can be operated directly by the caller.
There are two functions that can create a new AVBuffer with one reference -- av_buffer_alloc() is used to allocate a new buffer, av_buffer_create() is used to wrap an existing array in AVBuffer. From existing references, you can use av_buffer_ref() creates another reference. Using av_buffer_unref() releases a reference (once all references are released, the data is automatically released).
The Convention between this API and the rest of FFmpeg is that a buffer is considered writable if there is only one reference to it (and it is not marked read-only). AV is provided_ buffer_ is_ Write() function to check if this is true, and av_buffer_make_writable() will automatically create a new writable buffer if necessary.
Of course, nothing prevents the calling code from violating this Convention, but it is only safe if all existing references are under its control.
Reference and dereference buffers are thread safe, so they can be used by multiple threads at the same time without any additional locks.
Two different references to the same buffer can point to different parts of the buffer (for example, their AVBufferRef.data The data will not be equal).
## 4, AVPacketSideData
Additional Packet data that the container can provide. A Packet can contain several types of side information.
libavcodec/packet.h
```
typedef struct AVPacketSideData {
uint8_t *data;
#if FF_API_BUFFER_SIZE_T
int size;
#else
size_t size;
#endif
enum AVPacketSideDataType type;
} AVPacketSideData;
```
| field | meaning |
| ------------------------------ | ------------------------------------ |
| uint8_t *data | Data cache. |
| int / size_t size | The size of the data cache in bytes. |
| enum AVPacketSideDataType type | Packet side data type. |
The AVPacketSideDataType enumeration defines various side data types.
libavcodec/packet.h
```
/**
* @defgroup lavc_packet AVPacket
*
* Types and functions for working with AVPacket.
* @{
*/
enum AVPacketSideDataType {
/**
* An AV_PKT_DATA_PALETTE side data packet contains exactly AVPALETTE_SIZE
* bytes worth of palette. This side data signals that a new palette is
* present.
*/
AV_PKT_DATA_PALETTE,
/**
* The AV_PKT_DATA_NEW_EXTRADATA is used to notify the codec or the format
* that the extradata buffer was changed and the receiving side should
* act upon it appropriately. The new extradata is embedded in the side
* data buffer and should be immediately used for processing the current
* frame or packet.
*/
AV_PKT_DATA_NEW_EXTRADATA,
/**
* An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows:
* @code
* u32le param_flags
* if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT)
* s32le channel_count
* if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT)
* u64le channel_layout
* if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE)
* s32le sample_rate
* if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS)
* s32le width
* s32le height
* @endcode
*/
AV_PKT_DATA_PARAM_CHANGE,
/**
* An AV_PKT_DATA_H263_MB_INFO side data packet contains a number of
* structures with info about macroblocks relevant to splitting the
* packet into smaller packets on macroblock edges (e.g. as for RFC 2190).
* That is, it does not necessarily contain info about all macroblocks,
* as long as the distance between macroblocks in the info is smaller
* than the target payload size.
* Each MB info structure is 12 bytes, and is laid out as follows:
* @code
* u32le bit offset from the start of the packet
* u8 current quantizer at the start of the macroblock
* u8 GOB number
* u16le macroblock address within the GOB
* u8 horizontal MV predictor
* u8 vertical MV predictor
* u8 horizontal MV predictor for block number 3
* u8 vertical MV predictor for block number 3
* @endcode
*/
AV_PKT_DATA_H263_MB_INFO,
/**
* This side data should be associated with an audio stream and contains
* ReplayGain information in form of the AVReplayGain struct.
*/
AV_PKT_DATA_REPLAYGAIN,
/**
* This side data contains a 3x3 transformation matrix describing an affine
* transformation that needs to be applied to the decoded video frames for
* correct presentation.
*
* See libavutil/display.h for a detailed description of the data.
*/
AV_PKT_DATA_DISPLAYMATRIX,
/**
* This side data should be associated with a video stream and contains
* Stereoscopic 3D information in form of the AVStereo3D struct.
*/
AV_PKT_DATA_STEREO3D,
/**
* This side data should be associated with an audio stream and corresponds
* to enum AVAudioServiceType.
*/
AV_PKT_DATA_AUDIO_SERVICE_TYPE,
/**
* This side data contains quality related information from the encoder.
* @code
* u32le quality factor of the compressed frame. Allowed range is between 1 (good) and FF_LAMBDA_MAX (bad).
* u8 picture type
* u8 error count
* u16 reserved
* u64le[error count] sum of squared differences between encoder in and output
* @endcode
*/
AV_PKT_DATA_QUALITY_STATS,
/**
* This side data contains an integer value representing the stream index
* of a "fallback" track. A fallback track indicates an alternate
* track to use when the current track can not be decoded for some reason.
* e.g. no decoder available for codec.
*/
AV_PKT_DATA_FALLBACK_TRACK,
/**
* This side data corresponds to the AVCPBProperties struct.
*/
AV_PKT_DATA_CPB_PROPERTIES,
/**
* Recommmends skipping the specified number of samples
* @code
* u32le number of samples to skip from start of this packet
* u32le number of samples to skip from end of this packet
* u8 reason for start skip
* u8 reason for end skip (0=padding silence, 1=convergence)
* @endcode
*/
AV_PKT_DATA_SKIP_SAMPLES,
/**
* An AV_PKT_DATA_JP_DUALMONO side data packet indicates that
* the packet may contain "dual mono" audio specific to Japanese DTV
* and if it is true, recommends only the selected channel to be used.
* @code
* u8 selected channels (0=mail/left, 1=sub/right, 2=both)
* @endcode
*/
AV_PKT_DATA_JP_DUALMONO,
/**
* A list of zero terminated key/value strings. There is no end marker for
* the list, so it is required to rely on the side data size to stop.
*/
AV_PKT_DATA_STRINGS_METADATA,
/**
* Subtitle event position
* @code
* u32le x1
* u32le y1
* u32le x2
* u32le y2
* @endcode
*/
AV_PKT_DATA_SUBTITLE_POSITION,
/**
* Data found in BlockAdditional element of matroska container. There is
* no end marker for the data, so it is required to rely on the side data
* size to recognize the end. 8 byte id (as found in BlockAddId) followed
* by data.
*/
AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
/**
* The optional first identifier line of a WebVTT cue.
*/
AV_PKT_DATA_WEBVTT_IDENTIFIER,
/**
* The optional settings (rendering instructions) that immediately
* follow the timestamp specifier of a WebVTT cue.
*/
AV_PKT_DATA_WEBVTT_SETTINGS,
/**
* A list of zero terminated key/value strings. There is no end marker for
* the list, so it is required to rely on the side data size to stop. This
* side data includes updated metadata which appeared in the stream.
*/
AV_PKT_DATA_METADATA_UPDATE,
/**
* MPEGTS stream ID as uint8_t, this is required to pass the stream ID
* information from the demuxer to the corresponding muxer.
*/
AV_PKT_DATA_MPEGTS_STREAM_ID,
/**
* Mastering display metadata (based on SMPTE-2086:2014). This metadata
* should be associated with a video stream and contains data in the form
* of the AVMasteringDisplayMetadata struct.
*/
AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
/**
* This side data should be associated with a video stream and corresponds
* to the AVSphericalMapping structure.
*/
AV_PKT_DATA_SPHERICAL,
/**
* Content light level (based on CTA-861.3). This metadata should be
* associated with a video stream and contains data in the form of the
* AVContentLightMetadata struct.
*/
AV_PKT_DATA_CONTENT_LIGHT_LEVEL,
/**
* ATSC A53 Part 4 Closed Captions. This metadata should be associated with
* a video stream. A53 CC bitstream is stored as uint8_t in AVPacketSideData.data.
* The number of bytes of CC data is AVPacketSideData.size.
*/
AV_PKT_DATA_A53_CC,
/**
* This side data is encryption initialization data.
* The format is not part of ABI, use av_encryption_init_info_* methods to
* access.
*/
AV_PKT_DATA_ENCRYPTION_INIT_INFO,
/**
* This side data contains encryption info for how to decrypt the packet.
* The format is not part of ABI, use av_encryption_info_* methods to access.
*/
AV_PKT_DATA_ENCRYPTION_INFO,
/**
* Active Format Description data consisting of a single byte as specified
* in ETSI TS 101 154 using AVActiveFormatDescription enum.
*/
AV_PKT_DATA_AFD,
/**
* Producer Reference Time data corresponding to the AVProducerReferenceTime struct,
* usually exported by some encoders (on demand through the prft flag set in the
* AVCodecContext export_side_data field).
*/
AV_PKT_DATA_PRFT,
/**
* ICC profile data consisting of an opaque octet buffer following the
* format described by ISO 15076-1.
*/
AV_PKT_DATA_ICC_PROFILE,
/**
* DOVI configuration
* ref:
* dolby-vision-bitstreams-within-the-iso-base-media-file-format-v2.1.2, section 2.2
* dolby-vision-bitstreams-in-mpeg-2-transport-stream-multiplex-v1.2, section 3.3
* Tags are stored in struct AVDOVIDecoderConfigurationRecord.
*/
AV_PKT_DATA_DOVI_CONF,
/**
* Timecode which conforms to SMPTE ST 12-1:2014. The data is an array of 4 uint32_t
* where the first uint32_t describes how many (1-3) of the other timecodes are used.
* The timecode format is described in the documentation of av_timecode_get_smpte_from_framenum()
* function in libavutil/timecode.h.
*/
AV_PKT_DATA_S12M_TIMECODE,
/**
* The number of side data types.
* This is not part of the public API/ABI in the sense that it may
* change when new side data types are added.
* This must stay the last enum value.
* If its value becomes huge, some code using it
* needs to be updated as it assumes it to be smaller than other limits.
*/
AV_PKT_DATA_NB
};
```
| type | meaning |
| -------------------------------------- | ------------------------------------------------------------ |
| AV_PKT_DATA_PALETTE | Palette, data size by AVPALETTE_SIZE decision. |
| AV_PKT_DATA_NEW_EXTRADATA | Used to inform the codec or format that the extradata buffer has changed, and the receiver should take appropriate measures to do so. The new extradata is embedded in the side data buffer and should be used immediately to process the current frame or packet. |
| AV_PKT_DATA_PARAM_CHANGE | The layout is affected by the AVSideDataParamChangeFlags type. |
| AV_PKT_DATA_H263_MB_INFO | It contains a lot of structure about macroblock information, which is related to dividing the packet into smaller packets at the edge of macroblock. |
| AV_PKT_DATA_REPLAYGAIN | It is associated with audio stream and contains replay gain information in the form of AVReplayGain structure. |
| AV_PKT_DATA_DISPLAYMATRIX | It contains a 3x3 transformation matrix, which describes an affine transformation, which needs to be applied to the decoded video frame to display correctly. |
| AV_PKT_DATA_STEREO3D | It is associated with video stream and contains stereo 3D information in the form of avstereo 3D structure. |
| AV_PKT_DATA_AUDIO_SERVICE_TYPE | Associated with an audio stream and corresponding to enum type enum AVAudioServiceType. |
| AV_PKT_DATA_QUALITY_STATS | Contains quality related information from the encoder. |
| AV_PKT_DATA_FALLBACK_TRACK | Contains an integer value that represents the stream index of the fallback track. |
| AV_PKT_DATA_CPB_PROPERTIES | It corresponds to AVCPBProperties structure. |
| AV_PKT_DATA_SKIP_SAMPLES | It is recommended to skip the specified number of samples. |
| AV_PKT_DATA_JP_DUALMONO | Indicates that the packet may contain "dual mono" audio specific to Japanese DTV. If it is true, it is recommended to use only the selected channel. |
| AV_PKT_DATA_STRINGS_METADATA | List of string key value pairs. |
| AV_PKT_DATA_SUBTITLE_POSITION | The location of the subtitle event. |
| AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL | The data found in the BlockAdditional element of the matroska container. |
| AV_PKT_DATA_WEBVTT_IDENTIFIER | The optional first identifier line of the WebVTT cue. |
| AV_PKT_DATA_WEBVTT_SETTINGS | Optional setting (rendering description) after the timestamp specifier of WebVTT cue. |
| AV_PKT_DATA_METADATA_UPDATE | List of string key value pairs. Include update metadata that appears in the stream. |
| AV_PKT_DATA_MPEGTS_STREAM_ID | uint8_t type MPEGTS stream ID, which needs to transfer stream ID information from demuxer to corresponding muxer. |
| AV_PKT_DATA_MASTERING_DISPLAY_METADATA | Mastering display metadata (based on SMPTE-2086:2014), which should be associated with video stream and stored in the form of avmasteringdisplay metadata structure. |
| AV_PKT_DATA_SPHERICAL | It is associated with video stream and corresponds to avspherical mapping structure. |
| AV_PKT_DATA_CONTENT_LIGHT_LEVEL | Content light level (based on CTA-861.3). The metadata should be associated with the video stream and stored in the form of AVContentLightMetadata structure. |
| AV_PKT_DATA_A53_CC | ATSC A53 Part 4 Closed Captions. |
| AV_PKT_DATA_ENCRYPTION_INIT_INFO | Encrypt initialization data. |
| AV_PKT_DATA_ENCRYPTION_INFO | Contains encrypted information about how to decrypt a packet. |
| AV_PKT_DATA_AFD | Active Format Description data. Describes the use of AVActiveFormatDescription in ETSI TS 101 154 to enumerate specified data consisting of a single byte. |
| AV_PKT_DATA_PRFT | Producer reference time data corresponds to avproducer reference time structure, which is usually exported by some encoders (by exporting in AVCodecContext)_ side_ The prft tag is set in the data field. |
| AV_PKT_DATA_ICC_PROFILE | ICC profile data consisting of opaque eight byte buffers in the format described in ISO 15076-1. |
| AV_PKT_DATA_DOVI_CONF | DOVI configuration. |
| AV_PKT_DATA_S12M_TIMECODE | Timecode in accordance with SMPTE ST 12-1:2014. |
| AV_PKT_DATA_NB | Number of side data types. |
reference material:
1. https://ffmpeg.org/doxygen/trunk/structAVPacket.html
2. https://ffmpeg.org/doxygen/trunk/structAVBufferRef.html
3. https://ffmpeg.org/doxygen/trunk/structAVBuffer.html
4. https://ffmpeg.org/doxygen/trunk/structAVPacketSideData.html
5. https://ffmpeg.org/doxygen/trunk/group__lavc__packet.html#ga9a80bfcacc586b483a973272800edb97
================================================
FILE: FFmpeg 学习(一):FFmpeg 简介 .md
================================================
> 本文转载自博客园:https://www.cnblogs.com/renhui/p/6922971.html
# 一、FFmpeg 介绍
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库。
# 二、FFmpeg 组成
- libavformat:用于各种音视频[封装格式](https://baike.baidu.com/item/封装格式)的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能;
- libavcodec:用于各种类型声音/图像编解码;
- libavutil:包含一些公共的工具函数;
- libswscale:用于视频场景比例缩放、色彩映射转换;
- libpostproc:用于后期效果处理;
- ffmpeg:该项目提供的一个工具,可用于格式转换、解码或[电视卡](https://baike.baidu.com/item/电视卡)即时编码等;
- ffsever:一个 HTTP 多媒体即时广播串流服务器;
- ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示;
# 三、FFmpeg包含类库说明
### 2.1 类库说明
- libavformat - 用于各种音视频封装格式的生成和解析,包括获取解码所需信息、读取音视频数据等功能。各种流媒体协议代码(如rtmpproto.c等)以及音视频格式的(解)复用代码(如flvdec.c、flvenc.c等)都位于该目录下。
- libavcodec - 音视频各种格式的编解码。各种格式的编解码代码(如aacenc.c、aacdec.c等)都位于该目录下。
- libavutil - 包含一些公共的工具函数的使用库,包括算数运算,字符操作等。
- libswscale - 提供原始视频的比例缩放、色彩映射转换、图像颜色空间或格式转换的功能。
- libswresample - 提供音频重采样,采样格式转换和混合等功能。
- libavfilter - 各种音视频滤波器。
- libpostproc - 用于后期效果处理,如图像的去块效应等。
- libavdevice - 用于硬件的音视频采集、加速和显示。
如果您之前没有阅读FFmpeg代码的经验,建议优先阅读libavformat、libavcodec以及libavutil下面的代码,它们提供了音视频开发的最基本功能,应用范围也是最广的。
### 2.2 常用结构
FFmpeg里面最常用的数据结构,按功能可大致分为以下几类(以下代码行数,以branch: origin/release/3.4为准):
#### 1. 封装格式
- AVFormatContext - 描述了媒体文件的构成及基本信息,是统领全局的基本结构体,贯穿程序始终,很多函数都要用它作为参数;
- AVInputFormat - 解复用器对象,每种作为输入的封装格式(例如FLV、MP4、TS等)对应一个该结构体,如libavformat/flvdec.c的ff_flv_demuxer;
- AVOutputFormat - 复用器对象,每种作为输出的封装格式(例如FLV, MP4、TS等)对应一个该结构体,如libavformat/flvenc.c的ff_flv_muxer;
- AVStream - 用于描述一个视频/音频流的相关数据信息。
#### 2.编解码
- AVCodecContext - 描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息;
- AVCodec - 编解码器对象,每种编解码格式(例如H.264、AAC等)对应一个该结构体,如libavcodec/aacdec.c的ff_aac_decoder。每个AVCodecContext中含有一个AVCodec;
- AVCodecParameters - 编解码参数,每个AVStream中都含有一个AVCodecParameters,用来存放当前流的编解码参数。
#### 3. 网络协议
- AVIOContext - 管理输入输出数据的结构体;
- URLProtocol - 描述了音视频数据传输所使用的协议,每种传输协议(例如HTTP、RTMP)等,都会对应一个URLProtocol结构,如libavformat/http.c中的ff_http_protocol;
- URLContext - 封装了协议对象及协议操作对象。
#### 4. 数据存放
- AVPacket - 存放编码后、解码前的压缩数据,即ES数据;
- AVFrame - 存放编码前、解码后的原始数据,如YUV格式的视频数据或PCM格式的音频数据等;
================================================
FILE: FFmpeg 学习(七):FFmpeg 学习整理总结.md
================================================
# 一、FFmpeg 播放视频的基本流程整理
播放流程: video.avi(Container) -> 打开得到 Video_Stream -> 读取Packet -> 解析到 Frame -> 显示Frame。
- Container:在音视频中的容器,一般指的是一种特定的文件格式(如 AVI/QT ),里面指明了所包含的音视频,字幕等相关信息。
- Stream:媒体流,指时间轴上的一段连续数据,如一段声音、视频或字幕数据。
- Packet:Stream中的Raw数据,包含了可以被解码成方便我们最后在应用程序中操作的帧的原始数据。
- Frame:Stream中的一个数据单元。
- Codec:编解码器(Code 和 Decode),如 Divx和 MP3,以帧为单位实现压缩数据和原始数据之间的相互转换。
# 二、FFmpeg 各个结构体及相关方法流程整理
### 1. AVCodec
AVCodec -- 编解码器,采用链表维护,每一个都有其对应的名字、类型、CodecID和对数据进行处理的编解码函数指针。
- avcodec_find_decoder/avcodec_find_encoder :根据给定的codec id或解码器名称从系统中搜寻并返回一个AVCodec结构的指针
- avcodec_alloc_context3:根据 AVCodec 分配合适的 AVCodecContext
- avcodec_open/avcodec_open2/avcodec_close :根据给定的 AVCodec 打开对应的Codec,并初始化 AVCodecContext/ 关闭Codec
- avcodec_alloc_frame:分配编解码需要的 AVFrame 结构
- avcodec_decode_video/avcodec_decode_video2 :解码一个视频帧,输入数据在AVPacket结构中,输出数据在AVFrame结构中
- avcodec_decode_audio4:解码一个音频帧。输入数据在AVPacket结构中,输出数据在AVFrame结构中
- avcodec_encode_video/avcodec_encode_video2 :编码一个视频帧,输入数据在AVFrame结构中,输出数据在AVPacket结构中
### 2. AVCodecContext
AVCodecContext -- 和具体媒体数据相关的编解码器上下文,保存AVCodec指针和与codec相关的数据,包含了流中所使用的关于编解码器的所有信息
- codec_name[32]、codec_type(AVMediaType)、codec_id(CodecID)、codec_tag:编解码器的名字、类型(音频/视频/字幕等)、ID(H264/MPEG4等)、FOURC等信息
- hight/width,coded_width/coded_height: Video的高宽
- sample_fmt:音频的原始采样格式, 是 SampleFormat 枚举
- time_base:采用分数(den/num)保存了帧率的信息
### 3. AVFrame
- data/linesize:FFMpeg内部以平面的方式存储原始图像数据,即将图像像素分为多个平面(R/G/B或Y/U/V)数组
- data数组:其中的指针指向各个像素平面的起始位置,编码时需要用户设置数据
- linesize数组 :存放各个存贮各个平面的缓冲区的行宽,编码时需要用户设置数据
- key_frame:该图像是否是关键帧,由 libavcodec 设置
- pict_type:该图像的编码类型:Intra(1)/Predicted(2)/Bi-dir(3) 等,默认值是 NONE(0),其值由libavcodec设置
- pts:呈现时间,编码时由用户设置
- quality:从1(最好)到FF_LAMBDA_MAX(256*128-1,最差),编码时用户设置,默认值是0
- nterlaced_frame:表明是否是隔行扫描的,编码时用户指定,默认0
### 4. AVFormatContext
AVFormatContext -- 格式转换过程中实现输入和输出功能、保存相关数据的主要结构,描述了一个媒体文件或媒体流的构成和基本信息
- nb_streams/streams :AVStream结构指针数组, 包含了所有内嵌媒体流的描述,其内部有 AVInputFormat + AVOutputFormat 结构体,来表示输入输出的文件格式
- avformat_open_input:创建并初始化部分值,但其他一些值(如 mux_rate、key 等)需要手工设置初始值,否则可能出现异常
- avformat_alloc_output_context2:根据文件的输出格式、扩展名或文件名等分配合适的 AVFormatContext 结构
### 5. AVPacket
AVPacket -- 暂存解码之前的媒体数据(一个音/视频帧、一个字幕包等)及附加信息(解码时间戳、显示时间戳、时长等),主要用于建立缓冲区并装载数据。
- data/size/pos: 数据缓冲区指针、长度和媒体流中的字节偏移量
- flags:标志域的组合,1(AV_PKT_FLAG_KEY)表示该数据是一个关键帧, 2(AV_PKT_FLAG_CORRUPT)表示该数据已经损坏
- destruct:释放数据缓冲区的函数指针,其值可为 [av_destruct_packet]/av_destruct_packet_nofree, 会被 av_free_packet 调用
### 6. AVStream
AVStream -- 描述一个媒体流,其大部分信息可通过 avformat_open_input 根据文件头信息确定,其他信息可通过 avformat_find_stream_info 获取,典型的有 视频流、中英文音频流、中英文字幕流(Subtitle),可通过 av_new_stream、avformat_new_stream 等创建。
- index:在AVFormatContext中流的索引,其值自动生成(AVFormatContext::streams[index])
- nb_frames:流内的帧数目
- time_base:流的时间基准,是一个实数,该流中媒体数据的pts和dts都将以这个时间基准为粒度。通常,使用av_rescale/av_rescale_q可以实现不同时间基准的转换
- avformat_find_stream_info:获取必要的编解码器参数(如 AVMediaType、CodecID ),设置到 AVFormatContext::streams[i]::codec 中
- av_read_frame:从多媒体文件或多媒体流中读取媒体数据,获取的数据由 AVPacket 来存放
- av_seek_frame:改变媒体文件的读写指针来实现对媒体文件的随机访问,通常支持基于时间、文件偏移、帧号(AVSEEK_FLAG_FRAME)的随机访问方式
================================================
FILE: FFmpeg 学习(三):将 FFmpeg 移植到 Android平台.md
================================================
首先需要去FFmpeg的官网http://www.ffmpeg.org/去下载FFmpeg的源码,目前的版本号为FFmpeg3.3(Hilbert)。
下载的文件为压缩包,解压后得到ffmpeg-3.3目录。
**修改ffmpeg-3.3的configure文件:**
```
# 原来的配置内容:
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)'
```
原因:如果不修改配置,直接进行编译出来的so文件类似libavcodec.so.55.39.101,文件的版本号位于so之后,这样在Android上无法加载,所以需要修改!
**编写build_android.sh脚本文件:**
在编译FFmpeg之前需要进行配置,设置相应的环境变量等。所有的配置选项都在ffmpeg-3.3/configure这个脚本文件中,执行如下命令可查看所有的配置选项:
$ ./configure –help
下面将配置项和环境变量设置写成一个sh脚本文件来运行以便编译出Android平台需要的so文件出来。
build_android.sh的内容如下:
```
#!/bin/bash
NDK=/Users/renhui/framework/android-ndk-r14b
SYSROOT=$NDK/platforms/android-9/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
function build_one
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-doc \--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
build_one
```
需要确定的是NDK,SYSROOT和TOOLCHAIN是否是本地的环境,并确定cross-prefix指向的路径存在。
保存脚本文件后,将脚本的权限提升:
```
chmod 777 build_android.sh
```
然后执行脚本,该脚本会完成对ffmpeg的配置,并生成config.h等配置文件,后面的编译会用到。如果未经过配置直接进行编译会提示无法找到config.h文件等错误。
然后执行下面两个命令:
```
$make
$make install
```
至此,会在ffmpeg-3.3目录下生成一个android目录,其/android/arm/lib目录下的so库文件就是能够在Android上运行的so库。
创建Demo工程,测试上面生成的so文件能否正常使用:
1. 创建一个新的Android工程
2. 在工程根目录下创建jni文件夹
3. 在jni下创建prebuilt目录,然后:将上面编译成功的so文件放入到该目录下
4. 创建包含native方法的类,先在src下创建cn.renhui包,然后创建FFmpegNative.java类文件。主要包括加载so库文件和一个native测试方法两部分,其内容如下:
```
package cn.renhui;
public class FFmpegNative {
static {
System.loadLibrary("avutil-55");
System.loadLibrary("avcodec-57");
System.loadLibrary("swresample-2");
System.loadLibrary("avformat-57");
System.loadLibrary("swscale-4");
System.loadLibrary("avfilter-6");
System.loadLibrary("avdevice-57");
System.loadLibrary("ffmpeg_codec");
}
public native int avcodec_find_decoder(int codecID);
}
```
1. 用javah创建.头文件: classes目录,执行:javah-jni cn.renhui.FFmpegNative,会在当前目录产生cn_renhui_FFmpegNative.h的C头文件;
1. 根据头文件名,建立相同名字c文件cn_renhui_FFmpegNative.c,在这个源文件中实现头文件中定义的方法,代码如下:
```
#include "cn_renhui_FFmpegNative.h"
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNICALL Java_cn_renhui_FFmpegNative_avcodec_1find_1decoder
(JNIEnv *env, jobject obj, jint codecID)
{
AVCodec *codec = NULL;
/* register all formats and codecs */
av_register_all();
codec = avcodec_find_decoder(codecID);
if (codec != NULL)
{
return 0;
}
else
{
return -1;
}
}
#ifdef __cplusplus
}
#endif
```
1. 编写Android.mk,内容如下:
```
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := avcodec-57-prebuilt
LOCAL_SRC_FILES := prebuilt/libavcodec-57.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := avdevice-57-prebuilt
LOCAL_SRC_FILES := prebuilt/libavdevice-57.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := avfilter-6-prebuilt
LOCAL_SRC_FILES := prebuilt/libavfilter-6.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := avformat-57-prebuilt
LOCAL_SRC_FILES := prebuilt/libavformat-57.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := avutil-55-prebuilt
LOCAL_SRC_FILES := prebuilt/libavutil-55.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := avswresample-2-prebuilt
LOCAL_SRC_FILES := prebuilt/libswresample-2.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := swscale-4-prebuilt
LOCAL_SRC_FILES := prebuilt/libswscale-4.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg_codec
LOCAL_SRC_FILES := cn_dennishucd_FFmpegNative.c
LOCAL_LDLIBS := -llog -ljnigraphics -lz -landroid
LOCAL_SHARED_LIBRARIES := avcodec-57-prebuilt avdevice-57-prebuilt avfilter-6-prebuilt avformat-57-prebuilt avutil-55-prebuilt
include $(BUILD_SHARED_LIBRARY)
```
1. 编译so文件,执行ndk-build
2. 新建一个Activity,进行测试,测试核心代码:
```
FFmpegNative ffmpeg = new FFmpegNative();
int codecID = 28;
int res = ffmpeg.avcodec_find_decoder(codecID);
if (res == 0) {
tv.setText("Success!");
} else {
tv.setText("Failed!");
}
```
28是H264的编解码ID,可以在ffmpeg的源代码中找到,它是枚举类型定义的。在C语言中,可以换算为整型值。这里测试能否找到H264编解码,如果能找到,说明调用ffmpeg的库函数是成功的,这也表明我们编译的so文件是基本可用。
================================================
FILE: FFmpeg 学习(二):Mac下安装FFmpeg.md
================================================
> 本文转载自博客园:https://www.cnblogs.com/renhui/p/8458150.html
# 一、安装ffmpeg
分为两种安装方式:
### 1. 命令行安装
```
brew install ffmpeg
```
### 2. 下载压缩包安装
去 http://evermeet.cx/ffmpeg/ 下载7z压缩包,解压缩后,将ffmpeg文件拷贝到一个地方,然后在bash_profile里面配置好环境变量
# 二、安装ffplay
分为两种安装方式:
### 1. 命令行安装
执行下面的命令就可以进行安装操作
```
brew install ffmpeg --with-ffplay
```
> - 注:目前使用此安装方式安装后,执行ffplay会出现command not found的问题,可能是因为SDL的配置问题导致的。
### 2. 下载压缩包安装
去 http://evermeet.cx/ffmpeg/ 下载7z压缩包,解压缩后,将ffplay文件拷贝到一个地方,然后在bash_profile里面配置好环境变量
# 三、附言
在上面我们接触到了命令行安装ffmpeg的方法,除了安装选项 --with-ffplay外还有更多的选项如下:
```xml
–with-fdk-aac (Enable the Fraunhofer FDK AAC library)
–with-ffplay (Enable FFplay media player)
–with-freetype (Build with freetype support)
–with-frei0r (Build with frei0r support)
–with-libass (Enable ASS/SSA subtitle format)
–with-libcaca (Build with libcaca support)
–with-libvo-aacenc (Enable VisualOn AAC encoder)
–with-libvorbis (Build with libvorbis support)
–with-libvpx (Build with libvpx support)
–with-opencore-amr (Build with opencore-amr support)
–with-openjpeg (Enable JPEG 2000 image format)
–with-openssl (Enable SSL support)
–with-opus (Build with opus support)
–with-rtmpdump (Enable RTMP protocol)
–with-schroedinger (Enable Dirac video format)
–with-speex (Build with speex support)
–with-theora (Build with theora support)
–with-tools (Enable additional FFmpeg tools)
–without-faac (Build without faac support)
–without-lame (Disable MP3 encoder)
–without-x264 (Disable H.264 encoder)
–without-xvid (Disable Xvid MPEG-4 video encoder)
–devel (install development version 2.1.1)
–HEAD (install HEAD version)
```
================================================
FILE: FFmpeg 学习(五):FFmpeg 编解码 API 分析.md
================================================
在上一篇文章 FFmpeg学习(四):FFmpeg API 介绍与通用 API 分析 中,我们简单的讲解了一下FFmpeg 的API基本概念,并分析了一下通用API,本文我们将分析 FFmpeg 在编解码时使用的API。
## 一、FFmpeg 解码 API 分析
### 1. avformat_open_input 分析
函数 avformat_open_input 会根据所提供的文件路径判断文件的格式,其实就是通过这一步来决定到底是使用哪个Demuxer。
举个例子:如果是flv,那么Demuxer就会使用对应的ff_flv_demuxer,所以对应的关键生命周期的方法read_header、read_packet、read_seek、read_close都会使用该flv的Demuxer中函数指针指定的函数。read_header会将AVStream结构体构造好,以方便后续的步骤继续使用AVStream作为输入参数。
### 2. avformat_find_stream_info 分析
该方法的作用就是把所有的Stream的MetaData信息填充好。方法内部会先查找对于的解码器,然后打开对应的解码器,紧接着会利用Demuxer中的read_packet函数读取一段数据进行解码,当然,解码的数据越多,分析出来的流信息就越准确,如果是本地资源,那么很快就可以得到准确的信息了。但是对于网络资源来说,则会比较慢,因此该函数有几个参数可以控制读取数据的长度,一个是probe size,一个是max_analyze_duration, 还有一个就是fps_probe_size,这三个参数共同控制解码数据的长度,如果配置的这几个参数的数值越小,那么这个函数执行的时间就会越快,但会导致AVStream结构体里面的信息(视频的宽、高、fps、编码类型)不准确。
### 3. av_read_frame 分析
该方法读取出来的数据是AVPacket,在FFmpeg的早期版本中开发给开发者的函数其实就是av_read_packet,但是需要开发者自己来处理AVPacket中的数据不能被解码器处理完的情况,即需要把未处理完的压缩数据缓存起来的问题。所以在新版本的FFmpeg中,提供了该函数,用于处理此状况。 该函数的实现首先会委托到Demuxer的read_packet方法中,当然read_packet通过解服用层和协议层的处理后,会将数据返回到这里,在该函数中进行数据缓冲处理。
对于音频流,一个AVPacket可能会包含多个AVFrame,但是对于一个视频流,一个AVPacket只包含一个AVFrame,该函数最终只会返回一个AVPacket结构体。
### 4. avcodec_decode分析
该方法包含了两部分内容:一部分是解码视频,一部分是解码音频。在上面的函数分析中,我们知道,解码是会委托给对应的解码器来实施的,在打开解码器的时候就找到了对应的解码器的实现,比如对于解码H264来讲,会找到ff_h264_decoder,其中会有对应的生命周期函数的实现,最重要的就是init,decode,close三个方法,分别对应于打开解码器、解码及关闭解码器的操作,而解码过程就是调用decode方法。
### 5. avformat_close_input 分析
该函数负责释放对应的资源,首先会调用对应的Demuxer中的生命周期read_close方法,然后释放掉,AVFormatContext,最后关闭文件或者远程网络链接。
## 二、FFmpeg 编码 API 分析
### 1. avformat_alloc_output_context2 分析
该函数内部需要调用方法avformat_alloc_context来分配一个AVFormatContext结构体,当然最关键的还是根据上一步注册的Muxer和Demuxer部分(也就是封装格式部分)去找对应的格式。有可能是flv格式、MP4格式、mov格式,甚至是MP3格式等,如果找不到对应的格式(应该是因为在configure选项中没有打开这个格式的开关),那么这里会返回找不到对于的格式的错误提示。在调用API的时候,可以使用av_err2str把返回的整数类型的错误代码转换为肉眼可读的字符串,这是个在调试中非常有用的工具函数。该函数最终会将找出来的格式赋值给AVFormatContext类型的oformat。
### 2. avio_open2 分析
首先会调用函数ffurl_open,构造出URLContext结构体,这个结构体中包含了URLProtocol(需要去第一步register_protocol中已经注册的协议链表)中去寻找;接着会调用avio_alloc_contex方法,分配出AVIOContext结构体,并将上一步构造出来的URLProtocol传递进来;然后把上一步分配出来的AVIOContext结构体赋值给AVFormatContext属性。
下面就是针对上面的描述总结的结构之间的构架图,各位可以参考此图进行进一步的理解:

avio_open2的过程也恰好是在上面我们分析avformat_open_input过程的一个逆过程。编码过程和解码过程从逻辑上来讲,也是一个逆过程,所以在FFmpeg实现的过程中,他们也互为逆过程。
### 3. 编码其他API(步骤)分析
编码的其他步骤也是解码的一个逆过程,解码过程中的avformat_find_stream_info对应到编码就是avformat_new_stream和avformat_write_header。
- avformat_new_stream函数会将音频流或者视频流的信息填充好,分配出AVStream结构体,在音频流中分配声道、采样率、表示格式、编码器等信息,在视频中分配宽、高、帧率、表示格式、编码器等信息。
- avformat_write_header函数与解码过程中的read_header恰好是一个逆过程,这里就不多赘述了。
接下来就是编码阶段了:
1. 将手动封装好的AVFrame结构体,作为avcodec_encodec_video方法的输入,然后将其编码成为AVPacket,然后调用av_write_frame方法输出到媒体文件中。
2. av_write_frame 方法会将编码后的AVPacket结构体作为Muxer中的write_packet生命周期方法的输入,write_packet会加上自己封装格式的头信息,然后调用协议层,写到本地文件或者网络服务器上。
3. 最后一步就是av_write_trailer(该函数有一个非常大的坑,如果没执行write_header操作,就直接执行write_trailer操作,程序会直接Carsh掉,所以这两个函数必须成对出现),av_write_trailer会把没有输出的AVPacket全部丢给协议层去做输出,然后会调用Muxer的write_trailer生命周期方法(不同的格式,写出的尾部也不一样)。
## 三、FFmpeg 解码 API 超时设置
当视频流地址能打开,但是视频流中并没有流内容的时候,可能会导致整体执行流程阻塞在 avformat_open_input 或者 av_read_frame 方法上。
主要原因就是avformat_open_input 和av_read_frame 这两个方法是阻塞的。
av_read_frame() -> read_frame_internal() -> ff_read_packet() -> s->iformat->read_packet() -> read_from_url() -> ffurl_read() -> retry_transfer_wrapper() (此方法会堵塞)
虽然我们可以通过设置 ic->flags |= AVFMT_FLAG_NONBLOCK; 将操作设置为非阻塞,但这样设置是不推荐的,会导致后续的其他操作出现问题。
一般情况下,我们推荐另外两种机制进行设置:
### 1. 设置开流的超时时间
在设置开流超时时间的时候,需要注意 不同的协议设置的方式是不一样的。
```
方法:timeout --> 单位:(http:ms udp:s)``方法:stimeout --> 单位:(rtsp us)
```
设置udp、http 超时的示例代码如下:
```
AVDictionary* opts = NULL;
av_dict_set(&opts, "timeout", "3000000", 0);//单位 如果是http:ms 如果是udp:s
int ret = avformat_open_input(&ctx, url, NULL, &opts);
```
设置rtsp超时的示例代码如下:
```
AVDictionary* opts = NULL;
av_dict_set(&opts, "rtsp_transport", m_bTcp ? "tcp" : "udp", 0); //设置tcp or udp,默认一般优先tcp再尝试udp
av_dict_set(&opts, "stimeout", "3000000", 0);//单位us 也就是这里设置的是3s
ret = avformat_open_input(&ctx, url, NULL, &opts);
```
### 2. 设置interrupt_callback定义返回机制
设置回调,监控read超时情况,回调方法为:
```
int64_t lastReadPacktTime;
static int interrupt_cb(void *ctx)
{
int timeout = 3;
if (av_gettime() - lastReadPacktTime > timeout * 1000 * 1000)
{
return -1;
}
return 0;
}
```
回调函数中返回0则代表ffmpeg继续阻塞直到ffmpeg正常工作为止,否则就代表ffmpeg结束阻塞可以将操纵权交给用户线程并返回错误码。
对指定的 AVFormatContext 进行设置,并在需要调用的设置的时间之前,记录当前的时间,这样在回调的时候就能根据时间差,判断执行相应的逻辑:
avformat_open_input 设置方式:
```
inputContext = avformat_alloc_context();
lastReadPacktTime = av_gettime();
inputContext->interrupt_callback.callback = interrupt_cb;
int ret = avformat_open_input(&inputContext, inputUrl.c_str(), nullptr, nullptr);
```
av_read_frame 设置方式:
```
lastReadPacktTime = av_gettime();
ret = av_read_frame(inputContext, packet);
```
在实际开发中,只是设计这个机制,很容易出现超时,但如果超时时间设置过程,又容易阻塞线程。一般推荐的方案为:在超时的机制上增加连续读流的时长统计,当连续读流超时超过一定时间时就通知当前读流操作已失败。
================================================
FILE: FFmpeg 学习(六):FFmpeg 核心模块 libavformat 与 libavcodec 分析.md
================================================
# 一、libavformat介绍
libavformat的主要组成与层次调用关系如下图:

AVFromatContext是API层直接接触到的结构体,它会进行格式的封装和解封装,它的数据部分由底层提供,底层使用了AVIOContext,这个AVIOContext实际上就是为普通的I/O增加了一层Buffer缓冲区,再往底层就是URLContext,也就是达到了协议层,协议层的实现由很多,如rtmp、http、hls、file等,这个就是libavformat的内部封装结构了。
# 二、libavcodec介绍
libavcodec模块的主要组成和数据结构图如下:

对于开发者来说,这个模块我们能接触到的最顶层的数据结构就是AVCodecContext,该结构体包含的就是与实际的编解码有关的部分。
首先AVCodecContext是包含在一个AVStream里面的,即描述了这路流的编码格式是什么,然后利用该编码器或者解码器进行AVPacket与AVFrame之间的转换(实际上就是编码或者解码的过程),这是FFmpeg中最重要的一部分。
================================================
FILE: FFmpeg 学习(四):FFmpeg API 介绍与通用 API 分析.md
================================================
## 一、FFmpeg 编解码流程
FFmpeg编解码流程图如下,此图包含了整体的解封装、编解码的基本流程。

下面我们要介绍的术语及相关API都是围绕这个流程图展开的。
## 二、FFmpeg 相关术语
**1. 容器/文件(Container/File)**:即特定格式的多媒体文件,比如MP4,flv,mov等。
**2. 媒体流(Stream)**:表示在时间轴上的一段连续的数据,比如一段声音数据、一段视频数据或者一段字母数据,可以是压缩的,也可以是非压缩的,压缩的数据需要关联特定的编解码器。
**3. 数据帧/数据包(Frame/Packet)**:通常一个媒体流是由大量的数据帧组成的,对于压缩数据,帧对应着编解码器的最小处理单元,分属于不同媒体流的数据帧交错存储与容器之中。
**4. 编解码器**:编解码器是以帧为单位实现压缩数据和原始数据之间的相互转换的。
前面介绍的术语,就是FFmpeg中抽象出来的概念。其中:
**1. AVFormatContext**:就是对容器或者媒体文件层次的抽象。
**2. AVStream**:在文件中(容器里面)包含了多路流(音频流、视频流、字幕流),AVStream 就是对流的抽象。
**3. AVCodecContext 与 AVCodec**:在每一路流中都会描述这路流的编码格式,对编解码器格式以及编解码器的抽象就是AVCodecContext 与 AVCodec。
**4. AVPacket 与 AVFrame**:对于编码器或者解码器的输入输出部分,也就是压缩数据以及原始数据的抽象就是AVPacket与AVFrame。
**5. AVFilte**r:除了编解码之外,对音视频的处理肯定是针对于原始数据的处理,也就是针对AVFrame的处理,使用的就是AVFilter。
## 三、FFmpeg 通用 API 分析
### 1. av_register_all 分析
在最开始编译FFmpeg的时候,我们做了一个configure的配置,其中开启或者关闭了很多选项。configure的配置会生成两个文件:config.mk和config.h。
> config.mk:就是makefile文件需要包含进去的子模块,会作用在编译阶段,帮助开发者编译出正确的库。
>
> config.h:作用在运行阶段,主要是确定需要注册那些容器及编解码格式到FFmpeg框架中。
调用 av_register_all 就可以注册config.h里面开发的编解码器,然后会注册所有的Muxer和Demuxer(封装格式),最后注册所有的Protocol(协议)。
这样在configure时开启或者关闭的选项就作用到了运行时,该函数的源码分析设计的源码文件包括:url.c、allformats.c、mux.c、format.c 等文件。已经将这几个源码文件单独提出来了,并放在百度网盘上了,地址:https://pan.baidu.com/s/1p8-ish6oeRTaUs84juQtHg。
### 2. av_find_codec 分析
这个方法包含了两部分的内容:一部分是寻找解码器,一部分是寻找编码器。其实在av_register_all的函数执行时,就已经把编码器和解码器都存放到一个链表中了。这里寻找编解码器就是从上一步构造的链表中遍历,通过Codec的ID或者name进行条件匹配,最终返回对于的Codec。
### 3. avcodec_open2 分析
该函数是打开编解码器(Codec)的函数,无论是编码过程还是解码过程,都会用到这个函数。该函数的输入参数有三个:第一个是AVCodecContext,解码过程由FFmpeg引擎填充,编码过程由开发者自己构造,如果想传入私有参数,则为它的priv_data设置参数;第二个参数是上一步通过av_find_codec寻找出来的编解码器(Codec);第三个参数一般传NULL。
### 4. avcodec_close 分析
如果理解了avcodec_open,那么对应的close就是一个逆过程,找到对应的实现文件中的close函数指针所只指向的函数,然后该函数会调用对应第三方库的API来关闭掉对应的编码库。
## 四、总结
本文主要是讲述了FFmpeg的相关术语,并讲解了一下通用的API的分析,不难看出其实FFmpeg所做的事情就是透明化所有的编解码库,用自己的封装来为开发者提供统一的接口。开发者使用不同的编码库时,只需要指明要用哪一个即可,这也充分体现了面向对象编程中的封装特性。
================================================
FILE: FFmpeg 开发之 AVFilter 使用流程总结.md
================================================
在使用FFmpeg开发时,使用AVFilter的流程较为复杂,涉及到的数据结构和函数也比较多,那么使用FFmpeg AVFilter的整体流程是什么样,在其执行过程中都有哪些步骤,需要注意哪些细节?这些都是需要我们整理和总结的。
首先,我们需要引入三个概念结构体:AVFilterGraph 、AVFilterContext、AVFilter。
## 一、AVFilterGraph 、AVFilterContext、AVFilter
在 FFmpeg 中有多种多样的滤镜,你可以把他们当成一个个小工具,专门用于处理视频和音频数据,以便实现一定的目的。如 overlay 这个滤镜,可以将一个图画覆盖到另一个图画上;transport 这个滤镜可以将图画做旋转等等。
一个 filter 的输出可以作为另一个 filter 的输入,因此多个 filter 可以组织成为一个网状的 filter graph,从而实现更加复杂或者综合的任务。
在 libavfilter 中,我们用类型 AVFilter 来表示一个 filter,每一个 filter 都是经过注册的,其特性是相对固定的。而 AVFilterContext 则表示一个真正的 filter 实例,这和 AVCodec 以及 AVCodecContext 的关系是类似的。
AVFilter 中最重要的特征就是其所需的输入和输出。
AVFilterContext 表示一个 AVFilter 的实例,我们在实际使用 filter 时,就是使用这个结构体。AVFilterContext 在被使用前,它必须是 被初始化的,就是需要对 filter 进行一些选项上的设置,通过初始化告诉 FFmpeg 我们已经做了相关的配置。
AVFilterGraph 表示一个 filter graph,当然它也包含了 filter chain的概念。graph 包含了诸多 filter context 实例,并负责它们之间的 link,graph 会负责创建,保存,释放 这些相关的 filter context 和 link,一般不需要用户进行管理。除此之外,它还有线程特性和最大线程数量的字段,和filter context类似。graph 的操作有:分配一个graph,往graph中添加一个filter context,添加一个 filter graph,对 filter 进行 link 操作,检查内部的link和format是否有效,释放graph等。
## 二、AVFilter 相关Api使用方法整理
### 1. AVFilterContext 初始化方法
AVFilterContext 的初始化方式有三种,avfilter_init_str() 和 avfilter_init_dict()、avfilter_graph_create_filter().
```
/*
使用提供的参数初始化 filter。
参数args:表示用于初始化 filter 的 options。该字符串必须使用 ":" 来分割各个键值对, 而键值对的形式为 'key=value'。如果不需要设置选项,args为空。
除了这种方式设置选项之外,还可以利用 AVOptions API 直接对 filter 设置选项。
返回值:成功返回0,失败返回一个负的错误值
*/
int avfilter_init_str(AVFilterContext *ctx, const char *args);
```
```
/*
使用提供的参数初始化filter。
参数 options:以 dict 形式提供的 options。
返回值:成功返回0,失败返回一个负的错误值
注意:这个函数和 avfilter_init_str 函数的功能是一样的,只不过传递的参数形式不同。 但是当传入的 options 中有不被 filter 所支持的参数时,这两个函数的行为是不同: avfilter_init_str 调用会失败,而这个函数则不会失败,它会将不能应用于指定 filter 的 option 通过参数 options 返回,然后继续执行任务。
*/
int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options);
```
```
/**
* 创建一个Filter实例(根据args和opaque的参数),并添加到已存在的AVFilterGraph.
* 如果创建成功*filt_ctx会指向一个创建好的Filter实例,否则会指向NULL.
* @return 失败返回负数,否则返回大于等于0的数
*/
int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt, const char *name, const char *args, void *opaque, AVFilterGraph *graph_ctx);
```
### 2. AVFilterGraph 相关的Api
AVFilterGraph 表示一个 filter graph,当然它也包含了 filter chain的概念。graph 包含了诸多 filter context 实例,并负责它们之间的 link,graph 会负责创建,保存,释放 这些相关的 filter context 和 link,一般不需要用户进行管理。
graph 的操作有:分配一个graph,往graph中添加一个filter context,添加一个 filter graph,对 filter 进行 link 操作,检查内部的link和format是否有效,释放graph等。
根据上述操作,可以列举的方法分别为:
**分配空的filter graph:**
```
/*
分配一个空的 filter graph.
成功返回一个 filter graph,失败返回 NULL
*/
AVFilterGraph *avfilter_graph_alloc(void);
```
**创建一个新的filter实例:**
```
/*
在 filter graph 中创建一个新的 filter 实例。这个创建的实例尚未初始化。
详细描述:在 graph 中创建一个名称为 name 的 filter类型的实例。
创建失败,返回NULL。创建成功,返回 filter context实例。创建成功后的实例会加入到graph中,
可以通过 AVFilterGraph.filters 或者 avfilter_graph_get_filter() 获取。
*/
AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph, const AVFilter *filter, const char *name);
```
**返回名字为name的filter context:**
```
/*
返回 graph 中的名为 name 的 filter context。
*/
AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name);
```
**在 filter graph 中创建一个新的 filter context 实例,并使用args和opaque初始化这个filter context:**
```
/*
在 filter graph 中创建一个新的 filter context 实例,并使用 args 和 opaque 初始化这个实例。
参数 filt_ctx:返回成功创建的 filter context
返回值:成功返回正数,失败返回负的错误值。
*/
int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt, const char *name, const char *args, void *opaque, AVFilterGraph *graph_ctx);
```
**配置 AVFilterGraph 的链接和格式:**
```
/*
检查 graph 的有效性,并配置其中所有的连接和格式。
有效则返回 >= 0 的数,否则返回一个负值的 AVERROR.
*/
int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx);
```
**释放AVFilterGraph:**
```
/*
释放graph,摧毁内部的连接,并将其置为NULL。
*/
void avfilter_graph_free(AVFilterGraph **graph);
```
**在一个已经存在的link中插入一个FilterContext:**
```
/*
在一个已经存在的 link 中间插入一个 filter context。
参数filt_srcpad_idx和filt_dstpad_idx:指定filt要连接的输入和输出pad的index。
成功返回0.
*/
int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, unsigned filt_srcpad_idx, unsigned filt_dstpad_idx);
```
将字符串描述的filter graph 加入到一个已存在的graph中:
```
/*
将一个字符串描述的 filter graph 加入到一个已经存在的 graph 中。
注意:调用者必须提供 inputs 列表和 outputs 列表。它们在调用这个函数之前必须是已知的。
注意:inputs 参数用于描述已经存在的 graph 的输入 pad 列表,也就是说,从新的被创建的 graph 来讲,它们是 output。
outputs 参数用于已经存在的 graph 的输出 pad 列表,从新的被创建的 graph 来说,它们是 input。
成功返回 >= 0,失败返回负的错误值。
*/
int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
AVFilterInOut *inputs, AVFilterInOut *outputs,
void *log_ctx);
```
```
/*
和 avfilter_graph_parse 类似。不同的是 inputs 和 outputs 参数,即做输入参数,也做输出参数。
在函数返回时,它们将会保存 graph 中所有的处于 open 状态的 pad。返回的 inout 应该使用 avfilter_inout_free() 释放掉。
注意:在字符串描述的 graph 中,第一个 filter 的输入如果没有被一个字符串标识,默认其标识为"in",最后一个 filter 的输出如果没有被标识,默认为"output"。
intpus:作为输入参数是,用于保存已经存在的graph的open inputs,可以为NULL。
作为输出参数,用于保存这个parse函数之后,仍然处于open的inputs,当然如果传入为NULL,则并不输出。
outputs:同上。
*/
int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters,
AVFilterInOut **inputs, AVFilterInOut **outputs, void *log_ctx);
```
```
/*
和 avfilter_graph_parse_ptr 函数类似,不同的是,inputs 和 outputs 函数不作为输入参数,
仅作为输出参数,返回字符串描述的新的被解析的graph在这个parse函数后,仍然处于open状态的inputs和outputs。
返回的 inout 应该使用 avfilter_inout_free() 释放掉。
成功返回0,失败返回负的错误值。
*/
int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
AVFilterInOut **inputs, AVFilterInOut **outputs);
```
**将graph转换为可读取的字符串描述:**
```
/*
将 graph 转化为可读的字符串描述。
参数options:未使用,忽略它。
*/
char *avfilter_graph_dump(AVFilterGraph *graph, const char *options);
```
## 三、FFmpeg Filter Buffer 和 BufferSink 相关APi的使用方法整理
Buffer 和 BufferSink 作为 graph 的输入点和输出点来和我们交互,我们仅需要和其进行数据交互即可。其API如下:
```
//buffersrc flag
enum {
//不去检测 format 的变化
AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT = 1,
//立刻将 frame 推送到 output
AV_BUFFERSRC_FLAG_PUSH = 4,
//对输入的frame新建一个引用,而非接管引用
//如果 frame 是引用计数的,那么对它创建一个新的引用;否则拷贝frame中的数据
AV_BUFFERSRC_FLAG_KEEP_REF = 8,
};
```
**向 buffer_src 添加一个Frame:**
```
/*
向 buffer_src 添加一个 frame。
默认情况下,如果 frame 是引用计数的,那么这个函数将会接管其引用并重新设置 frame。
但这个行为可以由 flags 来控制。如果 frame 不是引用计数的,那么拷贝该 frame。
如果函数返回一个 error,那么 frame 并未被使用。frame为NULL时,表示 EOF。
成功返回 >= 0,失败返回负的AVERROR。
*/
int av_buffersrc_add_frame_flags(AVFilterContext *buffer_src, AVFrame *frame, int flags);
```
**添加一个frame到 src filter:**
```
/*
添加一个 frame 到 src filter。
这个函数等同于没有 AV_BUFFERSRC_FLAG_KEEP_REF 的 av_buffersrc_add_frame_flags() 函数。
*/
int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame);
/*
添加一个 frame 到 src filter。
这个函数等同于设置了 AV_BUFFERSRC_FLAG_KEEP_REF 的av_buffersrc_add_frame_flags() 函数。
*/
int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame);
```
**从sink获取已filtered处理的帧,并放到参数frame中:**
```
/*
从 sink 中获取已进行 filtered 处理的帧,并将其放到参数 frame 中。
参数ctx:指向 buffersink 或 abuffersink 类型的 filter context
参数frame:获取到的被处理后的frame,使用后必须使用av_frame_unref() / av_frame_free()释放掉它
成功返回非负数,失败返回负的错误值,如 EAGAIN(表示需要新的输入数据来产生filter后的数据),
AVERROR_EOF(表示不会再有新的输入数据)
*/
int av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags);
```
```
/*
同 av_buffersink_get_frame_flags ,不过不能指定 flag。
*/
int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame)
/*
和 av_buffersink_get_frame 相同,不过这个函数是针对音频的,而且可以指定读取的取样数。此时 ctx 只能指向 abuffersink 类型的 filter context。
*/
int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples);
```
## 四、FFmpeg AVFilter 使用整体流程
下图就是FFmpeg AVFilter在使用过程中的流程图:

我们对上图先做下说明,理解下图中每个步骤的关系,然后,才从代码的角度来给出其使用的步骤。
1. 最顶端的AVFilterGraph,这个结构前面介绍过,主要管理加入的过滤器,其中加入的过滤器就是通过函数avfilter_graph_create_filter来创建并加入,这个函数返回是AVFilterContext(其封装了AVFilter的详细参数信息)。
2. buffer和buffersink这两个过滤器是FFMpeg为我们实现好的,buffer表示源,用来向后面的过滤器提供数据输入(其实就是原始的AVFrame);buffersink过滤器是最终输出的(经过过滤器链处理后的数据AVFrame),其它的诸如filter 1 等过滤器是由avfilter_graph_parse_ptr函数解析外部传入的过滤器描述字符串自动生成的,内部也是通过avfilter_graph_create_filter来创建过滤器的。
3. 上面的buffer、filter 1、filter 2、filter n、buffersink之间是通过avfilter_link函数来进行关联的(通过AVFilterLink结构),这样子过滤器和过滤器之间就通过AVFilterLink进行关联上了,前一个过滤器的输出就是下一个过滤器的输入,注意,除了源和接收过滤器之外,其它的过滤器至少有一个输入和输出,这很好理解,中间的过滤器处理完AVFrame后,得到新的处理后的AVFrame数据,然后把新的AVFrame数据作为下一个过滤器的输入。
4. 过滤器建立完成后,首先我们通过av_buffersrc_add_frame把最原始的AVFrame(没有经过任何过滤器处理的)加入到buffer过滤器的fifo队列。
5. 然后调用buffersink过滤器的av_buffersink_get_frame_flags来获取处理完后的数据帧(这个最终放入buffersink过滤器的AVFrame是通过之前创建的一系列过滤器处理后的数据)。
使用流程图就介绍到这里,下面结合上面的使用流程图详细说下FFMpeg中使用过滤器的步骤,这个过程我们分为三个部分:过滤器构建、数据加工、资源释放。
### 1. 过滤器构建:
1)分配AVFilterGraph
```
AVFilterGraph* graph = avfilter_graph_alloc();
```
2)创建过滤器源
```
char srcArgs[256] = {0};
AVFilterContext *srcFilterCtx;
AVFilter* srcFilter = avfilter_get_by_name("buffer");
avfilter_graph_create_filter(&srcFilterCtx, srcFilter ,"out_buffer", srcArgs, NULL, graph);
```
3)创建接收过滤器
```
AVFilterContext *sinkFilterCtx;
AVFilter* sinkFilter = avfilter_get_by_name("buffersink");
avfilter_graph_create_filter(&sinkFilterCtx, sinkFilter,"in_buffersink", NULL, NULL, graph);
```
4)生成源和接收过滤器的输入输出
这里主要是把源和接收过滤器封装给AVFilterInOut结构,使用这个中间结构来把过滤器字符串解析并链接进graph,主要代码如下:
```
AVFilterInOut *inputs = avfilter_inout_alloc();
AVFilterInOut *outputs = avfilter_inout_alloc();
outputs->name = av_strdup("in");
outputs->filter_ctx = srcFilterCtx;
outputs->pad_idx = 0;
outputs->next = NULL;
inputs->name = av_strdup("out");
inputs->filter_ctx = sinkFilterCtx;
inputs->pad_idx = 0;
inputs->next = NULL;
```
这里源对应的AVFilterInOut的name最好定义为in,接收对应的name为out,因为FFMpeg源码里默认会通过这样个name来对默认的输出和输入进行查找。
5)通过解析过滤器字符串添加过滤器
```
const *char filtergraph = "[in1]过滤器名称=参数1:参数2[out1]";
int ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, NULL);
```
这里过滤器是以字符串形式描述的,其格式为:[in]过滤器名称=参数[out],过滤器之间用,或;分割,如果过滤器有多个参数,则参数之间用:分割,其中[in]和[out]分别为过滤器的输入和输出,可以有多个。
6)检查过滤器的完整性
```
avfilter_graph_config(graph, NULL);
```
### 2. 数据加工
1)向源过滤器加入AVFrame
```
AVFrame* frame; // 这是解码后获取的数据帧
int ret = av_buffersrc_add_frame(srcFilterCtx, frame);
```
2)从buffersink接收处理后的AVFrame
```
int ret = av_buffersink_get_frame_flags(sinkFilterCtx, frame, 0);
```
现在我们就可以使用处理后的AVFrame,比如显示或播放出来。
### 3.资源释放
使用结束后,调用avfilter_graph_free(&graph);释放掉AVFilterGraph类型的graph。
================================================
FILE: FFmpeg 结构体学习(一): AVFormatContext 分析.md
================================================
在 FFmpeg 学习(六):FFmpeg 核心模块 libavformat 与 libavcodec 分析 中,我们分析了FFmpeg中最重要的两个模块以及重要的结构体之间的关系。
后面的文章,我们先不去继续了解其他模块,先针对在之前的学习中接触到的结构体进行分析,然后在根据功能源码,继续了解FFmpeg。
**AVFormatContext是包含码流参数较多的结构体。本文将会详细分析一下该结构体里每个变量的含义和作用。**
# 一、源码整理
首先我们先看一下结构体AVFormatContext的定义的结构体源码(位于libavformat/avformat.h,本人已经将相关注释翻译成中文,方便大家理解):
View Code
# 二、AVForamtContext 重点字段
在使用FFMPEG进行开发的时候,AVFormatContext是一个贯穿始终的数据结构,很多函数都要用到它作为参数。它是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体。下面看几个主要变量的作用(在这里考虑解码的情况):
```
struct AVInputFormat *iformat:输入数据的封装格式
AVIOContext *pb:输入数据的缓存
unsigned int nb_streams:视音频流的个数
AVStream **streams:视音频流
char filename[1024]:文件名
int64_t duration:时长(单位:微秒us,转换为秒需要除以1000000)
int bit_rate:比特率(单位bps,转换为kbps需要除以1000)
AVDictionary *metadata:元数据
```
视频的时长可以转换成HH:MM:SS的形式,示例代码如下:
```
AVFormatContext *pFormatCtx;
CString timelong;
...
//duration是以微秒为单位
//转换成hh:mm:ss形式
int tns, thh, tmm, tss;
tns = (pFormatCtx->duration)/1000000;
thh = tns / 3600;
tmm = (tns % 3600) / 60;
tss = (tns % 60);
timelong.Format("%02d:%02d:%02d",thh,tmm,tss);
```
视频的原数据(metadata)信息可以通过AVDictionary获取。元数据存储在AVDictionaryEntry结构体中,如下所示:
```
typedef struct AVDictionaryEntry {
char *key;
char *value;
} AVDictionaryEntry;
```
每一条元数据分为key和value两个属性。
在ffmpeg中通过av_dict_get()函数获得视频的原数据。
下列代码显示了获取元数据并存入meta字符串变量的过程,注意每一条key和value之间有一个"\t:",value之后有一个"\r\n"
```
//MetaData------------------------------------------------------------
//从AVDictionary获得
//需要用到AVDictionaryEntry对象
//CString author,copyright,description;
CString meta=NULL,key,value;
AVDictionaryEntry *m = NULL;
//不用一个一个找出来
/* m=av_dict_get(pFormatCtx->metadata,"author",m,0);
author.Format("作者:%s",m->value);
m=av_dict_get(pFormatCtx->metadata,"copyright",m,0);
copyright.Format("版权:%s",m->value);
m=av_dict_get(pFormatCtx->metadata,"description",m,0);
description.Format("描述:%s",m->value);
*/
//使用循环读出
//(需要读取的数据,字段名称,前一条字段(循环时使用),参数)
while(m=av_dict_get(pFormatCtx->metadata,"",m,AV_DICT_IGNORE_SUFFIX)){
key.Format(m->key);
value.Format(m->value);
meta+=key+"\t:"+value+"\r\n" ;
}
```
================================================
FILE: FFmpeg 结构体学习(七): AVIOContext 分析.md
================================================
AVIOContext是FFMPEG管理输入输出数据的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。
# 一、源码整理
首先我们先看一下结构体AVIOContext的定义的结构体源码(位于libavformat/avio.h):
```
/**
* Bytestream IO Context.
* New fields can be added to the end with minor version bumps.
* Removal, reordering and changes to existing fields require a major
* version bump.
* sizeof(AVIOContext) must not be used outside libav*.
*
* @note None of the function pointers in AVIOContext should be called
* directly, they should only be set by the client application
* when implementing custom I/O. Normally these are set to the
* function pointers specified in avio_alloc_context()
*/
typedef struct {
/**
* A class for private options.
*
* If this AVIOContext is created by avio_open2(), av_class is set and
* passes the options down to protocols.
*
* If this AVIOContext is manually allocated, then av_class may be set by
* the caller.
*
* warning -- this field can be NULL, be sure to not pass this AVIOContext
* to any av_opt_* functions in that case.
*/
AVClass *av_class;
unsigned char *buffer; /**< Start of the buffer. */
int buffer_size; /**< Maximum buffer size */
unsigned char *buf_ptr; /**< Current position in the buffer */
unsigned char *buf_end; /**< End of the data, may be less than
buffer+buffer_size if the read function returned
less data than requested, e.g. for streams where
no more data has been received yet. */
void *opaque; /**< A private pointer, passed to the read/write/seek/...
functions. */
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
int64_t (*seek)(void *opaque, int64_t offset, int whence);
int64_t pos; /**< position in the file of the current buffer */
int must_flush; /**< true if the next seek should flush */
int eof_reached; /**< true if eof reached */
int write_flag; /**< true if open for writing */
int max_packet_size;
unsigned long checksum;
unsigned char *checksum_ptr;
unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
int error; /**< contains the error code or 0 if no error happened */
/**
* Pause or resume playback for network streaming protocols - e.g. MMS.
*/
int (*read_pause)(void *opaque, int pause);
/**
* Seek to a given timestamp in stream with the specified stream_index.
* Needed for some network streaming protocols which don't support seeking
* to byte position.
*/
int64_t (*read_seek)(void *opaque, int stream_index,
int64_t timestamp, int flags);
/**
* A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
*/
int seekable;
/**
* max filesize, used to limit allocations
* This field is internal to libavformat and access from outside is not allowed.
*/
int64_t maxsize;
} AVIOContext;
```
# 二、AVIOContext 重点字段
AVIOContext中有以下几个变量比较重要:
```
unsigned char *buffer:缓存开始位置
int buffer_size:缓存大小(默认32768)
unsigned char *buf_ptr:当前指针读取到的位置
unsigned char *buf_end:缓存结束的位置
void *opaque:URLContext结构体
```
在解码的情况下,buffer用于存储ffmpeg读入的数据。例如打开一个视频文件的时候,先把数据从硬盘读入buffer,然后在送给解码器用于解码。
其中opaque指向了URLContext。注意,这个结构体并不在FFMPEG提供的头文件中,而是在FFMPEG的源代码中。从FFMPEG源代码中翻出的定义如下所示:
```
typedef struct URLContext {
const AVClass *av_class; ///< information for av_log(). Set by url_open().
struct URLProtocol *prot;
int flags;
int is_streamed; /**< true if streamed (no seek possible), default = false */
int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */
void *priv_data;
char *filename; /**< specified URL */
int is_connected;
AVIOInterruptCB interrupt_callback;
} URLContext;
```
URLContext结构体中还有一个结构体URLProtocol。注:每种协议(rtp,rtmp,file等)对应一个URLProtocol。这个结构体也不在FFMPEG提供的头文件中。从FFMPEG源代码中翻出其的定义:
```
typedef struct URLProtocol {
const char *name;
int (*url_open)(URLContext *h, const char *url, int flags);
int (*url_read)(URLContext *h, unsigned char *buf, int size);
int (*url_write)(URLContext *h, const unsigned char *buf, int size);
int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);
int (*url_close)(URLContext *h);
struct URLProtocol *next;
int (*url_read_pause)(URLContext *h, int pause);
int64_t (*url_read_seek)(URLContext *h, int stream_index,
int64_t timestamp, int flags);
int (*url_get_file_handle)(URLContext *h);
int priv_data_size;
const AVClass *priv_data_class;
int flags;
int (*url_check)(URLContext *h, int mask);
} URLProtocol;
```
在这个结构体中,除了一些回调函数接口之外,有一个变量const char *name,该变量存储了协议的名称。每一种输入协议都对应这样一个结构体。
比如说,文件协议中代码如下(file.c):
```
URLProtocol ff_file_protocol = {
.name = "file",
.url_open = file_open,
.url_read = file_read,
.url_write = file_write,
.url_seek = file_seek,
.url_close = file_close,
.url_get_file_handle = file_get_handle,
.url_check = file_check,
};
```
libRTMP中代码如下(libRTMP.c):
```
URLProtocol ff_rtmp_protocol = {
.name = "rtmp",
.url_open = rtmp_open,
.url_read = rtmp_read,
.url_write = rtmp_write,
.url_close = rtmp_close,
.url_read_pause = rtmp_read_pause,
.url_read_seek = rtmp_read_seek,
.url_get_file_handle = rtmp_get_file_handle,
.priv_data_size = sizeof(RTMP),
.flags = URL_PROTOCOL_FLAG_NETWORK,
};
```
udp协议代码如下(udp.c):
```
URLProtocol ff_udp_protocol = {
.name = "udp",
.url_open = udp_open,
.url_read = udp_read,
.url_write = udp_write,
.url_close = udp_close,
.url_get_file_handle = udp_get_file_handle,
.priv_data_size = sizeof(UDPContext),
.flags = URL_PROTOCOL_FLAG_NETWORK,
};
```
等号右边的函数是完成具体读写功能的函数。可以看一下file协议的几个函数(其实就是读文件,写文件这样的操作)(file.c):
```
/* standard file protocol */
static int file_read(URLContext *h, unsigned char *buf, int size)
{
int fd = (intptr_t) h->priv_data;
int r = read(fd, buf, size);
return (-1 == r)?AVERROR(errno):r;
}
static int file_write(URLContext *h, const unsigned char *buf, int size)
{
int fd = (intptr_t) h->priv_data;
int r = write(fd, buf, size);
return (-1 == r)?AVERROR(errno):r;
}
static int file_get_handle(URLContext *h)
{
return (intptr_t) h->priv_data;
}
static int file_check(URLContext *h, int mask)
{
struct stat st;
int ret = stat(h->filename, &st);
if (ret < 0)
return AVERROR(errno);
ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ : 0;
ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0;
return ret;
}
#if CONFIG_FILE_PROTOCOL
static int file_open(URLContext *h, const char *filename, int flags)
{
int access;
int fd;
av_strstart(filename, "file:", &filename);
if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
access = O_CREAT | O_TRUNC | O_RDWR;
} else if (flags & AVIO_FLAG_WRITE) {
access = O_CREAT | O_TRUNC | O_WRONLY;
} else {
access = O_RDONLY;
}
#ifdef O_BINARY
access |= O_BINARY;
#endif
fd = open(filename, access, 0666);
if (fd == -1)
return AVERROR(errno);
h->priv_data = (void *) (intptr_t) fd;
return 0;
}
/* XXX: use llseek */
static int64_t file_seek(URLContext *h, int64_t pos, int whence)
{
int fd = (intptr_t) h->priv_data;
if (whence == AVSEEK_SIZE) {
struct stat st;
int ret = fstat(fd, &st);
return ret < 0 ? AVERROR(errno) : st.st_size;
}
return lseek(fd, pos, whence);
}
static int file_close(URLContext *h)
{
int fd = (intptr_t) h->priv_data;
return close(fd);
}
```
================================================
FILE: FFmpeg 结构体学习(三): AVPacket 分析.md
================================================
AVPacket是存储压缩编码数据相关信息的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。
# 一、源码整理
首先我们先看一下结构体AVPacket的定义的结构体源码(位于libavcodec/avcodec.h):
```
typedef struct AVPacket {
/**
* Presentation timestamp in AVStream->time_base units; the time at which
* the decompressed packet will be presented to the user.
* Can be AV_NOPTS_VALUE if it is not stored in the file.
* pts MUST be larger or equal to dts as presentation cannot happen before
* decompression, unless one wants to view hex dumps. Some formats misuse
* the terms dts and pts/cts to mean something different. Such timestamps
* must be converted to true pts/dts before they are stored in AVPacket.
*/
int64_t pts;
/**
* Decompression timestamp in AVStream->time_base units; the time at which
* the packet is decompressed.
* Can be AV_NOPTS_VALUE if it is not stored in the file.
*/
int64_t dts;
uint8_t *data;
int size;
int stream_index;
/**
* A combination of AV_PKT_FLAG values
*/
int flags;
/**
* Additional packet data that can be provided by the container.
* Packet can contain several types of side information.
*/
struct {
uint8_t *data;
int size;
enum AVPacketSideDataType type;
} *side_data;
int side_data_elems;
/**
* Duration of this packet in AVStream->time_base units, 0 if unknown.
* Equals next_pts - this_pts in presentation order.
*/
int duration;
void (*destruct)(struct AVPacket *);
void *priv;
int64_t pos; ///< byte position in stream, -1 if unknown
/**
* Time difference in AVStream->time_base units from the pts of this
* packet to the point at which the output from the decoder has converged
* independent from the availability of previous frames. That is, the
* frames are virtually identical no matter if decoding started from
* the very first frame or from this keyframe.
* Is AV_NOPTS_VALUE if unknown.
* This field is not the display duration of the current packet.
* This field has no meaning if the packet does not have AV_PKT_FLAG_KEY
* set.
*
* The purpose of this field is to allow seeking in streams that have no
* keyframes in the conventional sense. It corresponds to the
* recovery point SEI in H.264 and match_time_delta in NUT. It is also
* essential for some types of subtitle streams to ensure that all
* subtitles are correctly displayed after seeking.
*/
int64_t convergence_duration;
} AVPacket;
```
# 二、AVPacket 重点字段
```
uint8_t *data:压缩编码的数据。
int size:data的大小
int64_t pts:显示时间戳
int64_t dts:解码时间戳
int stream_index:标识该AVPacket所属的视频/音频流。
```
针对data做一下说明:对于H.264格式来说,在使用FFMPEG进行视音频处理的时候,我们常常可以将得到的AVPacket的data数据直接写成文件,从而得到视音频的码流文件。
================================================
FILE: FFmpeg 结构体学习(二): AVStream 分析.md
================================================
AVStream是存储每一个视频/音频流信息的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。
# 一、源码整理
首先我们先看一下结构体AVStream的定义的结构体源码(位于libavformat/avformat.h):
```
/**
* Stream structure.
* New fields can be added to the end with minor version bumps.
* Removal, reordering and changes to existing fields require a major
* version bump.
* sizeof(AVStream) must not be used outside libav*.
*/
typedef struct AVStream {
int index; /**< stream index in AVFormatContext */
/**
* Format-specific stream ID.
* decoding: set by libavformat
* encoding: set by the user
*/
int id;
AVCodecContext *codec; /**< codec context */
/**
* Real base framerate of the stream.
* This is the lowest framerate with which all timestamps can be
* represented accurately (it is the least common multiple of all
* framerates in the stream). Note, this value is just a guess!
* For example, if the time base is 1/90000 and all frames have either
* approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1.
*/
AVRational r_frame_rate;
void *priv_data;
/**
* encoding: pts generation when outputting stream
*/
struct AVFrac pts;
/**
* This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented. For fixed-fps content,
* time base should be 1/framerate and timestamp increments should be 1.
* decoding: set by libavformat
* encoding: set by libavformat in av_write_header
*/
AVRational time_base;
/**
* Decoding: pts of the first frame of the stream in presentation order, in stream time base.
* Only set this if you are absolutely 100% sure that the value you set
* it to really is the pts of the first frame.
* This may be undefined (AV_NOPTS_VALUE).
* @note The ASF header does NOT contain a correct start_time the ASF
* demuxer must NOT set this.
*/
int64_t start_time;
/**
* Decoding: duration of the stream, in stream time base.
* If a source file does not specify a duration, but does specify
* a bitrate, this value will be estimated from bitrate and file size.
*/
int64_t duration;
int64_t nb_frames; ///< number of frames in this stream if known or 0
int disposition; /**< AV_DISPOSITION_* bit field */
enum AVDiscard discard; ///< Selects which packets can be discarded at will and do not need to be demuxed.
/**
* sample aspect ratio (0 if unknown)
* - encoding: Set by user.
* - decoding: Set by libavformat.
*/
AVRational sample_aspect_ratio;
AVDictionary *metadata;
/**
* Average framerate
*/
AVRational avg_frame_rate;
/**
* For streams with AV_DISPOSITION_ATTACHED_PIC disposition, this packet
* will contain the attached picture.
*
* decoding: set by libavformat, must not be modified by the caller.
* encoding: unused
*/
AVPacket attached_pic;
/*****************************************************************
* All fields below this line are not part of the public API. They
* may not be used outside of libavformat and can be changed and
* removed at will.
* New public fields should be added right above.
*****************************************************************
*/
/**
* Stream information used internally by av_find_stream_info()
*/
#define MAX_STD_TIMEBASES (60*12+5)
struct {
int64_t last_dts;
int64_t duration_gcd;
int duration_count;
double duration_error[2][2][MAX_STD_TIMEBASES];
int64_t codec_info_duration;
int nb_decoded_frames;
int found_decoder;
} *info;
int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */
// Timestamp generation support:
/**
* Timestamp corresponding to the last dts sync point.
*
* Initialized when AVCodecParserContext.dts_sync_point >= 0 and
* a DTS is received from the underlying container. Otherwise set to
* AV_NOPTS_VALUE by default.
*/
int64_t reference_dts;
int64_t first_dts;
int64_t cur_dts;
int64_t last_IP_pts;
int last_IP_duration;
/**
* Number of packets to buffer for codec probing
*/
#define MAX_PROBE_PACKETS 2500
int probe_packets;
/**
* Number of frames that have been demuxed during av_find_stream_info()
*/
int codec_info_nb_frames;
/**
* Stream Identifier
* This is the MPEG-TS stream identifier +1
* 0 means unknown
*/
int stream_identifier;
int64_t interleaver_chunk_size;
int64_t interleaver_chunk_duration;
/* av_read_frame() support */
enum AVStreamParseType need_parsing;
struct AVCodecParserContext *parser;
/**
* last packet in packet_buffer for this stream when muxing.
*/
struct AVPacketList *last_in_packet_buffer;
AVProbeData probe_data;
#define MAX_REORDER_DELAY 16
int64_t pts_buffer[MAX_REORDER_DELAY+1];
AVIndexEntry *index_entries; /**< Only used if the format does not
support seeking natively. */
int nb_index_entries;
unsigned int index_entries_allocated_size;
/**
* flag to indicate that probing is requested
* NOT PART OF PUBLIC API
*/
int request_probe;
} AVStream;
```
# 二、AVStream 重点字段
```
int index:标识该视频/音频流
AVCodecContext *codec:指向该视频/音频流的AVCodecContext(它们是一一对应的关系)
AVRational time_base:时基。通过该值可以把PTS,DTS转化为真正的时间。FFMPEG其他结构体中也有这个字段,但是根据我的经验,只有AVStream中的time_base是可用的。PTS*time_base=真正的时间
int64_t duration:该视频/音频流长度
AVDictionary *metadata:元数据信息
AVRational avg_frame_rate:帧率(注:对视频来说,这个挺重要的)
AVPacket attached_pic:附带的图片。比如说一些MP3,AAC音频文件附带的专辑封面。
```
================================================
FILE: FFmpeg 结构体学习(五): AVCodec 分析.md
================================================
AVCodec是存储编解码器信息的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。
# 一、源码整理
首先我们先看一下结构体AVCodec的定义的结构体源码(位于libavcodec/avcodec.h):
```
/* 雷霄骅
* 中国传媒大学/数字电视技术
* leixiaohua1020@126.com
*
*/
/**
* AVCodec.
*/
typedef struct AVCodec {
/**
* Name of the codec implementation.
* The name is globally unique among encoders and among decoders (but an
* encoder and a decoder can share the same name).
* This is the primary way to find a codec from the user perspective.
*/
const char *name;
/**
* Descriptive name for the codec, meant to be more human readable than name.
* You should use the NULL_IF_CONFIG_SMALL() macro to define it.
*/
const char *long_name;
enum AVMediaType type;
enum CodecID id;
/**
* Codec capabilities.
* see CODEC_CAP_*
*/
int capabilities;
const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0}
const enum PixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1
const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0
const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
const uint64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0
uint8_t max_lowres; ///< maximum value for lowres supported by the decoder
const AVClass *priv_class; ///< AVClass for the private context
const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN}
/*****************************************************************
* No fields below this line are part of the public API. They
* may not be used outside of libavcodec and can be changed and
* removed at will.
* New public fields should be added right above.
*****************************************************************
*/
int priv_data_size;
struct AVCodec *next;
/**
* @name Frame-level threading support functions
* @{
*/
/**
* If defined, called on thread contexts when they are created.
* If the codec allocates writable tables in init(), re-allocate them here.
* priv_data will be set to a copy of the original.
*/
int (*init_thread_copy)(AVCodecContext *);
/**
* Copy necessary context variables from a previous thread context to the current one.
* If not defined, the next thread will start automatically; otherwise, the codec
* must call ff_thread_finish_setup().
*
* dst and src will (rarely) point to the same context, in which case memcpy should be skipped.
*/
int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src);
/** @} */
/**
* Private codec-specific defaults.
*/
const AVCodecDefault *defaults;
/**
* Initialize codec static data, called from avcodec_register().
*/
void (*init_static_data)(struct AVCodec *codec);
int (*init)(AVCodecContext *);
int (*encode)(AVCodecContext *, uint8_t *buf, int buf_size, void *data);
/**
* Encode data to an AVPacket.
*
* @param avctx codec context
* @param avpkt output AVPacket (may contain a user-provided buffer)
* @param[in] frame AVFrame containing the raw data to be encoded
* @param[out] got_packet_ptr encoder sets to 0 or 1 to indicate that a
* non-empty packet was returned in avpkt.
* @return 0 on success, negative error code on failure
*/
int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame,
int *got_packet_ptr);
int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt);
int (*close)(AVCodecContext *);
/**
* Flush buffers.
* Will be called when seeking
*/
void (*flush)(AVCodecContext *);
} AVCodec;
```
# 二、AVCodec 重点字段
下面说一下最主要的几个变量:
```
const char *name:编解码器的名字,比较短
const char *long_name:编解码器的名字,全称,比较长
enum AVMediaType type:指明了类型,是视频,音频,还是字幕
enum AVCodecID id:ID,不重复
const AVRational *supported_framerates:支持的帧率(仅视频)
const enum AVPixelFormat *pix_fmts:支持的像素格式(仅视频)
const int *supported_samplerates:支持的采样率(仅音频)
const enum AVSampleFormat *sample_fmts:支持的采样格式(仅音频)
const uint64_t *channel_layouts:支持的声道数(仅音频)
int priv_data_size:私有数据的大小
```
详细介绍几个变量:
### 1.enum AVMediaType type
AVMediaType定义如下:
```
enum AVMediaType {
AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA
AVMEDIA_TYPE_VIDEO,
AVMEDIA_TYPE_AUDIO,
AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous
AVMEDIA_TYPE_SUBTITLE,
AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse
AVMEDIA_TYPE_NB
};
```
### 2.enum AVCodecID id
AVCodecID定义如下:
```
enum AVCodecID {
AV_CODEC_ID_NONE,
/* video codecs */
AV_CODEC_ID_MPEG1VIDEO,
AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
AV_CODEC_ID_MPEG2VIDEO_XVMC,
AV_CODEC_ID_H261,
AV_CODEC_ID_H263,
AV_CODEC_ID_RV10,
AV_CODEC_ID_RV20,
AV_CODEC_ID_MJPEG,
AV_CODEC_ID_MJPEGB,
AV_CODEC_ID_LJPEG,
AV_CODEC_ID_SP5X,
AV_CODEC_ID_JPEGLS,
AV_CODEC_ID_MPEG4,
AV_CODEC_ID_RAWVIDEO,
AV_CODEC_ID_MSMPEG4V1,
AV_CODEC_ID_MSMPEG4V2,
AV_CODEC_ID_MSMPEG4V3,
AV_CODEC_ID_WMV1,
AV_CODEC_ID_WMV2,
AV_CODEC_ID_H263P,
AV_CODEC_ID_H263I,
AV_CODEC_ID_FLV1,
AV_CODEC_ID_SVQ1,
AV_CODEC_ID_SVQ3,
AV_CODEC_ID_DVVIDEO,
AV_CODEC_ID_HUFFYUV,
AV_CODEC_ID_CYUV,
AV_CODEC_ID_H264,
...
}
```
### 3.const enum AVPixelFormat *pix_fmts
AVPixelFormat定义如下:
```
enum AVPixelFormat {
AV_PIX_FMT_NONE = -1,
AV_PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
AV_PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
AV_PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB...
AV_PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR...
AV_PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
AV_PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
AV_PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
AV_PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
AV_PIX_FMT_GRAY8, ///< Y , 8bpp
AV_PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb
AV_PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb
AV_PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette
AV_PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV420P and setting color_range
AV_PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV422P and setting color_range
AV_PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV444P and setting color_range
AV_PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing
AV_PIX_FMT_XVMC_MPEG2_IDCT,
...(代码太长,略)
}
```
### 4.const enum AVSampleFormat *sample_fmts
```
enum AVSampleFormat {
AV_SAMPLE_FMT_NONE = -1,
AV_SAMPLE_FMT_U8, ///< unsigned 8 bits
AV_SAMPLE_FMT_S16, ///< signed 16 bits
AV_SAMPLE_FMT_S32, ///< signed 32 bits
AV_SAMPLE_FMT_FLT, ///< float
AV_SAMPLE_FMT_DBL, ///< double
AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
AV_SAMPLE_FMT_FLTP, ///< float, planar
AV_SAMPLE_FMT_DBLP, ///< double, planar
AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
};
```
每一个编解码器对应一个该结构体,查看一下ffmpeg的源代码,我们可以看一下H.264解码器的结构体如下所示(h264.c):
```
AVCodec ff_h264_decoder = {
.name = "h264",
.type = AVMEDIA_TYPE_VIDEO,
.id = CODEC_ID_H264,
.priv_data_size = sizeof(H264Context),
.init = ff_h264_decode_init,
.close = ff_h264_decode_end,
.decode = decode_frame,
.capabilities = /*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 | CODEC_CAP_DELAY |
CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS,
.flush= flush_dpb,
.long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
.init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
.update_thread_context = ONLY_IF_THREADS_ENABLED(decode_update_thread_context),
.profiles = NULL_IF_CONFIG_SMALL(profiles),
.priv_class = &h264_class,
};
```
JPEG2000解码器结构体(j2kdec.c):
```
AVCodec ff_jpeg2000_decoder = {
.name = "j2k",
.type = AVMEDIA_TYPE_VIDEO,
.id = CODEC_ID_JPEG2000,
.priv_data_size = sizeof(J2kDecoderContext),
.init = j2kdec_init,
.close = decode_end,
.decode = decode_frame,
.capabilities = CODEC_CAP_EXPERIMENTAL,
.long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"),
.pix_fmts =
(const enum PixelFormat[]) {PIX_FMT_GRAY8, PIX_FMT_RGB24, PIX_FMT_NONE}
};
```
下面简单介绍一下遍历ffmpeg中的解码器信息的方法(这些解码器以一个链表的形式存储):
1.注册所有编解码器:av_register_all();
2.声明一个AVCodec类型的指针,比如说AVCodec* first_c;
3.调用av_codec_next()函数,即可获得指向链表下一个解码器的指针,循环往复可以获得所有解码器的信息。注意,如果想要获得指向第一个解码器的指针,则需要将该函数的参数设置为NULL。
================================================
FILE: FFmpeg 结构体学习(八):FFMPEG中重要结构体之间的关系.md
================================================
FFMPEG中结构体很多。最关键的结构体可以分成以下几类:
### 解协议(http,rtsp,rtmp,mms)
AVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。
### 解封装(flv,avi,rmvb,mp4)
AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。
### 解码(h264,mpeg2,aac,mp3)
每个AVStream存储一个视频/音频流的相关数据;每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。
### 存数据
视频的话,每个结构一般是存一帧;音频可能有好几帧
解码前数据:AVPacket
解码后数据:AVFrame
他们之间的对应关系如下所示:

================================================
FILE: FFmpeg 结构体学习(六): AVCodecContext 分析.md
================================================
AVCodecContext是包含变量较多的结构体(感觉差不多是变量最多的结构体)。下面我们来分析一下该结构体里重要变量的含义和作用。
# 一、源码整理
首先我们先看一下结构体AVCodecContext的定义的结构体源码(位于libavcodec/avcodec.h):
```
/**
* main external API structure.
* New fields can be added to the end with minor version bumps.
* Removal, reordering and changes to existing fields require a major
* version bump.
* Please use AVOptions (av_opt* / av_set/get*()) to access these fields from user
* applications.
* sizeof(AVCodecContext) must not be used outside libav*.
*/
typedef struct AVCodecContext {
/**
* information on struct for av_log
* - set by avcodec_alloc_context3
*/
const AVClass *av_class;
int log_level_offset;
enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */
const struct AVCodec *codec;
char codec_name[32];
enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */
/**
* fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A').
* This is used to work around some encoder bugs.
* A demuxer should set this to what is stored in the field used to identify the codec.
* If there are multiple such fields in a container then the demuxer should choose the one
* which maximizes the information about the used codec.
* If the codec tag field in a container is larger than 32 bits then the demuxer should
* remap the longer ID to 32 bits with a table or other structure. Alternatively a new
* extra_codec_tag + size could be added but for this a clear advantage must be demonstrated
* first.
* - encoding: Set by user, if not then the default based on codec_id will be used.
* - decoding: Set by user, will be converted to uppercase by libavcodec during init.
*/
unsigned int codec_tag;
/**
* fourcc from the AVI stream header (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A').
* This is used to work around some encoder bugs.
* - encoding: unused
* - decoding: Set by user, will be converted to uppercase by libavcodec during init.
*/
unsigned int stream_codec_tag;
#if FF_API_SUB_ID
/**
* @deprecated this field is unused
*/
attribute_deprecated int sub_id;
#endif
void *priv_data;
/**
* Private context used for internal data.
*
* Unlike priv_data, this is not codec-specific. It is used in general
* libavcodec functions.
*/
struct AVCodecInternal *internal;
/**
* Private data of the user, can be used to carry app specific stuff.
* - encoding: Set by user.
* - decoding: Set by user.
*/
void *opaque;
/**
* the average bitrate
* - encoding: Set by user; unused for constant quantizer encoding.
* - decoding: Set by libavcodec. 0 or some bitrate if this info is available in the stream.
*/
int bit_rate;
/**
* number of bits the bitstream is allowed to diverge from the reference.
* the reference can be CBR (for CBR pass1) or VBR (for pass2)
* - encoding: Set by user; unused for constant quantizer encoding.
* - decoding: unused
*/
int bit_rate_tolerance;
/**
* Global quality for codecs which cannot change it per frame.
* This should be proportional to MPEG-1/2/4 qscale.
* - encoding: Set by user.
* - decoding: unused
*/
int global_quality;
/**
* - encoding: Set by user.
* - decoding: unused
*/
int compression_level;
#define FF_COMPRESSION_DEFAULT -1
/**
* CODEC_FLAG_*.
* - encoding: Set by user.
* - decoding: Set by user.
*/
int flags;
/**
* CODEC_FLAG2_*
* - encoding: Set by user.
* - decoding: Set by user.
*/
int flags2;
/**
* some codecs need / can use extradata like Huffman tables.
* mjpeg: Huffman tables
* rv10: additional flags
* mpeg4: global headers (they can be in the bitstream or here)
* The allocated memory should be FF_INPUT_BUFFER_PADDING_SIZE bytes larger
* than extradata_size to avoid prolems if it is read with the bitstream reader.
* The bytewise contents of extradata must not depend on the architecture or CPU endianness.
* - encoding: Set/allocated/freed by libavcodec.
* - decoding: Set/allocated/freed by user.
*/
uint8_t *extradata;
int extradata_size;
/**
* This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented. For fixed-fps content,
* timebase should be 1/framerate and timestamp increments should be
* identically 1.
* - encoding: MUST be set by user.
* - decoding: Set by libavcodec.
*/
AVRational time_base;
/**
* For some codecs, the time base is closer to the field rate than the frame rate.
* Most notably, H.264 and MPEG-2 specify time_base as half of frame duration
* if no telecine is used ...
*
* Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2.
*/
int ticks_per_frame;
/**
* Encoding: Number of frames delay there will be from the encoder input to
* the decoder output. (we assume the decoder matches the spec)
* Decoding: Number of frames delay in addition to what a standard decoder
* as specified in the spec would produce.
*
* Video:
* Number of frames the decoded output will be delayed relative to the
* encoded input.
*
* Audio:
* For encoding, this is the number of "priming" samples added to the
* beginning of the stream. The decoded output will be delayed by this
* many samples relative to the input to the encoder. Note that this
* field is purely informational and does not directly affect the pts
* output by the encoder, which should always be based on the actual
* presentation time, including any delay.
* For decoding, this is the number of samples the decoder needs to
* output before the decoder's output is valid. When seeking, you should
* start decoding this many samples prior to your desired seek point.
*
* - encoding: Set by libavcodec.
* - decoding: Set by libavcodec.
*/
int delay;
/* video only */
/**
* picture width / height.
* - encoding: MUST be set by user.
* - decoding: Set by libavcodec.
* Note: For compatibility it is possible to set this instead of
* coded_width/height before decoding.
*/
int width, height;
/**
* Bitstream width / height, may be different from width/height if lowres enabled.
* - encoding: unused
* - decoding: Set by user before init if known. Codec should override / dynamically change if needed.
*/
int coded_width, coded_height;
#define FF_ASPECT_EXTENDED 15
/**
* the number of pictures in a group of pictures, or 0 for intra_only
* - encoding: Set by user.
* - decoding: unused
*/
int gop_size;
/**
* Pixel format, see AV_PIX_FMT_xxx.
* May be set by the demuxer if known from headers.
* May be overridden by the decoder if it knows better.
* - encoding: Set by user.
* - decoding: Set by user if known, overridden by libavcodec if known
*/
enum AVPixelFormat pix_fmt;
/**
* Motion estimation algorithm used for video coding.
* 1 (zero), 2 (full), 3 (log), 4 (phods), 5 (epzs), 6 (x1), 7 (hex),
* 8 (umh), 9 (iter), 10 (tesa) [7, 8, 10 are x264 specific, 9 is snow specific]
* - encoding: MUST be set by user.
* - decoding: unused
*/
int me_method;
/**
* If non NULL, 'draw_horiz_band' is called by the libavcodec
* decoder to draw a horizontal band. It improves cache usage. Not
* all codecs can do that. You must check the codec capabilities
* beforehand.
* When multithreading is used, it may be called from multiple threads
* at the same time; threads might draw different parts of the same AVFrame,
* or multiple AVFrames, and there is no guarantee that slices will be drawn
* in order.
* The function is also used by hardware acceleration APIs.
* It is called at least once during frame decoding to pass
* the data needed for hardware render.
* In that mode instead of pixel data, AVFrame points to
* a structure specific to the acceleration API. The application
* reads the structure and can change some fields to indicate progress
* or mark state.
* - encoding: unused
* - decoding: Set by user.
* @param height the height of the slice
* @param y the y position of the slice
* @param type 1->top field, 2->bottom field, 3->frame
* @param offset offset into the AVFrame.data from which the slice should be read
*/
void (*draw_horiz_band)(struct AVCodecContext *s,
const AVFrame *src, int offset[AV_NUM_DATA_POINTERS],
int y, int type, int height);
/**
* callback to negotiate the pixelFormat
* @param fmt is the list of formats which are supported by the codec,
* it is terminated by -1 as 0 is a valid format, the formats are ordered by quality.
* The first is always the native one.
* @return the chosen format
* - encoding: unused
* - decoding: Set by user, if not set the native format will be chosen.
*/
enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt);
/**
* maximum number of B-frames between non-B-frames
* Note: The output will be delayed by max_b_frames+1 relative to the input.
* - encoding: Set by user.
* - decoding: unused
*/
int max_b_frames;
/**
* qscale factor between IP and B-frames
* If > 0 then the last P-frame quantizer will be used (q= lastp_q*factor+offset).
* If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset).
* - encoding: Set by user.
* - decoding: unused
*/
float b_quant_factor;
/** obsolete FIXME remove */
int rc_strategy;
#define FF_RC_STRATEGY_XVID 1
int b_frame_strategy;
#if FF_API_MPV_GLOBAL_OPTS
/**
* luma single coefficient elimination threshold
* - encoding: Set by user.
* - decoding: unused
*/
attribute_deprecated int luma_elim_threshold;
/**
* chroma single coeff elimination threshold
* - encoding: Set by user.
* - decoding: unused
*/
attribute_deprecated int chroma_elim_threshold;
#endif
/**
* qscale offset between IP and B-frames
* - encoding: Set by user.
* - decoding: unused
*/
float b_quant_offset;
/**
* Size of the frame reordering buffer in the decoder.
* For MPEG-2 it is 1 IPB or 0 low delay IP.
* - encoding: Set by libavcodec.
* - decoding: Set by libavcodec.
*/
int has_b_frames;
/**
* 0-> h263 quant 1-> mpeg quant
* - encoding: Set by user.
* - decoding: unused
*/
int mpeg_quant;
/**
* qscale factor between P and I-frames
* If > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset).
* If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset).
* - encoding: Set by user.
* - decoding: unused
*/
float i_quant_factor;
/**
* qscale offset between P and I-frames
* - encoding: Set by user.
* - decoding: unused
*/
float i_quant_offset;
/**
* luminance masking (0-> disabled)
* - encoding: Set by user.
* - decoding: unused
*/
float lumi_masking;
/**
* temporary complexity masking (0-> disabled)
* - encoding: Set by user.
* - decoding: unused
*/
float temporal_cplx_masking;
/**
* spatial complexity masking (0-> disabled)
* - encoding: Set by user.
* - decoding: unused
*/
float spatial_cplx_masking;
/**
* p block masking (0-> disabled)
* - encoding: Set by user.
* - decoding: unused
*/
float p_masking;
/**
* darkness masking (0-> disabled)
* - encoding: Set by user.
* - decoding: unused
*/
float dark_masking;
/**
* slice count
* - encoding: Set by libavcodec.
* - decoding: Set by user (or 0).
*/
int slice_count;
/**
* prediction method (needed for huffyuv)
* - encoding: Set by user.
* - decoding: unused
*/
int prediction_method;
#define FF_PRED_LEFT 0
#define FF_PRED_PLANE 1
#define FF_PRED_MEDIAN 2
/**
* slice offsets in the frame in bytes
* - encoding: Set/allocated by libavcodec.
* - decoding: Set/allocated by user (or NULL).
*/
int *slice_offset;
/**
* sample aspect ratio (0 if unknown)
* That is the width of a pixel divided by the height of the pixel.
* Numerator and denominator must be relatively prime and smaller than 256 for some video standards.
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
AVRational sample_aspect_ratio;
/**
* motion estimation comparison function
* - encoding: Set by user.
* - decoding: unused
*/
int me_cmp;
/**
* subpixel motion estimation comparison function
* - encoding: Set by user.
* - decoding: unused
*/
int me_sub_cmp;
/**
* macroblock comparison function (not supported yet)
* - encoding: Set by user.
* - decoding: unused
*/
int mb_cmp;
/**
* interlaced DCT comparison function
* - encoding: Set by user.
* - decoding: unused
*/
int ildct_cmp;
#define FF_CMP_SAD 0
#define FF_CMP_SSE 1
#define FF_CMP_SATD 2
#define FF_CMP_DCT 3
#define FF_CMP_PSNR 4
#define FF_CMP_BIT 5
#define FF_CMP_RD 6
#define FF_CMP_ZERO 7
#define FF_CMP_VSAD 8
#define FF_CMP_VSSE 9
#define FF_CMP_NSSE 10
#define FF_CMP_W53 11
#define FF_CMP_W97 12
#define FF_CMP_DCTMAX 13
#define FF_CMP_DCT264 14
#define FF_CMP_CHROMA 256
/**
* ME diamond size & shape
* - encoding: Set by user.
* - decoding: unused
*/
int dia_size;
/**
* amount of previous MV predictors (2a+1 x 2a+1 square)
* - encoding: Set by user.
* - decoding: unused
*/
int last_predictor_count;
/**
* prepass for motion estimation
* - encoding: Set by user.
* - decoding: unused
*/
int pre_me;
/**
* motion estimation prepass comparison function
* - encoding: Set by user.
* - decoding: unused
*/
int me_pre_cmp;
/**
* ME prepass diamond size & shape
* - encoding: Set by user.
* - decoding: unused
*/
int pre_dia_size;
/**
* subpel ME quality
* - encoding: Set by user.
* - decoding: unused
*/
int me_subpel_quality;
/**
* DTG active format information (additional aspect ratio
* information only used in DVB MPEG-2 transport streams)
* 0 if not set.
*
* - encoding: unused
* - decoding: Set by decoder.
*/
int dtg_active_format;
#define FF_DTG_AFD_SAME 8
#define FF_DTG_AFD_4_3 9
#define FF_DTG_AFD_16_9 10
#define FF_DTG_AFD_14_9 11
#define FF_DTG_AFD_4_3_SP_14_9 13
#define FF_DTG_AFD_16_9_SP_14_9 14
#define FF_DTG_AFD_SP_4_3 15
/**
* maximum motion estimation search range in subpel units
* If 0 then no limit.
*
* - encoding: Set by user.
* - decoding: unused
*/
int me_range;
/**
* intra quantizer bias
* - encoding: Set by user.
* - decoding: unused
*/
int intra_quant_bias;
#define FF_DEFAULT_QUANT_BIAS 999999
/**
* inter quantizer bias
* - encoding: Set by user.
* - decoding: unused
*/
int inter_quant_bias;
#if FF_API_COLOR_TABLE_ID
/**
* color table ID
* - encoding: unused
* - decoding: Which clrtable should be used for 8bit RGB images.
* Tables have to be stored somewhere. FIXME
*/
attribute_deprecated int color_table_id;
#endif
/**
* slice flags
* - encoding: unused
* - decoding: Set by user.
*/
int slice_flags;
#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display
#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG2 field pics)
#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1)
/**
* XVideo Motion Acceleration
* - encoding: forbidden
* - decoding: set by decoder
*/
int xvmc_acceleration;
/**
* macroblock decision mode
* - encoding: Set by user.
* - decoding: unused
*/
int mb_decision;
#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp
#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits
#define FF_MB_DECISION_RD 2 ///< rate distortion
/**
* custom intra quantization matrix
* - encoding: Set by user, can be NULL.
* - decoding: Set by libavcodec.
*/
uint16_t *intra_matrix;
/**
* custom inter quantization matrix
* - encoding: Set by user, can be NULL.
* - decoding: Set by libavcodec.
*/
uint16_t *inter_matrix;
/**
* scene change detection threshold
* 0 is default, larger means fewer detected scene changes.
* - encoding: Set by user.
* - decoding: unused
*/
int scenechange_threshold;
/**
* noise reduction strength
* - encoding: Set by user.
* - decoding: unused
*/
int noise_reduction;
#if FF_API_INTER_THRESHOLD
/**
* @deprecated this field is unused
*/
attribute_deprecated int inter_threshold;
#endif
#if FF_API_MPV_GLOBAL_OPTS
/**
* @deprecated use mpegvideo private options instead
*/
attribute_deprecated int quantizer_noise_shaping;
#endif
/**
* Motion estimation threshold below which no motion estimation is
* performed, but instead the user specified motion vectors are used.
*
* - encoding: Set by user.
* - decoding: unused
*/
int me_threshold;
/**
* Macroblock threshold below which the user specified macroblock types will be used.
* - encoding: Set by user.
* - decoding: unused
*/
int mb_threshold;
/**
* precision of the intra DC coefficient - 8
* - encoding: Set by user.
* - decoding: unused
*/
int intra_dc_precision;
/**
* Number of macroblock rows at the top which are skipped.
* - encoding: unused
* - decoding: Set by user.
*/
int skip_top;
/**
* Number of macroblock rows at the bottom which are skipped.
* - encoding: unused
* - decoding: Set by user.
*/
int skip_bottom;
/**
* Border processing masking, raises the quantizer for mbs on the borders
* of the picture.
* - encoding: Set by user.
* - decoding: unused
*/
float border_masking;
/**
* minimum MB lagrange multipler
* - encoding: Set by user.
* - decoding: unused
*/
int mb_lmin;
/**
* maximum MB lagrange multipler
* - encoding: Set by user.
* - decoding: unused
*/
int mb_lmax;
/**
*
* - encoding: Set by user.
* - decoding: unused
*/
int me_penalty_compensation;
/**
*
* - encoding: Set by user.
* - decoding: unused
*/
int bidir_refine;
/**
*
* - encoding: Set by user.
* - decoding: unused
*/
int brd_scale;
/**
* minimum GOP size
* - encoding: Set by user.
* - decoding: unused
*/
int keyint_min;
/**
* number of reference frames
* - encoding: Set by user.
* - decoding: Set by lavc.
*/
int refs;
/**
* chroma qp offset from luma
* - encoding: Set by user.
* - decoding: unused
*/
int chromaoffset;
/**
* Multiplied by qscale for each frame and added to scene_change_score.
* - encoding: Set by user.
* - decoding: unused
*/
int scenechange_factor;
/**
*
* Note: Value depends upon the compare function used for fullpel ME.
* - encoding: Set by user.
* - decoding: unused
*/
int mv0_threshold;
/**
* Adjust sensitivity of b_frame_strategy 1.
* - encoding: Set by user.
* - decoding: unused
*/
int b_sensitivity;
/**
* Chromaticity coordinates of the source primaries.
* - encoding: Set by user
* - decoding: Set by libavcodec
*/
enum AVColorPrimaries color_primaries;
/**
* Color Transfer Characteristic.
* - encoding: Set by user
* - decoding: Set by libavcodec
*/
enum AVColorTransferCharacteristic color_trc;
/**
* YUV colorspace type.
* - encoding: Set by user
* - decoding: Set by libavcodec
*/
enum AVColorSpace colorspace;
/**
* MPEG vs JPEG YUV range.
* - encoding: Set by user
* - decoding: Set by libavcodec
*/
enum AVColorRange color_range;
/**
* This defines the location of chroma samples.
* - encoding: Set by user
* - decoding: Set by libavcodec
*/
enum AVChromaLocation chroma_sample_location;
/**
* Number of slices.
* Indicates number of picture subdivisions. Used for parallelized
* decoding.
* - encoding: Set by user
* - decoding: unused
*/
int slices;
/** Field order
* - encoding: set by libavcodec
* - decoding: Set by user.
*/
enum AVFieldOrder field_order;
/* audio only */
int sample_rate; ///< samples per second
int channels; ///< number of audio channels
/**
* audio sample format
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
enum AVSampleFormat sample_fmt; ///< sample format
/* The following data should not be initialized. */
/**
* Samples per packet, initialized when calling 'init'.
*/
int frame_size;
/**
* Frame counter, set by libavcodec.
*
* - decoding: total number of frames returned from the decoder so far.
* - encoding: total number of frames passed to the encoder so far.
*
* @note the counter is not incremented if encoding/decoding resulted in
* an error.
*/
int frame_number;
/**
* number of bytes per packet if constant and known or 0
* Used by some WAV based audio codecs.
*/
int block_align;
/**
* Audio cutoff bandwidth (0 means "automatic")
* - encoding: Set by user.
* - decoding: unused
*/
int cutoff;
#if FF_API_REQUEST_CHANNELS
/**
* Decoder should decode to this many channels if it can (0 for default)
* - encoding: unused
* - decoding: Set by user.
* @deprecated Deprecated in favor of request_channel_layout.
*/
int request_channels;
#endif
/**
* Audio channel layout.
* - encoding: set by user.
* - decoding: set by user, may be overwritten by libavcodec.
*/
uint64_t channel_layout;
/**
* Request decoder to use this channel layout if it can (0 for default)
* - encoding: unused
* - decoding: Set by user.
*/
uint64_t request_channel_layout;
/**
* Type of service that the audio stream conveys.
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
enum AVAudioServiceType audio_service_type;
/**
* desired sample format
* - encoding: Not used.
* - decoding: Set by user.
* Decoder will decode to this format if it can.
*/
enum AVSampleFormat request_sample_fmt;
/**
* Called at the beginning of each frame to get a buffer for it.
*
* The function will set AVFrame.data[], AVFrame.linesize[].
* AVFrame.extended_data[] must also be set, but it should be the same as
* AVFrame.data[] except for planar audio with more channels than can fit
* in AVFrame.data[]. In that case, AVFrame.data[] shall still contain as
* many data pointers as it can hold.
*
* if CODEC_CAP_DR1 is not set then get_buffer() must call
* avcodec_default_get_buffer() instead of providing buffers allocated by
* some other means.
*
* AVFrame.data[] should be 32- or 16-byte-aligned unless the CPU doesn't
* need it. avcodec_default_get_buffer() aligns the output buffer properly,
* but if get_buffer() is overridden then alignment considerations should
* be taken into account.
*
* @see avcodec_default_get_buffer()
*
* Video:
*
* If pic.reference is set then the frame will be read later by libavcodec.
* avcodec_align_dimensions2() should be used to find the required width and
* height, as they normally need to be rounded up to the next multiple of 16.
*
* If frame multithreading is used and thread_safe_callbacks is set,
* it may be called from a different thread, but not from more than one at
* once. Does not need to be reentrant.
*
* @see release_buffer(), reget_buffer()
* @see avcodec_align_dimensions2()
*
* Audio:
*
* Decoders request a buffer of a particular size by setting
* AVFrame.nb_samples prior to calling get_buffer(). The decoder may,
* however, utilize only part of the buffer by setting AVFrame.nb_samples
* to a smaller value in the output frame.
*
* Decoders cannot use the buffer after returning from
* avcodec_decode_audio4(), so they will not call release_buffer(), as it
* is assumed to be released immediately upon return.
*
* As a convenience, av_samples_get_buffer_size() and
* av_samples_fill_arrays() in libavutil may be used by custom get_buffer()
* functions to find the required data size and to fill data pointers and
* linesize. In AVFrame.linesize, only linesize[0] may be set for audio
* since all planes must be the same size.
*
* @see av_samples_get_buffer_size(), av_samples_fill_arrays()
*
* - encoding: unused
* - decoding: Set by libavcodec, user can override.
*/
int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic);
/**
* Called to release buffers which were allocated with get_buffer.
* A released buffer can be reused in get_buffer().
* pic.data[*] must be set to NULL.
* May be called from a different thread if frame multithreading is used,
* but not by more than one thread at once, so does not need to be reentrant.
* - encoding: unused
* - decoding: Set by libavcodec, user can override.
*/
void (*release_buffer)(struct AVCodecContext *c, AVFrame *pic);
/**
* Called at the beginning of a frame to get cr buffer for it.
* Buffer type (size, hints) must be the same. libavcodec won't check it.
* libavcodec will pass previous buffer in pic, function should return
* same buffer or new buffer with old frame "painted" into it.
* If pic.data[0] == NULL must behave like get_buffer().
* if CODEC_CAP_DR1 is not set then reget_buffer() must call
* avcodec_default_reget_buffer() instead of providing buffers allocated by
* some other means.
* - encoding: unused
* - decoding: Set by libavcodec, user can override.
*/
int (*reget_buffer)(struct AVCodecContext *c, AVFrame *pic);
/* - encoding parameters */
float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0)
float qblur; ///< amount of qscale smoothing over time (0.0-1.0)
/**
* minimum quantizer
* - encoding: Set by user.
* - decoding: unused
*/
int qmin;
/**
* maximum quantizer
* - encoding: Set by user.
* - decoding: unused
*/
int qmax;
/**
* maximum quantizer difference between frames
* - encoding: Set by user.
* - decoding: unused
*/
int max_qdiff;
/**
* ratecontrol qmin qmax limiting method
* 0-> clipping, 1-> use a nice continuous function to limit qscale wthin qmin/qmax.
* - encoding: Set by user.
* - decoding: unused
*/
float rc_qsquish;
float rc_qmod_amp;
int rc_qmod_freq;
/**
* decoder bitstream buffer size
* - encoding: Set by user.
* - decoding: unused
*/
int rc_buffer_size;
/**
* ratecontrol override, see RcOverride
* - encoding: Allocated/set/freed by user.
* - decoding: unused
*/
int rc_override_count;
RcOverride *rc_override;
/**
* rate control equation
* - encoding: Set by user
* - decoding: unused
*/
const char *rc_eq;
/**
* maximum bitrate
* - encoding: Set by user.
* - decoding: unused
*/
int rc_max_rate;
/**
* minimum bitrate
* - encoding: Set by user.
* - decoding: unused
*/
int rc_min_rate;
float rc_buffer_aggressivity;
/**
* initial complexity for pass1 ratecontrol
* - encoding: Set by user.
* - decoding: unused
*/
float rc_initial_cplx;
/**
* Ratecontrol attempt to use, at maximum, <value> of what can be used without an underflow.
* - encoding: Set by user.
* - decoding: unused.
*/
float rc_max_available_vbv_use;
/**
* Ratecontrol attempt to use, at least, <value> times the amount needed to prevent a vbv overflow.
* - encoding: Set by user.
* - decoding: unused.
*/
float rc_min_vbv_overflow_use;
/**
* Number of bits which should be loaded into the rc buffer before decoding starts.
* - encoding: Set by user.
* - decoding: unused
*/
int rc_initial_buffer_occupancy;
#define FF_CODER_TYPE_VLC 0
#define FF_CODER_TYPE_AC 1
#define FF_CODER_TYPE_RAW 2
#define FF_CODER_TYPE_RLE 3
#define FF_CODER_TYPE_DEFLATE 4
/**
* coder type
* - encoding: Set by user.
* - decoding: unused
*/
int coder_type;
/**
* context model
* - encoding: Set by user.
* - decoding: unused
*/
int context_model;
/**
* minimum Lagrange multipler
* - encoding: Set by user.
* - decoding: unused
*/
int lmin;
/**
* maximum Lagrange multipler
* - encoding: Set by user.
* - decoding: unused
*/
int lmax;
/**
* frame skip threshold
* - encoding: Set by user.
* - decoding: unused
*/
int frame_skip_threshold;
/**
* frame skip factor
* - encoding: Set by user.
* - decoding: unused
*/
int frame_skip_factor;
/**
* frame skip exponent
* - encoding: Set by user.
* - decoding: unused
*/
int frame_skip_exp;
/**
* frame skip comparison function
* - encoding: Set by user.
* - decoding: unused
*/
int frame_skip_cmp;
/**
* trellis RD quantization
* - encoding: Set by user.
* - decoding: unused
*/
int trellis;
/**
* - encoding: Set by user.
* - decoding: unused
*/
int min_prediction_order;
/**
* - encoding: Set by user.
* - decoding: unused
*/
int max_prediction_order;
/**
* GOP timecode frame start number
* - encoding: Set by user, in non drop frame format
* - decoding: Set by libavcodec (timecode in the 25 bits format, -1 if unset)
*/
int64_t timecode_frame_start;
/* The RTP callback: This function is called */
/* every time the encoder has a packet to send. */
/* It depends on the encoder if the data starts */
/* with a Start Code (it should). H.263 does. */
/* mb_nb contains the number of macroblocks */
/* encoded in the RTP payload. */
void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb);
int rtp_payload_size; /* The size of the RTP payload: the coder will */
/* do its best to deliver a chunk with size */
/* below rtp_payload_size, the chunk will start */
/* with a start code on some codecs like H.263. */
/* This doesn't take account of any particular */
/* headers inside the transmitted RTP payload. */
/* statistics, used for 2-pass encoding */
int mv_bits;
int header_bits;
int i_tex_bits;
int p_tex_bits;
int i_count;
int p_count;
int skip_count;
int misc_bits;
/**
* number of bits used for the previously encoded frame
* - encoding: Set by libavcodec.
* - decoding: unused
*/
int frame_bits;
/**
* pass1 encoding statistics output buffer
* - encoding: Set by libavcodec.
* - decoding: unused
*/
char *stats_out;
/**
* pass2 encoding statistics input buffer
* Concatenated stuff from stats_out of pass1 should be placed here.
* - encoding: Allocated/set/freed by user.
* - decoding: unused
*/
char *stats_in;
/**
* Work around bugs in encoders which sometimes cannot be detected automatically.
* - encoding: Set by user
* - decoding: Set by user
*/
int workaround_bugs;
#define FF_BUG_AUTODETECT 1 ///< autodetection
#define FF_BUG_OLD_MSMPEG4 2
#define FF_BUG_XVID_ILACE 4
#define FF_BUG_UMP4 8
#define FF_BUG_NO_PADDING 16
#define FF_BUG_AMV 32
#define FF_BUG_AC_VLC 0 ///< Will be removed, libavcodec can now handle these non-compliant files by default.
#define FF_BUG_QPEL_CHROMA 64
#define FF_BUG_STD_QPEL 128
#define FF_BUG_QPEL_CHROMA2 256
#define FF_BUG_DIRECT_BLOCKSIZE 512
#define FF_BUG_EDGE 1024
#define FF_BUG_HPEL_CHROMA 2048
#define FF_BUG_DC_CLIP 4096
#define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders.
#define FF_BUG_TRUNCATED 16384
/**
* strictly follow the standard (MPEG4, ...).
* - encoding: Set by user.
* - decoding: Set by user.
* Setting this to STRICT or higher means the encoder and decoder will
* generally do stupid things, whereas setting it to unofficial or lower
* will mean the encoder might produce output that is not supported by all
* spec-compliant decoders. Decoders don't differentiate between normal,
* unofficial and experimental (that is, they always try to decode things
* when they can) unless they are explicitly asked to behave stupidly
* (=strictly conform to the specs)
*/
int strict_std_compliance;
#define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to an older more strict version of the spec or reference software.
#define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences.
#define FF_COMPLIANCE_NORMAL 0
#define FF_COMPLIANCE_UNOFFICIAL -1 ///< Allow unofficial extensions
#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things.
/**
* error concealment flags
* - encoding: unused
* - decoding: Set by user.
*/
int error_concealment;
#define FF_EC_GUESS_MVS 1
#define FF_EC_DEBLOCK 2
/**
* debug
* - encoding: Set by user.
* - decoding: Set by user.
*/
int debug;
#define FF_DEBUG_PICT_INFO 1
#define FF_DEBUG_RC 2
#define FF_DEBUG_BITSTREAM 4
#define FF_DEBUG_MB_TYPE 8
#define FF_DEBUG_QP 16
#define FF_DEBUG_MV 32
#define FF_DEBUG_DCT_COEFF 0x00000040
#define FF_DEBUG_SKIP 0x00000080
#define FF_DEBUG_STARTCODE 0x00000100
#define FF_DEBUG_PTS 0x00000200
#define FF_DEBUG_ER 0x00000400
#define FF_DEBUG_MMCO 0x00000800
#define FF_DEBUG_BUGS 0x00001000
#define FF_DEBUG_VIS_QP 0x00002000
#define FF_DEBUG_VIS_MB_TYPE 0x00004000
#define FF_DEBUG_BUFFERS 0x00008000
#define FF_DEBUG_THREADS 0x00010000
/**
* debug
* - encoding: Set by user.
* - decoding: Set by user.
*/
int debug_mv;
#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames
#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames
#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames
/**
* Error recognition; may misdetect some more or less valid parts as errors.
* - encoding: unused
* - decoding: Set by user.
*/
int err_recognition;
#define AV_EF_CRCCHECK (1<<0)
#define AV_EF_BITSTREAM (1<<1)
#define AV_EF_BUFFER (1<<2)
#define AV_EF_EXPLODE (1<<3)
#define AV_EF_CAREFUL (1<<16)
#define AV_EF_COMPLIANT (1<<17)
#define AV_EF_AGGRESSIVE (1<<18)
/**
* opaque 64bit number (generally a PTS) that will be reordered and
* output in AVFrame.reordered_opaque
* @deprecated in favor of pkt_pts
* - encoding: unused
* - decoding: Set by user.
*/
int64_t reordered_opaque;
/**
* Hardware accelerator in use
* - encoding: unused.
* - decoding: Set by libavcodec
*/
struct AVHWAccel *hwaccel;
/**
* Hardware accelerator context.
* For some hardware accelerators, a global context needs to be
* provided by the user. In that case, this holds display-dependent
* data FFmpeg cannot instantiate itself. Please refer to the
* FFmpeg HW accelerator documentation to know how to fill this
* is. e.g. for VA API, this is a struct vaapi_context.
* - encoding: unused
* - decoding: Set by user
*/
void *hwaccel_context;
/**
* error
* - encoding: Set by libavcodec if flags&CODEC_FLAG_PSNR.
* - decoding: unused
*/
uint64_t error[AV_NUM_DATA_POINTERS];
/**
* DCT algorithm, see FF_DCT_* below
* - encoding: Set by user.
* - decoding: unused
*/
int dct_algo;
#define FF_DCT_AUTO 0
#define FF_DCT_FASTINT 1
#define FF_DCT_INT 2
#define FF_DCT_MMX 3
#define FF_DCT_ALTIVEC 5
#define FF_DCT_FAAN 6
/**
* IDCT algorithm, see FF_IDCT_* below.
* - encoding: Set by user.
* - decoding: Set by user.
*/
int idct_algo;
#define FF_IDCT_AUTO 0
#define FF_IDCT_INT 1
#define FF_IDCT_SIMPLE 2
#define FF_IDCT_SIMPLEMMX 3
#define FF_IDCT_LIBMPEG2MMX 4
#define FF_IDCT_MMI 5
#define FF_IDCT_ARM 7
#define FF_IDCT_ALTIVEC 8
#define FF_IDCT_SH4 9
#define FF_IDCT_SIMPLEARM 10
#define FF_IDCT_H264 11
#define FF_IDCT_VP3 12
#define FF_IDCT_IPP 13
#define FF_IDCT_XVIDMMX 14
#define FF_IDCT_CAVS 15
#define FF_IDCT_SIMPLEARMV5TE 16
#define FF_IDCT_SIMPLEARMV6 17
#define FF_IDCT_SIMPLEVIS 18
#define FF_IDCT_WMV2 19
#define FF_IDCT_FAAN 20
#define FF_IDCT_EA 21
#define FF_IDCT_SIMPLENEON 22
#define FF_IDCT_SIMPLEALPHA 23
#define FF_IDCT_BINK 24
#if FF_API_DSP_MASK
/**
* Unused.
* @deprecated use av_set_cpu_flags_mask() instead.
*/
attribute_deprecated unsigned dsp_mask;
#endif
/**
* bits per sample/pixel from the demuxer (needed for huffyuv).
* - encoding: Set by libavcodec.
* - decoding: Set by user.
*/
int bits_per_coded_sample;
/**
* Bits per sample/pixel of internal libavcodec pixel/sample format.
* - encoding: set by user.
* - decoding: set by libavcodec.
*/
int bits_per_raw_sample;
/**
* low resolution decoding, 1-> 1/2 size, 2->1/4 size
* - encoding: unused
* - decoding: Set by user.
*/
int lowres;
/**
* the picture in the bitstream
* - encoding: Set by libavcodec.
* - decoding: Set by libavcodec.
*/
AVFrame *coded_frame;
/**
* thread count
* is used to decide how many independent tasks should be passed to execute()
* - encoding: Set by user.
* - decoding: Set by user.
*/
int thread_count;
/**
* Which multithreading methods to use.
* Use of FF_THREAD_FRAME will increase decoding delay by one frame per thread,
* so clients which cannot provide future frames should not use it.
*
* - encoding: Set by user, otherwise the default is used.
* - decoding: Set by user, otherwise the default is used.
*/
int thread_type;
#define FF_THREAD_FRAME 1 ///< Decode more than one frame at once
#define FF_THREAD_SLICE 2 ///< Decode more than one part of a single frame at once
/**
* Which multithreading methods are in use by the codec.
* - encoding: Set by libavcodec.
* - decoding: Set by libavcodec.
*/
int active_thread_type;
/**
* Set by the client if its custom get_buffer() callback can be called
* synchronously from another thread, which allows faster multithreaded decoding.
* draw_horiz_band() will be called from other threads regardless of this setting.
* Ignored if the default get_buffer() is used.
* - encoding: Set by user.
* - decoding: Set by user.
*/
int thread_safe_callbacks;
/**
* The codec may call this to execute several independent things.
* It will return only after finishing all tasks.
* The user may replace this with some multithreaded implementation,
* the default implementation will execute the parts serially.
* @param count the number of things to execute
* - encoding: Set by libavcodec, user can override.
* - decoding: Set by libavcodec, user can override.
*/
int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size);
/**
* The codec may call this to execute several independent things.
* It will return only after finishing all tasks.
* The user may replace this with some multithreaded implementation,
* the default implementation will execute the parts serially.
* Also see avcodec_thread_init and e.g. the --enable-pthread configure option.
* @param c context passed also to func
* @param count the number of things to execute
* @param arg2 argument passed unchanged to func
* @param ret return values of executed functions, must have space for "count" values. May be NULL.
* @param func function that will be called count times, with jobnr from 0 to count-1.
* threadnr will be in the range 0 to c->thread_count-1 < MAX_THREADS and so that no
* two instances of func executing at the same time will have the same threadnr.
* @return always 0 currently, but code should handle a future improvement where when any call to func
* returns < 0 no further calls to func may be done and < 0 is returned.
* - encoding: Set by libavcodec, user can override.
* - decoding: Set by libavcodec, user can override.
*/
int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count);
/**
* thread opaque
* Can be used by execute() to store some per AVCodecContext stuff.
* - encoding: set by execute()
* - decoding: set by execute()
*/
void *thread_opaque;
/**
* noise vs. sse weight for the nsse comparsion function
* - encoding: Set by user.
* - decoding: unused
*/
int nsse_weight;
/**
* profile
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
int profile;
#define FF_PROFILE_UNKNOWN -99
#define FF_PROFILE_RESERVED -100
#define FF_PROFILE_AAC_MAIN 0
#define FF_PROFILE_AAC_LOW 1
#define FF_PROFILE_AAC_SSR 2
#define FF_PROFILE_AAC_LTP 3
#define FF_PROFILE_AAC_HE 4
#define FF_PROFILE_AAC_HE_V2 28
#define FF_PROFILE_AAC_LD 22
#define FF_PROFILE_AAC_ELD 38
#define FF_PROFILE_DTS 20
#define FF_PROFILE_DTS_ES 30
#define FF_PROFILE_DTS_96_24 40
#define FF_PROFILE_DTS_HD_HRA 50
#define FF_PROFILE_DTS_HD_MA 60
#define FF_PROFILE_MPEG2_422 0
#define FF_PROFILE_MPEG2_HIGH 1
#define FF_PROFILE_MPEG2_SS 2
#define FF_PROFILE_MPEG2_SNR_SCALABLE 3
#define FF_PROFILE_MPEG2_MAIN 4
#define FF_PROFILE_MPEG2_SIMPLE 5
#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag
#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag
#define FF_PROFILE_H264_BASELINE 66
#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED)
#define FF_PROFILE_H264_MAIN 77
#define FF_PROFILE_H264_EXTENDED 88
#define FF_PROFILE_H264_HIGH 100
#define FF_PROFILE_H264_HIGH_10 110
#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_HIGH_422 122
#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_HIGH_444 144
#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244
#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_CAVLC_444 44
#define FF_PROFILE_VC1_SIMPLE 0
#define FF_PROFILE_VC1_MAIN 1
#define FF_PROFILE_VC1_COMPLEX 2
#define FF_PROFILE_VC1_ADVANCED 3
#define FF_PROFILE_MPEG4_SIMPLE 0
#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1
#define FF_PROFILE_MPEG4_CORE 2
#define FF_PROFILE_MPEG4_MAIN 3
#define FF_PROFILE_MPEG4_N_BIT 4
#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5
#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6
#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7
#define FF_PROFILE_MPEG4_HYBRID 8
#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9
#define FF_PROFILE_MPEG4_CORE_SCALABLE 10
#define FF_PROFILE_MPEG4_ADVANCED_CODING 11
#define FF_PROFILE_MPEG4_ADVANCED_CORE 12
#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13
#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14
#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15
/**
* level
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
int level;
#define FF_LEVEL_UNKNOWN -99
/**
*
* - encoding: unused
* - decoding: Set by user.
*/
enum AVDiscard skip_loop_filter;
/**
*
* - encoding: unused
* - decoding: Set by user.
*/
enum AVDiscard skip_idct;
/**
*
* - encoding: unused
* - decoding: Set by user.
*/
enum AVDiscard skip_frame;
/**
* Header containing style information for text subtitles.
* For SUBTITLE_ASS subtitle type, it should contain the whole ASS
* [Script Info] and [V4+ Styles] section, plus the [Events] line and
* the Format line following. It shouldn't include any Dialogue line.
* - encoding: Set/allocated/freed by user (before avcodec_open2())
* - decoding: Set/allocated/freed by libavcodec (by avcodec_open2())
*/
uint8_t *subtitle_header;
int subtitle_header_size;
/**
* Simulates errors in the bitstream to test error concealment.
* - encoding: Set by user.
* - decoding: unused
*/
int error_rate;
/**
* Current packet as passed into the decoder, to avoid having
* to pass the packet into every function. Currently only valid
* inside lavc and get/release_buffer callbacks.
* - decoding: set by avcodec_decode_*, read by get_buffer() for setting pkt_pts
* - encoding: unused
*/
AVPacket *pkt;
/**
* VBV delay coded in the last frame (in periods of a 27 MHz clock).
* Used for compliant TS muxing.
* - encoding: Set by libavcodec.
* - decoding: unused.
*/
uint64_t vbv_delay;
/**
* Timebase in which pkt_dts/pts and AVPacket.dts/pts are.
* Code outside libavcodec should access this field using:
* avcodec_set_pkt_timebase(avctx)
* - encoding unused.
* - decodimg set by user
*/
AVRational pkt_timebase;
/**
* AVCodecDescriptor
* Code outside libavcodec should access this field using:
* avcodec_get_codec_descriptior(avctx)
* - encoding: unused.
* - decoding: set by libavcodec.
*/
const AVCodecDescriptor *codec_descriptor;
/**
* Current statistics for PTS correction.
* - decoding: maintained and used by libavcodec, not intended to be used by user apps
* - encoding: unused
*/
int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far
int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far
int64_t pts_correction_last_pts; /// PTS of the last frame
int64_t pts_correction_last_dts; /// DTS of the last frame
} AVCodecContext;
```
# 二、AVCodecContext 重点字段
下面挑一些关键的变量来看看(这里只考虑解码):
```
enum AVMediaType codec_type:编解码器的类型(视频,音频...)
struct AVCodec *codec:采用的解码器AVCodec(H.264,MPEG2...)
int bit_rate:平均比特率
uint8_t *extradata; int extradata_size:针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储SPS,PPS等)
AVRational time_base:根据该参数,可以把PTS转化为实际的时间(单位为秒s)
int width, height:如果是视频的话,代表宽和高
int refs:运动估计参考帧的个数(H.264的话会有多帧,MPEG2这类的一般就没有了)
int sample_rate:采样率(音频)
int channels:声道数(音频)
enum AVSampleFormat sample_fmt:采样格式
int profile:型(H.264里面就有,其他编码标准应该也有)
int level:级(和profile差不太多)
```
在这里需要注意:AVCodecContext中很多的参数是编码的时候使用的,而不是解码的时候使用的。
其实这些参数都比较容易理解。就不多费篇幅了。在这里看一下以下几个参数:
### 1.codec_type
编解码器类型有以下几种:
```
enum AVMediaType {
AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA
AVMEDIA_TYPE_VIDEO,
AVMEDIA_TYPE_AUDIO,
AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous
AVMEDIA_TYPE_SUBTITLE,
AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse
AVMEDIA_TYPE_NB
};
```
### 2.sample_fmt
在FFMPEG中音频采样格式有以下几种:
```
enum AVSampleFormat {
AV_SAMPLE_FMT_NONE = -1,
AV_SAMPLE_FMT_U8, ///< unsigned 8 bits
AV_SAMPLE_FMT_S16, ///< signed 16 bits
AV_SAMPLE_FMT_S32, ///< signed 32 bits
AV_SAMPLE_FMT_FLT, ///< float
AV_SAMPLE_FMT_DBL, ///< double
AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
AV_SAMPLE_FMT_FLTP, ///< float, planar
AV_SAMPLE_FMT_DBLP, ///< double, planar
AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
};
```
### 3.profile
在FFMPEG中型有以下几种,可以看出AAC,MPEG2,H.264,VC-1,MPEG4都有型的概念。
```
#define FF_PROFILE_UNKNOWN -99
#define FF_PROFILE_RESERVED -100
#define FF_PROFILE_AAC_MAIN 0
#define FF_PROFILE_AAC_LOW 1
#define FF_PROFILE_AAC_SSR 2
#define FF_PROFILE_AAC_LTP 3
#define FF_PROFILE_AAC_HE 4
#define FF_PROFILE_AAC_HE_V2 28
#define FF_PROFILE_AAC_LD 22
#define FF_PROFILE_AAC_ELD 38
#define FF_PROFILE_DTS 20
#define FF_PROFILE_DTS_ES 30
#define FF_PROFILE_DTS_96_24 40
#define FF_PROFILE_DTS_HD_HRA 50
#define FF_PROFILE_DTS_HD_MA 60
#define FF_PROFILE_MPEG2_422 0
#define FF_PROFILE_MPEG2_HIGH 1
#define FF_PROFILE_MPEG2_SS 2
#define FF_PROFILE_MPEG2_SNR_SCALABLE 3
#define FF_PROFILE_MPEG2_MAIN 4
#define FF_PROFILE_MPEG2_SIMPLE 5
#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag
#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag
#define FF_PROFILE_H264_BASELINE 66
#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED)
#define FF_PROFILE_H264_MAIN 77
#define FF_PROFILE_H264_EXTENDED 88
#define FF_PROFILE_H264_HIGH 100
#define FF_PROFILE_H264_HIGH_10 110
#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_HIGH_422 122
#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_HIGH_444 144
#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244
#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_CAVLC_444 44
#define FF_PROFILE_VC1_SIMPLE 0
#define FF_PROFILE_VC1_MAIN 1
#define FF_PROFILE_VC1_COMPLEX 2
#define FF_PROFILE_VC1_ADVANCED 3
#define FF_PROFILE_MPEG4_SIMPLE 0
#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1
#define FF_PROFILE_MPEG4_CORE 2
#define FF_PROFILE_MPEG4_MAIN 3
#define FF_PROFILE_MPEG4_N_BIT 4
#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5
#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6
#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7
#define FF_PROFILE_MPEG4_HYBRID 8
#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9
#define FF_PROFILE_MPEG4_CORE_SCALABLE 10
#define FF_PROFILE_MPEG4_ADVANCED_CODING 11
#define FF_PROFILE_MPEG4_ADVANCED_CORE 12
#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13
#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14
#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15
```
================================================
FILE: FFmpeg 结构体学习(四): AVFrame 分析.md
================================================
AVFrame是包含码流参数较多的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。
# 一、源码整理
首先我们先看一下结构体AVFrame的定义的结构体源码(位于libavcodec/avcodec.h):
```
/*
*雷霄骅
*leixiaohua1020@126.com
*中国传媒大学/数字电视技术
*/
/**
* Audio Video Frame.
* New fields can be added to the end of AVFRAME with minor version
* bumps. Similarly fields that are marked as to be only accessed by
* av_opt_ptr() can be reordered. This allows 2 forks to add fields
* without breaking compatibility with each other.
* Removal, reordering and changes in the remaining cases require
* a major version bump.
* sizeof(AVFrame) must not be used outside libavcodec.
*/
typedef struct AVFrame {
#define AV_NUM_DATA_POINTERS 8
/**图像数据
* pointer to the picture/channel planes.
* This might be different from the first allocated byte
* - encoding: Set by user
* - decoding: set by AVCodecContext.get_buffer()
*/
uint8_t *data[AV_NUM_DATA_POINTERS];
/**
* Size, in bytes, of the data for each picture/channel plane.
*
* For audio, only linesize[0] may be set. For planar audio, each channel
* plane must be the same size.
*
* - encoding: Set by user
* - decoding: set by AVCodecContext.get_buffer()
*/
int linesize[AV_NUM_DATA_POINTERS];
/**
* pointers to the data planes/channels.
*
* For video, this should simply point to data[].
*
* For planar audio, each channel has a separate data pointer, and
* linesize[0] contains the size of each channel buffer.
* For packed audio, there is just one data pointer, and linesize[0]
* contains the total size of the buffer for all channels.
*
* Note: Both data and extended_data will always be set by get_buffer(),
* but for planar audio with more channels that can fit in data,
* extended_data must be used by the decoder in order to access all
* channels.
*
* encoding: unused
* decoding: set by AVCodecContext.get_buffer()
*/
uint8_t **extended_data;
/**宽高
* width and height of the video frame
* - encoding: unused
* - decoding: Read by user.
*/
int width, height;
/**
* number of audio samples (per channel) described by this frame
* - encoding: Set by user
* - decoding: Set by libavcodec
*/
int nb_samples;
/**
* format of the frame, -1 if unknown or unset
* Values correspond to enum AVPixelFormat for video frames,
* enum AVSampleFormat for audio)
* - encoding: unused
* - decoding: Read by user.
*/
int format;
/**是否是关键帧
* 1 -> keyframe, 0-> not
* - encoding: Set by libavcodec.
* - decoding: Set by libavcodec.
*/
int key_frame;
/**帧类型(I,B,P)
* Picture type of the frame, see ?_TYPE below.
* - encoding: Set by libavcodec. for coded_picture (and set by user for input).
* - decoding: Set by libavcodec.
*/
enum AVPictureType pict_type;
/**
* pointer to the first allocated byte of the picture. Can be used in get_buffer/release_buffer.
* This isn't used by libavcodec unless the default get/release_buffer() is used.
* - encoding:
* - decoding:
*/
uint8_t *base[AV_NUM_DATA_POINTERS];
/**
* sample aspect ratio for the video frame, 0/1 if unknown/unspecified
* - encoding: unused
* - decoding: Read by user.
*/
AVRational sample_aspect_ratio;
/**
* presentation timestamp in time_base units (time when frame should be shown to user)
* If AV_NOPTS_VALUE then frame_rate = 1/time_base will be assumed.
* - encoding: MUST be set by user.
* - decoding: Set by libavcodec.
*/
int64_t pts;
/**
* reordered pts from the last AVPacket that has been input into the decoder
* - encoding: unused
* - decoding: Read by user.
*/
int64_t pkt_pts;
/**
* dts from the last AVPacket that has been input into the decoder
* - encoding: unused
* - decoding: Read by user.
*/
int64_t pkt_dts;
/**
* picture number in bitstream order
* - encoding: set by
* - decoding: Set by libavcodec.
*/
int coded_picture_number;
/**
* picture number in display order
* - encoding: set by
* - decoding: Set by libavcodec.
*/
int display_picture_number;
/**
* quality (between 1 (good) and FF_LAMBDA_MAX (bad))
* - encoding: Set by libavcodec. for coded_picture (and set by user for input).
* - decoding: Set by libavcodec.
*/
int quality;
/**
* is this picture used as reference
* The values for this are the same as the MpegEncContext.picture_structure
* variable, that is 1->top field, 2->bottom field, 3->frame/both fields.
* Set to 4 for delayed, non-reference frames.
* - encoding: unused
* - decoding: Set by libavcodec. (before get_buffer() call)).
*/
int reference;
/**QP表
* QP table
* - encoding: unused
* - decoding: Set by libavcodec.
*/
int8_t *qscale_table;
/**
* QP store stride
* - encoding: unused
* - decoding: Set by libavcodec.
*/
int qstride;
/**
*
*/
int qscale_type;
/**跳过宏块表
* mbskip_table[mb]>=1 if MB didn't change
* stride= mb_width = (width+15)>>4
* - encoding: unused
* - decoding: Set by libavcodec.
*/
uint8_t *mbskip_table;
/**运动矢量表
* motion vector table
* @code
* example:
* int mv_sample_log2= 4 - motion_subsample_log2;
* int mb_width= (width+15)>>4;
* int mv_stride= (mb_width << mv_sample_log2) + 1;
* motion_val[direction][x + y*mv_stride][0->mv_x, 1->mv_y];
* @endcode
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
int16_t (*motion_val[2])[2];
/**宏块类型表
* macroblock type table
* mb_type_base + mb_width + 2
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
uint32_t *mb_type;
/**DCT系数
* DCT coefficients
* - encoding: unused
* - decoding: Set by libavcodec.
*/
short *dct_coeff;
/**参考帧列表
* motion reference frame index
* the order in which these are stored can depend on the codec.
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
int8_t *ref_index[2];
/**
* for some private data of the user
* - encoding: unused
* - decoding: Set by user.
*/
void *opaque;
/**
* error
* - encoding: Set by libavcodec. if flags&CODEC_FLAG_PSNR.
* - decoding: unused
*/
uint64_t error[AV_NUM_DATA_POINTERS];
/**
* type of the buffer (to keep track of who has to deallocate data[*])
* - encoding: Set by the one who allocates it.
* - decoding: Set by the one who allocates it.
* Note: User allocated (direct rendering) & internal buffers cannot coexist currently.
*/
int type;
/**
* When decoding, this signals how much the picture must be delayed.
* extra_delay = repeat_pict / (2*fps)
* - encoding: unused
* - decoding: Set by libavcodec.
*/
int repeat_pict;
/**
* The content of the picture is interlaced.
* - encoding: Set by user.
* - decoding: Set by libavcodec. (default 0)
*/
int interlaced_frame;
/**
* If the content is interlaced, is top field displayed first.
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
int top_field_first;
/**
* Tell user application that palette has changed from previous frame.
* - encoding: ??? (no palette-enabled encoder yet)
* - decoding: Set by libavcodec. (default 0).
*/
int palette_has_changed;
/**
* codec suggestion on buffer type if != 0
* - encoding: unused
* - decoding: Set by libavcodec. (before get_buffer() call)).
*/
int buffer_hints;
/**
* Pan scan.
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
AVPanScan *pan_scan;
/**
* reordered opaque 64bit (generally an integer or a double precision float
* PTS but can be anything).
* The user sets AVCodecContext.reordered_opaque to represent the input at
* that time,
* the decoder reorders values as needed and sets AVFrame.reordered_opaque
* to exactly one of the values provided by the user through AVCodecContext.reordered_opaque
* @deprecated in favor of pkt_pts
* - encoding: unused
* - decoding: Read by user.
*/
int64_t reordered_opaque;
/**
* hardware accelerator private data (FFmpeg-allocated)
* - encoding: unused
* - decoding: Set by libavcodec
*/
void *hwaccel_picture_private;
/**
* the AVCodecContext which ff_thread_get_buffer() was last called on
* - encoding: Set by libavcodec.
* - decoding: Set by libavcodec.
*/
struct AVCodecContext *owner;
/**
* used by multithreading to store frame-specific info
* - encoding: Set by libavcodec.
* - decoding: Set by libavcodec.
*/
void *thread_opaque;
/**
* log2 of the size of the block which a single vector in motion_val represents:
* (4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2)
* - encoding: unused
* - decoding: Set by libavcodec.
*/
uint8_t motion_subsample_log2;
/**(音频)采样率
* Sample rate of the audio data.
*
* - encoding: unused
* - decoding: read by user
*/
int sample_rate;
/**
* Channel layout of the audio data.
*
* - encoding: unused
* - decoding: read by user.
*/
uint64_t channel_layout;
/**
* frame timestamp estimated using various heuristics, in stream time base
* Code outside libavcodec should access this field using:
* av_frame_get_best_effort_timestamp(frame)
* - encoding: unused
* - decoding: set by libavcodec, read by user.
*/
int64_t best_effort_timestamp;
/**
* reordered pos from the last AVPacket that has been input into the decoder
* Code outside libavcodec should access this field using:
* av_frame_get_pkt_pos(frame)
* - encoding: unused
* - decoding: Read by user.
*/
int64_t pkt_pos;
/**
* duration of the corresponding packet, expressed in
* AVStream->time_base units, 0 if unknown.
* Code outside libavcodec should access this field using:
* av_frame_get_pkt_duration(frame)
* - encoding: unused
* - decoding: Read by user.
*/
int64_t pkt_duration;
/**
* metadata.
* Code outside libavcodec should access this field using:
* av_frame_get_metadata(frame)
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
AVDictionary *metadata;
/**
* decode error flags of the frame, set to a combination of
* FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there
* were errors during the decoding.
* Code outside libavcodec should access this field using:
* av_frame_get_decode_error_flags(frame)
* - encoding: unused
* - decoding: set by libavcodec, read by user.
*/
int decode_error_flags;
#define FF_DECODE_ERROR_INVALID_BITSTREAM 1
#define FF_DECODE_ERROR_MISSING_REFERENCE 2
/**
* number of audio channels, only used for audio.
* Code outside libavcodec should access this field using:
* av_frame_get_channels(frame)
* - encoding: unused
* - decoding: Read by user.
*/
int64_t channels;
} AVFrame;
```
# 二、AVFrame 重点字段
AVFrame结构体一般用于存储原始数据(即非压缩数据,例如对视频来说是YUV,RGB,对音频来说是PCM),此外还包含了一些相关的信息。比如说,解码的时候存储了宏块类型表,QP表,运动矢量表等数据。编码的时候也存储了相关的数据。因此在使用FFMPEG进行码流分析的时候,AVFrame是一个很重要的结构体。
下面看几个主要变量的作用(在这里考虑解码的情况):
```
uint8_t *data[AV_NUM_DATA_POINTERS]:解码后原始数据(对视频来说是YUV,RGB,对音频来说是PCM)
int linesize[AV_NUM_DATA_POINTERS]:data中“一行”数据的大小。注意:未必等于图像的宽,一般大于图像的宽。
int width, height:视频帧宽和高(1920x1080,1280x720...)
int nb_samples:音频的一个AVFrame中可能包含多个音频帧,在此标记包含了几个
int format:解码后原始数据类型(YUV420,YUV422,RGB24...)
int key_frame:是否是关键帧
enum AVPictureType pict_type:帧类型(I,B,P...)
AVRational sample_aspect_ratio:宽高比(16:9,4:3...)
int64_t pts:显示时间戳
int coded_picture_number:编码帧序号
int display_picture_number:显示帧序号
int8_t *qscale_table:QP表
uint8_t *mbskip_table:跳过宏块表
int16_t (*motion_val[2])[2]:运动矢量表
uint32_t *mb_type:宏块类型表
short *dct_coeff:DCT系数,这个没有提取过
int8_t *ref_index[2]:运动估计参考帧列表(貌似H.264这种比较新的标准才会涉及到多参考帧)
int interlaced_frame:是否是隔行扫描
uint8_t motion_subsample_log2:一个宏块中的运动矢量采样个数,取log的
```
其他的变量不再一一列举,源代码中都有详细的说明。在这里重点分析一下几个需要一定的理解的变量:
### 1.data[]
对于packed格式的数据(例如RGB24),会存到data[0]里面。
对于planar格式的数据(例如YUV420P),则会分开成data[0],data[1],data[2]...(YUV420P中data[0]存Y,data[1]存U,data[2]存V)
### 2.pict_type
包含以下类型:
```
enum AVPictureType {
AV_PICTURE_TYPE_NONE = 0, ///< Undefined
AV_PICTURE_TYPE_I, ///< Intra
AV_PICTURE_TYPE_P, ///< Predicted
AV_PICTURE_TYPE_B, ///< Bi-dir predicted
AV_PICTURE_TYPE_S, ///< S(GMC)-VOP MPEG4
AV_PICTURE_TYPE_SI, ///< Switching Intra
AV_PICTURE_TYPE_SP, ///< Switching Predicted
AV_PICTURE_TYPE_BI, ///< BI type
};
```
### 3.sample_aspect_ratio
宽高比是一个分数,FFMPEG中用AVRational表达分数:
```
/**
* rational number numerator/denominator
*/
typedef struct AVRational{
int num; ///< numerator
int den; ///< denominator
} AVRational;
```
### 4.qscale_table
QP表指向一块内存,里面存储的是每个宏块的QP值。宏块的标号是从左往右,一行一行的来的。每个宏块对应1个QP。
qscale_table[0]就是第1行第1列宏块的QP值;qscale_table[1]就是第1行第2列宏块的QP值;qscale_table[2]就是第1行第3列宏块的QP值。以此类推...
宏块的个数用下式计算:
注:宏块大小是16x16的。
每行宏块数:
```
int mb_stride = pCodecCtx->width/16+1
```
宏块的总数:
```
int mb_sum = ((pCodecCtx->height+15)>>4)*(pCodecCtx->width/16+1)
```
================================================
FILE: FFmpeg源码分析:内存管理系统.md
================================================
FFmpeg有专门的内存管理系统,包括:内存分配、内存拷贝、内存释放。其中内存分配包含分配内存与对齐、内存分配与清零、分配指定大小的内存块、重新分配内存块、快速分配内存、分配指定最大值的内存、分配数组内存、快速分配数组内存、重新分配数组内存。
FFmpeg的内存管理位于libavutil/mem.c,相关函数如下图所示:

一、内存分配
1、av_malloc
av_malloc()内存分配,并且内存对齐,方便系统快速访问内存。代码如下:
```c
void *av_malloc(size_t size)
{
void *ptr = NULL;
if (size > max_alloc_size)
return NULL;
#if HAVE_POSIX_MEMALIGN
if (size)
if (posix_memalign(&ptr, ALIGN, size))
ptr = NULL;
#elif HAVE_ALIGNED_MALLOC
ptr = _aligned_malloc(size, ALIGN);
#elif HAVE_MEMALIGN
#ifndef __DJGPP__
ptr = memalign(ALIGN, size);
#else
ptr = memalign(size, ALIGN);
#endif
/* Why 64?
* Indeed, we should align it:
* on 4 for 386
* on 16 for 486
* on 32 for 586, PPro - K6-III
* on 64 for K7 (maybe for P3 too).
* Because L1 and L2 caches are aligned on those values.
* But I don't want to code such logic here!
*/
/* Why 32?
* For AVX ASM. SSE / NEON needs only 16.
* Why not larger? Because I did not see a difference in benchmarks ...
*/
/* benchmarks with P3
* memalign(64) + 1 3071, 3051, 3032
* memalign(64) + 2 3051, 3032, 3041
* memalign(64) + 4 2911, 2896, 2915
* memalign(64) + 8 2545, 2554, 2550
* memalign(64) + 16 2543, 2572, 2563
* memalign(64) + 32 2546, 2545, 2571
* memalign(64) + 64 2570, 2533, 2558
*
* BTW, malloc seems to do 8-byte alignment by default here.
*/
#else
ptr = malloc(size);
#endif
if(!ptr && !size) {
size = 1;
ptr= av_malloc(1);
}
#if CONFIG_MEMORY_POISONING
if (ptr)
memset(ptr, FF_MEMORY_POISON, size);
#endif
return ptr;
}2、av_mallocz
av_mallocz()是在av_malloc()基础上,调用memset()进行内存清零:
```
```c
void *av_mallocz(size_t size)
{
void *ptr = av_malloc(size);
if (ptr)
memset(ptr, 0, size);
return ptr;
}
```
3、av_malloc_array
av_malloc_array()先计算数组所需要内存块大小,然后用av_malloc()分配数组内存:
```c
void *av_malloc_array(size_t nmemb, size_t size)
{
size_t result;
if (av_size_mult(nmemb, size, &result) < 0)
return NULL;
return av_malloc(result);
}
```
4、av_mallocz_array
av_mallocz_array()先计算数组所需要内存块大小,然后用av_mallocz()分配数组内存:
```c
void *av_mallocz_array(size_t nmemb, size_t size)
{
size_t result;
if (av_size_mult(nmemb, size, &result) < 0)
return NULL;
return av_mallocz(result);
}
```
5、av_calloc
av_calloc()操作与av_mallocz_array(),先计算内存大小再用av_mallocz()分配内存:
```c
void *av_calloc(size_t nmemb, size_t size)
{
size_t result;
if (av_size_mult(nmemb, size, &result) < 0)
return NULL;
return av_mallocz(result);
}
```
6、av_max_alloc
av_max_alloc()主要是指定分配内存的最大值:
```c
static size_t max_alloc_size= INT_MAX;
void av_max_alloc(size_t max)
{
max_alloc_size = max;
}
```
在av_malloc()用于判断size是否超出最大值:
```c
void *av_malloc(size_t size)
{
void *ptr = NULL;
if (size > max_alloc_size)
return NULL;
......
}7、av_realloc
av_realloc()是对系统的realloc函数进行封装,重新分配内存块:
```
```c
void *av_realloc(void *ptr, size_t size)
{
if (size > max_alloc_size)
return NULL;
#if HAVE_ALIGNED_MALLOC
return _aligned_realloc(ptr, size + !size, ALIGN);
#else
return realloc(ptr, size + !size);
#endif
}
```
8、av_realloc_array
av_realloc_array()先计算内存块大小,然后用av_realloc()重新分配数组内存:
```c
void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
{
size_t result;
if (av_size_mult(nmemb, size, &result) < 0)
return NULL;
return av_realloc(ptr, result);
}
```
9、av_fast_realloc
av_fast_realloc()快速重新分配内存,如果原始内存块足够大直接复用:
```c
void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
{
if (min_size <= *size)
return ptr;
if (min_size > max_alloc_size) {
*size = 0;
return NULL;
}
min_size = FFMIN(max_alloc_size, FFMAX(min_size + min_size / 16 + 32, min_size));
ptr = av_realloc(ptr, min_size);
/* we could set this to the unmodified min_size but this is safer
* if the user lost the ptr and uses NULL now
*/
if (!ptr)
min_size = 0;
*size = min_size;
return ptr;
}
```
10、av_fast_malloc
av_fast_malloc()快速分配内存:
```c
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
{
ff_fast_malloc(ptr, size, min_size, 0);
}
```
其中ff_fast_malloc()代码位于libavutil/mem_internal.h:
```c
static inline int ff_fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
{
void *val;
memcpy(&val, ptr, sizeof(val));
if (min_size <= *size) {
av_assert0(val || !min_size);
return 0;
}
min_size = FFMAX(min_size + min_size / 16 + 32, min_size);
av_freep(ptr);
val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
memcpy(ptr, &val, sizeof(val));
if (!val)
min_size = 0;
*size = min_size;
return 1;
}
```
11、av_fast_mallocz
av_fast_mallocz()快速分配内存,并且内存清零:
```c
void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
{
ff_fast_malloc(ptr, size, min_size, 1);
}
```
二、内存拷贝
1、av_strdup
av_strdup()用于重新分配内存与拷贝字符串:
```c
char *av_strdup(const char *s)
{
char *ptr = NULL;
if (s) {
size_t len = strlen(s) + 1;
ptr = av_realloc(NULL, len);
if (ptr)
memcpy(ptr, s, len);
}
return ptr;
}
```
2、av_strndup
av_strndup()用于分配指定大小内存与拷贝字符串,先用memchr()获取有效字符串长度,然后使用av_realloc()重新分配内存,再用memcpy()拷贝字符串:
```c
char *av_strndup(const char *s, size_t len)
{
char *ret = NULL, *end;
if (!s)
return NULL;
end = memchr(s, 0, len);
if (end)
len = end - s;
ret = av_realloc(NULL, len + 1);
if (!ret)
return NULL;
memcpy(ret, s, len);
ret[len] = 0;
return ret;
}
```
3、av_memdup
av_memdup()用于内存分配与内存拷贝,先用av_malloc()分配内存,再用memcpy()拷贝内存:
```c
void *av_memdup(const void *p, size_t size)
{
void *ptr = NULL;
if (p) {
ptr = av_malloc(size);
if (ptr)
memcpy(ptr, p, size);
}
return ptr;
}
```
4、av_memcpy_backptr
av_memcpy_backptr()用于内存拷贝,与系统提供的memcpy()类似,并且考虑16位、24位、32位内存对齐:
```c
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
{
const uint8_t *src = &dst[-back];
if (!back)
return;
if (back == 1) {
memset(dst, *src, cnt);
} else if (back == 2) {
fill16(dst, cnt);
} else if (back == 3) {
fill24(dst, cnt);
} else if (back == 4) {
fill32(dst, cnt);
} else {
if (cnt >= 16) {
int blocklen = back;
while (cnt > blocklen) {
memcpy(dst, src, blocklen);
dst += blocklen;
cnt -= blocklen;
blocklen <<= 1;
}
memcpy(dst, src, cnt);
return;
}
if (cnt >= 8) {
AV_COPY32U(dst, src);
AV_COPY32U(dst + 4, src + 4);
src += 8;
dst += 8;
cnt -= 8;
}
if (cnt >= 4) {
AV_COPY32U(dst, src);
src += 4;
dst += 4;
cnt -= 4;
}
if (cnt >= 2) {
AV_COPY16U(dst, src);
src += 2;
dst += 2;
cnt -= 2;
}
if (cnt)
*dst = *src;
}
```
}
三、内存释放
1、av_free
av_free()用于释放内存块,主要是调用系统free()进行释放。如果宏定义了对齐分配,那么要对齐释放:
```c
void av_free(void *ptr)
{
#if HAVE_ALIGNED_MALLOC
_aligned_free(ptr);
#else
free(ptr);
#endif
}
```
2、av_freep
av_freep()用于释放内存指针,先备份内存指针,然后把指针地址清空,再释放内存:
```c
void av_freep(void *arg)
{
void *val;
memcpy(&val, arg, sizeof(val));
memcpy(arg, &(void *){ NULL }, sizeof(val));
av_free(val);
}
```
================================================
FILE: Linux上的ffmpeg完全使用指南.md
================================================
**[ffmpeg](https://ffmpeg.org/)** 是一个处理媒体文件的命令行工具 (command line based) 。它是一个拥有非常多功能的框架,并且因为他是开源的,很多知名的工具如 VLC,YouTube, iTunes 等等,都是再其之上开发出来的。
ffmpeg最吸引我的地方就是它可以用非常简练的方式(通过一两个命令)完成许多的处理任务,当然,作为一个强大的工具,他也有很多较为复杂的使用方式,有些时候甚至可以代替一个完整的视频处理流程。
在这个ffmpeg教程中,我会告诉你如何安装ffmpeg,以及各种使用方法,也会讲解一些复杂的功能。
我会详细的说明各个方面,这样即便你是linux新手也能明白。
我使用的linux是 **Ubuntu 18.04**, 不过下面的命令应该可以在其他的linux发行版中同样适用。

## 在 Ubuntu 和其他 Linux 系统上安装 ffmpeg
安装 **ffmpeg** 是非常容易的,它是个很流行的程序,所以大多数的linux发行版中您都可以通过包管理器直接安装。
### 在 Ubuntu 上安装 ffmpeg
在 Ubuntu 上,ffmpeg 存在于 “Universe repository”, 所以确保您开启了enable universe repository,然后更新并安装ffmpeg。下面就是您可能需要的命令。
```c
sudo add-apt-repository universe
sudo apt update
sudo apt install ffmpeg
```
这就OK了,您可以通过下面的命令尝试一下有没有正确安装:
```c
ffmpeg
```
他会打印出一些ffmpeg的配置和版本信息。

正如上图所示,安装的版本是 3.4.4。不过ffmpeg的最新版本应该是4.1。为了安装4.x的版本,您需要使用ffmpeg ppa, 您可以自己研究一下……
### 在 Arch 系的Linux上安装 ffmpeg
这个也非常简单,用下面的命令就行:
```c
sudo pacman -S ffmpeg
```
### 在 Fedora 系的Linux上安装 ffmpeg
使用下面的命令就好了:
```c
sudo dnf install ffmpeg
```
## 如何使用 ffmpeg: 基础
**ffmpeg** 安装就绪了,我来讲述一些使用这个强力工具的基本概念。
### 0. ffmpeg 命令
使用 **ffmpeg 命令** 的**基本形式**是:
```c
ffmpeg [全局参数] {[输入文件参数] -i 输入文件地址} ... {[输出文件参数] 输出文件地址} ...
```
要注意的是,所有的参数仅仅对仅接下来的文件有效(下一个文件得把参数再写一遍)。
所有没有使用 **-i** 指定的文件都被认为是输出文件。 **Ffmpeg** 可以接受多个输入文件并输出到您指定的位置。你也可以将输入输出都指定为同一个文件名,不过这个时候要在输出文件前使用用 **-y** 标记。
Note
*你不应该将输入和输出混淆,先指定输入,再指定输出文件*
### 1. 获得媒体文件的信息
**ffmpeg** 最简单的使用就是用来 **显示文件信息** 。不用给输出,只是简单的写:
```c
ffmpeg -i file_name
```
视频和音频文件都可以使用:
```c
ffmpeg -i video_file.mp4
ffmpeg -i audio_file.mp3
```

通过ffmpeg查看文件属性
命令会输出很多与您文件无关的信息(ffmpeg本身的信息),虽说这个蛮有用的,你可以使用 **-hide_banner** 来隐藏掉它们:
```c
ffmpeg -i video_file.mp4 -hide_banner
ffmpeg -i audio_file.mp3 -hide_banner
```

如图所示,现在命令只显示你文件相关的信息了(编码器,数据流等)。
### 2. 转换媒体文件
**ffmpeg** 最让人称道常用的恐怕就是你轻而易举的在不同媒体格式之间进行自由转换了。你是要指明输入和输出文件名就行了, **ffmpeg** 会从后缀名猜测格式,这个方法同时适用于视频和音频文件
下面是一些例子:
```c
ffmpeg -i video_input.mp4 video_output.avi
ffmpeg -i video_input.webm video_output.flv
ffmpeg -i audio_input.mp3 audio_output.ogg
ffmpeg -i audio_input.wav audio_output.flac
```
你也可以同时指定多个输出后缀:
```c
ffmpeg -i audio_input.wav audio_output_1.mp3 audio_output_2.ogg
```
这样会同时输出多个文件.
想看支持的格式,可以用:
```c
ffmpeg -formats
```
同样的,你可以使用 **-hide_banner** 来省略一些程序信息。
你可以在输出文件前使用 **-qscale 0** 来保留原始的视频质量:
```c
ffmpeg -i video_input.wav -qscale 0 video_output.mp4
```
进一步,你可以指定编码器,使用 **-c:a** (音频) 和 **g-c:v** (视频) 来指定编码器名称,或者写 **copy** 来使用与源文件相同的编码器:
```c
ffmpeg -i video_input.mp4 -c:v copy -c:a libvorbis video_output.avi
```
**Note:** *这样做会让文件后缀使人困惑,所以请避免这么做。*
### 3. 从视频中抽取音频
为了从视频文件中抽取音频,直接加一个 **-vn** 参数就可以了:
```c
ffmpeg -i video.mp4 -vn audio.mp3
```
这会让命令复用原有文件的比特率,一般来说,使用 **-ab** (音频比特率)来指定编码比特率是比较好的:
```c
ffmpeg -i video.mp4 -vn -ab 128k audio.mp3
```
一些常见的比特率有 96k, 128k, 192k, 256k, 320k (mp3也可以使用最高的比特率)。
其他的一些常用的参数比如 **-ar** **(采样率**: 22050, 441000, 48000), **-ac** (**声道数**), **-f** (**音频格式**, 通常会自动识别的). **-ab** 也可以使用 **-b:a** 来替代. 比如:
```c
ffmpeg -i video.mov -vn -ar 44100 -ac 2 -b:a 128k -f mp3 audio.mp3
```
### 4. 让视频静音
和之前的要求类似,我们可以使用 **-an** 来获得纯视频(之前是 **-vn**).
```c
ffmpeg -i video_input.mp4 -an -video_output.mp4
```
**Note:** *这个 **-an** 标记会让所有的音频参数无效,因为最后没有音频会产生。*
### 5. 从视频中提取图片
这个功能可能对很多人都挺有用,比如你可能有一些幻灯片,你想从里面提取所有的图片,那么下面这个命令就能帮你:
```c
ffmpeg -i video.mp4 -r 1 -f image2 image-%3d.png
```
我们来解释一下这个命令:
**-r** 代表了帧率(一秒内导出多少张图像,默认25), **-f** 代表了输出格式(**image2** 实际上上 image2 序列的意思)。
最后一个参数 (输出文件) 有一个有趣的命名:它使用 **%3d** 来指示输出的图片有三位数字 (000, 001, 等等.)。你也可以用 **%2d** (两位数字) 或者 **%4d** (4位数字) ,只要你愿意,你可以随便实验 一下可以怎么写!
**Note:** *同样也有将图片转变为视频/幻灯片的方式,下面的**高级应用**中会讲到。*
### 6. 更改视频分辨率或长宽比
对 **ffmpeg** 来说又是个简单的任务,你只需要使用 **-s** 参数来缩放视频就行了:
```c
ffmpeg -i video_input.mov -s 1024x576 video_output.mp4
```
同时,你可能需要使用 **-c:a** 来保证音频编码是正确的:
```c
ffmpeg -i video_input.h264 -s 640x480 -c:a video_output.mov
```
你也可是使用**-aspect** 来更改长宽比:
```c
ffmpeg -i video_input.mp4 -aspect 4:3 video_output.mp4
```
**Note:** 在高级应用中还会提到更强大的方法
### 7. 为音频增加封面图片
有个很棒的方法把音频变成视频,全程使用一张图片(比如专辑封面)。当你想往某个网站上传音频,但那个网站又仅接受视频(比如YouTube, Facebook等)的情况下会非常有用。
下面是例子:
```c
ffmpeg -loop 1 -i image.jpg -i audio.wav -c:v libx264 -c:a aac -strict experimental -b:a 192k -shortest output.mp4
```
只要改一下编码设置 (**-c:v** 是 视频编码, **-c:a** 是音频编码) 和文件的名称就能用了。
**Note:** *如果你使用一个较新的ffmpeg版本(4.x),你就可以不指定 **-strict experimental***
### 8. 为视频增加字幕
另一个常见又很容易实现的要求是给视频增加字母,比如一部外文电源,使用下面的命令:
```c
ffmpeg -i video.mp4 -i subtitles.srt -c:v copy -c:a copy -preset veryfast -c:s mov_text -map 0 -map 1 output.mp4
```
当然,你可以指定自己的编码器和任何其他的音频视频参数。
### 9. 压缩媒体文件
压缩文件可以极大减少文件的体积,节约存储空间,这对于文件传输尤为重要。通过ffmepg,有好几个方法来压缩文件体积。
**Note:** 文件压缩的太厉害会让文件质量显著降低。
首先,对于音频文件,可以通过降低比特率(使用 **-b:a** 或 **-ab**):
```c
ffmpeg -i audio_input.mp3 -ab 128k audio_output.mp3
ffmpeg -i audio_input.mp3 -b:a 192k audio_output.mp3
```
再次重申,一些常用的比特率有: 96k, 112k, 128k, 160k, 192k, 256k, 320k.值越大,文件所需要的体积就越大。
对于视频文件,选项就多了,一个简单的方法是通过降低视频比特率 (通过 **-b:v**):
```c
ffmpeg -i video_input.mp4 -b:v 1000k -bufsize 1000k video_output.mp4
```
**Note:** 视频的比特率和音频是不同的(一般要大得多)。
你也可以使用 **-crf** 参数 (恒定质量因子). 较小的**crf** 意味着较大的码率。同时使用 **libx264** 编码器也有助于减小文件体积。这里有个例子,压缩的不错,质量也不会显著变化:
```c
ffmpeg -i video_input.mp4 -c:v libx264 -crf 28 video_output.mp4
```
**crf** 设置为20 到 30 是最常见的,不过您也可以尝试一些其他的值。
降低帧率在有些情况下也能有效(不过这往往让视频看起来很卡):
```c
ffmpeg -i video_input.mp4 -r 24 video_output.mp4
```
**-r** 指示了帧率 (这里是 **24**)。
你还可以通过压缩音频来降低视频文件的体积,比如设置为立体声或者降低比特率:
```c
ffmpeg -i video_input.mp4 -c:v libx264 -ac 2 -c:a aac -strict -2 -b:a 128k -crf 28 video_output.mp4
```
**Note:** ***-strict -2** 和 **-ac 2** 是来处理立体声部分的。*
### 10. 裁剪媒体文件(基础)
想要从开头开始剪辑一部分,使用T **-t** 参数来指定一个时间:
```c
ffmpeg -i input_video.mp4 -t 5 output_video.mp4
ffmpeg -i input_audio.wav -t 00:00:05 output_audio.wav
```
这个参数对音频和视频都适用,上面两个命令做了类似的事情:保存一段5s的输出文件(文件开头开始算)。上面使用了两种不同的表示时间的方式,一个单纯的数字(描述)或者 **HH:MM:SS** (小时, 分钟, 秒). 第二种方式实际上指示了结束时间。
也可以通过 **-ss** 给出一个开始时间,**-to** 给出结束时间:
```c
ffmpeg -i input_audio.mp3 -ss 00:01:14 output_audio.mp3
ffmpeg -i input_audio.wav -ss 00:00:30 -t 10 output_audio.wav
ffmpeg -i input_video.h264 -ss 00:01:30 -to 00:01:40 output_video.h264
ffmpeg -i input_audio.ogg -ss 5 output_audio.ogg
```
可以看到 **开始时间** (**-ss HH:MM:SS**), **持续秒数** (**-t duration**), **结束时间** (**-to HH:MM:SS**), 和**开始秒数** (**-s duration**)的用法.
你可以在媒体文件的任何部分使用这些命令。
## ffmpeg: 高级使用
现在该开始讲述一些高级的特性了(比如截屏等),让我们开始吧。
### 1. 分割媒体文件
前面已经讲述了如何裁剪文件,那么如何分割媒体文件呢?只需要为每个输出文件分别指定开始时间、结束或者持续时间就可以了。
看下面这个例子:
```c
ffmpeg -i video.mp4 -t 00:00:30 video_1.mp4 -ss 00:00:30 video_2.mp4
```
语法很简单,为第一个文件指定了 **-t 00:00:30** 作为持续时间(第一个部分是原始文件的前30秒内容),然后指定接下来的所有内容作为第二个文件(从第一部分的结束时间开始,也就是 **00:00:30**)。
你可以任意指定多少个部分,尝试一下吧,这个功能真的很厉害,同时它也适用用音频文件。
### 2. 拼接媒体文件
**ffmpeg** 也可以进行相反的动作:把多个文件合在一起。
为了实现这一点,你得用自己顺手的编辑器来创建一个文本文件。
因为我喜欢使用终端,所以这里我用了 **touch** 和 **vim**. 文件名无关紧要,这里我用 **touch** 命令创建 **video_to_join.txt** 文件:
```c
touch videos_to_join.txt
```
现在,使用 **vim** 编辑它:
```c
vim videos_to_join.txt
```
你可以使用任何你喜欢的工具,比如nano,gedit等等。
在文件内容中, 输入您想拼接的文件的完整路径(文件会按照顺序拼合在一起),一行一个文件。确保他们拥有相同的后缀名。下面是我的例子:
```c
/home/ubuntu/Desktop/video_1.mp4
/home/ubuntu/Desktop/video_2.mp4
/home/ubuntu/Desktop/video_3.mp4
```
保存这个文件,同样这个方法适用与任何音频或者视频文件。
然后使用下面的命令:
```c
ffmpeg -f concat -i join.txt output.mp4
```
**Note:** *使用的输出文件的名称是 **output.mp4**, 因为我的输入文件都是mp4的 。*
这样,你 **videos_to_join.txt** 里的所有文件都会被拼接成一个独立的文件了。
### 3. 将图片转变为视频
这会告诉你如何将图片变成幻灯片秀,同时也会告诉你如何加上音频。
首先我建议您将所有的图片放到一个文件夹下面,我把它们放到了 **my_photos** 里,同时图片的后缀名最好是 **.png** 或者 **.jpg**, 不管选那个,他们应该是同一个后缀名,否则ffmpeg可能会工作的不正常,您可以很方便的把 .png 转变为 .jpg (或者倒过来也行)。
我们这次转换的格式 (**-f**) 应该被设置为 **image2pipe**. 你必须使用使用连词符(**–**)来指明输入。 **image2pipe** 允许你使用管道 (在命令间使用 **|**)的结果而不是文件作为ffmpeg的输入。命令结果便是将所有图片的内容逐个输出,还要注意指明视频编码器是 copy (**-c:v copy**) 以正确使用图片输入:
```c
cat my_photos/* | ffmpeg -f image2pipe -i - -c:v copy video.mkv
```
如果你播放这个文件,你可能会觉得只有一部分图片被加入了,事实上所有的图片都在,但是**ffmpeg** 播放它们的时候太快了,默认是23fps,一秒播放了23张图片。
你应该指定帧率 (**-framerate**) :
```c
cat my_photos/* | ffmpeg -framerate 1 -f image2pipe -i - -c:v copy video.mkv
```
在这个例子里,把帧率设置为1,也就是每帧(每张图)会显示1秒。
为了加一些声音,可以使用音频文件作为输入 (**-i audo_file**) 并且设定copy音频编码 (**-c:a copy**). 你可以同时为音频和视频设定编码器,在输出文件前设置就可以了。你要计算一下音频文件的长度和图片张数,已确定合适的帧率。比如我的音频文件是22秒,图片有9张,那么帧率应该是 9 / 22 大约0.4,所以我这么输入命令:
```c
cat my_photos/* | ffmpeg -framerate 0.40 -f image2pipe -i - -i audio.wav -c copy video.mkv
```
### 4. 录制屏幕
通过 **ffmpeg** 录制屏幕同样没有困难的,将格式(**-f**) 设定为**x11grab**. 他就会抓取你的**XSERVER**. 输入的话可以这是屏幕编号(一般都是**0:0**). 抓取是从左上角开始计算的,可以指定屏幕分辨率 (**-s**). 我的屏幕是 **1920×1080**. 注意屏幕分辨率硬在输入之前指定**t**:
```c
ffmpeg -f x11grab -s 1920x1080 -i :0.0 output.mp4
```
按 **q** 或者 **CTRL+C** 以结束录制屏幕。
**小技巧:**你可以通过命令获得真实的分辨率而不是写死一个固定的大小**:**
```c
-s $(xdpyinfo | grep dimensions | awk '{print $2;}')
```
完整的命令这么写:
```c
ffmpeg -f x11grab -s $(xdpyinfo | grep dimensions | awk '{print $2;}') -i :0.0 output.mp4
```
### 5. 录制摄像头
从摄像头录制就更简单了,linux上设备都是在/dev中的,比如 **/dev/video0, /dev/video1, etc.**:
```c
ffmpeg -i /dev/video0 output.mkv
```
同样, **q** 或者 **CTRL+C** 来结束录制。
### 6. 录制声音
Linux上同时是使用 **ALSA** 和 **pulseaudio** 来处理声音的。 **ffmpeg** 可以录制两者,不过我要特别说明 **pulseaudio**, 因为 Debian 系列的发行版默认用了它。命令如下:
在 **pulseaudio**, 你必须强制指定(**-f**) **alsa** 然后指定 **default** 作为输入**t** (**-i default**):
```c
ffmpeg -f alsa -i default output.mp3
```
**Note:** *在你系统音频设置里,应该能看到默认的录音设备。*
我经常玩吉他,我平时使用一个专业音频设备才能录制声音,当我发现ffmpeg也可以很轻松的录制的时候颇为惊讶。
### 录制小贴士
对于录制任务来说,通常都需要指定编码器以及帧率,之前讲过的参数当然也可以用到这里来!
```c
ffmpeg -i /dev/video0 -f alsa -i default -c:v libx264 -c:a flac -r 30 output.mkv
```
有时候不直接录音,而是在录屏/录像的时候给一个音频文件,那么可以这么做:
```c
ffmpeg -f x11grab -s $(xdpyinfo | grep dimensions | awk '{print $2;}') -i :0.0 -i audio.wav -c:a copy output.mp4
```
**Note:** ***ffmpeg** 使用片段录取,所有有时候非常短的录制可能不会保存文件。我建议录地可以稍微长一些(然后后期裁剪),已保证录制的文件成功写到磁盘上。*
## ffmpeg中的过滤器的基本使用
**过滤器** 是 **ffmpeg** 中最为强大的功能。在ffmepg中有数不甚数的过滤器存在,可以满足各种编辑需要。因为过滤器实在太多了,这里只会简单讲述几个常用的。
使用 过滤的基本结构是:
```c
ffmpeg -i input.mp4 -vf "filter=setting_1=value_1:setting_2=value_2,etc" output.mp4
ffmpeg -i input.wav -af "filter=setting_1=value_1:setting_2=value_2,etc" output.wav
```
可以指定视频过滤器 (**-vf**, **-filter:v**的简写) 和 音频过滤器 (**-af**, **-filter:a**的简写). 过滤器的内容写到双引号里面 (**“**) 并且可以使用逗号(**,**)连接。你可以使用任意数量的过滤器(我写了个etc代表更多的,这不是做一个真实的过滤器)。
过滤器设定的通常格式是:
```c
filter=setting_2=value_2:setting_2=value_2
```
过滤器不同的值使用冒号分割。
你甚至可以在值里面使用进行数学符号计算。
**Note:** 参考 **[ffmpeg 过滤器手册](https://ffmpeg.org/ffmpeg-filters.html)**查看更多高级用法
这里举几个例子来说明视频和音频的过滤器。
### 1. 视频缩放
这是个简单过滤器,设定里只有 **width** 和 **height**:
```c
ffmpeg -i input.mp4 -vf "scale=w=800:h=600" output.mp4
```
我说过你可以使用数学运算来给值:
```c
ffmpeg -i input.mkv -vf "scale=w=1/2*in_w:h=1/2*in_h" output.mkv
```
很明显,这个命令让输入的尺寸变成了输入尺寸(in_w, in_h)的1/2.
### 2. 视频裁剪
类似缩放,这个设定也有 **width** 和 **height** ,另外可以指定裁剪的原点(默认是视频的中心)
```c
ffmpeg -i input.mp4 -vf "crop=w=1280:h=720:x=0:y=0" output.mp4
ffmpeg -i input.mkv -vf "crop=w=400:h=400" output.mkv
```
第二个命令裁剪原点是视频的中心点(因为我没有给x和y坐标),第一个命令会从左上角开始裁剪 (**x=0:y=0**).
这里也有一个使用数学计算的例子:
```c
ffmpeg -i input.mkv -vf "crop=w=3/4*in_w:h=3/4*in_h" output.mkv
```
这会把视频裁剪剩下原大小的3/4/。
### 3. 视频旋转
你可以指定一个弧度,顺时针旋转视频。为了让计算简单一些,你可以给角度然后乘以 **PI/180**:
```c
ffmpeg -i input.avi -vf "rotate=90*PI/180"
ffmpeg -i input.mp4 -vf "rotate=PI"
```
第一个命令将视频顺时针旋转90°,第二个则是上下颠倒了视频(翻转了180°)。
### 4. 音频声道重映射
有的时候,你的音频只有右耳可以听到声音,那么这个功能就很有用了。你可以让声音同时在左右声道出现:
```c
ffmpeg -i input.mp3 -af "channelmap=1-0|1-1" output.mp3
```
这将右声道(1)同时映射到左(0)右(1)两个声道(左边的数字是输入,右边的数字是输出)。
### 5. 更改音量
你可以将音量大小乘以一个实数(可以是整数也可以不是),你只需要给出那个数大小就行了。
```c
ffmpeg -i input.wav -af "volume=1.5" output.wav
ffmpeg -i input.ogg -af "volume=0.75" output.ogg
```
第一个将音量变为1.5倍,第二个则让音量变成了原来的1/4那么安静。
### 技巧:更改播放速度
这里会介绍视频(不影响音频)和音频的过滤器。
1. **视频**
视频过滤器是 **setpts** (PTS = presentation time stamp). 这个参数以一种有趣的方式工作,因为我们修改的是PTS,所以较大的数值意味着较慢的播放速度,反之亦然:
```c
ffmpeg -i input.mkv -vf "setpts=0.5*PTS" output.mkv
ffmpeg -i input.mp4 -vf "setpts=2*PTS" output,mp4
```
第一个命令让播放速度加倍了,第二个则是让播放速度降低了一半。
**2. 音频**
这里的过滤器是 **atempo**. 这里有个限制,它只接受 **0.5**(半速) 到 **2** (倍速)之间的值。为了越过这个限制,你可以链式使用这个过滤器:
```c
ffmpeg -i input.wav -af "atempo=0.75" output.wav
ffmpeg -i input.mp3 -af "atempo=2.0,atempo=2.0" ouutput.mp3
```
第一个命令让音频速度慢了1/4,第二个则是加速到原来的4(2*2)倍。
**Note:** *如果想在同一个命令中同时修改视频和音频的速度,你得查看一下 **[filtergraphs](https://ffmpeg.org/ffmpeg-filters.html#Filtergraph-description)**.*
**小结**
在这个手册中,我讲述了安装、基本的使用、高级的使用和一些过滤器的基础。
我希望这对于一些尝试使用ffmpeg的人,或者希望使用ffmpeg做很多工作的人来说是个有用的资源,ffmepg真的是个多功能又极其好用的工具。
================================================
FILE: README.md
================================================
# 💯 2024年,最新 ffmpeg 资料整理,项目(调试可用),命令手册,文章,编解码论文,视频讲解,面试题全套资料
</br>
<p align="center">
<a> <img width="70%" height="70%" src="https://ahmadawais.com/wp-content/uploads/2021/05/FFmpeg.jpg"></a>
</p>
</br>
本repo搜集整理全网ffmpeg学习资料。
所有数据来源于互联网。所谓取之于互联网,用之于互联网。
如果涉及版权侵犯,请邮件至 wchao_isvip@163.com ,我们将第一时间处理。
如果您对我们的项目表示赞同与支持,欢迎您 [lssues](https://github.com/0voice/ffmpeg_develop_doc/issues) 我们,或者邮件 wchao_isvip@163.com 我们,更加欢迎您 pull requests 加入我们。
感谢您的支持!
<p align="center">
<a href="https://github.com/0voice/ffmpeg_develop_doc#%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E5%90%8E%E5%8F%B0%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E5%B8%88%E8%81%94%E7%B3%BB%E6%88%91%E4%BB%AC%E5%85%8D%E8%B4%B9%E8%8E%B7%E5%8F%96%E6%9B%B4%E5%A4%9Affmepg%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99"><img src="https://img.shields.io/badge/微信公众号-green" alt=""></a>
<a href="https://www.zhihu.com/people/xiao-zhai-nu-linux"><img src="https://img.shields.io/badge/知乎-blue" alt=""></a>
<a href="https://space.bilibili.com/64514973"><img src="https://img.shields.io/badge/bilibili-red" alt=""></a>
</p>
- 目录
- [@ 开源项目](https://github.com/0voice/ffmpeg_develop_doc#-%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE)
- [@ 典藏文档](https://github.com/0voice/ffmpeg_develop_doc#-%E5%85%B8%E8%97%8F%E6%96%87%E6%A1%A3)
- [@ 系列文章](https://github.com/0voice/ffmpeg_develop_doc#-%E6%96%87%E7%AB%A0)
- [@ 面试题](https://github.com/0voice/ffmpeg_develop_doc#-%E9%9D%A2%E8%AF%95%E9%A2%98)
- [@ 教学视频](https://github.com/0voice/ffmpeg_develop_doc#-%E8%A7%86%E9%A2%91)
- [@ 学术论文](https://github.com/0voice/ffmpeg_develop_doc#-%E8%AE%BA%E6%96%87)
- [@ 资料下载](https://github.com/0voice/ffmpeg_develop_doc#%E8%81%94%E7%B3%BB%E4%B8%93%E6%A0%8F)
## 🏗 开源项目
- [bilibili/ijkplayer](https://github.com/bilibili/ijkplayer): 基于FFmpeg n3.4的Android/iOS视频播放器,支持MediaCodec, VideoToolbox。
- [befovy/fijkplayer](https://github.com/befovy/fijkplayer): ijkplayer for flutter. ijkplayer 的 flutter 封装。 Flutter video/audio player. Flutter media player plugin for android/iOS based on ijkplayer. fijkplayer 是基于 ijkplayer 封装的 flutter 媒体播放器,开箱即用,无需编译 ijkplayer
- [mpv-player/mpv](https://github.com/mpv-player/mpv): 命令行视频播放器
- [CarGuo/GSYVideoPlayer](https://github.com/CarGuo/GSYVideoPlayer): 视频播放器(IJKplayer、ExoPlayer、MediaPlayer),HTTPS,支持弹幕,外挂字幕,支持滤镜、水印、gif截图,片头广告、中间广告,多个同时播放,支持基本的拖动,声音、亮度调节,支持边播边缓存,支持视频自带rotation的旋转(90,270之类),重力旋转与手动旋转的同步支持,支持列表播放 ,列表全屏动画,视频加载速度,列表小窗口支持拖动,动画效果,调整比例,多分辨率切换,支持切换播放器,进度条小窗口预览,列表切换详情页面无缝播放,rtsp、concat、mpeg。
- [mpenkov/ffmpeg-tutorial](https://github.com/mpenkov/ffmpeg-tutorial): 教程,演示如何编写一个基于FFmpeg的视频播放器
- [imoreapps/ffmpeg-avplayer-for-ios-tvos](https://github.com/imoreapps/ffmpeg-avplayer-for-ios-tvos): 一个微小但强大的iOS
gitextract_9rzpuyiq/ ├── 3个重点,20个函数分析,浅析FFmpeg转码过程.md ├── FFMpeg写MP4文件例子分析.c ├── FFmpeg source code structure AVPacket, AVPacketSideData, AVBufferRef and AVBuffer.md ├── FFmpeg 学习(一):FFmpeg 简介 .md ├── FFmpeg 学习(七):FFmpeg 学习整理总结.md ├── FFmpeg 学习(三):将 FFmpeg 移植到 Android平台.md ├── FFmpeg 学习(二):Mac下安装FFmpeg.md ├── FFmpeg 学习(五):FFmpeg 编解码 API 分析.md ├── FFmpeg 学习(六):FFmpeg 核心模块 libavformat 与 libavcodec 分析.md ├── FFmpeg 学习(四):FFmpeg API 介绍与通用 API 分析.md ├── FFmpeg 开发之 AVFilter 使用流程总结.md ├── FFmpeg 结构体学习(一): AVFormatContext 分析.md ├── FFmpeg 结构体学习(七): AVIOContext 分析.md ├── FFmpeg 结构体学习(三): AVPacket 分析.md ├── FFmpeg 结构体学习(二): AVStream 分析.md ├── FFmpeg 结构体学习(五): AVCodec 分析.md ├── FFmpeg 结构体学习(八):FFMPEG中重要结构体之间的关系.md ├── FFmpeg 结构体学习(六): AVCodecContext 分析.md ├── FFmpeg 结构体学习(四): AVFrame 分析.md ├── FFmpeg源码分析:内存管理系统.md ├── H.264视频解码优化及DSP实现.caj ├── Linux上的ffmpeg完全使用指南.md ├── README.md ├── case_interview/ │ ├── 001-README.md │ └── 002-README.md ├── ffmpeg常用命令.md ├── ffmpeg源码example解析之decode_audio.md ├── ffmpeg源码example解析之decode_video.md ├── ffplay源码和书籍/ │ └── ffplay/ │ ├── Debug/ │ │ ├── allcodecs.obj │ │ ├── allformats.obj │ │ ├── avidec.obj │ │ ├── avio.obj │ │ ├── aviobuf.obj │ │ ├── cutils.obj │ │ ├── dsputil.obj │ │ ├── ffplay.Build.CppClean.log │ │ ├── ffplay.ilk │ │ ├── ffplay.log │ │ ├── ffplay.obj │ │ ├── ffplay.pdb │ │ ├── ffplay.tlog/ │ │ │ ├── CL.read.1.tlog │ │ │ ├── CL.write.1.tlog │ │ │ ├── cl.command.1.tlog │ │ │ ├── ffplay.lastbuildstate │ │ │ ├── link.command.1.tlog │ │ │ ├── link.read.1.tlog │ │ │ └── link.write.1.tlog │ │ ├── file.obj │ │ ├── imgconvert.obj │ │ ├── msrle.obj │ │ ├── truespeech.obj │ │ ├── utils_codec.obj │ │ ├── utils_format.obj │ │ ├── vc120.idb │ │ └── vc120.pdb │ ├── berrno.h │ ├── ffplay.c │ ├── ffplay.dsp │ ├── ffplay.vcxproj │ ├── ffplay.vcxproj.filters │ ├── libavcodec/ │ │ ├── allcodecs.c │ │ ├── avcodec.h │ │ ├── dsputil.c │ │ ├── dsputil.h │ │ ├── imgconvert.c │ │ ├── imgconvert_template.h │ │ ├── msrle.c │ │ ├── truespeech.c │ │ ├── truespeech_data.h │ │ └── utils_codec.c │ ├── libavformat/ │ │ ├── allformats.c │ │ ├── avformat.h │ │ ├── avidec.c │ │ ├── avio.c │ │ ├── avio.h │ │ ├── aviobuf.c │ │ ├── cutils.c │ │ ├── file.c │ │ └── utils_format.c │ ├── libavutil/ │ │ ├── avutil.h │ │ ├── bswap.h │ │ ├── common.h │ │ ├── mathematics.h │ │ └── rational.h │ └── update.txt ├── iOS资料/ │ ├── AVFoundation之视频捕捉.md │ ├── IOS 剪辑编辑器.md │ ├── IOS之多媒体API.md │ ├── MACiOS利用FFmpeg解析音视频数据流.md │ ├── iOS - 图形高级处理 (一、图片显示相关理论).md │ ├── iOS AVDemo(5):音频解码.md │ ├── iOS AVDemo(6):音频渲染.md │ ├── iOS AVDemo(7):视频采集.md │ ├── iOS AVDemo(8):视频编码,H.264 和 H.265 都支持.md │ ├── iOS AVDemo(9):视频封装,采集编码 H.264H.265 并封装 MP4.md │ ├── iOS AVDemo:音频封装,采集编码并封装为 M4A.md │ ├── iOS AVDemo:音频编码,采集 PCM 数据编码为 AAC.md │ ├── iOS AVDemo:音频解封装,从 MP4 中解封装出 AAC.md │ ├── iOS AVDemo:音频采集.md │ ├── iOS Runtime详解.md │ ├── iOS 入门(2):管理第三方库.md │ ├── iOS 离屏渲染探究.md │ ├── iOS 系统架构及常用框架.md │ ├── iOS-WebRTC静态库,framework下载、编译,使用.md │ ├── iOSAVDemo(10):视频解封装,从 MP4 解出 H.264H.265.md │ ├── iOS下 WebRTC 视频渲染.md │ ├── iOS下的渲染框架.md │ ├── iOS使用AVPlayer,播放本地,在线音频 │ ├── iOS动画系列之三:Core Animation.md │ ├── iOS图像渲染及卡顿问题优化.md │ ├── iOS学习音视频的过程.md │ ├── iOS拉取SRS流媒体服务器的Rtc流.md │ ├── iOS短视频篇:音视频编辑之音视频合成,添加水印及音视频导出.md │ ├── iOS硬编解码相关知识.md │ ├── iOS视图渲染与性能优化.md │ ├── iOS视频开发:视频H264硬编码.md │ ├── iOS视频推流、拉流原理.md │ ├── iOS逆向 MachO文件.md │ ├── iOS配置FFmpeg框架.md │ ├── iOS音视频 -- AVFoundation捕捉.md │ ├── iOS音视频同步探讨.md │ ├── iOS音视频开发-了解编码及视频.md │ ├── iOS音视频开发-代码实现视频编码.md │ ├── iOS音视频开发-采集、编码、滤镜.md │ ├── iOS音视频开发——FFmpeg库编译.md │ ├── iOS音视频开发——视频采集.md │ ├── iOS音视频开源框架WebRTC入门-AppRTCMobile.md │ ├── iOS音视频的那些事儿:数据的采集和编码.md │ ├── iOS音视频:OpenGL常用术语介绍.md │ ├── iOS音频录制及合成,以及优化处理 │ ├── iOS音频视频开发.md │ ├── iOS音频采集过程中的音效实现.md │ ├── iOS项目集成OpenCV及踩过的坑.md │ ├── iOS高级视频渲染.md │ ├── macOS 下单步调试 WebRTC Android & iOS.md │ ├── 【OpenGL入门】iOS 图像渲染原理.md │ ├── 【如何快速的开发一个完整的iOS直播app】(美颜篇).md │ ├── 关于iOS离屏渲染的深入研究.md │ ├── 基于 AVFoundation 框架开发小视频功能的方案解析.md │ ├── 最简单的基于FFmpeg的移动端例子:IOS HelloWorld.md │ ├── 视频直播iOS端技术.md │ ├── 资深程序员的Metal入门教程总结.md │ └── 音视频学习--iOS适配H265实战踩坑记.md ├── paper/ │ └── README.md ├── teaching video/ │ └── video.md ├── 使用FFMpeg进行H264编码.c └── 基于RTMP的高清流媒体直播点播封装技术的研究与实现.caj
SYMBOL INDEX (208 symbols across 24 files) FILE: FFMpeg写MP4文件例子分析.c function AVStream (line 27) | static AVStream *add_audio_stream(AVFormatContext *oc, enum CodecID code... function open_audio (line 56) | static void open_audio(AVFormatContext *oc, AVStream *st) function get_audio_frame (line 107) | static void get_audio_frame(int16_t *samples, int frame_size, int nb_cha... function write_audio_frame (line 122) | static void write_audio_frame(AVFormatContext *oc, AVStream *st) function close_audio (line 147) | static void close_audio(AVFormatContext *oc, AVStream *st) function AVStream (line 163) | static AVStream *add_video_stream(AVFormatContext *oc, enum CodecID code... function AVFrame (line 219) | static AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int h... function open_video (line 239) | static void open_video(AVFormatContext *oc, AVStream *st) function fill_yuv_image (line 292) | static void fill_yuv_image(AVFrame *pict, int frame_index, int width, in... function write_video_frame (line 314) | static void write_video_frame(AVFormatContext *oc, AVStream *st) function close_video (line 393) | static void close_video(AVFormatContext *oc, AVStream *st) function main (line 409) | int main(int argc, char **argv) FILE: ffplay源码和书籍/ffplay/ffplay.c type PacketQueue (line 36) | typedef struct PacketQueue type VideoPicture (line 51) | typedef struct VideoPicture type VideoState (line 60) | typedef struct VideoState function av_gettime (line 117) | int64_t av_gettime(void) function packet_queue_init (line 133) | static void packet_queue_init(PacketQueue *q) // packet queue handling function packet_queue_flush (line 143) | static void packet_queue_flush(PacketQueue *q) function packet_queue_end (line 161) | static void packet_queue_end(PacketQueue *q) function packet_queue_put (line 169) | static int packet_queue_put(PacketQueue *q, AVPacket *pkt) function packet_queue_abort (line 195) | static void packet_queue_abort(PacketQueue *q) function packet_queue_get (line 208) | static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) function alloc_picture (line 250) | static void alloc_picture(void *opaque) function video_display (line 270) | static int video_display(VideoState *is, AVFrame *src_frame, double pts) function video_thread (line 321) | static int video_thread(void *arg) function audio_decode_frame (line 365) | static int audio_decode_frame(VideoState *is, uint8_t *audio_buf, double... function sdl_audio_callback (line 409) | void sdl_audio_callback(void *opaque, Uint8 *stream, int len) function stream_component_open (line 445) | static int stream_component_open(VideoState *is, int stream_index) function stream_component_close (line 512) | static void stream_component_close(VideoState *is, int stream_index) function decode_thread (line 541) | static int decode_thread(void *arg) function VideoState (line 685) | static VideoState *stream_open(const char *filename, AVInputFormat *ifor... function stream_close (line 710) | static void stream_close(VideoState *is) function do_exit (line 732) | void do_exit(void) function event_loop (line 744) | void event_loop(void) // handle an event sent by the GUI function main (line 774) | int main(int argc, char **argv) FILE: ffplay源码和书籍/ffplay/libavcodec/allcodecs.c function avcodec_register_all (line 12) | void avcodec_register_all(void) FILE: ffplay源码和书籍/ffplay/libavcodec/avcodec.h type CodecID (line 30) | enum CodecID type CodecType (line 38) | enum CodecType type AVPicture (line 58) | typedef struct AVPicture type AVFrame (line 65) | typedef struct AVFrame type AVCodecContext (line 78) | typedef struct AVCodecContext type AVCodec (line 116) | typedef struct AVCodec type AVPaletteControl (line 137) | typedef struct AVPaletteControl type CodecID (line 164) | enum CodecID FILE: ffplay源码和书籍/ffplay/libavcodec/dsputil.c function dsputil_static_init (line 11) | void dsputil_static_init(void) FILE: ffplay源码和书籍/ffplay/libavcodec/imgconvert.c type PixFmtInfo (line 19) | typedef struct PixFmtInfo function avcodec_get_chroma_sub_sample (line 58) | void avcodec_get_chroma_sub_sample(int pix_fmt, int *h_shift, int *v_shift) function avpicture_fill (line 65) | int avpicture_fill(AVPicture *picture, uint8_t *ptr, int pix_fmt, int wi... function avpicture_get_size (line 159) | int avpicture_get_size(int pix_fmt, int width, int height) function avpicture_alloc (line 165) | int avpicture_alloc(AVPicture *picture, int pix_fmt, int width, int height) function avpicture_free (line 183) | void avpicture_free(AVPicture *picture) function avg_bits_per_pixel (line 188) | static int avg_bits_per_pixel(int pix_fmt) function ff_img_copy_plane (line 235) | void ff_img_copy_plane(uint8_t *dst, int dst_wrap, const uint8_t *src, i... function img_copy (line 248) | void img_copy(AVPicture *dst, const AVPicture *src, int pix_fmt, int wid... function yuv422_to_yuv420p (line 298) | static void yuv422_to_yuv420p(AVPicture *dst, const AVPicture *src, int ... function uyvy422_to_yuv420p (line 359) | static void uyvy422_to_yuv420p(AVPicture *dst, const AVPicture *src, int... function uyvy422_to_yuv422p (line 421) | static void uyvy422_to_yuv422p(AVPicture *dst, const AVPicture *src, int... function yuv422_to_yuv422p (line 455) | static void yuv422_to_yuv422p(AVPicture *dst, const AVPicture *src, int ... function yuv422p_to_yuv422 (line 489) | static void yuv422p_to_yuv422(AVPicture *dst, const AVPicture *src, int ... function yuv422p_to_uyvy422 (line 523) | static void yuv422p_to_uyvy422(AVPicture *dst, const AVPicture *src, int... function uyvy411_to_yuv411p (line 557) | static void uyvy411_to_yuv411p(AVPicture *dst, const AVPicture *src, int... function yuv420p_to_yuv422 (line 593) | static void yuv420p_to_yuv422(AVPicture *dst, const AVPicture *src, int ... function yuv420p_to_uyvy422 (line 629) | static void yuv420p_to_uyvy422(AVPicture *dst, const AVPicture *src, int... function C_JPEG_TO_CCIR (line 714) | static inline int C_JPEG_TO_CCIR(int y) function img_apply_table (line 752) | static void img_apply_table(uint8_t *dst, int dst_wrap, const uint8_t *s... function shrink41 (line 792) | static void shrink41(uint8_t *dst, int dst_wrap, const uint8_t *src, int... function shrink21 (line 814) | static void shrink21(uint8_t *dst, int dst_wrap, const uint8_t *src, int... function shrink12 (line 836) | static void shrink12(uint8_t *dst, int dst_wrap, const uint8_t *src, int... function ff_shrink22 (line 870) | void ff_shrink22(uint8_t *dst, int dst_wrap, const uint8_t *src, int src... function ff_shrink44 (line 904) | void ff_shrink44(uint8_t *dst, int dst_wrap, const uint8_t *src, int src... function grow21_line (line 932) | static void grow21_line(uint8_t *dst, const uint8_t *src, int width) function grow41_line (line 961) | static void grow41_line(uint8_t *dst, const uint8_t *src, int width) function grow21 (line 982) | static void grow21(uint8_t *dst, int dst_wrap, const uint8_t *src, int s... function grow22 (line 993) | static void grow22(uint8_t *dst, int dst_wrap, const uint8_t *src, int s... function grow41 (line 1005) | static void grow41(uint8_t *dst, int dst_wrap, const uint8_t *src, int s... function grow44 (line 1016) | static void grow44(uint8_t *dst, int dst_wrap, const uint8_t *src, int s... function conv411 (line 1028) | static void conv411(uint8_t *dst, int dst_wrap, const uint8_t *src, int ... function gif_clut_index (line 1060) | static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b) function build_rgb_palette (line 1065) | static void build_rgb_palette(uint8_t *palette, int has_alpha) function bitcopy_n (line 1090) | static inline unsigned int bitcopy_n(unsigned int a, int n) function mono_to_gray (line 1229) | static void mono_to_gray(AVPicture *dst, const AVPicture *src, int width... function monowhite_to_gray (line 1274) | static void monowhite_to_gray(AVPicture *dst, const AVPicture *src, int ... function monoblack_to_gray (line 1279) | static void monoblack_to_gray(AVPicture *dst, const AVPicture *src, int ... function gray_to_mono (line 1284) | static void gray_to_mono(AVPicture *dst, const AVPicture *src, int width... function gray_to_monowhite (line 1332) | static void gray_to_monowhite(AVPicture *dst, const AVPicture *src, int ... function gray_to_monoblack (line 1337) | static void gray_to_monoblack(AVPicture *dst, const AVPicture *src, int ... type ConvertEntry (line 1342) | typedef struct ConvertEntry function img_convert_init (line 1365) | static void img_convert_init(void) function is_yuv_planar (line 1457) | static inline int is_yuv_planar(PixFmtInfo *ps) function img_convert (line 1463) | int img_convert(AVPicture *dst, int dst_pix_fmt, const AVPicture *src, i... FILE: ffplay源码和书籍/ffplay/libavcodec/imgconvert_template.h function yuv444p_to_rgb24 (line 543) | static void yuv444p_to_rgb24(AVPicture *dst, const AVPicture *src, int w... function yuvj444p_to_rgb24 (line 577) | static void yuvj444p_to_rgb24(AVPicture *dst, const AVPicture *src, int ... function rgb24_to_yuv444p (line 611) | static void rgb24_to_yuv444p(AVPicture *dst, const AVPicture *src, int w... function rgb24_to_yuvj420p (line 645) | static void rgb24_to_yuvj420p(AVPicture *dst, const AVPicture *src, int ... function rgb24_to_yuvj444p (line 757) | static void rgb24_to_yuvj444p(AVPicture *dst, const AVPicture *src, int ... FILE: ffplay源码和书籍/ffplay/libavcodec/msrle.c type MsrleContext (line 18) | typedef struct MsrleContext function msrle_decode_pal4 (line 38) | static void msrle_decode_pal4(MsrleContext *s) function msrle_decode_pal8 (line 144) | static void msrle_decode_pal8(MsrleContext *s) function msrle_decode_init (line 242) | static int msrle_decode_init(AVCodecContext *avctx) function msrle_decode_frame (line 255) | static int msrle_decode_frame(AVCodecContext *avctx, void *data, int *da... function msrle_decode_end (line 284) | static int msrle_decode_end(AVCodecContext *avctx) FILE: ffplay源码和书籍/ffplay/libavcodec/truespeech.c type TSContext (line 10) | typedef struct TSContext function truespeech_decode_init (line 37) | static int truespeech_decode_init(AVCodecContext *avctx) function truespeech_read_frame (line 42) | static void truespeech_read_frame(TSContext *dec, uint8_t *input) function truespeech_correlate_filter (line 130) | static void truespeech_correlate_filter(TSContext *dec) function truespeech_filters_merge (line 152) | static void truespeech_filters_merge(TSContext *dec) function truespeech_apply_twopoint_filter (line 179) | static void truespeech_apply_twopoint_filter(TSContext *dec, int quart) function truespeech_place_pulses (line 207) | static void truespeech_place_pulses(TSContext *dec, int16_t *out, int qu... function truespeech_update_filters (line 253) | static void truespeech_update_filters(TSContext *dec, int16_t *out, int ... function truespeech_synth (line 267) | static void truespeech_synth(TSContext *dec, int16_t *out, int quart) function truespeech_save_prevvec (line 321) | static void truespeech_save_prevvec(TSContext *c) function truespeech_decode_frame (line 329) | static int truespeech_decode_frame(AVCodecContext *avctx, void *data, in... FILE: ffplay源码和书籍/ffplay/libavcodec/utils_codec.c function av_free (line 35) | void av_free(void *ptr) function av_freep (line 63) | void av_freep(void *arg) function register_avcodec (line 74) | void register_avcodec(AVCodec *format) type InternalBuffer (line 85) | typedef struct InternalBuffer function avcodec_align_dimensions (line 96) | void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height) function avcodec_check_dimensions (line 136) | int avcodec_check_dimensions(void *av_log_ctx, unsigned int w, unsigned ... function avcodec_default_get_buffer (line 144) | int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic) function avcodec_default_release_buffer (line 231) | void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic) function avcodec_default_reget_buffer (line 259) | int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic) function avcodec_default_free_buffers (line 269) | void avcodec_default_free_buffers(AVCodecContext *s) function AVCodecContext (line 290) | AVCodecContext *avcodec_alloc_context(void) function avcodec_open (line 310) | int avcodec_open(AVCodecContext *avctx, AVCodec *codec) function avcodec_decode_video (line 343) | int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture, int *g... function avcodec_decode_audio (line 363) | int avcodec_decode_audio(AVCodecContext *avctx, int16_t *samples, int *f... function avcodec_close (line 379) | int avcodec_close(AVCodecContext *avctx) function AVCodec (line 389) | AVCodec *avcodec_find_decoder(enum CodecID id) function avcodec_init (line 403) | void avcodec_init(void) FILE: ffplay源码和书籍/ffplay/libavformat/allformats.c function av_register_all (line 9) | void av_register_all(void) FILE: ffplay源码和书籍/ffplay/libavformat/avformat.h type AVPacket (line 55) | typedef struct AVPacket type AVPacketList (line 68) | typedef struct AVPacketList function av_destruct_packet (line 75) | static inline void av_destruct_packet(AVPacket *pkt) function av_free_packet (line 83) | static inline void av_free_packet(AVPacket *pkt) function av_get_packet (line 95) | static inline int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size) type AVProbeData (line 135) | typedef struct AVProbeData type AVIndexEntry (line 148) | typedef struct AVIndexEntry type AVStream (line 161) | typedef struct AVStream type AVFormatParameters (line 181) | typedef struct AVFormatParameters type AVInputFormat (line 191) | typedef struct AVInputFormat type AVFormatContext (line 221) | typedef struct AVFormatContext // format I/O context FILE: ffplay源码和书籍/ffplay/libavformat/avidec.c type AVIStream (line 31) | typedef struct type AVIContext (line 48) | typedef struct type CodecTag (line 57) | typedef struct function codec_get_id (line 76) | enum CodecID codec_get_id(const CodecTag *tags, unsigned int tag) function get_riff (line 91) | static int get_riff(AVIContext *avi, ByteIOContext *pb) function clean_index (line 109) | static void clean_index(AVFormatContext *s) function avi_read_header (line 138) | static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) function avi_read_packet (line 394) | int avi_read_packet(AVFormatContext *s, AVPacket *pkt) function avi_read_idx1 (line 630) | static int avi_read_idx1(AVFormatContext *s, int size) function guess_ni_flag (line 678) | static int guess_ni_flag(AVFormatContext *s) function avi_load_index (line 701) | static int avi_load_index(AVFormatContext *s) function avi_read_close (line 737) | static int avi_read_close(AVFormatContext *s) function avi_probe (line 754) | static int avi_probe(AVProbeData *p) function avidec_init (line 776) | int avidec_init(void) FILE: ffplay源码和书籍/ffplay/libavformat/avio.c function register_protocol (line 14) | int register_protocol(URLProtocol *protocol) function url_open (line 26) | int url_open(URLContext **puc, const char *filename, int flags) function url_read (line 101) | int url_read(URLContext *h, unsigned char *buf, int size) function offset_t (line 111) | offset_t url_seek(URLContext *h, offset_t pos, int whence) function url_close (line 122) | int url_close(URLContext *h) function url_get_max_packet_size (line 131) | int url_get_max_packet_size(URLContext *h) FILE: ffplay源码和书籍/ffplay/libavformat/avio.h type offset_t (line 10) | typedef int64_t offset_t; type URLContext (line 22) | typedef struct URLContext type URLProtocol (line 38) | typedef struct URLProtocol type ByteIOContext (line 52) | typedef struct ByteIOContext FILE: ffplay源码和书籍/ffplay/libavformat/aviobuf.c function init_put_byte (line 18) | int init_put_byte(ByteIOContext *s, function offset_t (line 51) | offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence) function url_fskip (line 86) | void url_fskip(ByteIOContext *s, offset_t offset) function offset_t (line 92) | offset_t url_ftell(ByteIOContext *s) function offset_t (line 98) | offset_t url_fsize(ByteIOContext *s) function url_feof (line 110) | int url_feof(ByteIOContext *s) function url_ferror (line 116) | int url_ferror(ByteIOContext *s) function fill_buffer (line 123) | static void fill_buffer(ByteIOContext *s) function get_byte (line 147) | int get_byte(ByteIOContext *s) // NOTE: return 0 if EOF, so you cannot u... function get_le16 (line 165) | unsigned int get_le16(ByteIOContext *s) function get_le32 (line 174) | unsigned int get_le32(ByteIOContext *s) function url_read_buf (line 185) | static int url_read_buf(void *opaque, uint8_t *buf, int buf_size) function offset_t (line 192) | static offset_t url_seek_buf(void *opaque, offset_t offset, int whence) function url_setbufsize (line 199) | int url_setbufsize(ByteIOContext *s, int buf_size) // must be called bef... function url_fopen (line 218) | int url_fopen(ByteIOContext *s, const char *filename, int flags) function url_fclose (line 266) | int url_fclose(ByteIOContext *s) function url_fread (line 276) | int url_fread(ByteIOContext *s, unsigned char *buf, int size) // get_buffer FILE: ffplay源码和书籍/ffplay/libavformat/cutils.c function strstart (line 10) | int strstart(const char *str, const char *val, const char **ptr) function pstrcpy (line 30) | void pstrcpy(char *buf, int buf_size, const char *str) FILE: ffplay源码和书籍/ffplay/libavformat/file.c function file_open (line 24) | static int file_open(URLContext *h, const char *filename, int flags) function file_read (line 53) | static int file_read(URLContext *h, unsigned char *buf, int size) function file_write (line 60) | static int file_write(URLContext *h, unsigned char *buf, int size) function offset_t (line 67) | static offset_t file_seek(URLContext *h, offset_t pos, int whence) function file_close (line 74) | static int file_close(URLContext *h) FILE: ffplay源码和书籍/ffplay/libavformat/utils_format.c function av_register_input_format (line 17) | void av_register_input_format(AVInputFormat *format) function match_ext (line 28) | int match_ext(const char *filename, const char *extensions) function AVInputFormat (line 58) | AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened) function av_open_input_stream (line 90) | int av_open_input_stream(AVFormatContext **ic_ptr, ByteIOContext *pb, co... function av_open_input_file (line 144) | int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, A... function av_read_packet (line 211) | int av_read_packet(AVFormatContext *s, AVPacket *pkt) function av_add_index_entry (line 220) | int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, int... function av_index_search_timestamp (line 266) | int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, in... function av_close_input_file (line 302) | void av_close_input_file(AVFormatContext *s) function AVStream (line 324) | AVStream *av_new_stream(AVFormatContext *s, int id) function av_set_pts_info (line 341) | void av_set_pts_info(AVStream *s, int pts_wrap_bits, int pts_num, int pt... FILE: ffplay源码和书籍/ffplay/libavutil/avutil.h type PixelFormat (line 24) | enum PixelFormat FILE: ffplay源码和书籍/ffplay/libavutil/bswap.h function bswap_16 (line 9) | static inline uint16_t bswap_16(uint16_t x) function bswap_32 (line 15) | static inline uint32_t bswap_32(uint32_t x) FILE: ffplay源码和书籍/ffplay/libavutil/common.h function strcasecmp (line 49) | static int strcasecmp(char *s1, const char *s2) function clip (line 59) | static inline int clip(int a, int amin, int amax) FILE: ffplay源码和书籍/ffplay/libavutil/mathematics.h function av_rescale (line 5) | static inline int64_t av_rescale(int64_t a, int64_t b, int64_t c) FILE: ffplay源码和书籍/ffplay/libavutil/rational.h type AVRational (line 8) | typedef struct AVRational function av_q2d (line 15) | static inline double av_q2d(AVRational a)
Condensed preview — 147 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,467K chars).
[
{
"path": "3个重点,20个函数分析,浅析FFmpeg转码过程.md",
"chars": 5407,
"preview": "## **写在前面**\n\n最近在做和转码有关的项目,接触到ffmpeg这个神器。从一开始简单的写脚本直接调用ffmpeg的可执行文件做些转码的工作,到后来需要写程序调用ffmpeg的API。虽然上网搜了别人的demo稍微改改顺利完成了工作,"
},
{
"path": "FFMpeg写MP4文件例子分析.c",
"chars": 15616,
"preview": "/**\n这段时间看了FFMpeg提供的例子muxing.c,我略微修改了下源代码,使其生成一个MP4文件,音频使用AAC编码,视频使用H.264编码。代码很简单,我就不做说明了,代码如下。\n\n以后我们继续写如何将DirectShow中采集的"
},
{
"path": "FFmpeg source code structure AVPacket, AVPacketSideData, AVBufferRef and AVBuffer.md",
"chars": 25125,
"preview": "AVPacket stores the encoded frame data, which is usually output by demuxer and then transferred to decoder as input, or "
},
{
"path": "FFmpeg 学习(一):FFmpeg 简介 .md",
"chars": 2049,
"preview": "> 本文转载自博客园:https://www.cnblogs.com/renhui/p/6922971.html\n\n# 一、FFmpeg 介绍\n\nFFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LG"
},
{
"path": "FFmpeg 学习(七):FFmpeg 学习整理总结.md",
"chars": 3040,
"preview": "# 一、FFmpeg 播放视频的基本流程整理\n\n播放流程: video.avi(Container) -> 打开得到 Video_Stream -> 读取Packet -> 解析到 Frame -> 显示Frame。\n\n- Containe"
},
{
"path": "FFmpeg 学习(三):将 FFmpeg 移植到 Android平台.md",
"chars": 5249,
"preview": "首先需要去FFmpeg的官网http://www.ffmpeg.org/去下载FFmpeg的源码,目前的版本号为FFmpeg3.3(Hilbert)。\n\n下载的文件为压缩包,解压后得到ffmpeg-3.3目录。\n\n**修改ffmpeg-3."
},
{
"path": "FFmpeg 学习(二):Mac下安装FFmpeg.md",
"chars": 1628,
"preview": "> 本文转载自博客园:https://www.cnblogs.com/renhui/p/8458150.html\n\n# 一、安装ffmpeg\n\n分为两种安装方式:\n\n### 1. 命令行安装\n\n```\nbrew install ffmpeg"
},
{
"path": "FFmpeg 学习(五):FFmpeg 编解码 API 分析.md",
"chars": 4995,
"preview": "在上一篇文章 FFmpeg学习(四):FFmpeg API 介绍与通用 API 分析 中,我们简单的讲解了一下FFmpeg 的API基本概念,并分析了一下通用API,本文我们将分析 FFmpeg 在编解码时使用的API。\n\n## 一、FFm"
},
{
"path": "FFmpeg 学习(六):FFmpeg 核心模块 libavformat 与 libavcodec 分析.md",
"chars": 694,
"preview": "# 一、libavformat介绍\n\nlibavformat的主要组成与层次调用关系如下图:\n\n:FFmpeg API 介绍与通用 API 分析.md",
"chars": 2051,
"preview": "\n## 一、FFmpeg 编解码流程\n\nFFmpeg编解码流程图如下,此图包含了整体的解封装、编解码的基本流程。\n\n: AVFormatContext 分析.md",
"chars": 2058,
"preview": "在 FFmpeg 学习(六):FFmpeg 核心模块 libavformat 与 libavcodec 分析 中,我们分析了FFmpeg中最重要的两个模块以及重要的结构体之间的关系。\n\n后面的文章,我们先不去继续了解其他模块,先针对在之前的"
},
{
"path": "FFmpeg 结构体学习(七): AVIOContext 分析.md",
"chars": 8167,
"preview": "AVIOContext是FFMPEG管理输入输出数据的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。\n\n# 一、源码整理\n\n首先我们先看一下结构体AVIOContext的定义的结构体源码(位于libavformat/avio.h"
},
{
"path": "FFmpeg 结构体学习(三): AVPacket 分析.md",
"chars": 2858,
"preview": "AVPacket是存储压缩编码数据相关信息的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。\n\n# 一、源码整理\n\n首先我们先看一下结构体AVPacket的定义的结构体源码(位于libavcodec/avcodec.h):\n\n\n\n"
},
{
"path": "FFmpeg 结构体学习(二): AVStream 分析.md",
"chars": 5823,
"preview": "AVStream是存储每一个视频/音频流信息的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。\n\n# 一、源码整理\n\n首先我们先看一下结构体AVStream的定义的结构体源码(位于libavformat/avformat.h):\n"
},
{
"path": "FFmpeg 结构体学习(五): AVCodec 分析.md",
"chars": 10036,
"preview": "AVCodec是存储编解码器信息的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。\n\n# 一、源码整理\n\n首先我们先看一下结构体AVCodec的定义的结构体源码(位于libavcodec/avcodec.h):\n\n\n\n```\n/*"
},
{
"path": "FFmpeg 结构体学习(八):FFMPEG中重要结构体之间的关系.md",
"chars": 637,
"preview": "FFMPEG中结构体很多。最关键的结构体可以分成以下几类:\n\n### 解协议(http,rtsp,rtmp,mms)\n\nAVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。URLPro"
},
{
"path": "FFmpeg 结构体学习(六): AVCodecContext 分析.md",
"chars": 53902,
"preview": "AVCodecContext是包含变量较多的结构体(感觉差不多是变量最多的结构体)。下面我们来分析一下该结构体里重要变量的含义和作用。\n\n# 一、源码整理\n\n首先我们先看一下结构体AVCodecContext的定义的结构体源码(位于liba"
},
{
"path": "FFmpeg 结构体学习(四): AVFrame 分析.md",
"chars": 13836,
"preview": "AVFrame是包含码流参数较多的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。\n\n# 一、源码整理\n\n首先我们先看一下结构体AVFrame的定义的结构体源码(位于libavcodec/avcodec.h):\n\n\n\n```\n/*"
},
{
"path": "FFmpeg源码分析:内存管理系统.md",
"chars": 7594,
"preview": "FFmpeg有专门的内存管理系统,包括:内存分配、内存拷贝、内存释放。其中内存分配包含分配内存与对齐、内存分配与清零、分配指定大小的内存块、重新分配内存块、快速分配内存、分配指定最大值的内存、分配数组内存、快速分配数组内存、重新分配数组内存"
},
{
"path": "Linux上的ffmpeg完全使用指南.md",
"chars": 12723,
"preview": "**[ffmpeg](https://ffmpeg.org/)** 是一个处理媒体文件的命令行工具 (command line based) 。它是一个拥有非常多功能的框架,并且因为他是开源的,很多知名的工具如 VLC,YouTube, i"
},
{
"path": "README.md",
"chars": 32709,
"preview": "# 💯 2024年,最新 ffmpeg 资料整理,项目(调试可用),命令手册,文章,编解码论文,视频讲解,面试题全套资料\n\n</br>\n\n<p align=\"center\">\n<a> <img width=\"70%\" height=\"70%"
},
{
"path": "case_interview/001-README.md",
"chars": 14594,
"preview": "# <h3 id=\"subject_001\">面试题1</h3>\n\n为什么巨大的原始视频可以编码成很小的视频呢?这其中的技术是什么呢?\n\n##### 参考答案\n\n* 1)空间冗余:图像相邻像素之间有较强的相关性\n* 2)时间冗余:视频序列的"
},
{
"path": "case_interview/002-README.md",
"chars": 1295,
"preview": "# <h3 id=\"subject_051\">面试题51</h3>\n\n什么是GOP?\n\n##### 参考答案\n\nGOP ( Group of Pictures ) 是一组连续的画面,由一张 I 帧和数张 B / P 帧组成,是视频图像编码器"
},
{
"path": "ffmpeg常用命令.md",
"chars": 26472,
"preview": "# ffmpeg常用命令\n\n## `ffmpeg --help`大概分为6个部分,具体如下:\n\n- ffmpeg信息查询部分\n- 公共操作参数部分\n- 文件主要操作参数部分\n- 视频操作参数部分\n- 音频操作参数部分\n- 字母操作参数部分\n"
},
{
"path": "ffmpeg源码example解析之decode_audio.md",
"chars": 720,
"preview": "# 音频播放\n\n## 源码文件\n\n```\n<ffmpeg>/doc/examples/decode_audio.c\n<ffmpeg>/doc/examples/muxing.c\n<ffmpeg>/doc/examples/resamplin"
},
{
"path": "ffmpeg源码example解析之decode_video.md",
"chars": 1586,
"preview": "# 视频解码流程\n\n## 源码文件\n\n```\n<ffmpeg>/doc/examples/decode_video.c\n```\n\n## 代码调用流程\n\n[\r\n#include <sys/types.h>\r\n#include <sys/timeb.h>\r\n#inclu"
},
{
"path": "ffplay源码和书籍/ffplay/ffplay.dsp",
"chars": 5476,
"preview": "# Microsoft Developer Studio Project File - Name=\"ffplay\" - Package Owner=<4>\r\n# Microsoft Developer Studio Generated Bu"
},
{
"path": "ffplay源码和书籍/ffplay/ffplay.vcxproj",
"chars": 7793,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.micro"
},
{
"path": "ffplay源码和书籍/ffplay/ffplay.vcxproj.filters",
"chars": 3170,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbui"
},
{
"path": "ffplay源码和书籍/ffplay/libavcodec/allcodecs.c",
"chars": 533,
"preview": "#include \"avcodec.h\"\r\n\r\n/************************************************************************/\r\n/* ע/ʼѱӦڲʶ */\r\n/***"
},
{
"path": "ffplay源码和书籍/ffplay/libavcodec/avcodec.h",
"chars": 5352,
"preview": "#ifndef AVCODEC_H\r\n#define AVCODEC_H\r\n\r\n/*\r\n** ʹõĺꡢݽṹͺͨЩꡢݽṹͺڴģȫЧ\r\n*/\r\n#ifdef __cplusplus\r\nextern \"C\"\r\n{\r\n#endif\r\n\r\n#incl"
},
{
"path": "ffplay源码和书籍/ffplay/libavcodec/dsputil.c",
"chars": 556,
"preview": "/************************************************************************/\r\n/* dsp ŻʹõIJұʵʼ */\r\n/*************"
},
{
"path": "ffplay源码和书籍/ffplay/libavcodec/dsputil.h",
"chars": 334,
"preview": "#ifndef DSPUTIL_H\r\n#define DSPUTIL_H\r\n\r\n/************************************************************************/\r\n/* "
},
{
"path": "ffplay源码和书籍/ffplay/libavcodec/imgconvert.c",
"chars": 48075,
"preview": "/************************************************************************/\r\n/* 岢ʵͼɫռתʹõĺͺ "
},
{
"path": "ffplay源码和书籍/ffplay/libavcodec/imgconvert_template.h",
"chars": 22547,
"preview": "#ifndef RGB_OUT\r\n#define RGB_OUT(d, r, g, b) RGBA_OUT(d, r, g, b, 0xff)\r\n#endif\r\n\r\n/************************************"
},
{
"path": "ffplay源码和书籍/ffplay/libavcodec/msrle.c",
"chars": 8439,
"preview": "/*\r\n** ļʵг̳ѹ㷨\r\n*/\r\n#include <stdio.h>\r\n#include <stdlib.h>\r\n#include <string.h>\r\n\r\n#include \"../libavutil/common.h\"\r\n#i"
},
{
"path": "ffplay源码和书籍/ffplay/libavcodec/truespeech.c",
"chars": 9883,
"preview": "/************************************************************************/\r\n/* ļʵ truespeed Ƶ "
},
{
"path": "ffplay源码和书籍/ffplay/libavcodec/truespeech_data.h",
"chars": 4826,
"preview": "#ifndef __TRUESPEECH_DATA__\r\n#define __TRUESPEECH_DATA__\r\n\r\n/***********************************************************"
},
{
"path": "ffplay源码和书籍/ffplay/libavcodec/utils_codec.c",
"chars": 9427,
"preview": "/************************************************************************/\r\n/* ʹõİߺ "
},
{
"path": "ffplay源码和书籍/ffplay/libavformat/allformats.c",
"chars": 478,
"preview": "/*\r\n** ע/ʼӦЭ飬ļʽӦڲ\r\n*/\r\n#include \"avformat.h\"\r\n\r\nextern URLProtocol file_protocol;\r\n\r\n/* עֵ֧ĸʽ */\r\nvoid av_register_all("
},
{
"path": "ffplay源码和书籍/ffplay/libavformat/avformat.h",
"chars": 6269,
"preview": "#ifndef AVFORMAT_H\r\n#define AVFORMAT_H\r\n\r\n/*************************************************\r\n** ʶļʽýͿʹõĺꡢݽṹͺ\r\n**ͨЩꡢݽṹͺڴ"
},
{
"path": "ffplay源码和书籍/ffplay/libavformat/avidec.c",
"chars": 23214,
"preview": "/*\r\n** AVI ļغעЩطЩԴ롣\r\nע 1AVI ļýִŷʽǽ֯źͽ֯š֯žƵ֡Ϊ\r\nСλţƵཻ֡֯һ𣬲Ҵŵļûر涨ǽ֯žǰ\r\nһý֡һ𣬷ǽ֯ŵ avi ļ١\r\nע 2AVI ļṹ AVIINDEXENTRY е dwChunkOf"
},
{
"path": "ffplay源码和书籍/ffplay/libavformat/avio.c",
"chars": 2733,
"preview": "/************************************************************************\r\n** ļʵ URLProtocol ļ\r\n** URLProtocol ǵײļ(file"
},
{
"path": "ffplay源码和书籍/ffplay/libavformat/avio.h",
"chars": 3305,
"preview": "#ifndef AVIO_H\r\n#define AVIO_H\r\n\r\n/*\r\n** ļдģ鶨ݽṹͺ\r\n*/\r\n\r\n#define URL_EOF (-1)\r\n\r\ntypedef int64_t offset_t;\r\n\r\n/* ļʵȨĶ */"
},
{
"path": "ffplay源码和书籍/ffplay/libavformat/aviobuf.c",
"chars": 7285,
"preview": "/*\r\n** лĹļ ByteIOContext صļ\r\n** ByteIOContextURLContextIJͬڣByteIOContextǴģByteIOContextIJǻڻĶǻļ\r\n** URLContextȡݽByteIOConte"
},
{
"path": "ffplay源码和书籍/ffplay/libavformat/cutils.c",
"chars": 672,
"preview": "/*\r\n** ַIJ\r\n*/\r\n\r\n#include \"avformat.h\"\r\n\r\n/*\r\n** str ַ val ַָʾͷȥͷ*ptr \r\n*/\r\nint strstart(const char *str, const char *v"
},
{
"path": "ffplay源码和书籍/ffplay/libavformat/file.c",
"chars": 1768,
"preview": "/*\r\n** ffplay file rtsprtptcp ЭһЭ飬 file:ǰʾ file Э顣\r\n** URLContext ṹͳһʾЩϵЭ飬ṩͳһijӿڡ\r\n** ĹЭʵļʵ URLContext ӿڡļʵ file Э URL"
},
{
"path": "ffplay源码和书籍/ffplay/libavformat/utils_format.c",
"chars": 7697,
"preview": "/*\r\n** ʶļʽýʽʹõһЩຯ\r\n*/\r\n#include \"../berrno.h\"\r\n#include \"avformat.h\"\r\n#include <assert.h>\r\n\r\n#define UINT_MAX (0xffffff"
},
{
"path": "ffplay源码和书籍/ffplay/libavutil/avutil.h",
"chars": 2016,
"preview": "#ifndef AVUTIL_H\r\n#define AVUTIL_H\r\n\r\n#ifdef __cplusplus\r\nextern \"C\"\r\n{\r\n#endif\r\n\r\n#include \"common.h\"\r\n#include \"bswap."
},
{
"path": "ffplay源码和书籍/ffplay/libavutil/bswap.h",
"chars": 754,
"preview": "/************************************************************************/\r\n/* ֽ˳ "
},
{
"path": "ffplay源码和书籍/ffplay/libavutil/common.h",
"chars": 1614,
"preview": "\r\n/************************************************************************/\r\n/* õͺͺ "
},
{
"path": "ffplay源码和书籍/ffplay/libavutil/mathematics.h",
"chars": 161,
"preview": "#ifndef MATHEMATICS_H\r\n#define MATHEMATICS_H\r\n\r\n/* */\r\nstatic inline int64_t av_rescale(int64_t a, int64_t b, int64_t c"
},
{
"path": "ffplay源码和书籍/ffplay/libavutil/rational.h",
"chars": 495,
"preview": "/************************************************************************/\r\n/* "
},
{
"path": "ffplay源码和书籍/ffplay/update.txt",
"chars": 42,
"preview": "ӭ mcodec.cnblogs.com \r\nϵ tslking@tom.com"
},
{
"path": "iOS资料/AVFoundation之视频捕捉.md",
"chars": 6187,
"preview": "# AVFoundation之视频捕捉\r\n\r\n## 1.概念\r\n\r\n### 1.1 捕捉会话\r\n\r\nAV Foundation 捕捉栈核心类是AVCaptureSession。一个捕捉会话相当于一个虚拟的“插线板”。用于连接输入和输出的资源"
},
{
"path": "iOS资料/IOS 剪辑编辑器.md",
"chars": 8445,
"preview": "# IOS 剪辑编辑器\r\n\r\n最近这两年视频剪辑非常火,很多APP都内置了视频剪辑功能。\r\n\r\nIOS视频剪辑主要依赖AVFoundation实现。\r\n\r\n## 1、AVMutableComposition \r\n\r\n视频剪辑需要创建一个工程"
},
{
"path": "iOS资料/IOS之多媒体API.md",
"chars": 12545,
"preview": "# IOS之多媒体API\r\n\r\n## 1、播放视频\r\n\r\n**视频文件介绍**\r\n\r\n视频格式可以分为适合本地播放的本地影像视频和适合在网络中播放的网络流媒体影像视频两大类。尽管后者在播放的稳定性和播放画面质量上可能没有前者优秀,但网络流媒"
},
{
"path": "iOS资料/MACiOS利用FFmpeg解析音视频数据流.md",
"chars": 10507,
"preview": "# MAC/iOS利用FFmpeg解析音视频数据流\r\n\r\n## 1.简易流程\r\n\r\n**使用流程**\r\n\r\n- 初始化解析类: `- (instancetype)initWithPath:(NSString *)path;`\r\n- 开始解析"
},
{
"path": "iOS资料/iOS - 图形高级处理 (一、图片显示相关理论).md",
"chars": 6828,
"preview": "# iOS - 图形高级处理 (一、图片显示相关理论)\r\n\r\n## 1、图片从磁盘中读入到显示到屏幕全过程\r\n\r\n### 1.1图片的加载过程:\r\n\r\n- 使用 +imageWithContentsOfFile: 方法从磁盘中加载一张图片或"
},
{
"path": "iOS资料/iOS AVDemo(5):音频解码.md",
"chars": 22744,
"preview": "# iOS AVDemo(5):音频解码\r\n\r\niOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对[音视频基础概念知识](https://mp.weixin.qq.com/mp/appmsgalbum?__b"
},
{
"path": "iOS资料/iOS AVDemo(6):音频渲染.md",
"chars": 22127,
"preview": "# iOS AVDemo(6):音频渲染\r\n\r\niOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对[音视频基础概念知识](https://mp.weixin.qq.com/mp/appmsgalbum?__b"
},
{
"path": "iOS资料/iOS AVDemo(7):视频采集.md",
"chars": 25804,
"preview": "# iOS AVDemo(7):视频采集\r\n\r\niOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对[音视频基础概念知识](https://mp.weixin.qq.com/mp/appmsgalbum?__b"
},
{
"path": "iOS资料/iOS AVDemo(8):视频编码,H.264 和 H.265 都支持.md",
"chars": 32399,
"preview": "# iOS AVDemo(8):视频编码,H.264 和 H.265 都支持\r\n\r\niOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对[音视频基础概念知识](https://mp.weixin.qq.com/"
},
{
"path": "iOS资料/iOS AVDemo(9):视频封装,采集编码 H.264H.265 并封装 MP4.md",
"chars": 13058,
"preview": "# iOS AVDemo(9):视频封装,采集编码 H.264/H.265 并封装 MP4\r\n\r\niOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对[音视频基础概念知识](https://mp.weixin."
},
{
"path": "iOS资料/iOS AVDemo:音频封装,采集编码并封装为 M4A.md",
"chars": 29334,
"preview": "# iOS AVDemo:音频封装,采集编码并封装为 M4A\r\n\r\niOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对[音视频基础概念知识](https://mp.weixin.qq.com/mp/appms"
},
{
"path": "iOS资料/iOS AVDemo:音频编码,采集 PCM 数据编码为 AAC.md",
"chars": 25257,
"preview": "# iOS AVDemo:音频编码,采集 PCM 数据编码为 AAC\r\n\r\niOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对[音视频基础概念知识](https://mp.weixin.qq.com/mp/a"
},
{
"path": "iOS资料/iOS AVDemo:音频解封装,从 MP4 中解封装出 AAC.md",
"chars": 30293,
"preview": "# iOS AVDemo:音频解封装,从 MP4 中解封装出 AAC\r\n\r\niOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对[音视频基础概念知识](https://mp.weixin.qq.com/mp/a"
},
{
"path": "iOS资料/iOS AVDemo:音频采集.md",
"chars": 20022,
"preview": "# iOS AVDemo:音频采集\r\n\r\niOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对[音视频基础概念知识](https://mp.weixin.qq.com/mp/appmsgalbum?__biz="
},
{
"path": "iOS资料/iOS Runtime详解.md",
"chars": 25499,
"preview": "# iOS Runtime详解\r\n\r\nRuntime的特性主要是消息(`方法`)传递,如果消息(`方法`)在对象中找不到,就进行转发,具体怎么实现的呢。我们从下面几个方面探寻Runtime的实现机制。\r\n\r\n- Runtime介绍\r\n- R"
},
{
"path": "iOS资料/iOS 入门(2):管理第三方库.md",
"chars": 3357,
"preview": "# iOS 入门(2):管理第三方库\r\n\r\n## **1、安装 CocoaPods**\r\n\r\n代码复用是提高工程开发效率的重要方法,使用第三方库就是一种普遍的方式。在 iOS 开发中使用最广泛的管理第三方库的方案就是使用 CocoaPods"
},
{
"path": "iOS资料/iOS 离屏渲染探究.md",
"chars": 10165,
"preview": "# iOS 离屏渲染探究\r\n\r\n## 1.为什么要理解离屏渲染\r\n\r\n离屏渲染(Offscreen rendering)对iOS开发者来说不是一个陌生的东西,项目中或多或少都会存在离屏渲染,也是面试中经常考察的知识点。一般来说,大多数人都能"
},
{
"path": "iOS资料/iOS 系统架构及常用框架.md",
"chars": 2108,
"preview": "# iOS 系统架构及常用框架\r\n\r\n## 1、ios稳定性\r\n\r\niOS基于UNIX系统,因此从系统的稳定性上来说它要比其他操作系统的产品好很多\r\n\r\n## 2、ios系统架构\r\n\r\niOS的系统架构分为四层,由上到下一次为:可触摸层(C"
},
{
"path": "iOS资料/iOS-WebRTC静态库,framework下载、编译,使用.md",
"chars": 5789,
"preview": "# iOS-WebRTC静态库,framework下载、编译,使用\r\n\r\n网上的对于WebRTC的下载和编译的文章其实已经很多,但是有些比较久远,里面很多方法都无法再使用,所以写一篇文章来简单的说下当前的一些使用方法和注意事项。\r\n\r\n##"
},
{
"path": "iOS资料/iOSAVDemo(10):视频解封装,从 MP4 解出 H.264H.265.md",
"chars": 13795,
"preview": "# iOSAVDemo(10):视频解封装,从 MP4 解出 H.264/H.265\r\n\r\n\r\niOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对[音视频基础概念知识](https://mp.weixin.q"
},
{
"path": "iOS资料/iOS下 WebRTC 视频渲染.md",
"chars": 6366,
"preview": "# iOS下 WebRTC 视频渲染\r\n\r\n## 1、前言\r\n\r\n今天为大家介绍一下 iOS 下 WebRTC是如何渲染视频的。在iOS中有两种加速渲染视频的方法。一种是使用OpenGL;另一种是使用 Metal。\r\n\r\nOpenGL的好处"
},
{
"path": "iOS资料/iOS下的渲染框架.md",
"chars": 5102,
"preview": "# iOS下的渲染框架\r\n\r\n## 1.图形渲染框架\r\n\r\niOS APP图形渲染框架,APP在显示可视化的图形时,使用到了Core Animation、Core Graphics、Core Image等框架,这些框架在渲染图形时,都需要通"
},
{
"path": "iOS资料/iOS使用AVPlayer,播放本地,在线音频",
"chars": 6862,
"preview": "**AVPlayer**属于AVFoundation框架,不仅能够播放音频,还可以播放视频,支持本地和网链,更加接近底层,定制也更加灵活。\n\n为什么要写这篇文章呢?其因有二:\n\n- 1、github上有很多播放音频的优秀三方的框架,很方便,"
},
{
"path": "iOS资料/iOS动画系列之三:Core Animation.md",
"chars": 3886,
"preview": "# iOS动画系列之三:Core Animation\r\n\r\n## 1. 介绍\r\n\r\n- Core Animation是一个非常强大的动画处理 API,使用它能做出非常绚丽的动画效果,而且往往是事半功倍,也就是说,使用少量的代码就可以实现非"
},
{
"path": "iOS资料/iOS图像渲染及卡顿问题优化.md",
"chars": 7858,
"preview": "# iOS图像渲染及卡顿问题优化\r\n\r\n## 1.基本知识\r\n\r\n下面来看下GPU和CPU的基本概念:\r\n\r\n- **CPU(Central Processing Unit)**:系统的运算和控制单元,是信息处理、程序执行的最终执行单元。C"
},
{
"path": "iOS资料/iOS学习音视频的过程.md",
"chars": 2163,
"preview": "# iOS:学习音视频的过程\r\n\r\n## 1.音视频学习中涉及到的概念\r\n\r\n1.我们常见的音视频格式有.mp4,mkv.avi,正如我们常见的.word 需要word 工具打开,不同格式的音视频也需要不同格式的播放器打开,这种视频格式相当"
},
{
"path": "iOS资料/iOS拉取SRS流媒体服务器的Rtc流.md",
"chars": 1805,
"preview": "# iOS拉取SRS流媒体服务器的Rtc流\r\n\r\n## 1、搭建flutter环境\r\n\r\n已经有的可以跳过\r\n安装教程:https://flutter.cn/docs/get-started/install/macos\r\n1.下载以下安装包"
},
{
"path": "iOS资料/iOS短视频篇:音视频编辑之音视频合成,添加水印及音视频导出.md",
"chars": 8994,
"preview": "# iOS短视频篇:音视频编辑之音视频合成,添加水印及音视频导出\r\n\r\n## 1.基本介绍\r\n\r\n音视频编辑主要依靠AVFoundation框架,首先要有一个AVMutableComposition对象composition,一个compo"
},
{
"path": "iOS资料/iOS硬编解码相关知识.md",
"chars": 9440,
"preview": "# iOS硬编解码相关知识\r\n\r\n## 1、软编与硬编概念\r\n\r\n**1、软编码:使用CPU进行编码。**\r\n\r\n实现直接、简单,参数调整方便,升级易,但CPU负载重,性能较硬编码低,低码率下质量通常比硬编码要好一点。\r\n\r\n**2、硬编码"
},
{
"path": "iOS资料/iOS视图渲染与性能优化.md",
"chars": 7118,
"preview": "# iOS视图渲染与性能优化\r\n\r\n## 1、视图渲染\r\n\r\n视图渲染的处理层级图如下:\r\n \r\n- 增加编码效率(将编码一帧的时间缩短)\r\n- 延长电量使用(耗电量大大降低)\r\n\r\n**Video"
},
{
"path": "iOS资料/iOS音视频开发-采集、编码、滤镜.md",
"chars": 4938,
"preview": "# iOS音视频开发-采集、编码、滤镜\r\n\r\n## 1.OpenGL(绘制点 线 三角形)\r\n\r\n**OpenGL 是⼀种图形编程接口(Application Programming Interface, API).简单理解就是开发的图形库"
},
{
"path": "iOS资料/iOS音视频开发——FFmpeg库编译.md",
"chars": 2375,
"preview": "# iOS音视频开发——FFmpeg库编译\r\n\r\n## 1.安装 Homebrew\r\n\r\n**Homebrew:**是 Mac 平台上的一个包管理工具,提供了许多 Mac 下没有的 Linux工具等,\r\n而且安装工具极其简单,一句命令行的事"
},
{
"path": "iOS资料/iOS音视频开发——视频采集.md",
"chars": 11813,
"preview": "# iOS音视频开发——视频采集\r\n\r\n## 1.认识 AVCapture 系列\r\n\r\nAVCapture 系列是 AVFoundation 框架为我们提供的用于管理输入设备、采集、输出、预览等一系列接口,其工作原理如下:\r\n\r\n:现代计算机的三大核心部分之一,作为整个系统的运算和控制单元。CPU 内部的流水线结构使其拥有一定程度的并行计算能力。\r\n- G"
},
{
"path": "iOS资料/【如何快速的开发一个完整的iOS直播app】(美颜篇).md",
"chars": 7711,
"preview": "# 【如何快速的开发一个完整的iOS直播app】(美颜篇)\r\n\r\n## 1、前言\r\n\r\n在看这篇之前,如果您还不了解直播原理,请查看这篇文章[如何快速的开发一个完整的iOS直播app(原理篇)](https://www.jianshu.co"
},
{
"path": "iOS资料/关于iOS离屏渲染的深入研究.md",
"chars": 7577,
"preview": "# 关于iOS离屏渲染的深入研究\r\n\r\n在平时的iOS面试中,我们经常会考察有关离屏渲染(Offscreen rendering)的知识点。一般来说,绝大多数人都能答出“圆角、mask、阴影会触发离屏渲染”,但是也仅止于此。如果再问得深入哪"
},
{
"path": "iOS资料/基于 AVFoundation 框架开发小视频功能的方案解析.md",
"chars": 5254,
"preview": "# 基于 AVFoundation 框架开发小视频功能的方案解析\r\n\r\n开发视频录制功能最简单的就是使用系统封装的 UIImagePickerController,但是这种方式比较封闭,可自定义东西比较少,所以就需要基于 AVFoundat"
},
{
"path": "iOS资料/最简单的基于FFmpeg的移动端例子:IOS HelloWorld.md",
"chars": 26185,
"preview": "# 最简单的基于FFmpeg的移动端例子:IOS HelloWorld\r\n\r\n本文记录IOS平台下基于FFmpeg的HelloWorld程序。该示例C语言的源代码来自于《最简单的基于FFMPEG的Helloworld程序》。相关的概念就不再"
},
{
"path": "iOS资料/视频直播iOS端技术.md",
"chars": 2902,
"preview": "# 视频直播iOS端技术\r\n\r\n直播架构\r\n\r\n 想必了解过直播的人都清楚直播主要分为3部分:推流->流媒体服务器->拉流。\r\n\r\n\r\n\r\n"
},
{
"path": "iOS资料/音视频学习--iOS适配H265实战踩坑记.md",
"chars": 5890,
"preview": "# 音视频学习--iOS适配H265实战踩坑记\r\n\r\n## 1.背景介绍\r\n\r\n熟悉webrtc都知道:谷歌的webrtc,默认不支持h265,毕竟涉及到很多专利的事宜,这中间的八卦就暂时不做探究。但是今天拿到一个IPC,该设备会发送H26"
},
{
"path": "paper/README.md",
"chars": 1,
"preview": "\n"
},
{
"path": "teaching video/video.md",
"chars": 1,
"preview": "\n"
},
{
"path": "使用FFMpeg进行H264编码.c",
"chars": 3819,
"preview": "/**\n使用FFMpeg可以很方便的对音视频进行编码,并且写文件。\n\n下面的代码是将5幅1280*720大小的图片进行编码,并且写到文件中。\n\n代码有些乱,但希望能抛砖引玉,对学习这方面的朋友有帮助。\n*/\n\n\nCFile file[5];"
}
]
// ... and 26 more files (download for full content)
About this extraction
This page contains the full source code of the 0voice/ffmpeg_develop_doc GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 147 files (1.0 MB), approximately 393.5k tokens, and a symbol index with 208 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.