当前位置: 首页 > news >正文

Android codec2 视频框架 之输入buffer

文章目录

      • 输入端的内存管理
      • 输入数据包buffer结构体的转换

在这里插入图片描述
主要的流程如上, 申请内存在CCodecBufferChannel,申请之后回调到MediaCodec。然后应用从MediaCodec获取 将解码数据放到buffer中,CCodecBufferChannel在将这块buffer 送到componet模块。

输入端的内存管理

  • 内部解码输入buffer的申请个数以及获取方式

mediacodec 中会申请一部分(默认情况下是4个)待解码的buffer。

status_t CCodecBufferChannel::requestInitialInputBuffers() {if (mInputSurface) {return OK;}size_t numInputSlots = mInput.lock()->numSlots;struct ClientInputBuffer {size_t index;sp<MediaCodecBuffer> buffer;size_t capacity;};std::list<ClientInputBuffer> clientInputBuffers;{Mutexed<Input>::Locked input(mInput);while (clientInputBuffers.size() < numInputSlots) {ClientInputBuffer clientInputBuffer;if (!input->buffers->requestNewBuffer(&clientInputBuffer.index,&clientInputBuffer.buffer)) {break;}}}其中在构造函数中定义了
constexpr size_t kSmoothnessFactor = 4;
input->numSlots = kSmoothnessFactor;

这个buffer 外部有两种方式可以获取到。

  1. 直接调用dequeueInputBuffer。
  2. 设置回调到Mediacodec,有buffer 可用的时候 回调到callback中。
    输入输出都可以这样做, 在NuPlayer 中是设置回调到mediacodec,然后mediacodec回调回来。nuplayer中是在MediaCodec 有bufer 可用的时候 handleAnInputBuffer 从source读取数据,这个是一个新的 ABuffer buffer,读到数据后将会有拷贝的动作 将ABuffer拷贝到MediaCodecBuffer中。
sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
mCodec->setCallback(reply);
  • 输入buffer的申请、存储

在CCodecBufferChannel中 requestInitialInputBuffers 将调用input->buffers->requestNewBuffer申请到index和buffer。这些buffer也同时存储到input->buffers中。然后通过回调 回调到Mediacodec的kWhatFillThisBuffer,FillThisBuffer的 updateBuffers 存储buffer到mPortBuffers,存储index 到mAvailPortBuffers。 如果有设置callback的话,会把index 返回给注册callback的地方。如果是getInputBuffer 那么获取的是CCodecBufferChannel的input->buffers.

上述的回调有两个地方会调用

  1. InitialInputBuffers的时候。
  2. 是feedInputBufferIfAvailable的时候。而feedInputBufferIfAvailable 在onWorkDone, discardBuffer、renderOutputBuffe、onInputBufferDone等都可会调用。
MediaCodec.cppstatus_t MediaCodec::init(const AString &name) {mBufferChannel->setCallback(std::unique_ptr<CodecBase::BufferCallback>(new BufferCallback(new AMessage(kWhatCodecNotify, this))));
}ccodec.cppvoid CCodec::start() {(void)mChannel->requestInitialInputBuffers();
}MediaCodec.cpp
void BufferCallback::onInputBufferAvailable(size_t index, const sp<MediaCodecBuffer> &buffer) {sp<AMessage> notify(mNotify->dup());notify->setInt32("what", kWhatFillThisBuffer);notify->setSize("index", index);notify->setObject("buffer", buffer);notify->post();
}
  • 申请的内存不够的情况会怎么处理?

在nuplayer中拷贝解码数据到mediacodec的时候 会判断从codec取出来的buffer 够不够 不够的话会报错。而这个buffer 大小的申请也是外部设置的,一般是在解析的时候能够知道 最大是多少。比如下面的MP4解析的代码中会获取box 中sample的最大值,然后依据这个值设定输入的buffer的最大值。

bool NuPlayer::Decoder::onInputBufferFetched(const sp<AMessage> &msg) {
CHECK(msg->findSize("buffer-ix", &bufferIx));
CHECK_LT(bufferIx, mInputBuffers.size());
sp<MediaCodecBuffer> codecBuffer = mInputBuffers[bufferIx];sp<ABuffer> buffer;
bool hasBuffer = msg->findBuffer("buffer", &buffer);if (needsCopy) {
if (buffer->size() > codecBuffer->capacity()) {
handleError(ERROR_BUFFER_TOO_SMALL);
mDequeuedInputBuffers.push_back(bufferIx);
return false;
}
}status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) {
status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit);
reply->setBuffer("buffer", accessUnit);
}sp<Codec2Buffer> LinearInputBuffers::Alloc(
const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
int32_t capacity = kLinearBufferSize;
(void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
}size_t max_size;
err = mLastTrack->sampleTable->getMaxSampleSize(&max_size);if (max_size != 0) {
if (max_size > SIZE_MAX - 10 * 2) {
ALOGE("max sample size too big: %zu", max_size);
return ERROR_MALFORMED;
}
AMediaFormat_setInt32(mLastTrack->meta,
AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, max_size + 10 * 2);
}
  • PipelineWatcher控制外部输入buffer的速度

监控输入buffer的情况,有buffer送入解码器的时候 mFramesInPipeline 存储buffer、index 和时间。送入componet 处理完成之后调用onWorkDone从队列中删除。而这个mFramesInPipeline队列的大小不能超过mInputDelay + mPipelineDelay + mOutputDelay + mSmoothnessFactor.默认是4,就是输入最多存储4块了,超过4块,就不会回调到外部,让外部送数据进来了。

    if (!items.empty()) {{Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);PipelineWatcher::Clock::time_point now = PipelineWatcher::Clock::now();for (const std::unique_ptr<C2Work> &work : items) {watcher->onWorkQueued(work->input.ordinal.frameIndex.peeku(),std::vector(work->input.buffers),now);}}err = mComponent->queue(&items);}while (!mPipelineWatcher.lock()->pipelineFull()) {sp<MediaCodecBuffer> inBuffer;size_t index;{Mutexed<Input>::Locked input(mInput);numActiveSlots = input->buffers->numActiveSlots();ALOGD("active:%d, numslot:%d", (int)numActiveSlots, (int)input->numSlots);if (numActiveSlots >= input->numSlots) {break;}if (!input->buffers->requestNewBuffer(&index, &inBuffer)) {ALOGE("[%s] no new buffer available", mName);break;}}ALOGE("[%s] new input index = %zu [%p]", mName, index, inBuffer.get());mCallback->onInputBufferAvailable(index, inBuffer);}

