Swift基础--视频按帧分解成图片

参考:iOS开发视频分解成图片(OC版)

 open func generateCGImagesAsynchronously(forTimes requestedTimes: [NSValue], completionHandler handler: @escaping AVFoundation.AVAssetImageGeneratorCompletionHandler)
  • 调用视频分解Function
func slipImgsBtnClick() {
   imgArray.removeAll()
   
   //电脑桌面的一份mp4文件,时长3分20秒。。。path看情况自己定。。。。
   let tmpFileUrl = URL(fileURLWithPath: "/Users/tmy/Downloads/好好(你的名字).mp4")
   
   //调用视频分解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("图片总数目imgcount:\(String(describing: self?.imgArray.count))")
       }
   })
}
  • 视频分解Function
/// 视频分解成帧
/// - parameter fileUrl                 : 视频地址
/// - parameter fps                     : 自定义帧数 每秒内取的帧数
/// - parameter splitCompleteClosure    : 回调
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) //视频总秒数
   
   var times = [NSValue]()
   let totalFrames: Float64 = durationSeconds * Float64(fps) //获取视频的总帧数
   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 //防止时间出现偏差
   imgGenerator.requestedTimeToleranceAfter = kCMTimeZero
   
   let timesCount = times.count
   
   //获取每一帧的图片
   imgGenerator.generateCGImagesAsynchronously(forTimes: times) { (requestedTime, image, actualTime, result, error) in
       
       //times有多少次body就循环多少次。。。。
       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)) { //最后一帧时 回调赋值
               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")
        
        //调用视频分解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("图片总数目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                     : 自定义帧数 每秒内取的帧数
    /// - parameter splitCompleteClosure    : 回调
    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) //视频总秒数
        
        var times = [NSValue]()
        let totalFrames: Float64 = durationSeconds * Float64(fps) //获取视频的总帧数
        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 //防止时间出现偏差
        imgGenerator.requestedTimeToleranceAfter = kCMTimeZero
        
        let timesCount = times.count
        
        //获取每一帧的图片
        imgGenerator.generateCGImagesAsynchronously(forTimes: times) { (requestedTime, image, actualTime, result, error) in
            
            //times有多少次body就循环多少次。。。。
            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)) { //最后一帧时 回调赋值
                    isSuccess = true
                    splitCompleteClosure(isSuccess, splitImages)
                    print("completed")
                }
            }
        }
    }
}

Demo下载

你可能感兴趣的:(Swift基础--视频按帧分解成图片)