ffmpeg4.2.3--libavutil硬件編碼接口hwcontext

硬件編解碼

如何利用日益強大的硬件來實現高效的編解碼有則非比尋常的意義,對於開發者來講,面對日益增長的不一樣硬件,帶來的不一樣的接口,如何快速的使用和對接,自己就是一個問題,還好ffmpeg爲了咱們提供很是好的解決方案,徹底不用去關心底層的實現,一切面向接口的良好體現。linux

hwcontext模塊

支持的平臺

static const char *const hw_type_names[] = {
    [AV_HWDEVICE_TYPE_CUDA]   = "cuda",   //CUDA是Nvidia出的一個GPU計算庫
    [AV_HWDEVICE_TYPE_DRM]    = "drm",  //DRM 是linux 下的圖形渲染架構(Direct Render Manager)
    [AV_HWDEVICE_TYPE_DXVA2]  = "dxva2",//微軟dx套件,使用D3D9
    [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va",//微軟dx套件,使用D3D11
    [AV_HWDEVICE_TYPE_OPENCL] = "opencl",//第一個面向異構系統(此係統中可由CPU,GPU或其它類型的處理器架構組成)的並行編程的開放式標準。面向GPU編程
    [AV_HWDEVICE_TYPE_QSV]    = "qsv",//英特爾Quick Sync Video,號稱地球最強
    [AV_HWDEVICE_TYPE_VAAPI]  = "vaapi",  //Video Acceleration Api,UNINX下的編碼接口,intel提供
    [AV_HWDEVICE_TYPE_VDPAU]  = "vdpau",  //Video Decode and Presentation API for Unix ,NVIDIA提供的
    [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox", // mac iOS
    [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",  // Android
};

查看狀態或者指定使用某種解碼器

ffmpeg -hwaccels編程

hwcontext 核心接口

建立初始化av_hwdevice_ctx_create

  1. av_hwdevice_ctx_alloc
  2. device_ctx->internal->hw_type->device_create 綁定到具體硬件的指針函數上
  3. av_hwdevice_ctx_init

建立初始化AVHWFramesContext

描述硬件frame的一個pool,包括大小,格式,AVHWDeviceContext,長/寬等內容api

  1. av_hwframe_ctx_alloc
  2. av_hwframe_ctx_init
  3. hwframe_ctx_free

AVFrame操做

  1. av_hwframe_transfer_data //gpu frame和memory freme之間的拷貝
  2. av_hwframe_get_buffer //分配AVFrame空間

硬件解碼流程

截屏2020-06-05下午10.25.15.png

av_register_all && av_format_init_next && 初始化outdev_list/indev_list (已經被廢棄了)
avdevice_register_all && avpriv_register_device && av_format_init_next && 初始化outdev_list/indev_list;
void av_register_all(void)
{
    ff_thread_once(&av_format_next_init, av_format_init_next);
    //保證多線程下只執行一次,屏蔽不一樣平臺的多線程代碼差別,不一樣的平臺下映射到不一樣線程庫中的pthread_once函數
}

#define PTHREAD_ONCE_INIT {0, _FMUTEX_INITIALIZER}
#define AV_ONCE_INIT PTHREAD_ONCE_INIT
static AVOnce av_format_next_init = AV_ONCE_INIT;
//實際上av_format_next_init就是{0}

static void av_format_init_next(void)
{
    //輸入輸出結構封裝成鏈表,加鎖處理
    AVOutputFormat *prevout = NULL, *out; 
    AVInputFormat *previn = NULL, *in;

    ff_mutex_lock(&avpriv_register_devices_mutex);

    for (int i = 0; (out = (AVOutputFormat*)muxer_list[i]); i++) {
        if (prevout)
            prevout->next = out;
        prevout = out;
    }

    if (outdev_list) {
        for (int i = 0; (out = (AVOutputFormat*)outdev_list[i]); i++) {
            if (prevout)
                prevout->next = out;
            prevout = out;
        }
    }

    for (int i = 0; (in = (AVInputFormat*)demuxer_list[i]); i++) {
        if (previn)
            previn->next = in;
        previn = in;
    }

    if (indev_list) {
        for (int i = 0; (in = (AVInputFormat*)indev_list[i]); i++) {
            if (previn)
                previn->next = in;
            previn = in;
        }
    }

    ff_mutex_unlock(&avpriv_register_devices_mutex);
}

//h264的AVOutputFormat結構
AVOutputFormat ff_h264_muxer = {
    .name              = "h264",
    .long_name         = NULL_IF_CONFIG_SMALL("raw H.264 video"),
    .extensions        = "h264,264",
    .audio_codec       = AV_CODEC_ID_NONE,
    .video_codec       = AV_CODEC_ID_H264,
    .write_header      = force_one_stream,
    .write_packet      = ff_raw_write_packet,
    .check_bitstream   = h264_check_bitstream,
    .flags             = AVFMT_NOTIMESTAMPS,
};
如何關聯硬件解碼器

經過hw_device_setup_for_encode/hw_device_setup_for_decode進行設置,和4.x以前差別較大。多線程

查找hw_devices裏面的解碼器。架構

相關文章
相關標籤/搜索