ffmpeg 从avio_read 到 file_read

2024-03-14 05:44
文章标签 ffmpeg file read avio

本文主要是介绍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也就可以理解了.
 

这篇关于ffmpeg 从avio_read 到 file_read的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/807382

相关文章

解决Maven项目idea找不到本地仓库jar包问题以及使用mvn install:install-file

《解决Maven项目idea找不到本地仓库jar包问题以及使用mvninstall:install-file》:本文主要介绍解决Maven项目idea找不到本地仓库jar包问题以及使用mvnin... 目录Maven项目idea找不到本地仓库jar包以及使用mvn install:install-file基

关于pandas的read_csv方法使用解读

《关于pandas的read_csv方法使用解读》:本文主要介绍关于pandas的read_csv方法使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录pandas的read_csv方法解读read_csv中的参数基本参数通用解析参数空值处理相关参数时间处理相关

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

Java实现将byte[]转换为File对象

《Java实现将byte[]转换为File对象》这篇文章将通过一个简单的例子为大家演示Java如何实现byte[]转换为File对象,并将其上传到外部服务器,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言1. 问题背景2. 环境准备3. 实现步骤3.1 从 URL 获取图片字节数据3.2 将字节数组

解决JavaWeb-file.isDirectory()遇到的坑问题

《解决JavaWeb-file.isDirectory()遇到的坑问题》JavaWeb开发中,使用`file.isDirectory()`判断路径是否为文件夹时,需要特别注意:该方法只能判断已存在的文... 目录Jahttp://www.chinasem.cnvaWeb-file.isDirectory()遇

VMWare报错“指定的文件不是虚拟磁盘“或“The file specified is not a virtual disk”问题

《VMWare报错“指定的文件不是虚拟磁盘“或“Thefilespecifiedisnotavirtualdisk”问题》文章描述了如何修复VMware虚拟机中出现的“指定的文件不是虚拟... 目录VMWare报错“指定的文件不是虚拟磁盘“或“The file specified is not a virt

提示:Decompiled.class file,bytecode version如何解决

《提示:Decompiled.classfile,bytecodeversion如何解决》在处理Decompiled.classfile和bytecodeversion问题时,通过修改Maven配... 目录问题原因总结问题1、提示:Decompiled .class file,China编程 bytecode

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

ffmpeg面向对象-待定

1.常用对象 rtsp拉流第一步都是avformat_open_input,其入参可以看下怎么用: AVFormatContext *fmt_ctx = NULL;result = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL); 其中fmt_ctx 如何分配内存的?如下 int avformat_open_input(