Skip to main content

ff_format/
lib.rs

1//! # ff-format
2//!
3//! Common types for video/audio processing - the Rust way.
4//!
5//! This crate provides shared type definitions used across the ff-* crate family.
6//! It completely hides `FFmpeg` internals and provides Rust-idiomatic type safety.
7//!
8//! ## Module Structure
9//!
10//! - `pixel` - Pixel format definitions ([`PixelFormat`])
11//! - `sample` - Audio sample format definitions ([`SampleFormat`])
12//! - `time` - Time primitives ([`Timestamp`], [`Rational`])
13//! - `frame` - Frame types ([`VideoFrame`], [`AudioFrame`])
14//! - `stream` - Stream info ([`VideoStreamInfo`], [`AudioStreamInfo`])
15//! - `media` - Media container info ([`MediaInfo`])
16//! - `color` - Color space definitions ([`ColorSpace`], [`ColorRange`], [`ColorPrimaries`])
17//! - `codec` - Codec definitions ([`VideoCodec`], [`AudioCodec`])
18//! - `channel` - Channel layout definitions ([`ChannelLayout`])
19//! - `error` - Error types ([`FormatError`])
20//!
21//! ## Usage
22//!
23//! ```
24//! use ff_format::prelude::*;
25//!
26//! // Access pixel formats
27//! let format = PixelFormat::Yuv420p;
28//! assert!(format.is_planar());
29//!
30//! // Access sample formats
31//! let audio = SampleFormat::F32;
32//! assert!(audio.is_float());
33//! assert_eq!(audio.bytes_per_sample(), 4);
34//!
35//! // Work with timestamps
36//! let time_base = Rational::new(1, 90000);
37//! let ts = Timestamp::new(90000, time_base);
38//! assert!((ts.as_secs_f64() - 1.0).abs() < 0.001);
39//!
40//! // Access color and codec types
41//! use ff_format::color::ColorSpace;
42//! use ff_format::codec::VideoCodec;
43//! let space = ColorSpace::Bt709;
44//! let codec = VideoCodec::H264;
45//! ```
46
47#![warn(missing_docs)]
48#![warn(clippy::all)]
49#![warn(clippy::pedantic)]
50
51// Module declarations
52pub mod channel;
53pub mod codec;
54pub mod color;
55pub mod error;
56pub mod frame;
57pub mod media;
58pub mod pixel;
59pub mod sample;
60pub mod stream;
61pub mod time;
62
63pub use channel::ChannelLayout;
64pub use codec::{AudioCodec, VideoCodec};
65pub use color::{ColorPrimaries, ColorRange, ColorSpace};
66pub use error::{FormatError, FrameError};
67pub use ff_common::PooledBuffer;
68pub use frame::{AudioFrame, VideoFrame};
69pub use media::{MediaInfo, MediaInfoBuilder};
70pub use pixel::PixelFormat;
71pub use sample::SampleFormat;
72pub use stream::{
73    AudioStreamInfo, AudioStreamInfoBuilder, VideoStreamInfo, VideoStreamInfoBuilder,
74};
75pub use time::{Rational, Timestamp};
76
77/// Prelude module for convenient imports.
78///
79/// This module re-exports all commonly used types for easy access:
80///
81/// ```ignore
82/// use ff_format::prelude::*;
83/// ```
84pub mod prelude {
85    pub use crate::{
86        AudioCodec, AudioFrame, AudioStreamInfo, ChannelLayout, ColorPrimaries, ColorRange,
87        ColorSpace, FormatError, FrameError, MediaInfo, PixelFormat, PooledBuffer, Rational,
88        SampleFormat, Timestamp, VideoCodec, VideoFrame, VideoStreamInfo,
89    };
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn test_prelude_exports() {
98        // Verify prelude exports all expected types
99        let _pixel: PixelFormat = PixelFormat::default();
100        let _sample: SampleFormat = SampleFormat::default();
101        let _rational: Rational = Rational::default();
102        let _timestamp: Timestamp = Timestamp::default();
103        let _video_frame: VideoFrame = VideoFrame::default();
104        let _audio_frame: AudioFrame = AudioFrame::default();
105
106        // New types
107        let _color_space: ColorSpace = ColorSpace::default();
108        let _color_range: ColorRange = ColorRange::default();
109        let _color_primaries: ColorPrimaries = ColorPrimaries::default();
110        let _video_codec: VideoCodec = VideoCodec::default();
111        let _audio_codec: AudioCodec = AudioCodec::default();
112        let _channel_layout: ChannelLayout = ChannelLayout::default();
113        let _video_stream: VideoStreamInfo = VideoStreamInfo::default();
114        let _audio_stream: AudioStreamInfo = AudioStreamInfo::default();
115        let _media_info: MediaInfo = MediaInfo::default();
116    }
117
118    #[test]
119    fn test_stream_info_builder() {
120        // Test VideoStreamInfo builder
121        let video = VideoStreamInfo::builder()
122            .index(0)
123            .codec(VideoCodec::H264)
124            .width(1920)
125            .height(1080)
126            .frame_rate(Rational::new(30, 1))
127            .pixel_format(PixelFormat::Yuv420p)
128            .color_space(ColorSpace::Bt709)
129            .build();
130
131        assert_eq!(video.width(), 1920);
132        assert_eq!(video.height(), 1080);
133        assert_eq!(video.codec(), VideoCodec::H264);
134        assert_eq!(video.color_space(), ColorSpace::Bt709);
135
136        // Test AudioStreamInfo builder
137        let audio = AudioStreamInfo::builder()
138            .index(1)
139            .codec(AudioCodec::Aac)
140            .sample_rate(48000)
141            .channels(2)
142            .sample_format(SampleFormat::F32)
143            .build();
144
145        assert_eq!(audio.sample_rate(), 48000);
146        assert_eq!(audio.channels(), 2);
147        assert_eq!(audio.codec(), AudioCodec::Aac);
148        assert_eq!(audio.channel_layout(), ChannelLayout::Stereo);
149    }
150
151    #[test]
152    fn test_media_info_builder() {
153        use std::time::Duration;
154
155        // Create streams
156        let video = VideoStreamInfo::builder()
157            .index(0)
158            .codec(VideoCodec::H264)
159            .width(1920)
160            .height(1080)
161            .frame_rate(Rational::new(30, 1))
162            .build();
163
164        let audio = AudioStreamInfo::builder()
165            .index(1)
166            .codec(AudioCodec::Aac)
167            .sample_rate(48000)
168            .channels(2)
169            .build();
170
171        // Create media info
172        let media = MediaInfo::builder()
173            .path("/path/to/video.mp4")
174            .format("mp4")
175            .format_long_name("QuickTime / MOV")
176            .duration(Duration::from_secs(120))
177            .file_size(100_000_000)
178            .bitrate(8_000_000)
179            .video_stream(video)
180            .audio_stream(audio)
181            .metadata("title", "Test Video")
182            .build();
183
184        assert!(media.has_video());
185        assert!(media.has_audio());
186        assert_eq!(media.resolution(), Some((1920, 1080)));
187        assert!((media.frame_rate().unwrap() - 30.0).abs() < 0.001);
188        assert_eq!(media.sample_rate(), Some(48000));
189        assert_eq!(media.channels(), Some(2));
190        assert_eq!(media.format(), "mp4");
191        assert_eq!(media.format_long_name(), Some("QuickTime / MOV"));
192        assert_eq!(media.metadata_value("title"), Some("Test Video"));
193    }
194}