FFmpeg5.0源码阅读—— avcodec_send_packetavcodec_receive_frame

news2025/1/11 0:55:20

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

  avcodec_send_packet接口将AVPacket数据发送给解码器进行解码,然后通过avcodec_receive_frame获取数据。

1 avcodec_send_packet

在这里插入图片描述

  avcodec_send_packet首先是检查解码器的合法性以及数据是否为空,如果输入数据和Context符合要求就会删除AVcodecContext->internal->buffer_pkt中缓存的一帧码流数据,将输入的Packet拷贝到该buffer上。av_bsf_send_packet只是拷贝增加输入的Packet引用计数到AVBSFInternal->buffer_pkt,最后如果缓存的buffer_frame是空的就会调用decode_receive_frame_internal解码帧,该过程根据配置项可谓同步也可为异步。

1.1 decode_receive_frame_internal

  decode_receive_frame_internal内就是真正的调用解码流程,如果解码器的receive_frame函数指针不为空就直接调用解码器的receive_frame进行解码该过程是同步的。否则就会调用decode_simple_receive_frame进行解码。解码完成后需要根据解码的数据和当前解码器Context的一些pts相关的值计算当前帧的具体pts和dts,另外如果有指定FrameDecodeData还会调用后处理流程fdd->post_process进行解码。

1.2 decode_simple_receive_frame

  decode_simple_receive_frame主要是调用decode_simple_internal进行解码。这里使用的Packet就是前面存储在AVBSFInternal中的buffer_pkt。然后就是实际调用解码的流程,如果没有配置解码线程就直接调用每个解码器对应的函数指针的avctx->codec->decode直接同步拿到帧。否则就会调用ff_thread_decode_frame进行多线程解码。
  FFmpeg中每种格式,解码器等都有自己的描述结构,比如下面是gif的解码器描述。

static const AVClass decoder_class = {
    .class_name = "gif decoder",
    .item_name  = av_default_item_name,
    .option     = options,
    .version    = LIBAVUTIL_VERSION_INT,
    .category   = AV_CLASS_CATEGORY_DECODER,
};

const AVCodec ff_gif_decoder = {
    .name           = "gif",
    .long_name      = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_GIF,
    .priv_data_size = sizeof(GifState),
    .init           = gif_decode_init,
    .close          = gif_decode_close,
    .decode         = gif_decode_frame,
    .capabilities   = AV_CODEC_CAP_DR1,
    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
                      FF_CODEC_CAP_INIT_CLEANUP,
    .priv_class     = &decoder_class,
};

  ff_thread_decode_frame内都是通过锁和条件变量进行同步的。首先根据当前的状态获取一个解码线程的Context,然后将当前的Packet提交到该线程上,提交就是将一帧数据增加引用让解码Context的avpkt也占用输入帧的引用计数,提交完成就会发送信号通知在等待的解码线程启动。
  解码线程起始在avcodec_open2的时候就已经创建好了,在wait数据。具体的执行函数就是frame_worker_thread,该函数内就是调用codec->decode进行解码解码完成后就会发送通知到ff_thread_decode_frame中取解码完的帧。令条件if (!p->avctx->thread_safe_callbacks && ( p->avctx->get_format != avcodec_default_get_format || p->avctx->get_buffer2 != avcodec_default_get_buffer2))为A,如果A为true则当前线程是会被阻塞的,完全就是同步运行,否则就是多线程的。

