如何使用openCV python读取Youtube直播流?

23

我想从YouTube读取实时流以执行一些基本的计算机视觉操作,可能需要将YouTube URL 转换为OpenCV可读取的格式,例如:

cap = cv2.VideoCapture('https://www.youtube.com/watch?v=_9OBhtLA9Ig')

有人做过吗?


尝试使用 urllib,请参阅此页面 - Jeru Luke
4个回答

27

我相信您已经知道答案了,但我会为其他搜索相同主题的人回答。您可以使用 Pafy 来完成此操作。

(可能需要与 youtube_dl 一起使用)。

import pafy
import cv2

url = "https://www.youtube.com/watch?v=_9OBhtLA9Ig"
video = pafy.new(url)
best = video.getbest(preftype="mp4")

capture = cv2.VideoCapture(best.url)
while True:
    grabbed, frame = capture.read()
    # ...

就是这样了。


1
它对于视频效果很好。但是我正在尝试用于直播,VideoCapture读取方法在大约40或50帧后会卡住。有什么想法吗? - Guillem
@Guillem 这对于直播流似乎也很有效。也许是特定的流的问题? - de1
@Guillem 尝试垃圾回收。 - Willy satrio nugroho
证书验证失败,可能是YouTube网站做了一些更改导致无法工作。 - mWindows

6
我在我的VidGear Python库中添加了Youtube URL源支持,只需提供URL即可自动将YouTube视频导入OpenCV。以下是完整的Python示例:
# import libraries
from vidgear.gears import CamGear
import cv2

stream = CamGear(source='https://youtu.be/dQw4w9WgXcQ', stream_mode = True, logging=True).start() # YouTube Video URL as input

# infinite loop
while True:
    
    frame = stream.read()
    # read frames

    # check if frame is None
    if frame is None:
        #if True break the infinite loop
        break
    
    # do something with frame here
    
    cv2.imshow("Output Frame", frame)
    # Show output window

    key = cv2.waitKey(1) & 0xFF
    # check for 'q' key-press
    if key == ord("q"):
        #if 'q' key-pressed break out
        break

cv2.destroyAllWindows()
# close output window

# safely close video stream.
stream.stop()

代码来源


很好的源URL。可惜我在你的示例和我的测试URL上得到了无效的源。事实上,这两个都是有效的,并且在浏览器中可以正常工作。具体的错误代码是: RuntimeError: [CamGear:ERROR] :: 源无效,CamGear无法初始化此源上的流! - Mr Purple
1
@MrPurple 如果它们是直播的YouTube视频源,那么你需要使用GSTREAMER后端(或者编译带有GSTREAMER支持的OpenCV),如文档中所述。否则,如果URL不是直播的,它应该能够无缝工作,否则请在此处提出问题:https://github.com/abhiTronix/vidgear/issues - abhiTronix
我认为你的评论完全适用,值得更新你的回答,因为原帖直接询问的是关于直播的内容。 - undefined

2

在获得100-120帧后,@lee hannigan的答案使我的YouTube直播流崩溃了。

我使用Pafy想出了一个方法,只获取x个帧并将它们拼接在一起。然而,这最终拼凑出结果很差,并且结果不连贯。也许Pafy不适用于直播流,我找不到无缝拼接帧的方法。

最终有效的方法稍有修改,来自guttentag_liu在此篇文章中的回答。需要安装几个软件包,代码有点冗长,但是可行。因为文件是直播的,所以需要分块保存在临时文件中。您可以在每个块上进行openCV处理,然后最后保存到文件而不是重新打开。

# pip install urllib
# pip install m3u8
# pip install streamlink
from datetime import datetime, timedelta, timezone
import urllib
import m3u8
import streamlink
import cv2 #openCV

