当前位置: 首页 > news >正文

FFmpeg源码分析:avcodec_find_decoder()查找解码器

FFmpeg提供两种方式查找解码器,通过codecId查找avcodec_find_decoder()与通过名字查找avcodec_find_decoder_by_name()。同样地,也提供两种方式查找编码器,通过codecId查找avcodec_find_encoder()与通过名字查找avcodec_find_encoder_by_name()。源码位于libavcodec/allcodecs.c中。

查找编解码器过程如下图所示:
在这里插入图片描述

一、查找解码器

1、avcodec_find_decoder
通codecId来查找解码器的方法如下:

AVCodec *avcodec_find_decoder(enum AVCodecID id)
{
    return find_codec(id, av_codec_is_decoder);
}

函数体只有一行代码,就是调用find_codec()来查找,第一个参数为codecId,第二个参数为属于解码器类型,具体方法如下:

static AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *))
{
    const AVCodec *p, *experimental = NULL;
    void *i = 0;
 
    id = remap_deprecated_codec_id(id);
 
    while ((p = av_codec_iterate(&i))) {
        if (!x(p))
            continue;
        if (p->id == id) {
            if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) {
                experimental = p;
            } else
                return (AVCodec*)p;
        }
    }
 
    return (AVCodec*)experimental;
}

可以看到,是通过while循环调用av_codec_iterate()来迭代遍历,获取AVCodec,然后用id判断是否相等。如果id相等,就返回对应的AVCodec。我们来看下av_codec_iterate()的实现:

static void av_codec_init_static(void)
{
    for (int i = 0; codec_list[i]; i++) {
        if (codec_list[i]->init_static_data)
            codec_list[i]->init_static_data((AVCodec*)codec_list[i]);
    }
}
 
const AVCodec *av_codec_iterate(void **opaque)
{
    uintptr_t i = (uintptr_t)*opaque;
    const AVCodec *c = codec_list[i];
 
    ff_thread_once(&av_codec_static_init, av_codec_init_static);
 
    if (c)
        *opaque = (void*)(i + 1);
 
    return c;
}

2、avcodec_find_decoder_by_name
通过名字查找解码器的方法如下:

AVCodec *avcodec_find_decoder_by_name(const char *name)
{
    return find_codec_by_name(name, av_codec_is_decoder);
}

主要调用find_codec_by_name(),第一个参数为解码器名字,第二个参数为属于解码器类型,具体方法如下:

static AVCodec *find_codec_by_name(const char *name, int (*x)(const AVCodec *))
{
    void *i = 0;
    const AVCodec *p;
 
    if (!name)
        return NULL;
 
    while ((p = av_codec_iterate(&i))) {
        if (!x(p))
            continue;
        if (strcmp(name, p->name) == 0)
            return (AVCodec*)p;
    }
 
    return NULL;
}

可以看到,是通过while循环调用av_codec_iterate()来迭代遍历,获取AVCodec,然后用名字进行比较。如果匹配成功,就返回对应的AVCodec。

二、查找编码器

1、avcodec_find_encoder
通过codecId查找编码器的方法如下:

AVCodec *avcodec_find_encoder(enum AVCodecID id)
{
    return find_codec(id, av_codec_is_encoder);
}

2、avcodec_find_encoder_by_name
通过名字查找编码器的方法如下:

AVCodec *avcodec_find_encoder_by_name(const char *name)
{
    return find_codec_by_name(name, av_codec_is_encoder);
}

三、编解码器列表与id

1、 编解码器列表
编解码器列表来自libavcodec/allcodecs.c,有声明全局变量(详情可查看:avcodec注册与介绍):

extern AVCodec ff_flv_encoder;
extern AVCodec ff_flv_decoder;
extern AVCodec ff_h264_decoder;
extern AVCodec ff_hevc_decoder;
extern AVCodec ff_mpeg4_encoder;
extern AVCodec ff_mpeg4_decoder;
extern AVCodec ff_msmpeg4v1_decoder;
extern AVCodec ff_msmpeg4v2_encoder;
extern AVCodec ff_msmpeg4v2_decoder;
extern AVCodec ff_msmpeg4v3_encoder;
extern AVCodec ff_msmpeg4v3_decoder;
extern AVCodec ff_vp8_decoder;
extern AVCodec ff_vp9_decoder;
extern AVCodec ff_wmv1_encoder;
extern AVCodec ff_wmv1_decoder;
extern AVCodec ff_wmv2_encoder;
extern AVCodec ff_wmv2_decoder;
extern AVCodec ff_wmv3_decoder;
 
