This is my study note of FFMPEG.
Basic structure
1、AVCodeContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| typedef struct AVCodecContext { int bit_rate; int frame_number; unsigned char *extradata; int extradata_size; int width, height; enum PixelFormat pix_fmt; int sample_rate; int channels; int bits_per_sample; int block_align; struct AVCodec *codec; void *priv_data; int(*get_buffer)(struct AVCodecContext *c, AVFrame *pic); void(*release_buffer)(struct AVCodecContext *c, AVFrame *pic); int(*reget_buffer)(struct AVCodecContext *c, AVFrame *pic); }AVCodecContext;
|
2、AVFilter
- AVFilter可以看作是一对的avfilter节点链结组成
- AVFilter Graph可以看作为链的管理者
- 每个avfilter节点都会对数据进行处理,处理结束后发送到下个结点
- 第一个节点音视频名称为buffer/abuffer,最后一个节点名称为buffersink/abuffersink
- 至少包括两个节点
1 2 3 4 5 6 7 8 9 10 11
| avfilter_get_by_name(); avfilter_inout_alloc(); int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt, const char *name, const char *args, void *opaque, AVFilterGraph *graph_ctx); int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters, AVFilterInOut **inputs, AVFilterInOut **outputs, void *log_ctx); avfilter_graph_config
|
3、av_bitstream_filter
将文件分为音频和视频,最简单的操作就是将avpacket直接存储,但是面对某些格式文件,例如MP4等,我们还需要对
avpackage进行一部分操作,以MP4分离h264为例,我们需要对每个avpackage添加SPS、PPS等信息,并且将avpackage
首四个字节数据替换为0x0001。
1 2 3
| av_bitstream_filter_init(); av_bitstream_filter_filter(); av_bitstream_filter_close();
|
- 每个AVPacket中的数据(data字段)经过bitstream filter“过滤”一遍
Uncommon parameters
1、AVRational
1 2 3 4
| typedef struct AVRational{ int num; int den; } AVRational
|
- 时间刻度为num/den,以25帧为例,num = 1, den = 25
2、Paramers
- GOP 指的就是两个I帧之间的间隔
- max_b_frames设置相邻两个非B帧之间最多出现的B帧数量
- pts显示时间戳,第n帧的pts = n * ((1 / timbase)/ fps)
3、av_image_alloc
1
| int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align);
|
- pointers[4]:保存图像通道的地址。如果是RGB,则前三个指针分别指向R,G,B的内存地址。第四个指针保留不⽤
- linesizes[4]:保存图像每个通道的内存对齐的步长,即一行的对齐内存的宽度,此值大小等于图像宽度
3、av_parser_parse2
1 2 3 4 5
| int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, uint8_t **poutb uf, int *poutbuf_size, const uint8_t *buf, int buf_size, int64_t pts, int64_t dts, int64_t pos)
|
- 拿到AVPaket数据,将一个个AVPaket数据解析组成完整的一帧未解码的压缩数据
4、avpicture_fill
1 2
| int avpicture_fill(AVPicture *picture, const uint8_t *ptr, enum AVPixelFormat pix_fmt, int width, int height)
|
- 将ptr的数据给予picture,但是不是进行拷贝工作,而是将picture的指针指向ptr
5、Avframe::data[4]
对于planar模式的YUV:
- data[0]指向Y分量的开始位置
- data[1]指向U分量的开始位置
- data[2]指向V分量的开始位置
对于packed模式YUV:
- data[0]指向数据的开始位置
- data[1]和data[2]都为NULL
6、avpicture_get_size
1
| av_image_fill_arrays(pictureYUV->data, pictureYUV->linesize, buffer_YUV, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height,1);
|
- 是一个函数,用于计算给定图像的大小(以字节为单位),以便在分配足够的内存来存储该图像。
7、av_find_best_stream
以前没有av_find_best_stream时,寻找stream操作如下:
1 2 3 4 5 6 7
| for(int i=0; i< 100; i++) { if(pformat->stream[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) vedio_index = i; if(pformat->stream[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) audio_index = i; }
|
打开媒体格式上下文后,如果输出媒体格式有 AVFMT_GLOBALHEADER 这个标记,那么音视频编码器创建的时候也需要设置 AV_CODEC_FLAG_GLOBAL_HEADER 标记。
1 2 3
| if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
9、AVFMT_NOFILE
- 根据该值是否为AVFMT_NOFILE,决定是否通过avio_open打开
1 2
| if (!(ofmt_a->flags & AVFMT_NOFILE)) // 此时根据ofmt_a->flags与AVFMT_NOFILE想与的结果判断是否开启
|
10、av_rescale_q_rnd
1
| int64_t av_rescale_q_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd);
|
- 计算 “a * b / c” 的值并分五种方式来取整
- a 表式要换算的值,b 表式原来的时间基,c表示要转换的时间基
11、codec_tag
- 若AVStream->codecpar->codec_tag有值,则会校验AVStream->codecpar->codec_tag是否在封装格式支持的codec_tag列表中,若不在,就会打印错误信息
- 若AVStream->codecpar->codec_tag为0,则会根据AVCodecID从封装格式的codec_tag列表中,找一个匹配的codec_tag