123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887 |
- import 'dart:async';
- import 'dart:io';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter_ffmpeg/flutter_ffmpeg.dart';
- import 'package:flutter_ffmpeg/log_level.dart';
- import 'package:path/path.dart';
- import 'package:path_provider/path_provider.dart';
- void main() => runApp(FlutterFFmpegTestApp());
- class FlutterFFmpegTestApp extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- theme: ThemeData(
- primaryColor: Color(0xFFF46842),
- ),
- home: MainPage(),
- );
- }
- }
- class MainPage extends StatefulWidget {
- @override
- FlutterFFmpegTestAppState createState() => new FlutterFFmpegTestAppState();
- }
- class DecoratedTabBar extends StatelessWidget implements PreferredSizeWidget {
- DecoratedTabBar({@required this.tabBar, @required this.decoration});
- final TabBar tabBar;
- final BoxDecoration decoration;
- @override
- Size get preferredSize => tabBar.preferredSize;
- @override
- Widget build(BuildContext context) {
- return Stack(
- children: [
- Positioned.fill(child: Container(decoration: decoration)),
- tabBar,
- ],
- );
- }
- }
- class VideoUtil {
- static Future<Directory> get tempDirectory async {
- return await getTemporaryDirectory();
- }
- static Future<File> copyFileAssets(String assetName, String localName) async {
- final ByteData assetByteData = await rootBundle.load(assetName);
- final List<int> byteList = assetByteData.buffer
- .asUint8List(assetByteData.offsetInBytes, assetByteData.lengthInBytes);
- final String fullTemporaryPath =
- join((await tempDirectory).path, localName);
- return new File(fullTemporaryPath)
- .writeAsBytes(byteList, mode: FileMode.writeOnly, flush: true);
- }
- static Future<String> assetPath(String assetName) async {
- return join((await tempDirectory).path, assetName);
- }
- static String generateEncodeVideoScript(
- String image1Path,
- String image2Path,
- String image3Path,
- String videoFilePath,
- String videoCodec,
- String customOptions) {
- return "-hide_banner -y -loop 1 -i '" +
- image1Path +
- "' " +
- "-loop 1 -i \"" +
- image2Path +
- "\" " +
- "-loop 1 -i \"" +
- image3Path +
- "\" " +
- "-filter_complex " +
- "\"[0:v]setpts=PTS-STARTPTS,scale=w='if(gte(iw/ih,640/427),min(iw,640),-1)':h='if(gte(iw/ih,640/427),-1,min(ih,427))',scale=trunc(iw/2)*2:trunc(ih/2)*2,setsar=sar=1/1,split=2[stream1out1][stream1out2];" +
- "[1:v]setpts=PTS-STARTPTS,scale=w='if(gte(iw/ih,640/427),min(iw,640),-1)':h='if(gte(iw/ih,640/427),-1,min(ih,427))',scale=trunc(iw/2)*2:trunc(ih/2)*2,setsar=sar=1/1,split=2[stream2out1][stream2out2];" +
- "[2:v]setpts=PTS-STARTPTS,scale=w='if(gte(iw/ih,640/427),min(iw,640),-1)':h='if(gte(iw/ih,640/427),-1,min(ih,427))',scale=trunc(iw/2)*2:trunc(ih/2)*2,setsar=sar=1/1,split=2[stream3out1][stream3out2];" +
- "[stream1out1]pad=width=640:height=427:x=(640-iw)/2:y=(427-ih)/2:color=#00000000,trim=duration=3,select=lte(n\\,90)[stream1overlaid];" +
- "[stream1out2]pad=width=640:height=427:x=(640-iw)/2:y=(427-ih)/2:color=#00000000,trim=duration=1,select=lte(n\\,30)[stream1ending];" +
- "[stream2out1]pad=width=640:height=427:x=(640-iw)/2:y=(427-ih)/2:color=#00000000,trim=duration=2,select=lte(n\\,60)[stream2overlaid];" +
- "[stream2out2]pad=width=640:height=427:x=(640-iw)/2:y=(427-ih)/2:color=#00000000,trim=duration=1,select=lte(n\\,30),split=2[stream2starting][stream2ending];" +
- "[stream3out1]pad=width=640:height=427:x=(640-iw)/2:y=(427-ih)/2:color=#00000000,trim=duration=2,select=lte(n\\,60)[stream3overlaid];" +
- "[stream3out2]pad=width=640:height=427:x=(640-iw)/2:y=(427-ih)/2:color=#00000000,trim=duration=1,select=lte(n\\,30)[stream3starting];" +
- "[stream2starting][stream1ending]blend=all_expr='if(gte(X,(W/2)*T/1)*lte(X,W-(W/2)*T/1),B,A)':shortest=1[stream2blended];" +
- "[stream3starting][stream2ending]blend=all_expr='if(gte(X,(W/2)*T/1)*lte(X,W-(W/2)*T/1),B,A)':shortest=1[stream3blended];" +
- "[stream1overlaid][stream2blended][stream2overlaid][stream3blended][stream3overlaid]concat=n=5:v=1:a=0,scale=w=640:h=424,format=yuv420p[video]\"" +
- " -map [video] -vsync 2 -async 1 " +
- customOptions +
- "-c:v " +
- videoCodec +
- " -r 30 " +
- videoFilePath;
- }
- }
- class FlutterFFmpegTestAppState extends State<MainPage>
- with TickerProviderStateMixin {
- static const String ASSET_1 = "1.jpg";
- static const String ASSET_2 = "2.jpg";
- static const String ASSET_3 = "3.jpg";
- final FlutterFFmpegConfig _flutterFFmpegConfig = new FlutterFFmpegConfig();
- final FlutterFFmpeg _flutterFFmpeg = new FlutterFFmpeg();
- final FlutterFFprobe _flutterFFprobe = new FlutterFFprobe();
- TextEditingController _commandController;
- TabController _controller;
- String _commandOutput;
- String _encodeOutput;
- String _currentCodec;
- List<DropdownMenuItem<String>> _codecDropDownMenuItems;
- @override
- void initState() {
- super.initState();
- _commandController = TextEditingController();
- _controller = TabController(length: 2, vsync: this);
- _commandOutput = "";
- _encodeOutput = "";
- _codecDropDownMenuItems = _getCodecDropDownMenuItems();
- _currentCodec = _codecDropDownMenuItems[0].value;
- startupTests();
- prepareAssets();
- }
- void startupTests() {
- getFFmpegVersion().then((version) => print("FFmpeg version: $version"));
- getPlatform().then((platform) => print("Platform: $platform"));
- getLogLevel().then(
- (level) => print("Old log level: " + LogLevel.levelToString(level)));
- setLogLevel(LogLevel.AV_LOG_INFO);
- getLogLevel().then(
- (level) => print("New log level: " + LogLevel.levelToString(level)));
- getPackageName().then((packageName) => print("Package name: $packageName"));
- getExternalLibraries().then((packageList) {
- packageList.forEach((value) => print("External library: $value"));
- });
- }
- void prepareAssets() {
- VideoUtil.copyFileAssets('assets/pyramid.jpg', ASSET_1)
- .then((path) => print('Loaded asset $path.'));
- VideoUtil.copyFileAssets('assets/colosseum.jpg', ASSET_2)
- .then((path) => print('Loaded asset $path.'));
- VideoUtil.copyFileAssets('assets/tajmahal.jpg', ASSET_3)
- .then((path) => print('Loaded asset $path.'));
- }
- void testParseArguments() {
- testParseSimpleCommand();
- testParseSingleQuotesInCommand();
- testParseDoubleQuotesInCommand();
- testParseDoubleQuotesAndEscapesInCommand();
- }
- void testRunFFmpegCommand() {
- getLastReturnCode().then((rc) => print("Last rc: $rc"));
- getLastCommandOutput().then((output) =>
- debugPrint("Last command output: \"$output\"", wrapWidth: 1024));
- print("Testing ParseArguments.");
- testParseArguments();
- registerNewFFmpegPipe().then((path) => print("New FFmpeg pipe: $path"));
- print("Testing FFmpeg COMMAND.");
- // ENABLE LOG CALLBACK ON EACH CALL
- _flutterFFmpegConfig.enableLogCallback(commandOutputLogCallback);
- _flutterFFmpegConfig.enableStatisticsCallback(statisticsCallback);
- // CLEAR OUTPUT ON EACH EXECUTION
- _commandOutput = "";
- // COMMENT OPTIONAL TESTS
- // VideoUtil.tempDirectory.then((tempDirectory) {
- // Map<String, String> mapNameMap = new Map();
- // mapNameMap["my_custom_font"] = "my custom font";
- // setFontDirectory(tempDirectory.path, null);
- // });
- VideoUtil.tempDirectory.then((tempDirectory) {
- setFontconfigConfigurationPath(tempDirectory.path);
- });
- // disableRedirection();
- // disableLogs();
- // enableLogs();
- executeFFmpeg(_commandController.text)
- .then((rc) => print("FFmpeg process exited with rc $rc"));
- // executeWithArguments(_commandController.text.split(" ")).then((rc) => print("FFmpeg process exited with rc $rc"));
- setState(() {});
- }
- void testRunFFprobeCommand() {
- getLastReturnCode().then((rc) => print("Last rc: $rc"));
- getLastCommandOutput().then((output) =>
- debugPrint("Last command output: \"$output\"", wrapWidth: 1024));
- print("Testing ParseArguments.");
- testParseArguments();
- registerNewFFmpegPipe().then((path) => print("New FFmpeg pipe: $path"));
- print("Testing FFprobe COMMAND.");
- // ENABLE LOG CALLBACK ON EACH CALL
- _flutterFFmpegConfig.enableLogCallback(commandOutputLogCallback);
- _flutterFFmpegConfig.enableStatisticsCallback(statisticsCallback);
- // CLEAR OUTPUT ON EACH EXECUTION
- _commandOutput = "";
- VideoUtil.tempDirectory.then((tempDirectory) {
- setFontconfigConfigurationPath(tempDirectory.path);
- });
- executeFFprobe(_commandController.text)
- .then((rc) => print("FFprobe process exited with rc $rc"));
- setState(() {});
- }
- void testGetMediaInformation(String mediaPath) {
- print("Testing Get Media Information.");
- // ENABLE LOG CALLBACK ON EACH CALL
- _flutterFFmpegConfig.enableLogCallback(commandOutputLogCallback);
- _flutterFFmpegConfig.enableStatisticsCallback(null);
- // CLEAR OUTPUT ON EACH EXECUTION
- _commandOutput = "";
- VideoUtil.assetPath(mediaPath).then((image1Path) {
- getMediaInformation(image1Path).then((info) {
- print('Media Information');
- print('Path: ${info['path']}');
- print('Format: ${info['format']}');
- print('Duration: ${info['duration']}');
- print('Start time: ${info['startTime']}');
- print('Bitrate: ${info['bitrate']}');
- if (info['streams'] != null) {
- final streamsInfoArray = info['streams'];
- if (streamsInfoArray.length > 0) {
- for (var streamsInfo in streamsInfoArray) {
- print('Stream id: ${streamsInfo['index']}');
- print('Stream type: ${streamsInfo['type']}');
- print('Stream codec: ${streamsInfo['codec']}');
- print('Stream full codec: ${streamsInfo['fullCodec']}');
- print('Stream format: ${streamsInfo['format']}');
- print('Stream full format: ${streamsInfo['fullFormat']}');
- print('Stream width: ${streamsInfo['width']}');
- print('Stream height: ${streamsInfo['height']}');
- print('Stream bitrate: ${streamsInfo['bitrate']}');
- print('Stream sample rate: ${streamsInfo['sampleRate']}');
- print('Stream sample format: ${streamsInfo['sampleFormat']}');
- print('Stream channel layout: ${streamsInfo['channelLayout']}');
- print('Stream sar: ${streamsInfo['sampleAspectRatio']}');
- print('Stream dar: ${streamsInfo['displayAspectRatio']}');
- print(
- 'Stream average frame rate: ${streamsInfo['averageFrameRate']}');
- print('Stream real frame rate: ${streamsInfo['realFrameRate']}');
- print('Stream time base: ${streamsInfo['timeBase']}');
- print('Stream codec time base: ${streamsInfo['codecTimeBase']}');
- final metadataMap = streamsInfo['metadata'];
- if (metadataMap != null) {
- print('Stream metadata encoder: ${metadataMap['encoder']}');
- print('Stream metadata rotate: ${metadataMap['rotate']}');
- print(
- 'Stream metadata creation time: ${metadataMap['creation_time']}');
- print(
- 'Stream metadata handler name: ${metadataMap['handler_name']}');
- }
- final sideDataMap = streamsInfo['sidedata'];
- if (sideDataMap != null) {
- print(
- 'Stream side data displaymatrix: ${sideDataMap['displaymatrix']}');
- }
- }
- }
- }
- });
- });
- setState(() {});
- }
- void testEncodeVideo() {
- print("Testing VIDEO.");
- // ENABLE LOG CALLBACK ON EACH CALL
- _flutterFFmpegConfig.enableLogCallback(encodeOutputLogCallback);
- _flutterFFmpegConfig.enableStatisticsCallback(statisticsCallback);
- // CLEAR OUTPUT ON EACH EXECUTION
- _encodeOutput = "";
- disableStatistics();
- enableStatistics();
- VideoUtil.assetPath(ASSET_1).then((image1Path) {
- VideoUtil.assetPath(ASSET_2).then((image2Path) {
- VideoUtil.assetPath(ASSET_3).then((image3Path) {
- final String videoPath = getVideoPath();
- final String customOptions = getCustomEncodingOptions();
- final String ffmpegCodec = getFFmpegCodecName();
- VideoUtil.assetPath(videoPath).then((fullVideoPath) {
- executeFFmpeg(VideoUtil.generateEncodeVideoScript(image1Path, image2Path,
- image3Path, fullVideoPath, ffmpegCodec, customOptions))
- .then((rc) {
- if (rc == 0) {
- testGetMediaInformation(fullVideoPath);
- }
- });
- // resetStatistics();
- getLastReceivedStatistics().then((lastStatistics) {
- if (lastStatistics == null) {
- print('No last statistics');
- } else {
- print('Last statistics');
- int time = lastStatistics['time'];
- int size = lastStatistics['size'];
- double bitrate = _doublePrecision(lastStatistics['bitrate'], 2);
- double speed = _doublePrecision(lastStatistics['speed'], 2);
- int videoFrameNumber = lastStatistics['videoFrameNumber'];
- double videoQuality =
- _doublePrecision(lastStatistics['videoQuality'], 2);
- double videoFps =
- _doublePrecision(lastStatistics['videoFps'], 2);
- statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
- videoQuality, videoFps);
- }
- });
- });
- });
- });
- });
- setState(() {});
- }
- void commandOutputLogCallback(int level, String message) {
- _commandOutput += message;
- setState(() {});
- }
- void encodeOutputLogCallback(int level, String message) {
- _encodeOutput += message;
- setState(() {});
- }
- void statisticsCallback(int time, int size, double bitrate, double speed,
- int videoFrameNumber, double videoQuality, double videoFps) {
- print(
- "Statistics: time: $time, size: $size, bitrate: $bitrate, speed: $speed, videoFrameNumber: $videoFrameNumber, videoQuality: $videoQuality, videoFps: $videoFps");
- }
- Future<String> getFFmpegVersion() async {
- return await _flutterFFmpegConfig.getFFmpegVersion();
- }
- Future<String> getPlatform() async {
- return await _flutterFFmpegConfig.getPlatform();
- }
- Future<int> executeFFmpegWithArguments(List arguments) async {
- return await _flutterFFmpeg.executeWithArguments(arguments);
- }
- Future<int> executeFFmpeg(String command) async {
- return await _flutterFFmpeg.execute(command);
- }
- Future<int> executeFFprobeWithArguments(List arguments) async {
- return await _flutterFFprobe.executeWithArguments(arguments);
- }
- Future<int> executeFFprobe(String command) async {
- return await _flutterFFprobe.execute(command);
- }
- Future<void> cancel() async {
- return await _flutterFFmpeg.cancel();
- }
- Future<void> disableRedirection() async {
- return await _flutterFFmpegConfig.disableRedirection();
- }
- Future<int> getLogLevel() async {
- return await _flutterFFmpegConfig.getLogLevel();
- }
- Future<void> setLogLevel(int logLevel) async {
- return await _flutterFFmpegConfig.setLogLevel(logLevel);
- }
- Future<void> enableLogs() async {
- return await _flutterFFmpegConfig.enableLogs();
- }
- Future<void> disableLogs() async {
- return await _flutterFFmpegConfig.disableLogs();
- }
- Future<void> enableStatistics() async {
- return await _flutterFFmpegConfig.enableStatistics();
- }
- Future<void> disableStatistics() async {
- return await _flutterFFmpegConfig.disableStatistics();
- }
- Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
- return await _flutterFFmpegConfig.getLastReceivedStatistics();
- }
- Future<void> resetStatistics() async {
- return await _flutterFFmpegConfig.resetStatistics();
- }
- Future<void> setFontconfigConfigurationPath(String path) async {
- return await _flutterFFmpegConfig.setFontconfigConfigurationPath(path);
- }
- Future<void> setFontDirectory(
- String fontDirectory, Map<String, String> fontNameMap) async {
- return await _flutterFFmpegConfig.setFontDirectory(fontDirectory, fontNameMap);
- }
- Future<String> getPackageName() async {
- return await _flutterFFmpegConfig.getPackageName();
- }
- Future<List<dynamic>> getExternalLibraries() async {
- return await _flutterFFmpegConfig.getExternalLibraries();
- }
- Future<int> getLastReturnCode() async {
- return await _flutterFFmpegConfig.getLastReturnCode();
- }
- Future<String> getLastCommandOutput() async {
- return await _flutterFFmpegConfig.getLastCommandOutput();
- }
- Future<Map<dynamic, dynamic>> getMediaInformation(String path) async {
- return await _flutterFFprobe.getMediaInformation(path);
- }
- Future<String> registerNewFFmpegPipe() async {
- return await _flutterFFmpegConfig.registerNewFFmpegPipe();
- }
- void _changedCodec(String selectedCodec) {
- setState(() {
- _currentCodec = selectedCodec;
- });
- }
- String getFFmpegCodecName() {
- String ffmpegCodec = _currentCodec;
- // VIDEO CODEC MENU HAS BASIC NAMES, FFMPEG NEEDS LONGER LIBRARY NAMES.
- if (ffmpegCodec == "x264") {
- ffmpegCodec = "libx264";
- } else if (ffmpegCodec == "x265") {
- ffmpegCodec = "libx265";
- } else if (ffmpegCodec == "xvid") {
- ffmpegCodec = "libxvid";
- } else if (ffmpegCodec == "vp8") {
- ffmpegCodec = "libvpx";
- } else if (ffmpegCodec == "vp9") {
- ffmpegCodec = "libvpx-vp9";
- }
- return ffmpegCodec;
- }
- String getVideoPath() {
- String ffmpegCodec = _currentCodec;
- String videoPath;
- if ((ffmpegCodec == "vp8") || (ffmpegCodec == "vp9")) {
- videoPath = "video.webm";
- } else {
- // mpeg4, x264, x265, xvid
- videoPath = "video.mp4";
- }
- return videoPath;
- }
- String getCustomEncodingOptions() {
- String videoCodec = _currentCodec;
- if (videoCodec == "x265") {
- return "-crf 28 -preset fast ";
- } else if (videoCodec == "vp8") {
- return "-b:v 1M -crf 10 ";
- } else if (videoCodec == "vp9") {
- return "-b:v 2M ";
- } else {
- return "";
- }
- }
- List<DropdownMenuItem<String>> _getCodecDropDownMenuItems() {
- List<DropdownMenuItem<String>> items = new List();
- items.add(new DropdownMenuItem(value: "mpeg4", child: new Text("mpeg4")));
- items.add(new DropdownMenuItem(value: "x264", child: new Text("x264")));
- items.add(new DropdownMenuItem(value: "x265", child: new Text("x265")));
- items.add(new DropdownMenuItem(value: "xvid", child: new Text("xvid")));
- items.add(new DropdownMenuItem(value: "vp8", child: new Text("vp8")));
- items.add(new DropdownMenuItem(value: "vp9", child: new Text("vp9")));
- return items;
- }
- double _doublePrecision(double value, int precision) {
- if (value == null) {
- return 0;
- } else {
- return num.parse(value.toStringAsFixed(precision));
- }
- }
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text('FlutterFFmpeg Test'),
- centerTitle: true,
- ),
- bottomNavigationBar: Material(
- child: DecoratedTabBar(
- tabBar: TabBar(
- tabs: <Tab>[
- Tab(text: "COMMAND"),
- Tab(
- text: "VIDEO",
- )
- ],
- controller: _controller,
- labelColor: Color(0xFF1e90ff),
- unselectedLabelColor: Color(0xFF808080),
- ),
- decoration: BoxDecoration(
- border: Border(
- top: BorderSide(
- color: Color(0xFF808080),
- width: 1.0,
- ),
- bottom: BorderSide(
- width: 0.0,
- ),
- ),
- ),
- ),
- ),
- body: TabBarView(
- children: <Widget>[
- Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: <Widget>[
- Container(
- padding: const EdgeInsets.fromLTRB(20, 40, 20, 40),
- child: TextField(
- controller: _commandController,
- decoration: InputDecoration(
- border: const OutlineInputBorder(
- borderSide:
- const BorderSide(color: Color(0xFF3498DB)),
- borderRadius: const BorderRadius.all(
- const Radius.circular(5),
- ),
- ),
- focusedBorder: const OutlineInputBorder(
- borderSide:
- const BorderSide(color: Color(0xFF3498DB)),
- borderRadius: const BorderRadius.all(
- const Radius.circular(5),
- ),
- ),
- enabledBorder: const OutlineInputBorder(
- borderSide:
- const BorderSide(color: Color(0xFF3498DB)),
- borderRadius: const BorderRadius.all(
- const Radius.circular(5),
- ),
- ),
- contentPadding: EdgeInsets.fromLTRB(8, 12, 8, 12),
- hintStyle: new TextStyle(
- fontSize: 14, color: Colors.grey[400]),
- hintText: "Enter command"),
- style: new TextStyle(fontSize: 14, color: Colors.black),
- ),
- ),
- Container(
- padding: const EdgeInsets.only(bottom: 20),
- child: new InkWell(
- onTap: () => testRunFFmpegCommand(),
- child: new Container(
- width: 130,
- height: 38,
- decoration: new BoxDecoration(
- color: Color(0xFF2ECC71),
- borderRadius: new BorderRadius.circular(5),
- ),
- child: new Center(
- child: new Text(
- 'RUN FFMPEG',
- style: new TextStyle(
- fontSize: 14.0,
- fontWeight: FontWeight.bold,
- color: Colors.white),
- ),
- ),
- ),
- ),
- ),
- Container(
- padding: const EdgeInsets.only(bottom: 20),
- child: new InkWell(
- onTap: () => testRunFFprobeCommand(),
- child: new Container(
- width: 130,
- height: 38,
- decoration: new BoxDecoration(
- color: Color(0xFF2ECC71),
- borderRadius: new BorderRadius.circular(5),
- ),
- child: new Center(
- child: new Text(
- 'RUN FFPROBE',
- style: new TextStyle(
- fontSize: 14.0,
- fontWeight: FontWeight.bold,
- color: Colors.white),
- ),
- ),
- ),
- ),
- ),
- Expanded(
- child: Container(
- alignment: Alignment(-1.0, -1.0),
- margin: EdgeInsets.all(20.0),
- padding: EdgeInsets.all(4.0),
- decoration: new BoxDecoration(
- borderRadius:
- BorderRadius.all(new Radius.circular(5)),
- color: Color(0xFFF1C40F)),
- child: SingleChildScrollView(
- reverse: true, child: Text(_commandOutput))),
- )
- ],
- ),
- Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: <Widget>[
- Container(
- padding: const EdgeInsets.fromLTRB(20, 40, 20, 40),
- child: Container(
- width: 200,
- alignment: Alignment(0.0, 0.0),
- decoration: BoxDecoration(
- color: Color.fromRGBO(155, 89, 182, 1.0),
- borderRadius: BorderRadius.circular(5)),
- child: DropdownButtonHideUnderline(
- child: DropdownButton(
- style: new TextStyle(
- fontSize: 14,
- color: Colors.black,
- ),
- value: _currentCodec,
- items: _codecDropDownMenuItems,
- onChanged: _changedCodec,
- iconSize: 0,
- isExpanded: false,
- )),
- )),
- Container(
- padding: const EdgeInsets.only(bottom: 20),
- child: new InkWell(
- onTap: () => testEncodeVideo(),
- child: new Container(
- width: 100,
- height: 38,
- decoration: new BoxDecoration(
- color: Color(0xFF2ECC71),
- borderRadius: new BorderRadius.circular(5),
- ),
- child: new Center(
- child: new Text(
- 'ENCODE',
- style: new TextStyle(
- fontSize: 14.0,
- fontWeight: FontWeight.bold,
- color: Colors.white),
- ),
- ),
- ),
- ),
- ),
- Expanded(
- child: Container(
- alignment: Alignment(-1.0, -1.0),
- margin: EdgeInsets.all(20.0),
- padding: EdgeInsets.all(4.0),
- decoration: new BoxDecoration(
- borderRadius:
- BorderRadius.all(new Radius.circular(5)),
- color: Color(0xFFF1C40F)),
- child: SingleChildScrollView(
- reverse: true, child: Text(_encodeOutput))),
- )
- ],
- ),
- ],
- controller: _controller,
- ));
- }
- @override
- void dispose() {
- super.dispose();
- _commandController.dispose();
- }
- void testParseSimpleCommand() {
- var argumentArray = FlutterFFmpeg.parseArguments(
- "-hide_banner -loop 1 -i file.jpg -filter_complex [0:v]setpts=PTS-STARTPTS[video] -map [video] -vsync 2 -async 1 video.mp4");
- assert(argumentArray != null);
- assert(argumentArray.length == 14);
- assert("-hide_banner" == argumentArray[0]);
- assert("-loop" == argumentArray[1]);
- assert("1" == argumentArray[2]);
- assert("-i" == argumentArray[3]);
- assert("file.jpg" == argumentArray[4]);
- assert("-filter_complex" == argumentArray[5]);
- assert("[0:v]setpts=PTS-STARTPTS[video]" == argumentArray[6]);
- assert("-map" == argumentArray[7]);
- assert("[video]" == argumentArray[8]);
- assert("-vsync" == argumentArray[9]);
- assert("2" == argumentArray[10]);
- assert("-async" == argumentArray[11]);
- assert("1" == argumentArray[12]);
- assert("video.mp4" == argumentArray[13]);
- }
- void testParseSingleQuotesInCommand() {
- var argumentArray = FlutterFFmpeg.parseArguments(
- "-loop 1 'file one.jpg' -filter_complex '[0:v]setpts=PTS-STARTPTS[video]' -map [video] video.mp4 ");
- assert(argumentArray != null);
- assert(argumentArray.length == 8);
- assert("-loop" == argumentArray[0]);
- assert("1" == argumentArray[1]);
- assert("file one.jpg" == argumentArray[2]);
- assert("-filter_complex" == argumentArray[3]);
- assert("[0:v]setpts=PTS-STARTPTS[video]" == argumentArray[4]);
- assert("-map" == argumentArray[5]);
- assert("[video]" == argumentArray[6]);
- assert("video.mp4" == argumentArray[7]);
- }
- void testParseDoubleQuotesInCommand() {
- var argumentArray = FlutterFFmpeg.parseArguments(
- "-loop 1 \"file one.jpg\" -filter_complex \"[0:v]setpts=PTS-STARTPTS[video]\" -map [video] video.mp4 ");
- assert(argumentArray != null);
- assert(argumentArray.length == 8);
- assert("-loop" == argumentArray[0]);
- assert("1" == argumentArray[1]);
- assert("file one.jpg" == argumentArray[2]);
- assert("-filter_complex" == argumentArray[3]);
- assert("[0:v]setpts=PTS-STARTPTS[video]" == argumentArray[4]);
- assert("-map" == argumentArray[5]);
- assert("[video]" == argumentArray[6]);
- assert("video.mp4" == argumentArray[7]);
- argumentArray = FlutterFFmpeg.parseArguments(
- " -i file:///tmp/input.mp4 -vcodec libx264 -vf \"scale=1024:1024,pad=width=1024:height=1024:x=0:y=0:color=black\" -acodec copy -q:v 0 -q:a 0 video.mp4");
- assert(argumentArray != null);
- assert(argumentArray.length == 13);
- assert("-i" == argumentArray[0]);
- assert("file:///tmp/input.mp4" == argumentArray[1]);
- assert("-vcodec" == argumentArray[2]);
- assert("libx264" == argumentArray[3]);
- assert("-vf" == argumentArray[4]);
- assert("scale=1024:1024,pad=width=1024:height=1024:x=0:y=0:color=black" ==
- argumentArray[5]);
- assert("-acodec" == argumentArray[6]);
- assert("copy" == argumentArray[7]);
- assert("-q:v" == argumentArray[8]);
- assert("0" == argumentArray[9]);
- assert("-q:a" == argumentArray[10]);
- assert("0" == argumentArray[11]);
- assert("video.mp4" == argumentArray[12]);
- }
- void testParseDoubleQuotesAndEscapesInCommand() {
- var argumentArray = FlutterFFmpeg.parseArguments(
- " -i file:///tmp/input.mp4 -vf \"subtitles=file:///tmp/subtitles.srt:force_style=\'FontSize=16,PrimaryColour=&HFFFFFF&\'\" -vcodec libx264 -acodec copy -q:v 0 -q:a 0 video.mp4");
- assert(argumentArray != null);
- assert(argumentArray.length == 13);
- assert("-i" == argumentArray[0]);
- assert("file:///tmp/input.mp4" == argumentArray[1]);
- assert("-vf" == argumentArray[2]);
- assert(
- "subtitles=file:///tmp/subtitles.srt:force_style='FontSize=16,PrimaryColour=&HFFFFFF&'" ==
- argumentArray[3]);
- assert("-vcodec" == argumentArray[4]);
- assert("libx264" == argumentArray[5]);
- assert("-acodec" == argumentArray[6]);
- assert("copy" == argumentArray[7]);
- assert("-q:v" == argumentArray[8]);
- assert("0" == argumentArray[9]);
- assert("-q:a" == argumentArray[10]);
- assert("0" == argumentArray[11]);
- assert("video.mp4" == argumentArray[12]);
- argumentArray = FlutterFFmpeg.parseArguments(
- " -i file:///tmp/input.mp4 -vf \"subtitles=file:///tmp/subtitles.srt:force_style=\\\"FontSize=16,PrimaryColour=&HFFFFFF&\\\"\" -vcodec libx264 -acodec copy -q:v 0 -q:a 0 video.mp4");
- assert(argumentArray != null);
- assert(argumentArray.length == 13);
- assert("-i" == argumentArray[0]);
- assert("file:///tmp/input.mp4" == argumentArray[1]);
- assert("-vf" == argumentArray[2]);
- assert(
- "subtitles=file:///tmp/subtitles.srt:force_style=\\\"FontSize=16,PrimaryColour=&HFFFFFF&\\\"" ==
- argumentArray[3]);
- assert("-vcodec" == argumentArray[4]);
- assert("libx264" == argumentArray[5]);
- assert("-acodec" == argumentArray[6]);
- assert("copy" == argumentArray[7]);
- assert("-q:v" == argumentArray[8]);
- assert("0" == argumentArray[9]);
- assert("-q:a" == argumentArray[10]);
- assert("0" == argumentArray[11]);
- assert("video.mp4" == argumentArray[12]);
- }
- }
|