iOS直播技術總結

GuadalupeRo 8年前發布 | 23K 次閱讀 GPUImage iOS開發 移動開發

直播總結

1.概述

關于直播的技術文章不少,成體系的不多。我們將用這篇文章,更系統化地介紹當下大熱的視頻直播各環節的關鍵技術,幫助視頻直播創業者們更全面、深入地了解視頻直播技術,更好地技術選型。

1.1 一個完整的直播APP原理

直播原理 : 把主播錄制的視頻,推流送到服務器,服務器經過處理(鑒黃等),通過CDN分發給觀眾看。

直播環節 : 推流端(采集、美顏、編碼、推流),服務端處理(轉碼、錄制、截圖、鑒黃)、播放器(拉流、解碼、渲染)、互動系統(聊天室、禮物系統、贊)

1.2 一個完整直播APP實現流程

1.采集、2.濾鏡處理、3.編碼、4.推流、5.CDN分發、6.拉流、7.解碼、8.播放、9.聊天互動

1.3 一個完整直播APP架構

1.采集端、服務端、播放端

1.4 一個完整直播APP技術點

下面我們會選擇一部分技術進行講解。

2. 視頻采集

2.1 基本知識介紹

AVFundation : 音視頻數據采集需要用AVFundation框架

AVCaptureDevice : 硬件設備,包括麥克風、攝像頭、通過該對象可以設置物理設備的一些屬性。例如相機焦距,白平衡等

AVCaptureDeviceInput : 硬件輸入對象,可以根據AVCaptureDevice創建對應的AVCaptureDeviceInput對象,用于管理硬件輸入數據

AVCaptureOutput : 硬件輸出對象,用于接收各類輸出數據,通常使用對應的子類AVCaptureAudioDataOutput(聲音數據輸出對象), AVCaptureVideoDataOutput(視頻輸出對象)

AVCaptureConnection : 當把一個輸入和輸出添加到AVCaptureSession后。AVCaptureSession就會在輸出、輸出設備之間建立連接,而且通過AVCaptureOutput可以獲得這個對象

AVCaptureVideoPreviewLayer : 相機拍攝預覽圖層,能實時查看相機效果。創建該對象需要指定對應的AVCaptureSession對象,因為AVCaptureSession包含輸出數據,有視頻數據才能顯示。

AVCaptureSession : 協調輸入與輸出之間傳遞數據

2.2 捕獲音視頻步驟

包含關系:

步驟:

  1. 創建AVCaptureDevice(video或者audio)
  2. 根據AVCaptureDevice創建AVCaptureDeviceInput。
  3. 創建AVCaptureSession
  4. 把創建的AVCaptureDeviceInput加入AVCaptureSession
  5. 添加視頻預覽圖層AVCaptureVideoPreviewLayer
  6. 創建AVCaptureAudioDataOutput,并加入AVCaptureSession
  7. 啟動會話

官方步驟(可以忽略):

  1. 創建AVCaptureSession對象
  2. 獲取AVCaptureDevice錄像設備(攝像頭),錄音設備(麥克風)。只用于配置
  3. 根據音頻/視頻硬件設備(AVCaptureDevice)創建音頻/視頻硬件輸入數據對象(AVCaptureDeviceInput),專門管理數據輸入。
  4. 創建視頻輸出數據管理對象(AVCaptureVideoDataOutput),并且設置樣品緩存代理(setSampleBufferDelegate)就可以通過它拿到采集到的視頻數據
  5. 創建音頻輸出數據管理對象(AVCaptureAudioDataOutput),并且設置樣品緩存代理(setSampleBufferDelegate)就可以通過它拿到采集到的音頻數據
  6. 將數據輸入對象AVCaptureDeviceInput、數據輸出對象AVCaptureOutput添加到媒體會話管理對象AVCaptureSession中,就會自動讓音頻輸入與輸出和視頻輸入與輸出產生連接.
  7. 創建視頻預覽圖層AVCaptureVideoPreviewLayer并指定媒體會話,添加圖層到顯示容器layer中
  8. 啟動AVCaptureSession,只有開啟,才會開始輸入到輸出數據流傳輸

