【mBaaS】NSData型で取得したデータをmp4に変換して再生する

mBaaSのファイルストアは動画ファイルを保存することもでできます。
ただし、公開ファイルではないデータをファイルストアから取得する場合は、NSData形式で取得することになります。
imageファイルは、UIImageにinitWithDataがあるのですが、AVPlayerにはinitWithDataがないため、mp4ファイルに変換するには自分で変換する必要があります。

## 使用するクラス

AVPlayerViewController
AVAssetResourceLoaderDelegate
AVURLAsset
AVAssetResourceLoader
AVPlayerItem

# Objective-C
mBaaSから動画データを取得して、AVPlayerViewControllerを継承したクラスに渡します。

```objc
//ファイル名の指定
NCMBFile *fileData = [NCMBFile fileWithName:@"fileName" data:nil];

//ファイルストアからファイルを取得
[fileData getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
    if (error){
        //エラー時の処理
    } else {
        //成功時の処理
        PlayerViewController *playerViewController = [[PlayerViewController alloc]init];
        playerViewController.movieData = data;
        
        [self presentViewController:playerViewController animated:YES completion:nil];
    }
}];
```

```objc:PlayerViewController.h
@import AVFoundation;
@import AVKit;

@interface PlayerViewController : AVPlayerViewController

@property (nonatomic) NSData *movieData;

@end
```

```objc:PlayerViewController.m
#import "PlayerViewController.h"

@interface PlayerViewController ()<AVAssetResourceLoaderDelegate>

@end

@implementation PlayerViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:@""] options:nil];
    
    AVAssetResourceLoader *resourceLoader = asset.resourceLoader;
    [resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
    
    AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:asset];
    self.player = [AVPlayer playerWithPlayerItem:playerItem];
}

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {
    // 元データがmp4の場合
    loadingRequest.contentInformationRequest.contentType = @"public.mpeg-4";
    loadingRequest.contentInformationRequest.contentLength = [self.movieData length];
    loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;
    
    NSData *requestedData = [self.movieData subdataWithRange:NSMakeRange((NSUInteger)loadingRequest.dataRequest.requestedOffset,
                                                                         (NSUInteger)loadingRequest.dataRequest.requestedLength)];
    
    [loadingRequest.dataRequest respondWithData:requestedData];
    [loadingRequest finishLoading];
    
    return YES;
}
```

# Swift


```swift
//ファイル名の指定
let fileData = NCMBFile.file(withName: "fileName", data: nil) as! NCMBFile

fileData.getDataInBackground { (data, error) in
    if error != nil {
        //エラー時の処理
    } else {
        //成功時の処理
        let playerViewController = PlayerViewController()
        playerViewController.movieData = data
        
        self.present(playerViewController, animated: true, completion: nil)
    }
}
```

URLは構造体なので、空文字を使うとnilとなってしまうため、NSURLをキャストしたものを使用しています。

```swift:PlayerViewController.swift
import UIKit
import AVFoundation
import AVKit

class PlayerViewController: AVPlayerViewController,AVAssetResourceLoaderDelegate {
    
    var movieData:Data? = nil
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let asset = AVURLAsset.init(url: NSURL.init(string: "")! as URL)
        
        let resourceLoader = asset.resourceLoader
        resourceLoader.setDelegate(self, queue: DispatchQueue.main)
        
        let playerItem = AVPlayerItem.init(asset: asset)
        self.player = AVPlayer (playerItem: playerItem)
    }
    
    func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
        
        // 元データがmp4の場合
        loadingRequest.contentInformationRequest?.contentType = "public.mpeg-4";
        loadingRequest.contentInformationRequest?.contentLength = Int64((self.movieData?.count)!)
        loadingRequest.contentInformationRequest?.isByteRangeAccessSupported = true
        
        let requestedData = self.movieData?.subdata(in: Int(loadingRequest.dataRequest!.requestedOffset) ..< Int(loadingRequest.dataRequest!.requestedLength))
        
        loadingRequest.dataRequest?.respond(with: requestedData!)
        loadingRequest.finishLoading()
        
        return true
    }
}
```