FFmpeg5.0源码阅读—— avcodec_send_frame avcodec_receive_packet

news2024/11/24 13:55:53

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

1 avcodec_send_frame

  avcodec_send_frame用于在编码时将一帧raw数据发送给编码器,其基本的调用流程比较简单,主要工作就是将输入的数据ref到Internal Frame上。
在这里插入图片描述

  avcodec_send_frame首先检查当前的codec是不是编码器且是否打开,并且检查codec中的buffer是否有数据没有,有的话就意味着上一帧的数据还没处理完需要等待这一帧处理完才能继续发送。

    if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
        return AVERROR(EINVAL);

    if (avci->draining)
        return AVERROR_EOF;

    if (avci->buffer_frame->data[0])
        return AVERROR(EAGAIN);

  然后是根据输入的frame是否为空来设置标志位,如果为空就表示是最后一帧数据后续的数据就无效了。能够看到在最后如果codec中的packet buffer是空的就会尝试获取一帧packet。

    if (!frame) {
        avci->draining = 1;
    } else {
        ret = encode_send_frame_internal(avctx, frame);
        if (ret < 0)
            return ret;
    }

    if (!avci->buffer_pkt->data && !avci->buffer_pkt->side_data) {
        ret = encode_receive_packet_internal(avctx, avci->buffer_pkt);
        if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
            return ret;
    }

  encode_send_frame_internal比较简单,主要就是针对音频数据进行参数检查并对数据进行填充,最后调用av_frame_ref将输入的数据的引用计数+1、

2 avcodec_receive_packet

2.1 基本流程

  avcodec_receive_packet相对复杂一点点儿,下面是其调用流程图。
在这里插入图片描述

  首先是检查当前codec是否为编码器并且是否打开,如果是就继续。然后检查codec中的packet buffer是否有数据有的话就直接返回了,不然就会调用encode_receive_packet_internal

