不使用video播放mp4

import { _decorator, Component, Node, Sprite, Texture2D, view, SpriteFrame, UITransform } from 'cc';

const { ccclass, property } = _decorator;

@ccclass('WebVideo')

export class WebVideo extends Component {

private cameraNode: Node = null;

private videoStream: MediaStream = null;

private videoTexture: Texture2D = null;

private canvas: HTMLCanvasElement = null;

private context: CanvasRenderingContext2D = null;

private video: HTMLVideoElement = null;

update(deltaTime: number) {

if (this.video && this.videoTexture && this.context) {

try {

this.context.drawImage(this.video, 0, 0, this.canvas.width, this.canvas.height);

this.videoTexture.uploadData(this.canvas);

} catch (error) {

console.error("Error updating videoTexture:", error);

}

}

}

public showCamera() {

this.cameraNode = new Node();

this.node.insertChild(this.cameraNode, 0);

this.startVideoStream();

}

private async startVideoStream() {

try {

this.videoStream = await navigator.mediaDevices.getUserMedia({ video: true });

this.setupVideoElement();

this.setupCanvas();

this.setupVideoTexture();

} catch (err) {

console.error("Error accessing media devices.", err);

}

}

private setupVideoElement() {

this.video = document.createElement('video');

this.video.srcObject = this.videoStream;

this.video.play();

this.video.onloadedmetadata = () => {

this.video.width = this.video.videoWidth;

this.video.height = this.video.videoHeight;

};

}

private setupCanvas() {

this.canvas = document.createElement('canvas');

this.context = this.canvas.getContext('2d');

document.body.appendChild(this.canvas);

this.canvas.style.display = 'none';

const videoTrack = this.videoStream.getVideoTracks()0;

const videoSettings = videoTrack.getSettings();

this.canvas.width = videoSettings.width;

this.canvas.height = videoSettings.height;

}

private setupVideoTexture() {

this.videoTexture = new Texture2D();

this.videoTexture.reset({

width: this.canvas.width,

height: this.canvas.height,

format: Texture2D.PixelFormat.RGBA8888

});

const sprite = this.cameraNode.addComponent(Sprite);

const spriteFrame = new SpriteFrame();

spriteFrame.texture = this.videoTexture;

sprite.spriteFrame = spriteFrame;

const visibleSize = view.getVisibleSize();

const uiTransform = this.cameraNode.getComponent(UITransform);

uiTransform.setContentSize(visibleSize.width, (this.canvas.height / this.canvas.width) * visibleSize.width);

console.log("UITransform size set to:", visibleSize.width, (this.canvas.height / this.canvas.width) * visibleSize.width);

}

public cleanup() {

if (this.cameraNode) {

this.cameraNode.destroy();

this.cameraNode = null;

}

if (this.videoTexture) {

this.videoTexture.destroy();

this.videoTexture = null;

}

if (this.videoStream) {

this.videoStream.getTracks().forEach(track => track.stop());

this.videoStream = null;

}

if (this.canvas) {

document.body.removeChild(this.canvas);

this.canvas = null;

this.context = null;

}

if (this.video) {

this.video.pause();

this.video.srcObject = null;

this.video = null;

}

}

}

下面我解释一下代码

这段代码实现了一个在Cocos Creator中使用Web视频流的组件`WebVideo`。该组件允许通过摄像头获取视频流并将其显示在Cocos Creator的场景中。下面是对这段代码的详细解释:

导入和装饰器

```typescript

import { _decorator, Component, Node, Sprite, Texture2D, view, SpriteFrame, UITransform } from 'cc';

const { ccclass, property } = _decorator;

```

  • 这部分代码导入了Cocos Creator框架中的一些模块,如`Component`, `Node`, `Sprite`, `Texture2D`, `view`, `SpriteFrame`和`UITransform`。

  • `_decorator`模块用于定义Cocos Creator的类装饰器,如`ccclass`和`property`。

类定义

```typescript

@ccclass('WebVideo')

export class WebVideo extends Component {

private cameraNode: Node = null;

private videoStream: MediaStream = null;

private videoTexture: Texture2D = null;

private canvas: HTMLCanvasElement = null;

private context: CanvasRenderingContext2D = null;

private video: HTMLVideoElement = null;

```

  • `WebVideo`类继承自Cocos Creator的`Component`类。

  • 定义了一些私有变量:`cameraNode`, `videoStream`, `videoTexture`, `canvas`, `context`, 和 `video`,用于管理视频流和显示。

更新方法

```typescript

update(deltaTime: number) {

if (this.video && this.videoTexture && this.context) {

try {

this.context.drawImage(this.video, 0, 0, this.canvas.width, this.canvas.height);

this.videoTexture.uploadData(this.canvas);

} catch (error) {

console.error("Error updating videoTexture:", error);

}

}

}

```

  • `update`方法在每帧调用,用于将视频帧绘制到canvas上,并将canvas的数据上传到`videoTexture`。

  • 通过`drawImage`将视频帧绘制到canvas,再通过`uploadData`上传到纹理。

