FFmpeg5.0源码阅读—— avcodec_open2

news2024/9/27 7:20:46

  摘要:本文主要描述了FFmpeg中用于打开编解码器接口avcodec_open2大致流程的具体调用流程,详细描述了该接口被调用时所作的具体工作。
  关键字ffmpegavcodec_open2大致流程
  注意:读者需要了解FFmpeg的基本使用流程,以及一些FFmpeg的基本常识,了解FFmpegIO相关的内容,以及大致的解码流程。

1 avcodec_open2大致流程

  打开codec(codec和编码器统称为codec)前需要通过avcodec_find_decoder找到具体的codec,该函数的实现本身就是遍历FFmpeg内部的一个全局codec_list,该列表存储了目前FFmpeg设置成的所有codec和编码器的AVCodec指针。
  找到codecAVCodec之后需要自己通过avcodec_alloc_context3创建一个AVCodecContext的对象,该对象描述了当前codec的上下文,包含了一些流相关的信息,而AVCodec仅仅描述codec本身和流无关。一切准备好之后就需要调用avcodec_open2打开codec。
在这里插入图片描述

2 调用流程详情

  从上面的流程中能够看出来avcodec_open2主要做了三件事情:

  1. 参数检查与设置;
  2. 初始化codec线程;
  3. 初始化codec。

  参数设置基本上都是一个基本涉及解码过程的参数。首先是进行一些基本的参数设置与检查然后对codec的加锁,该锁是一个全局锁,所以这部分是线程安全的。FFmpeg使用的锁和线程相关都是pthread

static AVMutex codec_mutex = AV_MUTEX_INITIALIZER;

  中间还有一些基本的参数设置与检查就不细细描述了。
  初始化codec时会创建一个AVCodecDescriptorcodec描述,这个也是从一个内部的全局表格codec_descriptors中搜索得到的。之后会根据当前codec的类型分别调用ff_encode_preinitff_decode_preinit做一些基本的初始化,这里面也是对当前codec的一些基本参数设置和一些和codec本身相关的对象的创建。而最终的codec初始化就是调用具体的codec初始化函数指针进行。
  avctx->codec->init就是一个函数指针,每个codec对象都有初始化,编解码相关的接口,这里直接调用的是具体codec内部的函数指针。比如H264解码的AVCodec的指针为如下所示。

const AVCodec ff_h264_decoder = {
    .name                  = "h264",
    .long_name             = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
    .type                  = AVMEDIA_TYPE_VIDEO,
    .id                    = AV_CODEC_ID_H264,
    .priv_data_size        = sizeof(H264Context),
    .init                  = h264_decode_init,
    .close                 = h264_decode_end,
    .decode                = h264_decode_frame,
    //....    
}

  线程初始化ff_thread_init用于初始化codec运行时的解码线程内部会创建多个线程的context并初始化,初始化最终调用的是pthread_***_init接口进行初始化。

err = init_pthread(fctx, thread_ctx_offsets);
if (err < 0) {
    free_pthread(fctx, thread_ctx_offsets);
    av_freep(&avctx->internal->thread_ctx);
    return err;
}

fctx->async_lock = 1;
fctx->delaying = 1;

if (codec->type == AVMEDIA_TYPE_VIDEO)
    avctx->delay = src->thread_count - 1;

fctx->threads = av_mallocz_array(thread_count, sizeof(PerThreadContext));
if (!fctx->threads) {
    err = AVERROR(ENOMEM);
    goto error;
}

for (; i < thread_count; ) {
    PerThreadContext *p  = &fctx->threads[i];
    int first = !i;

    err = init_thread(p, &i, fctx, avctx, src, codec, first);
    if (err < 0)
        goto error;
}

3 其他细节

  avcodec_open2参数部分针对解码器和编码器的不同有区分,具体的代码就是下面这部分

    if (av_codec_is_decoder(avctx->codec)) {
        if (!avctx->bit_rate)
            //这里的码率获取是根据数据源的不同而不同的,非音频流都是返回avtx的bitrate。而音频流则需要根据当前的解码器参数进行计算避免参数不一致
            avctx->bit_rate = get_bit_rate(avctx);
        /* validate channel layout from the decoder */
        if (avctx->channel_layout) {
            int channels = av_get_channel_layout_nb_channels(avctx->channel_layout);
            if (!avctx->channels)
                avctx->channels = channels;
            else if (channels != avctx->channels) { 
                char buf[512];
                av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout);
                av_log(avctx, AV_LOG_WARNING,
                       "Channel layout '%s' with %d channels does not match specified number of channels %d: "
                       "ignoring specified channel layout\n",
                       buf, channels, avctx->channels);
                avctx->channel_layout = 0;
            }
        }
        if (avctx->channels && avctx->channels < 0 ||
            avctx->channels > FF_SANE_NB_CHANNELS) {
            ret = AVERROR(EINVAL);
            goto free_and_end;
        }
        if (avctx->bits_per_coded_sample < 0) {
            ret = AVERROR(EINVAL);
            goto free_and_end;
        }

