参考博客:https://blog.csdn.net/leixiaohua1020/article/details/44110683
void avformat_close_input(AVFormatContext **ps)
{
AVFormatContext *s;
AVIOContext *pb;
//“不存在” 直接返回
if (!ps || !*ps)
return;
s = *ps;
pb = s->pb;
//image2是什么格式?为什么要单独处理
if ((s->iformat && strcmp(s->iformat->name, "image2") && s->iformat->flags & AVFMT_NOFILE) ||
(s->flags & AVFMT_FLAG_CUSTOM_IO))
pb = NULL;
//清理:parse_queue packet_buffer raw_packet_buffer
flush_packet_queue(s);
//read_close为函数指针,具体与iformat相关
if (s->iformat)
if (s->iformat->read_close)
s->iformat->read_close(s);
//释放AVFormatContext结构体
avformat_free_context(s);
*ps = NULL;
//释放AVIOContext结构体
avio_close(pb);
}
//==================================
//read_close是一个函数指针,作用是关闭输入流
//此为rtsp_read_close,网络流
static int rtsp_read_close(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN))
ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
ff_rtsp_close_streams(s);
ff_rtsp_close_connections(s);
ff_network_close();
rt->real_setup = NULL;
av_freep(&rt->real_setup_cache);
return 0;
}
//====================================================
//flv_read_close关闭文件流
//主要是释放一些关键的指针
static int flv_read_close(AVFormatContext *s)
{
int i;
FLVContext *flv = s->priv_data;
for (i=0; i<FLV_STREAM_TYPE_NB; i++)
av_freep(&flv->new_extradata[i]);
av_freep(&flv->keyframe_times);
av_freep(&flv->keyframe_filepositions);
return 0;
}
//=====================================================
//avformat_free_context是释放AVFormatContext结构体,及所有的流
void avformat_free_context(AVFormatContext *s)
{
int i;
if (!s)
return;
if (s->oformat && s->oformat->deinit && s->internal->initialized)
s->oformat->deinit(s);
/* 下面是调用了一系列的函数进行释放操作 */
av_opt_free(s);
if (s->iformat && s->iformat->priv_class && s->priv_data)
av_opt_free(s->priv_data);
if (s->oformat && s->oformat->priv_class && s->priv_data)
av_opt_free(s->priv_data);
for (i = 0; i < s->nb_streams; i++)//遍历所有的流并释放
free_stream(&s->streams[i]);
s->nb_streams = 0;//number置零
for (i = 0; i < s->nb_programs; i++) {//遍历所有的programes并释放
av_dict_free(&s->programs[i]->metadata);
av_freep(&s->programs[i]->stream_index);
av_freep(&s->programs[i]);
}
s->nb_programs = 0;//置零
av_freep(&s->programs);
av_freep(&s->priv_data);
while (s->nb_chapters--) {//遍历所有的chapters并释放
av_dict_free(&s->chapters[s->nb_chapters]->metadata);
av_freep(&s->chapters[s->nb_chapters]);
}
av_freep(&s->chapters);
av_dict_free(&s->metadata);
av_dict_free(&s->internal->id3v2_meta);
av_packet_free(&s->internal->pkt);
av_packet_free(&s->internal->parse_pkt);
av_freep(&s->streams);
flush_packet_queue(s);
for (int i = 0; i < count; ++i)
{
/* code */
} av_freep(&s->internal);
av_freep(&s->url);
av_free(s);
}
//================================================================
//avio_close函数的作用:关闭AVIOContext并释放
//仅当avio_open打开了s时有效
int avio_close(AVIOContext *s)
{
URLContext *h;
if (!s)
return 0;
avio_flush(s);//调用函数avio_flush
h = s->opaque;
s->opaque = NULL;
av_freep(&s->buffer);
if (s->write_flag)
av_log(s, AV_LOG_VERBOSE, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count);
else
av_log(s, AV_LOG_VERBOSE, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count);
av_opt_free(s);
avio_context_free(&s);
//调用函数ffurl_close
return ffurl_close(h);
}
//========================================================
//ffurl_close函数调用ffurl_closep
//功能:关闭URLContext并释放
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);//url_close函数指针,与protocol相关
// prot: const struct URLProtocol *prot;
#if CONFIG_NETWORK
if (h->prot->flags & URL_PROTOCOL_FLAG_NETWORK)
ff_network_close();//network
#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_opt_free(h);
av_freep(hh);
return ret;
}