FFMPEG系统结构
主要接口
(1) 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 openone */
//根据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);
gotofail;
}
}
//解析获取的数据
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;
}
(1.1)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;
}
(1.2)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 alphabeticchars */
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);
}
(1.3)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 needto 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;
}
(1.4) 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 backcan
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;
}
(1.5) 识别文件格式并相应的Demuxer
AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int*score_max)
(2) AVCodec *avcodec_find_decoder(enumAVCodecID id)
(3) int avcodec_decode_video2(AVCodecContext*avctx, AVFrame *picture, int *got_picture_ptr, const AVPacket *avpkt)
(4) int avcodec_decode_audio4(AVCodecContext*avctx, AVFrame *frame, int *got_frame_ptr, const AVPacket *avpkt)
(5) intsws_scale(struct SwsContext *c, const uint8_t * const srcSlice[],const intsrcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[],const intdstStride[])
(6) int swr_convert(struct SwrContext *s,uint8_t *out_arg[SWR_CH_MAX], int out_count, const uint8_t *in_arg[SWR_CH_MAX], int in_count)