if (!p->avctx->thread_safe_callbacks && (
         p->avctx->get_format != avcodec_default_get_format ||
         p->avctx->get_buffer2 != avcodec_default_get_buffer2)) {
        while (atomic_load(&p->state) != STATE_SETUP_FINISHED && atomic_load(&p->state) != STATE_INPUT_READY) {
            int call_done = 1;
            pthread_mutex_lock(&p->progress_mutex);
            while (atomic_load(&p->state) == STATE_SETTING_UP)
                pthread_cond_wait(&p->progress_cond, &p->progress_mutex);

            switch (atomic_load_explicit(&p->state, memory_order_acquire)) {
            case STATE_GET_BUFFER:
                p->result = ff_get_buffer(p->avctx, p->requested_frame, p->requested_flags);
                break;
            case STATE_GET_FORMAT:
                p->result_format = ff_get_format(p->avctx, p->available_formats);
                break;
            default:
                call_done = 0;
                break;
            }
            if (call_done) {
                atomic_store(&p->state, STATE_SETTING_UP);
                pthread_cond_signal(&p->progress_cond);
            }
            pthread_mutex_unlock(&p->progress_mutex);
        }
    }

2 avcodec_receive_frame

  avcodec_receive_frame比较简单先检查buffer_frame有没有数据,有的话就直接返回,没有即调用decode_receive_frame_internal进行解码。

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

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

相关文章

CUDA C编程及GPU基本知识【二】

文章目录 1、CPU和GPU的架构2、CPUs: 延迟导向设计和GPUs: 吞吐导向设计2.1 CPUs: 延迟导向设计2.2 GPUs: 吞吐导向设计2.3 GPU&CPU特点2.4 GPU编程:什么样的问题适合GPU 3、GPU编程与CUDA3.1 CUDA编程并行计算整体流程3.2 CUDA编程术语3.2.1 硬件3.2.2 内存模型…

Hive分桶

分桶的概述 为什么要分桶 数据分区可能导致有些分区数据过多,有些分区数据极少。分桶是将数据集分解为若干部分(数据文件)的另一种技术。分区和分桶其实都是对数据更细粒度的管理。当单个分区或者表中的数据越来越大,分区不能细粒度的划分数据时&#x…

阐述说明NLP发展历史,以及 NLP与chatgpt的关系

自然语言处理(Natural Language Processing,NLP)是人工智能(AI)领域的一个重要分支,关注计算机与人类(自然)语言之间的交互。NLP的目标是使计算机能够理解、生成和解释自然语言&…

心法利器[89] | 实用文本生成中的解码方法

心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会,与大家一起成长。具体介绍:仓颉专项:飞机大炮我都会,利器心法我还有。 2022年新一版的文章合集已经发布,累计已经60w字了,获取方式看这里&…

[CVPR‘23] PanoHead: Geometry-Aware 3D Full-Head Synthesis in 360 deg

论文|项目 总结: 任务:3D human head synthesis现有问题:GANs无法在「in-the-wild」「single-view」的图片情况下,生成360度人像解决方案:1)提出了two-stage self-adaptive image alignment&am…

C++ 设计模式之策略模式

文章目录 一、简介二、场景三、举个栗子四、小结参考资料 一、简介 策略模式的定义很简单:即创建一系列的算法,把它们一个个封装起来 , 并且使它们可相互替换(用扩展的方式来面对未来变化)。在GoF一书中将其定位为一种“对象行为式模式”&…

vs code insiders 配置c语言

