FFmpeg 将 .mp3 输出保存到变量中
FFmpeg save .mp3 output into a variable
在我的应用程序中,我想修改各种 mp3,然后将它们混合在一起。我知道我可以在 FFmpeg 中使用单个命令行来完成,但它最终会变得非常混乱,因为我需要在每个样本上使用各种过滤器,而我有五个。
我的想法是单独编辑每个样本,将它们保存到一个变量中,最后混合它们。这是我的代码:
import subprocess
def create_samp():
sample= subprocess.run(["ffmpeg", "-y", "-i", "https://freesound.org/data/previews/186/186942_2594536-hq.mp3", \
"-filter_complex", "adelay=15000|15000", "-codec:v", "copy", "-f", "mp3","-"], stdout=subprocess.PIPE)
return(sample)
def record(samp):
subprocess.run(["ffmpeg", "-y", "-i", "https://cdns-preview-b.dzcdn.net/stream/c-b0b684fe962f93dc43f1f7ea493683a1-3.mp3", \
"-i", samp.stdout, "-f", "-mp3", "copy", "output.mp3"])
samp = create_samp()
record(samp)
我的问题是我必须对 stdout
进行编码。我试过 'utf-8'
但出现此错误:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 45: invalid start byte
与`'utf-16':
UnicodeDecodeError: 'utf-16-le' codec can't decode bytes in position 239454-239455: illegal encoding
为什么要解决这个问题?我的方法正确吗?
感谢@Rotem,我成功地完成了我想做的事情。但现在我面临另一个问题,因为我想混合多达 5 种声音,所以我尝试以 lazy/easy 方式实现它:
import subprocess
def create_samp_2():
sample= subprocess.run(["ffmpeg", "-i", "https://freesound.org/data/previews/186/186942_2594536-hq.mp3", \
"-af", "adelay=15000|15000", "-f", "mp3", "pipe:"], stdout=subprocess.PIPE).stdout
return(sample)
def create_samp():
sample= subprocess.run(["ffmpeg", "-i", "https://freesound.org/data/previews/370/370934_6399962-lq.ogg", \
"-af", "adelay=1000|1000", "-f", "mp3", "pipe:"], stdout=subprocess.PIPE).stdout
return(sample)
def record(samp, samp_2):
process = subprocess.Popen(["ffmpeg", "-y", '-f', 'mp3', \
"-i", "https://cdns-preview-b.dzcdn.net/stream/c-b0b684fe962f93dc43f1f7ea493683a1-3.mp3", \
"-i", "pipe:", \
"-i", "pipe:", \
"-filter_complex", "amix=inputs=3:duration=longest", "output.mp3"], stdin=subprocess.PIPE)
process.stdin.write(samp)
process.stdin.write(samp_2)
process.stdin.close()
process.wait()
samp = create_samp()
samp_2 = create_samp_2()
record(samp, samp_2)
令人惊讶的是它有效,我的两个声音在正确的时间开始,但第二个声音搞砸了。所以这不是正确的做法。
然后我按照建议尝试了命名管道:
"pipe1:"
但是我得到这个错误:
pipe1:: Protocol not found
Did you mean file:pipe1:?
阅读命名管道 wiki 说明我必须使用 mkfifo()
创建它们。
所以我尝试了:
import os
pipe1 = "pipe1"
def create_pipe1():
os.mkfifo(pipe1)
But now I have this error: pipe1:: Protocol not found
Did you mean file:pipe1:?
您的方法是正确的,但需要修正。
正在修复 create_samp()
:
- 您不需要
"-codec:v", "copy"
个参数,因为没有视频流。
正在修复 record(samp)
:
- 你不能使用
"-i"
"samp.stdout"
,因为samp.stdout
是一个字节数组(Python子进程模块将它用作字符串)。
- 使用
"-i", "pipe:"
从标准输入管道接收第二个音频。
- 由于您想要混合两个音频流,因此您必须使用
"-filter_complex"
参数和 amix
音频过滤器或 amerge
音频过滤器,如 here 所述。
- 将
samp
写入标准输入管道,并关闭标准输入管道。
代码如下:
import subprocess
def create_samp():
# Read audio stream from https://freesound.org/data/previews/186/186942_2594536-hq.mp3
# Apply adelay audio filter.
# Encode the audio in mp3 format.
# FFmpeg output is passed to stdout pipe, and stored in sample bytes array.
sample= subprocess.run(["ffmpeg", "-i", "https://freesound.org/data/previews/186/186942_2594536-hq.mp3", \
"-af", "adelay=15000|15000", "-f", "mp3", "pipe:"], stdout=subprocess.PIPE).stdout
return(sample)
def record(samp):
# Open FFmpeg as sub-process
# Use two audio input streams:
# 1. WEB address
# 2. PIPE (the input is going to be written stdin pipe).
# Merge the two audio streams using amix audio filter.
# Store the result to output file: output.mp3
process = subprocess.Popen(["ffmpeg", "-y", '-f', 'mp3', \
"-i", "https://cdns-preview-b.dzcdn.net/stream/c-b0b684fe962f93dc43f1f7ea493683a1-3.mp3", \
"-i", "pipe:", \
"-filter_complex", "amix=inputs=2:duration=longest", "output.mp3"], stdin=subprocess.PIPE)
process.stdin.write(samp) # Write samp (bytes array containing mp3 data).
process.stdin.close() # Close stdin pipe.
process.wait() # Wait for FFmpeg sub-process to finish
samp = create_samp()
record(samp)
听起来不错...
更新:
命名管道实现移至 post。
在我的应用程序中,我想修改各种 mp3,然后将它们混合在一起。我知道我可以在 FFmpeg 中使用单个命令行来完成,但它最终会变得非常混乱,因为我需要在每个样本上使用各种过滤器,而我有五个。 我的想法是单独编辑每个样本,将它们保存到一个变量中,最后混合它们。这是我的代码:
import subprocess
def create_samp():
sample= subprocess.run(["ffmpeg", "-y", "-i", "https://freesound.org/data/previews/186/186942_2594536-hq.mp3", \
"-filter_complex", "adelay=15000|15000", "-codec:v", "copy", "-f", "mp3","-"], stdout=subprocess.PIPE)
return(sample)
def record(samp):
subprocess.run(["ffmpeg", "-y", "-i", "https://cdns-preview-b.dzcdn.net/stream/c-b0b684fe962f93dc43f1f7ea493683a1-3.mp3", \
"-i", samp.stdout, "-f", "-mp3", "copy", "output.mp3"])
samp = create_samp()
record(samp)
我的问题是我必须对 stdout
进行编码。我试过 'utf-8'
但出现此错误:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 45: invalid start byte
与`'utf-16':
UnicodeDecodeError: 'utf-16-le' codec can't decode bytes in position 239454-239455: illegal encoding
为什么要解决这个问题?我的方法正确吗?
感谢@Rotem,我成功地完成了我想做的事情。但现在我面临另一个问题,因为我想混合多达 5 种声音,所以我尝试以 lazy/easy 方式实现它:
import subprocess
def create_samp_2():
sample= subprocess.run(["ffmpeg", "-i", "https://freesound.org/data/previews/186/186942_2594536-hq.mp3", \
"-af", "adelay=15000|15000", "-f", "mp3", "pipe:"], stdout=subprocess.PIPE).stdout
return(sample)
def create_samp():
sample= subprocess.run(["ffmpeg", "-i", "https://freesound.org/data/previews/370/370934_6399962-lq.ogg", \
"-af", "adelay=1000|1000", "-f", "mp3", "pipe:"], stdout=subprocess.PIPE).stdout
return(sample)
def record(samp, samp_2):
process = subprocess.Popen(["ffmpeg", "-y", '-f', 'mp3', \
"-i", "https://cdns-preview-b.dzcdn.net/stream/c-b0b684fe962f93dc43f1f7ea493683a1-3.mp3", \
"-i", "pipe:", \
"-i", "pipe:", \
"-filter_complex", "amix=inputs=3:duration=longest", "output.mp3"], stdin=subprocess.PIPE)
process.stdin.write(samp)
process.stdin.write(samp_2)
process.stdin.close()
process.wait()
samp = create_samp()
samp_2 = create_samp_2()
record(samp, samp_2)
令人惊讶的是它有效,我的两个声音在正确的时间开始,但第二个声音搞砸了。所以这不是正确的做法。
然后我按照建议尝试了命名管道:
"pipe1:"
但是我得到这个错误:
pipe1:: Protocol not found
Did you mean file:pipe1:?
阅读命名管道 wiki 说明我必须使用 mkfifo()
创建它们。
所以我尝试了:
import os
pipe1 = "pipe1"
def create_pipe1():
os.mkfifo(pipe1)
But now I have this error: pipe1:: Protocol not found
Did you mean file:pipe1:?
您的方法是正确的,但需要修正。
正在修复 create_samp()
:
- 您不需要
"-codec:v", "copy"
个参数,因为没有视频流。
正在修复 record(samp)
:
- 你不能使用
"-i"
"samp.stdout"
,因为samp.stdout
是一个字节数组(Python子进程模块将它用作字符串)。 - 使用
"-i", "pipe:"
从标准输入管道接收第二个音频。 - 由于您想要混合两个音频流,因此您必须使用
"-filter_complex"
参数和amix
音频过滤器或amerge
音频过滤器,如 here 所述。 - 将
samp
写入标准输入管道,并关闭标准输入管道。
代码如下:
import subprocess
def create_samp():
# Read audio stream from https://freesound.org/data/previews/186/186942_2594536-hq.mp3
# Apply adelay audio filter.
# Encode the audio in mp3 format.
# FFmpeg output is passed to stdout pipe, and stored in sample bytes array.
sample= subprocess.run(["ffmpeg", "-i", "https://freesound.org/data/previews/186/186942_2594536-hq.mp3", \
"-af", "adelay=15000|15000", "-f", "mp3", "pipe:"], stdout=subprocess.PIPE).stdout
return(sample)
def record(samp):
# Open FFmpeg as sub-process
# Use two audio input streams:
# 1. WEB address
# 2. PIPE (the input is going to be written stdin pipe).
# Merge the two audio streams using amix audio filter.
# Store the result to output file: output.mp3
process = subprocess.Popen(["ffmpeg", "-y", '-f', 'mp3', \
"-i", "https://cdns-preview-b.dzcdn.net/stream/c-b0b684fe962f93dc43f1f7ea493683a1-3.mp3", \
"-i", "pipe:", \
"-filter_complex", "amix=inputs=2:duration=longest", "output.mp3"], stdin=subprocess.PIPE)
process.stdin.write(samp) # Write samp (bytes array containing mp3 data).
process.stdin.close() # Close stdin pipe.
process.wait() # Wait for FFmpeg sub-process to finish
samp = create_samp()
record(samp)
听起来不错...
更新:
命名管道实现移至