diff options
Diffstat (limited to 'client/src/assets/player/video-renderer.ts')
-rw-r--r-- | client/src/assets/player/video-renderer.ts | 55 |
1 files changed, 37 insertions, 18 deletions
diff --git a/client/src/assets/player/video-renderer.ts b/client/src/assets/player/video-renderer.ts index bda40b11d..174676ffa 100644 --- a/client/src/assets/player/video-renderer.ts +++ b/client/src/assets/player/video-renderer.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | // Thanks: https://github.com/feross/render-media | 1 | // Thanks: https://github.com/feross/render-media |
2 | // TODO: use render-media once https://github.com/feross/render-media/issues/32 is fixed | 2 | // TODO: use render-media once https://github.com/feross/render-media/issues/32 is fixed |
3 | 3 | ||
4 | import { extname } from 'path' | ||
5 | import * as MediaElementWrapper from 'mediasource' | 4 | import * as MediaElementWrapper from 'mediasource' |
5 | import { extname } from 'path' | ||
6 | import * as videostream from 'videostream' | 6 | import * as videostream from 'videostream' |
7 | 7 | ||
8 | const VIDEOSTREAM_EXTS = [ | 8 | const VIDEOSTREAM_EXTS = [ |
@@ -27,7 +27,7 @@ function renderVideo ( | |||
27 | return renderMedia(file, elem, opts, callback) | 27 | return renderMedia(file, elem, opts, callback) |
28 | } | 28 | } |
29 | 29 | ||
30 | function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, callback: (err: Error, renderer: any) => void) { | 30 | function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, callback: (err: Error, renderer?: any) => void) { |
31 | const extension = extname(file.name).toLowerCase() | 31 | const extension = extname(file.name).toLowerCase() |
32 | let preparedElem = undefined | 32 | let preparedElem = undefined |
33 | let currentTime = 0 | 33 | let currentTime = 0 |
@@ -41,18 +41,33 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca | |||
41 | 41 | ||
42 | function useVideostream () { | 42 | function useVideostream () { |
43 | prepareElem() | 43 | prepareElem() |
44 | preparedElem.addEventListener('error', fallbackToMediaSource) | 44 | preparedElem.addEventListener('error', function onError () { |
45 | preparedElem.removeEventListener('error', onError) | ||
46 | |||
47 | return fallbackToMediaSource() | ||
48 | }) | ||
45 | preparedElem.addEventListener('loadstart', onLoadStart) | 49 | preparedElem.addEventListener('loadstart', onLoadStart) |
46 | return videostream(file, preparedElem) | 50 | return videostream(file, preparedElem) |
47 | } | 51 | } |
48 | 52 | ||
49 | function useMediaSource () { | 53 | function useMediaSource (useVP9 = false) { |
54 | const codecs = getCodec(file.name, useVP9) | ||
55 | |||
50 | prepareElem() | 56 | prepareElem() |
51 | preparedElem.addEventListener('error', callback) | 57 | preparedElem.addEventListener('error', function onError(err) { |
58 | // Try with vp9 before returning an error | ||
59 | if (codecs.indexOf('vp8') !== -1) { | ||
60 | preparedElem.removeEventListener('error', onError) | ||
61 | |||
62 | return fallbackToMediaSource(true) | ||
63 | } | ||
64 | |||
65 | return callback(err) | ||
66 | }) | ||
52 | preparedElem.addEventListener('loadstart', onLoadStart) | 67 | preparedElem.addEventListener('loadstart', onLoadStart) |
53 | 68 | ||
54 | const wrapper = new MediaElementWrapper(preparedElem) | 69 | const wrapper = new MediaElementWrapper(preparedElem) |
55 | const writable = wrapper.createWriteStream(getCodec(file.name)) | 70 | const writable = wrapper.createWriteStream(codecs) |
56 | file.createReadStream().pipe(writable) | 71 | file.createReadStream().pipe(writable) |
57 | 72 | ||
58 | if (currentTime) preparedElem.currentTime = currentTime | 73 | if (currentTime) preparedElem.currentTime = currentTime |
@@ -60,10 +75,11 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca | |||
60 | return wrapper | 75 | return wrapper |
61 | } | 76 | } |
62 | 77 | ||
63 | function fallbackToMediaSource () { | 78 | function fallbackToMediaSource (useVP9 = false) { |
64 | preparedElem.removeEventListener('error', fallbackToMediaSource) | 79 | if (useVP9 === true) console.log('Falling back to media source with VP9 enabled.') |
80 | else console.log('Falling back to media source..') | ||
65 | 81 | ||
66 | useMediaSource() | 82 | useMediaSource(useVP9) |
67 | } | 83 | } |
68 | 84 | ||
69 | function prepareElem () { | 85 | function prepareElem () { |
@@ -96,16 +112,19 @@ function validateFile (file) { | |||
96 | } | 112 | } |
97 | } | 113 | } |
98 | 114 | ||
99 | function getCodec (name: string) { | 115 | function getCodec (name: string, useVP9 = false) { |
100 | const ext = extname(name).toLowerCase() | 116 | const ext = extname(name).toLowerCase() |
101 | return { | 117 | if (ext === '.mp4') { |
102 | '.m4a': 'audio/mp4; codecs="mp4a.40.5"', | 118 | return 'video/mp4; codecs="avc1.640029, mp4a.40.5"' |
103 | '.m4v': 'video/mp4; codecs="avc1.640029, mp4a.40.5"', | 119 | } |
104 | '.mkv': 'video/webm; codecs="avc1.640029, mp4a.40.5"', | 120 | |
105 | '.mp3': 'audio/mpeg', | 121 | if (ext === '.webm') { |
106 | '.mp4': 'video/mp4; codecs="avc1.640029, mp4a.40.5"', | 122 | if (useVP9 === true) return 'video/webm; codecs="vp9, opus"' |
107 | '.webm': 'video/webm; codecs="opus, vorbis, vp8"' | 123 | |
108 | }[ext] | 124 | return 'video/webm; codecs="vp8, vorbis"' |
125 | } | ||
126 | |||
127 | return undefined | ||
109 | } | 128 | } |
110 | 129 | ||
111 | export { | 130 | export { |