Cope with resolution changes when rotate

Add swap facing mode icon in preparation for implementing
facing mode change
This commit is contained in:
David Halls
2021-08-20 12:39:32 +01:00
parent 47b35d34bb
commit e863e4443e
3 changed files with 37 additions and 10 deletions

View File

@@ -12,3 +12,7 @@ canvas.zoom {
.navbar-light .navbar-toggler-icon { .navbar-light .navbar-toggler-icon {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z'/%3E%3C/svg%3E");
} }
.camera-swap-icon {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z'/%3E%3Cpath fill-rule='evenodd' d='M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z'/%3E%3C/svg%3E") !important;
}

View File

@@ -28,6 +28,11 @@
</div> </div>
</div> </div>
</div> </div>
<div id="camera-swap" class="col-sm col-auto order-0 d-none">
<button type="button" class="navbar-toggler">
<span class="navbar-toggler-icon camera-swap-icon"></span>
</button>
</div>
</div> </div>
</div> </div>
</nav> </nav>

View File

@@ -53,6 +53,8 @@ lock_portrait_el.addEventListener('input', function () {
localStorage.setItem('streamana-lock-portrait', this.checked ? 'true' : ''); localStorage.setItem('streamana-lock-portrait', this.checked ? 'true' : '');
}); });
let facing_mode = localStorage.getItem('streamana-facing-mode') || 'user';
function collapse_nav() { function collapse_nav() {
const collapse = bootstrap.Collapse.getInstance(document.getElementById('navbarToggleExternalContent')); const collapse = bootstrap.Collapse.getInstance(document.getElementById('navbarToggleExternalContent'));
if (collapse) { if (collapse) {
@@ -107,6 +109,8 @@ resolution_el.addEventListener('change', function (ev) {
})); }));
}); });
const camera_swap_el = document.getElementById('camera-swap');
let hls; let hls;
async function start() { async function start() {
@@ -186,6 +190,7 @@ async function start() {
resolution_el.disabled = false; resolution_el.disabled = false;
waiting_el.classList.add('d-none'); waiting_el.classList.add('d-none');
canvas_el.classList.add('d-none'); canvas_el.classList.add('d-none');
camera_swap_el.classList.add('d-none');
} }
try { try {
@@ -204,12 +209,13 @@ async function start() {
// capture video from webcam // capture video from webcam
const camera_video_constraints = { const camera_video_constraints = {
width: 4096, width: video_encoder_config.width,
height: 2160, height: video_encoder_config.height,
frameRate: { frameRate: {
ideal: 30, ideal: 30,
max: 30 max: 30
} },
facingMode: facing_mode
}; };
try { try {
@@ -226,6 +232,10 @@ async function start() {
}); });
} }
const video_settings = camera_stream.getVideoTracks()[0].getSettings();
facing_mode = video_settings.facingMode || 'user';
localStorage.setItem('streamana-facing-mode', facing_mode);
canvas_el.addEventListener('webglcontextlost', cleanup); canvas_el.addEventListener('webglcontextlost', cleanup);
// use glsl-canvas to make managing webgl stuff easier // use glsl-canvas to make managing webgl stuff easier
@@ -249,7 +259,6 @@ async function start() {
console.log(`encoder resolution: ${video_encoder_config.width}x${video_encoder_config.height}`); console.log(`encoder resolution: ${video_encoder_config.width}x${video_encoder_config.height}`);
// set aspect ratios of video and encoder // set aspect ratios of video and encoder
const ar_video = this.videoWidth / this.videoHeight;
const ar_encoder = video_encoder_config.ratio; const ar_encoder = video_encoder_config.ratio;
const ar_encoder_inv = 1/ar_encoder; const ar_encoder_inv = 1/ar_encoder;
@@ -259,8 +268,7 @@ async function start() {
// check whether we're locking portrait mode or zooming (display without bars) // check whether we're locking portrait mode or zooming (display without bars)
let zoom_video = zoom_video_el.checked; let zoom_video = zoom_video_el.checked;
const portrait = ar_video < 1; if ((this.videoWidth < this.videoHeight) && lock_portrait_el.checked) {
if (portrait && lock_portrait_el.checked) {
lock_portrait = true; lock_portrait = true;
// rotate the canvas // rotate the canvas
canvas_el.classList.add('rotate'); canvas_el.classList.add('rotate');
@@ -296,7 +304,7 @@ async function start() {
// capture video from the canvas // capture video from the canvas
// Note: Safari on iOS doesn't get any data, might be related to // Note: Safari on iOS doesn't get any data, might be related to
// https://bugs.webkit.org/show_bug.cgi?id=181663 // https://bugs.webkit.org/show_bug.cgi?id=181663
const frame_rate = camera_stream.getVideoTracks()[0].getSettings().frameRate; const frame_rate = video_settings.frameRate;
canvas_stream = canvas_el.captureStream(frame_rate); canvas_stream = canvas_el.captureStream(frame_rate);
// add audio if present // add audio if present
@@ -305,9 +313,11 @@ async function start() {
canvas_stream.addTrack(audio_tracks[0]); canvas_stream.addTrack(audio_tracks[0]);
} }
function update() { const update = () => {
// update the canvas // update the canvas
if (gl_canvas.onLoop()) { if (gl_canvas.onLoop()) {
const ar_video = this.videoWidth / this.videoHeight;
// Note: we need to use canvas_el_parent.parentNode.offsetWidth // Note: we need to use canvas_el_parent.parentNode.offsetWidth
// to take into account margins // to take into account margins
let width, height; let width, height;
@@ -364,11 +374,18 @@ async function start() {
canvas_el.style.height = `${height}px`; canvas_el.style.height = `${height}px`;
// TODO: // TODO:
// select which camera to use (front/rear)? // select which camera to use (front/rear)?
// have an icon which click to swap between user and environment
// we'll need to close the camera stream and start it again
// but leave the canvas going
// check behaviour when rotate phone
// chrome bug when rotate (sometimes half page doesn't render)
// chrome inspect not working
// allow select audio and video devices
// performance on mobile
// a40 no buffers currently available in the reader queue // a40 no buffers currently available in the reader queue
// windows, android, iOS, find a mac to test // windows, android, iOS, find a mac to test
// check behaviour when rotate phone
} }
} };
// start HLS from the canvas stream to the ingestion URL // start HLS from the canvas stream to the ingestion URL
hls = new HLS(canvas_stream, ingestion_url, ffmpeg_lib_url, frame_rate, lock_portrait); hls = new HLS(canvas_stream, ingestion_url, ffmpeg_lib_url, frame_rate, lock_portrait);
@@ -388,6 +405,7 @@ async function start() {
this.end(true); this.end(true);
} }
waiting_el.classList.add('d-none'); waiting_el.classList.add('d-none');
camera_swap_el.classList.remove('d-none');
canvas_el.classList.remove('invisible'); canvas_el.classList.remove('invisible');
go_live_el.disabled = false; go_live_el.disabled = false;
update(); update();