Захват видео с трепетанием

Привет, я нахожусь в процессе разработки приложения с трепетом с функцией записи видео. Я наткнулся на 2 плагина с возможностью захвата/сохранения изображения в виде файла с трепетом:

Camera v0.0.2 и Image_picker v0.2.1, они хорошо работают и являются официальными плагинами флаттера.

По сути, я хотел бы создать плагин для мини-камеры с возможностью записи видео с флаттером, который без проблем работал бы с iOS и Android.

Любые предложения, указания, способы обновления этих плагинов приветствуются.

Ответ 1

Запись видео теперь включена нашей командой на официальном плагине камеры v0.2.0

отправив запрос на извлечение данных в хранилище.

Пример приложения для этого плагина использует дополнительные плагины path_provider
и video_player для отображения образца записанного видео.

Надеюсь, что это помогает другим разработчикам трепетать аплодисменты!

Ответ 2

Я хочу интегрировать плагин для видео и камеры в свое приложение таким образом, чтобы моя камера оставалась открытой в фоновом режиме, а видео воспроизводилось через обзор камеры и через некоторый интервал времени снимались изображения с обзора камеры. Как я могу достичь этого, я новичок в этом.

Ответ 3

Я использовал этот пакет: image_picker 0.5.0

Использование для видео

   Future picker() async {
   File vid = await ImagePicker.pickVideo(source: ImageSource.camera);

   print(vid.path);
}

Ответ 4

Flutter предоставляет пакеты "камера" и "video_player". Камера используется для доступа к камере телефона, а video_plater используется для записи видео. Вы можете использовать пакет камеры и записать видео. Вы можете найти код ниже:

Сначала вы должны обновить файл pubspec, например:

dependencies:
   camera: ^0.2.9+1
   fluttertoast: 
   path_provider:
   video_player:

fluttertoast - это тост для вашей камеры, а path_provider указывает путь, по которому ваше видео будет сохранено. Затем вы должны импортировать эти пакеты в ваш файл dart и написать свою собственную реализацию. Вы можете найти образец кода ниже. Откроется список доступных камер в вашем телефоне, включая внешние камеры, чтобы вы могли выбрать любую из них для записи видео.

