# NativeImageDemo
**Repository Path**: scenario-samples/native-image-demo
## Basic Information
- **Project Name**: NativeImageDemo
- **Description**: 【鸿蒙 Harmony Next 示例 代码】本示例基于OpenGL渲染实现Lut滤镜相机场景
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 4
- **Forks**: 1
- **Created**: 2025-03-28
- **Last Updated**: 2025-09-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 基于OpenGL渲染实现Lut滤镜相机
### 介绍
C++侧录制渲染,ArkTs侧UI展示和接口功能
1. 预览:NDKCamera()
2. 渲染:RenderThread()
3. 取帧:glReadPixels()
### 效果预览

### 约束限制
1. 本示例仅支持标准系统上运行,支持设备:华为手机。
2. HarmonyOS系统:HarmonyOS NEXT Release及以上。
3. DevEco Studio版本:DevEco Studio 5.0.0 Release及以上。
4. HarmonyOS SDK版本:HarmonyOS 5.0.0 Release SDK及以上。
### 使用说明
1. 预览:相机、设备、渲染器、管理器、窗口、初始化并开启
2. 渲染:渲染线程进入渲染主循环,额外线程开启lut上传、任务信号、绑定纹理、输出滤镜
3. 录制:渲染线程进入渲染主循环,录制线程进入录制循环
4. 拍照:渲染线程进入渲染主循环,额外线程开启帧输出
5. 保存:photoAccessHelper保存,SaveButton获取权限
### 权限申请
1. ohos.permission.CAMERA
### 实现思路
1. 初始化:
1) 获取环境XComponent对象和id,绑定nativeXComponent、render,注册回调,暴露接口
2. 预览程序主流程:
1) 获取render实例,渲染线程获取到nativeImageSurfaceid后,相机配置初始化并开启预览流
3. 渲染程序主流程:
1) 渲染线程初始化开启进入渲染主循环,初始化eglcontext、垂直同步、帧画面nativeimage生成并监听,根据条件封锁等待唤醒信号,主线程继续执行,nativexcomponent注册回调,回调自动获取window,window初始化eglsurface,eglsurface关联eglcontext,可获取eglsurfaceid,eglcontext配置egl渲染程序、矩阵
4. 录制程序主流程:
1) 获取render实例,配置视频格式,创建编码Surface,开始录制,进入录制主循环
5. 获取渲染帧图像:
1) glReadPixels获取帧数据
2) 线程间获取图片先后顺序:渲染获取图片顺序后于执行任务顺序,导致当前任务无法获得当前渲染图,需要设置条件锁(线程和锁解决当前图片为最新获取图片)
3) 图片数据、宽高可以获取到,但传回arkts侧一直接收不到(去除解码再编码步骤,image.createPixelMap直接把arraybufer转pixelmap解决)
4) 图像上下颠倒、重复多次、花屏(数据上下倒转解决)
5) 图片能正常获取到,渲染颜色混乱,滤镜之外带有额外滤镜颜色偏蓝紫(rb通道互换解决)
6) 图片右侧部分空白,图片宽高倒转(原为屏幕宽高,录制宽高对调为录制高宽解决)
### 参考项目
1. 预览渲染支持算法:https://gitee.com/scenario-samples/open-gl
2. 视频录制和播放:https://gitee.com/harmonyos_samples/AVCodecVideo
3. 安卓lut滤镜文件转换纹理途径:https://blog.csdn.net/wangyantaozzu/article/details/103768611
4. LUT滤镜算法解析:https://blog.csdn.net/katherine_qj/article/details/112666379
5. 图片(lut)数据加载纹理:https://blog.csdn.net/s12117719679/article/details/144869409
6. 图像加载器:https://blog.csdn.net/github_27263697/article/details/143647456
### 工程结构
```
├─entry/src/main/cpp
│ ├─camera
│ │ ├─ndk_camera.cpp // 相机功能页
│ │ └─ndk_camera.h
│ ├─capbilities
│ │ ├─include
│ │ │ ├─demuxer.h
│ │ │ ├─muxer.h
│ │ │ ├─video_decoder.h
│ │ │ └─video_encoder.h
│ │ ├─demuxer.cpp // 解复用器功能页
│ │ ├─muxer.cpp // 复用器功能页
│ │ ├─video_decoder.cpp // 解码功能页
│ │ └─video_encoder.cpp // 编码功能页
│ ├─common
│ │ ├─dfx
│ │ │ ├─error
│ │ │ │ └─av_codec_sample_error.h // 错误页
│ │ │ └─log
│ │ │ └─av_codec_sample_log.h // 日志页
│ │ ├─common.h // 作用域配置页
│ │ ├─sample_callback.cpp // 回调功能页
│ │ ├─sample_callback.h
│ │ └─sample_info.h // 回调信息页
│ ├─manager
│ │ ├─plugin_manager.cpp // 管理器功能页
│ │ └─plugin_manager.h
│ ├─render
│ │ ├─egl_render_context.cpp // 渲染内容页
│ │ ├─egl_render_context.h
│ │ ├─plugin_render.cpp // 渲染器功能页
│ │ ├─plugin_render.h
│ │ ├─render_thread.cpp // 渲染线程功能页
│ │ ├─render_thread.h
│ │ ├─shader_program.cpp // 渲染程序功能页
│ │ └─shader_program.h
│ ├─sample
│ │ ├─player
│ │ │ ├─Player.cpp // 播放功能页
│ │ │ └─Player.h
│ │ └─recorder
│ │ ├─Recorder.cpp // 录制功能页
│ │ └─Recorder.h
│ ├─types
│ │ └─libentry
│ │ ├─index.d.ets
│ │ └─oh-package.json5 // 依赖配置页
│ ├─CMakeLists.txt // 构建配置页
│ └─main.cpp // 接口配置页
│
├─entry/src/main/ets
│ ├─common
│ │ ├─Constants.ets // 常量页
│ │ └─DisplayCalculator.ets // 设备页
│ ├─components
│ │ └─KComponentView.ets // 功能页
│ ├─entryability
│ │ └─EntryAbility.ets // 启动页
│ ├─interface
│ │ └─XComponentContext.ets // 接口页
│ └─pages
│ └─Index.ets // 主页
├─entry/src/main
│ └─module.json5 // 模块权限配置信息
```
### 项目依赖
无
### ChangeLog
1. 修改内容(时间):初始版本(2025.3.19)
2. 修改内容(时间):大小写和方法规范,使用安全控件,参考项目和实现思路拆分和完善(2025.3.24)
3. 内存释放、闪退、异常相关:
1)闪退:lut滤镜上传渲染两分钟左右程序崩溃,删除每次新生成纹理ID:GLuint texture,更换为固定纹理ID:glGenTextures(1, &lutTexId_),更改后渲染五分钟程序未出现崩溃(25.4.1)
2)内存释放:arkts侧new对象,初始化创建对象只生成一次,方法调用创建对象,正常情况下,当前对象需要使用,之前对象会失去引用被垃圾回收
3)内存释放:native侧new对象,初始化创建对象,实例绑定id,根据id增删改查实例,线程循环内创建对象同初始化创建对象一致,创建唯一变量绑定,避免循环生成速度大于垃圾回收速度造成崩溃
4)空指针异常:DestroyEglSurface新增判断条件,避免多线程前销毁后空指针异常
5)拍照卡顿:耗时操作阻塞渲染线程,考虑主线程继续渲染帧画面,耗时操作移交任务线程处理即arkts端传来取帧信号的此任务线程,数据最后获取到返回arkts侧及后续操作(25.5.22)
## 一份简单的问卷反馈
亲爱的Harmony Next开发者,您好!
为了协助您高效开发,提高鸿蒙场景化示例的质量,希望您在浏览或使用后抽空填写一份简单的问卷,我们将会收集您的宝贵意见进行优化:heart:
[:arrow_right: **点击此处填写问卷** ](https://wj.qq.com/s2/19042938/95ab/)