run ffmpeg from PHP web script - php

I need to manage the recording/capture of a website mindwhile it is running a slide-show to get videos form these slides.
My approach is:
<?php
define('FFMPEG_LIBRARY', '/usr/bin/ffmpeg ');
$ffmpegcmd = "ffmpeg -f x11grab -r 25 -s 800x600 -i :0.0 /tmp/output.mpg";
shell_exec($ffmpegcmd);
?>
But i get this error from php error log:
[x11grab # 0x81e8aa0] device: :0.0 -> display: :0.0 x: 0 y: 0 width: 800 height: 600
No protocol specified
No protocol specified
[x11grab # 0x81e8aa0] Could not open X display.
:0.0: Input/output error
Similar command from console run good.
Please, any help to get display and be able to control ffmpeg from browser php script?
Thanks in advance.
thanks for your time.
I got rid the X display error, but not I still haven't got the capture.
Using xvfb I get an unknown file at /tmp written by www-data user:
-rw-r--r-- 1 www-data www-data 11252 Sep 12 09:49 server-B20D7FC79C7F597315E3E501AEF10E0D866E8E92.xkm
Running startx I got also an unknown file at /tmp
-rw------- 1 www-data www-data 59 Sep 12 09:53 serverauth.oLcFlG7tXC
any of both grow in size so it is not capturing anything. The content is some binary thing.
What are those files about?
What I am trying is to write a script in which I can control the time ffmpeg is capturing the desktop to create a video from a jquery slide displayed on a website.
My try from console is closer, but if I can do it by browser I will be able to know when to stop sending an AJAX request once the slide is finished.
This is my try from console:
#!/bin/bash
# start the slide website: I will need to change it to control by querystring the language and course level
firefox http://www.languagecourse.net/vocabulary-trainer.php &
# start recording: I will need to adjust the frame to capture
ffmpeg -f x11grab -r 25 -s 800x600 -i :0.0 /tmp/output2.mpg &
# since I can't control the time a course takes I pause an arbitrary time
sleep 5
# look for the capture PID and close it
for i in $(ps aux | grep ffmpeg | sed "s/ */#/g" | cut -f2 -d#)
do
echo "proceso $i killed"
kill -9 $i
done
I wonder once the website is opened I can continue doing the control from AJAX, but not know if I will be able to get the ffmpeg PID to stop the command.
I will appreciate any kind of comments.
Regards,
·_-

You can use Xvfb to emulate a x-environment
<?php
$ffmpegcmd = "xvfb-run -a ffmpeg -f x11grab -r 25 -s 800x600 -i :0.0 /tmp/output.mpg";
shell_exec($ffmpegcmd);
or something like this
<?php
$ffmpegcmd = "startx -- `which Xvfb` :1 -screen 0 800x600x24 && DISPLAY=:1 && ffmpeg -f x11grab -r 25 -s 800x600 -i :0.0 /tmp/output.mpg");
shell_exec($ffmpegcmd);
That should be good to get rid of the "Could not open X display." error, and will probably solve your problem.

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

ffmpeg loudness doesn't return any file

I'm using a shared server managed by Aruba.it
It uses
ffmpeg version 4.1
built with gcc 4.8.5
(GCC) 20150623
(Red Hat 4.8.5-36)
I need to use ffmpeg to fix the loudness of any uploaded MP3 to -12 dB LUFS -1 dB TP
I found on internet the following commands, but not any output.mp3 is generated
PHP
exec("/usr/bin/ffmpeg -i Temp.mp3 -af loudnorm=I=-12:LRA=7:tp=-2:measured_I=-30:measured_LRA=1.1:measured_tp=-11 04:measured_thresh=-40.21:offset=-0.47 -y output.mp3");
Where do I wrong please?
EDIT
Not any error is returned.
If you run it manually, unscripted in your terminal you will get an error:
Unable to find a suitable output format for '04:measured_thresh=-40.21:offset=-0.47'
04:measured_thresh=-40.21:offset=-0.47: Invalid argument
There is an errant space in your command, so change measured_tp=-11 04 to measured_tp=-11.04.
Based on the suggestion by #llogan I found the solution.
It should be in 3 steps and not in only one.
The MP3 to MP3 doesn't work, on my case.
So I converted the input MP3 into wave, normalized it, and converted back to MP3
exec("/usr/bin/ffmpeg -i Temp.mp3 Temp.wav");
exec("/usr/bin/ffmpeg -i Temp.wav -af loudnorm=I=-12:LRA=7:tp=-2:measured_I=-30:measured_LRA=1.1:measured_tp=-11.04:measured_thresh=-40.21:offset=-0.47 output.wav");
exec("/usr/bin/ffmpeg -i output.wav -ab 320k output.mp3");
this solution worked perfectly
With shell_exe or exec use:
$output = shell_exec('/usr/bin/ffmpeg -i Temp.mp3 -af loudnorm=I=-12:LRA=7:tp=-2:measured_I=-30:measured_LRA=1.1:measured_tp=-11 04:measured_thresh=-40.21:offset=-0.47 -y output.mp 2>&1');
2 refers to the second file descriptor of the process, i.e. stderr.
> means redirection.
&1 means the target of the redirection should be the same location as the first file descriptor, i.e. stdout.
In $output you will have the response. If the apache user www-data doesn't have enough rights execute the comand as sudo

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;

Running two linux commands via PHP, don't wait for first to end before executing second

This is pretty weird, and I searched and tried everything, but I think I'm just making a dumb syntax error here.
I'm trying to run a stress test on the CPU , then immediately limit it's cpu usage to 30% , all this via PHP. The test is also run under another user and with a specified name so it can be limited. The stress test starts fine, but I can see the PHP file still loading, and it ends the second the stress test ends.
Here's some of the ways I tried doing it
$output = exec('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30"');
$output = exec('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s > /dev/null & cpulimit -e MyUniqueProcessName -l 30"');
The whole purpose of this is because I am writing a script for a game hosting website, and I want to limit the resource consumption of each server to improve quality and not let someone hog all the resources.
Basically, instead of the stress test, a game server will run.
edit::
here's what I have now:
I need to run the stress under "test" , but the cpulimit under either sudo apache or root, because it requires special permissions. The stress still starts fine but it eats 99.9%
passthru('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s &" & sudo cpulimit -e MyUniqueProcessName -l 30 -i -z');
I can't see the cpulimit in the process list after doing this http://i.imgur.com/iK2nL43.png
Unfortunately, the && does more or less the opposite of what you want. :-) When you do A && B in Bash, that means, "Run command A and wait until it's done; if it succeeded, then run command B."
By contrast, A & B means, "Run command A and then immediately run command B."
So you're close to right in your command, but just getting tripped up by using two bash commands (should only need one) and the &&.
Also, did you try running each command separately, outside PHP, in two terminals? I just downloaded and built both stress and cpulimit (I assume these are the ones you're using?), ran the commands separately, and spotted a problem: cpulimit still isn't limiting the percentage.
Looking at the docs for stress, I see it works by forking child processes, so the one you're trying to CPU-limit is the parent, but that's not the one using the CPU. cpulimit --help reveals there's option -i, which includes child processes in what is limited.
This gets me to the point of being able to enter this in one terminal (first line shows input at the prompt; subsequent show output):
$> exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30 -i
[1] 20229
MyUniqueProcessName: info: [20229] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
Process 20229 found
Then, in another terminal running top, I see:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
20237 stackov+ 20 0 7164 100 0 R 30.2 0.0 0:04.38 stress
Much better. (Notice that outside the Bash shell where you aliased it with exec -a, you will see the process name as stress.) Unfortunately, I also see another issue, which is cpulimit remaining "listening" for more processes with that name. Back to cpulimit --help, which reveals the -z option.
Just to reduce the complexity a bit, you could leave the alias off and use the PID of the stress process, via the special Bash variable $!, which refers to the PID of the last process launched. Running the following in a terminal seems to do everything you want:
stress -c 1 -t 60s & cpulimit -p $! -l 30 -i -z
So now, just change the PHP script with what we've learned:
exec('bash -c "exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30 -i -z"');
...or, simpler version:
exec('bash -c "stress -c 1 -t 60s & cpulimit -p \$! -l 30 -i -z"');
(Notice the $ in the $! had to be escaped with a backslash, \$!, because of the way it's quoted when passed to bash -c.)
Final Answer:
Based on the last example you amended to your question, you'll want something like this:
passthru('bash -c "sudo -u test stress -c 1 -t 60s & sudo -u root cpulimit -p \$! -l 30 -i -z"');
When I run this with php stackoverflow-question.php, it outputs the following:
stress: info: [3374] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
stress: info: [3374] successful run completed in 60s
Process 3371 found
(The second two lines only appear after the PHP script finishes, so don't be mislead. Use top to check.)
Running top in another terminal during the 60 seconds the PHP script is running, I see:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3472 test 20 0 7160 92 0 R 29.5 0.0 0:07.50 stress
3470 root 9 -11 4236 712 580 S 9.0 0.0 0:02.28 cpulimit
This is exactly what you've described wanting: stress is running under the user test, and cpulimit is running under the user root (both of which you can change in the command, if desired). stress is limited to around 30%.
I'm not familiar with runuser and don't see the applicability, since sudo is the standard way to run a process as another user. To get this to work, you may have to adjust your settings in /etc/sudoers (which will require root access, but you obviously already have that). That's entirely outside the scope of this discussion, but as an example, I added the following rules:
my-user ALL=(test) NOPASSWD:NOEXEC: /home/my-user/development/stackoverflow/stress
my-user ALL=(root) NOPASSWD:NOEXEC: /home/my-user/development/stackoverflow/cpulimit

Browser unable to open php page?

First of all I am showing the PHP code ....
<?php
echo ("hello");
echo exec("sendip -v -p ipv6 -6s 2001::100 -p tcp -ts 21 -td 21 2001::200 2>
&1");
echo ("hi");
?>
When I entered the command through linux command line it is working fine.The command is sending a tcp ipv6 packet on 2001::200 machine from 2001::100.
[root#udit-pc]# sendip -v -p ipv6 -6s 2001::100 -p tcp -ts 21
-td 21 2001::200 > /dev/null &
/* (-v for verbose) */
Output of above command ...
Added 34 options
Initializing module ipv6
Initializing module tcp
Finalizing module tcp
Finalizing module ipv6
Final packet data:
60 00 00 00 `...
/*
here other packet
contents gets printed
*/
7D 62 00 00 }b..
61 62 63 64 abcd
Sent 64 bytes to 2001::200
Freeing module ipv6
Freeing module tcp
When I execute the php script through command line...
[root#udit-pc]# php test.php
Freeing module tcp
hellohi gets printed and packet arrived at 2001::200.
But problem arise when I try to run php script through browser...
http:://localhost/test.php
hellohi gets printed but packet does not arrive at other machine.
sh: sendip: command not found
Also in both case packet contents are not printed at terminal although using verbose option but when directly using command verbose option works fine.
I tried with many things although I do not think they would help like......
I added /usr/local/lib and usr/local/bin to PATH variable but no benefit.
chmod +s /usr/local/bin/sendip .Sticky bit set but again no benefit.
paste the /usr/local/bin/sendip itself in /var/www/html folder although I have changed the PATH variable but as i said i m just using hit n trial getting no clue.....
There are some output snapshots which may further help ....
[root#cc html]# echo $PATH
/usr/lib/qt-3.3/bin:/usr/kerberos/sbin:/usr/kerberos/bin:
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:
/usr/X11R6/bin:/root/bin:/usr/local/lib
[root#cc html]# locate sendip
.....
/usr/local/bin/sendip
/usr/local/lib/sendip
.....
[root#cc bin]# chmod +s sendip
[root#cc bin]# ls -l sendip
-rwsrwsrwx 1 apache apache 41071 Sep 26 19:41 sendip
[root#cc bin]# cd /usr/local/lib/
[root#cc lib]# ls -ld sendip
drwxrwxrwx 2 root root 4096 Sep 28 22:48 sendip
[root#cc lib]# chmod +s sendip
[root#cc lib]# ls -ld sendip
drwsrwsrwx 2 root root 4096 Sep 28 22:48 sendip
When file contents are changed .......
<?php
echo exec("/usr/bin/sendip ........ 2 > &1");
?>
Then oputput is :
[root#cc html]# php test.php
Freeing module tcp[root#cc html]#
On browser....
No error gets printed but packet still not arrived.
I am stuck in between.Please suggest me what else should I rather try ??????/
is sendip() in the path of the shell being invoked by PHP? You're not checking for error conditions, so possibly you're not actually executing sendip, and just getting a "no such program or file" type errors.
Instead of redirecting the exec()'d command's output to null, redirect it all to the browser so you can see what happens:
echo exec("sendiip yada yada yada 2>&1");
Try using the full path:
exec("/usr/lib/sendip -v -p ipv6 -6s 2001::100 -p tcp -ts 21 -td 21 2001::200 > /dev/null &");
The server is most likely not running with the same permissions as the user, you are testing with.
The server is most likely discarding any PATH variable. Make sure that you specify the complete path to sendip in the exec call.
The Problem is solved although I can not say its fully solved but as per my need its working.
What i did is I re-installed the sendip ,then I set its sticky bit and then after that I set the Path variable to as above mentioned in question.
Actually the tool is by default installing the libraries in /usr/local/lib/sendip folder and sendip in /usr/local/bin folder.
Although after setting PATH variable still I need to use full path in the PHP Script
/usr/local/bin/sendip -v .....
(one of my friend suggested me this..)
What I think is PHP Path is something different from Shell PATH.I need to paste sendip to /usr/bin and then I need to run updatedb before setting its sticky bit if I don't want to mention full path in PHP Script .Now this command will work fine in PHP Script.
sendip -v .........
Although May be I am wrong but this all works fine for me.

Categories