当前位置: 首页 > article >正文

qt+vlc实现解码h264/h265裸码流播放

一 概述本文章实现了对h264/h265裸码流的解码播放功能,主要是一个基于VLC实现的H.264/H.265裸流解码播放类。主要功能包括1)通过OpenStream接口打开流并指定显示窗口2)使用InputStream接口输入裸流数据3)通过CloseStream关闭流。核心实现采用VLC的回调机制(vlc_open_cb/vlc_read_cb/vlc_close_cb)处理流数据支持自动检测H.264/H.265编码格式。类中还包含了数据缓冲管理、线程安全控制以及调试日志功能通过配置选项优化了网络缓存和编解码器选择策略确保稳定播放不同编码格式的视频流。二 实现接口1. bool OpenStream(WId winId); // 打开流传入窗口句柄2. void CloseStream(); // 关闭流3. void InputStream(const char* data, int len, string streamType); // 输入裸流数据三 vlc解码播放类1.vlcstreamdecoder.h#ifndef VLCSTREAMDECODER_H #define VLCSTREAMDECODER_H #include QObject #include vlc/vlc.h #include QByteArray #include QMutex #include mutex #include QMutexLocker #include QtWidgets/QWidget #include basic.h class VLCStreamDecoder : public QObject { Q_OBJECT public: explicit VLCStreamDecoder(QObject *parent nullptr); ~VLCStreamDecoder(); bool OpenStream(WId winId); // 打开流传入窗口句柄 void CloseStream(); // 关闭流 void InputStream(const char* data, int len, string streamType); // 输入裸流数据 void InputStreamEx(const char* data,int len); void configureForBothCodecs(); private: bool h26xWriteOpen(const char* filename); void h26xWriteFrame(unsigned char* data, int len); void h26xWriteClose(); private: // VLC 回调修复后签名 static int vlc_open_cb(void* opaque, void** datap, uint64_t* sizep); static void vlc_close_cb(void* opaque); static ssize_t vlc_read_cb(void* opaque, unsigned char* buf, size_t len); libvlc_instance_t* m_vlcInst; libvlc_media_t* m_vlcMedia; libvlc_media_player_t* m_vlcPlayer; std::vectoruint8_t m_buffer; std::mutex m_mutex; QMutex m_packetMutex; std::listQByteArray m_packetList; FILE* m_h26x_file nullptr; bool m_isPlaying false; }; #endif // VLCSTREAMDECODER_H2.vlcstreamdecoder.cpp#include vlcstreamdecoder.h #include QDebug #include iostream using namespace std; VLCStreamDecoder::VLCStreamDecoder(QObject *parent) : QObject(parent) , m_vlcInst(nullptr) , m_vlcMedia(nullptr) , m_vlcPlayer(nullptr) { const char* vlc_args[] { -I, dummy, --no-audio, // 关闭音频如果你不需要播放声音保留需要声音就删掉 --no-video-title-show, // 不显示标题 --quiet, --live-caching0, --network-caching0, --verbose1, //日志级别 --file-logging, --logfilevlc_log.txt //日志文件 }; m_vlcInst libvlc_new(sizeof(vlc_args)/sizeof(vlc_args[0]), vlc_args); #ifdef WRITE_FILE h26xWriteOpen(camera.26x); #endif } VLCStreamDecoder::~VLCStreamDecoder() { CloseStream(); if (m_vlcInst) { libvlc_release(m_vlcInst); m_vlcInst nullptr; } } bool VLCStreamDecoder::OpenStream(WId winId) { if (!m_vlcInst){ qDebug() m_vlcInst is null; return false; } // 修复使用正确的回调函数 m_vlcMedia libvlc_media_new_callbacks( m_vlcInst, vlc_open_cb, vlc_read_cb, nullptr, vlc_close_cb, this ); if (!m_vlcMedia){ qDebug() m_vlcMedia is null; return false; } // 尝试使用通用解复用器 #if 0 libvlc_media_add_option(m_vlcMedia, :demuxh264); libvlc_media_add_option(m_vlcMedia, :codech264); libvlc_media_add_option(m_vlcMedia, :demuxhevc); libvlc_media_add_option(m_vlcMedia, :codechevc); #endif // configureForBothCodecs(); // 设置媒体到播放器 m_vlcPlayer libvlc_media_player_new_from_media(m_vlcMedia); if (!m_vlcPlayer) { qDebug() m_vlcPlayer is null; return false; } // 绑定窗口句柄 #ifdef WIN32 libvlc_media_player_set_hwnd(m_vlcPlayer, (void*)winId); #else libvlc_media_player_set_xwindow(m_vlcPlayer, (uint32_t)winId); #endif qDebug() VLC 打开流成功窗口句柄 winId; return true; } void VLCStreamDecoder::CloseStream() { if (m_vlcPlayer) { libvlc_media_player_stop(m_vlcPlayer); libvlc_media_player_release(m_vlcPlayer); m_vlcPlayer nullptr; } if (m_vlcMedia) { libvlc_media_release(m_vlcMedia); m_vlcMedia nullptr; } #ifdef WRITE_FILE h26xWriteClose(); #endif qDebug() VLC 流已关闭; } // 喂流接口 void VLCStreamDecoder::InputStream(const char *data, int len,string streamType) { // // 1. 超强防御判断 // if (!data || len 0) return; if (!m_vlcPlayer) return; #if 1 if(!m_isPlaying){ if(streamType h264){ libvlc_media_add_option(m_vlcMedia, :demuxh264); libvlc_media_add_option(m_vlcMedia, :codech264); }else if(streamType h265){ libvlc_media_add_option(m_vlcMedia, :demuxhevc); libvlc_media_add_option(m_vlcMedia, :codechevc); } qDebug() 设置当前播放器支持解码类型为: streamType.data(); libvlc_media_player_set_media(m_vlcPlayer,m_vlcMedia); libvlc_media_player_play(m_vlcPlayer); m_isPlaying true; } #endif #ifdef WRITE_FILE h26xWriteFrame((unsigned char*)data,len); #endif std::lock_guardstd::mutex lock(m_mutex); const uint8_t *p (const uint8_t*)data; m_buffer.insert(m_buffer.end(), p, p len); } void VLCStreamDecoder::InputStreamEx(const char *data, int len) { if(!data || len0) return; if (len 30) { QByteArray ba((const char*)data, 30); qDebug() 数据十六进制 ba.toHex( ); } QByteArray ba(data,len); { QMutexLocker lck(m_packetMutex); if(m_packetList.size()40) return; m_packetList.push_back(ba); } } void VLCStreamDecoder::configureForBothCodecs() { if (!m_vlcMedia) return; // 不指定特定的解复用器让VLC自动检测 // 这样VLC可以根据数据内容自动选择h264或h265解复用器 // libvlc_media_add_option(m_vlcMedia, :demuxh264); // 不要强制指定 // 使用通用的原始视频解复用器作为备选 libvlc_media_add_option(m_vlcMedia, :demuxh26x); // 网络缓存设置对于流数据很重要 libvlc_media_add_option(m_vlcMedia, :network-caching300); // 时钟同步设置 libvlc_media_add_option(m_vlcMedia, :clock-jitter0); libvlc_media_add_option(m_vlcMedia, :clock-synchro0); // 不强制指定解码器让VLC自动选择可用的解码器 // 这样VLC可以根据媒体内容自动选择h264或h265解码器 // libvlc_media_add_option(m_vlcMedia, :codech264); // 不要强制指定 // 增加缓冲区大小 libvlc_media_add_option(m_vlcMedia, :input-buffer-size16384); // 禁用硬件加速以避免兼容性问题 libvlc_media_add_option(m_vlcMedia, :avcodec-hwnone); // 添加错误处理选项 libvlc_media_add_option(m_vlcMedia, :ignore-config); libvlc_media_add_option(m_vlcMedia, :no-audio); // 专注于视频解码 // 添加编解码器自动检测选项 libvlc_media_add_option(m_vlcMedia, :codecany); // 允许任何可用的解码器 // 启用格式自动检测 libvlc_media_add_option(m_vlcMedia, :autodetect-fmts); qDebug() Configured for both H.264 and H.265 codecs; } bool VLCStreamDecoder::h26xWriteOpen(const char *filename) { if (m_h26x_file ! NULL) { fclose(m_h26x_file); } m_h26x_file fopen(filename, wb); // 二进制写入 if (m_h26x_file NULL) { perror(fopen failed); return false; } qDebug([H26x] 已打开文件: %s\n, filename); return true; } void VLCStreamDecoder::h26xWriteFrame(unsigned char *data, int len) { if (m_h26x_file NULL || data NULL || len 0) { return; } // 直接写入一帧 fwrite(data, 1, len, m_h26x_file); // 立即刷新到磁盘防止掉电丢失 fflush(m_h26x_file); // printf([H26x] 写入一帧: %d 字节\n, len); } void VLCStreamDecoder::h26xWriteClose() { if (m_h26x_file ! NULL) { fclose(m_h26x_file); m_h26x_file NULL; qDebug([H26x] 文件已关闭\n); } } // // VLC 回调实现修复版 // int VLCStreamDecoder::vlc_open_cb(void *opaque, void **datap, uint64_t *sizep) { *datap opaque; *sizep 0; // 未知大小 return 0; } void VLCStreamDecoder::vlc_close_cb(void *opaque) { } ssize_t VLCStreamDecoder::vlc_read_cb(void *opaque, unsigned char *buf, size_t len) { VLCStreamDecoder* self (VLCStreamDecoder*)opaque; std::lock_guardstd::mutex lock(self-m_mutex); if (self-m_buffer.empty()){ buf[0] 0; return 1; } unsigned int copyLen std::min(len, (unsigned long)self-m_buffer.size()); memcpy(buf, self-m_buffer.data(), copyLen); #if 0 qDebug(vlc_read_cb: asked for %zu bytes, have %zu, return %zu\n, len, self-m_buffer.size(), copyLen); #endif self-m_buffer.erase(self-m_buffer.begin(), self-m_buffer.begin() copyLen); return copyLen; }

