1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at https://mozilla.org/MPL/2.0/.
4#
5# This file incorporates work covered by the following copyright and
6# permission notice:
7#
8# Copyright (c) Jeremy Lainé.
9# All rights reserved.
10#
11# Redistribution and use in source and binary forms, with or without
12# modification, are permitted provided that the following conditions are met:
13#
14# * Redistributions of source code must retain the above copyright notice,
15# this list of conditions and the following disclaimer.
16# * Redistributions in binary form must reproduce the above copyright notice,
17# this list of conditions and the following disclaimer in the documentation
18# and/or other materials provided with the distribution.
19# * Neither the name of aiortc nor the names of its contributors may
20# be used to endorse or promote products derived from this software without
21# specific prior written permission.
22#
23# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34from abc import ABCMeta, abstractmethod
35from fractions import Fraction
36from typing import Any, Optional
37
38
39class EncodedPacket:
40 """A pre-encoded media sample on the WebRTC send path: the encoder's output
41 buffer with its presentation timestamp and clock.
42
43 It is what pixelflux/pcmflux hand the packers, replacing `av.Packet` as the
44 passthrough container so packing pulls in no libav wrapper and allocates no
45 per-frame FFmpeg object. `data` is any buffer-protocol object (the encoder's
46 own memory), referenced and never copied; packers walk it through
47 `memoryview(packet.data)` and materialize bytes only for the RTP payloads
48 they emit. Keeping the whole-frame copy out of the path both cuts latency
49 and frees the GIL that a `bytes(frame)` copy would hold for the memcpy.
50 `keyframe` says whether the sample decodes on its own, as the encoder
51 reported it; audio samples always do. `timing` is a video frame's capture,
52 encode-start, and encode-end instants in CLOCK_MONOTONIC nanoseconds as the
53 capture library stamped them, or None where it did not. `dependency` is a
54 video frame's own id and the id of the frame it predicts from (None for a
55 frame predicting from nothing), where the encoder tracks its references
56 and can be told to leave a lost frame out of them; None where it cannot.
57 `codec` is the MIME type of the codec a video frame was coded with, as its
58 capture names it, or None where the source does not say. `anchor` says a
59 video delta frame is a long-term reference predicting from a frame every
60 peer holds, which every peer can decode.
61 """
62
63 __slots__ = ("data", "pts", "dts", "time_base", "keyframe", "timing", "dependency", "codec", "anchor")
64
65 def __init__(self, data: Any, pts: Optional[int] = None,
66 time_base: Optional[Fraction] = None, keyframe: bool = True,
67 timing: Optional[tuple] = None,
68 dependency: Optional[tuple] = None,
69 codec: Optional[str] = None, anchor: bool = False) -> None:
70 self.data = data
71 self.pts = pts
72 self.dts = pts
73 self.time_base = time_base
74 self.keyframe = keyframe
75 self.timing = timing
76 self.dependency = dependency
77 self.codec = codec
78 self.anchor = anchor
79
80 def __len__(self) -> int:
81 return len(self.data)
82
83
84class Decoder:
85 """Receive-codec marker. Decoding of the browser uplink is done by pcmflux
86 (audio) and pixelflux (video), which the encoded frames are routed to, so a
87 registry decoder carries only the codec's identity, no libav decode."""
88
89
90class Encoder(metaclass=ABCMeta):
91 """Packs frames a pixelflux/pcmflux encoder has already produced into RTP
92 payloads. Encoding itself lives in those libraries, not here."""
93
94 @abstractmethod
95 def pack(self, packet: EncodedPacket) -> tuple[list[bytes], int, bool]:
96 """The RTP payloads of one frame, its RTP timestamp, and whether the
97 frame is a key frame (read from the bitstream; always False for audio)."""
98 pass # pragma: no cover