首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用streamlink将流作为单个帧处理

使用streamlink将流作为单个帧处理
EN

Stack Overflow用户
提问于 2021-10-08 07:30:37
回答 1查看 747关注 0票数 1

我试图使用streamlink将流作为单个帧处理。

代码语言:javascript
运行
复制
args = ['streamlink', stream_url, "best", "-O"]
process = subprocess.Popen(args, stdout=subprocess.PIPE)
while True:
        frame_size = width * height * 3
        in_frame = streamlink.stdout.read(frame_size)
        if in_frame is None:
            break
        #cv2.imwrite(f'frames/{i}.jpg', in_frame)
        #do anything with in_frame

但是得到的图像看起来像白噪音。我认为这是因为流也包含以字节为单位的音频。然后,我尝试将其传输到ffmpeg,但无法从ffmpeg中获得解码字节。

代码语言:javascript
运行
复制
args = (
        ffmpeg.input('pipe:')
        .filter('fps', fps=1)
        .output('pipe:', vframes=1, format='image2', vcodec='mjpeg')
        .compile()
 )
 process2 = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=None)
 buff = process1.stdout.read(n)
 process2.stdin.write(buff)
 frame = process2.stdout.read(n)

当我尝试这样的smt时,我所有的脚本都挂着,等待着什么。如何正确处理流链接中的流作为单独的帧。以字节或其他方式获取帧?谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-10-08 21:00:53

与其将数据传递给FFmpeg,不如将URL作为输入参数传递给FFmpeg。

  • 从网站URL获取流URL:

def stream_to_url(url,quality='best'):session = Streamlink() stream_to_url= session.streams(url)返回stream_to_url

  • 使用FFprobe获得视频分辨率(如果需要的话):

P= ffmpeg.probe(stream_url,select_streams='v');宽度=p‘streams’宽度‘高度=ffmpeg.probe

  • 以URL作为输入和原始输出格式执行FFmpeg子进程:

