return true;
}
- bool FlushDownStream(T type) {
+ bool FlushDownStream(T type, gboolean reset_time) {
GstElement* obj = mainbin_[static_cast<int>(type)];
if (!obj) return false;
auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));
TRACKRENDERER_ERROR("Fail to send flush start");
return false;
}
- if (!gst_pad_send_event(peer_pad, gst_event_new_flush_stop(FALSE))) {
+ if (!gst_pad_send_event(peer_pad, gst_event_new_flush_stop(reset_time))) {
TRACKRENDERER_ERROR("Fail to send flush stop");
return false;
}
return gst_element_factory_list_is_type(gst_element_get_factory(obj), type);
}
+ bool PushSegmentEvent(T type, uint64_t position, gdouble rate) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));
+ auto peer_pad = GST_PAD_PEER(pad.get());
+ GstSegment segment;
+ gst_segment_init(&segment, GST_FORMAT_TIME);
+ segment.rate = rate;
+ segment.start = position;
+ segment.position = position;
+ segment.time = position;
+ GstEvent* seg_event = gst_event_new_segment(&segment);
+ if (!gst_pad_send_event(peer_pad, seg_event)) {
+ TRACKRENDERER_ERROR("Fail to send segment event");
+ return false;
+ }
+ return true;
+ }
+
//////////////// /////////////////
//////////////// Utilities (Leaving) /////////////////
//////////////// /////////////////
return false;
}
- resource_cv_.wait(lock);
+ resource_cv_.wait(lock);
if (state_ != State::kWorking) {
TRACKRENDERER_ERROR(
gint(playback_rate * 100));
}
}
- if (!pipeline_->Seek(
- playback_rate, GST_FORMAT_TIME,
- (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
- GST_SEEK_TYPE_SET, curtime_in_msec * GST_MSECOND, GST_SEEK_TYPE_NONE,
- GST_CLOCK_TIME_NONE)) {
- TRACKRENDERER_ERROR("Fail to seek ");
+
+ Elements audio_probe_element = Elements::kDecAudio;
+ Elements video_probe_element = Elements::kDecVideo;
+ Elements subtitle_probe_element = Elements::kAppSrcSubtitle;
+ Elements close_caption_probe_element = Elements::kQueueCaption;
+
+ std::map<Elements, std::pair<std::string, std::string>> probe_map = {
+ {audio_probe_element,
+ {"AUDIO_RATE_IDLE_PROBE", "AUDIO_RATE_BLOCK_PROBE"}},
+ {video_probe_element,
+ {"VIDEO_RATE_IDLE_PROBE", "VIDEO_RATE_BLOCK_PROBE"}},
+ {subtitle_probe_element,
+ {"SUBTITLE_RATE_IDLE_PROBE", "SUBTITLE_RATE_BLOCK_PROBE"}},
+ {close_caption_probe_element,
+ {"CLOSE_CAPTION_RATE_IDLE_PROBE", "CLOSE_CAPTION_RATE_BLOCK_PROBE"}}};
+
+ std::map<Elements, Elements> probe_sink_map = {
+ {audio_probe_element, Elements::kSinkAudio},
+ {video_probe_element, Elements::kSinkVideo},
+ {subtitle_probe_element, Elements::kSinkSubtitle},
+ {close_caption_probe_element, Elements::kSinkCaption}};
+
+ for (auto& kv : probe_map) {
+ const Elements& element = kv.first;
+ std::pair<std::string, std::string>& probe = kv.second;
+ pipeline_->PadAddProbe(element, (probe.second).c_str(), "src",
+ GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, nullptr,
+ nullptr, nullptr);
+ gboolean is_sync = FALSE;
+ pipeline_->GetProperty(probe_sink_map[element], "sync", &is_sync);
+ pipeline_->SetProperty(probe_sink_map[element], "sync", FALSE);
+ FlushDownStream_(element, (probe.first).c_str(), TRUE);
+ if (is_sync) pipeline_->SetProperty(probe_sink_map[element], "sync", TRUE);
}
+
if (playback_rate != kDefaultPlaybackRate) {
TRACKRENDERER_INFO("sequential mode should be off during trickplay");
pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", TRUE);
pipeline_->GetProperty(Elements::kSinkVideo, "last-video-pts",
&last_video_pts);
- if (last_video_pts > 0) {
- pipeline_->SetProperty(Elements::kAppSrcVideo, "update-segment",
- last_video_pts);
- pipeline_->SetProperty(Elements::kAppSrcAudio, "update-segment",
- last_video_pts);
- pipeline_->SetProperty(Elements::kAppSrcSubtitle, "update-segment",
- last_video_pts);
+
+ TRACKRENDERER_INFO("target %" PRIu64 " ms rate [%lf] mute [%d]", curtime_in_msec,
+ playback_rate, audio_mute);
+
+ for (auto& kv : probe_map) {
+ const Elements& element = kv.first;
+ std::pair<std::string, std::string>& probe = kv.second;
+ pipeline_->PushSegmentEvent(element, curtime_in_msec * GST_MSECOND,
+ playback_rate);
+ pipeline_->PadRemoveProbe((probe.second).c_str());
}
+
playback_rate_ = playback_rate;
TRACKRENDERER_LEAVE;
return true;
return GST_PAD_PROBE_DROP;
}
-void TrackRenderer::FlushAudioDownStream_(Elements element) {
- TRACKRENDERER_ENTER;
+void TrackRenderer::FlushDownStream_(Elements element, const char* key,
+ gboolean reset_time) {
+ TRACKRENDERER_ENTER_P(this);
if (!pipeline_) return;
Pipeline<Elements>::Pad pad;
- pipeline_->PadAddProbe(element, kPadProbeAudioIdle, "src",
- GST_PAD_PROBE_TYPE_IDLE, GstSrcPadProbeIdleCb_, &pad,
- nullptr);
-
- pipeline_->FlushDownStream(element);
+ pipeline_->PadAddProbe(element, key, "src", GST_PAD_PROBE_TYPE_IDLE,
+ GstSrcPadProbeIdleCb_, &pad, nullptr);
- {
+ if (pipeline_->FlushDownStream(element, reset_time)) {
std::unique_lock<std::mutex> pad_block_locker(pad.m);
if (!pad.is_idle) {
pad.cv.wait(pad_block_locker);
- TRACKRENDERER_INFO("pad block wait end");
+ TRACKRENDERER_INFO_P(this, "pad block wait end");
}
}
- pipeline_->PadRemoveProbe(kPadProbeAudioIdle);
- TRACKRENDERER_LEAVE;
+ pipeline_->PadRemoveProbe(key);
+ TRACKRENDERER_LEAVE_P(this);
}
bool TrackRenderer::ActivateAudio_() {
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
GstSrcPadProbeBlockCb_, nullptr, nullptr);
pipeline_->SetProperty(Elements::kFakeSinkAudio, "async", FALSE);
- FlushAudioDownStream_(element);
+ FlushDownStream_(element, kPadProbeAudioIdle, FALSE);
pipeline_->BinRemove(Elements::kBinAudio, Elements::kFakeSinkAudio);
auto caps = caps_builder_.Build(track, internal::IsDrmEmeElementNecessary(
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
GstSrcPadProbeBlockCb_, nullptr, nullptr);
pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
- FlushAudioDownStream_(element);
+ FlushDownStream_(element, kPadProbeAudioIdle, FALSE);
pipeline_->BinRemove(Elements::kBinAudio, Elements::kDecAudio,
Elements::kSinkAudio);
std::string sink_name("fakesink");