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