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

  • 相关阅读:
    HDU 4539郑厂长系列故事――排兵布阵(状压DP)
    HDU 2196Computer(树形DP)
    HDU 4284Travel(状压DP)
    HDU 1520Anniversary party(树型DP)
    HDU 3920Clear All of Them I(状压DP)
    HDU 3853LOOPS(简单概率DP)
    UVA 11983 Weird Advertisement(线段树求矩形并的面积)
    POJ 2886Who Gets the Most Candies?(线段树)
    POJ 2828Buy Tickets
    HDU 1394Minimum Inversion Number(线段树)
  • 原文地址:https://www.cnblogs.com/wainiwann/p/4223776.html
Copyright © 2011-2022 走看看