Skip to content

Commit b0d276d

Browse files
committed
fix: Replace Popen in mediainfo_json decoder
1 parent a5190e1 commit b0d276d

File tree

5 files changed

+94
-9
lines changed

5 files changed

+94
-9
lines changed

tagstudio/src/qt/helpers/silent_popen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ def promptless_Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None,
66
if sys.platform == "win32":
77
creation_flags = subprocess.CREATE_NO_WINDOW
88

9-
return subprocess.Popen(args=args, bufsize=bufsize, executable=executable, stdin=stdin, stdout=stdout, stderr=stderr, preexec_fn=preexec_fn, close_fds=close_fds, shell=shell, cwd=cwd, env=env, universal_newlines=universal_newlines, startupinfo=startupinfo, creationflags=creation_flags, restore_signals=restore_signals, start_new_session=start_new_session, pass_fds=pass_fds, group=group, extra_groups=extra_groups, user=user, umask=umask, encoding=encoding, errors=errors, text=text, pipesize=pipesize, process_group=process_group)
9+
return subprocess.Popen(args=args, bufsize=bufsize, executable=executable, stdin=stdin, stdout=stderr, stderr=stderr, preexec_fn=preexec_fn, close_fds=close_fds, shell=shell, cwd=cwd, env=env, universal_newlines=universal_newlines, startupinfo=startupinfo, creationflags=creation_flags, restore_signals=restore_signals, start_new_session=start_new_session, pass_fds=pass_fds, group=group, extra_groups=extra_groups, user=user, umask=umask, encoding=encoding, errors=errors, text=text, pipesize=pipesize, process_group=process_group)

tagstudio/src/qt/helpers/vendored/ffmpeg.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@ def _probe(filename, cmd='ffprobe', timeout=None, **kwargs):
2323
args += ffmpeg._utils.convert_kwargs_to_cmd_line_args(kwargs)
2424
args += [filename]
2525

26-
creation_flags = 0
27-
if sys.platform == "win32":
28-
creation_flags = subprocess.CREATE_NO_WINDOW
29-
3026
# PATCHED
3127
p = promptless_Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
3228
communicate_kwargs = {}

tagstudio/src/qt/helpers/vendored/audio_segment.py renamed to tagstudio/src/qt/helpers/vendored/pydub/audio_segment.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import sys
1313
import struct
1414
from pydub.logging_utils import log_conversion, log_subprocess_output
15-
from pydub.utils import mediainfo_json, fsdecode
15+
from pydub.utils import fsdecode
1616
import base64
1717
from collections import namedtuple
1818
from io import StringIO, BytesIO
@@ -40,6 +40,7 @@
4040
MissingAudioParameter,
4141
)
4242

43+
from src.qt.helpers.vendored.pydub.utils import _mediainfo_json
4344
from src.qt.helpers.silent_popen import promptless_Popen
4445

