如何使用 ffmpeg 合并 python 中的音频和视频文件?
how to merge audio and video file in python using ffmpeg?
我正在尝试创建一个 python 脚本,将音频和视频文件合并到一个(音频+视频)文件中。
我正在使用 ffmpeg 来实现此目的,但它无法正常工作,并且出现错误。
而 运行 这里的脚本是我的脚本。
import os
import subprocess
import time
from datetime import datetime
def merge_all():
global p
p =subprocess.Popen('ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -
strftime 1 ' + dt_file_name ,stdin=subprocess.PIPE,creationflags = subprocess.CREATE_NO_WINDOW)
time.sleep(2)
print('merging done')
os.remove('temp_vid.mp4')
os.remove('temp_voice.wav')
print('file delete done')>
这里是错误
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\kp\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "C:\Users\kp\Desktop\test.py", line 179, in change_icon
merge_all()
File "C:\Users\kp\Desktop\test.py", line 104, in merge_all
p =subprocess.Popen('ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -strftime 1 ' + dt_file_name ,stdin=subprocess.PIPE,creationflags = subprocess.CREATE_NO_WINDOW)
File "C:\Users\kp\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 854, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "C:\Users\kp\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 1307, in _execute_child
hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
FileNotFoundError: [WinError 2] The system cannot find the file specified
先做pip install ffmpeg-python
然后您可以使用以下方式组合它们:
import ffmpeg
video = ffmpeg.input('directory_to_video')
audio = ffmpeg.input('directory_to_audio')
ffmpeg.concat(video, audio, v=1, a=1).output('directory_to_save_mp4').run()
你有这条线:
p =subprocess.Popen('ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -strftime 1 ' + dt_file_name ,stdin=subprocess.PIPE,creationflags = subprocess.CREATE_NO_WINDOW)
相反,试试这个:
cmd = 'ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -strftime 1 ' + dt_file_name
p = subprocess.Popen(cmd.split(), stdin=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)
当然,这是假设这些选项是正确的。
感谢@x00 指出拆分命令的更安全方法是使用 shlex.split()
。所以:
cmd = 'ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -strftime 1 ' + dt_file_name
p = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)
之所以更安全,是因为参数也可以包含空格,str.split()
不会考虑这一点。例如:
cmd = 'ffmpeg -i "C:\My long folder name with spaces\temp_vid.mp4"'
这被 shlex.split()
正确拆分,但不是 str.split()
。
来自docs:
An example of passing some arguments to an external program as a sequence is:
Popen(["/usr/bin/git", "commit", "-m", "Fixes a bug."])
On POSIX, if args
is a string, the string is interpreted as the name or path of the program to execute. However, this can only be done if not passing arguments to the program.
Note It may not be obvious how to break a shell command into a sequence of arguments, especially in complex cases. shlex.split()
can illustrate how to determine the correct tokenization for args:
>>> import shlex, subprocess
>>> command_line = input()
/bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'"
>>> args = shlex.split(command_line)
>>> print(args)
['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"]
>>> p = subprocess.Popen(args) # Success!
Note in particular that options (such as -input
) and arguments (such as eggs.txt
) that are separated by whitespace in the shell go in separate list elements, while arguments that need quoting or backslash escaping when used in the shell (such as filenames containing spaces or the echo command shown above) are single list elements.
所以对 Popen
的正确调用应该如下所示:
command_line = 'ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -strftime 1 ' + dt_file_name
p = subprocess.Popen(shlex.split(command_line), ...)
在您的特定情况下,您可以按照@Grismar 的建议使用 command_line.split()
,但我认为这是一种容易出错的方法。
这是在您的环境中安装 pip ffmpeg-python 后的 python 代码:
import ffmpeg
input_video = ffmpeg.input('./test_Directory/test.webm')
input_audio = ffmpeg.input('./test_Directory/test.webm')
ffmpeg.concat(input_video, input_audio, v=1, a=1).output('./test_Directory/complete.mp4').run()
或
video = ffmpeg.input('video.mp4')
audio = ffmpeg.input('audio.wav')
out = ffmpeg.output(video, audio, video_path, vcodec='copy', acodec='aac', strict='experimental')
out.run()
或
cmd = 'ffmpeg -y -i Audio.wav -r 30 -i Video.h264 -filter:a aresample=async=1 -c:a flac -c:v copy av.mkv'
subprocess.call(cmd, shell=True)
print('Mixing Done')
我正在尝试创建一个 python 脚本,将音频和视频文件合并到一个(音频+视频)文件中。
我正在使用 ffmpeg 来实现此目的,但它无法正常工作,并且出现错误。 而 运行 这里的脚本是我的脚本。
import os
import subprocess
import time
from datetime import datetime
def merge_all():
global p
p =subprocess.Popen('ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -
strftime 1 ' + dt_file_name ,stdin=subprocess.PIPE,creationflags = subprocess.CREATE_NO_WINDOW)
time.sleep(2)
print('merging done')
os.remove('temp_vid.mp4')
os.remove('temp_voice.wav')
print('file delete done')>
这里是错误
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\kp\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "C:\Users\kp\Desktop\test.py", line 179, in change_icon
merge_all()
File "C:\Users\kp\Desktop\test.py", line 104, in merge_all
p =subprocess.Popen('ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -strftime 1 ' + dt_file_name ,stdin=subprocess.PIPE,creationflags = subprocess.CREATE_NO_WINDOW)
File "C:\Users\kp\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 854, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "C:\Users\kp\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 1307, in _execute_child
hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
FileNotFoundError: [WinError 2] The system cannot find the file specified
先做pip install ffmpeg-python
然后您可以使用以下方式组合它们:
import ffmpeg
video = ffmpeg.input('directory_to_video')
audio = ffmpeg.input('directory_to_audio')
ffmpeg.concat(video, audio, v=1, a=1).output('directory_to_save_mp4').run()
你有这条线:
p =subprocess.Popen('ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -strftime 1 ' + dt_file_name ,stdin=subprocess.PIPE,creationflags = subprocess.CREATE_NO_WINDOW)
相反,试试这个:
cmd = 'ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -strftime 1 ' + dt_file_name
p = subprocess.Popen(cmd.split(), stdin=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)
当然,这是假设这些选项是正确的。
感谢@x00 指出拆分命令的更安全方法是使用 shlex.split()
。所以:
cmd = 'ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -strftime 1 ' + dt_file_name
p = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)
之所以更安全,是因为参数也可以包含空格,str.split()
不会考虑这一点。例如:
cmd = 'ffmpeg -i "C:\My long folder name with spaces\temp_vid.mp4"'
这被 shlex.split()
正确拆分,但不是 str.split()
。
来自docs:
An example of passing some arguments to an external program as a sequence is:
Popen(["/usr/bin/git", "commit", "-m", "Fixes a bug."])
On POSIX, if
args
is a string, the string is interpreted as the name or path of the program to execute. However, this can only be done if not passing arguments to the program.Note It may not be obvious how to break a shell command into a sequence of arguments, especially in complex cases.
shlex.split()
can illustrate how to determine the correct tokenization for args:>>> import shlex, subprocess >>> command_line = input() /bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'" >>> args = shlex.split(command_line) >>> print(args) ['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"] >>> p = subprocess.Popen(args) # Success!
Note in particular that options (such as
-input
) and arguments (such aseggs.txt
) that are separated by whitespace in the shell go in separate list elements, while arguments that need quoting or backslash escaping when used in the shell (such as filenames containing spaces or the echo command shown above) are single list elements.
所以对 Popen
的正确调用应该如下所示:
command_line = 'ffmpeg -i temp_vid.mp4 -i temp_voice.wav -c:v copy -c:a aac -strict experimental -strftime 1 ' + dt_file_name
p = subprocess.Popen(shlex.split(command_line), ...)
在您的特定情况下,您可以按照@Grismar 的建议使用 command_line.split()
,但我认为这是一种容易出错的方法。
这是在您的环境中安装 pip ffmpeg-python 后的 python 代码:
import ffmpeg
input_video = ffmpeg.input('./test_Directory/test.webm')
input_audio = ffmpeg.input('./test_Directory/test.webm')
ffmpeg.concat(input_video, input_audio, v=1, a=1).output('./test_Directory/complete.mp4').run()
或
video = ffmpeg.input('video.mp4')
audio = ffmpeg.input('audio.wav')
out = ffmpeg.output(video, audio, video_path, vcodec='copy', acodec='aac', strict='experimental')
out.run()
或
cmd = 'ffmpeg -y -i Audio.wav -r 30 -i Video.h264 -filter:a aresample=async=1 -c:a flac -c:v copy av.mkv'
subprocess.call(cmd, shell=True)
print('Mixing Done')