zoukankan      html  css  js  c++  java
  • 【并行计算与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
  • 相关阅读:
    大数加法、乘法实现的简单版本
    hdu 4027 Can you answer these queries?
    zoj 1610 Count the Colors
    2018 徐州赛区网赛 G. Trace
    1495 中国好区间 尺取法
    LA 3938 动态最大连续区间 线段树
    51nod 1275 连续子段的差异
    caioj 1172 poj 2823 单调队列过渡题
    数据结构和算法题
    一个通用分页类
  • 原文地址:https://www.cnblogs.com/huty/p/8517648.html
Copyright © 2011-2022 走看看