ffmpeg使用NVIDIA GPU硬件编解码

这篇具有很好参考价值的文章主要介绍了ffmpeg使用NVIDIA GPU硬件编解码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在Ubuntu14.04版本上编译安装ffmpeg3.4.8,开启NVIDIA硬件加速功能。

1、安装依赖库

sudo apt-get install libtool automake autoconf nasm yasm  //nasm yasm注意版本
sudo apt-get install libx264-dev
sudo apt-get install libx265-dev
sudo apt-get install libmp3lame-dev
sudo apt-get install libvpx-dev
sudo apt-get install libfaac-dev

2、安装ffnvcodec

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

3、安装NVIDIA驱动

直接使用apt安装方便,在官方网站下载驱动未安装成功

1.卸载系统里的Nvidia低版本显卡驱动

sudo apt-get purge nvidia*

2.把显卡驱动加入PPA

sudo add-apt-repository ppa:graphics-drivers
sudo apt-get update

3.查找显卡驱动最新的版本号

查找并安装最新驱动

sudo apt-cache search nvidia
sudo apt-get install nvidia-430

4、安装CUDA

CUDA是Nvidia出的一个GPU计算库,让程序员可以驱动Nvidia显卡的GPU进行各种工作,其中就包含了视频的编解码。

1.下载https://developer.download.nvidia.cn/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_8.0.44-1_amd64.deb

sudo dpkg -i cuda-repo-ubuntu1604_8.0.44-1_amd64.deb
sudo apt-get update
sudo apt-get install cuda
2.检查驱动和CUDA安装是否成功
nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.64       Driver Version: 430.64       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 106...  Off  | 00000000:01:00.0  On |                  N/A |
| 42%   25C    P8     6W / 120W |     62MiB /  6077MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1311      G   /usr/lib/xorg/Xorg                            59MiB |
+-----------------------------------------------------------------------------+

5、编译ffmpeg

./configure --enable-gpl --enable-version3 --enable-nonfree --enable-shared --enable-ffmpeg --enable-ffplay --enable-ffprobe --enable-ffserver --enable-libx264 --enable-nvenc --enable-cuda --enable-cuvid --enable-libnpp --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64
make
sudo make install 

检查:

ffmpeg -codecs | grep nv
 DEV.LS h264                 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_cuvid ) (encoders: libx264 libx264rgb h264_nvenc nvenc nvenc_h264 )
 DEV.L. hevc                 H.265 / HEVC (High Efficiency Video Coding) (decoders: hevc hevc_cuvid ) (encoders: nvenc_hevc hevc_nvenc )
测试:
ffmpeg -i aidedaijia.mkv -c:v h264_nvenc -c:a aac output.mp4
ffmpeg -hwaccel cuvid -i output.mp4 output.yuv

6、修改部分

1.突破NVIDIA显卡NVENC并发Session数目限制

具体查看Video Encode and Decode GPU Support Matrix | NVIDIA Developer

我使用的是gtx1060显卡,最大只能并发2路编码,最后看到老雷blog突破NVIDIA NVENC并发Session数目限制,发现是驱动里面进行了限制。但老雷是windows下进行了修改,Linux下修改方法在githu中有(找了很久),而且可以针对很多驱动程序版本都做了匹配(牛!)。地址在:GitHub - keylase/nvidia-patch: This patch removes restriction on maximum number of simultaneous NVENC video encoding sessions imposed by Nvidia to consumer-grade GPUs.

git clone https://github.com/keylase/nvidia-patch.git
sudo bash ./patch.sh    (修改驱动)
sudo bash ./patch.sh -r (恢复原驱动)

2.关于nvenc编码输出帧的问题

使用nvenc和h264_nvenc编码的时候,每帧的前面都添加了一个SEI帧,在使用RTP传输的时候,对方接收到的编码出错,于是直接在ffmpeg源码进行了修改。

在ffmpeg-3.4.8/libavcodec/nvenc.c文件中修改:

