You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python无本地存储播放m3u8音频流及PyQt QMediaPlayer对接咨询

PyQt 无本地缓存播放m3u8广播流实现方案

核心逻辑是通过子进程调用ffmpeg拉流转码后直接输出到标准输出,Python读取流后通过内存缓冲区传给QMediaPlayer播放,全程不会写入本地文件。

前置依赖

  • 系统已安装ffmpeg且配置到环境变量
  • 已安装PyQt多媒体相关组件,PyQt6安装命令:
    pip install PyQt6 PyQt6-Multimedia
    如果使用PyQt5,替换包名为PyQt5和PyQt5-Multimedia即可。

核心ffmpeg命令调整

需要将原本输出到本地文件的ffmpeg命令调整为输出到标准输出,同时屏蔽多余日志避免污染音频数据流,调整后命令如下:

ffmpeg -i "http://example.com/live/playlist.m3u8" -c:a aac -f adts -hide_banner -loglevel error -

参数说明:

  • -f adts 指定输出为ADTS封装的AAC流,无需本地文件即可被播放器直接识别
  • -hide_banner -loglevel error 仅输出错误级别的日志,避免ffmpeg的启动信息、进度信息写入stdout破坏音频数据
  • 末尾的- 代表将流输出到stdout而非本地文件

完整实现代码

import sys
import subprocess
from PyQt6.QtCore import QBuffer, QIODevice, QThread, pyqtSignal
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout

class StreamReader(QThread):
    # 读取到音频数据的信号
    data_received = pyqtSignal(bytes)
    def __init__(self, m3u8_url):
        super().__init__()
        self.m3u8_url = m3u8_url
        self.ffmpeg_process = None
        self.running = False

    def run(self):
        self.running = True
        # 启动ffmpeg子进程
        cmd = [
            "ffmpeg",
            "-i", self.m3u8_url,
            "-c:a", "aac",
            "-f", "adts",
            "-hide_banner",
            "-loglevel", "error",
            "-"
        ]
        self.ffmpeg_process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.DEVNULL,
            bufsize=1024*1024
        )
        # 循环读取ffmpeg输出的流
        while self.running:
            data = self.ffmpeg_process.stdout.read(4096)
            if not data:
                break
            self.data_received.emit(data)

    def stop(self):
        self.running = False
        if self.ffmpeg_process:
            self.ffmpeg_process.terminate()
            self.ffmpeg_process.wait()
        self.wait()

class RadioPlayer(QWidget):
    def __init__(self, m3u8_url):
        super().__init__()
        self.m3u8_url = m3u8_url
        self.init_ui()
        self.init_player()
        self.stream_reader = None
        self.buffer = QBuffer()
        self.buffer.open(QIODevice.OpenModeFlag.ReadWrite)

    def init_ui(self):
        self.setWindowTitle("网络广播播放器")
        self.resize(300, 150)
        layout = QVBoxLayout()
        self.play_btn = QPushButton("播放")
        self.play_btn.clicked.connect(self.toggle_play)
        layout.addWidget(self.play_btn)
        self.setLayout(layout)

    def init_player(self):
        self.audio_output = QAudioOutput()
        self.player = QMediaPlayer()
        self.player.setAudioOutput(self.audio_output)

    def toggle_play(self):
        if self.play_btn.text() == "播放":
            self.play_btn.setText("停止")
            # 启动流读取线程
            self.stream_reader = StreamReader(self.m3u8_url)
            self.stream_reader.data_received.connect(self.write_to_buffer)
            self.stream_reader.start()
            # 给player设置缓冲区为播放源
            self.player.setSourceDevice(self.buffer)
            self.player.play()
        else:
            self.play_btn.setText("播放")
            self.player.stop()
            if self.stream_reader:
                self.stream_reader.stop()
                self.stream_reader = None
            self.buffer.reset()

    def write_to_buffer(self, data):
        # 将读取到的音频数据写入缓冲区
        pos = self.buffer.pos()
        self.buffer.seek(self.buffer.size())
        self.buffer.write(data)
        self.buffer.seek(pos)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    # 替换为你自己的m3u8链接
    M3U8_URL = "http://example.com/live/playlist.m3u8"
    window = RadioPlayer(M3U8_URL)
    window.show()
    sys.exit(app.exec())

注意事项

  • 运行前请将代码中的M3U8_URL替换为实际的广播m3u8地址
  • 退出程序时会自动终止ffmpeg子进程,不会产生残留进程
  • 如果需要调整音频质量,可以修改ffmpeg命令中的-b:a参数指定比特率,比如添加-b:a 128k即可固定输出128kbps的音频流

内容的提问来源于stack exchange,提问作者AlexMercer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 08:09:04