無線端的彈幕實現方案

xiaoqb發表於2016-05-27

TB1ugdZKXXXXXbRXpXXXXXXXXXX-900-500.jpg

前段時間做了遊戲的相關業務,其中彈幕相關的內容自成一塊。彈幕已經不只是最初的視訊彈幕了,戰火已經燒到了評論區,燒到了手機淘寶的首頁搜尋結果。作為一種近幾年迅速燃起的內容呈現形式,有必要適時引入,對於休閒化、娛樂化的業務更是如此。那麼,要做出一個較為完整的彈幕效果來,需要哪幾個部分呢?尤其是,在集團內部,怎麼快速地搭建起一個可用的彈幕框架來?本文分3塊來闡述。

  1. 彈幕渲染層
  2. 彈幕資料通道
  3. 彈幕服務邏輯

彈幕渲染層

目前彈幕的呈現載體主要是Web、無線客戶端。因為我們的工作主要針對無線端,所以本文主要以無線端為例——包括iOS,Android兩類系統。

碰撞檢測

彈幕無非是動畫,是分佈在時間軸上影像的連續運動。自然可以用Native的動畫來實現。不過彈幕動畫有一個重要的特徵,即保持動畫元素(sprites)儘可能少地碰撞,以使彈幕承載的資訊能夠清晰地傳達,執行碰撞檢測是必須的。但彈幕裡的碰撞檢測相對簡單,因為彈幕的運動軌跡相對簡單並且容易預測,所以只需要在一條彈幕將要顯示之前,根據已經顯示的彈幕(位置、速度、活躍的時間等)來確定他的運動軌跡。以盡最大可能地在其生命週期內不與已有彈幕衝突。

彈幕碰撞檢測範例

彈幕的同步問題

彈幕不是超然而獨立的,往往相伴業務場景而生,目前可見最多的場景是視訊,直播或者錄播皆有。到此時則涉及到一個時間同步的問題。比如,一位使用者在看一段時間第314s的時候突然有感而發,發出了一條彈幕,自然希望其他觀眾能夠在看到視訊此刻看到他的彈幕。所以一條彈幕上屏的時間是需要明確的,想想那些年文不對題的字幕君吧。那麼,如何實現呢?一般,可以為一條彈幕提供一個時間點delay,當到了這個時刻,由控制器把這條彈幕播放出去。但僅僅這些是不夠的,因為視訊還存在暫停,存在快進快退,所以你必須也為彈幕元件提供類似的介面,以期能和視訊內容同步。其他的應用場景也是類似的。比如下面的樣子(彈幕在向左運動):

彈幕的樣式

彈幕的運動樣式主要有兩種,一種是橫向的過場彈幕,一種是縱向的浮動彈幕。彈幕的內容形式不外乎一段文字或者圖片,其中以文字為主。對於文字,則有文字的顏色、背景、字型、邊框等屬性,這一切必須是靈活可配的。當然實際應用中一個APP需要的是風格統一的、優雅美觀的彈幕動畫。所以彈幕的方向不要太混亂,不要有太多不一樣的主題配置。你可以定義幾類色調協調但樣式不同的彈幕,然後由業務程式碼決定使用哪一種風格的彈幕。

渲染效率

效能直接關係到使用者體驗。在絕大多數場景中,錦上添花的彈幕往往伴隨著具體的業務邏輯,業務邏輯會佔用CPU——甚至很高的CPU,比如視訊解碼———所以彈幕動畫應該儘可能地使用GPU渲染。為應對線上可能的大規模彈幕的情況,本地最好也能測試到大量彈幕的情況。可以使用一個定時器,模擬客戶端頻繁接受渲染彈幕的情況,看看實際中彈幕的效能究竟如何。

限流

彈幕稀稀疏疏地鋪滿半屏視窗,朦朧中猶抱琵琶半遮面的感覺,自然是最好的。但萬一遇到彈幕決堤,內容瘋狂湧來,那當如何應對?渲染內容層層堆疊,既看不清,又降低了系統應用效能,為此可以在業務或者元件中選擇限流。

彈幕資料層

若不考慮彈幕在使用者間共享,只需下圖左側的模組即可;若需引入彈幕共享、儲存功能,則如下圖右側所示。

簡要結構圖

