def _on_warning(self, _bus, message): assert message.type == Gst.MessageType.WARNING if self.sink_pipeline is not None: Gst.debug_bin_to_dot_file_with_ts( self.sink_pipeline, Gst.DebugGraphDetails.ALL, "WARNING") err, dbg = message.parse_warning() warn("%s: %s\n%s\n" % (err, err.message, dbg))
def restart_source(self, *_args): warn("Attempting to recover from video loss: " "Stopping source pipeline and waiting 5s...") self.source_pipeline.set_state(Gst.State.NULL) self.source_pipeline = None GObjectTimeout(5, self.start_source).start() return False # stop the timeout from running again
def restart_source(self, *_args): warn("Attempting to recover from video loss: " "Stopping source pipeline and waiting 5s...") self.source_pipeline.set_state(Gst.State.NULL) self.source_pipeline = None GObjectTimeout(5, self.start_source).start() return False # stop the timeout from running again
def start_source(self): if self.tearing_down: return False warn("Restarting source pipeline...") self.create_source_pipeline() self.set_source_pipeline_playing() warn("Restarted source pipeline") return False # stop the timeout from running again
def start_source(self): if self.tearing_down: return False warn("Restarting source pipeline...") self.create_source_pipeline() self.set_source_pipeline_playing() warn("Restarted source pipeline") if self.restart_source_enabled: self.underrun_timeout.start() return False # stop the timeout from running again
def _push_sample(self, sample): # Calculate whether we need to draw any annotations on the output video. now = sample.time annotations = [] with self.annotations_lock: # Remove expired annotations self.text_annotations = [x for x in self.text_annotations if now < x.end_time] current_texts = [x for x in self.text_annotations if x.time <= now] for annotation in list(self.annotations): if annotation.time == now: annotations.append(annotation) if now >= annotation.time: self.annotations.remove(annotation) sample = gst_sample_make_writable(sample) img = array_from_sample(sample, readwrite=True) # Text: _draw_text( img, datetime.datetime.fromtimestamp(now).strftime("%H:%M:%S.%f")[:-4], (10, 30), (255, 255, 255)) for i, x in enumerate(reversed(current_texts)): origin = (10, (i + 2) * 30) age = float(now - x.time) / 3 color = (native(int(255 * max([1 - age, 0.5]))).__int__(),) * 3 _draw_text(img, x.text, origin, color) # Regions: for annotation in annotations: _draw_annotation(img, annotation) APPSRC_LIMIT_BYTES = 100 * 1024 * 1024 # 100MB if self.appsrc.props.current_level_bytes > APPSRC_LIMIT_BYTES: # appsrc is backed-up, perhaps something's gone wrong. We don't # want to use up all RAM, so let's drop the buffer on the floor. if not self._appsrc_was_full: warn("sink pipeline appsrc is full, dropping buffers from now " "on") self._appsrc_was_full = True return elif self._appsrc_was_full: debug("sink pipeline appsrc no longer full, pushing buffers again") self._appsrc_was_full = False self.appsrc.props.caps = sample.get_caps() self.appsrc.emit("push-buffer", sample.get_buffer()) self._sample_count += 1
def on_new_sample(self, appsink): sample = appsink.emit("pull-sample") running_time = sample.get_segment().to_running_time( Gst.Format.TIME, sample.get_buffer().pts) sample.time = float(appsink.base_time + running_time) / 1e9 if (sample.time > self.init_time + 31536000 or sample.time < self.init_time - 31536000): # 1 year warn("Received frame with suspicious timestamp: %f. Check your " "source-pipeline configuration." % sample.time) frame = array_from_sample(sample) frame.flags.writeable = False # See also: logging.draw_on frame._draw_sink = weakref.ref(self._sink_pipeline) # pylint: disable=protected-access self.tell_user_thread(frame) self._sink_pipeline.on_sample(sample) return Gst.FlowReturn.OK
def on_new_sample(self, appsink): sample = appsink.emit("pull-sample") running_time = sample.get_segment().to_running_time( Gst.Format.TIME, sample.get_buffer().pts) sample.time = ( float(appsink.base_time + running_time) / 1e9) if (sample.time > self.init_time + 31536000 or sample.time < self.init_time - 31536000): # 1 year warn("Received frame with suspicious timestamp: %f. Check your " "source-pipeline configuration." % sample.time) frame = array_from_sample(sample) frame.flags.writeable = False # See also: logging.draw_on frame._draw_sink = weakref.ref(self._sink_pipeline) # pylint: disable=protected-access self.tell_user_thread(frame) self._sink_pipeline.on_sample(sample) return Gst.FlowReturn.OK
def on_warning(self, _bus, message): assert message.type == Gst.MessageType.WARNING Gst.debug_bin_to_dot_file_with_ts( self.source_pipeline, Gst.DebugGraphDetails.ALL, "WARNING") err, dbg = message.parse_warning() warn("%s: %s\n%s\n" % (err, err.message, dbg))
def on_eos_from_source_pipeline(self, _bus, _message): if not self.tearing_down: warn("Got EOS from source pipeline") self.restart_source()
def on_eos_from_source_pipeline(self, _bus, _message): if not self.tearing_down: warn("Got EOS from source pipeline") self.restart_source()
def new_device_under_test_from_config(parsed_args=None, transformation_pipeline=None): """ `parsed_args` if present should come from calling argparser().parse_args(). """ from _stbt.control import uri_to_control if parsed_args is None: args = argparser().parse_args([]) else: args = parsed_args if args.source_pipeline is None: args.source_pipeline = get_config('global', 'source_pipeline') if args.sink_pipeline is None: args.sink_pipeline = get_config('global', 'sink_pipeline') if args.control is None: args.control = get_config('global', 'control') if args.save_video is None: args.save_video = False if args.restart_source is None: args.restart_source = get_config('global', 'restart_source', type_=bool) if transformation_pipeline is None: transformation_pipeline = get_config('global', 'transformation_pipeline') source_teardown_eos = get_config('global', 'source_teardown_eos', type_=bool) use_old_threading_behaviour = get_config('global', 'use_old_threading_behaviour', type_=bool) if use_old_threading_behaviour: warn( dedent("""\ global.use_old_threading_behaviour is enabled. This is intended as a stop-gap measure to allow upgrading to stb-tester v28. We recommend porting functions that depend on stbt.get_frame() returning consecutive frames on each call to use stbt.frames() instead. This should make your functions usable from multiple threads. If porting to stbt.frames is not suitable please let us know on https://github.com/stb-tester/stb-tester/pull/449 otherwise this configuration option will be removed in a future release of stb-tester. """)) display = [None] def raise_in_user_thread(exception): display[0].tell_user_thread(exception) mainloop = _mainloop() if not args.sink_pipeline and not args.save_video: sink_pipeline = NoSinkPipeline() else: sink_pipeline = SinkPipeline( # pylint: disable=redefined-variable-type args.sink_pipeline, raise_in_user_thread, args.save_video) display[0] = Display(args.source_pipeline, sink_pipeline, args.restart_source, transformation_pipeline, source_teardown_eos) return DeviceUnderTest( display=display[0], control=uri_to_control(args.control, display[0]), sink_pipeline=sink_pipeline, mainloop=mainloop, use_old_threading_behaviour=use_old_threading_behaviour)