{"_id":"wasmvideoplayer","_rev":"6-89e0810804aa77160f36bfe318aa48f2","time":{"1.0.0":"2020-02-19T11:17:08.784Z","created":"2020-02-21T02:13:33.591Z","0.1.0":"2020-02-21T02:13:33.741Z","modified":"2022-05-24T01:47:15.988Z","0.2.0":"2020-02-26T04:11:53.947Z","0.3.0":"2020-02-28T04:02:10.281Z","0.4.0":"2020-03-02T14:18:46.049Z"},"name":"wasmvideoplayer","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"wasmvideoplayer","version":"0.1.0","description":"@[TOC](基于WASM的H265 Web播放器) # 1 背景 目前这个时间点，原生支持H265(HEVC)播放的浏览器极少，可以说基本没有，主要原因一个是H265的解码有更高的性能要求，从而换取更高的压缩率，目前大多数机器CPU软解H265的超清视频还是有点吃力，硬解兼容性又不好，另外一个原因主要是H265的专利费问题。因此H265有被各大浏览器厂商放弃的趋势，转而去支持更加开放的AV1编码，但是AV1编码的商用和普及估计还有段时间。","main":"player.js","scripts":{"debug":"http-server","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/sonysuqin/WasmVideoPlayer.git"},"author":"","license":"GPL-3.0","bugs":{"url":"https://github.com/sonysuqin/WasmVideoPlayer/issues"},"homepage":"https://github.com/sonysuqin/WasmVideoPlayer#readme","dependencies":{},"gitHead":"fce26abc8b66859dc6633e0ae1f6036e431af527","_id":"wasmvideoplayer@0.1.0","_nodeVersion":"12.13.1","_npmVersion":"6.12.1","dist":{"integrity":"sha512-h021ht5XQ0t0pw042gZA8uH2sES1jRyCPl9PxlkXXcFbnclDhPhb+TPSavwFMgz6Jswu557SRIBPw+p14luanw==","shasum":"6dd0b6416993b5a47a647c44d06bd6db6f818f93","tarball":"https://registry.npmjs.org/wasmvideoplayer/-/wasmvideoplayer-0.1.0.tgz","fileCount":138,"unpackedSize":9147091,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeTzzOCRA9TVsSAnZWagAAk2oQAJalKX4vM5ShWC+MkeCi\nJZzm2XvNy5agBJDCuDNAxEJCo/IEMJqhlSIuFrPdYIrgA4RVpj4TOxqBVctv\nXF3Qgajr2gjsdemSOum+S8U3gDP7j9Bewyh5QSPf3tTADD2aUr/As9P+h4jC\nyx91fhOAcDtG8KEdQzb5jY+7wb6UUYayvtSARZyKfpI4OEmPzSmAKPCOTyJT\nkmJqkdIqeCnWHHZoidRqUU4GJr7hjZcBaGWnvnkWdIjnIovavPGQ7/6oorym\nLRiYMifu5h0MJCJ5DyMLemMYjIBJKLvGaLfiHJjtD/d+zdynBgvxWQ2RiGDE\nUoc+KyM6CPJdWmjpQvt3wQgUvEJp3YW+A/oUnaW81WGndoxAQHlE2a+f/WDc\n5KVs5WbCJLOvQKjwRZVWVWLFWqPtHWk3jnrwUtzLwZaZBnclIBHv+yx2AVDX\nytRE3b7ERyGBr1kJkww6VkX0SCLq9USjG7zuzo9qGBYC8NKCnm59tEZhipAe\nswB3zSDkYQ5GvKliVMNEdudo52XktFzVFd6Rs5pGBfWVkssPby6tWk1Lnnst\n1pxAu4oUtakE1UjzNCw0BXVt1GrjlzHwUcstG/dg7xZXXrB94SQI2VRry/AK\n2VxgiC8km/GIBJljhIkm9vMfgJ7QBDSiVq3hF42bE5aXwhOA9WuINxKDYc05\n+EQQ\r\n=NIIp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDtim09zrqC6DdseobKUnAlxiaRvtjk2vjnOJuHtcXzrAiEA00yk0h5Oj1aL5Vt6G3UJkiNKVnbaiYIgdnCtiRwNbNA="}]},"maintainers":[{"name":"snadn","email":"snadn@snadn.cn"}],"_npmUser":{"name":"snadn","email":"snadn@snadn.cn"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/wasmvideoplayer_0.1.0_1582251213592_0.9913311564476683"},"_hasShrinkwrap":false},"0.2.0":{"name":"wasmvideoplayer","version":"0.2.0","description":"@[TOC](基于WASM的H265 Web播放器) # 1 背景 目前这个时间点，原生支持H265(HEVC)播放的浏览器极少，可以说基本没有，主要原因一个是H265的解码有更高的性能要求，从而换取更高的压缩率，目前大多数机器CPU软解H265的超清视频还是有点吃力，硬解兼容性又不好，另外一个原因主要是H265的专利费问题。因此H265有被各大浏览器厂商放弃的趋势，转而去支持更加开放的AV1编码，但是AV1编码的商用和普及估计还有段时间。","main":"player.js","scripts":{"dev":"http-server","test":"rm -rf test/dist && webpack --config test/webpack.config.js --cache=false"},"repository":{"type":"git","url":"git+https://github.com/sonysuqin/WasmVideoPlayer.git"},"author":"","license":"GPL-3.0","bugs":{"url":"https://github.com/sonysuqin/WasmVideoPlayer/issues"},"homepage":"https://github.com/sonysuqin/WasmVideoPlayer#readme","dependencies":{},"devDependencies":{"@babel/core":"^7.8.4","babel-loader":"^8.0.6","file-loader":"^5.1.0","string-replace-loader":"^2.2.0","webpack":"^4.41.6","webpack-cli":"^3.3.11","worker-loader":"^2.0.0"},"gitHead":"4a9f3ec1985f4af0ca170fd583929a6505d24485","_id":"wasmvideoplayer@0.2.0","_nodeVersion":"12.13.1","_npmVersion":"6.12.1","dist":{"integrity":"sha512-6tQmTsdo6t0ayTdXC4je4T46Wf2a5Db3G3d58lPRzmKfjxMo580jhMYfZHC5ycXJexp+Kx6V1aQK4pbqLErzEw==","shasum":"a21110d9422baf10ef633ddee7513e698e0195ee","tarball":"https://registry.npmjs.org/wasmvideoplayer/-/wasmvideoplayer-0.2.0.tgz","fileCount":139,"unpackedSize":9150017,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeVfAKCRA9TVsSAnZWagAAFeIP/i/NfxzbTq6kbUVi93I6\ne9qcB8+NDQlRbKl22nw6cbVF0rAhwQ5qYc9kN6t9ldlofVAff/zWe2FhfznH\nXDDEHPOxYMx2awIId0ok8QTLZRIv/3VsCzTNhEEo468Sk765grBA0whwcoXn\nWYmlGG2xXrlf7qMgjZOJU7Ce/gg3E5+WH/ZenWcqHMQ30vYoze5uDA7S3+C7\nKblkjMPKcVhkEHY6UFvtWjb8s/EWZg3yKfyHaicozB7gjZ2uxxS7ivEh0wRO\nOaMHGXTErTnhIk3T0p/w0zM4xBExgfU2sy2UA/Us1x8bPNvS8bsD4iWZ4le9\nu1VSLhP08ckr23tv51Zc1EfqugaJEZvLA8tqqddJwupbnunVCqqFR5QYGJWz\nI65ms8VYC0kqTuZLzwGp1xo9g299gG2J0U1IjNNXwiAsrIb5tBwceA7fj+ko\nzTbLaKLBWRcufWhhRWgVpYVOWt7d1oWX46pHtKbY4MKIwQfMOIwC2i/jXV7J\novmPqHi49DUZMuZDvj+K2UfwahRCDkr9asu7fB9YRDh6CGru05enMTkrlg73\nwxHjFmQGN1f9v80lDtvatVNgjFZljxQ0pGZ/AtI8sdzugAbkxcE0lpjXUxko\nXPuirY9WG7Tcb6HeSdyAV4YIu/aatL6i7jx2pEBPU8o9RCFEWzeTocQhaRr3\nPhYB\r\n=o4uO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD/CJ2skOeVu+Yd3gFbLsMtGzrfaN0UY98SQX/9J/59MgIhAPZAtxeci6xg+YuLUst+87JegyJk2evuyrj2XwJ4t6wG"}]},"maintainers":[{"name":"snadn","email":"snadn@snadn.cn"}],"_npmUser":{"name":"snadn","email":"snadn@snadn.cn"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/wasmvideoplayer_0.2.0_1582690313725_0.5121555945791438"},"_hasShrinkwrap":false},"0.3.0":{"name":"wasmvideoplayer","version":"0.3.0","description":"@[TOC](基于WASM的H265 Web播放器) # 1 背景 目前这个时间点，原生支持H265(HEVC)播放的浏览器极少，可以说基本没有，主要原因一个是H265的解码有更高的性能要求，从而换取更高的压缩率，目前大多数机器CPU软解H265的超清视频还是有点吃力，硬解兼容性又不好，另外一个原因主要是H265的专利费问题。因此H265有被各大浏览器厂商放弃的趋势，转而去支持更加开放的AV1编码，但是AV1编码的商用和普及估计还有段时间。","main":"player.js","scripts":{"dev":"http-server","test":"rm -rf test/dist && webpack --config test/webpack.config.js --cache=false"},"repository":{"type":"git","url":"git+https://github.com/sonysuqin/WasmVideoPlayer.git"},"author":"","license":"GPL-3.0","bugs":{"url":"https://github.com/sonysuqin/WasmVideoPlayer/issues"},"homepage":"https://github.com/sonysuqin/WasmVideoPlayer#readme","dependencies":{},"devDependencies":{"@babel/core":"^7.8.4","babel-loader":"^8.0.6","file-loader":"^5.1.0","string-replace-loader":"^2.2.0","webpack":"^4.41.6","webpack-cli":"^3.3.11","worker-loader":"^2.0.0"},"gitHead":"5fd44a9deb91ffd44d83813059a3f2f20f89c2c2","_id":"wasmvideoplayer@0.3.0","_nodeVersion":"12.13.1","_npmVersion":"6.12.1","dist":{"integrity":"sha512-nLmCB4E0+Og1hBX9H7na1A3MzV7dlsAaYGsVodKmqQnWLZNm+yVPP98uZRJQaL5RAUZgJ2Fwi3o0+cpojIuPtA==","shasum":"e888a5e820bb3592e7527b5251fe66e45e3cc987","tarball":"https://registry.npmjs.org/wasmvideoplayer/-/wasmvideoplayer-0.3.0.tgz","fileCount":139,"unpackedSize":9150671,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeWJDCCRA9TVsSAnZWagAAE5kP/ROIcm9Qj8HJZDvkJQdF\nHy986yEa+I/vPexUfu59cqN5fybyf5BI1n66sKy+nkwKMmNWMpWTQ9l3iljF\nFvWy0fxviR2+hKaLE+IHlfay0M6AieHmHQ1bZQL36R+c6pcuu6gdM4wbulh9\nCRUR8Ga0TXMO5Ul6qJ1aTTvVMohRBJlaCl8c+Ve+W18vC0R0ATaD0vxKAuf9\nbmsjnTeJOdhPK8LxPtQ1aS+QrQPdrdQ08rlspA6y1PbClagFiIaiI0u+DWVH\nd31pW5C0ECGAM3Sq+itN070H82uZAUzOm2y3EFXWXkimv/mbVAmnfdJ/Z9BE\nwtCs41ljsLIpwUKjIe90AC3aKRhH57gAMsGTA3gCToRhbPQrIGPL/0Y/BpAj\nWQ/gTcJK6zpiha2dMMfeGrvgyRS3FCX08DTRLpXr5KGMbv7/wUyLZTYyPIZn\n6PuvD5mTBs+PFdiZK/GBHAZVlk4cB5uBY0oiMrIalJ4EuDhDRfWURDBpNuAL\nv0uVJN8x9wffz+jT5dCK3KgIm+WIGzo+tOPpVzoJroR+91uV2QNArIxY0/dU\nL3E8Ez5PixvcH+gGcoArRmYlFZWe7O+vZimdiFDsrjZfgGDEzIoOQVWpFKjX\nL4TkdZxRJG18XgnPQzQ/HEFycbtRNJLLZmxTHz6VQrxS3CjnoSrka/KlzeE2\n+OTI\r\n=Ga23\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC18iWz2nuByd5SPpKu6LRcaCRkGsdR6ma6wnt4F/FnNwIhALvGOszkQ26yWJ8lYKslUAnk7d6ll6dmgJUz0lIouJMT"}]},"maintainers":[{"name":"snadn","email":"snadn@snadn.cn"}],"_npmUser":{"name":"snadn","email":"snadn@snadn.cn"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/wasmvideoplayer_0.3.0_1582862530065_0.20532517254752092"},"_hasShrinkwrap":false},"0.4.0":{"name":"wasmvideoplayer","version":"0.4.0","description":"@[TOC](基于WASM的H265 Web播放器) # 1 背景 目前这个时间点，原生支持H265(HEVC)播放的浏览器极少，可以说基本没有，主要原因一个是H265的解码有更高的性能要求，从而换取更高的压缩率，目前大多数机器CPU软解H265的超清视频还是有点吃力，硬解兼容性又不好，另外一个原因主要是H265的专利费问题。因此H265有被各大浏览器厂商放弃的趋势，转而去支持更加开放的AV1编码，但是AV1编码的商用和普及估计还有段时间。","main":"player.js","scripts":{"dev":"http-server","test":"rm -rf test/dist && webpack --config test/webpack.config.js --cache=false"},"repository":{"type":"git","url":"git+https://github.com/sonysuqin/WasmVideoPlayer.git"},"author":"","license":"GPL-3.0","bugs":{"url":"https://github.com/sonysuqin/WasmVideoPlayer/issues"},"homepage":"https://github.com/sonysuqin/WasmVideoPlayer#readme","dependencies":{},"devDependencies":{"@babel/core":"^7.8.4","babel-loader":"^8.0.6","file-loader":"^5.1.0","string-replace-loader":"^2.2.0","webpack":"^4.41.6","webpack-cli":"^3.3.11","worker-loader":"^2.0.0"},"gitHead":"43d2917a526ed432021e8657b998e0d196f19f82","_id":"wasmvideoplayer@0.4.0","_nodeVersion":"12.13.1","_npmVersion":"6.12.1","dist":{"integrity":"sha512-Q99C2CqUfG9Ulxrz4pGQs4wcjR/14cS5hpKIVqNuPYJ3wETDHiPiNufLaeZge7aJJsrr5eF9lpdZDi8yDkPDoQ==","shasum":"6e487fe9a62d2cb78a06fa9dae5b38be7d634f76","tarball":"https://registry.npmjs.org/wasmvideoplayer/-/wasmvideoplayer-0.4.0.tgz","fileCount":139,"unpackedSize":9116169,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeXRXGCRA9TVsSAnZWagAA0bcQAInhpO5liz2sR44EGZFg\npHvz7xoo6yZm3xhaUGXsnKkBlT8zWIwaBoSreKJoWnXjOJBc9G3J3A/+AeZC\nP41BmucKJOHipkiKABlZHvi7CxPJM+AWEpHfPSh0hqnost3x26QImDMRb4Pp\nQd0LpqKbsg08ika1MvlHlXljguYTsaZdoCWDI8Ks8n3rC+B7DQp9MtUzkIjr\nvsodT1BMlmw1SxqVdoF7l62S87rntC5+wvzG6PyRNrKSxopWo2cp8z76g9Xc\n4kNZ0BQetnYeaJA0WEBV3bc1Vo+Ahgr01hCKSwMYrrk9bZ8aIPaHkodLAxqQ\nT1K2p26XpKch2tJuG1tWE/BDZ3S1fYEAysgoWxh+wnKAj9QWXGKW4Ashh6NG\nPPU1Jki43iPZ92tSBQSwkBsz9EnP8mdSDB4ZJgcqQkoEHzWE+/EJcxDcUSb4\nus4Sky4BXvgevD+davNUvmju5E0mCPKR6gJzc44gSq/thOa+r3lNQ5lCLxHa\nVj+dK0Goz2WOUUec0DJlKODhn1ZsIxl+ZL646TTFE0IaQYUANIQ7bhbKiKSp\n6yGrqiTyHnjon1JGlyQ9hj/kycBAV9vIy+xlsoYvVcdleBMHttuAYuZDAozn\n8s2iwCNGFBZ0arJCQFtLbNhGCT02XyYHN1hVC10a/M8H2B0c6t13gX0iLLrT\nOPdb\r\n=jz5K\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGlsQ5GVAu7EZrEEXKE8UtXRJQCexHi0wB7yf+oTWdW4AiEAkqC29ID7IAgYoV5Erpm6tIWuM001eEgAkAeP+sTLNSE="}]},"maintainers":[{"name":"snadn","email":"snadn@snadn.cn"}],"_npmUser":{"name":"snadn","email":"snadn@snadn.cn"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/wasmvideoplayer_0.4.0_1583158725854_0.8546535628596452"},"_hasShrinkwrap":false}},"maintainers":[{"name":"snadn","email":"snadn@snadn.cn"}],"description":"@[TOC](基于WASM的H265 Web播放器) # 1 背景 目前这个时间点，原生支持H265(HEVC)播放的浏览器极少，可以说基本没有，主要原因一个是H265的解码有更高的性能要求，从而换取更高的压缩率，目前大多数机器CPU软解H265的超清视频还是有点吃力，硬解兼容性又不好，另外一个原因主要是H265的专利费问题。因此H265有被各大浏览器厂商放弃的趋势，转而去支持更加开放的AV1编码，但是AV1编码的商用和普及估计还有段时间。","homepage":"https://github.com/sonysuqin/WasmVideoPlayer#readme","repository":{"type":"git","url":"git+https://github.com/sonysuqin/WasmVideoPlayer.git"},"bugs":{"url":"https://github.com/sonysuqin/WasmVideoPlayer/issues"},"license":"GPL-3.0","readme":"@[TOC](基于WASM的H265 Web播放器)\n# 1 背景\n目前这个时间点，原生支持H265(HEVC)播放的浏览器极少，可以说基本没有，主要原因一个是H265的解码有更高的性能要求，从而换取更高的压缩率，目前大多数机器CPU软解H265的超清视频还是有点吃力，硬解兼容性又不好，另外一个原因主要是H265的专利费问题。因此H265有被各大浏览器厂商放弃的趋势，转而去支持更加开放的AV1编码，但是AV1编码的商用和普及估计还有段时间。\n\nH265与H264相比主要的好处在于相同分辨率下降低了几乎一倍的码率，对带宽压力比较大的网站来说，使用H265可以极大削减带宽消耗(尽管可能面临专利费麻烦)，但是由于浏览器的支持问题，目前H265的播放主要在APP端实现，借助硬件解码，可以获得比较好的性能和体验。\n\n本文相关的代码使用WASM、FFmpeg、WebGL、Web Audio等组件实现了一个简易的支持H265的Web播放器，作为探索、验证，just for fun。\n# 2 代码\ngithub地址: [https://github.com/sonysuqin/WasmVideoPlayer](https://github.com/sonysuqin/WasmVideoPlayer).\n\n# 3 依赖\n## 3.1 WASM\nWASM的介绍在[这里](https://webassembly.org/)，可以在浏览器里执行原生代码(例如C、C++)，要开发可以在浏览器运行的原生代码，需要安装他的[工具链](https://emscripten.org/docs/getting_started/downloads.html)，我使用的是目前最新的版本(1.39.5)。编译环境有Ubuntu、MacOS等，[这里](https://emscripten.org/docs/getting_started/downloads.html#platform-notes-installation-instructions-sdk)有介绍。\n## 3.2 FFmpeg\n主要使用FFmpeg来做解封装(demux)和解码(decoder)，由于使用了FFmpeg(3.3)，理论上可以播放绝大多数格式的视频，这里只针对H265编码、MP4封装，在编译时可以只按需编译最少的模块，从而得到比较小的库。\n\n使用Emscripten编译FFmpeg主要参考下面这个网页，做了一些修改：\n[https://blog.csdn.net/Jacob_job/article/details/79434207](https://blog.csdn.net/Jacob_job/article/details/79434207)\n## 3.3 WebGL\nH5使用Canvas来绘图，但是默认的2d模式只能绘制RGB格式，使用FFmpeg解码出来的视频数据是YUV格式，想要渲染出来需要进行颜色空间转换，可以使用FFmpeg的libswscale模块进行转换，为了提升性能，这里使用了WebGL来硬件加速，主要参考了这个项目，做了一些修改：\n[https://github.com/p4prasoon/YUV-Webgl-Video-Player](https://github.com/p4prasoon/YUV-Webgl-Video-Player)\n## 3.4 Web Audio\nFFmpeg解码出来的音频数据是PCM格式，可以使用H5的Web Audio Api来播放，主要参考了这个项目，做了一些修改：\n[https://github.com/samirkumardas/pcm-player](https://github.com/samirkumardas/pcm-player)\n\n# 4 播放器实现\n这里只是简单实现了播放器的部分功能，包括下载、解封装、解码、渲染、音视频同步等基本功能，每个环节还有很多细节可以优化。目前可以支持FFmpeg的各种内置codec，如H264/H265等，默认支持MP4/FLV文件播放、HTTP-FLV流的播放。\n## 4.1 模块结构\n![在这里插入图片描述](https://img-blog.csdnimg.cn/20190207123204349.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NvbnlzdXFpbg==,size_16,color_FFFFFF,t_70)\n## 4.2 线程模型\n理论上来说，播放器应该使用这样的线程模型，各个模块在各自线程各司其职：\n![在这里插入图片描述](https://img-blog.csdnimg.cn/20181221114548421.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NvbnlzdXFpbg==,size_16,color_FFFFFF,t_70)\n但是WASM目前对多线程(pthread)的支持不够好，各个浏览器的WASM多线程支持还处于试验阶段，因此现在最好不要在原生代码里编写pthread的代码。这里使用了Web Worker，把下载和对FFmpeg的调用放到单独的线程中去。\n\n主要有三个线程：\n- 主线程(Player)：界面控制、播放控制、下载控制、音视频渲染、音视频同步；\n- 解码线程(Decoder Worker)：音视频数据的解封装、解码；\n- 下载线程(Downloader Worker)：下载某个chunk。\n线程之间通过postMessage进行异步通信，在需要传输大量数据(例如视频帧)的地方，需要使用Transferable接口来传输，避免大数据的拷贝损耗性能。\n\n## 4.3 Player\n### 4.3.1 接口\n- play：开始播放；\n- pause：暂停播放；\n- resume：恢复播放；\n- stop：停止播放；\n- fullscreen：全屏播放；\n- seek：seek播放未实现。\n### 4.3.2 下载控制\n为防止播放器无限制地下载文件，在下载操作中占用过多的CPU，浪费过多带宽，这里在获取到文件码率之后，以码率一定倍数的速率下载文件。\n### 4.3.3 缓冲控制\n缓存控制对这个播放器的意义重大，在这个时间点，WASM还无法使用多线程以及多线程的同步，FFmpeg的同步读数据接口必须保证返回数据。所以这里有两个措施，1：在未获取到文件元信息之前的数据缓存；2：解码帧缓存。必须控制好这两个缓存，才能保证任何时候FFmpeg需要读取数据时都能够返回数据，在数据不足时停止解码，进入Buffer状态，数据足够时继续解码播放，返回Play状态，保证FFmpeg不会报错退出播放。\n### 4.3.4 音视频同步\n音频数据直接喂给Web Audio，通过Web Audio的Api可以获得当前播放的音频的时间戳，以该时间戳为时间基准来同步视频帧，如果当前视频帧的时间已经落后则立刻渲染，如果比较早，则需要delay。\n在H5里delay可以通过setTimeout实现(还未找到更好的方式)，上面做缓冲控制的另外一个意义在于控制视频的渲染频率，如果调用setTimeout的视频帧太多，内存会暴涨。\n### 4.3.5 渲染\n简单地将PCM数据交给PCM Player，YUV数据交给WebGL Player。\n## 4.4 Downloader\n这个模块很简单，只是单纯为了不在主线程做太多事情而分离，功能主要有：\n\n- 通过Content-Length字段获取文件的长度；\n- 通过Range字段下载一个chunk。\n\n如上面提到的，Player会进行速率控制，因此需要把文件分成chunk，按照chunk方式进行下载。下载的数据先发给Player，由Player转交给Decoder(理论上应该直接交给Decoder，但是Downloader无法直接与Decoder通信)。\n对流式的数据，则使用[Fetch](https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch)。\n\n## 4.5 Decoder\n这个模块需要加载原生代码生成的胶水代码(glue code)，胶水代码会加载wasm。\n\n```\nself.importScripts(\"libffmpeg.js\");\n```\n### 4.5.1 接口\n- initDecoder：初始化解码器，开辟文件缓存；\n- uninitDecoder：反初始化解码器；\n- openDecoder：打开解码器，获取文件信息；\n- closeDecoder：关闭解码器；\n- startDecoding：开始解码；\n- pauseDecoding：暂停解码。 \n\n这些方法都由Player模块通过postMessage异步调用。\n### 4.5.2 缓存\n这里简单使用了WASM的MEMFS文件接口([WASM的文件系统参考](https://emscripten.org/docs/api_reference/Filesystem-API.html#filesystem-api))，使用方式就是直接调用stdio的方法，然后在emcc的编译命令中加入编译选项：\n\n```\n-s FORCE_FILESYSTEM=1 \n```\nMEMFS会在内存中虚拟一个文件系统，Decoder收到Player发过来的文件数据直接写入缓存，由解码任务读取缓存。\n对流式的数据，则使用FFmpeg的环形缓存FIFO。\n### 4.5.3 解码\n- 播放开始后不能立刻打开解码器，因为FFmpeg探测数据格式需要一定的数据长度(例如MP4头的长度)；\n- 缓存的数据足够后Player打开解码器，会得到音频的参数(通道数、采样率、采样大小、数据格式)，视频的参数(分辨率，duration、颜色空间)，以这些参数来初始化渲染器、界面；\n- Player调用startDecoding会启动一个定时器执行解码任务，以一定的速率开始解码；\n- Player缓存满后会调用pauseDecoding暂停解码器。\n### 4.5.4 数据交互\n解码后的数据直接通过Transferable Objects postMessage给Player，这样传递的是引用，不需要拷贝数据，提高了性能。\n\nJavascript与C的数据交互：\n\n```\n发送：\n……\nthis.cacheBuffer = Module._malloc(chunkSize);\n……\nDecoder.prototype.sendData = function (data) {\n    var typedArray = new Uint8Array(data);\n    Module.HEAPU8.set(typedArray, this.cacheBuffer); //拷贝\n    Module._sendData(this.cacheBuffer, typedArray.length); //传递\n};\n\n接收：\nthis.videoCallback = Module.addFunction(function (buff, size, timestamp) {\n    var outArray = Module.HEAPU8.subarray(buff, buff + size); //拷贝\n    var data = new Uint8Array(outArray);\n    var objData = {\n        t: kVideoFrame,\n        s: timestamp,\n        d: data\n    };\n    self.postMessage(objData, [objData.d.buffer]); //发送给Player\n});\n需要把回调通过openDecoder方法传入C层，在C层调用。\n```\n# 5 编译\n## 5.1 安装Emscripten\n参考其[官方文档](https://emscripten.org/docs/getting_started/downloads.html)。\n## 5.2 下载FFmpeg\n```\ngit clone https://git.ffmpeg.org/ffmpeg.git\n```\n这里切到了3.3分支。\n## 5.3 下载本文的代码\n保证FFmpeg目录和代码目录平级。\n```\ngit clone https://github.com/sonysuqin/WasmVideoPlayer.git\n```\n## 5.4 编译\n进入代码目录，执行：\n```\n./build_decoder.sh\n```\n# 6 测试\n可以使用任意的Http Server(Apache、Nginx等)，例如：\n如果安装了node/npm/http-server，则在代码目录下执行：\n\n```\nhttp-server -p 8080 .\n```\n在浏览器输入即可：\n\n```\nhttp://127.0.0.1:8080\n```\nDemo地址：[播放](https://roblin.cn/wasm/)。\n# 7 浏览器支持\n目前(20190207)没有做太多严格的浏览器兼容性测试，主要在Chrome上开发，以下浏览器比较新的版本都可以运行：\n\n- Chrome(360浏览器、搜狗浏览器等webkit内核也支持)；\n- Firefox；\n- Edge。\n# 8 主要问题\n- 解码、播放H265的CPU占用相对来说较高；\n- 如果不及时传递音频数据，AudioContext的currentTime不做控制可能会导致音视频不同步。\n","readmeFilename":"README.md"}