输入数据包buffer结构体的转换

  • MediaCodec 层
    ABuffer(Nuplayer)------>MediaCodecBuffer ----->C2Buffer
  1. Nuplayer: 拷贝解码数据到前面requestInitialInputBuffers申请的Codec2buffer(基类是MediaCodecBuffer)
  2. MediaCodec: Nuplayer中拷贝好的buffer queueInputBuffer到MediaCodec 中,MediaCodec要把这块buffer 传递到
    底下具体的componet需要要转换为一个c2buffer。这个c2buffer封装在c2work中 queue 到componet中。
  • componet层:
    是调用到simplec2componet 中,调用的是queue_nb。 在simpleC2的实现中是发送一个process的消息到looper
    执行processQueue,processQueue在调用到具体的解码componet的proces进行处理。
    std::unique_ptr<C2Work> work(new C2Work);work->input.ordinal.timestamp = timeUs;work->input.ordinal.frameIndex = mFrameIndex++;// WORKAROUND: until codecs support handling work after EOS and max output sizing, use timestamp// manipulation to achieve image encoding via video codec, and to constrain encoded output.// Keep client timestamp in customOrdinalwork->input.ordinal.customOrdinal = timeUs;work->input.buffers.clear();sp<Codec2Buffer> copy;bool usesFrameReassembler = false;if (buffer->size() > 0u) {Mutexed<Input>::Locked input(mInput);std::shared_ptr<C2Buffer> c2buffer;if (!input->buffers->releaseBuffer(buffer, &c2buffer, false)) {return -ENOENT;}}err = mComponent->queue(&items);