其中 AVCaptureAudioDataOutput 、 AVCaptureVideoDataOutput 包含兩個代理方法,可以一直監聽捕獲屬性。

- (void)captureOutput:(AVCaptureOutput )captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection )connection
{
    if (self.videoConnection == connection)
    {
        NSLog(@"采集到視頻");
    }
    else if(self.audioConnection == connection)
    {
        NSLog(@"采集到音頻");
    }
}

// 丟失幀會調用這里

  • (void)captureOutput:(AVCaptureOutput )captureOutput didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection )connection NS_AVAILABLE(10_7, 6_0) { NSLog(@"丟失幀"); }</code></pre>

    2.3 捕捉圖片

    AVCaptureStillImageOutput 可以將捕獲到的Video轉換為圖片。

    1. 創建device
    2. 根據device創建deviceInput
    3. 添加deviceInput進session
    4. 添加預覽圖層
    5. 添加deviceOutput進session
    6. 調用AVCaptureConnection生成圖片

    2.4 捕捉視頻

    AVCaptureMovieFileOutput 可以將捕捉到的視頻輸出到磁盤。可以設置錄制最長時限或錄制到特定大小,還可以配置成保留最小可用磁盤空間。

    1. 創建device
    2. 根據device創建deviceInput
    3. 添加deviceInput進session
    4. 添加預覽圖層
    5. 添加deviceOutput進session
    6. 調用AVCaptureMovieFileOutput把視頻寫入文件

    AVCaptureMovieFileOutput 包含有幾個代理方法。分別是 視頻開始錄制 , 視頻暫停 , 視頻恢復 , 視頻將要錄制完成 , 視頻錄制完成 。

    2.5 采集音頻視頻按幀輸出流程解析

    1.找到物理設備攝像頭_inputCamera、麥克風_microphone,創建攝像頭輸入videoInput和麥克風輸入audioInput;

    2.設置videoInput和audioInput為_captureSession的輸入,同時設置videoOutput和audioOutput為_captureSession的輸出,并且設置videoOutput和audioOutput的輸出delegate;

    3._captureSession調用startRunning,開始捕獲信號;

    4.音頻數據到達,把數據轉發給之前設置的audioEncodingTarget,并通過調用assetWriterAudioInput的appendSampleBuffer方法寫入音頻數據;

    5.視頻數據到達,視頻數據傳入響應鏈,經過處理后通過assetWriterPixelBufferInput的appendSampleBuffer方法寫入視頻數據;

    6.選擇保存后,文件通過ALAssertLibrary寫入手機照片庫。

    流程圖:

    2.6 Demo在這里

    代碼 :捕獲音視頻Demo

    3. GPUImage

    前面好像沒看懂,可以看這里嗎?

    可以,GPUImage對AVFundation進行了一層封裝,就算你不會前面的也沒關系。

    3.1 基本概念

    GPU 手機或者電腦用于處理圖像渲染的硬件

    OpenGL ES 一套圖形與硬件接口,用于把處理好的圖片顯示到屏幕上。

    GPUImage 是一個基于OpenGL ES 2.0圖像和視頻處理的開源iOS框架,提供各種各樣的圖像處理濾鏡,并且支持照相機和攝像機的實時濾鏡,內置120多種濾鏡效果,并且能夠自定義圖像濾鏡。

    GPUImage 是一個基于OpenGL ES 2.0圖像和視頻處理的開源iOS框架,提供各種各樣的圖像處理濾鏡,并且支持照相機和攝像機的實時濾鏡,內置120多種濾鏡效果,并且能夠自定義圖像濾鏡。

    濾鏡處理的原理 就是把靜態圖片或者視頻的每一幀進行圖形變換再顯示出來。它的本質就是像素點的坐標和顏色變化

    3.1 利用GPUImage處理直播過程中美顏流程

    采集視頻 => 獲取每一幀圖片 => 濾鏡處理 => GPUImageView展示

    3.2 處理畫面原理

    GPUImage采用鏈式方式來處理畫面,通過addTarget:方法為鏈條添加每個環節的對象,處理完一個target,就會把上一個環節處理好的圖像數據傳遞下一個target去處理,稱為GPUImage處理鏈。 一般的target可以分為兩類: 中間環節 的target,一般是指各種filter,是GPUImageFilter或者是子類

    最終環節 的target,GPUImageView 用于顯示到屏幕上或者GPUImageMovieWriter寫成視頻文件。

    主要分為三個環節: source(視頻,圖片源) => filter(濾鏡) => final target(處理后的視頻、圖片)

    3.3 美顏原理

    磨皮(GPUImageBilateralFilter) :本質就是讓像素點模糊,可以使用高斯模糊,但是可能導致邊緣會不清晰,用雙邊濾波(Bilateral Filter) ,有針對性的模糊像素點,能保證邊緣不被模糊。

    美白(GPUImageBrightnessFilter) :本質就是提高亮度。

    3.4 GPUImage源對象

    GPUImage的數據源只能是4類:

    GPUImageVideoCamera ios攝像頭的實時美顏。GPUImageVideoCamera是GPUImageOutput的子類,提供來自攝像頭的圖像數據作為源數據,一般是響應鏈的源頭。

    GPUImageStillCamera 相機拍照

    GPUImagePicture 處理靜止圖像

    GPUImageMovie 電影

    3.5 用法

    1. 創建過濾器
    2. 創建源對象
    3. 把過濾器添加到源對象
    4. 生成target

    靜態圖片處理:

    UIImage *inputImage = [UIImage imageNamed:@"105"];