import 'dart:async';
  import 'dart:io';

  import 'package:camera/camera.dart';
  import 'package:flutter/material.dart';
  import 'package:path_provider/path_provider.dart';
  import 'package:video_player/video_player.dart';
  import 'package:fluttertoast/fluttertoast.dart';

  class VideoRecorderExample extends StatefulWidget {
    @override
    _VideoRecorderExampleState createState() {
      return _VideoRecorderExampleState();
    }
  }

  class _VideoRecorderExampleState extends State<VideoRecorderExample> {
    CameraController controller;
    String videoPath;

    List<CameraDescription> cameras;
    int selectedCameraIdx;

    final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

    @override
    void initState() {
      super.initState();

      // Get the listonNewCameraSelected of available cameras.
      // Then set the first camera as selected.
      availableCameras()
          .then((availableCameras) {
        cameras = availableCameras;

        if (cameras.length > 0) {
          setState(() {
            selectedCameraIdx = 0;
          });

          _onCameraSwitched(cameras[selectedCameraIdx]).then((void v) {});
        }
      })
          .catchError((err) {
        print('Error: $err.code\nError Message: $err.message');
      });
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        key: _scaffoldKey,
        appBar: AppBar(
          title: const Text('Camera example'),
        ),
        body: Column(
          children: <Widget>[
            Expanded(
              child: Container(
                child: Padding(
                  padding: const EdgeInsets.all(1.0),
                  child: Center(
                    child: _cameraPreviewWidget(),
                  ),
                ),
                decoration: BoxDecoration(
                  color: Colors.black,
                  border: Border.all(
                    color: controller != null && controller.value.isRecordingVideo
                        ? Colors.redAccent
                        : Colors.grey,
                    width: 3.0,
                  ),
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(5.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.start,
                children: <Widget>[
                  _cameraTogglesRowWidget(),
                  _captureControlRowWidget(),
                  Expanded(
                    child: SizedBox(),
                  ),
                ],
              ),
            ),
          ],
        ),
      );
    }

    IconData _getCameraLensIcon(CameraLensDirection direction) {
      switch (direction) {
        case CameraLensDirection.back:
          return Icons.camera_rear;
        case CameraLensDirection.front:
          return Icons.camera_front;
        case CameraLensDirection.external:
          return Icons.camera;
        default:
          return Icons.device_unknown;
      }
    }

    // Display 'Loading' text when the camera is still loading.
    Widget _cameraPreviewWidget() {
      if (controller == null || !controller.value.isInitialized) {
        return const Text(
          'Loading',
          style: TextStyle(
            color: Colors.white,
            fontSize: 20.0,
            fontWeight: FontWeight.w900,
          ),
        );
      }

      return AspectRatio(
        aspectRatio: controller.value.aspectRatio,
        child: CameraPreview(controller),
      );
    }

    /// Display a row of toggle to select the camera (or a message if no camera is available).
    Widget _cameraTogglesRowWidget() {
      if (cameras == null) {
        return Row();
      }

      CameraDescription selectedCamera = cameras[selectedCameraIdx];
      CameraLensDirection lensDirection = selectedCamera.lensDirection;

      return Expanded(
        child: Align(
          alignment: Alignment.centerLeft,
          child: FlatButton.icon(
              onPressed: _onSwitchCamera,
              icon: Icon(
                  _getCameraLensIcon(lensDirection)
              ),
              label: Text("${lensDirection.toString()
                  .substring(lensDirection.toString().indexOf('.')+1)}")
          ),
        ),
      );
    }

    /// Display the control bar with buttons to record videos.
    Widget _captureControlRowWidget() {
      return Expanded(
        child: Align(
          alignment: Alignment.center,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            mainAxisSize: MainAxisSize.max,
            children: <Widget>[
              IconButton(
                icon: const Icon(Icons.videocam),
                color: Colors.blue,
                onPressed: controller != null &&
                    controller.value.isInitialized &&
                    !controller.value.isRecordingVideo
                    ? _onRecordButtonPressed
                    : null,
              ),
              IconButton(
                icon: const Icon(Icons.stop),
                color: Colors.red,
                onPressed: controller != null &&
                    controller.value.isInitialized &&
                    controller.value.isRecordingVideo
                    ? _onStopButtonPressed
                    : null,
              )
            ],
          ),
        ),
      );
    }

    String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();

    Future<void> _onCameraSwitched(CameraDescription cameraDescription) async {
      if (controller != null) {
        await controller.dispose();
      }

      controller = CameraController(cameraDescription, ResolutionPreset.high);

      // If the controller is updated then update the UI.
      controller.addListener(() {
        if (mounted) {
          setState(() {});
        }

        if (controller.value.hasError) {
          Fluttertoast.showToast(
              msg: 'Camera error ${controller.value.errorDescription}',
              toastLength: Toast.LENGTH_SHORT,
              gravity: ToastGravity.CENTER,
              timeInSecForIos: 1,
              backgroundColor: Colors.red,
              textColor: Colors.white
          );
        }
      });

      try {
        await controller.initialize();
      } on CameraException catch (e) {
        _showCameraException(e);
      }

      if (mounted) {
        setState(() {});
      }
    }

    void _onSwitchCamera() {
      selectedCameraIdx = selectedCameraIdx < cameras.length - 1
          ? selectedCameraIdx + 1
          : 0;
      CameraDescription selectedCamera = cameras[selectedCameraIdx];

      _onCameraSwitched(selectedCamera);

      setState(() {
        selectedCameraIdx = selectedCameraIdx;
      });
    }

    void _onRecordButtonPressed() {
      _startVideoRecording().then((String filePath) {
        if (filePath != null) {
          Fluttertoast.showToast(
              msg: 'Recording video started',
              toastLength: Toast.LENGTH_SHORT,
              gravity: ToastGravity.CENTER,
              timeInSecForIos: 1,
              backgroundColor: Colors.grey,
              textColor: Colors.white
          );
        }
      });
    }

    void _onStopButtonPressed() {
      _stopVideoRecording().then((_) {
        if (mounted) setState(() {});
        Fluttertoast.showToast(
            msg: 'Video recorded to $videoPath',
            toastLength: Toast.LENGTH_SHORT,
            gravity: ToastGravity.CENTER,
            timeInSecForIos: 1,
            backgroundColor: Colors.grey,
            textColor: Colors.white
        );
      });
    }

    Future<String> _startVideoRecording() async {
      if (!controller.value.isInitialized) {
        Fluttertoast.showToast(
            msg: 'Please wait',
            toastLength: Toast.LENGTH_SHORT,
            gravity: ToastGravity.CENTER,
            timeInSecForIos: 1,
            backgroundColor: Colors.grey,
            textColor: Colors.white
        );

        return null;
      }

      // Do nothing if a recording is on progress
      if (controller.value.isRecordingVideo) {
        return null;
      }

      final Directory appDirectory = await getApplicationDocumentsDirectory();
      final String videoDirectory = '${appDirectory.path}/Videos';
      await Directory(videoDirectory).create(recursive: true);
      final String currentTime = DateTime.now().millisecondsSinceEpoch.toString();
      final String filePath = '$videoDirectory/${currentTime}.mp4';

      try {
        await controller.startVideoRecording(filePath);
        videoPath = filePath;
      } on CameraException catch (e) {
        _showCameraException(e);
        return null;
      }

      return filePath;
    }

    Future<void> _stopVideoRecording() async {
      if (!controller.value.isRecordingVideo) {
        return null;
      }

      try {
        await controller.stopVideoRecording();
      } on CameraException catch (e) {
        _showCameraException(e);
        return null;
      }
    }

    void _showCameraException(CameraException e) {
      String errorText = 'Error: ${e.code}\nError Message: ${e.description}';
      print(errorText);

      Fluttertoast.showToast(
          msg: 'Error: ${e.code}\n${e.description}',
          toastLength: Toast.LENGTH_SHORT,
          gravity: ToastGravity.CENTER,
          timeInSecForIos: 1,
          backgroundColor: Colors.red,
          textColor: Colors.white
      );
    }
  }

  class VideoRecorderApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        home: VideoRecorderExample(),
      );
    }
  }

  Future<void> main() async {
    runApp(VideoRecorderApp());
  }