|
|
|
use crate::av::as_ptr::AsMutPtr;
|
|
|
|
use crate::av::frame::Frame;
|
|
|
|
use crate::av::packet::Packet;
|
|
|
|
use crate::av::stream::Stream;
|
|
|
|
use crate::av::xcoder::{process_return, XCoder};
|
|
|
|
use crate::av::{encoder_from_name, verify_response};
|
|
|
|
use crate::av_err2str;
|
|
|
|
use ffmpeg_sys_next::{
|
|
|
|
avcodec_free_context, avcodec_parameters_from_context, avcodec_receive_packet,
|
|
|
|
avcodec_send_frame, AVCodecContext,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub struct Encoder(pub *mut AVCodecContext);
|
|
|
|
|
|
|
|
impl Encoder {
|
|
|
|
pub fn send_video_frame(&self, frame: &Frame) -> Result<(), String> {
|
|
|
|
if frame.width() != self.width()
|
|
|
|
|| frame.height() != self.height()
|
|
|
|
|| frame.pixel_format() != self.pixel_format()
|
|
|
|
{
|
|
|
|
return Err(format!(
|
|
|
|
"Frame and encoder data differ (frame: {}x{} {:?}, encoder: {}x{} {:?})",
|
|
|
|
frame.width(),
|
|
|
|
frame.height(),
|
|
|
|
frame.pixel_format(),
|
|
|
|
self.width(),
|
|
|
|
self.height(),
|
|
|
|
self.pixel_format()
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
self.send_frame(frame)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn send_audio_frame(&self, frame: &Frame) -> Result<(), String> {
|
|
|
|
// if frame.sample_format() != self.sample_format() {
|
|
|
|
// return Err(format!(
|
|
|
|
// "Frame and encoder data differ (frame: {:?}, encoder: {:?})",
|
|
|
|
// frame.sample_format(),
|
|
|
|
// self.sample_format()
|
|
|
|
// ));
|
|
|
|
// }
|
|
|
|
self.send_frame(frame)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn send_frame(&self, frame: &Frame) -> Result<(), String> {
|
|
|
|
verify_response("Failed sending frame to encoder", unsafe {
|
|
|
|
avcodec_send_frame(self.0, frame.as_mut_ptr())
|
|
|
|
})
|
|
|
|
.and(Ok(()))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn read_packet(&self) -> Result<Option<Packet>, String> {
|
|
|
|
let packet = Packet::alloc();
|
|
|
|
let resp = unsafe { avcodec_receive_packet(self.as_mut_ptr(), packet.as_mut_ptr()) };
|
|
|
|
|
|
|
|
if !process_return("Failed to read packet from encoder", resp)? {
|
|
|
|
Ok(None)
|
|
|
|
} else {
|
|
|
|
Ok(Some(packet))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl XCoder for Encoder {
|
|
|
|
fn from_name(name: &str) -> Option<Self> {
|
|
|
|
encoder_from_name(name).map(|codec| Encoder(codec))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_mut_ptr(&self) -> *mut AVCodecContext {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn configure(&self, stream: &Stream) -> Result<(), String> {
|
|
|
|
let resp =
|
|
|
|
unsafe { avcodec_parameters_from_context((*stream.0).codecpar, self.as_mut_ptr()) };
|
|
|
|
|
|
|
|
if resp < 0 {
|
|
|
|
return Err(format!(
|
|
|
|
"Failed configuring decoder from stream (code {}: {})",
|
|
|
|
resp,
|
|
|
|
av_err2str(resp)
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Encoder {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe { avcodec_free_context(&mut self.as_mut_ptr()) }
|
|
|
|
}
|
|
|
|
}
|