电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

如何在IOS上使用ReplayKit與RTC

瀏覽:7日期:2022-09-16 18:00:55

在日益繁多的直播場景中,如果你也是某位游戲主播的粉絲的話,有一種直播方式是你一定不陌生的,那就是我們今天要聊的屏幕分享。

直播場景下的屏幕分享,不僅要將當前顯示器所展示的畫面分享給遠端,也要將聲音傳輸出去,包括應用的聲音,以及主播的聲音。鑒于這兩點需求,我們可以簡單分析出,進行一次屏幕分享的直播所需要的媒體流如下:

一條顯示器畫面的視頻流 一條應用聲音的音頻流 一條主播聲音的音頻流

ReplayKit 是蘋果提供的用于 iOS 系統進行屏幕錄制的框架。

首先我們來看看蘋果提供的用于屏幕錄制的 ReplayKit 的數據回調接口:

override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {DispatchQueue.main.async { switch sampleBufferType { case .video:AgoraUploader.sendVideoBuffer(sampleBuffer) case .audioApp:AgoraUploader.sendAudioAppBuffer(sampleBuffer) case .audioMic:AgoraUploader.sendAudioMicBuffer(sampleBuffer) @unknown default:break }} }

從枚舉 sampleBufferType 上,我們不難看出,剛好能符合我們上述對媒體流的需求。

視頻格式

guard let videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer) else { return}let type = CVPixelBufferGetPixelFormatType(videoFrame)

type = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange

通過 CVPixelBufferGetPixelFormatType,我們可以獲取到每幀的視頻格式為 yuv420

幀率

通過打印接口的回調次數,可以知道每秒能夠獲取的視頻幀為30次,也就是幀率為 30。

格式與幀率都能符合 Agora RTC 所能接收的范圍,所以通過 Agora RTC 的 pushExternalVideoFrame 就可以將視頻分享到遠端了。

agoraKit.pushExternalVideoFrame(frame)插入一個小知識

顯示器所顯示的幀來自于一個幀緩存區,一般常見的為雙緩存或三緩存。當屏幕顯示完一幀后,發出一個垂直同步信號(V-Sync),告訴幀緩存區切換到下一幀的緩存上,然后顯示器開始讀取新的一幀數據做顯示。

這個幀緩存區是系統級別的,一般的開發者是無法讀取跟寫入的。但是如果是蘋果自身提供的錄制框架 ReplayKit 能夠直接讀取到已經渲染好且將用于顯示器的幀,且這一過程不會影響渲染流程而造成掉幀,那就能減少一次用于提供給 ReplayKit 回調數據的渲染過程。

音頻

ReplayKit 能提供的音頻有兩種,分為麥克風錄制進來的音頻流,與當前響應的應用播放的音頻流。(下文將前者稱為 AudioMic,后者為 AudioApp)

可以通過下面的兩行代碼,來獲取音頻格式

CMAudioFormatDescriptionRef format = CMSampleBufferGetFormatDescription(sampleBuffer);const AudioStreamBasicDescription *description = CMAudioFormatDescriptionGetStreamBasicDescription(format);AudioApp

AudioApp 會在不同的機型下有不一樣的聲道數。例如在 iPad 或 iPhone7 以下機型中,不具備雙聲道播放的設備,這時候 AudioApp 的數據就是單聲道,反之則是雙聲道。

采樣率在部分試過的機型里,都是 44100,但不排除在未測試過的機型會是其他的采樣率。

AudioMic

AudioMic 在測試過的機型里,采樣率為 32000,聲道數為單聲道。

音頻前處理

如果我們將 AudioApp 與 AudioMic 作為兩條音頻流去發送,那么流量肯定是大于一條音頻流的。我們為了節省一條音頻流的流量,就需要將這兩條音頻流做混音(融合)。

但是通過上述,我們不難看出,兩條音頻流的格式是不一樣的,而且不能保證隨著機型的不同,是不是會出現其他的格式。在測試的過程中還發現 OS 版本的不同,每次回調給到的音頻數據長度也會出現變化。那么我們在對兩條音頻流做混音前,就需要進行格式統一,來應對 ReplayKit 給出的各種格式。所以我們采取了以下幾個重要的步驟:

