Convert mp3 to wav on the fly using ffmpeg in Python - python

I'm trying to convert a mp3 file on the fly in Python to wav file using ffmpeg.
I call it using subprocess, how can I get it's output to play it as wav on the fly wthout saving it as the file (or playing it while its converting) and then playing it?
This is what I have so far:
I'm using aplay just for a example.
FileLocation = "/home/file.mp3"
subprocess.call(["ffmpeg", "-i", FileLocation etc etc "newfail.wav"])
os.system("aplay ... ") #play it on the fly here
As far as I understand, if I put "-" as file name, it will output it instead to stdout, but I don't know how to read stdout...

To emulate source arg1 arg2 | sink shell command without the shell:
from subprocess import Popen, PIPE
source = Popen(['source', 'arg1', 'arg2'], stdout=PIPE)
sink = Popen(['sink'], stdin=source.stdout)
source.stdout.close()
source.wait()
sink.wait()

Related

python subprocess with ffmpeg give no output

I m want to extract the scene change timestamp using the scene change detection from ffmpeg. I have to run it on a few hundreds of videos , so i wanted to use a python subprocess to loop over all the content of a folder.
My problem is that the command that i was using for getting these values on a single video involve piping the output to a file which seems to not be an option from inside a subprocess call.
this is my code :
p=subprocess.check_output(["ffmpeg", "-i", sourcedir+"/"+name+".mpg","-filter:v", "select='gt(scene,0.4)',showinfo\"","-f","null","-","2>","output"])
this one tell ffmpeg need an output
output = "./result/"+name
p=subprocess.check_output(["ffmpeg", "-i", sourcedir+"/"+name+".mpg","-filter:v", "select='gt(scene,0.4)',metadata=print:file=output","-an","-f","null","-"])
this one give me no error but doesn't create the file
this is the original command that i use directly with ffmpeg:
ffmpeg -i input.flv -filter:v "select='gt(scene,0.4)',showinfo" -f null - 2> ffout
I just need the ouput of this command to be written to a file, anyone see how i could make it work?
is there a better way then subprocess ? or just another way ? will it be easier in C?
You can redirect the stderr output directly from Python without any need for shell=True which can lead to shell injection.
It's as simple as:
with open(output_path, 'w') as f:
subprocess.check_call(cmd, stderr=f)
Things are easier in your case if you use the shell argument of the subprocess command and it should behave the same. When using the shell command, you can pass in a string as the command rather then a list of args.
cmd = "ffmpeg -i {0} -filter:v \"select='gt(scene,0.4)',showinfo\" -f {1} - 2> ffout".format(inputName, outputFile)
p=subprocess.check_output(cmd, shell=True)
If you want to pass arguments, you can easily format your string

take raw streaming data from stdout into python program

I have a hackrf hardware unit that is feeding a continuous raw uint8 data stream to a linux shell pipe.
For example this will pipe continous data to another application in a linux shell like so:
hackrf_transfer -r /dev/stdout -f 92700000 -s 8000000 - | (another application)
In python this will do the same:
hackout = subprocess.Popen(['hackrf_transfer', '-r', '/dev/stdout', '-f', '92700000', '-s', '8000000'], stdout=subprocess.PIPE)
BUT I cannot get the Hackrf pipe stream into a python script. For example I may want to decimate that raw data stream or manipulate it in some way and then send it on to another subprocess application etc. like so:
(HackRF)source subprocess >> a python script >> sink subprocess (eg.
baudline)
or in a single python script:
source hackrf >> my_function >> sink application
I can do source >> sink in a python script where both applications already accept a shell command such as a hackrf subprocess pipe into Baudline subprocess stdin pipe. In other words if the two apps work in the shell using a pipe it works in a python subprocess call. But I can't get a python function between this shell pipe to alter the data using a python script or function.
Does anyone have any ideas on how I could go about this please?
The output of hackrf_transfer is a byte stream, not line-oriented, so readlines() doesn't work; use read(8*1024) instead.
If I use hackout.stdout.read() or hackout.communicate it 'sinks' the data stream.
Right, those calls without arguments cannot be used to read a continuous data stream in parallel.
read(size=-1):
As a convenience, if size is unspecified or -1, all bytes until EOF are returned.
communicate(input=None, timeout=None):
Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate.
This is why I told to use read(8*1024).
Its not running errors or messages with this: data = hackout.stdout.readlines(8*1024) but I want to take this and feed it to stdout. I tried sys.stdin.write(data) its not writing but It's seeing 'data' as a list. So its captured the data but I can't write that captured data back out.
I hope you meant read rather than readlines, for the reason I stated at the beginning of this post.
Here's a sketch of working code, based on what you posted in a meanwhile deleted "answer":
hackout = subprocess.Popen(['hackrf_transfer', …], stdout=subprocess.PIPE)
# We need to start the "sink subprocess" at the outset, and that with stdin=PIPE
baudline = subprocess.Popen("baudline … -stdin …", stdin=subprocess.PIPE, shell=True)
def decimator():
for iq_samples in iter(lambda: bytearray(hackout.stdout.read(8*1024)), b''):
# convert the samples chunk for use by numpy, if you wish
dat = np.array(iq_samples)
dat = dat.astype(float)/255
# dat = … do further processing, as you wish
# now convert data back for use by baudline -format u8 and write out
baudline.stdin.write((dat*255).astype('i1').tostring())
decimator()

