David's Blog

Transcode video file with ffmpeg.

By David Li on 2024-03-05T01:45:04.000Z

Transcoding a Video File with FFmpeg

FFmpeg is a powerful open-source library for processing multimedia files like videos and audios. It provides various tools and APIs for tasks like format conversion, resizing, editing, and more. In this article, we will see how to use ffmpeg to transcode a video file from one format to another.

To follow along, you will need:

  • FFmpeg installed on your system
  • A video file to transcode
  • Basic C++ knowledge

Overview

At a high level, transcoding a video involves these steps:

  1. Initialize FFmpeg and open the input video file
  2. Get stream information from the input file
  3. Set up the output format context with desired parameters
  4. Read frames from input, decode, process, and encode them
  5. Write the processed frames to the output file

Let’s look at the code to implement these steps.

Initializing FFmpeg

We begin by including the required FFmpeg headers and registering all the codecs and formats:

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
// other headers
}

av_register_all();

Opening Input File

Next, we open the input video file using avformat_open_input() and get the input format context:

AVFormatContext *input_format_ctx = nullptr;

if (avformat_open_input(&input_format_ctx, input_file, nullptr, nullptr) < 0) {
  // error handling
}

Getting Stream Info

We find the index of the video stream inside the input file:

int video_stream_idx = -1;

for (int i = 0; i < input_format_ctx->nb_streams; i++) {
  if (input_format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
    video_stream_idx = i;
    break;
  }
}

And get the codec context and parameters for decoding:

AVCodecParameters *codecpar = 
  input_format_ctx->streams[video_stream_idx]->codecpar;

AVCodec *decoder = avcodec_find_decoder(codecpar->codec_id);

AVCodecContext *codec_ctx = avcodec_alloc_context3(decoder);
avcodec_parameters_to_context(codec_ctx, codecpar);

Initializing Output File

We now setup the output format context with the filename, codec and other parameters:

AVFormatContext *output_format_ctx = nullptr;

avformat_alloc_output_context2(&output_format_ctx, nullptr, 
                                nullptr, output_file); 

AVStream *out_stream = avformat_new_stream(output_format_ctx, 
                                           codec);
                                           
avcodec_parameters_copy(out_stream->codecpar, codecpar);

And open the output file for writing:

if (!(output_format_ctx->oformat->flags & AVFMT_NOFILE)) {
  if (avio_open(&output_format_ctx->pb, output_file, 
                AVIO_FLAG_WRITE) < 0) {
    // error handling
  }
}

Transcoding Frames

Now we can read frames from input, decode them using avcodec_send_packet() and avcodec_receive_frame(), do processing if needed, and finally encode the frames with the output codec and write them to output file.

while (av_read_frame(input_format_ctx, &packet) >= 0) {

  avcodec_send_packet(codec_ctx, &packet);
  
  while (avcodec_receive_frame(codec_ctx, frame) == 0) {
    // decoding successful

    // process frame if needed

    avcodec_send_frame(output_codec_ctx, frame);

    avcodec_receive_packet(output_codec_ctx, &opacket);
    
    av_interleaved_write_frame(output_format_ctx, &opacket);
  }
}

Finally, we free the allocated resources and close the files.

This covers the basic transcoding workflow with FFmpeg. Several additional steps may be needed for robust encoding, like handling subtitles, metadata etc. But this gives an overview of the process.

© Copyright 2024 by FriendlyUsers Tech Blog. Built with ♥ by FriendlyUser. Last updated on 2024-05-06.