if (channels == 1) { int16_t* intData = (int16_t*)dataPointer; int16_t newBuffer[totalSamples * 2];for (int i = 0; i < totalSamples; i++) {newBuffer[2 * i] = intData[i];newBuffer[2 * i + 1] = intData[i]; } totalSamples *= 2; memcpy(dataPointer, newBuffer, sizeof(int16_t) * totalSamples); totalBytes *= 2; channels = 2;}

無論是 AudioMic 還是 AudioApp,只要進來的流為單聲道,我們都將它轉化為雙聲道;

if (sampleRate != resampleRate) { int inDataSamplesPer10ms = sampleRate / 100; int outDataSamplesPer10ms = (int)resampleRate / 100; int16_t* intData = (int16_t*)dataPointer; switch (type) {case AudioTypeApp: totalSamples = resampleApp(intData, dataPointerSize, totalSamples, inDataSamplesPer10ms, outDataSamplesPer10ms, channels, sampleRate, (int)resampleRate); break;case AudioTypeMic: totalSamples = resampleMic(intData, dataPointerSize, totalSamples, inDataSamplesPer10ms, outDataSamplesPer10ms, channels, sampleRate, (int)resampleRate); break; } totalBytes = totalSamples * sizeof(int16_t);}

無論是 AudioMic 還是 AudioApp,只要進來的流采樣率不為 48000,我們將它們重采樣為 48000;

memcpy(appAudio + appAudioIndex, dataPointer, totalBytes);appAudioIndex += totalSamples;

memcpy(micAudio + micAudioIndex, dataPointer, totalBytes);micAudioIndex += totalSamples;

通過第一步與第二步,我們保證了兩條音頻流都為同樣的音頻格式。但是由于 ReplayKit 是一次回調給到一種數據的,所以在混音前我們還得用兩個緩存區來存儲這兩條流數據;

int64_t mixIndex = appAudioIndex > micAudioIndex ? micAudioIndex : appAudioIndex;int16_t pushBuffer[appAudioIndex];memcpy(pushBuffer, appAudio, appAudioIndex * sizeof(int16_t));for (int i = 0; i < mixIndex; i ++) { pushBuffer[i] = (appAudio[i] + micAudio[i]) / 2;}

ReplayKit 有選項是否開啟麥克風錄制,所以在關閉麥克風錄制的時候,我們就只有一條 AudioApp 音頻流。所以我們以這條流為主,去讀取 AudioMic 緩存區的數據長度,然后對比兩個緩存區的數據長度,以最小的數據長度為我們的混音長度。將混音長度的兩個緩存區里的數據做融合,得到混音后的數據,寫入一個新的混音緩存區(或者直接寫入 AudioApp 緩存區);

[AgoraAudioProcessing pushAudioFrame:(*unsigned* *char* *)pushBuffer withFrameSize:appAudioIndex * *sizeof*(int16_t)];

最后我們再將這段混音后的數據拷貝進 Agora RTC 的 C++ 錄制回調接口里,這時候就可以把麥克風錄制的聲音與應用播放的聲音傳輸到遠端了。

通過對音視頻流的處理,結合 Agora RTC SDK,我們就完成了一個屏幕分享直播場景的實現了。

以上就是如何在IOS上使用ReplayKit與RTC的詳細內容,更多關于IOS上使用ReplayKit與RTC的資料請關注好吧啦網其它相關文章!

