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