流媒体-H264协议-编码-x264学习-C++11多线程实现编码(四)

  1. 流媒体-H264协议-编码-x264学习-相关概念x264编译及文件解析(一)
  2. 流媒体-H264协议-编码-x264学习-主要结构体(二)
  3. 流媒体-H264协议-编码-x264学习-主要函数(三)
  4. 流媒体-H264协议-编码-x264学习-C++11多线程实现编码(四)

文章目录

    • 一、Encode类实现
    • 二、完整代码下载

一、Encode类实现

/**
* @projectName   Testx264_01
* @author        wangbaojia
* @date          2020-12-16
* @brief         参考x264源码:example.c文件
*                读取yuv文件进行h264编码
*       //生成原生的yuv数据
*         ffmpeg -i in.mp4 -pix_fmt yuv420p -vcodec rawvideo -an out.yuv
*/
#ifndef X264ENCODE_H
#define X264ENCODE_H

#include <stdio.h>
#include <string>
#include <atomic>

#include <x264.h>
#include <x264_config.h>


class X264Encode
{

public:
    X264Encode();
    virtual ~X264Encode();
    virtual bool Open(std::string infile,std::string outfile);
    virtual void Close();
    virtual void Clear();
    /**
     * @brief Init  x264_param_t参数初始化及相关设置
     * @return
     */
    virtual bool Init();
    virtual bool Encode();
    virtual bool IsFileEnd();


private:

    std::string m_strInFileName = "";
    std::string m_strOutFileName = "";
    FILE* m_pInFp = nullptr;
    FILE* m_pOutFp = nullptr;
    std::atomic<bool> m_bIsFileEnd;

    int m_iWidth = 768;
    int m_iHeight = 320;

    /**
     * @brief m_pParam 结构体x264_param_t定义在x264.h中,用来初始化编码器
     */
    x264_param_t* m_pParam = nullptr;

    x264_t* m_pX264Handle = nullptr;

    /**
     * @brief m_pPicIn 描述一视频帧的特征
     */
    x264_picture_t* m_pPicIn = nullptr;
    x264_picture_t* m_pPicOut = nullptr;

//    x264_nal_t* m_pNals = nullptr;

    /* Colorspace type */
//    #define X264_CSP_MASK           0x00ff  /* */
//    #define X264_CSP_NONE           0x0000  /* Invalid mode     */
//    #define X264_CSP_I400           0x0001  /* monochrome 4:0:0 */
//    #define X264_CSP_I420           0x0002  /* yuv 4:2:0 planar */
//    #define X264_CSP_YV12           0x0003  /* yvu 4:2:0 planar */
//    #define X264_CSP_NV12           0x0004  /* yuv 4:2:0, with one y plane and one packed u+v */
//    #define X264_CSP_NV21           0x0005  /* yuv 4:2:0, with one y plane and one packed v+u */
//    #define X264_CSP_I422           0x0006  /* yuv 4:2:2 planar */
//    #define X264_CSP_YV16           0x0007  /* yvu 4:2:2 planar */
//    #define X264_CSP_NV16           0x0008  /* yuv 4:2:2, with one y plane and one packed u+v */
//    #define X264_CSP_YUYV           0x0009  /* yuyv 4:2:2 packed */
//    #define X264_CSP_UYVY           0x000a  /* uyvy 4:2:2 packed */
//    #define X264_CSP_V210           0x000b  /* 10-bit yuv 4:2:2 packed in 32 */
//    #define X264_CSP_I444           0x000c  /* yuv 4:4:4 planar */
//    #define X264_CSP_YV24           0x000d  /* yvu 4:4:4 planar */
//    #define X264_CSP_BGR            0x000e  /* packed bgr 24bits */
//    #define X264_CSP_BGRA           0x000f  /* packed bgr 32bits */
//    #define X264_CSP_RGB            0x0010  /* packed rgb 24bits */
//    #define X264_CSP_MAX            0x0011  /* end of list */
//    #define X264_CSP_VFLIP          0x1000  /* the csp is vertically flipped */
//    #define X264_CSP_HIGH_DEPTH     0x2000  /* the csp has a depth of 16 bits per pixel component */
    int m_icsp = X264_CSP_I420 ;/* 编码比特流的CSP(Colorspace type:颜色空间类型),视频图像色彩空间设置 */

};