def get_stream(url):

    """
    Get upload chunk url
    input: youtube URL
    output: m3u8 object segment
    """
    #Try this line tries number of times, if it doesn't work, 
    # then show the exception on the last attempt
    # Credit, theherk, https://dev59.com/1XI95IYBdhLWcg3w8iv1
    tries = 10
    for i in range(tries):
    try:
        streams = streamlink.streams(url)
    except:
        if i < tries - 1: # i is zero indexed
            print(f"Attempt {i+1} of {tries}")
            time.sleep(0.1) #Wait half a second, avoid overload
            continue
        else:
            raise
    break

    stream_url = streams["best"] #Alternate, use '360p'

    m3u8_obj = m3u8.load(stream_url.args['url'])
    return m3u8_obj.segments[0] #Parsed stream


def dl_stream(url, filename, chunks):
    """
    Download each chunk to file
    input: url, filename, and number of chunks (int)
    output: saves file at filename location
    returns none.
    """
    pre_time_stamp = datetime(1, 1, 1, 0, 0, tzinfo=timezone.utc)

    
    #Repeat for each chunk
    #Needs to be in chunks because 
    #  1) it's live
    #  2) it won't let you leave the stream open forever
    i=1
    while i <= chunks:
       
        #Open stream
        stream_segment = get_stream(url)
    
        #Get current time on video
        cur_time_stamp = stream_segment.program_date_time
        #Only get next time step, wait if it's not new yet
        if cur_time_stamp <= pre_time_stamp:
            #Don't increment counter until we have a new chunk
            print("NO   pre: ",pre_time_stamp, "curr:",cur_time_stamp)
            time.sleep(0.5) #Wait half a sec
            pass
        else:
            print("YES: pre: ",pre_time_stamp, "curr:",cur_time_stamp)
            print(f'#{i} at time {cur_time_stamp}')
            #Open file for writing stream
            file = open(filename, 'ab+') #ab+ means keep adding to file
            #Write stream to file
            with urllib.request.urlopen(stream_segment.uri) as response:
                html = response.read()
                file.write(html)
            
            #Update time stamp
            pre_time_stamp = cur_time_stamp
            time.sleep(stream_segment.duration) #Wait duration time - 1

            i += 1 #only increment if we got a new chunk

    return None

def openCVProcessing(saved_video_file):
    '''View saved video with openCV
    Add your other steps here'''
    capture = cv2.VideoCapture(saved_video_file)

    while capture.isOpened():
        grabbed, frame = capture.read()  #read in single frame
        if grabbed == False:
            break

        #openCV processing goes here
        #
        
        cv2.imshow('frame',frame)  #Show the frame
        
        #Shown in a new window, To exit, push q on the keyboard
        if cv2.waitKey(20) & 0xFF == ord('q'):
            break

    capture.release()
    cv2.destroyAllWindows()  #close the windows automatically
                  
tempFile = "temp.ts"  #files are format ts, open cv can view them
videoURL = "https://www.youtube.com/watch?v=_9OBhtLA9Ig"

dl_stream(videoURL, tempFile, 3)
openCVProcessing(tempFile)

嘿,杰夫!干得好!我已经尝试过这个程序,但它对我来说表现不一致。有时候,它很好地按预期工作,而其他时候,我会收到“插件错误”,如下所示:“PluginError:无法打开URL:https://youtube.com/get_video_info(404客户端错误:未找到网址:https://www.youtube.com/get_video_info?video_id=1EiC9bvVGnk&el=detailpage)我猜这可能与我尝试过于频繁地访问该页面有关。不确定。你有什么想法吗? - user2813606
@user2813606 我现在遇到了相同的 pluginError 和 HTTPError(之前没有遇到)。如果你访问列出的错误网址,它会给出以下错误信息:status=fail&errorcode=2&reason=Invalid+parameters。我已经添加了一个循环几次重试的代码来等待片段时间,以避免过载系统。如果你喜欢这个答案,请点赞 :) - Rejexx

-1

可能是因为Youtube不再提供喜欢/不喜欢计数,所以第一种解决方案会出现错误。作为解决方案,您应该在pafy包文件中的backend_youtube_dl.py中注释掉第53和54行,如下图所示,之后第一种解决方案中的代码将正常工作:

其次,您不能使用OpenCV获取音频,它是一个计算机视觉库,而不是多媒体库。您应该尝试其他选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接