4546
if sys.version_info >= (3, 0):
@@ -726,7 +727,8 @@ def is_format(f):
726727
if codec:
727728
info = None
728729
else:
729-
info = mediainfo_json(orig_file, read_ahead_limit=read_ahead_limit)
730+
# PATCHED
731+
info = _mediainfo_json(orig_file, read_ahead_limit=read_ahead_limit)
730732
if info:
731733
audio_streams = [x for x in info['streams']
732734
if x['codec_type'] == 'audio']
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import json
2+
import re
3+
import subprocess
4+
5+
from pydub.utils import (
6+
get_prober_name,
7+
fsdecode,
8+
_fd_or_path_or_tempfile,
9+
get_extra_info,
10+
)
11+
12+
from src.qt.helpers.silent_popen import promptless_Popen
13+
14+
def _mediainfo_json(filepath, read_ahead_limit=-1):
15+
"""Return json dictionary with media info(codec, duration, size, bitrate...) from filepath
16+
"""
17+
prober = get_prober_name()
18+
command_args = [
19+
"-v", "info",
20+
"-show_format",
21+
"-show_streams",
22+
]
23+
try:
24+
command_args += [fsdecode(filepath)]
25+
stdin_parameter = None
26+
stdin_data = None
27+
except TypeError:
28+
if prober == 'ffprobe':
29+
command_args += ["-read_ahead_limit", str(read_ahead_limit),
30+
"cache:pipe:0"]
31+
else:
32+
command_args += ["-"]
33+
stdin_parameter = subprocess.PIPE
34+
file, close_file = _fd_or_path_or_tempfile(filepath, 'rb', tempfile=False)
35+
file.seek(0)
36+
stdin_data = file.read()
37+
if close_file:
38+
file.close()
39+
40+
command = [prober, '-of', 'json'] + command_args
41+
# PATCHED
42+
res = promptless_Popen(command, stdin=stdin_parameter, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
43+
output, stderr = res.communicate(input=stdin_data)
44+
output = output.decode("utf-8", 'ignore')
45+
stderr = stderr.decode("utf-8", 'ignore')
46+
47+
try:
48+
info = json.loads(output)
49+
except json.decoder.JSONDecodeError:
50+
# If ffprobe didn't give any information, just return it
51+
# (for example, because the file doesn't exist)
52+
return None
53+
if not info:
54+
return info
55+
56+
extra_info = get_extra_info(stderr)
57+
58+
audio_streams = [x for x in info['streams'] if x['codec_type'] == 'audio']
59+
if len(audio_streams) == 0:
60+
return info
61+
62+
# We just operate on the first audio stream in case there are more
63+
stream = audio_streams[0]
64+
65+
def set_property(stream, prop, value):
66+
if prop not in stream or stream[prop] == 0:
67+
stream[prop] = value
68+
69+
for token in extra_info[stream['index']]:
70+
m = re.match(r'([su]([0-9]{1,2})p?) \(([0-9]{1,2}) bit\)$', token)
71+
m2 = re.match(r'([su]([0-9]{1,2})p?)( \(default\))?$', token)
72+
if m:
73+
set_property(stream, 'sample_fmt', m.group(1))
74+
set_property(stream, 'bits_per_sample', int(m.group(2)))
75+
set_property(stream, 'bits_per_raw_sample', int(m.group(3)))
76+
elif m2:
77+
set_property(stream, 'sample_fmt', m2.group(1))
78+
set_property(stream, 'bits_per_sample', int(m2.group(2)))
79+
set_property(stream, 'bits_per_raw_sample', int(m2.group(2)))
80+
elif re.match(r'(flt)p?( \(default\))?$', token):
81+
set_property(stream, 'sample_fmt', token)
82+
set_property(stream, 'bits_per_sample', 32)
83+
set_property(stream, 'bits_per_raw_sample', 32)
84+
elif re.match(r'(dbl)p?( \(default\))?$', token):
85+
set_property(stream, 'sample_fmt', token)
86+
set_property(stream, 'bits_per_sample', 64)
87+
set_property(stream, 'bits_per_raw_sample', 64)
88+
return info

tagstudio/src/qt/widgets/thumb_renderer.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@
2828
from PIL.Image import DecompressionBombError
2929
from pillow_heif import register_avif_opener, register_heif_opener
3030
from pydub import exceptions
31-
from src.qt.helpers.vendored.audio_segment import _AudioSegment as AudioSegment
32-
from src.qt.helpers.blender_thumbnailer import blend_thumb
31+
from src.qt.helpers.vendored.pydub.audio_segment import _AudioSegment as AudioSegment
3332
from PySide6.QtCore import QObject, QSize, Qt, Signal
3433
from PySide6.QtGui import QGuiApplication, QPixmap
3534
from src.core.constants import FONT_SAMPLE_SIZES, FONT_SAMPLE_TEXT

0 commit comments

Comments
 (0)