ffmpeg 从avio_read 到 file_read

#############################################
author: hjjdebug
date:   2024年 03月 13日 星期三 15:39:30 CST
description: ffmpeg 从avio_read 到 file_read
#############################################

int nRet = avio_open(&pReadCtx, "200M.ts"), AVIO_FLAG_READ);
只分析一句话.
char buf[10240];
int nret=avio_read(pReadCtx, buf, sizeof(buf));

先看一下程序调用栈,看起来还挺深奥的样子!
0 in file_read of libavformat/file.c:110
1 in retry_transfer_wrapper of libavformat/avio.c:370
2 in ffurl_read of libavformat/avio.c:405
3 in read_packet_wrapper of libavformat/aviobuf.c:521
4 in fill_buffer of libavformat/aviobuf.c:570
5 in avio_read of libavformat/aviobuf.c:663
6 in main of main.cpp:43
------------------------------------------------------------
第一层: aviobuf.c中, AVIOContext对象当家, 这就是pReadCtx.
------------------------------------------------------------
int nret=avio_read(pReadCtx, buf, sizeof(buf));
通俗说就是,嘿!pReadCtx, 给我10240个数据. 放到buf地址处.
pReadCtx 是谁啊? 是个对象,就是说在它的周围有一帮小弟(属性,函数指针等)可以使用.
这个对象是跟200M.ts 文件关联的
下面看看它的执行过程:
它看了看自己缓冲区内容, 一个字节都没有, len=s->buf_end-s->buf_ptr;
哪来10240个数据,于是调用了把缓冲区填满命令. 
fill_buffer(s);
这个s 有一个自己的资源 buffer, 它的开始地址是s->buffer, 大小s->buffer_size=32768
fill_buffer(s) 调用
read_packer_wrapper(s,dst,len) 来向内部缓冲区灌数.
这个wrapper 会调用s->read_packet 指针函数,并传递s->opaque 为第一参数.
ret = s->read_packet(s->opaque, buf, size); 

s->opaque 在aviobuf.c中是一个void指针, 进入下一层函数后,它是一个URLContext 对象指针.
s->read_packet 被赋值的是ffurl_read 函数, 这当然都是在初始化时完成的(avio_open时)
于是程序进入到下一层avio.c 中, 在这里,由URLContext 当家

------------------------------------------------------------
第二层: avio.c中, URLContext 当家, 简记为h.
------------------------------------------------------------
int ffurl_read(URLContext *h, unsigned char *buf, int size)
嘿! URLContext, 给我往buf中填size 个数据.
URLContext 对象设计的目的是, 不管任何协议,我都用一套接口来读写数据.
于是它调用了
    retry_transfer_wrapper(h, buf, size, 1, h->prot->url_read);

多出来的两个参数是,最少读1个byte, 调用h->prot-url_read 来进行实际的读写
于是我们就进入了h->prot->url_read, 它正式file_read, 乖乖,神奇! 它是怎么实现的? 初始化时是怎样赋值的?
先按下不表,一会说清楚, 再继续跟踪代码. 看看数据如何读取.

------------------------------------------------------------
第三层: file.c中, FileContext 对象当家,简记为c.
------------------------------------------------------------
static int file_read(URLContext *h, unsigned char *buf, int size)
该函数传来的是URLContext, 但这里是file.c 文件, 当家的是FileContext, 从URLContext 中可以得到它.
    FileContext *c = h->priv_data;
    ret = read(c->fd, buf, size);  // 这就是libc 的read 了,从fd中读取size个数据到buf, 追到底了!
    返回实际读取到的字节数. 
    欲读32768, 现在返回了32768
    于是打道回府,file_read 返回32768, retry_transfer_wrapper 返回32768,ffurl_read返回32768,
    read_packer_wrapper 返回32768,
    fill_buffer(s) 也调整了自己的参数 s->buf_ptr=dst, s->buf_end=dst+len,s->pos+=len,s->bytes_read+=len
出来后再循环,发现avio_read 还等着10240个数据呢, 咱有32768个数据,它要10240,小case, 给它吧.
            memcpy(buf, s->buf_ptr, len);
            s->buf_ptr += len;
            buf += len;
            size -= len;
