mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-29 21:40:31 +00:00
video: migrate to new ClockTime design
This commit is contained in:
parent
c2de0649a7
commit
e16cad7c8f
24 changed files with 677 additions and 342 deletions
|
@ -186,7 +186,12 @@ impl VideoDecoderImpl for CdgDec {
|
|||
}
|
||||
}
|
||||
|
||||
gst_debug!(CAT, obj: element, "Finish frame pts={}", frame.pts());
|
||||
gst_debug!(
|
||||
CAT,
|
||||
obj: element,
|
||||
"Finish frame pts={}",
|
||||
frame.pts().display()
|
||||
);
|
||||
|
||||
element.finish_frame(frame)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ use gst::format::Bytes;
|
|||
use gst::glib;
|
||||
use gst::gst_debug;
|
||||
use gst::subclass::prelude::*;
|
||||
use gst::SECOND_VAL;
|
||||
use gst_base::prelude::*;
|
||||
use gst_base::subclass::prelude::*;
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -94,23 +93,22 @@ impl ElementImpl for CdgParse {
|
|||
}
|
||||
|
||||
fn bytes_to_time(bytes: Bytes) -> gst::ClockTime {
|
||||
match bytes {
|
||||
Bytes(Some(bytes)) => {
|
||||
let nb = bytes / CDG_PACKET_SIZE as u64;
|
||||
gst::ClockTime(nb.mul_div_round(SECOND_VAL, CDG_PACKET_PERIOD))
|
||||
}
|
||||
Bytes(None) => gst::ClockTime::none(),
|
||||
}
|
||||
let nb = bytes.0 / CDG_PACKET_SIZE as u64;
|
||||
gst::ClockTime::from_nseconds(
|
||||
nb.mul_div_round(*gst::ClockTime::SECOND, CDG_PACKET_PERIOD)
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
fn time_to_bytes(time: gst::ClockTime) -> Bytes {
|
||||
match time.nseconds() {
|
||||
Some(time) => {
|
||||
let bytes = time.mul_div_round(CDG_PACKET_PERIOD * CDG_PACKET_SIZE as u64, SECOND_VAL);
|
||||
Bytes(bytes)
|
||||
}
|
||||
None => Bytes(None),
|
||||
}
|
||||
Bytes(
|
||||
time.nseconds()
|
||||
.mul_div_round(
|
||||
CDG_PACKET_PERIOD * CDG_PACKET_SIZE as u64,
|
||||
*gst::ClockTime::SECOND,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
impl BaseParseImpl for CdgParse {
|
||||
|
@ -122,8 +120,8 @@ impl BaseParseImpl for CdgParse {
|
|||
let pad = element.src_pad();
|
||||
if pad.query(&mut query) {
|
||||
let size = query.result();
|
||||
let duration = bytes_to_time(size.try_into().unwrap());
|
||||
element.set_duration(duration, 0);
|
||||
let bytes: Option<Bytes> = size.try_into().unwrap();
|
||||
element.set_duration(bytes.map(bytes_to_time), 0);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -198,7 +196,7 @@ impl BaseParseImpl for CdgParse {
|
|||
}
|
||||
};
|
||||
|
||||
let pts = bytes_to_time(Bytes(Some(frame.offset())));
|
||||
let pts = bytes_to_time(Bytes(frame.offset()));
|
||||
let buffer = frame.buffer_mut().unwrap();
|
||||
buffer.set_pts(pts);
|
||||
|
||||
|
@ -226,10 +224,10 @@ impl BaseParseImpl for CdgParse {
|
|||
|
||||
match (src_val, dest_format) {
|
||||
(gst::GenericFormattedValue::Bytes(bytes), gst::Format::Time) => {
|
||||
Some(bytes_to_time(bytes).into())
|
||||
Some(bytes.map(bytes_to_time).into())
|
||||
}
|
||||
(gst::GenericFormattedValue::Time(time), gst::Format::Bytes) => {
|
||||
Some(time_to_bytes(time).into())
|
||||
Some(time.map(time_to_bytes).into())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ fn test_cdgdec() {
|
|||
.expect("Unable to set the pipeline to the `Playing` state");
|
||||
|
||||
let bus = pipeline.bus().unwrap();
|
||||
for msg in bus.iter_timed(gst::CLOCK_TIME_NONE) {
|
||||
for msg in bus.iter_timed(gst::ClockTime::NONE) {
|
||||
use gst::MessageView;
|
||||
match msg.view() {
|
||||
MessageView::Error(err) => {
|
||||
|
|
|
@ -35,13 +35,13 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
|
|||
)
|
||||
});
|
||||
|
||||
const DEFAULT_WINDOW: u64 = 10 * gst::SECOND_VAL;
|
||||
const DEFAULT_WINDOW: gst::ClockTime = gst::ClockTime::from_seconds(10);
|
||||
const DEFAULT_CC608: bool = false;
|
||||
const DEFAULT_CC708: bool = false;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct Settings {
|
||||
pub window: u64,
|
||||
pub window: gst::ClockTime,
|
||||
pub cc608: bool,
|
||||
pub cc708: bool,
|
||||
}
|
||||
|
@ -65,8 +65,8 @@ enum CCFormat {
|
|||
#[derive(Debug, Clone, Copy)]
|
||||
struct State {
|
||||
format: CCFormat,
|
||||
last_cc608_change: gst::ClockTime,
|
||||
last_cc708_change: gst::ClockTime,
|
||||
last_cc608_change: Option<gst::ClockTime>,
|
||||
last_cc708_change: Option<gst::ClockTime>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -177,27 +177,27 @@ impl CCDetect {
|
|||
);
|
||||
|
||||
if cc_packet.cc608 != settings.cc608 {
|
||||
if state.last_cc608_change.is_none()
|
||||
|| ts - state.last_cc608_change > settings.window.into()
|
||||
{
|
||||
if state.last_cc608_change.map_or(true, |last_cc608_change| {
|
||||
ts > last_cc608_change + settings.window
|
||||
}) {
|
||||
settings.cc608 = cc_packet.cc608;
|
||||
state.last_cc608_change = ts;
|
||||
state.last_cc608_change = Some(ts);
|
||||
notify_cc608 = true;
|
||||
}
|
||||
} else {
|
||||
state.last_cc608_change = ts;
|
||||
state.last_cc608_change = Some(ts);
|
||||
}
|
||||
|
||||
if cc_packet.cc708 != settings.cc708 {
|
||||
if state.last_cc708_change.is_none()
|
||||
|| ts - state.last_cc708_change > settings.window.into()
|
||||
{
|
||||
if state.last_cc708_change.map_or(true, |last_cc708_change| {
|
||||
ts > last_cc708_change + settings.window
|
||||
}) {
|
||||
settings.cc708 = cc_packet.cc708;
|
||||
state.last_cc708_change = ts;
|
||||
state.last_cc708_change = Some(ts);
|
||||
notify_cc708 = true;
|
||||
}
|
||||
} else {
|
||||
state.last_cc708_change = ts;
|
||||
state.last_cc708_change = Some(ts);
|
||||
}
|
||||
|
||||
gst_trace!(CAT, "changed to settings {:?} state {:?}", settings, state);
|
||||
|
@ -230,8 +230,8 @@ impl ObjectImpl for CCDetect {
|
|||
"Window",
|
||||
"Window of time (in ns) to determine if captions exist in the stream",
|
||||
0,
|
||||
u64::MAX,
|
||||
DEFAULT_WINDOW,
|
||||
u64::MAX - 1,
|
||||
DEFAULT_WINDOW.nseconds(),
|
||||
glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_PLAYING,
|
||||
),
|
||||
glib::ParamSpec::new_boolean(
|
||||
|
@ -264,7 +264,8 @@ impl ObjectImpl for CCDetect {
|
|||
match pspec.name() {
|
||||
"window" => {
|
||||
let mut settings = self.settings.lock().unwrap();
|
||||
settings.window = value.get().expect("type checked upstream");
|
||||
settings.window =
|
||||
gst::ClockTime::from_nseconds(value.get().expect("type checked upstream"));
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
|
@ -274,7 +275,7 @@ impl ObjectImpl for CCDetect {
|
|||
match pspec.name() {
|
||||
"window" => {
|
||||
let settings = self.settings.lock().unwrap();
|
||||
settings.window.to_value()
|
||||
settings.window.nseconds().to_value()
|
||||
}
|
||||
"cc608" => {
|
||||
let settings = self.settings.lock().unwrap();
|
||||
|
@ -350,14 +351,14 @@ impl BaseTransformImpl for CCDetect {
|
|||
) -> Result<gst::FlowSuccess, gst::FlowError> {
|
||||
let map = buf.map_readable().map_err(|_| gst::FlowError::Error)?;
|
||||
|
||||
if buf.pts().is_none() {
|
||||
let pts = buf.pts().ok_or_else(|| {
|
||||
gst::element_error!(
|
||||
element,
|
||||
gst::ResourceError::Read,
|
||||
["Input buffers must have valid timestamps"]
|
||||
);
|
||||
return Err(gst::FlowError::Error);
|
||||
}
|
||||
gst::FlowError::Error
|
||||
})?;
|
||||
|
||||
let format = {
|
||||
let mut state_guard = self.state.lock().unwrap();
|
||||
|
@ -377,7 +378,7 @@ impl BaseTransformImpl for CCDetect {
|
|||
}
|
||||
};
|
||||
|
||||
self.maybe_update_properties(element, buf.pts(), cc_packet)
|
||||
self.maybe_update_properties(element, pts, cc_packet)
|
||||
.map_err(|_| gst::FlowError::Error)?;
|
||||
|
||||
Ok(gst::FlowSuccess::Ok)
|
||||
|
@ -428,8 +429,8 @@ impl BaseTransformImpl for CCDetect {
|
|||
|
||||
*self.state.lock().unwrap() = Some(State {
|
||||
format: cc_format,
|
||||
last_cc608_change: gst::ClockTime::none(),
|
||||
last_cc708_change: gst::ClockTime::none(),
|
||||
last_cc608_change: gst::ClockTime::NONE,
|
||||
last_cc708_change: gst::ClockTime::NONE,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -42,8 +42,8 @@ use std::collections::BTreeMap;
|
|||
#[derive(Debug)]
|
||||
struct TimestampedLines {
|
||||
lines: Lines,
|
||||
pts: gst::ClockTime,
|
||||
duration: gst::ClockTime,
|
||||
pts: Option<gst::ClockTime>,
|
||||
duration: Option<gst::ClockTime>,
|
||||
}
|
||||
|
||||
struct Cursor {
|
||||
|
@ -182,9 +182,9 @@ struct State {
|
|||
mode: Option<Cea608Mode>,
|
||||
last_cc_data: Option<u16>,
|
||||
rows: BTreeMap<u32, Row>,
|
||||
first_pts: gst::ClockTime,
|
||||
current_pts: gst::ClockTime,
|
||||
current_duration: gst::ClockTime,
|
||||
first_pts: Option<gst::ClockTime>,
|
||||
current_pts: Option<gst::ClockTime>,
|
||||
current_duration: Option<gst::ClockTime>,
|
||||
carriage_return: Option<bool>,
|
||||
clear: Option<bool>,
|
||||
cursor: Cursor,
|
||||
|
@ -197,9 +197,9 @@ impl Default for State {
|
|||
mode: None,
|
||||
last_cc_data: None,
|
||||
rows: BTreeMap::new(),
|
||||
first_pts: gst::CLOCK_TIME_NONE,
|
||||
current_pts: gst::CLOCK_TIME_NONE,
|
||||
current_duration: gst::CLOCK_TIME_NONE,
|
||||
first_pts: gst::ClockTime::NONE,
|
||||
current_pts: gst::ClockTime::NONE,
|
||||
current_duration: gst::ClockTime::NONE,
|
||||
carriage_return: None,
|
||||
clear: None,
|
||||
cursor: Cursor {
|
||||
|
@ -377,20 +377,31 @@ fn eia608_to_text(cc_data: u16) -> String {
|
|||
fn dump(
|
||||
element: &super::Cea608ToJson,
|
||||
cc_data: u16,
|
||||
pts: gst::ClockTime,
|
||||
duration: gst::ClockTime,
|
||||
pts: impl Into<Option<gst::ClockTime>>,
|
||||
duration: impl Into<Option<gst::ClockTime>>,
|
||||
) {
|
||||
let pts = pts.into();
|
||||
let end = pts
|
||||
.zip(duration.into())
|
||||
.map(|(pts, duration)| pts + duration);
|
||||
|
||||
if cc_data != 0x8080 {
|
||||
gst_debug!(
|
||||
CAT,
|
||||
obj: element,
|
||||
"{} -> {}: {}",
|
||||
pts,
|
||||
pts + duration,
|
||||
pts.display(),
|
||||
end.display(),
|
||||
eia608_to_text(cc_data)
|
||||
);
|
||||
} else {
|
||||
gst_trace!(CAT, obj: element, "{} -> {}: padding", pts, pts + duration);
|
||||
gst_trace!(
|
||||
CAT,
|
||||
obj: element,
|
||||
"{} -> {}: padding",
|
||||
pts.display(),
|
||||
end.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,11 +449,16 @@ impl State {
|
|||
let pts = self.first_pts;
|
||||
|
||||
let duration = match self.mode {
|
||||
Some(Cea608Mode::PopOn) => gst::CLOCK_TIME_NONE,
|
||||
_ => self.current_pts + self.current_duration - self.first_pts,
|
||||
Some(Cea608Mode::PopOn) => gst::ClockTime::NONE,
|
||||
_ => self
|
||||
.current_pts
|
||||
.zip(self.current_duration)
|
||||
.map(|(cur_pts, cur_duration)| cur_pts + cur_duration)
|
||||
.zip(self.first_pts)
|
||||
.and_then(|(cur_end, first_pts)| cur_end.checked_sub(first_pts)),
|
||||
};
|
||||
|
||||
self.first_pts = gst::CLOCK_TIME_NONE;
|
||||
self.first_pts = gst::ClockTime::NONE;
|
||||
|
||||
let mut lines: Vec<Line> = vec![];
|
||||
|
||||
|
@ -477,7 +493,7 @@ impl State {
|
|||
clear,
|
||||
},
|
||||
pts: self.current_pts,
|
||||
duration: 0.into(),
|
||||
duration: Some(gst::ClockTime::ZERO),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -487,7 +503,12 @@ impl State {
|
|||
fn drain_pending(&mut self, element: &super::Cea608ToJson) -> Option<TimestampedLines> {
|
||||
if let Some(mut pending) = self.pending_lines.take() {
|
||||
gst_log!(CAT, obj: element, "Draining pending");
|
||||
pending.duration = self.current_pts + self.current_duration - pending.pts;
|
||||
pending.duration = self
|
||||
.current_pts
|
||||
.zip(self.current_duration)
|
||||
.map(|(cur_pts, cur_dur)| cur_pts + cur_dur)
|
||||
.zip(pending.pts)
|
||||
.and_then(|(cur_end, pending_pts)| cur_end.checked_sub(pending_pts));
|
||||
Some(pending)
|
||||
} else {
|
||||
None
|
||||
|
@ -675,8 +696,8 @@ impl State {
|
|||
fn handle_cc_data(
|
||||
&mut self,
|
||||
element: &super::Cea608ToJson,
|
||||
pts: gst::ClockTime,
|
||||
duration: gst::ClockTime,
|
||||
pts: Option<gst::ClockTime>,
|
||||
duration: Option<gst::ClockTime>,
|
||||
cc_data: u16,
|
||||
) -> Option<TimestampedLines> {
|
||||
if (is_specialna(cc_data) || is_control(cc_data)) && Some(cc_data) == self.last_cc_data {
|
||||
|
|
|
@ -76,12 +76,12 @@ impl Cea608ToTt {
|
|||
}
|
||||
};
|
||||
|
||||
let buffer_pts = buffer.pts();
|
||||
if buffer_pts.is_none() {
|
||||
let buffer_pts = buffer.pts().ok_or_else(|| {
|
||||
gst_error!(CAT, obj: pad, "Require timestamped buffers");
|
||||
return Err(gst::FlowError::Error);
|
||||
}
|
||||
let pts = (buffer_pts.unwrap() as f64) / 1_000_000_000.0;
|
||||
gst::FlowError::Error
|
||||
})?;
|
||||
|
||||
let pts = (buffer_pts.nseconds() as f64) / 1_000_000_000.0;
|
||||
|
||||
let data = buffer.map_readable().map_err(|_| {
|
||||
gst_error!(CAT, obj: pad, "Can't map buffer readable");
|
||||
|
@ -130,11 +130,7 @@ impl Cea608ToTt {
|
|||
}
|
||||
};
|
||||
|
||||
let duration = if buffer_pts > previous_text.0 {
|
||||
buffer_pts - previous_text.0
|
||||
} else {
|
||||
0.into()
|
||||
};
|
||||
let duration = buffer_pts.saturating_sub(previous_text.0);
|
||||
|
||||
let (timestamp, text) = previous_text;
|
||||
|
||||
|
@ -181,7 +177,7 @@ impl Cea608ToTt {
|
|||
}
|
||||
|
||||
fn split_time(time: gst::ClockTime) -> (u64, u8, u8, u16) {
|
||||
let time = time.unwrap();
|
||||
let time = time.nseconds();
|
||||
|
||||
let mut s = time / 1_000_000_000;
|
||||
let mut m = s / 60;
|
||||
|
@ -347,11 +343,18 @@ impl Cea608ToTt {
|
|||
};
|
||||
|
||||
let buffer = match format {
|
||||
Format::Vtt => Self::create_vtt_buffer(timestamp, 0.into(), text),
|
||||
Format::Srt => {
|
||||
Self::create_srt_buffer(timestamp, 0.into(), state.index, text)
|
||||
Format::Vtt => {
|
||||
Self::create_vtt_buffer(timestamp, gst::ClockTime::ZERO, text)
|
||||
}
|
||||
Format::Srt => Self::create_srt_buffer(
|
||||
timestamp,
|
||||
gst::ClockTime::ZERO,
|
||||
state.index,
|
||||
text,
|
||||
),
|
||||
Format::Raw => {
|
||||
Self::create_raw_buffer(timestamp, gst::ClockTime::ZERO, text)
|
||||
}
|
||||
Format::Raw => Self::create_raw_buffer(timestamp, 0.into(), text),
|
||||
};
|
||||
state.index += 1;
|
||||
drop(state);
|
||||
|
|
|
@ -53,7 +53,7 @@ struct PullState {
|
|||
need_stream_start: bool,
|
||||
stream_id: String,
|
||||
offset: u64,
|
||||
duration: gst::ClockTime,
|
||||
duration: Option<gst::ClockTime>,
|
||||
}
|
||||
|
||||
impl PullState {
|
||||
|
@ -62,7 +62,7 @@ impl PullState {
|
|||
need_stream_start: true,
|
||||
stream_id: pad.create_stream_id(element, Some("src")).to_string(),
|
||||
offset: 0,
|
||||
duration: gst::CLOCK_TIME_NONE,
|
||||
duration: gst::ClockTime::NONE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,8 +74,8 @@ struct State {
|
|||
format: Option<Format>,
|
||||
need_segment: bool,
|
||||
pending_events: Vec<gst::Event>,
|
||||
start_position: gst::ClockTime,
|
||||
last_position: gst::ClockTime,
|
||||
start_position: Option<gst::ClockTime>,
|
||||
last_position: Option<gst::ClockTime>,
|
||||
last_timecode: Option<gst_video::ValidVideoTimeCode>,
|
||||
timecode_rate: Option<(u8, bool)>,
|
||||
segment: gst::FormattedSegment<gst::ClockTime>,
|
||||
|
@ -100,11 +100,11 @@ impl Default for State {
|
|||
format: None,
|
||||
need_segment: true,
|
||||
pending_events: Vec::new(),
|
||||
start_position: gst::CLOCK_TIME_NONE,
|
||||
last_position: gst::CLOCK_TIME_NONE,
|
||||
start_position: None,
|
||||
last_position: None,
|
||||
last_timecode: None,
|
||||
timecode_rate: None,
|
||||
segment: gst::FormattedSegment::<gst::ClockTime>::new(),
|
||||
segment: gst::FormattedSegment::new(),
|
||||
pull: None,
|
||||
seeking: false,
|
||||
discont: false,
|
||||
|
@ -221,33 +221,35 @@ impl State {
|
|||
element: &super::MccParse,
|
||||
timecode: &gst_video::ValidVideoTimeCode,
|
||||
) {
|
||||
let nsecs = gst::ClockTime::from(timecode.nsec_since_daily_jam());
|
||||
let nsecs = timecode.time_since_daily_jam();
|
||||
if self.start_position.is_none() {
|
||||
self.start_position = nsecs;
|
||||
self.start_position = Some(nsecs);
|
||||
}
|
||||
let start_position = self.start_position.expect("checked above");
|
||||
|
||||
let nsecs = if nsecs < self.start_position {
|
||||
let nsecs = nsecs.checked_sub(start_position).unwrap_or_else(|| {
|
||||
gst_fixme!(
|
||||
CAT,
|
||||
obj: element,
|
||||
"New position {} < start position {}",
|
||||
nsecs,
|
||||
self.start_position
|
||||
start_position,
|
||||
);
|
||||
self.start_position
|
||||
} else {
|
||||
nsecs - self.start_position
|
||||
};
|
||||
start_position
|
||||
});
|
||||
|
||||
if self.last_position.is_none() || nsecs >= self.last_position {
|
||||
self.last_position = nsecs;
|
||||
if self
|
||||
.last_position
|
||||
.map_or(true, |last_position| nsecs >= last_position)
|
||||
{
|
||||
self.last_position = Some(nsecs);
|
||||
} else {
|
||||
gst_fixme!(
|
||||
CAT,
|
||||
obj: element,
|
||||
"New position {} < last position {}",
|
||||
nsecs,
|
||||
self.last_position
|
||||
self.last_position.display(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -272,9 +274,8 @@ impl State {
|
|||
}
|
||||
|
||||
buffer.set_duration(
|
||||
gst::SECOND
|
||||
.mul_div_ceil(*framerate.denom() as u64, *framerate.numer() as u64)
|
||||
.unwrap_or(gst::CLOCK_TIME_NONE),
|
||||
gst::ClockTime::SECOND
|
||||
.mul_div_ceil(*framerate.denom() as u64, *framerate.numer() as u64),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -518,11 +519,15 @@ impl MccParse {
|
|||
) -> Result<MutexGuard<State>, gst::FlowError> {
|
||||
let (framerate, drop_frame) = parse_timecode_rate(state.timecode_rate)?;
|
||||
let timecode = state.handle_timecode(element, framerate, drop_frame, tc)?;
|
||||
let nsecs = gst::ClockTime::from(timecode.nsec_since_daily_jam());
|
||||
let nsecs = timecode.time_since_daily_jam();
|
||||
|
||||
state.last_timecode = Some(timecode);
|
||||
|
||||
if nsecs >= state.segment.start() {
|
||||
if state
|
||||
.segment
|
||||
.start()
|
||||
.map_or(false, |seg_start| nsecs >= seg_start)
|
||||
{
|
||||
state.seeking = false;
|
||||
state.discont = true;
|
||||
state.replay_last_line = true;
|
||||
|
@ -558,8 +563,12 @@ impl MccParse {
|
|||
// Update the last_timecode to the current one
|
||||
state.last_timecode = Some(timecode);
|
||||
|
||||
let send_eos = state.segment.stop().is_some()
|
||||
&& buffer.pts() + buffer.duration() >= state.segment.stop();
|
||||
let send_eos = state.segment.stop().map_or(false, |stop| {
|
||||
buffer
|
||||
.pts()
|
||||
.zip(buffer.duration())
|
||||
.map_or(false, |(pts, duration)| pts + duration >= stop)
|
||||
});
|
||||
|
||||
// Drop our state mutex while we push out buffers or events
|
||||
drop(state);
|
||||
|
@ -670,8 +679,8 @@ impl MccParse {
|
|||
}
|
||||
|
||||
let size = match q.result().try_into().unwrap() {
|
||||
gst::format::Bytes(Some(size)) => size,
|
||||
gst::format::Bytes(None) => {
|
||||
Some(gst::format::Bytes(size)) => size,
|
||||
None => {
|
||||
return Err(loggable_error!(CAT, "Failed to query upstream duration"));
|
||||
}
|
||||
};
|
||||
|
@ -820,12 +829,12 @@ impl MccParse {
|
|||
Ok(Some(tc)) => {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
let mut pull = state.pull.as_mut().unwrap();
|
||||
pull.duration = tc.nsec_since_daily_jam().into();
|
||||
pull.duration = Some(tc.time_since_daily_jam());
|
||||
}
|
||||
Ok(None) => {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
let mut pull = state.pull.as_mut().unwrap();
|
||||
pull.duration = 0.into();
|
||||
pull.duration = Some(gst::ClockTime::ZERO);
|
||||
}
|
||||
Err(err) => {
|
||||
err.log();
|
||||
|
@ -886,11 +895,11 @@ impl MccParse {
|
|||
if let Some(pull) = &mut state.pull {
|
||||
pull.offset = 0;
|
||||
}
|
||||
state.segment = gst::FormattedSegment::<gst::ClockTime>::new();
|
||||
state.segment = gst::FormattedSegment::new();
|
||||
state.need_segment = true;
|
||||
state.pending_events.clear();
|
||||
state.start_position = 0.into();
|
||||
state.last_position = 0.into();
|
||||
state.start_position = Some(gst::ClockTime::ZERO);
|
||||
state.last_position = None;
|
||||
state.last_timecode = None;
|
||||
state.timecode_rate = None;
|
||||
state.last_raw_line = [].to_vec();
|
||||
|
@ -954,7 +963,7 @@ impl MccParse {
|
|||
|
||||
let (rate, flags, start_type, start, stop_type, stop) = event.get();
|
||||
|
||||
let mut start: gst::ClockTime = match start.try_into() {
|
||||
let mut start: Option<gst::ClockTime> = match start.try_into() {
|
||||
Ok(start) => start,
|
||||
Err(_) => {
|
||||
gst_error!(CAT, obj: element, "seek has invalid format");
|
||||
|
@ -962,7 +971,7 @@ impl MccParse {
|
|||
}
|
||||
};
|
||||
|
||||
let mut stop: gst::ClockTime = match stop.try_into() {
|
||||
let mut stop: Option<gst::ClockTime> = match stop.try_into() {
|
||||
Ok(stop) => stop,
|
||||
Err(_) => {
|
||||
gst_error!(CAT, obj: element, "seek has invalid format");
|
||||
|
@ -1002,11 +1011,17 @@ impl MccParse {
|
|||
let pull = state.pull.as_ref().unwrap();
|
||||
|
||||
if start_type == gst::SeekType::Set {
|
||||
start = start.min(pull.duration).unwrap_or(start);
|
||||
start = start
|
||||
.zip(pull.duration)
|
||||
.map(|(start, duration)| start.min(duration))
|
||||
.or(start);
|
||||
}
|
||||
|
||||
if stop_type == gst::SeekType::Set {
|
||||
stop = stop.min(pull.duration).unwrap_or(stop);
|
||||
stop = stop
|
||||
.zip(pull.duration)
|
||||
.map(|(stop, duration)| stop.min(duration))
|
||||
.or(stop);
|
||||
}
|
||||
|
||||
state.seeking = true;
|
||||
|
@ -1069,7 +1084,7 @@ impl MccParse {
|
|||
if let Some(pull) = state.pull.as_ref() {
|
||||
q.set(
|
||||
true,
|
||||
gst::GenericFormattedValue::Time(0.into()),
|
||||
gst::GenericFormattedValue::Time(gst::ClockTime::ZERO.into()),
|
||||
gst::GenericFormattedValue::Time(pull.duration),
|
||||
);
|
||||
true
|
||||
|
|
|
@ -194,12 +194,10 @@ impl State {
|
|||
assert!(self.framerate.is_some());
|
||||
let framerate = self.framerate.unwrap();
|
||||
|
||||
let dur = gst::SECOND
|
||||
.mul_div_floor(
|
||||
self.internal_buffer.len() as u64 * *framerate.denom() as u64,
|
||||
*framerate.numer() as u64,
|
||||
)
|
||||
.unwrap_or(gst::CLOCK_TIME_NONE);
|
||||
let dur = gst::ClockTime::SECOND.mul_div_floor(
|
||||
self.internal_buffer.len() as u64 * *framerate.denom() as u64,
|
||||
*framerate.numer() as u64,
|
||||
);
|
||||
buf_mut.set_duration(dur);
|
||||
|
||||
// Copy the metadata of the first buffer
|
||||
|
|
|
@ -47,7 +47,7 @@ struct PullState {
|
|||
need_stream_start: bool,
|
||||
stream_id: String,
|
||||
offset: u64,
|
||||
duration: gst::ClockTime,
|
||||
duration: Option<gst::ClockTime>,
|
||||
}
|
||||
|
||||
impl PullState {
|
||||
|
@ -56,7 +56,7 @@ impl PullState {
|
|||
need_stream_start: true,
|
||||
stream_id: pad.create_stream_id(element, Some("src")).to_string(),
|
||||
offset: 0,
|
||||
duration: gst::CLOCK_TIME_NONE,
|
||||
duration: gst::ClockTime::NONE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ struct State {
|
|||
need_segment: bool,
|
||||
pending_events: Vec<gst::Event>,
|
||||
framerate: Option<gst::Fraction>,
|
||||
last_position: gst::ClockTime,
|
||||
last_position: Option<gst::ClockTime>,
|
||||
last_timecode: Option<gst_video::ValidVideoTimeCode>,
|
||||
segment: gst::FormattedSegment<gst::ClockTime>,
|
||||
|
||||
|
@ -90,9 +90,9 @@ impl Default for State {
|
|||
need_segment: true,
|
||||
pending_events: Vec::new(),
|
||||
framerate: None,
|
||||
last_position: gst::CLOCK_TIME_NONE,
|
||||
last_position: None,
|
||||
last_timecode: None,
|
||||
segment: gst::FormattedSegment::<gst::ClockTime>::new(),
|
||||
segment: gst::FormattedSegment::new(),
|
||||
pull: None,
|
||||
seeking: false,
|
||||
discont: false,
|
||||
|
@ -196,17 +196,20 @@ impl State {
|
|||
timecode: &gst_video::ValidVideoTimeCode,
|
||||
element: &super::SccParse,
|
||||
) {
|
||||
let nsecs = gst::ClockTime::from(timecode.nsec_since_daily_jam());
|
||||
let nsecs = timecode.time_since_daily_jam();
|
||||
|
||||
if self.last_position.is_none() || nsecs >= self.last_position {
|
||||
self.last_position = nsecs;
|
||||
if self
|
||||
.last_position
|
||||
.map_or(true, |last_position| nsecs >= last_position)
|
||||
{
|
||||
self.last_position = Some(nsecs);
|
||||
} else {
|
||||
gst_fixme!(
|
||||
CAT,
|
||||
obj: element,
|
||||
"New position {} < last position {}",
|
||||
nsecs,
|
||||
self.last_position
|
||||
self.last_position.display(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -225,9 +228,8 @@ impl State {
|
|||
|
||||
buffer.set_pts(self.last_position);
|
||||
buffer.set_duration(
|
||||
gst::SECOND
|
||||
.mul_div_ceil(*framerate.denom() as u64, *framerate.numer() as u64)
|
||||
.unwrap_or(gst::CLOCK_TIME_NONE),
|
||||
gst::ClockTime::SECOND
|
||||
.mul_div_ceil(*framerate.denom() as u64, *framerate.numer() as u64),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -371,7 +373,7 @@ impl SccParse {
|
|||
};
|
||||
|
||||
let mut timecode = state.handle_timecode(&tc, framerate, element)?;
|
||||
let start_time = gst::ClockTime::from(timecode.nsec_since_daily_jam());
|
||||
let start_time = timecode.time_since_daily_jam();
|
||||
let segment_start = state.segment.start();
|
||||
let clip_buffers = if state.seeking {
|
||||
// If we are in the middle of seeking, check whether this line
|
||||
|
@ -380,7 +382,7 @@ impl SccParse {
|
|||
let mut end_timecode = timecode.clone();
|
||||
// add one more frame here so that add duration of the last frame
|
||||
end_timecode.add_frames(num_bufs + 1);
|
||||
let stop_time = gst::ClockTime::from(end_timecode.nsec_since_daily_jam());
|
||||
let stop_time = end_timecode.time_since_daily_jam();
|
||||
|
||||
gst_trace!(
|
||||
CAT,
|
||||
|
@ -388,11 +390,11 @@ impl SccParse {
|
|||
"Checking inside of segment, line start {} line stop {} segment start {} num bufs {}",
|
||||
start_time,
|
||||
stop_time,
|
||||
segment_start,
|
||||
segment_start.display(),
|
||||
num_bufs,
|
||||
);
|
||||
|
||||
if stop_time > segment_start {
|
||||
if segment_start.map_or(false, |seg_start| stop_time > seg_start) {
|
||||
state.seeking = false;
|
||||
state.discont = true;
|
||||
state.need_flush_stop = true;
|
||||
|
@ -427,8 +429,14 @@ impl SccParse {
|
|||
timecode.increment_frame();
|
||||
|
||||
if clip_buffers {
|
||||
let end_time = buffer.pts() + buffer.duration();
|
||||
if end_time < segment_start {
|
||||
let end_time = buffer
|
||||
.pts()
|
||||
.zip(buffer.duration())
|
||||
.map(|(pts, duration)| pts + duration);
|
||||
if end_time
|
||||
.zip(segment_start)
|
||||
.map_or(false, |(end_time, segment_start)| end_time < segment_start)
|
||||
{
|
||||
gst_trace!(
|
||||
CAT,
|
||||
obj: element,
|
||||
|
@ -440,8 +448,12 @@ impl SccParse {
|
|||
}
|
||||
}
|
||||
|
||||
send_eos = state.segment.stop().is_some()
|
||||
&& buffer.pts() + buffer.duration() >= state.segment.stop();
|
||||
send_eos = state.segment.stop().map_or(false, |stop| {
|
||||
buffer
|
||||
.pts()
|
||||
.zip(buffer.duration())
|
||||
.map_or(false, |(pts, duration)| pts + duration >= stop)
|
||||
});
|
||||
|
||||
let buffers = buffers.get_mut().unwrap();
|
||||
buffers.add(buffer);
|
||||
|
@ -564,8 +576,8 @@ impl SccParse {
|
|||
}
|
||||
|
||||
let size = match q.result().try_into().unwrap() {
|
||||
gst::format::Bytes(Some(size)) => size,
|
||||
gst::format::Bytes(None) => {
|
||||
Some(gst::format::Bytes(size)) => size,
|
||||
None => {
|
||||
return Err(loggable_error!(CAT, "Failed to query upstream duration"));
|
||||
}
|
||||
};
|
||||
|
@ -704,12 +716,12 @@ impl SccParse {
|
|||
Ok(Some(tc)) => {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
let mut pull = state.pull.as_mut().unwrap();
|
||||
pull.duration = tc.nsec_since_daily_jam().into();
|
||||
pull.duration = Some(tc.time_since_daily_jam());
|
||||
}
|
||||
Ok(None) => {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
let mut pull = state.pull.as_mut().unwrap();
|
||||
pull.duration = 0.into();
|
||||
pull.duration = Some(gst::ClockTime::ZERO);
|
||||
}
|
||||
Err(err) => {
|
||||
err.log();
|
||||
|
@ -770,10 +782,10 @@ impl SccParse {
|
|||
if let Some(pull) = &mut state.pull {
|
||||
pull.offset = 0;
|
||||
}
|
||||
state.segment = gst::FormattedSegment::<gst::ClockTime>::new();
|
||||
state.segment = gst::FormattedSegment::new();
|
||||
state.need_segment = true;
|
||||
state.pending_events.clear();
|
||||
state.last_position = 0.into();
|
||||
state.last_position = None;
|
||||
state.last_timecode = None;
|
||||
|
||||
drop(state);
|
||||
|
@ -835,7 +847,7 @@ impl SccParse {
|
|||
|
||||
let (rate, flags, start_type, start, stop_type, stop) = event.get();
|
||||
|
||||
let mut start: gst::ClockTime = match start.try_into() {
|
||||
let mut start: Option<gst::ClockTime> = match start.try_into() {
|
||||
Ok(start) => start,
|
||||
Err(_) => {
|
||||
gst_error!(CAT, obj: element, "seek has invalid format");
|
||||
|
@ -843,7 +855,7 @@ impl SccParse {
|
|||
}
|
||||
};
|
||||
|
||||
let mut stop: gst::ClockTime = match stop.try_into() {
|
||||
let mut stop: Option<gst::ClockTime> = match stop.try_into() {
|
||||
Ok(stop) => stop,
|
||||
Err(_) => {
|
||||
gst_error!(CAT, obj: element, "seek has invalid format");
|
||||
|
@ -883,11 +895,17 @@ impl SccParse {
|
|||
let pull = state.pull.as_ref().unwrap();
|
||||
|
||||
if start_type == gst::SeekType::Set {
|
||||
start = start.min(pull.duration).unwrap_or(start);
|
||||
start = start
|
||||
.zip(pull.duration)
|
||||
.map(|(start, duration)| start.min(duration))
|
||||
.or(start);
|
||||
}
|
||||
|
||||
if stop_type == gst::SeekType::Set {
|
||||
stop = stop.min(pull.duration).unwrap_or(stop);
|
||||
stop = stop
|
||||
.zip(pull.duration)
|
||||
.map(|(stop, duration)| stop.min(duration))
|
||||
.or(stop);
|
||||
}
|
||||
|
||||
state.seeking = true;
|
||||
|
@ -950,7 +968,7 @@ impl SccParse {
|
|||
if let Some(pull) = state.pull.as_ref() {
|
||||
q.set(
|
||||
true,
|
||||
gst::GenericFormattedValue::Time(0.into()),
|
||||
gst::GenericFormattedValue::Time(gst::ClockTime::ZERO.into()),
|
||||
gst::GenericFormattedValue::Time(pull.duration),
|
||||
);
|
||||
true
|
||||
|
|
|
@ -218,7 +218,7 @@ impl State {
|
|||
*self.framerate.denom() as u64,
|
||||
);
|
||||
|
||||
let pts = (self.last_frame_no * gst::SECOND)
|
||||
let pts = (self.last_frame_no * gst::ClockTime::SECOND)
|
||||
.mul_div_round(fps_d, fps_n)
|
||||
.unwrap();
|
||||
|
||||
|
@ -228,7 +228,7 @@ impl State {
|
|||
gst_debug!(CAT, obj: element, "More text than bandwidth!");
|
||||
}
|
||||
|
||||
let next_pts = (self.last_frame_no * gst::SECOND)
|
||||
let next_pts = (self.last_frame_no * gst::ClockTime::SECOND)
|
||||
.mul_div_round(fps_d, fps_n)
|
||||
.unwrap();
|
||||
|
||||
|
@ -567,10 +567,12 @@ impl TtToCea608 {
|
|||
*state.framerate.denom() as u64,
|
||||
);
|
||||
|
||||
let frame_no = (pts.mul_div_round(fps_n, fps_d).unwrap() / gst::SECOND).unwrap();
|
||||
let frame_no = pts.mul_div_round(fps_n, fps_d).unwrap().seconds();
|
||||
|
||||
state.max_frame_no =
|
||||
((pts + duration).mul_div_round(fps_n, fps_d).unwrap() / gst::SECOND).unwrap();
|
||||
state.max_frame_no = (pts + duration)
|
||||
.mul_div_round(fps_n, fps_d)
|
||||
.unwrap()
|
||||
.seconds();
|
||||
|
||||
state.pad(element, mut_list, frame_no);
|
||||
|
||||
|
@ -792,10 +794,8 @@ impl TtToCea608 {
|
|||
state.column = col;
|
||||
|
||||
if state.mode == Cea608Mode::PopOn {
|
||||
state.erase_display_frame_no = Some(
|
||||
state.last_frame_no
|
||||
+ (duration.mul_div_round(fps_n, fps_d).unwrap() / gst::SECOND).unwrap(),
|
||||
);
|
||||
state.erase_display_frame_no =
|
||||
Some(state.last_frame_no + duration.mul_div_round(fps_n, fps_d).unwrap().seconds());
|
||||
}
|
||||
|
||||
state.pad(element, mut_list, state.max_frame_no);
|
||||
|
@ -809,29 +809,23 @@ impl TtToCea608 {
|
|||
element: &super::TtToCea608,
|
||||
buffer: gst::Buffer,
|
||||
) -> Result<gst::FlowSuccess, gst::FlowError> {
|
||||
let pts = match buffer.pts() {
|
||||
gst::CLOCK_TIME_NONE => {
|
||||
gst::element_error!(
|
||||
element,
|
||||
gst::StreamError::Format,
|
||||
["Stream with timestamped buffers required"]
|
||||
);
|
||||
Err(gst::FlowError::Error)
|
||||
}
|
||||
pts => Ok(pts),
|
||||
}?;
|
||||
let pts = buffer.pts().ok_or_else(|| {
|
||||
gst::element_error!(
|
||||
element,
|
||||
gst::StreamError::Format,
|
||||
["Stream with timestamped buffers required"]
|
||||
);
|
||||
gst::FlowError::Error
|
||||
})?;
|
||||
|
||||
let duration = match buffer.duration() {
|
||||
gst::CLOCK_TIME_NONE => {
|
||||
gst::element_error!(
|
||||
element,
|
||||
gst::StreamError::Format,
|
||||
["Buffers of stream need to have a duration"]
|
||||
);
|
||||
Err(gst::FlowError::Error)
|
||||
}
|
||||
duration => Ok(duration),
|
||||
}?;
|
||||
let duration = buffer.duration().ok_or_else(|| {
|
||||
gst::element_error!(
|
||||
element,
|
||||
gst::StreamError::Format,
|
||||
["Buffers of stream need to have a duration"]
|
||||
);
|
||||
gst::FlowError::Error
|
||||
})?;
|
||||
|
||||
let data = buffer.map_readable().map_err(|_| {
|
||||
gst_error!(CAT, obj: pad, "Can't map buffer readable");
|
||||
|
@ -947,9 +941,10 @@ impl TtToCea608 {
|
|||
);
|
||||
|
||||
let (timestamp, duration) = e.get();
|
||||
let frame_no = ((timestamp + duration).mul_div_round(fps_n, fps_d).unwrap()
|
||||
/ gst::SECOND)
|
||||
.unwrap();
|
||||
let frame_no = (timestamp + duration.unwrap())
|
||||
.mul_div_round(fps_n, fps_d)
|
||||
.unwrap()
|
||||
.seconds();
|
||||
state.max_frame_no = frame_no;
|
||||
|
||||
let mut bufferlist = gst::BufferList::new();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// Boston, MA 02110-1335, USA.
|
||||
|
||||
use gst::prelude::*;
|
||||
use gst::ClockTime;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
|
@ -94,16 +95,37 @@ fn test_have_cc_data_notify() {
|
|||
});
|
||||
|
||||
/* valid cc608 data moves cc608 property to true */
|
||||
assert_push_data!(h, state, valid_cc608_data, 0.into(), 1, 0);
|
||||
assert_push_data!(h, state, valid_cc608_data, ClockTime::ZERO, 1, 0);
|
||||
|
||||
/* invalid cc608 data moves cc608 property to false */
|
||||
assert_push_data!(h, state, invalid_cc608_data, 1_000_000_000.into(), 2, 0);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
invalid_cc608_data,
|
||||
ClockTime::from_nseconds(1_000_000_000),
|
||||
2,
|
||||
0
|
||||
);
|
||||
|
||||
/* valid cc708 data moves cc708 property to true */
|
||||
assert_push_data!(h, state, valid_cc708_data, 2_000_000_000.into(), 2, 1);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
valid_cc708_data,
|
||||
ClockTime::from_nseconds(2_000_000_000),
|
||||
2,
|
||||
1
|
||||
);
|
||||
|
||||
/* invalid cc708 data moves cc708 property to false */
|
||||
assert_push_data!(h, state, invalid_cc708_data, 3_000_000_000.into(), 2, 2);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
invalid_cc708_data,
|
||||
ClockTime::from_nseconds(3_000_000_000),
|
||||
2,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -137,36 +159,57 @@ fn test_cc_data_window() {
|
|||
});
|
||||
|
||||
/* valid cc608 data moves cc608 property to true */
|
||||
assert_push_data!(h, state, valid_cc608_data.clone(), 0.into(), 1, 0);
|
||||
assert_push_data!(h, state, valid_cc608_data.clone(), ClockTime::ZERO, 1, 0);
|
||||
|
||||
/* valid cc608 data moves within window */
|
||||
assert_push_data!(h, state, valid_cc608_data.clone(), 300_000_000.into(), 1, 0);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
valid_cc608_data.clone(),
|
||||
ClockTime::from_nseconds(300_000_000),
|
||||
1,
|
||||
0
|
||||
);
|
||||
|
||||
/* invalid cc608 data before window expires, no change */
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
invalid_cc608_data.clone(),
|
||||
600_000_000.into(),
|
||||
ClockTime::from_nseconds(600_000_000),
|
||||
1,
|
||||
0
|
||||
);
|
||||
|
||||
/* invalid cc608 data after window expires, cc608 changes to false */
|
||||
assert_push_data!(h, state, invalid_cc608_data, 1_000_000_000.into(), 2, 0);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
invalid_cc608_data,
|
||||
ClockTime::from_nseconds(1_000_000_000),
|
||||
2,
|
||||
0
|
||||
);
|
||||
|
||||
/* valid cc608 data before window expires, no change */
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
valid_cc608_data.clone(),
|
||||
1_300_000_000.into(),
|
||||
ClockTime::from_nseconds(1_300_000_000),
|
||||
2,
|
||||
0
|
||||
);
|
||||
|
||||
/* valid cc608 data after window expires, property changes */
|
||||
assert_push_data!(h, state, valid_cc608_data, 1_600_000_000.into(), 3, 0);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
valid_cc608_data,
|
||||
ClockTime::from_nseconds(1_600_000_000),
|
||||
3,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -215,10 +258,17 @@ fn test_have_cdp_notify() {
|
|||
});
|
||||
|
||||
/* valid cc608 data moves cc608 property to true */
|
||||
assert_push_data!(h, state, valid_cc608_data, 0.into(), 1, 0);
|
||||
assert_push_data!(h, state, valid_cc608_data, ClockTime::ZERO, 1, 0);
|
||||
|
||||
/* invalid cc608 data moves cc608 property to false */
|
||||
assert_push_data!(h, state, invalid_cc608_data, 1_000_000_000.into(), 2, 0);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
invalid_cc608_data,
|
||||
ClockTime::from_nseconds(1_000_000_000),
|
||||
2,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -276,14 +326,56 @@ fn test_malformed_cdp_notify() {
|
|||
});
|
||||
|
||||
/* all invalid data does not change properties */
|
||||
assert_push_data!(h, state, too_short, 0.into(), 0, 0);
|
||||
assert_push_data!(h, state, wrong_magic, 1_000.into(), 0, 0);
|
||||
assert_push_data!(h, state, length_too_long, 2_000.into(), 0, 0);
|
||||
assert_push_data!(h, state, length_too_short, 3_000.into(), 0, 0);
|
||||
assert_push_data!(h, state, wrong_cc_data_header_byte, 4_000.into(), 0, 0);
|
||||
assert_push_data!(h, state, big_cc_count, 5_000.into(), 0, 0);
|
||||
assert_push_data!(h, state, wrong_cc_count_reserved_bits, 6_000.into(), 0, 0);
|
||||
assert_push_data!(h, state, cc608_after_cc708, 7_000.into(), 0, 0);
|
||||
assert_push_data!(h, state, too_short, ClockTime::from_nseconds(0), 0, 0);
|
||||
assert_push_data!(h, state, wrong_magic, ClockTime::from_nseconds(1_000), 0, 0);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
length_too_long,
|
||||
ClockTime::from_nseconds(2_000),
|
||||
0,
|
||||
0
|
||||
);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
length_too_short,
|
||||
ClockTime::from_nseconds(3_000),
|
||||
0,
|
||||
0
|
||||
);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
wrong_cc_data_header_byte,
|
||||
ClockTime::from_nseconds(4_000),
|
||||
0,
|
||||
0
|
||||
);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
big_cc_count,
|
||||
ClockTime::from_nseconds(5_000),
|
||||
0,
|
||||
0
|
||||
);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
wrong_cc_count_reserved_bits,
|
||||
ClockTime::from_nseconds(6_000),
|
||||
0,
|
||||
0
|
||||
);
|
||||
assert_push_data!(
|
||||
h,
|
||||
state,
|
||||
cc608_after_cc708,
|
||||
ClockTime::from_nseconds(7_000),
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -316,11 +408,14 @@ fn test_gap_events() {
|
|||
});
|
||||
|
||||
/* valid cc608 data moves cc608 property to true */
|
||||
assert_push_data!(h, state, valid_cc608_data, 0.into(), 1, 0);
|
||||
assert_push_data!(h, state, valid_cc608_data, ClockTime::ZERO, 1, 0);
|
||||
|
||||
/* pushing gap event within the window changes nothing */
|
||||
assert_eq!(
|
||||
h.push_event(gst::event::Gap::builder(100_000_000.into(), 1.into()).build()),
|
||||
h.push_event(gst::event::Gap::new(
|
||||
ClockTime::from_nseconds(100_000_000),
|
||||
ClockTime::from_nseconds(1)
|
||||
)),
|
||||
true
|
||||
);
|
||||
|
||||
|
@ -332,7 +427,10 @@ fn test_gap_events() {
|
|||
|
||||
/* pushing gap event outside the window moves cc608 property to false */
|
||||
assert_eq!(
|
||||
h.push_event(gst::event::Gap::builder(1_000_000_000.into(), 1.into()).build()),
|
||||
h.push_event(gst::event::Gap::new(
|
||||
ClockTime::from_nseconds(1_000_000_000),
|
||||
ClockTime::from_nseconds(1)
|
||||
)),
|
||||
true
|
||||
);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// Boston, MA 02110-1335, USA.
|
||||
|
||||
use gst::prelude::*;
|
||||
use gst::ClockTime;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
|
@ -42,25 +43,25 @@ fn test_parse() {
|
|||
assert_eq!(h.push(buf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
// Check the first 4 output buffers
|
||||
let expected: [(gst::ClockTime, gst::ClockTime, &'static str); 4] = [
|
||||
let expected: [(ClockTime, ClockTime, &'static str); 4] = [
|
||||
(
|
||||
15_048_366_666.into(),
|
||||
3_236_566_667.into(),
|
||||
ClockTime::from_nseconds(15_048_366_666),
|
||||
ClockTime::from_nseconds(3_236_566_667),
|
||||
"From New York,\r\nthis is Democracy Now!",
|
||||
),
|
||||
(
|
||||
18_985_633_333.into(),
|
||||
1_234_566_667.into(),
|
||||
ClockTime::from_nseconds(18_985_633_333),
|
||||
ClockTime::from_nseconds(1_234_566_667),
|
||||
"Yes, I’m supporting\r\nDonald Trump.",
|
||||
),
|
||||
(
|
||||
20_220_200_000.into(),
|
||||
2_168_833_333.into(),
|
||||
ClockTime::from_nseconds(20_220_200_000),
|
||||
ClockTime::from_nseconds(2_168_833_333),
|
||||
"I’m doing so as enthusiastically\r\nas I can,",
|
||||
),
|
||||
(
|
||||
22_389_033_333.into(),
|
||||
2_235_566_667.into(),
|
||||
ClockTime::from_nseconds(22_389_033_333),
|
||||
ClockTime::from_nseconds(2_235_566_667),
|
||||
"even the fact I think\r\nhe’s a terrible human being.",
|
||||
),
|
||||
];
|
||||
|
@ -68,10 +69,15 @@ fn test_parse() {
|
|||
for (i, e) in expected.iter().enumerate() {
|
||||
let buf = h.try_pull().unwrap();
|
||||
|
||||
assert_eq!(e.0, buf.pts(), "Unexpected PTS for {}th buffer", i + 1);
|
||||
assert_eq!(
|
||||
e.0,
|
||||
buf.pts().unwrap(),
|
||||
"Unexpected PTS for {}th buffer",
|
||||
i + 1
|
||||
);
|
||||
assert_eq!(
|
||||
e.1,
|
||||
buf.duration(),
|
||||
buf.duration().unwrap(),
|
||||
"Unexpected duration for {}th buffer",
|
||||
i + 1
|
||||
);
|
||||
|
|
|
@ -136,8 +136,8 @@ Time Code Rate=30DF\r\n\
|
|||
.tc();
|
||||
assert_eq!(timecode, tc);
|
||||
|
||||
let pts = buf.pts();
|
||||
assert_eq!(pts, gst::ClockTime::from_seconds(0));
|
||||
let pts = buf.pts().unwrap();
|
||||
assert_eq!(pts, gst::ClockTime::ZERO);
|
||||
|
||||
let map = buf.map_readable().expect("Couldn't map buffer readable");
|
||||
assert_eq!(
|
||||
|
|
|
@ -175,9 +175,9 @@ fn test_pull() {
|
|||
1.0,
|
||||
gst::SeekFlags::FLUSH,
|
||||
gst::SeekType::Set,
|
||||
gst::GenericFormattedValue::Time(gst::SECOND),
|
||||
gst::GenericFormattedValue::Time(Some(gst::ClockTime::SECOND)),
|
||||
gst::SeekType::Set,
|
||||
gst::GenericFormattedValue::Time(2 * gst::SECOND),
|
||||
gst::GenericFormattedValue::Time(Some(2 * gst::ClockTime::SECOND)),
|
||||
));
|
||||
|
||||
loop {
|
||||
|
@ -185,8 +185,8 @@ fn test_pull() {
|
|||
|
||||
while h.buffers_in_queue() != 0 {
|
||||
if let Ok(buffer) = h.pull() {
|
||||
let pts = buffer.pts();
|
||||
assert!(pts > gst::SECOND && pts < 2 * gst::SECOND);
|
||||
let pts = buffer.pts().unwrap();
|
||||
assert!(pts > gst::ClockTime::SECOND && pts < 2 * gst::ClockTime::SECOND);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,8 +69,8 @@ fn test_encode_single_packet() {
|
|||
.tc();
|
||||
assert_eq!(timecode, tc);
|
||||
|
||||
let pts = buf.pts();
|
||||
assert_eq!(pts, gst::ClockTime::from_seconds(0));
|
||||
let pts = buf.pts().unwrap();
|
||||
assert_eq!(pts, gst::ClockTime::ZERO);
|
||||
|
||||
let map = buf.map_readable().expect("Couldn't map buffer readable");
|
||||
assert_eq!(
|
||||
|
@ -168,8 +168,8 @@ fn test_encode_multiple_packets() {
|
|||
.tc();
|
||||
assert_eq!(timecode, tc1);
|
||||
|
||||
let pts = buf.pts();
|
||||
assert_eq!(pts, gst::ClockTime::from_seconds(0));
|
||||
let pts = buf.pts().unwrap();
|
||||
assert_eq!(pts, gst::ClockTime::ZERO);
|
||||
|
||||
let map = buf.map_readable().expect("Couldn't map buffer readable");
|
||||
|
||||
|
@ -186,8 +186,8 @@ fn test_encode_multiple_packets() {
|
|||
.tc();
|
||||
assert_eq!(timecode, tc2);
|
||||
|
||||
// let pts = buf.get_pts();
|
||||
// assert_eq!(pts, gst::ClockTime::from_seconds(0));
|
||||
// let pts = buf.get_pts().unwrap();
|
||||
// assert_eq!(pts, gst::ClockTime::ZERO);
|
||||
|
||||
let map = buf.map_readable().expect("Couldn't map buffer readable");
|
||||
assert_eq!(
|
||||
|
@ -215,8 +215,8 @@ fn test_encode_multiple_packets() {
|
|||
.tc();
|
||||
assert_eq!(timecode, tc3);
|
||||
|
||||
// let pts = buf.get_pts();
|
||||
// assert_eq!(pts, gst::ClockTime::from_seconds(0));
|
||||
// let pts = buf.get_pts().unwrap();
|
||||
// assert_eq!(pts, gst::ClockTime::ZERO);
|
||||
|
||||
let map = buf.map_readable().expect("Couldn't map buffer readable");
|
||||
assert_eq!(
|
||||
|
|
|
@ -245,9 +245,9 @@ fn test_pull() {
|
|||
1.0,
|
||||
gst::SeekFlags::FLUSH,
|
||||
gst::SeekType::Set,
|
||||
gst::GenericFormattedValue::Time(18 * gst::SECOND),
|
||||
gst::GenericFormattedValue::Time(Some(18 * gst::ClockTime::SECOND)),
|
||||
gst::SeekType::Set,
|
||||
gst::GenericFormattedValue::Time(19 * gst::SECOND),
|
||||
gst::GenericFormattedValue::Time(Some(19 * gst::ClockTime::SECOND)),
|
||||
));
|
||||
|
||||
loop {
|
||||
|
@ -255,10 +255,12 @@ fn test_pull() {
|
|||
|
||||
while h.buffers_in_queue() != 0 {
|
||||
if let Ok(buffer) = h.pull() {
|
||||
let pts = buffer.pts();
|
||||
let end_time = pts + buffer.duration();
|
||||
let pts = buffer.pts().unwrap();
|
||||
let end_time = pts + buffer.duration().unwrap();
|
||||
|
||||
assert!(end_time >= 18 * gst::SECOND && pts < 19 * gst::SECOND);
|
||||
assert!(
|
||||
end_time >= 18 * gst::ClockTime::SECOND && pts < 19 * gst::ClockTime::SECOND
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
|
||||
// Boston, MA 02110-1335, USA.
|
||||
|
||||
use gst::ClockTime;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
fn init() {
|
||||
|
@ -29,8 +30,8 @@ fn init() {
|
|||
|
||||
fn new_timed_buffer<T: AsRef<[u8]> + Send + 'static>(
|
||||
slice: T,
|
||||
timestamp: gst::ClockTime,
|
||||
duration: gst::ClockTime,
|
||||
timestamp: ClockTime,
|
||||
duration: ClockTime,
|
||||
) -> gst::buffer::Buffer {
|
||||
let mut buf = gst::Buffer::from_slice(slice);
|
||||
let buf_ref = buf.get_mut().unwrap();
|
||||
|
@ -63,13 +64,13 @@ fn test_one_timed_buffer_and_eos() {
|
|||
let _event = h.pull_event().unwrap();
|
||||
}
|
||||
|
||||
let inbuf = new_timed_buffer(&"Hello", gst::SECOND, gst::SECOND);
|
||||
let inbuf = new_timed_buffer(&"Hello", ClockTime::SECOND, ClockTime::SECOND);
|
||||
|
||||
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
loop {
|
||||
let outbuf = h.pull().unwrap();
|
||||
if outbuf.pts() + outbuf.duration() >= gst::SECOND {
|
||||
if outbuf.pts().unwrap() + outbuf.duration().unwrap() >= ClockTime::SECOND {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -77,23 +78,56 @@ fn test_one_timed_buffer_and_eos() {
|
|||
assert_eq!(&*data, &[0x80, 0x80]);
|
||||
}
|
||||
|
||||
let expected: [(gst::ClockTime, gst::ClockTime, [u8; 2usize]); 7] = [
|
||||
(1_000_000_000.into(), 33_333_333.into(), [0x94, 0x20]), /* resume_caption_loading */
|
||||
(1_033_333_333.into(), 33_333_334.into(), [0x94, 0xae]), /* erase_non_displayed_memory */
|
||||
(1_066_666_667.into(), 33_333_333.into(), [0x94, 0x70]), /* preamble */
|
||||
(1_100_000_000.into(), 33_333_333.into(), [0xc8, 0xe5]), /* H e */
|
||||
(1_133_333_333.into(), 33_333_334.into(), [0xec, 0xec]), /* l l */
|
||||
(1_166_666_667.into(), 33_333_333.into(), [0xef, 0x80]), /* o, nil */
|
||||
(1_200_000_000.into(), 33_333_333.into(), [0x94, 0x2f]), /* end_of_caption */
|
||||
let expected: [(ClockTime, ClockTime, [u8; 2usize]); 7] = [
|
||||
(
|
||||
ClockTime::from_nseconds(1_000_000_000),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0x94, 0x20],
|
||||
), /* resume_caption_loading */
|
||||
(
|
||||
ClockTime::from_nseconds(1_033_333_333),
|
||||
ClockTime::from_nseconds(33_333_334),
|
||||
[0x94, 0xae],
|
||||
), /* erase_non_displayed_memory */
|
||||
(
|
||||
ClockTime::from_nseconds(1_066_666_667),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0x94, 0x70],
|
||||
), /* preamble */
|
||||
(
|
||||
ClockTime::from_nseconds(1_100_000_000),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0xc8, 0xe5],
|
||||
), /* H e */
|
||||
(
|
||||
ClockTime::from_nseconds(1_133_333_333),
|
||||
ClockTime::from_nseconds(33_333_334),
|
||||
[0xec, 0xec],
|
||||
), /* l l */
|
||||
(
|
||||
ClockTime::from_nseconds(1_166_666_667),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0xef, 0x80],
|
||||
), /* o, nil */
|
||||
(
|
||||
ClockTime::from_nseconds(1_200_000_000),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0x94, 0x2f],
|
||||
), /* end_of_caption */
|
||||
];
|
||||
|
||||
for (i, e) in expected.iter().enumerate() {
|
||||
let outbuf = h.try_pull().unwrap();
|
||||
|
||||
assert_eq!(e.0, outbuf.pts(), "Unexpected PTS for {}th buffer", i + 1);
|
||||
assert_eq!(
|
||||
e.0,
|
||||
outbuf.pts().unwrap(),
|
||||
"Unexpected PTS for {}th buffer",
|
||||
i + 1
|
||||
);
|
||||
assert_eq!(
|
||||
e.1,
|
||||
outbuf.duration(),
|
||||
outbuf.duration().unwrap(),
|
||||
"Unexpected duration for {}th buffer",
|
||||
i + 1
|
||||
);
|
||||
|
@ -110,7 +144,7 @@ fn test_one_timed_buffer_and_eos() {
|
|||
loop {
|
||||
let outbuf = h.try_pull().unwrap();
|
||||
let data = outbuf.map_readable().unwrap();
|
||||
if outbuf.pts() == 2_200_000_000.into() {
|
||||
if outbuf.pts().unwrap() == ClockTime::from_nseconds(2_200_000_000) {
|
||||
assert_eq!(&*data, &[0x94, 0x2c]);
|
||||
break;
|
||||
} else {
|
||||
|
@ -139,10 +173,18 @@ fn test_erase_display_memory_non_spliced() {
|
|||
let _event = h.pull_event().unwrap();
|
||||
}
|
||||
|
||||
let inbuf = new_timed_buffer(&"Hello", 1_000_000_000.into(), gst::SECOND);
|
||||
let inbuf = new_timed_buffer(
|
||||
&"Hello",
|
||||
ClockTime::from_nseconds(1_000_000_000),
|
||||
ClockTime::SECOND,
|
||||
);
|
||||
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
let inbuf = new_timed_buffer(&"World", 3_000_000_000.into(), gst::SECOND);
|
||||
let inbuf = new_timed_buffer(
|
||||
&"World",
|
||||
ClockTime::from_nseconds(3_000_000_000),
|
||||
ClockTime::SECOND,
|
||||
);
|
||||
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
let mut erase_display_buffers = 0;
|
||||
|
@ -150,7 +192,7 @@ fn test_erase_display_memory_non_spliced() {
|
|||
while h.buffers_in_queue() > 0 {
|
||||
let outbuf = h.pull().unwrap();
|
||||
|
||||
if outbuf.pts() == 2_200_000_000.into() {
|
||||
if outbuf.pts().unwrap() == ClockTime::from_nseconds(2_200_000_000) {
|
||||
let data = outbuf.map_readable().unwrap();
|
||||
assert_eq!(&*data, &[0x94, 0x2c]);
|
||||
erase_display_buffers += 1;
|
||||
|
@ -175,28 +217,37 @@ fn test_erase_display_memory_spliced() {
|
|||
let _event = h.pull_event().unwrap();
|
||||
}
|
||||
|
||||
let inbuf = new_timed_buffer(&"Hello", 1_000_000_000.into(), gst::SECOND);
|
||||
let inbuf = new_timed_buffer(
|
||||
&"Hello",
|
||||
ClockTime::from_nseconds(1_000_000_000),
|
||||
ClockTime::SECOND,
|
||||
);
|
||||
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
let inbuf = new_timed_buffer(&"World", 2_000_000_000.into(), gst::SECOND);
|
||||
let inbuf = new_timed_buffer(
|
||||
&"World",
|
||||
ClockTime::from_nseconds(2_000_000_000),
|
||||
ClockTime::SECOND,
|
||||
);
|
||||
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
let mut erase_display_buffers = 0;
|
||||
let mut prev_pts: gst::ClockTime = 0.into();
|
||||
let mut prev_pts: ClockTime = ClockTime::ZERO;
|
||||
|
||||
while h.buffers_in_queue() > 0 {
|
||||
let outbuf = h.pull().unwrap();
|
||||
|
||||
/* Check that our timestamps are strictly ascending */
|
||||
assert!(outbuf.pts() >= prev_pts);
|
||||
let pts = outbuf.pts().unwrap();
|
||||
assert!(pts >= prev_pts);
|
||||
|
||||
if outbuf.pts() == 2_000_000_000.into() {
|
||||
if pts == ClockTime::from_nseconds(2_000_000_000) {
|
||||
let data = outbuf.map_readable().unwrap();
|
||||
assert_eq!(&*data, &[0x94, 0x2c]);
|
||||
erase_display_buffers += 1;
|
||||
}
|
||||
|
||||
prev_pts = outbuf.pts();
|
||||
prev_pts = pts;
|
||||
}
|
||||
|
||||
assert_eq!(erase_display_buffers, 1);
|
||||
|
@ -216,10 +267,18 @@ fn test_output_gaps() {
|
|||
let _event = h.pull_event().unwrap();
|
||||
}
|
||||
|
||||
let inbuf = new_timed_buffer(&"Hello", 1_000_000_000.into(), gst::SECOND);
|
||||
let inbuf = new_timed_buffer(
|
||||
&"Hello",
|
||||
ClockTime::from_nseconds(1_000_000_000),
|
||||
ClockTime::SECOND,
|
||||
);
|
||||
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
let inbuf = new_timed_buffer(&"World", 3_000_000_000.into(), gst::SECOND);
|
||||
let inbuf = new_timed_buffer(
|
||||
&"World",
|
||||
ClockTime::from_nseconds(3_000_000_000),
|
||||
ClockTime::SECOND,
|
||||
);
|
||||
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
h.push_event(gst::event::Eos::new());
|
||||
|
@ -227,7 +286,7 @@ fn test_output_gaps() {
|
|||
/* Padding */
|
||||
loop {
|
||||
let outbuf = h.pull().unwrap();
|
||||
if outbuf.pts() + outbuf.duration() >= gst::SECOND {
|
||||
if outbuf.pts().unwrap() + outbuf.duration().unwrap() >= ClockTime::SECOND {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -238,7 +297,9 @@ fn test_output_gaps() {
|
|||
/* Hello */
|
||||
loop {
|
||||
let outbuf = h.pull().unwrap();
|
||||
if outbuf.pts() + outbuf.duration() >= 1_233_333_333.into() {
|
||||
if outbuf.pts().unwrap() + outbuf.duration().unwrap()
|
||||
>= ClockTime::from_nseconds(1_233_333_333)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -249,12 +310,14 @@ fn test_output_gaps() {
|
|||
/* Padding */
|
||||
loop {
|
||||
let outbuf = h.pull().unwrap();
|
||||
if outbuf.pts() + outbuf.duration() >= 3_000_000_000.into() {
|
||||
if outbuf.pts().unwrap() + outbuf.duration().unwrap()
|
||||
>= ClockTime::from_nseconds(3_000_000_000)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
let data = outbuf.map_readable().unwrap();
|
||||
if outbuf.pts() == 2_200_000_000.into() {
|
||||
if outbuf.pts().unwrap() == ClockTime::from_nseconds(2_200_000_000) {
|
||||
/* Erase display one second after Hello */
|
||||
assert_eq!(&*data, &[0x94, 0x2C]);
|
||||
} else {
|
||||
|
@ -265,7 +328,9 @@ fn test_output_gaps() {
|
|||
/* World */
|
||||
loop {
|
||||
let outbuf = h.pull().unwrap();
|
||||
if outbuf.pts() + outbuf.duration() >= 3_233_333_333.into() {
|
||||
if outbuf.pts().unwrap() + outbuf.duration().unwrap()
|
||||
>= ClockTime::from_nseconds(3_233_333_333)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -290,16 +355,16 @@ fn test_one_timed_buffer_and_eos_roll_up2() {
|
|||
let _event = h.pull_event().unwrap();
|
||||
}
|
||||
|
||||
let inbuf = new_timed_buffer(&"Hello", gst::SECOND, gst::SECOND);
|
||||
let inbuf = new_timed_buffer(&"Hello", ClockTime::SECOND, ClockTime::SECOND);
|
||||
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
let inbuf = new_timed_buffer(&"World", 2 * gst::SECOND, 1.into());
|
||||
let inbuf = new_timed_buffer(&"World", 2 * ClockTime::SECOND, ClockTime::from_nseconds(1));
|
||||
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
/* Padding */
|
||||
loop {
|
||||
let outbuf = h.pull().unwrap();
|
||||
if outbuf.pts() + outbuf.duration() >= gst::SECOND {
|
||||
if outbuf.pts().unwrap() + outbuf.duration().unwrap() >= ClockTime::SECOND {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -307,21 +372,46 @@ fn test_one_timed_buffer_and_eos_roll_up2() {
|
|||
assert_eq!(&*data, &[0x80, 0x80]);
|
||||
}
|
||||
|
||||
let expected: [(gst::ClockTime, gst::ClockTime, [u8; 2usize]); 5] = [
|
||||
(1_000_000_000.into(), 33_333_333.into(), [0x94, 0x25]), /* roll_up_2 */
|
||||
(1_033_333_333.into(), 33_333_334.into(), [0x94, 0x70]), /* preamble */
|
||||
(1_066_666_667.into(), 33_333_333.into(), [0xc8, 0xe5]), /* H e */
|
||||
(1_100_000_000.into(), 33_333_333.into(), [0xec, 0xec]), /* l l */
|
||||
(1_133_333_333.into(), 33_333_334.into(), [0xef, 0x80]), /* o nil */
|
||||
let expected: [(ClockTime, ClockTime, [u8; 2usize]); 5] = [
|
||||
(
|
||||
ClockTime::from_nseconds(1_000_000_000),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0x94, 0x25],
|
||||
), /* roll_up_2 */
|
||||
(
|
||||
ClockTime::from_nseconds(1_033_333_333),
|
||||
ClockTime::from_nseconds(33_333_334),
|
||||
[0x94, 0x70],
|
||||
), /* preamble */
|
||||
(
|
||||
ClockTime::from_nseconds(1_066_666_667),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0xc8, 0xe5],
|
||||
), /* H e */
|
||||
(
|
||||
ClockTime::from_nseconds(1_100_000_000),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0xec, 0xec],
|
||||
), /* l l */
|
||||
(
|
||||
ClockTime::from_nseconds(1_133_333_333),
|
||||
ClockTime::from_nseconds(33_333_334),
|
||||
[0xef, 0x80],
|
||||
), /* o nil */
|
||||
];
|
||||
|
||||
for (i, e) in expected.iter().enumerate() {
|
||||
let outbuf = h.try_pull().unwrap();
|
||||
|
||||
assert_eq!(e.0, outbuf.pts(), "Unexpected PTS for {}th buffer", i + 1);
|
||||
assert_eq!(
|
||||
e.0,
|
||||
outbuf.pts().unwrap(),
|
||||
"Unexpected PTS for {}th buffer",
|
||||
i + 1
|
||||
);
|
||||
assert_eq!(
|
||||
e.1,
|
||||
outbuf.duration(),
|
||||
outbuf.duration().unwrap(),
|
||||
"Unexpected duration for {}th buffer",
|
||||
i + 1
|
||||
);
|
||||
|
@ -333,7 +423,7 @@ fn test_one_timed_buffer_and_eos_roll_up2() {
|
|||
/* Padding */
|
||||
loop {
|
||||
let outbuf = h.pull().unwrap();
|
||||
if outbuf.pts() + outbuf.duration() >= 2 * gst::SECOND {
|
||||
if outbuf.pts().unwrap() + outbuf.duration().unwrap() >= 2 * ClockTime::SECOND {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -341,19 +431,36 @@ fn test_one_timed_buffer_and_eos_roll_up2() {
|
|||
assert_eq!(&*data, &[0x80, 0x80]);
|
||||
}
|
||||
|
||||
let expected: [(gst::ClockTime, gst::ClockTime, [u8; 2usize]); 3] = [
|
||||
(2_000_000_000.into(), 0.into(), [0x20, 0x57]), /* SPACE W */
|
||||
(2_000_000_000.into(), 0.into(), [0xef, 0xf2]), /* o r */
|
||||
(2_000_000_000.into(), 0.into(), [0xec, 0x64]), /* l d */
|
||||
let expected: [(ClockTime, ClockTime, [u8; 2usize]); 3] = [
|
||||
(
|
||||
ClockTime::from_nseconds(2_000_000_000),
|
||||
ClockTime::ZERO,
|
||||
[0x20, 0x57],
|
||||
), /* SPACE W */
|
||||
(
|
||||
ClockTime::from_nseconds(2_000_000_000),
|
||||
ClockTime::ZERO,
|
||||
[0xef, 0xf2],
|
||||
), /* o r */
|
||||
(
|
||||
ClockTime::from_nseconds(2_000_000_000),
|
||||
ClockTime::ZERO,
|
||||
[0xec, 0x64],
|
||||
), /* l d */
|
||||
];
|
||||
|
||||
for (i, e) in expected.iter().enumerate() {
|
||||
let outbuf = h.try_pull().unwrap();
|
||||
|
||||
assert_eq!(e.0, outbuf.pts(), "Unexpected PTS for {}th buffer", i + 1);
|
||||
assert_eq!(
|
||||
e.0,
|
||||
outbuf.pts().unwrap(),
|
||||
"Unexpected PTS for {}th buffer",
|
||||
i + 1
|
||||
);
|
||||
assert_eq!(
|
||||
e.1,
|
||||
outbuf.duration(),
|
||||
outbuf.duration().unwrap(),
|
||||
"Unexpected duration for {}th buffer",
|
||||
i + 1
|
||||
);
|
||||
|
@ -387,13 +494,13 @@ fn test_word_wrap_roll_up() {
|
|||
let _event = h.pull_event().unwrap();
|
||||
}
|
||||
|
||||
let inbuf = new_timed_buffer(&"Hello World", gst::SECOND, gst::SECOND);
|
||||
let inbuf = new_timed_buffer(&"Hello World", ClockTime::SECOND, ClockTime::SECOND);
|
||||
assert_eq!(h.push(inbuf), Ok(gst::FlowSuccess::Ok));
|
||||
|
||||
/* Padding */
|
||||
loop {
|
||||
let outbuf = h.pull().unwrap();
|
||||
if outbuf.pts() + outbuf.duration() >= gst::SECOND {
|
||||
if outbuf.pts().unwrap() + outbuf.duration().unwrap() >= ClockTime::SECOND {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -401,27 +508,76 @@ fn test_word_wrap_roll_up() {
|
|||
assert_eq!(&*data, &[0x80, 0x80]);
|
||||
}
|
||||
|
||||
let expected: [(gst::ClockTime, gst::ClockTime, [u8; 2usize]); 11] = [
|
||||
(1_000_000_000.into(), 33_333_333.into(), [0x94, 0x25]), /* roll_up_2 */
|
||||
(1_033_333_333.into(), 33_333_334.into(), [0x94, 0x7c]), /* preamble */
|
||||
(1_066_666_667.into(), 33_333_333.into(), [0xc8, 0xe5]), /* H e */
|
||||
(1_100_000_000.into(), 33_333_333.into(), [0xec, 0xec]), /* l l */
|
||||
(1_133_333_333.into(), 33_333_334.into(), [0xef, 0x20]), /* o SPACE */
|
||||
(1_166_666_667.into(), 33_333_333.into(), [0x94, 0xad]), /* carriage return */
|
||||
(1_200_000_000.into(), 33_333_333.into(), [0x94, 0x25]), /* roll_up_2 */
|
||||
(1_233_333_333.into(), 33_333_334.into(), [0x94, 0x7c]), /* preamble */
|
||||
(1_266_666_667.into(), 33_333_333.into(), [0x57, 0xef]), /* W o */
|
||||
(1_300_000_000.into(), 33_333_333.into(), [0xf2, 0xec]), /* r l */
|
||||
(1_333_333_333.into(), 33_333_334.into(), [0x64, 0x80]), /* d nil */
|
||||
let expected: [(ClockTime, ClockTime, [u8; 2usize]); 11] = [
|
||||
(
|
||||
ClockTime::from_nseconds(1_000_000_000),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0x94, 0x25],
|
||||
), /* roll_up_2 */
|
||||
(
|
||||
ClockTime::from_nseconds(1_033_333_333),
|
||||
ClockTime::from_nseconds(33_333_334),
|
||||
[0x94, 0x7c],
|
||||
), /* preamble */
|
||||
(
|
||||
ClockTime::from_nseconds(1_066_666_667),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0xc8, 0xe5],
|
||||
), /* H e */
|
||||
(
|
||||
ClockTime::from_nseconds(1_100_000_000),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0xec, 0xec],
|
||||
), /* l l */
|
||||
(
|
||||
ClockTime::from_nseconds(1_133_333_333),
|
||||
ClockTime::from_nseconds(33_333_334),
|
||||
[0xef, 0x20],
|
||||
), /* o SPACE */
|
||||
(
|
||||
ClockTime::from_nseconds(1_166_666_667),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0x94, 0xad],
|
||||
), /* carriage return */
|
||||
(
|
||||
ClockTime::from_nseconds(1_200_000_000),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0x94, 0x25],
|
||||
), /* roll_up_2 */
|
||||
(
|
||||
ClockTime::from_nseconds(1_233_333_333),
|
||||
ClockTime::from_nseconds(33_333_334),
|
||||
[0x94, 0x7c],
|
||||
), /* preamble */
|
||||
(
|
||||
ClockTime::from_nseconds(1_266_666_667),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0x57, 0xef],
|
||||
), /* W o */
|
||||
(
|
||||
ClockTime::from_nseconds(1_300_000_000),
|
||||
ClockTime::from_nseconds(33_333_333),
|
||||
[0xf2, 0xec],
|
||||
), /* r l */
|
||||
(
|
||||
ClockTime::from_nseconds(1_333_333_333),
|
||||
ClockTime::from_nseconds(33_333_334),
|
||||
[0x64, 0x80],
|
||||
), /* d nil */
|
||||
];
|
||||
|
||||
for (i, e) in expected.iter().enumerate() {
|
||||
let outbuf = h.try_pull().unwrap();
|
||||
|
||||
assert_eq!(e.0, outbuf.pts(), "Unexpected PTS for {}th buffer", i + 1);
|
||||
assert_eq!(
|
||||
e.0,
|
||||
outbuf.pts().unwrap(),
|
||||
"Unexpected PTS for {}th buffer",
|
||||
i + 1
|
||||
);
|
||||
assert_eq!(
|
||||
e.1,
|
||||
outbuf.duration(),
|
||||
outbuf.duration().unwrap(),
|
||||
"Unexpected duration for {}th buffer",
|
||||
i + 1
|
||||
);
|
||||
|
|
|
@ -138,8 +138,8 @@ impl Dav1dDec {
|
|||
frame: &gst_video::VideoCodecFrame,
|
||||
) -> Result<Vec<(dav1d::Picture, gst_video::VideoFormat)>, gst::FlowError> {
|
||||
let mut decoder = self.decoder.lock().unwrap();
|
||||
let timestamp = frame.dts().0.map(|ts| ts as i64);
|
||||
let duration = frame.duration().0.map(|d| d as i64);
|
||||
let timestamp = frame.dts().map(|ts| *ts as i64);
|
||||
let duration = frame.duration().map(|d| *d as i64);
|
||||
|
||||
let frame_number = Some(frame.system_frame_number() as i64);
|
||||
let input_data = input_buffer
|
||||
|
|
|
@ -72,7 +72,7 @@ struct StreamingState {
|
|||
video: Option<VideoFormat>,
|
||||
expect_video: bool,
|
||||
got_all_streams: bool,
|
||||
last_position: gst::ClockTime,
|
||||
last_position: Option<gst::ClockTime>,
|
||||
|
||||
metadata: Option<Metadata>,
|
||||
|
||||
|
@ -103,7 +103,7 @@ struct VideoFormat {
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
||||
struct Metadata {
|
||||
duration: gst::ClockTime,
|
||||
duration: Option<gst::ClockTime>,
|
||||
|
||||
creation_date: Option<String>,
|
||||
creator: Option<String>,
|
||||
|
@ -683,7 +683,7 @@ impl StreamingState {
|
|||
video: None,
|
||||
expect_video: video,
|
||||
got_all_streams: false,
|
||||
last_position: gst::CLOCK_TIME_NONE,
|
||||
last_position: gst::ClockTime::NONE,
|
||||
metadata: None,
|
||||
aac_sequence_header: None,
|
||||
avc_sequence_header: None,
|
||||
|
@ -1197,12 +1197,16 @@ impl StreamingState {
|
|||
}
|
||||
|
||||
fn update_position(&mut self, buffer: &gst::Buffer) {
|
||||
if buffer.pts().is_some() {
|
||||
let pts = buffer.pts();
|
||||
self.last_position = self.last_position.max(pts).unwrap_or(pts);
|
||||
} else if buffer.dts().is_some() {
|
||||
let dts = buffer.dts();
|
||||
self.last_position = self.last_position.max(dts).unwrap_or(dts);
|
||||
if let Some(pts) = buffer.pts() {
|
||||
self.last_position = self
|
||||
.last_position
|
||||
.map(|last_pos| last_pos.max(pts))
|
||||
.or(Some(pts));
|
||||
} else if let Some(dts) = buffer.dts() {
|
||||
self.last_position = self
|
||||
.last_position
|
||||
.map(|last_pos| last_pos.max(dts))
|
||||
.or(Some(dts));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1521,7 +1525,9 @@ impl Metadata {
|
|||
for arg in args {
|
||||
match (arg.name, &arg.data) {
|
||||
("duration", &flavors::ScriptDataValue::Number(duration)) => {
|
||||
metadata.duration = ((duration * 1000.0 * 1000.0 * 1000.0) as u64).into();
|
||||
metadata.duration = Some(gst::ClockTime::from_nseconds(
|
||||
(duration * 1000.0 * 1000.0 * 1000.0) as u64,
|
||||
));
|
||||
}
|
||||
("creationdate", &flavors::ScriptDataValue::String(date)) => {
|
||||
metadata.creation_date = Some(String::from(date));
|
||||
|
|
|
@ -30,7 +30,7 @@ fn main() {
|
|||
.set_state(gst::State::Playing)
|
||||
.expect("Failed to set pipeline state to playing");
|
||||
|
||||
for msg in bus.iter_timed(gst::CLOCK_TIME_NONE) {
|
||||
for msg in bus.iter_timed(gst::ClockTime::NONE) {
|
||||
use gst::MessageView;
|
||||
|
||||
match msg.view() {
|
||||
|
|
|
@ -84,7 +84,7 @@ struct State {
|
|||
video_info: gst_video::VideoInfo,
|
||||
cache: Arc<CacheBuffer>,
|
||||
gif_pts: Option<gst::ClockTime>,
|
||||
last_actual_pts: gst::ClockTime,
|
||||
last_actual_pts: Option<gst::ClockTime>,
|
||||
context: Option<gif::Encoder<CacheBufferWriter>>,
|
||||
}
|
||||
|
||||
|
@ -94,14 +94,14 @@ impl State {
|
|||
video_info,
|
||||
cache: Arc::new(CacheBuffer::new()),
|
||||
gif_pts: None,
|
||||
last_actual_pts: gst::ClockTime::none(),
|
||||
last_actual_pts: None,
|
||||
context: None,
|
||||
}
|
||||
}
|
||||
pub fn reset(&mut self, settings: Settings) {
|
||||
self.cache.clear();
|
||||
self.gif_pts = None;
|
||||
self.last_actual_pts = gst::ClockTime::none();
|
||||
self.last_actual_pts = None;
|
||||
// initialize and configure encoder with a CacheBufferWriter pointing
|
||||
// to our CacheBuffer instance
|
||||
let mut encoder = gif::Encoder::new(
|
||||
|
@ -321,20 +321,30 @@ impl VideoEncoderImpl for GifEnc {
|
|||
// Calculate delay to new frame by calculating the difference between the current actual
|
||||
// presentation timestamp of the last frame within the gif, and the pts of the new frame.
|
||||
// This results in variable frame delays in the gif - but an overall constant fps.
|
||||
state.last_actual_pts = in_frame.buffer().pts();
|
||||
let pts = in_frame.buffer().pts();
|
||||
state.last_actual_pts = pts;
|
||||
if state.gif_pts.is_none() {
|
||||
// First frame: use pts of first input frame as origin
|
||||
state.gif_pts = Some(in_frame.buffer().pts());
|
||||
state.gif_pts = pts;
|
||||
}
|
||||
let frame_delay = in_frame.buffer().pts() - state.gif_pts.unwrap();
|
||||
if frame_delay.is_none() {
|
||||
let pts = pts.ok_or_else(|| {
|
||||
gst::element_error!(
|
||||
element,
|
||||
gst::CoreError::Failed,
|
||||
["No PTS set on input frame. Unable to calculate proper frame timing."]
|
||||
);
|
||||
return Err(gst::FlowError::Error);
|
||||
}
|
||||
gst::FlowError::Error
|
||||
})?;
|
||||
let frame_delay = pts
|
||||
.checked_sub(state.gif_pts.expect("checked above"))
|
||||
.ok_or_else(|| {
|
||||
gst::element_error!(
|
||||
element,
|
||||
gst::CoreError::Failed,
|
||||
["Input frame PTS is greater than gif_pts. Unable to calculate proper frame timing."]
|
||||
);
|
||||
gst::FlowError::Error
|
||||
})?;
|
||||
|
||||
let mut raw_frame = tightly_packed_framebuffer(&in_frame);
|
||||
let mut gif_frame = match in_frame.info().format() {
|
||||
|
@ -361,10 +371,10 @@ impl VideoEncoderImpl for GifEnc {
|
|||
// use float arithmetic with rounding for this calculation, since small stuttering
|
||||
// is probably less visible than the large stuttering when a complete 10ms have to
|
||||
// "catch up".
|
||||
gif_frame.delay = (frame_delay.mseconds().unwrap() as f32 / 10.0).round() as u16;
|
||||
state.gif_pts.replace(
|
||||
state.gif_pts.unwrap() + gst::ClockTime::from_mseconds(gif_frame.delay as u64 * 10),
|
||||
);
|
||||
gif_frame.delay = (frame_delay.mseconds() as f32 / 10.0).round() as u16;
|
||||
state.gif_pts = state.gif_pts.map(|gif_pts| {
|
||||
gif_pts + gst::ClockTime::from_mseconds(gif_frame.delay as u64 * 10)
|
||||
});
|
||||
|
||||
// encode new frame
|
||||
let context = state.context.as_mut().unwrap();
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
use gst::prelude::*;
|
||||
|
||||
const ENCODE_PIPELINE: &str = "videotestsrc is-live=false num-buffers=1 ! videoconvert ! video/x-raw, format=RGB, width=160, height=120 !
|
||||
const ENCODE_PIPELINE: &str = "videotestsrc is-live=false num-buffers=1 ! videoconvert ! video/x-raw, format=RGB, width=160, height=120 !
|
||||
rspngenc compression-level=2 filter=4 ! filesink location=frame.png";
|
||||
|
||||
fn main() {
|
||||
|
@ -22,7 +22,7 @@ fn main() {
|
|||
.set_state(gst::State::Playing)
|
||||
.expect("Failed to set pipeline state to playing");
|
||||
|
||||
for msg in bus.iter_timed(gst::CLOCK_TIME_NONE) {
|
||||
for msg in bus.iter_timed(gst::ClockTime::NONE) {
|
||||
use gst::MessageView;
|
||||
|
||||
match msg.view() {
|
||||
|
|
|
@ -169,7 +169,7 @@ impl WebPDec {
|
|||
}
|
||||
|
||||
fn decode(&self, _element: &super::WebPDec) -> Result<(), gst::ErrorMessage> {
|
||||
let mut prev_timestamp: gst::ClockTime = 0.into();
|
||||
let mut prev_timestamp: Option<gst::ClockTime> = Some(gst::ClockTime::ZERO);
|
||||
let mut state = self.state.lock().unwrap();
|
||||
|
||||
if state.buffers.is_empty() {
|
||||
|
@ -223,8 +223,9 @@ impl WebPDec {
|
|||
gst::error_msg!(gst::StreamError::Decode, ["Failed to get next frame"])
|
||||
})?;
|
||||
|
||||
let timestamp = frame.timestamp as u64 * gst::MSECOND;
|
||||
let duration = timestamp - prev_timestamp;
|
||||
let timestamp = frame.timestamp as u64 * gst::ClockTime::MSECOND;
|
||||
let duration =
|
||||
prev_timestamp.and_then(|prev_timestamp| timestamp.checked_sub(prev_timestamp));
|
||||
|
||||
let mut out_buf =
|
||||
gst::Buffer::with_size((info.width * info.height * 4) as usize).unwrap();
|
||||
|
@ -235,7 +236,7 @@ impl WebPDec {
|
|||
out_buf_mut.set_duration(duration);
|
||||
}
|
||||
|
||||
prev_timestamp = timestamp;
|
||||
prev_timestamp = Some(timestamp);
|
||||
|
||||
match self.srcpad.push(out_buf) {
|
||||
Ok(_) => (),
|
||||
|
|
|
@ -40,15 +40,17 @@ fn test_decode() {
|
|||
assert_eq!(h.push(buf), Ok(gst::FlowSuccess::Ok));
|
||||
h.push_event(gst::event::Eos::new());
|
||||
|
||||
let mut expected_timestamp: gst::ClockTime = 0.into();
|
||||
let mut expected_timestamp: Option<gst::ClockTime> = Some(gst::ClockTime::ZERO);
|
||||
let mut count = 0;
|
||||
let expected_duration: gst::ClockTime = 40_000_000.into();
|
||||
let expected_duration: Option<gst::ClockTime> = Some(gst::ClockTime::from_nseconds(40_000_000));
|
||||
|
||||
while let Some(buf) = h.try_pull() {
|
||||
assert_eq!(buf.pts(), expected_timestamp);
|
||||
assert_eq!(buf.duration(), expected_duration);
|
||||
|
||||
expected_timestamp += expected_duration;
|
||||
expected_timestamp = expected_timestamp
|
||||
.zip(expected_duration)
|
||||
.map(|(ts, duration)| ts + duration);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue