Android Camera预览通道

    在《Android图形显示系统》中介绍了2D图形和3D图形的生产过程,对于视频的生产方式没有介绍,这里以Camera预览为例,介绍Camera拍摄得到的图像是如何传递到显示设备显示的。 

    首先来看一个Camera预览的简单示例,代码如下。

package com.sino.camera;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;public class MainActivity extends AppCompatActivity {SurfaceView surfaceView;Camera mCamera;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);surfaceView = findViewById(R.id.surface_view);surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(@NonNull SurfaceHolder holder) {try {mCamera.setPreviewDisplay(holder);} catch (IOException e) {e.printStackTrace();}mCamera.startPreview();}@Overridepublic void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(@NonNull SurfaceHolder holder) {mCamera.stopPreview();}});mCamera = Camera.open();setPreviewOrientation(mCamera);}public void setPreviewOrientation(Camera camera){Camera.CameraInfo info = new Camera.CameraInfo();Camera.getCameraInfo(0, info);int rotation = getWindowManager().getDefaultDisplay().getRotation();int degree = 0;if(rotation == Surface.ROTATION_90){degree = 90;}else if(rotation == Surface.ROTATION_180){degree = 180;}if(rotation == Surface.ROTATION_270){degree = 270;}int orientation = (info.orientation - degree+360) % 360;camera.setDisplayOrientation(orientation);}
}

    本示例的功能也很简单,创建一个Camera对象,通过setPreviewDisplay把SurfaceHolder作为预览输出。有了SurfaceHolder相当于已经创建好了图层Surface,剩下的主要是申请缓存,把视频内容绘制到缓存里,再把缓存投递到队列里。

    下面介绍setPreviewDisplay的流程,调用流程如下。

/* frameworks\base\core\java\android\hardware\Camera.java */
public class Camera {public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {if (holder != null) {setPreviewSurface(holder.getSurface());} else {setPreviewSurface((Surface)null);}}public native final void setPreviewSurface(Surface surface) throws IOException;
}/* frameworks\base\core\jni\android_hardware_Camera.cpp */
static void android_hardware_Camera_setPreviewSurface(JNIEnv *env, jobject thiz, jobject jSurface)
{sp<Camera> camera = get_native_camera(env, thiz, NULL);sp<IGraphicBufferProducer> gbp;sp<Surface> surface;if (jSurface) {surface = android_view_Surface_getSurface(env, jSurface);if (surface != NULL) {gbp = surface->getIGraphicBufferProducer();}}if (camera->setPreviewTarget(gbp) != NO_ERROR) {}
}/* frameworks\av\camera\Camera.cpp */
status_t Camera::setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer)
{sp <::android::hardware::ICamera> c = mCamera;return c->setPreviewTarget(bufferProducer);
}

   setPreviewTarget把Surface的IGraphicBufferProducer传给了CameraService进程。接下来是CameraService的处理流程。

/*frameworks\av\services\camera\libcameraservice\api1\CameraClient.cpp */
status_t CameraClient::setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer) {sp<IBinder> binder;sp<ANativeWindow> window;if (bufferProducer != 0) {binder = IInterface::asBinder(bufferProducer);window = new Surface(bufferProducer, /*controlledByApp*/ true);}return setPreviewWindow(binder, window);
}status_t CameraClient::setPreviewWindow(const sp<IBinder>& binder,const sp<ANativeWindow>& window) {if (mHardware->previewEnabled()) {if (window != 0) {mHardware->setPreviewScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);mHardware->setPreviewTransform(mOrientation);result = mHardware->setPreviewWindow(window);}}
}

在CameraService中,根据GraphicBufferProducer构造出ANativeWindow对象(其实就是Surface),然后传递HAL进程。HAL拿到ANativeWindow后,就可以申请图像缓存,把图像缓存传递到SurfaceFlinger处理。