相关文章:

qt+vlc实现解码h264/h265裸码流播放

一 概述本文章实现了对h264/h265裸码流的解码播放功能,主要是一个基于VLC实现的H.264/H.265裸流解码播放类。主要功能包括:1)通过OpenStream接口打开流并指定显示窗口;2)使用InputStream接口输入裸流数据;3)通过CloseStream关闭流。核心实现采…...

git restore --source 提交id 和 git reset --hard 提交id 有什么区别

这两个命令长得像、都能“回到过去”,但核心逻辑、操作范围、安全性天差地别,一句话先点破: ✅ git restore --source 提交id:文件级操作,只恢复文件内容,不删提交历史、不改动分支,安全无风险 …...

macOS一键部署OpenClaw:Phi-3-vision-128k-instruct多模态体验教程

macOS一键部署OpenClaw:Phi-3-vision-128k-instruct多模态体验教程 1. 为什么选择OpenClawPhi-3组合 上周我在整理团队项目文档时,突然意识到一个痛点:每次收到同事发来的截图和文字混合内容,都需要手动复制粘贴到笔记软件里分类…...

嵌入式c语言——关键字4

typedef 给数据类型起个别名,使得对程序的可读性更高吗,同时和#define不一样typedeff是关键字,对已经存在的数据类型取别名。 在编译阶段处理,会进行类型检查,只能在定义的作用域内使用。 define是预处理指令&#xff…...