#endif // X264ENCODE_H

#include "x264encode.h"

#include <iostream>
#include <chrono>

X264Encode::X264Encode()
{
    m_bIsFileEnd = true;
}

X264Encode::~X264Encode()
{
    std::cout<<"destory.."<<std::endl;

}

bool X264Encode::Open(std::string infile,std::string outfile)
{
    if(infile.length()== 0 || outfile.length() == 0)
    {
        std::cout<<"file name is empty.."<<std::endl;
        return false;
    }

    m_strInFileName = infile;
    m_strOutFileName = outfile;

    m_pInFp = fopen(const_cast<char*>(infile.c_str()),"rb");
    if(!m_pInFp)
    {
        std::cout<<"open input file failed.."<<std::endl;
        return false;
    }

    m_bIsFileEnd = false;//初始化文件读取位置

    m_pOutFp = fopen(const_cast<char*>(outfile.c_str()),"wb");
    if(!m_pInFp)
    {
        std::cout<<"open output file failed.."<<std::endl;
        return false;
    }

    return true;
}

/**
 * @brief X264Encode::Init x264_param_t参数初始化及相关设置
 * @return
 */
bool X264Encode::Init()
{
    /参数设置start
    //分配空间
    m_pParam = static_cast<x264_param_t*>(malloc(sizeof (x264_param_t)));
    if(!m_pParam)
    {
        std::cout<<"malloc x264_param_t failed"<<std::endl;
        return false;
    }

#ifdef PRESET

    if( x264_param_default_preset( m_pParam, "medium", nullptr ) < 0 )
    {

        return false;
    }
#else
    /**
     * fill x264_param_t with default values and do CPU detection
     *  函数内部第一行执行 memset( param, 0, sizeof( x264_param_t ) );因此需要先分配空间
     */
    x264_param_default(m_pParam);
#endif
//    int x264_param_default_preset( x264_param_t *param, const char *preset, const char *tune );将调用以下两个函数
//    static int param_apply_preset( x264_param_t *param, const char *preset );
//    static int param_apply_tune( x264_param_t *param, const char *tune );

    /* Configure non-default params */

    m_pParam->i_log_level = X264_LOG_NONE;//X264_LOG_DEBUG; // 打印debug信息
    /* 编码比特流的CSP(Colorspace type:颜色空间类型),视频图像色彩空间设置 */
//    m_pParam->i_csp = X264_CSP_I420;//可不设置,默认即为此格式

    m_pParam->i_width = m_iWidth;
    m_pParam->i_height = m_iHeight;

//    std::cout<<m_pParam->i_width<<std::endl;
//    m_pParam->i_bitdepth = 8; //像素比特位深度,新版增

    /* VFR input.  If 1, use timebase and timestamps for ratecontrol purposes.
     * If 0, use fps only. */
//    m_pParam->b_vfr_input = 0;

//    m_pParam->b_repeat_headers = 1; /* put SPS/PPS before each keyframe */

    /* if set, place start codes (4 bytes) before NAL units,
     * otherwise place size (4 bytes) before NAL units. */
//    m_pParam->b_annexb = 1;


    /**
     * @brief x264_param_apply_profile 设置画质级别
     * static const char * const x264_profile_names[] = { "baseline", "main", "high", "high10", "high422", "high444", 0 };
     */
    x264_param_apply_profile(m_pParam, x264_profile_names[0]);

    /* 描述一视频帧的特征
    typedef struct
    {
        int   i_type;       // 帧的类型,取值有X264_TYPE_KEYFRAME、X264_TYPE_P、
        // X264_TYPE_AUTO等。初始化为auto,则在编码过程自行控制。
        int   i_qpplus1;     // 此参数减1代表当前帧的量化参数值
        int   i_pic_struct;  // 帧的结构类型,表示是帧还是场,是逐行还是隔行,
        // 取值为枚举值 pic_struct_e,定义在x264.h中
        int   b_keyframe;    // 输出:是否是关键帧
        int64_t   i_pts;     // 一帧的显示时间戳
        int64_t   i_dts;     // 输出:解码时间戳。当一帧的pts非常接近0时,该dts值可能为负。

        //编码器参数设置,如果为NULL则表示继续使用前一帧的设置。某些参数
        //(例如aspect ratio) 由于收到H264本身的限制,只能每隔一个GOP才能改变。
        //这种情况下,如果想让这些改变的参数立即生效,则必须强制生成一个IDR帧。
        x264_param_t    *param;
        x264_image_t     img;         // 存放一帧图像的真实数据
        x264_image_properties_t    prop;
        x264_hrd_t    hrd_timing;     // 输出:HRD时间信息,仅当i_nal_hrd设置了才有效
        void    *opaque;              // 私有数据存放区,将输入数据拷贝到输出帧中
    } x264_picture_t ;
    */

    m_pPicIn = static_cast<x264_picture_t*>(malloc(sizeof (x264_picture_t)));
    m_pPicOut = static_cast<x264_picture_t*>(malloc(sizeof (x264_picture_t)));

    /* x264_picture_alloc:
     *  alloc data for a picture. You must call x264_picture_clean on it.
     *  returns 0 on success, or -1 on malloc failure or invalid colorspace. */
    x264_picture_alloc(m_pPicIn,m_icsp,m_pParam->i_width,m_pParam->i_height);

    /* x264_picture_init:
     *  initialize an x264_picture_t.  Needs to be done if the calling application
     *  allocates its own x264_picture_t 而不是使用 using x264_picture_alloc. */
    x264_picture_init(m_pPicOut);


    参数设置end/

    /**
     * 用于打开编码器,其中初始化了libx264编码所需要的各种变量
     * create a new encoder handler, all parameters from x264_param_t are copied
     *
        x264_validate_parameters():检查输入参数(例如输入图像的宽高是否为正数)。
        x264_predict_16x16_init():初始化Intra16x16帧内预测汇编函数。
        x264_predict_4x4_init():初始化Intra4x4帧内预测汇编函数。
        x264_pixel_init():初始化像素值计算相关的汇编函数(包括SAD、SATD、SSD等)。
        x264_dct_init():初始化DCT变换和DCT反变换相关的汇编函数。
        x264_mc_init():初始化运动补偿相关的汇编函数。
        x264_quant_init():初始化量化和反量化相关的汇编函数。
        x264_deblock_init():初始化去块效应滤波器相关的汇编函数。
        x264_lookahead_init():初始化Lookahead相关的变量。
        x264_ratecontrol_new():初始化码率控制相关的变量。
     */
    m_pX264Handle = x264_encoder_open(m_pParam);
    if(!m_pX264Handle)
    {
        std::cout<<"x264_encoder_open failed"<<std::endl;
        return false;
    }


    return true;

}

