Flutter摄像头切换插件switch_camera的使用

发布于 1周前 作者 songsunli 来自 Flutter

Flutter摄像头切换插件switch_camera的使用

switch_camera 是一个Dart库,它提供了与Rust交互的Dart FFI接口,用于摄像头和音频录制功能。它支持视频捕捉、帧流、视频写入以及音频录制,并且可以将视频与音频合并。我使用 switch_camera 库构建了一个名为Zed Camera的桌面应用程序,您可以在 YouTube 上观看其演示。该库在物联网(IoT)、闭路电视(CCTV)和工业环境中特别有用,在这些环境中多个摄像头输入和可靠的音视频记录至关重要。

功能

  • 列出可用的摄像头设备
  • 打开和释放摄像头设备
  • 捕获视频帧(带翻转和不带翻转)
  • 流式传输视频帧(带翻转和不带翻转)
  • 开始视频写入
  • 写入视频帧(带翻转和不带翻转)
  • 音频录制(开始、停止、暂停、恢复)
  • 合并音频和视频

平台支持

  • Linux

安装

要安装 switch_camera,请使用 flutter pub add

Flutter

flutter pub add switch_camera

依赖项

Linux - Ubuntu:

  • sudo apt-get update
  • 获取 OpenCV: sudo apt-get install libopencv-dev clang libclang-dev
  • 安装 JACK 开发文件: sudo apt-get install libjack-jackd2-dev
  • 安装 ALSA 开发文件: sudo apt-get install libasound2-dev
  • 安装 FFmpeg: sudo apt-get install ffmpeg

使用方法

相机

import 'package:switch_camera/switch_camera.dart';

void main() {
  final camera = Camera();

  // 列出最多10个设备
  final devices = camera.getDevices(10);
  print('可用设备: $devices');

  // 打开摄像头设备
  camera.open(0);

  // 捕获帧
  final frame = camera.captureFrame();
  print('捕获帧: ${frame.length} 字节');

  // 捕获翻转帧
  final flippedFrame = camera.captureFrameFlip();
  print('捕获翻转帧: ${flippedFrame.length} 字节');

  // 流式传输帧
  camera.streamFrames();

  // 流式传输翻转帧
  camera.streamFramesFlip();

  // 开始视频写入
  camera.startVideoWriter('output.mp4', 30.0, 1920, 1080);

  // 写入帧
  camera.writeFrame();

  // 写入翻转帧
  camera.writeFrameFlip();

  // 释放摄像头
  camera.release();

  // 释放摄像头资源
  camera.dispose();
}

音频录制器

import 'package:switch_camera/switch_camera.dart';

void main() {
  final recorder = RustAudioRecorder();

  // 开始录音
  recorder.startRecording();

  // 暂停录音
  recorder.pauseRecording();

  // 恢复录音
  recorder.resumeRecording();

  // 停止录音
  recorder.stopRecording();
}

合并音频和视频

import 'package:switch_camera/switch_camera.dart';

void main() {
  final result = mergeCamAudioVideo('output_with_audio.mp4');
  print('合并结果: $result');
}

注意:为分发准备Linux应用

要将Flutter应用程序作为发布版本构建,请运行以下命令:

flutter build linux --release

之后,进入 build/linux/release/bundle/ 目录并使用以下命令运行应用程序:

./projectname

通过运行应用程序在目录中,会自动将文件复制到 lib 文件夹下的 src/rust_native/librust_camera.so。此文件负责使库在您的应用程序中正常工作。

API 参考

相机

  • List<int> getDevices(int limit)
    列出指定限制内的可用摄像头设备。

  • void open(int index)
    通过索引打开摄像头设备。

  • void release()
    释放当前打开的摄像头设备。

  • Uint8List captureFrame()
    捕获单个视频帧。

  • Uint8List captureFrameFlip()
    捕获单个翻转的视频帧。

  • Stream<Uint8List> streamFrames()
    流式传输视频帧。

  • Stream<Uint8List> streamFramesFlip()
    流式传输翻转的视频帧。

  • void startVideoWriter(String filename, double fps, int width, int height)
    开始向指定文件写入视频。

  • void startAVideoWriter(double fps, int width, int height)
    不指定文件名开始视频写入。

  • void writeFrame()
    写入视频帧。

  • void writeFrameFlip()
    写入翻转的视频帧。

  • void dispose()
    释放摄像头资源。

