Я пытаюсь получить кадры из потока Mjpeg в PHP. Я пытался прочитать файл, чтобы прочитать файл, а затем на основе заголовков выборки кадров. Но я не могу этого сделать.
Я могу видеть заголовки, присутствующие в файле, но при использовании exif_read_data, чтобы найти, существуют ли заголовки, он показывает, что заголовков нет.
Мой код для получения кадра:
function grab_frame($url) {
$f = fopen($url, 'r'); //6,168
if($f) {
$r = null;
while(substr_count($r, "Content-Length")!= 5){
$r.= fread($f,40000000);
$start = strpos($img,'F1');
$end = strpos($img,'F2');
$frame = substr($r, $start, $end);
}
fclose($f);
return $frame;
}
}
Я хочу использовать заголовок content-length, чтобы найти длину кадра, а затем извлечь данные всего кадра, а затем повторить цикл, чтобы найти следующий кадр.
Код здесь может помочь вам. Он создаст снимок JPEG из потока MJPEG. Вам нужно будет изменить $ border для соответствия имени границы, найденному в вашем потоке mjpeg. Вы должны быть в состоянии изменить код для захвата нескольких кадров.
(от https://gist.github.com/megasaturnv/81279fca49f2f34b42e77815c9bb1eb8 . код генерирует изображение в теге img в https://gist.github.com/megasaturnv/35578337662acd28e0bcd2946a4b069e)
<?php
//Megasaturnv 2018-01-12
$camurl="http://192.168.1.100:8081/"; // Mjpeg URL
//$camurl="http://username:[email protected]:8081/" // HTTP Auth mjpeg URL (optional)
$boundary="--BoundaryString"; // $boundary = The boundary string between jpegs in an mjpeg stream
//NOTE: $boundary changes between mjpeg stream providers. For example, https://github.com/Motion-Project/motion uses '--BoundaryString'. https://github.com/ZoneMinder/ZoneMinder uses '--ZoneMinderFrame'. To find out $boundary for your stream you will need to save 1 or more frames of the mjpeg and open it with a text editor. --<boundary string> should be visible on the first line
$f = fopen($camurl, "r"); // Open mjpeg url as $f in readonly mode
$r = ""; // Set $r to blank variable
if($f) {
while (substr_count($r,"Content-Length") < 2) // While the number of times "Content-Length" appears in $r is less than 2
$r.=fread($f, 16384); // Append 16384 bytes of $f to $r
$start = strpos("$r", $boundary); // $start is set to the position of the first occurrence of '$boundary' in $r
$end = strpos("$r", $boundary, $start + strlen($boundary)); // $end is essentially set to the position of the second occurrence of '$boundary' in $r. I use $start + strlen($boundary) to offset the start position and skip the first occurrence
$boundaryAndFrame = substr("$r", $start, $end - $start); // $boundaryAndframe is set to the string in $r starting at position $start and with a length of ($end - $start)
$pattern="/(Content-Length:\s*\d*\r\n\r\n)([\s\S]*)/"; // Use regex to search for '(Content-Length: 90777\r\n\r\n)(<jpeg image data>)
preg_match_all($pattern, $boundaryAndFrame, $matches); // Search for regex matches in $boundaryAndFrame
$frame = $matches[2][0]; // $frame is set to the second regex character group (in this case, <jpeg image data>)
header("Content-type: image/jpeg"); // Set header for jpeg image
echo $frame; // Echo the jpeg image data
} else {
echo "Error, cannot open URL"; // Error message if $camurl cannot be opened
}
fclose($f); // Close the url
?>
Мое решение для анализа кадра
function readPixel($url, $x, $y, $callback)
{
$loop = 0;
//Megasaturnv 2018-01-12
// Mjpeg URL
$camurl = $url;
//$camurl="http://username:[email protected]:8081/" // HTTP Auth mjpeg URL (optional)
$boundary="--BoundaryString"; // $boundary = The boundary string between jpegs in an mjpeg stream
//NOTE: $boundary changes between mjpeg stream providers. For example, https://github.com/Motion-Project/motion uses '--BoundaryString'. https://github.com/ZoneMinder/ZoneMinder uses '--ZoneMinderFrame'. To find out $boundary for your stream you will need to save 1 or more frames of the mjpeg and open it with a text editor. --<boundary string> should be visible on the first line
$f = fopen($camurl, "r"); // Open mjpeg url as $f in readonly mode
$r = ""; // Set $r to blank variable
if($f) {
while (true){
$r.=fread($f, 50000);
$startsearch = strpos($r, "Content-Length: ");
if($startsearch!==false){
$r = substr($r, $startsearch+16);
$index=0;
$length = "";
while(true){
$char = substr($r, $index, 1);
$index++;
if(is_numeric($char)){
$length.= $char;
}else{
break;
}
}
$r = substr($r, strlen($length)+4);
$totalbytes = $length-0;
$havebytes=strlen($r);
$remain = $totalbytes-$havebytes;
//echo "Length:$length\n";
//echo "Stream:$r\n";
//echo "HaveBytes $havebytes totalbytes: $totalbytes, Remain: $remain\n";
while($havebytes < $totalbytes){
$r .=fread($f, $totalbytes-$havebytes);
$havebytes = strlen($r);
}
//save/debug image
//file_put_contents("test.jpg", $r);
$im = imagecreatefromstring($r);
//test if image is valid
//$valid = ($im != FALSE);
//echo ($valid?"VALID":"INVALID")."\n";
//echo imagesx($im).'x'.imagesy($im) ."\n";
$rgb = imagecolorat ($im, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
imagedestroy($im);
$loop++;
if($callback($r,$g,$b, $loop)){
echo "TEST colors: $r $g $b\n";
}else{
fclose($f);
return true;
}
$r="";
}
}
} else {
echo "Error, cannot open URL"; // Error message if $camurl cannot be opened
}
fclose($f); // Close the url
}