13、ffmpeg使用nvidia显卡对OAK深度相机进行解码和编码

news2024/11/26 2:39:47

基本思想:简单使用nvidia的硬件解码进行oak相机的编码和解码学习

一、在本机rtx3060配置好显卡驱动和cuda之后进行下面操作50、ubuntu18.04&20.04+CUDA11.1+cudnn11.3+TensorRT7.2/8.6+Deepsteam5.1+vulkan环境搭建和YOLO5部署_ubuntu18.04安装vulkan_sxj731533730的博客-CSDN博客

二、配置环境和编译库

ubuntu@ubuntu:~$ sudo apt-get install libtool automake autoconf nasm yasm
ubuntu@ubuntu:~$ sudo apt-get install libx264-dev
ubuntu@ubuntu:~$ sudo apt-get install libx265-dev
ubuntu@ubuntu:~$ sudo apt-get install libmp3lame-dev
ubuntu@ubuntu:~$ sudo apt-get install libvpx-dev
ubuntu@ubuntu:~$ sudo apt-get install libfaac-dev

ubuntu@ubuntu:~$ git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
ubuntu@ubuntu:~$ cd nv-codec-headers
ubuntu@ubuntu:~$ make
ubuntu@ubuntu:~$ sudo make install


ubuntu@ubuntu:~$ git clone https://github.com/FFmpeg/FFmpeg
ubuntu@ubuntu:~$ cd FFmpeg/
ubuntu@ubuntu:~$ mkdir build
ubuntu@ubuntu:~$ cd build/
 ubuntu@ubuntu:~/FFmpeg$./configure  --prefix=/usr/local --enable-gpl --enable-nonfree --enable-libfreetype --enable-libmp3lame --enable-libvpx --enable-libx264 --enable-libx265 --enable-gpl --enable-version3 --enable-nonfree --enable-shared --enable-ffmpeg --enable-ffplay --enable-ffprobe --enable-libx264 --enable-nvenc --enable-cuda --enable-cuvid --enable-libnpp --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64
ubuntu@ubuntu:~/FFmpeg$ sudo ldconfig
ubuntu@ubuntu:~$

三、使用oak相机进行h264解码测试

cmakelists.txt

cmake_minimum_required(VERSION 3.16)
project(depthai)
set(CMAKE_CXX_STANDARD 11)
find_package(OpenCV REQUIRED)
#message(STATUS ${OpenCV_INCLUDE_DIRS})
#添加头文件
include_directories(${OpenCV_INCLUDE_DIRS})
include_directories(${CMAKE_SOURCE_DIR}/utility)
#链接Opencv库
find_package(depthai CONFIG REQUIRED)
add_executable(depthai main.cpp utility/utility.cpp)
target_link_libraries(depthai ${OpenCV_LIBS}  depthai::opencv -lavformat -lavcodec -lswscale -lavutil -lz)

main.cpp


#include <stdio.h>
#include <string>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}


#include "utility.hpp"

#include "depthai/depthai.hpp"

using namespace std::chrono;

