use derive_more::{IsVariant, TryUnwrap, Unwrap};
use ffmpeg_next::{codec::Parameters, frame};
use mediadecode::{
Received, Sent, Timebase, decoder::AudioStreamDecoder, frame::AudioFrame, packet::AudioPacket,
};
use mediaframe::audio::ChannelLayoutDescription;
use crate::{
DecoderLimits, Error, Ffmpeg, boundary,
convert::{self, ConvertError},
decoder::build_codec_context,
extras::{AudioFrameExtra, AudioPacketExtra},
frame::alloc_av_audio_frame,
sample_format::SampleFormat,
};
pub struct CarrierAudioStreamDecoder<C: crate::FfmpegCarrier> {
decoder: ffmpeg_next::decoder::Audio,
scratch: frame::Audio,
time_base: Timebase,
limits: DecoderLimits,
_callback_state: Box<crate::ffi::CallbackState>,
scratch_pending: bool,
eof: bool,
_carrier: core::marker::PhantomData<C>,
}
impl<C: crate::FfmpegCarrier + crate::CarrierOps> CarrierAudioStreamDecoder<C> {
pub(crate) fn open_impl(
parameters: Parameters,
time_base: Timebase,
limits: DecoderLimits,
) -> Result<Self, AudioDecodeError> {
let (ctx, callback_state) =
build_codec_context(¶meters, limits).map_err(AudioDecodeError::Decode)?;
let codec = crate::decoder::find_decoder(¶meters).map_err(AudioDecodeError::Decode)?;
let opened = ctx
.decoder()
.open_as(codec)
.map_err(|e| AudioDecodeError::Decode(Error::Ffmpeg(e)))?;
crate::decoder::ensure_codec_type(&opened, ffmpeg_next::ffi::AVMediaType::AVMEDIA_TYPE_AUDIO)
.map_err(AudioDecodeError::Decode)?;
let decoder = ffmpeg_next::decoder::Audio(opened);
let scratch = alloc_av_audio_frame().map_err(AudioDecodeError::Decode)?;
Ok(Self {
decoder,
scratch,
time_base,
limits,
_callback_state: callback_state,
scratch_pending: false,
eof: false,
_carrier: core::marker::PhantomData,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn time_base_impl(&self) -> Timebase {
self.time_base
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn limits_impl(&self) -> DecoderLimits {
self.limits
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn inner_impl(&self) -> &ffmpeg_next::decoder::Audio {
&self.decoder
}
}
impl<C: crate::FfmpegCarrier + crate::CarrierOps> CarrierAudioStreamDecoder<C> {
const fn phase(&self) -> crate::decoder::SessionPhase {
if self.eof {
crate::decoder::SessionPhase::Draining
} else {
crate::decoder::SessionPhase::Streaming
}
}
pub(crate) fn send_packet_impl(
&mut self,
packet: &AudioPacket<AudioPacketExtra, C::Buffer>,
) -> Result<Sent, AudioDecodeError> {
let state: *const crate::ffi::CallbackState = &*self._callback_state;
let phase = self.phase();
let decoder = &mut self.decoder;
boundary::with_ffmpeg_audio_packet::<C, _>(
packet,
self.limits.packet_limits(),
crate::carrier::BodyRoute::Submission,
|av_pkt| {
match decoder.send_packet(av_pkt) {
Ok(()) => Ok(Sent::Accepted),
Err(e) => {
crate::decoder::software_send(state, e, phase).map_err(AudioDecodeError::Decode)
}
}
},
)
.map_err(|e| AudioDecodeError::Decode(Error::PacketBuild(e)))?
}
pub(crate) fn receive_frame_impl(
&mut self,
dst: &mut AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, C::Buffer>,
) -> Result<Received, AudioDecodeError> {
let state: *const crate::ffi::CallbackState = &*self._callback_state;
let phase = self.phase();
if !self.scratch_pending {
if let Err(e) = self.decoder.receive_frame(&mut self.scratch) {
return crate::decoder::software_receive(state, e, phase).map_err(AudioDecodeError::Decode);
}
}
let converted = unsafe {
convert::av_frame_to_audio_frame_as::<C>(
self.scratch.as_ptr(),
self.time_base,
self.limits.frame(),
)
};
match converted {
Ok(new_frame) => {
self.scratch_pending = false;
*dst = new_frame;
Ok(Received::Frame)
}
Err(e) => {
self.scratch_pending = e.parks_in_decode();
Err(AudioDecodeError::Convert(e))
}
}
}
pub(crate) fn send_eof_impl(&mut self) -> Result<Sent, AudioDecodeError> {
let state: *const crate::ffi::CallbackState = &*self._callback_state;
let phase = self.phase();
match self.decoder.send_eof() {
Ok(()) => {
self.eof = true;
Ok(Sent::Accepted)
}
Err(e) => crate::decoder::software_send(state, e, phase).map_err(AudioDecodeError::Decode),
}
}
pub(crate) fn flush_impl(&mut self) -> Result<(), AudioDecodeError> {
self.scratch_pending = false;
self.eof = false;
self.decoder.flush();
Ok(())
}
}
macro_rules! audio_lane_face {
($($lane:ty),+ $(,)?) => { $(
impl CarrierAudioStreamDecoder<$lane> {
pub fn open(
parameters: Parameters,
time_base: Timebase,
limits: DecoderLimits,
) -> Result<Self, AudioDecodeError> {
Self::open_impl(parameters, time_base, limits)
}
pub const fn time_base(&self) -> Timebase {
self.time_base_impl()
}
pub const fn limits(&self) -> DecoderLimits {
self.limits_impl()
}
pub const fn inner(&self) -> &ffmpeg_next::decoder::Audio {
self.inner_impl()
}
}
impl AudioStreamDecoder for CarrierAudioStreamDecoder<$lane> {
type Adapter = Ffmpeg;
type Buffer = <$lane as crate::FfmpegCarrier>::Buffer;
type Error = AudioDecodeError;
fn send_packet(
&mut self,
packet: &AudioPacket<AudioPacketExtra, Self::Buffer>,
) -> Result<Sent, Self::Error> {
self.send_packet_impl(packet)
}
fn receive_frame(
&mut self,
dst: &mut AudioFrame<
SampleFormat,
ChannelLayoutDescription,
AudioFrameExtra,
Self::Buffer,
>,
) -> Result<Received, Self::Error> {
self.receive_frame_impl(dst)
}
fn send_eof(&mut self) -> Result<Sent, Self::Error> {
self.send_eof_impl()
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_impl()
}
}
)+ };
}
audio_lane_face!(crate::View, crate::Owned);
#[derive(thiserror::Error, Debug, Clone, IsVariant, Unwrap, TryUnwrap)]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
#[non_exhaustive]
pub enum AudioDecodeError {
#[error(transparent)]
Decode(#[from] Error),
#[error(transparent)]
Convert(#[from] ConvertError),
}