Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Save JPG image every second - but avoid saving damaged/corrupt images comprised of multiple images?

saveing jpg image corrupt speed improvment stream video

This topic has been archived. This means that you cannot reply to this topic.
15 replies to this topic

#1 elliottveares

elliottveares

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 56 posts

Posted 24 November 2015 - 09:46 PM

Hi all, my site features a webcam what is a Jpeg image updated every second (or is supposed to be ;) ). The image from the webcam is saved to my virtual server running via the PHP script below what is run in the Cent OS command line on start-up of the server. The image is then refreshed every second in the users browser using JavaScript.

 

The main issue is that occasionally the image being saved gets corrupted and thus the image displayed on the website to the viewers is that of a corrupt one made up of 2-3 images combined in weird ways. See the link here for what I mean: http://www.grottotre...live-setup.html or see the image attached.

 

Now "$picture" in the PHP script below is getting a image from a program called Webcam-XP what in turn gets the image from a hard wired HD Foscam IP cam. The Cam and Webcam-XP software are run locally in my home, the script below is on my 1&1 Virtual server. 

<?php
ini_set('memory_limit','128M');
set_time_limit(0);
ignore_user_abort(true);


$opts = array(
 'http'=>array(

	'timeout' => 0.5,
	'ignore_errors' => '0',
 	'header' => 'Connection: keep-alive' 
	 )
);

$context = stream_context_create($opts);

        
while(1) 
{

$picture = file_get_contents("http://MYIPADDRESS:8008/cam_1.jpg", false,$context);
$fp = fopen("/var/www/vhosts/grottotree.com/httpdocs/jpgs/current_cam_image/cam.jpg", "r+");
fwrite($fp, $picture);



}        

		
?>

Now it's like the PHP can't save the file fast enough and that multiple images get combined OR that there is some other performance bottle neck coming into play regarding the virtual server???. Either way, how do I fix my problem so that no corrupt or incomplete images are saved and thus displayed to the viewers on the site.

 

It's doing my head in knowing how to fix the issue, and I have already tried things like disabling caching under apache for "cam.jpg". It's also to note that I seem to have to rely on timeout as using sleep(x) or usleep(x) in the PHP scripts while loop does not work as the image $picture is never got and saved to $fp .

 

 

 

Virtual Server Environment:

 

Cent OS 6.7 Final

Apache 2.2

PHP 5.6.1

MySQL Ver 14.14 Distrib 5.5.46

 

 

Regards: Elliott of GrottoTree  :thumbup1:



#2 oldhendra

oldhendra

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 52 posts

Posted 26 November 2015 - 01:23 AM

Hi elliottveares,

 

I'm just curious, is it good practice to use while(1){...} thus putting PHP into an infinite-loop? There's no time, not even a single-second for your virtual server on Cent OS to relax.

 

Your "streaming" seems okay though, I starred at it for a couple of minutes and saw no corrupt / incomplete images, viewed from here. Maybe you should put there too on cam, something with slow perpetual-motion... a metronome? :biggrin:

FYI, I browse with old XP machine and my browser is a Firefox 42.

 

A quick look at your http://www.grottotre...js/setup_cam.js :

maybe you should let users' browser to have sometime to finish current image loading too, before loading another. So instead of using setTimeout() function, perhaps you should use image onload event handler?

 

Hendra



#3 jLinux

jLinux

    CC Lurker

  • New Member
  • Pip
  • 6 posts

Posted 26 November 2015 - 09:24 AM

Whoa, dude this is not the best way to go about doing it...

 

Instead of using php to pull that image down and save it every second, why don't you just create an AJAX page to refresh the image every second...

 

If you're going to be overwriting it, then you dont need it locally that bad, obviously.. So just take that step out and use AJAX via jQuery or something to do that. Would be muchhh easier on your server, much less bandwidth, etc



#4 elliottveares

elliottveares

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 56 posts

Posted 26 November 2015 - 05:56 PM

Whoa, dude this is not the best way to go about doing it...

 

Instead of using php to pull that image down and save it every second, why don't you just create an AJAX page to refresh the image every second...

 

 

Because I need to keep the bandwith between my virtual server and server running Webcam XP down, can't have multiple simultaneous connections to my home. Thus the viewers on my site don't saturate my personal upload bandwith by viewing the saved jpg on my server what gets updated every second.



#5 elliottveares

elliottveares

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 56 posts

Posted 26 November 2015 - 06:37 PM

 