xpath爬取网页图片

# 1. 导入需要的工具包 import requests # 用来发送网络请求,爬取网页 from lxml import etree # 用来解析网页,提取图片 import os # 用来创建文件夹,保存图片 import time # 用来延时,防止爬太快被封# 2. 设置图片保存的位置…...

LeetCode 删除无效的括号:python 题解匆

这个代码的核心功能是:基于输入词的长度动态选择反义词示例,并调用大模型生成反义词,体现了 “动态少样本提示(Dynamic Few-Shot Prompting)” 与 “上下文长度感知的示例选择” 的能力。 from langchain.prompts impo…...

一文学习 工作流开发 BPMN、 Flowable参

一、什么是requests? requests 是一个用于发送HTTP请求的 Python 库。 它可以帮助你: 轻松发送GET、POST、PUT、DELETE等请求 处理Cookie、会话等复杂性 自动解压缩内容 处理国际化域名和URL 二、应用场景 requests 广泛应用于以下实际场景: …...

Windows安卓应用运行新方案:轻量级安卓环境搭建与实践指南

Windows安卓应用运行新方案:轻量级安卓环境搭建与实践指南 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 在数字化办公与多设备协同的时代,用户…...

WarcraftHelper终极指南:如何让经典魔兽争霸III在现代电脑上完美运行

