ffmpeg源码分析--3.avformat_alloc_context与avformat_open_input
2016-09-05 17:07
1641 查看
一. avformat_alloc_context
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;
}
为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
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;
}
2.2.3
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=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层
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;
}
3.2.2 avio层
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;
}
注:ffmpeg所支持的所有的protocol都在libavformat/Makefile中以CONFIG_XXX_PROTOCOL标志
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;
}
3.2.4 这就到了protocol层
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 媒体文件的读过程
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;
}
为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
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;
}
2.2.3
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=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层
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;
}
3.2.2 avio层
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;
}
注:ffmpeg所支持的所有的protocol都在libavformat/Makefile中以CONFIG_XXX_PROTOCOL标志
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;
}
3.2.4 这就到了protocol层
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 媒体文件的读过程
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
相关文章推荐
- ffmpeg源码分析之四-----avformat_open_input()下
- FFMPEG源码分析:avformat_open_input()(媒体打开函数)
- FFMPEG源码分析:avformat_open_input()(媒体打开函数)
- ffmpeg源码分析之avformat_alloc_context
- FFMPEG源码分析: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_open_input,avformat_find_stream_info()
- FFMpeg分析:第一个函数avformat_open_input
- FFmpeg源代码简单分析:avformat_open_input()
- FFmpeg源代码简单分析:avformat_open_input()
- ffmpeg源码跟踪笔记之avformat_open_input
- ffmpeg之avformat_open_input函数分析
- FFmpeg源代码简单分析:avformat_open_input()
- avformat_open_input()源码分析
- FFmpeg源代码简单分析:avformat_open_input
- ffmpeg源码简析(五)编码——avformat_alloc_output_context2(),avcodec_encode_video2()