David's Blog

Using FFmpeg in C++ A Comprehensive Guide

By David Li on 2023-05-03T14:16:44.767Z

Using FFmpeg in C++: A Comprehensive Guide

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.

Table of Contents

  1. Introduction to FFmpeg
  2. Setting Up FFmpeg
  3. Integrating FFmpeg in Your C++ Project
  4. Example: Reading Video Frames
  5. Example: Transcoding a Video File
  6. Conclusion

Introduction to FFmpeg

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:

  • libavcodec: audio/video codec library
  • libavformat: audio/video container muxing and demuxing library
  • libavutil: utility library with various functions
  • libavfilter: audio/video filtering library
  • libavdevice: input/output devices for grabbing and rendering
  • libswscale: color space and scaling library

Setting Up FFmpeg

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:

  1. 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.

  2. Link Libraries: In your C++ project, link the necessary FFmpeg libraries. This step will vary depending on your development environment and build system.

Integrating FFmpeg in Your C++ Project

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++.

Example: Reading Video Frames

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.

Example: Transcoding a Video File

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++
© Copyright 2024 by FriendlyUsers Tech Blog. Built with ♥ by FriendlyUser. Last updated on 2024-11-21.