ionic3 localの動画をvideoタグで再生

はじめに

今回やりたかったことは以下
・フォトライブラリから選択した動画をvideoタグで再生
・カメラを起動して撮影した動画をvideoタグで再生

基本的な方針は以下に書いた画像の場合と同じ
http://kimagureneet.hatenablog.com/entry/2018/09/05/165323

1. ファイルへの絶対パスを取得。取得したパスに「file://」がついてなければ付ける
2. 1.で取得したURLを引数に、Ionic.WebView.convertFileSrcメソッド(cordova-plugin-ionic-webview)でローカルサーバーのURL(http://localhost:8080)に変換
3. 2.で取得したURLからBlob URLを作成
4. 3.で取得したBlob URLをvideoタグに設定

大きく違う点が3.で、localサーバーのURLからBlobURLを作成しているところ。Blob URLを使った理由は以下。
iOSで再生できなかった
Androidでは再生されるがvideo.currentTimeを設定しても期待した挙動にならなかった

それぞれ理由はわからないのだがブラウザの仕様なんじゃないかとちょっと気持ち悪いけど勝手に解釈。Androidのvideo.currentTimeが動かない点については同じコードでもローカルの動画の場合に期待通りに動かないということについてstack overflowでも触れられてる方がいた。

使用したプラグイン
https://github.com/apache/cordova-plugin-camera
https://github.com/apache/cordova-plugin-media-capture

実装

html

<button ion-button (click)="openPhoto()">フォトライブラリ</button>
<video controls muted="true" webkit-playsinline playsinline preload="auto" style="width:100%;" [src]="videoUrl"></video>

<button ion-button (click)="openCamera()">カメラを起動</button>
<video controls muted="true" webkit-playsinline playsinline preload="auto" style="width:100%;" [src]="videoCameraUrl"></video>

javascript(typescript)

import { Component } from '@angular/core'
import { Platform } from 'ionic-angular'
import { Camera } from '@ionic-native/camera'
import { PhotoLibrary } from '@ionic-native/photo-library'
import { MediaCapture } from '@ionic-native/media-capture';

declare var Ionic :any
declare var window;

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  public imageUrl = ""
  public imageCameraUrl = ""

  constructor(
    public navCtrl: NavController,
    public platform: Platform,
    public camera: Camera,
    public mediaCapture: MediaCapture
  ) {
  }

  // フォトライブラリ
  openPhoto = () => {
    const options = {
      quality: 100,
      sourceType: this.camera.PictureSourceType.PHOTOLIBRARY,
      destinationType: this.camera.DestinationType.FILE_URI,
      mediaType: this.camera.MediaType.VIDEO
    }
    this.camera.getPicture(options).then((url) => {
      let videoPath = this.platform.is('android') ? 'file://' + url : url
      let videoUrl = Ionic.WebView.convertFileSrc(videoPath)
      this.createBlobUrl(videoUrl)
      .then(blobUrl => {
        this.presentVideoEditor(blobUrl, videoPath)
      })
      .catch(error => {
        console.log(error)
      })
    })
  }

  // カメラ
  openCamera = () => {
    this.mediaCapture.captureVideo().then(data => {
      let url = Ionic.WebView.convertFileSrc(data[0]['fullPath'])
      if (this.platform.is('ios')) {
        url = 'file://' + url
      }
      this.createBlobUrl(url)
      .then(blobUrl => {
	this.videoCameraUrl = blobUrl
      })
      .catch(error => {
	console.log(error)
      })
    }, error => {
      console.log(error)
    })
  }

  // Blob URL生成
  createBlobUrl = (url) => {
    return new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest()
        xhr.open("GET", url)
        xhr.responseType = "blob"
        xhr.addEventListener('load', () => {
          // BlobデータからBlob URLを生成
          let blob = xhr.response
          blob.name = 'file'
          blob.lastModifiedDate = new Date()
          let blobUrl = window.URL.createObjectURL(blob)
          resolve(blobUrl)
        })
        xhr.onerror = (error) => {
          reject(error)
        }
        xhr.send();
    })
  }
}

以上です