int main(int argc, char **argv) {
    dai::Pipeline pipeline;
    //定义
    auto cam = pipeline.create<dai::node::ColorCamera>();
    cam->setBoardSocket(dai::CameraBoardSocket::RGB);
    cam->setResolution(dai::ColorCameraProperties::SensorResolution::THE_1080_P);
    cam->setVideoSize(1920, 1080);
    auto Encoder = pipeline.create<dai::node::VideoEncoder>();
    Encoder->setDefaultProfilePreset(cam->getVideoSize(), cam->getFps(),
                                     dai::VideoEncoderProperties::Profile::H264_MAIN);


    cam->video.link(Encoder->input);
    cam->setFps(60);

    //定义输出
    auto xlinkoutpreviewOut = pipeline.create<dai::node::XLinkOut>();
    xlinkoutpreviewOut->setStreamName("out");

    Encoder->bitstream.link(xlinkoutpreviewOut->input);


    //结构推送相机
    dai::Device device(pipeline);
    //取帧显示
    auto outqueue = device.getOutputQueue("out", cam->getFps(), false);//maxsize 代表缓冲数据


    // auto videoFile = std::ofstream("video.h265", std::ios::binary);


    int width = 1920;
    int height = 1080;
    //const AVCodec *pCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
    const AVCodec *pCodec = avcodec_find_decoder_by_name("h264_cuvid");
    AVCodecContext *pCodecCtx = avcodec_alloc_context3(pCodec);

    AVDictionary* decoderOptions = nullptr;
    av_dict_set(&decoderOptions, "threads", "auto", 0);
    av_dict_set(&decoderOptions, "gpu", "cuda", 0);


    int ret = avcodec_open2(pCodecCtx, pCodec, &decoderOptions);
    if (ret < 0) {//打开解码器
        printf("Could not open codec.\n");
        return -1;
    }

    if (pCodecCtx != nullptr) {
        // 打印解码器支持的格式
        printf("Supported Formats:\n");
        const AVPixelFormat *pixFmt = pCodec->pix_fmts;
        while (*pixFmt != AV_PIX_FMT_NONE) {
            printf("- %s\n", av_get_pix_fmt_name(*pixFmt));
            pixFmt++;
        }

    }
    AVFrame *picture = av_frame_alloc();
    picture->width = width;
    picture->height = height;
    picture->format = AV_PIX_FMT_NV12;
    ret = av_frame_get_buffer(picture, 1);
    if (ret < 0) {
        printf("av_frame_get_buffer error\n");
        return -1;
    }
    AVFrame *pFrame = av_frame_alloc();
    pFrame->width = width;
    pFrame->height = height;
    pFrame->format = AV_PIX_FMT_NV12;
    ret = av_frame_get_buffer(pFrame, 1);
    if (ret < 0) {
        printf("av_frame_get_buffer error\n");
        return -1;
    }
    AVFrame *pFrameRGB = av_frame_alloc();
    pFrameRGB->width = width;
    pFrameRGB->height = height;
    pFrameRGB->format = AV_PIX_FMT_RGB24;
    ret = av_frame_get_buffer(pFrameRGB, 1);
    if (ret < 0) {
        printf("av_frame_get_buffer error\n");
        return -1;
    }


    int picture_size = av_image_get_buffer_size(AV_PIX_FMT_NV12, width, height,
                                                1);//计算这个格式的图片,需要多少字节来存储
    uint8_t *out_buff = (uint8_t *) av_malloc(picture_size * sizeof(uint8_t));
    av_image_fill_arrays(picture->data, picture->linesize, out_buff, AV_PIX_FMT_NV12, width,
                         height, 1);
    //这个函数 是缓存转换格式,可以不用 以为上面已经设置了AV_PIX_FMT_YUV420P
    SwsContext *img_convert_ctx = sws_getContext(width, height, AV_PIX_FMT_NV12,
                                                 width, height, AV_PIX_FMT_RGB24, 4,
                                                 NULL, NULL, NULL);
    AVPacket *packet = av_packet_alloc();
    auto startTime = steady_clock::now();
    int counter = 0;
    float fps = 0;

    while (true) {

        auto h265Packet = outqueue->get<dai::ImgFrame>();
        //videoFile.write((char *) (h265Packet->getData().data()), h265Packet->getData().size());

        packet->data = (uint8_t *) h265Packet->getData().data();    //这里填入一个指向完整H264数据帧的指针
        packet->size = h265Packet->getData().size();        //这个填入H265 数据帧的大小
        packet->stream_index = 0;
        ret = avcodec_send_packet(pCodecCtx, packet);
        if (ret < 0) {
            printf("avcodec_send_packet \n");
            continue;
        }
        av_packet_unref(packet);
        int got_picture = avcodec_receive_frame(pCodecCtx, pFrame);
        av_frame_is_writable(pFrame);
        if (got_picture < 0) {
            printf("avcodec_receive_frame \n");
            continue;
        }

        sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0,
                  height,
                  pFrameRGB->data, pFrameRGB->linesize);


        cv::Mat mRGB(cv::Size(width, height), CV_8UC3);
        mRGB.data = (unsigned char *) pFrameRGB->data[0];
        cv::Mat mBGR;
        cv::cvtColor(mRGB, mBGR, cv::COLOR_RGB2BGR);
        counter++;
        auto currentTime = steady_clock::now();
        auto elapsed = duration_cast<duration<float>>(currentTime - startTime);
        if (elapsed > seconds(1)) {
            fps = counter / elapsed.count();
            counter = 0;
            startTime = currentTime;
        }


        std::stringstream fpsStr;
        fpsStr << "NN fps: " << std::fixed << std::setprecision(2) << fps;
        printf("fps %f\n",fps);
        cv::putText(mBGR, fpsStr.str(), cv::Point(32, 24), cv::FONT_HERSHEY_TRIPLEX, 0.4,
                    cv::Scalar(0, 255, 0));


        cv::imshow("demo", mBGR);
        cv::waitKey(1);


    }


    return 0;
}

测试结果

四、使用oak进行解码测试

cmakelists.txt

