帶你實現完整的 iOS 視頻彈幕系統

2021-02-24 知識小集

彈幕誕生於日本的視頻平臺,後來被B站這種短視頻平臺引入到國內,並在國內發展壯大。後來逐漸被長視頻平臺所接受,現在視頻相關的應用基本上都會有彈幕。

但是長視頻彈幕和B站這類的短視頻彈幕還不太一樣,短視頻平臺有自己特有的彈幕文化,所以彈幕更注重和用戶的互動。長視頻平臺還是以看劇為主,彈幕類似於評論的功能,所以不能影響用戶看劇,彈幕不能太密集,而且相互之間最好不要有遮蓋,否則會對視頻內容會有比較明顯的影響。

本篇文章主要從長視頻平臺的角度來講彈幕的實現原理,但其實短視頻平臺的彈幕也是同樣的原理,區別在於短視頻可能彈幕種類會多一些。

畫布

以我公司應用為例,有iPhone和iPad兩個平臺,在iPhone平臺上有橫豎屏的概念,都需要展示彈幕。在iPad上有大小屏的概念,也需要都展示彈幕。彈幕的技術方案肯定是兩個平臺用一套,但需要考慮跨不同設備和屏幕的情況。

所以,對於這個問題,我通過畫布的概念來解決通用性的問題。畫布並不區分屏幕大小和比例的概念,只是單純的用來展示彈幕,並不處理其他業務邏輯,通過一個Render類來控制畫布的渲染。對於不同設備上的差異,例如iPad字體大一些,iPhone字體小一些這種情況,通過config類來進行控制,畫布內部不做判斷。

小屏上畫布會根據比例少展示一些,大屏上則多展示一些。字體變大畫布也會根據比例和左右間距進行控制,保證展示比例是對的,並且在屏幕寬高發生改變後,自動適應新的尺寸,不會出現彈幕銜接斷開的問題,例如iPad上大小屏切換。外部在使用時,只需要傳入一個frame即可,不需要關注畫布內部的調整。

彈幕軌道

從屏幕上來看,可以看到彈幕一般都是一行一行的。為了方便對彈幕視圖進行管理,以及後續的擴展工作,我對彈幕設計了「軌道」的概念。每一行都是一個軌道,對彈幕進行橫向的管理,這一行包括速度、末端彈幕、高度等參數,這些參數適用於這一行的所有彈幕。軌道是一個虛擬的概念,並沒有對應的視圖。

軌道有對應的類來實現,類中會包含一個數組,數組中有這一行所有的彈幕。這個思路有點像玩過的一款遊戲-節奏大師,裡面也有音樂軌道的概念,每個軌道上對應不同速度和顏色的音符,音符數量也是不固定的,根據節奏來決定。

軌道還有一個好處在於,對於不同速度的彈幕比較好控制。例如騰訊視頻的彈幕其實是不同速度的,但是你仔細觀察的話,可以發現他們的彈幕是「奇偶行不同速」,也就是奇數行一個速度,偶數行一個速度,讓人從感官上來覺得所有彈幕的速度都不一樣。如果通過軌道的方式就很好實現,不同的軌道根據當前所在行數,對發出的彈幕設置不同的速度即可。

有時候看視頻過程中會從右側出現一條活動彈幕,可能是視頻中的梗,也可能是類似於廣告的互動。但是活動彈幕出現時一般是單行清屏的,也就是和普通彈幕是互斥的,展示活動彈幕的時候前後沒有普通彈幕。這種通過軌道的方式也比較好實現,每條彈幕都對應一個時間段,根據活動彈幕的時間和速度,將活動彈幕展示的前後時間,將這段時間軌道暫時關閉,只保留活動彈幕即可。

輪詢

每條彈幕都對應著一個展示時間,所以需要每隔一段時間就找一下有沒有需要展示的彈幕。我設計的方案是通過輪詢,來驅動彈幕展示。

通過CADisplayLink來進行輪訓,將frameInterval設置為60,即每秒輪詢一次。在輪詢的回調中查找有沒有要展示的彈幕,有的話就從上到下查找每條軌道,某條軌道有位置可以展示的話就交給這條軌道展示,如果所有軌道都有正在展示的彈幕,則將此條彈幕丟棄。是否有位置是根據屏幕最右側,最後一條彈幕是否已經展示完全,並且後面有空餘位置來決定的。

