使用Qt下QAudioOutput播放聲音

導讀

? ? ? ? 本項目目的是使用QAudioOutput播放聲音 ,音頻數據來源為ffmpeg解碼后的音頻數據。

Qt音頻播放類說明?

QAudioFormat

QAudioFormat是Qt多媒體框架中用于定義音頻格式的核心類,用于設置音頻數據的參數,確保與硬件設備兼容。其主要功能和參數如下:
一,采樣率(Sample Rate)
定義每秒采集或播放的樣本數,單位為Hz。常用值:
44,100 Hz(CD音質)
48,000 Hz(高清音頻)

二,通道數(Channel Count)
定義音頻聲道數量:
1:單聲道(Mono)
2:立體聲(Stereo)

三,樣本大小(Sample Size)
定義每個樣本的位數(量化精度),常見值為16位

四,編碼類型(Codec)
指定音頻編碼格式,通常為PCM原始數據

五,字節序(Byte Order)
定義數據存儲順序:
QAudioFormat::LittleEndian(小端序,Intel架構常用)
QAudioFormat::BigEndian(大端序)

六,樣本類型(Sample Type)
定義樣本數據類型:
QAudioFormat::SignedInt(有符號整數)
QAudioFormat::UnSignedInt(無符號整數)

QAudioOutput

QAudioOutput 是 Qt 多媒體框架中用于音頻輸出的核心類,支持將 PCM 原始音頻數據發送到音頻設備(如揚聲器)。以下是其核心特性和使用要點:
一,功能定位
音頻輸出控制
管理音頻播放狀態(播放/暫停/停止)和音頻數據流傳輸,適用于低延遲實時音頻場景。
對比高級類 QMediaPlayer,它更底層且靈活性強,但需手動處理原始 PCM 數據。?

二,核心方法
方法 功能說明
start(QIODevice*)?? ?綁定輸入設備(如 QFile 或自定義 QIODevice)并開始播放音頻數據。
stop()?? ?停止播放并釋放資源。
suspend()?? ?暫停播放(保留資源)。
resume()?? ?從暫停狀態恢復播放。
setVolume(float)?? ?設置音量(0.0 靜音 ~ 1.0 最大)。
setBufferSize(int)?? ?設置緩沖區大小(需在 start() 前調用生效)。

三,關鍵信號
stateChanged(QAudio::State)
播放狀態變更時觸發,狀態包括:
ActiveState(正在播放)
SuspendedState(暫停)
StoppedState(停止)
IdleState(數據耗盡或未啟動)

QIODevice

QIODevice是Qt框架中所有輸入/輸出設備的核心抽象基類,為文件、內存緩沖區和網絡通信等設備提供了統一的I/O接口。其主要特性如下:

一,設備抽象與繼承結構
作為所有Qt I/O設備的基類,定義了通用讀寫接口,無法直接實例化。
具體子類包括:
QFile(文件操作)
QBuffer(內存緩沖區)
QTcpSocket/QTcpServer(網絡通信)
QProcess(進程通信)
QSerialPort(串口通信)

二,設備類型區分
隨機訪問設備(如文件):支持seek()定位和pos()獲取當前位置?
順序設備(如網絡套接字):不支持隨機定位,數據必須一次性讀取
通過isSequential()判斷設備類型

音頻播放代碼關鍵實現

初始化qt音頻相關對象?

int FFPlayer::initQtAudio(const AVCodecParameters *codecPar)
{QAudioFormat format;format.setSampleRate(codecPar->sample_rate);format.setChannelCount(codecPar->channels);format.setSampleSize(16); // 統一轉換為16位輸出format.setCodec("audio/pcm");format.setByteOrder(QAudioFormat::LittleEndian);format.setSampleType(QAudioFormat::SignedInt);m_audioOutput = new QAudioOutput(format);m_audioDevice = m_audioOutput->start();// 初始化重采樣器swr_ctx = swr_alloc_set_opts(NULL,av_get_default_channel_layout(codecPar->channels),AV_SAMPLE_FMT_S16,codecPar->sample_rate,av_get_default_channel_layout(audio_codec_ctx->channels),audio_codec_ctx->sample_fmt,audio_codec_ctx->sample_rate,0, NULL);logger()->info("swr_alloc_set_opts()sample_fmt:%d ",audio_codec_ctx->sample_fmt);if(!swr_ctx || swr_init(swr_ctx)<0){logger()->info("重采樣初始化失敗");return -1;}//初始化音頻播放線程_audioPlayThread = std::thread(playAudioFunc,this);return 0;
}

