FFmpeg is a powerful and versatile library for multimedia processing, capable of handling various audio, video, and container formats. In this article, we will explore how to harness the power of FFmpeg in your C++ projects, discussing the necessary steps for integrating the library, and providing example code to help you get started.
FFmpeg is a free and open-source collection of libraries and programs for handling multimedia files. It provides utilities for audio and video compression, decompression, streaming, and conversion. The key components of FFmpeg are:
Before diving into the code, you need to set up FFmpeg on your system. The process is platform-dependent, but a general outline is provided below:
Download and Install: Download the precompiled binaries or source code for your platform from the official FFmpeg website. Follow the installation instructions specific to your platform.
Link Libraries: In your C++ project, link the necessary FFmpeg libraries. This step will vary depending on your development environment and build system.
To start using FFmpeg in your C++ project, include the appropriate FFmpeg headers:
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
}
The extern "C"
block is necessary because FFmpeg is written in C, and we need to ensure the correct linkage when used in C++.
In this example, we will read video frames from a file and print their basic properties.
#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
}
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <input_file>" << std::endl;
return 1;
}
const char* input_file = argv[1];
// Register all available codecs, demuxers, and protocols
av_register_all();
// Open input file and allocate format context
AVFormatContext* format_ctx = nullptr;
if (avformat_open_input(&format_ctx, input_file, nullptr, nullptr) < 0) {
std::cerr << "Could not open input file: " << input_file << std::endl;
return 2;
}
// Retrieve stream information
if (avformat_find_stream_info(format_ctx, nullptr) < 0) {
std::cerr << "Could not find stream information" << std::endl;
return 3;
}
// Find video stream
int video_stream_idx = -1;
for (unsigned int i = 0; i < format_ctx->nb_streams; ++i) {
if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_idx = i;
break;
}
}
if (video_stream_idx == -1) {
std::cerr << "Could not find video stream" << std::endl;
return 4;
}
// Get codec parameters and codec context
AVCodecParameters* codecpar = format_ctx->streams[video_stream_idx]->codecpar;
AVCodec* codec = avcodec_find_decoder(codecpar->codec_id);
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codec_ctx, codecpar);
// Open codec
if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
std::cerr << "Could not open codec" << std::endl;
return 5;
}
// Allocate frame and packet
AVFrame* frame = av_frame_alloc();
AVPacket packet;
av_init_packet(&packet);
// Read frames from the video stream
while (av_read_frame(format_ctx, &packet) >= 0) {
if (packet.stream_index == video_stream_idx) {
// Decode video frame
int ret = avcodec_send_packet(codec_ctx, &packet);
if (ret < 0) {
std::cerr << "Error sending packet for decoding" << std::endl;
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
std::cerr << "Error during decoding" << std::endl;
break;
}
// Print basic frame properties
std::cout << "Frame " << codec_ctx->frame_number
<< " (type=" << av_get_picture_type_char(frame->pict_type)
<< ", size=" << frame->pkt_size
<< " bytes) pts " << frame->pts
<< " key_frame " << frame->key_frame
<< std::endl;
}
}
av_packet_unref(&packet);
}
// Free allocated resources
av_frame_free(&frame);
avcodec_free_context(&codec_ctx);
avformat_close_input(&format_ctx);
return 0;
}
This example demonstrates how to open a video file, locate the video stream, read and decode video frames, and print basic frame properties.
In this example, we will transcode a video file to another format.
#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
}
int main(int argc, char* argv[]) {
if (argc < 3) {
std::cerr << "Usage: " << argv[0] << " <input_file> <output_file>" << std::endl;
return 1;
}
const char* input_file = argv[1];
const char* output_file = argv[2];
// Register all available codecs, demuxers, and protocols
av_register_all();
// Open input file and allocate format context
// ...
// Find video stream
// ...
// Get codec parameters and codec context
// ...
// Open codec
// ...
// Initialize output format context
AVFormatContext* output_format_ctx = nullptr;
avformat_alloc_output_context2(&output_format_ctx, nullptr, nullptr, output_file);
if (!output_format_ctx) {
std::cerr << "Could not create output context" << std::endl;
return 6;
}
// Add video stream to output format context
AVStream* out_stream = avformat_new_stream(output_format_ctx, codec);
if (!out_stream) {
std::cerr << "Could not allocate output stream" << std::endl;
return 7;
}
// Copy codec context parameters to output stream
if (avcodec_parameters_copy(out_stream->codecpar, codecpar) < 0) {
std::cerr << "Could not copy codec parameters" << std::endl;
return 8;
}
// Open output file
if (!(output_format_ctx->oformat->flags & AVFMT_NOFILE)) {
if (avio_open(&output_format_ctx->pb, output_file, AVIO_FLAG_WRITE) < 0) {
std::cerr << "Could not open output file: " << output_file << std::endl;
return 9;
}
}
// Write output file header
if (avformat_write_header(output_format_ctx, nullptr) < 0) {
std::cerr << "Error occurred when writing output file header" << std::endl;
return 10;
}
// Read frames from the video stream
// ...
// Decode video frame
// ...
// Transcode and write frames to the output file
while (av_read_frame(format_ctx, &packet) >= 0) {
// ...
while (ret >= 0) {
// ...
// Write transcoded frame to output file
AVPacket out_packet;
av_init_packet(&out_packet);
out_packet.data = nullptr;
out_packet.size = 0;
ret = avcodec_send_frame
Write a techncial article about using Dear ImGui in C++