1: av_open_input_file的简单分析(主要是针对读数据)
int av_open_input_file(AVFormatContext **ic_ptr, const char
*filename,
AVInputFormat *fmt,
int buf_size,
AVFormatParameters *ap)
{
int err, probe_size;
AVProbeData probe_data, *pd = &probe_data;
//此结构中成员包括:数据操作,缓冲区块等(读取的数据先存入此结构中的缓冲区)
ByteIOContext *pb = NULL;
pd->filename = "";
if (filename)
pd->filename = filename;
pd->buf = NULL;
pd->buf_size = 0;
if (!fmt)
{
/* guess format if no file can be opened */
fmt = av_probe_input_format(pd, 0);
}
/* Do not open file if the format does not need it. XXX: specific
hack needed to handle RTSP/TCP */
if (!fmt || !(fmt->flags & AVFMT_NOFILE))
{
/* if no file needed do not try to open one */
//根据filename中协议头,准备相应的网络连接,并初始化pb结构体变量
if ((err=url_fopen(&pb, filename, URL_RDONLY)) < 0)
{
goto fail;
}
if (buf_size > 0)
{
url_setbufsize(pb, buf_size);
}
for (probe_size= PROBE_BUF_MIN; probe_size<=PROBE_BUF_MAX && !fmt; probe_size<<=1)
{
int score= probe_size < PROBE_BUF_MAX ? AVPROBE_SCORE_MAX/4 : 0;
/* read probe data */
pd->buf= av_realloc(pd->buf, probe_size + AVPROBE_PADDING_SIZE);
//从ByteIOContext中获取数据
pd->buf_size = get_buffer(pb, pd->buf, probe_size);
memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE);
if (url_fseek(pb, 0, SEEK_SET) < 0)
{
url_fclose(pb);
if (url_fopen(&pb, filename, URL_RDONLY) < 0)
{
pb = NULL;
err = AVERROR(EIO);
goto fail;
}
}
//解析获取的数据
fmt = av_probe_input_format2(pd, 1, &score);
}
av_freep(&pd->buf);
}
/* if still no format found, error */
if (!fmt)
{
err = AVERROR_NOFMT;
goto fail;
}
/* check filename in case an image number is expected */
if (fmt->flags & AVFMT_NEEDNUMBER)
{
if (!av_filename_number_test(filename))
{
err = AVERROR_NUMEXPECTED;
goto fail;
}
}
err = av_open_input_stream(ic_ptr, pb, filename, fmt, ap);
if (err)
goto fail;
return 0;
fail:
av_freep(&pd->buf);
if (pb)
url_fclose(pb);
*ic_ptr = NULL;
return err;
}
(2)网络连接初始化
int url_fopen(ByteIOContext **s, const char *filename, int flags)
{
URLContext *h; //
int err;
//根据filename中协议头,来初始化初始化URLContext变量,并进行
//相应的网络连接
err = url_open(&h, filename, flags);
if (err < 0)
return err;
//创建并初始化ByteIOContext变量
err = url_fdopen(s, h);
if (err < 0)
{
url_close(h);
return err;
}
return 0;
}
(3)
int url_open(URLContext **puc, const char *filename, int flags)
{
URLProtocol *up;
const char *p;
char proto_str[128], *q;
p = filename;
q = proto_str;
//----解析出协议头(如HTTP,TCP)--------//
while (*p != '/0' && *p != ':')
{
/* protocols can only contain alphabetic chars */
if (!isalpha(*p))
goto file_proto;
if ((q - proto_str) < sizeof(proto_str) - 1)
*q++ = *p;
p++;
}
/* if the protocol has length 1, we consider it is a dos drive */
if (*p == '/0' || is_dos_path(filename))
{
file_proto:
strcpy(proto_str, "file");
}
else
{
*q = '/0';
}
//遍历URLProtocol全局指针变量链表(这个在av_register_all()中预先
//准备好了), 根据协议头找到对应的协议URLProtocol变量, 再创建并初始化URLContext,然后进行相应的网络连接(如TCP会去连接相应的服务器)
up = first_protocol;
while (up != NULL)
{
if (!strcmp(proto_str, up->name))
return url_open_protocol (puc, up, filename, flags);
up = up->next;
}
*puc = NULL;
return AVERROR(ENOENT);
}
(4)
int url_fdopen(ByteIOContext **s, URLContext *h)
{
uint8_t *buffer;
int buffer_size, max_packet_size;
//设置缓冲块大小(默认值IO_BUFFER_SIZE:32768)
max_packet_size = url_get_max_packet_size(h);
if (max_packet_size)
{
buffer_size = max_packet_size; /* no need to bufferize more than one packet */
}
else
{
buffer_size = IO_BUFFER_SIZE;
}
//创建缓冲块
buffer = av_malloc(buffer_size);
if (!buffer)
return AVERROR(ENOMEM);
//创建ByteIOContext
*s = av_mallocz(sizeof(ByteIOContext));
if (!*s)
{
av_free(buffer);
return AVERROR(ENOMEM);
}
//初始化ByteIOContext,如缓冲块大小,读写等操作函数指针
if (init_put_byte(*s, buffer, buffer_size,
(h->flags & URL_WRONLY || h->flags & URL_RDWR), h,
url_read, url_write, url_seek) < 0)
{
av_free(buffer);
av_freep(s);
return AVERROR(EIO);
}
(*s)->is_streamed = h->is_streamed;
(*s)->max_packet_size = max_packet_size;
if (h->prot)
{
(*s)->read_pause = (int (*)(void *, int))h->prot->url_read_pause;
(*s)->read_seek = (int64_t (*)(void *, int, int64_t, int))h->prot->url_read_seek;
}
return 0;
}
(5) int get_buffer(ByteIOContext *s, unsigned char *buf, int size)
{
int len, size1;
size1 = size;
while (size > 0)
{
//缓冲块中还没被读取的数据量
len = s->buf_end - s->buf_ptr;
if (len > size)
len = size;
if (len == 0)
{
if (size > s->buffer_size && !s->update_checksum)
{
if (s->read_packet)
len = s->read_packet(s->opaque, buf, size);
if (len <= 0)
{
/* do not modify buffer if EOF reached so that a seek back can
be done without rereading data */
s->eof_reached = 1;
if (len<0)
s->error= len;
break;
}
else
{
s->pos += len;
size -= len;
buf += len;
s->buf_ptr = s->buffer;
s->buf_end = s->buffer/* + len*/;
}
}
else
{
//根据ByteIOContext先初始的成员变量,从文件或网络源获取数据
//后COPY到缓冲块中,实际的操作由先初始化的URLProtocol变量
//中成员方法来完成(如url_read,url_seek等)
fill_buffer(s);
len = s->buf_end - s->buf_ptr;
if (len == 0)
break;
}
}
else //直接从缓冲中获取数据
{
memcpy(buf, s->buf_ptr, len);
buf += len;
s->buf_ptr += len;
size -= len;
}
}
return size1 - size;
}
2: http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html 介绍Using libavformat and libavcodec