再绕回去,size就等于0了,循环退出,avio_read读到数据返回.

这里我们再总结一下:
URLContext h对象地址付给了 AVIOContext 对象成员 s->oopaque
FileContext c对象地址付给了 URLContext 对象成员 h->priv_data
这样各对象关系就明确了.
h->prot 是什么? 是协议protocal, 也是一个对象指针, 
它被付给了ff_file_protocol, 它是怎么付给的? 是在一个协议列表中找协议name为"file" 而找到的.
该对象就在file.c中第356行, 是一个在全局数据区构建的对象
const URLProtocol ff_file_protocol = {
    .name                = "file",
    .url_open            = file_open,
    .url_read            = file_read,
    .url_write           = file_write,
    .url_seek            = file_seek,
    .url_close           = file_close,
    .url_get_file_handle = file_get_handle,
    .url_check           = file_check,
    .url_delete          = file_delete,
    .url_move            = file_move,
    .priv_data_size      = sizeof(FileContext),
    .priv_data_class     = &file_class,
    .url_open_dir        = file_open_dir,
    .url_read_dir        = file_read_dir,
    .url_close_dir       = file_close_dir,
    .default_whitelist   = "file,crypto,data"
};
有了这个对象,就有了h->prot->url_read, 它就是file_read
有了这些基础,再去读avio_open也就可以理解了.
 

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

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

相关文章

开源生态与软件供应链研讨会

✦ 日程安排 开源生态与软件供应链研讨会 时间: 2024年3月12日(星期二)13:30 – 17:00 地点: 复旦大学江湾校区二号交叉学科楼E1021 联系人: 陈碧欢(bhchenfudan.edu.cn) 点击文末“阅读原文”或扫描下方二维码进入报名通…

ROS 语音交互(二)nlp

目录 背景: 一、模型选择 二、操作流程 三、核心代码展示 背景: 成功设置自己的知识库,语音交互问答会优先选择自己的知识库的答案进行回答,减少了耗时 一、模型选择 商汤 商量日日新 二、操作流程 文档中心 | 日日新开放…

Node.js的事件驱动模型(非阻塞I/O)

Node.js的事件驱动模型是它能高效处理并发的关键。这个模型允许Node.js在单个线程上运行,同时通过非阻塞I/O操作来处理成千上万的并发连接。下面是对Node.js事件驱动模型的详细解释: 事件循环(Event Loop) 事件循环是Node.js事件…

ChatGLM3 源码解析(五)

PrefixEncoder # 根据前缀 ID 获取前缀嵌入 # 前缀嵌入将连接到分头之后的 K 和 V 上 class PrefixEncoder(torch.nn.Module):"""The torch.nn model to encode the prefixInput shape: (batch-size, prefix-length)Output shape: (batch-size, prefix-length,…

2024 前端javaScript+ES6

JavaScript 基础 1、基本数据类型: 1.1 基本数据类型: Number(数值):表示数字,包括整数和浮点数。例如:5、3.14。 String(字符串):表示文本数据&#xff…

视觉图像处理和FPGA实现第三次作业--实现一个加法器模块