显示摄像头方法

```typescript

public showCamera() {

this.cameraNode = new Node();

this.node.insertChild(this.cameraNode, 0);

this.startVideoStream();

}

```

  • `showCamera`方法创建一个新的`Node`作为`cameraNode`,并调用`startVideoStream`方法开始视频流。

开始视频流方法

```typescript

private async startVideoStream() {

try {

this.videoStream = await navigator.mediaDevices.getUserMedia({ video: true });

this.setupVideoElement();

this.setupCanvas();

this.setupVideoTexture();

} catch (err) {

console.error("Error accessing media devices.", err);

}

}

```

  • `startVideoStream`方法异步获取视频流,并调用三个方法来设置视频元素、canvas和视频纹理。

设置视频元素

```typescript

private setupVideoElement() {

this.video = document.createElement('video');

this.video.srcObject = this.videoStream;

this.video.play();

this.video.onloadedmetadata = () => {

this.video.width = this.video.videoWidth;

this.video.height = this.video.videoHeight;

};

}

```

  • `setupVideoElement`方法创建一个HTML视频元素,并将视频流设置为视频源。

  • 当视频元数据加载完成时,设置视频的宽度和高度。

设置Canvas

```typescript

private setupCanvas() {

this.canvas = document.createElement('canvas');

this.context = this.canvas.getContext('2d');

document.body.appendChild(this.canvas);

this.canvas.style.display = 'none';

const videoTrack = this.videoStream.getVideoTracks()0;

const videoSettings = videoTrack.getSettings();

this.canvas.width = videoSettings.width;

this.canvas.height = videoSettings.height;

}

```

  • `setupCanvas`方法创建一个隐藏的canvas元素,用于绘制视频帧。

  • 设置canvas的大小与视频流的大小相同。

设置视频纹理

```typescript

private setupVideoTexture() {

this.videoTexture = new Texture2D();

this.videoTexture.reset({

width: this.canvas.width,

height: this.canvas.height,

format: Texture2D.PixelFormat.RGBA8888

});

const sprite = this.cameraNode.addComponent(Sprite);

const spriteFrame = new SpriteFrame();

spriteFrame.texture = this.videoTexture;

sprite.spriteFrame = spriteFrame;

const visibleSize = view.getVisibleSize();

const uiTransform = this.cameraNode.getComponent(UITransform);

uiTransform.setContentSize(visibleSize.width, (this.canvas.height / this.canvas.width) * visibleSize.width);

console.log("UITransform size set to:", visibleSize.width, (this.canvas.height / this.canvas.width) * visibleSize.width);

}

```

  • `setupVideoTexture`方法创建一个新的`Texture2D`对象并重置它的大小和格式。

  • 创建一个新的`Sprite`组件并将其`spriteFrame`设置为视频纹理。

  • 设置`cameraNode`的大小以匹配屏幕的可见大小,并保持视频的宽高比。

清理方法

```typescript

public cleanup() {

if (this.cameraNode) {

this.cameraNode.destroy();

this.cameraNode = null;

}

if (this.videoTexture) {

this.videoTexture.destroy();

this.videoTexture = null;

}

if (this.videoStream) {

this.videoStream.getTracks().forEach(track => track.stop());

this.videoStream = null;

}

if (this.canvas) {

document.body.removeChild(this.canvas);

this.canvas = null;

this.context = null;

}

if (this.video) {

this.video.pause();

this.video.srcObject = null;

this.video = null;

}

}

}

```

  • `cleanup`方法销毁所有创建的节点、纹理和元素,停止视频流,并清理资源。

欢迎大家来玩我的抖音小游戏

相关推荐
2501_947575803 小时前
计算机毕业设计之jsp开山车行二手车交易系统
java·开发语言·hadoop·python·信息可视化·django·课程设计
骑士雄师3 小时前
java面试题 4:鉴权
java·开发语言
KaMeidebaby4 小时前
卡梅德生物技术快报|蛋白 N 端测序在重组贻贝融合蛋白表征中的应用,解决原核表达序列偏移工艺难题
前端·人工智能·物联网·算法·百度
时间的拾荒人4 小时前
C语言字符函数与字符串函数完全指南
c语言·开发语言
2501_948106914 小时前
计算机毕业设计之基于jsp教科研信息共享系统
java·开发语言·信息可视化·spark·课程设计
kyriewen5 小时前
我筛了 1400 个 Claude Code Skills,留下 5 个天天在用的
前端·ai编程·claude
取经蜗牛5 小时前
Python 第一阶段完全指南:从零到第一个实用工具
开发语言·python
JNX_SEMI5 小时前
AT2401C 2.4GHz 全集成射频前端单芯片技术解析
前端·单片机·嵌入式硬件·物联网·硬件工程
anOnion5 小时前
Agentic 前端开发之 实时显示 AI Agent 终端输出
前端·javascript·人工智能
dog2505 小时前
从重尾到截断流量模型的演进
开发语言·php