int attribute_align_arg avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt){
    AVCodecInternal *avci = avctx->internal;
    int ret;

    av_packet_unref(avpkt);

    if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
        return AVERROR(EINVAL);

    if (avci->buffer_pkt->data || avci->buffer_pkt->side_data) {
        av_packet_move_ref(avpkt, avci->buffer_pkt);
    } else {
        ret = encode_receive_packet_internal(avctx, avpkt);
        if (ret < 0)
            return ret;
    }

    return 0;
}

  encode_receive_packet_internal首先就是参数检查,然后根据codec的函数指针设置看调用哪个流程获取编码流。encode_simple_receive_packet就是个while循环调用encode_simple_internal直到获取编码数据或者出错为止。

    if (avctx->codec->receive_packet) {
        ret = avctx->codec->receive_packet(avctx, avpkt);
        if (ret < 0)
            av_packet_unref(avpkt);
        else
            // Encoders must always return ref-counted buffers.
            // Side-data only packets have no data and can be not ref-counted.
            av_assert0(!avpkt->data || avpkt->buf);
    } else
        ret = encode_simple_receive_packet(avctx, avpkt);

  encode_simple_internal除了前面一大坨参数检查,主要救赎下面这块儿,看是利用多线程编码还是利用codec的encode接口编码。

    if (CONFIG_FRAME_THREAD_ENCODER &&
        avci->frame_thread_encoder && (avctx->active_thread_type & FF_THREAD_FRAME))
        /* This might modify frame, but it doesn't matter, because
         * the frame properties used below are not used for video
         * (due to the delay inherent in frame threaded encoding, it makes
         *  no sense to use the properties of the current frame anyway). */
        ret = ff_thread_video_encode_frame(avctx, avpkt, frame, &got_packet);
    else {
        ret = avctx->codec->encode2(avctx, avpkt, frame, &got_packet);
        if (avctx->codec->type == AVMEDIA_TYPE_VIDEO && !ret && got_packet &&
            !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
            avpkt->pts = avpkt->dts = frame->pts;
    }

2.2 多线程

  编码的线程和解码的线程一样都是在avcodec_open2时创建的,编码是调用ff_frame_thread_encoder_init创建的,其中主要就是调用pthread的接口创建线程和相关的参数,可以看到其工作的函数为static void * attribute_align_arg worker(void *v),编码过程中有多个线程每个线程都运行一个worker任务,通过信号量来进行消息的同步。该任务中最终会调用avctx->codec->encode2对数据进行编码。而所有的数据交互都是通过ThreadContext进行的,无论是输入数还是输出的数据还是消息同步都是通过该Context进行的。

typedef struct{
    AVCodecContext *parent_avctx;
    pthread_mutex_t buffer_mutex;

    pthread_mutex_t task_fifo_mutex; /* Used to guard (next_)task_index */
    pthread_cond_t task_fifo_cond;

    unsigned max_tasks;
    Task tasks[BUFFER_SIZE];
    pthread_mutex_t finished_task_mutex; /* Guards tasks[i].finished */
    pthread_cond_t finished_task_cond;

    unsigned next_task_index;
    unsigned task_index;
    unsigned finished_task_index;

    pthread_t worker[MAX_THREADS];
    atomic_int exit;
} ThreadContext;

  当数据到达时主线程会先拷贝数据然后发送信号量signal给任务线程,任务线程拿到消息后编码完成后给主线程发信号finish,主线程取走数据。

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

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

相关文章

AQS概述

基本介绍 队列同步器AbstractQueuedSynchronizer&#xff08;以下简称同步器&#xff09;&#xff0c;是用来构建锁或者其他同步组件的基础框架。 使用了一个int成员变量&#xff08;volatile int state&#xff09;表示同步状态&#xff0c;通过内置的FIFO队列来完成资源获取…

【NLP】如何使用Hugging-Face-Pipelines?

一、说明 随着最近开发的库&#xff0c;执行深度学习分析变得更加容易。其中一个库是拥抱脸。Hugging Face 是一个平台&#xff0c;可为 NLP 任务&#xff08;如文本分类、情感分析等&#xff09;提供预先训练的语言模型。 本博客将引导您了解如何使用拥抱面部管道执行 NLP 任务…

不写代码开启Restful服务

1 前言 很久没有写文章了&#xff0c;不管什么原因&#xff0c;总觉得心里还是觉得有点焦虑&#xff0c;不看看书写点东西就有莫名的焦虑&#xff0c;仿佛只有忙起来才能忘记焦虑。虽然我也知道更重要的是思考方向&#xff0c;但是就像走路&#xff0c;不出发随着时间的流逝&am…

MacBook外接键盘修改键位

众所周知&#xff0c;MacBook的键盘和Windows差别很大&#xff0c;比如我们最常用的ctrlcv在Mac下是commandcv…而外接键盘往往是Windows布局&#xff0c;因此如何修改外接键盘键位就是一件很重要的事情&#xff01; 首先&#xff0c;我们要知道Win键在Mac系统中是多余的&…

微服务一 实用篇 - 5.分布式搜索引擎(ElasticSearch基础)

《微服务一 实用篇 - 5.分布式搜索引擎&#xff08;ElasticSearch基础&#xff09;》 提示: 本材料只做个人学习参考,不作为系统的学习流程,请注意识别!!! 《微服务一 实用篇 - 5.分布式搜索引擎&#xff08;ElasticSearch基础&#xff09;》 《微服务一 实用篇 - 5.分布式搜索…

mysql悲观锁与乐观锁、死锁

mysql悲观锁与乐观锁、死锁 乐观锁的缺点 这个策略源于 mysql 的 mvcc 机制&#xff0c;使用这个策略其实本身没有什么问题&#xff0c;主要的问题就是**对数据表侵入较大&#xff0c;我们要为每个表设计一个版本号字段&#xff0c;然后写一条判断 sql 每次进行判断&#xff…

k8s Service网络详解(一)

有关K8s网络的几个概念 Service&#xff1a;服务 Endpoint&#xff1a;端点 Ingress&#xff1a;和Service类似&#xff0c;基于OSI&#xff08;Open System Interconnection&#xff09;网络模型的七层协议数据&#xff08;如HTTP&#xff09;的转发 Kube Proxy&#xff1…

155、基于STM32单片机老人防跌倒摔倒GSM短信报警系统ADXL345加速度设计(程序+原理图+PCB源文件+参考论文+硬件设计资料+元器件清单等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件方案 二、设计功能 三、实物图 四、原理图 五、PCB图 六、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 单片机主芯片选…

【C语言初阶】指针的运算or数组与指针的关系你了解吗?

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《快速入门C语言》《C语言初阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 &#x1f4cb; 前言&#x1f4ac; 指针运算&#x1f4ad; 指针-整数&#x1f4ad; 指针-指针&#x1f4ad; 指针…

类和对象(中)--运算符重载

目录 1.运算符重载①运算符重载的概念②日期类和运算符重载 2.赋值运算符重载3. 流插入运算符<<重载4.Date类实现5.const成员6.取地址及const取地址操作符重载 1.运算符重载 大家有没有想过内置类型可以使用的运算符是否自定义类型的成员变量也可以使用呢&#xff1f; …

pyqt5-多行文本区QTextEdit实现鼠标滚轮调整文本大小

核心 在 PyQt5 中&#xff0c;你可以通过处理鼠标滚轮事件来设置 QTextEdit 的字体大小。具体做法是在 QTextEdit 上重新实现 wheelEvent 方法&#xff0c;并根据滚轮方向调整字体大小。 代码 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5…

MATLAB 最小二乘法拟合直线点云 方法一 (26)

MATLAB 最小二乘法拟合直线点云 方法一 (26) 一、算法简介二、算法实现1.代码(详细注释)2.结果展示2.1 拟合效果可视化2.2 对比拟合系数与实际值一、算法简介 提供一组点云(x1 y1 )(x2 y2 )(x3 y3 )…等等多个点… 算法自动拟合直线方程 二维点云的直线方程为:y=kx+…

Mac 预览(Preview)丢失PDF标注恢复

感谢https://blog.csdn.net/yaoyao_chen/article/details/127462497的推荐&#xff01; 辛苦用预览在pdf上做的阅读标记&#xff0c;关闭后打开全丢失了&#xff0c;推荐尝试下网站导入文件进行恢复&#xff1a; 直接使用该网页应用PDF Annotation Recovery 或者访问该项目&a…

在 Windows 中通过 WSL 2 高效使用 Docker

大家好&#xff0c;我是比特桃。平时开发中&#xff0c;不免会使用一些容器来跑中间件。而开发者使用的操作系统&#xff0c;大多是Mac OS 、Windows。Docker 为了兼顾这两个平台的用户&#xff0c;推出了 Docker Desktop 应用。Docker Desktop 中的内核还是采用了 Linux 的内核…

swift简单弹幕例子,仿哔哩哔哩

先看例子 每个弹幕的速度都是不一样的&#xff0c;支持弹幕整体开始暂停。 如果弹幕实在是太多了&#xff0c;有个缓冲队列&#xff0c;不停的重试能否显示&#xff0c;保证文字都能显示全&#xff0c;并且每条都能显示。 实现是基于 CADisplayLink 实现的&#xff0c;如此来…

mac使用教程【快速从windows切换为mac,mac快捷键合集】

mac使用教程 1. 安装brew并通过brew安装git 1.1 安装brew 打开终端输入如下命令&#xff1a; % /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"选择对应的镜像进行安装 # 例如&#xff1a;输入5&#xff…

了解 3DS MAX 3D摄像机跟踪设置:第 5部分

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 创建陨石坑 步骤 1 启动 3ds Max 和 打开本教程最后一部分中保存的文件。 启动 3ds Max 步骤 2 删除所有占位符 从头开始创建陨石坑。 删除所有占位符 步骤 3 创建具有“长度”的平面 段和宽度段各…

如何创建vue2,vue3项目

前提需安装node.js和Vue CLI node.js:https://nodejs.org/zh-cn Vue CLI&#xff1a; npm install -g vue/cli 如何创建一个vue2项目 &#xff08;1&#xff09; 使用cmd终端直接创建 进入到vue项目所创建的目录里&#xff08;我是直接创建在桌面上&#xff09; 选择vue2 …

【mysql】聚簇索引和非聚簇索引(B树和B+树)

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: mysql 目录 一、索引分类 二、索引的数据结构 2.1 B树&#xff1a;改造二叉树 2.2 B树&#xff1a;改造B树 三、Mysql索引实现—InnoDB引擎 3.1 主键索引&#xff08;聚簇索引&#xff09; 3.2 …

如何利用plotly和geopandas根据美国邮政编码(Zip-Code)绘制美国地图

对于我自己来说&#xff0c;该需求源自于分析Movielens-1m数据集的用户数据&#xff1a; UserID::Gender::Age::Occupation::Zip-code 1::F::1::10::48067 2::M::56::16::70072 3::M::25::15::55117 4::M::45::7::02460 5::M::25::20::55455 6::F::50::9::55117我希望根据Zip-…