pythonffmpegmp3wavsoundfile

Why is mp3/wav duration different when I convert a numpy array with ffmpeg into audiofile (python)?


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:


Solution

  • 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)