最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何在IOS上使用ReplayKit與RTC

 更新時(shí)間:2021年04月13日 09:22:27   作者:聲網(wǎng)Agora  
這篇文章主要介紹了如何在IOS上使用ReplayKit 與 RTC,對(duì)IOS音視頻感興趣的同學(xué),一定要看一下

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

直播場(chǎng)景下的屏幕分享,不僅要將當(dāng)前顯示器所展示的畫(huà)面分享給遠(yuǎn)端,也要將聲音傳輸出去,包括應(yīng)用的聲音,以及主播的聲音。鑒于這兩點(diǎn)需求,我們可以簡(jiǎn)單分析出,進(jìn)行一次屏幕分享的直播所需要的媒體流如下:

  1. 一條顯示器畫(huà)面的視頻流
  2. 一條應(yīng)用聲音的音頻流
  3. 一條主播聲音的音頻流

ReplayKit 是蘋(píng)果提供的用于 iOS 系統(tǒng)進(jìn)行屏幕錄制的框架。

首先我們來(lái)看看蘋(píng)果提供的用于屏幕錄制的 ReplayKit 的數(shù)據(jù)回調(diào)接口:

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 上,我們不難看出,剛好能符合我們上述對(duì)媒體流的需求。

視頻格式

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

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

幀率

通過(guò)打印接口的回調(diào)次數(shù),可以知道每秒能夠獲取的視頻幀為30次,也就是幀率為 30。

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

agoraKit.pushExternalVideoFrame(frame)

插入一個(gè)小知識(shí)

顯示器所顯示的幀來(lái)自于一個(gè)幀緩存區(qū),一般常見(jiàn)的為雙緩存或三緩存。當(dāng)屏幕顯示完一幀后,發(fā)出一個(gè)垂直同步信號(hào)(V-Sync),告訴幀緩存區(qū)切換到下一幀的緩存上,然后顯示器開(kāi)始讀取新的一幀數(shù)據(jù)做顯示。

這個(gè)幀緩存區(qū)是系統(tǒng)級(jí)別的,一般的開(kāi)發(fā)者是無(wú)法讀取跟寫(xiě)入的。但是如果是蘋(píng)果自身提供的錄制框架 ReplayKit 能夠直接讀取到已經(jīng)渲染好且將用于顯示器的幀,且這一過(guò)程不會(huì)影響渲染流程而造成掉幀,那就能減少一次用于提供給 ReplayKit 回調(diào)數(shù)據(jù)的渲染過(guò)程。

音頻

ReplayKit 能提供的音頻有兩種,分為麥克風(fēng)錄制進(jìn)來(lái)的音頻流,與當(dāng)前響應(yīng)的應(yīng)用播放的音頻流。(下文將前者稱(chēng)為 AudioMic,后者為 AudioApp)

可以通過(guò)下面的兩行代碼,來(lái)獲取音頻格式

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

AudioApp

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

采樣率在部分試過(guò)的機(jī)型里,都是 44100,但不排除在未測(cè)試過(guò)的機(jī)型會(huì)是其他的采樣率。

AudioMic

AudioMic 在測(cè)試過(guò)的機(jī)型里,采樣率為 32000,聲道數(shù)為單聲道。

音頻前處理

如果我們將 AudioApp 與 AudioMic 作為兩條音頻流去發(fā)送,那么流量肯定是大于一條音頻流的。我們?yōu)榱斯?jié)省一條音頻流的流量,就需要將這兩條音頻流做混音(融合)。

但是通過(guò)上述,我們不難看出,兩條音頻流的格式是不一樣的,而且不能保證隨著機(jī)型的不同,是不是會(huì)出現(xiàn)其他的格式。在測(cè)試的過(guò)程中還發(fā)現(xiàn) OS 版本的不同,每次回調(diào)給到的音頻數(shù)據(jù)長(zhǎng)度也會(huì)出現(xiàn)變化。那么我們?cè)趯?duì)兩條音頻流做混音前,就需要進(jìn)行格式統(tǒng)一,來(lái)應(yīng)對(duì) ReplayKit 給出的各種格式。所以我們采取了以下幾個(gè)重要的步驟:

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;
}

無(wú)論是 AudioMic 還是 AudioApp,只要進(jìn)來(lái)的流為單聲道,我們都將它轉(zhuǎn)化為雙聲道;

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);
}

無(wú)論是 AudioMic 還是 AudioApp,只要進(jìn)來(lái)的流采樣率不為 48000,我們將它們重采樣為 48000;

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

通過(guò)第一步與第二步,我們保證了兩條音頻流都為同樣的音頻格式。但是由于 ReplayKit 是一次回調(diào)給到一種數(shù)據(jù)的,所以在混音前我們還得用兩個(gè)緩存區(qū)來(lái)存儲(chǔ)這兩條流數(shù)據(jù);

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 有選項(xiàng)是否開(kāi)啟麥克風(fēng)錄制,所以在關(guān)閉麥克風(fēng)錄制的時(shí)候,我們就只有一條 AudioApp 音頻流。所以我們以這條流為主,去讀取 AudioMic 緩存區(qū)的數(shù)據(jù)長(zhǎng)度,然后對(duì)比兩個(gè)緩存區(qū)的數(shù)據(jù)長(zhǎng)度,以最小的數(shù)據(jù)長(zhǎng)度為我們的混音長(zhǎng)度。將混音長(zhǎng)度的兩個(gè)緩存區(qū)里的數(shù)據(jù)做融合,得到混音后的數(shù)據(jù),寫(xiě)入一個(gè)新的混音緩存區(qū)(或者直接寫(xiě)入 AudioApp 緩存區(qū));

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

