Skip to main content

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}