FFMpeg working in command line but not in PHP using exec(); - php

I am using FFMpeg to covert videos and it is working fine from the command line. I am using the following command:
ffmpeg -i input.mpg -vcodec libx264 -b 819200 -s 100x100 -g 15 -bf 3 -b_strategy 1 -coder 1 -qmin 10 -qmax 51 -sc_threshold 40 -flags +loop -cmp +chroma -me_range 16 -me_method hex -subq 5 -i_qfactor 0.71 -qcomp 0.6 -qdiff 4 -directpred 1 -flags2 +fastpskip -dts_delta_threshold 1 -acodec libfaac -ab 48000 output.m4v
However, when I run the command using PHP exec(), the output video is not encoded correctly and is distorted and cropped. I am using the following in PHP:
$output = exec($cmd . ' 2>&1', $output, $return);
The $output returns a '0' successful code.
Does any one have any suggestions?
Thank you.

This is unusual. It is possible that you have more than one ffmpeg binary installed, and the one that is being called by the PHP/Apache user is not the same as the one you call as your user from the command line.
Try specifying the full path to your ffmpeg binary (/usr/bin/ffmpeg or whatever) inside your exec().

It sounds like some command line options are getting lost/altered. I would try to split this into a 2 part process:
write a shell script on-the-fly (from PHP) that has all the proper command arguments (make it executable)
execute the shell script (from PHP)

I would probably try:
1) change ' 2>&1' to ' 2>&1 &'
Also, transcoding can take a while. Are you certain you are waiting long enough for the transcode to complete?

Related

Track PHP memory usage from command line

I can use both ini_set('memory_limit', '512M'); in the file and php -d memory_limit=512M from the command line, but can also trace memory usage from terminal?
I know I can use memory_get_usage() inside a PHP file, but how to trace it from the command line?
Try:
$ watch -n 5 'php -r "var_dump(memory_get_usage());"'
This will watch every 5 seconds the memory state
Or may be you can use the 'ps' tool:
$ ps -F -C php-cgi
Output:
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
http 10794 10786 0 4073 228 0 Jun09 ? 00:00:00 /usr/bin/php-cgi
RSS is the Real-memory (resident set) size in kilobytes of the process.
The solution I was looking for with a simple output is
watch -n 5 'php -r "echo (string) memory_get_usage(true)/pow(10, 6);"'
Will return how many MB the PHP process is using.
2.097152
NOTICE: Solution like ps -F -C php-cgi on macOS machines will fail with
ps: illegal option -- F

Reduce FFmpeg CPU Usage with cpulimit and PHP

I run FFmpeg on my server using PHP exec().
It currently uses 100% of the cpu thread while encoding.
I followed this gude that uses a program called cpulimit to reduce it to 30%.
PHP
$args = "nice -19 cpulimit -l 30 -- ffmpeg -y -i intput.avi -vcodec libx264 -acodec aac -b:a 192k -threads 1 output.mp4"
exec(escapeshellcmd($args));
FFmpeg/PHP works, and it will work with nice/cpulimit through the terminal, but after adding
nice -19 cpulimit -l 30 -- to the PHP script it no longer works with exec().
Output
FFmpeg output returns blank. I'm not able to see the full output, I tried using:
$output = shell_exec($args);
echo "<p>$output</p>"
and
file_put_contents("/var/www/mysite/logs/$output.log", $line . PHP_EOL, FILE_APPEND);
But they return 1 empty line.
Solution
My thought is that www-data runs FFmpeg and nice/cpulimit may need root?
How can I get PHP exec() to work with FFmpeg args and cpulimit?
Or is there an alternative way to limit the usage %?
If safemode is enabled then, the execution of programes are limited. Check this documentation here, http://php.net/manual/en/function.exec.php
I found the answer on this forum post using google translate.
https://murobbs.muropaketti.com/threads/nice-komento-ja-php-n-exec-funktio-ratkaistu.551174/
Define the path to FFmpeg if using nice or cpulimit
nice -19 cpulimit -l 30 /usr/local/bin/ffmpeg -i ...
Now it works through PHP exec().

Change ffmpeg snapshot filenames using PHP

