MediaObjectV3 and MediaFrame stored their compressed access unit as an owned Vec<u8>. The host builds one object/frame per connected client per encoded frame, so every fanout copied the whole payload out of the shared EncodedFrame.data: Arc<[u8]> via .as_ref().to_vec() — N full payload copies per frame for N clients. Both payload fields now hold Arc<[u8]>, and the two constructors take impl Into<Arc<[u8]>>. The host build sites clone the Arc (a refcount bump, zero payload copy); the wire format is unchanged (payload is written as raw bytes with no serde), and the receive paths convert the freshly-read buffer into the Arc exactly once.
- commit
- c8d78469cb8e114f6114b75710769dda07614267
- parent
- 28d94b5185eb47c07c522c7438f1958ad0c8f097
- author
- Dami <dami.etoile@gmail.com>
| M | crates/ | 2 | +- |
| M | crates/ | 2 | +- |
| M | crates/ | 12 | +++++++++--- |
| M | crates/ | 15 | ++++++++++++--- |
@@ -842,7 +842,7 @@ fn media_v3_object_for_encoded(
842842 frame.presentation_timestamp_micros,843843 delivery_timeout_ms,844844 )?;845- MediaObjectV3::new(header, frame.data.as_ref().to_vec()).map_err(Into::into)845+ MediaObjectV3::new(header, frame.data.clone()).map_err(Into::into)846846 }847847 848848 async fn send_media_v3_object(@@ -570,7 +570,7 @@ pub(super) fn media_frame_for_encoded(
570570 frame.presentation_timestamp_micros,571571 flags,572572 )?;573- MediaFrame::new(header, frame.data.as_ref().to_vec()).map_err(Into::into)573+ MediaFrame::new(header, frame.data.clone()).map_err(Into::into)574574 }575575 576576 @@ -1,3 +1,5 @@
1+use std::sync::Arc;2+13 use crate::{24 MAX_MEDIA_PAYLOAD_LEN, MAX_VIDEO_DIMENSION, MAX_VIDEO_PIXELS, PROTOCOL_VERSION, ProtocolError,35 Result,@@ -203,7 +205,10 @@ impl MediaFrameHeader {
203205 204206 pub struct MediaFrame {205207 pub header: MediaFrameHeader,206- pub payload: Vec<u8>,208+ /// The compressed access unit. Held behind an `Arc` so the host can fan the209+ /// same encoded frame out to every connected client without copying the210+ /// payload per connection.211+ pub payload: Arc<[u8]>,207212 }208213 209214 /// Encode one complete application media frame for an object transport such@@ -256,12 +261,13 @@ pub fn decode_media_frame_object(object: &[u8]) -> Result<MediaFrame> {
256261 reason: "object length does not match declared payload",257262 });258263 }259- MediaFrame::new(header, object[MEDIA_HEADER_LEN..].to_vec())264+ MediaFrame::new(header, &object[MEDIA_HEADER_LEN..])260265 }261266 262267 impl MediaFrame {263- pub fn new(header: MediaFrameHeader, payload: Vec<u8>) -> Result<Self> {268+ pub fn new(header: MediaFrameHeader, payload: impl Into<Arc<[u8]>>) -> Result<Self> {264269 header.validate()?;270+ let payload = payload.into();265271 if payload.len() != header.payload_len as usize {266272 return Err(ProtocolError::InvalidMessage {267273 message_type: "media frame",@@ -4,6 +4,8 @@
44 //! delivery-timeout semantics. It is intentionally not an implementation of55 //! the IETF MoQ Transport protocol.66 7+use std::sync::Arc;8+79 use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};810 911 use crate::{@@ -225,12 +227,16 @@ impl MediaObjectHeaderV3 {
225227 226228 pub struct MediaObjectV3 {227229 pub header: MediaObjectHeaderV3,228- pub payload: Vec<u8>,230+ /// The compressed access unit. Held behind an `Arc` so the host can fan the231+ /// same encoded object out to every connected client without copying the232+ /// payload per connection.233+ pub payload: Arc<[u8]>,229234 }230235 231236 impl MediaObjectV3 {232- pub fn new(header: MediaObjectHeaderV3, payload: Vec<u8>) -> Result<Self> {237+ pub fn new(header: MediaObjectHeaderV3, payload: impl Into<Arc<[u8]>>) -> Result<Self> {233238 header.validate()?;239+ let payload = payload.into();234240 if payload.len() != header.payload_len as usize {235241 return Err(ProtocolError::InvalidMessage {236242 message_type: "v3 media object",@@ -261,7 +267,10 @@ where
261267 reason: "trailing bytes after the media object",262268 });263269 }264- Ok(MediaObjectV3 { header, payload })270+ Ok(MediaObjectV3 {271+ header,272+ payload: payload.into(),273+ })265274 }266275 267276 /// Validate and write one complete v3 media object.