vs code insiders 配置c语言 1.下载插件 2.再配置代码 (1)launch.json {// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information, visit: https://go.microsoft.com/…

操作系统的可扩展访问控制

访问控制是操作系统安全的基石,当前的操作系统已部署了很多访问控制的模型:Unix和Windows NT多用户安全;SELinux中的类型执行;反恶意软件产品;Apple OS X,Apple iOS和Google Android中的应用沙盒&#xff1…

RNN介绍

时间序列的表示 [seq_len, batch_size, vec ] seq_len表示一个句子通常有多少个单词或者一个序列有多少个时间段,batch_size表示同时多个样本,vec表示单词的编码长度 请问rnn和lstm中batchsize和timestep的区别是什么? - 知乎 (zhihu.com) import torch import torch.nn …

MYSQL05高级_查看修改存储引擎、InnoDB和MyISAM对比、其他存储引擎介绍

文章目录 ①. 查看、修改存储引擎②. InnoDB和MyISAM对比③. Archive引擎 - 归档④. Blackhole引擎丢数据⑤. CSV - 引擎⑥. Memory引擎 - 内存表⑦. Federated引擎 - 访问远程表⑧. Merge引擎 - 管理多个MyISAM⑨. NDB引擎 - 集群专用 ①. 查看、修改存储引擎 ①. 查看mysql提…

Spring Boot原理分析(一):项目启动(上)——@SpringBootApplication

文章目录 〇、准备工作一、SpringBootApplication.java源码解析1.源码2.自定义注解3.组合注解4.注解ComponentScan过滤器 5.注解SpringBootConfigurationConfiguration 6.注解EnableAutoConfiguration 本文章是Spring Boot源码解读与原理分析系列博客的第一篇,将会介…

Mac(M1Pro)下运行ChatGLM2

最近很多人都尝试在M1/M2芯片下跑chatglm/chatglm2,结果都不太理想,或者是说要32G内存才可以运行。本文使用cpu基于chatglm-cpp运行chatglm2的int4版本。开了多个网页及应用的情况下(包括chatglm2),总体内存占用9G左右。chatglm2可…

PYTHON+YOLOV5+OPENCV,实现数字仪表自动读数,并将读数结果进行输出显示和保存

最近完成了一个项目,利用pythonyolov5实现数字仪表的自动读数,并将读数结果进行输出和保存,现在完成的7788了,写个文档记录一下,若需要数据集和源代码可以私信。 最后实现的结果如下: 项目过程 首先查阅文…

从单体到SpringBoot/SpringCloud微服务架构无感升级的最佳实践

目录导读 从单体到SpringBoot/SpringCloud微服务架构无感升级的最佳实践1. 业务背景2. 当前问题3. 升级方案3.1 架构设计4. 详细设计4.1 迁移阻碍4.2 解决思路 5. 实现过程5.1 认证兼容改造5.2 抽象业务流程5.2.1 抽象业务的思路5.2.2 抽象业务的抽象编码5.2.3 抽象业务的具体实…

BFF网关模式开发指南

BFF是近些年新衍生出来的一种开发模式,或者说是一种适配模式的系统,BFF全称为Backend OF Front意为后端的前端,为了适配微服务模式下前端后端系统接口调用混乱而出现的。在如今微服务盛行的趋势下,大型系统中划分出了数十个服务模…

前端优化的一些方向

对于浏览器来说,加载网页的过程可以分为两部分,下载文档并响应(5%左右),下载各种组件(95%左右)。 而对比大部分优秀网页来说下载文档(10%~ 20%),下载组件&…

23_7第一周LeetCode刷题回顾

目录 1. 两数之和2. 两数相加3.无重复字符的最长子串4.寻找两个正序数组的中位数5.最长回文子串6.N 形变换7.整数反转8.字符串转整数(atoi)9.回文数10. 正则表达式匹配11. 盛最多水的容器12. 整数转罗马数字13. 罗马数字转整数14. 最长公共前缀15.三数之…

MyBatis中的动态SQL(sql标签、where标签、set标签、批量增加与批量删除)

目录 sql标签 ​编辑 where标签 set标签 foreach标签 批量增加 批量删除 将基础SQL语句中重复性高的增加它的复用性&#xff0c;使得sql语句的灵活性更强 sql标签<sql> <sql id"text">select * from user</sql><select id"selectA…

如何在苹果商店发布App?

一、介绍 众所周知&#xff0c;苹果对于自家产品的安全问题十分重视&#xff0c;他们有严格的一套审核标准和流程&#xff0c;当我们想要在苹果商店发布一款App的时候就需要经过重重艰难险阻&#xff0c;克服不少繁杂的问题去完成这项工作。 另外有一点需要注意的是&#xff…

C语言库函数strcpy学习

strcpy是C语言的一个标准库函数&#xff1b; strcpy把含有\0结束符的字符串复制到另一个地址空间&#xff0c;返回值的类型为char*。 原型声明&#xff1a;char *strcpy(char* dest, const char *src); 头文件&#xff1a;#include <string.h> 和 #include <stdio.h&g…