Stream as html5 audio or convert .amr to .ogg - php

I want to stream .amr audio files on my server. After spending a couple hours of research, it's clear to me that this is not feasible under the current state of html5 audio. Following this disappointing finding, I spent several additional hours looking for a simple way to convert .amr files to .ogg, with similarly disappointing results.
I'm shocked that after well over 10 years of use, there is no simple way to play/convert files encoded under this standard, but can someone please help me to find a usable solution? The closest viable options seem to be sox and ffmpeg. I'm ideally looking for a concise set of instructions for converting .amr to .ogg directly from php but using the command line would be fine.
I am about to dig into the specifics of using these two libraries but figured that I would post here in hopes that some kind soul might help enlighten others that are under time constraints and so do not wish to spend an afternoon untangling the use-case specifics of what should be a straightforward task. If someone else does not post, I will answer the question myself.
Here are some of the other 'answers' that I've found which led me to post here:
Converting 3gp (amr) to mp3 using ffmpeg api calls
https://stackoverflow.com/q/4899195/418584
Advice - How To Start Converting Video / Audio
Ffmpeg not converting properly to ogg
ffmpeg/PHP - Problems converting any video format to ogg - Choppy Video / No Audio - win64 (Poster actually seems to answer question themselves, and I'm about to pursue this route first, but no other answers and the fact that it's not specific to my question led me to post this anyway)
If you are about to mark this as 'off-topic' or close the question for some other reason, please consider the following:
A search on https://superuser.com/search?q=convert+.amr+to+.ogg, which is stated in at least one of the above links as the appropriate forum for the question, (as of today) results in 4 posts, none of which even remotely address this question.
The SO Posting Guidelines seem to me to be completely in alignment with this kind of question. I'm baffled as to why someone would close the questions that came up in my search. I'm a very experienced developer, asking a question directly related to development work that I'm doing, and have been blocked by an issue that I would like to provide a solution for to aid in other developers being held up by similar issues.
The fact that nothing came up in my search to save me from doing hours of research leads me to see this as a worthy question for SO. Please help restore my sentiment for this site which is a valuable resource but has left me cold due to so many of these kinds of senseless and seemingly indiscriminate post closings.
Thanks...

If you're in an environment where the tools are already installed, converting the file is actually a very simple procedure. For ffmpeg and sox, the commands in their most basic forms are just:
ffmpeg -i ./file.amr ./file.ogg
or
sox ./file.amr ./file.ogg
So if we upload a file with an input name of 'audio', from PHP this would look something like:
<?php
if (isset($_FILES['audio']) && is_file($TmpFile=$_FILES['audio']['tmp_name'])) {
// I name uploaded files as curr ms timestamp and track file data via db.
$NewFile = './uploads/'.round(microtime(true)*1000).'.ogg';
shell_exec("ffmpeg -i {$TmpFile} -acodec libvorbis ".$NewFile);
// You'll want to add other file data to the database here...
} else {
// Deal with bad file uploads...
}
?>
Unfortunately, my server environment doesn't have these tools installed, so I have to compile them manually. For my case specifically, I'm using a virtual shared host so I don't have universal access privileges on the system. Keep in mind that this is reflected in some of the code I'm using to install the various ffmpeg components.
cd ~/
curl -O http://ffmpeg.org/releases/ffmpeg-2.0.tar.gz
tar -xzvf ffmpeg-2.0.tar.gz
mv -fv ./ffmpeg-2.0 ./ffmpeg
rm -v ./ffmpeg-2.0.tar.gz
cd ~/ffmpeg
curl -O http://downloads.xiph.org/releases/ogg/libogg-1.3.1.tar.gz
tar -xzvf libogg-1.3.1.tar.gz
rm -v libogg-1.3.1.tar.gz
cd libogg-1.3.1
./configure --prefix="$HOME/ffmpeg" --disable-shared
make
make install
make distclean
cd ~/ffmpeg/
curl -O http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.3.tar.gz
tar -xzvf libvorbis-1.3.3.tar.gz
rm -v libvorbis-1.3.3.tar.gz
cd libvorbis-1.3.3
./configure --prefix="$HOME/ffmpeg" --with-ogg="$HOME/ffmpeg" --disable-shared
make
make install
make distclean
cd ~/ffmpeg/
curl -O -L http://sourceforge.net/projects/opencore-amr/files/opencore-amr/opencore-amr-0.1.3.tar.gz
tar -xzvf opencore-amr-0.1.3.tar.gz
rm -v opencore-amr-0.1.3.tar.gz
cd opencore-amr-0.1.3
./configure --prefix="$HOME/ffmpeg" --disable-shared --bindir="$HOME/bin"
make
make install
make distclean
cd ~/ffmpeg/
curl -O http://www.tortall.net/projects/yasm/releases/yasm-1.2.0.tar.gz
tar -xzvf yasm-1.2.0.tar.gz
rm -v yasm-1.2.0.tar.gz
cd yasm-1.2.0
./configure --prefix="$HOME/ffmpeg" --bindir="$HOME/bin"
make
make install
make distclean
cd ~/ffmpeg/
mkdir ~/ffmpeg/tmp
chmod 777 ~/ffmpeg/tmp
export TMPDIR="$HOME/ffmpeg/tmp"
export PKG_CONFIG_PATH="$HOME/ffmpeg/lib/pkgconfig"
./configure --prefix="$HOME/ffmpeg" --extra-cflags="-I$HOME/ffmpeg/include" --extra-ldflags="-L$HOME/ffmpeg/lib" --bindir="$HOME/bin" --extra-libs="-ldl" --enable-gpl --enable-nonfree --enable-version3 --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libvorbis
make
make install
make distclean
rm -rfv $TMPDIR
export TMPDIR=""
export PKG_CONFIG_PATH=""
You could just copy and paste the above bash commands into a shell, or you could put them into an executable script, and it should take care of everything. You'll probably want to check for the newest versions of each component and update the code accordingly. You may also want to add other libraries if you're working with different file formats as well, but this boiled down to what I needed specifically.
You could also use:
git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg
and eliminate the first block of code in the installation script if you have git installed, or if you have neither git nor curl you could just download each and upload to your server or use fget or something similar.
In all, this amounted to several hours of hunting down files, tracing compilation errors, tracking down the correct options for my scenario, and other aspects of this kind of tedium that makes up the worst of exactly what I like least about development work. I hope that this post might save others from this kind of unnecessary pain and suffering :-)