最后我們?cè)賹⑦@段混音后的數(shù)據(jù)拷貝進(jìn) Agora RTC 的 C++ 錄制回調(diào)接口里,這時(shí)候就可以把麥克風(fēng)錄制的聲音與應(yīng)用播放的聲音傳輸?shù)竭h(yuǎn)端了。

通過(guò)對(duì)音視頻流的處理,結(jié)合 Agora RTC SDK,我們就完成了一個(gè)屏幕分享直播場(chǎng)景的實(shí)現(xiàn)了。

以上就是如何在IOS上使用ReplayKit與RTC的詳細(xì)內(nèi)容,更多關(guān)于IOS上使用ReplayKit與RTC的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • IOS 中UITextField和UITextView中字符串為空和空格的解決辦法

    IOS 中UITextField和UITextView中字符串為空和空格的解決辦法

    這篇文章主要介紹了IOS 中UITextField和UITextView中字符串為空和空格的解決辦法的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • iOS11上Xcode9 AppIcon 圖標(biāo)不顯示

    iOS11上Xcode9 AppIcon 圖標(biāo)不顯示

    升級(jí)到iOS11系統(tǒng)下自己的項(xiàng)目桌面app圖標(biāo)不見(jiàn)了,是什么原因呢,經(jīng)過(guò)一番查找,終于發(fā)現(xiàn)問(wèn)題所在,現(xiàn)在分享給大家
    2017-11-11
  • iOS中修改UISearchBar圓角的小技巧分享

    iOS中修改UISearchBar圓角的小技巧分享

    UISearchBar也是iOS開(kāi)發(fā)常用控件之一,點(diǎn)進(jìn)去看看里面的屬性barStyle、text、placeholder等等。下面這篇文章主要給大家分享了iOS中修改UISearchBar圓角的小技巧,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),需要的朋友們下面來(lái)一起看看吧。
    2017-05-05
  • 詳解iOS tableViewCell自適應(yīng)高度 第三發(fā)類(lèi)庫(kù)

    詳解iOS tableViewCell自適應(yīng)高度 第三發(fā)類(lèi)庫(kù)

    在github中有許多大牛封裝好的第三發(fā)類(lèi)庫(kù),其中有個(gè)自適應(yīng)cell高度的類(lèi)庫(kù)。接下來(lái)通過(guò)本文給大家介紹iOS tableViewCell自適應(yīng)高度 第三發(fā)類(lèi)庫(kù),需要的朋友參考下
    2016-04-04
  • iOS實(shí)現(xiàn)多控制器切換效果

    iOS實(shí)現(xiàn)多控制器切換效果

    這篇文章主要為大家詳細(xì)介紹了iOS實(shí)現(xiàn)多控制器切換效果,帶滑動(dòng)動(dòng)畫(huà),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • iOS面試中如何優(yōu)雅回答B(yǎng)lock導(dǎo)致循環(huán)引用的問(wèn)題

    iOS面試中如何優(yōu)雅回答B(yǎng)lock導(dǎo)致循環(huán)引用的問(wèn)題

    這篇文章主要給大家介紹了iOS面試中關(guān)于如何優(yōu)雅回答B(yǎng)lock導(dǎo)致循環(huán)引用的問(wèn)題的相關(guān)資料,文中通過(guò)圖文介紹的非常相信,相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-03-03
  • iOS UICollectionView實(shí)現(xiàn)橫向滑動(dòng)

    iOS UICollectionView實(shí)現(xiàn)橫向滑動(dòng)

    這篇文章主要為大家詳細(xì)介紹了iOS UICollectionView實(shí)現(xiàn)橫向滑動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • Objective-C中關(guān)于實(shí)例所占內(nèi)存的大小詳解

    Objective-C中關(guān)于實(shí)例所占內(nèi)存的大小詳解

    這篇文章主要給大家介紹了關(guān)于Objective-C中實(shí)例所占內(nèi)存的大小的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位iOS開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • 你應(yīng)該知道的tableViewCell行高計(jì)算處理

    你應(yīng)該知道的tableViewCell行高計(jì)算處理

    這篇文章主要給大家介紹了關(guān)于tableViewCell行高計(jì)算的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • IOS開(kāi)發(fā)中異步網(wǎng)絡(luò)請(qǐng)求上實(shí)現(xiàn)同步邏輯

    IOS開(kāi)發(fā)中異步網(wǎng)絡(luò)請(qǐng)求上實(shí)現(xiàn)同步邏輯

    這篇文章主要介紹了IOS開(kāi)發(fā)中異步網(wǎng)絡(luò)請(qǐng)求上實(shí)現(xiàn)同步邏輯的相關(guān)資料,需要的朋友可以參考下
    2017-03-03

最新評(píng)論

科尔| 木兰县| 安图县| 九寨沟县| 鸡西市| 嵊州市| 句容市| 武义县| 孙吴县| 偏关县| 虎林市| 秦安县| 太保市| 徐州市| 通渭县| 格尔木市| 新巴尔虎左旗| 合阳县| 高唐县| 济南市| 军事| 郴州市| 文安县| 岑巩县| 兰溪市| 龙陵县| 甘南县| 钟山县| 隆化县| 尉氏县| 凤翔县| 穆棱市| 井研县| 太原市| 马鞍山市| 新和县| 富锦市| 永顺县| 长武县| 苗栗市| 汝阳县|