相关文章:

Android codec2 视频框架 之输入buffer

文章目录 输入端的内存管理输入数据包buffer结构体的转换 主要的流程如上&#xff0c; 申请内存在CCodecBufferChannel&#xff0c;申请之后回调到MediaCodec。然后应用从MediaCodec获取 将解码数据放到buffer中&#xff0c;CCodecBufferChannel在将这块buffer 送到componet模块…...

Python实现局部二进制算法(LBP)

1.介绍 局部二进制算法是一种用于获取图像纹理的算法。这算法可以应用于人脸识别、纹理分类、工业检测、遥感图像分析、动态纹理识别等领域。 2.示例 """ 局部二进制算法&#xff0c;计算图像纹理特征 """ import cv2 import numpy as np imp…...

如何评价现在的CSGO游戏搬砖市场

如何评价现在的csgo市场&#xff1f; 其实整个搬砖市场&#xff0c;现在已经变得乌烟瘴气&#xff0c;散发着“恶臭”。我个人非常鄙视那些虚有其表&#xff0c;大小通吃的做法&#xff0c;那些甚至连搬砖数据都看不懂的人&#xff0c;也出来吹嘘着“实力强大&#xff0c;经验丰…...

ResourceQuota对象在K8s上的说明

ResourceQuota资源对象的说明&#xff0c;以及在集群中的作用说明 定义说明 https://kubernetes.io/zh-cn/docs/concepts/policy/resource-quotas/ 集群中的资源组的划分和设计 在具有 32 GiB 内存和 16 核 CPU 资源的集群中&#xff0c;允许 A 团队使用 20 GiB 内存 和 10 核…...

悟空crm二次开发 增加客户保护功能 (很久没有消息,但是有觉得有机会的客户)就进入了保护转态

需求&#xff1a;客户信息录入不限数量&#xff0c;但是录入的信息1个月内只有自己和部门领导能看到&#xff0c;如果1个月内未成交或者未转移至自己的客保 则掉入公海所有人可见&#xff0c;这里所说的客保就是现在系统自带的客保 1、需求思维导图 2、新增保护按钮 3、点击该…...

k8s之配置资源管理

一&#xff0c;secret Secret 是用来保存密码、token、密钥等敏感数据的 k8s 资源&#xff0c;这类数据虽然也可以存放在 Pod 或者镜像中&#xff0c;但是放在 Secret 中是为了更方便的控制如何使用数据&#xff0c;并减少暴露的风险。 有三种类型&#xff1a; 1&#xff0c;k…...

赛氪助力全国大学生数学竞赛山东赛区圆满举办

近日&#xff0c;全国大学生数学竞赛山东赛区比赛有序进行&#xff0c;赛氪已连续6年助力本项赛事蓬勃发展。在中国高等教育学会高校竞赛评估与管理体系研究专家工作组发布的《2022全国普通高校大学生竞赛分析报告》中&#xff0c;本赛事荣登观察目录。 全国大学生数学竞赛旨在…...

pytorch基础语法问题

