1 // Thanks: https://github.com/feross/render-media
3 const MediaElementWrapper = require('mediasource')
4 import { extname } from 'path'
5 const Videostream = require('videostream')
7 const VIDEOSTREAM_EXTS = [
13 type RenderMediaOptions = {
18 function renderVideo (
20 elem: HTMLVideoElement,
21 opts: RenderMediaOptions,
22 callback: (err: Error, renderer: any) => void
26 return renderMedia(file, elem, opts, callback)
29 function renderMedia (file: any, elem: HTMLVideoElement, opts: RenderMediaOptions, callback: (err: Error, renderer?: any) => void) {
30 const extension = extname(file.name).toLowerCase()
36 if (VIDEOSTREAM_EXTS.includes(extension)) {
37 renderer = useVideostream()
39 renderer = useMediaSource()
45 function useVideostream () {
47 preparedElem.addEventListener('error', function onError (err: Error) {
48 preparedElem.removeEventListener('error', onError)
52 preparedElem.addEventListener('loadstart', onLoadStart)
53 return new Videostream(file, preparedElem)
56 function useMediaSource (useVP9 = false) {
57 const codecs = getCodec(file.name, useVP9)
60 preparedElem.addEventListener('error', function onError (err: Error) {
61 preparedElem.removeEventListener('error', onError)
63 // Try with vp9 before returning an error
64 if (codecs.includes('vp8')) return fallbackToMediaSource(true)
68 preparedElem.addEventListener('loadstart', onLoadStart)
70 const wrapper = new MediaElementWrapper(preparedElem)
71 const writable = wrapper.createWriteStream(codecs)
72 file.createReadStream().pipe(writable)
74 if (currentTime) preparedElem.currentTime = currentTime
79 function fallbackToMediaSource (useVP9 = false) {
80 if (useVP9 === true) console.log('Falling back to media source with VP9 enabled.')
81 else console.log('Falling back to media source..')
83 useMediaSource(useVP9)
86 function prepareElem () {
87 if (preparedElem === undefined) {
90 preparedElem.addEventListener('progress', function () {
91 currentTime = elem.currentTime
96 function onLoadStart () {
97 preparedElem.removeEventListener('loadstart', onLoadStart)
98 if (opts.autoplay) preparedElem.play()
100 callback(null, renderer)
104 function validateFile (file: any) {
106 throw new Error('file cannot be null or undefined')
108 if (typeof file.name !== 'string') {
109 throw new Error('missing or invalid file.name property')
111 if (typeof file.createReadStream !== 'function') {
112 throw new Error('missing or invalid file.createReadStream property')
116 function getCodec (name: string, useVP9 = false) {
117 const ext = extname(name).toLowerCase()
118 if (ext === '.mp4') {
119 return 'video/mp4; codecs="avc1.640029, mp4a.40.5"'
122 if (ext === '.webm') {
123 if (useVP9 === true) return 'video/webm; codecs="vp9, opus"'
125 return 'video/webm; codecs="vp8, vorbis"'