cmake_minimum_required(VERSION 3.16)
project(depthai)
set(CMAKE_CXX_STANDARD 11)
find_package(OpenCV REQUIRED)
#message(STATUS ${OpenCV_INCLUDE_DIRS})
#添加头文件
include_directories(${OpenCV_INCLUDE_DIRS})
include_directories(${CMAKE_SOURCE_DIR}/utility)
#链接Opencv库
find_package(depthai CONFIG REQUIRED)
add_executable(depthai main.cpp utility/utility.cpp)
target_link_libraries(depthai ${OpenCV_LIBS}  depthai::opencv -lavformat -lavcodec -lswscale -lavutil -lz)

main.cpp

#include <iostream>
#include <stdio.h>
#include <string>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}

#include "fstream"

#include "utility.hpp"

#include "depthai/depthai.hpp"

using namespace std;

int main() {

    int WIDTH = 1920;
    int HEIGHT = 1080;
    AVPacket pack;
    int vpts = 0;
    uint8_t *in_data[AV_NUM_DATA_POINTERS] = {0};
    SwsContext *sws_context =NULL;
    // AVCodecContext *codec_context = nullptr;
    int in_size[AV_NUM_DATA_POINTERS] = {0};

    std::ofstream videoFile;
    // 2.初始化格式转换上下文
    int fps = 25;
     sws_context = sws_getCachedContext(sws_context,
                                                   WIDTH, HEIGHT, AV_PIX_FMT_BGR24,    // 源格式
                                                   WIDTH, HEIGHT, AV_PIX_FMT_YUV420P,  // 目标格式
                                                   SWS_BICUBIC,    // 尺寸变化使用算法
                                                   0, 0, 0);

    if (NULL == sws_context) {
        cout << "sws_getCachedContext error" << endl;
        return -1;
    }



    // 3.初始化输出的数据结构
    AVFrame *yuv = av_frame_alloc();
    yuv->format = AV_PIX_FMT_YUV420P;
    yuv->width = WIDTH;
    yuv->height = HEIGHT;
    yuv->pts = 0;

    // 分配yuv空间
    int ret_code = av_frame_get_buffer(yuv, 32);
    if (0 != ret_code) {
        cout << "  yuv init fail" << endl;
        return -1;
    }

    // 4.初始化编码上下文
    // 4.1找到编码器
    // const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    const AVCodec *codec = avcodec_find_encoder_by_name("h264_nvenc");//nvenc nvenc_h264 h264_nvenc

    // const AVCodec * codec = avcodec_find_encoder_by_name("nvenc");
    if (NULL == codec) {
        cout << "Can't find h264 encoder." << endl;
        return -1;
    }

    // 4.2创建编码器上下文
    AVCodecContext *codec_context = avcodec_alloc_context3(codec);
    if (NULL == codec_context) {
        cout << "avcodec_alloc_context3 failed." << endl;
        return -1;
    }


    // 4.3配置编码器参数
    // vc->flags           |= AV_CODEC_FLAG_GLOBAL_HEADER;
    codec_context->codec_id = codec->id;
    codec_context->thread_count = 16;

    // 压缩后每秒视频的bit流 5M
    codec_context->bit_rate = 5 * 1024 * 1024;
    codec_context->width = WIDTH;
    codec_context->height = HEIGHT;
    codec_context->time_base = {1, fps};
    codec_context->framerate = {fps, 1};
    // 画面组的大小,多少帧一个关键帧
    codec_context->gop_size = 50;
    codec_context->max_b_frames = 0;
    codec_context->pix_fmt = AV_PIX_FMT_YUV420P;
    codec_context->qmin = 10;
    codec_context->qmax = 51;

    AVDictionary *codec_options = nullptr;
    //(baseline | high | high10 | high422 | high444 | main)
//    av_dict_set(&codec_options, "profile", "baseline", 0);
//    av_dict_set(&codec_options, "preset", "superfast", 0);
//    av_dict_set(&codec_options, "tune", "zerolatency", 0);
    AVDictionary* decoderOptions = nullptr;
    av_dict_set(&decoderOptions, "threads", "auto", 0);
    av_dict_set(&decoderOptions, "gpu", "cuda", 0);

//
//    if (codec->id == AV_CODEC_ID_H264) {
//        av_dict_set(&codec_options, "preset", "medium", 0);
//        av_dict_set(&codec_options, "tune", "zerolatency", 0);
//        av_dict_set(&codec_options, "rc", "cbr", 0);
//    }
    // 4.4打开编码器上下文
    ret_code = avcodec_open2(codec_context, codec, &codec_options);
    if (0 != ret_code) {

        return -1;
    }

    videoFile = std::ofstream("video.h264", std::ios::binary);


    dai::Pipeline pipeline;
    //定义左相机
    auto mono = pipeline.create<dai::node::ColorCamera>();
    mono->setBoardSocket(dai::CameraBoardSocket::RGB);

    //定义输出
    auto xlinkOut = pipeline.create<dai::node::XLinkOut>();
    xlinkOut->setStreamName("rgb");

    //相机和输出链接
    mono->video.link(xlinkOut->input);;
    //结构推送相机
    dai::Device device(pipeline);
    //取帧显示
    auto queue = device.getOutputQueue("rgb", 1);//maxsize 代表缓冲数据



    while (1) {

        auto image = queue->get<dai::ImgFrame>();

        auto frame = image->getCvFrame();

        memset(&pack, 0, sizeof(pack));

        in_data[0] = frame.data;
        // 一行(宽)数据的字节数
        in_size[0] = frame.cols * frame.elemSize();
        int h = sws_scale(sws_context, in_data, in_size, 0, frame.rows,
                          yuv->data, yuv->linesize);
        if (h <= 0) { return -1; }

        // h264编码
        yuv->pts = vpts;
        vpts++;

        int ret_code = avcodec_send_frame(codec_context, yuv);
        if (0 != ret_code) { return -1; }

        ret_code = avcodec_receive_packet(codec_context, &pack);

        if (0 != ret_code || pack.buf != nullptr) {//
            cout << "avcodec_receive_packet." << endl;

        } else {
            cout << "avcodec_receive_packet contiune." << endl;
            return -1;
        }
        //写入文件

        videoFile.write((char *) (pack.data), pack.size);

    }
    return 0;
}