/* audio codecs */
extern AVCodec ff_aac_encoder;
extern AVCodec ff_aac_decoder;
extern AVCodec ff_ac3_encoder;
extern AVCodec ff_ac3_decoder;
extern AVCodec ff_amrnb_decoder;
extern AVCodec ff_amrwb_decoder;
extern AVCodec ff_ape_decoder;
extern AVCodec ff_eac3_encoder;
extern AVCodec ff_eac3_decoder;
extern AVCodec ff_flac_encoder;
extern AVCodec ff_flac_decoder;
extern AVCodec ff_mp3_decoder;
extern AVCodec ff_opus_encoder;
extern AVCodec ff_opus_decoder;
extern AVCodec ff_truehd_encoder;
extern AVCodec ff_truehd_decoder;
extern AVCodec ff_vorbis_encoder;
extern AVCodec ff_vorbis_decoder;
extern AVCodec ff_wmav1_encoder;
extern AVCodec ff_wmav1_decoder;
extern AVCodec ff_wmav2_encoder;
extern AVCodec ff_wmav2_decoder;
 
/* PCM codecs */
extern AVCodec ff_pcm_alaw_encoder;
extern AVCodec ff_pcm_alaw_decoder;
extern AVCodec ff_pcm_mulaw_encoder;
extern AVCodec ff_pcm_mulaw_decoder;
extern AVCodec ff_pcm_s8_encoder;
extern AVCodec ff_pcm_s8_decoder;
extern AVCodec ff_pcm_s16le_encoder;
extern AVCodec ff_pcm_s16le_decoder;
extern AVCodec ff_pcm_s16le_planar_encoder;
extern AVCodec ff_pcm_s16le_planar_decoder;
extern AVCodec ff_pcm_s24le_encoder;
extern AVCodec ff_pcm_s24le_decoder;
extern AVCodec ff_pcm_s32le_encoder;
extern AVCodec ff_pcm_s32le_decoder;
extern AVCodec ff_pcm_s64le_encoder;
extern AVCodec ff_pcm_s64le_decoder;
extern AVCodec ff_pcm_u8_encoder;
extern AVCodec ff_pcm_u8_decoder;
 
/* ADPCM codecs */
extern AVCodec ff_adpcm_ima_wav_encoder;
extern AVCodec ff_adpcm_ima_wav_decoder;
extern AVCodec ff_adpcm_ms_encoder;
extern AVCodec ff_adpcm_ms_decoder;
 
/* subtitles */
extern AVCodec ff_ssa_encoder;
extern AVCodec ff_ssa_decoder;
extern AVCodec ff_ass_encoder;
extern AVCodec ff_ass_decoder;
extern AVCodec ff_movtext_encoder;
extern AVCodec ff_movtext_decoder;
extern AVCodec ff_pgssub_decoder;
extern AVCodec ff_sami_decoder;
extern AVCodec ff_srt_encoder;
extern AVCodec ff_srt_decoder;
extern AVCodec ff_subrip_encoder;
extern AVCodec ff_subrip_decoder;
extern AVCodec ff_ttml_encoder;
extern AVCodec ff_webvtt_encoder;
extern AVCodec ff_webvtt_decoder;
 
/* external libraries */
extern AVCodec ff_aac_at_encoder;
extern AVCodec ff_aac_at_decoder;
extern AVCodec ff_ac3_at_decoder;
extern AVCodec ff_amr_nb_at_decoder;
extern AVCodec ff_eac3_at_decoder;
extern AVCodec ff_mp3_at_decoder;
extern AVCodec ff_libaom_av1_encoder;
extern AVCodec ff_libdav1d_decoder;
extern AVCodec ff_libfdk_aac_encoder;
extern AVCodec ff_libfdk_aac_decoder;
extern AVCodec ff_libmp3lame_encoder;
extern AVCodec ff_libopencore_amrnb_decoder;
extern AVCodec ff_libopencore_amrwb_decoder;
extern AVCodec ff_libopus_encoder;
extern AVCodec ff_libopus_decoder;
extern AVCodec ff_libshine_encoder;
extern AVCodec ff_libspeex_encoder;
extern AVCodec ff_libspeex_decoder;
extern AVCodec ff_libvorbis_encoder;
extern AVCodec ff_libvorbis_decoder;
extern AVCodec ff_libvpx_vp8_encoder;
extern AVCodec ff_libvpx_vp8_decoder;
extern AVCodec ff_libvpx_vp9_encoder;
extern AVCodec ff_libvpx_vp9_decoder;
extern AVCodec ff_libwebp_encoder;
extern AVCodec ff_libx264_encoder;
extern AVCodec ff_libx265_encoder;
 