A quick look at your http://www.grottotre...js/setup_cam.js :

maybe you should let users' browser to have sometime to finish current image loading too, before loading another. So instead of using setTimeout() function, perhaps you should use image onload event handler?

 

 

Not sure what food that will do, the php script is saving the images corrupted, and simply using the onload event handler will just load them. The script has not been changed in a few years and I did not have this issue last year, although I was using a USB webcam with webcam XP and not a Foscam IP camera.

Could it be CentOS and the file system causing the issues do you think?



#6 jLinux

jLinux

    CC Lurker

  • New Member
  • Pip
  • 6 posts

Posted 26 November 2015 - 09:47 PM

Because I need to keep the bandwith between my virtual server and server running Webcam XP down, can't have multiple simultaneous connections to my home. Thus the viewers on my site don't saturate my personal upload bandwith by viewing the saved jpg on my server what gets updated every second.

 

What i would do if i were you, is use websockets, then use JS to listen to the websocket, then on the websocket server, pull the image ever N seconds, and push it to every client listening to the server. Kinda like a chat server, except only going one way. Instead of a user sending a message that gets sent out to every other user, it just pulls an image and sends it to every viewer.

 

I would think theres a way to take the image that gets pulled and send it to the clients to be displayed, without actually saving it. Could just encode the image and transfer the encoded data


Edited by jLinux, 26 November 2015 - 09:50 PM.


#7 elliottveares

elliottveares

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 56 posts

Posted 26 November 2015 - 10:02 PM

What i would do if i were you, is use websockets, then use JS to listen to the websocket, then on the websocket server, pull the image ever N seconds, and push it to every client listening to the server. Kinda like a chat server, except only going one way. Instead of a user sending a message that gets sent out to every other user, it just pulls an image and sends it to every viewer.

 

I would think theres a way to take the image that gets pulled and send it to the clients to be displayed, without actually saving it. Could just encode the image and transfer the encoded data

 

And how would I do/implement that?? What are websockets?



#8 jLinux

jLinux

    CC Lurker

  • New Member
  • Pip
  • 6 posts

Posted 27 November 2015 - 12:57 AM

And how would I do/implement that?? What are websockets?

 

Websockets, think of Apache as a really advanced websocket program, you can also create basic ones in PHP, as well as Javascript/jQuery. I would create the server in PHP, then create the clients in jQuery if I were you. All it is is a server that has a web socket open, and waits for clients to connect, then can accept and receive data. I think the main restriction is that IE8 doesnt support websockets.. I think.

 

Here are some resources I have bookmarked from when I was going to create a PHP websocket (Switched to NodeJS/React)

 

The http://socketo.me/ one I think might be the most useful.



#9 oldhendra

oldhendra

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 52 posts

Posted 27 November 2015 - 01:24 AM

 

Not sure what food that will do, the php script is saving the images corrupted, and simply using the onload event handler will just load them. The script has not been changed in a few years and I did not have this issue last year, although I was using a USB webcam with webcam XP and not a Foscam IP camera.

Yeah I wish all my code lasts forever too,

but browsers do change and so does the code.

Even in months time range, no?

 

For client-side, you may want to this as a test:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>2015's GrottoTree Setup!</title>
		<style>
			body:after{
				margin: 0.5em;
				content: ' ';
				display: table;
				clear: both;
			}
			img{
				display: block;
				max-width: 100%;
				height: auto;
				float: left;
				margin: auto 1em 1em auto;
			}
			div{
				float: left;
			}
			label{
				display: block;
				text-align: right;
			}
		</style>
	</head>
	<body>
		<img id="setup_cam_image"
			src="http://www.grottotree.com/jpgs/current_cam_image/cam.jpg" alt="Webcam">
		<div>
			<label>
				<span>Additional delay [ms]:</span>
				<input id="delay" value="1000" type="number" min="0" step="10">
			</label>
			<label>
				<span>Speed at client-side [frames/s]:</span>
				<input id="speed" type="text" readonly>
			</label>
			<label>
				<span>Error:</span>
				<input id="err" value="" type="text" readonly>
			</label>
		</div>
		
		<script>
			+function(){
				var updateT = null,
					updateFn = function(){
						img.src = src + '?t=' + tNow;
					},
					src = 'http://www.grottotree.com/jpgs/current_cam_image/cam.jpg',
					img = document.getElementById('setup_cam_image'),
					delay = document.getElementById('delay'),
					speed = document.getElementById('speed'),
					err = document.getElementById('err'),
					tPast,
					tNow = (new Date()).getTime();
					
				img.onerror = function(){
					err.value = 'Error just occured.';
				};
				
				img.onload = function(){
					tPast = tNow;
					tNow = (new Date()).getTime();
					speed.value = (1000 / (tNow - tPast)).toFixed(3);
					updateT = setTimeout(updateFn, delay.value);
				};
			}();
		</script>
	</body>
