iOS - 自定義視頻播放器 -- (1)

背景需求

如何將視頻添加上自定義的渲染效果袍患,并顯示?

大致流程

1竣付、解碼視頻
2诡延、獲取視頻幀
3、渲染視頻幀
4古胆、顯示渲染后的視頻幀
5肆良、編碼視頻幀,生成新的視頻

通過(guò)AVPlayer進(jìn)行實(shí)時(shí)獲取視頻幀

核心對(duì)象:AVPlayer逸绎,AVPlayerItemVideoOutput

AVPlayer:驅(qū)動(dòng)播放用例的中心階層惹恃,是用于管理媒體資產(chǎn)的回放和定時(shí)的控制器對(duì)象
這里AVPlayer,我制作簡(jiǎn)單的播放棺牧,暫停巫糙,seek。并且添加上AVPlayerItemVideoOutput做一個(gè)視頻幀輸出的工作陨帆。
創(chuàng)建一個(gè)播放器

    init(videoPath url:URL) {
        super.init()
        videoURL = url
        let urlAsset = AVURLAsset(url: videoURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey:true])
        
        playerItem = AVPlayerItem(asset: urlAsset)
        playerItem?.add(playerOutput)
        
        player = AVPlayer(playerItem: playerItem)
        player?.isMuted = false
        
        playerItem?.addObserver(self, forKeyPath: "status", options: .new, context: nil)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "status" {
            if let item = object as? AVPlayerItem {
                switch item.status {
                case .readyToPlay:
                    durationTime = CMTimeGetSeconds(item.duration)*1000
                    sendPlayerStauDelegate(videoStatu: .Prepared)
                default:
                    sendPlayerStauDelegate(videoStatu: .Error)
                }
            }
            
        }
    }

    func play() {
        if !playing {
            player?.play()
            playing = true
        }
    }
    
    func pause() {
        if playing {
            player?.pause()
            playing = false
        }
    }
    
    func seekTo(time:CMTime) {
        player?.seek(to: time, toleranceBefore: .zero, toleranceAfter: .zero)
    }

AVPlayerItemVideoOutput獲取視頻幀

   var playerOutput:AVPlayerItemVideoOutput = {
        // 根據(jù)需求獲取相對(duì)于視頻幀數(shù)據(jù)  通常選擇RGBA數(shù)據(jù),比較容易處理.系統(tǒng)默認(rèn)是Y-UV數(shù)據(jù)
        let out = AVPlayerItemVideoOutput(pixelBufferAttributes: [kCVPixelBufferPixelFormatTypeKey as String:kCVPixelFormatType_32BGRA])
        return out
    }()
    
   var onPixelBuffer:CVPixelBuffer? {
        get {
            //獲取當(dāng)前視頻幀
            let time = self.playerOutput.itemTime(forHostTime: CACurrentMediaTime())
            if self.playerOutput.hasNewPixelBuffer(forItemTime: time) {
                return self.playerOutput.copyPixelBuffer(forItemTime: time, itemTimeForDisplay: nil)
            } else {
                return nil
            }
        }
    }

主要的核心工具是AVPlayerItemVideoOutput曲秉,這對(duì)象相當(dāng)于一個(gè)視頻解碼工具,對(duì)它進(jìn)行屬性設(shè)置疲牵,可以獲取視頻中某一時(shí)刻的想要數(shù)據(jù)的CVPixelBuffer視頻幀承二。

func copyPixelBuffer(forItemTime itemTime: CMTime, itemTimeForDisplay outItemTimeForDisplay: UnsafeMutablePointer<CMTime>?) -> CVPixelBuffer?

通過(guò)獲取到的CVPixelBuffer,進(jìn)行OPenGL自定義渲染顯示纲爸。
外部需要開(kāi)啟一個(gè)定時(shí)器亥鸠,來(lái)實(shí)時(shí)的進(jìn)行畫(huà)面的刷新。定時(shí)器時(shí)間可以根據(jù)視頻的FPS來(lái)控制。

至此如何獲取視頻幀就可以了负蚊。


如何獲取視頻幀神妹,這里都比較簡(jiǎn)單,都是通過(guò)系統(tǒng)層去實(shí)現(xiàn)功能家妆。
主要注意的是:
1鸵荠、AVPlayerItemVideoOutput的獲取的數(shù)據(jù)格式定義,根據(jù)需求設(shè)置RGBA還是YUV420的數(shù)據(jù)伤极。
2蛹找、AVPlayer使用seek時(shí)候,使用精度比較高的方法哨坪,提高在seek時(shí)候的畫(huà)面流暢度

 func seek(to time: CMTime, toleranceBefore: CMTime, toleranceAfter: CMTime)

3庸疾、獲取的CVPixelBuffer在Swift語(yǔ)言,不需要手動(dòng)釋放当编。在OC上需要調(diào)用CVPixelBufferRelease()手動(dòng)釋放


Git Code:AVPlayer-Render

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末届慈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子忿偷,更是在濱河造成了極大的恐慌金顿,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牵舱,死亡現(xiàn)場(chǎng)離奇詭異串绩,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)芜壁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)礁凡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人慧妄,你說(shuō)我怎么就攤上這事顷牌。” “怎么了塞淹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵窟蓝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我饱普,道長(zhǎng)运挫,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任套耕,我火速辦了婚禮谁帕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘冯袍。我一直安慰自己匈挖,他們只是感情好碾牌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著儡循,像睡著了一般舶吗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上择膝,一...
    開(kāi)封第一講書(shū)人閱讀 49,842評(píng)論 1 290
  • 那天誓琼,我揣著相機(jī)與錄音,去河邊找鬼肴捉。 笑死踊赠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的每庆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼今穿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼缤灵!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蓝晒,我...
    開(kāi)封第一講書(shū)人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤腮出,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后芝薇,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體胚嘲,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年洛二,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了馋劈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晾嘶,死狀恐怖妓雾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情垒迂,我是刑警寧澤械姻,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站机断,受9級(jí)特大地震影響楷拳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吏奸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一欢揖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧苦丁,春花似錦浸颓、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)棵磷。三九已至,卻和暖如春晋涣,著一層夾襖步出監(jiān)牢的瞬間仪媒,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工谢鹊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留算吩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓佃扼,卻偏偏與公主長(zhǎng)得像偎巢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子兼耀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349