utils: migrate to new ClockTime design

This commit is contained in:
François Laignel 2021-05-28 18:35:28 +02:00
parent b8ad30610b
commit c2de0649a7
17 changed files with 933 additions and 794 deletions

View file

@ -42,7 +42,7 @@ fn create_pipeline() -> (gst::Pipeline, gst::Pad, gst::Element, gtk::Widget) {
let fallbackswitch = gst::ElementFactory::make("fallbackswitch", None).unwrap(); let fallbackswitch = gst::ElementFactory::make("fallbackswitch", None).unwrap();
fallbackswitch fallbackswitch
.set_property("timeout", &gst::SECOND) .set_property("timeout", &gst::ClockTime::SECOND)
.unwrap(); .unwrap();
let decodebin = gst::ElementFactory::make("decodebin", None).unwrap(); let decodebin = gst::ElementFactory::make("decodebin", None).unwrap();
@ -134,7 +134,7 @@ fn create_ui(app: &gtk::Application) {
let position = video_sink let position = video_sink
.query_position::<gst::ClockTime>() .query_position::<gst::ClockTime>()
.unwrap_or_else(|| 0.into()); .unwrap_or(gst::ClockTime::ZERO);
position_label.set_text(&format!("Position: {:.1}", position)); position_label.set_text(&format!("Position: {:.1}", position));
glib::Continue(true) glib::Continue(true)

View file

@ -1,19 +1,15 @@
// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com> // Take a look at the license at the top of the repository in the LICENSE file.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::ffi; use super::ffi;
use super::Aggregator; use super::Aggregator;
use glib::signal::{connect_raw, SignalHandlerId}; use glib::signal::{connect_raw, SignalHandlerId};
use glib::translate::*; use glib::translate::*;
use glib::IsA; use glib::IsA;
use glib::Value; use glib::Value;
use gst::glib; use gst::glib;
use gst::prelude::*; use gst::prelude::*;
use std::boxed::Box as Box_; use std::boxed::Box as Box_;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
@ -26,7 +22,8 @@ pub trait AggregatorExtManual: 'static {
fn set_min_upstream_latency(&self, min_upstream_latency: gst::ClockTime); fn set_min_upstream_latency(&self, min_upstream_latency: gst::ClockTime);
fn connect_property_min_upstream_latency_notify<F: Fn(&Self) + Send + Sync + 'static>( #[doc(alias = "min-upstream-latency")]
fn connect_min_upstream_latency_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self, &self,
f: F, f: F,
) -> SignalHandlerId; ) -> SignalHandlerId;
@ -47,13 +44,12 @@ impl<O: IsA<Aggregator>> AggregatorExtManual for O {
} }
fn finish_buffer(&self, buffer: gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> { fn finish_buffer(&self, buffer: gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> {
let ret: gst::FlowReturn = unsafe { unsafe {
from_glib(ffi::gst_aggregator_finish_buffer( try_from_glib(ffi::gst_aggregator_finish_buffer(
self.as_ref().to_glib_none().0, self.as_ref().to_glib_none().0,
buffer.into_ptr(), buffer.into_ptr(),
)) ))
}; }
ret.into_result()
} }
fn min_upstream_latency(&self) -> gst::ClockTime { fn min_upstream_latency(&self) -> gst::ClockTime {
@ -80,7 +76,7 @@ impl<O: IsA<Aggregator>> AggregatorExtManual for O {
} }
} }
fn connect_property_min_upstream_latency_notify<F: Fn(&Self) + Send + Sync + 'static>( fn connect_min_upstream_latency_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self, &self,
f: F, f: F,
) -> SignalHandlerId { ) -> SignalHandlerId {
@ -89,8 +85,8 @@ impl<O: IsA<Aggregator>> AggregatorExtManual for O {
connect_raw( connect_raw(
self.as_ptr() as *mut _, self.as_ptr() as *mut _,
b"notify::min-upstream-latency\0".as_ptr() as *const _, b"notify::min-upstream-latency\0".as_ptr() as *const _,
Some(mem::transmute( Some(mem::transmute::<_, unsafe extern "C" fn()>(
notify_min_upstream_latency_trampoline::<Self, F> as usize, notify_min_upstream_latency_trampoline::<Self, F> as *const (),
)), )),
Box_::into_raw(f), Box_::into_raw(f),
) )

View file

@ -1,18 +1,14 @@
// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com> // Take a look at the license at the top of the repository in the LICENSE file.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::ffi; use super::ffi;
use super::AggregatorPad; use super::AggregatorPad;
use glib::object::IsA; use glib::object::IsA;
use glib::translate::*; use glib::translate::*;
use gst::glib; use gst::glib;
pub trait AggregatorPadExtManual: 'static { pub trait AggregatorPadExtManual: 'static {
#[doc(alias = "get_segment")]
fn segment(&self) -> gst::Segment; fn segment(&self) -> gst::Segment;
} }

View file

@ -4,13 +4,14 @@
// DO NOT EDIT // DO NOT EDIT
use super::super::ffi; use super::super::ffi;
use glib::object::Cast;
use glib::object::IsA;
use glib::signal::connect_raw; use glib::signal::connect_raw;
use glib::signal::SignalHandlerId; use glib::signal::SignalHandlerId;
use glib::translate::*; use glib::translate::*;
use glib::StaticType;
use gst::glib; use gst::glib;
use gst::prelude::*;
use std::boxed::Box as Box_; use std::boxed::Box as Box_;
use std::mem::transmute; use std::mem::transmute;
@ -29,38 +30,45 @@ pub const NONE_AGGREGATOR: Option<&Aggregator> = None;
pub trait AggregatorExt: 'static { pub trait AggregatorExt: 'static {
//#[doc(alias = "gst_aggregator_get_allocator")] //#[doc(alias = "gst_aggregator_get_allocator")]
//#[doc(alias = "get_allocator")]
//fn allocator(&self, allocator: /*Ignored*/Option<gst::Allocator>, params: /*Ignored*/gst::AllocationParams); //fn allocator(&self, allocator: /*Ignored*/Option<gst::Allocator>, params: /*Ignored*/gst::AllocationParams);
#[doc(alias = "gst_aggregator_get_buffer_pool")] #[doc(alias = "gst_aggregator_get_buffer_pool")]
#[doc(alias = "get_buffer_pool")]
fn buffer_pool(&self) -> Option<gst::BufferPool>; fn buffer_pool(&self) -> Option<gst::BufferPool>;
#[doc(alias = "gst_aggregator_get_latency")] #[doc(alias = "gst_aggregator_get_latency")]
fn latency(&self) -> gst::ClockTime; #[doc(alias = "get_latency")]
fn latency(&self) -> Option<gst::ClockTime>;
#[doc(alias = "gst_aggregator_negotiate")] #[doc(alias = "gst_aggregator_negotiate")]
fn negotiate(&self) -> bool; fn negotiate(&self) -> bool;
#[doc(alias = "gst_aggregator_set_latency")] #[doc(alias = "gst_aggregator_set_latency")]
fn set_latency(&self, min_latency: gst::ClockTime, max_latency: gst::ClockTime); fn set_latency(
&self,
min_latency: gst::ClockTime,
max_latency: impl Into<Option<gst::ClockTime>>,
);
#[doc(alias = "gst_aggregator_set_src_caps")] #[doc(alias = "gst_aggregator_set_src_caps")]
fn set_src_caps(&self, caps: &gst::Caps); fn set_src_caps(&self, caps: &gst::Caps);
#[doc(alias = "gst_aggregator_simple_get_next_time")] #[doc(alias = "gst_aggregator_simple_get_next_time")]
fn simple_get_next_time(&self) -> gst::ClockTime; fn simple_get_next_time(&self) -> Option<gst::ClockTime>;
#[doc(alias = "get_property_start_time")] #[doc(alias = "start-time")]
fn start_time(&self) -> u64; fn start_time(&self) -> u64;
#[doc(alias = "set_property_start_time")] #[doc(alias = "start-time")]
fn set_start_time(&self, start_time: u64); fn set_start_time(&self, start_time: u64);
fn connect_property_latency_notify<F: Fn(&Self) + Send + Sync + 'static>( #[doc(alias = "latency")]
&self, fn connect_latency_notify<F: Fn(&Self) + Send + Sync + 'static>(&self, f: F)
f: F, -> SignalHandlerId;
) -> SignalHandlerId;
fn connect_property_start_time_notify<F: Fn(&Self) + Send + Sync + 'static>( #[doc(alias = "start-time")]
fn connect_start_time_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self, &self,
f: F, f: F,
) -> SignalHandlerId; ) -> SignalHandlerId;
@ -79,7 +87,7 @@ impl<O: IsA<Aggregator>> AggregatorExt for O {
} }
} }
fn latency(&self) -> gst::ClockTime { fn latency(&self) -> Option<gst::ClockTime> {
unsafe { unsafe {
from_glib(ffi::gst_aggregator_get_latency( from_glib(ffi::gst_aggregator_get_latency(
self.as_ref().to_glib_none().0, self.as_ref().to_glib_none().0,
@ -95,12 +103,16 @@ impl<O: IsA<Aggregator>> AggregatorExt for O {
} }
} }
fn set_latency(&self, min_latency: gst::ClockTime, max_latency: gst::ClockTime) { fn set_latency(
&self,
min_latency: gst::ClockTime,
max_latency: impl Into<Option<gst::ClockTime>>,
) {
unsafe { unsafe {
ffi::gst_aggregator_set_latency( ffi::gst_aggregator_set_latency(
self.as_ref().to_glib_none().0, self.as_ref().to_glib_none().0,
min_latency.into_glib(), min_latency.into_glib(),
max_latency.into_glib(), max_latency.into().into_glib(),
); );
} }
} }
@ -111,7 +123,7 @@ impl<O: IsA<Aggregator>> AggregatorExt for O {
} }
} }
fn simple_get_next_time(&self) -> gst::ClockTime { fn simple_get_next_time(&self) -> Option<gst::ClockTime> {
unsafe { unsafe {
from_glib(ffi::gst_aggregator_simple_get_next_time( from_glib(ffi::gst_aggregator_simple_get_next_time(
self.as_ref().to_glib_none().0, self.as_ref().to_glib_none().0,
@ -138,22 +150,24 @@ impl<O: IsA<Aggregator>> AggregatorExt for O {
glib::gobject_ffi::g_object_set_property( glib::gobject_ffi::g_object_set_property(
self.to_glib_none().0 as *mut glib::gobject_ffi::GObject, self.to_glib_none().0 as *mut glib::gobject_ffi::GObject,
b"start-time\0".as_ptr() as *const _, b"start-time\0".as_ptr() as *const _,
glib::Value::from(&start_time).to_glib_none().0, start_time.to_value().to_glib_none().0,
); );
} }
} }
fn connect_property_latency_notify<F: Fn(&Self) + Send + Sync + 'static>( #[doc(alias = "latency")]
fn connect_latency_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self, &self,
f: F, f: F,
) -> SignalHandlerId { ) -> SignalHandlerId {
unsafe extern "C" fn notify_latency_trampoline<P, F: Fn(&P) + Send + Sync + 'static>( unsafe extern "C" fn notify_latency_trampoline<
P: IsA<Aggregator>,
F: Fn(&P) + Send + Sync + 'static,
>(
this: *mut ffi::GstAggregator, this: *mut ffi::GstAggregator,
_param_spec: glib::ffi::gpointer, _param_spec: glib::ffi::gpointer,
f: glib::ffi::gpointer, f: glib::ffi::gpointer,
) where ) {
P: IsA<Aggregator>,
{
let f: &F = &*(f as *const F); let f: &F = &*(f as *const F);
f(&Aggregator::from_glib_borrow(this).unsafe_cast_ref()) f(&Aggregator::from_glib_borrow(this).unsafe_cast_ref())
} }
@ -170,17 +184,19 @@ impl<O: IsA<Aggregator>> AggregatorExt for O {
} }
} }
fn connect_property_start_time_notify<F: Fn(&Self) + Send + Sync + 'static>( #[doc(alias = "start-time")]
fn connect_start_time_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self, &self,
f: F, f: F,
) -> SignalHandlerId { ) -> SignalHandlerId {
unsafe extern "C" fn notify_start_time_trampoline<P, F: Fn(&P) + Send + Sync + 'static>( unsafe extern "C" fn notify_start_time_trampoline<
P: IsA<Aggregator>,
F: Fn(&P) + Send + Sync + 'static,
>(
this: *mut ffi::GstAggregator, this: *mut ffi::GstAggregator,
_param_spec: glib::ffi::gpointer, _param_spec: glib::ffi::gpointer,
f: glib::ffi::gpointer, f: glib::ffi::gpointer,
) where ) {
P: IsA<Aggregator>,
{
let f: &F = &*(f as *const F); let f: &F = &*(f as *const F);
f(&Aggregator::from_glib_borrow(this).unsafe_cast_ref()) f(&Aggregator::from_glib_borrow(this).unsafe_cast_ref())
} }

View file

@ -3,13 +3,14 @@
// DO NOT EDIT // DO NOT EDIT
use super::super::ffi; use super::super::ffi;
use glib::object::Cast;
use glib::object::IsA;
use glib::signal::connect_raw; use glib::signal::connect_raw;
use glib::signal::SignalHandlerId; use glib::signal::SignalHandlerId;
use glib::translate::*; use glib::translate::*;
use glib::StaticType;
use gst::glib; use gst::glib;
use gst::prelude::*;
use std::boxed::Box as Box_; use std::boxed::Box as Box_;
use std::mem::transmute; use std::mem::transmute;
@ -42,10 +43,10 @@ pub trait AggregatorPadExt: 'static {
#[doc(alias = "gst_aggregator_pad_pop_buffer")] #[doc(alias = "gst_aggregator_pad_pop_buffer")]
fn pop_buffer(&self) -> Option<gst::Buffer>; fn pop_buffer(&self) -> Option<gst::Buffer>;
#[doc(alias = "get_property_emit_signals")] #[doc(alias = "emit-signals")]
fn emits_signals(&self) -> bool; fn emits_signals(&self) -> bool;
#[doc(alias = "set_property_emit_signals")] #[doc(alias = "emit-signals")]
fn set_emit_signals(&self, emit_signals: bool); fn set_emit_signals(&self, emit_signals: bool);
fn connect_buffer_consumed<F: Fn(&Self, &gst::Buffer) + Send + Sync + 'static>( fn connect_buffer_consumed<F: Fn(&Self, &gst::Buffer) + Send + Sync + 'static>(
@ -53,7 +54,8 @@ pub trait AggregatorPadExt: 'static {
f: F, f: F,
) -> SignalHandlerId; ) -> SignalHandlerId;
fn connect_property_emit_signals_notify<F: Fn(&Self) + Send + Sync + 'static>( #[doc(alias = "emit-signals")]
fn connect_emit_signals_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self, &self,
f: F, f: F,
) -> SignalHandlerId; ) -> SignalHandlerId;
@ -119,25 +121,24 @@ impl<O: IsA<AggregatorPad>> AggregatorPadExt for O {
glib::gobject_ffi::g_object_set_property( glib::gobject_ffi::g_object_set_property(
self.to_glib_none().0 as *mut glib::gobject_ffi::GObject, self.to_glib_none().0 as *mut glib::gobject_ffi::GObject,
b"emit-signals\0".as_ptr() as *const _, b"emit-signals\0".as_ptr() as *const _,
glib::Value::from(&emit_signals).to_glib_none().0, emit_signals.to_value().to_glib_none().0,
); );
} }
} }
#[doc(alias = "buffer-consumed")]
fn connect_buffer_consumed<F: Fn(&Self, &gst::Buffer) + Send + Sync + 'static>( fn connect_buffer_consumed<F: Fn(&Self, &gst::Buffer) + Send + Sync + 'static>(
&self, &self,
f: F, f: F,
) -> SignalHandlerId { ) -> SignalHandlerId {
unsafe extern "C" fn buffer_consumed_trampoline< unsafe extern "C" fn buffer_consumed_trampoline<
P, P: IsA<AggregatorPad>,
F: Fn(&P, &gst::Buffer) + Send + Sync + 'static, F: Fn(&P, &gst::Buffer) + Send + Sync + 'static,
>( >(
this: *mut ffi::GstAggregatorPad, this: *mut ffi::GstAggregatorPad,
object: *mut gst::ffi::GstBuffer, object: *mut gst::ffi::GstBuffer,
f: glib::ffi::gpointer, f: glib::ffi::gpointer,
) where ) {
P: IsA<AggregatorPad>,
{
let f: &F = &*(f as *const F); let f: &F = &*(f as *const F);
f( f(
&AggregatorPad::from_glib_borrow(this).unsafe_cast_ref(), &AggregatorPad::from_glib_borrow(this).unsafe_cast_ref(),
@ -157,17 +158,19 @@ impl<O: IsA<AggregatorPad>> AggregatorPadExt for O {
} }
} }
fn connect_property_emit_signals_notify<F: Fn(&Self) + Send + Sync + 'static>( #[doc(alias = "emit-signals")]
fn connect_emit_signals_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self, &self,
f: F, f: F,
) -> SignalHandlerId { ) -> SignalHandlerId {
unsafe extern "C" fn notify_emit_signals_trampoline<P, F: Fn(&P) + Send + Sync + 'static>( unsafe extern "C" fn notify_emit_signals_trampoline<
P: IsA<AggregatorPad>,
F: Fn(&P) + Send + Sync + 'static,
>(
this: *mut ffi::GstAggregatorPad, this: *mut ffi::GstAggregatorPad,
_param_spec: glib::ffi::gpointer, _param_spec: glib::ffi::gpointer,
f: glib::ffi::gpointer, f: glib::ffi::gpointer,
) where ) {
P: IsA<AggregatorPad>,
{
let f: &F = &*(f as *const F); let f: &F = &*(f as *const F);
f(&AggregatorPad::from_glib_borrow(this).unsafe_cast_ref()) f(&AggregatorPad::from_glib_borrow(this).unsafe_cast_ref())
} }

View file

@ -1,10 +1,4 @@
// Copyright (C) 2017-2019 Sebastian Dröge <sebastian@centricular.com> // Take a look at the license at the top of the repository in the LICENSE file.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::super::ffi; use super::super::ffi;
@ -109,7 +103,7 @@ pub trait AggregatorImpl: AggregatorImplExt + ElementImpl {
self.parent_stop(aggregator) self.parent_stop(aggregator)
} }
fn next_time(&self, aggregator: &Self::Type) -> gst::ClockTime { fn next_time(&self, aggregator: &Self::Type) -> Option<gst::ClockTime> {
self.parent_next_time(aggregator) self.parent_next_time(aggregator)
} }
@ -213,7 +207,7 @@ pub trait AggregatorImplExt: ObjectSubclass {
fn parent_stop(&self, aggregator: &Self::Type) -> Result<(), gst::ErrorMessage>; fn parent_stop(&self, aggregator: &Self::Type) -> Result<(), gst::ErrorMessage>;
fn parent_next_time(&self, aggregator: &Self::Type) -> gst::ClockTime; fn parent_next_time(&self, aggregator: &Self::Type) -> Option<gst::ClockTime>;
fn parent_create_new_pad( fn parent_create_new_pad(
&self, &self,
@ -243,18 +237,17 @@ pub trait AggregatorImplExt: ObjectSubclass {
impl<T: AggregatorImpl> AggregatorImplExt for T { impl<T: AggregatorImpl> AggregatorImplExt for T {
fn parent_flush(&self, aggregator: &Self::Type) -> Result<gst::FlowSuccess, gst::FlowError> { fn parent_flush(&self, aggregator: &Self::Type) -> Result<gst::FlowSuccess, gst::FlowError> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
(*parent_class) (*parent_class)
.flush .flush
.map(|f| { .map(|f| {
from_glib(f(aggregator try_from_glib(f(aggregator
.unsafe_cast_ref::<Aggregator>() .unsafe_cast_ref::<Aggregator>()
.to_glib_none() .to_glib_none()
.0)) .0))
}) })
.unwrap_or(gst::FlowReturn::Ok) .unwrap_or(Ok(gst::FlowSuccess::Ok))
.into_result()
} }
} }
@ -265,7 +258,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
buffer: gst::Buffer, buffer: gst::Buffer,
) -> Option<gst::Buffer> { ) -> Option<gst::Buffer> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
match (*parent_class).clip { match (*parent_class).clip {
None => Some(buffer), None => Some(buffer),
@ -284,16 +277,15 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
buffer: gst::Buffer, buffer: gst::Buffer,
) -> Result<gst::FlowSuccess, gst::FlowError> { ) -> Result<gst::FlowSuccess, gst::FlowError> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
let f = (*parent_class) let f = (*parent_class)
.finish_buffer .finish_buffer
.expect("Missing parent function `finish_buffer`"); .expect("Missing parent function `finish_buffer`");
gst::FlowReturn::from_glib(f( try_from_glib(f(
aggregator.unsafe_cast_ref::<Aggregator>().to_glib_none().0, aggregator.unsafe_cast_ref::<Aggregator>().to_glib_none().0,
buffer.into_ptr(), buffer.into_ptr(),
)) ))
.into_result()
} }
} }
@ -304,7 +296,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
event: gst::Event, event: gst::Event,
) -> bool { ) -> bool {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
let f = (*parent_class) let f = (*parent_class)
.sink_event .sink_event
@ -324,17 +316,16 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
event: gst::Event, event: gst::Event,
) -> Result<gst::FlowSuccess, gst::FlowError> { ) -> Result<gst::FlowSuccess, gst::FlowError> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
let f = (*parent_class) let f = (*parent_class)
.sink_event_pre_queue .sink_event_pre_queue
.expect("Missing parent function `sink_event_pre_queue`"); .expect("Missing parent function `sink_event_pre_queue`");
gst::FlowReturn::from_glib(f( try_from_glib(f(
aggregator.unsafe_cast_ref::<Aggregator>().to_glib_none().0, aggregator.unsafe_cast_ref::<Aggregator>().to_glib_none().0,
aggregator_pad.to_glib_none().0, aggregator_pad.to_glib_none().0,
event.into_ptr(), event.into_ptr(),
)) ))
.into_result()
} }
} }
@ -365,7 +356,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
query: &mut gst::QueryRef, query: &mut gst::QueryRef,
) -> bool { ) -> bool {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
let f = (*parent_class) let f = (*parent_class)
.sink_query_pre_queue .sink_query_pre_queue
@ -380,7 +371,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
fn parent_src_event(&self, aggregator: &Self::Type, event: gst::Event) -> bool { fn parent_src_event(&self, aggregator: &Self::Type, event: gst::Event) -> bool {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
let f = (*parent_class) let f = (*parent_class)
.src_event .src_event
@ -394,7 +385,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
fn parent_src_query(&self, aggregator: &Self::Type, query: &mut gst::QueryRef) -> bool { fn parent_src_query(&self, aggregator: &Self::Type, query: &mut gst::QueryRef) -> bool {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
let f = (*parent_class) let f = (*parent_class)
.src_query .src_query
@ -413,7 +404,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
active: bool, active: bool,
) -> Result<(), gst::LoggableError> { ) -> Result<(), gst::LoggableError> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
match (*parent_class).src_activate { match (*parent_class).src_activate {
None => Ok(()), None => Ok(()),
@ -436,22 +427,21 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
timeout: bool, timeout: bool,
) -> Result<gst::FlowSuccess, gst::FlowError> { ) -> Result<gst::FlowSuccess, gst::FlowError> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
let f = (*parent_class) let f = (*parent_class)
.aggregate .aggregate
.expect("Missing parent function `aggregate`"); .expect("Missing parent function `aggregate`");
gst::FlowReturn::from_glib(f( try_from_glib(f(
aggregator.unsafe_cast_ref::<Aggregator>().to_glib_none().0, aggregator.unsafe_cast_ref::<Aggregator>().to_glib_none().0,
timeout.into_glib(), timeout.into_glib(),
)) ))
.into_result()
} }
} }
fn parent_start(&self, aggregator: &Self::Type) -> Result<(), gst::ErrorMessage> { fn parent_start(&self, aggregator: &Self::Type) -> Result<(), gst::ErrorMessage> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
(*parent_class) (*parent_class)
.start .start
@ -475,7 +465,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
fn parent_stop(&self, aggregator: &Self::Type) -> Result<(), gst::ErrorMessage> { fn parent_stop(&self, aggregator: &Self::Type) -> Result<(), gst::ErrorMessage> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
(*parent_class) (*parent_class)
.stop .stop
@ -497,9 +487,9 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
} }
} }
fn parent_next_time(&self, aggregator: &Self::Type) -> gst::ClockTime { fn parent_next_time(&self, aggregator: &Self::Type) -> Option<gst::ClockTime> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
(*parent_class) (*parent_class)
.get_next_time .get_next_time
@ -509,7 +499,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
.to_glib_none() .to_glib_none()
.0)) .0))
}) })
.unwrap_or(gst::CLOCK_TIME_NONE) .unwrap_or(gst::ClockTime::NONE)
} }
} }
@ -521,7 +511,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
caps: Option<&gst::Caps>, caps: Option<&gst::Caps>,
) -> Option<AggregatorPad> { ) -> Option<AggregatorPad> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
let f = (*parent_class) let f = (*parent_class)
.create_new_pad .create_new_pad
@ -541,7 +531,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
caps: &gst::Caps, caps: &gst::Caps,
) -> Result<gst::Caps, gst::FlowError> { ) -> Result<gst::Caps, gst::FlowError> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
let f = (*parent_class) let f = (*parent_class)
.update_src_caps .update_src_caps
@ -559,7 +549,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
fn parent_fixate_src_caps(&self, aggregator: &Self::Type, caps: gst::Caps) -> gst::Caps { fn parent_fixate_src_caps(&self, aggregator: &Self::Type, caps: gst::Caps) -> gst::Caps {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
let f = (*parent_class) let f = (*parent_class)
@ -578,7 +568,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
caps: &gst::Caps, caps: &gst::Caps,
) -> Result<(), gst::LoggableError> { ) -> Result<(), gst::LoggableError> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
(*parent_class) (*parent_class)
.negotiated_src_caps .negotiated_src_caps
@ -598,7 +588,7 @@ impl<T: AggregatorImpl> AggregatorImplExt for T {
fn parent_negotiate(&self, aggregator: &Self::Type) -> bool { fn parent_negotiate(&self, aggregator: &Self::Type) -> bool {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorClass;
(*parent_class) (*parent_class)
.negotiate .negotiate
@ -879,7 +869,7 @@ unsafe extern "C" fn aggregator_get_next_time<T: AggregatorImpl>(
let imp = instance.impl_(); let imp = instance.impl_();
let wrap: Borrowed<Aggregator> = from_glib_borrow(ptr); let wrap: Borrowed<Aggregator> = from_glib_borrow(ptr);
gst::panic_to_error!(&wrap, &imp.panicked(), gst::CLOCK_TIME_NONE, { gst::panic_to_error!(&wrap, &imp.panicked(), gst::ClockTime::NONE, {
imp.next_time(wrap.unsafe_cast_ref()) imp.next_time(wrap.unsafe_cast_ref())
}) })
.into_glib() .into_glib()

View file

@ -1,17 +1,10 @@
// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com> // Take a look at the license at the top of the repository in the LICENSE file.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::super::ffi; use super::super::ffi;
use glib::translate::*; use glib::translate::*;
use gst::glib; use gst::glib;
use gst::prelude::*; use gst::prelude::*;
use gst::subclass::prelude::*; use gst::subclass::prelude::*;
use super::super::Aggregator; use super::super::Aggregator;
@ -58,12 +51,12 @@ impl<T: AggregatorPadImpl> AggregatorPadImplExt for T {
aggregator: &Aggregator, aggregator: &Aggregator,
) -> Result<gst::FlowSuccess, gst::FlowError> { ) -> Result<gst::FlowSuccess, gst::FlowError> {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorPadClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorPadClass;
(*parent_class) (*parent_class)
.flush .flush
.map(|f| { .map(|f| {
from_glib(f( try_from_glib(f(
aggregator_pad aggregator_pad
.unsafe_cast_ref::<AggregatorPad>() .unsafe_cast_ref::<AggregatorPad>()
.to_glib_none() .to_glib_none()
@ -71,8 +64,7 @@ impl<T: AggregatorPadImpl> AggregatorPadImplExt for T {
aggregator.to_glib_none().0, aggregator.to_glib_none().0,
)) ))
}) })
.unwrap_or(gst::FlowReturn::Ok) .unwrap_or(Ok(gst::FlowSuccess::Ok))
.into_result()
} }
} }
@ -83,7 +75,7 @@ impl<T: AggregatorPadImpl> AggregatorPadImplExt for T {
buffer: &gst::Buffer, buffer: &gst::Buffer,
) -> bool { ) -> bool {
unsafe { unsafe {
let data = T::type_data(); let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorPadClass; let parent_class = data.as_ref().parent_class() as *mut ffi::GstAggregatorPadClass;
(*parent_class) (*parent_class)
.skip_buffer .skip_buffer

View file

@ -1,10 +1,4 @@
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com> // Take a look at the license at the top of the repository in the LICENSE file.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use glib::translate::mut_override; use glib::translate::mut_override;
use gst::glib; use gst::glib;
@ -14,6 +8,7 @@ pub struct MutexGuard<'a>(&'a glib::ffi::GMutex);
impl<'a> MutexGuard<'a> { impl<'a> MutexGuard<'a> {
#[allow(clippy::trivially_copy_pass_by_ref)] #[allow(clippy::trivially_copy_pass_by_ref)]
#[doc(alias = "g_mutex_lock")]
pub fn lock(mutex: &'a glib::ffi::GMutex) -> Self { pub fn lock(mutex: &'a glib::ffi::GMutex) -> Self {
unsafe { unsafe {
glib::ffi::g_mutex_lock(mut_override(mutex)); glib::ffi::g_mutex_lock(mut_override(mutex));

View file

@ -20,9 +20,10 @@ use gst::prelude::*;
use gst::subclass::prelude::*; use gst::subclass::prelude::*;
use gst::{gst_debug, gst_error, gst_info, gst_warning}; use gst::{gst_debug, gst_error, gst_info, gst_warning};
use std::convert::TryFrom;
use std::mem; use std::mem;
use std::sync::Mutex; use std::sync::Mutex;
use std::time::{Duration, Instant}; use std::time::Instant;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -72,11 +73,11 @@ struct Settings {
uri: Option<String>, uri: Option<String>,
source: Option<gst::Element>, source: Option<gst::Element>,
fallback_uri: Option<String>, fallback_uri: Option<String>,
timeout: u64, timeout: gst::ClockTime,
restart_timeout: u64, restart_timeout: gst::ClockTime,
retry_timeout: u64, retry_timeout: gst::ClockTime,
restart_on_eos: bool, restart_on_eos: bool,
min_latency: u64, min_latency: gst::ClockTime,
buffer_duration: i64, buffer_duration: i64,
} }
@ -88,11 +89,11 @@ impl Default for Settings {
uri: None, uri: None,
source: None, source: None,
fallback_uri: None, fallback_uri: None,
timeout: 5 * gst::SECOND_VAL, timeout: 5 * gst::ClockTime::SECOND,
restart_timeout: 5 * gst::SECOND_VAL, restart_timeout: 5 * gst::ClockTime::SECOND,
retry_timeout: 60 * gst::SECOND_VAL, retry_timeout: 60 * gst::ClockTime::SECOND,
restart_on_eos: false, restart_on_eos: false,
min_latency: 0, min_latency: gst::ClockTime::ZERO,
buffer_duration: -1, buffer_duration: -1,
} }
} }
@ -112,7 +113,7 @@ enum Source {
struct Block { struct Block {
pad: gst::Pad, pad: gst::Pad,
probe_id: gst::PadProbeId, probe_id: gst::PadProbeId,
running_time: gst::ClockTime, running_time: Option<gst::ClockTime>,
} }
// Connects one source pad with fallbackswitch and the corresponding fallback input // Connects one source pad with fallbackswitch and the corresponding fallback input
@ -221,8 +222,8 @@ impl ObjectImpl for FallbackSrc {
"Timeout", "Timeout",
"Timeout for switching to the fallback URI", "Timeout for switching to the fallback URI",
0, 0,
std::u64::MAX, std::u64::MAX - 1,
5 * gst::SECOND_VAL, 5 * *gst::ClockTime::SECOND,
glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY, glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
), ),
glib::ParamSpec::new_uint64( glib::ParamSpec::new_uint64(
@ -230,8 +231,8 @@ impl ObjectImpl for FallbackSrc {
"Timeout", "Timeout",
"Timeout for restarting an active source", "Timeout for restarting an active source",
0, 0,
std::u64::MAX, std::u64::MAX - 1,
5 * gst::SECOND_VAL, 5 * *gst::ClockTime::SECOND,
glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY, glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
), ),
glib::ParamSpec::new_uint64( glib::ParamSpec::new_uint64(
@ -239,8 +240,8 @@ impl ObjectImpl for FallbackSrc {
"Retry Timeout", "Retry Timeout",
"Timeout for stopping after repeated failure", "Timeout for stopping after repeated failure",
0, 0,
std::u64::MAX, std::u64::MAX - 1,
60 * gst::SECOND_VAL, 60 * *gst::ClockTime::SECOND,
glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY, glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
), ),
glib::ParamSpec::new_boolean( glib::ParamSpec::new_boolean(
@ -265,7 +266,7 @@ impl ObjectImpl for FallbackSrc {
this allows to configure a minimum latency that would be configured \ this allows to configure a minimum latency that would be configured \
if initially the fallback is enabled", if initially the fallback is enabled",
0, 0,
std::u64::MAX, std::u64::MAX - 1,
0, 0,
glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY, glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
), ),
@ -274,7 +275,7 @@ impl ObjectImpl for FallbackSrc {
"Buffer Duration", "Buffer Duration",
"Buffer duration when buffering streams (-1 default value)", "Buffer duration when buffering streams (-1 default value)",
-1, -1,
std::i64::MAX, std::i64::MAX - 1,
-1, -1,
glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY, glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
), ),
@ -740,7 +741,7 @@ impl FallbackSrc {
fn create_fallback_video_input( fn create_fallback_video_input(
&self, &self,
_element: &super::FallbackSrc, _element: &super::FallbackSrc,
min_latency: u64, min_latency: gst::ClockTime,
fallback_uri: Option<&str>, fallback_uri: Option<&str>,
) -> gst::Element { ) -> gst::Element {
VideoFallbackSource::new(fallback_uri, min_latency).upcast() VideoFallbackSource::new(fallback_uri, min_latency).upcast()
@ -770,8 +771,8 @@ impl FallbackSrc {
fn create_stream( fn create_stream(
&self, &self,
element: &super::FallbackSrc, element: &super::FallbackSrc,
timeout: u64, timeout: gst::ClockTime,
min_latency: u64, min_latency: gst::ClockTime,
is_audio: bool, is_audio: bool,
fallback_uri: Option<&str>, fallback_uri: Option<&str>,
) -> Stream { ) -> Stream {
@ -797,7 +798,7 @@ impl FallbackSrc {
.set_properties(&[ .set_properties(&[
("max-size-buffers", &0u32), ("max-size-buffers", &0u32),
("max-size-bytes", &0u32), ("max-size-bytes", &0u32),
("max-size-time", &gst::SECOND), ("max-size-time", &gst::ClockTime::SECOND),
]) ])
.unwrap(); .unwrap();
@ -815,9 +816,9 @@ impl FallbackSrc {
let src = FallbackSrc::from_instance(&element); let src = FallbackSrc::from_instance(&element);
src.handle_switch_active_pad_change(&element); src.handle_switch_active_pad_change(&element);
}); });
switch.set_property("timeout", &timeout).unwrap(); switch.set_property("timeout", &timeout.nseconds()).unwrap();
switch switch
.set_property("min-upstream-latency", &min_latency) .set_property("min-upstream-latency", &min_latency.nseconds())
.unwrap(); .unwrap();
gst::Element::link_pads(&fallback_input, Some("src"), &switch, Some("fallback_sink")) gst::Element::link_pads(&fallback_input, Some("src"), &switch, Some("fallback_sink"))
@ -1067,7 +1068,7 @@ impl FallbackSrc {
|| (!state.source_is_live && transition == gst::StateChange::PausedToPlaying) || (!state.source_is_live && transition == gst::StateChange::PausedToPlaying)
{ {
assert!(state.source_restart_timeout.is_none()); assert!(state.source_restart_timeout.is_none());
self.schedule_source_restart_timeout(element, state, 0.into()); self.schedule_source_restart_timeout(element, state, gst::ClockTime::ZERO);
} }
} }
} }
@ -1230,7 +1231,7 @@ impl FallbackSrc {
let pts = match info.data { let pts = match info.data {
Some(gst::PadProbeData::Buffer(ref buffer)) => buffer.pts(), Some(gst::PadProbeData::Buffer(ref buffer)) => buffer.pts(),
Some(gst::PadProbeData::Event(ref ev)) => match ev.view() { Some(gst::PadProbeData::Event(ref ev)) => match ev.view() {
gst::EventView::Gap(ref ev) => ev.get().0, gst::EventView::Gap(ref ev) => Some(ev.get().0),
_ => return gst::PadProbeReturn::Pass, _ => return gst::PadProbeReturn::Pass,
}, },
_ => unreachable!(), _ => unreachable!(),
@ -1250,7 +1251,7 @@ impl FallbackSrc {
Block { Block {
pad: stream.clocksync_queue_srcpad.clone(), pad: stream.clocksync_queue_srcpad.clone(),
probe_id, probe_id,
running_time: gst::CLOCK_TIME_NONE, running_time: gst::ClockTime::NONE,
} }
} }
@ -1258,7 +1259,7 @@ impl FallbackSrc {
&self, &self,
element: &super::FallbackSrc, element: &super::FallbackSrc,
pad: &gst::Pad, pad: &gst::Pad,
pts: gst::ClockTime, pts: impl Into<Option<gst::ClockTime>>,
) -> Result<(), gst::ErrorMessage> { ) -> Result<(), gst::ErrorMessage> {
let mut state_guard = self.state.lock().unwrap(); let mut state_guard = self.state.lock().unwrap();
let state = match &mut *state_guard { let state = match &mut *state_guard {
@ -1354,21 +1355,22 @@ impl FallbackSrc {
gst::error_msg!(gst::CoreError::Clock, ["Have no time segment"]) gst::error_msg!(gst::CoreError::Clock, ["Have no time segment"])
})?; })?;
let running_time = if pts < segment.start() { let pts = pts.into();
segment.start() let running_time = if let Some((_, start)) =
} else if segment.stop().is_some() && pts >= segment.stop() { pts.zip(segment.start()).filter(|(pts, start)| pts < start)
segment.stop() {
Some(start)
} else if let Some((_, stop)) = pts.zip(segment.stop()).filter(|(pts, stop)| pts >= stop) {
Some(stop)
} else { } else {
segment.to_running_time(pts) segment.to_running_time(pts)
}; };
assert!(running_time.is_some());
gst_debug!( gst_debug!(
CAT, CAT,
obj: element, obj: element,
"Have block running time {}", "Have block running time {}",
running_time, running_time.display(),
); );
block.running_time = running_time; block.running_time = running_time;
@ -1414,13 +1416,13 @@ impl FallbackSrc {
let audio_running_time = state let audio_running_time = state
.audio_stream .audio_stream
.as_ref() .as_ref()
.and_then(|s| s.source_srcpad_block.as_ref().map(|b| b.running_time)) .and_then(|s| s.source_srcpad_block.as_ref())
.unwrap_or(gst::CLOCK_TIME_NONE); .and_then(|b| b.running_time);
let video_running_time = state let video_running_time = state
.video_stream .video_stream
.as_ref() .as_ref()
.and_then(|s| s.source_srcpad_block.as_ref().map(|b| b.running_time)) .and_then(|s| s.source_srcpad_block.as_ref())
.unwrap_or(gst::CLOCK_TIME_NONE); .and_then(|b| b.running_time);
let audio_srcpad = state let audio_srcpad = state
.audio_stream .audio_stream
@ -1444,7 +1446,14 @@ impl FallbackSrc {
// Also consider EOS, we'd never get a new running time after EOS so don't need to wait. // Also consider EOS, we'd never get a new running time after EOS so don't need to wait.
// FIXME: All this surely can be simplified somehow // FIXME: All this surely can be simplified somehow
let current_running_time = element.current_running_time(); // FIXME I guess this could be moved up
let current_running_time = match element.current_running_time() {
Some(current_running_time) => current_running_time,
None => {
gst_debug!(CAT, obj: element, "Waiting for current_running_time");
return;
}
};
if have_audio && want_audio && have_video && want_video { if have_audio && want_audio && have_video && want_video {
if audio_running_time.is_none() if audio_running_time.is_none()
@ -1466,18 +1475,21 @@ impl FallbackSrc {
return; return;
} }
let audio_running_time = audio_running_time.expect("checked above");
let video_running_time = video_running_time.expect("checked above");
let min_running_time = if audio_is_eos { let min_running_time = if audio_is_eos {
video_running_time video_running_time
} else if video_is_eos { } else if video_is_eos {
audio_running_time audio_running_time
} else { } else {
assert!(audio_running_time.is_some() && video_running_time.is_some()); audio_running_time.min(video_running_time)
audio_running_time.min(video_running_time).unwrap()
}; };
let offset = if current_running_time > min_running_time { let offset = if current_running_time > min_running_time {
(current_running_time - min_running_time).unwrap() as i64 (current_running_time - min_running_time).nseconds() as i64
} else { } else {
-((min_running_time - current_running_time).unwrap() as i64) -((min_running_time - current_running_time).nseconds() as i64)
}; };
gst_debug!( gst_debug!(
@ -1514,15 +1526,18 @@ impl FallbackSrc {
block.pad.remove_probe(block.probe_id); block.pad.remove_probe(block.probe_id);
} }
} else if have_audio && want_audio { } else if have_audio && want_audio {
if audio_running_time.is_none() { let audio_running_time = match audio_running_time {
gst_debug!(CAT, obj: element, "Waiting for audio pad to block"); Some(audio_running_time) => audio_running_time,
return; None => {
} gst_debug!(CAT, obj: element, "Waiting for audio pad to block");
return;
}
};
let offset = if current_running_time > audio_running_time { let offset = if current_running_time > audio_running_time {
(current_running_time - audio_running_time).unwrap() as i64 (current_running_time - audio_running_time).nseconds() as i64
} else { } else {
-((audio_running_time - current_running_time).unwrap() as i64) -((audio_running_time - current_running_time).nseconds() as i64)
}; };
gst_debug!( gst_debug!(
@ -1546,15 +1561,18 @@ impl FallbackSrc {
block.pad.remove_probe(block.probe_id); block.pad.remove_probe(block.probe_id);
} }
} else if have_video && want_video { } else if have_video && want_video {
if video_running_time.is_none() { let video_running_time = match video_running_time {
gst_debug!(CAT, obj: element, "Waiting for video pad to block"); Some(video_running_time) => video_running_time,
return; None => {
} gst_debug!(CAT, obj: element, "Waiting for video pad to block");
return;
}
};
let offset = if current_running_time > video_running_time { let offset = if current_running_time > video_running_time {
(current_running_time - video_running_time).unwrap() as i64 (current_running_time - video_running_time).nseconds() as i64
} else { } else {
-((video_running_time - current_running_time).unwrap() as i64) -((video_running_time - current_running_time).nseconds() as i64)
}; };
gst_debug!( gst_debug!(
@ -1911,8 +1929,7 @@ impl FallbackSrc {
gst_debug!(CAT, obj: element, "Waiting for 1s before retrying"); gst_debug!(CAT, obj: element, "Waiting for 1s before retrying");
let clock = gst::SystemClock::obtain(); let clock = gst::SystemClock::obtain();
let wait_time = clock.time() + gst::SECOND; let wait_time = clock.time().unwrap() + gst::ClockTime::SECOND;
assert!(wait_time.is_some());
assert!(state.source_pending_restart_timeout.is_none()); assert!(state.source_pending_restart_timeout.is_none());
let timeout = clock.new_single_shot_id(wait_time); let timeout = clock.new_single_shot_id(wait_time);
@ -1998,7 +2015,11 @@ impl FallbackSrc {
let mut state_guard = src.state.lock().unwrap(); let mut state_guard = src.state.lock().unwrap();
let state = state_guard.as_mut().expect("no state"); let state = state_guard.as_mut().expect("no state");
assert!(state.source_restart_timeout.is_none()); assert!(state.source_restart_timeout.is_none());
src.schedule_source_restart_timeout(element, state, 0.into()); src.schedule_source_restart_timeout(
element,
state,
gst::ClockTime::ZERO,
);
} }
}); });
}) })
@ -2024,9 +2045,7 @@ impl FallbackSrc {
} }
let clock = gst::SystemClock::obtain(); let clock = gst::SystemClock::obtain();
let wait_time = let wait_time = clock.time().unwrap() + state.settings.restart_timeout - elapsed;
clock.time() + gst::ClockTime::from_nseconds(state.settings.restart_timeout) - elapsed;
assert!(wait_time.is_some());
gst_debug!( gst_debug!(
CAT, CAT,
obj: element, obj: element,
@ -2063,9 +2082,7 @@ impl FallbackSrc {
// If we're not actively buffering right now let's restart the source // If we're not actively buffering right now let's restart the source
if state if state
.last_buffering_update .last_buffering_update
.map(|i| { .map(|i| i.elapsed() >= state.settings.restart_timeout.into())
i.elapsed() >= Duration::from_nanos(state.settings.restart_timeout)
})
.unwrap_or(state.stats.buffering_percent == 100) .unwrap_or(state.stats.buffering_percent == 100)
{ {
gst_debug!(CAT, obj: element, "Not buffering, restarting source"); gst_debug!(CAT, obj: element, "Not buffering, restarting source");
@ -2077,10 +2094,12 @@ impl FallbackSrc {
gst_debug!(CAT, obj: element, "Buffering, restarting source later"); gst_debug!(CAT, obj: element, "Buffering, restarting source later");
let elapsed = state let elapsed = state
.last_buffering_update .last_buffering_update
.map(|i| i.elapsed().as_nanos() as u64) .and_then(|last_buffering_update| {
.unwrap_or(0); gst::ClockTime::try_from(last_buffering_update.elapsed()).ok()
})
.unwrap_or(gst::ClockTime::ZERO);
src.schedule_source_restart_timeout(element, state, elapsed.into()); src.schedule_source_restart_timeout(element, state, elapsed);
} }
} else { } else {
gst_debug!(CAT, obj: element, "Restarting source not needed anymore"); gst_debug!(CAT, obj: element, "Restarting source not needed anymore");
@ -2150,7 +2169,7 @@ impl FallbackSrc {
if self.have_fallback_activated(element, state) { if self.have_fallback_activated(element, state) {
gst_warning!(CAT, obj: element, "Switched to fallback stream"); gst_warning!(CAT, obj: element, "Switched to fallback stream");
if state.source_restart_timeout.is_none() { if state.source_restart_timeout.is_none() {
self.schedule_source_restart_timeout(element, state, 0.into()); self.schedule_source_restart_timeout(element, state, gst::ClockTime::ZERO);
} }
drop(state_guard); drop(state_guard);

View file

@ -36,14 +36,14 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Settings { struct Settings {
uri: Option<String>, uri: Option<String>,
min_latency: u64, min_latency: gst::ClockTime,
} }
impl Default for Settings { impl Default for Settings {
fn default() -> Self { fn default() -> Self {
Settings { Settings {
uri: None, uri: None,
min_latency: 0, min_latency: gst::ClockTime::ZERO,
} }
} }
} }
@ -131,7 +131,7 @@ impl ObjectImpl for VideoFallbackSource {
gst_info!( gst_info!(
CAT, CAT,
obj: obj, obj: obj,
"Changing Minimum Latency from {:?} to {:?}", "Changing Minimum Latency from {} to {}",
settings.min_latency, settings.min_latency,
new_value, new_value,
); );
@ -276,7 +276,7 @@ impl VideoFallbackSource {
fn create_source( fn create_source(
&self, &self,
element: &super::VideoFallbackSource, element: &super::VideoFallbackSource,
min_latency: u64, min_latency: gst::ClockTime,
uri: Option<&str>, uri: Option<&str>,
) -> gst::Element { ) -> gst::Element {
gst_debug!(CAT, obj: element, "Creating source with uri {:?}", uri); gst_debug!(CAT, obj: element, "Creating source with uri {:?}", uri);
@ -313,7 +313,7 @@ impl VideoFallbackSource {
("max-size-bytes", &0u32), ("max-size-bytes", &0u32),
( (
"max-size-time", "max-size-time",
&gst::ClockTime::max(5 * gst::SECOND, min_latency.into()).unwrap(), &min_latency.max(5 * gst::ClockTime::SECOND).nseconds(),
), ),
]) ])
.unwrap(); .unwrap();

View file

@ -30,7 +30,7 @@ unsafe impl Send for VideoFallbackSource {}
unsafe impl Sync for VideoFallbackSource {} unsafe impl Sync for VideoFallbackSource {}
impl VideoFallbackSource { impl VideoFallbackSource {
pub fn new(uri: Option<&str>, min_latency: u64) -> VideoFallbackSource { pub fn new(uri: Option<&str>, min_latency: gst::ClockTime) -> VideoFallbackSource {
glib::Object::new(&[("uri", &uri), ("min-latency", &min_latency)]).unwrap() glib::Object::new(&[("uri", &uri), ("min-latency", &min_latency.nseconds())]).unwrap()
} }
} }

View file

@ -71,13 +71,13 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct PadOutputState { struct PadOutputState {
last_sinkpad_time: gst::ClockTime, last_sinkpad_time: Option<gst::ClockTime>,
stream_health: StreamHealth, stream_health: StreamHealth,
} }
#[derive(Debug)] #[derive(Debug)]
struct OutputState { struct OutputState {
last_output_time: gst::ClockTime, last_output_time: Option<gst::ClockTime>,
primary: PadOutputState, primary: PadOutputState,
fallback: PadOutputState, fallback: PadOutputState,
} }
@ -89,7 +89,7 @@ struct PadInputState {
video_info: Option<gst_video::VideoInfo>, video_info: Option<gst_video::VideoInfo>,
} }
const DEFAULT_TIMEOUT: u64 = 5 * gst::SECOND_VAL; const DEFAULT_TIMEOUT: gst::ClockTime = gst::ClockTime::from_seconds(5);
const DEFAULT_AUTO_SWITCH: bool = true; const DEFAULT_AUTO_SWITCH: bool = true;
const DEFAULT_STREAM_HEALTH: StreamHealth = StreamHealth::Inactive; const DEFAULT_STREAM_HEALTH: StreamHealth = StreamHealth::Inactive;
@ -108,7 +108,7 @@ impl Default for StreamHealth {
impl Default for OutputState { impl Default for OutputState {
fn default() -> Self { fn default() -> Self {
OutputState { OutputState {
last_output_time: gst::CLOCK_TIME_NONE, last_output_time: gst::ClockTime::NONE,
primary: PadOutputState::default(), primary: PadOutputState::default(),
fallback: PadOutputState::default(), fallback: PadOutputState::default(),
} }
@ -118,7 +118,7 @@ impl Default for OutputState {
impl Default for Settings { impl Default for Settings {
fn default() -> Self { fn default() -> Self {
Settings { Settings {
timeout: DEFAULT_TIMEOUT.into(), timeout: DEFAULT_TIMEOUT,
auto_switch: DEFAULT_AUTO_SWITCH, auto_switch: DEFAULT_AUTO_SWITCH,
} }
} }
@ -129,7 +129,7 @@ impl OutputState {
&self, &self,
settings: &Settings, settings: &Settings,
check_primary_pad: bool, check_primary_pad: bool,
cur_running_time: gst::ClockTime, cur_running_time: impl Into<Option<gst::ClockTime>>,
) -> StreamHealth { ) -> StreamHealth {
let last_sinkpad_time = if check_primary_pad { let last_sinkpad_time = if check_primary_pad {
self.primary.last_sinkpad_time self.primary.last_sinkpad_time
@ -137,11 +137,11 @@ impl OutputState {
self.fallback.last_sinkpad_time self.fallback.last_sinkpad_time
}; };
if last_sinkpad_time == gst::ClockTime::none() { if last_sinkpad_time.is_none() {
StreamHealth::Inactive StreamHealth::Inactive
} else if cur_running_time != gst::ClockTime::none() } else if cur_running_time.into().map_or(false, |cur_running_time| {
&& cur_running_time < last_sinkpad_time + settings.timeout cur_running_time < last_sinkpad_time.expect("checked above") + settings.timeout
{ }) {
StreamHealth::Present StreamHealth::Present
} else { } else {
StreamHealth::Inactive StreamHealth::Inactive
@ -153,7 +153,7 @@ impl OutputState {
settings: &Settings, settings: &Settings,
backup_pad: &Option<&gst_base::AggregatorPad>, backup_pad: &Option<&gst_base::AggregatorPad>,
preferred_is_primary: bool, preferred_is_primary: bool,
cur_running_time: gst::ClockTime, cur_running_time: impl Into<Option<gst::ClockTime>> + Copy,
) -> (bool, bool) { ) -> (bool, bool) {
let preferred_health = self.health(settings, preferred_is_primary, cur_running_time); let preferred_health = self.health(settings, preferred_is_primary, cur_running_time);
let backup_health = if backup_pad.is_some() { let backup_health = if backup_pad.is_some() {
@ -187,7 +187,7 @@ impl FallbackSwitch {
&self, &self,
state: &mut OutputState, state: &mut OutputState,
pad: &gst_base::AggregatorPad, pad: &gst_base::AggregatorPad,
target_running_time: gst::ClockTime, target_running_time: impl Into<Option<gst::ClockTime>> + Copy,
) -> Result<(), gst::FlowError> { ) -> Result<(), gst::FlowError> {
let segment = pad.segment(); let segment = pad.segment();
@ -201,13 +201,17 @@ impl FallbackSwitch {
gst::FlowError::Error gst::FlowError::Error
})?; })?;
let mut running_time = gst::ClockTime::none(); let mut running_time = gst::ClockTime::NONE;
while let Some(buffer) = pad.peek_buffer() { while let Some(buffer) = pad.peek_buffer() {
let pts = buffer.dts_or_pts(); let pts = buffer.dts_or_pts();
let new_running_time = segment.to_running_time(pts); let new_running_time = segment.to_running_time(pts);
if pts.is_none() || new_running_time <= target_running_time { if pts.is_none()
|| new_running_time
.zip(target_running_time.into())
.map_or(false, |(new, target)| new <= target)
{
gst_debug!(CAT, obj: pad, "Dropping trailing buffer {:?}", buffer); gst_debug!(CAT, obj: pad, "Dropping trailing buffer {:?}", buffer);
pad.drop_buffer(); pad.drop_buffer();
running_time = new_running_time; running_time = new_running_time;
@ -215,7 +219,7 @@ impl FallbackSwitch {
break; break;
} }
} }
if running_time != gst::ClockTime::none() { if running_time.is_some() {
if pad == &self.primary_sinkpad { if pad == &self.primary_sinkpad {
state.primary.last_sinkpad_time = running_time; state.primary.last_sinkpad_time = running_time;
} else { } else {
@ -234,7 +238,7 @@ impl FallbackSwitch {
mut buffer: gst::Buffer, mut buffer: gst::Buffer,
preferred_pad: &gst_base::AggregatorPad, preferred_pad: &gst_base::AggregatorPad,
backup_pad: &Option<&gst_base::AggregatorPad>, backup_pad: &Option<&gst_base::AggregatorPad>,
cur_running_time: gst::ClockTime, cur_running_time: impl Into<Option<gst::ClockTime>>,
) -> Result<Option<(gst::Buffer, gst::Caps, bool)>, gst::FlowError> { ) -> Result<Option<(gst::Buffer, gst::Caps, bool)>, gst::FlowError> {
// If we got a buffer on the sinkpad just handle it // If we got a buffer on the sinkpad just handle it
gst_debug!( gst_debug!(
@ -273,48 +277,46 @@ impl FallbackSwitch {
state.fallback.last_sinkpad_time = running_time; state.fallback.last_sinkpad_time = running_time;
} }
let is_late = { let cur_running_time = cur_running_time.into();
if cur_running_time != gst::ClockTime::none() { let (is_late, deadline) = cur_running_time
let latency = agg.latency(); .zip(agg.latency())
if latency.is_some() { .zip(running_time)
let deadline = running_time + latency + 40 * gst::MSECOND; .map_or(
(false, None),
|((cur_running_time, latency), running_time)| {
let dealine = running_time + latency + 40 * gst::ClockTime::MSECOND;
(cur_running_time > dealine, Some(dealine))
},
);
if cur_running_time > deadline { if is_late {
gst_debug!(
CAT,
obj: preferred_pad,
"Buffer is too late: {} > {}",
cur_running_time,
deadline
);
true
} else {
false
}
} else {
false
}
} else {
false
}
};
if state.last_output_time.is_some()
&& is_late
&& state.last_output_time + settings.timeout <= running_time
{
/* This buffer arrived too late - we either already switched
* to the other pad or there's no point outputting this anyway */
gst_debug!( gst_debug!(
CAT, CAT,
obj: preferred_pad, obj: preferred_pad,
"Buffer is too late and timeout reached: {} + {} <= {}", "Buffer is too late: {} > {}",
state.last_output_time, cur_running_time.display(),
settings.timeout, deadline.display(),
running_time,
); );
return Ok(None); if state.last_output_time.zip(running_time).map_or(
false,
|(last_output_time, running_time)| {
last_output_time + settings.timeout <= running_time
},
) {
/* This buffer arrived too late - we either already switched
* to the other pad or there's no point outputting this anyway */
gst_debug!(
CAT,
obj: preferred_pad,
"Buffer is too late and timeout reached: {} + {} <= {}",
state.last_output_time.display(),
settings.timeout,
running_time.display(),
);
return Ok(None);
}
} }
let mut active_sinkpad = self.active_sinkpad.lock().unwrap(); let mut active_sinkpad = self.active_sinkpad.lock().unwrap();
@ -416,14 +418,19 @@ impl FallbackSwitch {
} }
// Get the next one if this one is before the timeout // Get the next one if this one is before the timeout
if state.last_output_time + settings.timeout > running_time { if state.last_output_time.zip(running_time).map_or(
false,
|(last_output_time, running_time)| {
last_output_time + settings.timeout > running_time
},
) {
gst_debug!( gst_debug!(
CAT, CAT,
obj: backup_pad, obj: backup_pad,
"Timeout not reached yet: {} + {} > {}", "Timeout not reached yet: {} + {} > {}",
state.last_output_time, state.last_output_time.display(),
settings.timeout, settings.timeout,
running_time running_time.display(),
); );
continue; continue;
@ -433,9 +440,9 @@ impl FallbackSwitch {
CAT, CAT,
obj: backup_pad, obj: backup_pad,
"Timeout reached: {} + {} <= {}", "Timeout reached: {} + {} <= {}",
state.last_output_time, state.last_output_time.display(),
settings.timeout, settings.timeout,
running_time running_time.display(),
); );
let mut active_sinkpad = self.active_sinkpad.lock().unwrap(); let mut active_sinkpad = self.active_sinkpad.lock().unwrap();
@ -529,9 +536,12 @@ impl FallbackSwitch {
let base_time = agg.base_time(); let base_time = agg.base_time();
let cur_running_time = if let Some(clock) = clock { let cur_running_time = if let Some(clock) = clock {
clock.time() - base_time clock
.time()
.zip(base_time)
.and_then(|(time, base_time)| time.checked_sub(base_time))
} else { } else {
gst::ClockTime::none() gst::ClockTime::NONE
}; };
/* See if there's a buffer on the preferred pad and output that */ /* See if there's a buffer on the preferred pad and output that */
@ -677,8 +687,8 @@ impl ObjectImpl for FallbackSwitch {
"Timeout", "Timeout",
"Timeout in nanoseconds", "Timeout in nanoseconds",
0, 0,
std::u64::MAX, std::u64::MAX - 1,
DEFAULT_TIMEOUT, DEFAULT_TIMEOUT.nseconds() as u64,
glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY, glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
), ),
glib::ParamSpec::new_object( glib::ParamSpec::new_object(
@ -984,7 +994,7 @@ impl AggregatorImpl for FallbackSwitch {
} }
} }
fn next_time(&self, agg: &Self::Type) -> gst::ClockTime { fn next_time(&self, agg: &Self::Type) -> Option<gst::ClockTime> {
/* At each iteration, we have a preferred pad and a backup pad. If autoswitch is true, /* At each iteration, we have a preferred pad and a backup pad. If autoswitch is true,
* the sinkpad is always preferred, otherwise it's the active sinkpad as set by the app. * the sinkpad is always preferred, otherwise it's the active sinkpad as set by the app.
* The backup pad is the other one (may be None if there's no fallback pad yet). * The backup pad is the other one (may be None if there's no fallback pad yet).
@ -1020,10 +1030,10 @@ impl AggregatorImpl for FallbackSwitch {
"Have buffer on sinkpad {}, immediate timeout", "Have buffer on sinkpad {}, immediate timeout",
preferred_pad.name() preferred_pad.name()
); );
0.into() Some(gst::ClockTime::ZERO)
} else if self.primary_sinkpad.is_eos() { } else if self.primary_sinkpad.is_eos() {
gst_debug!(CAT, obj: agg, "Sinkpad is EOS, immediate timeout"); gst_debug!(CAT, obj: agg, "Sinkpad is EOS, immediate timeout");
0.into() Some(gst::ClockTime::ZERO)
} else if let Some((buffer, backup_sinkpad)) = backup_pad } else if let Some((buffer, backup_sinkpad)) = backup_pad
.as_ref() .as_ref()
.and_then(|p| p.peek_buffer().map(|buffer| (buffer, p))) .and_then(|p| p.peek_buffer().map(|buffer| (buffer, p)))
@ -1031,7 +1041,7 @@ impl AggregatorImpl for FallbackSwitch {
if buffer.pts().is_none() { if buffer.pts().is_none() {
gst_error!(CAT, obj: agg, "Only buffers with PTS supported"); gst_error!(CAT, obj: agg, "Only buffers with PTS supported");
// Trigger aggregate immediately to error out immediately // Trigger aggregate immediately to error out immediately
return 0.into(); return Some(gst::ClockTime::ZERO);
} }
let segment = match backup_sinkpad.segment().downcast::<gst::ClockTime>() { let segment = match backup_sinkpad.segment().downcast::<gst::ClockTime>() {
@ -1039,7 +1049,7 @@ impl AggregatorImpl for FallbackSwitch {
Err(_) => { Err(_) => {
gst_error!(CAT, obj: agg, "Only TIME segments supported"); gst_error!(CAT, obj: agg, "Only TIME segments supported");
// Trigger aggregate immediately to error out immediately // Trigger aggregate immediately to error out immediately
return 0.into(); return Some(gst::ClockTime::ZERO);
} }
}; };
@ -1049,12 +1059,12 @@ impl AggregatorImpl for FallbackSwitch {
obj: agg, obj: agg,
"Have buffer on {} pad, timeout at {}", "Have buffer on {} pad, timeout at {}",
backup_sinkpad.name(), backup_sinkpad.name(),
running_time running_time.display(),
); );
running_time running_time
} else { } else {
gst_debug!(CAT, obj: agg, "No buffer available on either input"); gst_debug!(CAT, obj: agg, "No buffer available on either input");
gst::CLOCK_TIME_NONE gst::ClockTime::NONE
} }
} }
@ -1096,25 +1106,21 @@ impl AggregatorImpl for FallbackSwitch {
return Some(buffer); return Some(buffer);
} }
let duration = if buffer.duration().is_some() { let duration = if let Some(duration) = buffer.duration() {
buffer.duration() Some(duration)
} else if let Some(ref audio_info) = pad_state.audio_info { } else if let Some(ref audio_info) = pad_state.audio_info {
gst::SECOND gst::ClockTime::SECOND.mul_div_floor(
.mul_div_floor( buffer.size() as u64,
buffer.size() as u64, audio_info.rate() as u64 * audio_info.bpf() as u64,
audio_info.rate() as u64 * audio_info.bpf() as u64, )
)
.unwrap()
} else if let Some(ref video_info) = pad_state.video_info { } else if let Some(ref video_info) = pad_state.video_info {
if *video_info.fps().numer() > 0 { if *video_info.fps().numer() > 0 {
gst::SECOND gst::ClockTime::SECOND.mul_div_floor(
.mul_div_floor( *video_info.fps().denom() as u64,
*video_info.fps().denom() as u64, *video_info.fps().numer() as u64,
*video_info.fps().numer() as u64, )
)
.unwrap()
} else { } else {
gst::CLOCK_TIME_NONE gst::ClockTime::NONE
} }
} else { } else {
unreachable!() unreachable!()
@ -1125,8 +1131,8 @@ impl AggregatorImpl for FallbackSwitch {
obj: agg_pad, obj: agg_pad,
"Clipping buffer {:?} with PTS {} and duration {}", "Clipping buffer {:?} with PTS {} and duration {}",
buffer, buffer,
pts, pts.display(),
duration duration.display(),
); );
if let Some(ref audio_info) = pad_state.audio_info { if let Some(ref audio_info) = pad_state.audio_info {
gst_audio::audio_buffer_clip( gst_audio::audio_buffer_clip(
@ -1136,12 +1142,16 @@ impl AggregatorImpl for FallbackSwitch {
audio_info.bpf(), audio_info.bpf(),
) )
} else if pad_state.video_info.is_some() { } else if pad_state.video_info.is_some() {
segment.clip(pts, pts + duration).map(|(start, stop)| { let stop = pts.zip(duration).map(|(pts, duration)| pts + duration);
segment.clip(pts, stop).map(|(start, stop)| {
{ {
let buffer = buffer.make_mut(); let buffer = buffer.make_mut();
buffer.set_pts(start); buffer.set_pts(start);
if duration.is_some() { if duration.is_some() {
buffer.set_duration(stop - start); buffer.set_duration(
stop.zip(start)
.and_then(|(stop, start)| stop.checked_sub(start)),
);
} }
} }

View file

@ -56,20 +56,20 @@ macro_rules! assert_buffer {
fn test_no_fallback_no_drops() { fn test_no_fallback_no_drops() {
let pipeline = setup_pipeline(None); let pipeline = setup_pipeline(None);
push_buffer(&pipeline, 0.into()); push_buffer(&pipeline, gst::ClockTime::ZERO);
set_time(&pipeline, 0.into()); set_time(&pipeline, gst::ClockTime::ZERO);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 0.into()); assert_buffer!(buffer, Some(gst::ClockTime::ZERO));
push_buffer(&pipeline, gst::SECOND); push_buffer(&pipeline, gst::ClockTime::SECOND);
set_time(&pipeline, gst::SECOND); set_time(&pipeline, gst::ClockTime::SECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, gst::SECOND); assert_buffer!(buffer, Some(gst::ClockTime::SECOND));
push_buffer(&pipeline, 2 * gst::SECOND); push_buffer(&pipeline, 2 * gst::ClockTime::SECOND);
set_time(&pipeline, 2 * gst::SECOND); set_time(&pipeline, 2 * gst::ClockTime::SECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 2 * gst::SECOND); assert_buffer!(buffer, Some(2 * gst::ClockTime::SECOND));
push_eos(&pipeline); push_eos(&pipeline);
wait_eos(&pipeline); wait_eos(&pipeline);
@ -90,23 +90,23 @@ fn test_no_drops_not_live() {
fn test_no_drops(live: bool) { fn test_no_drops(live: bool) {
let pipeline = setup_pipeline(Some(live)); let pipeline = setup_pipeline(Some(live));
push_buffer(&pipeline, 0.into()); push_buffer(&pipeline, gst::ClockTime::ZERO);
push_fallback_buffer(&pipeline, 0.into()); push_fallback_buffer(&pipeline, gst::ClockTime::ZERO);
set_time(&pipeline, 0.into()); set_time(&pipeline, gst::ClockTime::ZERO);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 0.into()); assert_buffer!(buffer, Some(gst::ClockTime::ZERO));
push_fallback_buffer(&pipeline, gst::SECOND); push_fallback_buffer(&pipeline, gst::ClockTime::SECOND);
push_buffer(&pipeline, gst::SECOND); push_buffer(&pipeline, gst::ClockTime::SECOND);
set_time(&pipeline, gst::SECOND); set_time(&pipeline, gst::ClockTime::SECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, gst::SECOND); assert_buffer!(buffer, Some(gst::ClockTime::SECOND));
push_buffer(&pipeline, 2 * gst::SECOND); push_buffer(&pipeline, 2 * gst::ClockTime::SECOND);
push_fallback_buffer(&pipeline, 2 * gst::SECOND); push_fallback_buffer(&pipeline, 2 * gst::ClockTime::SECOND);
set_time(&pipeline, 2 * gst::SECOND); set_time(&pipeline, 2 * gst::ClockTime::SECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 2 * gst::SECOND); assert_buffer!(buffer, Some(2 * gst::ClockTime::SECOND));
// EOS on the fallback should not be required // EOS on the fallback should not be required
push_eos(&pipeline); push_eos(&pipeline);
@ -128,22 +128,22 @@ fn test_no_drops_but_no_fallback_frames_not_live() {
fn test_no_drops_but_no_fallback_frames(live: bool) { fn test_no_drops_but_no_fallback_frames(live: bool) {
let pipeline = setup_pipeline(Some(live)); let pipeline = setup_pipeline(Some(live));
push_buffer(&pipeline, 0.into()); push_buffer(&pipeline, gst::ClockTime::ZERO);
// +10ms needed here because the immediate timeout will be always at running time 0, but // +10ms needed here because the immediate timeout will be always at running time 0, but
// aggregator also adds the latency to it so we end up at 10ms instead. // aggregator also adds the latency to it so we end up at 10ms instead.
set_time(&pipeline, 10 * gst::MSECOND); set_time(&pipeline, 10 * gst::ClockTime::MSECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 0.into()); assert_buffer!(buffer, Some(gst::ClockTime::ZERO));
push_buffer(&pipeline, gst::SECOND); push_buffer(&pipeline, gst::ClockTime::SECOND);
set_time(&pipeline, gst::SECOND); set_time(&pipeline, gst::ClockTime::SECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, gst::SECOND); assert_buffer!(buffer, Some(gst::ClockTime::SECOND));
push_buffer(&pipeline, 2 * gst::SECOND); push_buffer(&pipeline, 2 * gst::ClockTime::SECOND);
set_time(&pipeline, 2 * gst::SECOND); set_time(&pipeline, 2 * gst::ClockTime::SECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 2 * gst::SECOND); assert_buffer!(buffer, Some(2 * gst::ClockTime::SECOND));
// EOS on the fallback should not be required // EOS on the fallback should not be required
push_eos(&pipeline); push_eos(&pipeline);
@ -165,23 +165,26 @@ fn test_short_drop_not_live() {
fn test_short_drop(live: bool) { fn test_short_drop(live: bool) {
let pipeline = setup_pipeline(Some(live)); let pipeline = setup_pipeline(Some(live));
push_buffer(&pipeline, 0.into()); push_buffer(&pipeline, gst::ClockTime::ZERO);
push_fallback_buffer(&pipeline, 0.into()); push_fallback_buffer(&pipeline, gst::ClockTime::ZERO);
set_time(&pipeline, 0.into()); set_time(&pipeline, gst::ClockTime::ZERO);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 0.into()); assert_buffer!(buffer, Some(gst::ClockTime::ZERO));
// A timeout at 1s will get rid of the fallback buffer // A timeout at 1s will get rid of the fallback buffer
// but not output anything // but not output anything
push_fallback_buffer(&pipeline, gst::SECOND); push_fallback_buffer(&pipeline, gst::ClockTime::SECOND);
// Time out the fallback buffer at +10ms // Time out the fallback buffer at +10ms
set_time(&pipeline, gst::SECOND + 10 * gst::MSECOND); set_time(
&pipeline,
gst::ClockTime::SECOND + 10 * gst::ClockTime::MSECOND,
);
push_fallback_buffer(&pipeline, 2 * gst::SECOND); push_fallback_buffer(&pipeline, 2 * gst::ClockTime::SECOND);
push_buffer(&pipeline, 2 * gst::SECOND); push_buffer(&pipeline, 2 * gst::ClockTime::SECOND);
set_time(&pipeline, 2 * gst::SECOND); set_time(&pipeline, 2 * gst::ClockTime::SECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 2 * gst::SECOND); assert_buffer!(buffer, Some(2 * gst::ClockTime::SECOND));
push_eos(&pipeline); push_eos(&pipeline);
push_fallback_eos(&pipeline); push_fallback_eos(&pipeline);
@ -204,33 +207,45 @@ fn test_long_drop_and_eos(live: bool) {
let pipeline = setup_pipeline(Some(live)); let pipeline = setup_pipeline(Some(live));
// Produce the first frame // Produce the first frame
push_buffer(&pipeline, 0.into()); push_buffer(&pipeline, gst::ClockTime::ZERO);
push_fallback_buffer(&pipeline, 0.into()); push_fallback_buffer(&pipeline, gst::ClockTime::ZERO);
set_time(&pipeline, 0.into()); set_time(&pipeline, gst::ClockTime::ZERO);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 0.into()); assert_buffer!(buffer, Some(gst::ClockTime::ZERO));
// Produce a second frame but only from the fallback source // Produce a second frame but only from the fallback source
push_fallback_buffer(&pipeline, gst::SECOND); push_fallback_buffer(&pipeline, gst::ClockTime::SECOND);
set_time(&pipeline, gst::SECOND + 10 * gst::MSECOND); set_time(
&pipeline,
gst::ClockTime::SECOND + 10 * gst::ClockTime::MSECOND,
);
// Produce a third frame but only from the fallback source // Produce a third frame but only from the fallback source
push_fallback_buffer(&pipeline, 2 * gst::SECOND); push_fallback_buffer(&pipeline, 2 * gst::ClockTime::SECOND);
set_time(&pipeline, 2 * gst::SECOND + 10 * gst::MSECOND); set_time(
&pipeline,
2 * gst::ClockTime::SECOND + 10 * gst::ClockTime::MSECOND,
);
// Produce a fourth frame but only from the fallback source // Produce a fourth frame but only from the fallback source
// This should be output now // This should be output now
push_fallback_buffer(&pipeline, 3 * gst::SECOND); push_fallback_buffer(&pipeline, 3 * gst::ClockTime::SECOND);
set_time(&pipeline, 3 * gst::SECOND + 10 * gst::MSECOND); set_time(
&pipeline,
3 * gst::ClockTime::SECOND + 10 * gst::ClockTime::MSECOND,
);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_fallback_buffer!(buffer, 3 * gst::SECOND); assert_fallback_buffer!(buffer, Some(3 * gst::ClockTime::SECOND));
// Produce a fifth frame but only from the fallback source // Produce a fifth frame but only from the fallback source
// This should be output now // This should be output now
push_fallback_buffer(&pipeline, 4 * gst::SECOND); push_fallback_buffer(&pipeline, 4 * gst::ClockTime::SECOND);
set_time(&pipeline, 4 * gst::SECOND + 10 * gst::MSECOND); set_time(
&pipeline,
4 * gst::ClockTime::SECOND + 10 * gst::ClockTime::MSECOND,
);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_fallback_buffer!(buffer, 4 * gst::SECOND); assert_fallback_buffer!(buffer, Some(4 * gst::ClockTime::SECOND));
// Wait for EOS to arrive at appsink // Wait for EOS to arrive at appsink
push_eos(&pipeline); push_eos(&pipeline);
@ -254,54 +269,66 @@ fn test_long_drop_and_recover(live: bool) {
let pipeline = setup_pipeline(Some(live)); let pipeline = setup_pipeline(Some(live));
// Produce the first frame // Produce the first frame
push_buffer(&pipeline, 0.into()); push_buffer(&pipeline, gst::ClockTime::ZERO);
push_fallback_buffer(&pipeline, 0.into()); push_fallback_buffer(&pipeline, gst::ClockTime::ZERO);
set_time(&pipeline, 0.into()); set_time(&pipeline, gst::ClockTime::ZERO);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 0.into()); assert_buffer!(buffer, Some(gst::ClockTime::ZERO));
// Produce a second frame but only from the fallback source // Produce a second frame but only from the fallback source
push_fallback_buffer(&pipeline, gst::SECOND); push_fallback_buffer(&pipeline, gst::ClockTime::SECOND);
set_time(&pipeline, gst::SECOND + 10 * gst::MSECOND); set_time(
&pipeline,
gst::ClockTime::SECOND + 10 * gst::ClockTime::MSECOND,
);
// Produce a third frame but only from the fallback source // Produce a third frame but only from the fallback source
push_fallback_buffer(&pipeline, 2 * gst::SECOND); push_fallback_buffer(&pipeline, 2 * gst::ClockTime::SECOND);
set_time(&pipeline, 2 * gst::SECOND + 10 * gst::MSECOND); set_time(
&pipeline,
2 * gst::ClockTime::SECOND + 10 * gst::ClockTime::MSECOND,
);
// Produce a fourth frame but only from the fallback source // Produce a fourth frame but only from the fallback source
// This should be output now // This should be output now
push_fallback_buffer(&pipeline, 3 * gst::SECOND); push_fallback_buffer(&pipeline, 3 * gst::ClockTime::SECOND);
set_time(&pipeline, 3 * gst::SECOND + 10 * gst::MSECOND); set_time(
&pipeline,
3 * gst::ClockTime::SECOND + 10 * gst::ClockTime::MSECOND,
);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_fallback_buffer!(buffer, 3 * gst::SECOND); assert_fallback_buffer!(buffer, Some(3 * gst::ClockTime::SECOND));
// Produce a fifth frame but only from the fallback source // Produce a fifth frame but only from the fallback source
// This should be output now // This should be output now
push_fallback_buffer(&pipeline, 4 * gst::SECOND); push_fallback_buffer(&pipeline, 4 * gst::ClockTime::SECOND);
set_time(&pipeline, 4 * gst::SECOND + 10 * gst::MSECOND); set_time(
&pipeline,
4 * gst::ClockTime::SECOND + 10 * gst::ClockTime::MSECOND,
);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_fallback_buffer!(buffer, 4 * gst::SECOND); assert_fallback_buffer!(buffer, Some(4 * gst::ClockTime::SECOND));
// Produce a sixth frame from the normal source // Produce a sixth frame from the normal source
push_buffer(&pipeline, 5 * gst::SECOND); push_buffer(&pipeline, 5 * gst::ClockTime::SECOND);
push_fallback_buffer(&pipeline, 5 * gst::SECOND); push_fallback_buffer(&pipeline, 5 * gst::ClockTime::SECOND);
set_time(&pipeline, 5 * gst::SECOND); set_time(&pipeline, 5 * gst::ClockTime::SECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 5 * gst::SECOND); assert_buffer!(buffer, Some(5 * gst::ClockTime::SECOND));
// Produce a seventh frame from the normal source but no fallback. // Produce a seventh frame from the normal source but no fallback.
// This should still be output immediately // This should still be output immediately
push_buffer(&pipeline, 6 * gst::SECOND); push_buffer(&pipeline, 6 * gst::ClockTime::SECOND);
set_time(&pipeline, 6 * gst::SECOND); set_time(&pipeline, 6 * gst::ClockTime::SECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 6 * gst::SECOND); assert_buffer!(buffer, Some(6 * gst::ClockTime::SECOND));
// Produce a eight frame from the normal source // Produce a eight frame from the normal source
push_buffer(&pipeline, 7 * gst::SECOND); push_buffer(&pipeline, 7 * gst::ClockTime::SECOND);
push_fallback_buffer(&pipeline, 7 * gst::SECOND); push_fallback_buffer(&pipeline, 7 * gst::ClockTime::SECOND);
set_time(&pipeline, 7 * gst::SECOND); set_time(&pipeline, 7 * gst::ClockTime::SECOND);
let buffer = pull_buffer(&pipeline); let buffer = pull_buffer(&pipeline);
assert_buffer!(buffer, 7 * gst::SECOND); assert_buffer!(buffer, Some(7 * gst::ClockTime::SECOND));
// Wait for EOS to arrive at appsink // Wait for EOS to arrive at appsink
push_eos(&pipeline); push_eos(&pipeline);
@ -330,15 +357,15 @@ fn setup_pipeline(with_live_fallback: Option<bool>) -> Pipeline {
gst_debug!(TEST_CAT, "Setting up pipeline"); gst_debug!(TEST_CAT, "Setting up pipeline");
let clock = gst_check::TestClock::new(); let clock = gst_check::TestClock::new();
clock.set_time(0.into()); clock.set_time(gst::ClockTime::ZERO);
let pipeline = gst::Pipeline::new(None); let pipeline = gst::Pipeline::new(None);
// Running time 0 in our pipeline is going to be clock time 1s. All // Running time 0 in our pipeline is going to be clock time 1s. All
// clock ids before 1s are used for signalling to our clock advancing // clock ids before 1s are used for signalling to our clock advancing
// thread. // thread.
pipeline.use_clock(Some(&clock)); pipeline.use_clock(Some(&clock));
pipeline.set_base_time(gst::SECOND); pipeline.set_base_time(gst::ClockTime::SECOND);
pipeline.set_start_time(gst::CLOCK_TIME_NONE); pipeline.set_start_time(gst::ClockTime::NONE);
let src = gst::ElementFactory::make("appsrc", Some("src")) let src = gst::ElementFactory::make("appsrc", Some("src"))
.unwrap() .unwrap()
@ -359,7 +386,9 @@ fn setup_pipeline(with_live_fallback: Option<bool>) -> Pipeline {
.unwrap(); .unwrap();
let switch = gst::ElementFactory::make("fallbackswitch", Some("switch")).unwrap(); let switch = gst::ElementFactory::make("fallbackswitch", Some("switch")).unwrap();
switch.set_property("timeout", &(3 * gst::SECOND)).unwrap(); switch
.set_property("timeout", &(3 * gst::ClockTime::SECOND))
.unwrap();
let sink = gst::ElementFactory::make("appsink", Some("sink")) let sink = gst::ElementFactory::make("appsink", Some("sink"))
.unwrap() .unwrap()
@ -411,7 +440,7 @@ fn setup_pipeline(with_live_fallback: Option<bool>) -> Pipeline {
loop { loop {
while let Some(clock_id) = clock.peek_next_pending_id().and_then(|clock_id| { while let Some(clock_id) = clock.peek_next_pending_id().and_then(|clock_id| {
// Process if the clock ID is in the past or now // Process if the clock ID is in the past or now
if clock.time() >= clock_id.time() { if clock.time().map_or(false, |time| time >= clock_id.time()) {
Some(clock_id) Some(clock_id)
} else { } else {
None None
@ -420,7 +449,7 @@ fn setup_pipeline(with_live_fallback: Option<bool>) -> Pipeline {
gst_debug!(TEST_CAT, "Processing clock ID at {}", clock_id.time()); gst_debug!(TEST_CAT, "Processing clock ID at {}", clock_id.time());
if let Some(clock_id) = clock.process_next_clock_id() { if let Some(clock_id) = clock.process_next_clock_id() {
gst_debug!(TEST_CAT, "Processed clock ID at {}", clock_id.time()); gst_debug!(TEST_CAT, "Processed clock ID at {}", clock_id.time());
if clock_id.time() == 0.into() { if clock_id.time().is_zero() {
gst_debug!(TEST_CAT, "Stopping clock thread"); gst_debug!(TEST_CAT, "Stopping clock thread");
return; return;
} }
@ -431,7 +460,10 @@ fn setup_pipeline(with_live_fallback: Option<bool>) -> Pipeline {
// at the top of the queue. We don't want to do a busy loop here. // at the top of the queue. We don't want to do a busy loop here.
while clock.peek_next_pending_id().iter().any(|clock_id| { while clock.peek_next_pending_id().iter().any(|clock_id| {
// Sleep if the clock ID is in the future // Sleep if the clock ID is in the future
clock.time() < clock_id.time() // FIXME probably can expect clock.time()
clock
.time()
.map_or(true, |clock_time| clock_time < clock_id.time())
}) { }) {
use std::{thread, time}; use std::{thread, time};
@ -514,7 +546,7 @@ fn set_time(pipeline: &Pipeline, time: gst::ClockTime) {
.unwrap(); .unwrap();
gst_debug!(TEST_CAT, "Setting time to {}", time); gst_debug!(TEST_CAT, "Setting time to {}", time);
clock.set_time(gst::SECOND + time); clock.set_time(gst::ClockTime::SECOND + time);
} }
fn wait_eos(pipeline: &Pipeline) { fn wait_eos(pipeline: &Pipeline) {
@ -545,7 +577,7 @@ fn stop_pipeline(mut pipeline: Pipeline) {
.unwrap(); .unwrap();
// Signal shutdown to the clock thread // Signal shutdown to the clock thread
let clock_id = clock.new_single_shot_id(0.into()); let clock_id = clock.new_single_shot_id(gst::ClockTime::ZERO);
let _ = clock_id.wait(); let _ = clock_id.wait();
let switch = pipeline.by_name("switch").unwrap(); let switch = pipeline.by_name("switch").unwrap();

View file

@ -14,7 +14,6 @@ gst-video = { package = "gstreamer-video", git = "https://gitlab.freedesktop.org
gtk = { git = "https://github.com/gtk-rs/gtk3-rs", optional = true } gtk = { git = "https://github.com/gtk-rs/gtk3-rs", optional = true }
gio = { git = "https://github.com/gtk-rs/gtk-rs-core", optional = true } gio = { git = "https://github.com/gtk-rs/gtk-rs-core", optional = true }
parking_lot = "0.11" parking_lot = "0.11"
more-asserts = "0.2"
once_cell = "1.0" once_cell = "1.0"
[dev-dependencies] [dev-dependencies]

View file

@ -237,14 +237,14 @@ fn create_ui(app: &gtk::Application) {
let position = video_sink let position = video_sink
.query_position::<gst::ClockTime>() .query_position::<gst::ClockTime>()
.unwrap_or_else(|| 0.into()); .unwrap_or(gst::ClockTime::ZERO);
position_label.set_text(&format!("Position: {:.1}", position)); position_label.set_text(&format!("Position: {:.1}", position));
let recording_duration = togglerecord let recording_duration = togglerecord
.static_pad("src") .static_pad("src")
.unwrap() .unwrap()
.query_position::<gst::ClockTime>() .query_position::<gst::ClockTime>()
.unwrap_or_else(|| 0.into()); .unwrap_or(gst::ClockTime::ZERO);
recorded_duration_label.set_text(&format!("Recorded: {:.1}", recording_duration)); recorded_duration_label.set_text(&format!("Recorded: {:.1}", recording_duration));
glib::Continue(true) glib::Continue(true)

View file

@ -20,8 +20,6 @@ use gst::prelude::*;
use gst::subclass::prelude::*; use gst::subclass::prelude::*;
use gst::{gst_debug, gst_log, gst_trace, gst_warning}; use gst::{gst_debug, gst_log, gst_trace, gst_warning};
use more_asserts::{assert_ge, assert_le, assert_lt};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use parking_lot::{Condvar, Mutex}; use parking_lot::{Condvar, Mutex};
use std::cmp; use std::cmp;
@ -75,8 +73,8 @@ struct StreamState {
out_segment: gst::FormattedSegment<gst::ClockTime>, out_segment: gst::FormattedSegment<gst::ClockTime>,
segment_seqnum: gst::Seqnum, segment_seqnum: gst::Seqnum,
// Start/end running time of the current/last buffer // Start/end running time of the current/last buffer
current_running_time: gst::ClockTime, current_running_time: Option<gst::ClockTime>,
current_running_time_end: gst::ClockTime, current_running_time_end: Option<gst::ClockTime>,
eos: bool, eos: bool,
flushing: bool, flushing: bool,
segment_pending: bool, segment_pending: bool,
@ -92,8 +90,8 @@ impl Default for StreamState {
in_segment: gst::FormattedSegment::new(), in_segment: gst::FormattedSegment::new(),
out_segment: gst::FormattedSegment::new(), out_segment: gst::FormattedSegment::new(),
segment_seqnum: gst::Seqnum::next(), segment_seqnum: gst::Seqnum::next(),
current_running_time: gst::CLOCK_TIME_NONE, current_running_time: None,
current_running_time_end: gst::CLOCK_TIME_NONE, current_running_time_end: None,
eos: false, eos: false,
flushing: false, flushing: false,
segment_pending: false, segment_pending: false,
@ -127,23 +125,23 @@ enum RecordingState {
#[derive(Debug)] #[derive(Debug)]
struct State { struct State {
recording_state: RecordingState, recording_state: RecordingState,
last_recording_start: gst::ClockTime, last_recording_start: Option<gst::ClockTime>,
last_recording_stop: gst::ClockTime, last_recording_stop: Option<gst::ClockTime>,
// Accumulated duration of previous recording segments, // Accumulated duration of previous recording segments,
// updated whenever going to Stopped // updated whenever going to Stopped
recording_duration: gst::ClockTime, recording_duration: gst::ClockTime,
// Updated whenever going to Recording // Updated whenever going to Recording
running_time_offset: gst::ClockTime, running_time_offset: i64,
} }
impl Default for State { impl Default for State {
fn default() -> Self { fn default() -> Self {
Self { Self {
recording_state: RecordingState::Stopped, recording_state: RecordingState::Stopped,
last_recording_start: gst::CLOCK_TIME_NONE, last_recording_start: None,
last_recording_stop: gst::CLOCK_TIME_NONE, last_recording_stop: None,
recording_duration: 0.into(), recording_duration: gst::ClockTime::ZERO,
running_time_offset: gst::CLOCK_TIME_NONE, running_time_offset: 0,
} }
} }
} }
@ -157,9 +155,9 @@ enum HandleResult<T> {
} }
trait HandleData: Sized { trait HandleData: Sized {
fn pts(&self) -> gst::ClockTime; fn pts(&self) -> Option<gst::ClockTime>;
fn dts(&self) -> gst::ClockTime; fn dts(&self) -> Option<gst::ClockTime>;
fn dts_or_pts(&self) -> gst::ClockTime { fn dts_or_pts(&self) -> Option<gst::ClockTime> {
let dts = self.dts(); let dts = self.dts();
if dts.is_some() { if dts.is_some() {
dts dts
@ -167,7 +165,7 @@ trait HandleData: Sized {
self.pts() self.pts()
} }
} }
fn duration(&self, state: &StreamState) -> gst::ClockTime; fn duration(&self, state: &StreamState) -> Option<gst::ClockTime>;
fn is_keyframe(&self) -> bool; fn is_keyframe(&self) -> bool;
fn can_clip(&self, state: &StreamState) -> bool; fn can_clip(&self, state: &StreamState) -> bool;
fn clip( fn clip(
@ -177,16 +175,16 @@ trait HandleData: Sized {
) -> Option<Self>; ) -> Option<Self>;
} }
impl HandleData for (gst::ClockTime, gst::ClockTime) { impl HandleData for (gst::ClockTime, Option<gst::ClockTime>) {
fn pts(&self) -> gst::ClockTime { fn pts(&self) -> Option<gst::ClockTime> {
self.0 Some(self.0)
} }
fn dts(&self) -> gst::ClockTime { fn dts(&self) -> Option<gst::ClockTime> {
self.0 Some(self.0)
} }
fn duration(&self, _state: &StreamState) -> gst::ClockTime { fn duration(&self, _state: &StreamState) -> Option<gst::ClockTime> {
self.1 self.1
} }
@ -203,55 +201,48 @@ impl HandleData for (gst::ClockTime, gst::ClockTime) {
_state: &StreamState, _state: &StreamState,
segment: &gst::FormattedSegment<gst::ClockTime>, segment: &gst::FormattedSegment<gst::ClockTime>,
) -> Option<Self> { ) -> Option<Self> {
let stop = if self.1.is_some() { let stop = self.0 + self.1.unwrap_or(gst::ClockTime::ZERO);
self.0 + self.1
} else {
self.0
};
segment segment.clip(self.0, stop).map(|(start, stop)| {
.clip(self.0, stop) let start = start.expect("provided a defined value");
.map(|(start, stop)| (start, stop - start)) (start, stop.map(|stop| stop - start))
})
} }
} }
impl HandleData for gst::Buffer { impl HandleData for gst::Buffer {
fn pts(&self) -> gst::ClockTime { fn pts(&self) -> Option<gst::ClockTime> {
gst::BufferRef::pts(self) gst::BufferRef::pts(self)
} }
fn dts(&self) -> gst::ClockTime { fn dts(&self) -> Option<gst::ClockTime> {
gst::BufferRef::dts(self) gst::BufferRef::dts(self)
} }
fn duration(&self, state: &StreamState) -> gst::ClockTime { fn duration(&self, state: &StreamState) -> Option<gst::ClockTime> {
let duration = gst::BufferRef::duration(self); let duration = gst::BufferRef::duration(self);
if duration.is_some() { if duration.is_some() {
duration duration
} else if let Some(ref video_info) = state.video_info { } else if let Some(ref video_info) = state.video_info {
if video_info.fps() != 0.into() { if video_info.fps() != 0.into() {
gst::SECOND gst::ClockTime::SECOND.mul_div_floor(
.mul_div_floor( *video_info.fps().denom() as u64,
*video_info.fps().denom() as u64, *video_info.fps().numer() as u64,
*video_info.fps().numer() as u64, )
)
.unwrap_or(gst::CLOCK_TIME_NONE)
} else { } else {
gst::CLOCK_TIME_NONE gst::ClockTime::NONE
} }
} else if let Some(ref audio_info) = state.audio_info { } else if let Some(ref audio_info) = state.audio_info {
if audio_info.bpf() == 0 || audio_info.rate() == 0 { if audio_info.bpf() == 0 || audio_info.rate() == 0 {
return gst::CLOCK_TIME_NONE; return gst::ClockTime::NONE;
} }
let size = self.size() as u64; let size = self.size() as u64;
let num_samples = size / audio_info.bpf() as u64; let num_samples = size / audio_info.bpf() as u64;
gst::SECOND gst::ClockTime::SECOND.mul_div_floor(num_samples, audio_info.rate() as u64)
.mul_div_floor(num_samples, audio_info.rate() as u64)
.unwrap_or(gst::CLOCK_TIME_NONE)
} else { } else {
gst::CLOCK_TIME_NONE gst::ClockTime::NONE
} }
} }
@ -295,11 +286,7 @@ impl HandleData for gst::Buffer {
let pts = HandleData::pts(&self); let pts = HandleData::pts(&self);
let duration = HandleData::duration(&self, state); let duration = HandleData::duration(&self, state);
let stop = if duration.is_some() { let stop = pts.map(|pts| pts + duration.unwrap_or(gst::ClockTime::ZERO));
pts + duration
} else {
pts
};
if let Some(ref audio_info) = state.audio_info { if let Some(ref audio_info) = state.audio_info {
gst_audio::audio_buffer_clip( gst_audio::audio_buffer_clip(
@ -313,7 +300,11 @@ impl HandleData for gst::Buffer {
{ {
let buffer = self.make_mut(); let buffer = self.make_mut();
buffer.set_pts(start); buffer.set_pts(start);
buffer.set_duration(stop - start); buffer.set_duration(
stop.zip(start)
.and_then(|(stop, start)| stop.checked_sub(start)),
// FIXME we could expect here
);
} }
self self
@ -354,48 +345,47 @@ impl ToggleRecord {
) -> Result<HandleResult<T>, gst::FlowError> { ) -> Result<HandleResult<T>, gst::FlowError> {
let mut state = stream.state.lock(); let mut state = stream.state.lock();
let mut dts_or_pts = data.dts_or_pts(); let mut dts_or_pts = data.dts_or_pts().ok_or_else(|| {
let duration = data.duration(&state);
if !dts_or_pts.is_some() {
gst::element_error!( gst::element_error!(
element, element,
gst::StreamError::Format, gst::StreamError::Format,
["Buffer without DTS or PTS"] ["Buffer without DTS or PTS"]
); );
return Err(gst::FlowError::Error); gst::FlowError::Error
} })?;
let mut dts_or_pts_end = if duration.is_some() { let mut dts_or_pts_end = dts_or_pts + data.duration(&state).unwrap_or(gst::ClockTime::ZERO);
dts_or_pts + duration
} else {
dts_or_pts
};
let data = match data.clip(&state, &state.in_segment) { let data = match data.clip(&state, &state.in_segment) {
Some(data) => data,
None => { None => {
gst_log!(CAT, obj: pad, "Dropping raw data outside segment"); gst_log!(CAT, obj: pad, "Dropping raw data outside segment");
return Ok(HandleResult::Drop); return Ok(HandleResult::Drop);
} }
Some(data) => data,
}; };
// This will only do anything for non-raw data // This will only do anything for non-raw data
dts_or_pts = state.in_segment.start().max(dts_or_pts).unwrap(); // FIXME comment why we can unwrap
dts_or_pts_end = state.in_segment.start().max(dts_or_pts_end).unwrap(); dts_or_pts = state.in_segment.start().unwrap().max(dts_or_pts);
if state.in_segment.stop().is_some() { dts_or_pts_end = state.in_segment.start().unwrap().max(dts_or_pts_end);
dts_or_pts = state.in_segment.stop().min(dts_or_pts).unwrap(); if let Some(stop) = state.in_segment.stop() {
dts_or_pts_end = state.in_segment.stop().min(dts_or_pts_end).unwrap(); dts_or_pts = stop.min(dts_or_pts);
dts_or_pts_end = stop.min(dts_or_pts_end);
} }
let current_running_time = state.in_segment.to_running_time(dts_or_pts); let current_running_time = state.in_segment.to_running_time(dts_or_pts);
let current_running_time_end = state.in_segment.to_running_time(dts_or_pts_end); let current_running_time_end = state.in_segment.to_running_time(dts_or_pts_end);
state.current_running_time = current_running_time state.current_running_time = current_running_time
.max(state.current_running_time) .zip(state.current_running_time)
.unwrap_or(current_running_time); .map(|(cur_rt, state_rt)| cur_rt.max(state_rt))
.or(current_running_time);
state.current_running_time_end = current_running_time_end state.current_running_time_end = current_running_time_end
.max(state.current_running_time_end) .zip(state.current_running_time_end)
.unwrap_or(current_running_time_end); .map(|(cur_rt_end, state_rt_end)| cur_rt_end.max(state_rt_end))
.or(current_running_time_end);
// FIXME we should probably return if either current_running_time or current_running_time_end
// are None at this point
// Wake up everybody, we advanced a bit // Wake up everybody, we advanced a bit
// Important: They will only be able to advance once we're done with this // Important: They will only be able to advance once we're done with this
@ -407,10 +397,10 @@ impl ToggleRecord {
CAT, CAT,
obj: pad, obj: pad,
"Main stream current running time {}-{} (position: {}-{})", "Main stream current running time {}-{} (position: {}-{})",
current_running_time, current_running_time.display(),
current_running_time_end, current_running_time_end.display(),
dts_or_pts, dts_or_pts,
dts_or_pts_end dts_or_pts_end,
); );
let settings = *self.settings.lock(); let settings = *self.settings.lock();
@ -458,13 +448,17 @@ impl ToggleRecord {
// Remember the time when we stopped: now, i.e. right before the current buffer! // Remember the time when we stopped: now, i.e. right before the current buffer!
rec_state.last_recording_stop = current_running_time; rec_state.last_recording_stop = current_running_time;
let last_recording_duration = rec_state
.last_recording_stop
.zip(rec_state.last_recording_start)
.and_then(|(stop, start)| stop.checked_sub(start));
gst_debug!( gst_debug!(
CAT, CAT,
obj: pad, obj: pad,
"Stopping at {}, started at {}, current duration {}, previous accumulated recording duration {}", "Stopping at {}, started at {}, current duration {}, previous accumulated recording duration {}",
rec_state.last_recording_stop, rec_state.last_recording_stop.display(),
rec_state.last_recording_start, rec_state.last_recording_start.display(),
rec_state.last_recording_stop - rec_state.last_recording_start, last_recording_duration.display(),
rec_state.recording_duration rec_state.recording_duration
); );
@ -477,8 +471,9 @@ impl ToggleRecord {
&& !self.other_streams.lock().0.iter().all(|s| { && !self.other_streams.lock().0.iter().all(|s| {
let s = s.state.lock(); let s = s.state.lock();
s.eos s.eos
|| (s.current_running_time.is_some() || s.current_running_time
&& s.current_running_time >= current_running_time) .zip(current_running_time)
.map_or(false, |(s_cur_rt, cur_rt)| s_cur_rt >= cur_rt)
}) })
{ {
gst_log!(CAT, obj: pad, "Waiting for other streams to stop"); gst_log!(CAT, obj: pad, "Waiting for other streams to stop");
@ -492,17 +487,17 @@ impl ToggleRecord {
let mut rec_state = self.state.lock(); let mut rec_state = self.state.lock();
rec_state.recording_state = RecordingState::Stopped; rec_state.recording_state = RecordingState::Stopped;
let advance_by = rec_state.last_recording_stop - rec_state.last_recording_start; rec_state.recording_duration +=
rec_state.recording_duration += advance_by; last_recording_duration.unwrap_or(gst::ClockTime::ZERO);
rec_state.last_recording_start = gst::CLOCK_TIME_NONE; rec_state.last_recording_start = None;
rec_state.last_recording_stop = gst::CLOCK_TIME_NONE; rec_state.last_recording_stop = None;
gst_debug!( gst_debug!(
CAT, CAT,
obj: pad, obj: pad,
"Stopped at {}, recording duration {}", "Stopped at {}, recording duration {}",
current_running_time, current_running_time.display(),
rec_state.recording_duration rec_state.recording_duration.display(),
); );
// Then become Stopped and drop this buffer. We always stop right before // Then become Stopped and drop this buffer. We always stop right before
@ -538,12 +533,17 @@ impl ToggleRecord {
// Remember the time when we started: now! // Remember the time when we started: now!
rec_state.last_recording_start = current_running_time; rec_state.last_recording_start = current_running_time;
rec_state.running_time_offset = current_running_time - rec_state.recording_duration; rec_state.running_time_offset =
current_running_time.map_or(0, |current_running_time| {
current_running_time
.saturating_sub(rec_state.recording_duration)
.nseconds()
}) as i64;
gst_debug!( gst_debug!(
CAT, CAT,
obj: pad, obj: pad,
"Starting at {}, previous accumulated recording duration {}", "Starting at {}, previous accumulated recording duration {}",
current_running_time, current_running_time.display(),
rec_state.recording_duration, rec_state.recording_duration,
); );
@ -564,8 +564,9 @@ impl ToggleRecord {
&& !self.other_streams.lock().0.iter().all(|s| { && !self.other_streams.lock().0.iter().all(|s| {
let s = s.state.lock(); let s = s.state.lock();
s.eos s.eos
|| (s.current_running_time.is_some() || s.current_running_time
&& s.current_running_time >= current_running_time) .zip(current_running_time)
.map_or(false, |(s_cur_rt, cur_rt)| s_cur_rt >= cur_rt)
}) })
{ {
gst_log!(CAT, obj: pad, "Waiting for other streams to start"); gst_log!(CAT, obj: pad, "Waiting for other streams to start");
@ -583,7 +584,7 @@ impl ToggleRecord {
CAT, CAT,
obj: pad, obj: pad,
"Started at {}, recording duration {}", "Started at {}, recording duration {}",
current_running_time, current_running_time.display(),
rec_state.recording_duration rec_state.recording_duration
); );
@ -608,16 +609,12 @@ impl ToggleRecord {
// Calculate end pts & current running time and make sure we stay in the segment // Calculate end pts & current running time and make sure we stay in the segment
let mut state = stream.state.lock(); let mut state = stream.state.lock();
let mut pts = data.pts(); let mut pts = data.pts().ok_or_else(|| {
let duration = data.duration(&state);
if pts.is_none() {
gst::element_error!(element, gst::StreamError::Format, ["Buffer without PTS"]); gst::element_error!(element, gst::StreamError::Format, ["Buffer without PTS"]);
return Err(gst::FlowError::Error); gst::FlowError::Error
} })?;
let dts = data.dts(); if data.dts().map_or(false, |dts| dts != pts) {
if dts.is_some() && pts.is_some() && dts != pts {
gst::element_error!( gst::element_error!(
element, element,
gst::StreamError::Format, gst::StreamError::Format,
@ -635,11 +632,7 @@ impl ToggleRecord {
return Err(gst::FlowError::Error); return Err(gst::FlowError::Error);
} }
let mut pts_end = if duration.is_some() { let mut pts_end = pts + data.duration(&state).unwrap_or(gst::ClockTime::ZERO);
pts + duration
} else {
pts
};
let data = match data.clip(&state, &state.in_segment) { let data = match data.clip(&state, &state.in_segment) {
None => { None => {
@ -650,28 +643,31 @@ impl ToggleRecord {
}; };
// This will only do anything for non-raw data // This will only do anything for non-raw data
pts = state.in_segment.start().max(pts).unwrap(); // FIXME comment why we can unwrap
pts_end = state.in_segment.start().max(pts_end).unwrap(); pts = state.in_segment.start().unwrap().max(pts);
if state.in_segment.stop().is_some() { pts_end = state.in_segment.start().unwrap().max(pts_end);
pts = state.in_segment.stop().min(pts).unwrap(); if let Some(stop) = state.in_segment.stop() {
pts_end = state.in_segment.stop().min(pts_end).unwrap(); pts = stop.min(pts);
pts_end = stop.min(pts_end);
} }
let current_running_time = state.in_segment.to_running_time(pts); let current_running_time = state.in_segment.to_running_time(pts);
let current_running_time_end = state.in_segment.to_running_time(pts_end); let current_running_time_end = state.in_segment.to_running_time(pts_end);
state.current_running_time = current_running_time state.current_running_time = current_running_time
.max(state.current_running_time) .zip(state.current_running_time)
.unwrap_or(current_running_time); .map(|(cur_rt, state_rt)| cur_rt.max(state_rt))
.or(current_running_time);
state.current_running_time_end = current_running_time_end state.current_running_time_end = current_running_time_end
.max(state.current_running_time_end) .zip(state.current_running_time_end)
.unwrap_or(current_running_time_end); .map(|(cur_rt_end, state_rt_end)| cur_rt_end.max(state_rt_end))
.or(current_running_time_end);
gst_log!( gst_log!(
CAT, CAT,
obj: pad, obj: pad,
"Secondary stream current running time {}-{} (position: {}-{}", "Secondary stream current running time {}-{} (position: {}-{}",
current_running_time, current_running_time.display(),
current_running_time_end, current_running_time_end.display(),
pts, pts,
pts_end pts_end
); );
@ -697,13 +693,20 @@ impl ToggleRecord {
while (main_state.current_running_time.is_none() while (main_state.current_running_time.is_none()
|| rec_state.recording_state != RecordingState::Starting || rec_state.recording_state != RecordingState::Starting
&& rec_state.recording_state != RecordingState::Stopping && rec_state.recording_state != RecordingState::Stopping
&& main_state.current_running_time_end < current_running_time_end && main_state
.current_running_time_end
.zip(current_running_time_end)
.map_or(false, |(main_rt_end, cur_rt_end)| main_rt_end < cur_rt_end)
|| rec_state.recording_state == RecordingState::Starting || rec_state.recording_state == RecordingState::Starting
&& (rec_state.last_recording_start.is_none() && rec_state
|| rec_state.last_recording_start <= current_running_time) .last_recording_start
.map_or(true, |last_rec_start| {
current_running_time.map_or(false, |cur_rt| last_rec_start <= cur_rt)
})
|| rec_state.recording_state == RecordingState::Stopping || rec_state.recording_state == RecordingState::Stopping
&& (rec_state.last_recording_stop.is_none() && rec_state.last_recording_stop.map_or(true, |last_rec_stop| {
|| rec_state.last_recording_stop <= current_running_time)) current_running_time.map_or(false, |cur_rt| last_rec_stop <= cur_rt)
}))
&& !main_state.eos && !main_state.eos
&& !stream.state.lock().flushing && !stream.state.lock().flushing
{ {
@ -711,11 +714,11 @@ impl ToggleRecord {
CAT, CAT,
obj: pad, obj: pad,
"Waiting at {}-{} in {:?} state, main stream at {}-{}", "Waiting at {}-{} in {:?} state, main stream at {}-{}",
current_running_time, current_running_time.display(),
current_running_time_end, current_running_time_end.display(),
rec_state.recording_state, rec_state.recording_state,
main_state.current_running_time, main_state.current_running_time.display(),
main_state.current_running_time_end main_state.current_running_time_end.display(),
); );
drop(rec_state); drop(rec_state);
@ -742,9 +745,17 @@ impl ToggleRecord {
&mut state, &mut state,
&mut rec_state, &mut rec_state,
))); )));
} else if data.can_clip(&*state) }
&& current_running_time < rec_state.last_recording_start
&& current_running_time_end > rec_state.last_recording_start let last_recording_start = rec_state.last_recording_start.expect("recording started");
// FIXME it would help a lot if we could expect current_running_time
// and possibly current_running_time_end at some point.
if data.can_clip(&*state)
&& current_running_time.map_or(false, |cur_rt| cur_rt < last_recording_start)
&& current_running_time_end
.map_or(false, |cur_rt_end| cur_rt_end > last_recording_start)
{ {
// Otherwise if we're before the recording start but the end of the buffer is after // Otherwise if we're before the recording start but the end of the buffer is after
// the start and we can clip, clip the buffer and pass it onwards. // the start and we can clip, clip the buffer and pass it onwards.
@ -752,9 +763,9 @@ impl ToggleRecord {
CAT, CAT,
obj: pad, obj: pad,
"Main stream EOS and we're not EOS yet (overlapping recording start, {} < {} < {})", "Main stream EOS and we're not EOS yet (overlapping recording start, {} < {} < {})",
current_running_time, current_running_time.display(),
rec_state.last_recording_start, last_recording_start,
current_running_time_end current_running_time_end.display(),
); );
let mut clip_start = state let mut clip_start = state
@ -773,7 +784,7 @@ impl ToggleRecord {
segment.set_start(clip_start); segment.set_start(clip_start);
segment.set_stop(clip_stop); segment.set_stop(clip_stop);
gst_log!(CAT, obj: pad, "Clipping to segment {:?}", segment,); gst_log!(CAT, obj: pad, "Clipping to segment {:?}", segment);
if let Some(data) = data.clip(&*state, &segment) { if let Some(data) = data.clip(&*state, &segment) {
return Ok(HandleResult::Pass(data)); return Ok(HandleResult::Pass(data));
@ -781,7 +792,7 @@ impl ToggleRecord {
gst_warning!(CAT, obj: pad, "Complete buffer clipped!"); gst_warning!(CAT, obj: pad, "Complete buffer clipped!");
return Ok(HandleResult::Drop); return Ok(HandleResult::Drop);
} }
} else if current_running_time < rec_state.last_recording_start { } else if current_running_time.map_or(false, |cur_rt| cur_rt < last_recording_start) {
// Otherwise if the buffer starts before the recording start, drop it. This // Otherwise if the buffer starts before the recording start, drop it. This
// means that we either can't clip, or that the end is also before the // means that we either can't clip, or that the end is also before the
// recording start // recording start
@ -789,13 +800,19 @@ impl ToggleRecord {
CAT, CAT,
obj: pad, obj: pad,
"Main stream EOS and we're not EOS yet (before recording start, {} < {})", "Main stream EOS and we're not EOS yet (before recording start, {} < {})",
current_running_time, current_running_time.display(),
rec_state.last_recording_start last_recording_start,
); );
return Ok(HandleResult::Drop); return Ok(HandleResult::Drop);
} else if data.can_clip(&*state) } else if data.can_clip(&*state)
&& current_running_time < rec_state.last_recording_stop && current_running_time
&& current_running_time_end > rec_state.last_recording_stop .zip(rec_state.last_recording_stop)
.map_or(false, |(cur_rt, last_rec_stop)| cur_rt < last_rec_stop)
&& current_running_time_end
.zip(rec_state.last_recording_stop)
.map_or(false, |(cur_rt_end, last_rec_stop)| {
cur_rt_end > last_rec_stop
})
{ {
// Similarly if the end is after the recording stop but the start is before and we // Similarly if the end is after the recording stop but the start is before and we
// can clip, clip the buffer and pass it through. // can clip, clip the buffer and pass it through.
@ -803,9 +820,9 @@ impl ToggleRecord {
CAT, CAT,
obj: pad, obj: pad,
"Main stream EOS and we're not EOS yet (overlapping recording end, {} < {} < {})", "Main stream EOS and we're not EOS yet (overlapping recording end, {} < {} < {})",
current_running_time, current_running_time.display(),
rec_state.last_recording_stop, rec_state.last_recording_stop.display(),
current_running_time_end current_running_time_end.display(),
); );
let mut clip_start = state let mut clip_start = state
@ -837,7 +854,12 @@ impl ToggleRecord {
&mut rec_state, &mut rec_state,
))); )));
} }
} else if current_running_time_end > rec_state.last_recording_stop { } else if current_running_time_end
.zip(rec_state.last_recording_stop)
.map_or(false, |(cur_rt_end, last_rec_stop)| {
cur_rt_end > last_rec_stop
})
{
// Otherwise if the end of the buffer is after the recording stop, we're EOS // Otherwise if the end of the buffer is after the recording stop, we're EOS
// now. This means that we either couldn't clip or that the start is also after // now. This means that we either couldn't clip or that the start is also after
// the recording stop // the recording stop
@ -845,8 +867,8 @@ impl ToggleRecord {
CAT, CAT,
obj: pad, obj: pad,
"Main stream EOS and we're EOS too (after recording end, {} > {})", "Main stream EOS and we're EOS too (after recording end, {} > {})",
current_running_time_end, current_running_time_end.display(),
rec_state.last_recording_stop rec_state.last_recording_stop.display(),
); );
return Ok(HandleResult::Eos(self.check_and_update_eos( return Ok(HandleResult::Eos(self.check_and_update_eos(
pad, pad,
@ -857,16 +879,19 @@ impl ToggleRecord {
} else { } else {
// In all other cases the buffer is fully between recording start and end and // In all other cases the buffer is fully between recording start and end and
// can be passed through as is // can be passed through as is
assert_ge!(current_running_time, rec_state.last_recording_start); assert!(current_running_time.map_or(false, |cur_rt| cur_rt >= last_recording_start));
assert_le!(current_running_time_end, rec_state.last_recording_stop); assert!(current_running_time_end
.zip(rec_state.last_recording_stop)
.map_or(false, |(cur_rt_end, last_rec_stop)| cur_rt_end
<= last_rec_stop));
gst_debug!( gst_debug!(
CAT, CAT,
obj: pad, obj: pad,
"Main stream EOS and we're not EOS yet (before recording end, {} <= {} <= {})", "Main stream EOS and we're not EOS yet (before recording end, {} <= {} <= {})",
rec_state.last_recording_start, last_recording_start,
current_running_time, current_running_time.display(),
rec_state.last_recording_stop rec_state.last_recording_stop.display(),
); );
return Ok(HandleResult::Pass(data)); return Ok(HandleResult::Pass(data));
} }
@ -876,51 +901,61 @@ impl ToggleRecord {
RecordingState::Recording => { RecordingState::Recording => {
// The end of our buffer must be before/at the end of the previous buffer of the main // The end of our buffer must be before/at the end of the previous buffer of the main
// stream // stream
assert_le!( assert!(current_running_time_end
current_running_time_end, .zip(main_state.current_running_time_end)
main_state.current_running_time_end .map_or(false, |(cur_rt_end, main_cur_rt_end)| cur_rt_end
); <= main_cur_rt_end));
// We're properly started, must have a start position and // We're properly started, must have a start position and
// be actually after that start position // be actually after that start position
assert!(rec_state.last_recording_start.is_some()); assert!(current_running_time
assert_ge!(current_running_time, rec_state.last_recording_start); .zip(rec_state.last_recording_start)
.map_or(false, |(cur_rt, last_rec_start)| cur_rt >= last_rec_start));
gst_log!(CAT, obj: pad, "Passing buffer (recording)"); gst_log!(CAT, obj: pad, "Passing buffer (recording)");
Ok(HandleResult::Pass(data)) Ok(HandleResult::Pass(data))
} }
RecordingState::Stopping => { RecordingState::Stopping => {
// If we have no start position yet, the main stream is waiting for a key-frame
let last_recording_stop = match rec_state.last_recording_stop {
Some(last_recording_stop) => last_recording_stop,
None => {
gst_log!(
CAT,
obj: pad,
"Passing buffer (stopping: waiting for keyframe)",
);
return Ok(HandleResult::Pass(data));
}
};
// The start of our buffer must be before the last recording stop as // The start of our buffer must be before the last recording stop as
// otherwise we would be in Stopped state already // otherwise we would be in Stopped state already
assert_lt!(current_running_time, rec_state.last_recording_stop); assert!(current_running_time.map_or(false, |cur_rt| cur_rt < last_recording_stop));
let current_running_time = current_running_time.expect("checked above");
// If we have no start position yet, the main stream is waiting for a key-frame if current_running_time_end
if rec_state.last_recording_stop.is_none() { .map_or(false, |cur_rt_end| cur_rt_end <= last_recording_stop)
gst_log!( {
CAT,
obj: pad,
"Passing buffer (stopping: waiting for keyframe)",
);
Ok(HandleResult::Pass(data))
} else if current_running_time_end <= rec_state.last_recording_stop {
gst_log!( gst_log!(
CAT, CAT,
obj: pad, obj: pad,
"Passing buffer (stopping: {} <= {})", "Passing buffer (stopping: {} <= {})",
current_running_time_end, current_running_time_end.display(),
rec_state.last_recording_stop last_recording_stop,
); );
Ok(HandleResult::Pass(data)) Ok(HandleResult::Pass(data))
} else if data.can_clip(&*state) } else if data.can_clip(&*state)
&& current_running_time < rec_state.last_recording_stop && current_running_time < last_recording_stop
&& current_running_time_end > rec_state.last_recording_stop && current_running_time_end
.map_or(false, |cur_rt_end| cur_rt_end > last_recording_stop)
{ {
gst_log!( gst_log!(
CAT, CAT,
obj: pad, obj: pad,
"Passing buffer (stopping: {} < {} < {})", "Passing buffer (stopping: {} < {} < {})",
current_running_time, current_running_time,
rec_state.last_recording_stop, last_recording_stop,
current_running_time_end, current_running_time_end.display(),
); );
let mut clip_stop = state let mut clip_stop = state
@ -945,8 +980,8 @@ impl ToggleRecord {
CAT, CAT,
obj: pad, obj: pad,
"Dropping buffer (stopping: {} > {})", "Dropping buffer (stopping: {} > {})",
current_running_time_end, current_running_time_end.display(),
rec_state.last_recording_stop rec_state.last_recording_stop.display(),
); );
Ok(HandleResult::Drop) Ok(HandleResult::Drop)
} }
@ -954,10 +989,10 @@ impl ToggleRecord {
RecordingState::Stopped => { RecordingState::Stopped => {
// The end of our buffer must be before/at the end of the previous buffer of the main // The end of our buffer must be before/at the end of the previous buffer of the main
// stream // stream
assert_le!( assert!(current_running_time_end
current_running_time_end, .zip(main_state.current_running_time_end)
main_state.current_running_time_end .map_or(false, |(cur_rt_end, state_rt_end)| cur_rt_end
); <= state_rt_end));
// We're properly stopped // We're properly stopped
gst_log!(CAT, obj: pad, "Dropping buffer (stopped)"); gst_log!(CAT, obj: pad, "Dropping buffer (stopped)");
@ -965,38 +1000,44 @@ impl ToggleRecord {
} }
RecordingState::Starting => { RecordingState::Starting => {
// If we have no start position yet, the main stream is waiting for a key-frame // If we have no start position yet, the main stream is waiting for a key-frame
if rec_state.last_recording_start.is_none() { let last_recording_start = match rec_state.last_recording_start {
gst_log!( Some(last_recording_start) => last_recording_start,
CAT, None => {
obj: pad, gst_log!(
"Dropping buffer (starting: waiting for keyframe)", CAT,
); obj: pad,
return Ok(HandleResult::Drop); "Dropping buffer (starting: waiting for keyframe)",
} );
return Ok(HandleResult::Drop);
}
};
// The start of our buffer must be before the last recording start as // The start of our buffer must be before the last recording start as
// otherwise we would be in Recording state already // otherwise we would be in Recording state already
assert_lt!(current_running_time, rec_state.last_recording_start); assert!(current_running_time.map_or(false, |cur_rt| cur_rt < last_recording_start));
if current_running_time >= rec_state.last_recording_start { let current_running_time = current_running_time.expect("checked_above");
if current_running_time >= last_recording_start {
gst_log!( gst_log!(
CAT, CAT,
obj: pad, obj: pad,
"Passing buffer (starting: {} >= {})", "Passing buffer (starting: {} >= {})",
current_running_time, current_running_time,
rec_state.last_recording_start last_recording_start,
); );
Ok(HandleResult::Pass(data)) Ok(HandleResult::Pass(data))
} else if data.can_clip(&*state) } else if data.can_clip(&*state)
&& current_running_time < rec_state.last_recording_start && current_running_time < last_recording_start
&& current_running_time_end > rec_state.last_recording_start && current_running_time_end
.map_or(false, |cur_rt_end| cur_rt_end > last_recording_start)
{ {
gst_log!( gst_log!(
CAT, CAT,
obj: pad, obj: pad,
"Passing buffer (starting: {} < {} < {})", "Passing buffer (starting: {} < {} < {})",
current_running_time, current_running_time,
rec_state.last_recording_start, last_recording_start,
current_running_time_end, current_running_time_end.display(),
); );
let mut clip_start = state let mut clip_start = state
@ -1008,7 +1049,7 @@ impl ToggleRecord {
let mut segment = state.in_segment.clone(); let mut segment = state.in_segment.clone();
segment.set_start(clip_start); segment.set_start(clip_start);
gst_log!(CAT, obj: pad, "Clipping to segment {:?}", segment,); gst_log!(CAT, obj: pad, "Clipping to segment {:?}", segment);
if let Some(data) = data.clip(&*state, &segment) { if let Some(data) = data.clip(&*state, &segment) {
Ok(HandleResult::Pass(data)) Ok(HandleResult::Pass(data))
@ -1022,7 +1063,7 @@ impl ToggleRecord {
obj: pad, obj: pad,
"Dropping buffer (starting: {} < {})", "Dropping buffer (starting: {} < {})",
current_running_time, current_running_time,
rec_state.last_recording_start last_recording_start,
); );
Ok(HandleResult::Drop) Ok(HandleResult::Drop)
} }
@ -1151,10 +1192,9 @@ impl ToggleRecord {
// recording_duration // recording_duration
state.out_segment = state.in_segment.clone(); state.out_segment = state.in_segment.clone();
let offset = rec_state.running_time_offset.unwrap_or(0);
state state
.out_segment .out_segment
.offset_running_time(-(offset as i64)) .offset_running_time(-rec_state.running_time_offset)
.expect("Adjusting record duration"); .expect("Adjusting record duration");
events.push( events.push(
gst::event::Segment::builder(&state.out_segment) gst::event::Segment::builder(&state.out_segment)
@ -1187,8 +1227,8 @@ impl ToggleRecord {
CAT, CAT,
obj: pad, obj: pad,
"Pushing buffer with running time {}: {:?}", "Pushing buffer with running time {}: {:?}",
out_running_time, out_running_time.display(),
buffer buffer,
); );
stream.srcpad.push(buffer) stream.srcpad.push(buffer)
} }
@ -1238,8 +1278,8 @@ impl ToggleRecord {
state.flushing = false; state.flushing = false;
state.segment_pending = true; state.segment_pending = true;
state.discont_pending = true; state.discont_pending = true;
state.current_running_time = gst::CLOCK_TIME_NONE; state.current_running_time = None;
state.current_running_time_end = gst::CLOCK_TIME_NONE; state.current_running_time_end = None;
} }
EventView::Caps(c) => { EventView::Caps(c) => {
let mut state = stream.state.lock(); let mut state = stream.state.lock();
@ -1288,8 +1328,8 @@ impl ToggleRecord {
state.in_segment = segment; state.in_segment = segment;
state.segment_seqnum = event.seqnum(); state.segment_seqnum = event.seqnum();
state.segment_pending = true; state.segment_pending = true;
state.current_running_time = gst::CLOCK_TIME_NONE; state.current_running_time = None;
state.current_running_time_end = gst::CLOCK_TIME_NONE; state.current_running_time_end = None;
gst_debug!(CAT, obj: pad, "Got new Segment {:?}", state.in_segment); gst_debug!(CAT, obj: pad, "Got new Segment {:?}", state.in_segment);
@ -1305,14 +1345,19 @@ impl ToggleRecord {
}; };
forward = match handle_result { forward = match handle_result {
Ok(HandleResult::Pass((new_pts, new_duration))) if new_pts.is_some() => { Ok(HandleResult::Pass((new_pts, new_duration))) => {
if new_pts != pts || new_duration != duration { if new_pts != pts
event = gst::event::Gap::new(new_pts, new_duration); || new_duration
.zip(duration)
.map_or(false, |(new_duration, duration)| new_duration != duration)
{
event = gst::event::Gap::builder(new_pts)
.duration(new_duration)
.build();
} }
true true
} }
Ok(_) => false, _ => false,
Err(_) => false,
}; };
} }
EventView::Eos(..) => { EventView::Eos(..) => {
@ -1449,11 +1494,10 @@ impl ToggleRecord {
let forward = !matches!(event.view(), EventView::Seek(..)); let forward = !matches!(event.view(), EventView::Seek(..));
let rec_state = self.state.lock(); let rec_state = self.state.lock();
let running_time_offset = rec_state.running_time_offset.unwrap_or(0) as i64;
let offset = event.running_time_offset(); let offset = event.running_time_offset();
event event
.make_mut() .make_mut()
.set_running_time_offset(offset + running_time_offset); .set_running_time_offset(offset + rec_state.running_time_offset);
drop(rec_state); drop(rec_state);
if forward { if forward {
@ -1530,20 +1574,26 @@ impl ToggleRecord {
if rec_state.recording_state == RecordingState::Recording if rec_state.recording_state == RecordingState::Recording
|| rec_state.recording_state == RecordingState::Stopping || rec_state.recording_state == RecordingState::Stopping
{ {
gst_debug!( if let Some(delta) = state
CAT, .current_running_time_end
obj: pad, .zip(rec_state.last_recording_start)
"Returning position {} = {} - ({} + {})", .and_then(|(cur_rt_end, last_rec_start)| {
recording_duration cur_rt_end.checked_sub(last_rec_start)
+ (state.current_running_time_end - rec_state.last_recording_start), })
recording_duration, {
state.current_running_time_end, gst_debug!(
rec_state.last_recording_start CAT,
); obj: pad,
recording_duration += "Returning position {} = {} - ({} + {})",
state.current_running_time_end - rec_state.last_recording_start; recording_duration + delta,
recording_duration,
state.current_running_time_end.display(),
rec_state.last_recording_start.display(),
);
recording_duration += delta;
}
} else { } else {
gst_debug!(CAT, obj: pad, "Returning position {}", recording_duration,); gst_debug!(CAT, obj: pad, "Returning position {}", recording_duration);
} }
q.set(recording_duration); q.set(recording_duration);
true true
@ -1559,20 +1609,26 @@ impl ToggleRecord {
if rec_state.recording_state == RecordingState::Recording if rec_state.recording_state == RecordingState::Recording
|| rec_state.recording_state == RecordingState::Stopping || rec_state.recording_state == RecordingState::Stopping
{ {
gst_debug!( if let Some(delta) = state
CAT, .current_running_time_end
obj: pad, .zip(rec_state.last_recording_start)
"Returning duration {} = {} - ({} + {})", .and_then(|(cur_rt_end, last_rec_start)| {
recording_duration cur_rt_end.checked_sub(last_rec_start)
+ (state.current_running_time_end - rec_state.last_recording_start), })
recording_duration, {
state.current_running_time_end, gst_debug!(
rec_state.last_recording_start CAT,
); obj: pad,
recording_duration += "Returning duration {} = {} - ({} + {})",
state.current_running_time_end - rec_state.last_recording_start; recording_duration + delta,
recording_duration,
state.current_running_time_end.display(),
rec_state.last_recording_start.display(),
);
recording_duration += delta;
}
} else { } else {
gst_debug!(CAT, obj: pad, "Returning duration {}", recording_duration,); gst_debug!(CAT, obj: pad, "Returning duration {}", recording_duration);
} }
q.set(recording_duration); q.set(recording_duration);
true true

View file

@ -153,8 +153,8 @@ fn setup_sender_receiver(
let mut buffer = buffer.clone(); let mut buffer = buffer.clone();
{ {
let buffer = buffer.make_mut(); let buffer = buffer.make_mut();
buffer.set_pts(offset + i * 20 * gst::MSECOND); buffer.set_pts(offset + i * 20 * gst::ClockTime::MSECOND);
buffer.set_duration(20 * gst::MSECOND); buffer.set_duration(20 * gst::ClockTime::MSECOND);
} }
let _ = sinkpad.chain(buffer); let _ = sinkpad.chain(buffer);
i += 1; i += 1;
@ -166,8 +166,11 @@ fn setup_sender_receiver(
buffer buffer
.get_mut() .get_mut()
.unwrap() .unwrap()
.set_pts(offset + i * 20 * gst::MSECOND); .set_pts(offset + i * 20 * gst::ClockTime::MSECOND);
buffer.get_mut().unwrap().set_duration(20 * gst::MSECOND); buffer
.get_mut()
.unwrap()
.set_duration(20 * gst::ClockTime::MSECOND);
buffer buffer
.get_mut() .get_mut()
.unwrap() .unwrap()
@ -178,8 +181,10 @@ fn setup_sender_receiver(
} }
SendData::Gaps(n) => { SendData::Gaps(n) => {
for _ in 0..n { for _ in 0..n {
let event = let event = gst::event::Gap::new(
gst::event::Gap::new(offset + i * 20 * gst::MSECOND, 20 * gst::MSECOND); offset + i * 20 * gst::ClockTime::MSECOND,
20 * gst::ClockTime::MSECOND,
);
let _ = sinkpad.send_event(event); let _ = sinkpad.send_event(event);
i += 1; i += 1;
} }
@ -204,7 +209,14 @@ fn recv_buffers(
receiver_output: &mpsc::Receiver<Either<gst::Buffer, gst::Event>>, receiver_output: &mpsc::Receiver<Either<gst::Buffer, gst::Event>>,
segment: &mut gst::FormattedSegment<gst::ClockTime>, segment: &mut gst::FormattedSegment<gst::ClockTime>,
wait_buffers: usize, wait_buffers: usize,
) -> (Vec<(gst::ClockTime, gst::ClockTime, gst::ClockTime)>, bool) { ) -> (
Vec<(
Option<gst::ClockTime>,
Option<gst::ClockTime>,
Option<gst::ClockTime>,
)>,
bool,
) {
let mut res = Vec::new(); let mut res = Vec::new();
let mut n_buffers = 0; let mut n_buffers = 0;
let mut saw_eos = false; let mut saw_eos = false;
@ -228,7 +240,7 @@ fn recv_buffers(
EventView::Gap(ref e) => { EventView::Gap(ref e) => {
let (ts, duration) = e.get(); let (ts, duration) = e.get();
res.push((segment.to_running_time(ts), ts, duration)); res.push((segment.to_running_time(ts), Some(ts), duration));
n_buffers += 1; n_buffers += 1;
if wait_buffers > 0 && n_buffers == wait_buffers { if wait_buffers > 0 && n_buffers == wait_buffers {
return (res, saw_eos); return (res, saw_eos);
@ -281,7 +293,7 @@ fn test_one_stream_open() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input, _, receiver_output, thread) = let (sender_input, _, receiver_output, thread) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -294,9 +306,9 @@ fn test_one_stream_open() {
assert_eq!(buffers.len(), 10); assert_eq!(buffers.len(), 10);
for (index, &(running_time, pts, duration)) in buffers.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
thread.join().unwrap(); thread.join().unwrap();
@ -313,7 +325,7 @@ fn test_one_stream_gaps_open() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input, _, receiver_output, thread) = let (sender_input, _, receiver_output, thread) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -327,9 +339,9 @@ fn test_one_stream_gaps_open() {
assert_eq!(buffers.len(), 10); assert_eq!(buffers.len(), 10);
for (index, &(running_time, pts, duration)) in buffers.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
thread.join().unwrap(); thread.join().unwrap();
@ -346,7 +358,7 @@ fn test_one_stream_close_open() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input, receiver_input_done, receiver_output, thread) = let (sender_input, receiver_input_done, receiver_output, thread) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -361,9 +373,9 @@ fn test_one_stream_close_open() {
assert_eq!(buffers.len(), 10); assert_eq!(buffers.len(), 10);
for (index, &(running_time, pts, duration)) in buffers.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, (10 + index) * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), (10 + index) * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
thread.join().unwrap(); thread.join().unwrap();
@ -380,7 +392,7 @@ fn test_one_stream_open_close() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input, receiver_input_done, receiver_output, thread) = let (sender_input, receiver_input_done, receiver_output, thread) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -396,9 +408,9 @@ fn test_one_stream_open_close() {
assert_eq!(buffers.len(), 10); assert_eq!(buffers.len(), 10);
for (index, &(running_time, pts, duration)) in buffers.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
thread.join().unwrap(); thread.join().unwrap();
@ -415,7 +427,7 @@ fn test_one_stream_open_close_open() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input, receiver_input_done, receiver_output, thread) = let (sender_input, receiver_input_done, receiver_output, thread) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -434,15 +446,15 @@ fn test_one_stream_open_close_open() {
assert_eq!(buffers.len(), 20); assert_eq!(buffers.len(), 20);
for (index, &(running_time, pts, duration)) in buffers.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers.iter().enumerate() {
let pts_off = if index >= 10 { let pts_off = if index >= 10 {
10 * 20 * gst::MSECOND 10 * 20 * gst::ClockTime::MSECOND
} else { } else {
0.into() gst::ClockTime::ZERO
}; };
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, pts_off + index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), pts_off + index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
thread.join().unwrap(); thread.join().unwrap();
@ -459,9 +471,9 @@ fn test_two_stream_open() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -480,9 +492,9 @@ fn test_two_stream_open() {
let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
@ -491,9 +503,9 @@ fn test_two_stream_open() {
let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 10); assert_eq!(buffers_2.len(), 10);
@ -512,9 +524,14 @@ fn test_two_stream_open_shift() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 5 * gst::MSECOND); setup_sender_receiver(
&pipeline,
&togglerecord,
"src_%u",
5 * gst::ClockTime::MSECOND,
);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -533,9 +550,9 @@ fn test_two_stream_open_shift() {
let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
@ -544,12 +561,18 @@ fn test_two_stream_open_shift() {
let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, 5 * gst::MSECOND + index * 20 * gst::MSECOND); assert_eq!(
assert_eq!(pts, 5 * gst::MSECOND + index * 20 * gst::MSECOND); running_time.unwrap(),
5 * gst::ClockTime::MSECOND + index * 20 * gst::ClockTime::MSECOND
);
assert_eq!(
pts.unwrap(),
5 * gst::ClockTime::MSECOND + index * 20 * gst::ClockTime::MSECOND
);
if index == 9 { if index == 9 {
assert_eq!(duration, 15 * gst::MSECOND); assert_eq!(duration.unwrap(), 15 * gst::ClockTime::MSECOND);
} else { } else {
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
} }
assert_eq!(buffers_2.len(), 10); assert_eq!(buffers_2.len(), 10);
@ -569,9 +592,9 @@ fn test_two_stream_open_shift_main() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 5 * gst::MSECOND); setup_sender_receiver(&pipeline, &togglerecord, "src", 5 * gst::ClockTime::MSECOND);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -591,9 +614,12 @@ fn test_two_stream_open_shift_main() {
let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, 5 * gst::MSECOND + index * 20 * gst::MSECOND); assert_eq!(
assert_eq!(duration, 20 * gst::MSECOND); pts.unwrap(),
5 * gst::ClockTime::MSECOND + index * 20 * gst::ClockTime::MSECOND
);
assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
@ -604,17 +630,26 @@ fn test_two_stream_open_shift_main() {
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
if index == 0 { if index == 0 {
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, 5 * gst::MSECOND + index * 20 * gst::MSECOND); assert_eq!(
assert_eq!(duration, 15 * gst::MSECOND); pts.unwrap(),
5 * gst::ClockTime::MSECOND + index * 20 * gst::ClockTime::MSECOND
);
assert_eq!(duration.unwrap(), 15 * gst::ClockTime::MSECOND);
} else if index == 10 { } else if index == 10 {
assert_eq!(running_time, index * 20 * gst::MSECOND - 5 * gst::MSECOND); assert_eq!(
assert_eq!(pts, index * 20 * gst::MSECOND); running_time.unwrap(),
assert_eq!(duration, 5 * gst::MSECOND); index * 20 * gst::ClockTime::MSECOND - 5 * gst::ClockTime::MSECOND
);
assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration.unwrap(), 5 * gst::ClockTime::MSECOND);
} else { } else {
assert_eq!(running_time, index * 20 * gst::MSECOND - 5 * gst::MSECOND); assert_eq!(
assert_eq!(pts, index * 20 * gst::MSECOND); running_time.unwrap(),
assert_eq!(duration, 20 * gst::MSECOND); index * 20 * gst::ClockTime::MSECOND - 5 * gst::ClockTime::MSECOND
);
assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
} }
assert_eq!(buffers_2.len(), 11); assert_eq!(buffers_2.len(), 11);
@ -634,9 +669,9 @@ fn test_two_stream_open_close() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -671,9 +706,9 @@ fn test_two_stream_open_close() {
let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
@ -682,9 +717,9 @@ fn test_two_stream_open_close() {
let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 10); assert_eq!(buffers_2.len(), 10);
@ -703,9 +738,9 @@ fn test_two_stream_close_open() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -740,9 +775,9 @@ fn test_two_stream_close_open() {
let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, (10 + index) * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), (10 + index) * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
@ -751,9 +786,9 @@ fn test_two_stream_close_open() {
let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, (10 + index) * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), (10 + index) * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 10); assert_eq!(buffers_2.len(), 10);
@ -772,9 +807,9 @@ fn test_two_stream_open_close_open() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -822,15 +857,15 @@ fn test_two_stream_open_close_open() {
let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let pts_off = if index >= 10 { let pts_off = if index >= 10 {
10 * 20 * gst::MSECOND 10 * 20 * gst::ClockTime::MSECOND
} else { } else {
0.into() gst::ClockTime::ZERO
}; };
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, pts_off + index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), pts_off + index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 20); assert_eq!(buffers_1.len(), 20);
@ -839,15 +874,15 @@ fn test_two_stream_open_close_open() {
let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let pts_off = if index >= 10 { let pts_off = if index >= 10 {
10 * 20 * gst::MSECOND 10 * 20 * gst::ClockTime::MSECOND
} else { } else {
0.into() gst::ClockTime::ZERO
}; };
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, pts_off + index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), pts_off + index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 20); assert_eq!(buffers_2.len(), 20);
@ -866,9 +901,9 @@ fn test_two_stream_open_close_open_gaps() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -922,15 +957,15 @@ fn test_two_stream_open_close_open_gaps() {
let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let pts_off = if index >= 10 { let pts_off = if index >= 10 {
10 * 20 * gst::MSECOND 10 * 20 * gst::ClockTime::MSECOND
} else { } else {
0.into() gst::ClockTime::ZERO
}; };
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, pts_off + index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), pts_off + index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 20); assert_eq!(buffers_1.len(), 20);
@ -939,15 +974,15 @@ fn test_two_stream_open_close_open_gaps() {
let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let pts_off = if index >= 10 { let pts_off = if index >= 10 {
10 * 20 * gst::MSECOND 10 * 20 * gst::ClockTime::MSECOND
} else { } else {
0.into() gst::ClockTime::ZERO
}; };
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, pts_off + index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), pts_off + index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 20); assert_eq!(buffers_2.len(), 20);
@ -966,9 +1001,9 @@ fn test_two_stream_close_open_close_delta() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -1023,9 +1058,9 @@ fn test_two_stream_close_open_close_delta() {
let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, (11 + index) * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), (11 + index) * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
@ -1034,9 +1069,9 @@ fn test_two_stream_close_open_close_delta() {
let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, (11 + index) * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), (11 + index) * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 10); assert_eq!(buffers_2.len(), 10);
@ -1055,11 +1090,11 @@ fn test_three_stream_open_close_open() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
let (sender_input_3, receiver_input_done_3, receiver_output_3, thread_3) = let (sender_input_3, receiver_input_done_3, receiver_output_3, thread_3) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -1118,15 +1153,15 @@ fn test_three_stream_open_close_open() {
let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, _) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let pts_off = if index >= 10 { let pts_off = if index >= 10 {
10 * 20 * gst::MSECOND 10 * 20 * gst::ClockTime::MSECOND
} else { } else {
0.into() gst::ClockTime::ZERO
}; };
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, pts_off + index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), pts_off + index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 20); assert_eq!(buffers_1.len(), 20);
@ -1135,15 +1170,15 @@ fn test_three_stream_open_close_open() {
let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, _) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let pts_off = if index >= 10 { let pts_off = if index >= 10 {
10 * 20 * gst::MSECOND 10 * 20 * gst::ClockTime::MSECOND
} else { } else {
0.into() gst::ClockTime::ZERO
}; };
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, pts_off + index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), pts_off + index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 20); assert_eq!(buffers_2.len(), 20);
@ -1151,15 +1186,15 @@ fn test_three_stream_open_close_open() {
let (buffers_3, _) = recv_buffers(&receiver_output_3, &mut segment_3, 0); let (buffers_3, _) = recv_buffers(&receiver_output_3, &mut segment_3, 0);
for (index, &(running_time, pts, duration)) in buffers_3.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_3.iter().enumerate() {
let pts_off = if index >= 10 { let pts_off = if index >= 10 {
10 * 20 * gst::MSECOND 10 * 20 * gst::ClockTime::MSECOND
} else { } else {
0.into() gst::ClockTime::ZERO
}; };
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, pts_off + index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), pts_off + index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_3.len(), 20); assert_eq!(buffers_3.len(), 20);
@ -1179,9 +1214,9 @@ fn test_two_stream_main_eos() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -1228,9 +1263,9 @@ fn test_two_stream_main_eos() {
let (buffers_1, saw_eos) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, saw_eos) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1240,9 +1275,9 @@ fn test_two_stream_main_eos() {
let (buffers_2, saw_eos) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, saw_eos) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 10); assert_eq!(buffers_2.len(), 10);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1262,9 +1297,9 @@ fn test_two_stream_secondary_eos_first() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -1303,9 +1338,9 @@ fn test_two_stream_secondary_eos_first() {
let (buffers_1, saw_eos) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, saw_eos) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1316,9 +1351,9 @@ fn test_two_stream_secondary_eos_first() {
let (buffers_2, saw_eos) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, saw_eos) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 9); assert_eq!(buffers_2.len(), 9);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1338,11 +1373,11 @@ fn test_three_stream_main_eos() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
let (sender_input_3, receiver_input_done_3, receiver_output_3, thread_3) = let (sender_input_3, receiver_input_done_3, receiver_output_3, thread_3) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -1405,9 +1440,9 @@ fn test_three_stream_main_eos() {
let (buffers_1, saw_eos) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, saw_eos) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1417,9 +1452,9 @@ fn test_three_stream_main_eos() {
let (buffers_2, saw_eos) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, saw_eos) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 10); assert_eq!(buffers_2.len(), 10);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1428,9 +1463,9 @@ fn test_three_stream_main_eos() {
let (buffers_3, saw_eos) = recv_buffers(&receiver_output_3, &mut segment_3, 0); let (buffers_3, saw_eos) = recv_buffers(&receiver_output_3, &mut segment_3, 0);
for (index, &(running_time, pts, duration)) in buffers_3.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_3.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_3.len(), 10); assert_eq!(buffers_3.len(), 10);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1451,11 +1486,11 @@ fn test_three_stream_main_and_second_eos() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
let (sender_input_3, receiver_input_done_3, receiver_output_3, thread_3) = let (sender_input_3, receiver_input_done_3, receiver_output_3, thread_3) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -1517,9 +1552,9 @@ fn test_three_stream_main_and_second_eos() {
let (buffers_1, saw_eos) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, saw_eos) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1529,9 +1564,9 @@ fn test_three_stream_main_and_second_eos() {
let (buffers_2, saw_eos) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, saw_eos) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 9); assert_eq!(buffers_2.len(), 9);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1541,9 +1576,9 @@ fn test_three_stream_main_and_second_eos() {
let (buffers_3, saw_eos) = recv_buffers(&receiver_output_3, &mut segment_3, 0); let (buffers_3, saw_eos) = recv_buffers(&receiver_output_3, &mut segment_3, 0);
for (index, &(running_time, pts, duration)) in buffers_3.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_3.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_3.len(), 10); assert_eq!(buffers_3.len(), 10);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1564,11 +1599,11 @@ fn test_three_stream_secondary_eos_first() {
pipeline.add(&togglerecord).unwrap(); pipeline.add(&togglerecord).unwrap();
let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) = let (sender_input_1, receiver_input_done_1, receiver_output_1, thread_1) =
setup_sender_receiver(&pipeline, &togglerecord, "src", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src", gst::ClockTime::ZERO);
let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) = let (sender_input_2, receiver_input_done_2, receiver_output_2, thread_2) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
let (sender_input_3, receiver_input_done_3, receiver_output_3, thread_3) = let (sender_input_3, receiver_input_done_3, receiver_output_3, thread_3) =
setup_sender_receiver(&pipeline, &togglerecord, "src_%u", 0.into()); setup_sender_receiver(&pipeline, &togglerecord, "src_%u", gst::ClockTime::ZERO);
pipeline.set_state(gst::State::Playing).unwrap(); pipeline.set_state(gst::State::Playing).unwrap();
@ -1612,9 +1647,9 @@ fn test_three_stream_secondary_eos_first() {
let (buffers_1, saw_eos) = recv_buffers(&receiver_output_1, &mut segment_1, 0); let (buffers_1, saw_eos) = recv_buffers(&receiver_output_1, &mut segment_1, 0);
for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_1.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_1.len(), 10); assert_eq!(buffers_1.len(), 10);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1624,9 +1659,9 @@ fn test_three_stream_secondary_eos_first() {
let (buffers_2, saw_eos) = recv_buffers(&receiver_output_2, &mut segment_2, 0); let (buffers_2, saw_eos) = recv_buffers(&receiver_output_2, &mut segment_2, 0);
for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_2.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_2.len(), 9); assert_eq!(buffers_2.len(), 9);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);
@ -1635,9 +1670,9 @@ fn test_three_stream_secondary_eos_first() {
let (buffers_3, saw_eos) = recv_buffers(&receiver_output_3, &mut segment_3, 0); let (buffers_3, saw_eos) = recv_buffers(&receiver_output_3, &mut segment_3, 0);
for (index, &(running_time, pts, duration)) in buffers_3.iter().enumerate() { for (index, &(running_time, pts, duration)) in buffers_3.iter().enumerate() {
let index = index as u64; let index = index as u64;
assert_eq!(running_time, index * 20 * gst::MSECOND); assert_eq!(running_time.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(pts, index * 20 * gst::MSECOND); assert_eq!(pts.unwrap(), index * 20 * gst::ClockTime::MSECOND);
assert_eq!(duration, 20 * gst::MSECOND); assert_eq!(duration.unwrap(), 20 * gst::ClockTime::MSECOND);
} }
assert_eq!(buffers_3.len(), 9); assert_eq!(buffers_3.len(), 9);
assert_eq!(saw_eos, true); assert_eq!(saw_eos, true);