I try to encode single pictures to a .avi video. The goal is to have every picture displayed for a set amount of seconds to create a slide show. I tried my script with 10 pictures and a delay of 1/5 of a second but the output file was not even half a second long (but displayed every picture). For setting the framerate I use the time_base option of the AVCodeContext:
ctx->time_base = (AVRational) {1, 5};
When I use the command ffmpeg -framerate 1/3 -i img%03d.png -codec png output.avi
everything works fine and I get the file I want. I use the png codec because it was the only one i tried that is playable with Windows Media Player.
Am I missing anything here? Is there another option that has impact on the framerate?
This is my code so far:
Note: I use a couple of self made data structures and methodes from other classes. They are the ones written in Caps Lock. They basicly do what the name suggests but are necessary for my project. The Input Array contains the pictures that i want to encode.
include <libavutil/opt.h>
include <libavutil/imgutils.h>
include <libavutil/error.h>
void PixmapsToAVI (ARRAY* arr, String outfile, double secs)
{
if (arr!=nil && outfile!="" && secs!=0) {
AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_PNG);
if (codec) {
int width = -1;
int height = -1;
int ret = 0;
AVCodecContext* ctx = NULL;
ctx = avcodec_alloc_context3(codec);
AVFrame* frame = av_frame_alloc();
AVPacket* pkt = av_packet_alloc();
FILE* file = fopen(outfile, "wb");
ARRAYELEMENT* e;
int count = 0;
forall (e, *arr) {
BITMAP bitmap (e->value, false);
if (width < 0) {
width = bitmap.Width();
height = bitmap.Height();
ctx->width = width;
ctx->height = height;
ctx->time_base = (AVRational){1, 5};
ctx->framerate = (AVRational){5, 1};
ctx->pix_fmt = AV_PIX_FMT_RGB24;
ret = avcodec_open2(ctx, codec, NULL);
frame->width = width;
frame->height = height;
frame->format = ctx->pix_fmt;
av_opt_set(ctx->priv_data, "preset", "slow", 1);
}
ret = av_frame_get_buffer(frame, 1);
frame->linesize[0] = width*3;
bitmap.Convert32();
byte* pixels = bitmap.PixelsRGB();
//The two methodes above convert the Pixmap into the RGB structure we need
//They are not needed to get an output file but are needed to get one that makes sense
fflush(stdout);
int writeable = av_frame_make_writable(frame);
if (writeable>=0) {
for(int i=0; i<(height*width*3); i++){
frame->data[0][i] = pixels[i];
}
}
ret = avcodec_send_frame(ctx, frame);
for(int i=0; i<secs; i++){
fflush(stdout);
avcodec_send_frame(ctx, frame);
}
while (ret >= 0) {
ret = avcodec_receive_packet(ctx, pkt);
}
count++;
avcodec_receive_packet(ctx, pkt);
fwrite(pkt->data, 1, pkt->size, file);
fflush(stdout);
av_packet_unref(pkt);
}
fclose(file);
avcodec_free_context(&ctx);
av_frame_free(&frame);
av_packet_free(&pkt);
}
}
}