Support FFmpeg 7.0 (#48)

* sys: Run cargo fmt

* sys: Add new channel layout consts

* sys: Update build script for 7.0

- Add new FF_API flags
- Update version_check_info range
- Add ffmpeg_7_0 feature entry

* sys: Update non-exhaustive match statement

* Update enums

* Mark old APIs as removed with 7.0

* Make Audio frame work with 7.0

The .unwrap() in clone() is a bit wonky

* Add API for swr_alloc_set_opts2

* Use AVFrame::duration field in 7.0+

* Include 7.0 in CI runs

* Add fn ChanneLayoutIter::best

* Update examples for new API

* Add/update Context setter for ch layout
This commit is contained in:
FreezyLemon
2024-04-30 03:38:37 +02:00
committed by GitHub
parent 0107b62f56
commit fd2d71c92b
26 changed files with 419 additions and 43 deletions

View File

@ -30,7 +30,7 @@ jobs:
strategy: strategy:
matrix: matrix:
ffmpeg_version: ffmpeg_version:
["3.4", "4.0", "4.1", "4.2", "4.3", "4.4", "5.0", "5.1", "6.0", "6.1"] ["3.4", "4.0", "4.1", "4.2", "4.3", "4.4", "5.0", "5.1", "6.0", "6.1", "7.0"]
fail-fast: false fail-fast: false
steps: steps:
@ -45,8 +45,9 @@ jobs:
components: rustfmt, clippy components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
with: with:
prefix-key: "v2-rust"
# Only save cache for one FFmpeg version # Only save cache for one FFmpeg version
save-if: ${{ matrix.ffmpeg_version == '6.1' }} save-if: ${{ matrix.ffmpeg_version == '7.0' }}
- name: Check format - name: Check format
run: cargo fmt -- --check run: cargo fmt -- --check
@ -75,6 +76,8 @@ jobs:
with: with:
components: rustfmt, clippy components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
with:
prefix-key: "v2-rust"
- name: Check format - name: Check format
run: cargo fmt -- --check run: cargo fmt -- --check
@ -97,7 +100,7 @@ jobs:
strategy: strategy:
matrix: matrix:
# GyanD builds don't go as far back as the Ubuntu builds # GyanD builds don't go as far back as the Ubuntu builds
ffmpeg_version: ["4.4", "5.0", "5.1", "6.0", "6.1"] ffmpeg_version: ["4.4", "5.0", "5.1", "6.0", "6.1", "7.0"]
fail-fast: false fail-fast: false
env: env:
@ -127,8 +130,8 @@ jobs:
components: rustfmt, clippy components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
with: with:
prefix-key: "v1-rust" prefix-key: "v2-rust"
save-if: ${{ matrix.ffmpeg_version == '6.1' }} save-if: ${{ matrix.ffmpeg_version == '7.0' }}
- name: Check format - name: Check format
run: cargo fmt -- --check run: cargo fmt -- --check
@ -147,7 +150,7 @@ jobs:
msrv: msrv:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
container: jrottenberg/ffmpeg:6.1-ubuntu container: jrottenberg/ffmpeg:7.0-ubuntu
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -159,6 +162,8 @@ jobs:
- name: Install Rust 1.61.0 - name: Install Rust 1.61.0
uses: dtolnay/rust-toolchain@1.61.0 uses: dtolnay/rust-toolchain@1.61.0
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
with:
prefix-key: "v2-rust"
- name: Use predefined lockfile - name: Use predefined lockfile
run: mv Cargo.lock.MSRV Cargo.lock run: mv Cargo.lock.MSRV Cargo.lock

View File

@ -47,7 +47,8 @@ fn main() {
println!("\t formats: any"); println!("\t formats: any");
} }
if let Some(layouts) = audio.channel_layouts() { #[cfg(feature = "ffmpeg_5_1")]
if let Some(layouts) = audio.ch_layouts() {
println!("\t channel_layouts: {:?}", layouts.collect::<Vec<_>>()); println!("\t channel_layouts: {:?}", layouts.collect::<Vec<_>>());
} else { } else {
println!("\t channel_layouts: any"); println!("\t channel_layouts: any");
@ -97,7 +98,8 @@ fn main() {
println!("\t formats: any"); println!("\t formats: any");
} }
if let Some(layouts) = audio.channel_layouts() { #[cfg(feature = "ffmpeg_5_1")]
if let Some(layouts) = audio.ch_layouts() {
println!("\t channel_layouts: {:?}", layouts.collect::<Vec<_>>()); println!("\t channel_layouts: {:?}", layouts.collect::<Vec<_>>());
} else { } else {
println!("\t channel_layouts: any"); println!("\t channel_layouts: any");

View File

@ -73,10 +73,14 @@ fn main() -> Result<(), ffmpeg::Error> {
println!("\tmax_rate: {}", audio.max_bit_rate()); println!("\tmax_rate: {}", audio.max_bit_rate());
println!("\tdelay: {}", audio.delay()); println!("\tdelay: {}", audio.delay());
println!("\taudio.rate: {}", audio.rate()); println!("\taudio.rate: {}", audio.rate());
println!("\taudio.channels: {}", audio.channels());
println!("\taudio.format: {:?}", audio.format()); println!("\taudio.format: {:?}", audio.format());
println!("\taudio.frames: {}", audio.frames());
println!("\taudio.align: {}", audio.align()); println!("\taudio.align: {}", audio.align());
#[cfg(feature = "ffmpeg_5_1")]
println!("\taudio.ch_layout: {:?}", audio.ch_layout());
#[cfg(not(feature = "ffmpeg_5_1"))]
println!("\taudio.channels: {}", audio.channels());
#[cfg(not(feature = "ffmpeg_5_1"))]
println!("\taudio.channel_layout: {:?}", audio.channel_layout()); println!("\taudio.channel_layout: {:?}", audio.channel_layout());
} }
} }

View File

