0

I try to generate a video with a timebase more precise than the 1/fps (camera frame rate are not constant). But the generated AVI does not seem to take into account the framerate that I indicate.

#include <iostream>

extern "C" {
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
}

#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avformat.lib")

constexpr int TIMEFACTOR = 10;

static void encodeFrame(AVCodecContext *avctx, AVFormatContext *ctx, AVFrame* frame)
{
    int ret = avcodec_send_frame(avctx, frame);

    AVPacket packet;
    av_init_packet(&packet);
    ret = 0;
    while (ret >= 0) {
        ret = avcodec_receive_packet(avctx, &packet);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return;  // nothing to write
        };

        //packet.pts = (frame) ? frame->pts : packet.pts;
        av_packet_rescale_ts(&packet, avctx->time_base, ctx->streams[0]->time_base);
        packet.duration = TIMEFACTOR;
        av_interleaved_write_frame(ctx, &packet);
        av_packet_unref(&packet);
    }
}

static void fill_yuv_frame(AVFrame* frame, int width, int height, int frameId)
{
    // Y
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            frame->data[0][y * frame->linesize[0] + x] = x + y + frameId * 3;
        }
    }

    // Cb and Cr
    for (int y = 0; y < height / 2; y++) {
        for (int x = 0; x < width / 2; x++) {
            frame->data[1][y * frame->linesize[1] + x] = 128 + y + frameId * 2;
            frame->data[2][y * frame->linesize[2] + x] = 64 + x + frameId * 5;
        }
    }
}

int main(int argc, char** argv)
{
    const char filename[] = "output.avi";
    const char encoder[] = "mpeg4";
    constexpr int WIDTH = 640;
    constexpr int HEIGHT = 480;

    av_log_set_level(AV_LOG_DEBUG);

    //delete file because libavcodec reload file
    remove(filename);   

    AVFormatContext* ofmtCtx;
    int ret = avformat_alloc_output_context2(&ofmtCtx, NULL, "avi", filename);

    AVCodec* avcodec = avcodec_find_encoder_by_name(encoder);

    AVCodecContext*  avctx = avcodec_alloc_context3(avcodec);

    avctx->width = WIDTH ;
    avctx->height = HEIGHT ;    
    avctx->sample_aspect_ratio = { 1, 1 };
    avctx->pix_fmt = AV_PIX_FMT_YUV420P; //Do not work with other type

    avctx->codec_id = AV_CODEC_ID_MPEG4;
    avctx->bit_rate = 4 * 1000 * 1000;
    avctx->time_base = av_make_q(1, 25 * TIMEFACTOR);
    avctx->framerate = av_make_q(25, 1);
    avctx->ticks_per_frame = TIMEFACTOR;

    avctx->gop_size = 10;
    avctx->max_b_frames = 1;

    AVStream* m_outStream = avformat_new_stream(ofmtCtx, NULL);

    ret = avcodec_open2(avctx, avcodec, NULL);

    ret = avcodec_parameters_from_context(m_outStream->codecpar, avctx);

    m_outStream->time_base = avctx->time_base;
    m_outStream->r_frame_rate = avctx->framerate;
    m_outStream->avg_frame_rate = avctx->framerate;
    
    ret = avio_open(&(ofmtCtx->pb),
        filename,
        AVIO_FLAG_WRITE);

    ret = avformat_write_header(ofmtCtx, NULL);
    av_dump_format(ofmtCtx, 0, filename, 1);

    AVFrame * avframe = av_frame_alloc();

    avframe->format = avctx->pix_fmt;
    avframe->width = avctx->width;
    avframe->height = avctx->height;

    ret = av_frame_get_buffer(avframe, 0);

    ret = av_frame_make_writable(avframe);

    for (int i = 0; i < 25; ++i) {
        fflush(stdout);

        fill_yuv_frame(avframe, avctx->width, avctx->height, i);

        avframe->pts = i * TIMEFACTOR;

        encodeFrame(avctx, ofmtCtx, avframe);
    }

    encodeFrame(avctx, ofmtCtx, NULL);
    av_write_trailer(ofmtCtx);

    return 0;

}

And this is dump output :

[mpeg4 @ 000002AA64FA1880] intra_quant_bias = 0 inter_quant_bias = -64
[file @ 000002AA64F69AC0] Setting default whitelist 'file,crypto'
[avi @ 000002AA64F73400] reserve_index_space:0 master_index_max_size:256
[avi @ 000002AA64F73400] duration_est:36000.000, filesize_est:18.4GiB, master_index_max_size:256
Output #0, avi, to 'output.avi':
  Metadata:
    ISFT            : Lavf58.12.100
    Stream #0:0, 0, 1/250: Video: mpeg4, 1 reference frame (FMP4 / 0x34504D46), yuv420p, 640x480 (0x0) [SAR 1:1 DAR 4:3], 0/1, q=2-31, 4000 kb/s, 25 fps, 25 tbr, 250 tbn

But if I open the video in ffmpeg command line fps is 250, and video content 250 frames, with many dropframe.

themadmax
  • 2,344
  • 1
  • 31
  • 36

0 Answers0