今回の記事はFlutterでカメラ画面から動画を撮影する手順をご紹介です。
今回の記事に関してはカメラのFlutterプラグインがすでに用意されているのでそこに加えて動画を撮影するために必要なプラグインのご紹介とコードについてご紹介していきます。
まず今回の方針に関してですが、まずは「Android StudioにFlutter環境構築」→「Android studioにFlutterの必要なプラグインなどのインストール設定」→「Flutterのカメラアプリを作成し、動画を撮影する」という流れです。
では早速進んでいきましょう。
Android StudioにFlutter環境構築
こちらに関しては以前の記事で環境構築を行っているのでリンク記事よりご参照ください。
Fluttreの環境構築が完了している方は飛ばしていただいて問題ございません。
Android studioにFlutterのプラグインインストールの設定
次に今回使用するプラグインについてですが、下記です。
dependencies:
camera: ^0.5.8+5
path_provider: ^1.6.14
path: ^1.7.0
flutter:
sdk: flutter
こちらを「pub-get」すればインストール完了です。
私は初め動画に関してはcamera以外の専用のライブラリがあるのかと思っており、「video_player」のライブラリを使うものと考えていまいしたが、実際のところ「video_player」はmp4ファイルなどの動画ファイルをAndroid上で再生するためのプラグインということがわかりました。そのため動画の撮影のみの場合は、「camera」プラグインのみで問題ないようです。
「camera」と「video_player」プラグインを両方使用した撮影した動画を端末内で再生しているサンプルはFlutterの公式ドキュメントにのっているのでそのようなアプリを作ろうとしている方はその「example」からどのようなコードでどのような動きになるかを確認することをおすすめします。リンクは下記です。
「公式Flutter「camera」プラグインのドキュメント」
では実際のコードを見ていきましょう。
Flutterでカメラから動画を撮影するコード
まずは全体の「main.dart」ファイルを記載します。先に誤っておきますが、別目的で記述していたファイルから動画メソッドになる部分を抜き取ったため少し汚いコードになっておりますがご了承ください。
import 'package:flutter/services.dart';
import 'dart:async';
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();// runAppが実行される前に、cameraプラグインを初期化
final cameras = await availableCameras();// デバイスで使用可能なカメラの一覧を取得する
final firstCamera = cameras.first;// 利用可能なカメラの一覧から、指定のカメラを取得する
runApp(MyApp(camera: firstCamera));//メイン関数
}
class MyApp extends StatelessWidget {
final CameraDescription camera;
const MyApp({Key key, @required this.camera}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'camera_demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: CameraHome(
camera: camera,
),
);
}
}
class CameraHome extends StatefulWidget {
final CameraDescription camera;
const CameraHome({Key key, @required this.camera}) : super(key: key);
@override
State<StatefulWidget> createState() => CameraHomeState();
}
class CameraHomeState extends State<CameraHome> {
static const platform = const MethodChannel('samples.flutter.dev/battery');
StreamSubscription _intentDataStreamSubscription;
CameraController _cameraController;// デバイスのカメラを制御するコントローラ
Future<void> _initializeCameraController;// コントローラーに設定されたカメラを初期化する関数
@override
void initState() {
super.initState();
// コントローラを初期化 使用するカメラをコントローラに設定
_cameraController = CameraController(
widget.camera,
// low : 352x288 on iOS, 240p (320x240) on Android// 使用する解像度を設定
// medium : 480p (640x480 on iOS, 720x480 on Android)
// high : 720p (1280x720)
// veryHigh : 1080p (1920x1080)
// ultraHigh : 2160p (3840x2160)
// max : 利用可能な最大の解像度
ResolutionPreset.max);
_initializeCameraController = _cameraController.initialize();// コントローラーに設定されたカメラを初期化
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(''),
),
body: FutureBuilder<void>(
future: _initializeCameraController,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// カメラの初期化が完了したら、プレビューを表示
return CameraPreview(_cameraController);
} else {
// カメラの初期化中はインジケーターを表示
return const Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.videocam),
// ボタンが押下された際動画撮影
//////////////////下記で解説/////////////////////////
onPressed: () async {
try {
//カメラの初期化がなされていない場合抜ける
if (!_cameraController.value.isInitialized) {
print("初期化ができていません。");
return;
}
//すでにカメラの録画が始まっている際には録画をストップしてjavaをcall
if (_cameraController.value.isRecordingVideo) {
print("動画撮影終了");
_cameraController.stopVideoRecording();//カメラを止める&保存
return;
}
final Directory appDirectory = await getApplicationDocumentsDirectory();
final String videoDirectory = '${appDirectory.path}/Videos';//内部ストレージ用のフォルダpath
await Directory(videoDirectory).create(recursive: true);//内部ストレージ用のフォルダ作成
final String filePath = '$videoDirectory/test.mp4';//内部ストレージに保存する用のpath
print(filePath);//ここで表示されるpathに動画が入っている
try {
await _cameraController.startVideoRecording(filePath);
print("動画撮影開始");
} on CameraException catch (e) {
print("動画撮影ができません");
}
} catch (e) {
print(e);
}
},
),
);
}
}
「下記で解説」とコメントアウトしている部分がカメラでの動画撮影部分です。同じボタンをクリックして1度目の起動で撮影開始、2度目の起動で撮影終了と保存を行っております。
カメラの撮影オブジェクトにあたる「_cameraController」の状態をprintなどで見ていただけるとわかりやすいかもしれませんが「_cameraController.startVideoRecording」により「_cameraController.value.isRecordingVideo」の部分で分岐が起きているように「_cameraController.value」が「isRecordingVideo =false」から「isRecordingVideo =true」に変化しております。これは「stopVideoRecording()」でfalseに戻すことができるのでボタンを押すごとに撮影と終了&保存を切り替えられるという仕組みになっております。
言葉にすると長くなりますが実際にコードを動かしてもらえればコンソールから状況が分かるようにしておりますのでわかりやすいかと思います。
では今回の記事は以上です。他にもこの撮影したファイルをAWSのS3に上げるなどの操作をFlutterで行っている記事を記載しているので気になる方はご参照ください。
コメント