这里写目录标题 pytorch基础语法问题shapetorch.ones_like函数和torch.zeros_like函数y.backward(torch.ones_like(x), retain_graphTrue)torch.autograd.backward参数grad_tensors: z.backward(torch.ones_like(x))来个复杂例子z.backward(torch.Tensor([[1., 0]])更复杂例子实…...

【面试经典150 | 】颠倒二进制位

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;逐位颠倒方法二&#xff1a;分治 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于…...

十分钟了解自动化测试

自动化测试 自动化测试的定义&#xff1a;使用一种自动化测试工具来验证各种软件测试的需求&#xff0c;它包括测试活动的管理与实施、测试脚本的开发与执行。 自动化测试只是测试工作的一部分&#xff0c;是对手工测试的一种补充; 自动化测试绝不能代替手工测试;多数情况下&…...

Redis配置文件

Redis可以在没有配置文件的情况下使用内置的默认配置启动&#xff0c;但是这种设置仅推荐用于测试和开发。 配置Redis的正确方法是提供一个Redis配置文件&#xff0c;通常称为 redis.conf 。 通过命令行传递参数启动 你也可以直接使用命令行传递Redis配置参数。这对于测试非…...

[量化投资-学习笔记009]Python+TDengine从零开始搭建量化分析平台-KDJ

技术分析有点像烹饪&#xff0c;收盘价、最值、成交量等是食材&#xff1b;均值&#xff0c;移动平均&#xff0c;方差等是烹饪方法。随意组合一下就是一个技术指标。 KDJ又称随机指标&#xff08;随机这个名字起的很好&#xff09;。KDJ的计算依据是最高价、最低价和收盘价。…...

Activiti6工作流引擎:Form表单

表单约等于流程变量。StartEvent 有一个Form属性&#xff0c;用于关联流程中涉及到的业务数据。 一&#xff1a;内置表单 每个节点都可以有不同的表单属性。 1.1 获取开始节点对应的表单 Autowired private FormService formService;Test void delopyProcess() {ProcessEngi…...

Fortran 中的指针

Fortran 中的指针 指针可以看作一种数据类型 指针存储与之关联的数据的内存地址变量指针&#xff1a;指向变量数组指针&#xff1a;指向数组过程指针&#xff1a;指向函数或子程序指针状态 未定义未关联 integer, pointer::p1>null() !或者 nullify(p1) 已关联 指针操作 指…...

第七章 块为结构建模 P4|系统建模语言SysML实用指南学习

仅供个人学习记录 这部分感觉很模糊&#xff0c;理解的不好&#xff0c;后面的图也没画了&#xff0c;用到的时候再来翻书 应用端口实现接口建模 端口port表示了块边界上的一个访问点&#xff0c;也可以是由该块分类的任何组成或引用边界上的可访问点。一个块可以有多个端口规…...

提升中小企业效率的不可或缺的企业云盘网盘

相比之大型企业&#xff0c;中小型企业在挑选企业云盘工具更注重灵活性和成本。那么市面上有哪些企业云盘产品更适合中小企业呢&#xff1f; 说起中小企业不能错过的企业云盘网盘&#xff0c;Zoho Workdrive企业云盘绝对榜上有名&#xff01; Zoho Workdrive企业云盘为用户提…...

Web 安全之时序攻击 Timing Attack 详解

目录 什么是 Timing Attack 攻击&#xff1f; Timing Attack 攻击原理 Timing Attack 攻击的几种基本类型 如何防范 Timing Attack 攻击 小结 什么是 Timing Attack 攻击&#xff1f; Timing Attack&#xff08;时序攻击&#xff09;是一种侧信道攻击&#xff08;timing s…...

【objectarx.net】定时器的使用

【objectarx.net】定时器的使用...

C++:容器list的介绍及使用

目录 1.list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 list的构造 1.2.2 list iterator 的使用 1.2.3 list capacity 容量 1.2.4 list element access 访问list元素 1.2.5 list modifiers 修改 1.2.6 迭代器失效 1.list的介绍及使用 1.1 list的介绍 C官网 …...

元核云亮相金博会,智能质检助力金融合规

11月初&#xff0c;第五届中新&#xff08;苏州&#xff09;数字金融应用博览会&#xff5c;2023金融科技大会在苏州国际博览中心举办&#xff0c;围绕金融科技发展热点领域及金融行业信息科技领域重点工作&#xff0c;分享优秀实践经验&#xff0c;探讨数字化转型路径与未来发…...

org.openpnp.vision.pipeline.stages.WritePartTemplateImage

文章目录org.openpnp.vision.pipeline.stages.WritePartTemplateImage功能参数WritePartTemplateImage和ImageWrite的区别产生测试图片例子1 - 自动产生文件名效果ENDorg.openpnp.vision.pipeline.stages.WritePartTemplateImage 功能 将当前工作图像&#xff08;如检测到的元…...

AGI信任崩塌后如何重建公众信心:从ChatGPT幻觉事件到GPT-5发布前的危机预演手册

第一章&#xff1a;AGI信任崩塌的本质与公众认知断层 2026奇点智能技术大会(https://ml-summit.org) 当AGI系统在医疗诊断中给出高置信度但致命错误的治疗建议&#xff0c;或在司法辅助场景中隐性放大历史偏见时&#xff0c;公众的信任并非瞬间瓦解&#xff0c;而是经历一场缓…...

暗黑破坏神2存档编辑器:免费快速修改D2/D2R游戏存档的终极指南

暗黑破坏神2存档编辑器&#xff1a;免费快速修改D2/D2R游戏存档的终极指南 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 暗黑破坏神2存档编辑器&#xff08;d2s-editor&#xff09;是一款功能强大的开源工具&#xff0c;专为D…...

C#与VM视觉平台深度集成:Winform上位机核心模块与数据交互实战

1. 工业视觉检测中的C#与VM平台集成 在工业自动化领域&#xff0c;视觉检测系统已经成为质量控制的核心环节。作为一名长期从事工业视觉开发的工程师&#xff0c;我发现C# Winform与VM视觉平台的深度集成能够显著提升检测系统的开发效率和运行稳定性。这种组合特别适合需要快速…...

如何用IDM激活脚本实现永久试用:简单三步搞定下载加速神器

如何用IDM激活脚本实现永久试用&#xff1a;简单三步搞定下载加速神器 【免费下载链接】IDM-Activation-Script IDM Activation & Trail Reset Script 项目地址: https://gitcode.com/gh_mirrors/id/IDM-Activation-Script 还在为Internet Download Manager&#xf…...

SpringBoot 快速实现 api 加密,一个轮子搞定!

来源&#xff1a;网络目录项目介绍什么是 RSA 加密加密实战实战准备真刀真枪解密实战实战准备真刀真枪总结项目坑点在项目中&#xff0c;为了保证数据的安全&#xff0c;我们常常会对传递的数据进行加密。常用的加密算法包括对称加密&#xff08;AES&#xff09;和非对称加密&a…...

ControlNet-v1-1 FP16模型终极指南:在普通显卡上实现专业级图像控制

ControlNet-v1-1 FP16模型终极指南&#xff1a;在普通显卡上实现专业级图像控制 【免费下载链接】ControlNet-v1-1_fp16_safetensors 项目地址: https://ai.gitcode.com/hf_mirrors/comfyanonymous/ControlNet-v1-1_fp16_safetensors ControlNet-v1-1 FP16 Safetensors…...

45+图像工具+本地AI,这个自托管神器太香了

处理图片时&#xff0c;总是需要打开多个工具&#xff1f;在线工具担心隐私&#xff0c;本地工具功能不全&#xff1f;有了这个自托管的图像处理工具&#xff0c;这些问题都能解决。它把45种图像工具、本地AI功能和批量处理能力打包到一个Docker容器里&#xff0c;你的图片永远…...

如何用Python快速掌握严格耦合波分析:光学仿真的终极指南

如何用Python快速掌握严格耦合波分析&#xff1a;光学仿真的终极指南 【免费下载链接】Rigorous-Coupled-Wave-Analysis modules for semi-analytic fourier series solutions for Maxwells equations. Includes transfer-matrix-method, plane-wave-expansion-method, and rig…...

Xournal++ 终极指南:如何让手写笔记在高分辨率屏幕上清晰如纸 ✨

Xournal 终极指南&#xff1a;如何让手写笔记在高分辨率屏幕上清晰如纸 ✨ 【免费下载链接】xournalpp Xournal is a handwriting notetaking software with PDF annotation support. Written in C with GTK3, supporting Linux (e.g. Ubuntu, Debian, Arch, SUSE), macOS and …...