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:
17
.github/workflows/build.yml
vendored
17
.github/workflows/build.yml
vendored
@ -30,7 +30,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
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
|
||||
|
||||
steps:
|
||||
@ -45,8 +45,9 @@ jobs:
|
||||
components: rustfmt, clippy
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: "v2-rust"
|
||||
# Only save cache for one FFmpeg version
|
||||
save-if: ${{ matrix.ffmpeg_version == '6.1' }}
|
||||
save-if: ${{ matrix.ffmpeg_version == '7.0' }}
|
||||
|
||||
- name: Check format
|
||||
run: cargo fmt -- --check
|
||||
@ -75,6 +76,8 @@ jobs:
|
||||
with:
|
||||
components: rustfmt, clippy
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: "v2-rust"
|
||||
|
||||
- name: Check format
|
||||
run: cargo fmt -- --check
|
||||
@ -97,7 +100,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
# 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
|
||||
|
||||
env:
|
||||
@ -127,8 +130,8 @@ jobs:
|
||||
components: rustfmt, clippy
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: "v1-rust"
|
||||
save-if: ${{ matrix.ffmpeg_version == '6.1' }}
|
||||
prefix-key: "v2-rust"
|
||||
save-if: ${{ matrix.ffmpeg_version == '7.0' }}
|
||||
|
||||
- name: Check format
|
||||
run: cargo fmt -- --check
|
||||
@ -147,7 +150,7 @@ jobs:
|
||||
|
||||
msrv:
|
||||
runs-on: ubuntu-22.04
|
||||
container: jrottenberg/ffmpeg:6.1-ubuntu
|
||||
container: jrottenberg/ffmpeg:7.0-ubuntu
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -159,6 +162,8 @@ jobs:
|
||||
- name: Install Rust 1.61.0
|
||||
uses: dtolnay/rust-toolchain@1.61.0
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: "v2-rust"
|
||||
|
||||
- name: Use predefined lockfile
|
||||
run: mv Cargo.lock.MSRV Cargo.lock
|
||||
|
@ -47,7 +47,8 @@ fn main() {
|
||||
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<_>>());
|
||||
} else {
|
||||
println!("\t channel_layouts: any");
|
||||
@ -97,7 +98,8 @@ fn main() {
|
||||
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<_>>());
|
||||
} else {
|
||||
println!("\t channel_layouts: any");
|
||||
|
@ -73,10 +73,14 @@ fn main() -> Result<(), ffmpeg::Error> {
|
||||
println!("\tmax_rate: {}", audio.max_bit_rate());
|
||||
println!("\tdelay: {}", audio.delay());
|
||||
println!("\taudio.rate: {}", audio.rate());
|
||||
println!("\taudio.channels: {}", audio.channels());
|
||||
println!("\taudio.format: {:?}", audio.format());
|
||||
println!("\taudio.frames: {}", audio.frames());
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -13,12 +13,16 @@ fn filter(
|
||||
) -> Result<filter::Graph, ffmpeg::Error> {
|
||||
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!(
|
||||
"time_base={}:sample_rate={}:sample_fmt={}:channel_layout=0x{:x}",
|
||||
"time_base={}:sample_rate={}:sample_fmt={}:channel_layout={channel_layout}",
|
||||
decoder.time_base(),
|
||||
decoder.rate(),
|
||||
decoder.format().name(),
|
||||
decoder.channel_layout().bits()
|
||||
decoder.format().name()
|
||||
);
|
||||
|
||||
filter.add(&filter::find("abuffer").unwrap(), "in", &args)?;
|
||||
@ -28,7 +32,10 @@ fn filter(
|
||||
let mut out = filter.get("out").unwrap();
|
||||
|
||||
out.set_sample_format(encoder.format());
|
||||
#[cfg(not(feature = "ffmpeg_5_1"))]
|
||||
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());
|
||||
}
|
||||
|
||||
@ -88,18 +95,31 @@ fn transcoder<P: AsRef<Path>>(
|
||||
let context = ffmpeg::codec::context::Context::from_parameters(output.parameters())?;
|
||||
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 {
|
||||
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_channel_layout(channel_layout);
|
||||
encoder.set_channels(channel_layout.channels());
|
||||
encoder.set_format(
|
||||
codec
|
||||
.formats()
|
||||
|
@ -114,6 +114,7 @@ static AVUTIL_FEATURES: &[AVFeature] = &[
|
||||
AVFeature::new("FRAME_KEY"),
|
||||
AVFeature::new("PALETTE_HAS_CHANGED"),
|
||||
AVFeature::new("VULKAN_CONTIGUOUS_MEMORY"),
|
||||
AVFeature::new("H274_FILM_GRAIN_VCS"),
|
||||
];
|
||||
|
||||
static AVCODEC_FEATURES: &[AVFeature] = &[
|
||||
@ -199,6 +200,9 @@ static AVCODEC_FEATURES: &[AVFeature] = &[
|
||||
AVFeature::new("DROPCHANGED"),
|
||||
AVFeature::new("AVFFT"),
|
||||
AVFeature::new("FF_PROFILE_LEVEL"),
|
||||
AVFeature::new("AVCODEC_CLOSE"),
|
||||
AVFeature::new("BUFFER_MIN_SIZE"),
|
||||
AVFeature::new("VDPAU_ALLOC_GET_SET"),
|
||||
];
|
||||
|
||||
static AVFORMAT_FEATURES: &[AVFeature] = &[
|
||||
@ -220,9 +224,16 @@ static AVFORMAT_FEATURES: &[AVFeature] = &[
|
||||
AVFeature::new("LAVF_SHORTEST"),
|
||||
AVFeature::new("ALLOW_FLUSH"),
|
||||
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] = &[
|
||||
AVFeature::new("AVFILTERPAD_PUBLIC"),
|
||||
@ -237,6 +248,7 @@ static AVFILTER_FEATURES: &[AVFeature] = &[
|
||||
AVFeature::new("BUFFERSINK_ALLOC"),
|
||||
AVFeature::new("PAD_COUNT"),
|
||||
AVFeature::new("LIBPLACEBO_OPTS"),
|
||||
AVFeature::new("LINK_PUBLIC"),
|
||||
];
|
||||
|
||||
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
|
||||
version_check_info.iter()
|
||||
{
|
||||
@ -880,6 +892,7 @@ fn check_features(include_paths: &[PathBuf]) {
|
||||
("ffmpeg_5_1", 59, 37),
|
||||
("ffmpeg_6_0", 60, 3),
|
||||
("ffmpeg_6_1", 60, 31),
|
||||
("ffmpeg_7_0", 61, 3),
|
||||
];
|
||||
for &(ffmpeg_version_flag, lavc_version_major, lavc_version_minor) in
|
||||
ffmpeg_lavc_versions.iter()
|
||||
|
@ -77,9 +77,10 @@ impl fmt::Debug for AVChannelLayout {
|
||||
"map",
|
||||
&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
|
||||
// AVChannelOrder::FF_CHANNEL_ORDER_NB => {}
|
||||
}
|
||||
// Not part of public API, but we have to exhaustively match
|
||||
#[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;
|
||||
pub const AV_CH_LAYOUT_7POINT1POINT4_BACK: u64 =
|
||||
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
|
||||
| AV_CH_WIDE_LEFT
|
||||
| AV_CH_WIDE_RIGHT
|
||||
@ -285,6 +292,12 @@ pub const AV_CHANNEL_LAYOUT_7POINT1POINT2: AVChannelLayout =
|
||||
AV_CHANNEL_LAYOUT_MASK(10, AV_CH_LAYOUT_7POINT1POINT2);
|
||||
pub const AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK: AVChannelLayout =
|
||||
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 =
|
||||
AV_CHANNEL_LAYOUT_MASK(16, AV_CH_LAYOUT_HEXADECAGONAL);
|
||||
pub const AV_CHANNEL_LAYOUT_STEREO_DOWNMIX: AVChannelLayout =
|
||||
|
@ -1,5 +1,5 @@
|
||||
use libc::{c_double, c_int};
|
||||
use crate::AVRational;
|
||||
use libc::{c_double, c_int};
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn av_make_q(num: c_int, den: c_int) -> AVRational {
|
||||
|
@ -2,7 +2,10 @@ use std::ops::Deref;
|
||||
|
||||
use super::codec::Codec;
|
||||
use crate::ffi::*;
|
||||
use crate::{format, ChannelLayoutMask};
|
||||
use crate::format;
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
use crate::ChannelLayoutMask;
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||
pub struct Audio {
|
||||
@ -36,6 +39,7 @@ impl Audio {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
pub fn channel_layouts(&self) -> Option<ChannelLayoutMaskIter> {
|
||||
unsafe {
|
||||
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 {
|
||||
ptr: *const u64,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
impl ChannelLayoutMaskIter {
|
||||
pub fn new(ptr: *const u64) -> Self {
|
||||
ChannelLayoutMaskIter { ptr }
|
||||
@ -136,6 +142,7 @@ impl ChannelLayoutMaskIter {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
impl Iterator for ChannelLayoutMaskIter {
|
||||
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> {
|
||||
type Item = ChannelLayout<'a>;
|
||||
|
||||
|
@ -10,13 +10,16 @@ use crate::codec::Context;
|
||||
#[cfg(not(feature = "ffmpeg_5_0"))]
|
||||
use crate::frame;
|
||||
use crate::util::format;
|
||||
use crate::AudioService;
|
||||
#[cfg(not(feature = "ffmpeg_5_0"))]
|
||||
use crate::{packet, Error};
|
||||
use crate::{AudioService, ChannelLayoutMask};
|
||||
|
||||
#[cfg(feature = "ffmpeg_5_1")]
|
||||
use crate::ChannelLayout;
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
use crate::ChannelLayoutMask;
|
||||
|
||||
pub struct Audio(pub Opened);
|
||||
|
||||
impl Audio {
|
||||
@ -50,6 +53,7 @@ impl Audio {
|
||||
unsafe { (*self.as_ptr()).sample_rate as u32 }
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
pub fn channels(&self) -> 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 {
|
||||
unsafe { (*self.as_ptr()).frame_number as usize }
|
||||
}
|
||||
@ -72,16 +77,19 @@ impl Audio {
|
||||
unsafe { (*self.as_ptr()).block_align as usize }
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
pub fn channel_layout(&self) -> ChannelLayoutMask {
|
||||
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) {
|
||||
unsafe {
|
||||
(*self.as_mut_ptr()).channel_layout = value.bits();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
pub fn request_channel_layout(&mut self, value: ChannelLayoutMask) {
|
||||
unsafe {
|
||||
(*self.as_mut_ptr()).request_channel_layout = value.bits();
|
||||
|
@ -84,6 +84,7 @@ impl Video {
|
||||
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) {
|
||||
unsafe {
|
||||
(*self.as_mut_ptr()).slice_count = value as c_int;
|
||||
|
@ -10,11 +10,14 @@ use crate::codec::{traits, Context};
|
||||
use crate::util::format;
|
||||
#[cfg(not(feature = "ffmpeg_5_0"))]
|
||||
use crate::{frame, packet};
|
||||
use crate::{ChannelLayoutMask, Dictionary, Error};
|
||||
use crate::{Dictionary, Error};
|
||||
|
||||
#[cfg(feature = "ffmpeg_5_1")]
|
||||
use crate::ChannelLayout;
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
use crate::ChannelLayoutMask;
|
||||
|
||||
pub struct Audio(pub Super);
|
||||
|
||||
impl Audio {
|
||||
@ -96,22 +99,26 @@ impl Audio {
|
||||
unsafe { format::Sample::from((*self.as_ptr()).sample_fmt) }
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) {
|
||||
unsafe {
|
||||
(*self.as_mut_ptr()).channel_layout = value.bits();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
pub fn channel_layout(&self) -> ChannelLayoutMask {
|
||||
unsafe { ChannelLayoutMask::from_bits_truncate((*self.as_ptr()).channel_layout) }
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
pub fn set_channels(&mut self, value: i32) {
|
||||
unsafe {
|
||||
(*self.as_mut_ptr()).channels = value;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
pub fn channels(&self) -> u16 {
|
||||
unsafe { (*self.as_ptr()).channels as u16 }
|
||||
}
|
||||
|
@ -214,6 +214,7 @@ pub enum Id {
|
||||
AVRP,
|
||||
V012,
|
||||
AVUI,
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
AYUV,
|
||||
TARGA_Y216,
|
||||
V308,
|
||||
@ -656,10 +657,14 @@ pub enum Id {
|
||||
RTV1,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
VMIX,
|
||||
#[cfg(feature = "ffmpeg_7_0")]
|
||||
LEAD,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
AC4,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
OSQ,
|
||||
#[cfg(feature = "ffmpeg_7_0")]
|
||||
QOA,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
SMPTE_2038,
|
||||
}
|
||||
@ -881,6 +886,7 @@ impl From<AVCodecID> for Id {
|
||||
AV_CODEC_ID_AVRP => Id::AVRP,
|
||||
AV_CODEC_ID_012V => Id::V012,
|
||||
AV_CODEC_ID_AVUI => Id::AVUI,
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
AV_CODEC_ID_AYUV => Id::AYUV,
|
||||
AV_CODEC_ID_TARGA_Y216 => Id::TARGA_Y216,
|
||||
AV_CODEC_ID_V308 => Id::V308,
|
||||
@ -1322,10 +1328,14 @@ impl From<AVCodecID> for Id {
|
||||
AV_CODEC_ID_RTV1 => Id::RTV1,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
AV_CODEC_ID_VMIX => Id::VMIX,
|
||||
#[cfg(feature = "ffmpeg_7_0")]
|
||||
AV_CODEC_ID_LEAD => Id::LEAD,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
AV_CODEC_ID_AC4 => Id::AC4,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
AV_CODEC_ID_OSQ => Id::OSQ,
|
||||
#[cfg(feature = "ffmpeg_7_0")]
|
||||
AV_CODEC_ID_QOA => Id::QOA,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
AV_CODEC_ID_SMPTE_2038 => Id::SMPTE_2038,
|
||||
|
||||
@ -1541,6 +1551,7 @@ impl From<Id> for AVCodecID {
|
||||
Id::AVRP => AV_CODEC_ID_AVRP,
|
||||
Id::V012 => AV_CODEC_ID_012V,
|
||||
Id::AVUI => AV_CODEC_ID_AVUI,
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
Id::AYUV => AV_CODEC_ID_AYUV,
|
||||
Id::TARGA_Y216 => AV_CODEC_ID_TARGA_Y216,
|
||||
Id::V308 => AV_CODEC_ID_V308,
|
||||
@ -1982,10 +1993,14 @@ impl From<Id> for AVCodecID {
|
||||
Id::RTV1 => AV_CODEC_ID_RTV1,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
Id::VMIX => AV_CODEC_ID_VMIX,
|
||||
#[cfg(feature = "ffmpeg_7_0")]
|
||||
Id::LEAD => AV_CODEC_ID_LEAD,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
Id::AC4 => AV_CODEC_ID_AC4,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
Id::OSQ => AV_CODEC_ID_OSQ,
|
||||
#[cfg(feature = "ffmpeg_7_0")]
|
||||
Id::QOA => AV_CODEC_ID_QOA,
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
Id::SMPTE_2038 => AV_CODEC_ID_SMPTE_2038,
|
||||
}
|
||||
|
@ -57,6 +57,15 @@ pub enum Type {
|
||||
|
||||
#[cfg(feature = "ffmpeg_5_0")]
|
||||
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 {
|
||||
@ -110,6 +119,15 @@ impl From<AVPacketSideDataType> for Type {
|
||||
#[cfg(feature = "ffmpeg_5_0")]
|
||||
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")]
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
@ -166,6 +184,15 @@ impl From<Type> for AVPacketSideDataType {
|
||||
|
||||
#[cfg(feature = "ffmpeg_5_0")]
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,15 @@ use std::marker::PhantomData;
|
||||
|
||||
use super::{Sink, Source};
|
||||
use crate::ffi::*;
|
||||
use crate::{format, option, ChannelLayoutMask};
|
||||
use crate::{format, option};
|
||||
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> {
|
||||
ptr: *mut AVFilterContext,
|
||||
|
||||
@ -49,9 +55,15 @@ impl<'a> Context<'a> {
|
||||
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) {
|
||||
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> {
|
||||
|
@ -35,7 +35,7 @@ pub fn converter(
|
||||
#[cfg(feature = "software-resampling")]
|
||||
pub mod resampling;
|
||||
|
||||
#[cfg(feature = "software-resampling")]
|
||||
#[cfg(all(feature = "software-resampling", not(feature = "ffmpeg_7_0")))]
|
||||
#[inline]
|
||||
pub fn resampler(
|
||||
(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,
|
||||
)
|
||||
}
|
||||
|
||||
#[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,
|
||||
)
|
||||
}
|
||||
|
@ -8,6 +8,9 @@ use crate::{frame, ChannelLayoutMask, Error};
|
||||
use libc::c_int;
|
||||
use std::ffi::c_void;
|
||||
|
||||
#[cfg(feature = "ffmpeg_5_1")]
|
||||
use crate::ChannelLayout;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone)]
|
||||
pub struct Definition {
|
||||
pub format: format::Sample,
|
||||
@ -38,6 +41,7 @@ impl Context {
|
||||
|
||||
impl Context {
|
||||
/// Create a resampler with the given definitions.
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
pub fn get(
|
||||
src_format: format::Sample,
|
||||
src_channel_layout: ChannelLayoutMask,
|
||||
@ -58,6 +62,7 @@ impl Context {
|
||||
}
|
||||
|
||||
/// Create a resampler with the given definitions and custom options dictionary.
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
pub fn get_with(
|
||||
src_format: format::Sample,
|
||||
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.
|
||||
pub fn input(&self) -> &Definition {
|
||||
&self.input
|
||||
|
@ -1,8 +1,15 @@
|
||||
use super::Context;
|
||||
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 {
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
#[inline]
|
||||
pub fn resampler(
|
||||
&self,
|
||||
@ -19,9 +26,28 @@ impl frame::Audio {
|
||||
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 {
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
#[inline]
|
||||
pub fn resampler(
|
||||
&self,
|
||||
@ -38,4 +64,22 @@ impl decoder::Audio {
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -306,6 +306,11 @@ impl<'a> ChannelLayout<'a> {
|
||||
pub const _7POINT1POINT2: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_7POINT1POINT2));
|
||||
pub const _7POINT1POINT4_BACK: Scl =
|
||||
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 STEREO_DOWNMIX: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_STEREO_DOWNMIX));
|
||||
pub const _22POINT2: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_22POINT2));
|
||||
|
@ -28,6 +28,7 @@ bitflags! {
|
||||
const SURROUND_DIRECT_LEFT = AV_CH_SURROUND_DIRECT_LEFT;
|
||||
const SURROUND_DIRECT_RIGHT = AV_CH_SURROUND_DIRECT_RIGHT;
|
||||
const LOW_FREQUENCY_2 = AV_CH_LOW_FREQUENCY_2;
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
const NATIVE = AV_CH_LAYOUT_NATIVE;
|
||||
|
||||
const MONO = AV_CH_LAYOUT_MONO;
|
||||
@ -68,6 +69,10 @@ bitflags! {
|
||||
const _7POINT1POINT2 = AV_CH_LAYOUT_7POINT1POINT2;
|
||||
#[cfg(feature = "ffmpeg_5_1")]
|
||||
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 STEREO_DOWNMIX = AV_CH_LAYOUT_STEREO_DOWNMIX;
|
||||
#[cfg(feature = "ffmpeg_5_1")]
|
||||
@ -75,6 +80,7 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
impl ChannelLayoutMask {
|
||||
#[inline]
|
||||
pub fn channels(&self) -> i32 {
|
||||
|
@ -29,6 +29,9 @@ impl From<AVChannelOrder> for ChannelOrder {
|
||||
AV_CHANNEL_ORDER_NATIVE => Native,
|
||||
AV_CHANNEL_ORDER_CUSTOM => Custom,
|
||||
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")]
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ pub enum Pixel {
|
||||
VIDEOTOOLBOX,
|
||||
|
||||
// --- defaults
|
||||
#[cfg(feature = "ffmpeg_4_0")]
|
||||
#[cfg(all(feature = "ffmpeg_4_0", not(feature = "ffmpeg_7_0")))]
|
||||
XVMC,
|
||||
|
||||
RGB32,
|
||||
@ -417,6 +417,9 @@ pub enum Pixel {
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
GBRAP14LE,
|
||||
|
||||
#[cfg(feature = "ffmpeg_7_0")]
|
||||
D3D12,
|
||||
|
||||
#[cfg(feature = "rpi")]
|
||||
RPI,
|
||||
#[cfg(feature = "rpi")]
|
||||
@ -498,7 +501,7 @@ impl From<AVPixelFormat> for Pixel {
|
||||
AV_PIX_FMT_YUVJ420P => Pixel::YUVJ420P,
|
||||
AV_PIX_FMT_YUVJ422P => Pixel::YUVJ422P,
|
||||
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,
|
||||
#[cfg(all(feature = "ff_api_xvmc", not(feature = "ffmpeg_5_0")))]
|
||||
AV_PIX_FMT_XVMC_MPEG2_MC => Pixel::XVMC_MPEG2_MC,
|
||||
@ -825,6 +828,9 @@ impl From<AVPixelFormat> for Pixel {
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
AV_PIX_FMT_GBRAP14LE => Pixel::GBRAP14LE,
|
||||
|
||||
#[cfg(feature = "ffmpeg_7_0")]
|
||||
AV_PIX_FMT_D3D12 => Pixel::D3D12,
|
||||
|
||||
#[cfg(feature = "rpi")]
|
||||
AV_PIX_FMT_RPI => Pixel::RPI,
|
||||
#[cfg(feature = "rpi")]
|
||||
@ -1062,7 +1068,7 @@ impl From<Pixel> for AVPixelFormat {
|
||||
Pixel::VIDEOTOOLBOX => AV_PIX_FMT_VIDEOTOOLBOX,
|
||||
|
||||
// --- defaults
|
||||
#[cfg(feature = "ffmpeg_4_0")]
|
||||
#[cfg(all(feature = "ffmpeg_4_0", not(feature = "ffmpeg_7_0")))]
|
||||
Pixel::XVMC => AV_PIX_FMT_XVMC,
|
||||
|
||||
Pixel::RGB32 => AV_PIX_FMT_RGB32,
|
||||
@ -1254,6 +1260,9 @@ impl From<Pixel> for AVPixelFormat {
|
||||
#[cfg(feature = "ffmpeg_6_1")]
|
||||
Pixel::GBRAP14LE => AV_PIX_FMT_GBRAP14LE,
|
||||
|
||||
#[cfg(feature = "ffmpeg_7_0")]
|
||||
Pixel::D3D12 => AV_PIX_FMT_D3D12,
|
||||
|
||||
#[cfg(feature = "rpi")]
|
||||
Pixel::RPI => AV_PIX_FMT_RPI,
|
||||
#[cfg(feature = "rpi")]
|
||||
|
@ -6,11 +6,14 @@ use super::Frame;
|
||||
use crate::ffi::*;
|
||||
use crate::util::format;
|
||||
use crate::ChannelLayoutMask;
|
||||
use libc::{c_int, c_ulonglong};
|
||||
use libc::c_int;
|
||||
|
||||
#[cfg(feature = "ffmpeg_5_1")]
|
||||
use crate::ChannelLayout;
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
use libc::c_ulonglong;
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct Audio(Frame);
|
||||
|
||||
@ -29,7 +32,10 @@ impl Audio {
|
||||
) {
|
||||
self.set_format(format);
|
||||
self.set_samples(samples);
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
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);
|
||||
}
|
||||
@ -69,6 +75,7 @@ impl Audio {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
#[inline]
|
||||
pub fn channel_layout(&self) -> ChannelLayoutMask {
|
||||
unsafe {
|
||||
@ -76,6 +83,7 @@ impl Audio {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
#[inline]
|
||||
pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) {
|
||||
unsafe {
|
||||
@ -97,11 +105,13 @@ impl Audio {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
#[inline]
|
||||
pub fn channels(&self) -> u16 {
|
||||
unsafe { (*self.as_ptr()).channels as u16 }
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
#[inline]
|
||||
pub fn set_channels(&mut self, value: u16) {
|
||||
unsafe {
|
||||
@ -154,7 +164,12 @@ impl Audio {
|
||||
if self.is_packed() {
|
||||
1
|
||||
} 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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@ -177,7 +197,12 @@ impl Audio {
|
||||
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");
|
||||
}
|
||||
|
||||
@ -231,9 +256,14 @@ impl DerefMut for Audio {
|
||||
|
||||
impl ::std::fmt::Debug for Audio {
|
||||
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(&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!("samples: {:?} ", self.samples()))?;
|
||||
f.write_str("}")
|
||||
@ -242,7 +272,12 @@ impl ::std::fmt::Debug for Audio {
|
||||
|
||||
impl Clone for Audio {
|
||||
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
|
||||
|
@ -89,7 +89,10 @@ impl Frame {
|
||||
pub fn packet(&self) -> Packet {
|
||||
unsafe {
|
||||
Packet {
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
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,
|
||||
size: (*self.as_ptr()).pkt_size as usize,
|
||||
|
||||
|
@ -173,11 +173,13 @@ impl Video {
|
||||
unsafe { Rational::from((*self.as_ptr()).sample_aspect_ratio) }
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
#[inline]
|
||||
pub fn coded_number(&self) -> usize {
|
||||
unsafe { (*self.as_ptr()).coded_picture_number as usize }
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
#[inline]
|
||||
pub fn display_number(&self) -> usize {
|
||||
unsafe { (*self.as_ptr()).display_picture_number as usize }
|
||||
|
@ -26,9 +26,18 @@ pub enum Type {
|
||||
VideoRate,
|
||||
Duration,
|
||||
Color,
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
ChannelLayout,
|
||||
#[cfg(feature = "ffmpeg_5_1")]
|
||||
ChLayout,
|
||||
c_ulong,
|
||||
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 {
|
||||
@ -53,9 +62,13 @@ impl From<AVOptionType> for Type {
|
||||
AV_OPT_TYPE_VIDEO_RATE => Type::VideoRate,
|
||||
AV_OPT_TYPE_DURATION => Type::Duration,
|
||||
AV_OPT_TYPE_COLOR => Type::Color,
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
AV_OPT_TYPE_CHANNEL_LAYOUT => Type::ChannelLayout,
|
||||
#[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")]
|
||||
_ => unimplemented!(),
|
||||
@ -85,7 +98,13 @@ impl From<Type> for AVOptionType {
|
||||
Type::VideoRate => AV_OPT_TYPE_VIDEO_RATE,
|
||||
Type::Duration => AV_OPT_TYPE_DURATION,
|
||||
Type::Color => AV_OPT_TYPE_COLOR,
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,12 @@ use std::mem;
|
||||
|
||||
use crate::ffi::*;
|
||||
use crate::util::format;
|
||||
use crate::{ChannelLayoutMask, Error, Rational};
|
||||
use crate::{Error, Rational};
|
||||
use libc::{c_int, c_void};
|
||||
|
||||
#[cfg(not(feature = "ffmpeg_7_0"))]
|
||||
use crate::ChannelLayoutMask;
|
||||
|
||||
macro_rules! check {
|
||||
($expr: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> {
|
||||
unsafe {
|
||||
let name = CString::new(name).unwrap();
|
||||
|
Reference in New Issue
Block a user