bool X264Encode::Encode()
{
    static int isPts = 0;
    size_t iLumaSize = m_pParam->i_width * m_pParam->i_height;
    size_t iChromaSize = iLumaSize / 4;

    int iNnal;
    x264_nal_t *pNals;


    //读取yuv数据填充m_pPicIn
    if(fread(m_pPicIn->img.plane[0],1,iLumaSize,m_pInFp) != iLumaSize)         //Y
    {
        return false;
    }
    if(IsFileEnd()) return false;

    if(fread(m_pPicIn->img.plane[1],1,iChromaSize,m_pInFp) != iChromaSize)     //U
    {
        return false;
    }
    if(IsFileEnd()) return false;

    if(fread(m_pPicIn->img.plane[2],1,iChromaSize,m_pInFp) != iChromaSize)     //V
    {
        return false;
    }
    if(IsFileEnd()) return false;

    m_pPicIn->i_pts = isPts;


    /* x264_encoder_encode:用于编码一帧YUV为H.264码流
     *      encode one picture.
     *      *pi_nal is the number of NAL units outputted in pp_nal.
     *      returns the number of bytes in the returned NALs.
     *      returns negative on error and zero if no NAL units returned.
     *      the payloads of all output NALs are guaranteed to be sequential in memory. */
    int iFrameSize = x264_encoder_encode(m_pX264Handle,&pNals,&iNnal,m_pPicIn,m_pPicOut);
    if(iFrameSize < 0)
    {
        std::cout<<"x264_encoder_encode failed"<<std::endl;
        return false;
    }

//    std::cout<<"Encode iNals="<<iNnal<<std::endl;
    //生成多个NAL单元,进行处理
    for(int i = 0; i < iNnal;i++)
    {
        if( !fwrite( pNals[i].p_payload, 1,pNals[i].i_payload, m_pOutFp))
        {
            std::cout<<"fwrite failed"<<std::endl;
            return false;
        }
    }

    return true;

}

