📹

Flutterでmp4の動画を再生する方法 video_player

2023/07/02に公開

今回は、flutterでビデオを再生する方法を簡単に紹介します。

Flutterでさまざまなアプリを作成していくうちに『動画アプリを作ってみたい』となりました。
しかし、多くの記事は少し古かったり、サンプルプログラムが分かりづらい物ばっかりでしたので簡単に動かせて分かりやすいアプリを作りました。
これから動画アプリの作成方法を学習する方は、この記事を読むことで少し理解度が上がるかもしれません。

✅今回の内容

  1. 事前準備
  2. 使用するサンプルプログラムの配布
  3. 実際に動かしてみる

✅メイン内容

🛠 事前準備

1. 使用するパッケージ

今回、flutterでビデオアプリを作成するためにvideo_playerというパッケージを使用します。

こちらをpubspec.yamlに追加しましょう。

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  //ここ
  video_player: ^2.7.0

2. 動画ファイルを用意する

今回、サンプルプログラムで使用した動画はTwitter投稿した動画になります。
https://twitter.com/LisRas_Team/status/1675085390099943424?s=20

この動画はGithubのリポジトリに梱包されているので同じ動画を使用する方はGithubからcloneしてください。

https://github.com/LisRas-code/zenn_video_app/tree/master

自分で用意した動画ファイルを使用する方は、以下の手順を行います。

  1. プロジェクト直下にassetsフォルダを作成する
  2. pubspec.yamlでassetsを指定する

1.でプロジェクト直下にassetsフォルダを作成したら、
その中に自分で用意した動画ファイルを入れます。

2.ではpubspec.yamlを開いてassetsを指定します。

これで動画ファイルを使用する準備が整いました。🍎


🛠 使用するサンプルプログラムの配布

1. アプリの解説

今回作成したビデオアプリはとてもシンプルです。

右下のボタンを押して、ビデオ再生に使用するVideoPlayerControllerを初期化します。
(これがかなり時間かかる処理です)

初期化中はCircularProgressIndicatorをクルクルさせておき、
初期化が完了したら動画再生の画面が表示される仕組みです。

今回、特に詳しい説明等はありませんが、やっている事は
コントローラー初期化 → 初期化中をUIで表示 → 完了後動画再生
と非常にシンプルです。
ただ、コントローラーの初期化にこんなに時間かかることを知らず、学習中、疑問に思う時間が長かったので混乱しないためのプログラムを置いておきました。


2. サンプルプログラムの配布

Githubからcloneする人は、
2. 動画ファイルを用意するでリポジトリ載せてますのでそちらを使用してください。

サンプルプログラムは、下記になります。

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(),
      home: const MyHomePage(title: 'Video demo flutter'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late VideoPlayerController _controller;
  bool initSwitch = false;
  bool complate = false;
  bool playSwitch = false;

  
  void initState() {
    super.initState();
  }

  Future<void> _initVideoPlayer() async {
    _controller = VideoPlayerController.asset('assets/test_video.mp4');
    await _controller.initialize();
  }

  
  Widget build(BuildContext context) {
    return initSwitch
        ? !complate
            ? Scaffold(
                appBar: AppBar(
                  title: Text("${widget.title}"),
                ),
                body: const Center(
                    child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    CircularProgressIndicator(),
                    Text("ローディング中"),
                  ],
                )),
              )
            : Scaffold(
                appBar: AppBar(
                  title: Text("${widget.title}"),
                ),
                body: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    AspectRatio(
                      aspectRatio: _controller.value.aspectRatio,
                      // 動画を表示
                      child: VideoPlayer(_controller),
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        IconButton(
                          onPressed: () {
                            // 動画を最初から再生
                            _controller
                                .seekTo(Duration.zero)
                                .then((_) => _controller.play());
                            playSwitch = true;
                            setState(() {});
                          },
                          icon: const Icon(Icons.refresh),
                        ),
                        playSwitch
                            ? IconButton(
                                onPressed: () {
                                  // 動画を一時停止
                                  _controller.pause();
                                  playSwitch = !playSwitch;
                                  setState(() {});
                                },
                                icon: const Icon(Icons.pause),
                              )
                            : IconButton(
                                onPressed: () {
                                  // 動画を再生
                                  _controller.play();
                                  playSwitch = !playSwitch;
                                  setState(() {});
                                },
                                icon: const Icon(Icons.play_arrow),
                              )
                      ],
                    ),
                  ],
                ),
              )
        : Scaffold(
            appBar: AppBar(
              title: Text("${widget.title}"),
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: () async {
                initSwitch = true;
                setState(() {});
                await _initVideoPlayer();
                complate = true;
                setState(() {});
              },
              child: const Icon(Icons.play_circle_outline),
            ),
          );
  }
}

自分で用意した動画を使われる人は、
assetの()の中を自分の動画ファイルの名前に変更してください。

  Future<void> _initVideoPlayer() async {
    _controller = VideoPlayerController.asset('assets/test_video.mp4');
    await _controller.initialize();
  }

🛠 実際に動かしてみる

なぜか分からないけど、キャプチャしたら初期化が早くなりました...
原因調査中ですが、一旦早いバージョンを載せて起きます。


✅まとめ

一時期、初期化が長かった原因はまだ特定できていないので、判明し次第記事を書こうと思います。(キャッシュ等の問題では無かった)

似たような現象がもし起こったら、TwitterでDMをくださると嬉しいです!

https://twitter.com/LisRas_Team

今回はここまで 

Discussion