</html>

Note:

Try to speed-up by reducing number of "Additional delay [ms]"

 

 

Could it be CentOS and the file system causing the issues do you think?

Umm I don't know, sorry.

I still think that while(1) loop shouldn't be there. It feels like that there's somekind of a... "race-condition" happening: your server-side script is writing a file while your users browser is grabbing it.

 

Untested but for server-side, have you tried something like this "test.php" below?

//ref: http://php.net/manual/en/function.imagejpeg.php

//load from webcam to mem
$img = imagecreatefromjpeg('http://MYIPADDRESS:8008/cam_1.jpg');

//mem to requesting browser buffer
header('Content-Type: image/jpeg');
imagejpeg($img, NULL, 90);

//clean up mem
imagedestroy($img);

To use it, change line #54 of client-side code in my previous post to:

src = 'test.php',

Good luck!


Argh,

my posts merged somehow :confused:

 

It's not "in my previous post". It should say "in this same post".

 

Sorry



#10 elliottveares

elliottveares

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 56 posts

Posted 27 November 2015 - 03:23 AM

Thanks for the replys everyone;  oldhendra's idea is neat although wouldn't that just run "test.php" for every client on the side, defeating the purpose of only having 1 connection between the virtual server and the Win XP server  in my house running Webcam-XP. 

 

For the websocket based idea, I feel it's a bit beyond the scope of what I can do, plus I have got to keep maximum comparability across web browsers.

 

I have improved my PHP script though, and while not 100%, it's better than before.

<?php
ini_set('memory_limit','128M');
set_time_limit(0);
ignore_user_abort(true);


$opts = array(
'http'=>array(

    'timeout' => 0.5,
    'ignore_errors' => '0',
    'header' => 'Connection: keep-alive'
     )
);

$context = stream_context_create($opts);


while(1)
{

$picture = file_get_contents("http:///MYIPADDRESS:8008/cam_1.jpg", false,$context);sleep(1);
$fp = fopen("/var/www/vhosts/grottotree.com/httpdocs/jpgs/current_cam_image/cam.jpg", "r+");
fwrite($fp, $picture);



}

        
?>
 

Also how could I improve my PHP script above without lots of work. I can also confirm that the corrupt pictures are being created/saved by the PHP script and it is not just an issue of the client side script not fully loading them.

 

Regards: Elliott


Edited by elliottveares, 27 November 2015 - 08:37 AM.


#11 oldhendra

oldhendra

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 52 posts

Posted 27 November 2015 - 04:49 AM

 

...oldhendra's idea is neat although wouldn't that just run "test.php" for every client on the side, defeating the purpose of only having 1 connection between the virtual server and the Win XP server  in my house running Webcam-XP...

 

I think you're right.

Though that's what PHP is best at. Well, I guess while(1) is unavoidable in your case...

 

As for avoiding image corruption,

(if I were right thinking that the cause is a "race-condition") then perhaps you should test using flock(). This should make users to wait your script to complete writing image first.

 

That was quite long time ago though and I've already lost the logic / mechanism behind it :( The idea is probably like below:

while(1){
  $picture = file_get_contents("http://MYIPADDRESS:8008/cam_1.jpg", false,$context);
  $fp = fopen("/var/www/vhosts/grottotree.com/httpdocs/jpgs/current_cam_image/cam.jpg", "r+");
  if (flock($fp, LOCK_EX)) {  // if an exclusive lock is acquired,
    fwrite($fp, $picture); //write file,
    flock($fp, LOCK_UN);    // done writing, release the lock,
    sleep(1); // and allow users to read file, else make them to wait.
  }  
}

Edited by oldhendra, 27 November 2015 - 09:02 AM.


#12 elliottveares

elliottveares

    CC Resident

  • Advanced Member
  • PipPipPipPip
  • 56 posts

Posted 27 November 2015 - 08:39 AM

Oops I revealed my Private Static IP :eek: , oldhendra can you please edit your post to hide my private home IP address. It's static, so don't really want it in the public domain.






Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download