Windows 绝对路径直接塞进 movie 一定失败:盘符的冒号会被当成参数分隔符。 必须「反斜杠换正斜杠 + 冒号前加反斜杠」,两步一起做。
上一节用的是相对路径,所以没碰上这个坑。 一旦换成绝对路径——也就是实际做项目时的常态——就得处理它。
一、四种写法,只有一种能过
同一个文件,四种写法各试一次:
写法 送进去的字符串开头 结果
原样 I:\Desktop\… 失败 只换斜杠 I:/Desktop/… 失败 只转义冒号 I\:\Desktop\… 失败 斜杠加转义 I\:/Desktop/… 成功
失败的那三个报的都是 No such file or directory,
看起来像「文件不存在」,其实文件好好的。
二、为什么偏偏是冒号
滤镜的参数用冒号分隔:movie=文件名:loop=0:seek_point=1。
解析器从左往右扫,见到冒号就断。
I: 里那个冒号被当成了「参数到此结束」,
于是它拿着一个光秃秃的 I 去找文件,当然找不到。
转义成 I\: 之后,解析器才知道「这个冒号是路径的一部分」。
反斜杠也得换成正斜杠——这是 FFmpeg 自己的解析,不是 Windows 的 API。
两个坑叠在一起,所以必须同时处理。只做一步,还是失败。
三、相对路径为什么反而没事
在素材所在目录里写 movie=s5.mp4,一次就过。
因为字符串里没有冒号,解析器不会误断。
这就解释了「为什么照着别人的命令抄就是不行」: 写命令的人在 Linux 上,那里根本没有盘符,路径里也没有冒号。
换到 Windows,同一行命令凭空多出一个必须转义的字符。 而绝大多数教程压根不会提这件事。
四、一条能背下来的口诀
「先换斜杠,再转冒号,外面套单引号。」
前两步是滤镜的要求,第三步是命令行(shell)的要求,别混为一谈。 路径里有空格时,不套引号,空格之后的半截会被 shell 当成另一个参数。
在 Python 里直接调接口就没有 shell 这一层,加引号反而错—— 引号会变成文件名的两个字符。这一点在 6.6.3 还会再验一次。
五、动手 Demo:四种写法逐个试
把同一个文件的路径按四种方式拼出来,逐个交给 movie。 然后再切到文件所在目录,用相对路径试一次做对照。
import av, os
src = os.path.abspath(u"s5.mp4")
cand = [
(u"原样", src),
(u"只换斜杠", src.replace(u"\\", u"/")),
(u"只转义冒号", src.replace(u":", u"\\:")),
(u"斜杠加转义", src.replace(u"\\", u"/").replace(u":", u"\\:")),
]
for tag, p in cand:
try:
g = av.filter.Graph()
m = g.add(u"movie", p)
s = g.add(u"buffersink")
m.link_to(s)
g.configure()
s.pull()
print(u"%-12s 成功" % tag)
except Exception as e:
print(u"%-12s 失败 %s" % (tag, str(e)[:34]))
old = os.getcwd()
os.chdir(os.path.dirname(src))
try:
g = av.filter.Graph()
m = g.add(u"movie", u"s5.mp4")
s = g.add(u"buffersink")
m.link_to(s)
g.configure()
s.pull()
print(u"相对路径 s5.mp4 成功")
finally:
os.chdir(old)
实跑输出:
--------------------------------------------------------------------
6.2.2 movie 里的绝对路径——冒号必须转义
--------------------------------------------------------------------
**同一个文件,四种写法,全试一遍**
写法 送进去的字符串开头 结果
-----------------------------------------------------------
原样 I:\Desktop\自我教学\.workbuddy… 失败
只换斜杠 I:/Desktop/自我教学/.workbuddy… 失败
只转义冒号 I\:\Desktop\自我教学\.workbudd… 失败
斜杠加转义 I\:/Desktop/自我教学/.workbudd… 成功
**只有第四种成功,而且失败的那三个连「文件不存在」都不说清楚——**
**它们报的是一句笼统的 `No such file or directory`,让人以为是路径本身错了。**
**② 为什么偏偏是冒号**
**滤镜的参数用冒号分隔:`movie=文件名:loop=0:seek_point=1`。**
**解析器从头扫,见到冒号就断——`I:` 里的那个冒号被当成了「参数结束」。**
**于是它拿着 `I` 去找文件,当然找不到。转义成 `I\:` 才告诉它「这是路径的一部分」。**
**反斜杠也必须换成正斜杠:这里是 FFmpeg 自己的解析,不是 Windows 的 API,**
**它只认正斜杠。两个坑叠在一起,就必须同时处理。**
**③ 相对路径为什么反而没事**
写法 结果 为什么
-----------------------------------------------------
s5.mp4 成功 不含冒号,解析器不会误断
I:\…\s5.mp4 失败 盘符冒号被当成参数分隔
**这就是为什么很多人「照着别人命令抄就是不行」:**
**写命令的人在 Linux 上,那里根本没有盘符,路径里也没有冒号。**
**换到 Windows,同一行命令就多出一个必须转义的字符。**
**④ 一条能背下来的口诀**
**「先换斜杠,再转冒号,外面套单引号。」**
**第三步在命令行里尤其重要:`movie='I\:/a b/logo.png'`,**
**路径带空格时不套引号,空格之后的半截会被当成另一个参数。**
三次失败的报错里都有 No such file or directory,很容易被误导。
记住一句话:路径明明对却报「找不到」,先怀疑转义。
os.path.abspath 拿到的是 Windows 风格的反斜杠路径。
Python 里写这段要留神转义:u"\\\\" 是「两个字符」的反斜杠,别被自己绕晕。
最后那段 os.chdir 只是为了证明「相对路径能过」,真实项目里别这么写。
切工作目录会让程序的其他部分也受影响,用一个函数做完就够了。
30 秒实验
- 再试一次:把冒号转义写成
\:会不会被 Python 吃掉?用print(p)看真实字符串。 - 带空格的目录:把文件放进
C:\a b\,看命令行与代码两种场景的差别。 - 换个滤镜:把 movie 换成
subtitles或movie,验证规则是否通用。
常见误区
- 只换斜杠不转冒号。报「找不到文件」,其实文件在那儿。
- 只转冒号不换斜杠。反斜杠在滤镜参数里不是路径分隔符。
- 以为加单引号就更安全。在代码里加引号反而会把文件名弄错。
自测三问(点开对答案)
1. 盘符的冒号为什么会被吃掉? —— 滤镜用冒号分隔参数,`I:` 的冒号被当成「参数到此结束」。 2. 正确的两步是哪两步? —— 反斜杠全部换成正斜杠;冒号前加一个反斜杠。 3. 为什么 Linux 教程从不提这件事? —— Linux 路径里没有盘符,也就没有冒号需要转义。- ☐ (本节完,下一节 6.2.3 -vf 的 delogo 去掉水印)