Qt开发笔记之编码h264码流并封装mp4(五):ubuntu平台编译x264

简介: Qt开发笔记之编码h264码流并封装mp4(五):ubuntu平台编译x264

Qt开发笔记之编码h264码流并封装mp4

Qt开发笔记之编码h264码流并封装mp4(一):x264介绍、windows平台x264库编译

Qt开发笔记之编码h264码流并封装mp4(二):windows平台x264添加mp4支持,gpac库的介绍与编译

Qt开发笔记之编码h264码流并封装mp4(三):Qt使用x264库对.yuv文件编码为.h264文件

Qt开发笔记之编码h264码流并封装mp4(四):mp4v2库的介绍和windows平台编译

Qt开发笔记之编码h264码流并封装mp4(五):ubuntu平台编译x264》

Qt开发笔记之编码h264码流并封装mp4(六):ubuntu平台编译mp4v2并封装mp4

 

前言

前面成功在windows下使用mingw32编译x264,受mp4v2库影响,遂决定先转换到ubuntu平台继续。

 

Ubuntu下x264库编译

步骤一:下载、放入编译文件夹并解压

步骤二:配置configure

./configure --enable-shared --disable-asm

步骤三:编译make

(使用mingw32-make一样,因为使用的是同样的编译器g++编译)

步骤四:安装make install

 

Demo演示

该demo测试从yuv格式编码出h264文件。

 

关键代码

bool X264Manager::testYuvToH264(QString yuvFile, QString destFile)
{
    bool ret = false;
    // 检测输入文件
    if(!yuvFile.endsWith(".yuv"))
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to recgnize ext:" << yuvFile;
        return ret;
    }
    // 检测输出文件
    if(destFile.isEmpty())
    {
        destFile = yuvFile;
        destFile.truncate(destFile.lastIndexOf(".yuv"));
        destFile += ".h264";
    }else if(!destFile.endsWith(".h264"))
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to recgnize ext:" << destFile;
        return ret;
    }
    qDebug() << __FILE__ << __LINE__ << yuvFile << "to" << destFile;
    // 打开输入文件
    FILE *fpSrc = fopen(yuvFile.toUtf8().data(), "rb");
    if(!fpSrc)
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to open file:" << yuvFile;
    }
    // 打开输出文件
    FILE *fpDst = fopen(destFile.toUtf8().data(), "wb");
    if(!fpDst)
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to open file:" << destFile;
    }
    x264_nal_t * pX264NalT;
    // 编码参数
    int width = 640;                    // 宽度
    int height = 360;                   // 高度
    x264_param_t x264ParamT;            // 编码参数
    x264_picture_t x264PictureTIn;      // 帧缓存
    x264_picture_t x264PictureTOut;     // 帧缓存
    int inFrames = 0;
    int x264NalT;
    // 给结构体赋默认值
    x264_param_default(&x264ParamT);
    // 初始化编码参数
    // 日志登记
    x264ParamT.i_log_level = X264_LOG_DEBUG;
    // 自动选择最佳前瞻线程缓冲区大小
    x264ParamT.i_threads  = X264_SYNC_LOOKAHEAD_AUTO;
    // 颜色深度
    x264ParamT.i_bitdepth = 8;
    // 输入为420
    x264ParamT.i_csp = X264_CSP_I420;
    // 宽度
    x264ParamT.i_width  = width;
    // 高度
    x264ParamT.i_height = height;
    // 设置帧率(分子)
    x264ParamT.i_fps_num = 30;
    // 设置帧率时间1s(分母)
    x264ParamT.i_fps_den = 1;
    //在此间隔设置IDR关键帧的数量
    x264ParamT.i_keyint_max = 20;
//     码率控制方法,CQP(恒定质量),CRF(恒定码率,缺省值23),ABR(平均码率)
//    x264ParamT.rc.i_rc_method = X264_RC_CQP;  // 设置后,会导致参数应用失败
    x264ParamT.rc.i_rc_method = X264_RC_CRF;  // 设置后,会导致参数应用失败 或者 编码器打开失败