@ -13,12 +13,16 @@ fn filter(
) -> Result<filter::Graph, ffmpeg::Error> { ) -> Result<filter::Graph, ffmpeg::Error> {
let mut filter = filter::Graph::new(); let mut filter = filter::Graph::new();
#[cfg(feature = "ffmpeg_5_1")]
let channel_layout = decoder.ch_layout().description();
#[cfg(not(feature = "ffmpeg_5_1"))]
let channel_layout = format!("0x{:x}", decoder.channel_layout().bits());
let args = format!( let args = format!(
"time_base={}:sample_rate={}:sample_fmt={}:channel_layout=0x{:x}", "time_base={}:sample_rate={}:sample_fmt={}:channel_layout={channel_layout}",
decoder.time_base(), decoder.time_base(),
decoder.rate(), decoder.rate(),
decoder.format().name(), decoder.format().name()
decoder.channel_layout().bits()
); );
filter.add(&filter::find("abuffer").unwrap(), "in", &args)?; filter.add(&filter::find("abuffer").unwrap(), "in", &args)?;
@ -28,7 +32,10 @@ fn filter(
let mut out = filter.get("out").unwrap(); let mut out = filter.get("out").unwrap();
out.set_sample_format(encoder.format()); out.set_sample_format(encoder.format());
#[cfg(not(feature = "ffmpeg_5_1"))]
out.set_channel_layout(encoder.channel_layout()); out.set_channel_layout(encoder.channel_layout());
#[cfg(feature = "ffmpeg_5_1")]
out.set_ch_layout(encoder.ch_layout());
out.set_sample_rate(encoder.rate()); out.set_sample_rate(encoder.rate());
} }
@ -88,18 +95,31 @@ fn transcoder<P: AsRef<Path>>(
let context = ffmpeg::codec::context::Context::from_parameters(output.parameters())?; let context = ffmpeg::codec::context::Context::from_parameters(output.parameters())?;
let mut encoder = context.encoder().audio()?; let mut encoder = context.encoder().audio()?;
let channel_layout = codec
.channel_layouts()
.map(|cls| cls.best(decoder.channel_layout().channels()))
.unwrap_or(ffmpeg::channel_layout::ChannelLayoutMask::STEREO);
if global { if global {
encoder.set_flags(ffmpeg::codec::flag::Flags::GLOBAL_HEADER); encoder.set_flags(ffmpeg::codec::flag::Flags::GLOBAL_HEADER);
} }
#[cfg(feature = "ffmpeg_5_1")]
{
let ch_layout = codec
.ch_layouts()
.map(|cls| cls.best(decoder.ch_layout().channels()))
.unwrap_or(ffmpeg::channel_layout::ChannelLayout::STEREO);
encoder.set_ch_layout(ch_layout);
}
#[cfg(not(feature = "ffmpeg_5_1"))]
{
let channel_layout = codec
.channel_layouts()
.map(|cls| cls.best(decoder.channel_layout().channels()))
.unwrap_or(ffmpeg::channel_layout::ChannelLayoutMask::STEREO);
encoder.set_channel_layout(channel_layout);
encoder.set_channels(channel_layout.channels());
}
encoder.set_rate(decoder.rate() as i32); encoder.set_rate(decoder.rate() as i32);
encoder.set_channel_layout(channel_layout);
encoder.set_channels(channel_layout.channels());
encoder.set_format( encoder.set_format(
codec codec
.formats() .formats()

View File

@ -114,6 +114,7 @@ static AVUTIL_FEATURES: &[AVFeature] = &[
AVFeature::new("FRAME_KEY"), AVFeature::new("FRAME_KEY"),
AVFeature::new("PALETTE_HAS_CHANGED"), AVFeature::new("PALETTE_HAS_CHANGED"),
AVFeature::new("VULKAN_CONTIGUOUS_MEMORY"), AVFeature::new("VULKAN_CONTIGUOUS_MEMORY"),
AVFeature::new("H274_FILM_GRAIN_VCS"),
]; ];
static AVCODEC_FEATURES: &[AVFeature] = &[ static AVCODEC_FEATURES: &[AVFeature] = &[
@ -199,6 +200,9 @@ static AVCODEC_FEATURES: &[AVFeature] = &[
AVFeature::new("DROPCHANGED"), AVFeature::new("DROPCHANGED"),
AVFeature::new("AVFFT"), AVFeature::new("AVFFT"),
AVFeature::new("FF_PROFILE_LEVEL"), AVFeature::new("FF_PROFILE_LEVEL"),
AVFeature::new("AVCODEC_CLOSE"),
AVFeature::new("BUFFER_MIN_SIZE"),
AVFeature::new("VDPAU_ALLOC_GET_SET"),
]; ];
static AVFORMAT_FEATURES: &[AVFeature] = &[ static AVFORMAT_FEATURES: &[AVFeature] = &[
@ -220,9 +224,16 @@ static AVFORMAT_FEATURES: &[AVFeature] = &[
AVFeature::new("LAVF_SHORTEST"), AVFeature::new("LAVF_SHORTEST"),
AVFeature::new("ALLOW_FLUSH"), AVFeature::new("ALLOW_FLUSH"),
AVFeature::new("AVSTREAM_SIDE_DATA"), AVFeature::new("AVSTREAM_SIDE_DATA"),
AVFeature::new("GET_DUR_ESTIMATE_METHOD"),
AVFeature::new("R_FRAME_RATE"),
]; ];
static AVDEVICE_FEATURES: &[AVFeature] = &[AVFeature::new("DEVICE_CAPABILITIES")]; static AVDEVICE_FEATURES: &[AVFeature] = &[
AVFeature::new("DEVICE_CAPABILITIES"),
AVFeature::new("BKTR_DEVICE"),
AVFeature::new("OPENGL_DEVICE"),
AVFeature::new("SDL2_DEVICE"),
];
static AVFILTER_FEATURES: &[AVFeature] = &[ static AVFILTER_FEATURES: &[AVFeature] = &[
AVFeature::new("AVFILTERPAD_PUBLIC"), AVFeature::new("AVFILTERPAD_PUBLIC"),
@ -237,6 +248,7 @@ static AVFILTER_FEATURES: &[AVFeature] = &[
AVFeature::new("BUFFERSINK_ALLOC"), AVFeature::new("BUFFERSINK_ALLOC"),
AVFeature::new("PAD_COUNT"), AVFeature::new("PAD_COUNT"),
AVFeature::new("LIBPLACEBO_OPTS"), AVFeature::new("LIBPLACEBO_OPTS"),
AVFeature::new("LINK_PUBLIC"),
]; ];
static AVRESAMPLE_FEATURES: &[AVFeature] = &[AVFeature::new("RESAMPLE_CLOSE_OPEN")]; static AVRESAMPLE_FEATURES: &[AVFeature] = &[AVFeature::new("RESAMPLE_CLOSE_OPEN")];
@ -736,7 +748,7 @@ fn check_features(include_paths: &[PathBuf]) {
); );
} }
} }
let version_check_info = [("avcodec", 56, 61, 0, 108)]; let version_check_info = [("avcodec", 56, 62, 0, 108)];
for &(lib, begin_version_major, end_version_major, begin_version_minor, end_version_minor) in for &(lib, begin_version_major, end_version_major, begin_version_minor, end_version_minor) in
version_check_info.iter() version_check_info.iter()
{ {
@ -880,6 +892,7 @@ fn check_features(include_paths: &[PathBuf]) {
("ffmpeg_5_1", 59, 37), ("ffmpeg_5_1", 59, 37),
("ffmpeg_6_0", 60, 3), ("ffmpeg_6_0", 60, 3),
("ffmpeg_6_1", 60, 31), ("ffmpeg_6_1", 60, 31),
("ffmpeg_7_0", 61, 3),
]; ];
for &(ffmpeg_version_flag, lavc_version_major, lavc_version_minor) in for &(ffmpeg_version_flag, lavc_version_major, lavc_version_minor) in
ffmpeg_lavc_versions.iter() ffmpeg_lavc_versions.iter()

View File

@ -77,9 +77,10 @@ impl fmt::Debug for AVChannelLayout {
"map", "map",
&std::slice::from_raw_parts(self.u.map, self.nb_channels as usize), &std::slice::from_raw_parts(self.u.map, self.nb_channels as usize),
); );
} // Starting with FFmpeg 7.0: }
// Not part of public API, but we have to exhaustively match // Not part of public API, but we have to exhaustively match
// AVChannelOrder::FF_CHANNEL_ORDER_NB => {} #[cfg(feature = "ffmpeg_7_0")]
AVChannelOrder::FF_CHANNEL_ORDER_NB => {}
} }
} }
@ -184,6 +185,12 @@ pub const AV_CH_LAYOUT_7POINT1POINT2: u64 =
AV_CH_LAYOUT_7POINT1 | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT; AV_CH_LAYOUT_7POINT1 | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT;
pub const AV_CH_LAYOUT_7POINT1POINT4_BACK: u64 = pub const AV_CH_LAYOUT_7POINT1POINT4_BACK: u64 =
AV_CH_LAYOUT_7POINT1POINT2 | AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT; AV_CH_LAYOUT_7POINT1POINT2 | AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT;
#[cfg(feature = "ffmpeg_7_0")]
pub const AV_CH_LAYOUT_7POINT2POINT3: u64 =
AV_CH_LAYOUT_7POINT1POINT2 | AV_CH_TOP_BACK_CENTER | AV_CH_LOW_FREQUENCY_2;
#[cfg(feature = "ffmpeg_7_0")]
pub const AV_CH_LAYOUT_9POINT1POINT4_BACK: u64 =
AV_CH_LAYOUT_7POINT1POINT4_BACK | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER;
pub const AV_CH_LAYOUT_HEXADECAGONAL: u64 = AV_CH_LAYOUT_OCTAGONAL pub const AV_CH_LAYOUT_HEXADECAGONAL: u64 = AV_CH_LAYOUT_OCTAGONAL
| AV_CH_WIDE_LEFT | AV_CH_WIDE_LEFT
| AV_CH_WIDE_RIGHT | AV_CH_WIDE_RIGHT
@ -285,6 +292,12 @@ pub const AV_CHANNEL_LAYOUT_7POINT1POINT2: AVChannelLayout =
AV_CHANNEL_LAYOUT_MASK(10, AV_CH_LAYOUT_7POINT1POINT2); AV_CHANNEL_LAYOUT_MASK(10, AV_CH_LAYOUT_7POINT1POINT2);
pub const AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK: AVChannelLayout = pub const AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK: AVChannelLayout =
AV_CHANNEL_LAYOUT_MASK(12, AV_CH_LAYOUT_7POINT1POINT4_BACK); AV_CHANNEL_LAYOUT_MASK(12, AV_CH_LAYOUT_7POINT1POINT4_BACK);
#[cfg(feature = "ffmpeg_7_0")]
pub const AV_CHANNEL_LAYOUT_7POINT2POINT3: AVChannelLayout =
AV_CHANNEL_LAYOUT_MASK(12, AV_CH_LAYOUT_7POINT2POINT3);
#[cfg(feature = "ffmpeg_7_0")]
pub const AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK: AVChannelLayout =
AV_CHANNEL_LAYOUT_MASK(14, AV_CH_LAYOUT_9POINT1POINT4_BACK);
pub const AV_CHANNEL_LAYOUT_HEXADECAGONAL: AVChannelLayout = pub const AV_CHANNEL_LAYOUT_HEXADECAGONAL: AVChannelLayout =
AV_CHANNEL_LAYOUT_MASK(16, AV_CH_LAYOUT_HEXADECAGONAL); AV_CHANNEL_LAYOUT_MASK(16, AV_CH_LAYOUT_HEXADECAGONAL);
pub const AV_CHANNEL_LAYOUT_STEREO_DOWNMIX: AVChannelLayout = pub const AV_CHANNEL_LAYOUT_STEREO_DOWNMIX: AVChannelLayout =

