python subprocess with ffmpeg stops when launching an exit with ffmpeg

1

I'm trying to capture the output with ffmpeg and I've noticed that this binary throws the outputs by the stderr but I realized that when the file already exists it is thrown by stdout but here I have a problem and that the script it gets stuck, my purpose is to capture the outputs without waiting for the process to finish both the stdout and the stdin but I can not do it.

If the file does not exist everything works very well but if it exits then I am here with the problem.

from subprocess import PIPE,Popen
from time import sleep
import subprocess

p = Popen(['ffmpeg','-i','rufian.mp4','-f','mp3','rufiannn.mp3'],stdin=PIPE,\
            stdout=PIPE,\
            stderr=PIPE,universal_newlines=True)

while p.poll() == None:
    err = p.stderr.readline()
    print(err)

the problem is that once the file exists the script stops because the console says if you want to overwrite it and I can not capture this in any way even with stdout.readline() , with communicate it does not help me because it always waits for the process finish.

Is there a solution for this? for now all I find is having to program code to check if it exists.

    
asked by Francisco 03.07.2017 в 16:14
source

2 answers

0

Doing some tests I have observed that for some reason (that for now I do not reach to elucidate) with readline does not print all the output correctly, it is cut off.

Well, using read if you can get all the output (which in ffmpeg can be both stdout and stderr (although it is not an exception, someday I will understand it ...) without problems:

import subprocess
import sys



p = subprocess.Popen(['ffmpeg','-i','file.mp4','-f','mp3','file1.mp3'],
                     stdin=subprocess.PIPE,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT,
                     universal_newlines=True,
                     )

while p.poll() == None:
    out = p.stdout.read(1)
    if out != '':
        sys.stdout.write(out)
        sys.stdout.flush()

sys.stdout.write(out) is faster than print(out, end='') although you could use print .

In the end I managed to read the entire output and even use the stdin by entering y or N when asked to overwrite. The code is an adaptation to the peculiarities of ffmpeg and adding the possibility of using stdin of the magnificent response of J.F. Sebatian on non-blocking reading in subprocess.PIPE ':

link

My code is not very polished but as an example it works as it should:

import sys
import subprocess
from threading  import Thread
from queue import Queue, Empty

ON_POSIX = 'posix' in sys.builtin_module_names

def enqueue_output(out, queue):
    while p.poll() == None:
        out = p.stdout.read(1)   
        if out != '':
            queue.put(str(out))


p = subprocess.Popen(['ffmpeg','-i','file.mp4','-f','mp3','file1.mp3'],
                     stdin=subprocess.PIPE,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT,
                     universal_newlines=True,
                     bufsize=1,
                     close_fds=ON_POSIX
                    )

q = Queue()
t = Thread(target=enqueue_output, args=(p.stdout, q))
t.daemon = True
t.start()

string = ''
while p.poll() == None:
    try:
        c = q.get_nowait()
    except Empty:
        if 'Overwrite ? [y/N]' in string:
            i = input()
            p.stdin.write(i)
            p.stdin.close()
            string = ''
    else:
        sys.stdout.write(c)
        sys.stdout.flush()
        string += c 

Execution example in the same IDLE:

  

Warning: the code is tested in Python 3.6 under Windows.

    
answered by 04.07.2017 / 03:25
source
0

Thanks to all the answers, it has helped me to solve the problem, in the end I left the code in the following way

from __future__ import print_function
from subprocess import Popen,PIPE,STDOUT
import time


p = Popen('ffmpeg -i rufian.mp4 -f mp3 out.mp3',stdin=PIPE,stderr=STDOUT,stdout=PIPE,universal_newlines=True)

tmp = ''
while p.poll() == None:
    out = p.stdout.read(1)
    tmp += out
    if '\n' in out:
        print(tmp)
        tmp = ''
    elif 'Overwrite ? [y/N]' in tmp:
        print(tmp)
        tmp = ''
        p.stdin.write('Y\n')
    
answered by 04.07.2017 в 21:18