extern crate ffmpeg_next as ffmpeg;
use ffmpeg::codec::packet::Packet as AvPacket;
use ffmpeg::ffi::AV_TIME_BASE_Q;
use ffmpeg::format::context::{Input as AvInput, Output as AvOutput};
use ffmpeg::media::Type as AvMediaType;
use ffmpeg::Error as AvError;
use ffmpeg_next::ffi::av_seek_frame;
use crate::error::Error;
use crate::ffi;
use crate::location::Location;
use crate::options::Options;
use crate::packet::Packet;
use crate::stream::StreamInfo;
type Result<T> = std::result::Result<T, Error>;
pub struct ReaderBuilder<'a> {
source: Location,
options: Option<&'a Options>,
}
impl<'a> ReaderBuilder<'a> {
pub fn new(source: impl Into<Location>) -> Self {
Self {
source: source.into(),
options: None,
}
}
pub fn with_options(mut self, options: &'a Options) -> Self {
self.options = Some(options);
self
}
pub fn build(self) -> Result<Reader> {
match self.options {
None => Ok(Reader {
input: ffmpeg::format::input(&self.source.as_path())?,
source: self.source,
}),
Some(options) => Ok(Reader {
input: ffmpeg::format::input_with_dictionary(
&self.source.as_path(),
options.to_dict(),
)?,
source: self.source,
}),
}
}
}
pub struct Reader {
pub source: Location,
pub input: AvInput,
}
impl Reader {
#[inline]
pub fn new(source: impl Into<Location>) -> Result<Self> {
ReaderBuilder::new(source).build()
}
pub fn read(&mut self, stream_index: usize) -> Result<Packet> {
let mut error_count = 0;
loop {
match self.input.packets().next() {
Some((stream, packet)) => {
if stream.index() == stream_index {
return Ok(Packet::new(packet, stream.time_base()));
}
}
None => {
error_count += 1;
if error_count > 3 {
return Err(Error::ReadExhausted);
}
}
}
}
}
pub fn stream_info(&self, stream_index: usize) -> Result<StreamInfo> {
StreamInfo::from_reader(self, stream_index)
}
pub fn seek(&mut self, timestamp_milliseconds: i64) -> Result<()> {
const CONVERSION_FACTOR: i64 = (AV_TIME_BASE_Q.den / 1000) as i64;
const LEEWAY: i64 = AV_TIME_BASE_Q.den as i64;
let timestamp = CONVERSION_FACTOR * timestamp_milliseconds;
let range = timestamp - LEEWAY..timestamp + LEEWAY;
self.input
.seek(timestamp, range)
.map_err(Error::BackendError)
}
pub fn seek_to_frame(&mut self, frame_number: i64) -> Result<()> {
unsafe {
match av_seek_frame(self.input.as_mut_ptr(), -1, frame_number, 0) {
0 => Ok(()),
e => Err(Error::BackendError(AvError::from(e))),
}
}
}
pub fn seek_to_start(&mut self) -> Result<()> {
self.input.seek(i64::MIN, ..).map_err(Error::BackendError)
}
pub fn best_video_stream_index(&self) -> Result<usize> {
Ok(self
.input
.streams()
.best(AvMediaType::Video)
.ok_or(AvError::StreamNotFound)?
.index())
}
}
unsafe impl Send for Reader {}
unsafe impl Sync for Reader {}
pub trait Write: private::Write + private::Output {}
pub struct WriterBuilder<'a> {
destination: Location,
format: Option<&'a str>,
options: Option<&'a Options>,
}
impl<'a> WriterBuilder<'a> {
pub fn new(destination: impl Into<Location>) -> Self {
Self {
destination: destination.into(),
format: None,
options: None,
}
}
pub fn with_format(mut self, format: &'a str) -> Self {
self.format = Some(format);
self
}
pub fn with_options(mut self, options: &'a Options) -> Self {
self.options = Some(options);
self
}
pub fn build(self) -> Result<Writer> {
match (self.format, self.options) {
(None, None) => Ok(Writer {
output: ffmpeg::format::output(&self.destination.as_path())?,
destination: self.destination,
}),
(Some(format), None) => Ok(Writer {
output: ffmpeg::format::output_as(&self.destination.as_path(), format)?,
destination: self.destination,
}),
(None, Some(options)) => Ok(Writer {
output: ffmpeg::format::output_with(
&self.destination.as_path(),
options.to_dict(),
)?,
destination: self.destination,
}),
(Some(format), Some(options)) => Ok(Writer {
output: ffmpeg::format::output_as_with(
&self.destination.as_path(),
format,
options.to_dict(),
)?,
destination: self.destination,
}),
}
}
}
pub struct Writer {
pub destination: Location,
pub(crate) output: AvOutput,
}
impl Writer {
#[inline]
pub fn new(destination: impl Into<Location>) -> Result<Self> {
WriterBuilder::new(destination).build()
}
}
impl Write for Writer {}
unsafe impl Send for Writer {}
unsafe impl Sync for Writer {}
pub type Buf = Vec<u8>;
pub type Bufs = Vec<Buf>;
pub struct BufWriterBuilder<'a> {
format: &'a str,
options: Option<&'a Options>,
}
impl<'a> BufWriterBuilder<'a> {
pub fn new(format: &'a str) -> Self {
Self {
format,
options: None,
}
}
pub fn with_options(mut self, options: &'a Options) -> Self {
self.options = Some(options);
self
}
pub fn build(self) -> Result<BufWriter> {
Ok(BufWriter {
output: ffi::output_raw(self.format)?,
options: self.options.cloned().unwrap_or_default(),
})
}
}
pub struct BufWriter {
pub(crate) output: AvOutput,
options: Options,
}
impl BufWriter {
#[inline]
pub fn new(format: &str) -> Result<Self> {
BufWriterBuilder::new(format).build()
}
fn begin_write(&mut self) {
ffi::output_raw_buf_start(&mut self.output);
}
fn end_write(&mut self) -> Buf {
ffi::output_raw_buf_end(&mut self.output)
}
}
impl Write for BufWriter {}
impl Drop for BufWriter {
fn drop(&mut self) {
let _ = ffi::output_raw_buf_end(&mut self.output);
}
}
unsafe impl Send for BufWriter {}
unsafe impl Sync for BufWriter {}
pub struct PacketizedBufWriterBuilder<'a> {
format: &'a str,
options: Option<&'a Options>,
}
impl<'a> PacketizedBufWriterBuilder<'a> {
pub fn new(format: &'a str) -> Self {
Self {
format,
options: None,
}
}
pub fn with_options(mut self, options: &'a Options) -> Self {
self.options = Some(options);
self
}
pub fn build(self) -> Result<PacketizedBufWriter> {
Ok(PacketizedBufWriter {
output: ffi::output_raw(self.format)?,
options: self.options.cloned().unwrap_or_default(),
buffers: Vec::new(),
})
}
}
pub struct PacketizedBufWriter {
pub(crate) output: AvOutput,
options: Options,
buffers: Bufs,
}
impl PacketizedBufWriter {
const PACKET_SIZE: usize = 1024;
#[inline]
pub fn new(format: &str) -> Result<Self> {
PacketizedBufWriterBuilder::new(format).build()
}
fn begin_write(&mut self) {
ffi::output_raw_packetized_buf_start(
&mut self.output,
&mut self.buffers,
Self::PACKET_SIZE,
);
}
fn end_write(&mut self) {
ffi::output_raw_packetized_buf_end(&mut self.output);
}
#[inline]
fn take_buffers(&mut self) -> Bufs {
std::mem::take(&mut self.buffers)
}
}
impl Write for PacketizedBufWriter {}
unsafe impl Send for PacketizedBufWriter {}
unsafe impl Sync for PacketizedBufWriter {}
pub(crate) mod private {
use super::*;
type Result<T> = std::result::Result<T, Error>;
pub trait Write {
type Out;
fn write_header(&mut self) -> Result<Self::Out>;
fn write(&mut self, packet: &mut AvPacket) -> Result<Self::Out>;
fn write_interleaved(&mut self, packet: &mut AvPacket) -> Result<Self::Out>;
fn write_trailer(&mut self) -> Result<Self::Out>;
}
impl Write for Writer {
type Out = ();
fn write_header(&mut self) -> Result<()> {
Ok(self.output.write_header()?)
}
fn write(&mut self, packet: &mut AvPacket) -> Result<()> {
packet.write(&mut self.output)?;
Ok(())
}
fn write_interleaved(&mut self, packet: &mut AvPacket) -> Result<()> {
packet.write_interleaved(&mut self.output)?;
Ok(())
}
fn write_trailer(&mut self) -> Result<()> {
Ok(self.output.write_trailer()?)
}
}
impl Write for BufWriter {
type Out = Buf;
fn write_header(&mut self) -> Result<Buf> {
self.begin_write();
self.output.write_header_with(self.options.to_dict())?;
Ok(self.end_write())
}
fn write(&mut self, packet: &mut AvPacket) -> Result<Buf> {
self.begin_write();
packet.write(&mut self.output)?;
ffi::flush_output(&mut self.output)?;
Ok(self.end_write())
}
fn write_interleaved(&mut self, packet: &mut AvPacket) -> Result<Buf> {
self.begin_write();
packet.write_interleaved(&mut self.output)?;
ffi::flush_output(&mut self.output)?;
Ok(self.end_write())
}
fn write_trailer(&mut self) -> Result<Buf> {
self.begin_write();
self.output.write_trailer()?;
Ok(self.end_write())
}
}
impl Write for PacketizedBufWriter {
type Out = Bufs;
fn write_header(&mut self) -> Result<Bufs> {
self.begin_write();
self.output.write_header_with(self.options.to_dict())?;
self.end_write();
Ok(self.take_buffers())
}
fn write(&mut self, packet: &mut AvPacket) -> Result<Bufs> {
self.begin_write();
packet.write(&mut self.output)?;
ffi::flush_output(&mut self.output)?;
self.end_write();
Ok(self.take_buffers())
}
fn write_interleaved(&mut self, packet: &mut AvPacket) -> Result<Bufs> {
self.begin_write();
packet.write_interleaved(&mut self.output)?;
ffi::flush_output(&mut self.output)?;
self.end_write();
Ok(self.take_buffers())
}
fn write_trailer(&mut self) -> Result<Bufs> {
self.begin_write();
self.output.write_trailer()?;
self.end_write();
Ok(self.take_buffers())
}
}
pub trait Output {
fn output(&self) -> &AvOutput;
fn output_mut(&mut self) -> &mut AvOutput;
}
impl Output for Writer {
fn output(&self) -> &AvOutput {
&self.output
}
fn output_mut(&mut self) -> &mut AvOutput {
&mut self.output
}
}
impl Output for BufWriter {
fn output(&self) -> &AvOutput {
&self.output
}
fn output_mut(&mut self) -> &mut AvOutput {
&mut self.output
}
}
impl Output for PacketizedBufWriter {
fn output(&self) -> &AvOutput {
&self.output
}
fn output_mut(&mut self) -> &mut AvOutput {
&mut self.output
}
}
}