Return<Status> CameraDevice::setPreviewWindow(const sp<ICameraDevicePreviewCallback>& window) {mHalPreviewWindow.mPreviewCallback = window;if (mDevice->ops->set_preview_window) {return getHidlStatus(mDevice->ops->set_preview_window(mDevice,(window == nullptr) ? nullptr : &mHalPreviewWindow));}
}camera_device_ops_t QCameraMuxer::mCameraMuxerOps = {.set_preview_window =        QCameraMuxer::set_preview_window,
}int QCameraMuxer::set_preview_window(struct camera_device * device,struct preview_stream_ops *window)
{for (uint32_t i = 0; i < cam->numCameras; i++) {pCam = gMuxer->getPhysicalCamera(cam, i);if (pCam->mode == CAM_MODE_PRIMARY) {QCamera2HardwareInterface *hwi = pCam->hwi;rc = hwi->set_preview_window(pCam->dev, window);}}return rc;
}int QCamera2HardwareInterface::set_preview_window(struct camera_device *device,struct preview_stream_ops *window)
{QCamera2HardwareInterface *hw =reinterpret_cast<QCamera2HardwareInterface *>(device->priv);rc = hw->processAPI(QCAMERA_SM_EVT_SET_PREVIEW_WINDOW, (void *)window);
}void CameraDevice::initHalPreviewWindow()
{mHalPreviewWindow.dequeue_buffer = sDequeueBuffer;mHalPreviewWindow.enqueue_buffer = sEnqueueBuffer;
}int CameraDevice::sDequeueBuffer(struct preview_stream_ops* w,buffer_handle_t** buffer, int *stride) {CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w);Status s;object->mPreviewCallback->dequeueBuffer([&](auto status, uint64_t bufferId, const auto& buf, uint32_t strd) {s = status;if (s == Status::OK) {*buffer = &(object->mCirculatingBuffers[bufferId]);*stride = strd;}});
}int32_t QCamera2HardwareInterface::preparePreview()
{rc = addChannel(QCAMERA_CH_TYPE_PREVIEW);
}int32_t QCamera2HardwareInterface::addChannel(qcamera_ch_type_enum_t ch_type)
{switch (ch_type) {case QCAMERA_CH_TYPE_PREVIEW:rc = addPreviewChannel();break;}
}
int32_t QCamera2HardwareInterface::addPreviewChannel()
{rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_PREVIEW,preview_stream_cb_routine, this);
}void QCamera2HardwareInterface::preview_stream_cb_routine(mm_camera_super_buf_t *super_frame,QCameraStream * stream,void *userdata)
{err = memory->enqueueBuffer(idx);int dequeuedIdx = memory->dequeueBuffer();
}int32_t QCameraGrallocMemory::dequeueBuffer()
{err = mWindow->dequeue_buffer(mWindow, &buffer_handle, &stride);return dequeuedIdx;
}int32_t QCameraGrallocMemory::enqueueBuffer(uint32_t index, nsecs_t timeStamp)
{err = mWindow->enqueue_buffer(mWindow, (buffer_handle_t *)mBufferHandle[index]);
}

    在HAL进程中,调用ANativeWindow的dequeue_buffer申请缓存,调enqueue_buffer投递缓存,根据前面介绍eglSwapBuffers已经知道,enqueue_buffer会调到Surface的queueBuffer,dequeue_buffer调到Surface的dequeueBuffer。

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

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

相关文章

Golang ProtoBuf 初学者完整教程:语法

一、编码规范推荐 1、文件名使用小写下划线的命名风格&#xff0c;例如 lower_snake_case.proto 2、使用 2 个空格缩进 3、包名应该和目录结构对应 4、消息名使用首字母大写驼峰风格(CamelCase)&#xff0c;例如message StudentRequest { ... } 5、字段名使用小写下划线的风格…

【系统分析师】操作系统部分

文章目录 1、进程状态2、前趋图3、PV操作4、死锁问题5、存储管理5.1 页式存储5.2 段式存储5.3 段页式存储5.4 页面置换算法 6、文件管理6.1 索引文件结构6.2 空闲存储空间管理 7、设备管理7.1数据传输控制7.2 虚设备和SPOOLING技术7.3 微内核操作系统7.4 嵌入式操作系统 说明&a…

LeetCode-32. 最长有效括号【栈 字符串 动态规划】

LeetCode-32. 最长有效括号【栈 字符串 动态规划】 题目描述&#xff1a;解题思路一&#xff1a;辅助栈解题思路二&#xff1a;动态规划解题思路三&#xff1a;0 题目描述&#xff1a; 给你一个只包含 ‘(’ 和 ‘)’ 的字符串&#xff0c;找出最长有效&#xff08;格式正确且…

「51媒体-邀约媒体」活动发布会新闻通稿如何写?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 撰写活动发布会的新闻通稿需要遵循一定的结构和内容要点&#xff0c;以确保信息的准确性、完整性和吸引力。以下是撰写活动发布会新闻通稿的基本步骤和建议&#xff1a; 标题&#xff1…

初识 QT

初始QT 什么是QTQT发展史QT支持的平台QT的优点QT的应用场景搭建QT开发环境QT的开发工具概述QT下载安装 使用QT创建项目QT 实现Hello World程序使用按钮控件来实现使用标签控件来实现 项目文件解析widget.hmain.cppwidget.cppwidget.ui.pro文件 对象树QT 窗口坐标体系 什么是QT …

python linux服务器ssh简单爆破(测试用户名密码)(连接ssh服务器)(测试登录ssh服务器)

文章目录 背景示例代码代码解释导入模块SSH服务器的地址和端口用户名和密码列表生成所有可能的用户名和密码组合尝试连接到SSH服务器并验证用户名和密码遍历并测试每一对凭证 背景 我们华为摄像头linux终端的密码忘了&#xff0c;还不太好初始化&#xff0c;手动一个个测试太麻…

【QingHub】EMQX单节点一键部署

EMQX 简介 EMQX是全球最具扩展性的开源MQTT 代理&#xff0c;具有高性能&#xff0c;可在 1 个集群中连接 1 亿多个 IoT 设备&#xff0c;同时保持每秒 100 万条消息的吞吐量和亚毫秒级的延迟。 EMQX 支持MQTT、HTTP、QUIC、WebSocket等多种开放标准协议。它 100% 符合MQTT 5.…