音頻解碼線程實現

void decodeAudioFunc(void*ctx)
{FFPlayer* ptx = (FFPlayer*)ctx;if(ptx == nullptr)return;while(!ptx->quit){AVPacket pkt;if(ptx->_audioPktList.size()>0){std::lock_guard<std::mutex> lock(ptx->audioQueueMutex);pkt = ptx->_audioPktList.front();ptx->_audioPktList.pop_front();}else{std::this_thread::sleep_for(std::chrono::milliseconds(20));continue;}
#if 1//解碼int ret = 0;ret = avcodec_send_packet(ptx->audio_codec_ctx, &pkt);if (ret != 0) {logger()->info("avcodec_send_packet error: %d", ret);return;}while(avcodec_receive_frame(ptx->audio_codec_ctx, ptx->audioFrame)>=0){// 重采樣uint8_t* output;int out_samples = swr_get_out_samples(ptx->swr_ctx, ptx->audioFrame->nb_samples);av_samples_alloc(&output, NULL, ptx->audio_codec_ctx->channels,out_samples, AV_SAMPLE_FMT_S16, 0);out_samples = swr_convert(ptx->swr_ctx, &output, out_samples,(const uint8_t**)ptx->audioFrame->data, ptx->audioFrame->nb_samples);if(out_samples < 0){logger()->info("swr_convert failed %d",out_samples);}// 填充音頻緩沖區int aDataSize = 0;//兩種計算重采樣后音頻數據大小的方法 
#if 0aDataSize = out_samples * ptx->audio_codec_ctx->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
#elseaDataSize = av_samples_get_buffer_size(NULL,                         // 行大小(可忽略)ptx->audio_codec_ctx->channels, // 聲道數out_samples,                  // 實際樣本數AV_SAMPLE_FMT_S16,            // 目標格式0                             // 字節對齊);
#endif//將重采樣后的音頻數據加入隊列{QByteArray aData((char*)output,aDataSize);{std::lock_guard<mutex> lck(ptx->_audioDataMutex);ptx->_audioDataList.push_back(aData);}}av_freep(&output);}
#endifav_packet_unref(&pkt);}logger()->info("quit decodeAudioFunc");
}

音頻播放線程實現

void playAudioFunc(void*ctx)
{FFPlayer* player = (FFPlayer*)ctx;if(player == nullptr)return;QByteArray aData;while(!player->quit){if(!player->_audioDataList.empty()){std::lock_guard<std::mutex> lock(player->_audioDataMutex);aData = player->_audioDataList.front();player->_audioDataList.pop_front();}else{std::this_thread::sleep_for(std::chrono::milliseconds(2));continue;}if(player->m_audioDevice){//將pcm音頻數據寫入聲卡player->m_audioDevice->write((const char*)aData.data(),aData.length());}}
}

????????

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90365.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90365.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90365.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

日語學習-日語知識點小記-構建基礎-JLPT-N3階段(9):ようなN

日語學習-日語知識點小記-構建基礎-JLPT-N3階段&#xff08;9&#xff09;&#xff1a;ようなN 1、前言&#xff08;1&#xff09;情況說明&#xff08;2&#xff09;工程師的信仰2、知識點&#xff08;&#xff11;&#xff09;復習&#xff08;&#xff12;&#xff09;復習&…

洛谷P1512 伊甸園日歷游戲

一開始&#xff0c;我發現有“必勝策略”&#xff0c;就知道是博弈論&#xff0c;然后看了兩種操作&#xff08;月份1和天數1&#xff09;&#xff0c;于是想到用記憶化搜索找出所有的可能性 &#xff0c;但不知道怎么判斷當前是否為先手必勝/必敗態&#xff0c;使用了TJ方法后…

Kafka——消費者組到底是什么?

引言在分布式系統中&#xff0c;消息中間件的核心價值在于高效地連接生產者與消費者&#xff0c;實現數據的可靠傳遞。然而&#xff0c;傳統消息引擎面臨一個兩難困境&#xff1a;如何在“消息不重復消費”與“系統可擴展性”之間找到平衡&#xff1f;點對點模型&#xff08;如…

新mac電腦軟件安裝指南(前端開發用)

1. 下載git 未下載git直接下載homebrew也會提示你下載git 2. 下載homebrew 介紹&#xff1a; Homebrew 是 macOS 和 Linux 系統的開源包管理器?&#xff0c;通過命令行實現軟件的快速安裝、更新和管理&#xff0c;極大簡化了開發者及普通用戶的工作流程。 命令&#xff1a;…

【HarmonyOS】ArkUI 布局與容器組件

目錄前言一、線性布局(Column/Row)1.先布局后內容2.元素在主軸上的排列方式3.元素在交叉軸上的排列方式二、層疊布局(Stack)1.開發布局2.對齊方式三、彈性布局(Flex)四、創建列表(List)五、創建輪播(Swiper)1.基本用法2.常用屬性3.樣式自定義六、選項卡Tabs1.基本用法2.常用屬性…

MCNN-BiLSTM-Attention分類預測模型等!

MCNN-BiLSTM-Attention分類預測模型基于多尺度卷積神經網絡(MCNN)雙向長短期記憶網絡(BiLSTM)注意力機制(Attention)的分類預測模型&#xff0c;matlab代碼&#xff0c;直接運行使用&#xff01;1、模型介紹&#xff1a;針對傳統方法在噪聲環境下診斷精度低的問題&#xff0c;提…

【Luogu】每日一題——Day12. P3149 排序 (樹狀數組 + 逆序對)

鏈接&#xff1a;P3149 排序 - 洛谷 題目&#xff1a; 思路&#xff1a; 經典搭配了 首先我們來分析以下操作的作用&#xff0c;如果我們選了 a[k]&#xff0c;那么對逆序對有什么影響呢&#xff1f; ①.對于 x y&#xff0c;且 x > a[k]&#xff0c;y < a[k] 由于 x…

電商項目_秒殺_架構升級

1. 秒殺當前架構設計nginx節點和訂單服務都可以方便的擴容&#xff08;增加機器&#xff09;redis擴容需則需要考慮架構設計當前架構面臨的痛點&#xff1a;秒殺系統redis是單節點&#xff08;主從&#xff09;部署&#xff0c;讀redis時并發量會成為瓶頸。所以考慮將增加redis…

CodeBuddy IDE發布:編程新時代的顛覆者?

開場&#xff1a;編程界的 “新風暴” 來襲 你能想象&#xff0c;不用敲一行代碼就能開發軟件嗎&#xff1f;這個曾經只存在于科幻電影里的場景&#xff0c;如今已經成為現實&#xff01;就在最近&#xff0c;編程界迎來了一場 “新風暴”——CodeBuddy IDE 重磅發布&#xff…

深度分析Java類加載機制

Java 的類加載機制是其實現平臺無關性、安全性和動態性的核心基石。它不僅僅是簡單地將 .class 文件加載到內存中&#xff0c;而是一個精巧、可擴展、遵循特定規則的生命周期管理過程。以下是對其深度分析&#xff1a; 一、核心概念與生命周期 一個類型&#xff08;Class 或 In…

神經網絡實戰案例:用戶情感分析模型

在當今數字化時代&#xff0c;用戶評論和反饋成為企業了解產品滿意度的重要渠道。本項目將通過神經網絡構建一個情感分析模型&#xff0c;自動識別用戶評論中的情感傾向。我們將使用真實的產品評論數據&#xff0c;從數據預處理到模型部署&#xff0c;完整展示神經網絡在NLP領域…

now能減少mysql的壓力嗎

是否用數據庫的 NOW() 能減少 MySQL 的壓力&#xff1f;?答案是否定的——使用 NOW() 不僅不會降低壓力&#xff0c;反而可能略微增加 MySQL 的負載。以下是詳細分析&#xff1a;&#x1f50d; 性能對比&#xff1a;NOW() vs. Java 傳參?指標??Java 傳參 (e.g., new Date()…

數據結構01:鏈表

數據結構 鏈表 鏈表和數組的區別 1. 存儲方式 數組&#xff1a; 元素在內存中連續存儲&#xff0c;占用一塊連續的內存空間元素的地址可以通過索引計算&#xff08;基地址 索引 元素大小&#xff09;大小固定&#xff0c;在創建時需要指定容量 鏈表&#xff1a; 元素&#xf…

【Java學習|黑馬筆記|Day21】IO流|緩沖流,轉換流,序列化流,反序列化流,打印流,解壓縮流,常用工具包相關用法及練習

標題【Java學習|黑馬筆記|Day20】 今天看的是黑馬程序員的《Java從入門到起飛》下部的95-118節&#xff0c;筆記包含IO流中的字節、字符緩沖流&#xff0c;轉換流&#xff0c;序列化流反序列化流&#xff0c;打印流&#xff0c;解壓縮流&#xff0c;常用工具包相關用法及練習 …

API網關原理與使用場景詳解

一、API網關核心原理 1. 架構定位 #mermaid-svg-hpDCWfqoiLcVvTzq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-hpDCWfqoiLcVvTzq .error-icon{fill:#552222;}#mermaid-svg-hpDCWfqoiLcVvTzq .error-text{fill:#5…

OSPF路由協議——上

OSPF路由協議 RIP的不足 以跳數評估的路由并非最優路徑如果RTA選擇s0/0傳輸&#xff0c;傳輸需時會大大縮短為3s 最大跳數為16跳&#xff0c;導致網絡尺度小RIP協議限制網絡直徑不能超過16跳&#xff0c;并且16跳為不可達。 收斂速度慢 RIP 定期路由更新 更新計時器&#xff1a…

(LeetCode 面試經典 150 題) 219. 存在重復元素 II (哈希表)

題目&#xff1a;219. 存在重復元素 II 思路&#xff1a;哈希表&#xff0c;時間復雜度0(n)。 哈希表記錄每個數最新的下標&#xff0c;遇到符合要求的返回true即可。 C版本&#xff1a; class Solution { public:bool containsNearbyDuplicate(vector<int>& nums,…

Cookies 詳解及其與 Session 的協同工作

Cookies 詳解及其與 Session 的協同工作 一、Cookies 的本質與作用 1. 什么是 Cookies&#xff1f; Cookies 是由服務器發送到用戶瀏覽器并存儲在本地的小型文本文件。核心特性&#xff1a; 存儲位置&#xff1a;客戶端瀏覽器數據形式&#xff1a;鍵值對字符串&#xff08;最大…

DeepSeek Janus Pro本地部署與調用

step1、Janus模型下載與項目部署 創建文件夾autodl-tmp https://github.com/deepseek-ai/Janus?tabreadme-ov-file# janusflow 查看是否安裝了git&#xff0c;沒有安裝的話安裝一下&#xff0c;或者是直接github上下載&#xff0c;上傳到服務器&#xff0c;然后解壓 git --v…

【Elasticsearch】BM25的discount_overlaps參數

discount_overlaps 是 Elasticsearch/Lucene 相似度模型&#xff08;Similarity&#xff09;里的一個布爾參數&#xff0c;用來決定&#xff1a;> 在計算文檔長度歸一化因子&#xff08;norm&#xff09;時&#xff0c;是否忽略“重疊 token”&#xff08;即位置增量 positi…