// 創建過濾器 GPUImageBrightnessFilter *filter = [[GPUImageBrightnessFilter alloc] init]; filter.brightness = 0.5; [filter forceProcessingAtSize:inputImage.size]; [filter useNextFrameForImageCapture]; // 告訴系統從后來捕獲過濾器

// 處理靜止的圖像 GPUImagePicture *stillPic = [[GPUImagePicture alloc] initWithImage:inputImage]; [stillPic addTarget:filter]; //添加過濾器 [stillPic processImage]; // 執行渲染

UIImage *newImage = [filter imageFromCurrentFramebuffer];

UIImageView imageView = [[UIImageView alloc] initWithImage:newImage]; [imageView sizeToFit]; [self.view addSubview:imageView]; imageView.center = CGPointMake(CGRectGetWidth(self.view.frame)/2, CGRectGetHeight(self.view.frame)/2);</code></pre>

實時美顏處理:

// 創建視頻源
GPUImageVideoCamera videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPresetHigh cameraPosition:AVCaptureDevicePositionBack];
// 設置方向
videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;

// 創建預覽View GPUImageView *videoPreview = [[GPUImageView alloc] initWithFrame:self.view.bounds]; [self.view insertSubview:videoPreview atIndex:0];

// 添加預覽圖層到源 GPUImageBeautifyFilter *fiter = [[GPUImageBeautifyFilter alloc] init]; [_videoCamera addTarget:fiter]; [fiter addTarget:self.videoPreview]; // 開始采集視頻 [videoCamera startCameraCapture];</code></pre>

到這里,僅僅是屏幕顯示的內容有濾鏡效果,而作為直播應用,還需要輸出帶有美顏效果的視頻流。 我們需要使用 GPUImageMovieWriter 類,才能處理視頻流。

核心思路:

通過GPUImageVideoCamera采集視頻和音頻信息,音頻信息直接發送給 GPUImageMovieWriter ,視頻信息傳入響應鏈作為源頭,渲染后的視頻再寫入 GPUImageMovieWriter ,同時通過 GPUImageView 顯示在屏幕上。只需要 addTarget 就可以添加 GPUImageMovieWriter ;

3.6 實例代碼在這里

4. 音視頻編碼,解碼

這一章太難了,以后再寫。

VideoToolBox

AudioToolBox

5. 流媒體服務器

國內外有很多好用的流媒體服務區。這里為了方便搭建我們采用 nginx+RTMP 搭建流媒體服務器。

