mirror of
https://github.com/davedoesdev/streamana.git
synced 2025-10-22 21:19:23 +08:00
Display portrait video correctly
This commit is contained in:
7
site/example.css
Normal file
7
site/example.css
Normal file
@@ -0,0 +1,7 @@
|
||||
.portrait {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%) rotate(-90deg);
|
||||
width: unset !important;
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
<head>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4" crossorigin="anonymous"></script>
|
||||
<link href="./example.css" rel="stylesheet">
|
||||
<script type="module" src="./example.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -31,7 +32,7 @@
|
||||
<strong>An error occurred!</strong> See the Developer Console for details.
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="position-relative">
|
||||
<div class="position-relative h-100">
|
||||
<canvas id="canvas" class="w-100" playsinline></canvas>
|
||||
<div class="position-fixed top-50 start-50 translate-middle">
|
||||
<div id="waiting" class="text-primary spinner-border d-none" role="status">
|
||||
|
@@ -44,11 +44,11 @@ async function start() {
|
||||
|
||||
go_live_el.disabled = true;
|
||||
waiting_el.classList.remove('d-none');
|
||||
const parent_el = canvas_el.parentNode;
|
||||
parent_el.removeChild(canvas_el);
|
||||
const canvas_el_parent = canvas_el.parentNode;
|
||||
canvas_el_parent.removeChild(canvas_el);
|
||||
canvas_el = canvas_proto.cloneNode();
|
||||
canvas_el.classList.add('invisible');
|
||||
parent_el.appendChild(canvas_el);
|
||||
canvas_el_parent.appendChild(canvas_el);
|
||||
|
||||
if (error_alert_el.parentNode) {
|
||||
error_alert_el_parent.removeChild(error_alert_el);
|
||||
@@ -146,13 +146,16 @@ async function start() {
|
||||
video_el.addEventListener('loadeddata', async function () {
|
||||
try {
|
||||
// make canvas same size as native video dimensions so every pixel is seen
|
||||
if (this.videoWidth > this.videoHeight) {
|
||||
canvas_el.width = this.videoWidth;
|
||||
canvas_el.height = this.videoHeight;
|
||||
} else {
|
||||
const portrait = this.videoHeight > this.videoWidth;
|
||||
if (portrait) {
|
||||
canvas_el.width = this.videoHeight;
|
||||
canvas_el.height = this.videoWidth;
|
||||
canvas_el.classList.add('portrait');
|
||||
} else {
|
||||
canvas_el.width = this.videoWidth;
|
||||
canvas_el.height = this.videoHeight;
|
||||
}
|
||||
gl_canvas.setUniform('u_portrait', portrait);
|
||||
|
||||
// start the camera video
|
||||
this.play();
|
||||
@@ -169,6 +172,13 @@ async function start() {
|
||||
canvas_stream.addTrack(audio_tracks[0]);
|
||||
}
|
||||
|
||||
function update() {
|
||||
// update the canvas
|
||||
if (gl_canvas.onLoop() && portrait) {
|
||||
canvas_el.style.height = canvas_el_parent.clientWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// start HLS from the canvas stream to the ingestion URL
|
||||
hls = new HLS(canvas_stream, ingestion_url, ffmpeg_lib_url, frame_rate);
|
||||
hls.addEventListener('run', () => console.log('HLS running'));
|
||||
@@ -186,11 +196,9 @@ async function start() {
|
||||
waiting_el.classList.add('d-none');
|
||||
canvas_el.classList.remove('invisible');
|
||||
go_live_el.disabled = false;
|
||||
gl_canvas.onLoop();
|
||||
});
|
||||
hls.addEventListener('update', () => {
|
||||
gl_canvas.onLoop();
|
||||
update();
|
||||
});
|
||||
hls.addEventListener('update', update);
|
||||
await hls.start();
|
||||
} catch (ex) {
|
||||
cleanup(ex);
|
||||
|
@@ -42,7 +42,9 @@ export class GlCanvas extends Canvas {
|
||||
// Better to "support" only hardware rendering (or very fast CPUs!), where
|
||||
// time to render each frame is only 1ms max.
|
||||
this.update_limiter.threshold = (Date.now() - now) * 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Prevent errors after destruction
|
||||
destroy() {
|
||||
|
@@ -4,17 +4,16 @@ precision highp float;
|
||||
|
||||
uniform sampler2D u_texture;
|
||||
uniform vec2 u_resolution;
|
||||
uniform bool u_portrait;
|
||||
|
||||
out vec4 colour;
|
||||
|
||||
void main() {
|
||||
vec2 coord;
|
||||
// TODO: we should pass in whether to invert
|
||||
ivec2 size = textureSize(u_texture, 0);
|
||||
if (size.x > size.y) {
|
||||
coord = gl_FragCoord.xy / u_resolution.xy;
|
||||
} else {
|
||||
if (u_portrait) {
|
||||
coord = gl_FragCoord.yx / u_resolution.yx;
|
||||
} else {
|
||||
coord = gl_FragCoord.xy / u_resolution.xy;
|
||||
}
|
||||
vec3 color = texture(u_texture, coord).rgb;
|
||||
float grey = dot(color, vec3(0.299, 0.587, 0.114));
|
||||
|
Reference in New Issue
Block a user