WarcraftHelper终极指南:如何让经典魔兽争霸III在现代电脑上完美运行 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸III在…...

3小时搞定OpenClaw飞书机器人:Phi-3-mini-128k-instruct对话集成

3小时搞定OpenClaw飞书机器人:Phi-3-mini-128k-instruct对话集成 1. 为什么选择OpenClaw飞书Phi-3-mini组合 上周三下午4点,我正在为团队周会纪要焦头烂额时,突然想到:能不能让AI自动把飞书会议录音转成结构化纪要?经…...

Zookeeper分布式协调

一、总览图1、定义 ZooKeeper 集群协调器 它是一个分布式协调服务,专门为分布式应用提供一致性、可靠性的协调功能,解决分布式环境下的数据同步、配置管理、状态监控等问题。 2、部署3、数据模型 Znode树结构:采用层级化的命名空间&#xff…...

【C++可变模板参数】

C11 可变模板参数总结:搞懂参数包、包扩展和 emplace1. 为什么 C11 需要可变模板参数? 在 C11 之前,如果我们想写一个“参数个数可变、参数类型也可变”的函数,基本只能靠: 写很多重载或者用 ...(C 风格可变…...

广州邮科选型指南:挑选可调电源必须关注的四个核心参数

在电子工程师的工作台上,有一种设备兼具了灵活性与智能保护——它就是可调稳压恒流开关电源。这种电源不仅是供电工具,更像是懂得自我保护的"智能能源管家"。它如何同时实现稳压与恒流?传统电源往往只能固定输出,而这类…...

我用 LocalClaw 记忆系统管理项目知识:上下文永不丢失,问一句就能找到任何历史决策

LocalClaw官网:https://www.localclaw.me 前言:项目知识去哪了 我们团队有个老项目,30万行代码,5年历史。 上周我改一个功能,问同事:“当初为什么这样设计?” 他说:“不知道&…...

常见的服务器

常见的服务器 目录 [ 一、塔式服务器(Tower Server)](#%E4%B8%80%E3%80%81%E5%A1%94%E5%BC%8F%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%88Tower%20Server%EF%BC%89) [ 二、机架式服务器(Rack Server)](#%E4%BA%8C%E3%80%81%E6%9C%BA%E6…...

codex解决中文乱码

根源似乎不在codex的编码上,我设置了全局指令还是错误,现在观察到根源应该在控制台,参考文章: codex解决中文乱码问题-CSDN博客 Codex 中文乱码问题全链路解决方案(Windows 11)_codex 乱码-CSDN博客 原因…...

Java全核心-阿里大厂面试-Gemini版

完善更新中......一、Java 核心基础1、Java 四大引用与 ThreadLocal 深度拷问【核心连环炮】面试官:说一下 Java 的四大引用及其实际业务场景?面试官:ThreadLocal 为什么要用弱引用?不用行不行?面试官:既然…...

OpenClaw技能市场挖掘:百川2-13B-4bits量化版适配插件精选

OpenClaw技能市场挖掘:百川2-13B-4bits量化版适配插件精选 1. 为什么需要专门适配百川模型的技能? 去年冬天第一次尝试用OpenClaw对接百川2-13B模型时,我遇到了一个典型问题:虽然模型本身运行良好,但很多现成的技能模…...

AI基础设施权力更迭:AWS Bedrock 凭什么在 2026 年让开发者集体“倒戈”?

声明:本文由AI编辑生成,内容仅供参考。文中涉及的行业判断、平台能力分析、商业趋势推演与产品价值描述,均基于公开资料、通用观察及示意性表达整理,不构成任何商业承诺、采购建议、投资建议或服务保证。实际产品能力、接口支持范…...

golang如何理解值类型和引用类型_golang值类型与引用类型区别详解

<p>Go所有传参均为值传递&#xff0c;但“值”取决于类型底层&#xff1a;基础类型传数据副本&#xff0c;slice/map/chan传含指针的header副本&#xff0c;修改元素会影响原变量&#xff1b;需改变量本身&#xff08;如重置slice header&#xff09;时才必须传* T。<…...

Spring Boot 4.0 Agent-Ready架构的7个隐秘陷阱:90%团队在第4步就触发JVM元空间泄漏

第一章&#xff1a;Spring Boot 4.0 Agent-Ready架构的演进本质与企业级定位Spring Boot 4.0 并非简单版本迭代&#xff0c;而是面向可观测性、运行时可塑性与平台协同能力重构的范式跃迁。其核心突破在于将 Java Agent 集成从“可选插件”升维为“原生架构契约”&#xff0c;使…...

2026 安全生产精选:五款巡检软件实用清单,隐患排查与闭环管理轻松上手

安全生产是企业发展的核心防线&#xff0c;而巡检巡查则是守护这道防线的关键动作。无论是餐饮门店的消防安全检查、工厂车间的设备点检&#xff0c;还是建筑工地的隐患排查&#xff0c;传统的纸质记录和人工巡查方式正逐渐暴露出效率低、易造假、难追溯的问题。今天为大家整理…...

Python如何实现定时异步任务_结合asyncio与loop.call_later调用

asyncio.call_later不能直接await&#xff0c;因为它返回Handle对象而非Awaitable&#xff1b;正确做法是在回调中用asyncio.create_task启动协程。asyncio.call_later 为什么不能直接 await&#xff1f;因为 loop.call_later 是一个同步注册函数&#xff0c;它不返回协程对象&…...

嘉立创-AD PCB封装导入(含3D封装)

大多数元器件都可以在立创商城找到2D和3D封装&#xff0c;点击立即打开 COPY 2D封装 1.切换到PCB 2.导出PCB文件 3.用AD打开下载的PCB文件&#xff0c;复制时选择中心吸附点 4.在自己的库中添加&#xff0c;并重命名 5.对齐原点粘贴并保存 6.至此2D封装COPY完成 COPY 3D模型 …...

RAG系统的多路召回(Multi-Retrieval)详解

在RAG&#xff08;检索增强生成&#xff09;系统中&#xff0c;多路召回是一种通过多种检索策略并行获取候选文档&#xff0c;再进行结果融合的机制。它的核心目的是提高召回率&#xff0c;确保不同类型的查询都能被有效检索。一、为什么需要多路召回&#xff1f;单一检索方式存…...

【PHP 8.9命名空间终极指南】:5大突破性增强、3个迁移避坑清单与向后兼容性权威验证

第一章&#xff1a;PHP 8.9命名空间增强的演进背景与核心定位PHP 命名空间自 5.3 版本引入以来&#xff0c;已成为组织大型代码库的事实标准。然而&#xff0c;随着现代 PHP 应用向模块化、跨域共享和静态分析深度依赖方向演进&#xff0c;原有命名空间机制在别名解析、嵌套声明…...

固态新概念—准固态,或许车用准固态,手机用全固态,无奈的妥协

固态电池说了很多年了&#xff0c;但是到了如今离量产装车越来越近的时刻&#xff0c;电池行业和汽车行业终于清醒认识到全固态电池在汽车行业面临着无法跨越的技术难题&#xff0c;由此近期行业提出了一个新概念&#xff0c;那就是准固态电池。此前汽车行业曾提出了半固态电池…...

嵌入式系统中状态机的实现与优化技巧

1. 状态机在嵌入式系统中的核心价值在资源受限的嵌入式环境中&#xff0c;状态机&#xff08;State Machine&#xff09;是处理复杂逻辑的利器。我曾在智能家居控制器项目中&#xff0c;用状态机管理设备工作模式切换&#xff0c;代码量减少了40%而可靠性提升显著。状态机本质上…...

程序员副业图谱

引言&#xff1a;程序员副业的现状与趋势程序员副业需求增长的背景&#xff08;技术变现、职业发展多元化&#xff09;CSDN作为技术社区在副业生态中的角色CSDN程序员副业图谱的核心模块技术内容创作博客/专栏写作&#xff1a;技术干货、实战经验、行业分析视频教程&#xff1a…...

DDD难落地?就让AI干吧! - cleanddd-skills介绍嘶

AI训练存储选型的演进路线 第一阶段&#xff1a;单机直连时代 早期的深度学习数据集较小&#xff0c;模型训练通常在单台服务器或单张GPU卡上完成。此时直接将数据存储在训练机器的本地NVMe SSD/HDD上。 其优势在于IO延迟最低&#xff0c;吞吐量极高&#xff0c;也就是“数据离…...