5.1 MAC環境搭建

MACOS上搭建nginx+rtmp環境

5.2 Centos環境搭建

Centos下搭建的nginx + RTMP環境

5.3 服務端常用技術

CDN 直播數據上傳到服務器后,觀看直播的人比較多,服務器是承受不了的,會將數據分發到CDN,觀眾直接去CDN獲取數據。減少服務器的負載。

負載均衡 由多臺服務器組成一個服務器集群,每次請求的時候,會根據服務器負載選擇處理請求的服務器。

6. 推流

6.1 推流協議的選擇

HLS和RTMP

6.2 推流原理

在iOS設備上進行各推流的話,是通過AVCaptureSession這么一個捕捉會話,指定兩個AVCaptureDevice 也就是iOS的攝像頭和麥克風,獲取個原始視頻和音頻,然后需要進行個H.264的視頻編碼和AAC的音頻編碼,再將編碼后的數據整合成一個音視頻包,通過rmtp推送到nginx服務器

6.3 librtmp

這個參考資料很少。不過大部分都采用的這個。 因為涉及太多C/C++這里不討論。

7. 音視頻播放

7.1 播放框架的選擇

iOS的播放框架主要有以下三種:

  1. AVPlayer 可以播放本地、遠程視頻,可以自定義UI進行控制
  2. AVPlayerViewController 自帶播放控制UI,不能自定義UI
  3. MPMoviePlayerController,MPMoviePlayerViewController (iOS9后棄用)

如果只是簡單的播放視頻,選擇 AVPlayerViewController ,如果想自定義播放器,選擇 AVPlayer 。

7.2 AVPlayer

AVPlayer是一個用來播放基于時間的流媒體控制對象。支持播放從本地、分布下載或通過HTTP Live Streaming協議得到的流媒體。 AVPlayer只管理一個單獨資源的播放,不過框架還提供了AVPlayer的一個子類AVQueuePlayer,可以用來管理一個資源隊列。當你需要在一個序列中播放多個條目或者為音頻、視頻資源設置播放循環時可以使用該子類。

AVPlayer視頻播放使用步驟:

  1. 創建視頻資源地址URL,可以是網絡URL
  2. 通過URL創建視頻內容對象 AVPlayerItem ,一個視頻對應一個 AVPlayerItem
  3. 創建 AVPlayer 視頻播放對象,需要一個 AVPlayerItem 進行初始化
  4. 創建 AVPlayerLayer 播放圖層對象,添加到現實視圖上去
  5. 添加KVO監聽。 監聽到AVPlayerItemStatusReadyToPlay的時候調用play方法

7.3 AVPlayerViewController

AVPlayerViewController 屬于 AV Kit ,它是 UIViewController的子類 ,用于展示并控制AVPlayer實例的播放。

AVPlayerViewController 類使用步驟

  1. 創建URL
  2. 創建AVPlayerViewController,并根據URL設置player屬性
  3. 調用play方法

Xcode8模擬器可能有問題,打開播放不了。

8.開源框架

前面所講都有第三方框架支持。采集、美顏、推流有 LFLiveKit , 拉流播放有 IJKMediaFramework 。

LFLiveKit : LFLiveKit是iOS版開源RTMP流SDK。他支持后臺錄制、美顏功能、支持h264、AAC硬編碼,動態改變速率,RTMP傳輸等

IJKMediaFramework : ijkplayer是B站開源的一款視頻直播框架,它是基于ffmpeg。 如果從github下載是需要編譯。

個人實驗只需要配置Nginx+RTMP服務 這里我采用這兩個第三方框架寫了一個直播,包含在線觀看直播,和直播推流,支持在線美顏,前后攝像頭切換等你需要:

  1. 搭建 Nginx+RTMP環境 :MAC 或者Centos

  2. 下載項目真機運行。 https://github.com/tiantianlan/miaoboDemo 登陸界面

主頁

直播頁面

 

 

來自:https://github.com/tiantianlan/LiveExplanation

 

 本文由用戶 GuadalupeRo 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!