当前位置: 首页 > news >正文

临检中心网站建设大气的广告公司名称

临检中心网站建设,大气的广告公司名称,上海网站建设乐云seo,关于服装的网站规划与设计参考链接 FFmpeg源代码简单分析#xff1a;avio_open2()_雷霄骅的博客-CSDN博客_avio_open avio_open2() 该函数用于打开FFmpeg的输入输出文件avio_open2()的声明位于libavformat\avio.h文件中#xff0c;如下所示。 /*** Create and initialize a AVIOContext for accessi…参考链接 FFmpeg源代码简单分析avio_open2()_雷霄骅的博客-CSDN博客_avio_open avio_open2() 该函数用于打开FFmpeg的输入输出文件avio_open2()的声明位于libavformat\avio.h文件中如下所示。 /*** Create and initialize a AVIOContext for accessing the* resource indicated by url.* note When the resource indicated by url has been opened in* readwrite mode, the AVIOContext can be used only for writing.** param s Used to return the pointer to the created AVIOContext.* In case of failure the pointed to value is set to NULL.* param url resource to access* param flags flags which control how the resource indicated by url* is to be opened* param int_cb an interrupt callback to be used at the protocols level* param options A dictionary filled with protocol-private options. On return* this parameter will be destroyed and replaced with a dict containing options* that were not found. May be NULL.* return 0 in case of success, a negative value corresponding to an* AVERROR code in case of failure*/ int avio_open2(AVIOContext **s, const char *url, int flags,const AVIOInterruptCB *int_cb, AVDictionary **options); avio_open2()函数参数的含义如下 s函数调用成功之后创建的AVIOContext结构体。url输入输出协议的地址文件也是一种“广义”的协议对于文件来说就是文件的路径flags打开地址的方式。可以选择只读只写或者读写。取值如下。 /*** name URL open modes* The flags argument to avio_open must be one of the following* constants, optionally ORed with other flags.* {*/ #define AVIO_FLAG_READ 1 /** read-only */ #define AVIO_FLAG_WRITE 2 /** write-only */ #define AVIO_FLAG_READ_WRITE (AVIO_FLAG_READ|AVIO_FLAG_WRITE) /** read-write pseudo flag */ AVIO_FLAG_READ只读。 AVIO_FLAG_WRITE只写。 AVIO_FLAG_READ_WRITE读写。int_cb目前还没有用过。options目前还没有用过具体使用的参考链接最简单的基于FFMPEG的视频编码器YUV编码为H.264_雷霄骅的博客-CSDN博客_最简单的基于ffmpeg 函数调用结构图 avio_open() 有一个和avio_open2()“长得很像”的函数avio_open()应该是avio_open2()的早期版本。avio_open()比avio_open2()少了最后2个参数。而它前面几个参数的含义和avio_open2()是一样的。从源代码中可以看出avio_open()内部调用了avio_open2()并且把avio_open2()的后2个参数设置成了NULL因此它的功能实际上和avio_open2()是一样的。avio_open()源代码如下所示。 int avio_open(AVIOContext **s, const char *filename, int flags) {return avio_open2(s, filename, flags, NULL, NULL); } avio_open2() int avio_open2(AVIOContext **s, const char *filename, int flags,const AVIOInterruptCB *int_cb, AVDictionary **options) {return ffio_open_whitelist(s, filename, flags, int_cb, options, NULL, NULL); } 从avio_open2()的源代码可以看出它主要调用了ffio_open_whitelistAVIOContext则是在URLContext的读写函数外面加上了一层“包装”通过retry_transfer_wrapper()函数ffio_open_whitelist ffio_open_whitelist 主要调用了ffurl_open_whitelist、ffio_fdopen()和ffurl_close()根据URLContext初始化AVIOContext int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags,const AVIOInterruptCB *int_cb, AVDictionary **options,const char *whitelist, const char *blacklist) {URLContext *h;int err;*s NULL;err ffurl_open_whitelist(h, filename, flags, int_cb, options, whitelist, blacklist, NULL);if (err 0)return err;err ffio_fdopen(s, h);if (err 0) {ffurl_close(h);return err;}return 0; }ffurl_open_whitelist 初始化URLContext替代原有的 ffurl_open函数 int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags,const AVIOInterruptCB *int_cb, AVDictionary **options,const char *whitelist, const char* blacklist,URLContext *parent) {AVDictionary *tmp_opts NULL;AVDictionaryEntry *e;int ret ffurl_alloc(puc, filename, flags, int_cb);if (ret 0)return ret;if (parent) {ret av_opt_copy(*puc, parent);if (ret 0)goto fail;}if (options (ret av_opt_set_dict(*puc, options)) 0)goto fail;if (options (*puc)-prot-priv_data_class (ret av_opt_set_dict((*puc)-priv_data, options)) 0)goto fail;if (!options)options tmp_opts;av_assert0(!whitelist ||!(eav_dict_get(*options, protocol_whitelist, NULL, 0)) ||!strcmp(whitelist, e-value));av_assert0(!blacklist ||!(eav_dict_get(*options, protocol_blacklist, NULL, 0)) ||!strcmp(blacklist, e-value));if ((ret av_dict_set(options, protocol_whitelist, whitelist, 0)) 0)goto fail;if ((ret av_dict_set(options, protocol_blacklist, blacklist, 0)) 0)goto fail;if ((ret av_opt_set_dict(*puc, options)) 0)goto fail;ret ffurl_connect(*puc, options);if (!ret)return 0; fail:ffurl_closep(puc);return ret; }从代码中可以看出ffurl_open()主要调用了2个函数ffurl_alloc()和ffurl_connect()。ffurl_alloc()用于查找合适的URLProtocol并创建一个URLContextffurl_connect()用于打开获得的URLProtocol。 ffurl_open() 已经被弃用 ffurl_alloc() ffurl_alloc()的定义位于libavformat\avio.c中如下所示。 int ffurl_alloc(URLContext **puc, const char *filename, int flags,const AVIOInterruptCB *int_cb) {const URLProtocol *p NULL;p url_find_protocol(filename);if (p)return url_alloc_for_protocol(puc, p, filename, flags, int_cb);*puc NULL;return AVERROR_PROTOCOL_NOT_FOUND; } 从代码中可以看出ffurl_alloc()主要调用了2个函数url_find_protocol()根据文件路径查找合适的URLProtocolurl_alloc_for_protocol()为查找到的URLProtocol创建URLContext。  url_find_protocol() 先来看一下url_find_protocol()函数定义如下所示。 static const struct URLProtocol *url_find_protocol(const char *filename) {const URLProtocol **protocols;char proto_str[128], proto_nested[128], *ptr;size_t proto_len strspn(filename, URL_SCHEME_CHARS);int i;if (filename[proto_len] ! : (strncmp(filename, subfile,, 8) || !strchr(filename proto_len 1, :)) ||is_dos_path(filename))strcpy(proto_str, file);elseav_strlcpy(proto_str, filename,FFMIN(proto_len 1, sizeof(proto_str)));av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));if ((ptr strchr(proto_nested, )))*ptr \0;protocols ffurl_get_protocols(NULL, NULL);if (!protocols)return NULL;for (i 0; protocols[i]; i) {const URLProtocol *up protocols[i];if (!strcmp(proto_str, up-name)) {av_freep(protocols);return up;}if (up-flags URL_PROTOCOL_FLAG_NESTED_SCHEME !strcmp(proto_nested, up-name)) {av_freep(protocols);return up;}}av_freep(protocols);if (av_strstart(filename, https:, NULL) || av_strstart(filename, tls:, NULL))av_log(NULL, AV_LOG_WARNING, https protocol not found, recompile FFmpeg with openssl, gnutls or securetransport enabled.\n);return NULL; } #define URL_SCHEME_CHARS \abcdefghijklmnopqrstuvwxyz \ABCDEFGHIJKLMNOPQRSTUVWXYZ \0123456789-.url_find_protocol()函数表明了FFmpeg根据文件路径猜测协议的方法。该函数首先根据strspn()函数查找字符串中第一个“非字母或数字”的字符的位置并保存在proto_len中。一般情况下协议URL中都是包含“:”的比如说RTMP的URL格式是“rtmp://xxx…”UDP的URL格式是“udp://…”HTTP的URL格式是“http://...”。因此一般情况下proto_len的数值就是“:”的下标代表了“:”前面的协议名称的字符的个数例如rtmp://的proto_len为4。接下来函数将filename的前proto_len个字节拷贝至proto_str字符串中。这个地方比较纠结源代码中av_strlcpy()函数的第3个参数size写的字符串的长度是proto_len1但是查了一下av_strlcpy()的定义发现该函数至多拷贝size-1个字符。这么一涨一消最终还是拷贝了proto_len个字节。例如RTMP协议就拷贝了“rtmp”UDP协议就拷贝了“udp”。av_strlcpy()是FFMpeg的一个工具函数声明位于libavutil\avstring.h如下所示。 size_t av_strlcpy(char *dst, const char *src, size_t size) {size_t len 0;while (len size *src)*dst *src;if (len size)*dst 0;return len strlen(src) - 1; } 这里有一种例外那就是文件路径。“文件”在FFmpeg中也是一种“协议”并且前缀是“file”。也就是标准的文件路径应该是“file://...”格式的。但是这太不符合我们一般人的使用习惯我们一般是不会在文件路径前面加上“file”协议名称的。所以该函数采取的方法是一旦检测出来输入的URL是文件路径而不是网络协议就自动向proto_str中拷贝“file”。strcpy(proto_str, file);其中判断文件路径那里有一个很复杂的if()语句。根据我的理解“||”前面的语句用于判断是否是相对文件路径“||”后面的语句用于判断是否是绝对路径。判断绝对路径的时候用到了一个函数is_dos_path()定义位于libavformat\os_support.h如下所示。 static inline int is_dos_path(const char *path) { #if HAVE_DOS_PATHSif (path[0] path[1] :)return 1; #endifreturn 0; } 注意“”优先级低于“”。如果文件路径第1个字符不为空一般情况下是盘符而且第2个字符为“:”就认为它是绝对文件路径。 url_alloc_for_protocol() url_alloc_for_protocol()的定义位于libavformat\avio.c中如下所示。 static int url_alloc_for_protocol(URLContext **puc, const URLProtocol *up,const char *filename, int flags,const AVIOInterruptCB *int_cb) {URLContext *uc;int err;#if CONFIG_NETWORKif (up-flags URL_PROTOCOL_FLAG_NETWORK !ff_network_init())return AVERROR(EIO); #endifif ((flags AVIO_FLAG_READ) !up-url_read) {av_log(NULL, AV_LOG_ERROR,Impossible to open the %s protocol for reading\n, up-name);return AVERROR(EIO);}if ((flags AVIO_FLAG_WRITE) !up-url_write) {av_log(NULL, AV_LOG_ERROR,Impossible to open the %s protocol for writing\n, up-name);return AVERROR(EIO);}uc av_mallocz(sizeof(URLContext) strlen(filename) 1);if (!uc) {err AVERROR(ENOMEM);goto fail;}uc-av_class ffurl_context_class;uc-filename (char *)uc[1];strcpy(uc-filename, filename);uc-prot up;uc-flags flags;uc-is_streamed 0; /* default not streamed */uc-max_packet_size 0; /* default: stream file */if (up-priv_data_size) {uc-priv_data av_mallocz(up-priv_data_size);if (!uc-priv_data) {err AVERROR(ENOMEM);goto fail;}if (up-priv_data_class) {char *start;*(const AVClass **)uc-priv_data up-priv_data_class;av_opt_set_defaults(uc-priv_data);if (av_strstart(uc-filename, up-name, (const char**)start) *start ,) {int ret 0;char *p start;char sep *p;char *key, *val;p;if (strcmp(up-name, subfile))ret AVERROR(EINVAL);while(ret 0 (key strchr(p, sep)) pkey (val strchr(key1, sep))){*val *key 0;if (strcmp(p, start) strcmp(p, end)) {ret AVERROR_OPTION_NOT_FOUND;} elseret av_opt_set(uc-priv_data, p, key1, 0);if (ret AVERROR_OPTION_NOT_FOUND)av_log(uc, AV_LOG_ERROR, Key %s not found.\n, p);*val *key sep;p val1;}if(ret0 || p!key){av_log(uc, AV_LOG_ERROR, Error parsing options string %s\n, start);av_freep(uc-priv_data);av_freep(uc);err AVERROR(EINVAL);goto fail;}memmove(start, key1, strlen(key));}}}if (int_cb)uc-interrupt_callback *int_cb;*puc uc;return 0; fail:*puc NULL;if (uc)av_freep(uc-priv_data);av_freep(uc); #if CONFIG_NETWORKif (up-flags URL_PROTOCOL_FLAG_NETWORK)ff_network_close(); #endifreturn err; } url_alloc_for_protocol()完成了以下步骤首先检查输入的URLProtocol是否支持指定的flag。比如flag中如果指定了AVIO_FLAG_READ则URLProtocol中必须包含url_read()如果指定了AVIO_FLAG_WRITE则URLProtocol中必须包含url_write()。在检查无误之后接着就可以调用av_mallocz()为即将创建的URLContext分配内存了。接下来基本上就是各种赋值工作在这里不再详细记录。  ffurl_connect() ffurl_connect()用于打开获得的URLProtocol。该函数的定义位于libavformat\avio.c中如下所示。  int ffurl_connect(URLContext *uc, AVDictionary **options) {int err;AVDictionary *tmp_opts NULL;AVDictionaryEntry *e;if (!options)options tmp_opts;// Check that URLContext was initialized correctly and lists are matching if setav_assert0(!(eav_dict_get(*options, protocol_whitelist, NULL, 0)) ||(uc-protocol_whitelist !strcmp(uc-protocol_whitelist, e-value)));av_assert0(!(eav_dict_get(*options, protocol_blacklist, NULL, 0)) ||(uc-protocol_blacklist !strcmp(uc-protocol_blacklist, e-value)));if (uc-protocol_whitelist av_match_list(uc-prot-name, uc-protocol_whitelist, ,) 0) {av_log(uc, AV_LOG_ERROR, Protocol %s not on whitelist %s!\n, uc-prot-name, uc-protocol_whitelist);return AVERROR(EINVAL);}if (uc-protocol_blacklist av_match_list(uc-prot-name, uc-protocol_blacklist, ,) 0) {av_log(uc, AV_LOG_ERROR, Protocol %s on blacklist %s!\n, uc-prot-name, uc-protocol_blacklist);return AVERROR(EINVAL);}if (!uc-protocol_whitelist uc-prot-default_whitelist) {av_log(uc, AV_LOG_DEBUG, Setting default whitelist %s\n, uc-prot-default_whitelist);uc-protocol_whitelist av_strdup(uc-prot-default_whitelist);if (!uc-protocol_whitelist) {return AVERROR(ENOMEM);}} else if (!uc-protocol_whitelist)av_log(uc, AV_LOG_DEBUG, No default whitelist set\n); // This should be an error once all declare a default whitelistif ((err av_dict_set(options, protocol_whitelist, uc-protocol_whitelist, 0)) 0)return err;if ((err av_dict_set(options, protocol_blacklist, uc-protocol_blacklist, 0)) 0)return err;err uc-prot-url_open2 ? uc-prot-url_open2(uc,uc-filename,uc-flags,options) :uc-prot-url_open(uc, uc-filename, uc-flags);av_dict_set(options, protocol_whitelist, NULL, 0);av_dict_set(options, protocol_blacklist, NULL, 0);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; }URLProtocol中是否包含url_open2()如果包含的话就调用url_open2()否则就调用url_open()err uc-prot-url_open2 ? uc-prot-url_open2(uc,uc-filename,uc-flags,options) :uc-prot-url_open(uc, uc-filename, uc-flags); url_open()本身是URLProtocol的一个函数指针这个地方根据不同的协议调用的url_open()具体实现函数也是不一样的例如file协议的url_open()对应的是file_open()而file_open()最终调用了_wsopen()_sopen()Windows下或者open()Linux下类似于fopen()这样的系统中打开文件的API函数而libRTMP的url_open()对应的是rtmp_open()而rtmp_open()最终调用了libRTMP的API函数RTMP_Init()RTMP_SetupURL()RTMP_Connect() 以及RTMP_ConnectStream()。通用 转向与 偏特化 ffio_fdopen() ffio_fdopen()使用已经获得的URLContext初始化AVIOContext。它的函数定义位于libavformat\aviobuf.c中如下所示。 int ffio_fdopen(AVIOContext **s, URLContext *h) {uint8_t *buffer NULL;int buffer_size, max_packet_size;max_packet_size h-max_packet_size;if (max_packet_size) {buffer_size max_packet_size; /* no need to bufferize more than one packet */} else {buffer_size IO_BUFFER_SIZE;}if (!(h-flags AVIO_FLAG_WRITE) h-is_streamed) {if (buffer_size INT_MAX/2)return AVERROR(EINVAL);buffer_size * 2;}buffer av_malloc(buffer_size);if (!buffer)return AVERROR(ENOMEM);*s avio_alloc_context(buffer, buffer_size, h-flags AVIO_FLAG_WRITE, h,(int (*)(void *, uint8_t *, int)) ffurl_read,(int (*)(void *, uint8_t *, int)) ffurl_write,(int64_t (*)(void *, int64_t, int))ffurl_seek);if (!*s) {av_freep(buffer);return AVERROR(ENOMEM);}(*s)-protocol_whitelist av_strdup(h-protocol_whitelist);if (!(*s)-protocol_whitelist h-protocol_whitelist) {avio_closep(s);return AVERROR(ENOMEM);}(*s)-protocol_blacklist av_strdup(h-protocol_blacklist);if (!(*s)-protocol_blacklist h-protocol_blacklist) {avio_closep(s);return AVERROR(ENOMEM);}(*s)-direct h-flags AVIO_FLAG_DIRECT;(*s)-seekable h-is_streamed ? 0 : AVIO_SEEKABLE_NORMAL;(*s)-max_packet_size max_packet_size;(*s)-min_packet_size h-min_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;if (h-prot-url_read_seek)(*s)-seekable | AVIO_SEEKABLE_TIME;}((FFIOContext*)(*s))-short_seek_get (int (*)(void *))ffurl_get_short_seek;(*s)-av_class ff_avio_class;return 0; }ffio_fdopen()函数首先初始化AVIOContext中的Buffer。如果URLContext中设置了max_packet_size则将Buffer的大小设置为max_packet_size。如果没有设置的话似乎大部分URLContext都没有设置该值则会分配IO_BUFFER_SIZE个字节给Buffer。IO_BUFFER_SIZE取值为32768。 avio_alloc_context() ffio_fdopen()接下来会调用avio_alloc_context()初始化一个AVIOContext。avio_alloc_context()本身是一个FFmpeg的API函数。它的声明位于libavformat\avio.h中如下所示。 AVIOContext *avio_alloc_context(unsigned char *buffer,int buffer_size,int write_flag,void *opaque,int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),int64_t (*seek)(void *opaque, int64_t offset, int whence)) {FFIOContext *s av_malloc(sizeof(*s));if (!s)return NULL;ffio_init_context(s, buffer, buffer_size, write_flag, opaque,read_packet, write_packet, seek);return s-pub; }avio_alloc_context()看上去参数很多但实际上并不复杂。先简单解释一下它各个参数的含义 bufferAVIOContext中的Buffer。buffer_sizeAVIOContext中的Buffer的大小。write_flag设置为1则Buffer可写否则Buffer只可读。opaque用户自定义数据。read_packet()读取外部数据填充Buffer的函数。write_packet()向Buffer中写入数据的函数。seek()用于Seek的函数。该函数成功执行的话则会返回一个创建好的AVIOContext。该函数代码很简单首先调用av_mallocz()为AVIOContext分配一块内存空间然后基本上将所有输入参数传递给ffio_init_context()。 ffio_init_context() ffio_init_context()的定义如下。  void ffio_init_context(FFIOContext *ctx,unsigned char *buffer,int buffer_size,int write_flag,void *opaque,int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),int64_t (*seek)(void *opaque, int64_t offset, int whence)) {AVIOContext *const s ctx-pub;memset(ctx, 0, sizeof(*ctx));s-buffer buffer;ctx-orig_buffer_size s-buffer_size buffer_size;s-buf_ptr buffer;s-buf_ptr_max buffer;s-opaque opaque;s-direct 0;url_resetbuf(s, write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ);s-write_packet write_packet;s-read_packet read_packet;s-seek seek;s-pos 0;s-eof_reached 0;s-error 0;s-seekable seek ? AVIO_SEEKABLE_NORMAL : 0;s-min_packet_size 0;s-max_packet_size 0;s-update_checksum NULL;ctx-short_seek_threshold SHORT_SEEK_THRESHOLD;if (!read_packet !write_flag) {s-pos buffer_size;s-buf_end s-buffer buffer_size;}s-read_pause NULL;s-read_seek NULL;s-write_data_type NULL;s-ignore_boundary_point 0;ctx-current_type AVIO_DATA_MARKER_UNKNOWN;ctx-last_time AV_NOPTS_VALUE;ctx-short_seek_get NULL; #if FF_API_AVIOCONTEXT_WRITTEN FF_DISABLE_DEPRECATION_WARNINGSs-written 0; FF_ENABLE_DEPRECATION_WARNINGS #endif } ffurl_read()ffurl_write()ffurl_seek() 现在我们再回到ffio_fdopen()会发现它初始化AVIOContext的结构体的时候首先将自己分配的Buffer设置为该AVIOContext的Buffer然后将URLContext作为用户自定义数据对应AVIOContext的opaque变量提供给该AVIOContext最后分别将3个函数作为该AVIOContext的读写跳转函数ffurl_read()ffurl_write()ffurl_seek()。下面我们选择一个ffurl_read()看看它的定义。ffurl_read()的定义位于libavformat\avio.c如下所示。  int ffurl_read(URLContext *h, unsigned char *buf, int size) {if (!(h-flags AVIO_FLAG_READ))return AVERROR(EIO);return retry_transfer_wrapper(h, buf, size, 1, h-prot-url_read); } 该函数先判断了一下输入的URLContext是否支持“读”操作接着调用了一个函数retry_transfer_wrapper()。如果我们看ffurl_write()的代码如下所示。 int ffurl_write(URLContext *h, const unsigned char *buf, int size) {if (!(h-flags AVIO_FLAG_WRITE))return AVERROR(EIO);/* avoid sending too big packets */if (h-max_packet_size size h-max_packet_size)return AVERROR(EIO);return retry_transfer_wrapper(h, (unsigned char *)buf, size, size,(int (*)(struct URLContext *, uint8_t *, int))h-prot-url_write); } 会发现他也调用了同样的一个函数retry_transfer_wrapper()。唯一的不同在于ffurl_read()调用retry_transfer_wrapper()的时候最后一个参数是URLProtocol的url_read()而ffurl_write()调用retry_transfer_wrapper()的时候最后一个参数是URLProtocol的url_write()。下面我们看一下retry_transfer_wrapper()的定义位于libavformat\avio.c如下所示。  static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf,int size, int size_min,int (*transfer_func)(URLContext *h,uint8_t *buf,int size)) {int ret, len;int fast_retries 5;int64_t wait_since 0;len 0;while (len size_min) {if (ff_check_interrupt(h-interrupt_callback))return AVERROR_EXIT;ret transfer_func(h, buf len, size - len);if (ret AVERROR(EINTR))continue;if (h-flags AVIO_FLAG_NONBLOCK)return ret;if (ret AVERROR(EAGAIN)) {ret 0;if (fast_retries) {fast_retries--;} else {if (h-rw_timeout) {if (!wait_since)wait_since av_gettime_relative();else if (av_gettime_relative() wait_since h-rw_timeout)return AVERROR(EIO);}av_usleep(1000);}} else if (ret AVERROR_EOF)return (len 0) ? len : AVERROR_EOF;else if (ret 0)return ret;if (ret) {fast_retries FFMAX(fast_retries, 2);wait_since 0;}len ret;}return len; }从代码中可以看出它的核心实际上是调用了一个名称为transfer_func()的函数。而该函数就是retry_transfer_wrapper()的第四个参数。该函数实际上是对URLProtocol的读写操作中的错误进行了一些“容错”处理可以让数据的读写更加的稳定avio_alloc_context()执行完毕后ffio_fdopen()函数的工作就基本完成了avio_open2()的工作也就做完了。URLProtocol和URLContext 这两个结构体在FFmpeg的早期版本的SDK中是定义在头文件中可以直接使用的。但是近期的FFmpeg的SDK中已经找不到这两个结构体的定义了。FFmpeg把这两个结构体移动到了源代码的内部变成了内部结构体。URLProtocol的定义位于libavformat\url.h如下所示。 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_whitelist()* or ffurl_connect() for those nested protocols.*/int (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options);int (*url_accept)(URLContext *s, URLContext **c);int (*url_handshake)(URLContext *c);/*** 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);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_get_short_seek)(URLContext *h);int (*url_shutdown)(URLContext *h, int flags);const AVClass *priv_data_class;int priv_data_size;int flags;int (*url_check)(URLContext *h, int mask);int (*url_open_dir)(URLContext *h);int (*url_read_dir)(URLContext *h, AVIODirEntry **next);int (*url_close_dir)(URLContext *h);int (*url_delete)(URLContext *h);int (*url_move)(URLContext *h_src, URLContext *h_dst);const char *default_whitelist; } URLProtocol;从URLProtocol的定义可以看出其中包含了用于协议读写的函数指针。例如 url_open()打开协议。url_read()读数据。url_write()写数据。url_close()关闭协议。每种具体的协议都包含了一个URLProtocol结构体例如 FILE FILE协议“文件”在FFmpeg中也被当做一种协议的结构体ff_file_protocol的定义如下所示位于libavformat\file.c const 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,.url_delete file_delete,.url_move file_move,.priv_data_size sizeof(FileContext),.priv_data_class file_class,.url_open_dir file_open_dir,.url_read_dir file_read_dir,.url_close_dir file_close_dir,.default_whitelist file,crypto,data };在使用FILE协议进行读写的时候调用url_open()实际上就是调用了file_open()函数这里限于篇幅不再对file_open()的源代码进行分析。file_open()函数实际上调用了系统的打开文件函数open()。同理调用url_read()实际上就是调用了file_read()函数file_read()函数实际上调用了系统的读取文件函数read()。url_write()url_seek()等函数的道理都是一样的。 LibRTMP LibRTMP协议的结构体ff_librtmp_protocol的定义如下所示位于libavformat\librtmp.c RTMP_CLASS(rtmp) const URLProtocol ff_librtmp_protocol {.name rtmp,.url_open rtmp_open,.url_read rtmp_read,.url_write rtmp_write,.url_close rtmp_close,.url_read_pause rtmp_read_pause,.url_read_seek rtmp_read_seek,.url_get_file_handle rtmp_get_file_handle,.priv_data_size sizeof(LibRTMPContext),.priv_data_class librtmp_class,.flags URL_PROTOCOL_FLAG_NETWORK, };RTMP_CLASS(rtmpt) const URLProtocol ff_librtmpt_protocol {.name rtmpt,.url_open rtmp_open,.url_read rtmp_read,.url_write rtmp_write,.url_close rtmp_close,.url_read_pause rtmp_read_pause,.url_read_seek rtmp_read_seek,.url_get_file_handle rtmp_get_file_handle,.priv_data_size sizeof(LibRTMPContext),.priv_data_class librtmpt_class,.flags URL_PROTOCOL_FLAG_NETWORK, };RTMP_CLASS(rtmpe) const URLProtocol ff_librtmpe_protocol {.name rtmpe,.url_open rtmp_open,.url_read rtmp_read,.url_write rtmp_write,.url_close rtmp_close,.url_read_pause rtmp_read_pause,.url_read_seek rtmp_read_seek,.url_get_file_handle rtmp_get_file_handle,.priv_data_size sizeof(LibRTMPContext),.priv_data_class librtmpe_class,.flags URL_PROTOCOL_FLAG_NETWORK, };RTMP_CLASS(rtmpte) const URLProtocol ff_librtmpte_protocol {.name rtmpte,.url_open rtmp_open,.url_read rtmp_read,.url_write rtmp_write,.url_close rtmp_close,.url_read_pause rtmp_read_pause,.url_read_seek rtmp_read_seek,.url_get_file_handle rtmp_get_file_handle,.priv_data_size sizeof(LibRTMPContext),.priv_data_class librtmpte_class,.flags URL_PROTOCOL_FLAG_NETWORK, };RTMP_CLASS(rtmps) const URLProtocol ff_librtmps_protocol {.name rtmps,.url_open rtmp_open,.url_read rtmp_read,.url_write rtmp_write,.url_close rtmp_close,.url_read_pause rtmp_read_pause,.url_read_seek rtmp_read_seek,.url_get_file_handle rtmp_get_file_handle,.priv_data_size sizeof(LibRTMPContext),.priv_data_class librtmps_class,.flags URL_PROTOCOL_FLAG_NETWORK, }; URLContext URLContext的定义也位于libavformat\url.h如下所示。 typedef struct URLContext {const AVClass *av_class; /** information for av_log(). Set by url_open(). */const 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 */const char *protocol_whitelist;const char *protocol_blacklist;int min_packet_size; /** if non zero, the stream is packetized with this min packet size */ } URLContext; 从代码中可以看出URLProtocol结构体是URLContext结构体的一个成员。由于还没有对URLContext结构体进行详细研究有关该结构体的代码不再做过多分析。
http://www.huolong8.cn/news/49999/

