我试图在PHP中从Mjpeg流中获取帧。我已经尝试过文件读取读取文件,然后基于标头获取帧。但是我无法做到。 我能够在文件中看到标题,但是当使用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;
}
}
我想使用内容长度标头来查找帧长度,然后获取整个帧数据,然后再次循环以查找下一帧。
答案 0 :(得分:1)
此处的代码可能会对您有所帮助。它将从MJPEG流生成JPEG快照。您需要更改$ boundary以匹配mjpeg流中找到的边界名称。您应该能够修改代码以捕获多个帧。
(来自https://gist.github.com/megasaturnv/81279fca49f2f34b42e77815c9bb1eb8。代码在https://gist.github.com/megasaturnv/35578337662acd28e0bcd2946a4b069e)
的img标签中生成图片<?php
//Megasaturnv 2018-01-12
$camurl="http://192.168.1.100:8081/"; // Mjpeg URL
//$camurl="http://username:password@192.168.1.100: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
?>
答案 1 :(得分:0)
我对肛门镜架的解决方案
function readPixel($url, $x, $y, $callback)
{
$loop = 0;
//Megasaturnv 2018-01-12
// Mjpeg URL
$camurl = $url;
//$camurl="http://username:password@192.168.1.100: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
}
答案 2 :(得分:0)
读取mjpeg原始文件,直到完成。
<?php
$camurl="http://admin:pazz@192.168.137.252:80/getimage"; // Mjpeg URL
$f = fopen($camurl, "r");
$r = "";
if($f) {
// unless 1 frame raw read.
while (substr_count($r, "\xFF\xD8")<2) $r.=fread($f, 8192);
}
// clip frame out raw
$start = strpos($r, "\xFF\xD8");
$end = strpos($r, "\xFF\xD9", $start)+2;
$frame = substr($r, $start, $end-$start);
Header("Content-type: image/jpeg");
echo $frame;
?>