/* hwaccel hooks only, so prefer external decoders */
extern AVCodec ff_av1_decoder;
extern AVCodec ff_av1_cuvid_decoder;
extern AVCodec ff_av1_qsv_decoder;
extern AVCodec ff_libopenh264_encoder;
extern AVCodec ff_libopenh264_decoder;
extern AVCodec ff_h264_cuvid_decoder;
extern AVCodec ff_h264_nvenc_encoder;
extern AVCodec ff_h264_omx_encoder;
extern AVCodec ff_h264_qsv_encoder;
extern AVCodec ff_h264_v4l2m2m_encoder;
extern AVCodec ff_h264_vaapi_encoder;
extern AVCodec ff_h264_videotoolbox_encoder;
extern AVCodec ff_hevc_mediacodec_decoder;
extern AVCodec ff_hevc_nvenc_encoder;
extern AVCodec ff_hevc_qsv_encoder;
extern AVCodec ff_hevc_v4l2m2m_encoder;
extern AVCodec ff_hevc_vaapi_encoder;
extern AVCodec ff_hevc_videotoolbox_encoder;
extern AVCodec ff_mp3_mf_encoder;
extern AVCodec ff_mpeg4_cuvid_decoder;
extern AVCodec ff_mpeg4_mediacodec_decoder;
extern AVCodec ff_mpeg4_omx_encoder;
extern AVCodec ff_mpeg4_v4l2m2m_encoder;
extern AVCodec ff_vp9_cuvid_decoder;
extern AVCodec ff_vp9_mediacodec_decoder;
extern AVCodec ff_vp9_qsv_decoder;
extern AVCodec ff_vp9_vaapi_encoder;
extern AVCodec ff_vp9_qsv_encoder;

2、编解码器id
编解码器id是个枚举类型AVCodecId,定义位于libavcodec/codec_id.h(有删减):

enum AVCodecID {
    AV_CODEC_ID_NONE,
 
    /* video codecs */
    AV_CODEC_ID_MPEG1VIDEO,
    AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
    AV_CODEC_ID_MPEG4,
    AV_CODEC_ID_MSMPEG4V1,
    AV_CODEC_ID_MSMPEG4V2,
    AV_CODEC_ID_MSMPEG4V3,
    AV_CODEC_ID_WMV1,
    AV_CODEC_ID_WMV2,
    AV_CODEC_ID_FLV1,
    AV_CODEC_ID_H264,
    AV_CODEC_ID_PNG,
    AV_CODEC_ID_VC1,
    AV_CODEC_ID_WMV3,
    AV_CODEC_ID_AVS,
    AV_CODEC_ID_JPEG2000,
    AV_CODEC_ID_GIF,
    AV_CODEC_ID_VP8,
    AV_CODEC_ID_VP9,
    AV_CODEC_ID_HEVC,
#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC
    AV_CODEC_ID_VVC,
#define AV_CODEC_ID_H266 AV_CODEC_ID_VVC
    AV_CODEC_ID_AV1,
 
    /* various PCM "codecs" */
    AV_CODEC_ID_PCM_S16LE = 0x10000,
    AV_CODEC_ID_PCM_S16BE,
    AV_CODEC_ID_PCM_S8,
    AV_CODEC_ID_PCM_U8,
    AV_CODEC_ID_PCM_MULAW,
    AV_CODEC_ID_PCM_ALAW,
    AV_CODEC_ID_PCM_S32LE,
    AV_CODEC_ID_PCM_S24LE,
    AV_CODEC_ID_PCM_S24DAUD,
    AV_CODEC_ID_PCM_S16LE_PLANAR,
    AV_CODEC_ID_PCM_F32LE,
    AV_CODEC_ID_PCM_F64LE,
    AV_CODEC_ID_PCM_S8_PLANAR,
    AV_CODEC_ID_PCM_S24LE_PLANAR,
    AV_CODEC_ID_PCM_S32LE_PLANAR,
    AV_CODEC_ID_PCM_S64LE = 0x10800,
    AV_CODEC_ID_PCM_F16LE,
    AV_CODEC_ID_PCM_F24LE,
 
