Qt + FFmpeg 音频工具:媒体流详情实现
前言音视频文件在容器层面由一个或多个流stream组成每个流拥有独立的编码格式、参数配置和元数据。了解这些流的详细信息对于后续处理决策至关重要——比如判断音频是否需要重采样、视频帧率是否匹配、色彩空间是否正确等。AudioTools 的媒体流详情功能通过 FFmpeg 的媒体探测能力完整解析容器中每个流的编码参数、时长、disposition 标记和元数据以卡片形式清晰展示。功能流程用户导入文件 → 主页卡片点击 → parseMediaInfo() ↓ MediaInfoParser::parse() ↓ avformat_open_input avformat_find_stream_info ↓ 遍历 formatContext-nb_streams ├── 通用字段codec、profile、level、time_base、duration、disposition ├── 音频流字段sample_rate、channels、sample_format、bits_per_sample、frame_count └── 视频流字段width、height、pixel_format、frame_rate、nb_frames、color_space ↓ setMediaInfo(info) → mediaInfo 属性更新 ↓ StreamDetailPage 读取 mediaInfo.streams 数组 ↓ 逐流渲染详情卡片 元数据列表关键特点按需解析只在用户点击基础属性/元数据功能入口时调用parseMediaInfo()避免导入文件时产生不必要的耗时操作。一次性解析基础属性、元数据、流详情共用同一次MediaInfoParser::parse()调用结果。PCM 保留如果当前已解码过 PCM重新解析媒体信息时会保留mediaInfo[pcm]子字段避免解码页状态丢失。核心算法容器级信息MediaInfoParser::parse()通过avformat_open_input打开容器avformat_find_stream_info探测流信息后首先提取容器级字段result.insert(fileName,fileInfo.fileName());result.insert(fileSizeText,formatBytes(fileInfo.size()));result.insert(durationMs,durationMs);// AV_TIME_BASE → msresult.insert(durationText,formatDuration(durationMs));result.insert(formatName,formatContext-iformat-name);// mov,mp4,m4a,3gp,3g2,mj2result.insert(formatLongName,formatContext-iformat-long_name);// QuickTime / MOVresult.insert(bitRate,formatContext-bit_rate);result.insert(metadata,dictionaryToMap(formatContext-metadata));通用增强字段每个流在基础的codec和bitRate之外还解析了以下增强字段Profile 和 Level直接从AVCodecParameters读取数值streamInfo.insert(profile,stream-codecpar-profile0?QString::number(stream-codecpar-profile):-);streamInfo.insert(level,stream-codecpar-level!FF_LEVEL_UNKNOWN?QString::number(stream-codecpar-level):-);Time Base流的时间基准反映时间戳精度streamInfo.insert(timeBase,QString(%1/%2).arg(stream-time_base.num).arg(stream-time_base.den));流时长从流级 duration 换算为毫秒基于 time_baseconstqint64 streamDurationMsstream-duration!AV_NOPTS_VALUE?stream-duration*av_q2d(stream-time_base)*1000.0:-1;起始时间某些容器流存在非零起始时间如 TS 文件constqint64 startTimeMsstream-start_time!AV_NOPTS_VALUE?stream-start_time*av_q2d(stream-time_base)*1000.0:0;Codec Tag四字符编码标签hex 格式用于精确识别编码变体streamInfo.insert(codecTag,QString(0x%1).arg(params-codec_tag,4,16,QLatin1Char(0)));Disposition 标记流的特殊属性标志位包括default、dub、lyrics、comment、hearing_impaired、visual_impaired等QStringList dispFlags;if(stream-dispositionAV_DISPOSITION_DEFAULT)dispFlagsdefault;if(stream-dispositionAV_DISPOSITION_DUB)dispFlagsdub;if(stream-dispositionAV_DISPOSITION_LYRICS)dispFlagslyrics;// ... 更多标志位streamInfo.insert(disposition,dispFlags.join(, ));音频流字段音频流在通用字段基础上补充以下参数streamInfo.insert(type,audio);streamInfo.insert(channels,params-ch_layout.nb_channels);streamInfo.insert(channelLayout,channelLayoutName(params-ch_layout));streamInfo.insert(sampleRate,params-sample_rate);streamInfo.insert(sampleFormat,sampleFormatName(params-format));streamInfo.insert(bitsPerSample,bitsPerSample(params));帧数估算基于流时长和采样率推算总采样帧数if(streamDurationMs0params-sample_rate0)streamInfo.insert(frameCount,streamDurationMs*params-sample_rate/1000.0);第一个音频流的关键参数会被提升到容器顶层供主页卡片和 PCM 解码快速读取if(!result.contains(codec))result.insert(codec,streamInfo.value(codec));if(!result.contains(channels))result.insert(channels,streamInfo.value(channels));if(!result.contains(sampleRate))result.insert(sampleRate,streamInfo.value(sampleRate));// ... sampleFormat, bitsPerSample 同理视频流字段视频流补充分辨率、像素格式、帧率和色彩信息streamInfo.insert(type,video);streamInfo.insert(width,params-width);streamInfo.insert(height,params-height);streamInfo.insert(pixelFormat,av_get_pix_fmt_name(params-format));streamInfo.insert(frameRate,av_q2d(stream-avg_frame_rate));// 增强字段if(stream-nb_frames0)streamInfo.insert(nbFrames,stream-nb_frames);streamInfo.insert(colorSpace,QString::number(params-color_space));streamInfo.insert(colorRange,params-color_rangeAVCOL_RANGE_JPEG?JPEG/Full:(params-color_rangeAVCOL_RANGE_MPEG?MPEG/Limited:-));// Profile 名称需要 codec descriptorconstchar*profileNameavcodec_profile_name(params-codec_id,stream-codecpar-profile);streamInfo.insert(profileName,profileName?profileName:-);数据结构parse()返回的QVariantMap结构mediaInfo ├── fileName, fileSizeText, durationText ├── formatName, formatLongName, bitRate ├── metadata: { title, artist, album, ... } ├── streamCount, audioStreamCount, videoStreamCount ├── codec, channels, sampleRate, ... (第一个音频流的提升字段) ├── streams: [ stream0, stream1, ... ] │ ├── 通用: index, codec, codecLongName, bitRate, profile, level, │ │ timeBase, durationText, startTimeMs, codecTag, disposition, metadata │ ├── 音频: typeaudio, channels, channelLayout, sampleRate, sampleFormat, │ │ bitsPerSample, frameCount │ └── 视频: typevideo, width, height, pixelFormat, frameRate, nbFrames, │ colorSpace, colorRange, profileName ├── audioStreams: [ audioStream0, ... ] └── videoStreams: [ videoStream0, ... ]主处理函数MediaInfoParser::parse位于src/media/mediainfoparser.cpp无状态类只负责读取文件描述信息boolMediaInfoParser::parse(constQStringfilePath,QVariantMap*info,QString*errorText)const处理步骤文件校验QFileInfo检查文件存在性和类型。打开容器avformat_open_input创建AVFormatContext。探测流信息avformat_find_stream_info填充流参数。提取文件级信息文件名、大小、创建/修改时间、时长、格式。遍历流列表按类型提取音频/视频/其它流的参数和增强字段。组装输出streams、audioStreams、videoStreams三个列表 顶层常用字段。关闭容器avformat_close_input释放资源。注意该类不解码音频数据只读取描述信息因此执行速度很快。导出封装MediaAnalyzer::parseMediaInfoQML 调用入口调用MediaInfoParser::parse并更新mediaInfo属性boolMediaAnalyzer::parseMediaInfo(constQUrlfileUrl){constQString filePathtoLocalFile(fileUrl);setBusy(true);setCurrentFile(filePath);constboolokm_infoParser.parse(filePath,info,errorText);if(ok){// 保留已有的 PCM 子字段避免解码页状态丢失constQVariantMap pcmInfom_mediaInfo.value(pcm).toMap();if(!pcmInfo.isEmpty())info.insert(pcm,pcmInfo);setMediaInfo(info);setStatus(媒体属性解析完成);}setBusy(false);returnok;}默认字段保护文件可能没有音频流如纯视频文件顶层常用字段补默认值避免 QML 侧出现undefinedif(!result.contains(codec))result.insert(codec,-);if(!result.contains(channels))result.insert(channels,-);if(!result.contains(sampleRate))result.insert(sampleRate,-);// ... sampleFormat, bitsPerSample 同理UI 展示StreamDetailPageStreamDetailPage读取mediaAnalyzer.mediaInfo.streams数组为每个流渲染一个详情卡片容器概览区展示总流数、音频流数、视频流数和封装格式。逐流卡片卡片头部流索引#0、类型标签AUDIO/VIDEO颜色区分、编码全称。详情网格buildStreamRows()根据流类型动态生成字段列表音频流展示采样率/通道/位深等视频流展示分辨率/像素格式/帧率等。元数据区从stream.metadata中读取所有键值对按 key 排序展示。响应式布局详情网格在宽度 ≥600 时双列否则单列GridLayout{columns:width600?2:1columnSpacing:24rowSpacing:4// ...}空状态处理如果streams为空或不存在显示请先在基础属性页解析媒体信息的提示。状态清理媒体流详情数据存储在mediaInfo属性中清理时机时机行为openFile()导入新文件setMediaInfo(QVariantMap())完全清空parseMediaInfo()重新解析整体替换为新的解析结果clear()清空全部setMediaInfo(QVariantMap())与 PCM 相关的功能重采样、降噪等不会影响mediaInfo因为媒体信息是容器级别的描述和当前 PCM 数据无关。小结媒体流详情功能是媒体信息解析的可视化展示层算法层MediaInfoParser::parse通过 FFmpegavformatAPI 读取容器和流描述不执行音频解码执行速度快。增强字段覆盖了 profile、level、time_base、disposition、色彩空间和帧数等高级属性。状态层MediaAnalyzer将解析结果存入mediaInfo属性重新解析时保留已有的 PCM 子字段基础属性和流详情页面共用同一次解析结果。UI 层StreamDetailPage以流卡片形式展示每个流的详情支持音频/视频差异化字段和元数据折叠展示响应式布局适配不同窗口宽度。按需解析只在用户主动触发时解析避免导入文件时产生不必要的 I/O 开销。

