use ffmpeg_next::{codec::Parameters, frame};
use mediadecode::{
Timebase, channel::AudioChannelLayout, decoder::AudioStreamDecoder, frame::AudioFrame,
packet::AudioPacket,
};
use crate::{
Error, Ffmpeg, FfmpegBuffer, boundary,
convert::{self, ConvertError},
decoder::build_codec_context,
extras::{AudioFrameExtra, AudioPacketExtra},
frame::alloc_av_audio_frame,
sample_format::SampleFormat,
};
pub struct FfmpegAudioStreamDecoder {
decoder: ffmpeg_next::decoder::Audio,
scratch: frame::Audio,
time_base: Timebase,
}
impl FfmpegAudioStreamDecoder {
pub fn open(parameters: Parameters, time_base: Timebase) -> Result<Self, AudioDecodeError> {
let ctx = build_codec_context(¶meters).map_err(AudioDecodeError::Decode)?;
let decoder = ctx
.decoder()
.audio()
.map_err(|e| AudioDecodeError::Decode(Error::Ffmpeg(e)))?;
let scratch = alloc_av_audio_frame().map_err(AudioDecodeError::Decode)?;
Ok(Self {
decoder,
scratch,
time_base,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn time_base(&self) -> Timebase {
self.time_base
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn inner(&self) -> &ffmpeg_next::decoder::Audio {
&self.decoder
}
}
impl AudioStreamDecoder for FfmpegAudioStreamDecoder {
type Adapter = Ffmpeg;
type Buffer = FfmpegBuffer;
type Error = AudioDecodeError;
fn send_packet(
&mut self,
packet: &AudioPacket<AudioPacketExtra, Self::Buffer>,
) -> Result<(), Self::Error> {
let av_pkt = boundary::ffmpeg_packet_from_audio_packet(packet)
.map_err(|e| AudioDecodeError::Decode(Error::Ffmpeg(e)))?;
self
.decoder
.send_packet(&av_pkt)
.map_err(|e| AudioDecodeError::Decode(Error::Ffmpeg(e)))
}
fn receive_frame(
&mut self,
dst: &mut AudioFrame<SampleFormat, AudioChannelLayout, AudioFrameExtra, Self::Buffer>,
) -> Result<(), Self::Error> {
self
.decoder
.receive_frame(&mut self.scratch)
.map_err(|e| AudioDecodeError::Decode(Error::Ffmpeg(e)))?;
let new_frame =
unsafe { convert::av_frame_to_audio_frame(self.scratch.as_ptr(), self.time_base) }
.map_err(AudioDecodeError::Convert)?;
*dst = new_frame;
Ok(())
}
fn send_eof(&mut self) -> Result<(), Self::Error> {
self
.decoder
.send_eof()
.map_err(|e| AudioDecodeError::Decode(Error::Ffmpeg(e)))
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.decoder.flush();
Ok(())
}
}
#[derive(thiserror::Error, Debug)]
pub enum AudioDecodeError {
#[error(transparent)]
Decode(#[from] Error),
#[error(transparent)]
Convert(#[from] ConvertError),
}