bool X264Encode::IsFileEnd()
{
    if(!m_pInFp) return true;

    if(feof(m_pInFp))
    {
        std::cout<<"read to file end"<<std::endl;
        return true;
    }
    return false;

}

void X264Encode::Close()
{
    if(m_pPicIn)
    {
        free(m_pPicIn);
    }

    if(m_pPicOut)
    {
        free(m_pPicOut);
    }

    if(m_pParam)
    {
        free(m_pParam);
    }


    if(m_pInFp)
    {
        fclose(m_pInFp);
    }

    if(m_pOutFp)
    {
        fclose(m_pOutFp);
    }

}

void X264Encode::Clear()
{
    int iNnal;
    x264_nal_t *pNals;

    /* Flush delayed frames */
    std::cout<<"buffer size="<<x264_encoder_delayed_frames( m_pX264Handle)<<std::endl;

    while(x264_encoder_delayed_frames( m_pX264Handle))
    {
        //输入为nullptr
        int iFrameSize = x264_encoder_encode( m_pX264Handle, &pNals, &iNnal, nullptr, m_pPicOut );
//        std::cout<<"flush iNals="<<iNnal<<std::endl;
        if( iFrameSize < 0 )
            return;

        for(int i = 0; i < iNnal;i++)
        {
            if( !fwrite( pNals[i].p_payload, 1,pNals[i].i_payload, m_pOutFp))
            {
                std::cout<<"fwrite failed"<<std::endl;
                return;
            }
        }
    }

    if(m_pPicIn)//init分配需手动释放
    {
        x264_picture_clean(m_pPicIn);
    }

    if(m_pX264Handle)
    {
        x264_encoder_close(m_pX264Handle);
    }

}

二、完整代码下载

c++11多线程实现libx264编码

热门文章

暂无图片
编程学习 ·

论怂

从心为怂&#xff0c;世人的误解 老祖宗还是有智慧的&#xff0c;这不是个肯定句。这是个判断语句&#xff0c;if you want to follow your heart,you should be 怂
暂无图片
编程学习 ·

面试总结

面试总结 1.面试以项目为开始展开&#xff0c;不断深入&#xff0c;从项目的背景一直介绍到项目用到的技术原理。会不断的问为什么 2.考察底层原理 3.语言表达能力很重要&#xff0c;需要把原理背景说清楚 下面是题目&#xff0c;欢迎大家把想到的答案写在评论区一起讨论 题目&…
暂无图片
编程学习 ·

Windows安装redis

Windows安装redis 可以到https://github.com/microsoftarchive/redis/releases下载最新的windows版本 双击 redis-server 就会安装默认配置启动redis服务 这样就说明在windows下启动redis成功了&#xff0c;端口号是6379
暂无图片
编程学习 ·

Victor CMS 未授权sql注入(CVE-2020-29280)漏洞复现

0X00简介 The Victor CMS v1.0版本存在安全漏洞&#xff0c;该漏洞源于通过search.php页面上的“search”参数造成的。 0X01影响范围 The Victor CMS v1.0 0X02漏洞复现 在search.php中search参数未经过滤就直接和sql语句拼接导致sql注入漏洞 1.访问首页点击搜索框&#x…
暂无图片
编程学习 ·

从根本上把握防护DDoS的核心要素,不怕DDoS攻击防不住

