【问题标题】:how to merge audio and video file in python using ffmpeg?如何使用ffmpeg在python中合并音频和视频文件?
【发布时间】:2020-11-21 04:43:51
【问题描述】:

我正在尝试创建一个 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

【问题讨论】:

  • 将命令拆分为空格并将结果列表而不是整个命令作为字符串传递。
  • @Grismar 您可以编辑此代码并在答案部分显示吗?

标签: python ffmpeg subprocess audio-video-sync


【解决方案1】:

来自docs

将一些参数作为序列传递给外部程序的示例是:

Popen(["/usr/bin/git", "commit", "-m", "Fixes a bug."])

POSIX 上,如果args 是字符串,则该字符串被解释为要执行的程序的名称或路径。 但是,这只能在不向程序传递参数的情况下完成

注意 如何将 shell 命令分解为一系列参数可能并不明显,尤其是在复杂情况下。 shlex.split() 可以说明如何确定 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!

请特别注意,shell 中由空格分隔的选项(例如-input)和参数(例如eggs.txt)放在单独的列表元素中,而在使用时需要引用或反斜杠转义的参数shell(例如包含空格的文件名或上面显示的 echo 命令)是单个列表元素。

所以对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(),但我认为这是容易出错的方法。

【讨论】:

    【解决方案2】:

    这是在您的环境中安装 pip install 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')
    

    【讨论】:

    • 我个人可能也喜欢使用该库,但从问题看来,OP 已经安装了 ffmpeg 并且正在寻求使用它。此外,不使用该库的优势在于脚本可以在任何使用 Python 的机器上运行,而无需额外的依赖。
    【解决方案3】:

    你有这行:

    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() 拆分。

    【讨论】:

      【解决方案4】:

      先做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()
      

      【讨论】:

        猜你喜欢
        • 2019-11-20
        • 1970-01-01
        • 1970-01-01
        • 2019-05-04
        • 1970-01-01
        • 2018-02-07
        • 2016-05-30
        • 2013-05-22
        相关资源
        最近更新 更多