Swift基礎(chǔ)--視頻按幀分解成圖片

參考:iOS開發(fā)視頻分解成圖片(OC版)

 open func generateCGImagesAsynchronously(forTimes requestedTimes: [NSValue], completionHandler handler: @escaping AVFoundation.AVAssetImageGeneratorCompletionHandler)
  • 調(diào)用視頻分解Function
func slipImgsBtnClick() {
   imgArray.removeAll()
   
   //電腦桌面的一份mp4文件奠旺,時長3分20秒蜘澜。。响疚。path看情況自己定鄙信。。忿晕。装诡。
   let tmpFileUrl = URL(fileURLWithPath: "/Users/tmy/Downloads/好好(你的名字).mp4")
   
   //調(diào)用視頻分解func
   self.splitVideoFileUrlFps(splitFileUrl: tmpFileUrl, fps: 1, splitCompleteClosure: { [weak self](isSuccess, splitImgs) in
       if isSuccess {
           self?.imgArray = splitImgs as! [UIImage]
           
           //UI回主線程刷新
           DispatchQueue.main.async {[weak self] in
               self?.tableView.reloadData()
           }
           print("圖片總數(shù)目imgcount:\(String(describing: self?.imgArray.count))")
       }
   })
}
  • 視頻分解Function
/// 視頻分解成幀
/// - parameter fileUrl                 : 視頻地址
/// - parameter fps                     : 自定義幀數(shù) 每秒內(nèi)取的幀數(shù)
/// - parameter splitCompleteClosure    : 回調(diào)
func splitVideoFileUrlFps(splitFileUrl:URL, fps:Float, splitCompleteClosure:@escaping completeClosure) {
   
   // TODO: 判斷fileUrl是否為空
   print("QQQQQQQQQQ ==> split: \(splitFileUrl)")
   
   var splitImages = [UIImage]()
   let optDict = NSDictionary(object: NSNumber(value: false), forKey: AVURLAssetPreferPreciseDurationAndTimingKey as NSCopying)
   let urlAsset = AVURLAsset(url: splitFileUrl, options: optDict as? [String : Any])
   
   let cmTime = urlAsset.duration
   let durationSeconds: Float64 = CMTimeGetSeconds(cmTime) //視頻總秒數(shù)
   
   var times = [NSValue]()
   let totalFrames: Float64 = durationSeconds * Float64(fps) //獲取視頻的總幀數(shù)
   var timeFrame: CMTime
   
   for i in 0...Int(totalFrames) {
       timeFrame = CMTimeMake(Int64(i), Int32(fps)) //第i幀, 幀率
       let timeValue = NSValue(time: timeFrame)
       
       times.append(timeValue)
   }
   
   let imgGenerator = AVAssetImageGenerator(asset: urlAsset)
   imgGenerator.requestedTimeToleranceBefore = kCMTimeZero //防止時間出現(xiàn)偏差
   imgGenerator.requestedTimeToleranceAfter = kCMTimeZero
   
   let timesCount = times.count
   
   //獲取每一幀的圖片
   imgGenerator.generateCGImagesAsynchronously(forTimes: times) { (requestedTime, image, actualTime, result, error) in
       
       //times有多少次body就循環(huán)多少次践盼。鸦采。。咕幻。
       print("current-----\(requestedTime.value)   timesCount == \(timesCount)")
       print("timeScale-----\(requestedTime.timescale) requestedTime:\(requestedTime.value)")
       
       var isSuccess = false
       switch (result) {
       case AVAssetImageGeneratorResult.cancelled:
           print("cancelled------")
           
       case AVAssetImageGeneratorResult.failed:
           print("failed++++++")
           
       case AVAssetImageGeneratorResult.succeeded:
           let framImg = UIImage(cgImage: image!)
           splitImages.append(framImg)
           
           if (Int(requestedTime.value) == (timesCount-1)) { //最后一幀時 回調(diào)賦值
               isSuccess = true
               splitCompleteClosure(isSuccess, splitImages)
               print("completed")
           }
       }
   }
}

