先看一下我调试时,发现程序崩溃的代码位置
//这是我的程序释放流上下文时的操作
if(m_pAvFormatContext)
{
if(m_iVideoStreamIndex >= 0)
avcodec_free_context(&m_pVideoDecodeContext);
if(m_iAudioStreamIndex >= 0)
avcodec_free_context(&m_pAudioDecodeContext);
//此处发生崩溃
avformat_close_input(&m_pAvFormatContext);
avformat_free_context(m_pAvFormatContext);
m_pAvFormatContext = YNULL;
}
- 在一次释放流的上下文的调试中,发现调用avformat_close_input函数去释放时,程序崩溃退出。于是我就进入这个函数内部:
//函数功能简单介绍
Close an opened input AVFormatContext.
Free it and all its contents and set *s to NULL.
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;
if (s->iformat)
if (s->iformat->read_close)
s->iformat->read_close(s);
avformat_free_context(s);
*ps = NULL;
avio_close(pb);
}
- 我在程序中,直接将avformat_close_input函数所在的位置替换成以上函数,经过排查,发现是在内部调用avformat_free_context()函数时崩溃了。
- 进而我去研究avformat_free_context函数,查看avformat_free_context源码。
void avformat_free_context(AVFormatContext *s)
{
FFFormatContext *si;
if (!s)
return;
si = ffformatcontext(s);
if (s->oformat && s->oformat->deinit && si->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 (unsigned i = 0; i < s->nb_streams; i++)
ff_free_stream(&s->streams[i]);
s->nb_streams = 0;
for (unsigned i = 0; i < s->nb_programs; i++) {
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--) {
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(&si->id3v2_meta);
av_packet_free(&si->pkt);
av_packet_free(&si->parse_pkt);
av_freep(&s->streams);
ff_flush_packet_queue(s);
av_freep(&s->url);
av_free(s);
}
初步发现是在avformat_free_context内部的av_packet_free(&si->parse_pkt)处发生崩溃错误,这时候我就疑惑了,为什么在释放这个参数时会崩溃,为什么呢?由于这些函数内部的参数太多,而且不好理解,我就没有深究下去了。
-
进而,我去百度"调用avformat_free_context崩溃",发现一篇博主文章
里面说到一句话:
//下面是释放上下文的代码。 sws_freeContext(pSwsContext); av_frame_free(&pAVFrame); avcodec_close(pAVCodecContext); avformat_close_input(&pAVFormatContext);
-
这个顺序不能错,如果想关闭一个摄像头的取流地址不能单独调用avformat_close_input(&pAVFormatContext);
-
因为你释放掉这个内存,里面的一些结构体没有被释放会导致程序崩溃。
-
于是我打开代码去调试,查看调用顺序,经过一番查找后,发现没有调用顺序没有问题。但是有一个地方是跟上面代码不同的地方,是释放解码器上下文时,我使用到新的API接口
avcodec_free_context
而不是avcodec_close
,于是尝试换成avcodec_close
重新运行,发现没有问题了! -
为什么会这样呢,我带着问题去找答案。
原来要使用avcodec_free_context
去释放解码器上下文,是需要在分配解码器上下文时搭配使用avcodec_alloc_context3()
去分配
//通过传入的编码器名字查找编码器;
AVCodec *codec = avcodec_find_encoder_by_name(codec_name);
if (!codec) {
fprintf(stderr, "Codec '%s' not found\n", codec_name);
return -1;
}
//通过找到的AVCodec结构分配编码器上下文;
AVCodecContext *c = = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
return -1;
}
而我自己使用的是旧的方式去分配解码器上下文
//分配视频解码器上下文
AVCodecContext * m_pVideoDecodeContext;
m_pVideoDecodeContext = m_pAvFormatContext->streams[m_iVideoStreamIndex]->codec;
//分配音频解码器上下文
AVCodecContext * m_pAudioDecodeContext;
m_pAudioDecodeContext = m_pAvFormatContext->streams[m_iAudioStreamIndex]->codec;
//创建解码器
AVCodec * pVideoCodec = YNULL;
pVideoCodec = avcodec_find_decoder_by_name("h264_rkmpp_dec"); //arm的显示卡
avcodec_open2(m_pVideoDecodeContext, pVideoCodec, ¶m)
//官方案例
av_dict_set(&opts, "b", "2.5M", 0);
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec)
exit(1);
context = avcodec_alloc_context3(codec);
if (avcodec_open2(context, codec, opts) < 0)
exit(1);
avcodec_open2官方的解释:
Initialize the AVCodecContext to use the given AVCodec.
Prior to using this function the context has to be allocated with avcodec_alloc_context3().
初始化AVCodecContext以使用给定的AVCodec。
在使用此函数之前,必须为上下文分配avcodec_alloc_context3()。
综上所述,是自己对于ffmpeg函数的使用还没有炉火纯青。
标签:ffmpeg,avcodec,体时,free,avformat,context,av,close From: https://www.cnblogs.com/jj-Must-be-sucessful/p/16991504.html