У меня есть коллекция последовательных необработанных изображений YUYV422, которые я хочу превратить в видео. Кажется, проблема в том, что при создании кадра в avcodec_receive_frame
. Кадр содержит только один канал вместо четырех в формате YUYV. Это приводит к Input picture width <640> is greater then stride (0)
, поскольку во фрейме установлен только нулевой индекс данных и размер строки. Я не знаю, является ли это ошибкой ffmpeg или неверной конфигурацией с моей стороны.
#include "icsFfmpegImageDecoder.h"
#include <stdexcept>
ImageDecoder::ImageDecoder(std::string filename)
{
AVInputFormat* iformat;
if (!(iformat = av_find_input_format("image2")))
throw std::invalid_argument(std::string("input Codec not found\n"));
this->fctx = NULL;
if (avformat_open_input(&this->fctx, filename.c_str(), iformat, NULL) < 0)
{
std::string error = "Failed to open input file ";
error += filename;
error += "\n";
throw std::invalid_argument(error);
}
#ifdef LIB_AVFORMAT_STREAM_CODEC_DEPRECATED
if (!(this->codec = avcodec_find_decoder(this->fctx->streams[0]->codecpar->codec_id)))
throw std::invalid_argument(std::string("Failed to find codec\n"));
if (!(this->cctx = avcodec_alloc_context3(this->codec)))
throw std::invalid_argument(std::string("could not create image read context codec"));
if (avcodec_parameters_to_context(this->cctx, this->fctx->streams[0]->codecpar) < 0)
throw std::invalid_argument(std::string("could not get contest codec from stream"));
#else
this->cctx = this->fctx->streams[0]->codec;
if (!(this->codec = avcodec_find_decoder(this->cctx->codec_id)))
throw std::invalid_argument(std::string("Failed to find codec\n"));
#endif
if (this->cctx->codec_id == AV_CODEC_ID_RAWVIDEO) {
// TODO Make Dynamic
this->cctx->pix_fmt = AV_PIX_FMT_YUYV422 ;
this->cctx->height = 800;
this->cctx->width = 1280;
}
if (avcodec_open2(this->cctx, this->codec, NULL) < 0)
throw std::invalid_argument(std::string("Failed to open codec\n"));
#ifdef USING_NEW_AVPACKET_SETUP
if (!(this->pkt = av_packet_alloc()))
throw std::invalid_argument(std::string("Failed to alloc frame\n"));
#else
this->pkt = new AVPacket();
av_init_packet(this->pkt);
#endif
read_file();
}
ImageDecoder::~ImageDecoder()
{
avcodec_close(this->cctx);
avformat_close_input(&this->fctx);
#ifdef USING_NEW_AVPACKET_SETUP
av_packet_free(&this->pkt);
#else
av_free_packet(this->pkt);
delete this->pkt;
#endif
}
void ImageDecoder::read_file()
{
if (av_read_frame(this->fctx, this->pkt) < 0)
throw std::invalid_argument(std::string("Failed to read frame from file\n"));
if (this->pkt->size == 0)
this->ret = -1;
}
#ifdef LIB_AVCODEC_USE_SEND_RECEIVE_NOTATION
void ImageDecoder::send_next_packet() {
if ((this->ret = avcodec_send_packet(this->cctx, this->pkt)) < 0)
throw std::invalid_argument("Error sending a packet for decoding\n");
}
bool ImageDecoder::receive_next_frame(AVFrame* frame)
{
if (this->ret >= 0)
{
this->ret = avcodec_receive_frame(this->cctx, frame);
if (this->ret == AVERROR_EOF)
return false;
else if (this->ret == AVERROR(11))//11 == EAGAIN builder sucks
return false;
else if (this->ret < 0)
throw std::invalid_argument("Error during decoding\n");
return true;
}
return false;
}
#else
void ImageDecoder::decode_frame(AVFrame* frame)
{
int got_frame = 0;
if (avcodec_decode_video2(this->cctx, frame, &got_frame, this->pkt) < 0)
throw std::invalid_argument("Error while decoding frame %d\n");
}
#endif