if (IS_CBR(cc->rcParams.rateControlMode)) {
    h264->outputBufferingPeriodSEI = 1;//不知道干啥用的,修改了没有发现编码有变化
}
​
h264->outputPictureTimingSEI = 1;//重要是修改这里,将1修改为0,每个帧前就不再输出SEI帧了。

7、测试编码程序

#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <stdio.h>
​
/*
* Video encoding example
*/
​
​
#define H264_START_CODE 0x000001
uint32_t h264_find_next_start_code (uint8_t *pBuf,
                    uint32_t bufLen)
{
  uint32_t val;
  uint32_t offset;
 
  offset = 0;
  if (pBuf[0] == 0 && pBuf[1] == 0 && pBuf[2] == 0 && pBuf[3] == 1) {
    pBuf += 4;
    offset = 4;
  } else if (pBuf[0] == 0 && pBuf[1] == 0 && pBuf[2] == 1) {
    pBuf += 3;
    offset = 3;
  }
  val = 0xffffffff;
  while (offset < bufLen - 3) {
    val <<= 8;
    val |= *pBuf++;
    offset++;
    if (val == H264_START_CODE) {
      return offset - 4;
    }
    if ((val & 0x00ffffff) == H264_START_CODE) {
      return offset - 3;
    }
  }
  return 0;
}
​
static void video_encode_example(const char *filename)
{
    AVCodec *codec;
    AVCodecContext *c = NULL;
    int i, ret, x, y, got_output,k;
    AVFrame *frame;
    AVPacket pkt;
    uint8_t endcode[] = { 0, 0, 1, 0xb7 };
​
//    av_log_set_level(64);
​
​
    printf("Encode video file %s\n", filename);
​
    /* find the video encoder */
//    codec = avcodec_find_encoder_by_name("libx264");
    codec = avcodec_find_encoder_by_name("nvenc");//nvenc nvenc_h264 h264_nvenc
    //codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }
​
    c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate video codec context\n");
        exit(1);
    }
​
    c->bit_rate = 4000*1024;
    c->width = 1920;
    c->height = 1080;
    c->time_base.num = 1;
    c->time_base.den = 60;
    c->gop_size = 10;
    c->pix_fmt = AV_PIX_FMT_YUV420P;//AV_PIX_FMT_CUDA;
    c->max_b_frames = 0;
    c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
​
    AVDictionary *param = 0;
    //H.264
    if (codec->id == AV_CODEC_ID_H264) {
//        av_dict_set(&param, "preset", "medium", 0);
//        av_dict_set(&param, "tune", "zerolatency", 0);
//  av_dict_set(&param, "rc", "cbr", 0);
    }
    //H.265
    if (codec->id == AV_CODEC_ID_H265 || codec->id == AV_CODEC_ID_HEVC){
        //av_dict_set(&param, "x265-params", "qp=20", 0);
        av_dict_set(&param, "x265-params", "crf=25", 0);
        av_dict_set(&param, "preset", "fast", 0);
        av_dict_set(&param, "tune", "zero-latency", 0);
    }
​
    /* open it */
    if (avcodec_open2(c, codec, &param) < 0) {
        fprintf(stderr, "Could not open codec\n");
        system("pause");
        exit(1);
    }
​
    FILE *f;
    f = fopen(filename, "wb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        exit(1);
    }
​
    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate video frame\n");
        exit(1);
    }
    frame->format = c->pix_fmt;
    frame->width = c->width;
    frame->height = c->height;
​
    /* the image can be allocated by any means and av_image_alloc() is
    * just the most convenient way if av_malloc() is to be used */
    ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,
        c->pix_fmt, 32);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate raw picture buffer\n");
        exit(1);
    }
