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_previewYES

完整示例代码

以下是完整的示例代码,展示了如何使用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

1 回复

更多关于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}");
  }
});
回到顶部