I'm using ffmpeg to generate snapshot from an existing file, the command line is:
ffmpeg -ss 0:00 -f image2 -r 0.2 -s 640*480 test_%d.jpg -i media.flv
After exec the command line above the process start and will generate snapshot pics every 5 seconds, name start from test_1.jpg(test_1.jpg, test_2.jpg, test_3.jpg, etc).
But now I want the generated names start from test_0.jpg, and the step is 5(that is: test_0.jpg, test_5.jpg, test_10.jpg, etc)
Can anyone help me what should I do? (I'm using PHP). Thanks.
Cache your last number by saving it in the database or you using local file to write the last number reached in your exec and when you retrieving it back increase it by 5
//get your var from your database or from your cache file if it was empty leave it 0
$mycachednum = 0;
exec("ffmpeg -ss 0:00 -f image2 -r 0.2 -s 640*480 test_$mycachednum.jpg -i media.flv");
//save it
$mycachednum = $mycachednum + 5;

How to pipe a new command after ffmpeg background process completes?

This is my ffmpeg process:
exec("/usr/local/bin/ffmpeg -y -i source.avi dest.mp4 >/dev/null 2>/dev/null &
Now, I wish to execute a PHP file after the conversion is complete. Logically, this is what I have:
exec("/usr/local/bin/ffmpeg -y -i source.avi dest.mp4 >/dev/null 2>/dev/null ; php proceed.php &
This doesn't work though, since then PHP will hold up the process to wait till the ffmpeg conversion is complete. What I want is basically to call proceed.php after the conversion completes, both of which are done in the background.
If anyone can provide the Windows server solution, that will be awesome too.
Write an external (bash/php) script that executes both the ffmpeg and php process, and tack & after that.
For windows, please open a new question on SO.
To add on to what Evert had posted, here is an example of what I use for my FFMPEG bash script... it's far from done (it doesn't alert if the program crashes, for instance) but it's somewhere to start:
#!/bin/sh
## Set our paths
FFMPEG_PATH=/usr/local/bin
SITE_PATH=path_to_file
VIDEO_PATH=$SITE_PATH/public_html/videos
## Make sure we have permissions to do this stuff
chown -R wwwrun:www $VIDEO_PATH/$2
chmod -R 765 $VIDEO_PATH/$2
## Set the options for mp4 compression
options="-vcodec libx264 -b 512k -ar 22050 -flags +loop+mv4 -cmp 256 \
-partitions +parti4x4+parti8x8+partp4x4+partp8x8+partb8x8 \
-me_method hex -subq 7 -trellis 1 -refs 5 -bf 3 \
-flags2 +bpyramid+wpred+mixed_refs+dct8x8 -coder 1 -me_range 16 \
-g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qmin 10\
-qmax 51 -qdiff 4"
## Start the conversion.
$FFMPEG_PATH/ffmpeg -y -i $VIDEO_PATH/$2/original/$1 -an -pass 1 -threads 2 $options $VIDEO_PATH/$2/$2.mp4 2> $VIDEO_PATH/$2/pass_one.log
$FFMPEG_PATH/ffmpeg -y -i $VIDEO_PATH/$2/original/$1 -acodec libfaac -ab 96k -pass 2 -threads 2 $options $VIDEO_PATH/$2/$2.mp4 2> $VIDEO_PATH/$2/pass_two.log
## Create the thumbnail for the video
. $SITE_PATH/bin/create_thumbnail $2 00:00:15 2> $VIDEO_PATH/$2/generate_thumbnails.log
## Clean up the log files that were created
## find /log_path/ -name *log* -exec rm {} \;
## Update datbase and send email that we're done here.
php $SITE_PATH/public_html/admin/includes/video_status.php converting_finished $2
And this all gets called from a PHP file that does (along with some other code):
proc_close(proc_open(server_path.'/bin/convert_video_mp4 '.mysql_result($next_video, 0, "uid").'.'.mysql_result($next_video, 0, "original_ext").' '.mysql_result($next_video, 0, "uid").' &', array(), $foo));
PS - I know mysql extension are on their way out, I haven't been using or updating this code in a while, so please update to your specifications

how to convert video from one format to another using php

hi i want to include the vedio download option in my webpage. I am using ffmpeg, but it seems to work very slow. Is there is any other way to do this or how to spead up the ffmpeg.
i am using this code to get the frames from the vedio.
to convert the vedio
$call="ffmpeg -i ".$_SESSION['video_to_convert']." -vcodec libvpx -r 30 -b ".$quality." -acodec libvorbis -ab 128000 -ar ".$audio." -ac 2 -s ".$size." ".$converted_vids.$name.".".$type." -y 2> log/".$name.".txt";
$convert = (popen("start /b ".$call, "r"));
pclose($convert);
to get the frame from the vedio
exec("ffmpeg -vframes 1 -ss ".$time_in_seconds." -i $converted_vids video_images.jpg -y 2>);
but this code does not generate any error its loading continously.
Cache or pre-generate the output format.
Use the ffmpeg-php library. Should boost up some processes rather then manually calling the ffmpeg command line tool using exec.
I'd first of all take PHP out of the equasion and time how long it takes to do what you're after via the command line.
Once you're happy that works the way you'd like it to, make sure you've tweaked your script's execution time (see http://php.net/manual/en/function.set-time-limit.php) to accomodate what's likely to take a while.
Consider an async approach if it's getting in the way of UX.
Ta

Categories