1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//! Borrowed handle to a static FFmpeg `AVCodec`.
//!
//! [`Codec`] wraps a `*const AVCodec` returned by a finder such as
//! [`find_decoder`](Codec::find_decoder). FFmpeg codecs are static singletons
//! owned by the library, so this is a `Copy` borrowed handle with no `Drop`; it
//! replaces the raw `*const AVCodec` in the safe API.
use std::ffi::CString;
use std::ptr::NonNull;
use crate::{AVCodec, AVCodecID};
/// A borrowed handle to a static FFmpeg codec.
#[derive(Clone, Copy, Debug)]
pub struct Codec {
ptr: NonNull<AVCodec>,
}
impl Codec {
/// Finds a decoder by codec id, returning `None` when none is registered.
///
/// This is a pure table lookup with no precondition, so it is a safe fn.
#[must_use]
pub fn find_decoder(codec_id: AVCodecID) -> Option<Self> {
// SAFETY: `find_decoder` is a pure table lookup that dereferences no
// caller pointer; it returns a valid static codec pointer or `None`.
let ptr = unsafe { crate::avcodec::find_decoder(codec_id) }?;
NonNull::new(ptr.cast_mut()).map(|ptr| Self { ptr })
}
/// Finds an encoder by codec id, returning `None` when none is registered.
///
/// A pure table lookup with no precondition, so it is a safe fn.
#[must_use]
pub fn find_encoder(codec_id: AVCodecID) -> Option<Self> {
// SAFETY: `find_encoder` is a pure table lookup that dereferences no
// caller pointer; it returns a valid static codec pointer or `None`.
let ptr = unsafe { crate::avcodec::find_encoder(codec_id) }?;
NonNull::new(ptr.cast_mut()).map(|ptr| Self { ptr })
}
/// Finds an encoder by name (e.g. `"libx264"`), returning `None` when none is
/// registered or `name` contains an interior null byte.
///
/// A pure table lookup with no precondition, so it is a safe fn.
#[must_use]
pub fn find_encoder_by_name(name: &str) -> Option<Self> {
let c_name = CString::new(name).ok()?;
// SAFETY: `c_name` is a valid NUL-terminated C string that outlives the
// call; `find_encoder_by_name` reads only that string and returns a
// valid static codec pointer or `None`.
let ptr = unsafe { crate::avcodec::find_encoder_by_name(c_name.as_ptr()) }?;
NonNull::new(ptr.cast_mut()).map(|ptr| Self { ptr })
}
/// Returns the underlying codec pointer for FFI calls.
///
/// [`Codec`] is a lightweight borrowed handle to a static FFmpeg codec, not a
/// sealed owned resource, so it deliberately exposes its raw pointer for
/// consumers that read codec-descriptor fields (`sample_fmts`, `capabilities`,
/// …) the safe API does not (yet) mirror.
// seal-allow-raw: Codec is a borrowed static handle, intentionally out of the
// #1506 owned-type seal (see #1566); consumers read AVCodec descriptor fields
// through this pointer.
#[must_use]
pub const fn as_ptr(&self) -> *const AVCodec {
self.ptr.as_ptr()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn find_decoder_should_return_none_for_codec_none() {
// `AV_CODEC_ID_NONE` is the sentinel with no registered decoder, so the
// lookup is deterministically empty regardless of the linked FFmpeg build.
let result = Codec::find_decoder(crate::AVCodecID_AV_CODEC_ID_NONE);
assert!(result.is_none());
}
#[test]
fn find_encoder_should_return_none_for_codec_none() {
// `AV_CODEC_ID_NONE` has no registered encoder, so the lookup is
// deterministically empty regardless of the linked FFmpeg build.
let result = Codec::find_encoder(crate::AVCodecID_AV_CODEC_ID_NONE);
assert!(result.is_none());
}
}