随着互联网技术的广泛应用和飞速发展&#xff0c;DDoS流量攻击案件频发&#xff0c;网站防护DDoS变得越来越重要&#xff0c;只有采取有效的网站安全防护措施&#xff0c;才能够更好的防御黑客的攻击。 近日&#xff0c;公安部的微信公众号发布了一则重要提醒&#xff1a;你常…
暂无图片
编程学习 ·

211本,字节视频1面凉凉,三天后,却收到了美团offer?

写在开头 2020年的开端&#xff0c;似乎并不那么幸运&#xff0c;新冠肺炎的出现&#xff0c;对我们的生活、工作和学习都造成了非常大的影响&#xff0c;很多公司延期返工了&#xff0c;原本的金三银四似乎也不会如往年那般热闹&#xff0c;但这并不意味着我们就什么都不去做…
暂无图片
编程学习 ·

12.13补课周

记录2leetcode 104 递归 非递归的栈的还不会写 思路 利用DFS,深度递归&#xff1b;总深度为左石子树最大深度加1; 空树深度为0&#xff61; 代码 // An highlighted block /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode l…
暂无图片
编程学习 ·

程序猿小白艰辛学习的第三天

变量的三大组成部分 变量名&#xff1a;用来找值 赋值符号&#xff1a;将变量值的内存地址绑定给变量名 变量值&#xff1a;记录的事物的状态&#xff0c;也就是我们存储的数据 引用 print&#xff08;变量名&#xff09;运行会显示出变量值 变量名 变量名的命名应该遵循见名…
暂无图片
编程学习 ·

2020-12-17

显示如下问题&#xff1a;、Android studio No Debuggable Processes 解决方法&#xff1a;选中 Run->Debug 重新Debug编译运行就可以了。
暂无图片
编程学习 ·

大数据与云计算

大数据与云计算什么是云计算&#xff1f;云计算包含哪些关键技术&#xff1f;云计算有哪些特点&#xff1f;IaaS、PaaS、SaaS是什么&#xff1f;基础设施即服务IaaSIaaS的特点平台即服务PaaSPaaS的特点PaaS的作用软件即服务SaaSSaaS的特性云计算的基础设施和功能云计算的基础设…
暂无图片
编程学习 ·

TinyML-TVM是如何驯服Tiny的(下)

TinyML-TVM是如何驯服Tiny的&#xff08;下&#xff09; Lazy Execution 实际上&#xff0c;随着通信开销开始占主导地位&#xff0c;一旦用户请求&#xff0c;就执行算子的开销变得非常昂贵。可以通过延迟评估直到用户需要调用的结果来提高系统的吞吐量。 从实现的角度来看&a…
暂无图片
编程学习 ·

航次总结2020年7月

航次结束了快2个月&#xff0c;一直没有时间写本航次的总结&#xff0c;主要原因是自己承担的任务要验收&#xff0c;费了好大的劲&#xff0c;才将数据处理成验收单位所需要的&#xff0c;所幸现在应该是没有问题了&#xff0c;符合专项的要求了。航次期间&#xff0c;由于还有…
暂无图片
编程学习 ·

png是什么格式?

png是一种采用无损压缩算法的位图格式。PNG格式有8位、24位、32位三种形式&#xff0c;其中8位PNG支持两种不同的透明形式&#xff0c;24位PNG不支持透明&#xff0c;32位PNG在24位基础上增加了8位透明通道&#xff0c;因此可展现256级透明程度。 png是一种采用无损压缩算法的位…
暂无图片
编程学习 ·

aop 的使用

aop有两种方式&#xff0c;一个是注解&#xff0c;另外一个是配置xml 1、注解的方式&#xff1a; a、和xml一样&#xff0c;首先得有个配置&#xff0c;如果是springboot&#xff0c;写个配置类&#xff1a; Configuration EnableAspectJAutoProxy ComponentScan("xxx.…
暂无图片
编程学习 ·

python制作命令行工具——fire

一、快速介绍 来一波官方介绍。 Python Fire是一个库&#xff0c;用于从任何Python对象自动生成命令行接口。是用python创建CLI的一种简单方法。是开发和调试Python代码的一个有用工具。Python Fire帮助探索现有代码或将其他人的代码转换为CLI。使得Bash和Python之间的转换更…