Flutter视频处理插件videoiq_flutter_plugin的使用
Flutter视频处理插件videoiq_flutter_plugin的使用
本Flutter插件是为AirtelIQ Video SDK封装的。
AirtelIQ平台允许用户在其应用程序中嵌入实时通信服务,通常称为音频、视频和文本聊天服务。它提供了一组简单的API,可以在用户应用中调用以嵌入支持实时通信的服务(RTC)。
注意:该插件仍在开发中,某些API可能尚未可用。
使用方法
要使用此插件,在您的pubspec.yaml
文件中添加videoiq_flutter_plugin
作为依赖项:
dependencies:
videoiq_flutter_plugin: ^1.0.0
入门指南
请参阅示例目录中的示例应用,以了解如何使用videoiq_flutter_plugin
。
设备权限
AirtelIQ Video SDK需要相机和麦克风权限才能开始视频通话。
Android
在AndroidManifest.xml
文件中添加所需的设备权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
iOS
在info.plist
文件中添加以下内容:
- Privacy - Microphone Usage Description,并在值列中添加说明。
- Privacy - Camera Usage Description,并在值列中添加说明。
如果希望在应用切换到后台时仍能运行语音通话,则需要启用后台模式。在Xcode中选择应用目标,点击“功能”标签,启用“后台模式”,并勾选“音频、AirPlay和画中画”。
iOS黑屏问题
我们的SDK使用了PlatformView
,需要在info.plist
文件中设置io.flutter.embedded_views_preview
为YES
。
完整示例代码
以下是完整的示例代码,展示了如何使用videoiq_flutter_plugin
创建和加入房间。
import 'dart:convert';
import 'package:videoiq_flutter_plugin/videoiq_flutter_plugin.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'package:fluttertoast/fluttertoast.dart';
import 'VideoConferenceScreen.dart';
void main() {
runApp(MaterialApp(
title: "Sample App",
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Colors.deepPurple,
accentColor: Colors.pinkAccent),
home: MyApp(),
));
}
class MyApp extends StatefulWidget {
[@override](/user/override)
_State createState() => _State();
}
class _State extends State<MyApp> {
static final String kBaseURL = "https://api.videoiq.airtel.in/";
static bool kTry = true;
static final String kAppId = "App-Id";
static final String kAppkey = "App-key";
var header = (kTry)
? {
"x-app-id": kAppId,
"x-app-key": kAppkey,
"Content-Type": "application/json"
}
: {"Content-Type": "application/json"};
TextEditingController nameController = TextEditingController();
TextEditingController roomIdController = TextEditingController();
static String token = "";
String role='',roomID='';
Future<void> createRoomvalidations() async {
if (nameController.text.isEmpty) {
isValidated = false;
Fluttertoast.showToast(
msg: "请输入您的姓名",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
} else {
isValidated = true;
}
}
Future<void> joinRoomValidations() async {
if (nameController.text.isEmpty) {
Fluttertoast.showToast(
msg: "请输入您的姓名",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
isValidated = false;
} else if (roomIdController.text.isEmpty) {
Fluttertoast.showToast(
msg: "请输入房间ID",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
isValidated = false;
} else {
isValidated = true;
}
}
Future<String> getPin() async {
var response = await http.post(
Uri.parse(kBaseURL + 'getRoomByPin'),
headers: {"Content-Type": "application/json"},
body: jsonEncode({"pin": roomIdController.text}));
if (response.statusCode == 200) {
Map<String, dynamic> user = jsonDecode(response.body);
setState(() {
roomID = user['room_id'].toString();
role = user['role'].toString();
createToken();
});
return response.body;
} else {
throw Exception('Failed to load post');
}
}
Future<String> createRoom() async {
var response = await http.post(
Uri.parse(kBaseURL + "createRoom"),
headers: header);
if (response.statusCode == 200) {
Map<String, dynamic> user = jsonDecode(response.body);
Map<String, dynamic> room = user['room'];
setState(() => roomIdController.text = room['room_id'].toString());
return response.body;
} else {
throw Exception('Failed to load post');
}
}
Future<String> createToken() async {
var value = {
'user_ref': "2236",
"roomId": roomID,
"role": role,
"name": nameController.text
};
var response = await http.post(
Uri.parse(kBaseURL + "createToken"),
headers: header,
body: jsonEncode(value));
if (response.statusCode == 200) {
Map<String, dynamic> user = jsonDecode(response.body);
setState(() => token = user['token'].toString());
Navigator.push(
context,
MaterialPageRoute(builder: (context) => VideoConferenceScreen(token: token,)),
);
return response.body;
} else {
throw Exception('Failed to load post');
}
}
TextStyle style = TextStyle(fontFamily: 'Montserrat', fontSize: 16.0);
bool isValidated = false;
bool isPrecallTest = true;
void _addEnxrtcEventHandlers() {
EnxRtc.onClientDiagnosisFailed = (Map<dynamic, dynamic> map) {
Fluttertoast.showToast(
msg: "onClientDiagnosisFailed+${jsonEncode(map)}",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
};
EnxRtc.onClientDiagnosisFinished = (Map<dynamic, dynamic> map) {
Fluttertoast.showToast(
msg: "onClientDiagnosisFinished+${jsonEncode(map)}",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
};
EnxRtc.onClientDiagnosisStatus = (Map<dynamic, dynamic> map) {
Fluttertoast.showToast(
msg: "onClientDiagnosisStatus+${jsonEncode(map)}",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
};
EnxRtc.onClientDiagnosisStopped = (Map<dynamic, dynamic> map) {
Fluttertoast.showToast(
msg: "onClientDiagnosisStopped+${jsonEncode(map)}",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
};
}
[@override](/user/override)
void initState() {
super.initState();
_addEnxrtcEventHandlers();
}
[@override](/user/override)
Widget build(BuildContext context) {
final usernameField = TextField(
obscureText: false,
style: style,
controller: nameController,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
hintText: "用户名",
border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))),
);
final roomIdField = TextField(
obscureText: false,
controller: roomIdController,
style: style,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
hintText: "输入房间ID",
border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))),
);
final joinButon = Material(
elevation: 5.0,
borderRadius: BorderRadius.circular(30.0),
color: Colors.deepPurple,
child: MaterialButton(
minWidth: 100,
padding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
onPressed: () {
joinRoomValidations();
if (isValidated) {
getPin();
}
},
child: Text("加入",
textAlign: TextAlign.center,
style: style.copyWith(color: Colors.white, fontWeight: FontWeight.normal)),
),
);
final precallTestButon = Material(
elevation: 5.0,
borderRadius: BorderRadius.circular(30.0),
color: Colors.deepPurple,
child: MaterialButton(
minWidth: 100,
padding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
onPressed: () {
if (isPrecallTest) {
isPrecallTest = false;
} else {
isPrecallTest = true;
}
Map<String, dynamic> map = {
'audioDeviceId': "",
'audioDeviceId': "",
'regionId': 'IN',
'stop': isPrecallTest,
'testNames': "MicroPhone"
};
print(map);
EnxRtc.clientDiagnostics(map);
_addEnxrtcEventHandlers();
},
child: Text("预通话测试",
textAlign: TextAlign.center,
style: style.copyWith(color: Colors.white, fontWeight: FontWeight.normal)),
),
);
return Scaffold(
appBar: AppBar(
title: Text('示例应用'),
),
body: Padding(
padding: EdgeInsets.all(10),
child: ListView(
children: [
Container(
alignment: Alignment.center,
padding: EdgeInsets.all(10),
child: Text(
'VideoIQ',
style: TextStyle(
color: Colors.redAccent,
fontWeight: FontWeight.w500,
fontSize: 30),
)),
Container(
alignment: Alignment.center,
padding: EdgeInsets.all(10),
child: Text(
'欢迎!',
style: TextStyle(fontSize: 20),
)),
Container(
padding: EdgeInsets.all(10),
child: usernameField,
),
Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
child: roomIdField),
Container(
alignment: Alignment.center,
height: 100,
width: 100,
child: Row(
children: [
Expanded(
flex: 1,
child: Padding(
padding: EdgeInsets.all(10),
child: joinButon)),
Expanded(
flex: 1,
child: Padding(
padding: EdgeInsets.all(10),
child: precallTestButon)),
],
))
],
),
),
);
}
}
更多关于Flutter视频处理插件videoiq_flutter_plugin的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter视频处理插件videoiq_flutter_plugin的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
videoiq_flutter_plugin
是一个用于 Flutter 的视频处理插件,它提供了一系列功能来帮助开发者处理视频文件,如视频压缩、裁剪、合并、转码等。以下是如何使用 videoiq_flutter_plugin
的基本步骤:
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 videoiq_flutter_plugin
的依赖。
dependencies:
flutter:
sdk: flutter
videoiq_flutter_plugin: ^latest_version
然后运行 flutter pub get
来安装依赖。
2. 导入插件
在你的 Dart 文件中导入插件:
import 'package:videoiq_flutter_plugin/videoiq_flutter_plugin.dart';
3. 初始化插件
在使用插件之前,建议先初始化插件:
VideoIQFlutterPlugin.initialize();
4. 使用插件的功能
视频压缩
你可以使用 compressVideo
方法来压缩视频:
String inputPath = "/path/to/input/video.mp4";
String outputPath = "/path/to/output/video_compressed.mp4";
VideoIQFlutterPlugin.compressVideo(inputPath, outputPath).then((result) {
if (result.success) {
print("视频压缩成功: ${result.outputPath}");
} else {
print("视频压缩失败: ${result.errorMessage}");
}
});
视频裁剪
你可以使用 trimVideo
方法来裁剪视频:
String inputPath = "/path/to/input/video.mp4";
String outputPath = "/path/to/output/video_trimmed.mp4";
int startTime = 1000; // 开始时间(毫秒)
int endTime = 5000; // 结束时间(毫秒)
VideoIQFlutterPlugin.trimVideo(inputPath, outputPath, startTime, endTime).then((result) {
if (result.success) {
print("视频裁剪成功: ${result.outputPath}");
} else {
print("视频裁剪失败: ${result.errorMessage}");
}
});
视频合并
你可以使用 mergeVideos
方法来合并多个视频:
List<String> inputPaths = [
"/path/to/input/video1.mp4",
"/path/to/input/video2.mp4"
];
String outputPath = "/path/to/output/video_merged.mp4";
VideoIQFlutterPlugin.mergeVideos(inputPaths, outputPath).then((result) {
if (result.success) {
print("视频合并成功: ${result.outputPath}");
} else {
print("视频合并失败: ${result.errorMessage}");
}
});
视频转码
你可以使用 transcodeVideo
方法来转码视频:
String inputPath = "/path/to/input/video.mp4";
String outputPath = "/path/to/output/video_transcoded.mp4";
String outputFormat = "mp4"; // 输出格式
VideoIQFlutterPlugin.transcodeVideo(inputPath, outputPath, outputFormat).then((result) {
if (result.success) {
print("视频转码成功: ${result.outputPath}");
} else {
print("视频转码失败: ${result.errorMessage}");
}
});