CollectionViewを使って動画キャプチャーを作ってみる（１）


![collectionViewSample.gif](https://qiita-image-store.s3.amazonaws.com/0/40693/9c288ffd-d34b-738d-e8df-bed39bf596a6.gif "collectionViewSample.gif")



とりあえず動くものを作ってみる。動画を１０分割してキャプチャー一覧を表示。選択されたところから再生します。

UICollectionViewは基本的にはUITbaleViewを使うのと同じような仕組みで動く。

```
    //1
    override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }
    
    //2
    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }
    
    //3
    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    //cellの設定
    }
```

最低上記３つの関数を実装すれば良い（と思う）
セルに関してはUITableViewのセルのようにフォーマットが用意されてるわけではなさそうなので、毎回UICollectionViewCellのサブクラスを用意するっぽいです。

```
class CustomCell : UICollectionViewCell {
    

    @IBOutlet weak var imageView: UIImageView!

    @IBOutlet weak var timeLabel: UILabel!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        //fatalError("init(coder:) has not been implemented")
    }
    
    override func awakeFromNib() {
        
        let backgroundView = UIView(frame: frame)
        backgroundView.backgroundColor = UIColor.whiteColor()
        self.backgroundView = backgroundView
        
        let selectedBGView = UIView(frame: frame)
        selectedBGView.backgroundColor = UIColor.redColor()
        self.selectedBackgroundView = selectedBGView
    }
    
}

```

awakeFromNib内でセレクトされた時にCellの背景色を変えるロジックを入れてます。この場合、選択されたら赤くなる。他にも方法はあるみたいです。

動画を扱うプログラミングはなかなか奥が深いのですが、まず
AVFoundation
AssetsLibrary
上記２つのライブラリをプロジェクトに追加。
動画はiPhoneで撮った動画をプロジェクトに追加。
後はそれを読み込み、再生時間を１０分割した時のキャプチャー画像とその時の読み込み時間を配列に保存。

```
import UIKit
import AVFoundation
import AssetsLibrary

class ViewController: UICollectionViewController {
    
    struct Capture {
        var picture : CGImageRef
        var time : Float64
    }
    
    var generator : AVAssetImageGenerator!
    var captureAry : [Capture]!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        
        if let path = NSBundle.mainBundle().URLForResource("IMG_0727", withExtension: "mp4") {
            do {
                let avAsset = AVURLAsset(URL: path, options: nil)
                
                // assetから画像をキャプチャーする為のジュネレーターを生成.
                generator = AVAssetImageGenerator(asset: avAsset)
                
                let runningTime = Int64(CMTimeGetSeconds(avAsset.duration))
                
                let time : CMTime = CMTimeMake(runningTime, 10)
                var capturedTime : CMTime = kCMTimeZero
                
                captureAry = []
                
                for _ in 0...9 {
                    let capturedImage : CGImageRef! = try! generator.copyCGImageAtTime(capturedTime, actualTime: nil)
                    
                    let capture = Capture(picture: capturedImage, time: CMTimeGetSeconds(capturedTime))
                    captureAry.append(capture)
                    
                    capturedTime = CMTimeAdd(capturedTime, time)
                }
            }
        }
    }
```
セルを選択された際はstroyBoardでsegueを使う場合は以下のとおり

```
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        NSLog("segue")
        
        let index : NSIndexPath = (self.collectionView?.indexPathForCell(sender as! UICollectionViewCell))!
        
        let capture = captureAry[index.row]
        let value : UInt64 = UInt64(capture.time*100)
        
        
        NSUserDefaults.standardUserDefaults().setObject(NSNumber(unsignedLongLong: value), forKey: "time")
        NSUserDefaults.standardUserDefaults().synchronize()
    }
```

後はセルを選択された際に呼び出すDetailViewを作ればOK

```

import Foundation
import AVKit
import AVFoundation

class PlayerViewController: AVPlayerViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let item : Int64 = Int64(NSUserDefaults.standardUserDefaults().objectForKey("time") as! Int)
        
        //let time = item * Int64(1)
        
        let seektime =  CMTimeMake(item, 100)
        NSLog("%f", CMTimeGetSeconds(seektime))
        
        
        if let url = NSBundle.mainBundle().URLForResource("IMG_0727", withExtension: "mp4") {
            do {
                player = AVPlayer(URL: url)
                player?.seekToTime(seektime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
            }
        } else {
            fatalError("error")
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    override func viewDidAppear(animated: Bool) {
        player?.play()
    }
}
```

これでとりあえず動くものが出来ます。これをより汎用的に作り直すのは次回。

参考

[UICollectionViewを実装する[swift&xcode6]](http://kazuhei.hatenablog.com/entry/2014/11/26/233206)
UICollectionViewの使い方だけでなく、選択されたデータの遷移方法としてNSUserDefaultsを使っているのも参考にさせて頂きました。

[005 動画から静止画を取り出す](https://sites.google.com/a/gclue.jp/swift-docs/ni-yinki100-ios/3-avfoundation/005-dong-huakara-jing-zhi-huawo-quri-chusu)
キャプター画像を作るやり方はこのページを参照


[AVFoundation プログラミングガイド](https://developer.apple.com/jp/documentation/AVFoundationPG.pdf)
選択されたセルの背景色を変えるとか・・・それ以外にも少しずつ。