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//! - `container` - Container info ([`ContainerInfo`])
16//! - `media` - Media container info ([`MediaInfo`])
17//! - `color` - Color definitions ([`ColorSpace`], [`ColorRange`], [`ColorPrimaries`], [`Color`])
18//! - `text` - Text/title layer spec types ([`TextSpec`], [`TextStyle`], [`Anchor`])
19//! - `hdr` - HDR metadata types ([`Hdr10Metadata`], [`MasteringDisplay`])
20//! - `network` - Network configuration ([`NetworkOptions`])
21//! - `codec` - Codec definitions ([`VideoCodec`], [`AudioCodec`])
22//! - `channel` - Channel layout definitions ([`ChannelLayout`])
23//! - `chapter` - Chapter information ([`ChapterInfo`])
24//! - `error` - Error types ([`FormatError`])
25//!
26//! ## Usage
27//!
28//! ```
29//! use ff_format::prelude::*;
30//!
31//! // Access pixel formats
32//! let format = PixelFormat::Yuv420p;
33//! assert!(format.is_planar());
34//!
35//! // Access sample formats
36//! let audio = SampleFormat::F32;
37//! assert!(audio.is_float());
38//! assert_eq!(audio.bytes_per_sample(), 4);
39//!
40//! // Work with timestamps
41//! let time_base = Rational::new(1, 90000);
42//! let ts = Timestamp::new(90000, time_base);
43//! assert!((ts.as_secs_f64() - 1.0).abs() < 0.001);
44//!
45//! // Access color and codec types
46//! use ff_format::color::ColorSpace;
47//! use ff_format::codec::VideoCodec;
48//! let space = ColorSpace::Bt709;
49//! let codec = VideoCodec::H264;
50//! ```
51
52#![warn(missing_docs)]
53#![warn(clippy::all)]
54#![warn(clippy::pedantic)]
55
56// Module declarations
57pub mod channel;
58pub mod chapter;
59pub mod codec;
60pub mod color;
61pub mod container;
62pub mod error;
63pub mod frame;
64pub mod hdr;
65pub mod media;
66pub mod media_error;
67pub mod network;
68pub mod pixel;
69pub mod sample;
70pub mod stream;
71pub mod subtitle;
72pub mod text;
73pub mod time;
74
75pub use channel::ChannelLayout;
76pub use chapter::{ChapterInfo, ChapterInfoBuilder};
77pub use codec::{AudioCodec, SubtitleCodec, VideoCodec};
78pub use color::{AlphaMode, Color, ColorPrimaries, ColorRange, ColorSpace, ColorTransfer};
79pub use container::{ContainerInfo, ContainerInfoBuilder};
80pub use error::{FormatError, FrameError, SubtitleError};
81pub use ff_common::PooledBuffer;
82pub use frame::{AudioFrame, VideoFrame};
83pub use hdr::{Hdr10Metadata, MasteringDisplay};
84pub use media::{MediaInfo, MediaInfoBuilder};
85pub use media_error::{ErrorSeverity, MediaError};
86pub use network::NetworkOptions;
87pub use pixel::PixelFormat;
88pub use sample::SampleFormat;
89pub use stream::{
90    AudioStreamInfo, AudioStreamInfoBuilder, SubtitleStreamInfo, SubtitleStreamInfoBuilder,
91    VideoStreamInfo, VideoStreamInfoBuilder,
92};
93pub use text::{Anchor, TextSpec, TextStyle};
94pub use time::{Rational, Timestamp};
95
96/// Prelude module for convenient imports.
97///
98/// This module re-exports all commonly used types for easy access:
99///
100/// ```ignore
101/// use ff_format::prelude::*;
102/// ```
103pub mod prelude {
104    pub use crate::{
105        AudioCodec, AudioFrame, AudioStreamInfo, ChannelLayout, ChapterInfo, ColorPrimaries,
106        ColorRange, ColorSpace, ErrorSeverity, FormatError, FrameError, MediaError, MediaInfo,
107        NetworkOptions, PixelFormat, PooledBuffer, Rational, SampleFormat, Timestamp, VideoCodec,
108        VideoFrame, VideoStreamInfo,
109    };
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[test]
117    fn test_prelude_exports() {
118        // Verify prelude exports all expected types
119        let _pixel: PixelFormat = PixelFormat::default();
120        let _sample: SampleFormat = SampleFormat::default();
121        let _rational: Rational = Rational::default();
122        let _timestamp: Timestamp = Timestamp::default();
123        let _video_frame: VideoFrame = VideoFrame::default();
124        let _audio_frame: AudioFrame = AudioFrame::default();
125
126        // New types
127        let _color_space: ColorSpace = ColorSpace::default();
128        let _color_range: ColorRange = ColorRange::default();
129        let _color_primaries: ColorPrimaries = ColorPrimaries::default();
130        let _video_codec: VideoCodec = VideoCodec::default();
131        let _audio_codec: AudioCodec = AudioCodec::default();
132        let _channel_layout: ChannelLayout = ChannelLayout::default();
133        let _video_stream: VideoStreamInfo = VideoStreamInfo::default();
134        let _audio_stream: AudioStreamInfo = AudioStreamInfo::default();
135        let _media_info: MediaInfo = MediaInfo::default();
136        let _network_opts: NetworkOptions = NetworkOptions::default();
137    }
138
139    #[test]
140    fn test_stream_info_builder() {
141        // Test VideoStreamInfo builder
142        let video = VideoStreamInfo::builder()
143            .index(0)
144            .codec(VideoCodec::H264)
145            .width(1920)
146            .height(1080)
147            .frame_rate(Rational::new(30, 1))
148            .pixel_format(PixelFormat::Yuv420p)
149            .color_space(ColorSpace::Bt709)
150            .build();
151
152        assert_eq!(video.width(), 1920);
153        assert_eq!(video.height(), 1080);
154        assert_eq!(video.codec(), VideoCodec::H264);
155        assert_eq!(video.color_space(), ColorSpace::Bt709);
156
157        // Test AudioStreamInfo builder
158        let audio = AudioStreamInfo::builder()
159            .index(1)
160            .codec(AudioCodec::Aac)
161            .sample_rate(48000)
162            .channels(2)
163            .sample_format(SampleFormat::F32)
164            .build();
165
166        assert_eq!(audio.sample_rate(), 48000);
167        assert_eq!(audio.channels(), 2);
168        assert_eq!(audio.codec(), AudioCodec::Aac);
169        assert_eq!(audio.channel_layout(), ChannelLayout::Stereo);
170    }
171
172    #[test]
173    fn test_media_info_builder() {
174        use std::time::Duration;
175
176        // Create streams
177        let video = VideoStreamInfo::builder()
178            .index(0)
179            .codec(VideoCodec::H264)
180            .width(1920)
181            .height(1080)
182            .frame_rate(Rational::new(30, 1))
183            .build();
184
185        let audio = AudioStreamInfo::builder()
186            .index(1)
187            .codec(AudioCodec::Aac)
188            .sample_rate(48000)
189            .channels(2)
190            .build();
191
192        // Create media info
193        let media = MediaInfo::builder()
194            .path("/path/to/video.mp4")
195            .format("mp4")
196            .format_long_name("QuickTime / MOV")
197            .duration(Duration::from_secs(120))
198            .file_size(100_000_000)
199            .bitrate(8_000_000)
200            .video_stream(video)
201            .audio_stream(audio)
202            .metadata("title", "Test Video")
203            .build();
204
205        assert!(media.has_video());
206        assert!(media.has_audio());
207        assert_eq!(media.resolution(), Some((1920, 1080)));
208        assert!((media.frame_rate().unwrap() - 30.0).abs() < 0.001);
209        assert_eq!(media.sample_rate(), Some(48000));
210        assert_eq!(media.channels(), Some(2));
211        assert_eq!(media.format(), "mp4");
212        assert_eq!(media.format_long_name(), Some("QuickTime / MOV"));
213        assert_eq!(media.metadata_value("title"), Some("Test Video"));
214    }
215}