基于webassembly的H265视频播放器前端Angular学习笔记4:使用wasm解码H265数据

本文基于开源项目decoder_wasm使用Angular开发的前端页面项目,对项目整理结构进行的改动,并使用Typescript重写大部分js源码,便于维护。
着重学习Angular框架下Worker,Wasm的使用,本人非前端开发从业人员,页面简陋请见谅。

使用wasm解码H265

创建组件与路由

创建组件

$ ng generate component DecoderTest --skipTests=true
CREATE src/app/decoder-test/decoder-test.component.scss (0 bytes)
CREATE src/app/decoder-test/decoder-test.component.html (27 bytes)
CREATE src/app/decoder-test/decoder-test.component.ts (299 bytes)
UPDATE src/app/app.module.ts (790 bytes)

设置路由

{ path: 'decoder', component: DecoderTestComponent },

获取H265数据

详见的之前篇笔记
基于webassembly的H265视频播放器前端Angular学习笔记2:创建Angular组件获取H265文件数据
拷贝代码相关逻辑到新的测试组件中

加载Wasm文件

详见的之前篇笔记
基于webassembly的H265视频播放器前端Angular学习笔记3:创建Angular组件中加载wasm文件
拷贝代码相关逻辑到新的测试组件中

设置wasm的加载回调函数

常量

const CHUNK_SIZE = 4096;
const DECODER_H264 = 0;
const DECODER_H265 = 1;
const LOG_LEVEL_JS = 0;
const LOG_LEVEL_WASM = 1;
const LOG_LEVEL_FFMPEG = 2;

添加成员变量

private isWasmLoaded = false;
private wasm = (window as any).Module as any;
private decoderType = DECODER_H265;
private decoderLogLevel = LOG_LEVEL_WASM;

构造函数中设置加载回调

  constructor() {
    this.wasm = typeof this.wasm !== 'undefined' ? this.wasm : {};
    this.wasm.onRuntimeInitialized = () => {
      this.isWasmLoaded = true;
      this.onWasmLoaded();
    };
  }

onRuntimeInitialized这个回调是emscripten编译后自动生成的,只需要赋值给window.Module.onRuntimeInitialized赋值一个回调函数,在wasm文件加载完成后就会调用。

设置解码器数据回调函数

添加两个成员变量

private videoSize = 0;  // 计数
private onWasmLoaded(): void {
    const callback = this.wasm.addFunction((addr_y, addr_u, addr_v, stride_y, stride_u, stride_v, width, height, pts) => {
      console.log('[%d]In video callback, size = %d * %d, pts = %d', ++this.videoSize, width, height, pts);
    });
    this.wasm._openDecoder(this.decoderType, callback, this.decoderLogLevel);
  }

_openDecoder是开启解码器的API接口

向解码器喂数据

修改笔记2中的reader.onload回调函数

reader.onload = (ev: ProgressEvent<FileReader>) => {
        const typedArray: Uint8Array = new Uint8Array(ev.target.result as ArrayBuffer);
        const size = typedArray.byteLength;

        let cacheBuffer = this.wasm._malloc(size);
        this.wasm.HEAPU8.set(typedArray, cacheBuffer);
        this.wasm._decodeData(cacheBuffer, size, this.pts++);
        if (cacheBuffer != null) {
          this.wasm._free(cacheBuffer);
          cacheBuffer = null;
        }
        if (size < CHUNK_SIZE) {
          console.log('Flush frame data');
          this.wasm._flushDecoder();
          this.wasm._closeDecoder();
        }
      };

_malloc与_free时emscripten自动生成的接口,用于开辟和释放内存。
_decodeData是添加要解码的数据的API接口
_flushDecoder是清空解码器的API接口
_closeDecoder是关闭解码器的API接口

测试结果

decoder_wasm中下载测试H265文件到你的电脑;
打开http://localhost:4200/decoder进行测试。

decoder-test.component.ts:33[1]In video callback, size = 1000 * 504, pts = 0
decoder-test.component.ts:33 [2]In video callback, size = 1000 * 504, pts = 1
decoder-test.component.ts:33 [3]In video callback, size = 1000 * 504, pts = 2
decoder-test.component.ts:33 [4]In video callback, size = 1000 * 504, pts = 3
decoder-test.component.ts:33 [5]In video callback, size = 1000 * 504, pts = 4
decoder-test.component.ts:33 [6]In video callback, size = 1000 * 504, pts = 5
decoder-test.component.ts:33 [7]In video callback, size = 1000 * 504, pts = 6
decoder-test.component.ts:33 [8]In video callback, size = 10wasm-worker-test00 * 504, pts = 7
decoder-test.component.ts:33 [9]In video callback, size = 1000 * 504, pts = 8
decoder-test.component.ts:33 [10]In video callback, size = 1000 * 504, pts = 9

可以看到控制台解码后的数据已经在回调中输出出来了。

emscripten编译

关于emscripten编译使用ffmpeg库C/C++代码,我计划另外抽时间写专题,此专题我只是记录我学习angular的笔记,暂时不介绍。

如果想自己用emscripten编译,遇到问题的话可以联系我,我们一起探讨。
decoder_wasm并没有工程化C代码,是单个C文件编译的。
其实可以使用cmake或makefile等工具把整个C工程编译成一个wasm文件。

微信号:yjkhtddx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值