1. 程式人生 > >不用第三方寫一個簡單的推流軟體

不用第三方寫一個簡單的推流軟體

 README.md

#iOS不用任何第三方,寫一個簡單的RTMP直播推流器

2016年是移動直播爆發年,不到半年的時間內無數移動直播App掀起了全民直播的熱潮。然而個人覺得直播的門檻相對較高,從推流端到服務端器到播放端,無不需要專業的技術來支撐,僅僅推流端就有不少需要學習的知識.目前大部分直播採用的都是RTMP協議,我這裡寫一個簡單的Demo,幫助大家更好的理解直播推流的過程,主要包括:音視訊採集, 音視訊編碼, 資料打包, RTMP協議等相關的知識等.專案結構分的很清楚,各個模組也用協議進行了分離,方便大家學習不同的模組.

先闡述下推流的整體流程:

  • 建立tcp連線
  • 建立rtmp連線,以及傳送各種控制指令
  • 獲取原始視訊資料和音訊資料
  • 對原始視訊資料和音訊資料進行壓縮編碼
  • 對編碼後的視訊資料和音訊資料進行打包
  • 傳送打包後的音訊和視訊資料

專案各個類的作用

  • SGSimpleSession 是Api介面層,負責對外提供可直接呼叫的介面,同時也是一個數據分發中心,獲取到的原始音視訊資料和編碼後的資料都在這裡被分發到不同的類進行處理.

  • 視訊相關的類

    • SGVideoSource 原始視訊資料獲取類,底層用的是AVFoundation框架來實現.對外提供原始未經編碼的的視訊資料,同時提供影象預覽功能.如果需要新增美顏,攝像頭切換,翻轉,閃光燈等操作,也是在這裡處理的.

      原始視訊幀 : 原始視訊資料其實就是一幀一幀的資料,它們沒有經過壓縮編碼,每一幀包含了影象資訊和時間資訊,我們通過程式碼提取出圖片.

      fps :1s中包含的幀數就是幀速(fps),一般fps的範圍是15~30幀,幀速越高畫面越流暢,頻寬消耗量越大.實際直播中,大部分採用15到20就可以了.

      解析度: 一幀的影象的大小,iOS原生的有352*288,640*480,1280*720等,一般直播採用640 *480,然後裁剪為640 *360.

      位元速率 : 也叫位元率,資料傳輸時單位時間傳送的資料位數. 可以理解為位元速率決定一幀影象的顯示精細程度.在一定範圍內,位元速率越大,影象越清晰,消耗頻寬或者檔案體積就越大.超過一定範圍後,清晰度不變.一般640 * 480解析度的,位元速率512kbps就能夠保證清晰度.

    • SGVideoConfig

       這個視訊配置的類,主要包括壓縮等級,解析度,位元速率等的配置

    • SGH264Encoder 這個類是編碼器,主要功能是對原始的視訊幀進行編碼壓縮處理,這裡採用的是硬編碼,編碼輸出格式為H264格式.

      編碼 : 編碼是指將原始的幀資料編碼壓縮,編碼後資料更小,方便在網路上傳輸.原始資料體積較大,網路傳輸十分不方便,因此需要將資料壓縮,視訊壓縮演算法當前比較主流的是H264,這裡我們壓縮格式是H264格式.H264有不同的壓縮等級,壓縮等級不同,壓縮比也不同.常見的壓縮等級有:baseline , main , high.

      硬編碼 : 硬編碼是相對軟編碼而言的,一般軟編碼是通過cpu來運算,比較消耗cpu效能,耗時大,但是相容性好,軟編碼一般採用ffmpeg或者x264.相對而言,硬編碼使用gpu來編碼,速度效率很高.這裡採用的是iOS自帶的硬解碼,只支援iOS8以後的系統.

      壓縮後的視訊幀 : 壓縮後的視訊有三種幀型別:I ,B ,P幀,I幀也叫關鍵幀.經過解碼後能夠獨立展示出一幅影象,P幀是前向預測幀,參考前一幀才能解碼顯示出一幅完整的影象.B 為雙向預測幀,必須參考前一幀和後一幀才能解碼出影象.因此,I幀的壓縮比最低,大約為0.7,它只能採用幀內壓縮,P幀壓縮比次之,大概能達到0.5,B幀壓縮比則更高,達到了0.3~0.5,B幀和P幀採用的是幀內壓縮和幀間壓縮技術(也就是運動估計,原理是相鄰幀的影象有一部分是一樣的,專業術語叫空間冗餘).實際上,視訊壓縮等級不同,幀種類也不同,比如baseline等級壓縮後的視訊只有I幀 和 P幀.main等級 和 high等級 則三種幀都包含,它們的整體壓縮比要比baseline要高.但是因為B幀需要參考前一幀和後一幀才能顯示,很容易造成卡頓情況,因為萬一後面的幀沒有獲取到,導致前一幀已也不能顯示,所以在實際應用中(直播app),一般壓縮等級採用baseline.

      gop : 這個我試著描述一下:因為除了I幀,其它幀都不能獨立渲染顯示,理論上只需要一個I幀其它全部是非I幀,這樣壓縮比最高,但是因為(B幀和P幀)參考其他幀的原因會有一定的誤差,當一段時間後,累計誤差會原來越大,導致影象失真.解決辦法就是以一小段為一個單元,每個單元第一幀都是I幀;這樣,即使前面某一小段出了問題也不會影響後面的一小段,每一個小段我們稱作一個關gop.每個gop的第一幀一定是關鍵幀,因為你的沒得參考;通常我們設定gop的大小為1s到3s,因此關鍵幀與關鍵幀之間的間隔就是1s的幀數(對應gop為1s)到3s的幀數(對應gop為3s),根據上面的定義,1s的幀數為fps,因此關鍵幀間隔為1*fps 到 3*fps.秒開的優化點之一就是減小gop大小,因為gop第一幀是關鍵幀,能獨立渲染出來,使用者進入直播間的時間是隨機的,為確保使用者儘快拿到關鍵幀,儘快渲染出影象;同時gop越小,關鍵幀數量就越多,頻寬消耗量就越大.

    • SGH264Packager 這個類負責對已經編碼好的H264幀資料進行打包處理,打包成符合RTMP協議格式的資料,然後才能傳送.

  • 音訊相關類

    • SGAudioSource 這個類主要負責錄製音訊資料,輸出原始音訊幀,音訊的格式為PCM格式.

    • SGAudioConfig 這個類是音訊配置相關的類,主要包括聲道數,位元速率,取樣率的配置.

    • SGAACEncoder 這個類作用是將原始PCM音訊資料進行編碼壓縮,編碼結果為AAC格式的音訊資料,這裡採用的是硬編碼.軟編碼的庫有faac.

    • SGAACPackager 這個了類作用是將編碼後的AAC格式資料大波按成符合RTMP協議的資料.

  • RTMP相關類

    • SGStreamSession這個類主要是用來建立tcp連線,底層資料的讀取和傳送,以及連線狀態的回撥,整個連線狀態貫穿整個專案,十分重要.
    • SGRtmpSession這個類主要與RTMP相關,主要負責與伺服器互動,包括RTMP握手,指令的傳送,對資料的進一步封裝,封裝成訊息,然後再發送.指令有很多,說點重要的,比如握手完成以後,要重新協商訊息大小(預設128位元組),但是128位元組太小,影響效率,一般都稍微改大點,比如這裡設定為16kb,如果太大也不好,會導致頻寬浪費.這個類涉及到rtmp相關的比較多,比較難以理解,網上有開源的實現librtmp這個庫,可以用這個來替代.