Manipulating image output from shell in python without storing external file

I am trying to store an image that is the result of ffmpeg.
Using this command, I have frame.png as an external file output:
ffmpeg -flags2 +export_mvs -i video.avi -vf 'select=gte(n\,200),codecview=mv=pf+bf+bb' -vframes 1 frame.png
I want to be able to load the frame.png directly into python, maybe using openCV but without saving it in the computer.
I thought of something like this:
cmd = "ffmpeg -flags2 +export_mvs -i video.avi -vf 'select=gte(n\,200),codecview=mv=pf+bf+bb' -vframes 1 frame.png"
img = cv.imread(sp.Popen(cmd, shell=True, stdout = sp.PIPE, stderr = sp.PIPE).communicate()[0])
But I get an error:
TypeError: bad argument type for built-in operation
Any clue how to do this? The idea is, no frame.png should be generated as a file.
You can set the output file as /dev/stdout (you might need to specify the output format with -f)
Then you redirect your output to your python script like so
ffmpeg options /dev/stdout | python your_script.py
Then you can read this question to see how you can read an image from a file object. Just replace StringIO with sys.stdin

Using ffmpeg with subprocess python

I am trying to download videos from Wistia and I managed to download them but in .bin&amp format ; I'd like to convert them to .mp4 in order to use OpenCV. For this I am calling ffmpeg with subprocess on Python but I get 1 as the value for the return code, meaning the process has failed. Any idea why, and how I can change this...?
Code is the following:
import subprocess
infile = filename #a bin&amp file
outfile = filename[:-7]+'mp4'
subprocess.run(['ffmpeg', '-i', infile, outfile],shell=True)
I get :
CompletedProcess(args=['ffmpeg', '-i', '58c63bccfcc1c150646c261caad97a58ced4b5e3.bin&amp', '58c63bccfcc1c150646c261caad97a58ced4b5e3.mp4'], returncode=1)
Also, it works in the command prompt...
Thank you for your help,
Sincerely,
Try to use Popen. I I'm using FFmpeg in python and it works well
process_ = subprocess.Popen(ffmpeg_cmd, start_new_session=True)

Downsample wav RIFF file using python

I'm trying to downsample a 16khz wav file to 8khz in python 2.6. The file has RIFF header and is in a mulaw format and must remain in that format.
I've glanced at some things in this big list of python stuff and can't seem to find a simple library that will just change the sample rate of an audio file.
Any suggestions on a good python library to do this?
I ended up installing sox and then calling it via subprocess:
from subprocess import Popen, PIPE, STDOUT
soxCall = '/usr/local/bin/sox ' + infileName + \
' ' + outfileName + ' rate 8k'
p = Popen(soxCall, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
audioop looks designed to suit your needs.
Supports mu-law and looks like it can adjust the sample rate with audioop.ratecv

Categories