//    x264ParamT.rc.i_rc_method = X264_RC_CQP;  // 设置后,会导致参数应用失败
    // 应用参数
    if(x264_param_apply_profile(&x264ParamT, "baseline") < 0)
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to x264_param_apply_profile";
        return ret;
    }
    // 初始化删除
    x264_picture_init(&x264PictureTOut);
    // 分配帧缓存
    if(x264_picture_alloc(&x264PictureTIn, x264ParamT.i_csp, x264ParamT.i_width, x264ParamT.i_height) < 0)
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to x264_picture_alloc";
        return ret;
    }
    // 获取编码器
    x264_t *pX264T = 0;
    // 检测输入文件
    if(!yuvFile.endsWith(".yuv"))
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to recgnize ext:" << yuvFile;
        return ret;
    }
    // 检测输出文件
    if(destFile.isEmpty())
    {
        destFile = yuvFile;
        destFile.truncate(destFile.lastIndexOf(".yuv"));
        destFile += ".h264";
    }else if(!destFile.endsWith(".h264"))
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to recgnize ext:" << destFile;
        return ret;
    }
    qDebug() << __FILE__ << __LINE__ << yuvFile << "to" << destFile;
    pX264T = x264_encoder_open(&x264ParamT);
    if(!pX264T)
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to x264_encoder_open";
        x264_picture_clean(&x264PictureTIn);
        return ret;
    }
    // 总点大小
    int framesPixelCount = x264ParamT.i_width * x264ParamT.i_height;
    // 判断帧的数量(文件大小/每帧大小)
    if(inFrames == 0)
    {
        fseek(fpSrc, 0, SEEK_END);
        switch (x264ParamT.i_csp)
        {
        case X264_CSP_I444:
            inFrames = ftell(fpSrc) / (framesPixelCount * 3);
            break;
        case X264_CSP_I422:
            inFrames = ftell(fpSrc) / (framesPixelCount * 2);
            break;
        case X264_CSP_I420:
            inFrames = ftell(fpSrc) / (framesPixelCount * 3 / 2);
            break;
        default:
            break;
        }
        fseek(fpSrc, 0, SEEK_SET);
    }
    // 循环编码
    for(int index = 0; index < inFrames; index++)
    {
        switch (x264ParamT.i_csp)
        {
        case X264_CSP_I444:
            fread(x264PictureTIn.img.plane[0], framesPixelCount, 1, fpSrc);   // Y
            fread(x264PictureTIn.img.plane[1], framesPixelCount, 1, fpSrc);   // U
            fread(x264PictureTIn.img.plane[2], framesPixelCount, 1, fpSrc);   // V
            break;
        case X264_CSP_I422:
            {
                int i = 0;
                int y_i=0,u_i=0,v_i=0;
                for(i = 0 ; i < framesPixelCount * 2 ;)
                {
                    fread(&x264PictureTIn.img.plane[0][y_i++], 1, 1, fpSrc);   //Y
                    fread(&x264PictureTIn.img.plane[1][u_i++], 1, 1, fpSrc);   //U
                    fread(&x264PictureTIn.img.plane[0][y_i++], 1, 1, fpSrc);   //Y
                    fread(&x264PictureTIn.img.plane[2][v_i++], 1, 1, fpSrc);   //V
                }break;
            }
            break;
        case X264_CSP_I420:
            fread(x264PictureTIn.img.plane[0], framesPixelCount,   1, fpSrc);   // Y
            fread(x264PictureTIn.img.plane[1], framesPixelCount/4, 1, fpSrc);   // U
            fread(x264PictureTIn.img.plane[2], framesPixelCount/4, 1, fpSrc);   // V
            break;
        default:
            break;
        }
        // 当前帧数
        x264PictureTIn.i_pts = index;
        qDebug() << __FILE__ << __LINE__ << "Succeed to get frame:" << index << "/" << inFrames;
        int iRet = x264_encoder_encode(pX264T, &pX264NalT, &x264NalT, &x264PictureTIn, &x264PictureTOut);
        if(iRet < 0)
        {
            qDebug() << __FILE__ << __LINE__ << "Failed to x264_encoder_encode";
            return ret;
        }
        qDebug() << __FILE__ << __LINE__ << "Succeed to encode frame:" << index;
#if 1
        // 此处是一边拿到编码器一边编码写入到文件中
        int i = 0;
        // 编码器编码存入文件
        for(int j = 0; j < x264NalT; j++)
        {
            fwrite(pX264NalT[j].p_payload, 1, pX264NalT[j].i_payload, fpDst);
        }
#endif
    }
#if 0
    // 此处是全部拿到编码器里面后,再循环拿取所有,然后写入
    int i = 0;
    while(true)
    {
        int iRet = x264_encoder_encode(pX264T, &pX264NalT, &x264NalT, NULL, &x264PictureTOut);
        if(iRet == 0)
        {
            break;
        }
        qDebug() << __FILE__ << __LINE__ << i << inFrames << iRet;
        // 编码器编码存入文件
        for(int j = 0; j < x264NalT; j++)
        {
            fwrite(pX264NalT[j].p_payload, 1, pX264NalT[j].i_payload, fpDst);
        }
        i++;
    }
#endif
    qDebug() << __FILE__ << __LINE__ << "It's finished!!!";
    x264_picture_clean(&x264PictureTIn);
    x264_encoder_close(pX264T);
    pX264T = 0;
    fclose(fpSrc);
    fclose(fpDst);
}