以上就是整個專案的基本結構,整個過程類似工廠流水線,可以自行對各個模組進行替換和研究.demo中註釋也不少,方便理解.是不是感覺資訊量有點大?可能有些地方說的不嚴謹,還望大家多多指正哈.

這個專案在去年7月份左右就寫完了,後來加了一些烏七八糟的東西,後來專案掛了,轉戰新專案(還是直播).中間寫過幾篇入門文章,本來打算寫成一個系列文章,無奈太忙了,寫的不完整.新年伊始,趁著專案不太忙,趕緊整理了一下,純碼字,如果有任何問題可以直接留言.

附上學習部落格:

相關推薦

不用第三方一個簡單軟體

 README.md #iOS不用任何第三方,寫一個簡單的RTMP直播推流器 2016年是移動直播爆發年,不到半年的時間內無數移動直播App掀起了全民直播的熱潮。然而個人覺得直播的門檻相對較高,從推流端到服務端器到播放端,無不需要專業的技術來支撐,僅僅推流端就有不少需要學習的知識.目前大部分直播採用的都是

Android用File類一個簡單的檔案管理軟體

一,概要: Android中的File類和JAVA中File類是一樣的,方法也可以去看看java的API(點選檢視)。這裡補充幾點: File file=this.getFilesDir(); //當前應用資料預設的資料儲存路勁:/data/user/0

php利用yield一個簡單中介軟體

yield 協程 1.初識Generator Generator , 一種可以返回迭代器的生成器,當程式執行到yield的時候,當前程式就喚起協程記錄上下文,然後主函式繼續操作,當需要操作的時候,在通過迭代器的next重新調起 function x

linux設備驅動第三篇:一個簡單的字符設備驅動

提示 copy flags 驅動程序 相關 clas open ugo param 在linux設備驅動第一篇:設備驅動程序簡介中簡單介紹了字符驅動,本篇簡單介紹如何寫一個簡單的字符設備驅動。本篇借鑒LDD中的源碼,實現一個與硬件設備無關的字符設備驅動,僅僅操

采用jsp頁面與java代碼分離的方式一個簡單的二維表