View File

@ -1,5 +1,5 @@
use libc::{c_double, c_int};
use crate::AVRational; use crate::AVRational;
use libc::{c_double, c_int};
#[inline(always)] #[inline(always)]
pub unsafe fn av_make_q(num: c_int, den: c_int) -> AVRational { pub unsafe fn av_make_q(num: c_int, den: c_int) -> AVRational {

View File

@ -2,7 +2,10 @@ use std::ops::Deref;
use super::codec::Codec; use super::codec::Codec;
use crate::ffi::*; use crate::ffi::*;
use crate::{format, ChannelLayoutMask}; use crate::format;
#[cfg(not(feature = "ffmpeg_7_0"))]
use crate::ChannelLayoutMask;
#[derive(PartialEq, Eq, Copy, Clone)] #[derive(PartialEq, Eq, Copy, Clone)]
pub struct Audio { pub struct Audio {
@ -36,6 +39,7 @@ impl Audio {
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn channel_layouts(&self) -> Option<ChannelLayoutMaskIter> { pub fn channel_layouts(&self) -> Option<ChannelLayoutMaskIter> {
unsafe { unsafe {
if (*self.codec.as_ptr()).channel_layouts.is_null() { if (*self.codec.as_ptr()).channel_layouts.is_null() {
@ -116,10 +120,12 @@ impl Iterator for FormatIter {
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub struct ChannelLayoutMaskIter { pub struct ChannelLayoutMaskIter {
ptr: *const u64, ptr: *const u64,
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
impl ChannelLayoutMaskIter { impl ChannelLayoutMaskIter {
pub fn new(ptr: *const u64) -> Self { pub fn new(ptr: *const u64) -> Self {
ChannelLayoutMaskIter { ptr } ChannelLayoutMaskIter { ptr }
@ -136,6 +142,7 @@ impl ChannelLayoutMaskIter {
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
impl Iterator for ChannelLayoutMaskIter { impl Iterator for ChannelLayoutMaskIter {
type Item = ChannelLayoutMask; type Item = ChannelLayoutMask;
@ -171,6 +178,18 @@ mod ch_layout {
} }
} }
impl<'a> ChannelLayoutIter<'a> {
pub fn best(self, max: u32) -> ChannelLayout<'a> {
self.fold(ChannelLayout::MONO, |acc, cur| {
if cur.channels() > acc.channels() && cur.channels() <= max {
cur
} else {
acc
}
})
}
}
impl<'a> Iterator for ChannelLayoutIter<'a> { impl<'a> Iterator for ChannelLayoutIter<'a> {
type Item = ChannelLayout<'a>; type Item = ChannelLayout<'a>;

View File

@ -10,13 +10,16 @@ use crate::codec::Context;
#[cfg(not(feature = "ffmpeg_5_0"))] #[cfg(not(feature = "ffmpeg_5_0"))]
use crate::frame; use crate::frame;
use crate::util::format; use crate::util::format;
use crate::AudioService;
#[cfg(not(feature = "ffmpeg_5_0"))] #[cfg(not(feature = "ffmpeg_5_0"))]
use crate::{packet, Error}; use crate::{packet, Error};
use crate::{AudioService, ChannelLayoutMask};
#[cfg(feature = "ffmpeg_5_1")] #[cfg(feature = "ffmpeg_5_1")]
use crate::ChannelLayout; use crate::ChannelLayout;
#[cfg(not(feature = "ffmpeg_7_0"))]
use crate::ChannelLayoutMask;
pub struct Audio(pub Opened); pub struct Audio(pub Opened);
impl Audio { impl Audio {
@ -50,6 +53,7 @@ impl Audio {
unsafe { (*self.as_ptr()).sample_rate as u32 } unsafe { (*self.as_ptr()).sample_rate as u32 }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn channels(&self) -> u16 { pub fn channels(&self) -> u16 {
unsafe { (*self.as_ptr()).channels as u16 } unsafe { (*self.as_ptr()).channels as u16 }
} }
@ -64,6 +68,7 @@ impl Audio {
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn frames(&self) -> usize { pub fn frames(&self) -> usize {
unsafe { (*self.as_ptr()).frame_number as usize } unsafe { (*self.as_ptr()).frame_number as usize }
} }
@ -72,16 +77,19 @@ impl Audio {
unsafe { (*self.as_ptr()).block_align as usize } unsafe { (*self.as_ptr()).block_align as usize }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn channel_layout(&self) -> ChannelLayoutMask { pub fn channel_layout(&self) -> ChannelLayoutMask {
unsafe { ChannelLayoutMask::from_bits_truncate((*self.as_ptr()).channel_layout) } unsafe { ChannelLayoutMask::from_bits_truncate((*self.as_ptr()).channel_layout) }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) { pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) {
unsafe { unsafe {
(*self.as_mut_ptr()).channel_layout = value.bits(); (*self.as_mut_ptr()).channel_layout = value.bits();
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn request_channel_layout(&mut self, value: ChannelLayoutMask) { pub fn request_channel_layout(&mut self, value: ChannelLayoutMask) {
unsafe { unsafe {
(*self.as_mut_ptr()).request_channel_layout = value.bits(); (*self.as_mut_ptr()).request_channel_layout = value.bits();

View File

@ -84,6 +84,7 @@ impl Video {
unsafe { chroma::Location::from((*self.as_ptr()).chroma_sample_location) } unsafe { chroma::Location::from((*self.as_ptr()).chroma_sample_location) }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn set_slice_count(&mut self, value: usize) { pub fn set_slice_count(&mut self, value: usize) {
unsafe { unsafe {
(*self.as_mut_ptr()).slice_count = value as c_int; (*self.as_mut_ptr()).slice_count = value as c_int;

View File

@ -10,11 +10,14 @@ use crate::codec::{traits, Context};
use crate::util::format; use crate::util::format;
#[cfg(not(feature = "ffmpeg_5_0"))] #[cfg(not(feature = "ffmpeg_5_0"))]
use crate::{frame, packet}; use crate::{frame, packet};
use crate::{ChannelLayoutMask, Dictionary, Error}; use crate::{Dictionary, Error};
#[cfg(feature = "ffmpeg_5_1")] #[cfg(feature = "ffmpeg_5_1")]
use crate::ChannelLayout; use crate::ChannelLayout;
#[cfg(not(feature = "ffmpeg_7_0"))]
use crate::ChannelLayoutMask;
pub struct Audio(pub Super); pub struct Audio(pub Super);
impl Audio { impl Audio {
@ -96,22 +99,26 @@ impl Audio {
unsafe { format::Sample::from((*self.as_ptr()).sample_fmt) } unsafe { format::Sample::from((*self.as_ptr()).sample_fmt) }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) { pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) {
unsafe { unsafe {
(*self.as_mut_ptr()).channel_layout = value.bits(); (*self.as_mut_ptr()).channel_layout = value.bits();
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn channel_layout(&self) -> ChannelLayoutMask { pub fn channel_layout(&self) -> ChannelLayoutMask {
unsafe { ChannelLayoutMask::from_bits_truncate((*self.as_ptr()).channel_layout) } unsafe { ChannelLayoutMask::from_bits_truncate((*self.as_ptr()).channel_layout) }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn set_channels(&mut self, value: i32) { pub fn set_channels(&mut self, value: i32) {
unsafe { unsafe {
(*self.as_mut_ptr()).channels = value; (*self.as_mut_ptr()).channels = value;
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn channels(&self) -> u16 { pub fn channels(&self) -> u16 {
unsafe { (*self.as_ptr()).channels as u16 } unsafe { (*self.as_ptr()).channels as u16 }
} }

View File

@ -214,6 +214,7 @@ pub enum Id {
AVRP, AVRP,
V012, V012,
AVUI, AVUI,
#[cfg(not(feature = "ffmpeg_7_0"))]
AYUV, AYUV,
TARGA_Y216, TARGA_Y216,
V308, V308,
@ -656,10 +657,14 @@ pub enum Id {
RTV1, RTV1,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
VMIX, VMIX,
#[cfg(feature = "ffmpeg_7_0")]
LEAD,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
AC4, AC4,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
OSQ, OSQ,
#[cfg(feature = "ffmpeg_7_0")]
QOA,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
SMPTE_2038, SMPTE_2038,
} }
@ -881,6 +886,7 @@ impl From<AVCodecID> for Id {
AV_CODEC_ID_AVRP => Id::AVRP, AV_CODEC_ID_AVRP => Id::AVRP,
AV_CODEC_ID_012V => Id::V012, AV_CODEC_ID_012V => Id::V012,
AV_CODEC_ID_AVUI => Id::AVUI, AV_CODEC_ID_AVUI => Id::AVUI,
#[cfg(not(feature = "ffmpeg_7_0"))]
AV_CODEC_ID_AYUV => Id::AYUV, AV_CODEC_ID_AYUV => Id::AYUV,
AV_CODEC_ID_TARGA_Y216 => Id::TARGA_Y216, AV_CODEC_ID_TARGA_Y216 => Id::TARGA_Y216,
AV_CODEC_ID_V308 => Id::V308, AV_CODEC_ID_V308 => Id::V308,
@ -1322,10 +1328,14 @@ impl From<AVCodecID> for Id {
AV_CODEC_ID_RTV1 => Id::RTV1, AV_CODEC_ID_RTV1 => Id::RTV1,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
AV_CODEC_ID_VMIX => Id::VMIX, AV_CODEC_ID_VMIX => Id::VMIX,
#[cfg(feature = "ffmpeg_7_0")]
AV_CODEC_ID_LEAD => Id::LEAD,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
AV_CODEC_ID_AC4 => Id::AC4, AV_CODEC_ID_AC4 => Id::AC4,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
AV_CODEC_ID_OSQ => Id::OSQ, AV_CODEC_ID_OSQ => Id::OSQ,
#[cfg(feature = "ffmpeg_7_0")]
AV_CODEC_ID_QOA => Id::QOA,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
AV_CODEC_ID_SMPTE_2038 => Id::SMPTE_2038, AV_CODEC_ID_SMPTE_2038 => Id::SMPTE_2038,
@ -1541,6 +1551,7 @@ impl From<Id> for AVCodecID {
Id::AVRP => AV_CODEC_ID_AVRP, Id::AVRP => AV_CODEC_ID_AVRP,
Id::V012 => AV_CODEC_ID_012V, Id::V012 => AV_CODEC_ID_012V,
Id::AVUI => AV_CODEC_ID_AVUI, Id::AVUI => AV_CODEC_ID_AVUI,
#[cfg(not(feature = "ffmpeg_7_0"))]
Id::AYUV => AV_CODEC_ID_AYUV, Id::AYUV => AV_CODEC_ID_AYUV,
Id::TARGA_Y216 => AV_CODEC_ID_TARGA_Y216, Id::TARGA_Y216 => AV_CODEC_ID_TARGA_Y216,
Id::V308 => AV_CODEC_ID_V308, Id::V308 => AV_CODEC_ID_V308,
@ -1982,10 +1993,14 @@ impl From<Id> for AVCodecID {
Id::RTV1 => AV_CODEC_ID_RTV1, Id::RTV1 => AV_CODEC_ID_RTV1,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
Id::VMIX => AV_CODEC_ID_VMIX, Id::VMIX => AV_CODEC_ID_VMIX,
#[cfg(feature = "ffmpeg_7_0")]
Id::LEAD => AV_CODEC_ID_LEAD,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
Id::AC4 => AV_CODEC_ID_AC4, Id::AC4 => AV_CODEC_ID_AC4,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
Id::OSQ => AV_CODEC_ID_OSQ, Id::OSQ => AV_CODEC_ID_OSQ,
#[cfg(feature = "ffmpeg_7_0")]
Id::QOA => AV_CODEC_ID_QOA,
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
Id::SMPTE_2038 => AV_CODEC_ID_SMPTE_2038, Id::SMPTE_2038 => AV_CODEC_ID_SMPTE_2038,
} }

View File

@ -57,6 +57,15 @@ pub enum Type {
#[cfg(feature = "ffmpeg_5_0")] #[cfg(feature = "ffmpeg_5_0")]
DYNAMIC_HDR10_PLUS, DYNAMIC_HDR10_PLUS,
#[cfg(feature = "ffmpeg_7_0")]
IAMF_MIX_GAIN_PARAM,
#[cfg(feature = "ffmpeg_7_0")]
IAMF_DEMIXING_INFO_PARAM,
#[cfg(feature = "ffmpeg_7_0")]
IAMF_RECON_GAIN_INFO_PARAM,
#[cfg(feature = "ffmpeg_7_0")]
AMBIENT_VIEWING_ENVIRONMENT,
} }
impl From<AVPacketSideDataType> for Type { impl From<AVPacketSideDataType> for Type {
@ -110,6 +119,15 @@ impl From<AVPacketSideDataType> for Type {
#[cfg(feature = "ffmpeg_5_0")] #[cfg(feature = "ffmpeg_5_0")]
AV_PKT_DATA_DYNAMIC_HDR10_PLUS => Type::DYNAMIC_HDR10_PLUS, AV_PKT_DATA_DYNAMIC_HDR10_PLUS => Type::DYNAMIC_HDR10_PLUS,
#[cfg(feature = "ffmpeg_7_0")]
AV_PKT_DATA_IAMF_MIX_GAIN_PARAM => Type::IAMF_MIX_GAIN_PARAM,
#[cfg(feature = "ffmpeg_7_0")]
AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM => Type::IAMF_DEMIXING_INFO_PARAM,
#[cfg(feature = "ffmpeg_7_0")]
AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM => Type::IAMF_RECON_GAIN_INFO_PARAM,
#[cfg(feature = "ffmpeg_7_0")]
AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT => Type::AMBIENT_VIEWING_ENVIRONMENT,
#[cfg(feature = "non-exhaustive-enums")] #[cfg(feature = "non-exhaustive-enums")]
_ => unimplemented!(), _ => unimplemented!(),
} }
@ -166,6 +184,15 @@ impl From<Type> for AVPacketSideDataType {
#[cfg(feature = "ffmpeg_5_0")] #[cfg(feature = "ffmpeg_5_0")]
Type::DYNAMIC_HDR10_PLUS => AV_PKT_DATA_DYNAMIC_HDR10_PLUS, Type::DYNAMIC_HDR10_PLUS => AV_PKT_DATA_DYNAMIC_HDR10_PLUS,
#[cfg(feature = "ffmpeg_7_0")]
Type::IAMF_MIX_GAIN_PARAM => AV_PKT_DATA_IAMF_MIX_GAIN_PARAM,
#[cfg(feature = "ffmpeg_7_0")]
Type::IAMF_DEMIXING_INFO_PARAM => AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM,
#[cfg(feature = "ffmpeg_7_0")]
Type::IAMF_RECON_GAIN_INFO_PARAM => AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM,
#[cfg(feature = "ffmpeg_7_0")]
Type::AMBIENT_VIEWING_ENVIRONMENT => AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT,
} }
} }
} }

View File

@ -2,9 +2,15 @@ use std::marker::PhantomData;
use super::{Sink, Source}; use super::{Sink, Source};
use crate::ffi::*; use crate::ffi::*;
use crate::{format, option, ChannelLayoutMask}; use crate::{format, option};
use libc::c_void; use libc::c_void;
#[cfg(feature = "ffmpeg_5_1")]
use crate::ChannelLayout;
#[cfg(not(feature = "ffmpeg_7_0"))]
use crate::ChannelLayoutMask;
pub struct Context<'a> { pub struct Context<'a> {
ptr: *mut AVFilterContext, ptr: *mut AVFilterContext,
@ -49,9 +55,15 @@ impl<'a> Context<'a> {
let _ = option::Settable::set(self, "sample_rates", &i64::from(value)); let _ = option::Settable::set(self, "sample_rates", &i64::from(value));
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) { pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) {
let _ = option::Settable::set(self, "channel_layouts", &value.bits()); let _ = option::Settable::set(self, "channel_layouts", &value.bits());
} }
#[cfg(feature = "ffmpeg_5_1")]
pub fn set_ch_layout(&mut self, value: ChannelLayout) {
let _ = option::Settable::set_str(self, "channel_layouts", &value.description());
}
} }
unsafe impl<'a> option::Target for Context<'a> { unsafe impl<'a> option::Target for Context<'a> {

View File

@ -35,7 +35,7 @@ pub fn converter(
#[cfg(feature = "software-resampling")] #[cfg(feature = "software-resampling")]
pub mod resampling; pub mod resampling;
#[cfg(feature = "software-resampling")] #[cfg(all(feature = "software-resampling", not(feature = "ffmpeg_7_0")))]
#[inline] #[inline]
pub fn resampler( pub fn resampler(
(in_format, in_layout, in_rate): (crate::format::Sample, crate::ChannelLayoutMask, u32), (in_format, in_layout, in_rate): (crate::format::Sample, crate::ChannelLayoutMask, u32),
@ -45,3 +45,14 @@ pub fn resampler(
in_format, in_layout, in_rate, out_format, out_layout, out_rate, in_format, in_layout, in_rate, out_format, out_layout, out_rate,
) )
} }
#[cfg(all(feature = "software-resampling", feature = "ffmpeg_5_1"))]
#[inline]
pub fn resampler2(
(in_format, in_layout, in_rate): (crate::format::Sample, crate::ChannelLayout, u32),
(out_format, out_layout, out_rate): (crate::format::Sample, crate::ChannelLayout, u32),
) -> Result<resampling::Context, crate::Error> {
resampling::Context::get2(
in_format, in_layout, in_rate, out_format, out_layout, out_rate,
)
}

View File

@ -8,6 +8,9 @@ use crate::{frame, ChannelLayoutMask, Error};
use libc::c_int; use libc::c_int;
use std::ffi::c_void; use std::ffi::c_void;
#[cfg(feature = "ffmpeg_5_1")]
use crate::ChannelLayout;
#[derive(Eq, PartialEq, Copy, Clone)] #[derive(Eq, PartialEq, Copy, Clone)]
pub struct Definition { pub struct Definition {
pub format: format::Sample, pub format: format::Sample,
@ -38,6 +41,7 @@ impl Context {
impl Context { impl Context {
/// Create a resampler with the given definitions. /// Create a resampler with the given definitions.
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn get( pub fn get(
src_format: format::Sample, src_format: format::Sample,
src_channel_layout: ChannelLayoutMask, src_channel_layout: ChannelLayoutMask,
@ -58,6 +62,7 @@ impl Context {
} }
/// Create a resampler with the given definitions and custom options dictionary. /// Create a resampler with the given definitions and custom options dictionary.
#[cfg(not(feature = "ffmpeg_7_0"))]
pub fn get_with( pub fn get_with(
src_format: format::Sample, src_format: format::Sample,
src_channel_layout: ChannelLayoutMask, src_channel_layout: ChannelLayoutMask,
@ -114,6 +119,90 @@ impl Context {
} }
} }
/// Create a resampler with the given definitions.
#[cfg(feature = "ffmpeg_5_1")]
pub fn get2(
src_format: format::Sample,
src_channel_layout: ChannelLayout,
src_rate: u32,
dst_format: format::Sample,
dst_channel_layout: ChannelLayout,
dst_rate: u32,
) -> Result<Self, Error> {
Self::get_with2(
src_format,
src_channel_layout,
src_rate,
dst_format,
dst_channel_layout,
dst_rate,
Dictionary::new(),
)
}
/// Create a resampler with the given definitions and custom options dictionary.
#[cfg(feature = "ffmpeg_5_1")]
pub fn get_with2(
src_format: format::Sample,
src_channel_layout: ChannelLayout,
src_rate: u32,
dst_format: format::Sample,
dst_channel_layout: ChannelLayout,
dst_rate: u32,
options: Dictionary,
) -> Result<Self, Error> {
unsafe {
let mut context_ptr = ptr::null_mut();
let res = swr_alloc_set_opts2(
ptr::addr_of_mut!(context_ptr),
dst_channel_layout.as_ptr() as _,
dst_format.into(),
dst_rate as c_int,
src_channel_layout.as_ptr() as _,
src_format.into(),
src_rate as c_int,
0,
ptr::null_mut(),
);
if res < 0 {
return Err(Error::from(res));
}
let mut opts = options.disown();
let res = av_opt_set_dict(context_ptr as *mut c_void, &mut opts);
Dictionary::own(opts);
if res != 0 {
return Err(Error::from(res));
}
if !context_ptr.is_null() {
match swr_init(context_ptr) {
e if e < 0 => Err(Error::from(e)),
_ => Ok(Context {
ptr: context_ptr,
input: Definition {
format: src_format,
channel_layout: src_channel_layout.mask().unwrap(),
rate: src_rate,
},
output: Definition {
format: dst_format,
channel_layout: dst_channel_layout.mask().unwrap(),
rate: dst_rate,
},
}),
}
} else {
Err(Error::InvalidData)
}
}
}
/// Get the input definition. /// Get the input definition.
pub fn input(&self) -> &Definition { pub fn input(&self) -> &Definition {
&self.input &self.input

View File

@ -1,8 +1,15 @@
use super::Context; use super::Context;
use crate::util::format; use crate::util::format;
use crate::{decoder, frame, ChannelLayoutMask, Error}; use crate::{decoder, frame, Error};
#[cfg(feature = "ffmpeg_5_1")]
use crate::ChannelLayout;
#[cfg(not(feature = "ffmpeg_7_0"))]
use crate::ChannelLayoutMask;
impl frame::Audio { impl frame::Audio {
#[cfg(not(feature = "ffmpeg_7_0"))]
#[inline] #[inline]
pub fn resampler( pub fn resampler(
&self, &self,
@ -19,9 +26,28 @@ impl frame::Audio {
rate, rate,
) )
} }
#[cfg(feature = "ffmpeg_5_1")]
#[inline]
pub fn resampler2(
&self,
format: format::Sample,
ch_layout: ChannelLayout,
rate: u32,
) -> Result<Context, Error> {
Context::get2(
self.format(),
self.ch_layout(),
unsafe { (*self.as_ptr()).sample_rate as u32 },
format,
ch_layout,
rate,
)
}
} }
impl decoder::Audio { impl decoder::Audio {
#[cfg(not(feature = "ffmpeg_7_0"))]
#[inline] #[inline]
pub fn resampler( pub fn resampler(
&self, &self,
@ -38,4 +64,22 @@ impl decoder::Audio {
rate, rate,
) )
} }
#[cfg(feature = "ffmpeg_5_1")]
#[inline]
pub fn resampler2(
&self,
format: format::Sample,
ch_layout: ChannelLayout,
rate: u32,
) -> Result<Context, Error> {
Context::get2(
self.format(),
self.ch_layout(),
self.rate(),
format,
ch_layout,
rate,
)
}
} }

View File

@ -306,6 +306,11 @@ impl<'a> ChannelLayout<'a> {
pub const _7POINT1POINT2: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_7POINT1POINT2)); pub const _7POINT1POINT2: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_7POINT1POINT2));
pub const _7POINT1POINT4_BACK: Scl = pub const _7POINT1POINT4_BACK: Scl =
ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK)); ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK));
#[cfg(feature = "ffmpeg_7_0")]
pub const _7POINT2POINT3: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_7POINT2POINT3));
#[cfg(feature = "ffmpeg_7_0")]
pub const _9POINT1POINT4_BACK: Scl =
ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK));
pub const HEXADECAGONAL: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_HEXADECAGONAL)); pub const HEXADECAGONAL: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_HEXADECAGONAL));
pub const STEREO_DOWNMIX: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_STEREO_DOWNMIX)); pub const STEREO_DOWNMIX: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_STEREO_DOWNMIX));
pub const _22POINT2: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_22POINT2)); pub const _22POINT2: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_22POINT2));

View File

@ -28,6 +28,7 @@ bitflags! {
const SURROUND_DIRECT_LEFT = AV_CH_SURROUND_DIRECT_LEFT; const SURROUND_DIRECT_LEFT = AV_CH_SURROUND_DIRECT_LEFT;
const SURROUND_DIRECT_RIGHT = AV_CH_SURROUND_DIRECT_RIGHT; const SURROUND_DIRECT_RIGHT = AV_CH_SURROUND_DIRECT_RIGHT;
const LOW_FREQUENCY_2 = AV_CH_LOW_FREQUENCY_2; const LOW_FREQUENCY_2 = AV_CH_LOW_FREQUENCY_2;
#[cfg(not(feature = "ffmpeg_7_0"))]
const NATIVE = AV_CH_LAYOUT_NATIVE; const NATIVE = AV_CH_LAYOUT_NATIVE;
const MONO = AV_CH_LAYOUT_MONO; const MONO = AV_CH_LAYOUT_MONO;
@ -68,6 +69,10 @@ bitflags! {
const _7POINT1POINT2 = AV_CH_LAYOUT_7POINT1POINT2; const _7POINT1POINT2 = AV_CH_LAYOUT_7POINT1POINT2;
#[cfg(feature = "ffmpeg_5_1")] #[cfg(feature = "ffmpeg_5_1")]
const _7POINT1POINT4_BACK = AV_CH_LAYOUT_7POINT1POINT4_BACK; const _7POINT1POINT4_BACK = AV_CH_LAYOUT_7POINT1POINT4_BACK;
#[cfg(feature = "ffmpeg_7_0")]
const _7POINT2POINT3 = AV_CH_LAYOUT_7POINT2POINT3;
#[cfg(feature = "ffmpeg_7_0")]
const _9POINT1POINT4_BACK = AV_CH_LAYOUT_9POINT1POINT4_BACK;
const HEXADECAGONAL = AV_CH_LAYOUT_HEXADECAGONAL; const HEXADECAGONAL = AV_CH_LAYOUT_HEXADECAGONAL;
const STEREO_DOWNMIX = AV_CH_LAYOUT_STEREO_DOWNMIX; const STEREO_DOWNMIX = AV_CH_LAYOUT_STEREO_DOWNMIX;
#[cfg(feature = "ffmpeg_5_1")] #[cfg(feature = "ffmpeg_5_1")]
@ -75,6 +80,7 @@ bitflags! {
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
impl ChannelLayoutMask { impl ChannelLayoutMask {
#[inline] #[inline]
pub fn channels(&self) -> i32 { pub fn channels(&self) -> i32 {

View File

@ -29,6 +29,9 @@ impl From<AVChannelOrder> for ChannelOrder {
AV_CHANNEL_ORDER_NATIVE => Native, AV_CHANNEL_ORDER_NATIVE => Native,
AV_CHANNEL_ORDER_CUSTOM => Custom, AV_CHANNEL_ORDER_CUSTOM => Custom,
AV_CHANNEL_ORDER_AMBISONIC => Ambisonic, AV_CHANNEL_ORDER_AMBISONIC => Ambisonic,
#[cfg(feature = "ffmpeg_7_0")]
// Not part of the API, should never be used
FF_CHANNEL_ORDER_NB => unreachable!(),
#[cfg(feature = "non-exhaustive-enums")] #[cfg(feature = "non-exhaustive-enums")]
_ => unimplemented!(), _ => unimplemented!(),
} }

View File

@ -225,7 +225,7 @@ pub enum Pixel {
VIDEOTOOLBOX, VIDEOTOOLBOX,
// --- defaults // --- defaults
#[cfg(feature = "ffmpeg_4_0")] #[cfg(all(feature = "ffmpeg_4_0", not(feature = "ffmpeg_7_0")))]
XVMC, XVMC,
RGB32, RGB32,
@ -417,6 +417,9 @@ pub enum Pixel {
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
GBRAP14LE, GBRAP14LE,
#[cfg(feature = "ffmpeg_7_0")]
D3D12,
#[cfg(feature = "rpi")] #[cfg(feature = "rpi")]
RPI, RPI,
#[cfg(feature = "rpi")] #[cfg(feature = "rpi")]
@ -498,7 +501,7 @@ impl From<AVPixelFormat> for Pixel {
AV_PIX_FMT_YUVJ420P => Pixel::YUVJ420P, AV_PIX_FMT_YUVJ420P => Pixel::YUVJ420P,
AV_PIX_FMT_YUVJ422P => Pixel::YUVJ422P, AV_PIX_FMT_YUVJ422P => Pixel::YUVJ422P,
AV_PIX_FMT_YUVJ444P => Pixel::YUVJ444P, AV_PIX_FMT_YUVJ444P => Pixel::YUVJ444P,
#[cfg(feature = "ffmpeg_4_0")] #[cfg(all(feature = "ffmpeg_4_0", not(feature = "ffmpeg_7_0")))]
AV_PIX_FMT_XVMC => Pixel::XVMC, AV_PIX_FMT_XVMC => Pixel::XVMC,
#[cfg(all(feature = "ff_api_xvmc", not(feature = "ffmpeg_5_0")))] #[cfg(all(feature = "ff_api_xvmc", not(feature = "ffmpeg_5_0")))]
AV_PIX_FMT_XVMC_MPEG2_MC => Pixel::XVMC_MPEG2_MC, AV_PIX_FMT_XVMC_MPEG2_MC => Pixel::XVMC_MPEG2_MC,
@ -825,6 +828,9 @@ impl From<AVPixelFormat> for Pixel {
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
AV_PIX_FMT_GBRAP14LE => Pixel::GBRAP14LE, AV_PIX_FMT_GBRAP14LE => Pixel::GBRAP14LE,
#[cfg(feature = "ffmpeg_7_0")]
AV_PIX_FMT_D3D12 => Pixel::D3D12,
#[cfg(feature = "rpi")] #[cfg(feature = "rpi")]
AV_PIX_FMT_RPI => Pixel::RPI, AV_PIX_FMT_RPI => Pixel::RPI,
#[cfg(feature = "rpi")] #[cfg(feature = "rpi")]
@ -1062,7 +1068,7 @@ impl From<Pixel> for AVPixelFormat {
Pixel::VIDEOTOOLBOX => AV_PIX_FMT_VIDEOTOOLBOX, Pixel::VIDEOTOOLBOX => AV_PIX_FMT_VIDEOTOOLBOX,
// --- defaults // --- defaults
#[cfg(feature = "ffmpeg_4_0")] #[cfg(all(feature = "ffmpeg_4_0", not(feature = "ffmpeg_7_0")))]
Pixel::XVMC => AV_PIX_FMT_XVMC, Pixel::XVMC => AV_PIX_FMT_XVMC,
Pixel::RGB32 => AV_PIX_FMT_RGB32, Pixel::RGB32 => AV_PIX_FMT_RGB32,
@ -1254,6 +1260,9 @@ impl From<Pixel> for AVPixelFormat {
#[cfg(feature = "ffmpeg_6_1")] #[cfg(feature = "ffmpeg_6_1")]
Pixel::GBRAP14LE => AV_PIX_FMT_GBRAP14LE, Pixel::GBRAP14LE => AV_PIX_FMT_GBRAP14LE,
#[cfg(feature = "ffmpeg_7_0")]
Pixel::D3D12 => AV_PIX_FMT_D3D12,
#[cfg(feature = "rpi")] #[cfg(feature = "rpi")]
Pixel::RPI => AV_PIX_FMT_RPI, Pixel::RPI => AV_PIX_FMT_RPI,
#[cfg(feature = "rpi")] #[cfg(feature = "rpi")]

View File

@ -6,11 +6,14 @@ use super::Frame;
use crate::ffi::*; use crate::ffi::*;
use crate::util::format; use crate::util::format;
use crate::ChannelLayoutMask; use crate::ChannelLayoutMask;
use libc::{c_int, c_ulonglong}; use libc::c_int;
#[cfg(feature = "ffmpeg_5_1")] #[cfg(feature = "ffmpeg_5_1")]
use crate::ChannelLayout; use crate::ChannelLayout;
#[cfg(not(feature = "ffmpeg_7_0"))]
use libc::c_ulonglong;
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
pub struct Audio(Frame); pub struct Audio(Frame);
@ -29,7 +32,10 @@ impl Audio {
) { ) {
self.set_format(format); self.set_format(format);
self.set_samples(samples); self.set_samples(samples);
#[cfg(not(feature = "ffmpeg_7_0"))]
self.set_channel_layout(layout); self.set_channel_layout(layout);
#[cfg(feature = "ffmpeg_7_0")]
self.set_ch_layout(ChannelLayout::from_mask(layout).unwrap());
av_frame_get_buffer(self.as_mut_ptr(), 0); av_frame_get_buffer(self.as_mut_ptr(), 0);
} }
@ -69,6 +75,7 @@ impl Audio {
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
#[inline] #[inline]
pub fn channel_layout(&self) -> ChannelLayoutMask { pub fn channel_layout(&self) -> ChannelLayoutMask {
unsafe { unsafe {
@ -76,6 +83,7 @@ impl Audio {
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
#[inline] #[inline]
pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) { pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) {
unsafe { unsafe {
@ -97,11 +105,13 @@ impl Audio {
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
#[inline] #[inline]
pub fn channels(&self) -> u16 { pub fn channels(&self) -> u16 {
unsafe { (*self.as_ptr()).channels as u16 } unsafe { (*self.as_ptr()).channels as u16 }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
#[inline] #[inline]
pub fn set_channels(&mut self, value: u16) { pub fn set_channels(&mut self, value: u16) {
unsafe { unsafe {
@ -154,7 +164,12 @@ impl Audio {
if self.is_packed() { if self.is_packed() {
1 1
} else { } else {
self.channels() as usize #[cfg(not(feature = "ffmpeg_5_1"))]
let channels = self.channels() as usize;
#[cfg(feature = "ffmpeg_5_1")]
let channels = self.ch_layout().channels() as usize;
channels
} }
} }
@ -164,7 +179,12 @@ impl Audio {
panic!("out of bounds"); panic!("out of bounds");
} }
if !<T as Sample>::is_valid(self.format(), self.channels() as u16) { #[cfg(not(feature = "ffmpeg_5_1"))]
let channels = self.channels() as u16;
#[cfg(feature = "ffmpeg_5_1")]
let channels = self.ch_layout().channels() as u16;
if !<T as Sample>::is_valid(self.format(), channels) {
panic!("unsupported type"); panic!("unsupported type");
} }
@ -177,7 +197,12 @@ impl Audio {
panic!("out of bounds"); panic!("out of bounds");
} }
if !<T as Sample>::is_valid(self.format(), self.channels() as u16) { #[cfg(not(feature = "ffmpeg_5_1"))]
let channels = self.channels() as u16;
#[cfg(feature = "ffmpeg_5_1")]
let channels = self.ch_layout().channels() as u16;
if !<T as Sample>::is_valid(self.format(), channels) {
panic!("unsupported type"); panic!("unsupported type");
} }
@ -231,9 +256,14 @@ impl DerefMut for Audio {
impl ::std::fmt::Debug for Audio { impl ::std::fmt::Debug for Audio {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
#[cfg(not(feature = "ffmpeg_5_1"))]
let channels = self.channels() as u16;
#[cfg(feature = "ffmpeg_5_1")]
let channels = self.ch_layout().channels() as u16;
f.write_str("ffmpeg::frame::Audio { ")?; f.write_str("ffmpeg::frame::Audio { ")?;
f.write_str(&format!("format: {:?}, ", self.format()))?; f.write_str(&format!("format: {:?}, ", self.format()))?;
f.write_str(&format!("channels: {:?}, ", self.channels()))?; f.write_str(&format!("channels: {channels}, "))?;
f.write_str(&format!("rate: {:?}, ", self.rate()))?; f.write_str(&format!("rate: {:?}, ", self.rate()))?;
f.write_str(&format!("samples: {:?} ", self.samples()))?; f.write_str(&format!("samples: {:?} ", self.samples()))?;
f.write_str("}") f.write_str("}")
@ -242,7 +272,12 @@ impl ::std::fmt::Debug for Audio {
impl Clone for Audio { impl Clone for Audio {
fn clone(&self) -> Self { fn clone(&self) -> Self {
let mut cloned = Audio::new(self.format(), self.samples(), self.channel_layout()); #[cfg(not(feature = "ffmpeg_5_1"))]
let mask = self.channel_layout();
#[cfg(feature = "ffmpeg_5_1")]
let mask = self.ch_layout().mask().unwrap();
let mut cloned = Audio::new(self.format(), self.samples(), mask);
cloned.clone_from(self); cloned.clone_from(self);
cloned cloned

View File

@ -89,7 +89,10 @@ impl Frame {
pub fn packet(&self) -> Packet { pub fn packet(&self) -> Packet {
unsafe { unsafe {
Packet { Packet {
#[cfg(not(feature = "ffmpeg_7_0"))]
duration: (*self.as_ptr()).pkt_duration as i64, duration: (*self.as_ptr()).pkt_duration as i64,
#[cfg(feature = "ffmpeg_7_0")]
duration: (*self.as_ptr()).duration as i64,
position: (*self.as_ptr()).pkt_pos as i64, position: (*self.as_ptr()).pkt_pos as i64,
size: (*self.as_ptr()).pkt_size as usize, size: (*self.as_ptr()).pkt_size as usize,

View File

@ -173,11 +173,13 @@ impl Video {
unsafe { Rational::from((*self.as_ptr()).sample_aspect_ratio) } unsafe { Rational::from((*self.as_ptr()).sample_aspect_ratio) }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
#[inline] #[inline]
pub fn coded_number(&self) -> usize { pub fn coded_number(&self) -> usize {
unsafe { (*self.as_ptr()).coded_picture_number as usize } unsafe { (*self.as_ptr()).coded_picture_number as usize }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
#[inline] #[inline]
pub fn display_number(&self) -> usize { pub fn display_number(&self) -> usize {
unsafe { (*self.as_ptr()).display_picture_number as usize } unsafe { (*self.as_ptr()).display_picture_number as usize }

View File

@ -26,9 +26,18 @@ pub enum Type {
VideoRate, VideoRate,
Duration, Duration,
Color, Color,
#[cfg(not(feature = "ffmpeg_7_0"))]
ChannelLayout, ChannelLayout,
#[cfg(feature = "ffmpeg_5_1")]
ChLayout,
c_ulong, c_ulong,
bool, bool,
// FIXME: This is not supported yet. `enum Type` should become a bitflags struct.
// FIXME: AVOptionType is also not technically an enum because it may contain
// values that are outside the defined enum variants!
#[cfg(feature = "ffmpeg_7_0")]
ArrayFlag = 0x10000,
} }
impl From<AVOptionType> for Type { impl From<AVOptionType> for Type {
@ -53,9 +62,13 @@ impl From<AVOptionType> for Type {
AV_OPT_TYPE_VIDEO_RATE => Type::VideoRate, AV_OPT_TYPE_VIDEO_RATE => Type::VideoRate,
AV_OPT_TYPE_DURATION => Type::Duration, AV_OPT_TYPE_DURATION => Type::Duration,
AV_OPT_TYPE_COLOR => Type::Color, AV_OPT_TYPE_COLOR => Type::Color,
#[cfg(not(feature = "ffmpeg_7_0"))]
AV_OPT_TYPE_CHANNEL_LAYOUT => Type::ChannelLayout, AV_OPT_TYPE_CHANNEL_LAYOUT => Type::ChannelLayout,
#[cfg(feature = "ffmpeg_5_1")] #[cfg(feature = "ffmpeg_5_1")]
AV_OPT_TYPE_CHLAYOUT => Type::ChannelLayout, AV_OPT_TYPE_CHLAYOUT => Type::ChLayout,
#[cfg(feature = "ffmpeg_7_0")]
AV_OPT_TYPE_FLAG_ARRAY => Type::ArrayFlag,
#[cfg(feature = "non-exhaustive-enums")] #[cfg(feature = "non-exhaustive-enums")]
_ => unimplemented!(), _ => unimplemented!(),
@ -85,7 +98,13 @@ impl From<Type> for AVOptionType {
Type::VideoRate => AV_OPT_TYPE_VIDEO_RATE, Type::VideoRate => AV_OPT_TYPE_VIDEO_RATE,
Type::Duration => AV_OPT_TYPE_DURATION, Type::Duration => AV_OPT_TYPE_DURATION,
Type::Color => AV_OPT_TYPE_COLOR, Type::Color => AV_OPT_TYPE_COLOR,
#[cfg(not(feature = "ffmpeg_7_0"))]
Type::ChannelLayout => AV_OPT_TYPE_CHANNEL_LAYOUT, Type::ChannelLayout => AV_OPT_TYPE_CHANNEL_LAYOUT,
#[cfg(feature = "ffmpeg_5_1")]
Type::ChLayout => AV_OPT_TYPE_CHLAYOUT,
#[cfg(feature = "ffmpeg_7_0")]
Type::ArrayFlag => AV_OPT_TYPE_FLAG_ARRAY,
} }
} }
} }

View File

@ -5,9 +5,12 @@ use std::mem;
use crate::ffi::*; use crate::ffi::*;
use crate::util::format; use crate::util::format;
use crate::{ChannelLayoutMask, Error, Rational}; use crate::{Error, Rational};
use libc::{c_int, c_void}; use libc::{c_int, c_void};
#[cfg(not(feature = "ffmpeg_7_0"))]
use crate::ChannelLayoutMask;
macro_rules! check { macro_rules! check {
($expr:expr) => { ($expr:expr) => {
match $expr { match $expr {
@ -130,6 +133,7 @@ pub trait Settable: Target {
} }
} }
#[cfg(not(feature = "ffmpeg_7_0"))]
fn set_channel_layout(&mut self, name: &str, layout: ChannelLayoutMask) -> Result<(), Error> { fn set_channel_layout(&mut self, name: &str, layout: ChannelLayoutMask) -> Result<(), Error> {
unsafe { unsafe {
let name = CString::new(name).unwrap(); let name = CString::new(name).unwrap();