使用X264编码视频

使用X264编码视频

环境准备

  1. 使用git clone 下载x264源码
    https://www.videolan.org/developers/x264.html
  2. 如果电脑之前没有安装过 yasm,nasm 可以使用 brew 安装一下
    brew install yasm
    brew install nasm
  1. 进入到工程根目录下编译
  // 配置开启动态库,也可以不开启,默认MAC会安装在/usr/local目录下,其他可以使用./confiure --help 查看帮助
  1.  ./configure --enable-shared 
  // 配置成功后,开启编译
  2.  make 
  // 将编译完的产物安装到指定的目录
  3.  make install

x264 install 成功之后命令行会输出安装到的目录

install -d /usr/local/bin
install x264 /usr/local/bin
install -d /usr/local/include /usr/local/lib/pkgconfig
install -m 644 ./x264.h x264_config.h /usr/local/include
install -m 644 x264.pc /usr/local/lib/pkgconfig
install -d /usr/local/lib
ln -f -s libx264.164.dylib /usr/local/lib/libx264.dylib
install -m 755 libx264.164.dylib /usr/local/lib

命令行使用

x264  -o akiyo.264 --input-res=352x288   --input-csp=i420 --input-depth=8  akiyo_cif.yuv

更多使用方式可以参考

x264 --help

工程使用

我使用的是vscode + cmake
因为安装的时候将pkgconfig 安装到了这个路径
/usr/local/lib/pkgconfig/x264

可以打开该文件看看内容,描写了这个库的头文件路径,二进制文件路径等

  1 prefix=/usr/local
  2 exec_prefix=${prefix}
  3 libdir=${exec_prefix}/lib
  4 includedir=${prefix}/include
  5
  6 Name: x264
  7 Description: H.264 (MPEG4 AVC) encoder library
  8 Version: 0.164.3075
  9 Libs: -L${exec_prefix}/lib -lx264
 10 Libs.private: -lpthread -lm -ldl
 11 Cflags: -I${prefix}/include -DX264_API_IMPORTS

同时使用
pkg-config 命令确保,pkgconfig能够搜索到

pkgconfig pkg-config --list-all | grep x264
x264                                x264 - H.264 (MPEG4 AVC) encoder library

如搜索不到,可配置环境变量试试

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

pkgconfig 可以帮助我们简化依赖

  1. 资源准备

yuv 视频源: http://trace.eas.asu.edu/yuv/index.html
查看YUV视频源工具: https://files.cnblogs.com/littlejohnny/YUVviewer_src.rar
https://github.com/IENT/YUView/releases

我下载了一个资源名,名称为:akiyo_cif,是一个I420,8位深的资源

  1. CMakeList.txt
cmake_minimum_required(VERSION 3.14)
project(x264_encoder)
set(CMAKE_CXX_STANDARD 11)            # Enable c++11 standard

set(CMAKE_BUILD_TYPE Debug)
set(SOURCE_FILES X264Encoder.cpp)

# https://cmake.org/cmake/help/latest/module/FindPkgConfig.html
# https://zhuanlan.zhihu.com/p/111155574
find_package(PkgConfig REQUIRED)
// 使用PkgConfig寻找module
pkg_check_modules(x264 REQUIRED IMPORTED_TARGET x264 )

add_executable(x264_encoder ${SOURCE_FILES})

target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::x264)
  1. 代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <iomanip>
#include <x264.h>

