8.0 KiB
8.0 KiB
In [ ]:
import cv2
import m3u8
import requests
import numpy as np
from urllib.parse import urljoin
from threading import Thread
from queue import Queue
class HLSPlayer:
def __init__(self, m3u8_url):
self.m3u8_url = m3u8_url
self.playlist = None
self.current_segment = 0
self.frame_queue = Queue(maxsize=30)
self.running = False
self.load_playlist()
def load_playlist(self):
response = requests.get(self.m3u8_url,verify=False)
if response.status_code != 200:
raise Exception(f"无法下载m3u8文件: {response.status_code}")
self.playlist = m3u8.loads(response.text)
# 如果是多码率播放列表,选择最高码率
if self.playlist.is_variant:
best_stream = max(self.playlist.playlists, key=lambda p: p.stream_info.bandwidth)
self.m3u8_url = urljoin(self.m3u8_url, best_stream.uri)
self.load_playlist()
def fetch_segment(self, segment_url):
response = requests.get(segment_url,verify=False)
if response.status_code == 200:
# 将TS数据转换为OpenCV可读格式
video_data = np.frombuffer(response.content, dtype=np.uint8)
return video_data
return None
def decode_frames(self, video_data):
# 使用OpenCV解码视频帧
cap = cv2.VideoCapture()
cap.open(video_data)
frames = []
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
frames.append(frame)
cap.release()
return frames
def player_thread(self):
self.running = True
while self.running:
# 获取当前片段URL
if self.current_segment >= len(self.playlist.segments):
# 如果是直播流,重新加载播放列表
self.load_playlist()
self.current_segment = 0
segment = self.playlist.segments[self.current_segment]
segment_url = urljoin(self.m3u8_url, segment.uri)
# 下载并解码片段
video_data = self.fetch_segment(segment_url)
if video_data is not None:
frames = self.decode_frames(video_data)
# 将帧放入队列
for frame in frames:
self.frame_queue.put(frame)
self.current_segment += 1
def start(self):
# 启动播放器线程
Thread(target=self.player_thread, daemon=True).start()
# 显示视频
while True:
if not self.frame_queue.empty():
frame = self.frame_queue.get()
cv2.imshow('HLS Player', frame)
# 按q退出
if cv2.waitKey(1) & 0xFF == ord('q'):
self.running = False
break
cv2.destroyAllWindows()
if __name__ == "__main__":
m3u8_url = "http://113.45.217.230:18800/rtp/34020000001320000155_34020000001320000155/hls.m3u8"
player = HLSPlayer(m3u8_url)
player.start()Exception in thread Thread-8 (player_thread):
Traceback (most recent call last):
File "d:\Anaconda3\Lib\threading.py", line 1073, in _bootstrap_inner
self.run()
File "d:\Anaconda3\Lib\threading.py", line 1010, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\Administrator\AppData\Local\Temp\ipykernel_16072\2038425495.py", line 69, in player_thread
File "C:\Users\Administrator\AppData\Local\Temp\ipykernel_16072\2038425495.py", line 42, in decode_frames
cv2.error: OpenCV(4.11.0) :-1: error: (-5:Bad argument) in function 'open'
> Overload resolution failed:
> - Expected 'filename' to be a str or path-like object
> - VideoCapture.open() missing required argument 'apiPreference' (pos 2)
> - Argument 'index' is required to be an integer
> - VideoCapture.open() missing required argument 'apiPreference' (pos 2)
> - VideoCapture.open() missing required argument 'apiPreference' (pos 2)
[1;31m---------------------------------------------------------------------------[0m [1;31mKeyboardInterrupt[0m Traceback (most recent call last) Cell [1;32mIn[3], line 97[0m [0;32m 95[0m m3u8_url [38;5;241m=[39m [38;5;124m"[39m[38;5;124mhttp://113.45.217.230:18800/rtp/34020000001320000155_34020000001320000155/hls.m3u8[39m[38;5;124m"[39m [0;32m 96[0m player [38;5;241m=[39m HLSPlayer(m3u8_url) [1;32m---> 97[0m player[38;5;241m.[39mstart() Cell [1;32mIn[3], line 88[0m, in [0;36mHLSPlayer.start[1;34m(self)[0m [0;32m 85[0m cv2[38;5;241m.[39mimshow([38;5;124m'[39m[38;5;124mHLS Player[39m[38;5;124m'[39m, frame) [0;32m 87[0m [38;5;66;03m# 按q退出[39;00m [1;32m---> 88[0m [38;5;28;01mif[39;00m cv2[38;5;241m.[39mwaitKey([38;5;241m1[39m) [38;5;241m&[39m [38;5;241m0xFF[39m [38;5;241m==[39m [38;5;28mord[39m([38;5;124m'[39m[38;5;124mq[39m[38;5;124m'[39m): [0;32m 89[0m [38;5;28mself[39m[38;5;241m.[39mrunning [38;5;241m=[39m [38;5;28;01mFalse[39;00m [0;32m 90[0m [38;5;28;01mbreak[39;00m [1;31mKeyboardInterrupt[0m:
[1;31m在当前单元格或上一个单元格中执行代码时 Kernel 崩溃。 [1;31m请查看单元格中的代码,以确定故障的可能原因。 [1;31m单击<a href='https://aka.ms/vscodeJupyterKernelCrash'>此处</a>了解详细信息。 [1;31m有关更多详细信息,请查看 Jupyter <a href='command:jupyter.viewOutput'>log</a>。