相关新闻

一个简单的 Oracle SPA示例

一个简单的 Oracle SPA示例

简介 本文通过一个示例来说明如何进行SPA。 SPA即SQL Performance Analyzer,按照官网的说明: SQL Performance Analyzer enables you to assess the impact of system changes on the response time of SQL statements. SQL性能分析器(SQL …

2026/7/10 23:23:41阅读更多 →
计网物理层基本概念

计网物理层基本概念

物理层是五层协议体系中的最底层,它的任务极其单纯:把比特流从一个节点透明地传送到相邻节点。物理层关心的不是"数据是什么意思",而是:用什么样的电压表示 1 和 0?一个比特持续多长时间?要不要区…

2026/7/10 23:18:41阅读更多 →
文心输出的内容粘贴有符号好烦不用愁,AI 导出鸭轻松规整格式

文心输出的内容粘贴有符号好烦不用愁,AI 导出鸭轻松规整格式

1:文心输出的内容粘贴有符号好烦|AI 导出鸭一键清理符号高效整理内容 2:AI 导出鸭实用妙招,告别文心输出的内容粘贴有符号好烦各类排版困扰 3:文心输出的内容粘贴有符号好烦不用愁,AI 导出鸭轻松规整格式 引…

2026/7/10 23:18:41阅读更多 →
企业知识产权战略的“X光”透视报告:从“外包代工”到“法律军火库”的终极分野

企业知识产权战略的“X光”透视报告:从“外包代工”到“法律军火库”的终极分野

企业知识产权战略的“X光”透视报告:从“外包代工”到“法律军火库”的终极分野一、 引言:打破沉默的数据在传统的企业研发分析中,我们往往只关注研发投入金额、专利数量这些显性指标。然而,通过对奇瑞新能源与比亚迪等头部车企的…

2026/7/11 0:33:45阅读更多 →
SecHex-Spoofy终极指南:5分钟掌握Windows硬件标识修改核心技术

SecHex-Spoofy终极指南:5分钟掌握Windows硬件标识修改核心技术

SecHex-Spoofy终极指南:5分钟掌握Windows硬件标识修改核心技术 【免费下载链接】SecHex-Spoofy C# HWID Changer 🔑︎ Disk, Guid, Mac, Gpu, Pc-Name, Win-ID, EFI, SMBIOS Spoofing [Usermode] 项目地址: https://gitcode.com/gh_mirrors/se/SecHex-…

2026/7/11 0:33:45阅读更多 →
群面角色被抢|面试时想好的身份被别人占了?教你半路切入靠观点逆袭「蒸汽求职分享」

群面角色被抢|面试时想好的身份被别人占了?教你半路切入靠观点逆袭「蒸汽求职分享」

在校招或名企综合评估中,无领导小组讨论(群面)往往是淘汰率最高的一轮。很多同学在进考场前,都在心里给自己预设了一个标准的职场画像,比如负责卡时间的计时员(Timekeeper)、或者带节奏的队长&a…

2026/7/11 0:33:45阅读更多 →
2026小红书免费去水印软件教程,安卓苹果通用无下载方案

2026小红书免费去水印软件教程,安卓苹果通用无下载方案

日常浏览小红书时,优质的图文、短视频素材常常需要保存备份,但平台自带保存功能会自带水印,影响个人收藏、素材整理的观感。2026年市面上的小红书去水印工具五花八门,有手机端专属工具、在线网页工具、剪辑软件等多种类型&#xf…

2026/7/11 0:33:45阅读更多 →
华硕主板风扇控制异常终极解决方案:FanControl专业调校完整指南

华硕主板风扇控制异常终极解决方案:FanControl专业调校完整指南

华硕主板风扇控制异常终极解决方案:FanControl专业调校完整指南 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Tr…

2026/7/11 0:33:45阅读更多 →
Python自动化测试实战:Pytest从入门到企业级应用

Python自动化测试实战:Pytest从入门到企业级应用

1. 项目概述 如果你正在用Python做开发,无论是写个小工具还是维护一个大型系统,迟早会碰到一个灵魂拷问:这代码改完了,到底有没有把别的地方搞坏?手动测试?一次两次还行,但每次改完都手动点一遍…

2026/7/11 0:28:44阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/10 12:10:00阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/10 12:29:21阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/10 4:59:05阅读更多 →
Premiere Pro 2025安装失败原因与AGSIS验证绕过指南

Premiere Pro 2025安装失败原因与AGSIS验证绕过指南

1. 为什么2025版PR安装比以往更“磨人”?——从弹窗警告到路径陷阱的真实处境 Premiere Pro 2025版不是简单的一次版本迭代,它是一道分水岭。我从去年底开始帮影视工作室、高校剪辑实验室和自由职业者部署2025环境,累计处理了137台设备&#…

2026/7/11 0:03:43阅读更多 →
5款实用macOS系统优化工具:让你的Mac运行更流畅更高效

5款实用macOS系统优化工具:让你的Mac运行更流畅更高效

5款实用macOS系统优化工具:让你的Mac运行更流畅更高效 【免费下载链接】open-source-mac-os-apps 🚀 Awesome list of open source applications for macOS. https://t.me/s/opensourcemacosapps 项目地址: https://gitcode.com/gh_mirrors/op/open-so…

2026/7/11 0:03:43阅读更多 →
5分钟完全掌握:ComfyUI ControlNet预处理器终极使用指南

5分钟完全掌握:ComfyUI ControlNet预处理器终极使用指南

5分钟完全掌握:ComfyUI ControlNet预处理器终极使用指南 【免费下载链接】comfyui_controlnet_aux ComfyUIs ControlNet Auxiliary Preprocessors 项目地址: https://gitcode.com/gh_mirrors/co/comfyui_controlnet_aux 想要让AI图像生成真正听从你的指挥吗&…

2026/7/11 0:03:43阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/10 13:39:09阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/10 22:20:33阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/10 17:29:22阅读更多 →