extern crate ffmpeg_next as ffmpeg;
use ffmpeg::codec::Id as AvCodecId;
use ffmpeg::{Error as AvError, Rational as AvRational};
use crate::error::Error;
use crate::extradata::{extract_parameter_sets_h264, Pps, Sps};
use crate::ffi::extradata;
use crate::io::{Reader, Write};
use crate::packet::Packet;
use crate::stream::StreamInfo;
type Result<T> = std::result::Result<T, Error>;
pub struct MuxerBuilder<W: Write> {
writer: W,
interleaved: bool,
mapping: std::collections::HashMap<usize, StreamDescription>,
}
impl<W: Write> MuxerBuilder<W> {
pub fn new(writer: W) -> Self {
Self {
writer,
interleaved: false,
mapping: std::collections::HashMap::new(),
}
}
pub fn with_stream(mut self, stream_info: StreamInfo) -> Result<Self> {
let (index, codec_parameters, reader_stream_time_base) = stream_info.into_parts();
let mut writer_stream = self
.writer
.output_mut()
.add_stream(ffmpeg::encoder::find(codec_parameters.id()))?;
writer_stream.set_parameters(codec_parameters);
let stream_description = StreamDescription {
index: writer_stream.index(),
source_time_base: reader_stream_time_base,
};
self.mapping.insert(index, stream_description);
Ok(self)
}
pub fn with_streams(mut self, reader: &Reader) -> Result<Self> {
for stream in reader.input.streams() {
self = self.with_stream(reader.stream_info(stream.index())?)?;
}
Ok(self)
}
pub fn interleaved(mut self) -> Self {
self.interleaved = true;
self
}
pub fn build(self) -> Muxer<W> {
Muxer {
writer: self.writer,
mapping: self.mapping,
interleaved: self.interleaved,
have_written_header: false,
have_written_trailer: false,
}
}
}
pub struct Muxer<W: Write> {
pub(crate) writer: W,
mapping: std::collections::HashMap<usize, StreamDescription>,
interleaved: bool,
have_written_header: bool,
have_written_trailer: bool,
}
impl<W: Write> Muxer<W> {
pub fn mux(&mut self, packet: Packet) -> Result<W::Out> {
if self.have_written_header {
let mut packet = packet.into_inner();
let stream_description = self
.mapping
.get(&packet.stream())
.ok_or(AvError::StreamNotFound)?;
let destination_stream = self
.writer
.output()
.stream(stream_description.index)
.ok_or(AvError::StreamNotFound)?;
packet.set_stream(destination_stream.index());
packet.set_position(-1);
packet.rescale_ts(
stream_description.source_time_base,
destination_stream.time_base(),
);
Ok({
if self.interleaved {
self.writer.write_interleaved(&mut packet)?
} else {
self.writer.write(&mut packet)?
}
})
} else {
self.have_written_header = true;
self.writer.write_header()?;
self.mux(packet)
}
}
pub fn finish(&mut self) -> Result<Option<W::Out>> {
if self.have_written_header && !self.have_written_trailer {
self.have_written_trailer = true;
self.writer.write_trailer().map(Some)
} else {
Ok(None)
}
}
pub fn parameter_sets_h264(&self) -> Vec<Result<(Sps<'_>, Pps<'_>)>> {
self.writer
.output()
.streams()
.map(|stream| {
if stream.parameters().id() == AvCodecId::H264 {
extract_parameter_sets_h264(extradata(self.writer.output(), stream.index())?)
} else {
Err(Error::UnsupportedCodecParameterSets)
}
})
.collect::<Vec<_>>()
}
}
unsafe impl<W: Write> Send for Muxer<W> {}
unsafe impl<W: Write> Sync for Muxer<W> {}
#[derive(Debug, Clone, PartialEq, Eq)]
struct StreamDescription {
index: usize,
source_time_base: AvRational,
}