上一次分析到了av_url_read_fseek()函数,这一章从这里写起:
offset_t av_url_read_fseek(ByteIOContext *s,
int stream_index, int64_t timestamp, int flags)
{
URLContext *h = s->opaque;
offset_t ret;
if (!s->read_seek)
return AVERROR(ENOSYS);
ret = s->read_seek(h, stream_index, timestamp, flags); //上一次说过了ByteIOContext结构的初始化,它指向的read_seek函数将被初始化
为avio.c函数中的av_url_read_seek函数,一会在往下看
if(ret >= 0) {
s->buf_ptr = s->buf_end; // Flush buffer //此处这行代码非常重要,用于刷新环形缓冲区,否则seek之前的数据包将可能会被滞留在缓冲区
s->pos = s->seek(h, 0, SEEK_CUR); //此处的seek至SEEK_CUR不知所云,我的代码测试结果是seek到正确位置后又退回至seek
前的位置,相当于没有seek.所以我并没有初始化URLprotocol中的seek函数.
}
return ret;
}
现在我们已经接近了MMS协议内部的处理了,接着看一下av_url_read_seek()函数,这个函数会被调用多次,每一次都会因为指向不同的URLProtocol而调用不同的协议:
offset_t av_url_read_seek(URLContext *h,
int stream_index, int64_t timestamp, int flags)
{
if (!h->prot->url_read_seek) //h->prot表示MMS协议,其指向的从这里来说是URLProtocol结构,目前来说是mms协议.
return AVERROR(ENOSYS);
return h->prot->url_read_seek(h, stream_index, timestamp, flags);
}
这里要顺便提及一下,此函数同样也是tcp协议的调用函数,当然我们添加的seek功能并未循环调用此函数,但是我这里举例说一下MMS协议的read是循环调用了此函数的.我不细贴代码了,说一下过程:
第一次调用此函数,h->prot为MMS协议,因此调用mms_read()函数(在mms.c中,也可以在asf.c中实
现).mms_read会再次调用此函数,但是这个函数中的h->prot将会变为tcp协议,从而使用tcp协议读取数据.大致是这样,详细见代
码!!!
MMS协议中seek的命令是0x07,我也不细说了,翻阅文档就可以了.由于之前已经提到过seek函数的实现,也不打算贴很详细的代码,状态基的事情
呢,每个程序员都有自己的想法,我的贴出来也许还会被认为不高效,就自己琢磨吧!唯一需要在罗嗦一下的就是超时问题,超时使用select实现的:
static int tcp_read(URLContext *h, uint8_t *buf, int size)
{
TCPContext *s = h->priv_data;
int len, fd_max, ret;
fd_set rfds;
struct timeval tv;
for (;;) {
fd_max = s->fd;
FD_ZERO(&rfds);
FD_SET(s->fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
ret = select(fd_max + 1, &rfds, NULL, NULL, &tv);
if (ret > 0 && FD_ISSET(s->fd, &rfds)) {
len = recv(s->fd, buf, size, 0);
if (len < 0) {
if (ff_neterrno() != FF_NETERROR(EINTR) &&
ff_neterrno() != FF_NETERROR(EAGAIN))
return AVERROR(errno);
} else return len;
} else if (ret < 0) {
return -1;
}
}
}
阅读(1952) | 评论(0) | 转发(0) |