mirror of
https://github.com/davedoesdev/streamana.git
synced 2025-10-04 21:22:40 +08:00
Add ability to select encoder resolution
This commit is contained in:
@@ -44,6 +44,11 @@
|
|||||||
<input id="zoom-portrait" class="form-check-input" type="checkbox">
|
<input id="zoom-portrait" class="form-check-input" type="checkbox">
|
||||||
<label for="zoom-portrait" class="form-check-label">Zoom portrait video</label>
|
<label for="zoom-portrait" class="form-check-label">Zoom portrait video</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pt-4">
|
||||||
|
<label for="resolution" class="form-label">Encoder resolution</label>
|
||||||
|
<select id="resolution" class="form-select">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="error-alert" class="alert alert-danger alert-dismissible fade mb-0 flex-grow-0" role="alert">
|
<div id="error-alert" class="alert alert-danger alert-dismissible fade mb-0 flex-grow-0" role="alert">
|
||||||
<strong>An error occurred!</strong> See the Developer Console for details.
|
<strong>An error occurred!</strong> See the Developer Console for details.
|
||||||
|
@@ -1,6 +1,16 @@
|
|||||||
import { GlCanvas } from './gl-canvas.js';
|
import { GlCanvas } from './gl-canvas.js';
|
||||||
import { HLS } from './hls.js';
|
import {
|
||||||
|
HLS,
|
||||||
|
video_encoder_codec,
|
||||||
|
videoBitsPerSecond
|
||||||
|
} from './hls.js';
|
||||||
import shader from './greyscale-shader.js';
|
import shader from './greyscale-shader.js';
|
||||||
|
import {
|
||||||
|
supported_video_encoder_configs,
|
||||||
|
max_video_encoder_config,
|
||||||
|
min_camera_video_config,
|
||||||
|
max_camera_video_config
|
||||||
|
} from './resolution.js';
|
||||||
|
|
||||||
const ingestion_url_el = document.getElementById('ingestion-url');
|
const ingestion_url_el = document.getElementById('ingestion-url');
|
||||||
ingestion_url_el.value = localStorage.getItem('streamana-example-ingestion-url');
|
ingestion_url_el.value = localStorage.getItem('streamana-example-ingestion-url');
|
||||||
@@ -58,6 +68,42 @@ document.body.addEventListener('click', function (ev) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let preferred_resolution = localStorage.getItem('streamana-resolution');
|
||||||
|
if (preferred_resolution) {
|
||||||
|
preferred_resolution = JSON.parse(preferred_resolution);
|
||||||
|
} else {
|
||||||
|
preferred_resolution = {
|
||||||
|
width: 1280,
|
||||||
|
height: 720,
|
||||||
|
ratio: '16:9'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const resolution_el = document.getElementById('resolution');
|
||||||
|
let video_encoder_config = await max_video_encoder_config({
|
||||||
|
...preferred_resolution,
|
||||||
|
codec: video_encoder_codec,
|
||||||
|
bitrate: videoBitsPerSecond
|
||||||
|
});
|
||||||
|
const video_encoder_configs = new Map();
|
||||||
|
for (let config of await supported_video_encoder_configs({
|
||||||
|
codec: video_encoder_codec,
|
||||||
|
bitrate: videoBitsPerSecond
|
||||||
|
})) {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.innerHTML = `${config.width}x${config.height} — ${config.label}`;
|
||||||
|
option.selected = config.label === video_encoder_config.label;
|
||||||
|
resolution_el.appendChild(option);
|
||||||
|
video_encoder_configs.set(option.innerText, config);
|
||||||
|
}
|
||||||
|
resolution_el.addEventListener('change', function (ev) {
|
||||||
|
video_encoder_config = video_encoder_configs.get(this.value);
|
||||||
|
localStorage.setItem('streamana-resolution', JSON.stringify({
|
||||||
|
width: video_encoder_config.width,
|
||||||
|
height: video_encoder_config.height,
|
||||||
|
ratio: video_encoder_config.ratio
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
let hls;
|
let hls;
|
||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
@@ -150,29 +196,30 @@ async function start() {
|
|||||||
await video_el.play();
|
await video_el.play();
|
||||||
|
|
||||||
// capture video from webcam
|
// capture video from webcam
|
||||||
const video_constraints = {
|
const camera_video_constraints = {
|
||||||
//width: 4096,
|
ratio: video_encoder_config.ratio,
|
||||||
//height: 2160,
|
width: video_encoder_config.width,
|
||||||
width: 1280,
|
height: video_encoder_config.height,
|
||||||
height: 720,
|
|
||||||
//width: 800,
|
|
||||||
//height: 600,
|
|
||||||
frameRate: {
|
frameRate: {
|
||||||
ideal: 30,
|
ideal: 30,
|
||||||
max: 30
|
max: 30
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const camera_video_config = await min_camera_video_config(camera_video_constraints) ||
|
||||||
|
await max_camera_video_config(camera_video_constraints);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
camera_stream = await navigator.mediaDevices.getUserMedia({
|
camera_stream = await navigator.mediaDevices.getUserMedia({
|
||||||
audio: true,
|
audio: true,
|
||||||
video: video_constraints
|
video: camera_video_config
|
||||||
});
|
});
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
// retry in case audio isn't available
|
// retry in case audio isn't available
|
||||||
console.warn("Failed to get user media, retrying without audio");
|
console.warn("Failed to get user media, retrying without audio");
|
||||||
camera_stream = await navigator.mediaDevices.getUserMedia({
|
camera_stream = await navigator.mediaDevices.getUserMedia({
|
||||||
audio: false,
|
audio: false,
|
||||||
video: video_constraints
|
video: camera_video_config
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,9 +2,11 @@ import { UpdateLimiter } from './update-limiter.js';
|
|||||||
import { MuxReceiver } from './mux-receiver.js';
|
import { MuxReceiver } from './mux-receiver.js';
|
||||||
|
|
||||||
const audioBitsPerSecond = 128 * 1000;
|
const audioBitsPerSecond = 128 * 1000;
|
||||||
const videoBitsPerSecond = 2500 * 1000;
|
export const videoBitsPerSecond = 2500 * 1000;
|
||||||
const key_frame_interval = 3;
|
const key_frame_interval = 3;
|
||||||
|
|
||||||
|
export const video_encoder_codec = 'avc1.42E01E' /*'avc1.42001E'*/;
|
||||||
|
|
||||||
export class HLS extends EventTarget {
|
export class HLS extends EventTarget {
|
||||||
constructor(stream, base_url, ffmpeg_lib_url, frame_rate, rotate) {
|
constructor(stream, base_url, ffmpeg_lib_url, frame_rate, rotate) {
|
||||||
super();
|
super();
|
||||||
@@ -54,7 +56,7 @@ export class HLS extends EventTarget {
|
|||||||
console.warn(ex);
|
console.warn(ex);
|
||||||
try {
|
try {
|
||||||
// next try WebCodecs - this should work on Chrome including Android
|
// next try WebCodecs - this should work on Chrome including Android
|
||||||
this.webcodecs('avc1.42E01E' /*'avc1.42001E'*/,
|
this.webcodecs(video_encoder_codec,
|
||||||
'opus' /*'pcm'*/,
|
'opus' /*'pcm'*/,
|
||||||
{ avc: { format: 'annexb' } });
|
{ avc: { format: 'annexb' } });
|
||||||
console.log("Using WebCodecs");
|
console.log("Using WebCodecs");
|
||||||
|
1
site/resolution.js
Symbolic link
1
site/resolution.js
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../webm-muxer.js/resolution.js
|
Submodule webm-muxer.js updated: 24b15abd40...ecc4044d40
Reference in New Issue
Block a user