0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Web版!メディアプレーヤをつくってみよう!(videoタグ編)

0
Posted at

ローカルメディアの再生

ローカル保存したメディアの再生は「VIDEOタグ」を扱うと再生できることがわかった。
凝った表示内容は得意でないので、シンプルにこんな感じができると使えそう。

■プレーヤーの機能イメージ
image.png

アイコン 機能
📁 再生したいファイルを選択する
⏮ 再生中のコンテンツを最初から再生
⏭ 次のコンテンツを再生
🎦 プレイリストを表示

ちなみに、画面下部の再生コントロール類は、VIDEOタグでの標準機能なので、そのまま使うことにした。

VIDEOタグの機能

初期化

ものすごく簡単に、とにかく再生したいだけなら、こんな感じで十分に使える。

まずは、セットアップ。

const videoCssName = `evonaVideo-drop`
const videoElem = document.createElement(`video`)
videoElem.className = videoCssName
videoElem.id = videoCssName
videoElem.style.width = `98vw`  //`100vw`
videoElem.style.height = `98vh` //`100vh`
videoElem.controls = true
document.body.appendChild(videoElem)

そして再生。

const url = URL.createObjectURL(`ファイル選択したコンテンツ`)
videoElem.src = url
await videoElem.play()

再生終了したら、コンテンツを開放。

URL.revokeObjectURL(url)

最初から再生

再生中の位置を記録しているみたいで、その位置をゼロにしたら最初から再生してくれる。

videoElem.currentTime = 0

再生終了の検知

再生が終了するとイベントが発生するので、それを捕まえる。

async function onVideoEnded(event: Event) {
}
videoElem.addEventListener(`ended`, onVideoEnded)

連続再生もどき

プレイリスト内の次のコンテンツを再生したいなら、前述の「ended」イベント内で次のコンテンツを再生すればいいことになる。
ちなみに、再生位置をゼロに戻すかどうかは、好みの問題みたい。

async function onVideoEnded(event: Event) {
    //再生終了したコンテンツを開放
    //次のコンテンツを再生
}

知っていると便利かもなイベント

「ended」イベント以外にも、つかえそうなイベントがあった。

イベント名 機能概要
pause 一時停止
seeked シークバーで再生位置を変更
enterpictureinpicture PinP再生を開始
leavepictureinpicture PinP再生を終了

おまけ

ローカル保存したコンテンツの選択は、こんなクラスを作ってみた。

/**ファイル選択:📁📂 */
export class FileSelect {
    static emoji1 = `📁`
    static emoji2 = `📂`
    public parentElem = document.body
    public accept = `video/mp4,audio/mpeg`
    public multiple = true
    public autoClose = true
    public onSelect: ((files: FileList) => void) | undefined = undefined
    public onCancel: (() => void) | undefined = undefined

    private fileInput: HTMLInputElement | null = null

    public Open() {
        const fileInput = document.createElement('input')
        fileInput.type = 'file'
        fileInput.multiple = this.multiple  // 複数選択を許可する場合
        fileInput.accept = this.accept      // 必要に応じて拡張子を制限
        fileInput.style.display = 'none'
        this.parentElem.appendChild(fileInput)
        fileInput.addEventListener('change', this.onChange)
        fileInput.addEventListener('cancel', this.onCancelInternal)
        fileInput.click()
        this.fileInput = fileInput
    }
    private onChange = async (event: Event) => {
        const files = (event.target as HTMLInputElement).files
        if (files !== null) {
            if (this.onSelect !== undefined) {
                this.onSelect(files)
            }
        }
        if (this.autoClose) {
            this.dispose()
        }
    }
    private onCancelInternal = async (event: Event) => {
        if (this.autoClose) {
            this.dispose()
        }
        if (this.onCancel !== undefined) {
            this.onCancel()
        }
    }
    private dispose() {
        if (this.fileInput !== null) {
            this.parentElem.removeChild(this.fileInput)
            this.fileInput.removeEventListener('change', this.onChange)
            this.fileInput.removeEventListener('cancel', this.onCancelInternal)
            this.fileInput.remove()
            this.fileInput = null
        }
    }
}

使い方は、こんな感じ。

let openUI: FileSelect | null = null
openUI = new FileSelect()
openUI.onSelect = async (files: FileList) => {
    //選択したコンテンツを保存してプレイリストとして利用する
}

次は「YouTube IFrame Player API」編

普通に、ブラウザとかYouTubeアプリで再生すればいいのかもだが、とりあえず挑戦してみる。

つづく。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?