mpeg is a small Dart wrapper around the system ffmpeg and ffprobe binaries. It uses dart:io processes directly, so it works well in server-side Dart apps, Docker containers, and macOS environments where FFmpeg is installed on the host.
- Check whether
ffmpegandffprobeare available withMpegClient.isSupported() - Read parsed
ffmpegandffprobeversion information - Run
ffmpegandffprobecommands withProcess.runorProcess.start - Decode
ffprobeJSON output withprobeJson() - Pull out parsed format metadata, streams, duration, bitrate, and primary video/audio streams
- Parse
ffmpeg -formats/ffprobe -formatsoutput into structuredMpegFormatobjects - Resolve common supported video file extensions from the detected format list for both input and output support
- Use low-friction helpers for generic transcode, remux, and still-frame extraction
- Configure executable paths, base arguments, environment variables, and shell behavior
Add the package:
dart pub add mpegYou also need FFmpeg installed on the machine that runs your Dart code.
For Debian/Ubuntu-based Docker images, install FFmpeg like this:
RUN apt-get update && apt-get install -y ffmpegThat installs both ffmpeg and ffprobe.
Install FFmpeg with Homebrew:
brew install ffmpegYou can verify the install with:
ffmpeg -version
ffprobe -versionimport 'package:mpeg/mpeg.dart';
Future<void> main() async {
bool supported = await MpegClient.isSupported();
if (!supported) {
throw StateError('ffmpeg/ffprobe are not installed or not on PATH.');
}
}getFormats() parses the real -formats output from ffprobe first, then falls back to ffmpeg if needed.
import 'package:mpeg/mpeg.dart';
Future<void> main() async {
MpegClient client = MpegClient();
List<MpegFormat> formats = await client.getFormats();
for (MpegFormat format in formats.take(5)) {
print(
'${format.primaryName}: demux=${format.canDemux}, mux=${format.canMux}, '
'device=${format.isDevice}',
);
}
List<String> inputExtensions =
await client.getSupportedVideoInputExtensions();
List<String> outputExtensions =
await client.getSupportedVideoOutputExtensions();
print('Inputs: $inputExtensions');
print('Outputs: $outputExtensions');
}getSupportedVideoExtensions() resolves common video file extensions from the parsed format names. The input/output convenience methods are useful when you want to answer questions like "which video extensions can this machine decode?" versus "which containers can it mux?"
import 'package:mpeg/mpeg.dart';
Future<void> main() async {
MpegClient client = MpegClient();
MpegVersionInfo ffmpegVersion = await client.getFfmpegVersionInfo();
MpegVersionInfo ffprobeVersion = await client.getFfprobeVersionInfo();
print(ffmpegVersion.version);
print(ffprobeVersion.configurationLine);
}If you do not want to manually walk the full JSON payload, the client exposes small convenience helpers:
import 'package:mpeg/mpeg.dart';
Future<void> main() async {
MpegClient client = MpegClient();
Duration? duration = await client.probeDuration(inputPath: 'output.mp4');
int? bitRate = await client.probeBitRate(inputPath: 'output.mp4');
Map<String, dynamic>? videoStream = await client.probePrimaryVideoStream(
inputPath: 'output.mp4',
);
print(duration);
print(bitRate);
print(videoStream?['width']);
}import 'dart:convert';
import 'dart:io';
import 'package:mpeg/mpeg.dart';
Future<void> main() async {
MpegClient client = MpegClient();
File inputFile = File('input.mov');
File outputFile = File('output.mp4');
ProcessResult result = await client.runFfmpeg([
'-y',
'-i',
inputFile.path,
'-vf',
'scale=1280:720',
'-c:v',
'libx264',
'-pix_fmt',
'yuv420p',
'-movflags',
'+faststart',
outputFile.path,
]);
if (result.exitCode != 0) {
stderr.writeln(result.stderr);
return;
}
Map<String, dynamic> metadata = await client.probeJson(
inputPath: outputFile.path,
);
print(const JsonEncoder.withIndent(' ').convert(metadata));
}These are just thin wrappers around common ffmpeg command shapes, so you still control the real ffmpeg flags.
import 'package:mpeg/mpeg.dart';
Future<void> main() async {
MpegClient client = MpegClient();
await client.transcode(
inputPath: 'input.mov',
outputPath: 'output.mp4',
ffmpegArguments: [
'-vf',
'scale=1280:720',
'-c:v',
'libx264',
'-pix_fmt',
'yuv420p',
],
);
await client.remux(
inputPath: 'input.mov',
outputPath: 'faststart.mp4',
ffmpegArguments: ['-movflags', '+faststart'],
);
await client.extractFrame(
inputPath: 'input.mov',
outputPath: 'thumbnail.png',
position: const Duration(milliseconds: 500),
width: 320,
height: 180,
);
}If you want progress events or long-running streaming output, use startFfmpeg() or startFfprobe():
import 'dart:convert';
import 'dart:io';
import 'package:mpeg/mpeg.dart';
Future<void> main() async {
MpegClient client = MpegClient();
Process process = await client.startFfmpeg(
arguments: [
'-i',
'input.mov',
'-progress',
'pipe:2',
'output.mp4',
],
);
await for (String line in process.stderr
.transform(utf8.decoder)
.transform(const LineSplitter())) {
print(line);
}
int exitCode = await process.exitCode;
print('ffmpeg exited with $exitCode');
}You can point the client at custom binary paths or wrapper commands:
import 'package:mpeg/mpeg.dart';
MpegClient client = MpegClient(
ffmpegExecutable: '/usr/local/bin/ffmpeg',
ffprobeExecutable: '/usr/local/bin/ffprobe',
workingDirectory: '/tmp',
environment: {'FFREPORT': 'file=ffreport.log:level=32'},
);MpegClient.isSupported()checks whetherffmpegand optionallyffprobecan be startedrunFfmpeg()andrunFfprobe()wrapProcess.runstartFfmpeg()andstartFfprobe()wrapProcess.startprobeJson()returns decodedffprobeJSONprobeFormat(),probeStreams(),probeDuration(),probeBitRate(),probePrimaryVideoStream(), andprobePrimaryAudioStream()provide targeted probe helpersgetFormats()returns parsedMpegFormatrows from-formatsgetSupportedVideoExtensions(),getSupportedVideoInputExtensions(), andgetSupportedVideoOutputExtensions()return common video extensions inferred from the detected formatsgetFfmpegVersionInfo()andgetFfprobeVersionInfo()parse version output intoMpegVersionInfotranscode(),remux(), andextractFrame()wrap common ffmpeg operationsMpegExceptionincludes the command, arguments, exit code, stdout, stderr, and original cause when available