報錯現(xiàn)場
報錯反復出現(xiàn)入问,每次解決一個問題丹锹,又因為下一個文件找不到而報錯。
C:\etc\Python\Python39\python.exe "C:/Program Files/JetBrains/PyCharm 2022.2.2/plugins/python/helpers/pydev/pydevd.py" --multiprocess --qt-support=auto --client 127.0.0.1 --port 51307 --file C:\workplace\github.com\***\sources\medias\BMedia.py
Connected to pydev debugger (build 222.4167.33)
Traceback (most recent call last):
File "C:\etc\Python\Python39\lib\subprocess.py", line 951, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "C:\etc\Python\Python39\lib\subprocess.py", line 1420, in _execute_child
hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
File "C:\Program Files\JetBrains\PyCharm 2022.2.2\plugins\python\helpers\pydev\_pydev_bundle\pydev_monkey.py", line 578, in new_CreateProcess
return getattr(_subprocess, original_name)(app_name, patch_arg_str_win(cmd_line), *args)
FileNotFoundError: [WinError 2] 系統(tǒng)找不到指定的文件芬失。
python-BaseException
Backend QtAgg is interactive backend. Turning interactive mode on.
解決辦法
Windows 系統(tǒng)
- 下載安裝 ImageMagick ; ffmpeg-release-essentials.zip
-
設置環(huán)境變量
IMAGEMAGICK_BINARY
FFMPEG_BINARY
ffmpeg_bin_path
關鍵代碼展示
moviepy.config.py
config_defaults.py 編寫了針對 ffmpeg, imagemagick 的默認值獲取
import os
FFMPEG_BINARY = os.getenv('FFMPEG_BINARY', 'ffmpeg-imageio')
IMAGEMAGICK_BINARY = os.getenv('IMAGEMAGICK_BINARY', 'auto-detect')
config.py 嘗試加載 ffmpeg, imagemagick 資源
if IMAGEMAGICK_BINARY=='auto-detect':
if os.name == 'nt':
try:
key = wr.OpenKey(wr.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ImageMagick\\Current')
IMAGEMAGICK_BINARY = wr.QueryValueEx(key, 'BinPath')[0] + r"\convert.exe"
key.Close()
except:
IMAGEMAGICK_BINARY = 'unset'
elif try_cmd(['convert'])[0]:
IMAGEMAGICK_BINARY = 'convert'
else:
IMAGEMAGICK_BINARY = 'unset'
else:
if not os.path.exists(IMAGEMAGICK_BINARY):
raise IOError(
"ImageMagick binary cannot be found at {}".format(
IMAGEMAGICK_BINARY
)
)
if not os.path.isfile(IMAGEMAGICK_BINARY):
raise IOError(
"ImageMagick binary found at {} is not a file".format(
IMAGEMAGICK_BINARY
)
)
success, err = try_cmd([IMAGEMAGICK_BINARY])
if not success:
raise IOError("%s - The path specified for the ImageMagick binary might "
"be wrong: %s" % (err, IMAGEMAGICK_BINARY))
moviepy.config_defaults.py
if FFMPEG_BINARY=='ffmpeg-imageio':
from imageio.plugins.ffmpeg import get_exe
FFMPEG_BINARY = get_exe()
elif FFMPEG_BINARY=='auto-detect':
if try_cmd(['ffmpeg'])[0]:
FFMPEG_BINARY = 'ffmpeg'
elif try_cmd(['ffmpeg.exe'])[0]:
FFMPEG_BINARY = 'ffmpeg.exe'
else:
FFMPEG_BINARY = 'unset'
else:
success, err = try_cmd([FFMPEG_BINARY])
if not success:
raise IOError(
str(err) +
" - The path specified for the ffmpeg binary might be wrong")
很顯然楣黍, 系統(tǒng)沒有指定資源文件時,moviepy會自己嘗試加載棱烂。只不過找不到的時候拋出異常租漂。
pydub.utils.py
最關鍵的部分是,pydub借用了avprobe颊糜、ffprobe來完成它的邏輯哩治。
而借用的方式就是調用subprocess.Popen
創(chuàng)建子線程,直接調用操作系統(tǒng)衬鱼,執(zhí)行ffprobe工具业筏。
此處報錯找不到文件就是因為在環(huán)境中我當時并未配置 ffprobe
所在目錄,所以Popen
在執(zhí)行命令ffprobe
時鸟赫,自然就作為找不到ffprobe這個文件的異常爆出來了蒜胖。
def mediainfo_json(filepath, read_ahead_limit=-1):
"""Return json dictionary with media info(codec, duration, size, bitrate...) from filepath
"""
prober = get_prober_name()
command_args = [
"-v", "info",
"-show_format",
"-show_streams",
]
try:
command_args += [fsdecode(filepath)]
stdin_parameter = None
stdin_data = None
except TypeError:
if prober == 'ffprobe':
command_args += ["-read_ahead_limit", str(read_ahead_limit),
"cache:pipe:0"]
else:
command_args += ["-"]
stdin_parameter = PIPE
file, close_file = _fd_or_path_or_tempfile(filepath, 'rb', tempfile=False)
file.seek(0)
stdin_data = file.read()
if close_file:
file.close()
command = [prober, '-of', 'json'] + command_args
res = Popen(command, stdin=stdin_parameter, stdout=PIPE, stderr=PIPE)
output, stderr = res.communicate(input=stdin_data)
output = output.decode("utf-8", 'ignore')
stderr = stderr.decode("utf-8", 'ignore')
info = json.loads(output)
# ... 后續(xù)代碼省略
這段代碼就是他嘗試找到系統(tǒng)中的avprobe
命令,或者ffprobe
命令抛蚤。 如果都找不到就會警告:我只能使用默認配置台谢,但是可能運行不了~
def get_prober_name():
"""
Return probe application, either avconv or ffmpeg
"""
if which("avprobe"):
return "avprobe"
elif which("ffprobe"):
return "ffprobe"
else:
# should raise exception
warn("Couldn't find ffprobe or avprobe - defaulting to ffprobe, but may not work", RuntimeWarning)
return "ffprobe"
這段代碼就是具體尋找的過程了。顯然岁经,它遍歷了系統(tǒng)環(huán)境中配置的路徑朋沮,所有路徑都會嘗試找命令,本質上跟在cmd中輸入命令缀壤,系統(tǒng)查找可以運行的工具是一個邏輯樊拓。
def which(program):
"""
Mimics behavior of UNIX which command.
"""
# Add .exe program extension for windows support
if os.name == "nt" and not program.endswith(".exe"):
program += ".exe"
envdir_list = [os.curdir] + os.environ["PATH"].split(os.pathsep)
for envdir in envdir_list:
program_path = os.path.join(envdir, program)
if os.path.isfile(program_path) and os.access(program_path, os.X_OK):
return program_path
再次運行效果
Success
Popen: returncode