增加视频 FFMPEG C++ 的持续时间

Increase Duration of a video FFMPEG C++

我正在使用 FFmpeg 样本中的代码,将图片编码成视频。我想要做的就是给它一系列图片,它给了我一个视频,每张图片都需要一秒钟`下面的代码只是从我的文件系统中拍摄一张照片并从中创建视频

AVCodec *codec;
AVCodecContext *c = NULL;
int i, ret, x, y, got_output;
FILE *f;

AVPacket pkt;
uint8_t endcode[] = { 0, 0, 1, 0xb7 };

printf("Encode video file %s\n", filename);

/* find the mpeg1 video encoder */
codec = avcodec_find_encoder((AVCodecID)codec_id);
if (!codec)
{
    fprintf(stderr, "Codec not found\n");
    exit(1);
}

c = avcodec_alloc_context3(codec);
if (!c)
{
    fprintf(stderr, "Could not allocate video codec context\n");
    exit(1);
}

/* put sample parameters */
c->bit_rate = 400000;
/* resolution must be a multiple of two */
c->width = 200;
c->height = 200;
/* frames per second */
AVRational rational;
rational.num = 1;
rational.den = 25;
c->time_base = rational;
/* emit one intra frame every ten frames
* check frame pict_type before passing frame
* to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
* then gop_size is ignored and the output of encoder
* will always be I frame irrespective to gop_size
*/
c->gop_size = 10;
c->max_b_frames = 1;
c->pix_fmt = AV_PIX_FMT_YUV420P;

if (codec_id == AV_CODEC_ID_H264)
    av_opt_set(c->priv_data, "preset", "slow", 0);

/* open it */
if (avcodec_open2(c, codec, NULL) < 0)
{
    fprintf(stderr, "Could not open codec\n");
    exit(1);
}

fopen_s(&f, filename, "wb");
if (!f)
{
    fprintf(stderr, "Could not open %s\n", filename);
    exit(1);
}
AVFrame *frame = OpenImage("..\..\..\..\..\..\1.jpg");
//frame = av_frame_alloc();
if (!frame)
{
    fprintf(stderr, "Could not allocate video frame\n");
    exit(1);
}

frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
/* the image can be allocated by any means and av_image_alloc() is
* just the most convenient way if av_malloc() is to be used */

int screenHeight = 200;
int screenWidth = 200;
for (i = 0; i < 25; i++)
{
    av_init_packet(&pkt);
    pkt.data = NULL;    // packet data will be allocated by the encoder
    pkt.size = 0;

    fflush(stdout);



    frame->pts = i;

    /* encode the image */
    ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
    if (ret < 0)
    {
        fprintf(stderr, "Error encoding frame\n");
        exit(1);
    }

    if (got_output)
    {
        printf("Write frame %3d (size=%5d)\n", i, pkt.size);
        fwrite(pkt.data, 1, pkt.size, f);
        av_free_packet(&pkt);
    }
}

/* get the delayed frames */
for (got_output = 1; got_output; i++)
{
    fflush(stdout);

    ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
    if (ret < 0)
    {
        fprintf(stderr, "Error encoding frame\n");
        exit(1);
    }

    if (got_output)
    {
        printf("Write frame %3d (size=%5d)\n", i, pkt.size);
        fwrite(pkt.data, 1, pkt.size, f);
        av_free_packet(&pkt);
    }
}

/* add sequence end code to have a real mpeg file */
fwrite(endcode, 1, sizeof(endcode), f);
fclose(f);

avcodec_close(c);
av_free(c);
av_freep(&frame->data[0]);
av_frame_free(&frame);
printf("\n");`

在这部分代码中

/* frames per second */
AVRational rational;
rational.num = 1;
rational.den = 25;
c->time_base = rational;

您正在将时基设置为 25FPS(每秒帧数),您只需将其更改为所需的 FPS。

更多信息:AVCodecContext::time_base

您正在尝试对 h264 视频进行编码,然后将编码后的数据按原样写入文件。我想你要做的是写一个 annexb h264 文件。寻找使用 libavformat 的写入文件,以及 select 称为 "h264" 的文件(这基本上是一个 annexb 写入器)。有关 muxing 的更多文档,请参阅此 link

好的,现在你的问题是:1 fps。我不确定这在 annexb 中是否有效,但无论如何。参见ffmpeg的libavcodec/libx264.c:

中的如下代码
x4->params.i_fps_num = avctx->time_base.den;
x4->params.i_fps_den = avctx->time_base.num * avctx->ticks_per_frame;

由于 annexb 只是按原样采用编解码器参数,在这种特殊情况下,更改 AVCodecContext.time_base 就足以表明您想要的帧速率。但是,通常情况下,容器会指定时间戳和帧率,并且您想在使用 libavformat 编写的 AVPacket 的 pts/dts 字段中设置适当的时间戳。换句话说,AVCodecContext.time_base 仅适用于 annexb,AVPacket。pts/dts in AV_TIME_BASE 单位是 mp4 或 mkv 等容器格式所必需的。