相关文章
|
2月前
|
并行计算 PyTorch TensorFlow
Ubuntu安装笔记(一):安装显卡驱动、cuda/cudnn、Anaconda、Pytorch、Tensorflow、Opencv、Visdom、FFMPEG、卸载一些不必要的预装软件
这篇文章是关于如何在Ubuntu操作系统上安装显卡驱动、CUDA、CUDNN、Anaconda、PyTorch、TensorFlow、OpenCV、FFMPEG以及卸载不必要的预装软件的详细指南。
4564 3
|
2月前
|
监控 Ubuntu Linux
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
这篇文章介绍了如何在Ubuntu和Windows系统中通过设置相同的时区并使用ntp服务来解决时间同步问题。
73 4
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
|
2月前
|
Ubuntu 应用服务中间件 nginx
Ubuntu安装笔记(三):ffmpeg(3.2.16)源码编译opencv(3.4.0)
本文是关于Ubuntu系统中使用ffmpeg 3.2.16源码编译OpenCV 3.4.0的安装笔记,包括安装ffmpeg、编译OpenCV、卸载OpenCV以及常见报错处理。
181 2
Ubuntu安装笔记(三):ffmpeg(3.2.16)源码编译opencv(3.4.0)
|
2月前
|
Ubuntu Linux C语言
Ubuntu安装笔记(二):ubuntu18.04编译安装opencv 3.4.0 opencv_contrib3.4.0
本文介绍了在Ubuntu 18.04系统上编译安装OpenCV 3.4.0及其扩展包opencv_contrib 3.4.0的详细步骤,包括下载源码、安装依赖、配置CMake和编译安装,以及常见问题的解决方法。
175 1
Ubuntu安装笔记(二):ubuntu18.04编译安装opencv 3.4.0 opencv_contrib3.4.0
|
3月前
|
C++
vtkdicom0.8_vtk9.2_dcmtk3.6.7_qt6.2编译OK
本文介绍了如何编译整合VTK 9.2、DICOM 0.8、DCMTK 3.6.7和Qt 6.2的步骤,包括安装Qt、CMake配置以及确认相关路径和版本设置。
vtkdicom0.8_vtk9.2_dcmtk3.6.7_qt6.2编译OK
|
3月前
|
Unix 网络虚拟化 C++
VS2022+Qt5.14.2成功编译MITK2022.10
使用VS2022和Qt5.14.2成功编译MITK2022.10的过程,包括编译结果的截图、遇到的编译问题的解决方法、两个重要的注意事项(patch文件格式的修改和ITK-gitclone-lastrun文件的存在),以及参考链接。文中详细描述了如何解决编译过程中遇到的错误C2220和警告C4819,以及如何修改文件编码和尾行格式。
171 1
VS2022+Qt5.14.2成功编译MITK2022.10
|
3月前
|
计算机视觉
vs2019_qt6.2.4_dcmtk3.6.7_vtk9.2.2_itk5.3_opencv4.6.0编译记录
这篇文章记录了使用VS2019编译Qt6.2.4、DCMTK3.6.7、VTK9.2.2、ITK5.3和OpenCV4.6.0的过程,包括下载和编译步骤,并提供了遇到编译错误时的解决方案和参考链接。
vs2019_qt6.2.4_dcmtk3.6.7_vtk9.2.2_itk5.3_opencv4.6.0编译记录
|
3月前
|
C语言 C++ Windows
QT多插件通信框架CTK编译记录
本文记录了编译QT多插件通信框架CTK的过程,包括编译结果截图、部署配置、Log4Qt编译配置、参考链接和拓展资料。文中提供了详细的编译步骤和配置文件示例,以及相关的资源链接。
QT多插件通信框架CTK编译记录
|
3月前
|
机器学习/深度学习 Java 计算机视觉
opencv4.5.5+qt5.15.2+vtk9.1+mingw81_64编译记录
本文记录了使用mingw81_64编译OpenCV 4.5.5、Qt 5.15.2、VTK 9.1的详细过程,包括编译结果截图、编译步骤、遇到的问题及其解决方案,以及相关参考链接。文中还提到了如何编译boost源码为静态库,并提供了测试代码示例。
opencv4.5.5+qt5.15.2+vtk9.1+mingw81_64编译记录
|
3月前
|
C语言
BOOST1.75+QT5.15.2编译记录
本文记录了BOOST 1.75与Qt 5.15.2编译过程的详细步骤,包括编译结果截图、将boost源码编译为静态库的步骤,以及如何在Qt项目中使用BOOST库的测试代码。文章还提供了相关参考链接,以帮助解决在编译和使用过程中可能遇到的问题。
BOOST1.75+QT5.15.2编译记录