LivePhotosをmovとjpegから作る

# LivePhotos を mov と jpeg から作る
* mov と jpeg を LivePhotos として保存できます
* 動画ファイルの時間や、mov と jepg にそれぞれメタデータの設定が必要です
* AVAssetWriter と CoreImage を使って、それぞれのメタデータを設定する事が可能です

# サンプルアプリ
* リポジトリはこちらです

https://github.com/fuziki/VideoCreator

# LivePhotos として保存できる条件
* mov と jpeg に共通の content identifier を設定する必要があります

## mov を作成する AVAssetWriter の設定
* ファイルのメタデータに content identifier を設定します
* assetWriter.metadata に設定します

```swift
let assetWriter = try AVAssetWriter(outputURL: url, fileType: fileType)
let item = AVMutableMetadataItem()
item.key = AVMetadataKey.quickTimeMetadataKeyContentIdentifier as NSString
item.keySpace = AVMetadataKeySpace.quickTimeMetadata
item.value = contentIdentifier as NSString
item.dataType = kCMMetadataBaseDataType_UTF8 as String
assetWriter.metadata = [item]
```

* `AVMetadataKey.quickTimeMetadataKeyContentIdentifier` は `"com.apple.quicktime.content.identifier"` のようです

* メタデータトラックを作成して追加します

```swift
let spec : NSDictionary = [
    kCMMetadataFormatDescriptionMetadataSpecificationKey_Identifier: "mdta/com.apple.quicktime.still-image-time",
    kCMMetadataFormatDescriptionMetadataSpecificationKey_DataType: kCMMetadataBaseDataType_SInt8
]
var desc : CMFormatDescription? = nil
CMMetadataFormatDescriptionCreateWithMetadataSpecifications(allocator: kCFAllocatorDefault,
                                                            metadataType: kCMMetadataFormatType_Boxed,
                                                            metadataSpecifications: [spec] as CFArray,
                                                            formatDescriptionOut: &desc)
let input = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil, sourceFormatHint: desc)
let adaptor = AVAssetWriterInputMetadataAdaptor(assetWriterInput: input)
assetWriter.add(adaptor.assetWriterInput)
```

* 開始時刻と終了時刻と still image time のメタデータを書き込みます
* 録画中に書き込む必要があるようです

```swift
let item = AVMutableMetadataItem()
item.key = "com.apple.quicktime.still-image-time" as NSString
item.keySpace = AVMetadataKeySpace.quickTimeMetadata
item.value = 0 as NSNumber
item.dataType = kCMMetadataBaseDataType_SInt8 as String
let timeRange = CMTimeRange(start: startTime, end: latestTime)
metadataAdaptor.append(AVTimedMetadataGroup(items: [item], timeRange: timeRange))
```

## CoreImage を使った jpeg の Data の作成

* jpeg は "17" のキーに content identifier を設定する必要があるようです
* CIImage.settingProperties を使って、プロパティを設定します
* CIContext.jpegRepresentation を使って、CIImage から jpeg の Data を取得します

```swift
let ci: CIImage = ~~~~~
let context = CIContext()
let properties: [CFString : Any] = [kCGImagePropertyMakerAppleDictionary: ["17": contentIdentifier]]
let propertiedCi = ci.settingProperties(properties)
let jpegData = context.jpegRepresentation(of: propertiedCi, colorSpace: CGColorSpace(name: CGColorSpace.sRGB)!, options: [:])!
```

# Live Photos の保存

* PHPhotoLibrary を使って Live Photos として保存します
* mov を .pairedVideo として保存します

```swift
try PHPhotoLibrary.shared().performChangesAndWait {
    let request = PHAssetCreationRequest.forAsset()
    request.addResource(with: .photo, data: jpegData, options: nil)
    let videoOptions = PHAssetResourceCreationOptions()
    videoOptions.shouldMoveFile = true
    request.addResource(with: .pairedVideo, fileURL: videoUrl, options: videoOptions)
}
```

# おわりに
* Live Photosはなかなかドキュメントを見つけられず苦心しました
* PHPhotoLibrary のエラーも情報が落ちないので、AVCapturePhotoOutput の出力と見比べたり差し替えたりすることで、コンストラクタのオプションだと jpeg の設定で出来ていないことに気付いたり、など大変でした
* Live Photos は iOS 固有の機能なので活用して行きたいです