Tricky math problem with PHP

I’m building a PHP script that will create a time-lapse video from a folder of JPGs, and I’m almost finished, but stuck on the very last step.

I want to allow a user the ability to specify the maximum length in seconds of a video clip. For example, a 10 second maximum length, would mean at 30 frames per second I need to use 300 images to create my clip. If I happen to have 600 images on file, I need to discard 50% of them to make it work. Of course, the percentage of images I need to discard will be different every time.

My problem is I can’t figure out how to tell my main loop building the video how to skip certain frames. And obviously I can’t skip the last 300 frames in a row, I need to skip frames on and off throughout the loop. I’ve been trying to wrap my head around it for half the night, and thought someone much more clever than me might have an idea.

You can’t increase the frame rate?

I could for awhile, but images are automatically continually being added and when I get up to say 10,000 images my framerate is going to be 3000+ fps? That won’t work. 25- 30 fps is ideal for video that’s what I’m aiming for

What I seem to need is a way to express a percentage as a fraction and then grab the denominator. For example 50% is 1/2 so every 2nd clip I discard. Or 20% is 1/5 so every 5th clip I discard. This would work, but I’m not sure how to do that in PHP.

Is 30 fps a reliable constant though?

Yes 30 fps will be constant, I won’t give the user the ability to change this.

$y = number of pictures
$z = number of pictures needed (fps * length in seconds)

$indexes = range(0,$y,($y / $z));
$indexes = array_map('round',$indexes);

$indexes is an array of keys in your picture array.

The idea is that the perfect step is possible when Y = MZ, with M being a positive nonzero integer; if Z is greater than Y, duplicate entries will be created as per Pigeonhole Principle (in reverse.).

I havent used the range function before, but I looked it up in the PHP manual and I think it’s exactly what I need. I am going to plug your formula into my code and I’ll let you know if it works!


Your suggestion worked great, thanks a million!! That range() is a handy function! My code works perfectly and does exactly what I need it to do! Here it is in case you’re interested. Thanks again!

		//***** LOOP 2 *****
		//Loop through selected JPGs and discard some to maintain desired time
		//Adds final JPGs to list.txt for encoding in final step
		//If there are not enough frames, use them all to create the longest video cip possible
		$video_length_in_seconds = $framescount / 30;
		if ($video_length_in_seconds < $maxtime) {
			echo "Clip is shorter than ".$maxtime." seconds, so we will use all the images.<br />";
			foreach ($frames_list as $frame) {
				fwrite($fh, $frame."\\r\
");  //write the filename to a text file and bump down a line
		//If there are too many frames, we must discard some
		else {
			$y = $framescount; //total number of frames that fall within time period selected
			$z = $maxtime * 30; //number of pictures needed (length in seconds * fps)
			echo "Discarding ".($y - $z)." images to keep the clip within ".$maxtime." seconds.<br />";		

			foreach (range(0, $y, ($y / $z)) as $number) {
				//Create a file with the frames we will be keeping
				fwrite($fh, $frames_list[$number]."\\r\
");  //write the filename to a text file and bump down a line
				//echo round($number,0);
				//echo $frames_list[$number];				

			} //end else

The real trick here was realizing that you have to do the rounding AFTER the range is established, rather than rounding the step. Glad it works for you!

PS:you sure it works for you? Not 100% sure off the top of my head how PHP handles float array indicies

It doesn’t, they’re cast to ints (at least on my local machine here on PHP5.3.5 they are)



  3 => int 1
  1 => int 1


Mmmm, pie.[/ot]

In which case, you’ll want to make sure you round() that $number variable, scotts, to ensure you get the proper result. (as casting to int floors, instead of rounds)