WyattBlue / auto-editor

Auto-Editor: Efficient media analysis and rendering
https://auto-editor.com
The Unlicense
2.81k stars 411 forks source link

WinError 6: The handle is invalid, when running auto-editor from another process #407

Closed yutotakano closed 8 months ago

yutotakano commented 9 months ago

Bug description

On Windows, when running auto-editor from another process (such as from within an MPV script), the FFmpeg Popen call fails because of an OS error. The following is the traceback. Please don't mind the [autoeditor] prefix on each line, which is a result of the parent process processing the output.

[autoeditor] Traceback (most recent call last):
[autoeditor]   File "<frozen runpy>", line 198, in _run_module_as_main
[autoeditor]   File "<frozen runpy>", line 88, in _run_code
[autoeditor]   File "C:\Users\moa17\AppData\Roaming\Python\Python311\Scripts\auto-editor.exe\__main__.py", line 7, in <module>
[autoeditor]   File "C:\Users\moa17\AppData\Roaming\Python\Python311\site-packages\auto_editor\__main__.py", line 321, in main
[autoeditor]     ffmpeg = FFmpeg(
[autoeditor]              ^^^^^^^
[autoeditor]   File "C:\Users\moa17\AppData\Roaming\Python\Python311\site-packages\auto_editor\ffwrapper.py", line 44, in __init__
[autoeditor]     _version = get_stdout([self.path, "-version"]).split("\n")[0]
[autoeditor]                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[autoeditor]   File "C:\Users\moa17\AppData\Roaming\Python\Python311\site-packages\auto_editor\utils\func.py", line 116, in get_stdout
[autoeditor]     stdout, _ = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
[autoeditor]                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[autoeditor]   File "C:\Program Files\Python311\Lib\subprocess.py", line 992, in __init__
[autoeditor]     errread, errwrite) = self._get_handles(stdin, stdout, stderr)
[autoeditor]                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[autoeditor]   File "C:\Program Files\Python311\Lib\subprocess.py", line 1365, in _get_handles
[autoeditor]     p2cread = self._make_inheritable(p2cread)
[autoeditor]               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[autoeditor]   File "C:\Program Files\Python311\Lib\subprocess.py", line 1416, in _make_inheritable
[autoeditor]     h = _winapi.DuplicateHandle(
[autoeditor]         ^^^^^^^^^^^^^^^^^^^^^^^^
[autoeditor] OSError: [WinError 6] The handle is invalid

It seems to complain that one of the handles (maybe stdin? as it's not specified in Popen) is not a valid handle to replicate.

What's your platform?

Python Version: 3.11.4 64-bit
Platform: Windows 10 amd64
FFmpeg Version: N-110322-g0c25da5a28-g1440bf15e2+1
FFmpeg Path: C:\Users\moa17\AppData\Roaming\Python\Python311\site-packages\ae_ffmpeg\Windows\ffmpeg.exe
Auto-Editor Version: 23w46a

What command did you use

Invoked as a subprocess from within mpv's JavaScript runtime:

auto-editor file.mp4 --export json --quiet --frame-margin 12,6 --edit audio:threshold=4%

Below is example code from part of the mpv JavaScript plugin:

var AUTO_EDITOR_BIN = "auto-editor";
var AUTO_EDITOR_ARGS = ["--export", "json", "--quiet", "--frame-margin", "12,6", "--edit", "audio:threshold=4%"];
var cmd = {
    name: "subprocess",
    playback_only: false,
    capture_stdout: true,
    capture_stderr: true,
    args: [AUTO_EDITOR_BIN, "file.mp4"].concat(AUTO_EDITOR_ARGS)
};
mp.command_native_async(cmd, function (success, result, error) {
    if (result !== undefined) mp.msg.error(result.stdout);
    if (result !== undefined) mp.msg.error(result.stderr);
});
// result.stdout is empty, and result.stderr contains the Python traceback.

What properties does your input video have?

file.mp4:
 - video:
   - track 0:
     - codec: h264
     - fps: 30
     - resolution: 1280x720
     - aspect ratio: 16:9
     - pixel aspect ratio: 1
     - duration: 3164.2
     - pix fmt: yuv420p
     - color range: unknown
     - color space: unknown
     - color primaries: unknown
     - color transfer: unknown
     - timebase: 1/15360
     - bitrate: 99708
     - lang: und
 - audio:
   - track 0:
     - codec: aac
     - samplerate: 44100
     - channels: 2
     - duration: 3164.229002267574
     - bitrate: 218665
     - lang: und
 - container:
   - duration: 3164.229002
   - bitrate: 327060
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'file.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.76.100
  Duration: 00:52:44.23, start: 0.000000, bitrate: 327 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1280x720 [SAR 1:1 DAR 16:9], 99 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 218 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
At least one output file must be specified

Comments

The same issue was previously reported here: https://github.com/WyattBlue/auto-editor/issues/382

I suspect this problem is because Windows (or the way mpv does it?) does not pass a valid stdin handle to its subprocesses, which means using Popen will try to duplicate that non-existent handle when launching the secondary nested subprocess.

A StackOverflow answer suggests that adding stdin=subprocess.DEVNULL would solve the problem, maybe it'll work.

It appears that this could also happen if you run as a Windows Service or as a packaged executable with PyInstaller, suggesting that it's an issue that should be fixed on auto-editor's side, not mpv's side.

Would you be able to take a look?

WyattBlue commented 8 months ago

Hi, I've added stdin=DEVNULL to several functions in the new release. Can you check if you still reproduce this?

WyattBlue commented 8 months ago

No response from OP, assuming new release fixed this.