Related

is it possible to call command belonging to another container in docker [duplicate]

I have two Docker images, one containing pandoc (an utility to convert documents in different formats to many formats), and an other containing pdflatex (from texlive, to convert tex files into pdf). My goal here is to convert documents from md to pdf.
I can run each image separately :
# call pandoc inside my-pandoc-image (md -> tex)
docker run --rm \
-v $(pwd):/pandoc \
my-pandoc-image \
pandoc -s test.md -o test.tex
# call pdflatex inside my-texlive-image (tex -> pdf)
docker run --rm \
-v $(pwd):/texlive \
my-texlive-image \
pdflatex test.tex # generates test.pdf
But, in fact, what I want is to call pandoc (from its container) directly to convert md into pdf, like this :
docker run --rm \
-v $(pwd):/pandoc \
my-pandoc-image \
pandoc -s test.md --latex-engine pdflatex -o test.pdf
This command does not work here, because pandoc inside the container tries to call pdflatex (that must be in $PATH) to generate the pdf, but pdflatex does not exist since it is not installed in the my-pandoc-image.
In my case, pdflatex is installed in the image my-texlive-image.
So, from this example, my question is : Can a container A call an executable located on an other container B ?
I am pretty sure this is possible, because if I install pandoc on my host (without pdflatex), I can run pandoc -s test.md--latex-engine=pdflatex -o test.pdf by simply aliasing the pdflatex command with :
pdflatex() {
docker run --rm \
-v $(pwd):/texlive \
my-texlive-image \
pdflatex "$#"
}
Thus, when pdflatex is called by pandoc, a container starts and do the conversion.
But when using the 2 containers, how could I alias the pdflatex command to simulate its existence on the container having only pandoc ?
I took a look at docker-compose, since I have already used it to make 2 containers communicate (app communicating with a database). I even thought about ssh-ing from container A to container B to call the pdflatex command, but this is definitively not the right solution.
Finally, I also have built an image containing pandoc + pdflatex (it worked because the two executables were on the same image), but I really want to keep the 2 images separately, since they could be used independently by other images.
Edit :
A similar question is exposed here, as I understand the provided answer needs Docker to be installed on container A, and needs a docker socket binding (/var/run/docker.sock) between host and container A. I don't think this is best practice, it seems like a hack that can create security issues.
There are multiple solutions to your problem, I'll let you choose the one that suits you best. They are presented below, from the cleanest to the ugliest (in my opinion and regarding the best practices generally followed).
1. Make it a service
If you end up calling it often, it may be worth exposing pandoc as an (HTTP) API. Some images already do that, for example metal3d/pandoc-server (which I already used with success, but I'm sure you can find others).
In this case, you just run a container with pandoc + pdflatex once and you're set!
2. Use image inheritance!
Make 2 images : one with pandoc only, and the other one with pandoc + pdflatex, inheriting the first one with the FROM directive in the Dockerfile.
It will solve your concerns about size and still being able to run pandoc without having to fetch pdflatex too. Then if you need to pull the image with pdflatex, it will just be an extra layer, not the entire image.
You can also do it the other way, with a base image pdflatex and another adding pandoc to it if you find yourself using the pdflatex image alone often and rarely using the pandoc image without pdflatex. You could also make 3 images, pandoc, pdflatex, and pdflatex + pandoc, to cover every need you might have, but then you'll have at least one image that isn't linked in any way to the 2 others (can't heritate a "child" image), making it a bit harder to maintain.
3. Docker client in my-pandoc-image + Docker socket mount
This is the solution that you mentionned at the end of your post, and which is probably the most generic and straightforward solution for calling other containerized commands, not taking your precise usecase of pandoc + pdflatex into account.
Just add the docker client to your image my-pandoc-image and pass the Docker socket as volume at runtime using docker run -v /var/run/docker.sock:/var/run/docker.sock. And if you're concerned is not being able to make pandoc call docker run ... instead of pdflatex directly, just add a poor wrapper called pdflatex in /usr/local/bin/ which will be responsible of doing the docker run
4. Use volumes-from to get the binary
This one is probably the less clean I'll present here. You could try getting either the pandoc binary in a pdflatex container or the pdflatex binary in a pandoc container using --volumes-from to keep everything packaged in its own Docker image. But honnestly, it's more of a duct tape than a real solution.
Conclusion
You can chose the solution that best fits your needs, but I would advise the first 2 and strongly discourage the last one.

How to mix/merge 2 mp3 files in PHP?

I need a tool to join 2 mp3 files in 1.
The first file ( background ) will be some sound ( music, submitted by user ),
second file will be a machine (google) speaking text, which was submitted ( by user ).
In output I need a single mp3 file, with background music and speaking robot text playing together.
I can't really find any PHP standalone solution like some library or something like, only shell commands atc.
So are there some libraries?
or there's some unique shell command which works on all OS to combine files?
Or how do I complete the task?
Based off of this question, you should be able to install FFMPEG onto your server (hopefully not a shared host?) and use
//Reduce background volume, assuming it's input2.mp3
shell_exec('ffmpeg -i input2.mp3 -af "volume=0.3" backround.wav');
//Merge the two
shell_exec('ffmpeg -y -i input1.mp3 -i background.wav -filter_complex amerge -c:a libmp3lame -q:a 4 output.mp3');
Then you can simply serve up the output.mp3 file. If this is being performed by PHP running under apache (or other web host, instead of CLI) you'll need to make sure your www-data user has read access to the input files, and write access to the output directory.
All your temporary output, like the background, should be saved as .wav, and only converted back to .mp3 for the final output. Recompressing the audio at each step may result in a very poor final output.
I am making assumptions about how FFMPEG works here, so you may need to consult the documentation for it in order to build a functioning or more efficient set of commands.
You can simply do this
file_put_contents('combined.mp3',
file_get_contents('file1.mp3') .
file_get_contents('file2.mp3'));

File not found, but files are present

I'm working on a server where users should be able to run protein sequences against a database, and it uses an executable called blastall. The server generates an executable which it should then run using batch. However, it doesn't appear to be running. Here is an example of an executable is generates (cmd.sh):
#!/usr/bin/env sh
cd /var/www/dbCAN
php -q /var/www/dbCAN/tools/blast.php -e -w /var/www/dbCAN/data/blast/20121019135548
Where the crazy number at the end of that is an auto-generated job ID based on when the job was submitted. There are 2 issues, and I'm trying to solve one at a time. The first issue is that when manually executed (by me simply running ./cmd.sh), I get the following errors:
sh: 1: /var/www/dbCAN/tools/blast/bin/blastall: not found
sh: 1: /var/www/dbCAN/tools/blast/bin/blastall: not found
sh: 1: -t: not found
But this doesn't really make sense to me, as the directory specified does in fact contain blastall. It has full rwx permissions and every directory along the way has appropriate permissions.
The blast.php file in tools looks like this:
try {
do_blast($opts["w"]);
$info['status'] = 'done';
$fp = fopen("$opts['w']/info.yaml","w")
fwrite($fp, Sypc::YAMLDump($info)); fclose($fp);
}
With of course variable declarations above it, and the do_blast function looks like this (again with variables declared above it and a cd so the directories work out):
function do_blast($workdir)
{
system("/var/www/dbCAN/tools/blast/bin/blastall -d data/blast/all.seq.fa -m 9 -p blastp -i $workdir/input.faa -o $workdir/output.txt")
system("/var/www/dbCAN/tools/blast/bin/blastall -d data/blast/all.seq.fa -p blastp -i $workdir/input.faa -o $workdir/output2.txt")
}
Any idea what may be causing this issue? I thought it may be because I'm running it and it was created by apache, but rwx is allowed for all users. I can include more information if needed, but I chose not to at this point because the original person who wrote the PHP split up everything into tons of little files, so it's difficult to pinpoint where the problem is exactly. Any ideas (if not complete solutions) are very appreciated.
EDIT: Solution found. As it turns out, the blastall executable had been compiled on a different linux system. Switched to a different executable and it ran flawlessly.
Could it be an issue with relative paths in your script? See my answer here, maybe it helps:
finding a file in php that is 4 directories up
The solution was to recompile the blastall executable. It had been compiled for Redhat and I am using Ubuntu. Unfortunately I assumed the executable I was given was for my system, not the previous one.

Decode base64 in array to figure out hackers intents

A WordPress site of a client was recently hacked due to a theme vulnerability and I am now in the process of cleaning up and fortifying. I found guncompress(base64_decoded code. When I decoded it I had more base64 in an array:
$GLOBALS['_1780441916_']=Array(base64_decode('' .'ZXJ' .'yb3Jfc' .'mVwb3J' .'0a' .'W5'.'n'),base64_decode('Y3VybF9pb' .'ml0'),base64_decode('c
How can I decode base64 in an array on my localhost?
Try to using evalhook.so.
You need:
PHP >= 5.2
php5-devel
PHP Zend Optimizer
download source from http://php-security.org/downloads/evalhook-0.1.tar.gz
then unpack and install it
tar xvfz evalhook-0.1.tar.gz
cd evalhook
phpize
./configure
make
sudo make install
and you can use it from console.
php -d extension=evalhook.so encoded_script.php
where encoded_script.php is your encoded script.
every time it ask you
Do you want to allow execution? [y/N]
Type Y if your code after execution have some "base64_decode" in it.
Then when you get something like that
$GLOBALS['_889997777_'] = Array(
...
$GLOBALS['_224568216_'][21]('Xr' . 'x8f7g=')
);
Just run after that var_export($GLOBALS['_889997777_']);die; and you get all functions name, than you can replace it. Here is link that can automate it http://pastebin.com/kBj4iqWh

Compile C++ file Using PHP

I am using PHP on Windows machin. I also use Dev C++. I can perfectly compile .cpp file on CMD using this command:
g++ hello.cpp -O3 -o hello.exe
Now what I am trying to do is running the same command using php system() function, so it looks like this:
system("g++ c:\wamp\www\grader\hello.cpp -O3 -o C:\wamp\www\grader\hello.exe");
but it doesn't compile. I am lost, please tell me what am I missing?
I also looked up at this question and thats exactly what I need, but I couldnt find a usefull solution for my case there:
Php script to compile c++ file and run the executable file with input file
Use the PHP exec command.
echo exec('g++ hello.cpp -O3 -o hello.exe');
should work.
There's a whole family of different exec & system commands in PHP, see here:
http://www.php.net/manual/en/ref.exec.php
If you want the output into a variable, then use :
$variable = exec('g++ hello.cpp -O3 -o hello.exe');
If that doesn't work, then make sure that g++ is available in your path, and that your logged in with sufficient enough privliges to allow it to execute.
You may find also that it's failing beacuse PHP is essentially being executed by your web server (Unless your also running PHP from the cmd prompt) , and the web server user ID may not have write access to the folder where G++ is trying to create the output file.
Temporarily granting write access to 'Everybody' on the output folder will verify if that is the case.
Two things:
You are using double quotes and are not escaping the \ inside the path.
You are not using a full path to g++.
The first one is important as \ followed by something has a special meaning in such a string (you might know \n as new line), the second one is relevant since the PHP environment might have a different search path.
A solution might be
system("c:\\path\\to\\g++ c:\\wamp\\www\\grader\\hello.cpp -O3 -o C:\\wamp\\www\\grader\\hello.exe");
Alternatively you can use single quotes, intead of double quotes, they use diffeent,less strict escaping rules
system('c:\path\to\g++ c:\wamp\www\grader\hello.cpp -O3 -o C:\wamp\www\grader\hello.exe');
or use / instead of \, which is supported by windows, too.
system("c:/path/to/g++ c:/wamp/www/grader/hello.cpp -O3 -o C:/wamp/www/grader/hello.exe");
What you do is your choice, while many might consider the first one as ugly, and the last one as bad style on Windows ;-)
Thanks to everyone. I tried to run the codes given in above posts and it worked like a charm.
I ran the following code using my browser
$var = exec("g++ C:/wamp/www/cpp/hello.cpp -O3 -o C:/wamp/www/cpp/hello.exe");
echo $var;
The exe file is created. I am able to see the result when i run the exe file but the problem is when i run the above code in the browser, the result is not displayed on the webpage. I gave full access permission to all users but still give does not show the result on the webpage.
I really need help on this since i am doing a project on simulated annealing where i want to get the result from compiled c++ program and display it in the webpage with some jquery highcharts.
Thanks again to all, it has helped me alot and i have learnt alot as well.

Categories