ChatGPT深度科研应用、数据分析及机器学习、AI绘图与高效论文撰写

2022年11月30日&#xff0c;可能将成为一个改变人类历史的日子——美国人工智能开发机构OpenAI推出了聊天机器人ChatGPT3.5&#xff0c;将人工智能的发展推向了一个新的高度。2023年4月&#xff0c;更强版本的ChatGPT4.0上线&#xff0c;文本、语音、图像等多模态交互方式使其在…

基于Springboot+Vue的Java项目-在线视频教育平台系统(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

Flutter视图渲染过程三棵树------Widget、Element、RenderObject介绍

Widget widget存储视图的配置信息&#xff0c;没有状态所以是不可变的&#xff0c;每个绘制周期&#xff08;帧率&#xff09;&#xff0c;widget都不会刷新&#xff0c;而是会被重建。 StatelessWidget和StatefulWidget - - - 怎样判断是需要更新element&#xff0c;还是替换…

使用 Python 标记具有相同名称的条目

如果大家想在 Python 中标记具有相同名称的条目&#xff0c;可以使用字典&#xff08;Dictionary&#xff09;或集合&#xff08;Set&#xff09;来实现。这取决于你们希望如何存储和使用这些条目。下面我将提供两种常见的方法来实现这个目标。 1、问题背景 在处理数据时&…

C++进阶编程 --- 5.STL常用算法

文章目录 第五章&#xff1a;5.STL 常用算法5.1 遍历算法5.1.1 for_each5.1.2 transform 5.2 查找算法5.2.1 find内置数据类型自定义数据类型 5.2.2 find_if内置数据类型自定义数据类型 5.2.3 adjacent_find5.2.4 binary_search5.2.5 count内置数据类型自定义数据类型 5.2.6 co…

sed命令多行处理

1. sed 如何工作的 sed 维护两个空间&#xff1a; 模式空间保留空间 sed是以行为周期来处理文本的。 sed从输入流中读取一行&#xff0c;去掉最后的换行符&#xff0c;把它放入模式空间。随后执行命令&#xff0c;每个命令都有关联的地址和条件&#xff0c;只有匹配时才执行…

电脑端微信截图文字识别功能效率更高了

近期发现微信中的截图文字识别比QQ中的截图文字识别效率高更高&#xff0c;效果更好。 使用方法&#xff1a; 安装电脑端微信客户端&#xff1a;https://weixin.qq.com/(如果没有下载&#xff0c;可以安装一下) 默认截图组合快捷键是&#xff1a;ALTA (使用下来感觉不是很顺手…

AI在运维实践中的价值提升

在2024年的AI赛道上&#xff0c;利用大数据 、机器学习算法、人工智能来改善运维效率已成为软件运营商发展的新主张&#xff0c;通过AI在运维流程的洞察、决策和执行&#xff0c;从而提升效率、减少故障时间&#xff0c;优化用户体验。通过分析大量数据来识别趋势和模式&#x…

【MATLAB】GA_ELM神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 1 基本定义 GA_ELM&#xff08;Genetic Algorithm and Extreme Learning Machine&#xff09;是一种结合了遗传算法和极限学习机的神经网络时序预测算法。它的核心思想是通过使用遗传算法来优化极限学习机的权重和偏差&…

Python网络爬虫中JSON格式数据存储详解

目录 一、引言 二、JSON格式数据简介 三、Python中处理JSON数据 四、网络爬虫中获取JSON数据 五、存储JSON数据到文件 六、从文件中读取JSON数据 七、注意事项和常见问题 八、总结 一、引言 在网络爬虫的应用中&#xff0c;JSON格式数据以其轻量级、易读易写的…

element UI 设置type=“textarea“ 禁止输入框缩放

背景 在 Element UI 中&#xff0c;当您使用 el-input 组件并设置 type"textarea" 时&#xff0c;默认情况下&#xff0c;用户可以通过拖动输入框的右下角来调整其大小。如果您想禁止这种缩放行为&#xff0c;需要使用 CSS 来覆盖默认的浏览器行为。 注意上图&#x…

用于显著提高检索速度和降低成本的二进制和标量嵌入量化

我们引入了嵌入量化的概念&#xff0c;并展示了它们对检索速度、内存使用、磁盘空间和成本的影响。我们将讨论理论上和实践中如何对嵌入进行量化&#xff0c;然后介绍一个 演示&#xff0c;展示了 4100 万维基百科文本的真实检索场景。 演示地址https://hf.co/spaces/sentence-…

说说你对栈、队列的理解?应用场景?

一、栈 栈&#xff08;stack&#xff09;又名堆栈&#xff0c;它是一种运算受限的线性表&#xff0c;限定仅在表尾进行插入和删除操作的线性表 表尾这一端被称为栈顶&#xff0c;相反地另一端被称为栈底&#xff0c;向栈顶插入元素被称为进栈、入栈、压栈&#xff0c;从栈顶删…