使用ffplay 播放h264文件,感觉有问题,cpu占比还是比较高,待研究手册

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/785014.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# 右键菜单 contextMenuStrip

最近需要使用到C#的右键菜单contextMenuStrip控件。 这里记录一下。 首先在工具箱中找到contextMenuStrip控件。将他拖到你的窗体中&#xff0c;如下图所示&#xff1a; 默认名称为&#xff1a;contextMenuStrip1. 然后将你需要使用右键属性的控件和contextMenuStrip1绑定起…

Mac上安装sshfs

目录 写在前面安装使用参考完 写在前面 1、本文内容 Mac上安装sshfs 2、平台 mac 3、转载请注明出处&#xff1a; https://blog.csdn.net/qq_41102371/article/details/130156287 安装 参考&#xff1a;https://ports.macports.org/port/sshfs/ 通过port安装 点击啊insta…

IC设计从业者必备的宝藏网站!

对于IC设计从业者而言&#xff0c;获取准确的学习资源&#xff0c;行业资讯直观重要&#xff0c;今日我们推荐ic行业专业的宝藏网站&#xff0c;希望对从业者有所帮助。 01-找开源项目的网站 GitHub除了Git代码仓库托管及基本的 Web管理界面以外&#xff0c;还提供了订阅、讨论…

WebClient,HTTP Interface远程调用阿里云API

HTTP Interface Spring 允许我们通过定义接口的方式&#xff0c;给任意位置发送 http 请求&#xff0c;实现远程调用&#xff0c;可以用来简化 HTTP 远程访问。需要webflux场景才可 <dependency><groupId>org.springframework.boot</groupId><artifactId&…

进阶C语言——文件操作(上)

本章文章主要是关于文件教学的&#xff0c;大家可能会对C语言中的文件可能有点陌生&#xff0c;这两个看起老来完全扯不上边的东西&#xff0c;但是实际上他们有很多的关联&#xff0c;本章文章将讲解一些文件的打开和关闭&#xff0c;并和一些库函数一起使用之后的效果&#x…

MATLAB计算变异函数并绘制经验半方差图

本文介绍基于MATLAB求取空间数据的变异函数&#xff0c;并绘制经验半方差图的方法。 由于本文所用的数据并不是我的&#xff0c;因此遗憾不能将数据一并展示给大家&#xff1b;但是依据本篇博客的思想与对代码的详细解释&#xff0c;大家用自己的数据&#xff0c;可以将空间数据…

第一百一十五天学习记录:C++提高:STL初识(黑马教学视频)

STL的诞生 1、长久以来&#xff0c;软件界一直希望建立一种可重复利用的东西 2、C的面向对象和泛型编程思想&#xff0c;目的就是重复性的提升 3、大多数情况下&#xff0c;数据结构和算法都未能有一套标准&#xff0c;导致被迫从事大量重复工作 4、为了建立数据结构和算法的一…

