mirror of
https://github.com/encounter/rust-ffmpeg.git
synced 2026-07-10 21:18:39 -07:00
feat: add AVIO for outputs and refactor formats
This commit is contained in:
@@ -8,11 +8,17 @@ use std::{
|
||||
use libc;
|
||||
|
||||
use super::{common::Context, destructor};
|
||||
use crate::{codec::traits, ffi::*, format, ChapterMut, Dictionary, Error, Rational, StreamMut};
|
||||
use crate::{
|
||||
codec::traits,
|
||||
ffi::*,
|
||||
format::{self, io::Io},
|
||||
ChapterMut, Dictionary, Error, Rational, StreamMut,
|
||||
};
|
||||
|
||||
pub struct Output {
|
||||
ptr: *mut AVFormatContext,
|
||||
ctx: Context,
|
||||
_io: Option<Io>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Output {}
|
||||
@@ -22,6 +28,15 @@ impl Output {
|
||||
Output {
|
||||
ptr,
|
||||
ctx: Context::wrap(ptr, destructor::Mode::Output),
|
||||
_io: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn wrap_with(ptr: *mut AVFormatContext, io: Io) -> Self {
|
||||
Output {
|
||||
ptr,
|
||||
ctx: Context::wrap(ptr, destructor::Mode::Output),
|
||||
_io: Some(io),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::{ffi::CStr, str::from_utf8_unchecked};
|
||||
use std::{ffi::CStr, ptr, str::from_utf8_unchecked};
|
||||
|
||||
use crate::ffi::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Input {
|
||||
ptr: *mut AVInputFormat,
|
||||
}
|
||||
@@ -59,3 +60,58 @@ impl Input {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter {
|
||||
input: *mut AVInputFormat,
|
||||
}
|
||||
|
||||
impl Iter {
|
||||
pub fn new() -> Self {
|
||||
Iter {
|
||||
input: ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Iter {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Iter {
|
||||
type Item = Input;
|
||||
|
||||
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||
unsafe {
|
||||
let ptr = av_iformat_next(self.input);
|
||||
|
||||
if ptr.is_null() && !self.input.is_null() {
|
||||
None
|
||||
}
|
||||
else {
|
||||
self.input = ptr;
|
||||
Some(Input::wrap(ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all() -> Iter {
|
||||
Iter::new()
|
||||
}
|
||||
|
||||
pub fn by_name(name: impl Into<String>) -> impl Iterator<Item = Input> {
|
||||
let name = name.into();
|
||||
all().filter(move |i| i.name() == name)
|
||||
}
|
||||
|
||||
pub fn by_mime(mime: impl Into<String>) -> impl Iterator<Item = Input> {
|
||||
let mime = mime.into();
|
||||
all().filter(move |i| i.mime_types().contains(&mime.as_ref()))
|
||||
}
|
||||
|
||||
pub fn by_extension(ext: impl Into<String>) -> impl Iterator<Item = Input> {
|
||||
let ext = ext.into();
|
||||
all().filter(move |i| i.extensions().contains(&ext.as_ref()))
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
use std::ptr;
|
||||
|
||||
use super::{Format, Input, Output};
|
||||
use crate::ffi::*;
|
||||
|
||||
pub struct Iter {
|
||||
input: *mut AVInputFormat,
|
||||
output: *mut AVOutputFormat,
|
||||
step: Step,
|
||||
}
|
||||
|
||||
enum Step {
|
||||
Input,
|
||||
Output,
|
||||
Done,
|
||||
}
|
||||
|
||||
impl Iter {
|
||||
pub fn new() -> Self {
|
||||
Iter {
|
||||
input: ptr::null_mut(),
|
||||
output: ptr::null_mut(),
|
||||
step: Step::Input,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Iter {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Iter {
|
||||
type Item = Format;
|
||||
|
||||
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||
unsafe {
|
||||
match self.step {
|
||||
Step::Input => {
|
||||
let ptr = av_iformat_next(self.input);
|
||||
|
||||
if ptr.is_null() && !self.input.is_null() {
|
||||
self.step = Step::Output;
|
||||
|
||||
self.next()
|
||||
}
|
||||
else {
|
||||
self.input = ptr;
|
||||
|
||||
Some(Format::Input(Input::wrap(ptr)))
|
||||
}
|
||||
}
|
||||
|
||||
Step::Output => {
|
||||
let ptr = av_oformat_next(self.output);
|
||||
|
||||
if ptr.is_null() && !self.output.is_null() {
|
||||
self.step = Step::Done;
|
||||
|
||||
self.next()
|
||||
}
|
||||
else {
|
||||
self.output = ptr;
|
||||
|
||||
Some(Format::Output(Output::wrap(ptr)))
|
||||
}
|
||||
}
|
||||
|
||||
Step::Done => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
pub mod flag;
|
||||
pub use self::flag::Flags;
|
||||
|
||||
mod input;
|
||||
pub mod input;
|
||||
pub use self::input::Input;
|
||||
|
||||
mod output;
|
||||
pub mod output;
|
||||
pub use self::output::Output;
|
||||
|
||||
mod iter;
|
||||
pub use self::iter::Iter;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Format {
|
||||
Input(Input),
|
||||
Output(Output),
|
||||
@@ -45,6 +43,8 @@ impl Format {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list() -> Iter {
|
||||
Iter::new()
|
||||
pub fn all() -> impl Iterator<Item = Format> {
|
||||
input::all()
|
||||
.map(|i| Format::Input(i))
|
||||
.chain(output::all().map(|o| Format::Output(o)))
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use std::{
|
||||
use super::Flags;
|
||||
use crate::{codec, ffi::*, media};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Output {
|
||||
ptr: *mut AVOutputFormat,
|
||||
}
|
||||
@@ -84,3 +85,58 @@ impl Output {
|
||||
unsafe { Flags::from_bits_truncate((*self.as_ptr()).flags) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter {
|
||||
output: *mut AVOutputFormat,
|
||||
}
|
||||
|
||||
impl Iter {
|
||||
pub fn new() -> Self {
|
||||
Iter {
|
||||
output: ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Iter {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Iter {
|
||||
type Item = Output;
|
||||
|
||||
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||
unsafe {
|
||||
let ptr = av_oformat_next(self.output);
|
||||
|
||||
if ptr.is_null() && !self.output.is_null() {
|
||||
None
|
||||
}
|
||||
else {
|
||||
self.output = ptr;
|
||||
Some(Output::wrap(ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all() -> Iter {
|
||||
Iter::new()
|
||||
}
|
||||
|
||||
pub fn by_name(name: impl Into<String>) -> impl Iterator<Item = Output> {
|
||||
let name = name.into();
|
||||
all().filter(move |i| i.name() == name)
|
||||
}
|
||||
|
||||
pub fn by_mime(mime: impl Into<String>) -> impl Iterator<Item = Output> {
|
||||
let mime = mime.into();
|
||||
all().filter(move |i| i.mime_types().contains(&mime.as_ref()))
|
||||
}
|
||||
|
||||
pub fn by_extension(ext: impl Into<String>) -> impl Iterator<Item = Output> {
|
||||
let ext = ext.into();
|
||||
all().filter(move |i| i.extensions().contains(&ext.as_ref()))
|
||||
}
|
||||
|
||||
+58
-1
@@ -6,7 +6,11 @@ use std::{
|
||||
|
||||
use libc::{c_int, c_void, EINVAL, SEEK_CUR, SEEK_END, SEEK_SET};
|
||||
|
||||
use crate::{ffi::*, format::context, Error};
|
||||
use crate::{
|
||||
ffi::*,
|
||||
format::{context, format},
|
||||
Error,
|
||||
};
|
||||
|
||||
pub enum Proxy {
|
||||
Input(Box<dyn InputIo>),
|
||||
@@ -212,3 +216,56 @@ pub fn input(io: impl Read + Seek + 'static) -> Result<context::Input, Error> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input_as(
|
||||
io: impl Read + Seek + 'static,
|
||||
mut format: format::Input,
|
||||
) -> Result<context::Input, Error> {
|
||||
unsafe {
|
||||
let mut ps = avformat_alloc_context();
|
||||
let mut io = Io::input(io);
|
||||
(*ps).pb = io.as_mut_ptr();
|
||||
|
||||
match avformat_open_input(
|
||||
&mut ps,
|
||||
ptr::null_mut(),
|
||||
format.as_mut_ptr(),
|
||||
ptr::null_mut(),
|
||||
) {
|
||||
0 => match avformat_find_stream_info(ps, ptr::null_mut()) {
|
||||
r if r >= 0 => Ok(context::Input::wrap_with(ps, io)),
|
||||
|
||||
e => {
|
||||
avformat_close_input(&mut ps);
|
||||
Err(Error::from(e))
|
||||
}
|
||||
},
|
||||
|
||||
e => Err(Error::from(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output(
|
||||
io: impl Write + 'static,
|
||||
mut format: format::Output,
|
||||
) -> Result<context::Output, Error> {
|
||||
unsafe {
|
||||
let mut ps = ptr::null_mut();
|
||||
let mut io = Io::output(io);
|
||||
|
||||
match avformat_alloc_output_context2(
|
||||
&mut ps,
|
||||
format.as_mut_ptr(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
) {
|
||||
n if n >= 0 => {
|
||||
(*ps).pb = io.as_mut_ptr();
|
||||
Ok(context::Output::wrap_with(ps, io))
|
||||
}
|
||||
|
||||
e => Err(Error::from(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-31
@@ -10,17 +10,17 @@ pub mod context;
|
||||
pub use self::context::Context;
|
||||
|
||||
pub mod format;
|
||||
pub use self::format::{flag, list, Flags, Input, Output};
|
||||
pub use self::format::{all, flag, input, output, Flags, Input, Output};
|
||||
|
||||
pub mod network;
|
||||
|
||||
use std::{
|
||||
ffi::{CStr, CString, OsStr},
|
||||
ffi::{CStr, OsStr},
|
||||
ptr,
|
||||
str::from_utf8_unchecked,
|
||||
};
|
||||
|
||||
use crate::{ffi::*, Dictionary, Error, Format};
|
||||
use crate::{ffi::*, util::from_os_str, Dictionary, Error, Format};
|
||||
|
||||
pub fn register_all() {
|
||||
unsafe {
|
||||
@@ -52,7 +52,7 @@ pub fn license() -> &'static str {
|
||||
unsafe { from_utf8_unchecked(CStr::from_ptr(avformat_license()).to_bytes()) }
|
||||
}
|
||||
|
||||
pub fn open<P: AsRef<OsStr>>(path_or_url: P, format: &Format) -> Result<Context, Error> {
|
||||
pub fn open(path_or_url: impl AsRef<OsStr>, format: &Format) -> Result<Context, Error> {
|
||||
unsafe {
|
||||
let mut ps = ptr::null_mut();
|
||||
let path = from_os_str(path_or_url);
|
||||
@@ -89,8 +89,8 @@ pub fn open<P: AsRef<OsStr>>(path_or_url: P, format: &Format) -> Result<Context,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_with<P: AsRef<OsStr>>(
|
||||
path_or_url: P,
|
||||
pub fn open_with(
|
||||
path_or_url: impl AsRef<OsStr>,
|
||||
format: &Format,
|
||||
options: Dictionary<'_>,
|
||||
) -> Result<Context, Error> {
|
||||
@@ -132,7 +132,7 @@ pub fn open_with<P: AsRef<OsStr>>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input<P: AsRef<OsStr>>(path_or_url: P) -> Result<context::Input, Error> {
|
||||
pub fn input(path_or_url: impl AsRef<OsStr>) -> Result<context::Input, Error> {
|
||||
unsafe {
|
||||
let mut ps = ptr::null_mut();
|
||||
let path = from_os_str(path_or_url);
|
||||
@@ -151,8 +151,8 @@ pub fn input<P: AsRef<OsStr>>(path_or_url: P) -> Result<context::Input, Error> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input_with_dictionary<P: AsRef<OsStr>>(
|
||||
path_or_url: P,
|
||||
pub fn input_with_dictionary(
|
||||
path_or_url: impl AsRef<OsStr>,
|
||||
options: Dictionary<'_>,
|
||||
) -> Result<context::Input, Error> {
|
||||
unsafe {
|
||||
@@ -200,7 +200,7 @@ pub fn input_with_interrupt<P: AsRef<OsStr>>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output<P: AsRef<OsStr>>(path_or_url: P) -> Result<context::Output, Error> {
|
||||
pub fn output(path_or_url: impl AsRef<OsStr>) -> Result<context::Output, Error> {
|
||||
unsafe {
|
||||
let mut ps = ptr::null_mut();
|
||||
let path = from_os_str(path_or_url);
|
||||
@@ -216,8 +216,8 @@ pub fn output<P: AsRef<OsStr>>(path_or_url: P) -> Result<context::Output, Error>
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output_with<P: AsRef<OsStr>>(
|
||||
path_or_url: P,
|
||||
pub fn output_with(
|
||||
path_or_url: impl AsRef<OsStr>,
|
||||
options: Dictionary<'_>,
|
||||
) -> Result<context::Output, Error> {
|
||||
unsafe {
|
||||
@@ -248,13 +248,20 @@ pub fn output_with<P: AsRef<OsStr>>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output_as<P: AsRef<OsStr>>(path_or_url: P, format: &str) -> Result<context::Output, Error> {
|
||||
pub fn output_as(
|
||||
path_or_url: impl AsRef<OsStr>,
|
||||
mut format: format::Output,
|
||||
) -> Result<context::Output, Error> {
|
||||
unsafe {
|
||||
let mut ps = ptr::null_mut();
|
||||
let path = from_os_str(path_or_url);
|
||||
let format = CString::new(format).unwrap();
|
||||
|
||||
match avformat_alloc_output_context2(&mut ps, ptr::null_mut(), format.as_ptr(), path.as_ptr()) {
|
||||
match avformat_alloc_output_context2(
|
||||
&mut ps,
|
||||
format.as_mut_ptr(),
|
||||
ptr::null_mut(),
|
||||
path.as_ptr(),
|
||||
) {
|
||||
0 => match avio_open(&mut (*ps).pb, path.as_ptr(), AVIO_FLAG_WRITE) {
|
||||
0 => Ok(context::Output::wrap(ps)),
|
||||
e => Err(Error::from(e)),
|
||||
@@ -265,18 +272,22 @@ pub fn output_as<P: AsRef<OsStr>>(path_or_url: P, format: &str) -> Result<contex
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output_as_with<P: AsRef<OsStr>>(
|
||||
path_or_url: P,
|
||||
format: &str,
|
||||
pub fn output_as_with(
|
||||
path_or_url: impl AsRef<OsStr>,
|
||||
mut format: format::Output,
|
||||
options: Dictionary<'_>,
|
||||
) -> Result<context::Output, Error> {
|
||||
unsafe {
|
||||
let mut ps = ptr::null_mut();
|
||||
let path = from_os_str(path_or_url);
|
||||
let format = CString::new(format).unwrap();
|
||||
let mut opts = options.disown();
|
||||
|
||||
match avformat_alloc_output_context2(&mut ps, ptr::null_mut(), format.as_ptr(), path.as_ptr()) {
|
||||
match avformat_alloc_output_context2(
|
||||
&mut ps,
|
||||
format.as_mut_ptr(),
|
||||
ptr::null_mut(),
|
||||
path.as_ptr(),
|
||||
) {
|
||||
0 => {
|
||||
let res = avio_open2(
|
||||
&mut (*ps).pb,
|
||||
@@ -298,14 +309,3 @@ pub fn output_as_with<P: AsRef<OsStr>>(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn from_os_str(path_or_url: impl AsRef<OsStr>) -> CString {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
CString::new(path_or_url.as_ref().as_bytes()).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn from_os_str(path_or_url: impl AsRef<OsStr>) -> CString {
|
||||
CString::new(path_or_url.as_ref().to_str().unwrap()).unwrap()
|
||||
}
|
||||
|
||||
+15
-1
@@ -18,7 +18,10 @@ pub mod time;
|
||||
#[cfg(feature = "log")]
|
||||
pub mod log;
|
||||
|
||||
use std::{ffi::CStr, str::from_utf8_unchecked};
|
||||
use std::{
|
||||
ffi::{CStr, CString, OsStr},
|
||||
str::from_utf8_unchecked,
|
||||
};
|
||||
|
||||
use crate::ffi::*;
|
||||
|
||||
@@ -36,3 +39,14 @@ pub fn configuration() -> &'static str {
|
||||
pub fn license() -> &'static str {
|
||||
unsafe { from_utf8_unchecked(CStr::from_ptr(avutil_license()).to_bytes()) }
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn from_os_str(path_or_url: impl AsRef<OsStr>) -> CString {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
CString::new(path_or_url.as_ref().as_bytes()).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
pub fn from_os_str(path_or_url: impl AsRef<OsStr>) -> CString {
|
||||
CString::new(path_or_url.as_ref().to_str().unwrap()).unwrap()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user