Files
python----/视频流.ipynb
2025-10-20 12:32:18 +08:00

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)

---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
Cell In[3], line 97
     95 m3u8_url = "http://113.45.217.230:18800/rtp/34020000001320000155_34020000001320000155/hls.m3u8"
     96 player = HLSPlayer(m3u8_url)
---> 97 player.start()

Cell In[3], line 88, in HLSPlayer.start(self)
     85     cv2.imshow('HLS Player', frame)
     87 # 按q退出
---> 88 if cv2.waitKey(1) & 0xFF == ord('q'):
     89     self.running = False
     90     break

KeyboardInterrupt: 
在当前单元格或上一个单元格中执行代码时 Kernel 崩溃。

请查看单元格中的代码,以确定故障的可能原因。

单击<a href='https://aka.ms/vscodeJupyterKernelCrash'>此处</a>了解详细信息。

有关更多详细信息,请查看 Jupyter <a href='command:jupyter.viewOutput'>log</a>。