zoukankan      html  css  js  c++  java
  • ffmpeg-URL(转)

    ffmpeg中为方便对资源进行访问,定义了两个结构体,URLContext中是对具体资源文件进行操作的上下文,URLProtocol则是在将资源进行分类的基础上,对某一类资源操作的函数集,熟悉Linux设备驱动程序的话,很容易联想到file_operations结构体
    
    typedef struct URLContext 
     {
         const AVClass *av_class;    /**< information for av_log(). Set by url_open(). */
         struct URLProtocol *prot;
         void *priv_data;
         char *filename;             /**< specified URL */
         int flags;
         int max_packet_size;        /**< if non zero, the stream is packetized with this max packet size */
         int is_streamed;            /**< true if streamed (no seek possible), default = false */
         int is_connected;
         AVIOInterruptCB interrupt_callback;
         int64_t rw_timeout;         /**< maximum time to wait for (network) read/write operation completion, in mcs */
     } 
     URLContext;
    
    
    
    
    
    typedef struct URLProtocol 
     {
         const char *name;
         int     (*url_open)( URLContext *h, const char *url, int flags);
         /**
          * This callback is to be used by protocols which open further nested
          * protocols. options are then to be passed to ffurl_open()/ffurl_connect()
          * for those nested protocols.
          */
         int     (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options);
    
    
         /**
          * Read data from the protocol.
          * If data is immediately available (even less than size), EOF is
          * reached or an error occurs (including EINTR), return immediately.
          * Otherwise:
          * In non-blocking mode, return AVERROR(EAGAIN) immediately.
          * In blocking mode, wait for data/EOF/error with a short timeout (0.1s),
          * and return AVERROR(EAGAIN) on timeout.
          * Checking interrupt_callback, looping on EINTR and EAGAIN and until
          * enough data has been read is left to the calling function; see
          * retry_transfer_wrapper in avio.c.
          */
         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 (*url_get_multi_file_handle)(URLContext *h, int **handles,
                                          int *numhandles);
         int (*url_shutdown)(URLContext *h, int flags);
         int priv_data_size;
         const AVClass *priv_data_class;
         int flags;
         int (*url_check)(URLContext *h, int mask);
     }
     URLProtocol;
    
    
    在代码中搜索url_open,很容易能够找到ffmpeg中支持的几个协议:
    
    URLProtocol ff_bluray_protocol = 
     {
         .name            = "bluray",
         .url_close       = bluray_close,
         .url_open        = bluray_open,
         .url_read        = bluray_read,
         .url_seek        = bluray_seek,
         .priv_data_size  = sizeof(BlurayContext),
         .priv_data_class = &bluray_context_class,
     };
    
    URLProtocol ff_data_protocol = 
     {
         .name           = "data",
         .url_open       = data_open,
         .url_close      = data_close,
         .url_read       = data_read,
         .priv_data_size = sizeof(DataContext),
     };
    
    
    URLProtocol ff_file_protocol = 
     {
         .name                = "file",
         .url_open            = file_open,
         .url_read            = file_read,
         .url_write           = file_write,
         .url_seek            = file_seek,
         .url_close           = file_close,
         .url_get_file_handle = file_get_handle,
         .url_check           = file_check,
         .priv_data_size      = sizeof(FileContext),
         .priv_data_class     = &file_class,
     };
    
    
    URLProtocol ff_pipe_protocol = 
     {
         .name                = "pipe",
         .url_open            = pipe_open,
         .url_read            = file_read,
         .url_write           = file_write,
         .url_get_file_handle = file_get_handle,
         .url_check           = file_check,
         .priv_data_size      = sizeof(FileContext),
         .priv_data_class     = &pipe_class,
     };
    
    
    URLProtocol ff_ftp_protocol = 
     {
         .name                = "ftp",
         .url_open            = ftp_open,
         .url_read            = ftp_read,
         .url_write           = ftp_write,
         .url_seek            = ftp_seek,
         .url_close           = ftp_close,
         .url_get_file_handle = ftp_get_file_handle,
         .url_shutdown        = ftp_shutdown,
         .priv_data_size      = sizeof(FTPContext),
         .priv_data_class     = &ftp_context_class,
         .flags               = URL_PROTOCOL_FLAG_NETWORK,
     };
    
    URLProtocol ff_hls_protocol = 
     {
         .name           = "hls",
         .url_open       = hls_open,
         .url_read       = hls_read,
         .url_close      = hls_close,
         .flags          = URL_PROTOCOL_FLAG_NESTED_SCHEME,
         .priv_data_size = sizeof(HLSContext),
     };
    
    
    URLProtocol ff_httpproxy_protocol = 
     {
         .name                = "httpproxy",
         .url_open            = http_proxy_open,
         .url_read            = http_buf_read,
         .url_write           = http_proxy_write,
         .url_close           = http_proxy_close,
         .url_get_file_handle = http_get_file_handle,
         .priv_data_size      = sizeof(HTTPContext),
         .flags               = URL_PROTOCOL_FLAG_NETWORK,
     };
    
    
    ... 还有很多协议,不全部列出了,例如tcp, udp, ...
    
    支持这些协议而定义的结构体在av_register_all()函数被调用时而注册,例如:
    
     REGISTER_PROTOCOL(FILE,             file);
    
    
    
    
    
    #define REGISTER_PROTOCOL(X, x)                                         
         {                                                                   
             extern URLProtocol ff_##x##_protocol;                           
             if (CONFIG_##X##_PROTOCOL)                                      
                 ffurl_register_protocol(&ff_##x##_protocol);                
         }
    
    
    ffurl_register_protocol(&ff_file_protocol);
    
    int ffurl_register_protocol(URLProtocol *protocol)
     {
         URLProtocol **p;
         p = &first_protocol;
         while (*p != NULL)
             p = &(*p)->next;
         *p             = protocol;
         protocol->next = NULL;
         return 0;
     }
    
    
    注册到以static URLProtocol *first_protocol = NULL;为头的一个链表中,每一个协议结构体是链表中的一项;
    
    
    
    
    以avio_open2为例:
    
    int avio_open2(AVIOContext **s, const char *filename, int flags,
                    const AVIOInterruptCB *int_cb, AVDictionary **options)
     {
         URLContext *h;
         int err;
    
    
         err = ffurl_open(&h, filename, flags, int_cb, options);
         if (err < 0)
             return err;
         
         err = ffio_fdopen(s, h);
         if (err < 0) 
         {
             ffurl_close(h);
             return err;
         }
         
         return 0;
     }
    
    
    ffurl_open--->ffurl_alloc--->static struct URLProtocol *url_find_protocol(const char *filename)
    
    url_find_protocol函数会根据filename判断协议,这个函数的定义没太看懂,但是其作用,无非是先判断具体的协议,然后根据判读出来的协议,调用
    
    URLProtocol *ffurl_protocol_next(URLProtocol *prev)
     {
         return prev ? prev->next : first_protocol;
     }
    
    
    函数,在之前注册的first_protocol链表上找到相应的协议结构体,然后返回给函数url_alloc_for_protocol,在这个函数中,则是根据判断的协议,生成URLContext结构体,
    
    uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1);
    
    
    *puc = uc;
    
    
    
    
    
    在ffurl_open函数中,ffurl_alloc函数返回之后,URLContext **puc结构体就已经被设置完毕,然后在ffurl_open函数中,再调用ret = ffurl_connect(*puc, options);
    
    int ffurl_connect(URLContext *uc, AVDictionary **options)
     {
         int err =
             uc->prot->url_open2 ? uc->prot->url_open2(uc,
                                                       uc->filename,
                                                       uc->flags,
                                                       options) :
             uc->prot->url_open(uc, uc->filename, uc->flags);
         if (err)
             return err;
         uc->is_connected = 1;
         /* We must be careful here as ffurl_seek() could be slow,
          * for example for http */
         if ((uc->flags & AVIO_FLAG_WRITE) || !strcmp(uc->prot->name, "file"))
             if (!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
                 uc->is_streamed = 1;
         return 0;
     }
    
    
    prot是协议,在url_alloc_for_protocol函数中设置的:uc->prot            = up;
    
    然后url_open2, url_open都是在协议结构体中定义的函数指针,以"file"协议为例:
    
    URLProtocol ff_file_protocol = 
    {
        .name                = "file",
        .url_open            = file_open,
        .url_read            = file_read,
        .url_write           = file_write,
        .url_seek            = file_seek,
        .url_close           = file_close,
        .url_get_file_handle = file_get_handle,
        .url_check           = file_check,
        .priv_data_size      = sizeof(FileContext),
        .priv_data_class     = &file_class,
    };
    
    
    url_open2是NULL,则调用url_open函数指针指向的函数file_open:
    
    static int file_open(URLContext *h, const char *filename, int flags)
     {
         FileContext *c = h->priv_data;
         int access;
         int fd;
         struct stat st;
    
    
         av_strstart(filename, "file:", &filename);
    
    
         if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
             access = O_CREAT | O_RDWR;
             if (c->trunc)
                 access |= O_TRUNC;
         } else if (flags & AVIO_FLAG_WRITE) {
             access = O_CREAT | O_WRONLY;
             if (c->trunc)
                 access |= O_TRUNC;
         } else {
             access = O_RDONLY;
         }
     #ifdef O_BINARY
         access |= O_BINARY;
     #endif
         fd = avpriv_open(filename, access, 0666);
         if (fd == -1)
             return AVERROR(errno);
         c->fd = fd;
    
    
         h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
    
    
         return 0;
    
    
    }

    http://blog.csdn.net/xiruanliuwei/article/details/24928237

  • 相关阅读:
    MVC、MVP、MVVM架构模式
    JavaScript中的跨域详解(二)
    JavaScript中的跨域详解(一)
    RESTful基础知识
    Date类
    数据的相对比较
    递归应用
    浏览器在一次 HTTP 请求中,需要传输一个 4097 字节的文本数据给服务端,可以采用那些方式?
    【04】图解JSON
    【08】css sprite是什么,有什么优缺点
  • 原文地址:https://www.cnblogs.com/wainiwann/p/4223776.html
Copyright © 2011-2022 走看看