In-Depth FFmpeg: From Encoding and Decoding Principles to Linux Compilation Practices

In the field of audio and video processing technology, FFmpeg is a powerful and widely used open-source multimedia framework. It supports various encoding and decoding formats, providing developers with a rich set of tools and interfaces to handle audio and video data. Today, we will delve into the encoding and decoding technologies in FFmpeg, particularly how to compile the FFmpeg library with x264/x265 encoding support in a Linux environment, along with relevant code examples to deepen our understanding.

1. Basic Concepts of Encoding and Decoding

Encoding and decoding are crucial processes in information processing. Encoding is the process of converting information from one form or format to another, such as encoding text, numbers, and other objects into digital form, or converting information and data into specified electrical pulse signals. Encoding technology has wide applications in various fields, including electronic computers, television, remote control, and communications. Decoding, on the other hand, is the reverse process of encoding, responsible for restoring encoded data to its original information.

In the powerful multimedia processing framework FFmpeg, the processes of encoding and decoding have specific implementations. During decoding, the <span>avcodec_send_packet</span> function is generally called first, followed by the <span>avcodec_receive_frame</span> function to obtain the decoded frame data. The encoding process is the exact opposite: first, the <span>avcodec_send_frame</span> function is called, and then the <span>avcodec_receive_packet</span> function is used to get the encoded data packet.

2. Compiling FFmpeg with x264/x265 Support on Linux

