由 libavcodec 返回的损坏的 AVFrame
Corrupt AVFrame returned by libavcodec
作为一个更大项目的一部分,我正在尝试同时解码许多高清(1920x1080)视频流。每个视频流都以原始 yuv420p 格式存储在 AVI 容器中。我有一个解码器类,从中我可以在不同的线程中创建许多对象(每个线程一个对象)。Decoder 中的两个主要方法是 decode()
和 getNextFrame()
,我在下面提供实现。
当我分离解码逻辑并使用它来解码单个流时,一切正常。但是,当我使用多线程代码时,我得到一个分段错误,程序在解码循环中的处理代码中崩溃。经过一番调查,我意识到getNextFrame()
填写的AVFrame
的数据数组包含超出范围的地址(根据 gdb)。
我真的迷路了!我没有做任何会改变代码中AVFrame
内容的事情。我尝试访问AVFrame的唯一地方是当我调用sws_scale()
来转换颜色格式时,这就是由于AVFrame
损坏而在第二种情况下发生分割错误的地方。非常感谢任何关于为什么会发生这种情况的建议。提前谢谢。
decode()
方法:
void decode() {
QString filename("video.avi");
AVFormatContext* container = 0;
if (avformat_open_input(&container, filename.toStdString().c_str(), NULL, NULL) < 0) {
fprintf(stderr, "Could not open %sn", filename.toStdString().c_str());
exit(1);
}
if (avformat_find_stream_info(container, NULL) < 0) {
fprintf(stderr, "Could not find file info..n");
}
// find a video stream
int stream_id = -1;
for (unsigned int i = 0; i < container->nb_streams; i++) {
if (container->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
stream_id = i;
break;
}
}
if (stream_id == -1) {
fprintf(stderr, "Could not find a video stream..n");
}
av_dump_format(container, stream_id, filename.toStdString().c_str(), false);
// find the appropriate codec and open it
AVCodecContext* codec_context = container->streams[stream_id]->codec; // Get a pointer to the codec context for the video stream
AVCodec* codec = avcodec_find_decoder(codec_context->codec_id); // Find the decoder for the video stream
if (codec == NULL) {
fprintf(stderr, "Could not find a suitable codec..n");
return -1; // Codec not found
}
// Inform the codec that we can handle truncated bitstreams -- i.e.,
// bitstreams where frame boundaries can fall in the middle of packets
if (codec->capabilities & CODEC_CAP_TRUNCATED)
codec_context->flags |= CODEC_FLAG_TRUNCATED;
fprintf(stderr, "Codec: %sn", codec->name);
// open the codec
int ret = avcodec_open2(codec_context, codec, NULL);
if (ret < 0) {
fprintf(stderr, "Could not open the needed codec.. Error: %dn", ret);
return -1;
}
// allocate video frame
AVFrame *frame = avcodec_alloc_frame(); // deprecated, should use av_frame_alloc() instead
if (!frame) {
fprintf(stderr, "Could not allocate video frame..n");
return -1;
}
int frameNumber = 0;
// as long as there are remaining frames in the stream
while (getNextFrame(container, codec_context, stream_id, frame)) {
// Processing logic here...
// AVFrame data array contains three addresses which are out of range
}
// freeing resources
av_free(frame);
avcodec_close(codec_context);
avformat_close_input(&container);
}
getNextFrame()
方法:
bool getNextFrame(AVFormatContext *pFormatCtx,
AVCodecContext *pCodecCtx,
int videoStream,
AVFrame *pFrame) {
uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
char buf[1024];
int len;
int got_picture;
AVPacket avpkt;
av_init_packet(&avpkt);
memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
// read data from bit stream and store it in the AVPacket object
while(av_read_frame(pFormatCtx, &avpkt) >= 0) {
// check the stream index of the read packet to make sure it is a video stream
if(avpkt.stream_index == videoStream) {
// decode the packet and store the decoded content in the AVFrame object and set the flag if we have a complete decoded picture
avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &avpkt);
// if we have completed decoding an entire picture (frame), return true
if(got_picture) {
av_free_packet(&avpkt);
return true;
}
}
// free the AVPacket object that was allocated by av_read_frame
av_free_packet(&avpkt);
}
return false;
}
锁管理回调函数:
static int lock_call_back(void ** mutex, enum AVLockOp op) {
switch (op) {
case AV_LOCK_CREATE:
*mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
pthread_mutex_init((pthread_mutex_t *)(*mutex), NULL);
break;
case AV_LOCK_OBTAIN:
pthread_mutex_lock((pthread_mutex_t *)(*mutex));
break;
case AV_LOCK_RELEASE:
pthread_mutex_unlock((pthread_mutex_t *)(*mutex));
break;
case AV_LOCK_DESTROY:
pthread_mutex_destroy((pthread_mutex_t *)(*mutex));
free(*mutex);
break;
}
return 0;
}
我找出了问题的原因。这是获取解码帧时返回前av_free_packet()
调用。我注释掉了那个电话,程序有效!不过,我仍然不太确定为什么这会影响填充AVFrame
。
我也不确定删除该调用是否会导致我的代码中出现内存泄漏。
希望libavcodec专家可以对此有所了解,并解释我做错了什么。
相关文章:
- 为什么会发生堆损坏
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 平均图像时图像损坏
- 如何针对特定情况调试和修复此双自由内存损坏问题
- 为什么C中的通用链表中存储的数据已损坏
- gdb错误:Backtrace已停止:上一帧与此帧相同(堆栈已损坏?)
- C++双重释放或损坏(out)
- 捕获标准输出以压缩并使用 CTRL-C 中断会给出损坏的 zip 文件
- 使用全局声明的向量时,C++双重释放错误/损坏
- 变量周围的堆栈'...'已损坏
- 运行时检查失败 #2 变量"A"周围的堆栈已损坏
- 如何将AVFrame转换为类
- 检测到堆损坏:在正常块 c++ 动态 2D 数组之后
- 删除字符串后C++检测到堆损坏
- 两个垫子的 OpenCV 数据是相同的,但使用 Mat::at 检索时的值已损坏
- 我可以写入关闭的套接字并强制纠正损坏的管道错误吗?
- 将FFMpeg AVFrame对象从C++应用程序流式传输到Python的最佳方法?
- 损坏的结构字符数组 - sqlite C++
- 运行时检查失败 #2 - 变量"e"周围的堆栈已损坏。发生
- 由 libavcodec 返回的损坏的 AVFrame