来自网络摄像头的 WebRTC 快照并将其保存到 PHP 中的服务器:iPhone Safari 在分辨率高于 2096 时崩溃

WebRTC snapshot from webcam and save it to server in PHP : iPhone Safari crashes when resolution higher than 2096

我有一个工作代码可以从网络摄像头拍摄快照并通过 ajax 将其保存在 PHP 中...但是当我尝试使用高于 2000 的分辨率时,safari mobile 在 iPhone 崩溃,为什么以及如何解决这个问题?

在这里,如果我这样做 getUserMedia({ video:{width: { ideal: 2096 => 没问题

但是如果我 getUserMedia({ video:{width: { ideal: 3096 => 它崩溃了:(

HTML

<video id="precam" playsinline="true" muted autoplay style="max-width:90%;" ></video>
<canvas id="canvax" ></canvas>
<div onclick="sendToServer('ajaxanswer');">SAVE</div>
<div onclick="webcamFRONT();">SWITCH TO FRONT CAM</div>
<div id="ajaxanswer" ></div>

JAVASCRIPT

<script>
const videoPlayer = document.querySelector("#precam"); 
const canvas = document.querySelector("#canvax");

function webcamREAR () {
    navigator.mediaDevices.getUserMedia({ video:{width: { ideal: 2096 },facingMode: "environment"}, audio:false })
        .then(stream => videoPlayer.srcObject = stream)
        .catch(error => {console.error(error);});
}

function webcamFRONT () {
    navigator.mediaDevices.getUserMedia({ video:{width: { ideal: 2096 },facingMode: "user"}, audio:false })
        .then(stream => videoPlayer.srcObject = stream)
        .catch(error => {console.error(error);});
}
        
function wcanvasim () { 
    canvas.width = videoPlayer.videoWidth; canvas.height = videoPlayer.videoHeight;
    canvas.getContext("2d").drawImage(videoPlayer, 0, 0, canvas.width, canvas.height);
}

webcamREAR();

function sendToServer (divID) {
    var pcache = (Math.floor(Math.random() * 100000000) + 1);
    var params = "divID="+encodeURIComponent(divID)+"&canvablob="+encodeURIComponent(canvas.toDataURL());
    var xhr = new XMLHttpRequest(); xhr.open("POST", "/file.php?pcache="+pcache, true);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.onreadystatechange = function(e) { if (xhr.readyState == 4) { $("#"+divID).html(e.currentTarget.responseText) ; } }
    xhr.send(params);
}
</script>

PHP

<?php

$whereTOdeBlob = '/path/to/server/'.mt_rand().'.png';
$canvablob = ( $_REQUEST['canvablob'] ?? '' ) ;
$canva64 = explode('base64,',$canvablob)[1] ?? '';
file_put_contents(INCLUDE_PATH_ROOT.$whereTOdeBlob,base64_decode($canva64));

// CONVERT TO JPG
// ADD TO DATABASE
// ANY STUFF YOU WANT ;)

echo '<img src="'.$canvablob.'" />';

?>

******* 问题是:为什么大分辨率会使 safari 手机崩溃?

您使用.toDataURL() to encode that huge image as a lossless .png file. That probably generates a multimegabyte string that you try to POST. Somewhere along the way Safari probably runs out of contiguous RAM and gacks, either on allocation or garbage collection. It's also likely your POST's payload size exceeds php's maximum.

尝试 .toDataURL('image/jpeg', 0.3) 以获得低质量 JPEG image,这将生成更小的字符串。如果可行,请提高质量(0.3 到 0.4、0.5 等)。

或者,更好的是,转换您的 canvas to a binary Blob,然后 post 那个。与数据 URL 相比,它需要的 space 更少。像这样的东西。不是,重复不是,已调试。

function sendToServer (divID) {
    var pcache = (Math.floor(Math.random() * 100000000) + 1)
    canvas.toBlob (function (blob) {
      var xhr = new XMLHttpRequest()
      xhr.open("POST", "/file.php?pcache="+pcache, true);
      xhr.onreadystatechange = function (e) { 
        if (xhr.readyState == 4) 
           $("#"+divID).html(e.currentTarget.responseText) 
      }

      var fd = new FormData();
      fd.append('divID', divID)
      fd.append('canvaBlob', blob)
      xhr.send(fd)
    }, 'image/jpeg', 0.8)
}

此外,请尝试限制图像的高度和宽度。如果您的相机处于纵向模式并且您要求 2K 宽度,如果您让 .getUserMedia() 选择它想要的任何高度,您可能会得到 4K 高度;它遵循默认的纵横比。

最后,在实际意义上,如此高分辨率的图像在使用之前通常必须进行下采样。较低分辨率的 JPEG 图像通常可以满足实际要求。因此,只需捕获分辨率较低的图像即可。 (如果您是一名摄影师,拍摄的照片要打印在精美的杂志上,那么您已经知道 iPhone 相机的局限性。)