samba挂载报错“mount error(13): Permission denied“

“mount error(13): Permission denied” 环境&#xff1a;CentOS7 挂载报错&#xff1a; [rootchenshuyi ~]# mount -t cifs //127.0.0.1/printers /tmp/samba Password for root//127.0.0.1/printers: mount error(13): Permission denied Refer to the mount.cifs(8) manu…

印制电路板中常用标准有哪些?

在PCB电路板中一般都有哪些标准呢&#xff1f;一起来看看。 1) IPC-ESD-2020&#xff1a;静电放电控制程序开发的联合标准。包括静电放电控制程序所必须的设计、建立、实现和维护。根据某些军事组织和商业组织的历史经验&#xff0c;为静电放电敏感时期进行处理和保护提供指导。…

前端:运用html+css+js模仿百度热搜电影榜鼠标移入特效

前端:运用htmlcssjs模仿百度热搜电影榜鼠标移入特效 1. 实现原理2. 界面布局3. js实现对鼠标移入和移出的监听4. 参考代码如下&#xff1a; 1. 实现原理 百度热搜上电影榜鼠标移入特效如上图所示。个人觉得上述特效实现原理为使用相对定位、绝对定位实现的(鼠标移入和没有移入…

OrangePi Zero2 TTL 连接示意图

OrangePi 目前最方便的就是使用调试串口线进行PC与开发板进行链接。 OrangePi Zero2 GPIO引脚图 TTL连接图 本人使用的型号为CH340模块USB转TTL刷机线&#xff0c;Windows下免驱。 黑线对GND接口&#xff0c;绿线对RX接口&#xff0c;白线对TX接口。

element-ui form表单的动态rules校验

在vue 项目中&#xff0c;有时候可能会用到element-ui form表单的动态rules校验&#xff0c;比如说选择了哪个选项&#xff0c;然后动态显示或者禁用等等。 我们可以巧妙的运用element-ui form表单里面form-item想的校验规则来处理&#xff08;每一个form-item项都可以单独校验…

推荐几个Windows iso镜像下载的网站

文章目录 1. 微软官网2. MSDN网站3. 系统库(xitongku)4. 其他网站最后总结 给大家推荐几个 Windows iso镜像下载网站 1. 微软官网 入口地址&#xff1a;https://www.microsoft.com/zh-cn/software-download 以下载Windows11为例&#xff1a; 1&#xff09;找到下载Windows11…

【教程】查看CPU、GPU架构的拓扑结构和系统信息

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 一些概念 Package&#xff1a;处理器封装。在多处理器系统中&#xff0c;每个物理 CPU 芯片通常被封装在一个单独的封装中&#xff0c;这个封装被称为 Package。一个 Package 可以包含一个或多个物理 CPU 核心。…

计算机组成原理复习-例题版

目录 第一章&#xff1a;计算机系统概论 第二章&#xff1a;机器数 第三章&#xff1a;指令 第四章&#xff1a;机器数运算 第六章&#xff1a;CPU 第七章、第八章、第九章 &#xff1a;总线、辅存、中断 第一章&#xff1a;计算机系统概论 第二章&#xff1a;机器数 ​​…

SVG 简单应用

第一步赋值svg 第二步&#xff1a;fill 填充色设置为“” 第三步设置 svg 颜色和大小

基础算法-单链表

单链表 -> 邻接表:主要用于存储图和树。 双链表 : 主要用于优化某些问题。 单链表的相关操作&#xff1a;1.单链表的初始化 2.将x插到头节点 3.将x插入到下标是k的节点后面 4.将下标是k的节点的后面一个节点删除 1.单链表的初始化 代码&#xff1a; //单链表的初始…

第117天:免杀对抗-反VT沙盒反虚拟机反调试进程APC注入项目保护

知识点 #知识点&#xff1a; 1、反VT-沙盒检测-Go&Python&C 2、反调试-调试检测&进程注入-C 3、反VT反调试-程序保护-工具项目类#章节点&#xff1a; 编译代码面-ShellCode-混淆 编译代码面-编辑执行器-编写 编译代码面-分离加载器-编写 程序文件面-特征码定位-修…

Tripwire 完整性分析工具(Linxu系统)

环境&#xff1a;centos7 工作流程&#xff1a; 当前的系统数据状态建立数据库定期比较系统现状与数据库中的状态属性改变有详细报告分析报告发现入侵 1、安装相关软件包 [roothello ~]# yum install epel-release -y 已加载插件&#xff1a;fastestmirror Repository base …

自学网络安全(黑客)全笔记

一、什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面…