FFMPEG–CUDA硬解码

  • Post author:
  • Post category:其他




FFMPEG 动态库编译(GPU)

  1. 下载FFMPEG源码

    https://ffmpeg.org/

    ,这里选择的是ffmpeg-4.3.1.tar.bz2
  2. 下载nvenc的头文件

    git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
    cd nv-codec-headers
    make
    sudo make install
    export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig"
    


    注意选择对应cuda的版本

  3. 编译

    ./configure --prefix=/yourpath/install --disable-x86asm --enable-shared --disable-static \
    --enable-cuda --enable-cuvid --enable-nvenc --enable-nonfree \
    --enable-libnpp --extra-cflags=-I/usr/local/cuda/include \
    --extra-ldflags=-L/usr/local/cuda/lib64
    
  4. 验证,终端输入ffmpeg

    ffmpeg version 4.3.1 Copyright (c) 2000-2020 the FFmpeg developers
      built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
      configuration: --enable-shared --enable-cuda --enable-cuvid --enable-nvenc --enable-nonfree --enable-libnpp --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64
      libavutil      56. 51.100 / 56. 51.100
      libavcodec     58. 91.100 / 58. 91.100
      libavformat    58. 45.100 / 58. 45.100
      libavdevice    58. 10.100 / 58. 10.100
      libavfilter     7. 85.100 /  7. 85.100
      libswscale      5.  7.100 /  5.  7.100
      libswresample   3.  7.100 /  3.  7.100
    Hyper fast Audio and Video encoder
    usage: ffmpeg [options] [[infile options] -i infile]... {
         [outfile options] outfile}...
    
    Use -h to get full help or, even better, run 'man ffmpeg'
    
     ffmpeg -hwaccels
    

    打开 ld.so.conf添加 /usr/local/lib(ffmpeg安装库目录)

    sudo gedit /etc/ld.so.conf
    -------------------------------------------
    include /etc/ld.so.conf.d/*.conf
    添加ffmpeg的路径
    /usr/local/lib
    -------------------------------------------
    sudo ldconfig
    



硬解流图

在这里插入图片描述


同时支持软解和硬解,软解将HWDeviceName设置为gpu即可,即: std::string HWDeviceName = “cpu”;



文件目录

├── 3rdparty
│   ├── FreeSerif
│   ├── ffmpeg
│   │   ├── include
│   │   │   ├── libavcodec
│   │   │   ├── libavdevice
│   │   │   ├── libavfilter
│   │   │   ├── libavformat
│   │   │   ├── libavutil
│   │   │   ├── libswresample
│   │   │   └── libswscale
│   │   └── lib
│   ├── opencv
│   └── spd
│       └── spdlog
│           ├── cfg
│           ├── details
│           ├── fmt
│           │   └── bundled
│           └── sinks
├── CMakeLists.txt
├── README.md
├── build
├── docs
│   ├── imgs
│   │   └── spdlog.png
│   └── spdlog.md
├── incs
│   ├── CGDesktopCatch.hpp
│   ├── CGFFNvDecode.hpp
│   ├── CGUsbCamera.hpp
│   ├── common.hpp
│   └── mylog.hpp
├── srcs
│   ├── CGDesktopCatch.cpp
│   ├── CGFFNvDecode.cpp
│   └── CGUsbCamera.cpp
└── test
    ├── CGDesktopCatchDemo.cpp
    ├── CMakeLists.txt
    ├── FFNvDecode.cpp
    ├── UsbCameraDemo.cpp
    ├── demo.cpp
    └── spddemo.cpp



CGFFNvDecode.hpp

#pragma once
#include "common.hpp"

#include <iostream>
#include <memory>
#include <string>
#include <thread>

class CGFFNvDecode
{
   
  public:
    AVFormatContext *m_inputAVFormatCxt = nullptr;
    AVFormatContext *m_outputAVFormatCxt = nullptr;
    AVCodecContext *decoderCtx   = nullptr;
    AVStream *videoStream         = nullptr;
    AVCodec *decoder              = nullptr;

    int m_VideoStreamIdx;
    std::thread m_hThread;

  public:
    CGFFNvDecode(int chan);
    ~CGFFNvDecode();
    
    void SetInputUrl(std::string rtspUrl);
    void SetOutputPath(std::string ofilename);
    void StartDecode();
    void StopDecode();
    void closeOutputStream();

  private:
    int decChan;
    int64_t pts_v[2] = {
   0};
    int64_t dts_v[2] = {
   0};
    int64_t packetCount = 0;
    int64_t frameCount = 0;

    bool m_bUseHWDecode{
   true};
    bool m_bStoped{
   true};
    bool m_bInputInited{
   false};
    bool m_bOutputInited{
   false};
    bool m_bAddFilter{
   true};

    std::string HWDeviceName = "cuda";
    std::string m_inputUrl;
    std::string m_outputFile;
    AVBufferRef *hw_device_ctx = nullptr;
    enum AVPixelFormat hwPixFmt;
    enum AVHWDeviceType hwDeviceType;
    std::shared_ptr<std::mutex> ctxLock = std::make_shared<std::mutex>();

  private:
    void Init();
    int GetHWDeviceByName(std::string deviceName);
    void run();
    void ReadingThrd(void *pParam);
    int OpenInput(std::string inputUrl);
    int openOutputStream();
    int GetHwPixFormat();
    int InitHWdecoder(AVCodecContext *ctx, const enum AVHWDeviceType type);
    int GetDecodeResult(AVFrame *frame);
    std::shared_ptr<AVPacket> ReadPacketFromSource();
    std::shared_ptr<AVFrame> ReadFrameFromDecoder(AVPacket *pkt);
    int WritePacket(std::shared_ptr<AVPacket> packet);
    void Decoding();
    void CloseInput();
    void AddFilterToFrame(AVFrame *pSrcFrame, AVFrame *pDestFrame, int x, int y, int w, int h);
};



CGFFNvDecode.cpp

#include "CGFFNvDecode.hpp"
#include "opencv2/opencv.hpp"

#include <exception>
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>

using namespace std;

static string AvErrToStr(int avErrCode)
{
   
    const auto bufSize = 1024U;
    char *errString    = (char *) calloc(bufSize, sizeof(*errString));
    if (!errString)
    {
   
        return string();
    }

    if (0 != av_strerror(avErrCode, errString, bufSize - 1))
    {
   
        free(errString);
        stringstream ss;
        ss << "Unknown error with code " << avErrCode;
        return ss.str();
    }

    string str(errString);
    free(errString);

    return str;
}

static enum AVPixelFormat GetHwFormat(AVCodecContext *ctx, const enum AVPixelFormat *pixFmts)
{
   
    const enum AVPixelFormat *p;
    for (p = pixFmts; *p != -1; p++)
    {
   
        if (*p == AV_PIX_FMT_CUDA)
        {
   
            return *p;
        }
    }

    LOG_ERROR("Failed to get HW surface format");
    return AV_PIX_FMT_NONE;
}

CGFFNvDecode::CGFFNvDecode(int chan)
{
   
    this->decChan = chan;
    this->Init();
}

CGFFNvDecode::~CGFFNvDecode() {
   }

int CGFFNvDecode::GetHWDeviceByName(std::string deviceName)
{
   
    hwDeviceType = av_hwdevice_find_type_by_name(deviceName.c_str());
    if (hwDeviceType == AV_HWDEVICE_TYPE_NONE



版权声明:本文为xxboy61原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。