​
    /* encode (i=500/25) second of video */
    for (i = 0; i < 60*10; i++) {
        av_init_packet(&pkt);
        pkt.data = NULL;    // packet data will be allocated by the encoder
        pkt.size = 0;
​
        fflush(stdout);
        /* prepare a dummy image */
        /* Y */
        for (y = 0; y < c->height; y++) {
            for (x = 0; x < c->width; x++) {
                frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
            }
        }
​
        /* Cb and Cr */
        for (y = 0; y < c->height / 2; y++) {
            for (x = 0; x < c->width / 2; x++) {
                frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
                frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
            }
        }
​
        frame->pts = i;
​
        // encode the image 
        ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
        if (ret < 0) {
            fprintf(stderr, "Error encoding frame\n");
            exit(1);
        }
        if(pkt.flags & AV_PKT_FLAG_KEY){
        printf("@-\n");//输出的是关键帧
       for (k=0;k< c->extradata_size;k++){
        printf("%02x ",c->extradata[k]);
       }
       printf("\n");
int offset=0;
offset=h264_find_next_start_code(c->extradata,c->extradata_size);
printf("offset=%d\n",offset);
int spslen= offset;
int ppslen= c->extradata_size -offset;
​
           for (k=0;k<spslen;k++){
                printf("%02x ",c->extradata[k]);
           }
           printf("\n");
       for (k=0;k<ppslen;k++){       
                printf("%02x ",c->extradata[k+spslen]);
           }
           printf("\n");
​
    }
printf("[%d] ",i);
        if (got_output) {
        for (k=0;k<46;k++){
        printf("%02x ",pkt.data[k]);
        }
        printf(" size=%d\n",pkt.size);
            //printf("\n1:Write frame %3d (size=%5d)\n", i, pkt.size);
//            fwrite(pkt.data, 1, pkt.size, f);
            av_packet_unref(&pkt);
        }
​
    }
​
    /* get the delayed frames */
    for (got_output = 1; got_output; i++) {
        fflush(stdout);
​
        ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
        if (ret < 0) {
            fprintf(stderr, "Error encoding frame\n");
            exit(1);
        }
​
        if (got_output) {
            printf("2:Write frame %3d (size=%5d)\n", i, pkt.size);
            fwrite(pkt.data, 1, pkt.size, f);
            av_packet_unref(&pkt);
        }
    }
​
    /* add sequence end code to have a real MPEG file */
    fwrite(endcode, 1, sizeof(endcode), f);
    fclose(f);
​
    avcodec_close(c);
    av_free(c);
    av_freep(&frame->data[0]);
    av_frame_free(&frame);
}
​
int main(int argc, char **argv)
{
    /* register all the codecs */
    avcodec_register_all();
    video_encode_example("test.h264");
    return 0;
}

编译

gcc ./encode.c -o encode -lavcodec -lavutil

原文链接:ffmpeg使用NVIDIA GPU硬件编解码

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

 文章来源地址https://www.toymoban.com/news/detail-537944.html

