Skip to content

Add generic ActionType to Codec struct #105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion examples/remux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ fn main() {
stream_mapping[ist_index] = ost_index;
ist_time_bases[ist_index] = ist.time_base();
ost_index += 1;
let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap();
let mut ost = octx
.add_stream(encoder::find(codec::Id::None).expect("ID_NONE encoder exists"))
.unwrap();
ost.set_parameters(ist.parameters());
// We need to set codec_tag to 0 lest we run into incompatible codec tag
// issues when muxing into a different container format. Unfortunately
Expand Down
8 changes: 5 additions & 3 deletions examples/transcode-x264.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ impl Transcoder {
.decoder()
.video()?;

let codec = encoder::find(codec::Id::H264);
let codec = encoder::find(codec::Id::H264).ok_or(ffmpeg::Error::EncoderNotFound)?;
let mut ost = octx.add_stream(codec)?;

let mut encoder = codec::context::Context::new_with_codec(codec.unwrap())
let mut encoder = codec::context::Context::new_with_codec(codec)
.encoder()
.video()?;
ost.set_parameters(Parameters::from(&encoder));
Expand Down Expand Up @@ -221,7 +221,9 @@ fn main() {
);
} else {
// Set up for stream copy for non-video stream.
let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap();
let mut ost = octx
.add_stream(encoder::find(codec::Id::None).expect("ID_NONE encoder exists"))
.unwrap();
ost.set_parameters(ist.parameters());
// We need to set codec_tag to 0 lest we run into incompatible codec tag
// issues when muxing into a different container format. Unfortunately
Expand Down
180 changes: 99 additions & 81 deletions src/codec/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use super::descriptor::{CodecDescriptor, CodecDescriptorIter};
use super::profile::ProfileIter;
use super::{Capabilities, Id};
use crate::ffi::*;
use crate::AsPtr;
use crate::{media, utils};

#[cfg(feature = "ffmpeg_7_1")]
Expand All @@ -17,18 +18,41 @@ pub fn list_descriptors() -> CodecDescriptorIter {
CodecDescriptorIter::new()
}

pub type Audio = Codec<AudioType>;
pub type Video = Codec<VideoType>;
pub type Data = Codec<DataType>;
pub type Subtitle = Codec<SubtitleType>;
pub type Attachment = Codec<AttachmentType>;
pub type Audio<A> = Codec<A, AudioType>;
pub type Video<A> = Codec<A, VideoType>;
pub type Data<A> = Codec<A, DataType>;
pub type Subtitle<A> = Codec<A, SubtitleType>;
pub type Attachment<A> = Codec<A, AttachmentType>;

pub type Decoder<T> = Codec<DecodingAction, T>;
pub type UnknownDecoder = Codec<DecodingAction, UnknownType>;
pub type AudioDecoder = Codec<DecodingAction, AudioType>;
pub type VideoDecoder = Codec<DecodingAction, VideoType>;
pub type DataDecoder = Codec<DecodingAction, DataType>;
pub type SubtitleDecoder = Codec<DecodingAction, SubtitleType>;
pub type AttachmentDecoder = Codec<DecodingAction, AttachmentType>;

pub type Encoder<T> = Codec<EncodingAction, T>;
pub type UnknownEncoder = Codec<EncodingAction, UnknownType>;
pub type AudioEncoder = Codec<EncodingAction, AudioType>;
pub type VideoEncoder = Codec<EncodingAction, VideoType>;
pub type DataEncoder = Codec<EncodingAction, DataType>;
pub type SubtitleEncoder = Codec<EncodingAction, SubtitleType>;
pub type AttachmentEncoder = Codec<EncodingAction, AttachmentType>;

#[derive(PartialEq, Eq, Copy, Clone)]
pub struct Codec<Type = UnknownType> {
pub struct Codec<Action, Type> {
ptr: NonNull<AVCodec>,
_marker: PhantomData<Type>,
_marker: PhantomData<(Action, Type)>,
}

#[derive(PartialEq, Eq, Copy, Clone)]
pub struct UnknownAction;
#[derive(PartialEq, Eq, Copy, Clone)]
pub struct DecodingAction;
#[derive(PartialEq, Eq, Copy, Clone)]
pub struct EncodingAction;

#[derive(PartialEq, Eq, Copy, Clone)]
pub struct UnknownType;
#[derive(PartialEq, Eq, Copy, Clone)]
Expand All @@ -42,10 +66,10 @@ pub struct SubtitleType;
#[derive(PartialEq, Eq, Copy, Clone)]
pub struct AttachmentType;

unsafe impl<T> Send for Codec<T> {}
unsafe impl<T> Sync for Codec<T> {}
unsafe impl<A, T> Send for Codec<A, T> {}
unsafe impl<A, T> Sync for Codec<A, T> {}

impl Codec<UnknownType> {
impl<A, T> Codec<A, T> {
/// Create a new reference to a codec from a raw pointer.
///
/// Returns `None` if `ptr` is null.
Expand All @@ -59,84 +83,18 @@ impl Codec<UnknownType> {
// Helper function to easily convert to another codec type.
// TODO: Does this need to be unsafe?
/// Ensure that `self.medium()` is correct for `Codec<U>`.
fn as_other_codec<U>(self) -> Codec<U> {
fn as_other_codec<U, B>(&self) -> Codec<U, B> {
Codec {
ptr: self.ptr,
_marker: PhantomData,
}
}

pub fn is_video(&self) -> bool {
self.medium() == media::Type::Video
}

pub fn video(self) -> Option<Video> {
if self.is_video() {
Some(self.as_other_codec())
} else {
None
}
}

pub fn is_audio(&self) -> bool {
self.medium() == media::Type::Audio
}

pub fn audio(self) -> Option<Audio> {
if self.is_audio() {
Some(self.as_other_codec())
} else {
None
}
}

pub fn is_data(&self) -> bool {
self.medium() == media::Type::Data
}

pub fn data(self) -> Option<Data> {
if self.is_data() {
Some(self.as_other_codec())
} else {
None
}
}

pub fn is_subtitle(&self) -> bool {
self.medium() == media::Type::Subtitle
}

pub fn subtitle(self) -> Option<Subtitle> {
if self.is_subtitle() {
Some(self.as_other_codec())
} else {
None
}
}

pub fn is_attachment(&self) -> bool {
self.medium() == media::Type::Attachment
}

pub fn attachment(self) -> Option<Attachment> {
if self.is_attachment() {
Some(self.as_other_codec())
} else {
None
}
}
}

impl<T> Codec<T> {
pub fn as_ptr(&self) -> *const AVCodec {
self.ptr.as_ptr()
}

pub fn is_encoder(&self) -> bool {
pub fn is_encoder(self) -> bool {
unsafe { av_codec_is_encoder(self.as_ptr()) != 0 }
}

pub fn is_decoder(&self) -> bool {
pub fn is_decoder(self) -> bool {
unsafe { av_codec_is_decoder(self.as_ptr()) != 0 }
}

Expand Down Expand Up @@ -182,7 +140,61 @@ impl<T> Codec<T> {
}
}

impl Codec<AudioType> {
impl<A: Copy, T: Copy> Codec<A, T> {
pub fn as_encoder(&self) -> Option<Encoder<T>> {
self.is_encoder().then(|| self.as_other_codec())
}

pub fn as_decoder(&self) -> Option<Decoder<T>> {
self.is_decoder().then(|| self.as_other_codec())
}
}

impl<A> Codec<A, UnknownType> {
pub fn is_video(self) -> bool {
self.medium() == media::Type::Video
}

pub fn is_audio(self) -> bool {
self.medium() == media::Type::Audio
}

pub fn is_data(self) -> bool {
self.medium() == media::Type::Data
}

pub fn is_subtitle(self) -> bool {
self.medium() == media::Type::Subtitle
}

pub fn is_attachment(self) -> bool {
self.medium() == media::Type::Attachment
}
}

impl<A: Copy> Codec<A, UnknownType> {
pub fn video(self) -> Option<Codec<A, VideoType>> {
self.is_video().then(|| self.as_other_codec())
}

pub fn audio(self) -> Option<Codec<A, AudioType>> {
self.is_audio().then(|| self.as_other_codec())
}

pub fn data(self) -> Option<Codec<A, DataType>> {
self.is_data().then(|| self.as_other_codec())
}

pub fn subtitle(self) -> Option<Codec<A, SubtitleType>> {
self.is_subtitle().then(|| self.as_other_codec())
}

pub fn attachment(self) -> Option<Codec<A, AttachmentType>> {
self.is_attachment().then(|| self.as_other_codec())
}
}

impl<A> Codec<A, AudioType> {
/// Checks if the given sample rate is supported by this audio codec.
#[cfg(feature = "ffmpeg_7_1")]
pub fn supports_rate(self, rate: libc::c_int) -> bool {
Expand Down Expand Up @@ -228,7 +240,7 @@ impl Codec<AudioType> {
}
}

impl Codec<VideoType> {
impl<A> Codec<A, VideoType> {
/// Checks if the given frame rate is supported by this video codec.
#[cfg(feature = "ffmpeg_7_1")]
pub fn supports_rate(self, rate: crate::Rational) -> bool {
Expand Down Expand Up @@ -387,3 +399,9 @@ mod ch_layout {
std::mem::zeroed()
}
}

impl<A, T> AsPtr<AVCodec> for Codec<A, T> {
fn as_ptr(&self) -> *const AVCodec {
self.ptr.as_ptr()
}
}
11 changes: 7 additions & 4 deletions src/codec/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use crate::codec::Context;
#[cfg(feature = "ffmpeg_7_1")]
use crate::ffi::*;
#[cfg(feature = "ffmpeg_7_1")]
use crate::AsPtr;
#[cfg(feature = "ffmpeg_7_1")]
use crate::Codec;
#[cfg(feature = "ffmpeg_7_1")]
use crate::Error;
Expand Down Expand Up @@ -66,12 +68,13 @@ where
}

#[cfg(feature = "ffmpeg_7_1")]
fn supported<WrapperType, AVType, CodecType, I>(
codec: Codec<CodecType>,
fn supported<WrapperType, AVType, C, I>(
codec: C,
ctx: Option<&Context>,
cfg: AVCodecConfig,
) -> Result<Supported<I>, Error>
where
C: AsPtr<AVCodec>,
I: TerminatedPtrIter<AVType, WrapperType>,
AVType: Into<WrapperType>,
{
Expand Down Expand Up @@ -157,8 +160,8 @@ macro_rules! impl_config_iter_fn {
/// `avcodec_get_supported_config()`. Consider using one of the convenience methods
/// on the codecs or codec contexts instead.
#[cfg(feature = "ffmpeg_7_1")]
pub fn $fn_name<T>(
codec: Codec<T>,
pub fn $fn_name<A, T>(
codec: Codec<A, T>,
ctx: Option<&Context>,
) -> Result<Supported<$iter>, Error> {
supported(codec, ctx, $codec_cfg)
Expand Down
5 changes: 3 additions & 2 deletions src/codec/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::rc::Rc;
use super::decoder::Decoder;
use super::encoder::Encoder;
use super::{threading, Compliance, Debug, Flags, Id};
use crate::codec::codec::{UnknownAction, UnknownType};
use crate::ffi::*;
use crate::media;
use crate::option;
Expand Down Expand Up @@ -43,7 +44,7 @@ impl Context {
}
}

pub fn new_with_codec(codec: Codec) -> Self {
pub fn new_with_codec<A, T>(codec: Codec<A, T>) -> Self {
unsafe {
Context {
ptr: avcodec_alloc_context3(codec.as_ptr()),
Expand Down Expand Up @@ -71,7 +72,7 @@ impl Context {
Encoder(self)
}

pub fn codec(&self) -> Option<Codec> {
pub fn codec(&self) -> Option<Codec<UnknownAction, UnknownType>> {
unsafe { Codec::from_raw((*self.as_ptr()).codec) }
}

Expand Down
Loading