在PHP中从Mjpeg流中获取帧

时间:2017-05-19 15:34:31

标签: php frame mjpeg

我试图在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; 
 }
} 

我想使用内容长度标头来查找帧长度,然后获取整个帧数据,然后再次循环以查找下一帧。

3 个答案:

答案 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;

?>