gpt4 book ai didi

python - 从 ffmpeg 流中分离视频和音频

转载 作者:行者123 更新时间:2023-12-04 22:52:43 27 4
gpt4 key购买 nike

我已经创建了一个类似的线程 How to extract video and audio from ffmpeg stream in python ,但在收到的协商框架内,我无法执行我所询问的内容。我无法重新提出问题,也许无法更详细地制定它。所以我
再次在这里问这个问题。
我正在尝试从每个帧的 ffmpeg 流中实现数据解析过程(视频和音频)。理想情况下,我希望每单位时间为每种数据类型获得 1 个 numpy 数组。我研究了一个例子,分别从音频和视频中获取一个 numpy 数组(当流中存在一个或第二个时)
一切顺利。当流中同时存在视频和音频时,就会出现误解。不清楚要读取多少字节的信息,最重要的是,这些字节的音频是什么,还是视频?

input_stream = ffmpeg.input(in_url)
video = input_stream.video.vflip()
out_stream = ffmpeg.output(
input_stream.audio,
video,
filename='pipe:',
format='rawvideo',
pix_fmt='rgb24',
acodec='pcm_s16le',
ac=1,
ar='16k'
)
process = out_stream.run_async(pipe_stdout=True)
while True:
in_bytes = process.stdout.read(4096)
# what next ?
感谢帮助。

最佳答案

为了分割视频和音频,您可以将视频输出映射到 stderr管道并将音频输出映射到 stdout管道。

                                            -----------
--->| Raw Video | ---> stderr (pipe)
----------- ------------- | -----------
| Input | | FFmpeg | |
| Video and | ---> | sub-process | ---
| Audio | | | |
----------- ------------- | -----------
--->| Raw Audio | ---> stdout (pipe)
-----------

为了创建概念的简单演示,该示例使用合成视频和音频作为输入。
以下 FFmpeg CLI 命令可用作引用:
ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=10 -f lavfi -i sine=frequency=400:r=16384:duration=10 -vcodec rawvideo -pix_fmt rgb24 -map 0:v -f:v rawvideo vid.yuv -map 1:a -acodec pcm_s16le -ar 16384 -ac 1 -f:a s16le aud.pcm
上述命令创建合成视频和合成音频,并将原始视频映射到 vid.yuv文件,并将原始音频映射到 aud.pcm文件。
为了测试,执行上述命令,并保留 vid.yuvaud.pcm作为引用。
我们可以将输出映射到 stderr,而不是将输出映射到文件。和 stdout :
ffmpeg -hide_banner -loglevel error -f lavfi -i testsrc=size=192x108:rate=1:duration=10 -f lavfi -i sine=frequency=400:r=16384:duration=10 -vcodec rawvideo -pix_fmt rgb24 -map 0:v -f:v rawvideo pipe:2 -acodec pcm_s16le -ar 16384 -ac 1 -map 1:a -f:a s16le pipe:1 -report
由于我们使用 stderr对于视频输出,我们需要避免打印到 stderr ,所以我们要添加 -hide_banner -loglevel error论据。

Python 代码示例,使用 subprocess模块,而不是使用 ffmpeg-python .
我只是不知道如何使用 ffmpeg-python 应用映射模块...
Python 代码示例应用以下阶段:
  • 使用 sp.Popen 将 FFmpeg 作为子进程执行.
    申请 stdout=sp.PIPE , stderr=sp.PIPE用于“捕获”stdoutstderr输出管道。
  • 启动视频阅读器线程。
    视频阅读器线程从标准错误读取原始视频帧。
    该线程将视频写入video.yuv用于测试的二进制文件。
  • 启动音频阅读器线程。
    音频阅读器线程从标准输出读取原始音频样本。
    线程将音频写入audio.pcm用于测试的二进制文件。
  • 等待线程和进程完成。

  • 这是一个“独立”的代码示例:
    import subprocess as sp
    import shlex
    import threading

    # Reference command line (stores the video to vid.yuv and the audio to aud.pcm):
    # sp.run(shlex.split('ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=10 -f lavfi -i sine=frequency=400:r=16384:duration=10 -vcodec rawvideo -pix_fmt rgb24 -map 0:v -f:v rawvideo vid.yuv -acodec pcm_s16le -ar 16384 -ac 1 -map 1:a -f:a s16le aud.pcm'))

    # Video reader thread.
    def video_reader(pipe):
    f = open('video.yuv', 'wb') # For testing - store the raw video to video.yuv (binary file)

    while True:
    frame = pipe.read(192*108*3) # Read raw video frame

    # Break the loop when length is too small
    if len(frame) < 192*108*3:
    break

    f.write(frame)

    f.close()


    # Audio reader thread.
    def audio_reader(pipe):
    f = open('audio.pcm', 'wb') # For testing - store the raw audio to audio.pcm (binary file)

    while True:
    samples = pipe.read(4096) # Read raw audio packets (read 2048 samples in pcm_s16le format).

    # Break the loop when length is too small
    if len(samples) < 4096:
    break

    f.write(samples)

    f.close()



    # Execute FFmpeg as sub-process
    # Map the video to stderr and map the audio to stdout
    process = sp.Popen(shlex.split('ffmpeg -hide_banner -loglevel error ' # Set loglevel to error for disabling the prints ot stderr
    '-f lavfi -i testsrc=size=192x108:rate=1:duration=10 ' # Synthetic video 192x108 at 1Hz (10 seconds)
    '-f lavfi -i sine=frequency=400:r=16384:duration=10 ' # Synthetic audio mono, 16384 samples per second (10 seconds)
    '-vcodec rawvideo -pix_fmt rgb24 ' # Raw video codec with rgb24 pixel format
    '-map 0:v -f:v rawvideo pipe:2 ' # rawvideo format is mapped to stderr pipe
    '-acodec pcm_s16le -ar 16384 -ac 1 ' # Audio codec pcm_s16le (-ar 16k has no affect)
    '-map 1:a -f:a s16le pipe:1 ' # s16le audio format is mapped to stdout pipe
    '-report'), # Create a log file (because we can't the statuses that are usually printed to stderr).
    stdout=sp.PIPE, stderr=sp.PIPE)


    # Start video reader thread (pass stderr pipe as argument).
    video_thread = threading.Thread(target=video_reader, args=(process.stderr,))
    video_thread.start()

    # Start audio reader thread (pass stdout pipe as argument).
    audio_thread = threading.Thread(target=audio_reader, args=(process.stdout,))
    audio_thread.start()


    # Wait for threads (and process) to finish.
    video_thread.join()
    audio_thread.join()
    process.wait()
    如需验证,请比较 video.yuvvid.yuvaudio.pcmaud.pcm .
    文件应该相同。

    笔记:
  • 答案只是一个“概念证明”模板。
    用于添加过滤器(如)翻转,以及从 in_url 获取输入还有一些工作。
  • 当只有一个输入时,映射为:-map 0:v-map 0:a .
  • 输入视频的分辨率应该事先知道。
  • 如果音频源不是每秒 16384 个样本的单声道音频,您可能需要使用 aresample过滤器(-ar 16k 可能不起作用)。
  • 关于python - 从 ffmpeg 流中分离视频和音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71041370/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com