use std::collections::VecDeque;
use oxideav_core::{CodecId, CodecParameters, Error, Frame, MediaType, Packet, Result, TimeBase};
use oxideav_core::{Decoder, Encoder};
pub const ASS_CODEC_ID: &str = "ass";
pub fn make_decoder(params: &CodecParameters) -> Result<Box<dyn Decoder>> {
if params.codec_id.as_str() != ASS_CODEC_ID {
return Err(Error::unsupported(format!(
"not an ASS codec id: {}",
params.codec_id.as_str()
)));
}
Ok(Box::new(AssDecoder {
codec_id: params.codec_id.clone(),
pending: VecDeque::new(),
eof: false,
}))
}
pub fn make_encoder(params: &CodecParameters) -> Result<Box<dyn Encoder>> {
if params.codec_id.as_str() != ASS_CODEC_ID {
return Err(Error::unsupported(format!(
"not an ASS codec id: {}",
params.codec_id.as_str()
)));
}
let mut p = params.clone();
p.media_type = MediaType::Subtitle;
Ok(Box::new(AssEncoder {
params: p,
pending: VecDeque::new(),
}))
}
struct AssDecoder {
codec_id: CodecId,
pending: VecDeque<Frame>,
eof: bool,
}
impl Decoder for AssDecoder {
fn codec_id(&self) -> &CodecId {
&self.codec_id
}
fn send_packet(&mut self, packet: &Packet) -> Result<()> {
let cue = super::bytes_to_cue(&packet.data)?;
let mut cue = cue;
if let Some(pts) = packet.pts {
let us = rescale_to_us(pts, packet.time_base);
let span = cue.end_us - cue.start_us;
cue.start_us = us;
cue.end_us = us + span;
}
self.pending.push_back(Frame::Subtitle(cue));
Ok(())
}
fn receive_frame(&mut self) -> Result<Frame> {
if let Some(f) = self.pending.pop_front() {
return Ok(f);
}
if self.eof {
return Err(Error::Eof);
}
Err(Error::NeedMore)
}
fn flush(&mut self) -> Result<()> {
self.eof = true;
Ok(())
}
fn reset(&mut self) -> Result<()> {
self.pending.clear();
self.eof = false;
Ok(())
}
}
struct AssEncoder {
params: CodecParameters,
pending: VecDeque<Packet>,
}
impl Encoder for AssEncoder {
fn codec_id(&self) -> &CodecId {
&self.params.codec_id
}
fn output_params(&self) -> &CodecParameters {
&self.params
}
fn send_frame(&mut self, frame: &Frame) -> Result<()> {
let cue = match frame {
Frame::Subtitle(c) => c,
_ => return Err(Error::invalid("ASS encoder: expected Frame::Subtitle")),
};
let payload = super::cue_to_bytes(cue);
let tb = TimeBase::new(1, 1_000_000);
let mut pkt = Packet::new(0, tb, payload);
pkt.pts = Some(cue.start_us);
pkt.dts = Some(cue.start_us);
pkt.duration = Some((cue.end_us - cue.start_us).max(0));
pkt.flags.keyframe = true;
self.pending.push_back(pkt);
Ok(())
}
fn receive_packet(&mut self) -> Result<Packet> {
self.pending.pop_front().ok_or(Error::NeedMore)
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
fn rescale_to_us(pts: i64, tb: TimeBase) -> i64 {
tb.rescale(pts, TimeBase::new(1, 1_000_000))
}