RustAudioRecorder

  • void startRecording()
    开始音频录制。

  • void stopRecording()
    停止音频录制。

  • void pauseRecording()
    暂停音频录制。

  • void resumeRecording()
    恢复音频录制。

合并函数

  • String mergeCamAudioVideo(String outputFilePath)
    将录制的摄像头视频和音频合并到指定输出文件。

作者

Zacchaeus Oluwole


示例代码

以下是 switch_camera 插件的一个完整示例Demo:

import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:switch_camera/switch_camera.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Switch Camera Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Switch Camera Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late Stream<Uint8List> cam;
  final camera = Camera();

  [@override](/user/override)
  void initState() {
    super.initState();
    camera.open(0);
    cam = camera.streamFrames();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text("计算机视觉"),
            StreamBuilder<Uint8List>(
              stream: cam,
              builder: (context, snap) {
                final data = snap.data;
                if (data != null)
                  return Image.memory(
                    data,
                    gaplessPlayback: true,
                  );
                return const CircularProgressIndicator();
              },
            )
          ],
        ),
      ),
    );
  }
}

更多关于Flutter摄像头切换插件switch_camera的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter摄像头切换插件switch_camera的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter应用中使用switch_camera插件来切换摄像头的示例代码。这个插件允许你在运行时从后置摄像头切换到前置摄像头,或者反过来。

首先,你需要在你的pubspec.yaml文件中添加switch_camera依赖:

dependencies:
  flutter:
    sdk: flutter
  switch_camera: ^0.4.0  # 请检查最新版本号并替换

然后运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中,你可以按照以下步骤使用switch_camera插件:

  1. 导入必要的包
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:switch_camera/switch_camera.dart';

注意:camera插件是switch_camera依赖的一部分,所以你也需要确保camera插件也被正确安装和配置。

  1. 请求相机权限(在Android和iOS上都需要):

AndroidManifest.xml中添加:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

Info.plist中添加:

<key>NSCameraUsageDescription</key>
<string>Need camera access</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Need photo library access</string>
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access</string>
  1. 创建主应用组件
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CameraApp(),
    );
  }
}
  1. 创建CameraApp组件
class CameraApp extends StatefulWidget {
  @override
  _CameraAppState createState() => _CameraAppState();
}

class _CameraAppState extends State<CameraApp> {
  CameraController? controller;
  List<CameraDescription>? cameras;
  CameraLensDirection currentLensDirection = CameraLensDirection.back;

  Future<void> _initializeCamera() async {
    cameras = await availableCameras();

    if (cameras!.isNotEmpty) {
      controller = new CameraController(
        cameras![currentLensDirection == CameraLensDirection.back ? 0 : 1],
        ResolutionPreset.high,
        enableAudio: true,
      );

      controller!.initialize().then((_) {
        if (!mounted) {
          return;
        }
        setState(() {});
      });
    }
  }

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

    currentLensDirection =
        currentLensDirection == CameraLensDirection.back
            ? CameraLensDirection.front
            : CameraLensDirection.back;

    if (cameras!.isNotEmpty) {
      controller = new CameraController(
        cameras![currentLensDirection == CameraLensDirection.back ? 0 : 1],
        ResolutionPreset.high,
        enableAudio: true,
      );

      controller!.initialize().then((_) {
        if (!mounted) {
          return;
        }
        setState(() {});
      });
    }
  }

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

  @override
  void dispose() {
    controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Camera App'),
      ),
      body: cameras == null || !controller!.value.isInitialized
          ? Center(child: Text('Loading...'))
          : Stack(
              children: <Widget>[
                CameraPreview(controller!),
                Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    child: ElevatedButton(
                      onPressed: _switchCamera,
                      child: Text('Switch Camera'),
                    ),
                  ),
                ),
              ],
            ),
    );
  }
}

这个示例代码展示了如何初始化相机、显示相机预览、并在点击按钮时切换摄像头。注意,CameraController的初始化应该在UI线程上异步进行,并在dispose方法中释放资源以避免内存泄漏。

确保你已经正确配置了cameraswitch_camera插件的权限和依赖,这样你的应用才能成功访问和切换摄像头。

回到顶部