请教几个关于视频帧渲染的问题

  • Creator 版本:3.6.0

  • 目标平台:Android + iOS + macOS + Windows

我正在开发一个 Native 全平台 C++ SDK (一个 RTC 实时音视频 SDK ) 的 Cocos Creator TypeScript 封装层插件,利用 原生插件功能sebind 进行插件开发;目前已经跑通了 TypeScript <-> C++ SDK 的接口调用和回调。

现在遇到关于视频渲染的问题:

C++ Native 侧有视频帧数据回调(本地摄像头预览画面、远端用户推流的实时音视频画面、媒体播放器播放的视频画面等等)

回调的视频帧数据是内存裸数据( BGRA32 / RGBA32 / NV12 / NV21 / I420 / … )。

如何把视频帧数据渲染到 Cocos Creator 的游戏场景上?

调研了一下,可能的方式是获取 Cocos Sprite 精灵对象的 Texture2D 的 OpenGL 纹理 ID,
将此纹理 ID 传递到 Native 侧,通过 glTexImage2D 把内存裸数据转成纹理,
并绑定到此 Sprite 对象的纹理 ID 上。

找到了个 v2.4 版本的实现,但好像部分 API 在 v3.6 上没有了

var AgoraVideoRender = cc.Class({
    extends: cc.Component,
    properties: {
        sprite: {
            default: null,
            type: cc.Sprite
        },
        uid: 0
    },
    onLoad() {
        this.texture = new cc.Texture2D();
        // Cocos Creator v3.6.0 没有 initWithData() API
        this.texture.initWithData(null, cc.Texture2D.PixelFormat.RGBA8888, this.node.width, this.node.height);
        this.sprite.spriteFrame = new cc.SpriteFrame(this.texture);
    },
    _updateSize() {
        this.texture.width = this.node.width;
        this.texture.height = this.node.height;
    },
    onEnable() {
        this.node.on('size-changed', this._updateSize, this)
    },
    onDisable() {
        this.node.off('size-changed', this._updateSize, this)
    },
    update(dt) {
        if (agora && agora.bridge && agora.bridge.bindTextureId) {
            // v3.6.0 没有 getImpl() API
            agora.bridge.bindTextureId(this.texture.getImpl().getHandle(), this.uid);
        }
    },
});

所以这里的问题是 v3.6.0 如何获取 Sprite 对象的 OpenGL 纹理 ID?

或者说,是否有其他更好的方案来实现视频帧数据在游戏场景中的渲染?

另外还有一个关于视频画面更新的驱动方式,不大清楚下面哪种方案是可行的:

  1. Sprite 自刷新回调并从 native 获取、绑定最新的视频帧;

    是否有这种回调?(比如屏幕刷新驱动回调?类似 iOS 的 CADisplayLink?)
    update(deltaTime: number) 能否满足这个需求?这个回调的触发时机是什么?

  2. 当 Native 侧数据有更新时主动更新 Sprite 的 texture

    可能需要 native 侧持有这个 Sprite 对象并修改这个对象的属性;
    是否能直接修改 Sprite 对象绑定的纹理 ID?

2赞

应该有2种方案来实现:(以GLES API来看)
1.引擎提供指定外部创建的纹理ID的接口,比如在cc.Texture2D开发类似接口
这样的话在Android平台,视频的解码播放,相机预览画面都可以实现了,如mediaplayer+surface+surfacetexture,external的纹理再通过fbo二次渲染到纹理ID。
2.引擎提供获取cc.Texture2D对应的底层纹理ID接口,将此ID用于自定义的渲染流程中,接收渲染内容。

自定义渲染的刷新可以通过脚本的update去触发,有了自定义渲染,引擎还需要开个接口刷新渲染状态,告知引擎外部更改了渲染状态。

可以参考这个示例:(虽然效率不是最高)
https://github.com/cocos/cocos-awesome-tech-solutions/tree/3.4.x3.5.x-release/demo/Creator3.5.1_2D_VideoTexture

