scuffle_ffmpeg/
lib.rs

1//! A crate designed to provide a simple interface to the native ffmpeg c-bindings.
2//!
3//! ## Why do we need this?
4//!
5//! This crate aims to provide a simple-safe interface to the native ffmpeg c-bindings.
6//!
7//! Currently this crate only supports the latest versions of ffmpeg (7.x.x).
8//!
9//! ## How is this different from other ffmpeg crates?
10//!
11//! The other main ffmpeg crate is [ffmpeg-next](https://github.com/zmwangx/rust-ffmpeg).
12//!
13//! This crate adds a few features and has a safer API. Notably it adds the ability to provide an in-memory decode / encode buffer.
14//!
15//! ## Examples
16//!
17//! ### Decoding a audio/video file
18//!
19//! ```rust
20//! # use std::path::PathBuf;
21//! # use scuffle_ffmpeg::AVMediaType;
22//! # fn test_fn() -> Result<(), Box<dyn std::error::Error>> {
23//! # let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../assets").join("avc_aac.mp4");
24//! // 1. Store the input of the file from the path `path`
25//! // this can be any seekable io stream (std::io::Read + std::io::Seek)
26//! // if you don't have seek, you can just use Input::new(std::io::Read) (no seeking support)
27//! let mut input = scuffle_ffmpeg::io::Input::seekable(std::fs::File::open(path)?)?;
28//! // 2. Get the streams from the input
29//! let streams = input.streams();
30//!
31//! dbg!(&streams);
32//!
33//! // 3. Store video and audio stream into respective their variables; we will panic if either one doesn't exist.
34//! let best_video_stream = streams.best(AVMediaType::Video).expect("no video stream found");
35//! let best_audio_stream = streams.best(AVMediaType::Audio).expect("no audio stream found");
36//!
37//! dbg!(&best_video_stream);
38//! dbg!(&best_audio_stream);
39//!
40//! // 4. Create and store the respective video and audio decoders; we will panic if either one doesn't exist, or is an invalid decoder.
41//! let mut video_decoder = scuffle_ffmpeg::decoder::Decoder::new(&best_video_stream)?.video().expect("not an video decoder");
42//! let mut audio_decoder = scuffle_ffmpeg::decoder::Decoder::new(&best_audio_stream)?.audio().expect("not an audio decoder");
43//!
44//! dbg!(&video_decoder);
45//! dbg!(&audio_decoder);
46//!
47//! // 5. Get the stream index of the video and audio streams.
48//! let video_stream_index = best_video_stream.index();
49//! let audio_stream_index = best_audio_stream.index();
50//!
51//! // 6. Iterate over the packets in the input.
52//! for packet in input.packets() {
53//!     let packet = packet?;
54//!     // 7. Send the packet to the respective decoder.
55//!     // 8. Receive the frame from the decoder.
56//!     if packet.stream_index() == video_stream_index {
57//!         video_decoder.send_packet(&packet)?;
58//!         while let Some(frame) = video_decoder.receive_frame()? {
59//!             dbg!(&frame);
60//!         }
61//!     } else if packet.stream_index() == audio_stream_index {
62//!         audio_decoder.send_packet(&packet)?;
63//!         while let Some(frame) = audio_decoder.receive_frame()? {
64//!             dbg!(&frame);
65//!         }
66//!     }
67//! }
68//!
69//! // 9. Send the EOF to the decoders.
70//! video_decoder.send_eof()?;
71//! audio_decoder.send_eof()?;
72//!
73//! // 10. Receive the remaining frames from the decoders.
74//! while let Some(frame) = video_decoder.receive_frame()? {
75//!     dbg!(&frame);
76//! }
77//!
78//! while let Some(frame) = audio_decoder.receive_frame()? {
79//!     dbg!(&frame);
80//! }
81//! # Ok(())
82//! # }
83//! # test_fn().expect("failed to run test");
84//! ```
85//!
86//! ### Re-encoding a audio/video file
87//!
88//! ```rust
89//! # use std::path::PathBuf;
90//! # use scuffle_ffmpeg::{AVMediaType, AVCodecID};
91//! # use scuffle_ffmpeg::encoder::{AudioEncoderSettings, VideoEncoderSettings};
92//! # use scuffle_ffmpeg::io::OutputOptions;
93//! # use scuffle_ffmpeg::frame::AudioChannelLayout;
94//! #
95//! # fn test_fn() -> Result<(), Box<dyn std::error::Error>> {
96//! # let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../assets").join("avc_aac.mp4");
97//! // 1. Create an input for reading. In this case we open it from a std::fs::File, however
98//! // it can be from any seekable io stream (std::io::Read + std::io::Seek) for example a std::io::Cursor.
99//! // It can also be a non-seekable stream in that case you can use Input::new(std::io::Read)
100//! let input = scuffle_ffmpeg::io::Input::seekable(std::fs::File::open(path)?)?;
101//!
102//! // 2. Get the streams from the input.
103//! let streams = input.streams();
104//!
105//! // 3. Store the best video and audio streams into respective their variables; we will panic if either one doesn't exist.
106//! let best_video_stream = streams.best(AVMediaType::Video).expect("no video stream found");
107//! let best_audio_stream = streams.best(AVMediaType::Audio).expect("no audio stream found");
108//!
109//! // 4. Create and store the respective video and audio decoders; we will panic if either one doesn't exist, or is an invalid decoder.
110//! let mut video_decoder = scuffle_ffmpeg::decoder::Decoder::new(&best_video_stream)?.video().expect("not an video decoder");
111//! let mut audio_decoder = scuffle_ffmpeg::decoder::Decoder::new(&best_audio_stream)?.audio().expect("not an audio decoder");
112//!
113//! // 5. Create an output for writing. In this case we use a std::io::Cursor, however it can be any seekable io stream (std::io::Read + std::io::Seek) for example a std::io::Cursor.
114//! // It can also be a non-seekable stream in that case you can use Output::new(std::io::Read)
115//! let mut output = scuffle_ffmpeg::io::Output::seekable(std::io::Cursor::new(Vec::new()), OutputOptions::builder().format_name("mp4")?.build())?;
116//!
117//! // 6. Find the respective encoders for the video and audio streams.
118//! let x264 = scuffle_ffmpeg::codec::EncoderCodec::by_name("libx264").expect("no h264 encoder found");
119//! let aac = scuffle_ffmpeg::codec::EncoderCodec::new(AVCodecID::Aac).expect("no aac encoder found");
120//!
121//! // 7. Create the respective encoder settings for the video and audio streams.
122//! let video_settings = VideoEncoderSettings::builder()
123//!     .width(video_decoder.width())
124//!     .height(video_decoder.height())
125//!     .frame_rate(video_decoder.frame_rate())
126//!     .pixel_format(video_decoder.pixel_format())
127//!     .build();
128//!
129//! let audio_settings = AudioEncoderSettings::builder()
130//!     .sample_rate(audio_decoder.sample_rate())
131//!     .ch_layout(AudioChannelLayout::new(audio_decoder.channels()).expect("invalid channel layout"))
132//!     .sample_fmt(audio_decoder.sample_format())
133//!     .build();
134//!
135//! // 8. Create the respective encoders for the video and audio streams.
136//! let mut video_encoder = scuffle_ffmpeg::encoder::Encoder::new(x264, &mut output, best_video_stream.time_base(), best_video_stream.time_base(), video_settings).expect("not an video encoder");
137//! let mut audio_encoder = scuffle_ffmpeg::encoder::Encoder::new(aac, &mut output, best_audio_stream.time_base(), best_audio_stream.time_base(), audio_settings).expect("not an audio encoder");
138//!
139//! // 9. Write the header to the output.
140//! output.write_header()?;
141//!
142//! loop {
143//!     let mut audio_done = false;
144//!     let mut video_done = false;
145//!
146//!     // 10. Receive the frame from the decoders.
147//!     // 11. Send the frame to the encoders.
148//!     // 12. Receive the packet from the encoders.
149//!     // 13. Write the packet to the output.
150//!
151//!     if let Some(frame) = audio_decoder.receive_frame()? {
152//!         audio_encoder.send_frame(&frame)?;
153//!         while let Some(packet) = audio_encoder.receive_packet()? {
154//!             output.write_packet(&packet)?;
155//!         }
156//!     } else {
157//!         audio_done = true;
158//!     }
159//!
160//!     if let Some(frame) = video_decoder.receive_frame()? {
161//!         video_encoder.send_frame(&frame)?;
162//!         while let Some(packet) = video_encoder.receive_packet()? {
163//!             output.write_packet(&packet)?;
164//!         }
165//!     } else {
166//!         video_done = true;
167//!     }
168//!
169//!     // 14. Break the loop if both the audio and video are done.
170//!     if audio_done && video_done {
171//!         break;
172//!     }
173//! }
174//!
175//! // 15. Send the EOF to the decoders.
176//! video_decoder.send_eof()?;
177//! audio_decoder.send_eof()?;
178//!
179//! // 16. Receive the remaining packets from the encoders.
180//! while let Some(packet) = video_encoder.receive_packet()? {
181//!     output.write_packet(&packet)?;
182//! }
183//!
184//! while let Some(packet) = audio_encoder.receive_packet()? {
185//!     output.write_packet(&packet)?;
186//! }
187//!
188//! // 17. Write the trailer to the output.
189//! output.write_trailer()?;
190//!
191//! // 18. Do something with the output data (write to disk, upload to s3, etc).
192//! let output_data = output.into_inner();
193//! # drop(output_data);
194//! # Ok(())
195//! # }
196//! # test_fn().expect("failed to run test");
197//! ```
198//!
199//! ## Status
200//!
201//! This crate is currently under development and is not yet stable.
202//!
203//! Unit tests are not yet fully implemented. Use at your own risk.
204//!
205//! ## License
206//!
207//! This project is licensed under the [MIT](./LICENSE.MIT) or [Apache-2.0](./LICENSE.Apache-2.0) license.
208//! You can choose between one of them if you use this work.
209//!
210//! `SPDX-License-Identifier: MIT OR Apache-2.0`
211#![cfg_attr(all(coverage_nightly, test), feature(coverage_attribute))]
212#![cfg_attr(docsrs, feature(doc_cfg))]
213#![deny(missing_docs)]
214#![deny(unreachable_pub)]
215#![deny(clippy::undocumented_unsafe_blocks)]
216#![deny(clippy::multiple_unsafe_ops_per_block)]
217
218/// Codec specific functionality.
219pub mod codec;
220/// Constants.
221pub mod consts;
222/// Decoder specific functionality.
223pub mod decoder;
224/// Dictionary specific functionality.
225pub mod dict;
226/// Encoder specific functionality.
227pub mod encoder;
228/// Error handling.
229pub mod error;
230/// Filter graph specific functionality.
231pub mod filter_graph;
232/// Frame specific functionality.
233pub mod frame;
234/// Input/Output specific functionality.
235pub mod io;
236/// Logging specific functionality.
237pub mod log;
238/// Packet specific functionality.
239pub mod packet;
240/// Rational number specific functionality.
241pub mod rational;
242/// [`frame::AudioFrame`] resampling and format conversion.
243pub mod resampler;
244/// Scaler specific functionality.
245pub mod scaler;
246/// Stream specific functionality.
247pub mod stream;
248/// Utility functionality.
249pub mod utils;
250
251pub use rusty_ffmpeg::ffi;
252
253mod smart_object;
254
255mod enums;
256
257pub use enums::*;