對於取數據的部分,數據和視圖的邏輯是分離的,相互之間並沒有耦合關係。取數據時只是從一個很小的字典中,根據時間取出所用的彈幕數據,並轉化為model。字典的數據很少,最多十秒的數據,而且這裡並不會接觸到讀資料庫的操作,也沒有網絡請求的邏輯,這些都是獨立的邏輯,後面會講到。

彈幕視圖

經常看視頻的同學應該會知道,彈幕的展示形式有很多,有帶明星頭像的、有帶點讚數的、帶矩形背景色的,很多種展示形態。為了更好的對視圖進行組織,所以我採用的就是很普通的UIView的展示形式,並沒有為了性能去做很複雜的渲染操作。

用UIView的好處主要就是方便做布局和子視圖管理,但在屏幕上做動畫時,是對CALayer進行渲染的。也就是說UIView就是用來做視圖組織,並不會直接參與渲染,這也符合蘋果的設計理念。

復用池

彈幕是一個高頻使用的控制項,所以不能一直頻繁創建,以及添加和移除視圖,會對性能有影響。所以就像很多同學設計的模塊一樣,我也引入了緩存池的概念,我這裡叫復用池。

彈幕復用池和UITableView的復用池類似,離開屏幕的彈幕會被放在復用池中等待覆用,下次直接從復用池中取而不重新創建。彈幕視圖做的工作就是接收新的model對象,並根據彈幕類型進行不同的視圖布局。

並且彈幕只會在創建時被addSubview一次,當彈幕離開屏幕不會被從父視圖移除,這樣彈幕從復用池中取出時也不需要被addSubview。當動畫執行完成後,彈幕就直接留在動畫結束的位置,下次做動畫時彈幕會自動回到fromValue的位置。實際上視圖結構就如上圖所示,灰色區域就是可視區域。

系統彈幕

在視頻剛開始時會有引導信息,比如引導用戶發彈幕,或者提示彈幕有多少條,這個我們叫做系統彈幕。系統彈幕一般是展示到屏幕中間時,才開始展示後續彈幕。但是要精確的計算到彈幕到達屏幕中間,然後再展示後續彈幕,這種的採用清除前後特定時間段的彈幕就不太精確,所以我們採用的是另一套實現方案。

系統彈幕的實現是通過一個更高精度的CADisplayLink進行輪詢檢測,也就是把frameInterval設置的更小,我這裡設置的是10,也就是每秒檢測六次。但是進行檢測時不能直接用CALayer進行判斷,需要使用presentationLayer也就是屏幕上正在展示的layer進行檢測,通過這個layer獲取到的frame和屏幕上顯示的才是一致的。

這裡簡單介紹一下CALayer的結構,我們都知道UIView是對CALayer的一層封裝,實際上屏幕上的顯示都是通過layer來實現的,而layer本身也分為以下三層,並有不同的功能。

presentationLayer,其本身是當前幀的一個拷貝,每次獲取都是一個新的對象,和動畫過程中屏幕上顯示的位置是一樣的。modelLayer,表示layer動畫完成後的真實值,如果列印一下modelLayer和layer的話,發現二者其實是一個對象。renderLayer,渲染幀,應用程式會根據視圖層級,構成由layer組成的渲染樹,renderLayer就代表layer在渲染樹中的對象。炫彩彈幕

在播放彈幕的過程中,我們可以看到有漸變顏色的彈幕,我們叫做「炫彩彈幕」。這種彈幕有一個很明顯的特徵,就是其顏色是漸變的。這時候要考慮性能的問題,因為播放高清視頻時本身性能消耗就很大,在彈幕量比較大的情況下,會造成更多的性能消耗,所以減少性能消耗就是很重要的,漸變彈幕可能會使性能消耗加劇。

對於漸變文字,一般都是通過mask的方式實現,下面放一個CAGradientLayer做漸變,上面蓋一個文字的layer。但是這種會觸發離屏渲染,會導致性能下降,並不能用這種方案。經過我們的嘗試,決定用設置漸變文字顏色的方式解決。

