Skip to content

Commit 0ae734d

Browse files
authored
media encoders crate (#828)
* media encoders crate * crate READMEs
1 parent 96570d9 commit 0ae734d

39 files changed

+956
-840
lines changed

Cargo.lock

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/editor/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ cap-media = { path = "../media" }
1111
cap-project = { path = "../project" }
1212
cap-rendering = { path = "../rendering" }
1313
cap-audio = { path = "../audio" }
14+
cap-media-info = { path = "../media-info" }
1415

1516
tokio = { workspace = true, features = ["macros", "process", "fs"] }
1617
cpal.workspace = true

crates/editor/src/editor_instance.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use crate::editor;
22
use crate::playback::{self, PlaybackHandle};
33
use cap_audio::AudioData;
4-
use cap_media::data::RawVideoFormat;
5-
use cap_media::data::VideoInfo;
64
// use cap_media::feeds::AudioData;
75
use cap_media::frame_ws::create_frame_ws;
86
use cap_project::{CursorEvents, ProjectConfiguration, RecordingMeta, RecordingMetaInner, XY};

crates/editor/src/playback.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use std::{sync::Arc, time::Duration};
22

3-
use cap_media::data::{AudioInfo, FromSampleBytes};
4-
use cap_media::feeds::{AudioPlaybackBuffer, AudioSegment, AudioSegmentTrack};
3+
use cap_media::data::FromSampleBytes;
4+
use cap_media::feeds::{AudioPlaybackBuffer, AudioSegment};
55
use cap_media::MediaError;
6-
use cap_project::{AudioConfiguration, ProjectConfiguration, XY};
6+
use cap_media_info::AudioInfo;
7+
use cap_project::{ProjectConfiguration, XY};
78
use cap_rendering::{ProjectUniforms, RenderVideoConstants};
89
use cpal::{
910
traits::{DeviceTrait, HostTrait, StreamTrait},

crates/export/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ cap-rendering = { path = "../rendering" }
1010
cap-editor = { path = "../editor" }
1111
cap-media = { path = "../media" }
1212
cap-flags = { path = "../flags" }
13+
cap-media-encoders = { path = "../media-encoders" }
14+
cap-media-info = { path = "../media-info" }
1315

1416
tokio.workspace = true
1517
tempfile = "3.12.0"

crates/export/src/gif.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::path::PathBuf;
22

3-
use cap_media::encoders::GifEncoderWrapper;
3+
use cap_media_encoders::GifEncoderWrapper;
44
use cap_project::XY;
55
use cap_rendering::{ProjectUniforms, RenderSegment, RenderedFrame};
66
use futures::FutureExt;

crates/export/src/mp4.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ use std::{path::PathBuf, time::Duration};
22

33
use crate::ExporterBase;
44
use cap_editor::get_audio_segments;
5-
use cap_media::{
6-
data::{RawVideoFormat, VideoInfo},
7-
encoders::{AACEncoder, AudioEncoder, H264Encoder, MP4Input},
8-
feeds::AudioRenderer,
9-
};
5+
use cap_media::feeds::AudioRenderer;
6+
use cap_media_encoders::{AACEncoder, AudioEncoder, H264Encoder, MP4File, MP4Input};
7+
use cap_media_info::{RawVideoFormat, VideoInfo};
108
use cap_project::XY;
119
use cap_rendering::{ProjectUniforms, RenderSegment, RenderedFrame};
1210
use futures::FutureExt;
@@ -79,7 +77,7 @@ impl Mp4ExportSettings {
7977
let encoder_thread = tokio::task::spawn_blocking(move || {
8078
trace!("Creating MP4File encoder");
8179

82-
let mut encoder = cap_media::encoders::MP4File::init(
80+
let mut encoder = MP4File::init(
8381
"output",
8482
base.output_path.clone(),
8583
|o| {
@@ -91,6 +89,7 @@ impl Mp4ExportSettings {
9189
has_audio.then(|| {
9290
AACEncoder::init("output_audio", AudioRenderer::info(), o)
9391
.map(|v| v.boxed())
92+
.map_err(Into::into)
9493
})
9594
},
9695
)

crates/media-encoders/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "cap-media-encoders"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
cap-project = { path = "../project" }
8+
cap-flags = { path = "../flags" }
9+
cap-audio = { path = "../audio" }
10+
cap-fail = { path = "../fail" }
11+
cap-media-info = { path = "../media-info" }
12+
13+
ffmpeg.workspace = true
14+
thiserror.workspace = true
15+
tracing.workspace = true
16+
gif = "0.13.3"
17+
18+
[target.'cfg(target_os = "macos")'.dependencies]
19+
cidre = { workspace = true }
20+
21+
[lints]
22+
workspace = true

crates/media-encoders/README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# cap-media-encoders
2+
3+
A comprehensive collection of media encoders for various output formats, designed to work seamlessly with the Cap media processing pipeline. The crate provides unified interfaces for encoding captured audio and video data into different formats using multiple underlying media frameworks.
4+
5+
## Overview
6+
7+
This crate serves as a unified interface for encoding captured media into various output formats, with FFmpeg providing cross-platform support and AVFoundation offering optimized macOS-specific encoding. All encoders support real-time frame queuing and proper finalization for streaming applications.
8+
9+
## Available Encoders
10+
11+
### FFmpeg-based Encoders
12+
13+
**Video Encoders:**
14+
- `H264Encoder` - H.264/AVC video encoding with configurable quality presets and bitrate control
15+
- `MP4File` - Complete MP4 container handling H.264 video + audio stream muxing
16+
17+
**Audio Encoders:**
18+
- `AACEncoder` - AAC audio encoding at 320kbps with automatic resampling and format conversion
19+
- `OpusEncoder` - Opus audio encoding at 128kbps optimized for voice and music
20+
- `OggFile` - Ogg container wrapper specifically designed for Opus audio streams
21+
22+
### AVFoundation-based Encoders (macOS only)
23+
24+
**Video + Audio:**
25+
- `MP4AVAssetWriterEncoder` - Native macOS encoder using AVAssetWriter for hardware-accelerated MP4 encoding
26+
- Hardware acceleration support
27+
- Pause/resume functionality for recording sessions
28+
- Real-time encoding optimizations
29+
30+
### Standalone Encoders
31+
32+
**Animation:**
33+
- `GifEncoderWrapper` - GIF animation encoder with advanced features:
34+
- Floyd-Steinberg dithering for quality color reduction
35+
- Custom 256-color palette with grayscale fallback
36+
- Configurable frame delay and infinite loop support
37+
38+
## Common Interface
39+
40+
### AudioEncoder Trait
41+
42+
All audio encoders implement the `AudioEncoder` trait providing:
43+
- `queue_frame()` - Queue audio frames for encoding
44+
- `finish()` - Finalize encoding and flush remaining data
45+
- `boxed()` - Convert to boxed trait object for dynamic dispatch
46+
47+
## Key Features
48+
49+
### Format Handling
50+
- **Automatic conversion**: Seamless pixel format and sample format conversion between input and encoder requirements
51+
- **Resampling**: Built-in audio resampling for sample rate and format mismatches
52+
- **Validation**: Input validation with detailed error reporting
53+
54+
### Performance Optimizations
55+
- **Hardware acceleration**: AVFoundation encoder leverages macOS VideoToolbox
56+
- **Threading**: Multi-threaded encoding support where available
57+
- **Real-time processing**: Optimized for live capture and streaming scenarios
58+
59+
### Quality Control
60+
- **Configurable presets**: H.264 encoding supports Slow, Medium, and Ultrafast presets
61+
- **Bitrate control**: Intelligent bitrate calculation based on resolution and frame rate
62+
- **Format-specific optimizations**: Each encoder tuned for its target format characteristics
63+
64+
## Dependencies
65+
66+
- `cap-media-info` - Media stream information structures
67+
- `ffmpeg` - Cross-platform media processing (video and audio encoding)
68+
- `gif` - GIF image format encoding
69+
- `cidre` (macOS only) - AVFoundation bindings for native encoding
70+
71+
## Integration
72+
73+
The crate integrates with:
74+
- **cap-media-info** for media stream configuration and format definitions
75+
- **FFmpeg ecosystem** for broad codec and container support
76+
- **macOS AVFoundation** for optimized native encoding on Apple platforms
77+
- **Raw media pipelines** for direct frame processing
78+
79+
## Error Handling
80+
81+
Comprehensive error types for each encoder:
82+
- `H264EncoderError` - Video encoding failures
83+
- `AACEncoderError` / `OpusEncoderError` - Audio encoding issues
84+
- `GifEncodingError` - Animation encoding problems
85+
- `InitError` - Encoder initialization failures
86+
87+
Each error type provides detailed context about failures including codec availability, format compatibility, and resource constraints.
88+
89+
## Use Cases
90+
91+
This crate is designed for applications requiring:
92+
- **Screen recording** with multiple output formats
93+
- **Live streaming** with real-time encoding
94+
- **Video conferencing** with adaptive quality
95+
- **Media conversion** between different formats
96+
- **Animation creation** from frame sequences
97+
98+
The modular design allows applications to choose the most appropriate encoder for their specific requirements, whether prioritizing quality, performance, or compatibility.

0 commit comments

Comments
 (0)