Opus: Create a ChannelMask for OpusProperties

This commit is contained in:
Serial 2024-04-09 20:28:51 -04:00
parent 5c69024b91
commit 1ff1f8a441
No known key found for this signature in database
GPG key ID: DA95198DC17C4568
3 changed files with 60 additions and 2 deletions

View file

@ -2,7 +2,7 @@ use super::find_last_page;
use crate::error::Result;
use crate::macros::decode_err;
use crate::math::RoundedDivision;
use crate::properties::FileProperties;
use crate::properties::{ChannelMask, FileProperties};
use std::io::{Read, Seek, SeekFrom};
use std::time::Duration;
@ -18,6 +18,7 @@ pub struct OpusProperties {
pub(crate) overall_bitrate: u32,
pub(crate) audio_bitrate: u32,
pub(crate) channels: u8,
pub(crate) channel_mask: ChannelMask,
pub(crate) version: u8,
pub(crate) input_sample_rate: u32,
}
@ -31,7 +32,7 @@ impl From<OpusProperties> for FileProperties {
sample_rate: Some(input.input_sample_rate),
bit_depth: None,
channels: Some(input.channels),
channel_mask: None,
channel_mask: Some(input.channel_mask),
}
}
}
@ -57,6 +58,11 @@ impl OpusProperties {
self.channels
}
/// Channel mask
pub fn channel_mask(&self) -> ChannelMask {
self.channel_mask
}
/// Opus version
pub fn version(&self) -> u8 {
self.version
@ -103,6 +109,9 @@ where
decode_err!(@BAIL Opus, "Invalid channel count for mapping family");
}
properties.channel_mask =
ChannelMask::from_opus_channels(properties.channels).expect("Channel count is valid");
let last_page = find_last_page(data);
let file_length = data.seek(SeekFrom::End(0))?;

View file

@ -66,11 +66,59 @@ impl ChannelMask {
Self(Self::FRONT_LEFT.0 | Self::FRONT_RIGHT.0)
}
/// Front left+right+center channels
#[must_use]
pub const fn linear_surround() -> Self {
Self(Self::FRONT_LEFT.0 | Self::FRONT_RIGHT.0 | Self::FRONT_CENTER.0)
}
/// The bit mask
#[must_use]
pub const fn bits(self) -> u32 {
self.0
}
/// Create a channel mask from the number of channels in an Opus file
///
/// See <https://datatracker.ietf.org/doc/html/rfc7845#section-5.1.1.2> for the mapping.
pub const fn from_opus_channels(channels: u8) -> Option<Self> {
match channels {
1 => Some(Self::mono()),
2 => Some(Self::stereo()),
3 => Some(Self::linear_surround()),
4 => Some(Self(
Self::FRONT_LEFT.bits()
| Self::FRONT_RIGHT.bits()
| Self::BACK_LEFT.bits()
| Self::BACK_RIGHT.bits(),
)),
5 => Some(Self(
Self::linear_surround().bits() | Self::BACK_LEFT.bits() | Self::BACK_RIGHT.bits(),
)),
6 => Some(Self(
Self::linear_surround().bits()
| Self::BACK_LEFT.bits()
| Self::BACK_RIGHT.bits()
| Self::LOW_FREQUENCY.bits(),
)),
7 => Some(Self(
Self::linear_surround().bits()
| Self::SIDE_LEFT.bits()
| Self::SIDE_RIGHT.bits()
| Self::BACK_CENTER.bits()
| Self::LOW_FREQUENCY.bits(),
)),
8 => {
Some(Self(
Self::linear_surround().bits()
| Self::SIDE_LEFT.bits() | Self::SIDE_RIGHT.bits()
| Self::BACK_LEFT.bits() | Self::BACK_RIGHT.bits()
| Self::LOW_FREQUENCY.bits(),
))
},
_ => None,
}
}
}
impl BitOr for ChannelMask {

View file

@ -229,6 +229,7 @@ const OPUS_PROPERTIES: OpusProperties = OpusProperties {
overall_bitrate: 120,
audio_bitrate: 120,
channels: 2,
channel_mask: ChannelMask::stereo(),
version: 1,
input_sample_rate: 48000,
};