I am working on a PHP code as shown below in which conversion of mp4 into mp3 is happening at Line B.
I have added if block after system command to print Conversion Completed on the webpage once the conversion is complete but it doesn't seem to work.
Php code:
if (isset($_POST['id']))
{
for($i=0; $i <count($mp4_files); $i++) {
if($i == $_POST['id']) {
$f = $mp4_files[$i];
$parts = pathinfo($f);
switch ($parts['extension'])
{
case 'mp4' :
$filePath = $src_dir . DS . $f;
print_r($f); // Line A
system('ffmpeg -i ' . $filePath . ' -map 0:2 -ac 1 ' . $destination_dir . DS . $parts['filename'] . '.mp3', $result); // Line B
if($result)
{
echo "Conversion Completed";
}
}
}
}
}
Problem Statement:
I am wondering what changes I should make in the PHP code above so that once the conversion is complete; on the webpage, it should print Conversion Completed.
You can use shell_exec to get a return value and then put that in an if statement like this
$output = shell_exec('ffmpeg -i ' . $filePath . ' -map 0:2 -ac 1 ' . $destination_dir . DS . $parts['filename'] . '.mp3');
if ($output) {
echo "Conversion Completed!";
// or redirect here
}
Also, make sure to sanitize your inputs as they are exposed to a CLI interface.
Related
I am working on a php code as shown below on which Line#A prints the following array (shown below php code). My code doesn't seems to go inside switch statement. I am not sure why.
I added print_r($parts) at Line A in order to print the value of $parts.
php code:
<?php
if (!empty($_POST['id']))
{
for($i=0; $i <count($mp4_files); $i++) {
if($i == $_POST['id']) {
$f = $mp4_files[$i];
$parts = pathinfo($f);
print_r($parts); // Line A
switch ($parts['extension'])
{
echo "Hello World"; // Line B
case 'mp4' :
$filePath = $src_dir . DS . $f;
system('ffmpeg -i ' . $filePath . ' -map 0:2 -ac 1 ' . $destination_dir . DS . $parts['filename'] . '.mp3', $result);
}
}
}
}
?>
Output (Line#A):
Array
(
[dirname] => .
[basename] => hello.mp4
[extension] => mp4
[filename] => hello
)
I have used echo "Hello World" at Line B but for some reasons, its not getting printed and throwing 500 internal server error on console.
Problem Statement:
I am wondering what changes I should make in the php code so that it goes inside switch statement.
The error 500 is caused by echo "Hello World" at Line B which is outside of case mp4.
Your switch statement should be like this.
switch ($parts['extension']) {
case 'mp4':
echo "hello world";
$filePath = $src_dir . DS . $f;
system('ffmpeg -i ' . $filePath . ' -map 0:2 -ac 1 ' . $destination_dir . DS . $parts['filename'] . '.mp3', $result);
break;
}
I am working on a php function used to upload a .wav to server (along with converting to mp3 and creating waveform image png) , and within the function I would like it to use soundtouch / soundstrech to detect the B.P.M. (Beats Per Minute). I know it will not be the most accurate but for my purposes it will be all I need.
I was able to get the B.P.M. of a .wav file using soundtouch / soundstrech along with ffmpeg within a test.php file using deven's php-bpm-detect wrapper But When I try to integrate it within my PHP function it returns the B.P.M. as zero.
I am wondering if there is a simpler way to get the bpm as a string from the following shell exec without having to use a separate php library?
I would like to perform this and have it return as a string:
$song_bpm = shell_exec('soundstretch ' . $file_path . ' -bpm');
test.php (This works and returns the proper bpm:)
<?php
require "class.bpm.php";
$wavfile = "38a2819c20.wav";
$bpm_detect = new bpm_detect($wavfile);
$test = $bpm_detect->detectBPM();
echo ' bpm of ' . $wavfile . ' is: ' . $test . ' ';
?>
PHP Function: (returns bpm as zero)
function upload_a_sound($user_id, $file_temp, $file_extn, $name, $uploader, $keywords) {
$timecode = substr(md5(time()), 0, 10);
$mp3name = 'beats/' . $timecode . '.mp3';
$file_path = 'beats/' . $timecode . '.wav';
move_uploaded_file($file_temp, $file_path);
shell_exec('ffmpeg -i ' . $file_path . ' -vn -ar 44100 -ac 2 -ab 192k -f mp3 ' . $mp3name . '');
require ('classAudioFile.php'); // This creates a spectogram .png file of .wav
$AF = new AudioFile;
$AF->loadFile($file_path);
$AF->visual_width=200;
$AF->visual_height=200;
$AF->visual_graph_color="#c491db";
$AF->visual_background_color="#000000";
$AF->visual_grid=false;
$AF->visual_border=false;
$AF->visual_graph_mode=0;
$AF->getVisualization ('images/song/' . $timecode . '.png');
$imageloc = 'images/song/' . $timecode . '.png';
require ('class.bpm.php'); //Deseven's class to get bpm,
$bpm_detect = new bpm_detect($file_path);
$song_bpm = $bpm_detect->detectBPM(); //when used here this returns 0
mysql_query("INSERT INTO `content` VALUES ('', '', '$name', '$uploader', '$keywords', '$file_path', '$imageloc', '$mp3name', '$song_bpm')"); // I will update this to mysqli soon, for now it works
}
I also found this which works, but not when I integrate it into my function:
// create new files, because we don't want to override the old files
$wavFile = $filename . ".wav";
$bpmFile = $filename . ".bpm";
//convert to wav file with ffmpeg
$exec = "ffmpeg -loglevel quiet -i \"" . $filename . "\" -ar 32000 -ac 1 \"" . $wavFile . "\"";
$output = shell_exec($exec);
// now execute soundstretch with the newly generated wav file, write the result into a file
$exec = "soundstretch \"" . $wavFile . "\" -bpm 2> " . $bpmFile;
shell_exec($exec);
// read and parse the file
$output = file_get_contents($bpmFile);
preg_match_all("!(?:^|(?<=\s))[0-9]*\.?[0-9](?=\s|$)!is", $output, $match);
// don't forget to delete the new generated files
unlink($wavFile);
unlink($bpmFile);
// here we have the bpm
echo $match[0][2];
I've updated my class so it's supporting absolute and relative paths now.
And the straightforward solution:
exec('soundstretch "test.wav" -bpm 2>&1',$average_bpm);
foreach ($average_bpm as $line) {
if (strpos($line,"Detected BPM rate") !== false) {
$line = explode(" ",$line);
$average_bpm = round($line[3]);
break;
}
}
echo $average_bpm;
Just keep in mind that $average_bpm will contain the error if anything goes wrong.
A video can contain a meta info about the camera orientation. For example iPhone and other phones set this flag if you turn the device. Problem is while some player read this info and rotate the video accordingly, other players do not.
To fix this the video has to be rotated and the meta info needs to be set correctly.
Does ffmpeg provide a fix for this or do I have to go the hard way (Read rotation, rotate, set meta data)
I did go the hard way:
$ffmpeg == "path/to/ffmpeg";
$output_file_full = "file/after/normal/conversion";
// get rotation of the video
ob_start();
passthru($ffmpeg . " -i " . $output_file_full . " 2>&1");
$duration_output = ob_get_contents();
ob_end_clean();
// rotate?
if (preg_match('/rotate *: (.*?)\n/', $duration_output, $matches))
{
$rotation = $matches[1];
if ($rotation == "90")
{
echo shell_exec($ffmpeg . ' -i ' . $output_file_full . ' -metadata:s:v:0 rotate=0 -vf "transpose=1" ' . $output_file_full . ".rot.mp4 2>&1") . "\n";
echo shell_exec("mv $output_file_full.rot.mp4 $output_file_full") . "\n";
}
else if ($rotation == "180")
{
echo shell_exec($ffmpeg . ' -i ' . $output_file_full . ' -metadata:s:v:0 rotate=0 -vf "transpose=1,transpose=1" ' . $output_file_full . ".rot.mp4 2>&1") . "\n";
echo shell_exec("mv $output_file_full.rot.mp4 $output_file_full") . "\n";
}
else if ($rotation == "270")
{
echo shell_exec($ffmpeg . ' -i ' . $output_file_full . ' -metadata:s:v:0 rotate=0 -vf "transpose=2" ' . $output_file_full . ".rot.mp4 2>&1") . "\n";
echo shell_exec("mv $output_file_full.rot.mp4 $output_file_full") . "\n";
}
}
I used some ugly temp files. Sorry about that.
I'm using a Linux local computer and need to backup/mirror some very large file structures regularly. I only have access to SFTP.
I was after a simple one click solution. I originally tried to write the little script in BASH but I've never used it before and am not up to scratch with the syntax so I resorted to PHP. (I do understand PHP is not designed for this kind of work, but I'm on a tight time scale and don't have the time to get into BASH atm)
<?php
//init
parse_str(implode('&', array_slice($argv, 1)), $_GET);
$error = array();
$lPrefix = '/home/hozza/Sites/';
$archiveLocation = '/home/hozza/Backups/';
$lDir = isset($_GET['l']) ? $_GET['l'] : $error[] = 'Local Directory Required';
$rDir = isset($_GET['r']) ? $_GET['r'] : $error[] = 'Remote Directory Required';
$bookmark = isset($_GET['b']) ? $_GET['b'] : $error[] = 'lftp Bookmark Required';
//Check for args
if(count($error) == 0) {
$archiveName = end(explode('/', $lDir)) . '_' . date('Y-m-d_H-i');
//Validate local dir
if(is_dir($lPrefix . $lDir)) {
//preserve Sublime Text 2 config SFTP files
$ST2_SFTP_conf = false;
if(file_exists($lPrefix . $lDir . '/sftp-config.json')) {
$ST2_SFTP_conf = file_get_contents($lPrefix . $lDir . '/sftp-config.json');
unlink($lPrefix . $lDir . '/sftp-config.json');
}
//Start mirror
$lftOutput = explode("\n", shell_exec('lftp -e "mirror -e -p --parallel=10 --log=' . $archiveLocation . 'logs/' . $archiveName . '.txt ' . $rDir . '/ ' . $lPrefix . $lDir . '/; exit top" ' . $bookmark));
//Tar regardless of lftp error or success
$tarOutput = shell_exec('cd ' . $lPrefix . ' && tar -czf ' . $archiveLocation . $archiveName . '.tar.gz ' . $lDir);
//Output completion or errors
shell_exec('notify-send -i gnome-network-properties -t 0 "Mirror & Archive Complete" "' . $archiveName . '\n\n' . implode('\n', $lftOutput) . $tarOutput . '"');
//put back ST2 SFTP conf
if($ST2_SFTP_conf != false) file_put_contents($lPrefix . $lDir . '/sftp-config.json', $ST2_SFTP_conf);
exit;
}
else shell_exec('notify-send -i error -t 0 "Mirror & Archive Error" "' . date('Y-m-d') . ' ' . date('H-i') . '\n' . $lDir . ' \n Does not exist! D:"');
}
else shell_exec('notify-send -i error -t 0 "Mirror & Archive Error" "' . date('Y-m-d') . ' ' . date('H-i') . '\n' . implode('\n', $error) . '"');
?>
It can be run for many sites via a short-cut like so...
terminator -T "Mirror & Archive" -e "php ~/Programs/mirror.php l=local-dir_path r=./ b=lftp-bookmark-name"
If no password is in the LFTP bookmark (there shouldn’t be as it's stored in plain text) the terminal prompts for a password, after the script has run, a nice notification is given with some info about files/folders/speed etc.
However, when the script is running in a terminal, only the "input password" bit is output to the terminal, I would like all the output displayed in the terminal (normally that would display what file/folder is currently working with etc.)
Anyone know how to do that?
IIRC the reason that you see the password prompt output to the terminal is that it is using stderr. You could try redirecting stdout to stderr for your commands which should show you the 'real-time' progress. Tack this on to the end of the shell_exec() command: 1>&2
ie:
shell_exec('lftp -e "mirror -e -p --parallel=10 --log=' . $archiveLocation . 'logs/' . $archiveName . '.txt ' . $rDir . '/ ' . $lPrefix . $lDir . '/; exit top" ' . $bookmark . ' 1>&2')
However, this will preclude you from having anything returned by shell_exec for logging purposes. What I would suggest is something like:
$log_stem = '/tmp/' . time() . '_'; // ie: /tmp/1357581737_
$lfOutfile = $log_stem . 'lftp.log';
$tarOutfile = $log_stem . 'tar.log';
shell_exec('lftp -blah | tee ' . $lfOutfile ' 1>&2' );
shell_exec('tar -blah | tee ' . $tarOutfile ' 1>&2' );
$lfOut = file_get_contents($lfOutfile);
$tarOut = file_get_contetns(tarOutfile);
// remove tmp files
unlink($lfOutfile);
unlink($tarOutfile);
Which will capture a copy of the output to a file before redirecting the output to stderr so you can watch it live.
However, if you want to run this via cron I would recommend against writing anything to stderr that is not an error, otherwise cron will send a warning email every time it is run.
I think the last answer was close:
Either this:
shell_exec('lftp -blah |& tee ' . $lfOutfile );
shell_exec('tar -blah |& tee ' . $tarOutfile );
Or if that still doesn't work try this:
shell_exec('lftp -blah 2>&1 | tee ' . $lfOutfile );
shell_exec('tar -blah 2>&1 | tee ' . $tarOutfile );
I am trying to use the command given in the selected answer here, but it does not work when executed. I know that everything else is working since I can create thumbnails with a different command. What is the proper way to format this? I am assuming that the problem is with " -vsync 0 -vf select='not(mod(n,100))' " but have not been able to get it working.
$cmd = $ffmpeg . " -i " . $src . " -vsync 0 -vf select='not(mod(n,100))' " . $out . ".jpg";
exec($cmd);
You have error on this line:
$cmd = $ffmpeg . " -i " . $src . " -vsync 0 -vf select='not(mod(n,100))' " . $out . ".jpg";
Change it to:
$cmd = "ffmpeg -i " . $src . " -vsync 0 -vf \"select='not(mod(n,100))'\" " . $out . ".jpg";
Or try:
$cmd = "ffmpeg -i " . $src . " -vsync 0 -vf select='not(mod(n,100))' " . $out . ".jpg";
Also when you call exec function call it like this:
exec($cmd,$out);
print_r($out);
Print_r will print you output of what was executed in exec()...