#if FF_API_AVCTX_TIMEBASE
        if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
            avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));
#endif
    }

  预先初始化时解码器和编码器分别调用的ff_decode_preinitff_encode_preinit
  ff_decode_preinit主要就是初始化AVBSFContext,其他都是对参数进行校验。
  ff_encode_preinit中会检查编码器和编码器Context的参数是不是能够对上如果对不上就会尝试校正,这些参数包括音频通道数,视频色彩范围,音频采样率、音频layout等等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/712454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringMVC (一) 什么是SpringMVC

一、回顾MVC 1.1、什么是MVC MVC是模型(Model)、视图(View)、控制器(Controller)的简写&#xff0c;是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。MVC主要作用是降低了视图与业务逻辑间的双向偶合。MVC不是一种设计模式&#xff0c;MVC是一种架构模式。…

在 ZBrush、Maya 和 Substance 3D Painter 中制作后世界末日女性角色

今天瑞云渲染小编给大家带来了蒂亚戈布兰道 (Thiago Brandao) 分享的设计极其精细后世界末日女性角色背后的秘密&#xff0c;解释了复杂的纹理处理过程&#xff0c;并谈到了创造逼真的面部特征。 介绍 我的名字是蒂亚戈-布兰道。我来自巴西&#xff0c;目前住在这里。从小&…

【AJAX】原生AJAX

目录 一、AJAX的使用场景 二、原生的AJAX 三、HTTP &#xff1a; 1、原生AJAX GET请求 1、原生AJAX POST请求 四、总结 一、AJAX的使用场景 1、页面不刷新的情况下&#xff0c;浏览器等搜索框输入某关键字出现多个搜索选择内容,如下图所示&#xff1a; 2、登录、注册界面输…

前端JS如何实现对复杂文本进行句子分割,将每句话拆分出来?

文章目录 切割句子背景简介前端如何使用NLP&#xff1f;技术实现 切割句子背景简介 开发中遇到一种场景&#xff0c;在做文本翻译这块需求时&#xff0c;需要对输入的原文进行一句一句话的拆分出来&#xff0c;传给后台&#xff0c;获取每句话的翻译结果&#xff0c;便于实现页…

clickhouse系统日志引起的root目录磁盘满的问题处理

问题及追踪 对于生产环境&#xff0c;尤其是配置较低的生产环境&#xff0c;一定要注意资源的使用 今天就遇到一个问题&#xff0c;服务器磁盘接近满了&#xff0c;部署的平台服务异常&#xff0c;无法提供服务 简单说一下客户环境&#xff1a;客户只有老的Windows server 服…

hydra的简单使用

Hydra是一款开源的暴力PJ工具&#xff0c;集成在kali当中。 参数功能-l指定用户名-p指定密码-L指定用户名字典-P指定密码字典-C指定所用格式为“user:password”的字典文件-en null&#xff0c;表示尝试空密码-es same&#xff0c;把用户名本身当做密码进行尝试-er 反向&#…

哈工大计算机网络课程网络层协议详解之:距离向量路由算法与层次化路由算法

文章目录 距离向量路由算法Bellman-Ford算法举例距离向量路由算法 层次化路由算法层次化路由AS示例自治系统间&#xff08;Inter-AS&#xff09;路由任务 在上一节中我们介绍了路由算法中的链路状态路由算法&#xff0c;介绍它基于Dijkstra算法来实现&#xff0c;同时分析了其缺…

Jmeter接口测试断言详解

目录 前言&#xff1a; 响应断言 Apply to (响应断言的应用范围) 要测试的响应字段(可通过取样器结果查看) 响应断言&#xff1a;模式匹配 Json断言 前言&#xff1a; 在JMeter中进行接口测试时&#xff0c;断言是一个非常重要的概念。断言允许我们验证接口的响应是否符…

十七、docker学习-docker-compose安装nginx反向代理

compose安装nginx反向代理 IDEA安装docker插件 idea安装docker插件。Dockerfile、docker-compose.yml文件大部分内容会有提示信息。方便开发人员编写配置文件。 https://plugins.jetbrains.com/plugin/7724-docker/versions基础镜像 docker pull 1.21.0-alpine docker pull…