屏幕快照 2017-05-16 10.34.14.png

屏幕快照 2017-05-16 10.34.25.png

  • 使用
//
//  TMYImgTableViewController.swift
//  TMYSegmentController
//
//  Created by TMY on 2017/5/15.
//  Copyright ? 2017年 TMY. All rights reserved.
//

import UIKit
import AVFoundation

class TMYImgTableViewController: UITableViewController {

    var imgArray = [UIImage]()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1)
        
        title = "圖片展示"
        tableView.register(TMYImgCell.self, forCellReuseIdentifier: "imgCellIdentifier")
        tableView.tableFooterView = UIView()
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = UIScreen.main.bounds.size.height/3
        
        let rightBtn = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(slipImgsBtnClick))
        navigationItem.rightBarButtonItem = rightBtn
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return imgArray.count
    }
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UIScreen.main.bounds.size.height/3
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "imgCellIdentifier", for: indexPath) as!  TMYImgCell
        cell.imgView.image = imgArray[indexPath.row]

        return cell
    }
    
    func slipImgsBtnClick() {
        imgArray.removeAll()
        
        //電腦桌面的一份mp4文件赖淤,時長3分20秒。谅河。咱旱。path看情況自己定确丢。。吐限。鲜侥。
        let tmpFileUrl = URL(fileURLWithPath: "/Users/tmy/Downloads/好好(你的名字).mp4")
        
        //調(diào)用視頻分解func
        self.splitVideoFileUrlFps(splitFileUrl: tmpFileUrl, fps: 1, splitCompleteClosure: { [weak self](isSuccess, splitImgs) in
            
            if isSuccess {
                self?.imgArray = splitImgs as! [UIImage]
                
                //UI回主線程刷新
                DispatchQueue.main.async {[weak self] in
                    self?.tableView.reloadData()
                }
                print("圖片總數(shù)目imgcount:\(String(describing: self?.imgArray.count))")
            }
        })
    }
}

class TMYImgCell: UITableViewCell {
    
