webrtc是一個比較成熟的實時音視訊處理開源專案,一上來老大就扔給我一本webrtc native實踐,雖然狠下心“翻”完了一遍,但是還是雲裡霧裡的,在經過幾個月的摸索之後,我大概知道原因了,歸根到底,是基礎不在一個層次,理解不了的,所以我決定,嘗試寫一個接近我這種零基礎入門實時音視訊的記錄系列,希望能幫到一些同學

基礎概念的理解

實時音視訊是一個很長的流程,從採集-編碼-傳輸-接收-解碼-渲染,每一個步驟都是很大的模組,所以我們一個一個來,我們先從採集相關的設計開始,我們先看一些概念,否則直接看程式碼會有點懵

stream(流):包含音訊軌和視訊軌的編碼流

track(軌道):音訊軌或者視訊軌

音視訊同異點-我的理解

先說幾個點

  • 音訊和視訊還是很多地方不一樣的

    • 音訊採集了,自己不不要同時聽到自己,一般只需要傳輸給對方;一般只有一個採集的地方;即使有多個採集的地方,對方希望聽到是合流之後的一個聲音;
    • 視訊採集了,一般需要同時在己方和對方都渲染顯示出來;可能要多個採集源;一般希望每個視訊源獨立展示(甚至是不同的裝置展示)
  • 音訊和視訊有很多地方是一致的
    • 是同級的概念;整體的處理流程幾乎一致
  • 音訊和視訊輸入和輸出的過程不一樣

整體感覺是視訊的邏輯要比音訊複雜一些,所以下面我主要也是圍繞視訊展開,音訊也會順便說下

視訊程式碼設計

其實這個地方很難真正從零開始,我這裡也是從中間某個點開始說(對著程式碼說自己的理解);結合上面的同異點,我們來看下webrtc裡面的程式碼設計

source和sink

這是我覺得第一個坑的設計,但你理解了之後,覺得這樣設計也沒有問題

聯絡實際場景,攝像頭採集到影象之後,儲存視訊,成為視訊源,編碼和本地渲染需要消費影象做處理,類似於生產和消費的概念

對於消費者,也就是sink來說,如果我想要增加一個消費者,我繼承sink介面,塞到儲存視訊源的例項裡面去,讓例項不斷給我塞資料給我消費即可(onFrame),所以sink的介面定義比較好理解;

source的介面定義裡面只有對sink的操作,這是我覺得一開始不好理解的地方,source並沒有儲存視訊影象(為什麼叫source呢?);我現在的理解是,相對於sink,這樣的介面就可以理解為source(攝像頭採集影象之後,呼叫source的某個介面,這這個接口裡面,對影象資料進行分發給sink,對於sink來說,這個例項就可以理解為source);

videoBroadcaster

broadcaster做的就是我們上面那段話想做的事情

source的介面太簡單了,下面是videoSourceBase的函式定義,還增加了一個sinks的成員來儲存所有的sink成員;

而broadcaster同時繼承了sink和source,這就是我們想做的事情:初始化一個broadcaster例項,增加一個消費者sink的時候,把sink通過broadcaster的source介面存入sinks即可;當採集到影象的時候,把影象按照既定的邏輯呼叫所有sink的介面即可;

webrtc裡面同時是sink又是source的例項還有很多,例如

這是第一個實際概念到程式碼設計的實踐,可以看到,簡單的物理概念想真正用程式碼設計構架起來,還是需要很多抽象設計和構架思考的

source、track、stream

上面說完了整體一個大概念的影象採集之後,採集分發的小流程,這些影象資料source要變成track最後要形成 stream,我們看下這裡的設計,在這些之前,有些更細節的概念也要考慮到,例如音視訊發生了變化需要通知觀察者

所以首先定義了觀察者介面和通知者介面,都是很純粹的介面定義

而通知者的繼承關係則很長,通知介面有三個繼承者MediaSourceInterface,MediaStreamTrackInterface,MediaStreamInterface,基本source、track、stream都是通知者

MediaSourceInterface

定義了媒體源的基本狀態,媒體大類有兩個,音訊和視訊,所以有兩個繼承者VideoTrackSourceInterface,AudioSourceInterface,上面也說到過,音視訊細節上有些差異,從這裡的介面設計可以看到一些

AudioSourceInterface

AudioSourceInterface的介面,例如音量這些,都是音訊獨有的

VideoTrackSourceInterface

因為之前已經定義了VideoSourceInterface,所以這裡直接到了videoTrackSource的定義

從audio和video兩個繼承來看,這裡的分化挺明顯的

MediaStreamTrackInterface

track的定義和繼承如下,定義了trackState和必要介面;同時可以看到有音視訊track兩個子介面

videoTrack

audioTrack和VideoTrack有一個不一樣的地方是,audioTrack只是組合了audioSource,videoTrack還繼承了videoSource,我理解這是因為視訊的來源和分發比音訊複雜,因為所有的音訊可能最後會匯聚成一個,是多個視訊源可能需要分發和處理到不同的地方;

MediaStreamInterface

最後繼承Notifier的是MediaStreamInterface,可以看到,stream是videoTrack和audioTrack的組合

好了,今天就先寫到這裡,後面應該會持續更新

p