color arraylist 一個 3-9 業務 動態顯示 復雜 分層架構 方式 前提:在我們做程序時追求的是高內聚,低耦合,但是如果我們把jsp頁面的的代碼和java的代碼都放在了jsp的代碼編寫中,使java和jsp高耦合這樣的話不僅使jsp代碼頁面顯得很復雜,而

一個簡單的導航

utf-8 mar title shee 小圖標 list .cn display left 制作一個如下圖的導航按鈕。當鼠標移入導航欄的首頁,商店等字體時,前面的小圖標和字顏色一起變紅!代碼如下: <meta charset="UTF-8"> <

python一個簡單的接口

結果 服務 web框架 簡單的 bsp 16px 這樣的 flask span 寫一個接口: 1、用到的模塊是flask,flask是一個python的一個web框架,可以用來開發接口和web頁面 2、 啟動服務的效果是這樣的: 用postman測試的結

一個簡單的JQ插件(例子)

ont ava 兼容 app js代碼 lsp 是把 生成 order 雖然現在 vue angular react 當道啊但是那 JQ還是有一席之地很多很多的小單位啊.其實還會用到我也放一個例子吧雖然我也不是很肯定有沒有人寫的比我更好啊但是我相信 我這個還是蠻實用的 話不

用集合一個簡單的隨機分組,以及集合內元素數量查詢

移除 以及 表示 元素 move spa color 查詢 println 12個人,隨機分為4組 public static void main(String[] args) { List list = new ArrayList();

一個簡單的struts2

return 簡單的 index taglib struts2 text apach prepare mil 導包:struts2-core-2.5.1 寫action類, package web; public class HelloWorldAction {

一個簡單的servlet

打開 lips cli 簡單 找不到 -m 輸入12 右下角 dex 昨天寫完hibernate的小demo後,想寫一個簡單structs2,但是發現好像自己連servlet都忘了怎麽寫了,所以一切從頭開始,先寫一個簡單servlet把 第一步 肯定是建立項目了,打開自己e

一個簡單的配置文件和日誌管理(shell)

客戶端 數據 時間 r+ socket編程 har stdout scan 語言 最近在做一個Linux系統方案的設計,寫了一個之前升級服務程序的配置和日誌管理。 共4個文件,服務端一個UpdateServer.conf配置文件和一個UpdateServer腳本,客戶端一個

一個簡單的python腳本來返回ip地址的掩碼,子網個數等

pypi package 多少 ask pri 1.2 bfc pty rom 如果我們想快速得到一個IP地址段有多少個ip,快速得到IP地址段的子網掩碼,或者快速得到一個IP地址的二進制,那麽可以來學習一下。本文利用python的一個IP分析模塊IPy實現,首先安裝IPy

用python一個簡單的excel表格獲取當時的linux系統信息

psutil 生成 之前 建立 set ces ext 流量 關閉 最近在學習excel表格的制作,順便結合之前學習的內容,利用python的兩個模板,分別是獲取系統信息的psutil,和生成excel表格的xlsxwriter。利用這兩個模板將生成一個簡單的excel表格

一個簡單的form表單,當光標離開表單的時候表單的值發送給後臺

bsp name clas blog var tex txt rip () 1 <body> 2 <form action="index.php"> 3 <input type="text" name="txt" id="txt

用Canvas一個簡單的遊戲--別踩白塊兒

來吧 ber -c [] for 輸入 itl event 內部   第一次寫博客也不知怎麽寫,反正就按照我自己的想法來吧!怎麽說呢?還是不要扯那些多余的話了,直接上正題吧! 第一次用canvas寫遊戲,所以挑個簡單實現點的來幹:別踩白塊兒,其他那些怎麽操作的那些就不用再扯

python學習(8)實例:一個簡單商城購物車的代碼

商品 流程圖 index blog pen 什麽 author 數字 git 要求: 1、寫一段商城程購物車序的代碼2、用列表把商城的商品清單存儲下來,存到列表 shopping_mail3、購物車的列表為shopping_cart4、用戶首先輸入工資金額,判斷輸入為數字5

用shell一個簡單的告警系統

shell用shell寫一個簡單的告警系統 創建目錄結構 mkdir -p /usr/local/sbin/mon/{bin,conf,shares,mail,log} mon //主目錄 bin //主程序目錄 shares //子程序目錄 mail //發郵件目錄 log //日誌目錄 程序主入

一個簡單vue 中間件,$emit、$on

發布-訂閱模式 pre 原理 lse 取出 als new on() 訂閱 前言 使用過vue的同學大多數都知道$emit 與$on的使用。我們僅僅知道使用,有時候是完全不夠的。現在我就帶領大家寫一個簡單類似於vue空實例的中間件。 非父子組件的通信 非父子組件的通信vue

Layui 一個簡單的後臺頁面

觸發 scale item href method pts iframe 都是 rem 參考如下: 1、layui 官方文檔 http://www.layui.com/doc/ 2、https://blog.csdn.net/huyanliang/article/detai