ffmpeg源码分析--3.avformat_alloc_context与avformat_open_input
来源:互联网 发布:流浪诗人知乎 编辑:程序博客网 时间:2024/06/01 09:32
一. avformat_alloc_context
1.1 在./libavformat/options.c中
为AVFormatContext分配内存并初始化
二. avformat_open_init
2.1 avformat_open_init总体分析
在libavformat/utils.c中
avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
{
1. avformat_alloc_context ::分配一个AVFormatContext结构体
2.init_input(s, filename, &tmp);
--> av_probe_input_format2 ::没有打开媒体文件之前的probe
-->s->io_open ::打开媒体文件
-->io_open_default
-->ffio_open_whitelist
-->ffurl_alloc
-->url_find_protocol (file protocol)
-->url_alloc_for_protocol
-->ffurl_connect ::uc->prot->url_open
-->file_open
-->avpriv_open ::即调用系统的open
-->av_probe_input_buffer2 ::打开媒体文件之后的probe
--> avio_read ::s->read_packet
--> ffurl_read
--> file_read ::即调用系统的read
-->av_probe_input_format2
--> av_probe_input_format3
--> matroska_probe
--> mov_probe
3.s->iformat->read_header(s) ::读取媒体文件中的信息并分析
--> mov_read_header
}
2.2代码分析
2.2.1 avformat_open_input
--> init_input
说明:
a.av_probe_input_format2 时score=25,probe出来的probe_score=0,
probe_scoreiformat=NULL
b. av_probe_input_buffer2中也调用了av_probe_input_format2只不过中间的参数is_opened是1
说明文件己被打开
2.2.2
avformat_open_input
--> init_input
--> av_probe_input_buffer2
2.2.3
avformat_open_input
--> init_input
--> av_probe_input_buffer2
-->av_probe_input_format3
s->iformat->name=mov,mp4,m4a,3gp,3g2,mj2
s->iformat->name=matroska,webm
三. 媒体文件的读写
3.1 媒体文件的打开过程
avformat_open_input
init_input
--> s->io_open
-->io_open_default ::libavformat/options.c
--> ffio_open_whitelist ::libavformat/aviobuf.c
--> ffurl_open_whitelist ::libavformat/avio.c
-->ffurl_connect ::libavformat/avio.c
--> file_open ::libavformat/file.c
AVFormatContext s;
s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)
3.2代码分析
3.2.1 avio层
3.2.2 avio层
注:ffmpeg所支持的所有的protocol都在libavformat/Makefile中以CONFIG_XXX_PROTOCOL标志
3.2.3 avio层
3.2.4 这就到了protocol层
libavformat/file.c
3.3 媒体文件的读过程
3.3.1 读写函数的初始化过程
ffio_open_whitelist ::libavformat/aviobuf.c
ffio_fdopen 初始代读写函数 ::libavformat/aviobuf.c
avio_alloc_context ::libavformat/aviobuf.c
ffio_init_context ::libavformat/aviobuf.c
ffio_init_context ::libavformat/aviobuf.c
s->write_packet = write_packet; :: ffurl_write 终于找到了
s->read_packet = read_packet; :: ffurl_read
3.3.2 读写函数的调用过程
av_probe_input_buffer2 ::libavformat/format.c
avio_read ::libavformat/aviobuf.c ::ffmpeg提供的read接口
s->read_packet
ffurl_read ::libavformat/avio.c
retry_transfer_wrapper ::libavformat/avio.c
1.1 在./libavformat/options.c中
- AVFormatContext *avformat_alloc_context(void)
- {
- AVFormatContext *ic;
- ic = av_malloc(sizeof(AVFormatContext)); //为AVFormatContex分配内存
- avformat_get_context_defaults(ic); //下面就是一些初始化的操作
- ic->internal = av_mallocz(sizeof(*ic->internal));
- if (!ic->internal) {
- avformat_free_context(ic);
- return NULL;
- }
- ic->internal->offset = AV_NOPTS_VALUE;
- ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
- return ic;
- }
二. avformat_open_init
2.1 avformat_open_init总体分析
在libavformat/utils.c中
avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
{
1. avformat_alloc_context ::分配一个AVFormatContext结构体
2.init_input(s, filename, &tmp);
--> av_probe_input_format2 ::没有打开媒体文件之前的probe
-->s->io_open ::打开媒体文件
-->io_open_default
-->ffio_open_whitelist
-->ffurl_alloc
-->url_find_protocol (file protocol)
-->url_alloc_for_protocol
-->ffurl_connect ::uc->prot->url_open
-->file_open
-->avpriv_open ::即调用系统的open
-->av_probe_input_buffer2 ::打开媒体文件之后的probe
--> avio_read ::s->read_packet
--> ffurl_read
--> file_read ::即调用系统的read
-->av_probe_input_format2
--> av_probe_input_format3
--> matroska_probe
--> mov_probe
3.s->iformat->read_header(s) ::读取媒体文件中的信息并分析
--> mov_read_header
}
2.2代码分析
2.2.1 avformat_open_input
--> init_input
- static int init_input(AVFormatContext *s, const char *filename, AVDictionary **options)
- {
- int ret;
- AVProbeData pd = { filename, NULL, 0 };
- int score = AVPROBE_SCORE_RETRY;
- if (s->pb) { //如果用户指定了必须使用哪个iformat则进入下面的流程
- ... //这儿略过
- return 0;
- }
- if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
- (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
- return score;
- if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
- return ret;
- if (s->iformat)
- return 0;
- return av_probe_input_buffer2(s->pb, &s->iformat, filename, s, 0, s->format_probesize);
- }
a.av_probe_input_format2 时score=25,probe出来的probe_score=0,
probe_scoreiformat=NULL
b. av_probe_input_buffer2中也调用了av_probe_input_format2只不过中间的参数is_opened是1
说明文件己被打开
2.2.2
avformat_open_input
--> init_input
--> av_probe_input_buffer2
- int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt,
- const char *filename, void *logctx,
- unsigned int offset, unsigned int max_probe_size)
- {
- AVProbeData pd = { filename ? filename : "" };
- uint8_t *buf = NULL;
- int ret = 0, probe_size, buf_offset = 0;
- int score = 0;
- int ret2;
- if (!max_probe_size)
- max_probe_size = PROBE_BUF_MAX;
- else if (max_probe_size < PROBE_BUF_MIN) {
- av_log(logctx, AV_LOG_ERROR,
- "Specified probe size value %u cannot be < %u\n", max_probe_size, PROBE_BUF_MIN);
- return AVERROR(EINVAL);
- }
- if (offset >= max_probe_size)
- return AVERROR(EINVAL);
- if (pb->av_class) {
- uint8_t *mime_type_opt = NULL;
- char *semi;
- av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type_opt);
- pd.mime_type = (const char *)mime_type_opt;
- semi = pd.mime_type ? strchr(pd.mime_type, ';') : NULL;
- if (semi) {
- *semi = '\0';
- }
- }
- for (probe_size = PROBE_BUF_MIN; probe_size <= max_probe_size && !*fmt;
- probe_size = FFMIN(probe_size << 1,
- FFMAX(max_probe_size, probe_size + 1))) {
- score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0;
- //分配内存为读取媒体文件的内容作准备
- av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE);
- //读取媒体文件的内容作,就是一个调用read的过程
- avio_read(pb, buf + buf_offset, probe_size - buf_offset);
- buf_offset += ret;
- if (buf_offset < offset)
- continue;
- pd.buf_size = buf_offset - offset;
- pd.buf = &buf[offset];
- memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE);
- /* Guess file format. */
- *fmt = av_probe_input_format2(&pd, 1, &score); //对媒体文件的内容进行probe看是属于哪个类型
- if (*fmt) {
- /* This can only be true in the last iteration. */
- if (score <= AVPROBE_SCORE_RETRY) {
- av_log(logctx, AV_LOG_WARNING,
- "Format %s detected only with low score of %d, "
- "misdetection possible!\n", (*fmt)->name, score);
- } else
- av_log(logctx, AV_LOG_DEBUG,
- "Format %s probed with size=%d and score=%d\n",
- (*fmt)->name, probe_size, score);
- }
- }
- if (!*fmt)
- ret = AVERROR_INVALIDDATA;
- fail:
- /* Rewind. Reuse probe buffer to avoid seeking. */
- ret2 = ffio_rewind_with_probe_data(pb, &buf, buf_offset);
- if (ret >= 0)
- ret = ret2;
- av_freep(&pd.mime_type);
- return ret < 0 ? ret : score;
- }
avformat_open_input
--> init_input
--> av_probe_input_buffer2
-->av_probe_input_format3
- AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened,
- int *score_ret)
- {
- AVProbeData lpd = *pd;
- AVInputFormat *fmt1 = NULL, *fmt;
- int score, score_max = 0;
- const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE];
- enum nodat {
- NO_ID3,
- ID3_ALMOST_GREATER_PROBE,
- ID3_GREATER_PROBE,
- ID3_GREATER_MAX_PROBE,
- } nodat = NO_ID3;
- if (!lpd.buf)
- lpd.buf = (unsigned char *) zerobuffer;
- if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) {
- int id3len = ff_id3v2_tag_len(lpd.buf);
- if (lpd.buf_size > id3len + 16) {
- if (lpd.buf_size < 2LL*id3len + 16)
- nodat = ID3_ALMOST_GREATER_PROBE;
- lpd.buf += id3len;
- lpd.buf_size -= id3len;
- } else if (id3len >= PROBE_BUF_MAX) {
- nodat = ID3_GREATER_MAX_PROBE;
- } else
- nodat = ID3_GREATER_PROBE;
- }
- fmt = NULL;
- while ((fmt1 = av_iformat_next(fmt1))) {
- //当is_opened=0时,只对alsa fbdev rtp rtsp这样flag=AVFMT_NOFILE的AVInputFormat调用probe
- //当is_opened=1时,只对ac3 dts h263 h264 这样flag不含AVFMT_NOFILE的调用probe
- if (!is_opened == !(fmt1->flags & AVFMT_NOFILE) && strcmp(fmt1->name, "image2"))
- continue;
- score = 0;
- if (fmt1->read_probe) {
- score = fmt1->read_probe(&lpd); //lpd中的buf是媒体文件中的头2048个字节
- if (score)
- av_log(NULL, AV_LOG_TRACE, "Probing %s score:%d size:%d\n", fmt1->name, score, lpd.buf_size);
- if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) {
- switch (nodat) {
- case NO_ID3:
- score = FFMAX(score, 1);
- break;
- case ID3_GREATER_PROBE:
- case ID3_ALMOST_GREATER_PROBE:
- score = FFMAX(score, AVPROBE_SCORE_EXTENSION / 2 - 1);
- break;
- case ID3_GREATER_MAX_PROBE:
- score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
- break;
- }
- }
- } else if (fmt1->extensions) {
- if (av_match_ext(lpd.filename, fmt1->extensions))
- score = AVPROBE_SCORE_EXTENSION;
- }
- if (av_match_name(lpd.mime_type, fmt1->mime_type))
- score = FFMAX(score, AVPROBE_SCORE_MIME);
- if (score > score_max) { //循环结束之后就是要取最大的score所代表的fmt
- score_max = score;
- fmt = fmt1;
- } else if (score == score_max)
- fmt = NULL;
- }
- if (nodat == ID3_GREATER_PROBE)
- score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max);
- *score_ret = score_max; //将probe中产生的最大的score与fmt返回
- return fmt;
- }
s->iformat->name=matroska,webm
三. 媒体文件的读写
3.1 媒体文件的打开过程
avformat_open_input
init_input
--> s->io_open
-->io_open_default ::libavformat/options.c
--> ffio_open_whitelist ::libavformat/aviobuf.c
--> ffurl_open_whitelist ::libavformat/avio.c
-->ffurl_connect ::libavformat/avio.c
--> file_open ::libavformat/file.c
AVFormatContext s;
s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)
3.2代码分析
3.2.1 avio层
- int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags,
- const AVIOInterruptCB *int_cb, AVDictionary **options,
- const char *whitelist
- )
- {
- ffurl_open_whitelist(&h, filename, flags, int_cb, options, whitelist);
- --> furl_alloc(puc, filename, flags, int_cb);
- --> p = url_find_protocol(filename); //根据文件名判断protocol类型,并返回protocol的指针
- --> url_alloc_for_protocol(puc, p, filename, flags, int_cb); //分配内存并初始化p
- --> ffurl_connect(*puc, options);
- ffio_fdopen(s, h);
- return 0;
- }
- static struct URLProtocol *url_find_protocol(const char *filename)
- {
- URLProtocol *up = NULL;
- char proto_str[128], proto_nested[128], *ptr;
- size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
- //根据文件名来判断protocol类型,若文件名中没有:则为file类型的protocol
- if (filename[proto_len] != ':' &&
- (strncmp(filename, "subfile,", 8) || !strchr(filename + proto_len + 1, ':')) ||
- is_dos_path(filename))
- strcpy(proto_str, "file");
- else
- av_strlcpy(proto_str, filename,
- FFMIN(proto_len + 1, sizeof(proto_str)));
- if ((ptr = strchr(proto_str, ',')))
- *ptr = '\0';
- av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
- if ((ptr = strchr(proto_nested, '+')))
- *ptr = '\0';
- while (up = ffurl_protocol_next(up)) { //查找到file类型的URLProtocol并返回
- if (!strcmp(proto_str, up->name))
- break;
- if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
- !strcmp(proto_nested, up->name))
- break;
- }
- return up;
- }
3.2.3 avio层
- int ffurl_connect(URLContext *uc, AVDictionary **options)
- {
- //uc->prot->url_open是真正的打开文件的函数
- uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) :
- uc->prot->url_open(uc, uc->filename, uc->flags);
- return 0;
- }
libavformat/file.c
- static int file_open(URLContext *h, const char *filename, int flags)
- {
- FileContext *c = h->priv_data;
- int fd;
- fd = avpriv_open(filename, access, 0666);
- --> 这个就是open函数的最后一层封装
- c->fd = fd;
- return 0;
- }
3.3.1 读写函数的初始化过程
ffio_open_whitelist ::libavformat/aviobuf.c
ffio_fdopen 初始代读写函数 ::libavformat/aviobuf.c
avio_alloc_context ::libavformat/aviobuf.c
ffio_init_context ::libavformat/aviobuf.c
ffio_init_context ::libavformat/aviobuf.c
s->write_packet = write_packet; :: ffurl_write 终于找到了
s->read_packet = read_packet; :: ffurl_read
3.3.2 读写函数的调用过程
av_probe_input_buffer2 ::libavformat/format.c
avio_read ::libavformat/aviobuf.c ::ffmpeg提供的read接口
s->read_packet
ffurl_read ::libavformat/avio.c
retry_transfer_wrapper ::libavformat/avio.c
0 0
- ffmpeg源码分析--3.avformat_alloc_context与avformat_open_input
- ffmpeg源码分析之avformat_alloc_context
- ffmpeg源码分析之三avformat_open_input()上
- ffmpeg源码分析之四-----avformat_open_input()下
- FFMpeg 源码分析 (3)avformat_open_input()
- FFMPEG源码分析:avformat_open_input()(媒体打开函数)
- FFMPEG源码分析:avformat_open_input()(媒体打开函数)
- avformat_open_input()源码分析
- ffmpeg源代码分析之avformat_open_input
- FFmpeg源代码简单分析:avformat_open_input()
- FFmpeg源代码简单分析:avformat_open_input()
- FFmpeg源代码简单分析:avformat_open_input
- ffmpeg源码跟踪笔记之avformat_open_input
- ffmpeg学习:avformat_alloc_context
- ffmpeg学习五:avformat_open_input函数源码分析(以mp4文件为例)
- FFMpeg分析:第一个函数avformat_open_input
- FFMpeg分析:第一个函数avformat_open_input
- FFMPEG-avformat_open_input
- ffmpeg源码分析--2.av_register_all
- Java操作xml文件
- WebView实现的大致步骤
- Java开发中的23种设计模式之行为型模式(一)
- 迭代器将map或者list分批量操作
- ffmpeg源码分析--3.avformat_alloc_context与avformat_open_input
- 花花世界,不必当真
- 关于拦截器
- 千万级规模高性能、高并发的网络架构经验分享
- Supervisor安装与配置(Linux/Unix进程管理工具)
- slab内存分配
- ffmpeg源码分析--4.关于mpeg文件格式1总
- Node.js第一个代码
- 安卓开发:模仿微信,QQ评论输入框,使用PopupWindow完美实现