• 【并行计算与CUDA开发】基于NVIDIA显卡的硬编解码的一点心得 (完结)



    原文:基于NVIDIA显卡的硬编解码的一点心得 (完结)

    1.硬解码软编码方法:大体流程,先用ffmpeg来读取视频文件的包,接着开启两个线程,一个用于硬解码,一个用于软编码,然后将读取的包传给解码器,编码出的frame download到内存,然后做scale处理,将scale后的帧和编码参数一起传给编码函数,最终生成pkt包,将其写入文件。由于CUVID中CuvideoSource不支持rtsp视频流数据,不能由rtsp地址创建VideoSource,所以用ffmpeg来解析rtsp视频流。

    解码与编码之间维护一个队列,队列长度定为20(因为解码速度快于编码速度,数据被覆盖,丢帧)。

    2.软解码软编码方法:目前只是用ffmpeg自带的sample功能,没有经过设计,暂时应用sample进行测试。

    3.编解码结构
    硬解软编:   read(ffmpeg) ---> decoder(NVIDIA) ---> |  Queue(20)  | ---> encoder(ffmpeg)
    软解软编:   read(ffmpeg) ---> decoder(ffmpeg) ---> encoder(ffmpeg)

    硬解软编基本步骤:
    a.利用FFmpeg解析rtsp视频流
    b.创建VideoParser
    c.利用FFmpeg读取数据包(AVpacket)
    d.将数据包传输到VideoParser(AVpacket ---> CUVIDSOURCEDATAPACKET)
    e.VideoParser解码数据包

    伪代码如下图所示
    #include <nvcuvid.h>
    #include <cuviddec.h>

    //Called when the decoder encounters a video format change or initial sequence header
    int CUDAAPI HandleVideoSequence(void * UserData, CUVIDEOFORMAT* pFormat)
    {
        cuvidCreateDecoder();
    }
    //Called by the video parser to decode a single picture
    int CUDAAPI HandlePictureDecode(void *UserData, CUVIDPICPARAMS* pPicParams)
    {
        cuvidDecodePicture();
    }
    //Called by the video parser to display a video frame
    int CUDAAPI HandlePicutureDisplay(void *UserData, CUVIDPARSERDISPINFO *pPicParams)
    {
        cuvidMapVideoFrame();
        cuvidUnmapVideoFrame();
        download_frame(frame);
        queue.enqueue(frame);
    }
    // new thread read loop, read all frame
    void read_loop()
    {
        while(av_read_frame(ifmt_ctx,pkt) > 0)
        {
            CUVIDSOURCEDATAPACKET pkt;
            pkt.flags = 0;
            pkt.payload_size = pkt.size;
            pkt.payload = pkt.data;
            cuvidParseVideoData(cuParser, &pkt);
        }
    }
    //encode thread
    void encode_frame()
    {
        queue.dequeue(temp_frame);
        scale_frame(temp_frame);
        encode(temp_frame);
        write_to_file();
    }
    int main()
    {
        //set video parser paramters. create video parser
        //decode frame packet
        cuvidCreateVideoParser();
        //FFmpeg open rstp strea, read packet data
        ...
        thread(read_loop);
        thread(encode_frame);
        //destroy resources
        cuvidDestroyDecoder();
        cuvidDestroyVideoParser();
    }

    4.目前测试的多路是通过开启多个线程来进行的,下面是测试结果:
                   
     路数            硬解软编                          软解软编 
              Fps   CPU(%) MEM(%)    Fps  CPU(%) MEM(%)
      1      362      80.8         1.3         344   86.1             0.7
      5        81      92.5     1.3*5            72   92.5         0.7*5
     10    40.5     92.5   1.3*10            36   92.5       0.7*10
     20    20.6     92.5   1.3*20            18   92.5       0.7*20
    注释:上面CPU占用率92.5%,CPU空闲都是0,基本CPU在满负荷运行。
    需要说明的是,现在测试视频是电影的一个片段10000帧数据,可能运动比较多,如果变成直播可能运动较少,编码会更快。
    当硬解码软编码时,如果帧率25fps的时候支持16路,当软解码软编码时,如果帧率25fps的时候支持14路。

    5.测试环境以及参数
    CPU:  Intel(R) Core(TM) i5-3470 CPU @ 3.20GHz 
    MEM:  8G
    OS:   ubuntu 12.04
    Video:tears640x480p24_1000.y4m(10000frames,rate=1000)
    Param:Fps:25,gop:10,bframe:1,rate:40,level 3.1
  • 相关阅读:
    django-JWT的原理
    python-路由Routers-SimpleRouter-DefaultRouter的使用
    深入理解单例模式
    ArrayList
    队列----java实现
    栈--链表实现
    开发中CollectionUtils处理集合
    NullPointerException-----开发中遇到的空指针异常
    查询部门----返回给前台TreeView数据格式的数据
    git使用命令记录
  • 原文地址:https://www.cnblogs.com/huty/p/8517647.html
Copyright © 2020-2023  润新知