一、adder模块 module adder(ina, inb, outa); input [5:0] ina ; input [5:0] inb ; output [6:0] outa ;assign outa ina inb; endmodule二、add模块 module add(a,b,c,d,e); input [5:0] a ; input [5:0] b ; input [5:…

阿里云国际修改域名绑定的DDoS高防服务器

本文九河云介绍当您的业务需要绑定多个DDoS高防实例,或者已有的DDoS高防实例已过期需要更换时,如何修改域名接入的配置,才能在业务不中断的前提下平滑迁移。 需绑定多个DDoS高防实例的场景 当网站业务有如下业务需求时,可以为域…

PTA L2-020 功夫传人

一门武功能否传承久远并被发扬光大,是要看缘分的。一般来说,师傅传授给徒弟的武功总要打个折扣,于是越往后传,弟子们的功夫就越弱…… 直到某一支的某一代突然出现一个天分特别高的弟子(或者是吃到了灵丹、挖到了特别的…

netty服务器监听和接收数据

1.pom依赖 <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><!-- 根据需要选择版本 --><version>4.1.86.Final</version> </dependency>2.配置属性 application.properties #启动端口 ser…

从零开始,一步步构建服务网格istio

一、环境情况 环境&#xff1a;Ubuntu20.04 机器数量&#xff1a;单机1台 IP&#xff1a;10.9.2.83 二、准备知识 为什么使用 Istio&#xff1f; Istio提供了一种更高级别的服务网格解决方案&#xff0c;它可以简化和加强 Kubernetes 集群中的服务间通信、流量管理、安全…

Git操作指南:子模块、用户名修改和Subtree

引言 在软件开发中&#xff0c;版本控制是一个至关重要的环节。Git 作为目前最流行的版本控制工具之一&#xff0c;提供了丰富的功能和灵活的操作方式。本文将介绍一些常用的 Git 操作&#xff0c;包括管理子模块、修改用户名、使用 Git Subtree 合并项目以及其他一些常见操作…

基于R语言APSIM模型应用

随着数字农业和智慧农业的发展&#xff0c;基于过程的农业生产系统模型在模拟作物对气候变化的响应与适应、农田管理优化、作物品种和株型筛选、农田固碳和温室气体排放等领域扮演着越来越重要的作用。APSIM (Agricultural Production Systems sIMulator)模型是世界知名的作物生…

鸿蒙开发之MPChart图表开发

一、简介 随着移动应用的不断发展,数据可视化成为提高用户体验和数据交流的重要手段之一,因此需要经常使用图表,如折线图、柱形图等。OpenHarmony提供了一个强大而灵活的图表库是实现这一目标的关键。 在 ohpm 中心仓(https://ohpm.openharmony.cn/)中,汇聚了众多开发者…

ubuntu如何添加快捷方式到收藏夹、桌面

一、背景 有时候单独下载的软件包需要在特定路径里启动&#xff0c;这样使用起来非常不方便。因此需要在桌面和收藏夹里创建启动快捷方式。 二、具体步骤 这里以下载的zotero软件&#xff08;一款用于文献管理的软件&#xff09;为例。官网地址: Zotero | Your personal res…

python控制语句-2.1

目录 while循环 while循环练习-1 while 循环 - break 语法 while 循环 - continue 语法 while 循环 - else 语法 while循环练习-2 while循环 while循环练习-1 求1到n的交错和输入正整数 n&#xff0c;求 1 到 n 的交错和&#xff1a;即 -12-34-56-7...((-1)^n)*nn eval(…

shell脚本中数组元素赋值

在Shell&#xff08;特别是Bash&#xff09;脚本中定义和赋值数组有几种不同的方法。基本的数组赋值语句如下&#xff1a; # 无索引数组的赋值 array_name(element1 element2 element3)其中 element1 element2 element3 是数组 array_name 的元素。 如果你想要更新现有数组的…

【gpt实践】同时让chatgpt和claude开发俄罗斯方块

最近chatgpt和claude都在使用&#xff0c;其实大部分日常使用场景表现都没有相差太多&#xff0c;想搞一个有趣的小实验&#xff0c;如果同时让chatgpt和claude开发俄罗斯方块谁会表现的更好呢&#xff0c;说干就干&#xff01; prompt 我选择了用英文描述&#xff0c;毕竟英…

Unity中计算两个三维坐标点的各种方法

1、 根据勾股定理计算两点的距离 /// <summary>/// 根据勾股定理计算两点的距离/// </summary>/// <param name"point1"></param>/// <param name"point2"></param>/// <returns></returns>private float…

《如何使用C语言去下三子棋?》

目录 一、环境配置 二、功能模块 1.打印菜单 2.初始化并打印棋盘 3、行棋 3.1玩家行棋 3.2电脑行棋 4、判断是否和棋 5.判赢 三、代码实现 1、test.c文件 2、game.c文件 3、game.h文件 一、环境配置 本游戏用到三个文件&#xff0c;分别是两个源文件test.c game.c 和…

JWT令牌校验是什么东西?举个例子

JWT&#xff08;JSON Web Token&#xff09;令牌校验是验证JWT令牌的有效性和真实性的过程。JWT是一种用于在网络应用间安全传递信息的开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它由三部分组成&#xff1a;头部&#xff08;header&#xff09;、载荷&#xff08;p…