CGFloat scale = [UIScreen mainScreen].scale;
UIGraphicsBeginImageContextWithOptions(imageSize, NO, scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGColorSpaceRef colorSpace = CGColorGetColorSpace([[colors lastObject] CGColor]);
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)ar, NULL);
CGPoint start = CGPointMake(0.0, 0.0);
CGPoint end = CGPointMake(imageSize.width, 0.0);
CGContextDrawLinearGradient(context, gradient, start, end, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGGradientRelease(gradient);
CGContextRestoreGState(context);
UIGraphicsEndImageContext();

實現方式就是先開闢一個上下文,用來進行圖片繪製,隨後對上下文進行一個漸變的繪製,最後獲取到一個UIImage,並將圖片賦值給UILabel的textColor即可。

從離屏檢測來看,並未發生離屏渲染,fps也始終保持在一個很高的水平。

暫停和開始

彈幕是隨視頻播放和暫停的,所以需要對彈幕提供暫停和繼續的支持,對於這塊我採用的CAMediaTiming協議來處理,可以通過此協議對動畫的過程進行控制。

代碼中加0.05是為了避免彈幕在暫停時導致的回跳,所以加上一個時間差。具體原因是因為通過convertTime:fromLayer:方法計算得到的時間,和屏幕上彈幕的位置依然存在一個微弱的時間差,而導致渲染時視圖位置發生回跳,這個0.05是一個實踐得來的經驗值。

- (void)pauseAnimation {
    // 增加判斷條件,避免重複調用
    if (self.layer.speed == 0.f) {
        return;
    }
    CFTimeInterval pausedTime = [self.layer convertTime:CACurrentMediaTime() fromLayer:nil];
    self.layer.speed = 0.f;
    self.layer.timeOffset = pausedTime + 0.05f;
}

- (void)resumeAnimation {
    // 增加判斷條件,避免重複調用
    if (self.layer.speed == 1.f) {
        return;
    }
    CFTimeInterval pausedTime = self.layer.timeOffset;
    self.layer.speed = 1.0;
    self.layer.timeOffset = 0.0;
    self.layer.beginTime = 0.0;
    CFTimeInterval timeSincePause = [self.layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
    self.layer.beginTime = timeSincePause;
}

CAMediaTiming協議是用來對動畫過程控制的一個協議,例如通過CoreAnimation創建的動畫,CALayer遵守了這個協議。這樣如果需要對動畫進行控制的話,不需要引用一個CABasicAnimation對象,然後再修改動畫屬性這種方式對動畫流程進行控制,只需要直接對layer的屬性進行修改即可。

下面是CAMediaTiming協議中一些關鍵的屬性,在上文中也用到了其中的部分屬性。

beginTime,動畫開始時間,可以控制動畫延遲展示。一般是一個絕對時間,為了保證準確性,最好先對當前layer進行一個轉換,延遲展示在後面加對應的時間即可。speed,動畫執行速度,默認是1。動畫最終執行時間=duration/speed,也就是duration是3秒,speed是2,最終動畫執行時間是1.5秒。timeOffset,控制動畫進程,主要用來結合speed來對動畫進行暫停和開始。repeatCount,重複執行次數,和repeatDuration互斥。repeatDuration,重複執行時間,如果時間不是duration的倍數,最後一次的動畫會執行不完整。autoreverses,動畫反轉,在動畫執行完成後,是否按照原先的過程反向執行一次。此屬性會對duration有一個疊加效果,如果duration是1s,autoreverses設置為YES後時間就是2s。fillMode,如果想要動畫在開始時,就停留在fromValue的位置,就可以設置為kCAFillModeBackwards。如果想要動畫結束時停留在toValue的位置,就設置為kCAFillModeForwards,如果兩種都要就設置為kCAFillModeBoth,默認是kCAFillModeRemoved,即動畫結束後移除。插入彈幕

現在彈幕一般都會結合劇中主角,以及各種文字顏色讓你去選擇,通過這些功能也可以帶來一部分付費用戶。當發送一條彈幕時,會從上到下查找軌道,查找軌道時是通過presentationLayer來進行frame的判斷,如果layer的最右邊不在屏幕外,並且距離右側屏幕還有一定空隙,項目中寫的是10pt,則表示有空位可以插入下一條彈幕,這條彈幕會被放在這條軌道上。

如果當前軌道沒有空位置,則從上到下逐條查找軌道,直到找到有空位的軌道。如果當前屏幕上彈幕較多,所有軌道都沒有空位,則這一條彈幕會被拋棄。

如果是自己發的彈幕,這個是必須要展示出來的,因為用戶發的彈幕要在界面上給用戶一個反饋。對於自己發的彈幕,會有一個插隊操作,優先級比其他彈幕都要高。自己發的彈幕並不入本地資料庫,只是進行一個網絡請求傳給伺服器,以及在界面上進行展示。

選擇角色

在上面的圖片中可以看到,文本之前會有角色和角色名,這些都是獨立於輸入文字之外的。用戶如果刪除完輸入的文字之後,再點擊刪除要把角色也一起刪除掉。輸入框頁面構成是一個UITextField,左邊的角色頭像和角色名是一個自定義View,被當做textField的leftView來展示。如果刪除的話就是將leftView置nil即可。

問題在於,如果使用UIControlEventEditingChanged的事件,只能獲取到文本發生變化時的內容,如果輸入框的文字已經被刪完,而角色是一個leftView,但由於文本已經為空,則無法再獲取到刪除事件,也就不能把角色刪除掉。

對於這個問題,我們找到了下面的協議來實現。UITextField遵守UITextInput協議,但UITextInput協議繼承自UIKeyInput協議,所以也就擁有下面兩個方法。下面兩個方法分別在插入文字,以及點擊刪除按鈕時調用,即使文本已經為空,依然可以收到deleteBackward的回調。在這個回調裡就可以判斷文本是否為空,如果為空則刪除角色即可。

@protocol UIKeyInput <UITextInputTraits>
@property(nonatomic, readonly) BOOL hasText;
- (void)insertText:(NSString *)text;
- (void)deleteBackward;
@end

參數調整

彈幕一般都不是一種形態,很多參數都是可以調整的,對於iPhone和iPad兩個平臺參數還不一樣,調整範圍也不一樣。這些參數肯定是不能放在業務代碼裡進行判斷的,這樣各種判斷條件散落在項目中,會導致代碼耦合嚴重。

對於這個問題,我們的實現方式是通過BarrageConfig來區分不同平臺,將兩個平臺的數值差異都放在這個類中。業務部分直接讀取屬性即可,不需要做任何判斷,包括退出進程的持久化也在內部完成,這樣就可以讓業務部分使用無感知,也保證了各個類中的數值統一。

當有任何參數的改動,都可以對BarrageConfig進行修改,然後調用Render的layoutBarrageSubviews進行渲染即可。因為調整參數之後,屏幕上已經顯示的彈幕也需要跟著變,而且變得過程中還是在動畫執行過程中,動畫執行不能斷掉,所以對動畫的處理就很重要。這部分處理起來比較複雜,就不詳細講了。

點讚

彈幕還會有點讚和長按的功能,點讚一般是點擊屏幕然後出現一個選擇視圖,點擊點讚後有一個動畫效果。長按就是選中一個彈幕,識別到手勢長按之後,右側出現一個舉報頁面。

這兩個手勢我用tap和longPress兩個手勢來處理,並給longPress設置了一個0.2s的識別時間,將這兩種手勢的識別交給系統去做,這樣也比較省事。

這兩個手勢都加到Render上,而不是每個彈幕視圖對應一個手勢,這樣管理起來也比較簡單。這樣在手勢識別時,就需要先找到手勢觸摸點,再根據觸摸點查找對應的彈幕視圖,查找的時候依然通過presentationLayer來查找區域,而不能用視圖做查找。

- (void)singleTapHandle:(UITapGestureRecognizer *)tapGestureRecognizer {
    CGPoint touchLocation = [tapGestureRecognizer locationInView:self.barrageRender];
    __block BOOL barrageLiked = NO;
    weakifyself;
    [self enumerateObjectsUsingBlock:^(SVBarrageItemLabelView *itemLabel, NSUInteger index, BOOL *stop) {
        strongifyself;
        if ([itemLabel.layer.presentationLayer hitTest:touchLocation] && barrageLiked == NO) {
            barrageLiked = YES;
            [self likeAction:itemLabel withTouchLocation:touchLocation];
            *stop = YES;
        }
    }];
}

廣告

對於這麼好的一個展示位置,廣告部門必然不會放過。在視頻播放過程中,會根據金主爸爸投放要求,在指定的時間展示一個廣告彈幕,並且這個彈幕的形態還是不固定的。也就是說大小、動畫形式都不能確定,而且這條彈幕還要在最上層展示。

對於這個問題,我們採用的方案是,給廣告專門留了一個視圖,視圖層級高於Render,在初始化廣告SDK的時候傳給SDK,這樣就把廣告彈幕的控制交給SDK,我們不做處理。

圖層管理

播放器上存在很多圖層,播控、彈幕Render、廣告之類的,看得到的和看不到的有很多。對於這個問題,播放器創建了一個繼承自NSObject的視圖管理器,這個視圖管理器可以對視圖進行分層管理。

播放器上的視圖,都需要調用指定的方法,將自己加到對應的圖層上,移除也需要調用對應的方法。當需要調整前後順序時,修改定義的枚舉即可。

前面一直說的都是視圖的部分,沒有涉及數據的部分,這是因為UI和數據其實是解耦和的,二者並沒有強耦合,所以可以單獨拿出來講。數據部分的設計,類似於播放器的local server方案,將請求數據到本地,和從本地讀取數據做了一個拆分。

請求數據

彈幕數據量比較大,肯定是不能一次都請求下來的,這樣很容易造成請求失敗的情況。所以這塊採取的是五分鐘一個分片數據,在當前的五分鐘彈幕快播完的前十秒,開始請求下一個時間段的彈幕。如果拖動進度條,則拖動完成後開始請求新位置的彈幕。在每次請求前都會查一下庫,數據是否已存在。

請求數據由業務部分驅動,請求數據後並不會直接拿來使用,而是存入本地資料庫,這部分比較像伺服器往本地寫ts分片的操作。資料庫存儲的部分,推薦使用WCDB,彈幕這塊主要都是批量數據處理,而WCDB對於批量數據的處理,性能高於FMDB。

取數據

取數據同樣由業務層驅動,為了減少頻繁進行資料庫讀寫,每隔十秒鐘進行一次資料庫批量讀取,並轉換為model返回給上層。彈幕模塊在內存中維護了一個字典,字典以時間為key,數組為value,因為同一時間可能會有多條彈幕。

從資料庫批量獲取的數據會被保存到字典中,上層業務層在使用數據時,都是通過字典來獲取數據,這樣也實現了數據層和業務層的一個解耦和。上層業務層每隔一秒從字典中讀取一次數據,並通過數據找到合適的軌道,將數據傳給合適的軌道來處理。

現在很多視頻網站都上線了彈幕防遮擋方案,對於視頻中的人物,彈幕會在其下方展示,而不會遮擋住人物。還有的應用針對彈幕遮擋進行了新的探索,即成為付費會員後,可以選擇只有自己喜歡的愛豆不被遮擋,其他人依然被遮擋。

語義分割

根據業務場景我們分析,首先需要把人像部分分割出來,獲取到人像的位置之後才能做後續的操作。所以人像分割的部分採取語義分割的方式實現,提前對視頻關鍵幀進行標註,這個工作量是很龐大的,所以需要一個專門的標註團隊去完成。根據標註後的模型,通過機器學習的方式,讓計算機可以準確的識別出人的位置,並導出多邊形路徑。

這裡面還涉及一個問題,就是近景識別和遠景識別的問題,機器進行識別時只需要識別近景人物,遠景人物並不需要進行識別,否則彈幕展示效果會受到很大影響。語義分割可以通過Google的Mask_RCNN來實現。

客戶端實現方案

客戶端的實現方案是通過人像的多邊形路徑,對原視頻摳出人像並導出一個新的視頻。在播放的時候實際上是前後兩個播放器在播放,彈幕夾在兩個播放器中間來實現的。並且前面的人像層需要做邊緣虛化,讓彈幕的過渡顯得自然些,否則會太突兀。

這種方案的過渡效果會好一些。因為對每一幀視頻進行切割的時候,每一幀並不能保證相鄰幀切割的邊緣相差都不大,也就是相鄰近的幀邊緣不能保證很好的銜接,這樣就容易出現視頻連續性的問題。前後兩個播放器疊加的方案,兩個層的視頻內容實際上是銜接很緊密的,把彈幕層去掉你根本看不出來這是兩層播放器,所以連續性的問題就不明顯了。

前端實現方案

前端的實現方案是服務端將多邊形路徑放在一個svg文件中,並將文件下發給前端,前端通過css的mask‑image遮罩實現的。通過遮罩把人像部分摳出來,人像之外依然是黑色區域,黑色是可顯示區域,和iOS的mask屬性類似。

B站是最開始做彈幕防擋的,現在B站已經不局限於真人彈幕防擋了,現在很多番劇中的動漫人物也支持彈幕防擋。可以看下面的視頻感受一下。

B站番劇彈幕防擋視頻連結:https://www.bilibili.com/video/BV1Db411C7hJ

相關焦點

  • 杜小尚帶你逛展覽 你還在發彈幕吐槽?而藝術家已經把彈幕搬進了美術館!2333333333
    Transformers: The Premake, 2014Chinese / English, Color, Sound, 16:9, HD video 25』03』』李啟萬「變形金剛:預製作」  2014中英文 彩色高清16:9 影像25』03』』自AB兩站(註:指目前主流兩大彈幕視頻網站
  • 沒有彈幕,我看視頻做什麼
    你喜歡彈幕嗎?你是如何看待彈幕的呢?是影響了你的觀看體驗?還是能夠讓你從中體會到一些明悟或感動?
  • 彈幕到底好玩在哪裡??
    採納彈幕系統的在線平臺可以實現用戶與用戶之間的嵌入式互動,彈幕評論可以和視頻時間軸實現同步,評論內容可以嵌入視頻當中。
  • 用Python爬取B站、騰訊視頻、芒果TV和愛奇藝視頻彈幕
    ↑↑↑關注後"星標"簡說PythonOne old watch, like brief python大家好,我是老表~今天和大家分享的內容是爬蟲相關,帶你爬取四大視頻播放平臺的海量彈幕數據,學習了記得點讚、留言、轉發,三連哦~眾所周知,彈幕,即在網絡上觀看視頻時彈出的評論性字幕。
  • 前端實現彈幕效果的方法總結(包含css3和canvas的實現方式)
    css3實現乞丐版的彈幕css3彈幕性能優化canvas實現彈幕canva彈幕的擴展功能1. css3實現乞丐版的彈幕(1)如何通過css3實現彈幕首先來看如何通過css的方法實現一個最簡單的彈幕:首先在html中定義一條彈幕的dom結構:<div>我是彈幕</div>
  • 彈幕實名制要來了,關於彈幕,那些你不知道的事兒
    一般來說,彈幕在我眼中可以分為以下幾類。第一類,無聊型彈幕,例如「哈哈哈哈哈哈」、「23333」。這類彈幕可能是對視頻某個場景某個演員表達個人喜愛之情,但此類多到可以覆蓋整個屏幕,而看不到真正視頻的內容。一般我會下意識地用「關鍵詞」屏蔽此類彈幕。第二類,挑事類彈幕,例如「他/她長得好像XXX」「抱走我家XXX,某家是XXX」。
  • 「沙發、座機畫質、考古視頻」……原來外國網友也愛這些彈幕
    作者:雙語君本文來源:中國日報雙語新聞(Chinadaily_Mobile)文章已獲授權彈幕和評論早已成了看視頻的「佐餐必備」。要是彈幕不夠會「養肥了」再來看;刷完視頻也不會退出,左滑進去評論區看看網友的才華巧思。此前我們做過B站的彈幕專題,提到了彼時特別火的彈幕如「爺青回」、「yyds(永遠的神)」等。
  • 聊聊高並髮長連接架構:百萬在線的美拍直播彈幕系統如何實現
    導讀:直播彈幕是直播系統的核心功能之一。如何迅速作出一個有很好擴展性的彈幕系統?如何應對業務迅速發展?相信很多工程師/架構師都有自己的想法。
  • 原來日本媒體是這樣評價A站B站的彈幕,你服不服?
    為此,中國的宅人早就習慣了一邊看字幕一邊看視頻的行為,所以對於彈幕出現在視頻上也不會產生特別強的牴觸情緒。漢字本身就非常適合做成字幕,例如在字幕當中可以包含很多的信息量,並且也非常容易讓人通過肉眼進行識別。
  • WWDC 2019匯總,iOS 13系統,原生壁紙下載
    今年的WWDC 大會,亮點多多,給大家匯總一下昨晚的消息,主要內容有:最新iOS 13 系統。全新iPad OS 系統。watchOS 6macOS Catalina全新Mac Pro下面簡單給大家介紹一下。
  • B站彈幕都倒著飛了… 為什麼YouTube上還沒有彈幕呢?
    說起彈幕文化,「彈幕」最初其實是個炮兵術語,在軍事裡指集中火力攻擊某一區域。隨著媒體技術的發展,一些視頻播放網站開發了即時評論功能,由於這些即時評論在視頻播放器上飛過去的效果就像子彈一樣,「彈幕」一詞才被沿用到這個場景下。
  • Pakku高能進度條,彈幕合併器,提升嗶哩嗶哩彈幕體驗
    彈幕復讀終結者!瞬間合併B站的刷屏彈幕,還你清爽的彈幕體驗。Bilibili名場面彈幕合併
  • [彈幕]視頻網站<( ̄ ﹌  ̄)>
    再問自殺」or「愛的自殺,再問供養」「祥瑞玉兔,家宅平安」 or 「羊踹玉兔,玉兔喊疼」 再or 「羊踹玉兔,一秒八腳」……對啦!我還是強行解釋一下吧:bilibili彈幕視頻網站,現為國內最大的年輕人潮流文化娛樂社區,該網站於2009年6月26日創建,又稱「B站「。
  • 2333333-彈幕,彈幕的正確打開方式!
    來,感受一下——截圖來自Bilibili.com,【局長 / 白鼠】比利香不奇怪,對於彈幕的詬病主要集中在視覺上的混亂對觀賞造成的幹擾和內容的良莠不齊上。一方面,如果你選擇開啟彈幕,過分的彈幕厚度自然會對用戶的注意力造成幹擾,乃至完全覆蓋觀賞內容,甚至彈幕評論之間互相擁擠造成了彈幕本身的閱讀障礙,這也是為什麼在土豆網剛剛引入彈幕時,一大堆人都在刷「**,都閉嘴,擋住我看視頻了」「我去***這玩意哪關啊」。
  • 高難度的十級彈幕!你都能看懂嗎?
    馬子俊是一個什麼剛出道的新明星?別想了,你的答案都不對,進來看正解吧。彈幕彈(dàn)幕(Bullet Curtain)起源於日本,表示炮彈(dàn)一樣的評論(吐槽)充斥屏幕。彈幕(barrage)的本義是軍事術語,指用大量或少量火炮進行密集炮擊,後STG射擊遊戲中密集的子彈幕(Bullet Curtain)被稱為彈幕,進而在形式上類似的直接顯現在視頻上的流動評論也被稱作彈幕。
  • 關注 | 發這樣的彈幕,你的良心不會痛嗎?
    一般來說,彈幕在我眼中可以分為以下幾類。第一類,無聊型彈幕,例如「哈哈哈哈哈哈」、「23333」。這類彈幕可能是對視頻某個場景某個演員表達個人喜愛之情,但此類多到可以覆蓋整個屏幕,而看不到真正視頻的內容。一般我會下意識地用「關鍵詞」屏蔽此類彈幕。第二類,挑事類彈幕,例如「他/她長得好像XXX」「抱走我家XXX,某家是XXX」。
  • iOS10.0-iOS10.3.3系統支持一鍵越獄,64位系統
    這段時間,各大版本的越獄都有重大的更新,同時各個版本的越獄工具也開始普及,近日,愛思助手更新至7.61版本,正式在愛思助手上增加ios10.0-
  • 南知 | 彈幕時代,你若孤獨,就來集體狂歡
    而由於大量吐槽評論從屏幕飄過時效果看上去像是飛行射擊遊戲裡的彈幕,所以現常指觀影時從屏幕飄過的評論。當提到彈幕時,你會想到什麼?認真你就輸啦 (・ω・)ノ- ( ゜- ゜)つロAcFun是一家彈幕視頻網站,致力於為每一個人帶來歡樂。還是——
  • ios、安卓前端兼容性大全
    安卓系統下Date.parse(new Date('2018-03-30 12:00:00'))會直接轉換成時間戳的形式(簡單說就是整數形式)ios系統下Date.parse(new Date('2018-03-30 12:00:00'))sorry,轉換不了解決方法ios系統下使用
  • bilibili 架構師 高並發實時彈幕系統的實戰之路
    bilibili網站架構師劉丁,從這三個方面出發,為大家帶來了 bilibili 在直播彈幕服務架構上的最佳實踐。2011年畢業,加入獵豹移動從事 C++ 客戶端開發,曾開發「遠程維修平臺」2013年轉型後端開發,主要負責獵豹視頻軟體的後端API 支持、彈泡系統、GoPush-Cluster,GOIM開源項目。