先看一下我调试时,发现程序崩溃的代码位置
|
//这是我的程序释放流上下文时的操作 |
|
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; |
|
} |
1. 在一次释放文件流上下文的调试中,发现调用avformat_close_input
函数时程序崩溃退出。查看函数内部
功能
- Close an opened input AVFormatContext.(关闭打开的输入AVFormatContext)
- Free it and all its contents and set s to NULL.(释放它和它的所有内容,并设置为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); |
|
} |
2. 经过排查,发现是在内部调用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)
处发生崩溃错误。为什么在释放这个参数时会崩溃?由于这些函数内部的参数太多且不好理解,我没有深究下去
3. 百度"调用avformat_free_context崩溃",发现一篇博主文章 [ 关于avformat_free_context释放流上下文的一些问题 ]里面说到一句话:
|
//下面是释放上下文的步骤顺序 |
|
sws_freeContext(pSwsContext); |
|
av_frame_free(&pAVFrame); |
|
avcodec_close(pAVCodecContext); |
|
avformat_close_input(&pAVFormatContext); |
-
释放顺序不能错,如果想关闭一个取流地址不能单独调用avformat_close_input(&pAVFormatContext);
-
因为调用avformat_close_input释放文件流上下文时,如果里面的一些结构体在之前没有被提前释放掉,会导致程序崩溃。
4. 打开代码调试,查看调用顺序,经过一番查找后,发现没有调用顺序没有问题。但是有一个地方是跟上面代码不同的地方,是释放解码器上下文时,我使用到新的API接口avcodec_free_context
而不是avcodec_close
,于是尝试换成avcodec_close
重新运行,发现没有问题了!
|
//这是我的程序释放流上下文时的操作 |
|
if(m_pAvFormatContext) |
|
{ |
|
//释放视频解码器上下文 |
|
if(m_iVideoStreamIndex >= 0) |
|
avcodec_close(&m_pVideoDecodeContext); //修改此处则可以正常运行 |
|
|
|
//释放音频解码器上下文 |
|
if(m_iAudioStreamIndex >= 0) |
|
avcodec_close(&m_pAudioDecodeContext); //修改此处则可以正常运行 |
|
|
|
//释放文件流上下文 |
|
avformat_close_input(&m_pAvFormatContext); |
|
avformat_free_context(m_pAvFormatContext); |
|
m_pAvFormatContext = YNULL; |
|
} |
5. 去ffmpeg官网查看函数解析
AVCodecContext* avcodec_alloc_context3 (const AVCodec * codec)
功能
- 分配一个AVCodecContext,并将其字段设置为默认值。
- 结果由avcodec_free_context()释放
参数
- 如果非null,分配私有数据并初始化给定编解码器的默认值。使用不同的编解码器调用avcodec_open2()是非法的。
- 如果为NULL,那么特定于编解码器的默认值将不会被初始化,这可能会导致默认设置不理想(这对于编码器(例如libx264)尤为重要)。
返回值
- 一个用默认值填充的AVCodecContext,失败时返回NULL。
|
//通过传入的音频、视频编码器名字查找编码器 |
|
AVCodec * codec = avcodec_find_decoder(AV_CODEC_ID_H264); |
|
if (!codec) |
|
exit(1); |
|
|
|
//分配音频、视频编码器上下文,并初始化 |
|
AVCodecContext * context = avcodec_alloc_context3(codec); |
|
if (avcodec_open2(context, codec, YNULL) < 0) |
|
exit(1); |
|
|
|
//释放音频、视频解码器上下文 |
|
avcodec_free_context(c); |
avcodec_open2函数介绍:
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
功能
- 初始化AVCodecContext以使用给定的AVCodec
- 在使用此函数之前,必须为上下文分配avcodec_alloc_context3()
6. 我使用另外一种方式去分配解码器上下文,则使用avcodec_close()
释放解码器上下文
|
//分配视频解码器上下文 |
|
AVCodecContext * pVideoDecodeContext = YNULL; |
|
pVideoDecodeContext = m_pAvFormatContext->streams[m_iVideoStreamIndex]->codec; |
|
|
|
//分配音频解码器上下文 |
|
AVCodecContext * pAudioDecodeContext = YNULL; |
|
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, YNULL) |
|
|
|
//释放音频、视频解码器 |
|
avcodec_close(m_pVideoDecodeContext); |
综上所述,是因为不正常释放解码器上下文导致的崩溃。
分类:
ffmpeg、ffplay
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2018-08-11 【Darwin学习笔记】之TaskThread
2017-08-11 Linux下PostgreSQL 的安装与配置
2017-08-11 PostgreSQL 连接问题 FATAL: no pg_hba.conf entry for host
2017-08-11 PostgreSQ 连接问题 FATAL: no pg_hba.conf entry for host
2017-08-11 中文环境下PostgreSQL的使用
2017-08-11 初学者遇到的PostgreSQL字符集问题的解决
2017-08-11 PostgreSQL 图形化客户端工具有哪些