On Windows systems, the official FFmpeg library comes with built-in support for x264/x265 encoding. However, on Linux systems, the default command-line compiled FFmpeg library only supports h264/h265 decoding and does not include encoding functionality. Therefore, to use FFmpeg for x264/x265 encoding on Linux, you need to manually add the corresponding libraries and recompile. Below are the detailed compilation steps:

  1. Preparation: First, download the source packages for x264/x265 and extract them to a specified directory. Since the compiled libraries need to be copied to the <span>/usr/lib</span> directory, you need to switch to administrator privileges.
  2. Compile libx264 for h264 Encoding: Navigate to the extracted x264 directory and execute the following commands:
  • <span>./configure --disable-asm</span>: Configure the compilation options, where <span>--disable-asm</span> disables assembly optimizations, which may avoid potential compatibility issues on some systems.
  • <span>make -j4</span>: Compile using multiple threads (4 threads in this case) to speed up the compilation process. The number after the <span>-j</span> parameter indicates the number of tasks that can run simultaneously and can be adjusted based on the number of CPU cores in the machine.
  • <span>make install</span>: Install the compiled library into the system.
  • Compile libx265 for h265 (HEVC) Encoding: Navigate to the <span>build/linux</span> directory of x265 and execute the following commands:
    • <span>./make-Makefiles.bash</span>: Generate the Makefile, which is an important configuration file during the compilation process.
    • <span>make -j4</span>: Again, use multi-threaded compilation to improve efficiency.
    • <span>make install</span>: Complete the installation.
    • If you encounter the error <span>cmake: command not found</span>, you need to install <span>cmake-curses-gui</span> using the command <span>apt install cmake-curses-gui</span>.
  • Compile FFmpeg with x264/x265 Support: Depending on the location of the x264/x265 libraries, different compilation commands are required:
    • Specify the location to link libx264 header files and libraries: If the libraries are not installed in the system’s default paths, you need to manually specify the paths for the header files and libraries. For example: <span>./configure --prefix=host --disable-static --enable-shared --disable-doc --enable-libx264 --enable-libx265 --enable-gpl --enable-rpath --enable-libfreetype --disable-sdl2 --extra-cflags=-I/home/liu/qt/x264/host/include --extra-ldflags=-L/home/liu/qt/x264/host/lib</span> where <span>--prefix=host</span> specifies the installation path, <span>--disable-static</span> and <span>--enable-shared</span> indicate not to compile static libraries and to compile shared libraries, respectively, <span>--disable-doc</span> indicates not to generate documentation, <span>--enable-libx264</span> and <span>--enable-libx265</span> enable x264 and x265 encoding support, <span>--enable-gpl</span> allows the use of GPL-licensed libraries, <span>--enable-rpath</span> sets the runtime library path, and <span>--enable-libfreetype</span> supports filters (such as the <span>drawtext</span> filter that depends on this library), <span>--disable-sdl2</span> disables the dependency on the SDL2 library (if SDL is present in the environment, FFmpeg will default to enabling this dependency, which can be manually disabled), and <span>--extra-cflags</span> and <span>--extra-ldflags</span> specify the paths for header files and libraries, respectively.
    • If the header files and libraries are already in the system directories: If the header files and libraries are already installed in the system directories, you do not need to specify the paths. Use the following command to compile: <span>./configure --prefix=host --disable-static --enable-shared --disable-doc --enable-libx264 --enable-libx265 --enable-gpl --enable-rpath</span>
  • Other Operations:
    • Set rpath: If necessary, you can set the rpath for the compiled FFmpeg executable to ensure that the file can correctly find and run the libraries when they are in the same directory.
    • View rpath: Use the command <span>readelf -d ffmpeg | grep 'RPATH'</span> to view the rpath of the FFmpeg executable.
    • Modify rpath: Use the command <span>chrpath -r "\$ORIGIN" ffmpeg</span> to modify the rpath of the FFmpeg executable.

    During the compilation process, you can refer to the webpage https://www.cnblogs.com/yongdaimi/p/15526838.html for more detailed information and solutions to potential issues.

    3. Code Implementation of FFmpeg Encoding and Decoding

    Below is a C++ code example related to encoding and decoding based on FFmpeg, demonstrating how to perform encoding and decoding operations in a program:

    // Video or audio decoding function, selecting different decoding methods based on FFmpeg version
    int FFmpegHelper::decode(FFmpegThread *thread, AVCodecContext *avctx, AVPacket *packet, AVFrame *frame, bool video)
    {
        int result = -1;
    #ifdef videoffmpeg
        QString flag = video? "Video Decoding" : "Audio Decoding";
        // Decoding method for FFmpeg version less than 3
        if (FFMPEG_VERSION_MAJOR < 3) {
            if (video) {
                avcodec_decode_video2(avctx, frame, &result, packet);
                if (result < 0) {
                    thread->debug(flag, QString("Step: %1 Reason: %2").arg("avcodec_decode_video2").arg(getError(result)));
                    return result;
                }
            } else {
                avcodec_decode_audio4(avctx, frame, &result, packet);
                if (result < 0) {
                    thread->debug(flag, QString("Step: %1 Reason: %2").arg("avcodec_decode_audio4").arg(getError(result)));
                    return result;
                }
            }
            goto end;
        // Decoding method for FFmpeg version 3 or greater
        } else {
            result = avcodec_send_packet(avctx, packet);
            if (result < 0 && (result != AVERROR(EAGAIN)) && (result != AVERROR_EOF)) {
                thread->debug(flag, QString("Step: %1 Reason: %2").arg("avcodec_send_packet").arg(getError(result)));
                return result;
            }
            while (result >= 0) {
                result = avcodec_receive_frame(avctx, frame);
                if (result == AVERROR(EAGAIN) || result == AVERROR_EOF) {
                    break;
                } else if (result < 0) {
                    thread->debug(flag, QString("Step: %1 Reason: %2").arg("avcodec_receive_frame").arg(getError(result)));
                    break;
                }
                goto end;
            }
        }
        return result;
    end:
        // Call the corresponding thread processing function based on video or audio
        if (video) {
            thread->decodeVideo2(packet);
        } else {
            thread->decodeAudio2(packet);
        }
    #endif
        return result;
    }
    
    // Video or audio encoding function, selecting different encoding methods based on FFmpeg version
    int FFmpegHelper::encode(FFmpegSave *thread, AVCodecContext *avctx, AVPacket *packet, AVFrame *frame, bool video)
    {
        int result = -1;
    #ifdef videosave
        QString flag = video? "Video Encoding" : "Audio Encoding";
        // Encoding method for FFmpeg version less than 3
        if (FFMPEG_VERSION_MAJOR < 3) {
            if (video) {
                avcodec_encode_video2(avctx, packet, frame, &result);
                if (result < 0) {
                    thread->debug(flag, QString("Step: %1 Reason: %2").arg("avcodec_encode_video2").arg(getError(result)));
                    return result;
                }
            } else {
                avcodec_encode_audio2(avctx, packet, frame, &result);
                if (result < 0) {
                    thread->debug(flag, QString("Step: %1 Reason: %2").arg("avcodec_encode_audio2").arg(getError(result)));
                    return result;
                }
            }
            goto end;
        // Encoding method for FFmpeg version 3 or greater
        } else {
            result = avcodec_send_frame(avctx, frame);
            if (result < 0) {
                thread->debug(flag, QString("Step: %1 Reason: %2").arg("avcodec_send_frame").arg(getError(result)));
                return result;
            }
            while (result >= 0) {
                result = avcodec_receive_packet(avctx, packet);
                if (result == AVERROR(EAGAIN) || result == AVERROR_EOF) {
                    break;
                } else if (result < 0) {
                    thread->debug(flag, QString("Step: %1 Reason: %2").arg("avcodec_receive_packet").arg(getError(result)));
                    break;
                }
                goto end;
            }
        }
        return result;
    end:
        thread->writePacket(packet);
    #endif
        return result;
    }
    

    In this code, the <span>decode</span> function is responsible for the decoding operation, selecting different decoding functions based on the FFmpeg version (<span>avcodec_decode_video2</span>/<span>avcodec_decode_audio4</span> or <span>avcodec_send_packet</span> + <span>avcodec_receive_frame</span>). After decoding, the corresponding thread function (<span>decodeVideo2</span> or <span>decodeAudio2</span>) is called to process the decoded data.<span>encode</span> function is used for the encoding operation, similarly selecting different encoding functions based on the FFmpeg version (<span>avcodec_encode_video2</span>/<span>avcodec_encode_audio2</span> or <span>avcodec_send_frame</span> + <span>avcodec_receive_packet</span>), and after encoding, the <span>writePacket</span> function is called for subsequent processing.

    4. Experience Address

    If you want to personally experience the related features, you can obtain resources through the following addresses:

    1. Domestic Site: https://gitee.com/feiyangqingyun
    2. International Site: https://github.com/feiyangqingyun
    3. Personal Works: https://blog.csdn.net/feiyangqingyun/article/details/97565652
    4. Experience Address: https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g Extraction Code: 01jf File Name: bin_video_demo/bin_linux_video
    5. Contact: WeChat feiyangqingyun
    6. Official Store:https://shop114595942.taobao.com/

    In-Depth FFmpeg: From Encoding and Decoding Principles to Linux Compilation Practices

    Leave a Comment