但實際情況往往比這複雜。彈幕很多時候是實時的,最好使用長連線來傳輸資料。業務導向的專案,很少從零開始開發專門的彈幕服務通道,而是儘可能地應用已有的服務元件。淘寶在長連通道上有多個選擇,但其功能又是不盡相同的。這種不同也會帶來彈幕實現方案的不同。比如通道A支援訂閱功能,訊息會根據訂閱關係分發;而通道B是單純的通道,訂閱關係由業務方維護,凡是傳送到客戶端的訊息都會接收,所以流量需要業務服務端來控制。

經過服務端的必要性

僅僅使用長連線通道是不夠的,還需引入業務伺服器,其原因如下:

  • 如果長連通道不支援客戶端傳送訊息,那麼彈幕的傳送要走其它的介面
  • 因業務原因,需要統一多個長連線通道,以便更好地做 多端同步,故引入中間伺服器做協調
  • 一些業務相關的需求,不適合在長連線伺服器上做,比如內容過濾、彈幕儲存、服務端限流等

整體的資料流如下圖所示:

詳細結構圖

訊息格式制定

通過長連線傳輸的彈幕訊息會有一些附加資料需要考慮,比如彈幕的樣式、出現的時間,隨著業務的擴充套件,可能需要更多的輔助欄位。所以彈幕訊息必須能夠向後相容,一般可設定為message,version兩個欄位,message為純粹的json字串,version表示訊息的版本號。先解析version,根據判斷得到的version選擇響應的解析樣式。太多的附加資訊會降低資料的利用率,此是需要權衡的地方。當然,如果針對的是線上視訊業務,彈幕的流量相比於視訊流而言,就顯得不那麼重要了。

自發的彈幕訊息

主要有兩種:

  1. 使用者傳送了彈幕訊息後,通過網路傳送訊息的同時直接將彈幕資料上屏,以提升使用者所見即所得的體驗;當收到相同的彈幕訊息後,將訊息拋棄。
  2. 使用者傳送了彈幕訊息後,通過正常的網路接收訊息然後渲染呈現,這樣會因延時損失一定的使用者體驗,但邏輯簡單,並且可以控制所有彈幕資料。

彈幕服務層

主題維護

主題代表彈幕訊息圍繞的中心。在不同的業務場景中,主題的呈現方式可能是不同的。在視訊直播業務中,主題代表了一個個直播房間,彈幕圍繞著視訊展開;在新聞諮詢業務中,主題代表了一則則新聞,彈幕圍繞著新聞展開。客戶端與主題存在多對一的關係,如下圖所示:

主題房間維護

使用者U1、U2訂閱了主題T1,使用者U3、U4訂閱了主題T2。由於處於不同的語境中,U1、U2傳送的彈幕U3、U4應該是不能接收到的,反之亦然。很自然服務端需要維護一個使用者到主題的對映表簡單的實現是,客戶端監測到使用者進入特定主題之後,傳送一條網路請求登記這樣一條訂閱;使用者離開特定主題時傳送網路請求登出登記。但由於實際客戶端執行場景複雜,離開特定主題不一定來得及傳送網路請求。補充方案是,由客戶端每隔特定時間心跳一次,用以告知服務端維護對映表。一旦服務端一段時間沒有監聽到心跳資訊,就取消對映表中的一條訂閱。這裡需要注意的是,服務端需要防止心跳的偽造,否則可能對映表可能會因攻擊而混亂掉。一旦對映表正確建立,使用者傳送的彈幕訊息就可以準確傳達到相同主題的使用者客戶端了。

彈幕儲存

對於直播等即時性業務,彈幕資料一般沒有重播的必要;但是對於錄播,則需要持久化彈幕,如是方能在其他使用者看視訊的時候看到其他人發出過的彈幕訊息。持久化這類彈幕資料,必須在儲存彈幕的時候帶上彈幕對應的時間點。在使用者進入了某一主題之後,批量返回給客戶端對應的彈幕資料,由客戶端將彈幕資料對應到視訊業務響應的時間點上;如果此主題對應的彈幕資料很多,服務端可能實現做一定的篩選;對於錄播同時新傳送的彈幕,則由服務端記錄並新增到對應的彈幕資料列表中。

轉載自:http://taobaofed.org/blog/2016/05/13/barrage-in-mobile/

作者:拂銘


相關文章