Fetch frames from Mjpeg stream in php

mjpg-streamer vs gstreamer
mjpg-streamer no www-folder configured
mjpg-streamer usb camera
mjpg-streamer over internet
mjpg-streamer ubuntu
mjpg-streamer ffmpeg
mjpg-streamer raspberry pi camera module
mjpg-streamer nginx

I'm trying to fetch frames from an Mjpeg stream in PHP. I've tried file read to read file and then on the basis on headers fetch frames. But I'm not able to do it. I'm able to see headers present in file but when using exif_read_data to find if the headers exist, it shows there are no headers. My code to fetch frame is:

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; 
 }
} 

I want to use content-length header to find the frame length and then fetch the whole frame data and then loop again to find next frame.

The code here might help you. It will produce a JPEG snapshot from an MJPEG stream. You will need to change $boundary to match the boundary name found in your mjpeg stream. You should be able to modify the code to capture multiple frames.

(from https://gist.github.com/megasaturnv/81279fca49f2f34b42e77815c9bb1eb8 . code generates image in img tag at https://gist.github.com/megasaturnv/35578337662acd28e0bcd2946a4b069e)

<?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
?>

MjpegFrameGrabPHP < Motion < Foswiki, The PHP program receives the first picture frame of the mjpeg stream to the client browser with headers like it was a jpeg file that was fetched  Motion basically outputs a mjpeg stream. I'd like to use PHP to grab a single jpeg from the mjpeg stream and display it. The reason I'm doing this is because Motion doesn't have any built in password protection. With PHP, I can hide the port and IP address of my home server. I'm trying code provided by the creators of Motion on their website.

read mjpeg raw until complete.

<?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;

?>

grabing a single jpeg frame from mjpeg stream using PHP , The code is suppose to grab just a single jpeg from the mjpeg stream, but I get an error when trying to run it on an nginx server locally. <? $camurl  jpg frames to mjpeg in php. GitHub Gist: instantly share code, notes, and snippets.

My solution to analise frame

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
}

grabing a single jpeg frame from mjpeg stream using PHP, The code is suppose to grab just a single jpeg from the mjpeg stream, but I get an error when trying to run it on an nginx server locally. <? Hello,I have a webcam on a computer running Motion, a webcam streaming program popular in Linux. Motion basically outputs a mjpeg stream. Id like to use PHP to grab a single jpeg from the mjpeg stream and display it. The reason Im doing this is because Motion doesnt have any built in password pro

Streaming images from RaspberryPi to an HTML website, With MJPEG each frame is encoded as an entire JPEG picture. Step 3: Understand what the streaming server is giving us. We have 2 urls which  mjpeg-readable-stream. Code to read an Mjpeg stream using the Readable stream api. This code allows you to get an mjpeg stream using the fetch api and read from a ReadableStream in chunks and extract the jpeg frames and render it on an image or canvas object.

Grabbing a single jpeg frame from mjpeg stream using PHP , The code is suppose to grab just a single jpeg from the mjpeg stream, but I get an error when trying to run it on an nginx server locally. [php]. <? Anyway, still have problem reading mjpeg stream from esp cam using stock media players like VLC but at least I can fetch frame by programmed code so I close this issue. I'm still not sure why media players are not supporting chunked transfer btw.

Rendering MJpeg stream in html5, php mjpeg stream camera mjpeg I'm trying to render MJpeg stream in HTML5 using the img tag. My question is how can I get the stream frame by frame. 1 Fetch frames from Mjpeg stream in php Apr 15 '19. 1 How to read a local text file? Apr 26 '19. 0 Preventing Directory Traversal in PHP but allowing paths Jun 5 '19

Comments
  • Works flawlessly! Thanks!