def _setThumbnail(self, time, pixbuf): # Q: Is "time" guaranteed to be nanosecond precise? # A: Not always. # => __tim says: "that's how it should be" # => also see gst-plugins-good/tests/icles/gdkpixbufsink-test # => Daniel: It is *not* nanosecond precise when we remove the videorate # element from the pipeline # => thiblahute: not the case with mpegts original_time = time if time in self.thumbs: thumb = self.thumbs[time] else: sorted_times = sorted(self.thumbs.keys()) index = binary_search(sorted_times, time) time = sorted_times[index] thumb = self.thumbs[time] if thumb.has_pixel_data: # If this happens, it means the precision of the thumbnail # generator is not good enough for the current thumbnail # interval. # We could consider shifting the thumbnails, but seems like # too much trouble for something which does not happen in # practice. My last words.. self.fixme("Thumbnail is already set for time: %s, %s", format_ns(time), format_ns(original_time)) return thumb.set_from_gdkpixbuf_animated(pixbuf) if time in self.queue: self.queue.remove(time) self.thumb_cache[time] = pixbuf
def _seekTimeoutCb(self, relative=False): self.pending_seek_id = None if relative: try: self.emit('seek-relative', self._time) except PipelineError: self.error("Error while seeking %s relative", self._time) # if an exception happened while seeking, properly # reset ourselves return False self._time = None elif self.position is not None: position = max(0, self.position) self.position = None try: self.emit('seek', position) except PipelineError as e: self.error("Error while seeking to position: %s, reason: %s", format_ns(position), e) # if an exception happened while seeking, properly # reset ourselves return False if self.pending_position: self.seek(self.pending_position, on_idle=True) self.pending_position = None return False
def getPosition(self, blocks=False): """ Get the current position of the L{Pipeline}. @return: The current position or Gst.CLOCK_TIME_NONE @rtype: L{long} @raise PipelineError: If the position couldn't be obtained. """ maincontext = GLib.main_context_default() if blocks and self._recovery_state == self.RecoveryState.NOT_RECOVERING: while self._waiting_for_async_done and self._recovery_state == self.RecoveryState.NOT_RECOVERING: self.info("Iterating mainloop waiting for the pipeline to be ready to be queried") maincontext.iteration(True) try: res, cur = self._pipeline.query_position(Gst.Format.TIME) except Exception as e: self.handleException(e) raise PipelineError("Couldn't get position") if not res: raise PipelineError("Position not available") self.log("Got position %s", format_ns(cur)) return cur
def simple_seek(self, position): """ Seeks in the L{Pipeline} to the given position. @param position: Position to seek to @type position: L{long} @raise PipelineError: If seek failed """ if self._waiting_for_async_done is True: self._next_seek = position self.info("Setting next seek to %s", self._next_seek) return self.debug("position: %s", format_ns(position)) # clamp between [0, duration] position = max(0, min(position, self.getDuration())) res = self._pipeline.seek(1.0, Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE, Gst.SeekType.SET, position, Gst.SeekType.NONE, -1) self._addWaitingForAsyncDoneTimeout() if not res: raise PipelineError(self.get_name() + " seek failed: " + str(position)) self._last_position = position self.debug("seeking successful") self.emit('position', position)
def simple_seek(self, position): """Seeks in the low-level pipeline to the specified position. Args: position (int): Position to seek to. Raises: PipelineError: When the seek fails. """ if self._waiting_for_async_done is True: self._next_seek = position self.info("Setting next seek to %s", self._next_seek) return self.debug("position: %s", format_ns(position)) # clamp between [0, duration] position = max(0, min(position, self.getDuration())) res = self._pipeline.seek(1.0, Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE, Gst.SeekType.SET, position, Gst.SeekType.NONE, -1) if not res: raise PipelineError(self.get_name() + " seek failed: " + str(position)) self._addWaitingForAsyncDoneTimeout() self._last_position = position self.debug("seeking successful") self.emit('position', position)
def getPosition(self, fails=True): """Gets the current position of the low-level pipeline. Returns: int: The current position or Gst.CLOCK_TIME_NONE. Raises: PipelineError: If the position couldn't be obtained. """ try: res, cur = self._pipeline.query_position(Gst.Format.TIME) except Exception as e: self.handleException(e) raise PipelineError("Couldn't get position") if res: self._last_position = cur else: if fails: raise PipelineError("Position not available") cur = self._last_position self.log("Got position %s", format_ns(cur)) return cur
def simple_seek(self, position): """ Seeks in the L{Pipeline} to the given position. @param position: Position to seek to @type position: L{long} @raise PipelineError: If seek failed """ if self._waiting_for_async_done is True: self._next_seek = position self.info("Setting next seek to %s", self._next_seek) return self.debug("position: %s", format_ns(position)) # clamp between [0, duration] position = max(0, min(position, self.getDuration()) - 1) res = self._pipeline.seek(1.0, Gst.Format.TIME, Gst.SeekFlags.FLUSH, Gst.SeekType.SET, position, Gst.SeekType.NONE, -1) self._addWaitingForAsyncDoneTimeout() if not res: raise PipelineError(self.get_name() + " seek failed: " + str(position)) self._last_position = position self.debug("seeking successful") self.emit('position', position)
def simple_seek(self, position): """Seeks in the low-level pipeline to the specified position. Args: position (int): Position to seek to. Raises: PipelineError: When the seek fails. """ if self._busy_async or self.getState() < Gst.State.PAUSED: self._next_seek = position self.info("Setting next seek to %s", self._next_seek) return self._next_seek = None # clamp between [0, duration] position = max(0, min(position, self.getDuration())) self.debug("Seeking to position: %s", format_ns(position)) res = self._pipeline.seek(1.0, Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE, Gst.SeekType.SET, position, Gst.SeekType.NONE, -1) if not res: raise PipelineError(self.get_name() + " seek failed: " + str(position)) self._addWaitingForAsyncDoneTimeout() self.emit('position', position)
def clipTrimPreview(self, tl_obj, position): """ While a clip is being trimmed, show a live preview of it. """ if isinstance(tl_obj, GES.TitleClip) or tl_obj.props.is_image or not hasattr( tl_obj, "get_uri"): self.log("%s is an image or has no URI, so not previewing trim" % tl_obj) return False clip_uri = tl_obj.props.uri cur_time = time() if self.pipeline == self.app.project_manager.current_project.pipeline: self.debug("Creating temporary pipeline for clip %s, position %s", clip_uri, format_ns(position)) self._oldTimelinePos = self.pipeline.getPosition() self.setPipeline(AssetPipeline(tl_obj)) self._lastClipTrimTime = cur_time if (cur_time - self._lastClipTrimTime ) > 0.2 and self.pipeline.getState() == Gst.State.PAUSED: # Do not seek more than once every 200 ms (for performance) self.pipeline.simple_seek(position) self._lastClipTrimTime = cur_time
def getDuration(self): """Gets the duration of the low-level pipeline.""" dur = self._getDuration() self.log("Got duration %s", format_ns(dur)) if self._duration != dur: self.emit("duration-changed", dur) self._duration = dur return dur
def getDuration(self, format=Gst.Format.TIME): """ Get the duration of the C{Pipeline}. """ self.log("format %r", format) dur = self._getDuration(format) self.log("Got duration %s", format_ns(dur)) if self._duration != dur: self.emit("duration-changed", dur) self._duration = dur return dur
def getPosition(self): """ Get the current position of the L{Pipeline}. @return: The current position or Gst.CLOCK_TIME_NONE @rtype: L{long} @raise PipelineError: If the position couldn't be obtained. """ try: res, cur = self._pipeline.query_position(Gst.Format.TIME) except Exception as e: self.handleException(e) raise PipelineError("Couldn't get position") if not res: raise PipelineError("Position not available") self.log("Got position %s", format_ns(cur)) return cur
def simple_seek(self, position, format=Gst.Format.TIME): """ Seeks in the L{Pipeline} to the given position. @param position: Position to seek to @type position: L{long} @param format: The C{Format} of the seek position @type format: C{Gst.Format} @raise PipelineError: If seek failed """ if self._waiting_for_async_done is True: self._next_seek = (position, format) self.info("Setting next seek to %s", self._next_seek) return if format == Gst.Format.TIME: self.debug("position: %s", format_ns(position)) else: self.debug("position: %d, format: %d", position, format) # clamp between [0, duration] if format == Gst.Format.TIME: position = max(0, min(position, self.getDuration()) - 1) res = self._pipeline.seek(1.0, format, Gst.SeekFlags.FLUSH, Gst.SeekType.SET, position, Gst.SeekType.NONE, -1) self._waiting_for_async_done = True if self._timeout_async_id: GLib.source_remove(self._timeout_async_id) self._timeout_async_id = 0 self._timeout_async_id = GLib.timeout_add(1000, self._resetWaitingForAsyncDone) if not res: self.debug("seeking failed") raise PipelineError("seek failed") self.lastPosition = position self.debug("seeking successful") self.emit('position', position)
def simple_seek(self, position): if self.props.timeline.is_empty(): # Nowhere to seek. return if self._rendering(): raise PipelineError("Trying to seek while rendering") st = Gst.Structure.new_empty("seek") if self.getState() == Gst.State.PLAYING: st.set_value("playback_time", float( self.getPosition()) / Gst.SECOND) st.set_value("start", float(position / Gst.SECOND)) st.set_value("flags", "accurate+flush") self.app.write_action(st) try: SimplePipeline.simple_seek(self, position) except PipelineError as e: self.error("Error while seeking to position: %s, reason: %s", format_ns(position), e)
def clipTrimPreview(self, tl_obj, position): """ While a clip is being trimmed, show a live preview of it. """ if isinstance(tl_obj, GES.TitleClip) or tl_obj.props.is_image or not hasattr(tl_obj, "get_uri"): self.log("%s is an image or has no URI, so not previewing trim" % tl_obj) return False clip_uri = tl_obj.props.uri cur_time = time() if self.pipeline == self.app.current_project.pipeline: self.debug("Creating temporary pipeline for clip %s, position %s", clip_uri, format_ns(position)) self._oldTimelinePos = self.pipeline.getPosition() self.setPipeline(AssetPipeline(tl_obj)) self._lastClipTrimTime = cur_time if (cur_time - self._lastClipTrimTime) > 0.2 and self.pipeline.getState() == Gst.State.PAUSED: # Do not seek more than once every 200 ms (for performance) self.pipeline.simple_seek(position) self._lastClipTrimTime = cur_time
def simple_seek(self, position): if self._timeline.is_empty(): # Nowhere to seek. return if self._rendering(): raise PipelineError("Trying to seek while rendering") st = Gst.Structure.new_empty("seek") if self.getState() == Gst.State.PLAYING: st.set_value("playback_time", float( self.getPosition()) / Gst.SECOND) st.set_value("start", float(position / Gst.SECOND)) st.set_value("flags", "accurate+flush") self.app.write_action(st) try: SimplePipeline.simple_seek(self, position) except PipelineError as e: self.error("Error while seeking to position: %s, reason: %s", format_ns(position), e)
def clipTrimPreview(self, clip, position): """Shows a live preview of a clip being trimmed.""" if not hasattr(clip, "get_uri") or isinstance(clip, GES.TitleClip) or clip.props.is_image: self.log( "%s is an image or has no URI, so not previewing trim" % clip) return False clip_uri = clip.props.uri cur_time = time() if self.pipeline == self.app.project_manager.current_project.pipeline: self.debug("Creating temporary pipeline for clip %s, position %s", clip_uri, format_ns(position)) self._oldTimelinePos = self.pipeline.getPosition(False) self.pipeline.set_state(Gst.State.NULL) self.setPipeline(AssetPipeline(clip)) self.__owning_pipeline = True self._lastClipTrimTime = cur_time if (cur_time - self._lastClipTrimTime) > 0.2 and self.pipeline.getState() == Gst.State.PAUSED: # Do not seek more than once every 200 ms (for performance) self.pipeline.simple_seek(position) self._lastClipTrimTime = cur_time