Shahroz Tariq
Shahroz Tariq

Reputation: 33

Increase Duration of a video FFMPEG C++

I am using the code from the samples of FFmpeg which encodes a picture into a video. All I want to do is to give it a series of pictures and it gives me a video with each picture is taking one second`Code below is just taking one picture from my file system & creating video from it

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");`

Upvotes: 1

Views: 2054

Answers (2)

Ronald S. Bultje
Ronald S. Bultje

Reputation: 11184

You're trying to encode a h264 video and then write the encoded data as-is to a file. I think what you're trying to do is write an annexb h264 file. Look for writing files using libavformat, and select the one called "h264" (that's basically an annexb writer). See this link for more documentation on muxing.

OK, now your question: 1 fps. I'm not sure that's a valid value in annexb, but anyway. See the following code in ffmpeg's 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;

Since annexb just takes the codec parameters as is, in this particular case, changing AVCodecContext.time_base will be sufficient to indicate your desired frame-rate. However, typically, the container will specify timestamps and framerates, and you want to set appropriate timestamps in the pts/dts fields of the AVPacket that you're writing using libavformat. In other words, AVCodecContext.time_base only works for annexb, AVPacket.pts/dts in AV_TIME_BASE units is required for container formats like mp4 or mkv.

Upvotes: 1

Maxito
Maxito

Reputation: 629

In this part of your code

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

You're setting your time base to 25FPS (Frames per second), you can just change this to the desired FPS.

More info: AVCodecContext::time_base

Upvotes: 0

Related Questions