1

I want to convert a numpy array which should contain 60s of raw audio into .wav and .mp3 file. With ffmpeg (version 3.4.6) I try to convert the array to the desired formats. For comparison I also use the modul soundfile. Only the .wav-file created by soundfile has the expected length of exact 60s. The .wav-file created by ffmpeg is a little shorter and the .mp3-file is ca. 32s long.

I want all exports to be the same length.What am I doing wrong?

Here is a sample code:

import subprocess as sp
import numpy as np
import soundfile as sf

def data2audiofile(filename,data):
    out_cmds = ['ffmpeg',
                '-f', 'f64le', # input 64bit float little endian 
                '-ar', '44100', # inpt samplerate 44100 Hz
                '-ac','1', # input 1 channel (mono)
                '-i', '-', # inputfile via pipe
                '-y', #  overwrite outputfile if it already exists
                filename]
    pipe = sp.Popen(out_cmds, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE) 
    pipe.stdin.write(data)


data = (np.random.randint(low=-32000, high=32000, size=44100*60)/32678).astype('<f8')

data2audiofile('ffmpeg_mp3.mp3',data)
data2audiofile('ffmpeg_wav.wav',data)
sf.write('sf_wav.wav',data,44100)

Here the resulting files displayed in audacity:

Mips
  • 111
  • 2
  • 6
  • 1
    You need to close `pipe.stdin` and wait for the sub-process to end: Add `pipe.stdin.close()` and `pipe.wait()` after `pipe.stdin.write(data)`. Closing the pipe flushes the buffer. You can also try setting large buffer size in `sp.Popen`. I can't reproduce the problem in my machine, so I don't know if it's going to solve it (I checked the duration using `mediainfo` tool). – Rotem Feb 03 '20 at 17:33
  • Great answer! I added the code as you recommended and it works as I expect! – Mips Feb 03 '20 at 21:37
  • I posted the comment as an answer. – Rotem Feb 03 '20 at 22:16

1 Answers1

2

You need to close pipe.stdin and wait for the sub-process to end.

Closing pipe.stdin flushes stdin pipe.
The subject is explained here: Writing to a python subprocess pipe:

The key it to close stdin (flush and send EOF) before calling wait

Add the following code lines after pipe.stdin.write(data):

pipe.stdin.close()
pipe.wait()

You can also try setting a large buffer size in sp.Popen:

pipe = sp.Popen(out_cmds, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, bufsize=10**8)
Rotem
  • 30,366
  • 4
  • 32
  • 65