LoginSignup
1
2

More than 1 year has passed since last update.

YouTubeのライブ配信をOpenCVで再生する

Last updated at Posted at 2022-12-10

TL;DR

Pythonを使って、YouTubeのライブ配信をリアルタイムでOpenCVで再生しました。
動画に音声を付けるのは難しいため、今回は動画のみの再生を試みました。
結果としては、ライブ配信の動画をOpenCVで再生することは出来ましたが、リアルタイムというほどスムーズにはいかず、再生速度が遅かったりラグがあったりしました。
今後、スムーズに再生するために改良の余地はあるので、リトライしようと思います。

vdo_AdobeExpress.gif

ストリーミング技術 DASHについて

YouTubeのストリーミング技術はDASH(Dynamic Adaptive Streaming Over Http)とHLSを使っています。
ちなみに、HLSはApple製品でサポートされている形式です。
動画ファイルを数秒の短いセグメントに分割して配信することによって、高画質でリアルタイムに再生することができます。

実装

YouTubeのライブ配信を再生して、ネットワークの通信状況を確認してみると、セグメントに分割された数秒ほどの動画と音声が連続して取得されていることが分かります。
このURLリンクからwebm形式の動画やmp3形式の音声を読み込むことができます。
image.png

配信リンクからvideoplaybackを取得する必要があるので、youtube.com/watch?v=videoidからJavaScriptを用いて取得する。

var format_url = ytInitialPlayerResponse['streamingData']['adaptiveFormats'][0]['url']

取得したurlのパラメータに取得したいセグメントを指定するためにsq(sequence)パラメータを追加します。
これにより、sequenceパラメータをずらしていけばmp4のセグメントを順番に取得できるようになります。

ソースコード

threadingを用いて再生とダウンロードを並列処理できるようにした。

import re, os, requests, urllib, dukpy, tempfile, cv2, threading

_sequence = ""

def update_url(streamurl, sq):
    streamurl_parse = urllib.parse.urlparse(streamurl)
    params = urllib.parse.parse_qs(streamurl_parse.query)
    params['sq'] = sq
    streamurl = urllib.parse.urlunparse(streamurl_parse._replace(query=urllib.parse.urlencode(params, doseq=True)))
    return streamurl

def cv2destroy(cap):
    cap.release()
    cv2.destroyAllWindows()
    os._exit

def request_video():
    global req, sequence
    while True:
        print("load sequence:", str(sequence))
        req = requests.get(update_url(streamurl, str(sequence)))
        sequence += 1

def play_video():
    global req, _sequence
    while True:
        if _sequence != sequence:
            with tempfile.NamedTemporaryFile(dir='./') as fp:
                fp.write(req.content)
                fp.file.seek(0)
                cap = cv2.VideoCapture(fp.name)

                while(cap.isOpened()):
                    ret, frame = cap.read()
                    if ret == True:
                        frame = cv2.resize(frame, (1280,720))
                        cv2.imshow("YouTube", frame)
                        if cv2.waitKey(25) & 0xFF == ord('q'):
                            cv2destroy(cap)
                    else:
                        break
            _sequence = sequence

youtube_live_url = input("YouTube Live link here:")

f = urllib.request.urlopen(youtube_live_url)
html = f.read().decode('utf-8')
m = re.findall(r'<script nonce="(.*?)">(.*?)</script>', html, re.DOTALL)
script = m[10][1]
js_obj = dukpy.evaljs([script, 'ytInitialPlayerResponse'])
streamurl = js_obj['streamingData']['adaptiveFormats'][0]['url']

req = requests.get(streamurl)
sequence = int(req.headers['X-Sequence-Num'])

th1 = threading.Thread(target=request_video)
th2 = threading.Thread(target=play_video)
th1.start()
th2.start()

課題

  • OpenCVでの再生速度が遅いのでネックになっている部分を調査する
  • ダウンロード速度が遅いのでスレッド化を改善する必要がある

ありがとうございました。

参考

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2