ffmpeg4.2.3--libavutil硬件编码接口hwcontext

硬件编解码

如何利用日益强大的硬件来实现高效的编解码有则非比寻常的意义,对于开发者来说,面对日益增加的不同硬件,带来的不同的接口,如何快速的使用和对接,本身就是一个问题,还好ffmpeg为了我们提供非常好的解决方案,完全不用去关心底层的实现,一切面向接口的良好体现。

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,长/宽等内容

  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空间

硬件解码流程

ffmpeg4.2.3--libavutil硬件编码接口hwcontext_第1张图片

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里面的解码器。

你可能感兴趣的:(ffmpeg)