Android, iOS 및 macOS에서 하드웨어 H.264 인코더를 사용하여 원시 RGB 프레임을 효율적으로 MP4 비디오로 인코딩할 수 있는 플러터 패키지입니다. M4A 오디오 트랙 생성을 위해 PCM 오디오 입력을 지원하며 실시간 비디오 녹화 및 처리에 적합합니다. 패키지는 최소한의 CPU 사용량으로 높은 성능을 제공하기 위해 네이티브 플랫폼 기능을 활용합니다. 빠르고 낮은 지연 시간의 비디오 인코딩이 필요한 멀티미디어 애플리케이션 개발자를 위한 것입니다.
사용 사례
실시간 비디오 녹화
라이브 스트리밍 캡처
비디오 편집 워크플로우
기기 내 동영상 압축
음성-영상 싱크로나이즈
주요 기능
하드웨어 가속 H.264 인코딩
PCM 오디오 지원
크로스 플랫폼 호환성
낮은 CPU 오버헤드
프레임 입력을 위한 간단한 API
적합한 대상
모바일 동영상 앱
카메라 기반 애플리케이션
미디어 처리 도구
임베디드 비디오 시스템
고성능 녹화
고려 사항
네이티브 플랫폼 권한이 필요합니다
RGB 입력 형식에 제한됨
인코딩을 위한 소프트웨어 백업 없음
플랫폼별 구성이 필요합니다
오디오 동기화는 정밀한 타이밍이 필요합니다
원본 README
연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.
Quickly encode raw RGB images & PCM audio to MP4 video using the system h264 encoder
No Dependencies
FlutterQuickVideoEncoder has zero dependencies besides Flutter, Android, iOS, and MacOS themselves. No FFMPEG.
We use AVFoundation on iOS and MediaCodec on Android. These are native system libraries.
For encoding raw RGB pixels
Unlike the video_compress package, this package takes raw rgb pixel buffers as input, not video files.
⭐ Stars ⭐
Please star this repo & on pub.dev. We all benefit from having a larger community.
Usage
awaitFlutterQuickVideoEncoder.setup(
width: 1920,
height: 1080,
fps: 60,
videoBitrate: 2500000,
audioChannels: 1,
audioBitrate: 64000,
sampleRate: 44100,
filepath: "/documents/video.mp4", // output file
);
for(int i = 0; i < frameCount; i++) {
Uint8List rgba = _renderVideoFrame(i); // your video functionUint8List pcm = _renderAudioFrame(i); // your audio functionawaitFlutterQuickVideoEncoder.appendVideoFrame(rgba);
awaitFlutterQuickVideoEncoder.appendAudioFrame(pcm);
}
awaitFlutterQuickVideoEncoder.finish();
Example App
Enable the platforms you need.
cd ./example
flutter config --enable-macos-desktop
flutter config --enable-android
flutter config --enable-ios
flutter create .
flutter run
Create video frames using ui.Image
The easiest way to render a video frame is to use Flutter!
For example, you can render an RGBA frame using ui.Image
Future<Uint8List> _generateVideoFrame(int frameIndex) async {
constint boxSize = 50; // Size of the moving box// Calculate the box positionint boxX = (frameIndex * 5) % width;
int boxY = (frameIndex * 5) % height;
// Paint the moving boxfinal recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
final paint = Paint();
// Draw a white background
paint.color = Colors.white;
canvas.drawRect(Rect.fromLTWH(0, 0, width.toDouble(), height.toDouble()), paint);
// Draw the blue box
paint.color = Colors.blue;
canvas.drawRect(Rect.fromLTWH(boxX.toDouble(), boxY.toDouble(), boxSize.toDouble(), boxSize.toDouble()), paint);
// Convert canvas to imagefinal picture = recorder.endRecording();
final img = await picture.toImage(width, height);
// Convert the image to a byte arrayfinal byteData = await img.toByteData(format: ui.ImageByteFormat.rawRgba);
return byteData!.buffer.asUint8List();
}
Create video frames from Widgets
You can also create video frames from widgets, using RenderRepaintBoundary
import'dart:ui'as ui;
import'package:flutter/material.dart';
import'dart:typed_data';
classMyWidgetextendsStatefulWidget{
@override_MyWidgetStatecreateState() => _MyWidgetState();
}
class_MyWidgetStateextendsState<MyWidget> {
GlobalKey repaintBoundaryKey = GlobalKey();
@overrideWidgetbuild(BuildContext context) {
returnRepaintBoundary(
key: repaintBoundaryKey,
child: YourWidget(), // Replace with your actual widget
);
}
// you would then call appendVideoFrame with this dataFuture<Uint8List?> captureWidgetAsRGBA() async {
try {
RenderRepaintBoundary boundary = repaintBoundaryKey.currentContext!.findRenderObject() asRenderRepaintBoundary;
ui.Image image = await boundary.toImage(pixelRatio: 1.0);
ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
return byteData?.buffer.asUint8List();
} catch (e) {
print(e);
returnnull;
}
}
}