一文读懂SQL中的Aggregate(聚合) 函数和Scalar(标准)函数

目录 前言&#xff1a; 一、SQL Aggregate 函数 1、AVG() 函数 2、count()函数 3、MAX() 函数 4、MIN() 函数 5、SUM() 函数 6、SQL GROUP BY 语法 7、SQL HAVING 子句 8、SQL EXISTS 运算符 9、SQL UNION 操作符 二、SQL Scalar 函数 1、SQL UCASE() 函数 2、SQ…

Swift 周报 第三十二期

文章目录 前言新闻和社区现已提供新的设计资源visionOS SDK 现已发布 提案Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swift 编辑组自主整理周报的第二十三期&#xff0c;每个模块已初步成型。各位读者如果有好的提议&#xff0c;欢迎在文末留言。 欢迎投稿或推荐内容。…

力扣 -- 174. 地下城游戏

题目链接&#xff1a;174. 地下城游戏 - 力扣&#xff08;LeetCode&#xff09; 下面是用动态规划的思想解决这道题的过程&#xff0c;相信各位小伙伴都能看懂并且掌握这道经典的动规题目滴。 参考代码&#xff1a; class Solution { public:int calculateMinimumHP(vector&…

【上海海事大学806】23上岸学姐经验分享

今天很荣幸请到了一位23上岸上海海事大学的学姐来给大家做一期经验分享&#xff01;&#xff01;&#xff01;我之前也有做过关于上海海事大学806的一些真题解析以及重点勾画&#xff0c;希望能帮到大家&#xff0c; 一、学姐经验分享 很荣幸你能看到我的考研经验分享&#x…

第七章 版本控制器——git

第七章 版本控制器——git 一、git的历史二、git的特点与发展1、git的特点2、git与github 二、git的安装与注册1、git的安装2、git的使用&#xff08;1&#xff09;github注册&#xff08;2&#xff09;创建远端仓库&#xff08;3&#xff09;将远端仓库镜像复制到本地仓库指令…

LIS实验室信息管理系统功能模块(Oracle数据库、Client/Server架构)

一、系统框架简介 1、技术框架 &#xff08;1&#xff09;总体框架&#xff1a; ♦SaaS架构的Client/Server应用 ♦服务可伸缩&#xff0c;多服务协同 ♦服务可拆分&#xff0c;功能易扩展 &#xff08;2&#xff09;技术细节&#xff1a; ♦体系结构&#xff1a;Client/Serv…

零基础小白暑假QT实训1

一.前言 今天就要开始暑假短学期的实训了&#xff0c;本来课堂也要求记笔记&#xff0c;这里我就开始分享我将来五天的学习过程吧。 二.QT安装过程 首先&#xff0c;提供一下我的链接&#xff1a; 本来上传到我的阿里云盘了的&#xff0c;结果压缩包不给分享&#xff0c;抱歉…

互联网高可用架构探讨 | 京东云技术团队

高可用指标与问题 高可用&#xff0c;英文单词High Availability&#xff0c;缩写HA&#xff0c;它是分布式系统架构设计中一个重要的度量。业界通常用多个9来衡量系统的可用性&#xff0c;如下表&#xff1a; 既然有可用率&#xff0c;有一定会存在不可用的情况。系统宕机一般…

【动态规划上分复盘】下降路径最小和|礼物的最大价值

欢迎 前言一、动态规划五部曲二、下降路径最小和思路&#xff1a;动态规划解法具体代码如下 三、礼物的最大价值思路&#xff1a;动态规划具体代码如下: 总结 前言 本文主要讲述动态规划思路的下降路径最小和以及礼物的最大价值两道题。 一、动态规划五部曲 1.确定状态表示&a…

61. 旋转链表

61. 旋转链表 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 旋转链表 https://leetcode.cn/problems/rotate-list/ 完成情况&#xff1a; 解题思路&#xff1a; 参考代码&#xff1a; package 西湖算法题解_…

【C语言】指针进阶[中](函数指针、函数指针数组、指向函数指针数组的指针)

简单不先于复杂&#xff0c;而是在复杂之后。 目录 1. 函数指针 1.1 函数指针的用途 2. 函数指针数组 3. 指向函数指针数组的指针 1. 函数指针 这里的 * 可以省略: 因为函数指针本质上是一个指针&#xff0c;存储了一个函数的地址&#xff0c;因此可以通过函数指针调用对…