裸数据直接yuv作为纹理传给shader,用shader来解yuv,减少中间转rgba的cpu损耗,音频这块有点麻烦,cocos目前的音频组件有点不够用,需要自己搞音画同步和音频播放器

刚才查阅了一下 cc.d.ts 里的 Texture2D 类,没找到 “指定外部创建的纹理 ID 的接口” 以及 “获取cc.Texture2D对应的底层纹理ID接口”

也就是说这两种方案在目前的版本 (v3.6) 都走不通? :joy:

老哥是zego的开发人员吗

我也在做类似的事情,已经把声网agroa在2.x的C++ SDK移植到了3.6的原生插件中,不过也卡在了渲染这一步,确实已经不能使用像2.x一样的做法了,不知道你找到解决办法没有

我打算如果目前无法找到比较合适的解决方案,就使用2.4或者2dx来实施新的项目,毕竟这两种已经验证过了,就是眼馋新版本的creator,已经花了几天时间想办法

是的呢哈哈,ZEGO 的 Cocos Creator SDK 已经发布了要不试试 :stuck_out_tongue_closed_eyes:

:joy:这事整的有点尴尬,我之前跟你们客服沟通,说是Creator还没有支持,然后移植声网到3.6原生插件失败之后,我就打算用2.4.10,接入你们Android和IOS的SDK,然后定制引擎做直播流渲染,现在项目开始十多天了

不过既然你们已经解决问题支持到3.6了,我现在把项目迁移到3.6也来得及,要是当时能知道你们马上就能支持就不用浪费那么多时间了 :rofl:

如果以后SDK有什么使用上的问题,这边可以直接找你沟通吗?

V3.7可以通过Texture2D的接口.getGFXTexture().getGLTextureHandle()拿到纹理ID

没问题呀 :sunglasses: 也可以在 GitHub 提 issue,项目是开源的: https://github.com/zegoim/zego_express_cocos_creator_sdk

:+1: 看起来不错,等3.7发布后试试

创建引擎,然后开始预览,几秒之后崩溃,没有画面出现

手机是 HUAWEI Mate 40 OCE-AN10

操作系统是 Harmony OS 3.0

之前有做过一个性能比较差的Agora Creator 3.X方案,就是利用JSB手动绑定把agora的数据从原生层传到TS层做渲染;
1.从原生层获取Agora 的视频帧数据,和帧的尺寸;


2.JSB 绑定实现TS层调用原生层;

3.TS层获取数据创建Sprite渲染;

这个方案只在demo上验证过,但没有在真实产品中使用,可靠性有限,仅是分享思路给有需要的人。

1赞

請問.getGFXTexture().getGLTextureHandle()可以在Android跟iOS上使用嗎?
我目前是用3.8.2,引擎源碼有在GLES2、GLES3的getGLTextureHandle有實做
在Android上可以拿到ID,正在嘗試在原生端渲染
但是iOS上呼叫getGLTextureHandle拿到的ID是0

我想知道如果是原生把每帧的buffer 以桥接形式传到给ts,然后用rendertexture写入buffer来渲染可行吗?性能如何呢?

那为什么不直接在原生展示出来,用TS控制展示和关闭

如果視頻在原生上展示的話,那表示畫面只能在遊戲的上層或是下層,產品設計上會有侷限
目前的需求是希望可以渲染到sprite上

我的意思是,数据交互就在C++层,因为原生的数据如果上传到TS处理了,最终又还是要由C++提交,可以考虑直接在C++层实现,避免频繁的交换数据

目前讓原生渲染遊戲內的的方案,我知道效能比較好的是把TextureID傳給原生,讓原生對渲染Buffer操作
但是現在獲取TextureID的方式似乎有問題,getGLTextureHandle不生效

cocos2dx上做过 h264裸流 使用ffmpeg解码 直接更新sprite纹理
延迟控制500毫米以内 性能还可以。 稳定运行好几年了 :grinning: 就是不支持h5 只有原生安卓 ios。 后面更新了win版本