@vpalmisano/webrtcperf 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +296 -0
- package/app.min.js +2 -0
- package/build/src/app.d.ts +6 -0
- package/build/src/app.js +207 -0
- package/build/src/app.js.map +1 -0
- package/build/src/config.d.ts +104 -0
- package/build/src/config.js +880 -0
- package/build/src/config.js.map +1 -0
- package/build/src/generate-config-docs.d.ts +1 -0
- package/build/src/generate-config-docs.js +41 -0
- package/build/src/generate-config-docs.js.map +1 -0
- package/build/src/index.d.ts +9 -0
- package/build/src/index.js +26 -0
- package/build/src/index.js.map +1 -0
- package/build/src/media.d.ts +33 -0
- package/build/src/media.js +113 -0
- package/build/src/media.js.map +1 -0
- package/build/src/rtcstats.d.ts +302 -0
- package/build/src/rtcstats.js +418 -0
- package/build/src/rtcstats.js.map +1 -0
- package/build/src/server.d.ts +173 -0
- package/build/src/server.js +639 -0
- package/build/src/server.js.map +1 -0
- package/build/src/session.d.ts +277 -0
- package/build/src/session.js +1552 -0
- package/build/src/session.js.map +1 -0
- package/build/src/stats.d.ts +243 -0
- package/build/src/stats.js +1383 -0
- package/build/src/stats.js.map +1 -0
- package/build/src/utils.d.ts +249 -0
- package/build/src/utils.js +1220 -0
- package/build/src/utils.js.map +1 -0
- package/build/src/visqol.d.ts +6 -0
- package/build/src/visqol.js +61 -0
- package/build/src/visqol.js.map +1 -0
- package/build/src/vmaf.d.ts +83 -0
- package/build/src/vmaf.js +624 -0
- package/build/src/vmaf.js.map +1 -0
- package/build/tsconfig.tsbuildinfo +1 -0
- package/package.json +129 -0
- package/src/app.ts +241 -0
- package/src/config.ts +852 -0
- package/src/generate-config-docs.ts +47 -0
- package/src/index.ts +9 -0
- package/src/media.ts +151 -0
- package/src/rtcstats.ts +507 -0
- package/src/server.ts +645 -0
- package/src/session.ts +1908 -0
- package/src/stats.ts +1668 -0
- package/src/utils.ts +1295 -0
- package/src/visqol.ts +62 -0
- package/src/vmaf.ts +771 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { writeFile } from 'fs/promises'
|
|
2
|
+
|
|
3
|
+
import { getConfigDocs } from './config'
|
|
4
|
+
|
|
5
|
+
function formatJson(data: string): string {
|
|
6
|
+
return `\`${data.replace(/\n/g, '')}\``
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let data = `
|
|
10
|
+
The configuration properties are applied in the following order (from higher to
|
|
11
|
+
lower precedence):
|
|
12
|
+
|
|
13
|
+
- arguments passed to the executable in kebab case (e.g. \`--url-query\`);
|
|
14
|
+
- environment variables in uppercase snake format (e.g. \`URL_QUERY\`);
|
|
15
|
+
- \`config.json\` configuration file;
|
|
16
|
+
- default values.
|
|
17
|
+
|
|
18
|
+
`
|
|
19
|
+
|
|
20
|
+
const configDocs = getConfigDocs()
|
|
21
|
+
Object.entries(configDocs).forEach(entry => {
|
|
22
|
+
const [name, value] = entry
|
|
23
|
+
data += `\
|
|
24
|
+
## ${name}
|
|
25
|
+
${value.doc}
|
|
26
|
+
|
|
27
|
+
*Type*: \`${value.format === '"nat"' ? 'positive int' : value.format.replace(/^"(.+)"$/, '$1')}\`
|
|
28
|
+
|
|
29
|
+
*Default*: ${formatJson(value.default)}
|
|
30
|
+
|
|
31
|
+
`
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
data += `
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
`
|
|
39
|
+
|
|
40
|
+
writeFile('docs/config.md', data).then(
|
|
41
|
+
() => {
|
|
42
|
+
console.log('done')
|
|
43
|
+
},
|
|
44
|
+
err => {
|
|
45
|
+
console.error(`Error writing file: ${err.message}`)
|
|
46
|
+
},
|
|
47
|
+
)
|
package/src/index.ts
ADDED
package/src/media.ts
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { existsSync, promises as fs } from 'fs'
|
|
2
|
+
|
|
3
|
+
import { logger, runShellCommand, sha256 } from './utils'
|
|
4
|
+
|
|
5
|
+
const log = logger('webrtcperf:media')
|
|
6
|
+
|
|
7
|
+
const DEFAULT_VIDEO_PATH = 'https://github.com/vpalmisano/webrtcperf/releases/download/v2.0.4/video.mp4'
|
|
8
|
+
|
|
9
|
+
export type MediaPath = {
|
|
10
|
+
video: string
|
|
11
|
+
audio: string
|
|
12
|
+
mp4: string
|
|
13
|
+
m4a: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Converts the video file into raw audio and video files.
|
|
18
|
+
* @param {*} config
|
|
19
|
+
* @param {string} config.videoPath the video to convert
|
|
20
|
+
* @param {string} config.videoWidth the output video width
|
|
21
|
+
* @param {string} config.videoHeight the output video height
|
|
22
|
+
* @param {string} config.videoFramerate the output video framerate
|
|
23
|
+
* @param {string} config.videoSeek the seek position in seconds
|
|
24
|
+
* @param {string} config.videoDuration the output video duration in seconds
|
|
25
|
+
* @param {boolean} config.videoCacheRaw if true and the destinations raw files
|
|
26
|
+
* exist on file system, the conversion step is skipped
|
|
27
|
+
* @param {string} config.videoCachePath the destination directory path; if not
|
|
28
|
+
* existing, it will be created
|
|
29
|
+
* @param {string} config.videoFormat the raw video format (y4m or mjpeg)
|
|
30
|
+
*/
|
|
31
|
+
export async function prepareFakeMedia({
|
|
32
|
+
videoPath,
|
|
33
|
+
videoWidth,
|
|
34
|
+
videoHeight,
|
|
35
|
+
videoFramerate,
|
|
36
|
+
videoSeek,
|
|
37
|
+
videoDuration,
|
|
38
|
+
videoCacheRaw,
|
|
39
|
+
videoCachePath,
|
|
40
|
+
videoFormat,
|
|
41
|
+
useFakeMedia,
|
|
42
|
+
}: {
|
|
43
|
+
videoPath: string
|
|
44
|
+
videoWidth: number
|
|
45
|
+
videoHeight: number
|
|
46
|
+
videoFramerate: number
|
|
47
|
+
videoSeek: number
|
|
48
|
+
videoDuration: number
|
|
49
|
+
videoCacheRaw: boolean
|
|
50
|
+
videoCachePath: string
|
|
51
|
+
videoFormat: string
|
|
52
|
+
useFakeMedia: boolean
|
|
53
|
+
}): Promise<MediaPath> {
|
|
54
|
+
log.debug('prepareFakeMedia', {
|
|
55
|
+
videoPath,
|
|
56
|
+
videoWidth,
|
|
57
|
+
videoHeight,
|
|
58
|
+
videoFramerate,
|
|
59
|
+
videoSeek,
|
|
60
|
+
videoDuration,
|
|
61
|
+
videoCacheRaw,
|
|
62
|
+
videoCachePath,
|
|
63
|
+
videoFormat,
|
|
64
|
+
useFakeMedia,
|
|
65
|
+
})
|
|
66
|
+
if (!videoPath) {
|
|
67
|
+
throw new Error('empty video path')
|
|
68
|
+
}
|
|
69
|
+
if (!videoPath.startsWith('http') && !videoPath.startsWith('generate:') && !existsSync(videoPath)) {
|
|
70
|
+
log.warn(`video not found: ${videoPath}, using default test video`)
|
|
71
|
+
videoPath = DEFAULT_VIDEO_PATH
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
await fs.mkdir(videoCachePath, { recursive: true })
|
|
75
|
+
const name = sha256(videoPath)
|
|
76
|
+
|
|
77
|
+
const destVideoPath = `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.${videoFormat}`
|
|
78
|
+
const destAudioPath = `${videoCachePath}/${name}.wav`
|
|
79
|
+
const destMp4Path = useFakeMedia
|
|
80
|
+
? ''
|
|
81
|
+
: `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.mp4`
|
|
82
|
+
const destM4aPath = useFakeMedia ? '' : `${videoCachePath}/${name}.m4a`
|
|
83
|
+
|
|
84
|
+
if (
|
|
85
|
+
!existsSync(destVideoPath) ||
|
|
86
|
+
!existsSync(destAudioPath) ||
|
|
87
|
+
(destMp4Path && !existsSync(destMp4Path)) ||
|
|
88
|
+
(destM4aPath && !existsSync(destM4aPath)) ||
|
|
89
|
+
!videoCacheRaw
|
|
90
|
+
) {
|
|
91
|
+
log.info(
|
|
92
|
+
`Converting ${videoPath} to ${destVideoPath}, ${destAudioPath}${destMp4Path ? `, ${destMp4Path}` : ''}${destM4aPath ? `, ${destM4aPath}` : ''}`,
|
|
93
|
+
)
|
|
94
|
+
const destVideoPathTmp = `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.tmp.${videoFormat}`
|
|
95
|
+
const destAudioPathTmp = `${videoCachePath}/${name}.tmp.wav`
|
|
96
|
+
const destMp4PathTmp = useFakeMedia
|
|
97
|
+
? ''
|
|
98
|
+
: `${videoCachePath}/${name}_${videoWidth}x${videoHeight}_${videoFramerate}fps.tmp.mp4`
|
|
99
|
+
const destM4aPathTmp = useFakeMedia ? '' : `${videoCachePath}/${name}.tmp.m4a`
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
let source = `-i "${videoPath}"`
|
|
103
|
+
const videoMap = `-map 0:v`
|
|
104
|
+
const audioMap = videoPath.startsWith('generate:') ? '-map 1:a' : '-map 0:a'
|
|
105
|
+
if (videoPath === 'generate:null') {
|
|
106
|
+
source =
|
|
107
|
+
`-f lavfi -i color=size=${videoWidth}x${videoHeight}:rate=${videoFramerate}:color=black` +
|
|
108
|
+
` -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=48000`
|
|
109
|
+
} else if (videoPath === 'generate:test') {
|
|
110
|
+
source =
|
|
111
|
+
`-f lavfi -i testsrc=size=${videoWidth}x${videoHeight}:rate=${videoFramerate} -pix_fmt yuv420p` +
|
|
112
|
+
` -f lavfi -i sine=frequency=220:beep_factor=4:sample_rate=48000`
|
|
113
|
+
}
|
|
114
|
+
await runShellCommand(
|
|
115
|
+
`ffmpeg -loglevel warning -y -threads 0 ${source}` +
|
|
116
|
+
` -s ${videoWidth}:${videoHeight}` +
|
|
117
|
+
` -r ${videoFramerate}` +
|
|
118
|
+
` -ss ${videoSeek} -t ${videoDuration} -shortest -af apad` +
|
|
119
|
+
` ${videoMap} ${destVideoPathTmp}` +
|
|
120
|
+
` ${audioMap} -ar 48000 ${destAudioPathTmp}` +
|
|
121
|
+
(destMp4PathTmp
|
|
122
|
+
? ` ${videoMap} -c:v libx264 -crf 10 -f mp4 -movflags faststart ${destMp4PathTmp}` +
|
|
123
|
+
` ${audioMap} -c:a aac -b:a 192k ${destM4aPathTmp}`
|
|
124
|
+
: ''),
|
|
125
|
+
)
|
|
126
|
+
await fs.rename(destVideoPathTmp, destVideoPath)
|
|
127
|
+
await fs.rename(destAudioPathTmp, destAudioPath)
|
|
128
|
+
if (destMp4PathTmp) {
|
|
129
|
+
await fs.rename(destMp4PathTmp, destMp4Path)
|
|
130
|
+
}
|
|
131
|
+
if (destM4aPathTmp) {
|
|
132
|
+
await fs.rename(destM4aPathTmp, destM4aPath)
|
|
133
|
+
}
|
|
134
|
+
} catch (err) {
|
|
135
|
+
log.error(`Error converting video: ${(err as Error).stack}`)
|
|
136
|
+
fs.unlink(destVideoPathTmp).catch(e => log.debug(e.message))
|
|
137
|
+
fs.unlink(destAudioPathTmp).catch(e => log.debug(e.message))
|
|
138
|
+
if (destMp4PathTmp) {
|
|
139
|
+
fs.unlink(destMp4PathTmp).catch(e => log.debug(e.message))
|
|
140
|
+
}
|
|
141
|
+
throw err
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
video: destVideoPath,
|
|
147
|
+
audio: destAudioPath,
|
|
148
|
+
mp4: destMp4Path,
|
|
149
|
+
m4a: destM4aPath,
|
|
150
|
+
}
|
|
151
|
+
}
|