]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/assets/player/webtorrent/video-renderer.ts
tslint update
[github/Chocobozzz/PeerTube.git] / client / src / assets / player / webtorrent / video-renderer.ts
CommitLineData
aa8b6df4
C
1// Thanks: https://github.com/feross/render-media
2// TODO: use render-media once https://github.com/feross/render-media/issues/32 is fixed
3
244b4ae3 4const MediaElementWrapper = require('mediasource')
bf5685f0 5import { extname } from 'path'
244b4ae3 6const videostream = require('videostream')
aa8b6df4
C
7
8const VIDEOSTREAM_EXTS = [
9 '.m4a',
10 '.m4v',
11 '.mp4'
12]
13
14type RenderMediaOptions = {
15 controls: boolean
16 autoplay: boolean
17}
18
19function renderVideo (
244b4ae3 20 file: any,
aa8b6df4
C
21 elem: HTMLVideoElement,
22 opts: RenderMediaOptions,
23 callback: (err: Error, renderer: any) => void
24) {
25 validateFile(file)
26
27 return renderMedia(file, elem, opts, callback)
28}
29
244b4ae3 30function renderMedia (file: any, elem: HTMLVideoElement, opts: RenderMediaOptions, callback: (err: Error, renderer?: any) => void) {
aa8b6df4 31 const extension = extname(file.name).toLowerCase()
c4710631 32 let preparedElem: any
aa8b6df4 33 let currentTime = 0
244b4ae3 34 let renderer: any
aa8b6df4 35
0f56c6e5
C
36 try {
37 if (VIDEOSTREAM_EXTS.indexOf(extension) >= 0) {
38 renderer = useVideostream()
39 } else {
40 renderer = useMediaSource()
41 }
42 } catch (err) {
43 return callback(err)
aa8b6df4
C
44 }
45
46 function useVideostream () {
47 prepareElem()
244b4ae3 48 preparedElem.addEventListener('error', function onError (err: Error) {
bf5685f0
C
49 preparedElem.removeEventListener('error', onError)
50
575712a5 51 return callback(err)
bf5685f0 52 })
960a11e8 53 preparedElem.addEventListener('loadstart', onLoadStart)
aa8b6df4
C
54 return videostream(file, preparedElem)
55 }
56
bf5685f0
C
57 function useMediaSource (useVP9 = false) {
58 const codecs = getCodec(file.name, useVP9)
59
aa8b6df4 60 prepareElem()
244b4ae3 61 preparedElem.addEventListener('error', function onError (err: Error) {
0dcf9a14 62 preparedElem.removeEventListener('error', onError)
bf5685f0 63
0dcf9a14
C
64 // Try with vp9 before returning an error
65 if (codecs.indexOf('vp8') !== -1) return fallbackToMediaSource(true)
bf5685f0
C
66
67 return callback(err)
68 })
960a11e8 69 preparedElem.addEventListener('loadstart', onLoadStart)
aa8b6df4
C
70
71 const wrapper = new MediaElementWrapper(preparedElem)
bf5685f0 72 const writable = wrapper.createWriteStream(codecs)
aa8b6df4
C
73 file.createReadStream().pipe(writable)
74
75 if (currentTime) preparedElem.currentTime = currentTime
76
77 return wrapper
78 }
79
bf5685f0
C
80 function fallbackToMediaSource (useVP9 = false) {
81 if (useVP9 === true) console.log('Falling back to media source with VP9 enabled.')
82 else console.log('Falling back to media source..')
aa8b6df4 83
bf5685f0 84 useMediaSource(useVP9)
aa8b6df4
C
85 }
86
87 function prepareElem () {
88 if (preparedElem === undefined) {
89 preparedElem = elem
90
91 preparedElem.addEventListener('progress', function () {
92 currentTime = elem.currentTime
93 })
94 }
95 }
96
97 function onLoadStart () {
960a11e8 98 preparedElem.removeEventListener('loadstart', onLoadStart)
aa8b6df4 99 if (opts.autoplay) preparedElem.play()
aa8b6df4 100
aa8b6df4
C
101 callback(null, renderer)
102 }
103}
104
244b4ae3 105function validateFile (file: any) {
aa8b6df4
C
106 if (file == null) {
107 throw new Error('file cannot be null or undefined')
108 }
109 if (typeof file.name !== 'string') {
110 throw new Error('missing or invalid file.name property')
111 }
112 if (typeof file.createReadStream !== 'function') {
113 throw new Error('missing or invalid file.createReadStream property')
114 }
115}
116
bf5685f0 117function getCodec (name: string, useVP9 = false) {
aa8b6df4 118 const ext = extname(name).toLowerCase()
bf5685f0
C
119 if (ext === '.mp4') {
120 return 'video/mp4; codecs="avc1.640029, mp4a.40.5"'
121 }
122
123 if (ext === '.webm') {
124 if (useVP9 === true) return 'video/webm; codecs="vp9, opus"'
125
126 return 'video/webm; codecs="vp8, vorbis"'
127 }
128
129 return undefined
aa8b6df4
C
130}
131
132export {
133 renderVideo
134}