23
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

LivePhotoから動画や画像を取り出す方法

Last updated at Posted at 2015-12-19

この記事は学生エンジニア Advent Calendar19日目の記事です.

背景

iPhone6,Iphone6Sから新たに使えるようになったLivePhoto,皆様使っているでしょうか.
忘年会の多いこのシーズン,盛り上がってしまった友達を撮るために僕はよく使っています.

screenshot1.gif

(* 本人の許可を得て掲載しております)

しかし,ここで問題となるのがLivePhotoで撮った写真を如何に共有するかということ.
iPhone6S, 6S+以外を利用している人に共有するとただの画像として扱われてしまい,彼の躍動感も失われてしまいます。
LivePhotoを動画やGIFに変換するアプリもありましたが有料だったり制限があったりということで,LivePhotoを動画やGIFに変換する方法を調べてみました.

環境

Mac OS X(10.10.5)
Xcode (7.1)

PHLivePhotoクラス

LivePhotoを扱うためのクラスPHLivePhotoが用意されていたので,そのリファレンスを眺めてみました.
プロパティとして用意されているのはSizeのみで,構成する動画や画像を取り出すためのAPIは存在しません.

ということで,まずはLivePhotoクラスに設定されているプロパティを公開されていないものも含めて見てみます.


import ObjectiveC
var outCount:uint = 0
let propertyList = class_copyPropertyList(PHLivePhoto.self, &outCount)

for i in 0..<Int(outCount) {
    let property = propertyList[i]
    let propertyName = property_getName(property)
    let propertyType = property_getAttributes(property)
            
    print("\(String.fromCString(UnsafePointer<CChar>(propertyType))!):\(String.fromCString(UnsafePointer<CChar>(propertyName))!)")
}

すると,以下の様な結果が得られました.

出力
T{CGSize=dd},R,N,V_size:size
T@"UIImage",R,N,V_image:image
T@"AVAsset",R,N,V_videoAsset:videoAsset
T{?=qiIq},R,N,V_photoTime:photoTime
T@"NSString",R,C,N,V_assetLocalIdentifier:assetLocalIdentifier
T@"NSString",R,V_uniqueIdentifier:uniqueIdentifier
T@"NSURL",R,N,V_imageURL:imageURL
T@"PHSandboxExtensionWrapper",R,N,V_imageURLSandboxExtensionWrapper:imageURLSandboxExtensionWrapper
T@"NSURL",R,N,V_videoURL:videoURL
T@"PHSandboxExtensionWrapper",R,N,V_videoURLSandboxExtensionWrapper:videoURLSandboxExtensionWrapper
T@"NSString",R,N:originalFilename
T@"NSString",R,N:imageTypeIdentifier
T@"NSString",R,N:videoTypeIdentifier
T@?,R,N:imageFileLoader
T@?,R,N:videoFileLoader
T{CGSize=dd},R,N,V_targetSize:targetSize
Tq,R,N,V_contentMode:contentMode
T@"PHImageManager",W,N,V_imageManager:imageManager
T@"PHAsset",W,N,V_asset:asset

怪しいものにKVCを使ってアクセスしてその出力を見たいのですが,
その前にまず自分のカメラロール内のライブフォトにアクセスしたいので以下の様にしてカメラロールから取得します.

カメラロールからライブフォトの取り込み

適当なボタンをタップするとカメラロールを表示できるようにします.

ViewController.swift
import MobileCoreServices

//中略

 func didTapButton(button: UIButton) {
    let imagePickerController = UIImagePickerController()
    imagePickerController.delegate = self
    imagePickerController.sourceType = .PhotoLibrary
    imagePickerController.mediaTypes = [kUTTypeImage as String, kUTTypeLivePhoto as String]
    presentViewController(imagePickerController, animated: true, completion: nil)
}

そして写真を選択した時に呼ばれるdelegateメソッド内で以下のようにするとライブフォトを取り出すことが出来ます.

ViewController.swift

import Photos

//中略

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
    if let livePhoto = info[UIImagePickerControllerLivePhoto] as? PHLivePhoto {
        //この中で使える
    }
}

これでカメラロール内のライブフォトを扱えるようになったので早速,先ほど怪しかったpropertyのvalueを取り出してみた結果,
videoAssetに設定されているAVURLAssetのインスタンスにライブフォトのムービーファイルのURLが格納されていることがわかりました.

(ちなみにimageURLに表示されている画像のURLが格納されています)


if let urlAsset = livePhoto.valueForKey("videoAsset") as? AVURLAsset {
    print(urlAsset.URL)
}
出力
file:///var/mobile/Media/DCIM/105APPLE/IMG_5491.MOV

動画ファイル名が分かってしまえばこっちのもので,

UISaveVideoAtPathToSavedPhotosAlbum(urlAsset.URL.path!, self, "video:didFinishSavingWithError:contextInfo:", nil)

動画をカメラロールに保存するためのメソッドを呼び出してあげれば

screenshot2.gif

無事に動画として保存されました!

次にGIFとして保存する方法ですが,動画の場所が分かっているので,
NSGIFというmovファイルをgifに変換してくれるライブラリがございますのでそちらを使えば良いと思います。

感想

さくっとできるだろ〜って思ってたらまさかのPHLivePhotoで公開されているプロパティがサイズしかないということで思ったより時間がかかってしまいました。

忘年会の多いこのシーズン、あなたが撮った素敵なライブフォトを動画やGIFで共有したい場合,ぜひぜひご活用ください!

おまけ

動画から時系列に30枚くらい画像を切り出してみましたのでおまけで置いておきます.


if let image = livePhoto.valueForKey("videoAsset") as? AVURLAsset {
    let generator = AVAssetImageGenerator(asset: image)
    generator.maximumSize = livePhoto.size
    let defaultTime = image.duration
    let numberOfImage: Int64 = 30
    for i in 0..<numberOfImage {
        let targetTime = CMTimeMake((defaultTime.value / numberOfImage) * i, defaultTime.timescale)
        let imageRef: CGImageRef = try! generator.copyCGImageAtTime(targetTime, actualTime: nil)
        let image = UIImage(CGImage: imageRef)
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
    }
}

screenshot
こんなにいらない

23
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?