    let imgView = UIImageView()
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
         imgView.frame = CGRect(x: 10, y: 0, width: UIScreen.main.bounds.size.width - 20, height: UIScreen.main.bounds.size.height/3)
        imgView.contentMode = .scaleAspectFit
        addSubview(imgView)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension TMYImgTableViewController {
    
    /// 視頻分解成幀
    /// - parameter fileUrl                 : 視頻地址
    /// - parameter fps                     : 自定義幀數(shù) 每秒內(nèi)取的幀數(shù)
    /// - parameter splitCompleteClosure    : 回調(diào)
    func splitVideoFileUrlFps(splitFileUrl:URL, fps:Float, splitCompleteClosure:@escaping completeClosure) {
        
        // TODO: 判斷fileUrl是否為空
        print("QQQQQQQQQQ ==> split: \(splitFileUrl)")
        
        var splitImages = [UIImage]()
        let optDict = NSDictionary(object: NSNumber(value: false), forKey: AVURLAssetPreferPreciseDurationAndTimingKey as NSCopying)
        let urlAsset = AVURLAsset(url: splitFileUrl, options: optDict as? [String : Any])
        
        let cmTime = urlAsset.duration
        let durationSeconds: Float64 = CMTimeGetSeconds(cmTime) //視頻總秒數(shù)
        
        var times = [NSValue]()
        let totalFrames: Float64 = durationSeconds * Float64(fps) //獲取視頻的總幀數(shù)
        var timeFrame: CMTime
        
        for i in 0...Int(totalFrames) {
            timeFrame = CMTimeMake(Int64(i), Int32(fps)) //第i幀, 幀率
            let timeValue = NSValue(time: timeFrame)
            
            times.append(timeValue)
        }
        
        let imgGenerator = AVAssetImageGenerator(asset: urlAsset)
        imgGenerator.requestedTimeToleranceBefore = kCMTimeZero //防止時間出現(xiàn)偏差
        imgGenerator.requestedTimeToleranceAfter = kCMTimeZero
        
        let timesCount = times.count
        
        //獲取每一幀的圖片
        imgGenerator.generateCGImagesAsynchronously(forTimes: times) { (requestedTime, image, actualTime, result, error) in
            
            //times有多少次body就循環(huán)多少次诸典。描函。。狐粱。
            print("current-----\(requestedTime.value)   timesCount == \(timesCount)")
            print("timeScale-----\(requestedTime.timescale) requestedTime:\(requestedTime.value)")
            
            var isSuccess = false
            switch (result) {
            case AVAssetImageGeneratorResult.cancelled:
                print("cancelled------")
                
            case AVAssetImageGeneratorResult.failed:
                print("failed++++++")
                
            case AVAssetImageGeneratorResult.succeeded:
                let framImg = UIImage(cgImage: image!)
                splitImages.append(framImg)
                
                if (Int(requestedTime.value) == (timesCount-1)) { //最后一幀時 回調(diào)賦值
                    isSuccess = true
                    splitCompleteClosure(isSuccess, splitImages)
                    print("completed")
                }
            }
        }
    }
}

Demo下載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舀寓,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子肌蜻,更是在濱河造成了極大的恐慌互墓,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒋搜,死亡現(xiàn)場離奇詭異篡撵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)豆挽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門育谬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人帮哈,你說我怎么就攤上這事膛檀。” “怎么了娘侍?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵咖刃,是天一觀的道長。 經(jīng)常有香客問我私蕾,道長僵缺,這世上最難降的妖魔是什么胡桃? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任踩叭,我火速辦了婚禮,結(jié)果婚禮上翠胰,老公的妹妹穿的比我還像新娘容贝。我一直安慰自己,他們只是感情好之景,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布斤富。 她就那樣靜靜地躺著,像睡著了一般锻狗。 火紅的嫁衣襯著肌膚如雪满力。 梳的紋絲不亂的頭發(fā)上焕参,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機(jī)與錄音油额,去河邊找鬼叠纷。 笑死,一個胖子當(dāng)著我的面吹牛潦嘶,可吹牛的內(nèi)容都是我干的涩嚣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼掂僵,長吁一口氣:“原來是場噩夢啊……” “哼航厚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锰蓬,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤幔睬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后互妓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溪窒,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年冯勉,在試婚紗的時候發(fā)現(xiàn)自己被綠了澈蚌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡灼狰,死狀恐怖宛瞄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情交胚,我是刑警寧澤份汗,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站蝴簇,受9級特大地震影響杯活,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜熬词,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一旁钧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧互拾,春花似錦歪今、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至骑疆,卻和暖如春田篇,著一層夾襖步出監(jiān)牢的瞬間替废,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工泊柬, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留舶担,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓彬呻,卻偏偏與公主長得像衣陶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子闸氮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,110評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫赚爵、插件嵌纲、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,102評論 4 62
  • 快餐的社會里心铃,很少有人愿意從你馬虎的外在蟹地,去發(fā)現(xiàn)你優(yōu)秀的內(nèi)在。so或悲,我們內(nèi)外兼修孙咪! 有的人,說出的每...
    不打雷的雷閱讀 310評論 0 1
  • 1.填空題 AT89S51內(nèi)有( )個可編程的定時/計數(shù)器巡语,( )種工作模式翎蹈,( )工作方式。 【解析】 AT89...
    0206_景琪閱讀 239評論 1 3
  • 我叫空,剛剛白了一下 也因為那一刻枢赔,我叫空 我的出現(xiàn) 是因為悶騷波少年的狀態(tài)出現(xiàn)了斷層 “啪澄阳!”的一聲,就出世了踏拜,...
    馬刺愛波波閱讀 300評論 0 0