def _setScenarioFile(self, uri): if 'PITIVI_SCENARIO_FILE' in os.environ: uri = quote_uri(os.environ['PITIVI_SCENARIO_FILE']) else: cache_dir = get_dir(os.path.join(xdg_cache_home(), "scenarios")) scenario_name = str(time.strftime("%Y%m%d-%H%M%S")) project_path = None if uri: project_path = path_from_uri(uri) scenario_name += os.path.splitext( project_path.replace(os.sep, "_"))[0] uri = os.path.join(cache_dir, scenario_name + ".scenario") uri = quote_uri(uri) self._scenario_file = open(path_from_uri(uri), "w") if project_path: f = open(project_path) content = f.read() if not uri.endswith(".scenario"): self.write_action( "load-project", {"serialized-content": "%s" % content.replace("\n", "")}) f.close()
def _set_scenario_file(self, uri): if uri: project_path = path_from_uri(uri) else: # New project. project_path = None if 'PITIVI_SCENARIO_FILE' in os.environ: scenario_path = os.environ['PITIVI_SCENARIO_FILE'] else: cache_dir = xdg_cache_home("scenarios") scenario_name = str(time.strftime("%Y%m%d-%H%M%S")) if project_path: scenario_name += os.path.splitext( project_path.replace(os.sep, "_"))[0] scenario_path = os.path.join(cache_dir, scenario_name + ".scenario") scenario_path = path_from_uri(quote_uri(scenario_path)) self._scenario_file = open(scenario_path, "w") if project_path and not project_path.endswith(".scenario"): # It's an xges file probably. with open(project_path) as project: content = project.read().replace("\n", "") self.write_action("load-project", serialized_content=content)
def addUris(self, uris): """ Add c{uris} to the source list. The uris will be analyzed before being added. """ self.emit("starting") self.debug("Adding %s", uris) self.nb_files_to_import += len(uris) for uri in uris: # Ensure we have a correctly encoded URI according to RFC 2396. # Otherwise, in some cases we'd get rogue characters that break # searching for duplicates uri = quote_uri(uri) if uri not in self._sources: self.discoverer.discover_uri_async(uri) self.debug("Added a uri to discoverer async") else: self.nb_files_to_import -= 1 self.debug('"%s" is already in the media library' % uri) if self.nb_files_to_import == 0: # This is a cornercase hack for when you try to import a bunch of # clips that are all present in the media library already. # This will allow the progressbar to hide. self.emit("nothing-to-import") else: self.debug("Done adding all URIs to discoverer async")
def __init__(self, bElement, timeline): Clutter.Actor.__init__(self) PreviewGenerator.__init__(self, GES.TrackType.AUDIO) Zoomable.__init__(self) Loggable.__init__(self) self.pipeline = None self.discovered = False self.bElement = bElement self._uri = quote_uri(bElement.props.uri) # Guard against malformed URIs self.timeline = timeline self.actors = [] self.set_content_scaling_filters(Clutter.ScalingFilter.NEAREST, Clutter.ScalingFilter.NEAREST) self.canvas = Clutter.Canvas() self.set_content(self.canvas) self.width = 0 self._num_failures = 0 self.lastUpdate = None self.current_geometry = (-1, -1) self.adapter = None self.surface = None self.timeline.connect("scrolled", self._scrolledCb) self.canvas.connect("draw", self._drawContentCb) self.canvas.invalidate() self._callback_id = 0
def __init__(self, bElement): super(AudioPreviewer, self).__init__() PreviewGenerator.__init__(self, GES.TrackType.AUDIO) Zoomable.__init__(self) Loggable.__init__(self) self.pipeline = None self.discovered = False self.bElement = bElement self.timeline = bElement.get_parent().get_timeline().ui self.nSamples = self.bElement.get_parent().get_asset().get_duration() / 10000000 self._start = 0 self._end = 0 self._surface_x = 0 # Guard against malformed URIs self._uri = quote_uri(bElement.props.uri) self._num_failures = 0 self.adapter = None self.surface = None self._force_redraw = True self.bElement.connect("notify::in-point", self._inpointChangedCb)
def __init__(self, ges_elem, max_cpu_usage): Previewer.__init__(self, GES.TrackType.AUDIO, max_cpu_usage) Zoomable.__init__(self) Loggable.__init__(self) self.pipeline = None self._wavebin = None self.discovered = False self.ges_elem = ges_elem asset = self.ges_elem.get_parent().get_asset() self.n_samples = asset.get_duration() / SAMPLE_DURATION self.samples = None self.peaks = None self._start = 0 self._end = 0 self._surface_x = 0 # Guard against malformed URIs self.wavefile = None self._uri = quote_uri(get_proxy_target(ges_elem).props.id) self._num_failures = 0 self.adapter = None self.surface = None self._force_redraw = True self.ges_elem.connect("notify::in-point", self._inpoint_changed_cb) self.connect("notify::height-request", self._height_changed_cb) self.become_controlled()
def __init__(self, ges_elem): Previewer.__init__(self, GES.TrackType.AUDIO) Zoomable.__init__(self) Loggable.__init__(self) self.pipeline = None self._wavebin = None self.discovered = False self.ges_elem = ges_elem self.timeline = ges_elem.get_parent().get_timeline().ui asset = self.ges_elem.get_parent().get_asset() self.n_samples = asset.get_duration() / SAMPLE_DURATION self.samples = None self.peaks = None self._start = 0 self._end = 0 self._surface_x = 0 # Guard against malformed URIs self.wavefile = None self._uri = quote_uri(get_proxy_target(ges_elem).props.id) self._num_failures = 0 self.adapter = None self.surface = None self._force_redraw = True self.ges_elem.connect("notify::in-point", self._inpointChangedCb)
def __init__(self, bElement, timeline): Clutter.Actor.__init__(self) Zoomable.__init__(self) Loggable.__init__(self) PreviewGenerator.__init__(self, GES.TrackType.AUDIO) self.pipeline = None self.discovered = False self.bElement = bElement self._uri = quote_uri(bElement.props.uri) # Guard against malformed URIs self.timeline = timeline self.actors = [] self.set_content_scaling_filters(Clutter.ScalingFilter.NEAREST, Clutter.ScalingFilter.NEAREST) self.canvas = Clutter.Canvas() self.set_content(self.canvas) self.width = 0 self._num_failures = 0 self.lastUpdate = datetime.now() self.interval = timedelta(microseconds=INTERVAL) self.current_geometry = (-1, -1) self.adapter = None self.surface = None self.timeline.connect("scrolled", self._scrolledCb) self.canvas.connect("draw", self._drawContentCb) self.canvas.invalidate() self._callback_id = 0
def __init__(self, ges_elem, max_cpu_usage): Previewer.__init__(self, GES.TrackType.AUDIO, max_cpu_usage) Zoomable.__init__(self) Loggable.__init__(self) self.pipeline = None self._wavebin = None self.ges_elem = ges_elem self.samples = None self.peaks = None self.surface = None # The zoom level when self.surface has been created. self._surface_zoom_level = 0 # The samples range used when self.surface has been created. self._surface_start_ns = 0 self._surface_end_ns = 0 # Guard against malformed URIs self.wavefile = None self._uri = quote_uri(get_proxy_target(ges_elem).props.id) self._num_failures = 0 self.become_controlled()
def __init__(self, ges_elem, max_cpu_usage): Previewer.__init__(self, GES.TrackType.AUDIO, max_cpu_usage) Zoomable.__init__(self) Loggable.__init__(self) self.pipeline = None self._wavebin = None self.discovered = False self.ges_elem = ges_elem self.timeline = ges_elem.get_parent().get_timeline().ui asset = self.ges_elem.get_parent().get_asset() self.n_samples = asset.get_duration() / SAMPLE_DURATION self.samples = None self.peaks = None self._start = 0 self._end = 0 self._surface_x = 0 # Guard against malformed URIs self.wavefile = None self._uri = quote_uri(get_proxy_target(ges_elem).props.id) self._num_failures = 0 self.adapter = None self.surface = None self._force_redraw = True self.ges_elem.connect("notify::in-point", self._inpoint_changed_cb) self.connect("notify::height-request", self._height_changed_cb) self.becomeControlled()
def saveProject(self, project, uri=None, overwrite=False, formatter=None, backup=False): """ Save the L{Project} to the given location. If specified, use the given formatter. @type project: L{Project} @param project: The L{Project} to save. @type uri: L{str} @param uri: The absolute URI of the location to store the project to. @param overwrite: Whether to overwrite existing location. @type overwrite: C{bool} @type formatter: L{Formatter} @param formatter: The L{Formatter} to use to store the project if specified. If it is not specified, then it will be saved at its original format. @param backup: Whether the requested save operation is for a backup @type backup: C{bool} @see: L{Formatter.saveProject} """ if formatter is None: formatter = ges.PitiviFormatter() if backup: if project.uri and self.current.uri is not None: # Ignore whatever URI that is passed on to us. It's a trap. uri = self._makeBackupURI(project.uri) else: # Do not try to save backup files for blank projects. # It is possible that self.current.uri == None when the backup # timer sent us an old instance of the (now closed) project. return elif uri is None: # This allows calling saveProject without specifying the target URI uri = project.uri else: # Ensure the URI we are given is properly encoded, or GIO will fail uri = quote_uri(uri) # Update the project instance's uri for the "Save as" scenario. # Otherwise, subsequent saves will be to the old uri. if not backup: project.uri = uri if uri is None or not ges.formatter_can_save_uri(uri): self.emit("save-project-failed", project, uri) return # FIXME Using query_exist is not the best thing to do, but makes # the trick for now file = gio.File(uri) if overwrite or not file.query_exist(): formatter.set_sources(project.medialibrary.getSources()) saved = formatter.save_to_uri(project.timeline, uri) if saved: if not backup: # Do not emit the signal when autosaving a backup file self.emit("project-saved", project, uri) self.debug('Saved project "%s"' % uri) else: self.debug('Saved backup "%s"' % uri) return saved
def openCb(self, unused_app, giofiles, unused_count, unused_hint): assert giofiles self.createMainWindow() if len(giofiles) > 1: self.warning("Can open only one project file at a time. Ignoring the rest!") project_file = giofiles[0] self.project_manager.loadProject(quote_uri(project_file.get_uri())) return True
def _addAsset(self, asset): # 128 is the normal size for thumbnails, but for *icons* it looks insane LARGE_SIZE = 96 info = asset.get_info() # The code below tries to read existing thumbnails from the freedesktop # thumbnails directory (~/.thumbnails). The filenames are simply # the file URI hashed with md5, so we can retrieve them easily. video_streams = [i for i in info.get_stream_list() if isinstance(i, DiscovererVideoInfo)] if len(video_streams) > 0: # From the freedesktop spec: "if the environment variable # $XDG_CACHE_HOME is set and not blank then the directory # $XDG_CACHE_HOME/thumbnails will be used, otherwise # $HOME/.cache/thumbnails will be used." # Older version of the spec also mentioned $HOME/.thumbnails quoted_uri = quote_uri(info.get_uri()) thumbnail_hash = md5(quoted_uri).hexdigest() try: thumb_dir = os.environ['XDG_CACHE_HOME'] thumb_64, thumb_128 = self._getThumbnailInDir(thumb_dir, thumbnail_hash) except KeyError: thumb_64, thumb_128 = (None, None) if thumb_64 is None: thumb_dir = os.path.expanduser("~/.cache/thumbnails/") thumb_64, thumb_128 = self._getThumbnailInDir(thumb_dir, thumbnail_hash) if thumb_64 is None: thumb_dir = os.path.expanduser("~/.thumbnails/") thumb_64, thumb_128 = self._getThumbnailInDir(thumb_dir, thumbnail_hash) if thumb_64 is None: if asset.is_image(): thumb_64 = self._getIcon("image-x-generic") thumb_128 = self._getIcon("image-x-generic", None, LARGE_SIZE) else: thumb_64 = self._getIcon("video-x-generic") thumb_128 = self._getIcon("video-x-generic", None, LARGE_SIZE) # TODO ideally gst discoverer should create missing thumbnails. self.log("Missing a thumbnail for %s, queuing", path_from_uri(quoted_uri)) self._missing_thumbs.append(quoted_uri) else: thumb_64 = self._getIcon("audio-x-generic") thumb_128 = self._getIcon("audio-x-generic", None, LARGE_SIZE) if info.get_duration() == Gst.CLOCK_TIME_NONE: duration = '' else: duration = beautify_length(info.get_duration()) name = info_name(info) self.pending_rows.append((thumb_64, thumb_128, beautify_info(info), asset, info.get_uri(), duration, name)) if len(self.pending_rows) > 50: self.flush_pending_rows()
def do_open(self, giofiles, unused_count, unused_hint): assert giofiles self.create_main_window() if len(giofiles) > 1: self.warning( "Opening only one project at a time. Ignoring the rest!") project_file = giofiles[0] self.project_manager.load_project(quote_uri(project_file.get_uri())) return True
def openCb(self, unused_app, giofiles, unused_count, unused_hint): assert giofiles self.createMainWindow() if len(giofiles) > 1: self.warning( "Can open only one project file at a time. Ignoring the rest!") project_file = giofiles[0] self.project_manager.loadProject(quote_uri(project_file.get_uri())) return True
def _sourceIsUsed(self, uri): """Check if a given URI is present in the timeline""" layers = self.app.current.timeline.get_layers() for layer in layers: for tlobj in layer.get_objects(): tlobj_uri = quote_uri(tlobj.get_uri()) if tlobj_uri == uri: return True return False
def _projectLoadedCb(self, formatter, timeline): self.debug("Project Loaded") for uri in self.formatter.get_sources(): self._medialib_awaiting_discovery.append(quote_uri(uri)) self.current.medialibrary.addUris(self._medialib_awaiting_discovery) if self._medialib_awaiting_discovery: self.current.medialibrary.connect("source-added", self._sourceAddedCb) else: self.emit("new-project-loaded", self.current) self.time_loaded = time()
def getInfoFromUri(self, uri): """ Get the source corresponding to C{uri}. """ # Make sure the URI is properly quoted, as other modules calling this # method do not necessarily provide URIs encoded in the same way. uri = quote_uri(uri) info = self._sources.get(uri) if info is None: raise MediaLibraryError("URI not in the medialibrary", uri) return info
def __init__(self, media_filenames, add_to_timeline=False, debug=False): GuiPitivi.__init__(self, debug) # load the passed filenames, optionally adding them to the timeline # (useful during development) self.projectManager.newBlankProject(emission=False) uris = [quote_uri(os.path.abspath(media_filename)) for media_filename in media_filenames] lib = self.current_project.medialibrary lib.connect("source-added", self._sourceAddedCb, uris, add_to_timeline) lib.connect("discovery-error", self._discoveryErrorCb, uris) lib.addUris(uris)
def _setScenarioFile(self, uri): if 'PITIVI_SCENARIO_FILE' in os.environ: uri = quote_uri(os.environ['PITIVI_SCENARIO_FILE']) else: cache_dir = get_dir(os.path.join(xdg_cache_home(), "scenarios")) scenario_name = str(time.strftime("%Y%m%d-%H%M%S")) project_path = None if uri: project_path = path_from_uri(uri) scenario_name += os.path.splitext(project_path.replace(os.sep, "_"))[0] uri = os.path.join(cache_dir, scenario_name + ".scenario") uri = quote_uri(uri) self._scenario_file = open(path_from_uri(uri), "w") if project_path: f = open(project_path) content = f.read() self.write_action("load-project", {"serialized-content": "%s" % content.replace("\n", "")}) f.close()
def _addAsset(self, asset): info = asset.get_info() # The code below tries to read existing thumbnails from the freedesktop # thumbnails directory (~/.thumbnails). The filenames are simply # the file URI hashed with md5, so we can retrieve them easily. video_streams = [i for i in info.get_stream_list() if isinstance(i, DiscovererVideoInfo)] if len(video_streams) > 0: # From the freedesktop spec: "if the environment variable # $XDG_CACHE_HOME is set and not blank then the directory # $XDG_CACHE_HOME/thumbnails will be used, otherwise # $HOME/.cache/thumbnails will be used." # Older version of the spec also mentioned $HOME/.thumbnails thumbnail_hash = md5(quote_uri(info.get_uri())).hexdigest() try: thumb_dir = os.environ['XDG_CACHE_HOME'] thumbnail, thumbnail_large = self._getThumbnailInDir(thumb_dir, thumbnail_hash) except KeyError: thumbnail, thumbnail_large = (None, None) if thumbnail is None: thumb_dir = os.path.expanduser("~/.cache/thumbnails/") thumbnail, thumbnail_large = self._getThumbnailInDir(thumb_dir, thumbnail_hash) if thumbnail is None: thumb_dir = os.path.expanduser("~/.thumbnails/") thumbnail, thumbnail_large = self._getThumbnailInDir(thumb_dir, thumbnail_hash) if thumbnail is None: thumbnail = self.videofilepixbuf # TODO gst discoverer should create missing thumbnails. thumbnail_large = thumbnail else: thumbnail = self.audiofilepixbuf thumbnail_large = self.audiofilepixbuf if info.get_duration() == Gst.CLOCK_TIME_NONE: duration = '' else: duration = beautify_length(info.get_duration()) name = info_name(info) self.pending_rows.append((thumbnail, thumbnail_large, beautify_info(info), asset, info.get_uri(), duration, name)) if len(self.pending_rows) > 50: self.flush_pending_rows()
def __init__(self, ges_elem, max_cpu_usage): Previewer.__init__(self, GES.TrackType.VIDEO, max_cpu_usage) Zoomable.__init__(self) Loggable.__init__(self) # Variables related to the timeline objects self.timeline = ges_elem.get_parent().get_timeline().ui self.ges_elem = ges_elem # Guard against malformed URIs self.uri = quote_uri(get_proxy_target(ges_elem).props.id) self.__preroll_timeout_id = 0 # Variables related to thumbnailing self.wishlist = [] self.queue = [] self._thumb_cb_id = None self._running = False # We should have one thumbnail per thumb_period. # TODO: get this from the user settings self.thumb_period = int(0.5 * Gst.SECOND) self.thumb_height = THUMB_HEIGHT self.__image_pixbuf = None if isinstance(ges_elem, GES.ImageSource): self.__image_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( Gst.uri_get_location(self.uri), -1, self.thumb_height, True) self.thumbs = {} self.thumb_cache = ThumbnailCache.get(self.uri) self._ensure_proxy_thumbnails_cache() self.thumb_width, unused_height = self.thumb_cache.getImagesSize() self.cpu_usage_tracker = CPUUsageTracker() self.interval = 500 # Every 0.5 second, reevaluate the situation # Connect signals and fire things up self.ges_elem.connect("notify::in-point", self._inpoint_changed_cb) self.pipeline = None self.gdkpixbufsink = None self.becomeControlled() self.connect("notify::height-request", self._height_changed_cb)
def __init__(self, bElement, timeline): """ @param bElement : the backend GES.TrackElement @param track : the track to which the bElement belongs @param timeline : the containing graphic timeline. """ Zoomable.__init__(self) Clutter.ScrollActor.__init__(self) Loggable.__init__(self) PreviewGenerator.__init__(self, GES.TrackType.VIDEO) # Variables related to the timeline objects self.timeline = timeline self.bElement = bElement self.uri = quote_uri(bElement.props.uri) # Guard against malformed URIs self.duration = bElement.props.duration # Variables related to thumbnailing self.wishlist = [] self._callback_id = None self._thumb_cb_id = None self._allAnimated = False self._running = False # We should have one thumbnail per thumb_period. # TODO: get this from the user settings self.thumb_period = long(0.5 * Gst.SECOND) self.thumb_margin = BORDER_WIDTH self.thumb_height = EXPANDED_SIZE - 2 * self.thumb_margin self.thumb_width = None # will be set by self._setupPipeline() # Maps (quantized) times to Thumbnail objects self.thumbs = {} self.thumb_cache = get_cache_for_uri(self.uri) self.cpu_usage_tracker = CPUUsageTracker() self.interval = 500 # Every 0.5 second, reevaluate the situation # Connect signals and fire things up self.timeline.connect("scrolled", self._scrollCb) self.bElement.connect("notify::duration", self._durationChangedCb) self.bElement.connect("notify::in-point", self._inpointChangedCb) self.bElement.connect("notify::start", self._startChangedCb) self.pipeline = None self.becomeControlled()
def __init__(self, ges_elem, max_cpu_usage): Previewer.__init__(self, GES.TrackType.VIDEO, max_cpu_usage) Zoomable.__init__(self) Loggable.__init__(self) self.ges_elem = ges_elem # Guard against malformed URIs self.uri = quote_uri(get_proxy_target(ges_elem).props.id) self.__start_id = 0 self.__preroll_timeout_id = 0 self._thumb_cb_id = 0 # The thumbs to be generated. self.queue = [] # The position for which a thumbnail is currently being generated. self.position = -1 # The positions for which we failed to get a pixbuf. self.failures = set() self._thumb_cb_id = None self.thumbs = {} self.thumb_height = THUMB_HEIGHT self.thumb_width = 0 self.__image_pixbuf = None if not isinstance(ges_elem, GES.ImageSource): self.thumb_cache = ThumbnailCache.get(self.uri) self._ensure_proxy_thumbnails_cache() self.thumb_width, unused_height = self.thumb_cache.image_size self.pipeline = None self.gdkpixbufsink = None self.cpu_usage_tracker = CPUUsageTracker() # Initial delay before generating the next thumbnail, in millis. self.interval = 500 # Connect signals and fire things up self.ges_elem.connect("notify::in-point", self._inpoint_changed_cb) self.ges_elem.connect("notify::duration", self._duration_changed_cb) self.become_controlled() self.connect("notify::height-request", self._height_changed_cb)
def __init__(self, bElement, timeline): """ @param bElement : the backend GES.TrackElement @param track : the track to which the bElement belongs @param timeline : the containing graphic timeline. """ Clutter.ScrollActor.__init__(self) PreviewGenerator.__init__(self, GES.TrackType.VIDEO) Zoomable.__init__(self) Loggable.__init__(self) # Variables related to the timeline objects self.timeline = timeline self.bElement = bElement # Guard against malformed URIs self.uri = quote_uri(bElement.props.uri) self.duration = bElement.props.duration # Variables related to thumbnailing self.wishlist = [] self._thumb_cb_id = None self._allAnimated = False self._running = False # We should have one thumbnail per thumb_period. # TODO: get this from the user settings self.thumb_period = int(0.5 * Gst.SECOND) self.thumb_height = EXPANDED_SIZE - 2 * THUMB_MARGIN_PX self.thumb_width = None # will be set by self._setupPipeline() # Maps (quantized) times to Thumbnail objects self.thumbs = {} self.thumb_cache = get_cache_for_uri(self.uri) self.cpu_usage_tracker = CPUUsageTracker() self.interval = 500 # Every 0.5 second, reevaluate the situation # Connect signals and fire things up self.timeline.connect("scrolled", self._scrollCb) self.bElement.connect("notify::duration", self._durationChangedCb) self.bElement.connect("notify::in-point", self._inpointChangedCb) self.bElement.connect("notify::start", self._startChangedCb) self.pipeline = None self.becomeControlled()
def __init__(self, ges_elem): """ @param ges_elem : the backend GES.TrackElement @param track : the track to which the ges_elem belongs """ Previewer.__init__(self, GES.TrackType.VIDEO) Zoomable.__init__(self) Loggable.__init__(self) # Variables related to the timeline objects self.timeline = ges_elem.get_parent().get_timeline().ui self.ges_elem = ges_elem # Guard against malformed URIs self.uri = quote_uri(get_proxy_target(ges_elem).props.id) # Variables related to thumbnailing self.wishlist = [] self.queue = [] self._thumb_cb_id = None self._running = False # We should have one thumbnail per thumb_period. # TODO: get this from the user settings self.thumb_period = int(0.5 * Gst.SECOND) self.thumb_height = THUMB_HEIGHT # Maps (quantized) times to Thumbnail objects self.thumbs = {} self.thumb_cache = getThumbnailCache(self.uri) self.thumb_width, unused_height = self.thumb_cache.getImagesSize() self.cpu_usage_tracker = CPUUsageTracker() self.interval = 500 # Every 0.5 second, reevaluate the situation # Connect signals and fire things up self.ges_elem.connect("notify::in-point", self._inpointChangedCb) self.pipeline = None self.gdkpixbufsink = None self.__last_rectangle = Gdk.Rectangle() self.becomeControlled() self.connect("notify::height-request", self._heightChangedCb)
def __init__(self, bElement): """ @param bElement : the backend GES.TrackElement @param track : the track to which the bElement belongs """ super(VideoPreviewer, self).__init__() PreviewGenerator.__init__(self, GES.TrackType.VIDEO) Zoomable.__init__(self) Loggable.__init__(self) # Variables related to the timeline objects self.timeline = bElement.get_parent().get_timeline().ui self.bElement = bElement # Guard against malformed URIs self.uri = quote_uri(bElement.props.uri) # Variables related to thumbnailing self.wishlist = [] self._thumb_cb_id = None self._running = False # We should have one thumbnail per thumb_period. # TODO: get this from the user settings self.thumb_period = int(0.5 * Gst.SECOND) self.thumb_height = EXPANDED_SIZE - 2 * THUMB_MARGIN_PX # Maps (quantized) times to Thumbnail objects self.thumbs = {} self.thumb_cache = get_cache_for_uri(self.uri) self.thumb_width, unused_height = self.thumb_cache.getImagesSize() self.cpu_usage_tracker = CPUUsageTracker() self.interval = 500 # Every 0.5 second, reevaluate the situation # Connect signals and fire things up self.bElement.connect("notify::in-point", self._inpointChangedCb) self.pipeline = None self.__last_rectangle = Gdk.Rectangle() self.becomeControlled() self.connect("notify::height-request", self._heightChangedCb)
def removeUri(self, uri): """ Remove the info for c{uri} from the source list. """ # In theory we don't need quote_uri here, but since removeUri is public, # we can never be too sure. uri = quote_uri(uri) try: info = self._sources.pop(uri) except KeyError: raise MediaLibraryError("URI not in the medialibrary", uri) try: self._ordered_sources.remove(info) except ValueError: # this can only happen if discoverer hasn't finished scanning the # source, so info must be None assert info is None self.debug("Removing %s", uri) self.emit("source-removed", uri, info)
def __init__(self, ges_elem, max_cpu_usage): Previewer.__init__(self, GES.TrackType.VIDEO, max_cpu_usage) Zoomable.__init__(self) Loggable.__init__(self) self.ges_elem = ges_elem # Guard against malformed URIs self.uri = quote_uri(get_proxy_target(ges_elem).props.id) self.__start_id = 0 self.__image_pixbuf = None self.thumbs = {} self.thumb_height = THUMB_HEIGHT self.thumb_width = 0 self.ges_elem.connect("notify::duration", self._duration_changed_cb) self.become_controlled() self.connect("notify::height-request", self._height_changed_cb)
def _setScenarioFile(self, uri): if uri: project_path = path_from_uri(uri) else: # New project. project_path = None if 'PITIVI_SCENARIO_FILE' in os.environ: scenario_path = os.environ['PITIVI_SCENARIO_FILE'] else: cache_dir = get_dir(os.path.join(xdg_cache_home(), "scenarios")) scenario_name = str(time.strftime("%Y%m%d-%H%M%S")) if project_path: scenario_name += os.path.splitext(project_path.replace(os.sep, "_"))[0] scenario_path = os.path.join(cache_dir, scenario_name + ".scenario") scenario_path = path_from_uri(quote_uri(scenario_path)) self._scenario_file = open(scenario_path, "w") if project_path and not project_path.endswith(".scenario"): # It's an xges file probably. with open(project_path) as project: content = project.read().replace("\n", "") self.write_action("load-project", serialized_content=content)
def saveProject(self, project, uri=None, overwrite=False, formatter=None, backup=False): """ Save the L{Project} to the given location. If specified, use the given formatter. @type project: L{Project} @param project: The L{Project} to save. @type uri: L{str} @param uri: The absolute URI of the location to store the project to. @param overwrite: Whether to overwrite existing location. @type overwrite: C{bool} @type formatter: L{Formatter} @param formatter: The L{Formatter} to use to store the project if specified. If it is not specified, then it will be saved at its original format. @param backup: Whether the requested save operation is for a backup @type backup: C{bool} @see: L{Formatter.saveProject} """ if formatter is None: formatter = GES.PitiviFormatter() if backup: if project.uri and self.current.uri is not None: # Ignore whatever URI that is passed on to us. It's a trap. uri = self._makeBackupURI(project.uri) else: # Do not try to save backup files for blank projects. # It is possible that self.current.uri == None when the backup # timer sent us an old instance of the (now closed) project. return elif uri is None: # This allows calling saveProject without specifying the target URI uri = project.uri else: # Ensure the URI we are given is properly encoded, or GIO will fail uri = quote_uri(uri) # The following needs to happen before we change project.uri: if not isWritable(path_from_uri(uri)): # TODO: this will not be needed when GTK+ bug #601451 is fixed self.emit("save-project-failed", uri, _("You do not have permissions to write to this folder.")) return # Update the project instance's uri for the "Save as" scenario. # Otherwise, subsequent saves will be to the old uri. if not backup: project.uri = uri if uri is None or not formatter.can_save_uri(uri): self.emit("save-project-failed", uri, _("Cannot save with this file format.")) return if overwrite or not os.path.exists(path_from_uri(uri)): formatter.set_sources(project.medialibrary.getSources()) saved = formatter.save_to_uri(project.timeline, uri) if saved: if not backup: # Do not emit the signal when autosaving a backup file self.emit("project-saved", project, uri) self.debug('Saved project "%s"' % uri) else: self.debug('Saved backup "%s"' % uri) return saved
def _ensure_proxy_thumbnails_cache(self): """Ensures that both the target asset and the proxy assets have caches.""" uri = quote_uri(self.ges_elem.props.uri) if self.uri != uri: self.thumb_cache.copy(uri)
def _addAsset(self, asset): # 128 is the normal size for thumbnails, but for *icons* it looks # insane LARGE_SIZE = 96 info = asset.get_info() # The code below tries to read existing thumbnails from the freedesktop # thumbnails directory (~/.thumbnails). The filenames are simply # the file URI hashed with md5, so we can retrieve them easily. video_streams = [ i for i in info.get_stream_list() if isinstance(i, DiscovererVideoInfo) ] if len(video_streams) > 0: # From the freedesktop spec: "if the environment variable # $XDG_CACHE_HOME is set and not blank then the directory # $XDG_CACHE_HOME/thumbnails will be used, otherwise # $HOME/.cache/thumbnails will be used." # Older version of the spec also mentioned $HOME/.thumbnails quoted_uri = quote_uri(info.get_uri()) thumbnail_hash = md5(quoted_uri.encode()).hexdigest() try: thumb_dir = os.environ['XDG_CACHE_HOME'] thumb_64, thumb_128 = self._getThumbnailInDir( thumb_dir, thumbnail_hash) except KeyError: thumb_64, thumb_128 = (None, None) if thumb_64 is None: thumb_dir = os.path.expanduser("~/.cache/thumbnails/") thumb_64, thumb_128 = self._getThumbnailInDir( thumb_dir, thumbnail_hash) if thumb_64 is None: thumb_dir = os.path.expanduser("~/.thumbnails/") thumb_64, thumb_128 = self._getThumbnailInDir( thumb_dir, thumbnail_hash) if thumb_64 is None: if asset.is_image(): thumb_64 = self._getIcon("image-x-generic") thumb_128 = self._getIcon("image-x-generic", None, LARGE_SIZE) else: thumb_64 = self._getIcon("video-x-generic") thumb_128 = self._getIcon("video-x-generic", None, LARGE_SIZE) # TODO ideally gst discoverer should create missing thumbnails. self.log("Missing a thumbnail for %s, queuing", path_from_uri(quoted_uri)) self._missing_thumbs.append(quoted_uri) else: thumb_64 = self._getIcon("audio-x-generic") thumb_128 = self._getIcon("audio-x-generic", None, LARGE_SIZE) if info.get_duration() == Gst.CLOCK_TIME_NONE: duration = '' else: duration = beautify_length(info.get_duration()) name = info_name(info) self.pending_rows.append((thumb_64, thumb_128, beautify_info(info), asset, info.get_uri(), duration, name)) if len(self.pending_rows) > 50: self.flush_pending_rows()
def __init__(self, project_filename, debug=False): GuiPitivi.__init__(self, debug) if not os.path.exists(project_filename): self.error("Project file does not exist: %s" % project_filename) sys.exit(1) self.projectManager.loadProject(quote_uri(os.path.abspath(project_filename)))
def _loadProject(self, project_filename): self.projectManager.loadProject(quote_uri(os.path.abspath(project_filename)))