H5 worker 系列三 webworkify处理音视频解码

H5 worker 系列一 基础知识提到过browserify/webworkify,原理可以参考WebWorker实战使用中,作者表示:

实际开发中我们不会把所有的代码都放在一个文件中让子线程加载,肯定会选择模块化开发。官方提供的方式是使用importScripts,但是这个在实际开发中很不实用,importScripts的加载方式是阻塞式的,所以我们最好用打包工具将所有worker中需要的文件打包成一个文件。这里我推荐browserify/webworkify,这是webpack的一个插件。对于webworkify-webpack的原理其实并没有使用importScripts而是使用另一种方式来创建worker,将js代码stringify后创建Blob对象,然后又createObjectURL创建对象url来实例化worker。类似如下过程:

image.png

我们在github上下载browserify/webworkify源码后,先运行一下npm i -D安装一下环境,然后browserify example/main.js -o bundle.js,就可以在index.html中使用bundle.js了,关于browserify,可以参考Browserify + watchify

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>browserify</title>
    <script src="bundle.js"></script>
</head>
<body>
</body>
</html>
一、官方的使用Example
//main.js
var work = require('../');

var w = work(require('./worker.js'));

var first = true;
w.addEventListener('message', function (ev) {
    if (first) {
        // revoke the Object URL that was used to 
        // create this worker, so as not to leak it
        URL.revokeObjectURL(w.objectURL);
        first = false;
    }
    console.log(ev.data);
});

w.postMessage(4); // send the worker a message

//worker.js
var gamma = require('gamma');

module.exports = function (self) {
    self.addEventListener('message',function (ev){
         // ev.data=4 from main.js
        var startNum = parseInt(ev.data);
        
        setInterval(function () {
            var r = startNum / Math.random() - 1;
            self.postMessage([ startNum, r, gamma(r) ]);
        }, 500);
    });
};

二、hls.js demuxer.js的使用
hls.js 源码解读【3】中提到

import work from 'webworkify-webpack';
if (config.enableWorker && (typeof (Worker) !== 'undefined')) {
    logger.log('demuxing in webworker');
    let w;
    try {
        w = this.w = work(require.resolve('../demux/demuxer-worker.js'));
        this.onwmsg = this.onWorkerMessage.bind(this);
        w.addEventListener('message', this.onwmsg);
        w.onerror = function (event) {
            hls.trigger(Event.ERROR, {
                type: ErrorTypes.OTHER_ERROR,
                details: ErrorDetails.INTERNAL_EXCEPTION,
                fatal: true,
                event: 'demuxerWorker',
                err: {
                    message: event.message +
                    ' (' + event.filename + ':' + event.lineno + ')'
                }
            });
        };
        w.postMessage({
            cmd: 'init',
            typeSupported: typeSupported,
            vendor: vendor,
            id: id,
            config: JSON.stringify(config)
        });
    } catch (err) {
        logger.error('error while initializing DemuxerWorker' +
            ', fallback on DemuxerInline');
        if (w) {
            // revoke the Object URL that was used to create 
            //demuxer worker, so as not to leak it
            URL.revokeObjectURL(w.objectURL);
        }
        this.demuxer = new DemuxerInline(observer, typeSupported, config, vendor);
        this.w = undefined;
    }
} else {
    this.demuxer = new DemuxerInline(observer, typeSupported, config, vendor);
}

onWorkerMessage(ev) {
    let data = ev.data,
    hls = this.hls;
    //console.log('onWorkerMessage:' + data.event);
    ...
}

关于require.resolve:

// 用法
require.resolve('a.js')
// 返回 /home/ruanyf/tmp/a.js

简单的说,在 Node.js 中使用 fs 读取文件的时候,经常碰到要拼一个文件的绝对路径的问题 (fs 处理相对路径均以进程执行目录为准)。之前一直的方法都是,使用 path 模块以及 __dirname 变量 。代码如下所示:fs.readFileSync(path.join(__dirname, './assets/some-file.txt'));使用 require.resolve 可以简化这一过程fs.readFileSync(require.resolve('./assets/some-file.txt'));此外, require.resolve 还会在拼接好路径之后检查该路径是否存在, 如果 resolve 的目标路径不存在, 就会抛出 Cannot find module './some-file.txt'的异常. 省略了一道检查文件是否存在的工序 (fs.exists).这个报错并不会加重你的检查负担, 毕竟使用 fs 去操作文件时, 如果发现文件不存在也会抛出异常. 反之, 通过 require.resovle 可以在提前在文件中作为常量定义, 那么在应用启动时就可以抛异常, 而不是等到具体操作文件的时候才抛异常.

三、flv.js

在transmuxer.js中能看到类似的写法

import TransmuxingWorker from './transmuxing-worker.js';
...
if (config.enableWorker && typeof (Worker) !== 'undefined') {
    try {
        let work = require('webworkify');
        this._worker = work(TransmuxingWorker);
        this._workerDestroying = false;
        this._worker.addEventListener('message',
            this._onWorkerMessage.bind(this));
        this._worker.postMessage({
            cmd: 'init',
            param: [mediaDataSource, config]
        });
        this.e = {
            onLoggingConfigChanged:
            this._onLoggingConfigChanged.bind(this)
        };
        LoggingControl.registerListener(this.e.onLoggingConfigChanged);
        this._worker.postMessage({
            cmd: 'logging_config',
            param: LoggingControl.getConfig()
        });
    } catch (error) {
        Log.e(this.TAG, 'Error while initialize transmuxing worker' +
            ', fallback to inline transmuxing');
        this._worker = null;
        this._controller = new TransmuxingController(mediaDataSource, config);
    }
} else {
    this._controller = new TransmuxingController(mediaDataSource, config);
}

destroy() {
    if (this._worker) {
        if (!this._workerDestroying) {
            this._workerDestroying = true;
            this._worker.postMessage({ cmd: 'destroy' });
            LoggingControl.removeListener(
                this.e.onLoggingConfigChanged);
            this.e = null;
        }
    } else {
        this._controller.destroy();
        this._controller = null;
    }
    this._emitter.removeAllListeners();
    this._emitter = null;
}

然后就是transmuxing-worker.js里面各种通讯

/* post message to worker:
   data: {
       cmd: string
       param: any
   }

   receive message from worker:
   data: {
       msg: string,
       data: any
   }
 */
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容