arcly_stream/transcode.rs
1//! Transcoding & adaptive-bitrate contracts.
2//!
3//! The actual codec work needs native encoders (FFmpeg/GStreamer, NVENC/QSV via
4//! [`HwAccelBackend`](crate::HwAccelBackend)) and is intentionally **not** shipped
5//! here. This module defines the seams: a [`Transcoder`] turns one input frame
6//! into zero or more output frames, and a [`RenditionSpec`] describes one rung
7//! of an ABR ladder. A pipeline drives a [`Transcoder`] from a
8//! [`Subscription`](crate::Subscription) and republishes each output rendition.
9
10use crate::frame::CodecId;
11use crate::{MediaFrame, Result};
12use async_trait::async_trait;
13
14/// One target rendition in an adaptive-bitrate ladder.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct RenditionSpec {
17 /// Human label / variant id (e.g. `"720p"`).
18 pub name: String,
19 /// Target encoded width in pixels (0 = keep source).
20 pub width: u32,
21 /// Target encoded height in pixels (0 = keep source).
22 pub height: u32,
23 /// Target video bitrate in bits/sec.
24 pub video_bitrate_bps: u64,
25 /// Output video codec.
26 pub codec: CodecId,
27}
28
29impl RenditionSpec {
30 /// A 16:9 rendition of the given height at `video_bitrate_bps`.
31 pub fn new(
32 name: impl Into<String>,
33 height: u32,
34 video_bitrate_bps: u64,
35 codec: CodecId,
36 ) -> Self {
37 Self {
38 name: name.into(),
39 width: height * 16 / 9,
40 height,
41 video_bitrate_bps,
42 codec,
43 }
44 }
45}
46
47/// Transforms frames: decode/scale/encode, packetize, or fan into renditions.
48///
49/// Returning a `Vec` lets one input frame yield several outputs (e.g. one per
50/// ABR rung) or none (e.g. while priming an encoder).
51#[async_trait]
52pub trait Transcoder: Send + Sync {
53 /// Stable identifier (e.g. `"nvenc-abr"`).
54 fn id(&self) -> &str;
55
56 /// The renditions this transcoder emits.
57 fn renditions(&self) -> &[RenditionSpec];
58
59 /// Process one input frame into zero or more output frames.
60 async fn transcode(&mut self, frame: MediaFrame) -> Result<Vec<MediaFrame>>;
61
62 /// Flush any buffered output at end-of-stream.
63 async fn flush(&mut self) -> Result<Vec<MediaFrame>> {
64 Ok(Vec::new())
65 }
66}