到了这里,关于ffmpeg使用NVIDIA GPU硬件编解码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FFmpeg 在Windows环境下 Intel ,Nvidia ,AMD 硬件加速编解码支持列表

    目录 前言 一. Intel 编解码硬件支持列表   1. Encode 编码硬件支持列表 (1)Intel 独显编码硬件支持列表 (2)第 11,12,13 代 Intel 处理器编码硬件支持列表 (3)第 10 代 Intel 处理器编码硬件支持列表 (4)第 9 代 Intel 处理器编码硬件支持列表 (5)第 5,6,7,8 代 Intel 处理器

    2024年02月03日
    浏览(37)
  • 使用 GeForce Experience 更新 NVIDIA GPU 显卡驱动

    如果有可用的新版驱动的话,点击后方的 [下载] 按钮即可。 [快速安装] 按照默认设置安装驱动,[自定义安装] 可以自行进行安装设置。 出现一个错误 https://www.nvidia.cn/geforce/geforce-experience/ GeForce_Experience_v3.27.0.112.exe 使用 GeForce Experience 更新 NVIDIA GPU 显卡驱动失败时,需要卸载

    2024年02月05日
    浏览(39)
  • 20230403在WIN10下通过ffmpeg调用NVIDIA的硬件加速wmv视频转码为MP4格式

    20230403在WIN10下通过ffmpeg调用NVIDIA的硬件加速wmv视频转码为MP4格式 2023/4/3 15:50 最近向学习日语,找到日语发音的视频中,大多数是MP4格式,少量是WMV格式,PR2023貌似不能识别WMV格式。 于是:万能的ffmpeg上场了!   手动指定编解码器 通过 ffmpeg -codecs | findstr \\\"vc1\\\" 查看 vc1 的编解

    2023年04月22日
    浏览(35)
  • rk3588 ffmpeg使用硬件解码

    在https://johnvansickle.com/ffmpeg/下载最新的版本然后解压 将ffmpeg移动到/usr/local/bin文件夹 命令行输入ffmpeg没有报错就安装好了 git下载mpp包 编译安装 解压 –prefix 指定安装目录 –host 当前编译工具链的前缀 ll /usr/bin/gcc*查看 编译指令 –enable-gpl 允许使用GPL代码,生成的库和二进制

    2024年02月04日
    浏览(31)
  • opencv、ffmpeg使用nvidia-video-codec-sdk编解码

    opencv很早就支持cuda加速,但是一般用于图像处理模块。 在视频读(包含实时视频流)写上,opencv可以使用ffmpeg作为后端进行编解码,通常是cpu软编解。 如果ffmpeg的编译支持gpu硬编解,那么opencv的接口就直接支持硬件编解码了。 如果不想安装一堆依赖软件,可以直接下载 s

    2024年02月12日
    浏览(34)
  • ffmpeg cuda硬件解码后处理使用opengl渲染,全硬件流程

    使用硬件解码后不要transfer到内存,使用cuda转化nv12 - bgr24 转化完毕后cuda里面存了一份bgr24 如果需要opencv gpumat直接使用cuda内存,则可以手动构造gpumat 可以使用gpumat的各种函数 ptr(0)、ptr(1)和ptr(2)分别获取了R、G、B三个通道的数据指针。 使用reinterpret_cast将uchar 指针转换为ucha

    2024年04月12日
    浏览(36)
  • 使用NVIDIA GPU FFmpeg转码 YUV to H264(成功)

    NVIDIA官方教程:链接,本篇内容主要参考2.2 Software Setup。 确保nvidia-smi能够正常使用: 注意要与显卡驱动版本对应,验证toolkit是否正确安装: 下载地址 编译方法:解压进入文件夹后 验证安装          显示版本号证明安装成功: 下载地址 配置方法: 进入ffmpeg-x.x文件夹

    2024年02月06日
    浏览(35)
  • 使用GPU硬件加速FFmpeg视频转码

    本文内容包括: 在Linux环境下安装FFmpeg 通过命令行实现视频格式识别和转码 有Nvidia显卡的情况下,在Linux下使用GPU进行视频转码加速的方法 在FFmpeg官网https://ffmpeg.org/download.html可以下载到ubunto/debian的发行包,其他Linux发行版需自行编译。同时,如果要使用GPU进行硬件加速的话

    2024年02月08日
    浏览(38)
  • 最新NVIDIA英伟达GPU显卡算力表

    随着深度学习的火热, 显卡也变得越来越重要. 而我们在安装各种各样的适配显卡的软件工具时, 都会提到一个显卡算力的概念. 这里的显卡算力指的并不是显卡的计算能力, 而是指的显卡的架构版本. NVIDIA Data Center Products GPU Compute Capability NVIDIA A100 8.0 NVIDIA A40 8.6 NVIDIA A30 8.0 NV

    2024年02月05日
    浏览(37)
  • ffmpeg最简单方式支持nvidia硬编解码

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 因为工作内容的需要,之前写过一篇文章关于ffmpeg支持英伟达的硬编解码,那个方法比较适合定制化的ffmpeg编译,如果你仅仅使用ffmpeg进行硬件编解码的话,其实不需要这么麻烦。 ffmpeg定制化编译支持

    2024年02月15日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包