標簽: IOS
相關文章:
主站蜘蛛池模板: 自动螺旋上料机厂家价格-斗式提升机定制-螺杆绞龙输送机-杰凯上料机 | 百度关键词优化_网站优化_SEO价格 - 云无限好排名 | 北京遮阳网-防尘盖土网-盖土草坪-迷彩网-防尘网生产厂家-京兴科技 | 福建珂朗雅装饰材料有限公司「官方网站」| 无刷电机_直流无刷电机_行星减速机-佛山市藤尺机电设备有限公司 无菌检查集菌仪,微生物限度仪器-苏州长留仪器百科 | 预制直埋蒸汽保温管-直埋管道-聚氨酯发泡保温管厂家 - 唐山市吉祥保温工贸有限公司 | 郑州外墙清洗_郑州玻璃幕墙清洗_郑州开荒保洁-河南三恒清洗服务有限公司 | RO反渗透设备_厂家_价格_河南郑州江宇环保科技有限公司 | 充气膜专家-气膜馆-PTFE膜结构-ETFE膜结构-商业街膜结构-奥克金鼎 | 带锯机|木工带锯机圆木推台锯|跑车带锯机|河北茂业机械制造有限公司| | 众能联合-提供高空车_升降机_吊车_挖机等一站工程设备租赁 | 开云(中国)Kaiyun·官方网站 - 登录入口 | 免费B2B信息推广发布平台 - 推发网 | 深圳VI设计-画册设计-LOGO设计-包装设计-品牌策划公司-[智睿画册设计公司] | 吸音板,隔音板,吸音材料,吸音板价格,声学材料 - 佛山诺声吸音板厂家 | 环保袋,无纺布袋,无纺布打孔袋,保温袋,环保袋定制,环保袋厂家,环雅包装-十七年环保袋定制厂家 | 排烟防火阀-消防排烟风机-正压送风口-厂家-价格-哪家好-德州鑫港旺通风设备有限公司 | 杭州中央空调维修_冷却塔/新风机柜/热水器/锅炉除垢清洗_除垢剂_风机盘管_冷凝器清洗-杭州亿诺能源有限公司 | 合肥宠物店装修_合肥宠物美容院装修_合肥宠物医院设计装修公司-安徽盛世和居装饰 | 网站建设-网站制作-网站设计-网站开发定制公司-网站SEO优化推广-咏熠软件 | 免费B2B信息推广发布平台 - 推发网| 深圳市源和塑胶电子有限公司-首页 | 【MBA备考网】-2024年工商管理硕士MBA院校/报考条件/培训/考试科目/提前面试/考试/学费-MBA备考网 | 美国PARKER齿轮泵,美国PARKER柱塞泵,美国PARKER叶片泵,美国PARKER电磁阀,美国PARKER比例阀-上海维特锐实业发展有限公司二部 | CTAB,表面活性剂1631溴型(十六烷基三甲基溴化铵)-上海升纬化工原料有限公司 | 骨灰存放架|骨灰盒寄存架|骨灰架厂家|智慧殡葬|公墓陵园管理系统|网上祭奠|告别厅智能化-厦门慈愿科技 | 丹佛斯变频器-丹佛斯压力开关-变送器-广州市风华机电设备有限公司 | 东莞动力锂电池保护板_BMS智能软件保护板_锂电池主动均衡保护板-东莞市倡芯电子科技有限公司 | 云南外加剂,云南速凝剂,云南外加剂代加工-普洱澜湄新材料科技有限公司 | 亚洲工业智能制造领域专业门户网站 - 亚洲自动化与机器人网 | 耐磨焊丝,堆焊焊丝,耐磨药芯焊丝,碳化钨焊丝-北京耐默公司 | 东莞压铸厂_精密压铸_锌合金压铸_铝合金压铸_压铸件加工_东莞祥宇金属制品 | 齿轮减速机_齿轮减速电机-VEMT蜗轮蜗杆减速机马达生产厂家瓦玛特传动瑞环机电 | 双能x射线骨密度检测仪_dxa骨密度仪_双能x线骨密度仪_品牌厂家【品源医疗】 | 短信营销平台_短信群发平台_106短信发送平台-河南路尚 | 压接机|高精度压接机|手动压接机|昆明可耐特科技有限公司[官网] 胶泥瓷砖胶,轻质粉刷石膏,嵌缝石膏厂家,腻子粉批发,永康家德兴,永康市家德兴建材厂 | 旋片真空泵_真空泵_水环真空泵_真空机组-深圳恒才机电设备有限公司 | 非甲烷总烃分析仪|环控百科| 广州展览制作|展台制作工厂|展览设计制作|展览展示制作|搭建制作公司 | 石磨面粉机|石磨面粉机械|石磨面粉机组|石磨面粉成套设备-河南成立粮油机械有限公司 | 密集架|电动密集架|移动密集架|黑龙江档案密集架-大量现货厂家销售 |