ffmpeg中的http协议相关代码阅读笔记

ffmpeg中的http协议相关代码阅读笔记

今天闲来无事,尝试看了下ffmpeg中的相关http协议传输处理代码

先简单说下这个代码在整个仓库里面的位置:

ffmpeg/libavformat/http.h

ffmpeg/libavformat/http.c

 

avoi.h中的函数调用分析

avoi.h是ffmpeg中libavformat/目录下的一个重要的头文件,这个文件主要处理 了一些传输协议的传输封装。他的封装过程是通过函数指针来实现的。

可以先看http.c文件中的最后一个结构体:

 

URLProtocol http_protocol = {

    "http",

    http_open,

    http_read,

    http_write,

    http_seek,

    http_close,

    .url_get_file_handle = http_get_file_handle,

    .priv_data_size = sizeof(HTTPContext),

    .priv_data_class = &httpcontext_class,

};

 

 

URLProtocol这个结构是在avoi.h中一个很重要的结构,他的存在的意义就是为了统一接口,可以在avoi.h中查到他的定义:

 

typedef struct URLProtocol {

    const char *name;

    int (*url_open)(URLContext *h, const char *url, int flags);

    int (*url_read)(URLContext *h, unsigned char *buf, int size);

    int (*url_write)(URLContext *h, const unsigned char *buf, int size);

    int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);

    int (*url_close)(URLContext *h);

    struct URLProtocol *next;

    int (*url_read_pause)(URLContext *h, int pause);

    int64_t (*url_read_seek)(URLContext *h, int stream_index,

                             int64_t timestamp, int flags);

    int (*url_get_file_handle)(URLContext *h);

    int priv_data_size;

    const AVClass *priv_data_class;

} URLProtocol;

 

针对http.c文件处理的http协议,最主要的就是实现URLProtocol中的函数指针,至于每个函数的具体意义,相信看命名就可以知道。

 

那么avoi.h中的函数又是怎么使用到这个内容的呢?这就可以从avoi.h中的几个函数看出来:

int url_open();

int url_read();

int url_write();

int64_t url_seek(URLContext *h, int64_t pos, int whence);
int url_close(URLContext *h);
找其中的一个分析,url_open:
int url_open(URLContext **puc, const char *filename, int flags)
{
    int ret = url_alloc(puc, filename, flags);
    if (ret)
        return ret;
    ret = url_connect(*puc);
    if (!ret)
        return 0;
    url_close(*puc);
    *puc = NULL;
    return ret;
}
url_open函数中使用到了url_alloc, url_connect, url_close,折伞个函数可能会在不同的情况下进行使用,由于代码太多,就不贴了,仅记录如下
url_alloc函数:
  • 处理协议探测,如果url参数中没有正常的协议,就默认填上"file://"然后作为文件协议处理
  • 处理探测的过程是在所有的已经注册上的协议链表中搜索对应名称的协议,这个名称,就是URLProtocol.name
  • 如果探测成功会把puc,即URLContext结构体也帮忙分配好,并作为参数out

url_connect:

  • 和url_open函数一样,url_connect会调用协议中的http_open函数进行http请求初始化: uc->prot->url_open()
  • url_connect返回非零值代表失败

url_close:

  • 如果url_connect失败,返回是非0值,就会调用url_close,并返回整个url_open函数失败

 

http.c文件的一些关键点分析

http_open函数

http_open函数会尝试调用其中的http_open_cnx,然后http_open_cnx会调用静态成员函数http_connect来进行http请求,其中所有的请求发送都是通过http_write函数来进行的。

http_read函数

相关的函数:

http_read, http_getline, http_getc

http_getc会有个1024的缓冲区,如果发现缓冲区满了才会继续读取,如果没有慢就每次读缓冲区里面的一个字符

 

static int http_getc(HTTPContext *s)

{

    int len;

    if (s->buf_ptr >= s->buf_end) {

        len = url_read(s->hd, s->buffer, BUFFER_SIZE);

        if (len < 0) {

            return AVERROR(EIO);

        } else if (len == 0) {

            return -1;

        } else {

            s->buf_ptr = s->buffer;

            s->buf_end = s->buffer + len;

        }

    }

    return *s->buf_ptr++;

}

 

HTTP协议中数据发送和接受的处理

http.c函数的URLProtocol结构体中有个PrivateData的指针,这个指针存储了http协议中的一些内部使用到的数据变量,内部处理的数据变量结构体如下:

typedef struct {

    const AVClass *class;

    URLContext *hd;

    unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;

    int line_count;

    int http_code;

    int64_t chunksize;      /**< Used if "Transfer-Encoding: chunked" otherwise -1. */

    int64_t off, filesize;

    char location[MAX_URL_SIZE];

    HTTPAuthState auth_state;

    unsigned char headers[BUFFER_SIZE];

    int willclose;          /**< Set if the server correctly handles Connection: close and will close the connection after feeding us the content. */

} HTTPContext;

 

可以看到一个比较重要的信息是:该私有的内部数据中竟然也有一个URLContext,那这个是什么呢?这个URLContext的协议又是什么呢?我通过阅读代码发现这个URLContext就是指向的tcp协议,用来通过tcp读取和返回数据。很感慨阿。这样很简单的就可以同时支持http,tcp协议,而且把tcp,udp协议封装起来以后,基本上其他的像rtsp, mms等协议也可以通过制定他们自己的内在协议来处理了。

 

在http.c中的http_open_cnx函数中有一句代码:

ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);

这样就很好的把http的底层tcp协议比较好的串接起来

总结

通过看ffmpeg的代码,总结了下,其实ffmpeg本身并不是很神秘,他本身只是提供了一个很好的很平等并可以无线扩展的架构。而在ffmpeg这个架构上,才能有很多codec, decodec和mutex, io, protocol很好的共存处理。

很欣赏,能作这个完美架构的大师,只有这种完美的架构才能吸引更多的开源爱好着去研究ffmpeg的代码,并不断的丰富它!

 

你可能感兴趣的:(多媒体)