【问题标题】:FFmpeg save .mp3 output into a variableFFmpeg 将 .mp3 输出保存到变量中
【发布时间】:2021-07-25 22:34:44
【问题描述】:

在我的应用程序中,我想修改各种 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 种声音,所以我尝试以惰性/简单的方式实现它:

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:?

【问题讨论】:

    标签: python ffmpeg encoding


    【解决方案1】:

    您的方法是正确的,但需要修正。

    修复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)
    

    听起来不错……


    更新:

    命名管道实现移至following 帖子。

    【讨论】:

    • 按原样工作,但我正在努力混合两种以上的声音。这怎么可能实现?
    • 对于两个以上的输入流,您必须使用named pipes。我从未使用过命名管道,因为我使用的是 Windows。与 Linux 相比,在 Windows 中使用命名管道需要一些额外的工作。
    • 尝试使用命名管道。问题已编辑。
    • 我想出了如何使用命名管道(更新了我的帖子)。我希望我做对了,而不仅仅是过于复杂的想法。有趣的是,我找不到一个很好的参考来使用命名管道作为 FFmpeg 和 Python 的输入...
    猜你喜欢
    • 2015-06-22
    • 2021-12-30
    • 2011-11-10
    • 2021-11-12
    • 1970-01-01
    • 1970-01-01
    • 2011-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多