use std::ptr::NonNull;
use crate::ffi::*;
use crate::media;
use crate::utils;
use super::profile::ProfileIter;
use super::{CodecProperties, Id};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CodecDescriptor {
ptr: NonNull<AVCodecDescriptor>,
}
impl CodecDescriptor {
pub unsafe fn from_raw(ptr: *const AVCodecDescriptor) -> Option<Self> {
NonNull::new(ptr as *mut _).map(|ptr| Self { ptr })
}
pub fn as_ptr(self) -> *const AVCodecDescriptor {
self.ptr.as_ptr()
}
pub fn id(self) -> Id {
unsafe { (*self.as_ptr()).id.into() }
}
pub fn kind(self) -> media::Type {
unsafe { (*self.as_ptr()).type_.into() }
}
pub fn name(self) -> &'static str {
unsafe { utils::str_from_c_ptr((*self.as_ptr()).name) }
}
pub fn description(self) -> Option<&'static str> {
unsafe { utils::optional_str_from_c_ptr((*self.as_ptr()).long_name) }
}
pub fn props(self) -> CodecProperties {
unsafe { CodecProperties::from_bits_truncate((*self.as_ptr()).props) }
}
pub fn mime_types(self) -> Option<MimeTypeIter> {
unsafe { MimeTypeIter::from_raw((*self.as_ptr()).mime_types) }
}
pub fn profiles(self) -> Option<ProfileIter> {
unsafe {
if (*self.as_ptr()).profiles.is_null() {
None
} else {
Some(ProfileIter::new(self.id(), (*self.as_ptr()).profiles))
}
}
}
}
pub struct CodecDescriptorIter {
ptr: *const AVCodecDescriptor,
}
impl CodecDescriptorIter {
pub fn new() -> Self {
Self {
ptr: std::ptr::null(),
}
}
}
impl Default for CodecDescriptorIter {
fn default() -> Self {
Self::new()
}
}
impl Iterator for CodecDescriptorIter {
type Item = CodecDescriptor;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let next = avcodec_descriptor_next(self.ptr);
if let Some(desc) = CodecDescriptor::from_raw(next) {
self.ptr = next;
Some(desc)
} else {
None
}
}
}
}
pub struct MimeTypeIter {
ptr: NonNull<*const libc::c_char>,
}
impl MimeTypeIter {
pub unsafe fn from_raw(ptr: *const *const libc::c_char) -> Option<Self> {
NonNull::new(ptr as *mut _).map(|ptr| Self { ptr })
}
}
impl Iterator for MimeTypeIter {
type Item = &'static str;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let next = *self.ptr.as_ptr();
if next.is_null() {
return None;
}
self.ptr = self.ptr.add(1);
Some(utils::str_from_c_ptr(next))
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::decoder::find;
#[test]
fn descriptor() {
let targa = find(Id::TARGA).expect("can find targa decoder");
let desc = targa.descriptor().expect("targa has descriptor");
assert_eq!(desc.id(), Id::TARGA);
assert_eq!(desc.kind(), media::Type::Video);
assert_eq!(desc.name(), "targa");
assert!(matches!(
desc.description(),
None | Some("Truevision Targa image")
));
let props = desc.props();
assert!(
props.contains(CodecProperties::INTRA_ONLY)
&& props.contains(CodecProperties::LOSSLESS)
);
let mut mime_types = desc.mime_types().expect("has mime types");
assert_eq!(mime_types.next(), Some("image/x-targa"));
assert_eq!(mime_types.next(), Some("image/x-tga"));
assert_eq!(mime_types.next(), None);
}
}