opencv+nvcodec实现视频硬解码

2023-11-17

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


系统配置

操作系统:Ubuntu18.04
硬件架构:x86_64
OpenCV:4.5.1
FFmpeg:4.4.2
CUDA:11.2

前言`

最近遇到一个新项目,AI推理在CUDA上,为了方便和节省成本的考虑决定研究下NVCODEC模块。根据NVIDIA官网的说法显卡具有独立的编码解码模块,所以理论上编码解码是独立互不干涉的。以前的项目都只是把显卡当成推理工具,没有将它的编解码功能利用起来,本身也是一种浪费。事实真的有这么丝滑吗?看到这里,如果你真的觉得黄一刀是白叫的那就真的是too young to simple了,事实究竟如何,请听我娓娓道来。


一、NVCODEC是什么?

NVCODEC全称是 NVIDIA VIDEO CODEC,是NVIDIA为绝大多数显卡配置的硬件编解码单元。不一定是所有显卡都有,一般来讲越新的显卡硬件编解码就越强,支持的格式也就越新。比如,拿消费端的显卡来讲,只有RTX3000以上的显卡才支持AV1这种新格式,像RTX2000以下的显卡目前无缘。当然以后还有可能会出更多格式。目前我所知道的NVIDIA解码支持两种方式:

1、NVCODEC编解码

这种解码方式是我们这篇文章要讲的主角,也就是硬件编解码。这里的硬件编解码指的是利用专门运算单元来完成编解码过程,这种专门运算单元被设计出来就是固定只干这一种活的硬件,跟软解码最大的差别是,软编解码是利用通用运算单元硬算

2、CUDA编解码
通常情况下CUDA是拿来做AI推理的,但是有些特殊情况下CUDA也是可以直接拿来编解码的,这个时候CUDA就是通用运算单元了,因为它不是专门设计来做编解码工作的,属于被迫上岗。

我们看看NVIDIA自己怎么介绍自家的东西的:

NVIDIA GPUs contain one or more hardware-based decoder and encoder(s) (separate from the CUDA cores) which provides fully-accelerated hardware-based video decoding and encoding for several popular codecs. With decoding/encoding offloaded, the graphics engine and the CPU are free for other operations.

GPU hardware accelerator engines for video decoding (referred to as NVDEC) and video encoding (referred to as NVENC) support faster than real-time video processing which makes them suitable to be used for transcoding applications, in addition to video playback.

在这里插入图片描述
从上图我们看出,CUDA编解码是独立的硬件,所以他们是分别独立工作的,不会相互干扰。

好了,闲话已经说的差不多了,接下来我们进入正题。将opencvnvcodec结合起来完成视频的解码,并将解码后的GpuMat送入CUDA推理。

二、OpenCV编译

1.安装Driver&CUDA

这个地方要重点讲一下,安装CUDA的时候是可以顺手把Driver装上的,这里我推荐用这种方式,因为这种方式安装的驱动自带NVCODEC的库和头文件,这样的话我们就不用专门去下载NVIDIA VIDEO CODEC SDK了。而且我发现NVIDIA VIDEO CODEC SDKDriver有版本依赖,弄不好会出各种奇葩问题。所以,这里讲的所有教程都是基于同时安装CUDA+Driver的,至于怎么安装CUDADriver请大家自行搜索教程,由于篇幅有限这里不做详述。

驱动安装好之后需要检验是否正确,如果Driver安装正确执行nvidia-smi会出现Driver的详细信息,如下图所示:
在这里插入图片描述

这里我们说说最关键的两个信息Driver Version:460.27.04,这个意思是你安装的显卡驱动版本是460.27.04CUDA Version:11.2,这个的意思是和Driver配套的CUDA版本是11.2,就算你不装CUDA这个信息也会显示的。我建议你接受它的建议,就装那个版本的·CUDA·,除非有特殊需要,你就需要去NVIDIA的官网查询下具体支持的CUDA版本了。众所周知,DriverCUDA版本是存在依赖关系的,乱装是要出事情的。

接下来验证CUDA是不是装好了,命令行输入nvcc -V会看到以下的提示信息,说明CUDA安装成功了,

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2020 NVIDIA Corporation
Built on Mon_Nov_30_19:08:53_PST_2020
Cuda compilation tools, release 11.2, V11.2.67
Build cuda_11.2.r11.2/compiler.29373293_0

如果报了类似于command not fount一类的错误就说明CUDA没有装对或者环境变量没配置对,请检查下操作是否正确。

差点忘了,CuDNN也是需要的,千万别忘了装。CuDNN的验证比较简单,那就是不需要验证,你从官网下载3个deb包全部成功安装后就说明CuDNN安装成功了,不要有所怀疑。

2.编译OpenCV

下载opencv源代码这一步就不赘述了,这里我下载的是opencv-4.5.1.zip或者opencv-4.5.1.tar.gz两个包本质没有差别,只是压缩方式有差别罢了,没有影响。我们这里是需要opencv_contrib的,所以需要下载opencv_contrib-4.5.1.zipopencv_contrib-4.5.1.tar.gz,这两个压缩包也是一样的,一样用。

在这里要特别注意下opencv和opencv_contrib是有版本对应关系的,不能下错。

opencv的编译我不在这里详述了,网络上一抓一大把,这里我贴出来我的配置。

cmake -D CMAKE_BUILD_TYPE=RELEASE \
           -D CMAKE_INSTALL_PREFIX=/usr/local \
		   -D ENABLE_PRECOMPILED_HEADERS=OFF \
           -D INSTALL_C_EXAMPLES=OFF \
           -D INSTALL_PYTHON_EXAMPLES=OFF \
		   -D BUILD_opencv_python2=OFF \
           -D BUILD_opencv_python3=ON \
           -D PYTHON_DEFAULT_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")   \
           -D PYTHON3_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")   \
           -D PYTHON3_NUMPY_INCLUDE_DIRS=$(python3 -c "import numpy; print (numpy.get_include())") \
           -D PYTHON3_PACKAGES_PATH=$(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") \
		   -D WITH_TBB=ON \
           -D BUILD_TBB=ON  \
		   -D ENABLE_FAST_MATH=1 \
		   -D CUDA_FAST_MATH=1 \
           -D WITH_CUBLAS=1 \
           -D WITH_V4L=ON \
		   -D WITH_LIBV4L=ON \
           -D WITH_CUDA=ON \
		   -D WITH_CUDNN=ON \
		   -D WITH_GTK_2_X=ON \
           -D WITH_NVCUVID=ON \
           -D WITH_OPENGL=ON \
		   -D WITH_FFMPEG=ON  \
		   -D CUDA_ARCH_BIN=7.5 \
           -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.5.1/modules .

由于这里我用到了python cv2所以我编译了python模块。我的需求里面有拉流的需要,编译了ffmpeg模块。CUDA_ARCH_BIN=7.5不同的显卡不一样,我的显卡是RTX2080Ti,我是7.5,具体值都可以在NVIDIA官网查到。WITH_NVCUVID=ON这个一定要加上,这个就是编解码模块。

友情提示:
有个问题需要特别注意下,这种方式OpenCV是找不到NVCUVID的,原因是以前NVCUVIDCUDA放在一起的,后来NVIDIANVCUVID独立出来了,OpenCV的检测方式还是老的方式,所以找不到NVCUVID,解决方法也很简单,你只需要到opencv-4.5.1/cmake文件夹里找到OpenCVDetectCUDA.cmake

  if(WITH_NVCUVID)
    macro(ocv_cuda_SEARCH_NVCUVID_HEADER _filename _result)
      # place header file under CUDA_TOOLKIT_TARGET_DIR or CUDA_TOOLKIT_ROOT_DIR
      find_path(_header_result
        ${_filename}
        PATHS "${CUDA_TOOLKIT_TARGET_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}"
        ENV CUDA_PATH
        ENV CUDA_INC_PATH
        PATH_SUFFIXES include
        NO_DEFAULT_PATH
        )
      if("x${_header_result}" STREQUAL "x_header_result-NOTFOUND")
        set(${_result} 0)
      else()
        set(${_result} 1)
      endif()
      unset(_header_result CACHE)
    endmacro()
    ocv_cuda_SEARCH_NVCUVID_HEADER("nvcuvid.h" HAVE_NVCUVID_HEADER)
    ocv_cuda_SEARCH_NVCUVID_HEADER("dynlink_nvcuvid.h" HAVE_DYNLINK_NVCUVID_HEADER)
    find_cuda_helper_libs(nvcuvid)
    if(WIN32)
      find_cuda_helper_libs(nvcuvenc)
    endif()
    if(CUDA_nvcuvid_LIBRARY AND (${HAVE_NVCUVID_HEADER} OR ${HAVE_DYNLINK_NVCUVID_HEADER}))
      # make sure to have both header and library before enabling
      set(HAVE_NVCUVID 1)
    endif()
    if(CUDA_nvcuvenc_LIBRARY)
      set(HAVE_NVCUVENC 1)
    endif()
  endif()

注意这一句

PATHS "${CUDA_TOOLKIT_TARGET_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}"

是不是感觉很熟悉,这就是CUDA的安装目录,由于现在NVCUVIDCUDA不在一个目录了,所以只需要改成下面这样

PATHS "${CUDA_TOOLKIT_TARGET_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}" "/usr/include"

/usr/include是NVCUVID的头文件位置,你的在哪里就写什么目录就行了,改完执行cmake配置

如果cmake出错就缺什么安装什么就行了,这个我是亲身体验的,没有问题的。假如没有任何错误,你看到的应该是这样的:

Video I/O:
    DC1394:                      NO
    FFMPEG:                      YES
      avcodec:                   YES (58.134.100)
      avformat:                  YES (58.76.100)
      avutil:                    YES (56.70.100)
      swscale:                   YES (5.9.100)
      avresample:                YES (4.0.0)
    GStreamer:                   YES (1.14.5)
    v4l/v4l2:                    YES (linux/videodev2.h)
NVIDIA CUDA:                   YES (ver 11.2, CUFFT CUBLAS NVCUVID FAST_MATH)
    NVIDIA GPU arch:             75
    NVIDIA PTX archs:

  cuDNN:                         YES (ver 8.1.0)

 Python 3:
    Interpreter:                 /usr/bin/python3 (ver 3.6.9)
    Libraries:                   /usr/lib/x86_64-linux-gnu/libpython3.6m.so (ver 3.6.9)
    numpy:                       /usr/local/lib/python3.6/dist-packages/numpy/core/include (ver 1.19.5)
    install path:                /usr/lib/python3/dist-packages/cv2/python-3.6

  Python (for build):            /usr/bin/python3

FFMPEG一定都要是YES,不能是NONVIDIA CUDA: YES (ver 11.2, CUFFT CUBLAS NVCUVID FAST_MATH)这一行一定要有NVCUVID ,不然就是错误了。配置好后执行make -j$(nproc)等待编译完成执行sudo make install就可以了。这里有个地方需要注意,一定要把旧的opencv卸载干净,不然就会引发冲突或者未知错误。

注:ffmpeg的安装可以参考这篇文章
解决opencv源代码编译找不到ffmpeg

到这里我们的教程就算完了,如果一切顺利的话就可以使用NVCODEC来处理视频流了,RTSP格式的实时视频也是支持的,取出来的帧保存在GpuMat里面,可以送进去推理了。实测CPU解码帧率只有30左右(和CPU性能相关),GPU解码帧率7600多(和解码器性能相关),差距还是蛮大的。下面贴出测试代码:

opencv_test.cpp

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include "opencv2/opencv_modules.hpp"
#include <opencv2/core/utility.hpp>
#include <opencv2/core.hpp>
#include <opencv2/core/opengl.hpp>
#include <opencv2/cudacodec.hpp>
#include <opencv2/highgui.hpp>

int main(int argc, const char* argv[])
{
   std::cout<<cv::getBuildInformation()<<std::endl;
   //将这个流改成你自己的
   const std::string fname = "rtsp://admin:Wat0ne123@10.0.20.249";
    cv::cuda::setGlDevice();
    //cv::cuda::setGlDevice(1);
    cv::Mat frame;
    cv::VideoCapture reader(fname);
    cv::cuda::GpuMat d_frame;
    cv::Ptr<cv::cudacodec::VideoReader> d_reader = cv::cudacodec::createVideoReader(fname);
    cv::TickMeter tm;
    std::vector<double> cpu_times;
    std::vector<double> gpu_times;

    for (int i = 0;i<100;i++)
    {
        tm.reset(); tm.start();
        if (!reader.read(frame))
            break;
         tm.stop();
         cpu_times.push_back(tm.getTimeMilli());

         tm.reset(); tm.start();
        if (!d_reader->nextFrame(d_frame))
            break;
         tm.stop();
         gpu_times.push_back(tm.getTimeMilli());
    }

    if (!cpu_times.empty() && !gpu_times.empty())
    {
        std::cout << std::endl << "Results:" << std::endl;

        std::sort(cpu_times.begin(), cpu_times.end());
        std::sort(gpu_times.begin(), gpu_times.end());

        double cpu_avg = std::accumulate(cpu_times.begin(), cpu_times.end(), 0.0) / cpu_times.size();
        double gpu_avg = std::accumulate(gpu_times.begin(), gpu_times.end(), 0.0) / gpu_times.size();

        std::cout << "CPU : Avg : " << cpu_avg << " ms FPS : " << 1000.0 / cpu_avg << std::endl;
        std::cout << "GPU : Avg : " << gpu_avg << " ms FPS : " << 1000.0 / gpu_avg << std::endl;
    }

    return 0;
}
// #endif

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.2)
project(opencv_test)
SET(CMAKE_BUILD_TYPE "Debug")
include_directories(include)
find_package( OpenCV REQUIRED )
#find_package(OpenGL REQUIRED)
include_directories(
        ${OpenCV_INCLUDE_DIRS}
        #${OPENGL_INCLUDE_DIR}
        )
add_executable( opencv_test opencv_test.cpp )
#add_executable( opencv_test gpu_mat.cpp )
target_link_libraries( opencv_test
        ${OpenCV_LIBS}
        #${OPENGL_LIBRARIES}
        )
mkdir build && cd build
cmake ..
make
./opencv_test

特别说明:

	//默认执行设备,如果是单显卡请忽略,如果多显卡需要指定哪一个设备执行,默认是0
    cv::cuda::setGlDevice();
    //cv::cuda::setGlDevice(1);

总结

写到这里不得不感叹下,虽然只有区区几行命令却足足搞了一个星期。期间什么奇葩的错误都遇到了,甚至有些我认为是不必要出现的。

最典型的一个例子就是NVCODEC SDK,很多博主都说要从官网下载然后复制到系统目录,一开始我是这么做的,看起来好像全程没有遇到问题,直到最后一步跑程序的时候,终于所有的错误都来了,甚至遇到的最奇葩的问题是每次执行程序返回的错误码都是不一样的,这种BUG我也是生平仅见。最后甚至连Deiver都需要重新安装来解决。

事实真的如此吗?我真的需要每一步都照抄别人吗?实际上下载的CUDA Driver里面就有NVCODEC的SDK,不需要去官方下。只不过安装位置被从CUDA目录移除出来了,只需要修改opencv的检测方式就行了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

opencv+nvcodec实现视频硬解码 的相关文章

  • 如何查明 Ubuntu 上安装了哪个版本的 GTK+?

    我需要确定 Ubuntu 上安装了哪个版本的 GTK 男人似乎不帮忙 这个建议 https stackoverflow com a 126145 会告诉您安装了哪个 2 0 的次要版本 不同的主要版本将具有不同的包名称 因为它们可以在系统上
  • numpy 未定义符号:PyFPE_jbuf

    我正在尝试使用一百万首歌曲数据集 为此我必须安装 python 表 numpy cython hdf5 numexpr 等 昨天我设法安装了我需要的所有内容 在使用 hdf5 遇到一些麻烦之后 我下载了预编译的二进制包并将它们保存在我的 b
  • OpenCV 2.3 与 VS 2008 - 鼠标事件

    强制性 我是新手 有一份涉及编程的工作 并且我一边工作一边自学 不用说 作为一名老师 我经常犯彻底的错误 我现在所处的位置 我创建了 Graph 类 它 令人惊讶的是 制作了图表 但现在我想通过单击鼠标来修改图形 但我似乎无法让鼠标处理程序
  • 伊迪德信息

    重新定义问题 有什么方法可以获取所连接显示器的序列号吗 我想收集显示器的Eid信息 当我使用 logverbose 选项运行 X 时 我可以从 xorg 0 log 文件中获取它 但问题是 如果我切换显示器 拔出当前显示器 然后插入另一个显
  • 无法安装 WWW::Curl::Easy: SZBALINT/WWW-Curl-4.17.tar.gz : make NO

    我正在尝试在我的 Fedora 26 机器上安装 WWW Curl Easy gcc c I usr include D REENTRANT D GNU SOURCE O2 g pipe Wall Werror format securit
  • 为什么在 Linux 上字符串文字的内存地址与其他字符串文字的内存地址如此不同?

    我注意到字符串文字在内存中的地址与其他常量和变量 Linux 操作系统 非常不同 它们有许多前导零 未打印 Example const char h Hi int i 1 printf p n void h printf p n void
  • ffmpeg AVFrame 到 opencv Mat 转换

    我目前正在开发一个使用 ffmpeg 解码接收到的帧的项目 解码后 我想将 AVFrame 转换为 opencv Mat 帧 以便我可以在 imShow 函数上播放它 我拥有的是字节流 我将其读入缓冲区 解码为 AVFrame f fope
  • 从图像坐标获取对象的世界坐标

    I have been following this http docs opencv org modules calib3d doc camera calibration and 3d reconstruction html docume
  • 如何以编程方式从Linux中的进程名称获取进程ID

    在我的项目中 我们使用 ACE 自适应通信环境 中间件来编写可在 Windows 和 Linux 上运行的独立于操作系统的代码 要求是从进程名称中获取进程 ID 由于 ACE 不支持这一点 因此我们必须使用特定于平台的宏来分离 Window
  • Linux shell 脚本:十六进制数字到二进制字符串

    我正在 shell 脚本中寻找一些简单的方法来将十六进制数字转换为 0 和 1 字符的序列 Example 5F gt 01011111 是否有任何命令或简单的方法来完成它 或者我应该为其编写一些开关 echo ibase 16 obase
  • linux x86 汇编语言 sys_read 调用的第一个参数应为 0 (stdin)

    我正在编写一个简单的汇编程序来从标准输入读取 如 scanf 这是我的代码 section bss num resb 5 section txt global start start mov eax 3 sys read mov ebx 0
  • 从多线程程序中调用 system()

    我们正在开发一个用 C 编写的多线程内存消耗应用程序 我们必须执行大量的 shellscript linux 命令 并获取返回码 读完之后article http www linuxprogrammingblog com threads a
  • Composer 安装要求

    我正在尝试将 Composer 安装到 Laravel 项目中 当我做的时候sudo composer install在项目目录中它显示了两个错误 Problem 1 Installation request for simplesoftw
  • Docker:处理 tar 文件时出错(退出状态 1):设置枢轴目录时出错:不是目录

    我是 Docker 新手 不知道是什么原因导致此错误或如何诊断它 任何有关此问题的具体帮助或有关首先检查何处以诊断此类问题的提示将不胜感激 我的 Dockerfile FROM java 8 Install maven RUN apt ge
  • 使用 OpenCV 和/或 Numpy 对两个图像进行 Alpha 混合 [重复]

    这个问题在这里已经有答案了 我想将一个填充纯色的半透明矩形添加到已加载的半透明 PNG 中 这是我正在使用的输入图像示例 该图像加载了标准cv2 IMREAD UNCHANGED标志 以便完美保留 alpha 通道 该输入图像存储在imag
  • 没有可用的符号表信息

    我正在测试第三方的库 它崩溃了 当我想查看崩溃的原因时 我的 gdb 告诉我没有可用的调试符号 Program received signal SIGSEGV Segmentation fault Switching to Thread 0
  • 在 /dev/input/eventX 中写入事件需要哪些命令?

    我正在开发一个android需要将触摸事件发送到 dev input eventX 的应用程序 我知道C执行此类操作的代码结构如下 struct input event struct timeval time unsigned short
  • arm-linux-gnueabi 编译器选项

    我在用 ARM Linux gnueabi gcc在 Linux 中为 ARM 处理器编译 C 程序 但是 我不确定它编译的默认 ARM 模式是什么 例如 对于 C 代码 test c unsigned int main return 0x
  • diff 文件仅比较每行的前 n 个字符

    我有2个文件 我们将它们称为 md5s1 txt 和 md5s2 txt 两者都包含a的输出 find type f print0 xargs 0 md5sum sort gt md5s txt 不同目录下的命令 许多文件被重命名 但内容保
  • QFileDialog::getSaveFileName 和默认的 selectedFilter

    我有 getSaveFileName 和一些过滤器 我希望当用户打开 保存 对话框时选择其中之一 Qt 文档说明如下 可以通过将 selectedFilter 设置为所需的值来选择默认过滤器 我尝试以下变体 QString selFilte

随机推荐

  • 【计算机视觉

    文章目录 一 CSPResNeXt 二 ProxylessNet Mobile 三 ProxylessNet CPU 四 RandWire 五 MCKERNEL 六 Assemble ResNet 七 Convolution enhance
  • 短信信息服务器保存时效,长时间保存信息

    长时间保存信息 内容精选 换一换 华为云帮助中心 为用户提供产品简介 价格说明 购买指南 用户指南 API参考 最佳实践 常见问题 视频帮助等技术文档 帮助您快速上手使用华为云服务 向YARN服务器提交MapReduce任务后 客户端提示如
  • CentOS8结束生命周期后如何切换镜像源

    CentOS8结束生命周期后如何切换镜像源 官方提供了一个替代源 但不再进行任何更新 仅提供软件包 CentOS8系统在国内推荐使用阿里云的镜像源 具体切换过程如下 备份现有的repo配置文件 rename repo repo bak et
  • 【Python三大结构练习3】

    1 温度转换 题目描述 输入摄氏温度 华氏温度 输出对应的华氏温度 摄氏温度 这里采用82F表示华氏82度 采用28C表示摄氏28度 实数部分是温度值 转换算法 C F 32 1 8 F C 1 8 32 其中 C表示摄氏温度 F表示华氏温
  • [其他]IDEA中Maven项目配置国内源

    配置国内源主要解决了 在maven项目中pom xml下载jar包失败或过慢的问题 在IDEA中的设置分成两种 设置当前项目与新创项目 我们就需要两种都进行设置 不然只有在当前项目配置了国内源 新创项目的时候还是默认的状态 由于下面两种设置
  • msvcr120.dll丢失的解决方法-一键解决提示msvcr120.dll丢失问题

    msvcr120 dll是的动态链接库文件之一 它在Windows操作系统中发挥着重要的作用 它提供了应用程序所需的各种功能和方法 该文件返回编译后的代码所需的支持库 msvcr120 dll包含用于C C 编译器生成的应用程序所需的重要功
  • 区块链的结构和原理

    区块链的结构和原理 文章目录 区块链的结构和原理 区块链原理 区块链结构 关于区块链的几个问题 结语 区块链原理 区块链是一个链表 链表上存有交易信息 所有人共享同一个链表 因此它也是一个没有管理员的分布式数据库 即去中心化数据库 所有人都
  • 《Java并发编程的艺术》知识点

    目录 一 并发编程挑战 1 上下文切换 2 死锁 二 并发机制底层实现原理 1 volatile原理 2 synchronized原理 3 原子类实现原理 CAS存在的三大问题 三 内存模型 1 指令重排 四 并发编程基础 1 概念 2 优
  • myisamchk是用来做什么的?

    myisamchk是MySQL数据库管理系统中的一个工具 而不是Java编程语言的一部分 myisamchk是用于维护和修复MySQL数据库中MyISAM存储引擎表的工具 MyISAM是MySQL数据库中一种常用的存储引擎 它适用于读取频率
  • 冒泡排序代码python

    冒泡排序的python代码如下 def bubbleSort arr n len arr Traverse through all array elements for i in range n Last i elements are al
  • 微信小程序官方组件展示之画布canvas源码

    以下将展示微信小程序之画布canvas源码官方组件能力 组件样式仅供参考 开发者可根据自身需求定义组件样式 具体属性参数详见小程序开发文档 功能描述 画布 2 9 0 起支持一套新 Canvas 2D 接口 需指定 type 属性 同时支持
  • 数字IC设计——跨时钟域篇3(单比特处理)

    数字IC设计 跨时钟域篇3 单比特处理 下面介绍常见的单比特跨时钟域的处理方法 一 慢时钟域信号同步到快时钟域的处理方法 两级寄存器同步 慢时钟信号进入到更快的时钟域时 频率相差2倍以上 此时不用考虑快时钟域信号采样丢失问题 可以考虑使用两
  • java 线性表---------双向链表(源代码)

    1 public class DuLinkList
  • 【python数据挖掘课程】十二.Pandas、Matplotlib结合SQL语句对比图分析

    这篇文章主要讲述Python常用数据分析包Numpy Pandas Matplotlib结合MySQL分析数据 前一篇文章 python数据挖掘课程 十一 Pandas Matplotlib结合SQL语句可视化分析 讲述了MySQL绘图分析
  • msys2 修改国内源加速pacman

    1 msys2 修改国内源加速pacman 清华大学 etc pacman d mirrorlist mingw32 Server https mirrors tuna tsinghua edu cn msys2 mingw i686 1
  • netty源码分析之LengthFieldBasedFrameDecoder

    http www jianshu com p a0a51fd79f62 hmsr toutiao io utm medium toutiao io utm source toutiao io 拆包的原理 关于拆包原理的上一篇博文 netty
  • 五一节假期结束给团队开会,快速进入工作状态

    大家好 五一的假期大家过的都还开心吧 五一长假已经结束了 更开心的事情马上又要来了 再坚持10天 又要发工资了 再坚持上3天班又可以缓冲一下休息一天了 打工人 上班快乐 伴随着这些开心在这里我请大家尽快从自由松散的假期状态中走出来 重整旗鼓
  • Mac VS Code 如何去除右边的预览功能

    取消选中Minimap即可
  • Scala中的高阶函数

    1 定义 当一个函数 func1 中的 参数列表 传入的是函数 那么函数func1 就是高阶函数 上边几个函数可以 提炼出为一个高阶函数 因为 他们只是 黄线标志的部分不同 我们可以 定义一个 函数作为作为参数传递进去 来提取为 一般规律
  • opencv+nvcodec实现视频硬解码

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 系统配置 前言 一 NVCODEC是什么 二 OpenCV编译 1 安装Driver CUDA 2 编译OpenCV 总结 系统配置 操作系统 Ubuntu18 0