2017-12-05 07:52:31 +00:00
|
|
|
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
|
|
|
|
//
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Library General Public
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
// version 2 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// Library General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Library General Public
|
|
|
|
// License along with this library; if not, write to the
|
|
|
|
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
|
|
|
|
// Boston, MA 02110-1335, USA.
|
|
|
|
|
2021-06-03 18:20:54 +00:00
|
|
|
use gst::glib;
|
2017-12-05 07:52:31 +00:00
|
|
|
use gst::prelude::*;
|
2018-11-18 13:18:17 +00:00
|
|
|
use gst::subclass::prelude::*;
|
2020-12-20 18:43:45 +00:00
|
|
|
use gst::{gst_debug, gst_log, gst_trace, gst_warning};
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2020-11-22 16:59:46 +00:00
|
|
|
use once_cell::sync::Lazy;
|
2018-11-01 10:45:57 +00:00
|
|
|
use parking_lot::{Condvar, Mutex};
|
2017-12-05 07:52:31 +00:00
|
|
|
use std::cmp;
|
2018-04-05 08:35:34 +00:00
|
|
|
use std::collections::HashMap;
|
2017-12-05 07:52:31 +00:00
|
|
|
use std::f64;
|
2018-04-05 08:35:34 +00:00
|
|
|
use std::iter;
|
2018-11-01 10:45:57 +00:00
|
|
|
use std::sync::Arc;
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
const DEFAULT_RECORD: bool = false;
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
struct Settings {
|
|
|
|
record: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Settings {
|
|
|
|
fn default() -> Self {
|
|
|
|
Settings {
|
|
|
|
record: DEFAULT_RECORD,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
struct Stream {
|
|
|
|
sinkpad: gst::Pad,
|
|
|
|
srcpad: gst::Pad,
|
|
|
|
state: Arc<Mutex<StreamState>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Stream {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.sinkpad == other.sinkpad && self.srcpad == other.srcpad
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Eq for Stream {}
|
|
|
|
|
|
|
|
impl Stream {
|
|
|
|
fn new(sinkpad: gst::Pad, srcpad: gst::Pad) -> Self {
|
|
|
|
Self {
|
2018-10-11 10:49:10 +00:00
|
|
|
sinkpad,
|
|
|
|
srcpad,
|
2017-12-05 07:52:31 +00:00
|
|
|
state: Arc::new(Mutex::new(StreamState::default())),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct StreamState {
|
2017-12-09 17:41:54 +00:00
|
|
|
in_segment: gst::FormattedSegment<gst::ClockTime>,
|
|
|
|
out_segment: gst::FormattedSegment<gst::ClockTime>,
|
2017-12-05 21:34:01 +00:00
|
|
|
segment_seqnum: gst::Seqnum,
|
2020-08-05 15:24:10 +00:00
|
|
|
// Start/end running time of the current/last buffer
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time: Option<gst::ClockTime>,
|
|
|
|
current_running_time_end: Option<gst::ClockTime>,
|
2017-12-05 07:52:31 +00:00
|
|
|
eos: bool,
|
|
|
|
flushing: bool,
|
|
|
|
segment_pending: bool,
|
2020-05-08 19:39:05 +00:00
|
|
|
discont_pending: bool,
|
2017-12-05 07:52:31 +00:00
|
|
|
pending_events: Vec<gst::Event>,
|
2019-07-10 16:30:04 +00:00
|
|
|
audio_info: Option<gst_audio::AudioInfo>,
|
|
|
|
video_info: Option<gst_video::VideoInfo>,
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for StreamState {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2017-12-09 17:41:54 +00:00
|
|
|
in_segment: gst::FormattedSegment::new(),
|
|
|
|
out_segment: gst::FormattedSegment::new(),
|
2020-01-24 23:20:37 +00:00
|
|
|
segment_seqnum: gst::Seqnum::next(),
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time: None,
|
|
|
|
current_running_time_end: None,
|
2017-12-05 07:52:31 +00:00
|
|
|
eos: false,
|
|
|
|
flushing: false,
|
|
|
|
segment_pending: false,
|
2020-05-08 19:39:05 +00:00
|
|
|
discont_pending: true,
|
2017-12-05 07:52:31 +00:00
|
|
|
pending_events: Vec::new(),
|
2019-07-10 16:30:04 +00:00
|
|
|
audio_info: None,
|
|
|
|
video_info: None,
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recording behaviour:
|
|
|
|
//
|
|
|
|
// Secondary streams are *always* behind main stream
|
|
|
|
// Main stream EOS stops recording (-> Stopping), makes secondary streams go EOS
|
|
|
|
//
|
|
|
|
// Recording: Passing through all data
|
|
|
|
// Stopping: Main stream remembering current last_recording_stop, waiting for all
|
|
|
|
// other streams to reach this position
|
|
|
|
// Stopped: Dropping all data
|
|
|
|
// Starting: Main stream waiting until next keyframe and setting last_recording_start, waiting
|
|
|
|
// for all other streams to reach this position
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
|
|
enum RecordingState {
|
|
|
|
Recording,
|
|
|
|
Stopping,
|
|
|
|
Stopped,
|
|
|
|
Starting,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct State {
|
|
|
|
recording_state: RecordingState,
|
2021-05-28 16:35:28 +00:00
|
|
|
last_recording_start: Option<gst::ClockTime>,
|
|
|
|
last_recording_stop: Option<gst::ClockTime>,
|
2017-12-05 07:52:31 +00:00
|
|
|
// Accumulated duration of previous recording segments,
|
|
|
|
// updated whenever going to Stopped
|
|
|
|
recording_duration: gst::ClockTime,
|
|
|
|
// Updated whenever going to Recording
|
2021-05-28 16:35:28 +00:00
|
|
|
running_time_offset: i64,
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for State {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
recording_state: RecordingState::Stopped,
|
2021-05-28 16:35:28 +00:00
|
|
|
last_recording_start: None,
|
|
|
|
last_recording_stop: None,
|
|
|
|
recording_duration: gst::ClockTime::ZERO,
|
|
|
|
running_time_offset: 0,
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
2019-07-10 16:30:04 +00:00
|
|
|
enum HandleResult<T> {
|
|
|
|
Pass(T),
|
2017-12-05 07:52:31 +00:00
|
|
|
Drop,
|
2021-01-06 18:59:44 +00:00
|
|
|
Eos(bool),
|
2017-12-05 07:52:31 +00:00
|
|
|
Flushing,
|
|
|
|
}
|
|
|
|
|
2019-07-10 16:30:04 +00:00
|
|
|
trait HandleData: Sized {
|
2021-05-28 16:35:28 +00:00
|
|
|
fn pts(&self) -> Option<gst::ClockTime>;
|
|
|
|
fn dts(&self) -> Option<gst::ClockTime>;
|
|
|
|
fn dts_or_pts(&self) -> Option<gst::ClockTime> {
|
2021-04-12 12:49:54 +00:00
|
|
|
let dts = self.dts();
|
2019-07-10 16:30:04 +00:00
|
|
|
if dts.is_some() {
|
|
|
|
dts
|
|
|
|
} else {
|
2021-04-12 12:49:54 +00:00
|
|
|
self.pts()
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-28 16:35:28 +00:00
|
|
|
fn duration(&self, state: &StreamState) -> Option<gst::ClockTime>;
|
2019-07-10 16:30:04 +00:00
|
|
|
fn is_keyframe(&self) -> bool;
|
2019-07-10 21:45:02 +00:00
|
|
|
fn can_clip(&self, state: &StreamState) -> bool;
|
|
|
|
fn clip(
|
|
|
|
self,
|
|
|
|
state: &StreamState,
|
|
|
|
segment: &gst::FormattedSegment<gst::ClockTime>,
|
|
|
|
) -> Option<Self>;
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
impl HandleData for (gst::ClockTime, Option<gst::ClockTime>) {
|
|
|
|
fn pts(&self) -> Option<gst::ClockTime> {
|
|
|
|
Some(self.0)
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
fn dts(&self) -> Option<gst::ClockTime> {
|
|
|
|
Some(self.0)
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
fn duration(&self, _state: &StreamState) -> Option<gst::ClockTime> {
|
2019-07-10 16:30:04 +00:00
|
|
|
self.1
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_keyframe(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
2019-07-10 21:45:02 +00:00
|
|
|
|
|
|
|
fn can_clip(&self, _state: &StreamState) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clip(
|
|
|
|
self,
|
|
|
|
_state: &StreamState,
|
|
|
|
segment: &gst::FormattedSegment<gst::ClockTime>,
|
|
|
|
) -> Option<Self> {
|
2021-05-28 16:35:28 +00:00
|
|
|
let stop = self.0 + self.1.unwrap_or(gst::ClockTime::ZERO);
|
2019-07-10 21:45:02 +00:00
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
segment.clip(self.0, stop).map(|(start, stop)| {
|
|
|
|
let start = start.expect("provided a defined value");
|
|
|
|
(start, stop.map(|stop| stop - start))
|
|
|
|
})
|
2019-07-10 21:45:02 +00:00
|
|
|
}
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl HandleData for gst::Buffer {
|
2021-05-28 16:35:28 +00:00
|
|
|
fn pts(&self) -> Option<gst::ClockTime> {
|
2021-04-12 16:12:05 +00:00
|
|
|
gst::BufferRef::pts(self)
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
fn dts(&self) -> Option<gst::ClockTime> {
|
2021-04-12 16:12:05 +00:00
|
|
|
gst::BufferRef::dts(self)
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
fn duration(&self, state: &StreamState) -> Option<gst::ClockTime> {
|
2021-04-12 16:12:05 +00:00
|
|
|
let duration = gst::BufferRef::duration(self);
|
2019-07-10 16:30:04 +00:00
|
|
|
|
|
|
|
if duration.is_some() {
|
|
|
|
duration
|
|
|
|
} else if let Some(ref video_info) = state.video_info {
|
|
|
|
if video_info.fps() != 0.into() {
|
2021-05-28 16:35:28 +00:00
|
|
|
gst::ClockTime::SECOND.mul_div_floor(
|
|
|
|
*video_info.fps().denom() as u64,
|
|
|
|
*video_info.fps().numer() as u64,
|
|
|
|
)
|
2019-07-10 16:30:04 +00:00
|
|
|
} else {
|
2021-05-28 16:35:28 +00:00
|
|
|
gst::ClockTime::NONE
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
} else if let Some(ref audio_info) = state.audio_info {
|
|
|
|
if audio_info.bpf() == 0 || audio_info.rate() == 0 {
|
2021-05-28 16:35:28 +00:00
|
|
|
return gst::ClockTime::NONE;
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
|
2021-04-12 12:49:54 +00:00
|
|
|
let size = self.size() as u64;
|
2019-07-10 16:30:04 +00:00
|
|
|
let num_samples = size / audio_info.bpf() as u64;
|
2021-05-28 16:35:28 +00:00
|
|
|
gst::ClockTime::SECOND.mul_div_floor(num_samples, audio_info.rate() as u64)
|
2019-07-10 16:30:04 +00:00
|
|
|
} else {
|
2021-05-28 16:35:28 +00:00
|
|
|
gst::ClockTime::NONE
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_keyframe(&self) -> bool {
|
2021-04-12 16:12:05 +00:00
|
|
|
!gst::BufferRef::flags(self).contains(gst::BufferFlags::DELTA_UNIT)
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
2019-07-10 21:45:02 +00:00
|
|
|
|
|
|
|
fn can_clip(&self, state: &StreamState) -> bool {
|
|
|
|
// Only do actual clipping for raw audio/video
|
|
|
|
if let Some(ref audio_info) = state.audio_info {
|
|
|
|
if audio_info.format() == gst_audio::AudioFormat::Unknown
|
|
|
|
|| audio_info.format() == gst_audio::AudioFormat::Encoded
|
|
|
|
|| audio_info.rate() == 0
|
|
|
|
|| audio_info.bpf() == 0
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if let Some(ref video_info) = state.video_info {
|
|
|
|
if video_info.format() == gst_video::VideoFormat::Unknown
|
|
|
|
|| video_info.format() == gst_video::VideoFormat::Encoded
|
2021-04-12 12:49:54 +00:00
|
|
|
|| self.dts_or_pts() != self.pts()
|
2019-07-10 21:45:02 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clip(
|
|
|
|
mut self,
|
|
|
|
state: &StreamState,
|
|
|
|
segment: &gst::FormattedSegment<gst::ClockTime>,
|
|
|
|
) -> Option<Self> {
|
|
|
|
// Only do actual clipping for raw audio/video
|
|
|
|
if !self.can_clip(state) {
|
|
|
|
return Some(self);
|
|
|
|
}
|
|
|
|
|
2021-04-12 16:12:05 +00:00
|
|
|
let pts = HandleData::pts(&self);
|
2021-04-20 12:58:11 +00:00
|
|
|
let duration = HandleData::duration(&self, state);
|
2021-05-28 16:35:28 +00:00
|
|
|
let stop = pts.map(|pts| pts + duration.unwrap_or(gst::ClockTime::ZERO));
|
2019-07-10 21:45:02 +00:00
|
|
|
|
|
|
|
if let Some(ref audio_info) = state.audio_info {
|
|
|
|
gst_audio::audio_buffer_clip(
|
|
|
|
self,
|
|
|
|
segment.upcast_ref(),
|
|
|
|
audio_info.rate(),
|
|
|
|
audio_info.bpf(),
|
|
|
|
)
|
2019-11-24 22:00:27 +00:00
|
|
|
} else if state.video_info.is_some() {
|
2019-07-10 21:45:02 +00:00
|
|
|
segment.clip(pts, stop).map(move |(start, stop)| {
|
|
|
|
{
|
|
|
|
let buffer = self.make_mut();
|
|
|
|
buffer.set_pts(start);
|
2021-05-28 16:35:28 +00:00
|
|
|
buffer.set_duration(
|
|
|
|
stop.zip(start)
|
|
|
|
.and_then(|(stop, start)| stop.checked_sub(start)),
|
|
|
|
// FIXME we could expect here
|
|
|
|
);
|
2019-07-10 21:45:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
}
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
|
2020-11-15 12:08:54 +00:00
|
|
|
pub struct ToggleRecord {
|
2017-12-05 07:52:31 +00:00
|
|
|
settings: Mutex<Settings>,
|
|
|
|
state: Mutex<State>,
|
|
|
|
main_stream: Stream,
|
|
|
|
// Always must have main_stream.state locked!
|
|
|
|
// If multiple stream states have to be locked, the
|
|
|
|
// main_stream always comes first
|
|
|
|
main_stream_cond: Condvar,
|
|
|
|
other_streams: Mutex<(Vec<Stream>, u32)>,
|
|
|
|
pads: Mutex<HashMap<gst::Pad, Stream>>,
|
|
|
|
}
|
|
|
|
|
2020-11-22 16:59:46 +00:00
|
|
|
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
|
|
|
|
gst::DebugCategory::new(
|
2019-10-31 22:34:21 +00:00
|
|
|
"togglerecord",
|
|
|
|
gst::DebugColorFlags::empty(),
|
|
|
|
Some("Toggle Record Element"),
|
2020-11-22 16:59:46 +00:00
|
|
|
)
|
|
|
|
});
|
2019-10-31 22:34:21 +00:00
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
impl ToggleRecord {
|
2019-07-10 16:30:04 +00:00
|
|
|
fn handle_main_stream<T: HandleData>(
|
2017-12-05 07:52:31 +00:00
|
|
|
&self,
|
2020-11-15 12:08:54 +00:00
|
|
|
element: &super::ToggleRecord,
|
2017-12-05 07:52:31 +00:00
|
|
|
pad: &gst::Pad,
|
|
|
|
stream: &Stream,
|
2019-07-10 16:30:04 +00:00
|
|
|
data: T,
|
|
|
|
) -> Result<HandleResult<T>, gst::FlowError> {
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
let mut dts_or_pts = data.dts_or_pts().ok_or_else(|| {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2019-07-10 16:30:04 +00:00
|
|
|
element,
|
|
|
|
gst::StreamError::Format,
|
|
|
|
["Buffer without DTS or PTS"]
|
|
|
|
);
|
2021-05-28 16:35:28 +00:00
|
|
|
gst::FlowError::Error
|
|
|
|
})?;
|
2019-07-10 16:30:04 +00:00
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
let mut dts_or_pts_end = dts_or_pts + data.duration(&state).unwrap_or(gst::ClockTime::ZERO);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2019-07-10 21:45:02 +00:00
|
|
|
let data = match data.clip(&state, &state.in_segment) {
|
2021-05-28 16:35:28 +00:00
|
|
|
Some(data) => data,
|
2019-07-10 21:45:02 +00:00
|
|
|
None => {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Dropping raw data outside segment");
|
2019-07-10 21:45:02 +00:00
|
|
|
return Ok(HandleResult::Drop);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// This will only do anything for non-raw data
|
2021-05-28 16:35:28 +00:00
|
|
|
// FIXME comment why we can unwrap
|
|
|
|
dts_or_pts = state.in_segment.start().unwrap().max(dts_or_pts);
|
|
|
|
dts_or_pts_end = state.in_segment.start().unwrap().max(dts_or_pts_end);
|
|
|
|
if let Some(stop) = state.in_segment.stop() {
|
|
|
|
dts_or_pts = stop.min(dts_or_pts);
|
|
|
|
dts_or_pts_end = stop.min(dts_or_pts_end);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 21:45:02 +00:00
|
|
|
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);
|
2020-10-19 15:03:10 +00:00
|
|
|
state.current_running_time = current_running_time
|
2021-05-28 16:35:28 +00:00
|
|
|
.zip(state.current_running_time)
|
|
|
|
.map(|(cur_rt, state_rt)| cur_rt.max(state_rt))
|
|
|
|
.or(current_running_time);
|
2020-10-19 15:03:10 +00:00
|
|
|
state.current_running_time_end = current_running_time_end
|
2021-05-28 16:35:28 +00:00
|
|
|
.zip(state.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
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
// Wake up everybody, we advanced a bit
|
|
|
|
// Important: They will only be able to advance once we're done with this
|
|
|
|
// function or waiting for them to catch up below, otherwise they might
|
|
|
|
// get the wrong state
|
|
|
|
self.main_stream_cond.notify_all();
|
|
|
|
|
|
|
|
gst_log!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
|
|
|
"Main stream current running time {}-{} (position: {}-{})",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time.display(),
|
|
|
|
current_running_time_end.display(),
|
2017-12-05 07:52:31 +00:00
|
|
|
dts_or_pts,
|
2021-05-28 16:35:28 +00:00
|
|
|
dts_or_pts_end,
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
|
|
|
|
2018-11-01 10:45:57 +00:00
|
|
|
let settings = *self.settings.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
// First check if we have to update our recording state
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut rec_state = self.state.lock();
|
2017-12-10 10:34:53 +00:00
|
|
|
let settings_changed = match rec_state.recording_state {
|
|
|
|
RecordingState::Recording if !settings.record => {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Stopping recording");
|
2017-12-05 07:52:31 +00:00
|
|
|
rec_state.recording_state = RecordingState::Stopping;
|
2017-12-10 10:34:53 +00:00
|
|
|
true
|
|
|
|
}
|
|
|
|
RecordingState::Stopped if settings.record => {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Starting recording");
|
2017-12-05 07:52:31 +00:00
|
|
|
rec_state.recording_state = RecordingState::Starting;
|
2017-12-10 10:34:53 +00:00
|
|
|
true
|
|
|
|
}
|
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
match rec_state.recording_state {
|
|
|
|
RecordingState::Recording => {
|
|
|
|
// Remember where we stopped last, in case of EOS
|
|
|
|
rec_state.last_recording_stop = current_running_time_end;
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Passing buffer (recording)");
|
2019-07-10 16:30:04 +00:00
|
|
|
Ok(HandleResult::Pass(data))
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
RecordingState::Stopping => {
|
2019-07-10 16:30:04 +00:00
|
|
|
if !data.is_keyframe() {
|
2017-12-05 07:52:31 +00:00
|
|
|
// Remember where we stopped last, in case of EOS
|
|
|
|
rec_state.last_recording_stop = current_running_time_end;
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Passing non-keyframe buffer (stopping)");
|
2017-12-10 11:18:43 +00:00
|
|
|
|
|
|
|
drop(rec_state);
|
|
|
|
drop(state);
|
|
|
|
if settings_changed {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Requesting a new keyframe");
|
2017-12-10 20:45:06 +00:00
|
|
|
stream
|
|
|
|
.sinkpad
|
2020-06-25 16:49:07 +00:00
|
|
|
.push_event(gst_video::UpstreamForceKeyUnitEvent::builder().build());
|
2017-12-10 11:18:43 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 16:30:04 +00:00
|
|
|
return Ok(HandleResult::Pass(data));
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 21:45:02 +00:00
|
|
|
// Remember the time when we stopped: now, i.e. right before the current buffer!
|
2017-12-05 07:52:31 +00:00
|
|
|
rec_state.last_recording_stop = current_running_time;
|
2021-05-28 16:35:28 +00:00
|
|
|
let last_recording_duration = rec_state
|
|
|
|
.last_recording_stop
|
|
|
|
.zip(rec_state.last_recording_start)
|
|
|
|
.and_then(|(stop, start)| stop.checked_sub(start));
|
2020-05-08 12:57:07 +00:00
|
|
|
gst_debug!(
|
|
|
|
CAT,
|
|
|
|
obj: pad,
|
|
|
|
"Stopping at {}, started at {}, current duration {}, previous accumulated recording duration {}",
|
2021-05-28 16:35:28 +00:00
|
|
|
rec_state.last_recording_stop.display(),
|
|
|
|
rec_state.last_recording_start.display(),
|
|
|
|
last_recording_duration.display(),
|
2020-05-08 12:57:07 +00:00
|
|
|
rec_state.recording_duration
|
|
|
|
);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2020-08-05 15:24:10 +00:00
|
|
|
// Then unlock and wait for all other streams to reach a buffer that is completely
|
|
|
|
// after/at the recording stop position (i.e. can be dropped completely) or go EOS
|
|
|
|
// instead.
|
2017-12-05 07:52:31 +00:00
|
|
|
drop(rec_state);
|
|
|
|
|
2020-12-31 10:05:37 +00:00
|
|
|
while !state.flushing
|
|
|
|
&& !self.other_streams.lock().0.iter().all(|s| {
|
|
|
|
let s = s.state.lock();
|
|
|
|
s.eos
|
2021-05-28 16:35:28 +00:00
|
|
|
|| s.current_running_time
|
|
|
|
.zip(current_running_time)
|
|
|
|
.map_or(false, |(s_cur_rt, cur_rt)| s_cur_rt >= cur_rt)
|
2020-12-31 10:05:37 +00:00
|
|
|
})
|
|
|
|
{
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Waiting for other streams to stop");
|
2018-11-01 10:45:57 +00:00
|
|
|
self.main_stream_cond.wait(&mut state);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if state.flushing {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Flushing");
|
2019-07-10 16:30:04 +00:00
|
|
|
return Ok(HandleResult::Flushing);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut rec_state = self.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
rec_state.recording_state = RecordingState::Stopped;
|
2021-05-28 16:35:28 +00:00
|
|
|
rec_state.recording_duration +=
|
|
|
|
last_recording_duration.unwrap_or(gst::ClockTime::ZERO);
|
|
|
|
rec_state.last_recording_start = None;
|
|
|
|
rec_state.last_recording_stop = None;
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
gst_debug!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
|
|
|
"Stopped at {}, recording duration {}",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time.display(),
|
|
|
|
rec_state.recording_duration.display(),
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
// Then become Stopped and drop this buffer. We always stop right before
|
|
|
|
// a keyframe
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Dropping buffer (stopped)");
|
2017-12-06 12:10:01 +00:00
|
|
|
|
|
|
|
drop(rec_state);
|
|
|
|
drop(state);
|
2018-07-11 13:12:10 +00:00
|
|
|
element.notify("recording");
|
2017-12-06 12:10:01 +00:00
|
|
|
|
2019-07-10 16:30:04 +00:00
|
|
|
Ok(HandleResult::Drop)
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
RecordingState::Stopped => {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Dropping buffer (stopped)");
|
2019-07-10 16:30:04 +00:00
|
|
|
Ok(HandleResult::Drop)
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
RecordingState::Starting => {
|
|
|
|
// If this is no keyframe, we can directly go out again here and drop the frame
|
2019-07-10 16:30:04 +00:00
|
|
|
if !data.is_keyframe() {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Dropping non-keyframe buffer (starting)");
|
2017-12-10 11:18:43 +00:00
|
|
|
|
|
|
|
drop(rec_state);
|
|
|
|
drop(state);
|
|
|
|
if settings_changed {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Requesting a new keyframe");
|
2017-12-10 20:45:06 +00:00
|
|
|
stream
|
|
|
|
.sinkpad
|
2020-06-25 16:49:07 +00:00
|
|
|
.push_event(gst_video::UpstreamForceKeyUnitEvent::builder().build());
|
2017-12-10 11:18:43 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 16:30:04 +00:00
|
|
|
return Ok(HandleResult::Drop);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remember the time when we started: now!
|
|
|
|
rec_state.last_recording_start = current_running_time;
|
2021-05-28 16:35:28 +00:00
|
|
|
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;
|
2020-05-08 12:57:07 +00:00
|
|
|
gst_debug!(
|
|
|
|
CAT,
|
|
|
|
obj: pad,
|
|
|
|
"Starting at {}, previous accumulated recording duration {}",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time.display(),
|
2020-05-08 12:57:07 +00:00
|
|
|
rec_state.recording_duration,
|
|
|
|
);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
state.segment_pending = true;
|
2020-05-08 19:39:05 +00:00
|
|
|
state.discont_pending = true;
|
2018-11-01 10:45:57 +00:00
|
|
|
for other_stream in &self.other_streams.lock().0 {
|
2020-05-08 19:39:05 +00:00
|
|
|
let mut other_state = other_stream.state.lock();
|
|
|
|
other_state.segment_pending = true;
|
|
|
|
other_state.discont_pending = true;
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
2020-08-05 15:24:10 +00:00
|
|
|
// Then unlock and wait for all other streams to reach a buffer that is completely
|
|
|
|
// after/at the recording start position (i.e. can be passed through completely) or
|
|
|
|
// go EOS instead.
|
2017-12-05 07:52:31 +00:00
|
|
|
drop(rec_state);
|
|
|
|
|
2020-12-31 10:05:37 +00:00
|
|
|
while !state.flushing
|
|
|
|
&& !self.other_streams.lock().0.iter().all(|s| {
|
|
|
|
let s = s.state.lock();
|
|
|
|
s.eos
|
2021-05-28 16:35:28 +00:00
|
|
|
|| s.current_running_time
|
|
|
|
.zip(current_running_time)
|
|
|
|
.map_or(false, |(s_cur_rt, cur_rt)| s_cur_rt >= cur_rt)
|
2020-12-31 10:05:37 +00:00
|
|
|
})
|
|
|
|
{
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Waiting for other streams to start");
|
2018-11-01 10:45:57 +00:00
|
|
|
self.main_stream_cond.wait(&mut state);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if state.flushing {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Flushing");
|
2019-07-10 16:30:04 +00:00
|
|
|
return Ok(HandleResult::Flushing);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut rec_state = self.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
rec_state.recording_state = RecordingState::Recording;
|
|
|
|
gst_debug!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
|
|
|
"Started at {}, recording duration {}",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time.display(),
|
2017-12-05 07:52:31 +00:00
|
|
|
rec_state.recording_duration
|
|
|
|
);
|
|
|
|
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Passing buffer (recording)");
|
2017-12-06 12:10:01 +00:00
|
|
|
|
|
|
|
drop(rec_state);
|
|
|
|
drop(state);
|
2018-07-11 13:12:10 +00:00
|
|
|
element.notify("recording");
|
2017-12-06 12:10:01 +00:00
|
|
|
|
2019-07-10 16:30:04 +00:00
|
|
|
Ok(HandleResult::Pass(data))
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-10 16:30:04 +00:00
|
|
|
fn handle_secondary_stream<T: HandleData>(
|
2017-12-05 07:52:31 +00:00
|
|
|
&self,
|
2020-11-15 12:08:54 +00:00
|
|
|
element: &super::ToggleRecord,
|
2017-12-05 07:52:31 +00:00
|
|
|
pad: &gst::Pad,
|
|
|
|
stream: &Stream,
|
2019-07-10 16:30:04 +00:00
|
|
|
data: T,
|
|
|
|
) -> Result<HandleResult<T>, gst::FlowError> {
|
2017-12-05 07:52:31 +00:00
|
|
|
// Calculate end pts & current running time and make sure we stay in the segment
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
let mut pts = data.pts().ok_or_else(|| {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(element, gst::StreamError::Format, ["Buffer without PTS"]);
|
2021-05-28 16:35:28 +00:00
|
|
|
gst::FlowError::Error
|
|
|
|
})?;
|
2019-07-10 16:30:04 +00:00
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
if data.dts().map_or(false, |dts| dts != pts) {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2019-07-10 16:30:04 +00:00
|
|
|
element,
|
|
|
|
gst::StreamError::Format,
|
|
|
|
["DTS != PTS not supported for secondary streams"]
|
|
|
|
);
|
|
|
|
return Err(gst::FlowError::Error);
|
|
|
|
}
|
|
|
|
|
|
|
|
if !data.is_keyframe() {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2019-07-10 16:30:04 +00:00
|
|
|
element,
|
|
|
|
gst::StreamError::Format,
|
|
|
|
["Delta-units not supported for secondary streams"]
|
|
|
|
);
|
|
|
|
return Err(gst::FlowError::Error);
|
|
|
|
}
|
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
let mut pts_end = pts + data.duration(&state).unwrap_or(gst::ClockTime::ZERO);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2019-07-10 21:45:02 +00:00
|
|
|
let data = match data.clip(&state, &state.in_segment) {
|
|
|
|
None => {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Dropping raw data outside segment");
|
2019-07-10 21:45:02 +00:00
|
|
|
return Ok(HandleResult::Drop);
|
|
|
|
}
|
|
|
|
Some(data) => data,
|
|
|
|
};
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2019-07-10 21:45:02 +00:00
|
|
|
// This will only do anything for non-raw data
|
2021-05-28 16:35:28 +00:00
|
|
|
// FIXME comment why we can unwrap
|
|
|
|
pts = state.in_segment.start().unwrap().max(pts);
|
|
|
|
pts_end = state.in_segment.start().unwrap().max(pts_end);
|
|
|
|
if let Some(stop) = state.in_segment.stop() {
|
|
|
|
pts = stop.min(pts);
|
|
|
|
pts_end = stop.min(pts_end);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 21:45:02 +00:00
|
|
|
let current_running_time = state.in_segment.to_running_time(pts);
|
2017-12-09 17:41:54 +00:00
|
|
|
let current_running_time_end = state.in_segment.to_running_time(pts_end);
|
2020-10-19 15:03:10 +00:00
|
|
|
state.current_running_time = current_running_time
|
2021-05-28 16:35:28 +00:00
|
|
|
.zip(state.current_running_time)
|
|
|
|
.map(|(cur_rt, state_rt)| cur_rt.max(state_rt))
|
|
|
|
.or(current_running_time);
|
2020-10-19 15:03:10 +00:00
|
|
|
state.current_running_time_end = current_running_time_end
|
2021-05-28 16:35:28 +00:00
|
|
|
.zip(state.current_running_time_end)
|
|
|
|
.map(|(cur_rt_end, state_rt_end)| cur_rt_end.max(state_rt_end))
|
|
|
|
.or(current_running_time_end);
|
2019-07-10 21:45:02 +00:00
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
gst_log!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
|
|
|
"Secondary stream current running time {}-{} (position: {}-{}",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time.display(),
|
|
|
|
current_running_time_end.display(),
|
2017-12-05 07:52:31 +00:00
|
|
|
pts,
|
|
|
|
pts_end
|
|
|
|
);
|
|
|
|
|
|
|
|
drop(state);
|
|
|
|
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut main_state = self.main_stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
// Wake up, in case the main stream is waiting for us to progress up to here. We progressed
|
|
|
|
// above but all notifying must happen while the main_stream state is locked as per above.
|
|
|
|
self.main_stream_cond.notify_all();
|
|
|
|
|
2020-08-05 15:24:10 +00:00
|
|
|
let mut rec_state = self.state.lock();
|
|
|
|
|
|
|
|
// Wait until the main stream advanced completely past our current running time in
|
|
|
|
// Recording/Stopped modes to make sure we're not already outputting/dropping data that
|
|
|
|
// should actually be dropped/output if recording is started/stopped now.
|
|
|
|
//
|
|
|
|
// In Starting/Stopping mode we wait if we the start of this buffer is after last recording
|
|
|
|
// start/stop as in that case we should be in Recording/Stopped mode already. The main
|
|
|
|
// stream is waiting for us to reach that position to switch to Recording/Stopped mode so
|
|
|
|
// that in those modes we only have to pass through/drop the whole buffers.
|
2020-10-19 15:03:10 +00:00
|
|
|
while (main_state.current_running_time.is_none()
|
2020-08-05 15:24:10 +00:00
|
|
|
|| rec_state.recording_state != RecordingState::Starting
|
|
|
|
&& rec_state.recording_state != RecordingState::Stopping
|
2021-05-28 16:35:28 +00:00
|
|
|
&& 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)
|
2020-08-05 15:24:10 +00:00
|
|
|
|| rec_state.recording_state == RecordingState::Starting
|
2021-05-28 16:35:28 +00:00
|
|
|
&& rec_state
|
|
|
|
.last_recording_start
|
|
|
|
.map_or(true, |last_rec_start| {
|
|
|
|
current_running_time.map_or(false, |cur_rt| last_rec_start <= cur_rt)
|
|
|
|
})
|
2020-08-05 15:24:10 +00:00
|
|
|
|| rec_state.recording_state == RecordingState::Stopping
|
2021-05-28 16:35:28 +00:00
|
|
|
&& rec_state.last_recording_stop.map_or(true, |last_rec_stop| {
|
|
|
|
current_running_time.map_or(false, |cur_rt| last_rec_stop <= cur_rt)
|
|
|
|
}))
|
2018-10-11 10:49:48 +00:00
|
|
|
&& !main_state.eos
|
2018-11-01 10:45:57 +00:00
|
|
|
&& !stream.state.lock().flushing
|
2017-12-05 07:52:31 +00:00
|
|
|
{
|
|
|
|
gst_log!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
2020-08-05 15:24:10 +00:00
|
|
|
"Waiting at {}-{} in {:?} state, main stream at {}-{}",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time.display(),
|
|
|
|
current_running_time_end.display(),
|
2020-08-05 15:24:10 +00:00
|
|
|
rec_state.recording_state,
|
2021-05-28 16:35:28 +00:00
|
|
|
main_state.current_running_time.display(),
|
|
|
|
main_state.current_running_time_end.display(),
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
|
|
|
|
2020-08-05 15:24:10 +00:00
|
|
|
drop(rec_state);
|
2018-11-01 10:45:57 +00:00
|
|
|
self.main_stream_cond.wait(&mut main_state);
|
2020-08-05 15:24:10 +00:00
|
|
|
rec_state = self.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
2019-07-10 21:45:02 +00:00
|
|
|
|
|
|
|
state = stream.state.lock();
|
|
|
|
|
|
|
|
if state.flushing {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Flushing");
|
2019-07-10 16:30:04 +00:00
|
|
|
return Ok(HandleResult::Flushing);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the main stream is EOS, we are also EOS unless we are
|
|
|
|
// before the final last recording stop running time
|
|
|
|
if main_state.eos {
|
2019-07-10 21:45:02 +00:00
|
|
|
// If we have no start or stop position (we never recorded) then we're EOS too now
|
|
|
|
if rec_state.last_recording_stop.is_none() || rec_state.last_recording_start.is_none() {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Main stream EOS and recording never started",);
|
2021-01-06 18:59:44 +00:00
|
|
|
return Ok(HandleResult::Eos(self.check_and_update_eos(
|
|
|
|
pad,
|
|
|
|
stream,
|
|
|
|
&mut state,
|
|
|
|
&mut rec_state,
|
|
|
|
)));
|
2021-05-28 16:35:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2019-07-10 21:45:02 +00:00
|
|
|
{
|
|
|
|
// 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.
|
|
|
|
gst_debug!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2019-07-10 21:45:02 +00:00
|
|
|
obj: pad,
|
|
|
|
"Main stream EOS and we're not EOS yet (overlapping recording start, {} < {} < {})",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time.display(),
|
|
|
|
last_recording_start,
|
|
|
|
current_running_time_end.display(),
|
2019-07-10 21:45:02 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
let mut clip_start = state
|
|
|
|
.in_segment
|
|
|
|
.position_from_running_time(rec_state.last_recording_start);
|
|
|
|
if clip_start.is_none() {
|
2021-04-12 12:49:54 +00:00
|
|
|
clip_start = state.in_segment.start();
|
2019-07-10 21:45:02 +00:00
|
|
|
}
|
|
|
|
let mut clip_stop = state
|
|
|
|
.in_segment
|
|
|
|
.position_from_running_time(rec_state.last_recording_stop);
|
|
|
|
if clip_stop.is_none() {
|
2021-04-12 12:49:54 +00:00
|
|
|
clip_stop = state.in_segment.stop();
|
2019-07-10 21:45:02 +00:00
|
|
|
}
|
|
|
|
let mut segment = state.in_segment.clone();
|
|
|
|
segment.set_start(clip_start);
|
|
|
|
segment.set_stop(clip_stop);
|
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Clipping to segment {:?}", segment);
|
2019-07-10 21:45:02 +00:00
|
|
|
|
|
|
|
if let Some(data) = data.clip(&*state, &segment) {
|
|
|
|
return Ok(HandleResult::Pass(data));
|
|
|
|
} else {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_warning!(CAT, obj: pad, "Complete buffer clipped!");
|
2019-07-10 21:45:02 +00:00
|
|
|
return Ok(HandleResult::Drop);
|
|
|
|
}
|
2021-05-28 16:35:28 +00:00
|
|
|
} else if current_running_time.map_or(false, |cur_rt| cur_rt < last_recording_start) {
|
2019-07-10 21:45:02 +00:00
|
|
|
// 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
|
|
|
|
// recording start
|
2017-12-05 07:52:31 +00:00
|
|
|
gst_debug!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
2019-07-10 21:45:02 +00:00
|
|
|
"Main stream EOS and we're not EOS yet (before recording start, {} < {})",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time.display(),
|
|
|
|
last_recording_start,
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
2019-07-10 16:30:04 +00:00
|
|
|
return Ok(HandleResult::Drop);
|
2019-07-10 21:45:02 +00:00
|
|
|
} else if data.can_clip(&*state)
|
2021-05-28 16:35:28 +00:00
|
|
|
&& current_running_time
|
|
|
|
.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
|
|
|
|
})
|
2019-07-10 21:45:02 +00:00
|
|
|
{
|
|
|
|
// 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.
|
|
|
|
gst_debug!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2019-07-10 21:45:02 +00:00
|
|
|
obj: pad,
|
|
|
|
"Main stream EOS and we're not EOS yet (overlapping recording end, {} < {} < {})",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time.display(),
|
|
|
|
rec_state.last_recording_stop.display(),
|
|
|
|
current_running_time_end.display(),
|
2019-07-10 21:45:02 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
let mut clip_start = state
|
|
|
|
.in_segment
|
|
|
|
.position_from_running_time(rec_state.last_recording_start);
|
|
|
|
if clip_start.is_none() {
|
2021-04-12 12:49:54 +00:00
|
|
|
clip_start = state.in_segment.start();
|
2019-07-10 21:45:02 +00:00
|
|
|
}
|
|
|
|
let mut clip_stop = state
|
|
|
|
.in_segment
|
|
|
|
.position_from_running_time(rec_state.last_recording_stop);
|
|
|
|
if clip_stop.is_none() {
|
2021-04-12 12:49:54 +00:00
|
|
|
clip_stop = state.in_segment.stop();
|
2019-07-10 21:45:02 +00:00
|
|
|
}
|
|
|
|
let mut segment = state.in_segment.clone();
|
|
|
|
segment.set_start(clip_start);
|
|
|
|
segment.set_stop(clip_stop);
|
|
|
|
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Clipping to segment {:?}", segment,);
|
2019-07-10 21:45:02 +00:00
|
|
|
|
|
|
|
if let Some(data) = data.clip(&*state, &segment) {
|
|
|
|
return Ok(HandleResult::Pass(data));
|
|
|
|
} else {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_warning!(CAT, obj: pad, "Complete buffer clipped!");
|
2021-01-06 18:59:44 +00:00
|
|
|
return Ok(HandleResult::Eos(self.check_and_update_eos(
|
|
|
|
pad,
|
|
|
|
stream,
|
|
|
|
&mut state,
|
|
|
|
&mut rec_state,
|
|
|
|
)));
|
2019-07-10 21:45:02 +00:00
|
|
|
}
|
2021-05-28 16:35:28 +00:00
|
|
|
} 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
|
|
|
|
})
|
|
|
|
{
|
2019-07-10 21:45:02 +00:00
|
|
|
// 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
|
|
|
|
// the recording stop
|
|
|
|
gst_debug!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2019-07-10 21:45:02 +00:00
|
|
|
obj: pad,
|
|
|
|
"Main stream EOS and we're EOS too (after recording end, {} > {})",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time_end.display(),
|
|
|
|
rec_state.last_recording_stop.display(),
|
2019-07-10 21:45:02 +00:00
|
|
|
);
|
2021-01-06 18:59:44 +00:00
|
|
|
return Ok(HandleResult::Eos(self.check_and_update_eos(
|
|
|
|
pad,
|
|
|
|
stream,
|
|
|
|
&mut state,
|
|
|
|
&mut rec_state,
|
|
|
|
)));
|
2017-12-05 07:52:31 +00:00
|
|
|
} else {
|
2019-07-10 21:45:02 +00:00
|
|
|
// In all other cases the buffer is fully between recording start and end and
|
|
|
|
// can be passed through as is
|
2021-05-28 16:35:28 +00:00
|
|
|
assert!(current_running_time.map_or(false, |cur_rt| cur_rt >= last_recording_start));
|
|
|
|
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));
|
2019-07-10 21:45:02 +00:00
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
gst_debug!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
2019-07-10 21:45:02 +00:00
|
|
|
"Main stream EOS and we're not EOS yet (before recording end, {} <= {} <= {})",
|
2021-05-28 16:35:28 +00:00
|
|
|
last_recording_start,
|
|
|
|
current_running_time.display(),
|
|
|
|
rec_state.last_recording_stop.display(),
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
2019-07-10 16:30:04 +00:00
|
|
|
return Ok(HandleResult::Pass(data));
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match rec_state.recording_state {
|
|
|
|
RecordingState::Recording => {
|
2020-08-05 15:24:10 +00:00
|
|
|
// The end of our buffer must be before/at the end of the previous buffer of the main
|
|
|
|
// stream
|
2021-05-28 16:35:28 +00:00
|
|
|
assert!(current_running_time_end
|
|
|
|
.zip(main_state.current_running_time_end)
|
|
|
|
.map_or(false, |(cur_rt_end, main_cur_rt_end)| cur_rt_end
|
|
|
|
<= main_cur_rt_end));
|
2020-08-05 15:24:10 +00:00
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
// We're properly started, must have a start position and
|
|
|
|
// be actually after that start position
|
2021-05-28 16:35:28 +00:00
|
|
|
assert!(current_running_time
|
|
|
|
.zip(rec_state.last_recording_start)
|
|
|
|
.map_or(false, |(cur_rt, last_rec_start)| cur_rt >= last_rec_start));
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Passing buffer (recording)");
|
2019-07-10 16:30:04 +00:00
|
|
|
Ok(HandleResult::Pass(data))
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
RecordingState::Stopping => {
|
2021-05-28 16:35:28 +00:00
|
|
|
// 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));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-08-05 15:24:10 +00:00
|
|
|
// The start of our buffer must be before the last recording stop as
|
|
|
|
// otherwise we would be in Stopped state already
|
2021-05-28 16:35:28 +00:00
|
|
|
assert!(current_running_time.map_or(false, |cur_rt| cur_rt < last_recording_stop));
|
|
|
|
let current_running_time = current_running_time.expect("checked above");
|
2020-08-05 15:24:10 +00:00
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
if current_running_time_end
|
|
|
|
.map_or(false, |cur_rt_end| cur_rt_end <= last_recording_stop)
|
|
|
|
{
|
2017-12-05 07:52:31 +00:00
|
|
|
gst_log!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
|
|
|
"Passing buffer (stopping: {} <= {})",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time_end.display(),
|
|
|
|
last_recording_stop,
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
2019-07-10 16:30:04 +00:00
|
|
|
Ok(HandleResult::Pass(data))
|
2019-07-10 21:45:02 +00:00
|
|
|
} else if data.can_clip(&*state)
|
2021-05-28 16:35:28 +00:00
|
|
|
&& current_running_time < last_recording_stop
|
|
|
|
&& current_running_time_end
|
|
|
|
.map_or(false, |cur_rt_end| cur_rt_end > last_recording_stop)
|
2019-07-10 21:45:02 +00:00
|
|
|
{
|
|
|
|
gst_log!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2019-07-10 21:45:02 +00:00
|
|
|
obj: pad,
|
|
|
|
"Passing buffer (stopping: {} < {} < {})",
|
|
|
|
current_running_time,
|
2021-05-28 16:35:28 +00:00
|
|
|
last_recording_stop,
|
|
|
|
current_running_time_end.display(),
|
2019-07-10 21:45:02 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
let mut clip_stop = state
|
|
|
|
.in_segment
|
|
|
|
.position_from_running_time(rec_state.last_recording_stop);
|
|
|
|
if clip_stop.is_none() {
|
2021-04-12 12:49:54 +00:00
|
|
|
clip_stop = state.in_segment.stop();
|
2019-07-10 21:45:02 +00:00
|
|
|
}
|
|
|
|
let mut segment = state.in_segment.clone();
|
|
|
|
segment.set_stop(clip_stop);
|
|
|
|
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Clipping to segment {:?}", segment,);
|
2019-07-10 21:45:02 +00:00
|
|
|
|
|
|
|
if let Some(data) = data.clip(&*state, &segment) {
|
|
|
|
Ok(HandleResult::Pass(data))
|
|
|
|
} else {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_warning!(CAT, obj: pad, "Complete buffer clipped!");
|
2019-07-10 21:45:02 +00:00
|
|
|
Ok(HandleResult::Drop)
|
|
|
|
}
|
2017-12-05 07:52:31 +00:00
|
|
|
} else {
|
|
|
|
gst_log!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
|
|
|
"Dropping buffer (stopping: {} > {})",
|
2021-05-28 16:35:28 +00:00
|
|
|
current_running_time_end.display(),
|
|
|
|
rec_state.last_recording_stop.display(),
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
2019-07-10 16:30:04 +00:00
|
|
|
Ok(HandleResult::Drop)
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
RecordingState::Stopped => {
|
2020-08-05 15:24:10 +00:00
|
|
|
// The end of our buffer must be before/at the end of the previous buffer of the main
|
|
|
|
// stream
|
2021-05-28 16:35:28 +00:00
|
|
|
assert!(current_running_time_end
|
|
|
|
.zip(main_state.current_running_time_end)
|
|
|
|
.map_or(false, |(cur_rt_end, state_rt_end)| cur_rt_end
|
|
|
|
<= state_rt_end));
|
2020-08-05 15:24:10 +00:00
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
// We're properly stopped
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Dropping buffer (stopped)");
|
2019-07-10 16:30:04 +00:00
|
|
|
Ok(HandleResult::Drop)
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
RecordingState::Starting => {
|
|
|
|
// If we have no start position yet, the main stream is waiting for a key-frame
|
2021-05-28 16:35:28 +00:00
|
|
|
let last_recording_start = match rec_state.last_recording_start {
|
|
|
|
Some(last_recording_start) => last_recording_start,
|
|
|
|
None => {
|
|
|
|
gst_log!(
|
|
|
|
CAT,
|
|
|
|
obj: pad,
|
|
|
|
"Dropping buffer (starting: waiting for keyframe)",
|
|
|
|
);
|
|
|
|
return Ok(HandleResult::Drop);
|
|
|
|
}
|
|
|
|
};
|
2020-10-19 15:03:10 +00:00
|
|
|
|
|
|
|
// The start of our buffer must be before the last recording start as
|
|
|
|
// otherwise we would be in Recording state already
|
2021-05-28 16:35:28 +00:00
|
|
|
assert!(current_running_time.map_or(false, |cur_rt| cur_rt < last_recording_start));
|
|
|
|
let current_running_time = current_running_time.expect("checked_above");
|
|
|
|
|
|
|
|
if current_running_time >= last_recording_start {
|
2017-12-05 07:52:31 +00:00
|
|
|
gst_log!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
|
|
|
"Passing buffer (starting: {} >= {})",
|
|
|
|
current_running_time,
|
2021-05-28 16:35:28 +00:00
|
|
|
last_recording_start,
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
2019-07-10 16:30:04 +00:00
|
|
|
Ok(HandleResult::Pass(data))
|
2019-07-10 21:45:02 +00:00
|
|
|
} else if data.can_clip(&*state)
|
2021-05-28 16:35:28 +00:00
|
|
|
&& current_running_time < last_recording_start
|
|
|
|
&& current_running_time_end
|
|
|
|
.map_or(false, |cur_rt_end| cur_rt_end > last_recording_start)
|
2019-07-10 21:45:02 +00:00
|
|
|
{
|
|
|
|
gst_log!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2019-07-10 21:45:02 +00:00
|
|
|
obj: pad,
|
|
|
|
"Passing buffer (starting: {} < {} < {})",
|
|
|
|
current_running_time,
|
2021-05-28 16:35:28 +00:00
|
|
|
last_recording_start,
|
|
|
|
current_running_time_end.display(),
|
2019-07-10 21:45:02 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
let mut clip_start = state
|
|
|
|
.in_segment
|
|
|
|
.position_from_running_time(rec_state.last_recording_start);
|
|
|
|
if clip_start.is_none() {
|
2021-04-12 12:49:54 +00:00
|
|
|
clip_start = state.in_segment.start();
|
2019-07-10 21:45:02 +00:00
|
|
|
}
|
|
|
|
let mut segment = state.in_segment.clone();
|
|
|
|
segment.set_start(clip_start);
|
|
|
|
|
2021-05-28 16:35:28 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Clipping to segment {:?}", segment);
|
2019-07-10 21:45:02 +00:00
|
|
|
|
|
|
|
if let Some(data) = data.clip(&*state, &segment) {
|
|
|
|
Ok(HandleResult::Pass(data))
|
|
|
|
} else {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_warning!(CAT, obj: pad, "Complete buffer clipped!");
|
2019-07-10 21:45:02 +00:00
|
|
|
Ok(HandleResult::Drop)
|
|
|
|
}
|
2017-12-05 07:52:31 +00:00
|
|
|
} else {
|
|
|
|
gst_log!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
|
|
|
"Dropping buffer (starting: {} < {})",
|
|
|
|
current_running_time,
|
2021-05-28 16:35:28 +00:00
|
|
|
last_recording_start,
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
2019-07-10 16:30:04 +00:00
|
|
|
Ok(HandleResult::Drop)
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-06 18:59:44 +00:00
|
|
|
// should be called only if main stream is in eos state
|
|
|
|
fn check_and_update_eos(
|
|
|
|
&self,
|
|
|
|
pad: &gst::Pad,
|
|
|
|
stream: &Stream,
|
|
|
|
stream_state: &mut StreamState,
|
|
|
|
rec_state: &mut State,
|
|
|
|
) -> bool {
|
|
|
|
stream_state.eos = true;
|
|
|
|
|
|
|
|
// Check whether all secondary streams are in eos. If so, update recording
|
|
|
|
// state to Stopped
|
|
|
|
if rec_state.recording_state != RecordingState::Stopped {
|
|
|
|
let mut others_eos = true;
|
|
|
|
|
|
|
|
// Check eos state of all secondary streams
|
|
|
|
self.other_streams.lock().0.iter().all(|s| {
|
|
|
|
if s == stream {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
let s = s.state.lock();
|
|
|
|
if !s.eos {
|
|
|
|
others_eos = false;
|
|
|
|
}
|
|
|
|
others_eos
|
|
|
|
});
|
|
|
|
|
|
|
|
if others_eos {
|
|
|
|
gst_debug!(
|
|
|
|
CAT,
|
|
|
|
obj: pad,
|
|
|
|
"All streams are in EOS state, change state to Stopped"
|
|
|
|
);
|
|
|
|
|
|
|
|
rec_state.recording_state = RecordingState::Stopped;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
fn sink_chain(
|
|
|
|
&self,
|
|
|
|
pad: &gst::Pad,
|
2020-11-15 12:08:54 +00:00
|
|
|
element: &super::ToggleRecord,
|
2017-12-05 07:52:31 +00:00
|
|
|
buffer: gst::Buffer,
|
2019-01-11 23:45:05 +00:00
|
|
|
) -> Result<gst::FlowSuccess, gst::FlowError> {
|
2019-07-10 21:45:02 +00:00
|
|
|
let stream = self.pads.lock().get(pad).cloned().ok_or_else(|| {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2019-07-10 21:45:02 +00:00
|
|
|
element,
|
|
|
|
gst::CoreError::Pad,
|
2021-04-12 12:49:54 +00:00
|
|
|
["Unknown pad {:?}", pad.name()]
|
2019-07-10 21:45:02 +00:00
|
|
|
);
|
|
|
|
gst::FlowError::Error
|
|
|
|
})?;
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Handling buffer {:?}", buffer);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
{
|
2018-11-01 10:45:57 +00:00
|
|
|
let state = stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
if state.eos {
|
2019-01-11 23:45:05 +00:00
|
|
|
return Err(gst::FlowError::Eos);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
2020-12-31 10:06:18 +00:00
|
|
|
if state.flushing {
|
|
|
|
return Err(gst::FlowError::Flushing);
|
|
|
|
}
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let handle_result = if stream != self.main_stream {
|
2019-07-10 16:30:04 +00:00
|
|
|
self.handle_secondary_stream(element, pad, &stream, buffer)
|
2017-12-05 07:52:31 +00:00
|
|
|
} else {
|
2019-07-10 16:30:04 +00:00
|
|
|
self.handle_main_stream(element, pad, &stream, buffer)
|
|
|
|
}?;
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2020-05-08 19:39:05 +00:00
|
|
|
let mut buffer = match handle_result {
|
2017-12-05 07:52:31 +00:00
|
|
|
HandleResult::Drop => {
|
2019-01-11 23:45:05 +00:00
|
|
|
return Ok(gst::FlowSuccess::Ok);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
HandleResult::Flushing => {
|
2019-01-11 23:45:05 +00:00
|
|
|
return Err(gst::FlowError::Flushing);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
2021-01-06 18:59:44 +00:00
|
|
|
HandleResult::Eos(recording_state_updated) => {
|
2017-12-05 07:52:31 +00:00
|
|
|
stream.srcpad.push_event(
|
2020-06-24 22:33:57 +00:00
|
|
|
gst::event::Eos::builder()
|
2018-11-01 10:45:57 +00:00
|
|
|
.seqnum(stream.state.lock().segment_seqnum)
|
2017-12-05 07:52:31 +00:00
|
|
|
.build(),
|
|
|
|
);
|
2021-01-06 18:59:44 +00:00
|
|
|
|
|
|
|
if recording_state_updated {
|
|
|
|
element.notify("recording");
|
|
|
|
}
|
|
|
|
|
2019-01-11 23:45:05 +00:00
|
|
|
return Err(gst::FlowError::Eos);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
2019-07-10 16:30:04 +00:00
|
|
|
HandleResult::Pass(buffer) => {
|
2017-12-05 07:52:31 +00:00
|
|
|
// Pass through and actually push the buffer
|
2019-07-10 16:30:04 +00:00
|
|
|
buffer
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
2019-07-10 16:30:04 +00:00
|
|
|
};
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
let out_running_time = {
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = stream.state.lock();
|
2020-05-08 19:39:05 +00:00
|
|
|
|
|
|
|
if state.discont_pending {
|
|
|
|
gst_debug!(CAT, obj: pad, "Pending discont");
|
|
|
|
let buffer = buffer.make_mut();
|
|
|
|
buffer.set_flags(gst::BufferFlags::DISCONT);
|
|
|
|
state.discont_pending = false;
|
|
|
|
}
|
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
let mut events = Vec::with_capacity(state.pending_events.len() + 1);
|
|
|
|
|
|
|
|
if state.segment_pending {
|
2018-11-01 10:45:57 +00:00
|
|
|
let rec_state = self.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
// Adjust so that last_recording_start has running time of
|
|
|
|
// recording_duration
|
|
|
|
|
|
|
|
state.out_segment = state.in_segment.clone();
|
2019-01-17 18:30:46 +00:00
|
|
|
state
|
|
|
|
.out_segment
|
2021-05-28 16:35:28 +00:00
|
|
|
.offset_running_time(-rec_state.running_time_offset)
|
2019-01-17 18:30:46 +00:00
|
|
|
.expect("Adjusting record duration");
|
2017-12-05 07:52:31 +00:00
|
|
|
events.push(
|
2020-06-24 22:33:57 +00:00
|
|
|
gst::event::Segment::builder(&state.out_segment)
|
2017-12-05 07:52:31 +00:00
|
|
|
.seqnum(state.segment_seqnum)
|
|
|
|
.build(),
|
|
|
|
);
|
|
|
|
state.segment_pending = false;
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Pending Segment {:?}", &state.out_segment);
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if !state.pending_events.is_empty() {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Pushing pending events");
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
events.append(&mut state.pending_events);
|
|
|
|
|
2021-04-12 12:49:54 +00:00
|
|
|
let out_running_time = state.out_segment.to_running_time(buffer.pts());
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
// Unlock before pushing
|
|
|
|
drop(state);
|
|
|
|
|
|
|
|
for e in events.drain(..) {
|
|
|
|
stream.srcpad.push_event(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
out_running_time
|
|
|
|
};
|
|
|
|
|
|
|
|
gst_log!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
|
|
|
"Pushing buffer with running time {}: {:?}",
|
2021-05-28 16:35:28 +00:00
|
|
|
out_running_time.display(),
|
|
|
|
buffer,
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
|
|
|
stream.srcpad.push(buffer)
|
|
|
|
}
|
|
|
|
|
2020-11-15 12:08:54 +00:00
|
|
|
fn sink_event(
|
|
|
|
&self,
|
|
|
|
pad: &gst::Pad,
|
|
|
|
element: &super::ToggleRecord,
|
|
|
|
mut event: gst::Event,
|
|
|
|
) -> bool {
|
2017-12-05 07:52:31 +00:00
|
|
|
use gst::EventView;
|
|
|
|
|
2018-11-01 10:45:57 +00:00
|
|
|
let stream = match self.pads.lock().get(pad) {
|
2017-12-05 07:52:31 +00:00
|
|
|
None => {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2017-12-05 07:52:31 +00:00
|
|
|
element,
|
|
|
|
gst::CoreError::Pad,
|
2021-04-12 12:49:54 +00:00
|
|
|
["Unknown pad {:?}", pad.name()]
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Some(stream) => stream.clone(),
|
|
|
|
};
|
|
|
|
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Handling event {:?}", event);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
let mut forward = true;
|
|
|
|
let mut send_pending = false;
|
2021-01-06 18:59:44 +00:00
|
|
|
let mut recording_state_changed = false;
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
match event.view() {
|
|
|
|
EventView::FlushStart(..) => {
|
|
|
|
let _main_state = if stream != self.main_stream {
|
2018-11-01 10:45:57 +00:00
|
|
|
Some(self.main_stream.state.lock())
|
2017-12-05 07:52:31 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
state.flushing = true;
|
|
|
|
self.main_stream_cond.notify_all();
|
|
|
|
}
|
|
|
|
EventView::FlushStop(..) => {
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
state.eos = false;
|
|
|
|
state.flushing = false;
|
2020-05-08 19:39:05 +00:00
|
|
|
state.segment_pending = true;
|
|
|
|
state.discont_pending = true;
|
2021-05-28 16:35:28 +00:00
|
|
|
state.current_running_time = None;
|
|
|
|
state.current_running_time_end = None;
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
2019-07-10 16:30:04 +00:00
|
|
|
EventView::Caps(c) => {
|
|
|
|
let mut state = stream.state.lock();
|
2021-04-12 12:49:54 +00:00
|
|
|
let caps = c.caps();
|
2021-04-20 12:58:11 +00:00
|
|
|
let s = caps.structure(0).unwrap();
|
2021-04-12 12:49:54 +00:00
|
|
|
if s.name().starts_with("audio/") {
|
2019-12-14 15:26:20 +00:00
|
|
|
state.audio_info = gst_audio::AudioInfo::from_caps(caps).ok();
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Got audio caps {:?}", state.audio_info);
|
2019-07-10 16:30:04 +00:00
|
|
|
state.video_info = None;
|
2021-04-12 12:49:54 +00:00
|
|
|
} else if s.name().starts_with("video/") {
|
2019-07-10 16:30:04 +00:00
|
|
|
state.audio_info = None;
|
2019-12-15 08:51:12 +00:00
|
|
|
state.video_info = gst_video::VideoInfo::from_caps(caps).ok();
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Got video caps {:?}", state.video_info);
|
2019-07-10 16:30:04 +00:00
|
|
|
} else {
|
|
|
|
state.audio_info = None;
|
|
|
|
state.video_info = None;
|
|
|
|
}
|
|
|
|
}
|
2017-12-05 07:52:31 +00:00
|
|
|
EventView::Segment(e) => {
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2021-04-12 12:49:54 +00:00
|
|
|
let segment = match e.segment().clone().downcast::<gst::ClockTime>() {
|
2017-12-09 17:41:54 +00:00
|
|
|
Err(segment) => {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2017-12-09 17:41:54 +00:00
|
|
|
element,
|
|
|
|
gst::StreamError::Format,
|
2021-04-12 12:49:54 +00:00
|
|
|
["Only Time segments supported, got {:?}", segment.format(),]
|
2017-12-09 17:41:54 +00:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Ok(segment) => segment,
|
|
|
|
};
|
|
|
|
|
2021-04-12 12:49:54 +00:00
|
|
|
if (segment.rate() - 1.0).abs() > f64::EPSILON {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2017-12-05 07:52:31 +00:00
|
|
|
element,
|
|
|
|
gst::StreamError::Format,
|
|
|
|
[
|
|
|
|
"Only rate==1.0 segments supported, got {:?}",
|
2021-04-12 12:49:54 +00:00
|
|
|
segment.rate(),
|
2017-12-05 07:52:31 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-09 17:41:54 +00:00
|
|
|
state.in_segment = segment;
|
2021-04-12 12:49:54 +00:00
|
|
|
state.segment_seqnum = event.seqnum();
|
2017-12-05 07:52:31 +00:00
|
|
|
state.segment_pending = true;
|
2021-05-28 16:35:28 +00:00
|
|
|
state.current_running_time = None;
|
|
|
|
state.current_running_time_end = None;
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Got new Segment {:?}", state.in_segment);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
forward = false;
|
|
|
|
}
|
|
|
|
EventView::Gap(e) => {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Handling Gap event {:?}", event);
|
2017-12-05 07:52:31 +00:00
|
|
|
let (pts, duration) = e.get();
|
|
|
|
let handle_result = if stream == self.main_stream {
|
2019-07-10 16:30:04 +00:00
|
|
|
self.handle_main_stream(element, pad, &stream, (pts, duration))
|
2017-12-05 07:52:31 +00:00
|
|
|
} else {
|
2019-07-10 16:30:04 +00:00
|
|
|
self.handle_secondary_stream(element, pad, &stream, (pts, duration))
|
2017-12-05 07:52:31 +00:00
|
|
|
};
|
|
|
|
|
2019-07-10 16:30:04 +00:00
|
|
|
forward = match handle_result {
|
2021-05-28 16:35:28 +00:00
|
|
|
Ok(HandleResult::Pass((new_pts, new_duration))) => {
|
|
|
|
if new_pts != pts
|
|
|
|
|| new_duration
|
|
|
|
.zip(duration)
|
|
|
|
.map_or(false, |(new_duration, duration)| new_duration != duration)
|
|
|
|
{
|
|
|
|
event = gst::event::Gap::builder(new_pts)
|
|
|
|
.duration(new_duration)
|
|
|
|
.build();
|
2019-07-10 16:30:04 +00:00
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
2021-05-28 16:35:28 +00:00
|
|
|
_ => false,
|
2019-07-10 16:30:04 +00:00
|
|
|
};
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
EventView::Eos(..) => {
|
2021-01-06 18:59:44 +00:00
|
|
|
let main_state = if stream != self.main_stream {
|
2018-11-01 10:45:57 +00:00
|
|
|
Some(self.main_stream.state.lock())
|
2017-12-05 07:52:31 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
state.eos = true;
|
2021-01-06 18:59:44 +00:00
|
|
|
|
|
|
|
let main_is_eos = if let Some(main_state) = main_state {
|
|
|
|
main_state.eos
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
};
|
|
|
|
|
|
|
|
if main_is_eos {
|
|
|
|
let mut rec_state = self.state.lock();
|
|
|
|
recording_state_changed =
|
|
|
|
self.check_and_update_eos(pad, &stream, &mut state, &mut rec_state);
|
|
|
|
}
|
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
self.main_stream_cond.notify_all();
|
|
|
|
gst_debug!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2017-12-05 07:52:31 +00:00
|
|
|
obj: pad,
|
|
|
|
"Stream is EOS now, sending any pending events"
|
|
|
|
);
|
|
|
|
|
|
|
|
send_pending = true;
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
};
|
|
|
|
|
2021-01-06 18:59:44 +00:00
|
|
|
if recording_state_changed {
|
|
|
|
element.notify("recording");
|
|
|
|
}
|
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
// If a serialized event and coming after Segment and a new Segment is pending,
|
|
|
|
// queue up and send at a later time (buffer/gap) after we sent the Segment
|
2021-04-12 12:49:54 +00:00
|
|
|
let type_ = event.type_();
|
2018-07-27 10:35:58 +00:00
|
|
|
if forward
|
|
|
|
&& type_ != gst::EventType::Eos
|
|
|
|
&& type_.is_serialized()
|
2017-12-05 07:52:31 +00:00
|
|
|
&& type_.partial_cmp(&gst::EventType::Segment) == Some(cmp::Ordering::Greater)
|
|
|
|
{
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
if state.segment_pending {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Storing event for later pushing");
|
2017-12-05 07:52:31 +00:00
|
|
|
state.pending_events.push(event);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if send_pending {
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
let mut events = Vec::with_capacity(state.pending_events.len() + 1);
|
|
|
|
|
|
|
|
// Got not a single buffer on this stream before EOS, forward
|
|
|
|
// the input segment
|
|
|
|
if state.segment_pending {
|
|
|
|
events.push(
|
2020-06-24 22:33:57 +00:00
|
|
|
gst::event::Segment::builder(&state.in_segment)
|
2017-12-05 07:52:31 +00:00
|
|
|
.seqnum(state.segment_seqnum)
|
|
|
|
.build(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
events.append(&mut state.pending_events);
|
|
|
|
drop(state);
|
|
|
|
|
|
|
|
for e in events.drain(..) {
|
|
|
|
stream.srcpad.push_event(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if forward {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Forwarding event {:?}", event);
|
2017-12-05 07:52:31 +00:00
|
|
|
stream.srcpad.push_event(event)
|
|
|
|
} else {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Dropping event {:?}", event);
|
2017-12-05 07:52:31 +00:00
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-18 13:18:17 +00:00
|
|
|
fn sink_query(
|
|
|
|
&self,
|
|
|
|
pad: &gst::Pad,
|
2020-11-15 12:08:54 +00:00
|
|
|
element: &super::ToggleRecord,
|
2018-11-18 13:18:17 +00:00
|
|
|
query: &mut gst::QueryRef,
|
|
|
|
) -> bool {
|
2018-11-01 10:45:57 +00:00
|
|
|
let stream = match self.pads.lock().get(pad) {
|
2017-12-05 07:52:31 +00:00
|
|
|
None => {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2017-12-05 07:52:31 +00:00
|
|
|
element,
|
|
|
|
gst::CoreError::Pad,
|
2021-04-12 12:49:54 +00:00
|
|
|
["Unknown pad {:?}", pad.name()]
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Some(stream) => stream.clone(),
|
|
|
|
};
|
|
|
|
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Handling query {:?}", query);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
stream.srcpad.peer_query(query)
|
|
|
|
}
|
|
|
|
|
2020-10-19 15:03:10 +00:00
|
|
|
// FIXME `matches!` was introduced in rustc 1.42.0, current MSRV is 1.41.0
|
|
|
|
// FIXME uncomment when CI can upgrade to 1.47.1
|
|
|
|
//#[allow(clippy::match_like_matches_macro)]
|
2020-11-15 12:08:54 +00:00
|
|
|
fn src_event(
|
|
|
|
&self,
|
|
|
|
pad: &gst::Pad,
|
|
|
|
element: &super::ToggleRecord,
|
|
|
|
mut event: gst::Event,
|
|
|
|
) -> bool {
|
2017-12-05 07:52:31 +00:00
|
|
|
use gst::EventView;
|
|
|
|
|
2018-11-01 10:45:57 +00:00
|
|
|
let stream = match self.pads.lock().get(pad) {
|
2017-12-05 07:52:31 +00:00
|
|
|
None => {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2017-12-05 07:52:31 +00:00
|
|
|
element,
|
|
|
|
gst::CoreError::Pad,
|
2021-04-12 12:49:54 +00:00
|
|
|
["Unknown pad {:?}", pad.name()]
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Some(stream) => stream.clone(),
|
|
|
|
};
|
|
|
|
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Handling event {:?}", event);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2020-11-16 10:15:59 +00:00
|
|
|
let forward = !matches!(event.view(), EventView::Seek(..));
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2018-11-01 10:45:57 +00:00
|
|
|
let rec_state = self.state.lock();
|
2021-04-12 12:49:54 +00:00
|
|
|
let offset = event.running_time_offset();
|
2017-12-05 07:52:31 +00:00
|
|
|
event
|
|
|
|
.make_mut()
|
2021-05-28 16:35:28 +00:00
|
|
|
.set_running_time_offset(offset + rec_state.running_time_offset);
|
2017-12-05 07:52:31 +00:00
|
|
|
drop(rec_state);
|
|
|
|
|
|
|
|
if forward {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Forwarding event {:?}", event);
|
2017-12-05 07:52:31 +00:00
|
|
|
stream.sinkpad.push_event(event)
|
|
|
|
} else {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Dropping event {:?}", event);
|
2017-12-05 07:52:31 +00:00
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-15 12:08:54 +00:00
|
|
|
fn src_query(
|
|
|
|
&self,
|
|
|
|
pad: &gst::Pad,
|
|
|
|
element: &super::ToggleRecord,
|
|
|
|
query: &mut gst::QueryRef,
|
|
|
|
) -> bool {
|
2017-12-05 07:52:31 +00:00
|
|
|
use gst::QueryView;
|
|
|
|
|
2018-11-01 10:45:57 +00:00
|
|
|
let stream = match self.pads.lock().get(pad) {
|
2017-12-05 07:52:31 +00:00
|
|
|
None => {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2017-12-05 07:52:31 +00:00
|
|
|
element,
|
|
|
|
gst::CoreError::Pad,
|
2021-04-12 12:49:54 +00:00
|
|
|
["Unknown pad {:?}", pad.name()]
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Some(stream) => stream.clone(),
|
|
|
|
};
|
|
|
|
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Handling query {:?}", query);
|
2017-12-05 07:52:31 +00:00
|
|
|
match query.view_mut() {
|
|
|
|
QueryView::Scheduling(ref mut q) => {
|
2020-06-24 22:33:57 +00:00
|
|
|
let mut new_query = gst::query::Scheduling::new();
|
2018-02-16 08:43:27 +00:00
|
|
|
let res = stream.sinkpad.peer_query(&mut new_query);
|
2017-12-05 07:52:31 +00:00
|
|
|
if !res {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Downstream returned {:?}", new_query);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2021-04-12 12:49:54 +00:00
|
|
|
let (flags, min, max, align) = new_query.result();
|
2018-02-16 08:43:27 +00:00
|
|
|
q.set(flags, min, max, align);
|
2018-07-27 10:35:58 +00:00
|
|
|
q.add_scheduling_modes(
|
|
|
|
&new_query
|
2021-04-12 12:49:54 +00:00
|
|
|
.scheduling_modes()
|
2018-07-27 10:35:58 +00:00
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.filter(|m| m != &gst::PadMode::Pull)
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
);
|
2021-04-12 12:49:54 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Returning {:?}", q.query_mut());
|
2019-07-03 15:44:25 +00:00
|
|
|
true
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
QueryView::Seeking(ref mut q) => {
|
|
|
|
// Seeking is not possible here
|
2021-04-12 12:49:54 +00:00
|
|
|
let format = q.format();
|
2017-12-05 07:52:31 +00:00
|
|
|
q.set(
|
|
|
|
false,
|
2017-12-09 17:41:54 +00:00
|
|
|
gst::GenericFormattedValue::new(format, -1),
|
|
|
|
gst::GenericFormattedValue::new(format, -1),
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
|
|
|
|
2021-04-12 12:49:54 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Returning {:?}", q.query_mut());
|
2019-07-03 15:44:25 +00:00
|
|
|
true
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
// Position and duration is always the current recording position
|
2018-10-11 10:49:48 +00:00
|
|
|
QueryView::Position(ref mut q) => {
|
2021-04-12 12:49:54 +00:00
|
|
|
if q.format() == gst::Format::Time {
|
2018-11-01 10:45:57 +00:00
|
|
|
let state = stream.state.lock();
|
|
|
|
let rec_state = self.state.lock();
|
2018-10-11 10:49:48 +00:00
|
|
|
let mut recording_duration = rec_state.recording_duration;
|
|
|
|
if rec_state.recording_state == RecordingState::Recording
|
|
|
|
|| rec_state.recording_state == RecordingState::Stopping
|
|
|
|
{
|
2021-05-28 16:35:28 +00:00
|
|
|
if let Some(delta) = state
|
|
|
|
.current_running_time_end
|
|
|
|
.zip(rec_state.last_recording_start)
|
|
|
|
.and_then(|(cur_rt_end, last_rec_start)| {
|
|
|
|
cur_rt_end.checked_sub(last_rec_start)
|
|
|
|
})
|
|
|
|
{
|
|
|
|
gst_debug!(
|
|
|
|
CAT,
|
|
|
|
obj: pad,
|
|
|
|
"Returning position {} = {} - ({} + {})",
|
|
|
|
recording_duration + delta,
|
|
|
|
recording_duration,
|
|
|
|
state.current_running_time_end.display(),
|
|
|
|
rec_state.last_recording_start.display(),
|
|
|
|
);
|
|
|
|
recording_duration += delta;
|
|
|
|
}
|
2020-05-08 12:57:07 +00:00
|
|
|
} else {
|
2021-05-28 16:35:28 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Returning position {}", recording_duration);
|
2018-10-11 10:49:48 +00:00
|
|
|
}
|
|
|
|
q.set(recording_duration);
|
2019-07-03 15:44:25 +00:00
|
|
|
true
|
2018-10-11 10:49:48 +00:00
|
|
|
} else {
|
2019-07-03 15:44:25 +00:00
|
|
|
false
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
2018-10-11 10:49:48 +00:00
|
|
|
}
|
|
|
|
QueryView::Duration(ref mut q) => {
|
2021-04-12 12:49:54 +00:00
|
|
|
if q.format() == gst::Format::Time {
|
2018-11-01 10:45:57 +00:00
|
|
|
let state = stream.state.lock();
|
|
|
|
let rec_state = self.state.lock();
|
2018-10-11 10:49:48 +00:00
|
|
|
let mut recording_duration = rec_state.recording_duration;
|
|
|
|
if rec_state.recording_state == RecordingState::Recording
|
|
|
|
|| rec_state.recording_state == RecordingState::Stopping
|
|
|
|
{
|
2021-05-28 16:35:28 +00:00
|
|
|
if let Some(delta) = state
|
|
|
|
.current_running_time_end
|
|
|
|
.zip(rec_state.last_recording_start)
|
|
|
|
.and_then(|(cur_rt_end, last_rec_start)| {
|
|
|
|
cur_rt_end.checked_sub(last_rec_start)
|
|
|
|
})
|
|
|
|
{
|
|
|
|
gst_debug!(
|
|
|
|
CAT,
|
|
|
|
obj: pad,
|
|
|
|
"Returning duration {} = {} - ({} + {})",
|
|
|
|
recording_duration + delta,
|
|
|
|
recording_duration,
|
|
|
|
state.current_running_time_end.display(),
|
|
|
|
rec_state.last_recording_start.display(),
|
|
|
|
);
|
|
|
|
recording_duration += delta;
|
|
|
|
}
|
2020-05-08 12:57:07 +00:00
|
|
|
} else {
|
2021-05-28 16:35:28 +00:00
|
|
|
gst_debug!(CAT, obj: pad, "Returning duration {}", recording_duration);
|
2018-10-11 10:49:48 +00:00
|
|
|
}
|
|
|
|
q.set(recording_duration);
|
2019-07-03 15:44:25 +00:00
|
|
|
true
|
2018-10-11 10:49:48 +00:00
|
|
|
} else {
|
2019-07-03 15:44:25 +00:00
|
|
|
false
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
2018-10-11 10:49:48 +00:00
|
|
|
}
|
2019-07-03 15:44:25 +00:00
|
|
|
_ => {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_log!(CAT, obj: pad, "Forwarding query {:?}", query);
|
2019-07-03 15:44:25 +00:00
|
|
|
stream.sinkpad.peer_query(query)
|
|
|
|
}
|
|
|
|
}
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
2018-11-18 13:18:17 +00:00
|
|
|
fn iterate_internal_links(
|
|
|
|
&self,
|
|
|
|
pad: &gst::Pad,
|
2020-11-15 12:08:54 +00:00
|
|
|
element: &super::ToggleRecord,
|
2018-11-18 13:18:17 +00:00
|
|
|
) -> gst::Iterator<gst::Pad> {
|
2018-11-01 10:45:57 +00:00
|
|
|
let stream = match self.pads.lock().get(pad) {
|
2017-12-05 07:52:31 +00:00
|
|
|
None => {
|
2020-12-20 18:43:45 +00:00
|
|
|
gst::element_error!(
|
2017-12-05 07:52:31 +00:00
|
|
|
element,
|
|
|
|
gst::CoreError::Pad,
|
2021-04-12 12:49:54 +00:00
|
|
|
["Unknown pad {:?}", pad.name()]
|
2017-12-05 07:52:31 +00:00
|
|
|
);
|
|
|
|
return gst::Iterator::from_vec(vec![]);
|
|
|
|
}
|
|
|
|
Some(stream) => stream.clone(),
|
|
|
|
};
|
|
|
|
|
|
|
|
if pad == &stream.srcpad {
|
2019-11-24 22:00:27 +00:00
|
|
|
gst::Iterator::from_vec(vec![stream.sinkpad])
|
2017-12-05 07:52:31 +00:00
|
|
|
} else {
|
2019-11-24 22:00:27 +00:00
|
|
|
gst::Iterator::from_vec(vec![stream.srcpad])
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-07 16:22:24 +00:00
|
|
|
#[glib::object_subclass]
|
2018-11-18 13:18:17 +00:00
|
|
|
impl ObjectSubclass for ToggleRecord {
|
|
|
|
const NAME: &'static str = "RsToggleRecord";
|
2020-11-15 12:08:54 +00:00
|
|
|
type Type = super::ToggleRecord;
|
2018-11-18 13:18:17 +00:00
|
|
|
type ParentType = gst::Element;
|
|
|
|
|
2020-11-15 12:08:54 +00:00
|
|
|
fn with_class(klass: &Self::Class) -> Self {
|
2021-04-20 12:58:11 +00:00
|
|
|
let templ = klass.pad_template("sink").unwrap();
|
2020-06-22 08:03:52 +00:00
|
|
|
let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink"))
|
|
|
|
.chain_function(|pad, parent, buffer| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| Err(gst::FlowError::Error),
|
|
|
|
|togglerecord, element| togglerecord.sink_chain(pad, element, buffer),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.event_function(|pad, parent, event| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| false,
|
|
|
|
|togglerecord, element| togglerecord.sink_event(pad, element, event),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.query_function(|pad, parent, query| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| false,
|
|
|
|
|togglerecord, element| togglerecord.sink_query(pad, element, query),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.iterate_internal_links_function(|pad, parent| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| gst::Iterator::from_vec(vec![]),
|
|
|
|
|togglerecord, element| togglerecord.iterate_internal_links(pad, element),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.build();
|
2018-11-18 13:18:17 +00:00
|
|
|
|
2021-04-20 12:58:11 +00:00
|
|
|
let templ = klass.pad_template("src").unwrap();
|
2020-06-22 08:03:52 +00:00
|
|
|
let srcpad = gst::Pad::builder_with_template(&templ, Some("src"))
|
|
|
|
.event_function(|pad, parent, event| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| false,
|
|
|
|
|togglerecord, element| togglerecord.src_event(pad, element, event),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.query_function(|pad, parent, query| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| false,
|
|
|
|
|togglerecord, element| togglerecord.src_query(pad, element, query),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.iterate_internal_links_function(|pad, parent| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| gst::Iterator::from_vec(vec![]),
|
|
|
|
|togglerecord, element| togglerecord.iterate_internal_links(pad, element),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.build();
|
2018-11-18 13:18:17 +00:00
|
|
|
|
|
|
|
let main_stream = Stream::new(sinkpad, srcpad);
|
|
|
|
|
|
|
|
let mut pads = HashMap::new();
|
|
|
|
pads.insert(main_stream.sinkpad.clone(), main_stream.clone());
|
|
|
|
pads.insert(main_stream.srcpad.clone(), main_stream.clone());
|
|
|
|
|
|
|
|
Self {
|
|
|
|
settings: Mutex::new(Settings::default()),
|
|
|
|
state: Mutex::new(State::default()),
|
|
|
|
main_stream,
|
|
|
|
main_stream_cond: Condvar::new(),
|
|
|
|
other_streams: Mutex::new((Vec::new(), 0)),
|
|
|
|
pads: Mutex::new(pads),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ObjectImpl for ToggleRecord {
|
2021-01-21 18:21:29 +00:00
|
|
|
fn properties() -> &'static [glib::ParamSpec] {
|
|
|
|
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
|
|
|
vec![
|
2021-04-12 16:12:05 +00:00
|
|
|
glib::ParamSpec::new_boolean(
|
2021-01-21 18:21:29 +00:00
|
|
|
"record",
|
|
|
|
"Record",
|
|
|
|
"Enable/disable recording",
|
|
|
|
DEFAULT_RECORD,
|
2021-01-31 12:44:45 +00:00
|
|
|
glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_PLAYING,
|
2021-01-21 18:21:29 +00:00
|
|
|
),
|
2021-04-12 16:12:05 +00:00
|
|
|
glib::ParamSpec::new_boolean(
|
2021-01-21 18:21:29 +00:00
|
|
|
"recording",
|
|
|
|
"Recording",
|
|
|
|
"Whether recording is currently taking place",
|
|
|
|
DEFAULT_RECORD,
|
|
|
|
glib::ParamFlags::READABLE,
|
|
|
|
),
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
PROPERTIES.as_ref()
|
|
|
|
}
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2021-01-21 18:21:29 +00:00
|
|
|
fn set_property(
|
|
|
|
&self,
|
|
|
|
obj: &Self::Type,
|
|
|
|
_id: usize,
|
|
|
|
value: &glib::Value,
|
|
|
|
pspec: &glib::ParamSpec,
|
|
|
|
) {
|
2021-04-12 12:49:54 +00:00
|
|
|
match pspec.name() {
|
2021-01-21 18:21:29 +00:00
|
|
|
"record" => {
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut settings = self.settings.lock();
|
2021-04-25 12:41:22 +00:00
|
|
|
let record = value.get().expect("type checked upstream");
|
2017-12-05 07:52:31 +00:00
|
|
|
gst_debug!(
|
2019-10-31 22:34:21 +00:00
|
|
|
CAT,
|
2020-11-15 12:08:54 +00:00
|
|
|
obj: obj,
|
2017-12-05 07:52:31 +00:00
|
|
|
"Setting record from {:?} to {:?}",
|
|
|
|
settings.record,
|
|
|
|
record
|
|
|
|
);
|
2020-05-08 12:57:07 +00:00
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
settings.record = record;
|
|
|
|
}
|
|
|
|
_ => unimplemented!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-20 12:57:40 +00:00
|
|
|
fn property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
2021-04-12 12:49:54 +00:00
|
|
|
match pspec.name() {
|
2021-01-21 18:21:29 +00:00
|
|
|
"record" => {
|
2018-11-01 10:45:57 +00:00
|
|
|
let settings = self.settings.lock();
|
2020-11-19 15:55:57 +00:00
|
|
|
settings.record.to_value()
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
2021-01-21 18:21:29 +00:00
|
|
|
"recording" => {
|
2018-11-01 10:45:57 +00:00
|
|
|
let rec_state = self.state.lock();
|
2020-11-19 15:55:57 +00:00
|
|
|
(rec_state.recording_state == RecordingState::Recording).to_value()
|
2017-12-06 12:10:01 +00:00
|
|
|
}
|
2017-12-05 07:52:31 +00:00
|
|
|
_ => unimplemented!(),
|
|
|
|
}
|
|
|
|
}
|
2018-11-18 13:18:17 +00:00
|
|
|
|
2020-11-15 12:08:54 +00:00
|
|
|
fn constructed(&self, obj: &Self::Type) {
|
2018-11-18 13:18:17 +00:00
|
|
|
self.parent_constructed(obj);
|
|
|
|
|
2020-11-15 12:08:54 +00:00
|
|
|
obj.add_pad(&self.main_stream.sinkpad).unwrap();
|
|
|
|
obj.add_pad(&self.main_stream.srcpad).unwrap();
|
2018-11-18 13:18:17 +00:00
|
|
|
}
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
2018-11-18 13:18:17 +00:00
|
|
|
impl ElementImpl for ToggleRecord {
|
2021-01-21 18:21:29 +00:00
|
|
|
fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
|
|
|
|
static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
|
|
|
|
gst::subclass::ElementMetadata::new(
|
|
|
|
"Toggle Record",
|
|
|
|
"Generic",
|
|
|
|
"Valve that ensures multiple streams start/end at the same time",
|
|
|
|
"Sebastian Dröge <sebastian@centricular.com>",
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
Some(&*ELEMENT_METADATA)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pad_templates() -> &'static [gst::PadTemplate] {
|
|
|
|
static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
|
|
|
|
let caps = gst::Caps::new_any();
|
|
|
|
let src_pad_template = gst::PadTemplate::new(
|
|
|
|
"src",
|
|
|
|
gst::PadDirection::Src,
|
|
|
|
gst::PadPresence::Always,
|
|
|
|
&caps,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let sink_pad_template = gst::PadTemplate::new(
|
|
|
|
"sink",
|
|
|
|
gst::PadDirection::Sink,
|
|
|
|
gst::PadPresence::Always,
|
|
|
|
&caps,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let secondary_src_pad_template = gst::PadTemplate::new(
|
|
|
|
"src_%u",
|
|
|
|
gst::PadDirection::Src,
|
|
|
|
gst::PadPresence::Sometimes,
|
|
|
|
&caps,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let secondary_sink_pad_template = gst::PadTemplate::new(
|
|
|
|
"sink_%u",
|
|
|
|
gst::PadDirection::Sink,
|
|
|
|
gst::PadPresence::Request,
|
|
|
|
&caps,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
vec![
|
|
|
|
src_pad_template,
|
|
|
|
sink_pad_template,
|
|
|
|
secondary_src_pad_template,
|
|
|
|
secondary_sink_pad_template,
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
PAD_TEMPLATES.as_ref()
|
|
|
|
}
|
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
fn change_state(
|
|
|
|
&self,
|
2020-11-15 12:08:54 +00:00
|
|
|
element: &Self::Type,
|
2017-12-05 07:52:31 +00:00
|
|
|
transition: gst::StateChange,
|
2019-01-11 23:45:05 +00:00
|
|
|
) -> Result<gst::StateChangeSuccess, gst::StateChangeError> {
|
2019-10-31 22:34:21 +00:00
|
|
|
gst_trace!(CAT, obj: element, "Changing state {:?}", transition);
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
match transition {
|
|
|
|
gst::StateChange::ReadyToPaused => {
|
2018-07-27 10:35:58 +00:00
|
|
|
for s in self
|
|
|
|
.other_streams
|
2017-12-05 07:52:31 +00:00
|
|
|
.lock()
|
|
|
|
.0
|
|
|
|
.iter()
|
|
|
|
.chain(iter::once(&self.main_stream))
|
|
|
|
{
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = s.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
*state = StreamState::default();
|
|
|
|
}
|
|
|
|
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut rec_state = self.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
*rec_state = State::default();
|
|
|
|
}
|
|
|
|
gst::StateChange::PausedToReady => {
|
2018-11-01 10:45:57 +00:00
|
|
|
for s in &self.other_streams.lock().0 {
|
|
|
|
let mut state = s.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
state.flushing = true;
|
|
|
|
}
|
|
|
|
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut state = self.main_stream.state.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
state.flushing = true;
|
|
|
|
self.main_stream_cond.notify_all();
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
|
2019-01-11 23:45:05 +00:00
|
|
|
let success = self.parent_change_state(element, transition)?;
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2019-01-11 23:45:05 +00:00
|
|
|
if transition == gst::StateChange::PausedToReady {
|
|
|
|
for s in self
|
|
|
|
.other_streams
|
|
|
|
.lock()
|
|
|
|
.0
|
|
|
|
.iter()
|
|
|
|
.chain(iter::once(&self.main_stream))
|
|
|
|
{
|
|
|
|
let mut state = s.state.lock();
|
2017-12-06 12:10:01 +00:00
|
|
|
|
2019-01-11 23:45:05 +00:00
|
|
|
state.pending_events.clear();
|
2017-12-06 12:10:01 +00:00
|
|
|
}
|
2019-01-11 23:45:05 +00:00
|
|
|
|
|
|
|
let mut rec_state = self.state.lock();
|
|
|
|
*rec_state = State::default();
|
|
|
|
drop(rec_state);
|
|
|
|
element.notify("recording");
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
2019-01-11 23:45:05 +00:00
|
|
|
Ok(success)
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn request_new_pad(
|
|
|
|
&self,
|
2020-11-15 12:08:54 +00:00
|
|
|
element: &Self::Type,
|
2017-12-05 07:52:31 +00:00
|
|
|
_templ: &gst::PadTemplate,
|
|
|
|
_name: Option<String>,
|
2019-05-23 20:55:54 +00:00
|
|
|
_caps: Option<&gst::Caps>,
|
2017-12-05 07:52:31 +00:00
|
|
|
) -> Option<gst::Pad> {
|
2019-07-03 15:43:58 +00:00
|
|
|
let mut other_streams_guard = self.other_streams.lock();
|
|
|
|
let (ref mut other_streams, ref mut pad_count) = *other_streams_guard;
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut pads = self.pads.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
let id = *pad_count;
|
|
|
|
*pad_count += 1;
|
|
|
|
|
2021-04-20 12:58:11 +00:00
|
|
|
let templ = element.pad_template("sink_%u").unwrap();
|
2020-06-22 08:03:52 +00:00
|
|
|
let sinkpad =
|
|
|
|
gst::Pad::builder_with_template(&templ, Some(format!("sink_{}", id).as_str()))
|
|
|
|
.chain_function(|pad, parent, buffer| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| Err(gst::FlowError::Error),
|
|
|
|
|togglerecord, element| togglerecord.sink_chain(pad, element, buffer),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.event_function(|pad, parent, event| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| false,
|
|
|
|
|togglerecord, element| togglerecord.sink_event(pad, element, event),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.query_function(|pad, parent, query| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| false,
|
|
|
|
|togglerecord, element| togglerecord.sink_query(pad, element, query),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.iterate_internal_links_function(|pad, parent| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| gst::Iterator::from_vec(vec![]),
|
|
|
|
|togglerecord, element| togglerecord.iterate_internal_links(pad, element),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.build();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
2021-04-20 12:58:11 +00:00
|
|
|
let templ = element.pad_template("src_%u").unwrap();
|
2020-06-22 08:03:52 +00:00
|
|
|
let srcpad = gst::Pad::builder_with_template(&templ, Some(format!("src_{}", id).as_str()))
|
|
|
|
.event_function(|pad, parent, event| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| false,
|
|
|
|
|togglerecord, element| togglerecord.src_event(pad, element, event),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.query_function(|pad, parent, query| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| false,
|
|
|
|
|togglerecord, element| togglerecord.src_query(pad, element, query),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.iterate_internal_links_function(|pad, parent| {
|
|
|
|
ToggleRecord::catch_panic_pad_function(
|
|
|
|
parent,
|
|
|
|
|| gst::Iterator::from_vec(vec![]),
|
|
|
|
|togglerecord, element| togglerecord.iterate_internal_links(pad, element),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.build();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
sinkpad.set_active(true).unwrap();
|
|
|
|
srcpad.set_active(true).unwrap();
|
|
|
|
|
2019-07-03 15:43:58 +00:00
|
|
|
let stream = Stream::new(sinkpad.clone(), srcpad.clone());
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
pads.insert(stream.sinkpad.clone(), stream.clone());
|
|
|
|
pads.insert(stream.srcpad.clone(), stream.clone());
|
|
|
|
|
|
|
|
other_streams.push(stream);
|
|
|
|
|
2019-07-03 15:43:58 +00:00
|
|
|
drop(pads);
|
|
|
|
drop(other_streams_guard);
|
|
|
|
|
|
|
|
element.add_pad(&sinkpad).unwrap();
|
|
|
|
element.add_pad(&srcpad).unwrap();
|
|
|
|
|
2017-12-05 07:52:31 +00:00
|
|
|
Some(sinkpad)
|
|
|
|
}
|
|
|
|
|
2020-11-15 12:08:54 +00:00
|
|
|
fn release_pad(&self, element: &Self::Type, pad: &gst::Pad) {
|
2019-07-03 15:43:58 +00:00
|
|
|
let mut other_streams_guard = self.other_streams.lock();
|
|
|
|
let (ref mut other_streams, _) = *other_streams_guard;
|
2018-11-01 10:45:57 +00:00
|
|
|
let mut pads = self.pads.lock();
|
2017-12-05 07:52:31 +00:00
|
|
|
|
|
|
|
let stream = match pads.get(pad) {
|
|
|
|
None => return,
|
|
|
|
Some(stream) => stream.clone(),
|
|
|
|
};
|
|
|
|
|
|
|
|
stream.srcpad.set_active(false).unwrap();
|
|
|
|
stream.sinkpad.set_active(false).unwrap();
|
|
|
|
|
|
|
|
pads.remove(&stream.sinkpad).unwrap();
|
|
|
|
pads.remove(&stream.srcpad).unwrap();
|
|
|
|
|
|
|
|
// TODO: Replace with Vec::remove_item() once stable
|
|
|
|
let pos = other_streams.iter().position(|x| *x == stream);
|
|
|
|
pos.map(|pos| other_streams.swap_remove(pos));
|
2019-07-03 15:43:58 +00:00
|
|
|
|
|
|
|
drop(pads);
|
|
|
|
drop(other_streams_guard);
|
|
|
|
|
|
|
|
element.remove_pad(&stream.sinkpad).unwrap();
|
|
|
|
element.remove_pad(&stream.srcpad).unwrap();
|
2017-12-05 07:52:31 +00:00
|
|
|
}
|
|
|
|
}
|