Вызов avformat_find_stream_info предотвращает декодирование простого изображения PNG?

Я сталкиваюсь с проблемой декодирования простого изображения PNG с помощью libav. 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 печатает:

Введите # 0, image2, из '/path/to/test.png':
Продолжительность: N / A, битрейт: N / A
Поток № 0: 0, 0, 1/25: видео: png, 25 тбн

Формат дампа после avformat_find_stream_info печатает:

Введите # 0, image2, из '/path/to/test.png':
Продолжительность: 00: 00: 00.04, начало: 0.000000, битрейт: нет данных
Поток № 0: 0, 1, 1/25: видео: png, rgba, 512x512 [SAR 3780: 3780 DAR 1: 1], 1/25, 25 тбр, 25 тбн, 25 тбк

Похоже, что поиск дает потенциально полезную информацию. Кто-нибудь может пролить свет на эту проблему? Другие форматы изображений, кажется, работают нормально. Я предполагаю, что это простая ошибка пользователя, а не ошибка.

Редактировать: Ведение журнала отладки уже включено, но декодер PNG не выдает много выходных данных. Я также попытался установить пользовательский обратный вызов журнала.

Вот что я получаю без звонка avformat_find_stream_infoпри успешном декодировании:

Статистика: 52125 байт прочитано, 0 ищет

И вот что я получаю с призывом avformat_find_stream_infoпри неудачном декодировании:

Статистика: 52125 байт прочитано, 0 ищет

обнаружено 8 логических ядер

Размер изображения составляет 52125 байт, поэтому весь файл читается. Я не уверен, на что ссылаются логические ядра.

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;
}
3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]