process =( ffmpeg .input(stream_url) .video .output(管道:,格式=‘rawvideo’,pix_fmt='bgr24') .run_async(pipe_stdout=True) #以防ffmpeg在非可执行路径中,添加cmd=fullpath like:.run_async(pipe_stdout=True,cmd=r‘c:\FFmpeg\bin\ffmpeg.exe) )

  • 从管道读取帧,转换为NumPy数组,整形和显示:

..。in_bytes =process.stdout.read(宽*高* 3)帧= np.frombuffer(in_bytes,np.uint8).reshape(高,宽,3) cv2.imShow(帧,帧).

完整代码示例:

代码语言:javascript
运行
复制
from streamlink import Streamlink
import numpy as np
import cv2
import ffmpeg

def stream_to_url(url, quality='best'):
    """ Get URL, and return streamlink URL """
    session = Streamlink()
    streams = session.streams(url)

    if streams:
        return streams[quality].to_url()
    else:
        raise ValueError('Could not locate your stream.')


url = 'https://www.twitch.tv/riotgames'  # Login to twitch TV before starting (the URL is for a random live stream).
quality='best'

stream_url = stream_to_url(url, quality)

# Use FFprobe to get video frames resolution (required in case resolution is unknown).
###############################################
p = ffmpeg.probe(stream_url, select_streams='v');
width = p['streams'][0]['width']
height = p['streams'][0]['height']
###############################################

# Execute FFmpeg sub-process with URL as input and raw (BGR) output format.
process = (
    ffmpeg
    .input(stream_url)
    .video
    .output('pipe:', format='rawvideo', pix_fmt='bgr24')
    .run_async(pipe_stdout=True) # In case ffmpeg in not in executable path, add cmd=fullpath like: .run_async(pipe_stdout=True, cmd=r'c:\FFmpeg\bin\ffmpeg.exe')
)


# Read decoded video (frame by frame), and display each frame (using cv2.imshow)
while True:
    # Read raw video frame from stdout as bytes array.
    in_bytes = process.stdout.read(width * height * 3)

    if not in_bytes:
        break

    # Transform the byte read into a NumPy array
    frame = np.frombuffer(in_bytes, np.uint8).reshape([height, width, 3])

    # Display the frame
    cv2.imshow('frame', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

process.stdout.close()
process.wait()
cv2.destroyAllWindows()

有一个使用cv2.VideoCapture的更简单的解决方案

代码语言:javascript
运行
复制
stream_url = stream_to_url(url, quality)

cap = cv2.VideoCapture(stream_url)

while True:
    success, frame = cap.read()

    if not success:
        break

    cv2.imshow('frame', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

更新:

从Streamlink子进程到FFmpeg子进程的管道

假设您必须从Streamlink的stdout管道读取流,并将其写入FFmpeg的stdin管道:

  • Start Streamlink子进程(对管道使用-O参数):

streamlink_args = r'c:\Program (X86)\ Streamlink \bin\Strelin.exe‘,stream_url,“最佳”,"-O“# Windows可执行文件下载自:https://github.com/streamlink/streamlink/releases/tag/2.4.0 streamlink_process = sp.Popen(streamlink_args,stdout=sp.PIPE) # executable作为子进程

  • 实现了一个线程,该线程从Streamlink的stdout管道读取块并写入FFmpeg stdin管道:

def编写器(streamlink_proc,ffmpeg_proc):chunk (非streamlink_proc.poll())和(not ffmpeg_proc.poll()):try: chunk= streamlink_proc.stdout.read(1024) ffmpeg_proc.stdin.write(区块) (BrokenPipeError,OSError)作为e: pass

  • 使用输入管道和输出管道执行FFmpeg子进程:

ffmpeg_process =( ffmpeg .input(‘pix:’) .video .output(‘path:’,format='rawvideo',pix_fmt=‘bin 24’) .run_async(pipe_stdin=True,pipe_stdout=True) #以防ffmpeg在非可执行路径中,添加cmd=fullpath like:.run_async(pipe_stdout=True,cmd=r‘c:\FFmpeg\bin\ffmpeg.exe) )

  • 创建并启动线程:

thread.start() = threading.Thread(target=writer,args=(streamlink_process,ffmpeg_process))

完整代码示例:

代码语言:javascript
运行
复制
import numpy as np
import subprocess as sp
import threading
import cv2
import ffmpeg

#stream_url = 'https://www.nimo.tv/v/v-1712291636586087045'
stream_url = 'https://www.twitch.tv/esl_csgo'

# Assume video resolution is known.
width, height = 1920, 1080


# Writer thread (read from streamlink and write to FFmpeg in chunks of 1024 bytes).
def writer(streamlink_proc, ffmpeg_proc):
    while (not streamlink_proc.poll()) and (not ffmpeg_proc.poll()):
        try:
            chunk = streamlink_proc.stdout.read(1024)
            ffmpeg_proc.stdin.write(chunk)
        except (BrokenPipeError, OSError) as e:
            pass


streamlink_args = [r'c:\Program Files (x86)\Streamlink\bin\streamlink.exe', stream_url, "best", "-O"]  # Windows executable downloaded from: https://github.com/streamlink/streamlink/releases/tag/2.4.0
streamlink_process = sp.Popen(streamlink_args, stdout=sp.PIPE)  # Execute streamlink as sub-process


# Execute FFmpeg sub-process with URL as input and raw (BGR) output format.
ffmpeg_process = (
    ffmpeg
    .input('pipe:')
    .video
    .output('pipe:', format='rawvideo', pix_fmt='bgr24')
    .run_async(pipe_stdin=True, pipe_stdout=True) # In case ffmpeg in not in executable path, add cmd=fullpath like: .run_async(pipe_stdout=True, cmd=r'c:\FFmpeg\bin\ffmpeg.exe')
)


thread = threading.Thread(target=writer, args=(streamlink_process, ffmpeg_process))
thread.start()


# Read decoded video (frame by frame), and display each frame (using cv2.imshow)
while True:
    # Read raw video frame from stdout as bytes array.
    in_bytes = ffmpeg_process.stdout.read(width * height * 3)

    if not in_bytes:
        break

    # Transform the byte read into a NumPy array
    frame = np.frombuffer(in_bytes, np.uint8).reshape([height, width, 3])

    # Display the frame
    cv2.imshow('frame', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

ffmpeg_process.stdout.close()
ffmpeg_process.wait()
#streamlink_process.stdin.close()
streamlink_process.kill()
cv2.destroyAllWindows()

备注:

代码示例使用指向twitch.tv的链接,而不是nimo.tv,因为"Nimo已损坏了流链接插件“。

  • 示例假定宽度和高度是预先知道的。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69492115

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档