Skip to main content

mediadecode_ffmpeg/
adapter.rs

1//! `Ffmpeg` adapter — implements [`mediadecode::VideoAdapter`],
2//! [`mediadecode::AudioAdapter`], [`mediadecode::SubtitleAdapter`],
3//! [`mediadecode::adapter::ImageAdapter`] and
4//! [`mediadecode::demuxer::DemuxAdapter`] for this crate.
5//!
6//! The adapter is a zero-sized type whose sole purpose is to bind the
7//! associated types together so the rest of the API (Packet / Frame /
8//! Decoder) reads cleanly: `VideoPacket<Ffmpeg, FfmpegBytes>` etc.
9//!
10//! `DemuxAdapter` bundles the other three, and `Ffmpeg` fills all four
11//! seats with itself — the demux tier's `CodecId` bound (one
12//! codec-identifier namespace across a container's whole track table) is
13//! trivially satisfied when every family already binds
14//! [`crate::CodecId`].
15
16use mediadecode::{
17  PixelFormat,
18  adapter::{AudioAdapter, ImageAdapter, SubtitleAdapter, VideoAdapter},
19  demuxer::DemuxAdapter,
20};
21use mediaframe::audio::ChannelLayoutDescription;
22use smol_str::SmolStr;
23
24use crate::{
25  codec_id::CodecId,
26  extras::{
27    AttachmentPacketExtra, AudioFrameExtra, AudioPacketExtra, DataPacketExtra, ImageFrameExtra,
28    SubtitleFrameExtra, SubtitlePacketExtra, TrackExtra, VideoFrameExtra, VideoPacketExtra,
29  },
30  sample_format::SampleFormat,
31};
32
33/// Zero-sized type carrying the FFmpeg adapter's vocabulary.
34///
35/// Used as the `A` parameter on `mediadecode::VideoPacket<A, B>` /
36/// `Frame<A, B>` (and audio / subtitle counterparts) when this crate's
37/// decoders are in play. Construction is `Ffmpeg` (unit struct);
38/// nothing about the adapter is stateful.
39#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
40pub struct Ffmpeg;
41
42impl VideoAdapter for Ffmpeg {
43  type CodecId = CodecId;
44  type PixelFormat = PixelFormat;
45  type PacketExtra = VideoPacketExtra;
46  type FrameExtra = VideoFrameExtra;
47}
48
49impl AudioAdapter for Ffmpeg {
50  type CodecId = CodecId;
51  type SampleFormat = SampleFormat;
52  type ChannelLayout = ChannelLayoutDescription;
53  type PacketExtra = AudioPacketExtra;
54  type FrameExtra = AudioFrameExtra;
55}
56
57impl SubtitleAdapter for Ffmpeg {
58  type CodecId = CodecId;
59  type PacketExtra = SubtitlePacketExtra;
60  type FrameExtra = SubtitleFrameExtra;
61}
62
63impl ImageAdapter for Ffmpeg {
64  type CodecId = CodecId;
65  type PixelFormat = PixelFormat;
66  // The packet an image decoder is fed is the attachment packet the
67  // demuxer hands out — one type, both seats, so a cover-art payload
68  // goes straight from `next_packet` into `decode` with nothing to
69  // convert in between.
70  type PacketExtra = AttachmentPacketExtra;
71  type FrameExtra = ImageFrameExtra;
72}
73
74impl DemuxAdapter for Ffmpeg {
75  type CodecId = CodecId;
76  type Video = Ffmpeg;
77  type Audio = Ffmpeg;
78  type Subtitle = Ffmpeg;
79  type DataExtra = DataPacketExtra;
80  type AttachmentExtra = AttachmentPacketExtra;
81  type TrackExtra = TrackExtra;
82  // `AVStream.metadata` hands out borrowed `&str` that dies with the
83  // format context, so a track row has to own its identity strings.
84  // `SmolStr` stores a filename or a MIME type inline — both are short
85  // — which is why the rest of this crate's FFI text handling already
86  // uses it.
87  type Text = SmolStr;
88}
89
90#[cfg(test)]
91mod tests {
92  use super::*;
93
94  /// Compile-time proof that the three trait impls' associated types
95  /// resolve correctly when the `Ffmpeg` adapter parameterizes
96  /// mediadecode's generic types.
97  #[test]
98  fn adapter_parameterizes_mediadecode_types() {
99    use crate::FfmpegBytes;
100
101    use mediadecode::{
102      adapter::{AudioAdapter, SubtitleAdapter, VideoAdapter},
103      packet::{AudioPacket, SubtitlePacket, VideoPacket},
104    };
105
106    fn _video_packet_resolves(
107      _: &VideoPacket<Ffmpeg, FfmpegBytes>,
108      _: <Ffmpeg as VideoAdapter>::CodecId,
109      _: <Ffmpeg as VideoAdapter>::PixelFormat,
110      _: &<Ffmpeg as VideoAdapter>::PacketExtra,
111      _: &<Ffmpeg as VideoAdapter>::FrameExtra,
112    ) {
113    }
114
115    fn _audio_packet_resolves(
116      _: &AudioPacket<Ffmpeg, FfmpegBytes>,
117      _: <Ffmpeg as AudioAdapter>::CodecId,
118      _: <Ffmpeg as AudioAdapter>::SampleFormat,
119      _: &<Ffmpeg as AudioAdapter>::ChannelLayout,
120      _: &<Ffmpeg as AudioAdapter>::PacketExtra,
121      _: &<Ffmpeg as AudioAdapter>::FrameExtra,
122    ) {
123    }
124
125    fn _subtitle_packet_resolves(
126      _: &SubtitlePacket<Ffmpeg, FfmpegBytes>,
127      _: <Ffmpeg as SubtitleAdapter>::CodecId,
128      _: &<Ffmpeg as SubtitleAdapter>::PacketExtra,
129      _: &<Ffmpeg as SubtitleAdapter>::FrameExtra,
130    ) {
131    }
132  }
133
134  #[test]
135  fn ffmpeg_is_zero_sized() {
136    use core::mem::size_of;
137    assert_eq!(size_of::<Ffmpeg>(), 0);
138  }
139}