相关文章:

  • 乌克兰服装网站建设做购物网站适合的服务器
  • 新泰营销型网站建设硬件开发和软件开发
  • 成都logo设计公司排名宁波seo外包哪个品牌好
  • 周杰伦做的广告网站北京和隆优化怎么样
  • 做艺人资料卡的网站中国哪里建设最多
  • 外贸网站推广怎么样网站cname解析
  • 站长工具同大全站房车网站建设意义
  • 七初SEO网站建设找回我的微信
  • 响应式企业网站案例郑州网站开发douyanet
  • 帮别人做网站违法简单网站建设教学视频
  • 建一个国外网站多少钱wordpress金融模板
  • 建设网站 报告西瓜网站建设
  • 网站实现步骤及方法保险理财网站建设
  • 网站推广妙招网站外链资源
  • 网站建设技术合作合同文本文档做网站怎么加图片
  • 导入表格做地图中热力网站公司网络营销外包
  • 网站建站网站wordpress 分页文章静态化
  • 反网站搭建一条龙廊坊网站公司
  • 如何获取网站js图片阿玛尼手表
  • 苏州建站仿站o2o网站建设咨询
  • 做企业信用贷的网站西宁市建设网站公司电话
  • 广东建设厅的网站查询中国空间雷达卫星
  • 视频网站的制作教程讲究 网站
  • 网站迁移后 域名郑州高端网站定制公司
  • 长沙做网站建设行政单位单位网站建设
  • 香河做网站网站如何做分站
  • 淘宝导购网站备案如何登录中国建设银行网站
  • 建设网站价钱郑州网站推广公司服务
  • 厦门网站建设方案优化企业网站的首页设计
  • 大唐工作室 网站制作大连制作网站公司