pub trait FfmpegCarrier:
Sealed
+ Copy
+ Clone
+ Debug
+ 'static {
type Buffer: AsRef<[u8]> + Clone + Send + 'static;
}Expand description
How a lane turns FFmpeg’s bytes into a carrier.
Sealed, and almost empty by design. Naming a lane, bounding on one, and asking what it carries are public; performing a capture is not. Every operation lives on a private trait that is not a supertrait of this one — see the module docs for why that distinction is the whole of the wall.
What a downstream crate can do — name a lane, hold the types parameterized by one, be generic over it, and drive either:
use mediadecode_ffmpeg::{FfmpegBuffer, FfmpegBytes, FfmpegCarrier, Owned, View};
// Name what a lane carries, and be generic over the lane.
fn carried<C: FfmpegCarrier>(buffer: &C::Buffer) -> usize {
buffer.as_ref().len()
}
let _: fn(&FfmpegBytes) -> usize = carried::<Owned>;
let _: fn(&FfmpegBuffer) -> usize = carried::<View>;Holding a lane-parameterized type generically — the public structs carry only this bound, so a consumer’s own generic code can pass them around:
use mediadecode::demuxer::TrackInfo;
use mediadecode_ffmpeg::{
CarrierAudioStreamDecoder, CarrierDemuxer, CarrierVideoStreamDecoder, Ffmpeg,
FfmpegCarrier, Owned, View,
};
fn tracks_of<C: FfmpegCarrier>(demuxer: &CarrierDemuxer<C>) -> usize {
// A field read is not an operation on the lane, so this is
// exactly as generic as it looks.
core::mem::size_of_val(demuxer)
}
fn hold<C: FfmpegCarrier>(
_demuxer: &CarrierDemuxer<C>,
_audio: &CarrierAudioStreamDecoder<C>,
_video: &CarrierVideoStreamDecoder<C>,
) {
}
let _: fn(&CarrierDemuxer<View>) -> usize = tracks_of::<View>;
let _: fn(&CarrierDemuxer<Owned>) -> usize = tracks_of::<Owned>;
let _ = hold::<View>;
let _ = hold::<Owned>;
let _: fn() -> Vec<TrackInfo<Ffmpeg>> = || Vec::new();And calling at either concrete lane, through the aliases or through
the Carrier* names directly:
use mediadecode::demuxer::Demuxer;
use mediadecode_ffmpeg::{
CarrierDemuxer, FfmpegDemuxer, FfmpegOwnedDemuxer, Owned, View,
};
let mut viewed = FfmpegDemuxer::open("clip.mkv")?;
let mut owned = CarrierDemuxer::<Owned>::open("clip.mkv")?;
let _ = viewed.tracks().len();
let _ = owned.next_packet()?;
let _: fn(&std::path::Path) -> _ = CarrierDemuxer::<View>::open::<std::path::Path>;
let _: fn(&std::path::Path) -> _ = FfmpegOwnedDemuxer::open::<std::path::Path>;What no bound reaches is the operations — see below. Being
generic over the lane and driving it are different asks: the
second needs the operations, so a consumer writes lane-generic
helpers over C::Buffer and instantiates the doors at the two
concrete lanes. That is the trade the wall costs, and it is
deliberate.
What it cannot, and must not be able to: every one of these takes an
extent, a geometry or a provenance claim that only this crate is in
a position to establish. from_rows is the sharpest — it is
safe, and a caller who could reach it could ask for sixty-four
bytes out of a one-byte row.
use mediadecode_ffmpeg::FfmpegCarrier;
fn downstream<C: FfmpegCarrier>() -> C::Buffer {
C::empty()
}use mediadecode_ffmpeg::FfmpegCarrier;
fn downstream<C: FfmpegCarrier>(row: &[u8]) -> Option<C::Buffer> {
C::from_rows(1, 64, |_| row)
}use mediadecode_ffmpeg::FfmpegCarrier;
unsafe fn downstream<C: FfmpegCarrier>(
buf: *mut ffmpeg_next::ffi::AVBufferRef,
) -> Option<C::Buffer> {
unsafe { C::capture(buf, 0, 64) }
}use mediadecode_ffmpeg::FfmpegCarrier;
unsafe fn downstream<C: FfmpegCarrier>(
buf: *mut ffmpeg_next::ffi::AVBufferRef,
) -> Option<C::Buffer> {
// The provenance claim: minting this downstream would let a frame
// plane pass itself off as a padded packet payload.
unsafe { C::capture_packet_payload(buf, 0, 64) }
}use mediadecode_ffmpeg::FfmpegCarrier;
unsafe fn downstream<C: FfmpegCarrier>(buf: *mut ffmpeg_next::ffi::AVBufferRef) {
let reserved = unsafe { C::reserve(buf, 0, 64) };
}use mediadecode_ffmpeg::FfmpegCarrier;
unsafe fn downstream<C: FfmpegCarrier>(reserved: ()) -> C::Buffer {
unsafe { C::commit(reserved, 64) }
}The generic bodies behind the per-lane faces are equally out of reach. They carry the operations’ bound, so reaching one at a concrete lane would be a way around the wall that never names it:
use mediadecode_ffmpeg::{CarrierAudioStreamDecoder, DecoderLimits, Owned};
fn downstream(parameters: ffmpeg_next::codec::Parameters) {
let _ = CarrierAudioStreamDecoder::<Owned>::open_impl(
parameters,
mediadecode::Timebase::default(),
DecoderLimits::default(),
);
}use mediadecode_ffmpeg::{CarrierDemuxer, View};
fn downstream() {
let _ = CarrierDemuxer::<View>::open_impl("clip.mkv");
}Required Associated Types§
Sourcetype Buffer: AsRef<[u8]> + Clone + Send + 'static
type Buffer: AsRef<[u8]> + Clone + Send + 'static
The carrier this lane produces.
Send but not necessarily Sync: the view lane is Send-only,
and requiring Sync here would have closed the seam to it.
A type, and the only thing on this trait — naming
<View as FfmpegCarrier>::Buffer tells a consumer what a lane
hands them, and tells them nothing they could misuse. Everything
that acts is on the private ops trait.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".