Skip to main content

ffmpeg_pipeline/io/
mod.rs

1mod input;
2mod output;
3mod utils;
4
5use super::*;
6use ffmpeg_next::{
7    format::{input_with_dictionary, output_with},
8    media, Dictionary,
9};
10use input::BufferedInput;
11use output::BufferedOutput;
12use std::{io::Cursor, path::Path};
13use utils::{get_avio_context, AVInputContextData, AVOutputContextData, Readable, Writable};
14
15#[inline(always)]
16pub fn input_buffer(data: Vec<u8>) -> FFmpegResult<BufferedInput> {
17    input_reader(Cursor::new(data))
18}
19
20#[inline(always)]
21pub fn input_buffer_with_format(data: Vec<u8>, format: &str) -> FFmpegResult<BufferedInput> {
22    BufferedInput::from_reader_with_format(Cursor::new(data), Some(format))
23}
24
25#[inline(always)]
26pub fn input_buffer_with_format_options(
27    data: Vec<u8>,
28    format: &str,
29    options: &[(&str, &str)],
30) -> FFmpegResult<BufferedInput> {
31    BufferedInput::from_reader_with_format_and_options(Cursor::new(data), Some(format), options)
32}
33
34pub fn input_reader<R: Readable + 'static>(reader: R) -> FFmpegResult<BufferedInput> {
35    BufferedInput::from_reader(reader)
36}
37
38#[inline(always)]
39pub fn output_buffer(format: &str) -> FFmpegResult<BufferedOutput> {
40    output_writer(Cursor::new(vec![]), format)
41}
42
43pub fn output_writer<W: Writable + 'static>(
44    writer: W,
45    format: &str,
46) -> FFmpegResult<BufferedOutput> {
47    BufferedOutput::from_writer(writer, format)
48}
49
50pub fn input_file<P: AsRef<Path>>(path: P) -> FFmpegResult<Input> {
51    let mut options = Dictionary::new();
52    options.set("max_streams", "8192");
53    input_with_dictionary(&path, options).map_err(|e| e.into())
54}
55
56/// guess the output format from the file extension
57pub fn output_file<P: AsRef<Path>>(path: P) -> FFmpegResult<Output> {
58    let mut options = Dictionary::new();
59    options.set("max_streams", "8192");
60    output_with(&path, options).map_err(|e| e.into())
61}
62
63pub fn read_attachment<P: AsRef<Path>>(path: P, index: usize) -> FFmpegResult<Vec<u8>> {
64    let input = input_file(&path)?;
65    let mut ret = Vec::new();
66    if let Some(stream) = input.stream(index) {
67        if stream.parameters().medium() == media::Type::Attachment {
68            let params = stream.parameters();
69            unsafe {
70                let data = (*params.as_ptr()).extradata as *const u8;
71                let size = (*params.as_ptr()).extradata_size as usize;
72
73                if !data.is_null() && size > 0 {
74                    ret.extend_from_slice(std::slice::from_raw_parts(data, size));
75                }
76            }
77        }
78    }
79    if ret.is_empty() {
80        Err(FFmpegError::AttachmentNotFound(index))
81    } else {
82        Ok(ret)
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_read_attachment() {
92        initialize(log::Level::Error).unwrap();
93        let path = std::env::temp_dir().join(format!(
94            "ffmpeg-pipeline-attachment-{}.ivf",
95            std::process::id()
96        ));
97        std::fs::write(&path, crate::tests::encoded_ivf(1)).unwrap();
98        let result = read_attachment(&path, 0);
99        std::fs::remove_file(path).unwrap();
100        assert!(matches!(result, Err(FFmpegError::AttachmentNotFound(0))));
101    }
102}