=====================================================
FFmpeg的库函数源代码分析文章列表:
【架构图】
FFmpeg源代码结构图 - 解码
FFmpeg源代码结构图 - 编码
【通用】
FFmpeg 源代码简单分析:av_register_all()
FFmpeg 源代码简单分析:avcodec_register_all()
FFmpeg 源代码简单分析:内存的分配和释放(av_malloc()、av_free()等)
FFmpeg 源代码简单分析:常见结构体的初始化和销毁(AVFormatContext,AVFrame等)
FFmpeg 源代码简单分析:avio_open2()
FFmpeg 源代码简单分析:av_find_decoder()和av_find_encoder()
FFmpeg 源代码简单分析:avcodec_open2()
FFmpeg 源代码简单分析:avcodec_close()
【解码】
图解FFMPEG打开媒体的函数avformat_open_input
FFmpeg 源代码简单分析:avformat_open_input()
FFmpeg 源代码简单分析:avformat_find_stream_info()
FFmpeg 源代码简单分析:av_read_frame()
FFmpeg 源代码简单分析:avcodec_decode_video2()
FFmpeg 源代码简单分析:avformat_close_input()
【编码】
FFmpeg 源代码简单分析:avformat_alloc_output_context2()
FFmpeg 源代码简单分析:avformat_write_header()
FFmpeg 源代码简单分析:avcodec_encode_video()
FFmpeg 源代码简单分析:av_write_frame()
FFmpeg 源代码简单分析:av_write_trailer()
【其它】
FFmpeg源代码简单分析:日志输出系统(av_log()等)
FFmpeg源代码简单分析:结构体成员管理系统-AVClass
FFmpeg源代码简单分析:结构体成员管理系统-AVOption
FFmpeg源代码简单分析:libswscale的sws_getContext()
FFmpeg源代码简单分析:libswscale的sws_scale()
FFmpeg源代码简单分析:libavdevice的avdevice_register_all()
FFmpeg源代码简单分析:libavdevice的gdigrab
【脚本】
FFmpeg源代码简单分析:makefile
FFmpeg源代码简单分析:configure
【H.264】
FFmpeg的H.264解码器源代码简单分析:概述
=====================================================
本文简单分析FFmpeg的avformat_close_input()函数。该函数用于关闭一个AVFormatContext,一般情况下是和avformat_open_input()成对使用的。
/**
* Close an opened input AVFormatContext. Free it and all its contents
* and set *s to NULL.
*/
void avformat_close_input(AVFormatContext **s);
该函数最典型的例子可以参考:
最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)
函数的调用关系如下图所示。
void avformat_close_input(AVFormatContext **ps)
{
AVFormatContext *s;
AVIOContext *pb;
if (!ps || !*ps)
return;
s = *ps;
pb = s->pb;
if ((s->iformat && strcmp(s->iformat->name, "image2") && s->iformat->flags & AVFMT_NOFILE) ||
(s->flags & AVFMT_FLAG_CUSTOM_IO))
pb = NULL;
flush_packet_queue(s);
if (s->iformat)
if (s->iformat->read_close)
s->iformat->read_close(s);
avformat_free_context(s);
*ps = NULL;
avio_close(pb);
}
(1)调用AVInputFormat的read_close()方法关闭输入流下面我们分别来看上述几个步骤。
(2)调用avformat_free_context()释放AVFormatContext
(3)调用avio_close()关闭并且释放AVIOContext
AVInputFormat ff_flv_demuxer = {
.name = "flv",
.long_name = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"),
.priv_data_size = sizeof(FLVContext),
.read_probe = flv_probe,
.read_header = flv_read_header,
.read_packet = flv_read_packet,
.read_seek = flv_read_seek,
.read_close = flv_read_close,
.extensions = "flv",
.priv_class = &flv_class,
};
static int flv_read_close(AVFormatContext *s)
{
int i;
FLVContext *flv = s->priv_data;
for (i=0; inew_extradata[i]);
return 0;
}
有关avformat_free_context()可以参考文章:
FFmpeg源代码简单分析:内存的分配和释放
avio_close()是一个FFmpeg的API函数,用于关闭和释放AVIOContext。它的声明位于libavformat\avio.h,如下所示。
/**
* Close the resource accessed by the AVIOContext s and free it.
* This function can only be used if s was opened by avio_open().
*
* The internal buffer is automatically flushed before closing the
* resource.
*
* @return 0 on success, an AVERROR < 0 on error.
* @see avio_closep
*/
int avio_close(AVIOContext *s);
int avio_close(AVIOContext *s)
{
URLContext *h;
if (!s)
return 0;
avio_flush(s);
h = s->opaque;
av_freep(&s->buffer);
if (s->write_flag)
av_log(s, AV_LOG_DEBUG, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count);
else
av_log(s, AV_LOG_DEBUG, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count);
av_free(s);
return ffurl_close(h);
}
(1)调用avio_flush()强制清除缓存中的数据
(2)调用av_freep()释放掉AVIOContext种的buffer
(3)调用av_free()释放掉AVIOContext结构体
(4)调用ffurl_close()关闭并且释放掉URLContext
下面按照顺序分别看看avio_flush()和ffurl_close()这两个函数。
/**
* Force flushing of buffered data.
*
* For write streams, force the buffered data to be immediately written to the output,
* without to wait to fill the internal buffer.
*
* For read streams, discard all currently buffered data, and advance the
* reported file position to that of the underlying stream. This does not
* read new data, and does not perform any seeks.
*/
void avio_flush(AVIOContext *s);
void avio_flush(AVIOContext *s)
{
flush_buffer(s);
s->must_flush = 0;
}
static void flush_buffer(AVIOContext *s)
{
if (s->write_flag && s->buf_ptr > s->buffer) {
writeout(s, s->buffer, s->buf_ptr - s->buffer);
if (s->update_checksum) {
s->checksum = s->update_checksum(s->checksum, s->checksum_ptr,
s->buf_ptr - s->checksum_ptr);
s->checksum_ptr = s->buffer;
}
}
s->buf_ptr = s->buffer;
if (!s->write_flag)
s->buf_end = s->buffer;
}
static void writeout(AVIOContext *s, const uint8_t *data, int len)
{
if (s->write_packet && !s->error) {
int ret = s->write_packet(s->opaque, (uint8_t *)data, len);
if (ret < 0) {
s->error = ret;
}
}
s->writeout_count ++;
s->pos += len;
}
从定义可以看出,writeout()调用了AVIOContext的write_packet()方法。根据此前文章《FFmpeg源代码简单分析:avio_open2()》中的分析我们可以了解到,AVIOContext的write_packet()实际指向了ffurl_write()函数,而ffurl_write()经过retry_transfer_wrapper()函数最终调用了URLProtocol的url_write()函数。url_write()是一个函数指针,不同的URLProtocol的url_write()指向不同的函数。
例如,file(文件)对应的URLProtocol的定义位于libavformat\file.c,如下所示。
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,
};
static int file_write(URLContext *h, const unsigned char *buf, int size)
{
FileContext *c = h->priv_data;
int r;
size = FFMIN(size, c->blocksize);
r = write(c->fd, buf, size);
return (-1 == r)?AVERROR(errno):r;
}
/**
* Close the resource accessed by the URLContext h, and free the
* memory used by it. Also set the URLContext pointer to NULL.
*
* @return a negative value if an error condition occurred, 0
* otherwise
*/
int ffurl_closep(URLContext **h);
int ffurl_close(URLContext *h);
int ffurl_close(URLContext *h)
{
return ffurl_closep(&h);
}
int ffurl_closep(URLContext **hh)
{
URLContext *h= *hh;
int ret = 0;
if (!h)
return 0; /* can happen when ffurl_open fails */
if (h->is_connected && h->prot->url_close)
ret = h->prot->url_close(h);
#if CONFIG_NETWORK
if (h->prot->flags & URL_PROTOCOL_FLAG_NETWORK)
ff_network_close();
#endif
if (h->prot->priv_data_size) {
if (h->prot->priv_data_class)
av_opt_free(h->priv_data);
av_freep(&h->priv_data);
}
av_freep(hh);
return ret;
}
(1)调用URLProtocol的url_close()其中URLProtocol的url_close()是一个函数指针,其指向的函数与具体的URLProtocol有关,这里我们还是看一下file(文件)对应的URLProtocol,如下所示。
(2)调用av_freep()释放URLContext结构体
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,
};
static int file_close(URLContext *h)
{
FileContext *c = h->priv_data;
return close(c->fd);
}
至此avio_close()函数分析完毕。
雷霄骅
[email protected]
http://blog.csdn.net/leixiaohua1020