0
votes

Using the FFmpeg C API I'm trying to convert an input video into a video that looks like an animated gif - meaning no audio stream and a video stream of 4/fps.

I have the decode/encode part working. I can drop the audio stream from the output file, but I'm having trouble reducing the fps. I can change the output video stream's time_base to 4/fps, but it increases the video's duration - basically playing it in slow mo.

I think I need to drop the extra frames before I write them to the output container.

Below is the loop where I read the input frames, and then write them to output container.

Is this where I'd drop the extra frames? How do I determine which frames to drop (I,P,B frames)?

while(av_read_frame(input_container, &decoded_packet)>=0) {

    if (decoded_packet.stream_index == video_stream_index) {
        len = avcodec_decode_video2(input_stream->codec, decoded_frame, &got_frame, &decoded_packet);
        if(len < 0) {
            exit(1);
        }

        if(got_frame) {
            av_init_packet(&encoded_packet);
            encoded_packet.data =  NULL;
            encoded_packet.size =  0;

            if(avcodec_encode_video2(output_stream->codec, &encoded_packet, decoded_frame, &got_frame) < 0) {
                exit(1);
            }
            if(got_frame) {
                if (output_stream->codec->coded_frame->key_frame) {
                    encoded_packet.flags |= AV_PKT_FLAG_KEY;
                }

                encoded_packet.stream_index = output_stream->index;
                encoded_packet.pts = av_rescale_q(current_frame_num, output_stream->codec->time_base, output_stream->time_base);
                encoded_packet.dts = av_rescale_q(current_frame_num, output_stream->codec->time_base, output_stream->time_base);

                if(av_interleaved_write_frame(output_container, &encoded_packet) < 0) {
                    exit(1);
                }
                else {
                    current_frame_num +=1;
                }
            }
            frame_count+=1;
            av_free_packet(&encoded_packet);
        }
    }
}
1

1 Answers

1
votes

It looks like you are decoding then re-encoding the video. In the decoded state there is no such thing as I/B/P. They are all I frames. This is also where you should be dropping frames. You must decode every frame, but once decoded, drop the frames you no longer want by simply not sending them to the encoder. And finally, don't touch the timebase at all.