欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > FFmpeg源码:retry_transfer_wrapper、ffurl_read2、ffurl_write2函数分析

FFmpeg源码:retry_transfer_wrapper、ffurl_read2、ffurl_write2函数分析

2024/10/24 16:33:11 来源:https://blog.csdn.net/u014552102/article/details/141285057  浏览:    关键词:FFmpeg源码:retry_transfer_wrapper、ffurl_read2、ffurl_write2函数分析

一、retry_transfer_wrapper函数

retry_transfer_wrapper函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/avio.c中:

static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf,const uint8_t *cbuf,int size, int size_min,int read)
{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 = read ? h->prot->url_read (h, buf + len, size - len):h->prot->url_write(h, cbuf + 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;
}

该函数作用是:对本地媒体文件或网络流进行读取或写入。如果是读取,将读上来的数据保存到形参buf指向的缓冲区中;如果是写入,将形参cbuf指向的缓冲区中的数据写入到本地媒体文件或网络流中。

形参h:输入型参数。 指向一个url(Uniform Resource Locator)上下文结构体。

形参buf:如果是要将数据写入到本地媒体文件或网络流中,该值为NULL;如果是要读取本地媒体文件或网络流的数据,buf为输出型参数,指向“保存读上来的数据的缓冲区”;

形参cbuf:如果是要读取本地媒体文件或网络流的数据,该值为NULL;如果是要将数据写入到本地媒体文件或网络流中,buf为输入型参数,指向“存放需要写入到文件或网络流中的数据的缓冲区”。

形参size:输入型参数。如果是要读取本地媒体文件或网络流的数据,size为要读取的字节数;如果是要将数据写入到本地媒体文件或网络流中,size为要写入文件的字节数。

形参size_min:输入型参数。值一般等于形参size的值。如果实际读取到或写入到文件的字节数小于size_min,会继续读取或写入,直到不小于size_min为止。

形参read:输入型参数。值为0表示是要将数据写入到本地媒体文件或网络流中;值为1表示是要读取本地媒体文件或网络流的数据。

返回值:返回一个非负数表示成功,此时返回实际读取到或实际写入文件的字节数;返回一个负数表示出错。

retry_transfer_wrapper函数内部的核心是下面语句,通过形参read的值来决定是执行h->prot->url_read还是h->prot->url_write。read的值为1会执行h->prot->url_read,表示是要读取本地媒体文件或网络流的数据;read的值为0时,会执行h->prot->url_write,表示是要将数据写入到本地媒体文件或网络流中:

ret = read ? h->prot->url_read (h, buf + len, size - len):h->prot->url_write(h, cbuf + len, size - len);

下面分两种情况讨论:

(一)情况一:形参read的值为1

h->prot->url_read是函数指针。当形参read的值为1时,会执行语句h->prot->url_read (h, buf + len, size - len),调用不同的回调函数。h->prot->url_read指向的回调函数都有“读取”作用:

typedef struct URLProtocol {
//...int     (*url_read)( URLContext *h, unsigned char *buf, int size);
//...
}

举几个例子:

1.当执行命令:ffmpeg -i XXX.wav 获取本地媒体文件(比如wav音频文件)的信息时,FFmpeg会调用retry_transfer_wrapper函数。该函数内部执行h->prot->url_read语句时会调用libavformat/file.c中的file_read函数读取本地媒体文件的内容。关于file_read函数的用法可以参考:《FFmpeg源码:file_read、file_write函数分析》。

2.当执行命令:ffmpeg -i "rtsp:XXX" 获取rtsp流的信息时,FFmpeg会调用retry_transfer_wrapper函数。该函数内部执行h->prot->url_read语句时会调用libavformat/tcp.c中的tcp_read函数从TCP连接的另一端接收数据。

3.推流端执行FFmpeg命令:ffmpeg.exe -re -i XXX.mp4 -vcodec copy -acodec copy -f rtp_mpegts rtp://127.0.0.1:6005,拉流端通过:ffmpeg -i rtp://127.0.0.1:6005获取该基于RTP协议的MPEG-2传输流(MPEG-2 Transport Stream)的信息时,拉流端的FFmpeg会调用retry_transfer_wrapper函数。该函数内部执行h->prot->url_read语句时会调用libavformat/rtpproto.c中的rtp_read函数接收UDP数据。

(二)情况二:形参read的值为0

h->prot->url_write是函数指针。当形参read的值为0时,会执行语句h->prot->url_write(h, cbuf + len, size - len),调用不同的回调函数。h->prot->url_write指向的回调函数都有“写入”作用:

typedef struct URLProtocol {
//...int     (*url_write)(URLContext *h, const unsigned char *buf, int size);
//...
}

举个例子:

当执行命令:./ffmpeg -ar 44100 -ac 2 -f s16le -acodec pcm_s16le -i XXX.pcm XXX.wav 将某个PCM文件转为WAV格式的音频文件时,FFmpeg会调用retry_transfer_wrapper函数。该函数内部执行h->prot->url_write语句时会调用libavformat/file.c中的file_write函数将数据写入到本地媒体文件(WAV格式的音频文件)。关于file_write函数的用法可以参考:《FFmpeg源码:file_read、file_write函数分析》。

二、ffurl_read2函数

ffurl_read2函数定义在源文件libavformat/avio.c中:

int ffurl_read2(void *urlcontext, uint8_t *buf, int size)
{URLContext *h = urlcontext;if (!(h->flags & AVIO_FLAG_READ))return AVERROR(EIO);return retry_transfer_wrapper(h, buf, NULL, size, 1, 1);
}

该函数作用是:对本地媒体文件或网络流进行读取。可以看到该函数内部调用了retry_transfer_wrapper函数。

形参urlcontext:输入型参数。 指向一个url(Uniform Resource Locator)上下文结构体。

形参buf:输出型参数。保存读上来的数据的缓冲区。

形参size:输入型参数。要读取的字节数。

返回值:返回一个非负数表示成功,此时返回实际读取到的字节数;返回一个负数表示出错。

三、ffurl_write2函数

ffurl_write2函数定义在源文件libavformat/avio.c中:

int ffurl_write2(void *urlcontext, const uint8_t *buf, int size)
{URLContext *h = urlcontext;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, NULL, buf, size, size, 0);
}

该函数作用是:对本地媒体文件或网络流进行写入。可以看到该函数内部调用了retry_transfer_wrapper函数。

形参urlcontext:输入型参数。 指向一个url(Uniform Resource Locator)上下文结构体。

形参buf:输入型参数。存放需要写入到文件或网络流中的数据的缓冲区。

形参size:输入型参数。要写入文件或网络流的字节数。

返回值:返回一个非负数表示成功,此时返回实际读写入文件或网络流的字节数;返回一个负数表示出错。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com