pyinstaller packages the GUI program written by PySide2 and calls ffmpeg to hide the CMD console solution

1 Problem Description

Write a GUI program using PySide2, call ffmpeg command line tool, do simple batch video processing (adjust frame width, frame height, video speed, reduce video bitrate to limit video size), use ffmpeg, ffmpeg-python library;
It was easy, but I had a problem:

When pyinstaller packages:

  1. Without -w or--noconsole, there are ugly CMD black boxes, the program can run normally, but a large CMD black box behind the program interface is really ugly.
  2. With -w or--noconsole, without CMD black boxes, the program will wait directly and indefinitely and will not function properly. It is assumed that a shell environment is needed for PIPE input and output when ffmpeg is called

2 Solutions

Directly look anxiously 2.2 Hide the CMD black frame.

2.1 CMD black box is still in place, verbose information is not displayed (cure symptoms, cure diseases)

  1. Use subprocess.call():

    When the CMD command is invoked, adding -loglevel quiet to the parameter after ffmpeg will only have a black box and will not show real-time progress information

  2. Using ffmpeg, ffmpeg-python Libraries

    ffmpeg.run(quiet=True), set quiet to True, only the black box, do not display real-time progress information

2.2 Hide CMD black frame (Ah-ha-ha comfortable)

(I used the probe (call ffprobe.exe to get video stream information) and run (call ffmpeg.exe to perform operations) methods of the ffmpeg library)

  1. Find the **_probe.py** and **_run.py** files for the ffmpeg Library

    Back up these two files, modify them, package them, and restore them to their original state

    Copy the two files to the desktop and modify them before you put them back. (It took me a while. win10 did not open the files with administrator privileges because the ffmpeg library is installed on the Program.. path on the C drive. The changes made in PyCharm have not been saved.)

  2. Modify_probe.py

    Source: p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    Popen parameter adds shell=True, stdin=subprocess.PIPE

    def probe(filename, cmd='ffprobe', **kwargs):
        """Run ffprobe on the specified file and return a JSON representation of the output.
    
        Raises:
            :class:`ffmpeg.Error`: if ffprobe returns a non-zero exit code,
                an :class:`Error` is returned with a generic error message.
                The stderr output can be retrieved by accessing the
                ``stderr`` property of the exception.
        """
        args = [cmd, '-show_format', '-show_streams', '-of', 'json']
        args += convert_kwargs_to_cmd_line_args(kwargs)
        args += [filename]
    
        # Source: p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        # The Popen parameter adds shell=True, stdin=subprocess.PIPE,
    
        p = subprocess.Popen(args, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        out, err = p.communicate()
        if p.returncode != 0:
            raise Error('ffprobe', out, err)
        p.wait()
        return json.loads(out.decode('utf-8'))
  3. Modify_run.py

    Source: return subprocess.Popen(args, stdin=pipe_stdin, stdout=stdout_stream, stderr=stderr_stream)
    Add shell=True, modify stdin=subprocess.PIPE, or modify pipe_stdin=True

    def run_async(
            stream_spec,
            cmd='ffmpeg',
            pipe_stdin=False,
            pipe_stdout=False,
            pipe_stderr=False,
            quiet=False,
            overwrite_output=False,
    ):
        args = compile(stream_spec, cmd, overwrite_output=overwrite_output)
        stdin_stream = subprocess.PIPE if pipe_stdin else None
        stdout_stream = subprocess.PIPE if pipe_stdout or quiet else None
        stderr_stream = subprocess.PIPE if pipe_stderr or quiet else None
    
        # Source: return subprocess.Popen(
        #            args, stdin=pipe_stdin, stdout=stdout_stream, stderr=stderr_stream)    
        # Add shell=True, modify stdin=subprocess.PIPE, or modify pipe_stdin=True
    
        return subprocess.Popen(
            args, shell=True, stdin=subprocess.PIPE, stdout=stdout_stream, stderr=stderr_stream
        )
  4. Put the modified_probe.py and_run.py back into the ffmpeg Library

  5. When pyinstaller packages, add the -w or--noconsole parameter, and CMD black boxes will not appear

    ==The black box is gone, everything is comfortable==

Appendix 1: Instead of using the ffmpeg library, you can call ffmpeg.exe directly using subprocess by specifying the parameter shell=True and stdin=subprocess.PIPE when calling subprocess.Popen().

**Appendix 2: Pack up the program and restore the backup _probe.py and _run.py to the ffmpeg library. I don't know what's wrong with writing this, or restore it as it is**

Reference 1:https://blog.csdn.net/polyhedronx/article/details/82432148 ---- subprocess.Popen setting shell=True, stdin=subprocess.PIPE
Reference 2: https://my.oschina.net/u/2396236/blog/1610765 ---- subprocess.Popen setting shell=True, stdin=subprocess.PIPE
Reference 3:https://blog.csdn.net/iserfj/article/details/94487538 ---- creationflags=0x08000000 or creationflags=subprocess.CREAT_NO_WINDOW (this method I tried to be invalid)

Keywords: Python shell JSON Pycharm

Added by Sephiriz on Sun, 05 Jan 2020 22:37:36 +0200