flutter_video_compress 0.3.7+8 flutter_video_compress: ^0.3.7+8 copied to clipboard
Generate a new file by compressed video, and provide metadata. Get video thumbnail from a video path, supports JPEG/GIF. To reduce app size not using FFmpeg in IOS.
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_video_compress/flutter_video_compress.dart';
import 'package:image_picker/image_picker.dart' show ImagePicker, ImageSource;
import 'package:video_player/video_player.dart';
import 'my-theme.dart';
void main() => runApp(MyApp(title: 'Flutter Video Compress Example'));
class MyApp extends StatefulWidget {
MyApp({this.title});
final String title;
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _flutterVideoCompress = FlutterVideoCompress();
Subscription _subscription;
Image _thumbnailFileImage;
Image _gifFileImage;
MediaInfo _originalVideoInfo = MediaInfo(path: '');
MediaInfo _compressedVideoInfo = MediaInfo(path: '');
String _taskName;
double _progressState = 0;
final _loadingStreamCtrl = StreamController<bool>.broadcast();
@override
void initState() {
super.initState();
_subscription =
_flutterVideoCompress.compressProgress$.subscribe((progress) {
setState(() {
_progressState = progress;
});
});
}
@override
void dispose() {
super.dispose();
_subscription.unsubscribe();
_loadingStreamCtrl.close();
}
Future<void> runFlutterVideoCompressMethods(File videoFile) async {
_loadingStreamCtrl.sink.add(true);
var _startDateTime = DateTime.now();
print('[Compressing Video] start');
_taskName = '[Compressing Video]';
final compressedVideoInfo = await _flutterVideoCompress.compressVideo(
videoFile.path,
quality: VideoQuality.DefaultQuality,
deleteOrigin: false,
);
_taskName = null;
print(
'[Compressing Video] done! ${DateTime.now().difference(_startDateTime).inSeconds}s');
_startDateTime = DateTime.now();
print('[Getting Thumbnail File] start');
final thumbnailFile = await _flutterVideoCompress
.getThumbnailWithFile(videoFile.path, quality: 50);
print(
'[Getting Thumbnail File] done! ${DateTime.now().difference(_startDateTime).inSeconds}s');
_startDateTime = DateTime.now();
print('[Getting Gif File] start');
_taskName = '[Getting Gif File]';
final gifFile = await _flutterVideoCompress
.convertVideoToGif(videoFile.path, startTime: 0, duration: 5);
print(
'[Getting Gif File] done! ${DateTime.now().difference(_startDateTime).inSeconds}s');
_taskName = null;
final videoInfo = await _flutterVideoCompress.getMediaInfo(videoFile.path);
setState(() {
_thumbnailFileImage = Image.file(thumbnailFile);
_gifFileImage = Image.file(gifFile);
_originalVideoInfo = videoInfo;
_compressedVideoInfo = compressedVideoInfo;
});
_loadingStreamCtrl.sink.add(false);
}
Widget _buildMaterialWarp(Widget body) {
return MaterialApp(
title: widget.title,
theme: myTheme,
home: Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
IconButton(
onPressed: () async {
await _flutterVideoCompress.deleteAllCache();
},
icon: Icon(Icons.delete_forever),
),
],
),
body: body),
);
}
Widget _buildRoundedRectangleButton(String text, ImageSource source) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: RaisedButton(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
child: Text(text, style: TextStyle(color: Colors.white)),
color: Colors.grey[800],
onPressed: () async {
final videoFile = await ImagePicker.pickVideo(source: source);
if (videoFile != null) {
runFlutterVideoCompressMethods(videoFile);
}
},
),
);
}
String _infoConvert(MediaInfo info) {
return 'path: ${info.path}\n'
'duration: ${info.duration} microseconds\n'
'size: ${info.filesize} bytes\n'
'size: ${info.width} x ${info.height}\n'
'orientation: ${info.orientation}°\n'
'compression cancelled: ${info.isCancel}\n'
'author: ${info.author}';
}
List<Widget> _buildInfoPanel(String title,
{MediaInfo info, Image image, bool isVideoModel = false}) {
if (info?.file == null && image == null && !isVideoModel) return [];
return [
if (!isVideoModel || info?.file != null)
Card(
child: ListTile(
title: Text(title),
dense: true,
),
),
if (info?.file != null)
Padding(
padding: const EdgeInsets.all(8),
child: Text(_infoConvert(info)),
),
if (image != null) image,
if (isVideoModel && info?.file != null) VideoPlayerView(file: info.file)
];
}
@override
Widget build(context) {
return _buildMaterialWarp(
Stack(children: <Widget>[
ListView(
children: <Widget>[
const SizedBox(height: 20),
_buildRoundedRectangleButton(
'Take video from camera with Image Picker',
ImageSource.camera,
),
_buildRoundedRectangleButton(
'Take video from gallery with Image Picker',
ImageSource.gallery,
),
..._buildInfoPanel(
'Original video information',
info: _originalVideoInfo,
),
..._buildInfoPanel(
'Original video view',
info: _originalVideoInfo,
isVideoModel: true,
),
..._buildInfoPanel(
'Compressed video information',
info: _compressedVideoInfo,
),
..._buildInfoPanel(
'Compressed video view',
info: _compressedVideoInfo,
isVideoModel: true,
),
..._buildInfoPanel(
'Thumbnail image from file preview',
image: _thumbnailFileImage,
),
..._buildInfoPanel(
'Gif image from original video preview',
image: _gifFileImage,
),
].expand((widget) {
if (widget is SizedBox || widget is Card) {
return [widget];
}
return [widget, const SizedBox(height: 8)];
}).toList(),
),
StreamBuilder<bool>(
stream: _loadingStreamCtrl.stream,
builder: (context, AsyncSnapshot<bool> snapshot) {
if (snapshot.data == true) {
return GestureDetector(
onTap: () {
_flutterVideoCompress.cancelCompression();
},
child: Card(
child: Container(
color: Colors.black54,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
CircularProgressIndicator(),
if (_taskName != null)
Padding(
padding: const EdgeInsets.all(8),
child: Text('[$_taskName] $_progressState%'),
),
Padding(
padding: const EdgeInsets.all(8),
child: const Text('click cancel...'),
)
],
),
),
),
);
}
return Container();
},
),
]),
);
}
}
class VideoPlayerView extends StatefulWidget {
VideoPlayerView({this.file});
final File file;
@override
_VideoPlayerViewState createState() => _VideoPlayerViewState();
}
class _VideoPlayerViewState extends State<VideoPlayerView> {
VideoPlayerController _controller;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.file(widget.file)
..initialize().then((_) {
setState(() {});
})
..setVolume(1)
..play();
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(context) {
return GestureDetector(
onTap: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Stack(
alignment: Alignment.center,
children: <Widget>[
_controller.value.initialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
: Container(),
Icon(
_controller.value.isPlaying ? null : Icons.play_arrow,
size: 80,
),
],
),
VideoProgressIndicator(
_controller,
allowScrubbing: true,
colors: VideoProgressColors(
playedColor: Color.fromRGBO(255, 255, 255, 0.1),
),
),
],
),
),
);
}
}