    /* various ADPCM codecs */
    AV_CODEC_ID_ADPCM_IMA_QT = 0x11000,
    AV_CODEC_ID_ADPCM_IMA_WAV,
    AV_CODEC_ID_ADPCM_MS,
 
    AV_CODEC_ID_ADPCM_AFC = 0x11800,
    AV_CODEC_ID_ADPCM_IMA_OKI,
 
    /* AMR */
    AV_CODEC_ID_AMR_NB = 0x12000,
    AV_CODEC_ID_AMR_WB,
 
    /* audio codecs */
    AV_CODEC_ID_MP2 = 0x15000,
    AV_CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3
    AV_CODEC_ID_AAC,
    AV_CODEC_ID_AC3,
    AV_CODEC_ID_VORBIS,
    AV_CODEC_ID_WMAV1,
    AV_CODEC_ID_WMAV2,
    AV_CODEC_ID_FLAC,
    AV_CODEC_ID_APE,
    AV_CODEC_ID_EAC3,
    AV_CODEC_ID_TRUEHD,
    AV_CODEC_ID_OPUS,
 
    /* subtitle codecs */
    AV_CODEC_ID_DVD_SUBTITLE = 0x17000,
    AV_CODEC_ID_DVB_SUBTITLE,
    AV_CODEC_ID_SSA,
    AV_CODEC_ID_MOV_TEXT,
    AV_CODEC_ID_SRT,
 
    AV_CODEC_ID_MICRODVD   = 0x17800,
    AV_CODEC_ID_SAMI,
    AV_CODEC_ID_SUBRIP,
    AV_CODEC_ID_WEBVTT,
    AV_CODEC_ID_ASS,
    AV_CODEC_ID_TTML,
 
    AV_CODEC_ID_TTF = 0x18000,
};

相关文章:

  • [c++] 什么是平凡类型,标准布局类型,POD类型,聚合体
  • RT-Thread启动流程
  • char * 与 二维字符数组
  • Python 教程之控制流(4)Python 中的循环技术
  • 【历年IJCAI论文下载(含IJCAI2022)】图神经网络(GNN)(多行为推荐、多模态食谱表示学习、同质图表示学习)
  • UNIAPP实战项目笔记3 Swiper部分开发
  • Spring启动源码分析以及生命周期
  • 斜率优化dp
  • 前端开发常用网站整理
  • 直流有刷电机电流采集基于STM32F302R8+X-NUCLEO-IHM07M1
  • 27_GitGitHub
  • 微信公众号在线查题功能系统使用
  • WPS JS宏示例-批量添加链接
  • Java核心——面向对象编程(上)包-继承-多态
  • Ambari自动部署Hadoop集群实战
  • 【React系列】如何构建React应用程序
  • 2017-08-04 前端日报
  • docker容器内的网络抓包
  • interface和setter,getter
  • Laravel Telescope:优雅的应用调试工具
  • Laravel 菜鸟晋级之路
  • Laravel 中的一个后期静态绑定
  • node 版本过低
  • PAT A1120
  • select2 取值 遍历 设置默认值
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • Twitter赢在开放,三年创造奇迹
  • 猴子数据域名防封接口降低小说被封的风险
  • 面试遇到的一些题
  • 爬虫模拟登陆 SegmentFault
  • 前端js -- this指向总结。
  • 如何设计一个微型分布式架构?
  • 如何选择开源的机器学习框架?
  • 用mpvue开发微信小程序
  • postgresql行列转换函数
  • 关于Android全面屏虚拟导航栏的适配总结
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • 移动端高清、多屏适配方案
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #define、const、typedef的差别
  • #传输# #传输数据判断#
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (9)目标检测_SSD的原理
  • (多级缓存)多级缓存
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (转)Oracle存储过程编写经验和优化措施
  • (转)母版页和相对路径
  • (转载)Linux 多线程条件变量同步
  • ***php进行支付宝开发中return_url和notify_url的区别分析
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