use accessors for most codec fields for #47

I left alone `VideoFrame::new_parameters`, as I'll likely eliminate it
as described in #47.
This commit is contained in:
Scott Lamb 2022-04-29 16:14:09 -07:00
parent f94e2f78d3
commit efc02236d5
3 changed files with 165 additions and 81 deletions

View File

@ -547,7 +547,7 @@ impl<W: AsyncWrite + AsyncSeek + Send + Unpin> Mp4Writer<W> {
) -> Result<(), Error> { ) -> Result<(), Error> {
println!( println!(
"{}: {}-byte video frame", "{}: {}-byte video frame",
&frame.timestamp, &frame.timestamp(),
frame.data().remaining(), frame.data().remaining(),
); );
let sample_description_index = if let (Some(i), None) = ( let sample_description_index = if let (Some(i), None) = (
@ -582,15 +582,15 @@ impl<W: AsyncWrite + AsyncSeek + Send + Unpin> Mp4Writer<W> {
sample_description_index, sample_description_index,
self.mdat_pos, self.mdat_pos,
size, size,
frame.timestamp, frame.timestamp(),
frame.loss, frame.loss(),
self.allow_loss, self.allow_loss,
)?; )?;
self.mdat_pos = self self.mdat_pos = self
.mdat_pos .mdat_pos
.checked_add(size) .checked_add(size)
.ok_or_else(|| anyhow!("mdat_pos overflow"))?; .ok_or_else(|| anyhow!("mdat_pos overflow"))?;
if frame.is_random_access_point { if frame.is_random_access_point() {
self.video_sync_sample_nums self.video_sync_sample_nums
.push(u32::try_from(self.video_trak.samples)?); .push(u32::try_from(self.video_trak.samples)?);
} }
@ -599,26 +599,27 @@ impl<W: AsyncWrite + AsyncSeek + Send + Unpin> Mp4Writer<W> {
Ok(()) Ok(())
} }
async fn audio(&mut self, mut frame: retina::codec::AudioFrame) -> Result<(), Error> { async fn audio(&mut self, frame: retina::codec::AudioFrame) -> Result<(), Error> {
println!( println!(
"{}: {}-byte audio frame", "{}: {}-byte audio frame",
&frame.timestamp, frame.timestamp(),
frame.data.remaining() frame.data().remaining()
); );
let size = u32::try_from(frame.data.remaining())?; let size = u32::try_from(frame.data().remaining())?;
self.audio_trak.add_sample( self.audio_trak.add_sample(
/* sample_description_index */ 1, /* sample_description_index */ 1,
self.mdat_pos, self.mdat_pos,
size, size,
frame.timestamp, frame.timestamp(),
frame.loss, frame.loss(),
self.allow_loss, self.allow_loss,
)?; )?;
self.mdat_pos = self self.mdat_pos = self
.mdat_pos .mdat_pos
.checked_add(size) .checked_add(size)
.ok_or_else(|| anyhow!("mdat_pos overflow"))?; .ok_or_else(|| anyhow!("mdat_pos overflow"))?;
write_all_buf(&mut self.inner, &mut frame.data).await?; let mut data = frame.into_data();
write_all_buf(&mut self.inner, &mut data).await?;
Ok(()) Ok(())
} }
} }
@ -643,13 +644,13 @@ async fn copy<'a>(
pkt = session.next() => { pkt = session.next() => {
match pkt.ok_or_else(|| anyhow!("EOF"))?? { match pkt.ok_or_else(|| anyhow!("EOF"))?? {
CodecItem::VideoFrame(f) => { CodecItem::VideoFrame(f) => {
let stream = &session.streams()[f.stream_id]; let stream = &session.streams()[f.stream_id()];
let start_ctx = f.start_ctx(); let start_ctx = *f.start_ctx();
mp4.video(stream, f).await.with_context( mp4.video(stream, f).await.with_context(
|| format!("Error processing video frame starting with {}", start_ctx))?; || format!("Error processing video frame starting with {}", start_ctx))?;
}, },
CodecItem::AudioFrame(f) => { CodecItem::AudioFrame(f) => {
let ctx = f.ctx; let ctx = *f.ctx();
mp4.audio(f).await.with_context( mp4.audio(f).await.with_context(
|| format!("Error processing audio frame, {}", ctx))?; || format!("Error processing audio frame, {}", ctx))?;
}, },

View File

@ -54,7 +54,11 @@ async fn run_inner(opts: Opts, session_group: Arc<SessionGroup>) -> Result<(), E
item = session.next() => { item = session.next() => {
match item.ok_or_else(|| anyhow!("EOF"))?? { match item.ok_or_else(|| anyhow!("EOF"))?? {
CodecItem::MessageFrame(m) => { CodecItem::MessageFrame(m) => {
info!("{}: {}\n", &m.timestamp, std::str::from_utf8(&m.data[..]).unwrap()); info!(
"{}: {}\n",
&m.timestamp(),
std::str::from_utf8(&m.data()[..]).unwrap(),
);
}, },
_ => continue, _ => continue,
}; };

View File

@ -13,7 +13,7 @@ use crate::rtp::ReceivedPacket;
use crate::ConnectionContext; use crate::ConnectionContext;
use crate::Error; use crate::Error;
use crate::StreamContextRef; use crate::StreamContextRef;
use bytes::{Buf, Bytes}; use bytes::Bytes;
pub(crate) mod aac; pub(crate) mod aac;
pub(crate) mod g723; pub(crate) mod g723;
@ -186,18 +186,54 @@ impl AudioParameters {
/// An audio frame, which consists of one or more samples. /// An audio frame, which consists of one or more samples.
pub struct AudioFrame { pub struct AudioFrame {
pub ctx: crate::PacketContext, ctx: crate::PacketContext,
pub stream_id: usize, stream_id: usize,
pub timestamp: crate::Timestamp, timestamp: crate::Timestamp,
pub frame_length: NonZeroU32, frame_length: NonZeroU32,
loss: u16,
data: Bytes,
}
/// Number of lost RTP packets before this audio frame. See [crate::rtp::ReceivedPacket::loss]. impl AudioFrame {
/// Note that if loss occurs during a fragmented frame, more than this number of packets' worth #[inline]
/// of data may be skipped. pub fn ctx(&self) -> &crate::PacketContext {
pub loss: u16, &self.ctx
}
// TODO: expose bytes or Buf (for zero-copy)? #[inline]
pub data: Bytes, pub fn stream_id(&self) -> usize {
self.stream_id
}
#[inline]
pub fn timestamp(&self) -> crate::Timestamp {
self.timestamp
}
#[inline]
pub fn frame_length(&self) -> NonZeroU32 {
self.frame_length
}
/// Returns the number of lost RTP packets before this audio frame. See
/// [crate::rtp::ReceivedPacket::loss].
///
/// Note that if loss occurs during a fragmented frame, more than this
/// number of packets' worth of data may be skipped.
#[inline]
pub fn loss(&self) -> u16 {
self.loss
}
#[inline]
pub fn data(&self) -> &Bytes {
&self.data
}
#[inline]
pub fn into_data(self) -> Bytes {
self.data
}
} }
impl std::fmt::Debug for AudioFrame { impl std::fmt::Debug for AudioFrame {
@ -213,37 +249,17 @@ impl std::fmt::Debug for AudioFrame {
} }
} }
impl Buf for AudioFrame {
fn remaining(&self) -> usize {
self.data.remaining()
}
fn chunk(&self) -> &[u8] {
self.data.chunk()
}
fn advance(&mut self, cnt: usize) {
self.data.advance(cnt)
}
}
/// Parameters which describe a message stream, for `application` media types. /// Parameters which describe a message stream, for `application` media types.
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct MessageParameters(onvif::CompressionType); pub struct MessageParameters(onvif::CompressionType);
/// A single message, for `application` media types. /// A single message, for `application` media types.
pub struct MessageFrame { pub struct MessageFrame {
pub ctx: crate::PacketContext, ctx: crate::PacketContext,
pub timestamp: crate::Timestamp, timestamp: crate::Timestamp,
pub stream_id: usize, stream_id: usize,
loss: u16,
/// Number of lost RTP packets before this message frame. See data: Bytes,
/// [crate::rtp::ReceivedPacket::loss]. If this is non-zero, a prefix of the
/// message may be missing.
pub loss: u16,
// TODO: expose bytes or Buf (for zero-copy)?
pub data: Bytes,
} }
impl std::fmt::Debug for MessageFrame { impl std::fmt::Debug for MessageFrame {
@ -258,6 +274,43 @@ impl std::fmt::Debug for MessageFrame {
} }
} }
impl MessageFrame {
#[inline]
pub fn ctx(&self) -> &crate::PacketContext {
&self.ctx
}
#[inline]
pub fn stream_id(&self) -> usize {
self.stream_id
}
#[inline]
pub fn timestamp(&self) -> crate::Timestamp {
self.timestamp
}
/// Returns the number of lost RTP packets before this frame. See
/// [crate::rtp::ReceivedPacket::loss].
///
/// Note that if loss occurs during a fragmented frame, more than this
/// number of packets' worth of data may be skipped.
#[inline]
pub fn loss(&self) -> u16 {
self.loss
}
#[inline]
pub fn data(&self) -> &Bytes {
&self.data
}
#[inline]
pub fn into_data(self) -> Bytes {
self.data
}
}
/// A single video frame (aka video sample or video access unit). /// A single video frame (aka video sample or video access unit).
/// ///
/// Typically this is an encoded picture. It could also be a single field of an interlaced /// Typically this is an encoded picture. It could also be a single field of an interlaced
@ -266,51 +319,77 @@ impl std::fmt::Debug for MessageFrame {
/// Durations aren't specified here; they can be calculated from the timestamp of a following /// Durations aren't specified here; they can be calculated from the timestamp of a following
/// picture, or approximated via the frame rate. /// picture, or approximated via the frame rate.
pub struct VideoFrame { pub struct VideoFrame {
// New video parameters.
//
// Rarely populated and large, so boxed to reduce bloat.
//
// To obtain the current parameters for the stream regardless of whether this frame set new
// parameters, see [`crate::client::Stream::parameters`].
pub new_parameters: Option<Box<VideoParameters>>,
/// Number of lost RTP packets before this video frame. See [crate::rtp::ReceivedPacket::loss].
/// Note that if loss occurs during a fragmented frame, more than this number of packets' worth
/// of data may be skipped.
pub loss: u16,
// A pair of contexts: for the start and for the end. // A pair of contexts: for the start and for the end.
// Having both can be useful to measure the total time elapsed while receiving the frame. // Having both can be useful to measure the total time elapsed while receiving the frame.
start_ctx: crate::PacketContext, start_ctx: crate::PacketContext,
end_ctx: crate::PacketContext, end_ctx: crate::PacketContext,
/// This picture's timestamp in the time base associated with the stream. /// New video parameters.
pub timestamp: crate::Timestamp, ///
/// Rarely populated and large, so boxed to reduce bloat.
//
/// To obtain the current parameters for the stream regardless of whether this frame set new
/// parameters, see [`crate::client::Stream::parameters`].
pub new_parameters: Option<Box<VideoParameters>>,
pub stream_id: usize, loss: u16,
/// If this is a "random access point (RAP)" aka "instantaneous decoding refresh (IDR)" picture.
/// The former is defined in ISO/IEC 14496-12; the latter in H.264. Both mean that this picture
/// can be decoded without any other AND no pictures following this one depend on any pictures
/// before this one.
pub is_random_access_point: bool,
/// If no other pictures require this one to be decoded correctly.
/// In H.264 terms, this is a frame with `nal_ref_idc == 0`.
pub is_disposable: bool,
timestamp: crate::Timestamp,
stream_id: usize,
is_random_access_point: bool,
is_disposable: bool,
data: bytes::Bytes, data: bytes::Bytes,
} }
impl VideoFrame { impl VideoFrame {
#[inline] #[inline]
pub fn start_ctx(&self) -> crate::PacketContext { pub fn stream_id(&self) -> usize {
self.start_ctx self.stream_id
}
/// Returns the number of lost RTP packets before this video frame. See
/// [`crate::rtp::ReceivedPacket::loss`].
///
/// Note that if loss occurs during a fragmented frame, more than this
/// number of packets' worth of data may be skipped.
#[inline]
pub fn loss(&self) -> u16 {
self.loss
}
/// Returns this picture's timestamp in the time base associated with the stream.
#[inline]
pub fn timestamp(&self) -> crate::Timestamp {
self.timestamp
} }
#[inline] #[inline]
pub fn end_ctx(&self) -> crate::PacketContext { pub fn start_ctx(&self) -> &crate::PacketContext {
self.end_ctx &self.start_ctx
}
#[inline]
pub fn end_ctx(&self) -> &crate::PacketContext {
&self.end_ctx
}
/// Returns if this is a "random access point (RAP)" aka "instantaneous
/// decoding refresh (IDR)" picture.
///
/// The former is defined in ISO/IEC 14496-12; the latter in H.264. Both
/// mean that this picture can be decoded without any other AND no pictures
/// following this one depend on any pictures before this one.
#[inline]
pub fn is_random_access_point(&self) -> bool {
self.is_random_access_point
}
/// Returns if no other pictures require this one to be decoded correctly.
///
/// In H.264 terms, this is a frame with `nal_ref_idc == 0`.
#[inline]
pub fn is_disposable(&self) -> bool {
self.is_disposable
} }
/// Returns the data in a codec-specific format. /// Returns the data in a codec-specific format.