FFmpeg - вывод имеет только первый кадр - PullRequest
0 голосов
/ 30 ноября 2018

Я работаю над простым 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;
...