Video

This section describes how to render video.

Render the video view

The Video SDK for Flutter uses two different widgets to render video.

  • For Android it uses AndroidView.
  • For iOS it uses UiKitView.

Define a View class to render the video view for both of these platforms:

switch (defaultTargetPlatform) {
      case TargetPlatform.android:
        return AndroidView(
          viewType: 'the name of view type',
          layoutDirection: TextDirection.ltr,
          creationParams: creationParams,
          creationParamsCodec: const StandardMessageCodec(),
        );
      case TargetPlatform.iOS:
        return UiKitView(
          viewType: 'the name of view type',
          layoutDirection: TextDirection.ltr,
          creationParams: creationParams,
          creationParamsCodec: const StandardMessageCodec(),
        );
      default:
        throw UnsupportedError("Unsupported platform");
    }

Separate full screen and horizontal scrolling list views

To separate the full screen view and horizontal scrolling list view, define another class, VideoView, to render the View based on whether it is full screen or not:

class VideoView extends HookWidget {
  final ZoomVideoSdkUser? user;
  final bool sharing;
  final bool preview;
  final bool focused;
  final bool hasMultiCamera;
  final String multiCameraIndex;
  final String? videoAspect;
  final bool fullScreen;
  const VideoView({
    super.key,
    required this.user,
    required this.sharing,
    required this.preview,
    required this.focused,
    required this.hasMultiCamera,
    required this.multiCameraIndex,
    this.videoAspect,
    required this.fullScreen,
  });
}

In the example app file, lib/call-screen.dart, the function returns VideoView in two separate code blocks:

  • one for full screen visualization and
  • the other for a horizontally scrolling list of remote users in a video session at the bottom of the screen.

Full screen visualization

The full screen visualization, upon initialization with video enabled, renders what others participating in a video session see:

fullScreenView = AnimatedOpacity(
  opacity: opacityLevel,
  duration: const Duration(seconds: 3),
  child: VideoView(
    user: fullScreenUser.value,
    hasMultiCamera: false,
    sharing: sharingUser.value == null
        ? false
        : (sharingUser.value?.userId == fullScreenUser.value?.userId),
    preview: false,
    focused: false,
    multiCameraIndex: "0",
    videoAspect: VideoAspect.Original,
    fullScreen: true,
  ),
);

Creation parameters passed to View

This function passes the following parameters to View:

  • user: A ZoomVideoSdkUser type instantiated via an event listener for Video SDK session when a user creates, joins, or leaves a session.
  • sharing: A Boolean set to true if the current full screen user is currently the user who is sharing a screen with others.
  • preview: A Boolean set to true if the video view is for preview.
  • hasMultiCamera: A Boolean set to true if the user's device has more than one camera.
  • multiCameraIndex: The index of camera view that the View should render.
  • videoAspect: The aspect ratio.
  • fullScreen: A Boolean value that tells the View component to render itself full screen or horizontal ListView.

Horizontally scrolling list

At the bottom of the call-screen, users can see a horizontally scrolling list of other users in the call. Use VideoView in the horizontal ListView that renders this as well:

Container(
  height: 110,
  margin: const EdgeInsets.only(left: 20, right: 20),
  alignment: Alignment.center,
  child: ListView.separated(
    scrollDirection: Axis.horizontal,
    itemCount: users.value.length,
    itemBuilder: (BuildContext context, int index) {
      return InkWell(
        onTap: () async {
          onSelectedUser(users.value[index]);
        },
        child: Center(
          child: VideoView(
            user: users.value[index],
            hasMultiCamera: false,
            sharing: sharingUser.value == null
                ? false
                : sharingUser.value?.userId == users.value[index].userId,
            preview: false,
            focused: false,
            multiCameraIndex: "0",
            videoAspect: VideoAspect.Original,
            fullScreen: false,
          ),
        ),
      );
    },
    separatorBuilder: (BuildContext context, int index) =>
        const Divider(),
  ),
);

The horizontally scrolling ListView at the bottom of the screen renders mini video screens for all users in a session. Tapping a remote user's screen sets that user to the full screen user.

Use virtual background

Use ZoomVideoSdkVirtualBackgroundHelper to enable virtual backgrounds. First determine whether the device supports it using isSupportVirtualBackground. If the device supports it, use the helper functions to add, get, set, and remove virtual backgrounds.

To add virtual backgrounds:

  1. Use addVirtualBackgroundItem to add a virtual background item.
  2. Use getVirtualBackgroundItemList to get a list of available virtual background items.
  3. Choose a virtual background item from the list and use setVirtualBackgroundItem to set the virtual background.

Use removeVirtualBackgroundItem to remove the virtual background or set the virtual background to None. Use getSelectedVirtualBackgroundItem to get the current selected background.

// Check if virtual background is supported
@override
Future<bool> isSupportVirtualBackground() async {
  return await methodChannel
      .invokeMethod<bool>('isSupportVirtualBackground')
      .then<bool>((bool? value) => value ?? false);
}
// Add virtual background item
@override
Future<ZoomVideoSdkVirtualBackgroundItem?> addVirtualBackgroundItem(String filePath) async {
  var params = <String, dynamic>{};
  params.putIfAbsent("filePath", () => filePath);
  var itemString = await methodChannel
      .invokeMethod<String>('addVirtualBackgroundItem', params)
      .then<String>((String? value) => value ?? "");
  Map<String, dynamic> itemMap = jsonDecode(itemString!);
  var vbItem =
  ZoomVideoSdkVirtualBackgroundItem.fromJson(itemMap);
  return vbItem;
}
// Remove virtual background item
@override
Future<String> removeVirtualBackgroundItem(String imageName) async {
  var params = <String, dynamic>{};
  params.putIfAbsent("imageName", () => imageName);
  return await methodChannel
      .invokeMethod<String>('removeVirtualBackgroundItem', params)
      .then<String>((String? value) => value ?? "");
}
// Get virtual background item list
@override
Future<List<ZoomVideoSdkVirtualBackgroundItem>> getVirtualBackgroundItemList() async {
  var itemListString = await methodChannel
      .invokeMethod<String?>('getVirtualBackgroundItemList')
      .then<String?>((String? value) => value);
  var itemListJson = jsonDecode(itemListString!) as List;
  List<ZoomVideoSdkVirtualBackgroundItem> itemList = itemListJson
      .map((languageJson) =>
      ZoomVideoSdkVirtualBackgroundItem.fromJson(languageJson))
      .toList();
  return itemList;
}
// Set virtual background item
@override
Future<String> setVirtualBackgroundItem(String imageName) async {
  var params = <String, dynamic>{};
  params.putIfAbsent("imageName", () => imageName);
  return await methodChannel
      .invokeMethod<String>('setVirtualBackgroundItem', params)
      .then<String>((String? value) => value ?? "");
}
// Get selected virtual background
@override
Future<ZoomVideoSdkVirtualBackgroundItem> getSelectedVirtualBackgroundItem() async {
}