我遇到了用libav解码简单PNG图像的问题。调用decode_ok
后的avcodec_decode_video2
标志设置为0
,即使数据包包含整个图像。通过一些实验,我设法找出了问题,这似乎与调用avformat_find_stream_info
有关。如果删除了调用,则示例将成功运行。但是,我想对其他媒体使用相同的代码,并且在文档中建议调用avformat_find_stream_info
。
以下最小示例说明了行为(遗憾的是仍然有点冗长):
#include <iostream>
extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}
// Nothing to see here, it's just a helper function
AVCodecContext* open(AVMediaType mediaType, AVFormatContext* formatContext)
{
auto ret = 0;
if ((ret = av_find_best_stream(formatContext, mediaType, -1, -1, nullptr, 0)) < 0)
{
std::cerr << "Failed to find video stream." << std::endl;
return nullptr;
}
auto codecContext = formatContext->streams[ret]->codec;
auto codec = avcodec_find_decoder(codecContext->codec_id);
if (!codec)
{
std::cerr << "Failed to find codec." << std::endl;
return nullptr;
}
if ((ret = avcodec_open2(codecContext, codec, nullptr)) != 0)
{
std::cerr << "Failed to open codec context." << std::endl;
return nullptr;
}
return codecContext;
}
// All the interesting bits are here
int main(int argc, char* argv[])
{
auto path = "/path/to/test.png"; // Replace with valid path to PNG
auto ret = 0;
av_log_set_level(AV_LOG_DEBUG);
av_register_all();
avcodec_register_all();
auto formatContext = avformat_alloc_context();
if ((ret = avformat_open_input(&formatContext, path, NULL, NULL)) != 0)
{
std::cerr << "Failed to open input." << std::endl;
return -1;
}
av_dump_format(formatContext, 0, path, 0);
//*/ Info is successfully found, but interferes with decoding
if((ret = avformat_find_stream_info(formatContext, nullptr)) < 0)
{
std::cerr << "Failed to find stream info." << std::endl;
return -1;
}
av_dump_format(formatContext, 0, path, 0);
//*/
auto codecContext = open(AVMEDIA_TYPE_VIDEO, formatContext);
AVPacket packet;
av_init_packet(&packet);
if ((ret = av_read_frame(formatContext, &packet)) < 0)
{
std::cerr << "Failed to read frame." << std::endl;
return -1;
}
auto frame = av_frame_alloc();
auto decode_ok = 0;
if ((ret = avcodec_decode_video2(codecContext, frame, &decode_ok, &packet)) < 0 || !decode_ok)
{
std::cerr << "Failed to decode frame." << std::endl;
return -1;
}
av_frame_free(&frame);
av_free_packet(&packet);
avcodec_close(codecContext);
avformat_close_input(&formatContext);
av_free(formatContext);
return 0;
}
avformat_find_stream_info
之前的格式转储打印:
Input #0, image2, from '/path/to/test.png': Duration: N/A, bitrate: N/A Stream #0:0, 0, 1/25: Video: png, 25 tbn
avformat_find_stream_info
打印后的格式转储:
Input #0, image2, from '/path/to/test.png': Duration: 00:00:00.04, start: 0.000000, bitrate: N/A Stream #0:0, 1, 1/25: Video: png, rgba, 512x512 [SAR 3780:3780 DAR 1:1], 1/25, 25 tbr, 25 tbn, 25 tbc
所以看起来搜索会产生潜在有用的信息。任何人都可以对这个问题有所了解吗?其他图像格式似乎工作正常。我认为这是一个简单的用户错误而不是错误。
编辑:已启用调试日志记录,但PNG解码器不会产生大量输出。我也尝试过设置自定义日志回调。
这是我在没有调用avformat_find_stream_info
时获得的,当解码成功时:
Statistics: 52125 bytes read, 0 seeks
以下是解码失败时对avformat_find_stream_info
的调用所得到的内容:
Statistics: 52125 bytes read, 0 seeks detected 8 logical cores
图像为52125字节,因此读取整个文件。我不确定逻辑内核是指什么。
答案 0 :(得分:3)
似乎是libav中的一些多线程问题。 禁用多线程可以解决问题。
codecContext->thread_count=1;
if ((ret = avcodec_open2(codecContext, codec, nullptr)) < 0)
{
std::cerr << "Failed to open codec context." << std::endl;
return nullptr;
}