Я работаю над простым 3-кадровым анимированным GIF и пытаюсь получить тот же GIF, что и вывод, после уменьшения каждого кадра.
Программа, кажется, работает хорошо, за исключением того факта, что вывод имеет только один кадр (без анимации, только первый кадр).Какая ошибка кодирования может быть причиной этой проблемы?
- Я устанавливаю кодировщик
time_base
на вход AVStream.time_base
, который в моем случае равен 1/100 - Iпишу каждый кадр с помощью
av_interleaved_write_frame
, устанавливая пакет pts
на вход AVFrame.pts
(который бывает 0, 40 и 80) - Я точно знаю, что функция записи вызывается три раза сэти очкиВыходной GIF, проанализированный на https://ezgif.com/split, на самом деле содержит 3 кадра .Но все они идентичны.
Я уверен, что это ошибка в моей программе, поэтому я надеюсь, что кто-то может дать некоторые подсказки относительно того, почему это может происходить при мультиплексировании (неправильное повторное использование некоторого буфера,....).
Ниже приведены наиболее важные части (я начинающий):
Основная функция:
extern "C" int compress(Context* context) {
context->error = avformat_write_header(context->outFormat, &context->inFormat->metadata);
if (hasError(context, "Writing headers")) return context->error;
while (av_read_frame(context->inFormat, context->inPacket) >= 0) {
AVPacket origPacket = *context->inPacket;
int temp;
do {
context->error = decodePacket(context);
if (hasError(context, "Decoding packet")) return context->error;
temp = context->error;
context->inPacket->data += temp;
context->inPacket->size -= temp;
} while (context->inPacket->size > 0);
av_packet_unref(&origPacket);
}
// flush cached frames and the decoder
context->inPacket->data = NULL;
context->inPacket->size = 0;
do {} while (decodePacket(context) > 0);
// Write the trailer
context->error = av_write_trailer(context->outFormat);
if (hasError(context, "Writing trailers")) return context->error;
return 0;
}
Функция decodePacket:
extern "C" int decodePacket(Context* context) {
int size = context->inPacket->size;
int used = avcodec_send_packet(context->decoder, context->inPacket);
if (used < 0) return used;
int error;
while (used >= 0) {
used = avcodec_receive_frame(context->decoder, context->inFrame);
if (used == AVERROR(EAGAIN) || used == AVERROR_EOF) {
return size;
} else if (used < 0) {
return used;
}
error = encodeFrame(context);
if (error < 0) return error;
}
return size;
}
Функция writeFrame:
extern "C" int encodeFrame(Context* context) {
sws_scale(context->scale, context->inFrame->data,
context->inFrame->linesize, 0,
context->inFrame->height, context->outFrame->data,
context->outFrame->linesize);
AVPacket packet = { 0 };
av_init_packet(&packet);
context->outFrame->pts = context->inFrame->pts;
int temp = avcodec_send_frame(context->encoder, context->outFrame);
if (temp < 0) return temp;
while (temp >= 0) {
temp = avcodec_receive_packet(context->encoder, &packet);
if (temp == AVERROR(EAGAIN) || temp == AVERROR_EOF) {
return 0;
} else if (temp < 0) {
return temp;
}
packet.pts = context->inFrame->pts;
int error = av_interleaved_write_frame(context->outFormat, &packet);
if (error < 0) {
return error;
}
}
return 0;
}
И, наконец, эта структура контекста, которая передается:
typedef struct Context {
Context() {}
AVFrame* inFrame = NULL;
AVFrame* outFrame = NULL;
AVStream* inStream = NULL;
AVStream* outStream = NULL;
AVFormatContext* outFormat = NULL;
AVFormatContext* inFormat = NULL;
struct SwsContext* scale = NULL;
AVCodecContext* decoder = NULL;
AVCodecContext* encoder = NULL;
AVCodec* decoderCodec = NULL;
AVCodec* encoderCodec = NULL;
AVPacket* inPacket = NULL;
int error = 0;
const char* inFilename = NULL;
const char* outFilename = NULL;
int inStreamId = -1; // Video
AVPixelFormat sourceFormat;
AVPixelFormat destFormat;
int sourceWidth, sourceHeight;
int destWidth, destHeight;
} Context;