parent
efc02236d5
commit
2bbc847754
@ -550,9 +550,9 @@ impl<W: AsyncWrite + AsyncSeek + Send + Unpin> Mp4Writer<W> {
|
||||
&frame.timestamp(),
|
||||
frame.data().remaining(),
|
||||
);
|
||||
let sample_description_index = if let (Some(i), None) = (
|
||||
let sample_description_index = if let (Some(i), true) = (
|
||||
self.cur_video_params_sample_description_index,
|
||||
frame.new_parameters.as_ref(),
|
||||
frame.has_new_parameters(),
|
||||
) {
|
||||
// Use the most recent sample description index for most frames, without having to
|
||||
// scan through self.video_sample_index.
|
||||
|
@ -780,13 +780,12 @@ impl Stream {
|
||||
///
|
||||
/// # With [`Demuxed`]
|
||||
///
|
||||
/// When using [`Demuxed`]'s frame-by-frame `futures::Stream` impl:
|
||||
/// When using [`Demuxed`]'s frame-by-frame `futures::Stream` impl, `parameters` reflects
|
||||
/// all parameters as of returned frames that have been returned from from `poll_next` via
|
||||
/// `Poll::Ready`.
|
||||
///
|
||||
/// * After `poll_next` returns `Ready`, `parameters` reflects all parameter changes as of
|
||||
/// returned frame.
|
||||
/// * After `poll_next` returns `Pending`, currently the parameters may or may not reflect
|
||||
/// changes sent as part of the *next* frame that `poll_next` will return. (It's likely
|
||||
/// that an upcoming Retina release will guarantee not.)
|
||||
/// It's guaranteed to *not* reflect any parameter changes in the upcoming frame, even after
|
||||
/// a `Poll::Pending` return.
|
||||
///
|
||||
/// If there is no packet loss, parameters are generally available after the first frame is
|
||||
/// returned. In the case of H.264, [RFC 6184 section
|
||||
@ -2357,7 +2356,16 @@ impl futures::Stream for Demuxed {
|
||||
description,
|
||||
})
|
||||
})?;
|
||||
|
||||
// Note we're committed now to calling `pull` and returning
|
||||
// `Ready` if it has a frame. This is because the
|
||||
// `Stream::parameters` contract guarantees that changes in
|
||||
// upcoming frames are *not* reflected. It's implemented by a
|
||||
// call to `Depacketizer::pull`, which doesn't make a like
|
||||
// guarantee about the state between `push` and `pull`. So we
|
||||
// can't let our callers observe that state.
|
||||
}
|
||||
|
||||
match depacketizer.pull(conn_ctx, stream_ctx) {
|
||||
Ok(Some(item)) => {
|
||||
self.state = DemuxedState::Pulling(stream_id);
|
||||
|
@ -496,31 +496,27 @@ impl Depacketizer {
|
||||
self.nals.clear();
|
||||
self.pieces.clear();
|
||||
|
||||
let new_parameters = match (
|
||||
let has_new_parameters = match (
|
||||
new_sps.as_deref(),
|
||||
new_pps.as_deref(),
|
||||
self.parameters.as_ref(),
|
||||
) {
|
||||
(Some(sps_nal), Some(pps_nal), _) => {
|
||||
// TODO: could map this to a RtpPacketError more accurately.
|
||||
let ip = InternalParameters::parse_sps_and_pps(sps_nal, pps_nal)?;
|
||||
let p = ip.generic_parameters.clone();
|
||||
self.parameters = Some(ip);
|
||||
Some(Box::new(p))
|
||||
self.parameters = Some(InternalParameters::parse_sps_and_pps(sps_nal, pps_nal)?);
|
||||
true
|
||||
}
|
||||
(Some(_), None, Some(old_ip)) | (None, Some(_), Some(old_ip)) => {
|
||||
let sps_nal = new_sps.as_deref().unwrap_or(&old_ip.sps_nal);
|
||||
let pps_nal = new_pps.as_deref().unwrap_or(&old_ip.pps_nal);
|
||||
// TODO: as above, could map this to a RtpPacketError more accurately.
|
||||
let ip = InternalParameters::parse_sps_and_pps(sps_nal, pps_nal)?;
|
||||
let p = ip.generic_parameters.clone();
|
||||
self.parameters = Some(ip);
|
||||
Some(Box::new(p))
|
||||
self.parameters = Some(InternalParameters::parse_sps_and_pps(sps_nal, pps_nal)?);
|
||||
true
|
||||
}
|
||||
_ => None,
|
||||
_ => false,
|
||||
};
|
||||
Ok(VideoFrame {
|
||||
new_parameters,
|
||||
has_new_parameters,
|
||||
loss: au.loss,
|
||||
start_ctx: au.start_ctx,
|
||||
end_ctx: au.end_ctx,
|
||||
@ -1429,9 +1425,7 @@ mod tests {
|
||||
};
|
||||
|
||||
// After pull, new_parameters and parameters() both reflect the change.
|
||||
assert!(frame.new_parameters.is_some());
|
||||
let p = frame.new_parameters.unwrap();
|
||||
assert_eq!(p.pixel_dimensions(), (640, 480));
|
||||
assert!(frame.has_new_parameters);
|
||||
match d.parameters() {
|
||||
Some(crate::codec::Parameters::Video(v)) => {
|
||||
assert_eq!(v.pixel_dimensions(), (640, 480));
|
||||
@ -1538,7 +1532,7 @@ mod tests {
|
||||
Some(CodecItem::VideoFrame(frame)) => frame,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(frame.new_parameters.is_some());
|
||||
assert!(frame.has_new_parameters);
|
||||
assert!(d.parameters().is_some());
|
||||
}
|
||||
}
|
||||
|
@ -324,16 +324,8 @@ pub struct VideoFrame {
|
||||
start_ctx: crate::PacketContext,
|
||||
end_ctx: crate::PacketContext,
|
||||
|
||||
/// 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>>,
|
||||
|
||||
has_new_parameters: bool,
|
||||
loss: u16,
|
||||
|
||||
timestamp: crate::Timestamp,
|
||||
stream_id: usize,
|
||||
is_random_access_point: bool,
|
||||
@ -347,6 +339,14 @@ impl VideoFrame {
|
||||
self.stream_id
|
||||
}
|
||||
|
||||
/// Returns true if this frame set new video parameters.
|
||||
///
|
||||
/// The parameters can be obtained via [`crate::client::Stream::parameters`].
|
||||
#[inline]
|
||||
pub fn has_new_parameters(&self) -> bool {
|
||||
self.has_new_parameters
|
||||
}
|
||||
|
||||
/// Returns the number of lost RTP packets before this video frame. See
|
||||
/// [`crate::rtp::ReceivedPacket::loss`].
|
||||
///
|
||||
@ -418,7 +418,7 @@ impl std::fmt::Debug for VideoFrame {
|
||||
.field("start_ctx", &self.start_ctx)
|
||||
.field("end_ctx", &self.end_ctx)
|
||||
.field("loss", &self.loss)
|
||||
.field("new_parameters", &self.new_parameters)
|
||||
.field("has_new_parameters", &self.has_new_parameters)
|
||||
.field("is_random_access_point", &self.is_random_access_point)
|
||||
.field("is_disposable", &self.is_disposable)
|
||||
.field("data", &crate::hex::LimitedHex::new(&self.data, 64))
|
||||
|
Loading…
Reference in New Issue
Block a user