// https://blog.csdn.net/leixiaohua1020/article/details/42078645
int main(int argv, const char *args[])
{
    FILE *fp_src = fopen("res/akiyo_cif.yuv", "rb");
    FILE *fp_dst = fopen("res/akiyo_cif_code.h264", "wb");

    // 352x288
    int width = 352;
    int height = 288;
    int csp = X264_CSP_I420;
    // 设置为0,会根据文件大小计算帧数
    // 如果帧数设置的太小,可能会造成没有编码后的结果
    int frameNum = 0;

    if (fp_src && fp_dst)
    {
        x264_picture_t *pPic_in = new x264_picture_t();
        x264_picture_t *pPic_out = new x264_picture_t();
        x264_param_t *pParam = new x264_param_t();

        x264_param_default(pParam);

        // 根据资源的大小设置的尺寸
        // YUVView可以查看YUV资源的信息
        pParam->i_width = 352;
        pParam->i_height = 288;
        pParam->i_csp = csp;

        // https://blog.csdn.net/lcalqf/article/details/65635333
        x264_param_apply_profile(pParam, x264_profile_names[5]);

        x264_t *pHander = x264_encoder_open(pParam);

        x264_picture_init(pPic_out);
        x264_picture_alloc(pPic_in, csp, pParam->i_width, pParam->i_height);
        int ySize = pParam->i_width * pParam->i_height;
        if (frameNum == 0)
        {
            switch (csp)
            {
            case X264_CSP_I420:
                fseek(fp_src, 0, SEEK_END);
                frameNum = ftell(fp_src) / (ySize * 3 / 2);
                fseek(fp_src, 0, SEEK_SET);
                break;

            default:
                std::cout << "Colorespace are not support." << std::endl;
                return -1;
            }
        }

        x264_nal_t *pNals = nullptr;
        int iNal = 0;
        // Loop to encode
        for (int i = 0; i < frameNum; i++)
        {
            switch (csp)
            {
            case X264_CSP_I420:
                // https://www.cplusplus.com/reference/cstdio/fseek/
                fread(pPic_in->img.plane[0], ySize, 1, fp_src);     // Y
                fread(pPic_in->img.plane[1], ySize / 4, 1, fp_src); // U
                fread(pPic_in->img.plane[2], ySize / 4, 1, fp_src); // V
                break;

            default:
                std::cout << "Coloresapce are not support." << std::endl;
                return -1;
            }
            // PTS VS DTS
            // https://bitmovin.com/docs/encoding/faqs/why-is-an-timestamp-offset-for-ts-muxings-applied-by-default
            pPic_in->i_pts = i;

            int ret = x264_encoder_encode(pHander, &pNals, &iNal, pPic_in, pPic_out);
            if (ret < 0)
            {
                std::cout << "Error encode." << std::endl;
                return -1;
            }
            std::cout << "success encode frame" << std::setw(5) << i << std::endl;
            for (int j = 0; j < iNal; j++)
            {
                std::cout << "write nal to file" << std::setw(5) << j << std::endl;
                fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);
            }
        }
        std::cout << "to flush" << std::endl;
        // flush
        while (true)
        {
            int ret = x264_encoder_encode(pHander, &pNals, &iNal, pPic_in, pPic_out);
            if (ret == 0)
            {
                break;
            }
            else if (ret < 0)
            {
                std::cout << "Error encode ." << std::endl;
                break;
            }
            else
            {
                std::cout << "Flush 1 frame." << std::endl;
                for (int j = 0; j < iNal; j++)
                {
                    fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);
                }
                break;
            }
        }

        // clean
        std::cout << "to clean resource" << std::endl;
        x264_picture_clean(pPic_in);
        x264_encoder_close(pHander);
        pHander = nullptr;

        delete pPic_in;
        delete pPic_out;
        delete pParam;

        fclose(fp_src);
        fclose(fp_dst);
        return 0;
    }
    else
    {

        char *buffer;
        if ((buffer = getcwd(nullptr, 0)) == nullptr)
        {
            std::cout << "get cwd error." << std::endl;
            free(buffer);
        }
        else
        {
            std::cout << "Error open files. "
                      << "the current dir is "
                      << buffer
                      << std::endl
                      << "The fpSrc is"
                      << fp_src
                      << "the fpDst is "
                      << fp_dst
                      << std::endl;
        }
        return -1;
    }
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
x264是一款开源的视频编码器,它采用H.264/AVC视频编码标准,被广泛应用于视频压缩、视频传输等领域。下面是对x264视频编码器源码的简要解析。 x264的整体架构分为以下几个模块: 1. 预处理模块 预处理模块主要负责对输入的视频进行预处理,包括色彩空间转换、图像缩放、去噪等处理。在预处理模块中,会首先对输入的YUV格式的视频进行格式转换,转换成x264支持的色彩空间格式,然后再进行其他处理。 2. 分块模块 分块模块将图像划分成多个块,每个块的大小可以由用户指定,在x264中,块大小一般为16x16或者8x8。分块模块将每个块的像素值按照一定的顺序排列,并存储在一个数组中,以便后续操作。 3. 预测模块 预测模块主要负责对图像进行运动估计和帧内预测。运动估计是指在当前帧中,通过比对前一帧或者参考帧中相似块的像素值,预测当前块的像素值。帧内预测是指在当前帧中,通过相邻块的像素值,预测当前块的像素值。 4. 变换模块 变换模块主要负责对预测残差进行离散余弦变换(DCT),将空域中的像素变换到频域中,以便后续的量化操作。在x264中,采用了4x4和8x8两种不同大小的DCT变换。 5. 量化模块 量化模块将DCT系数按照一定的规则进行量化,即将大的DCT系数变小,以减小编码后的比特率。在x264中,采用了不同的量化矩阵,以适应不同的场景需求。 6. 熵编码模块 熵编码模块将量化后的DCT系数进行编码,生成比特流。在x264中,采用了自适应的上下文建模技术,以提高编码效率。 7. 决策模块 决策模块主要负责对编码参数进行优化,以达到最佳的编码效果。在x264中,采用了基于码率失真优化的算法,通过不断调整编码参数,使得编码后的视频质量最好,同时保证视频的比特率不超过预设的值。 总之,x264视频编码器源码的设计非常精妙,涵盖了众多的技术领域,从预处理到量化编码,每个模块都充分考虑到了实际应用场景的需求,使得x264成为了一款高效、稳定、灵活的视频编码器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值