I have 100 images(PNG) and I want to create a video using these images. I am using the ffmpeg library for this. Using command line I can create video easily. But how do I do it through coding?
Any help will be appreciated.
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif
extern "C"
{
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavcodec/avcodec.h"
#include "libavutil/mathematics.h"
#include "libavutil/samplefmt.h"
}
#define INBUF_SIZE 4096
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
static void video_encode_example(const char *filename, int codec_id)
{
AVCodec *codec;
AVCodecContext *c= NULL;
int i, out_size, size, x, y, outbuf_size;
FILE *f;
AVFrame *picture;
uint8_t *outbuf;
int nrOfFramesPerSecond =25;
int nrOfSeconds =1;
printf("Video encoding\n");
// find the mpeg1 video encoder
codec = avcodec_find_encoder((CodecID) codec_id);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
picture= avcodec_alloc_frame();
// put sample parameters
c->bit_rate = 400000;
// resolution must be a multiple of two
c->width = 352;
c->height = 288;
// frames per second
c->time_base= (AVRational){1,25};
c->gop_size = 10; //emit one intra frame every ten frames
c->max_b_frames=1;
c->pix_fmt = PIX_FMT_YUV420P;
if(codec_id == 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);
}
f = fopen(filename, "wb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
// alloc image and output buffer
outbuf_size = 100000;
outbuf = (uint8_t*) malloc(outbuf_size);
// 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
av_image_alloc(picture->data, picture->linesize,
c->width, c->height, c->pix_fmt, 1);
// encode 1 second of video
int nrOfFramesTotal = nrOfFramesPerSecond * nrOfSeconds;
// encode 1 second of video
for(i=0;i < nrOfFramesTotal; i++) {
fflush(stdout);
// prepare a dummy image
for(y=0;y<c->height;y++) {
for(x=0;x<c->width;x++) {
picture->data[0][y * picture->linesize[0] + x] = x + y + i * 3;
}
}
// Cb and Cr
for(y=0;y<c->height/2;y++) {
for(x=0;x<c->width/2;x++) {
picture->data[1][y * picture->linesize[1] + x] = 128 + y + i * 2;
picture->data[2][y * picture->linesize[2] + x] = 64 + x + i * 5;
}
}
// encode the image
out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture);
printf("encoding frame %3d (size=%5d)\n", i, out_size);
fwrite(outbuf, 1, out_size, f);
}
// get the delayed frames
for(; out_size; i++) {
fflush(stdout);
out_size = avcodec_encode_video(c, outbuf, outbuf_size, NULL);
printf("write frame %3d (size=%5d)\n", i, out_size);
fwrite(outbuf, 1, out_size, f);
}
// add sequence end code to have a real mpeg file
outbuf[0] = 0x00;
outbuf[1] = 0x00;
outbuf[2] = 0x01;
outbuf[3] = 0xb7;
fwrite(outbuf, 1, 4, f);
fclose(f);
free(outbuf);
avcodec_close(c);
// av_free(c);
// av_free(picture->data[0]);
// av_free(picture);
printf("\n");
}
int main(int argc, char **argv)
{
const char *filename;
avcodec_register_all();
if (argc <= 1) {
video_encode_example("/home/radix/Desktop/OpenCV/FFMPEG_Output/op89.png", AV_CODEC_ID_H264);
} else {
filename = argv[1];
}
return 0;
}
FFmpeg looks for image files with file names with 'img-' resulting in a two-digit number. In the command section, you will need to define a search pattern for the ffmpeg output file so that you can find the image sequence.
FFmpeg is an open-source audio and video converter that supports most industry-standard codecs and can convert from one file format to another quickly and easily. It also lets you capture video and audio from a live source and process it.
The reason this comes up again and again is because you're using encoding_example.c as your reference. Please don't do that. The most fundamental mistake in this example is that it doesn't teach you the difference between codecs and containers. In fact, it ignored containers altogether.
What is a codec? A codec is a method of compressing a media type. H264, for example, will compress raw video. Imagine a 1080p video frame, which is typically in YUV format with 4:2:0 chroma subsampling. Raw, this is 1080*1920*3/2 bytes per frame, i.e. ~3MB/f. For 60fps, this is 180MB/sec, or 1.44 gigabit/sec (gbps). That's a lot of data, so we compress it. At that resolution, you can get pretty quality at a few megabit/sec (mbps) for modern codecs, like H264, HEVC or VP9. For audio, codecs like AAC or Opus are popular.
What is a container? A container takes video or audio (or subtitle) packets (compressed or uncompressed) and interleaves them for combined storage in a single output file. So rather than getting one file for video and one for audio, you get one file that interleaves packets for both. This allows effective seeking and indexing, it typically also allows adding metadata storage ("author", "title") and so on. Examples of popular containers are MOV, MP4 (which is really just mov), AVI, Ogg, Matroska or WebM (which is really just matroska).
(You can store video-only data in a file if you want. For H264, this is called "annexb" raw H264. This is actually what you were doing above. So why didn't it work? Well, you're ignoring "header" packets like the SPS and PPS. These are in avctx->extradata and need to be written before the first video packet. Using a container would take care of that for you, but you didn't, so it didn't work.)
How do you use a container in FFmpeg? See e.g. this post, particularly the sections calling functions like avformat_write_*()
(basically anything that sounds like output). I'm happy to answer more specific questions, but I think the above post should clear out most confusion for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With