                  logger.warning("Aligned directory contains far fewer images than the input "
                                 "directory, are you sure this is the right folder?")
          return face_hashes
  
      # SKIP FRAME RANGES #
      def get_frame_ranges(self):
          """ split out the frame ranges and parse out 'min' and 'max' values """
          if not self.args.frame_ranges:
              return None
  
          minmax = {"min": 0,  # never any frames less than 0
                    "max": float("inf")}
          rng = [tuple(map(lambda q: minmax[q] if q in minmax.keys() else int(q),
                           v.split("-")))
                 for v in self.args.frame_ranges]
          return rng
  
      def check_skipframe(self, filename):
          """ Check whether frame is to be skipped """
          if not self.frame_ranges:
              return None
          idx = int(self.imageidxre.findall(filename)[0])
          skipframe = not any(map(lambda b: b[0] <= idx <= b[1],
                                  self.frame_ranges))
          if skipframe and self.args.discard_frames:
              skipframe = "discard"
          return skipframe
  
  
  class Legacy():
      """ Update legacy alignments:
          - Rotate landmarks and bounding boxes on legacy alignments
            and remove the 'r' parameter
 
</s> remove         landmarks = faces["landmarks"]
        detected_faces = faces["detected_faces"]
        final_faces = list()
 </s> add     def check_skipframe(self, filename):
        """ Check whether frame is to be skipped """
        if not self.frame_ranges:
            return None
        indices = self.imageidxre.findall(filename)
        if not indices:
            logger.warning("Could not determine frame number. Frame will be converted: '%s'",
                           filename)
            return False
        idx = int(indices[0]) if indices else None
        skipframe = not any(map(lambda b: b[0] <= idx <= b[1], self.frame_ranges))
        return skipframe </s> remove         Utils.finalize(self.images.images_found,
                       self.faces_count,
                       self.verify_output)
 </s> add         minmax = {"min": 0,  # never any frames less than 0
                  "max": float("inf")}
        retval = [tuple(map(lambda q: minmax[q] if q in minmax.keys() else int(q), v.split("-")))
                  for v in self.args.frame_ranges]
        logger.debug("frame ranges: %s", retval)
        return retval </s> remove         if self.extractor:
            queue_manager.terminate_queues()
 </s> add     def get_frame_ranges(self):
        """ split out the frame ranges and parse out 'min' and 'max' values """
        if not self.args.frame_ranges:
            logger.debug("No frame range set")
            return None </s> remove 
    def load_model(self):
        """ Load the model requested for conversion """
        logger.debug("Loading Model")
        model_dir = get_folder(self.args.model_dir)
        model = PluginLoader.get_model(self.args.trainer)(model_dir, self.args.gpus, predict=True)
        logger.debug("Loaded Model")
        return model

    def load_converter(self, model):
        """ Load the requested converter for conversion """
        conv = self.args.converter
        converter = PluginLoader.get_converter(conv)(
            model.converter(self.args.swap_model),
            model=model,
            arguments=self.args)
        return converter

    def prepare_images(self):
        """ Prepare the images for conversion """
        filename = ""
        if self.extractor:
            load_queue = queue_manager.get_queue("load")
        for filename, image in tqdm(self.images.load(),
                                    total=self.images.images_found,
                                    file=sys.stdout):

            if (self.args.discard_frames and
                    self.opts.check_skipframe(filename) == "discard"):
 </s> add         logger.debug("Loaded extractor")

    def init_threads(self):
        """ Initialize queues and threads """
        logger.debug("Initializing DiskIO Threads")
        for task in ("load", "save"):
            self.add_queue(task)
            self.start_thread(task)
        logger.debug("Initialized DiskIO Threads")

    def add_queue(self, task):
        """ Add the queue to queue_manager and set queue attribute """
        logger.debug("Adding queue for task: '%s'", task)
        q_name = "convert_in" if task == "load" else task
        setattr(self, "{}_queue".format(task), queue_manager.get_queue(q_name))
        logger.debug("Added queue for task: '%s'", task)

    def start_thread(self, task):
        """ Start the DiskIO thread """
        logger.debug("Starting thread: '%s'", task)
        args = self.completion_event if task == "save" else None
        func = getattr(self, task)
        io_thread = MultiThread(func, args, thread_count=1)
        io_thread.start()
        setattr(self, "{}_thread".format(task), io_thread)
        logger.debug("Started thread: '%s'", task)

    # Loading tasks
    def load(self, *args):  # pylint: disable=unused-argument
        """ Load the images with detected_faces"""
        logger.debug("Load Images: Start")
        extract_queue = queue_manager.get_queue("extract_in") if self.extractor else None
        idx = 0
        for filename, image in self.images.load():
            idx += 1
            if self.load_queue.shutdown.is_set():
                logger.debug("Load Queue: Stop signal received. Terminating")
                break
            if image is None or not image.any():
                logger.warning("Unable to open image. Skipping: '%s'", filename)
                continue
            if self.check_skipframe(filename):
                if self.args.keep_unchanged:
                    logger.trace("Saving unchanged frame: %s", filename)
                    out_file = os.path.join(self.args.output_dir, os.path.basename(filename))
                    self.save_queue.put((out_file, image))
                else:
                    logger.trace("Discarding frame: '%s'", filename) </s> remove         for item in batch.iterator():
            self.convert(converter, item)
 </s> add     @property
    def draw_transparent(self):
        """ Draw transparent is an image writer only parameter.
            Return the value here for easy access for predictor """
        return self.writer.config.get("draw_transparent", False)

    @property
    def pre_encode(self):
        """ Return the writer's pre-encoder """
        dummy = np.zeros((20, 20, 3)).astype("uint8")
        test = self.writer.pre_encode(dummy)
        retval = None if test is None else self.writer.pre_encode
        logger.debug("Writer pre_encode function: %s", retval)
        return retval

    @property
    def total_count(self):
        """ Return the total number of frames to be converted """
        if self.frame_ranges and not self.args.keep_unchanged:
            retval = sum([fr[1] - fr[0] for fr in self.frame_ranges])
        else:
            retval = self.images.images_found
        logger.debug(retval)
        return retval

    # Initalization
    def get_writer(self):
        """ Return the writer plugin """
        args = [self.args.output_dir]
        if self.args.writer in ("ffmpeg", "gif"):
            args.append(self.total_count)
        if self.args.writer == "ffmpeg":
            if self.images.is_video:
                args.append(self.args.input_dir)
            else:
                args.append(self.args.reference_video)
        logger.debug("Writer args: %s", args)
        return PluginLoader.get_converter("writer", self.args.writer)(*args)
                  logger.warning("Aligned directory contains far fewer images than the input "
                                 "directory, are you sure this is the right folder?")
          return face_hashes
  
























  
  class Legacy():
      """ Update legacy alignments:
          - Rotate landmarks and bounding boxes on legacy alignments
            and remove the 'r' parameter
keep keep keep keep replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace keep keep keep keep keep
 Convert refactor (#703)

* Separate predict and implement pool

* Add check and raise error to multithreading

Box functions to config. Add crop box option.

* All masks to mask module. Refactor convert masks

Predicted mask passed from model. Cli update

* Intesect box with mask and fixes

* Use raw NN output for convert

Use raw mask for face adjustments. Split adjustments to pre and post warp

* Separate out adjustments. Add unmask sharpen

* Set sensible defaults. Pre PR Testing

* Fix queue sizes. Move masked.py to lib

* Fix Skip Frames. Fix GUI Config popup

* Sensible queue limits. Add a less resource intensive single processing mode

* Fix predicted mask. Amend smooth box defaults

* Deterministic ordering for video output

* Video to Video convert implemented

* Fixups

- Remove defaults from folders across all stages
- Move match-hist and aca into color adjustments selectable
- Handle crashes properly for pooled processes
- Fix output directory does not exist error when creating a new output folder
- Force output to frames if input is not a video

* Add Color Transfer adjustment method

Wrap info text in GUI plugin configure popup

* Refactor image adjustments. Easier to create plugins

Start implementing config options for video encoding

* Add video encoding config options

Allow video encoding for frames input (must pass in a reference video)
Move video and image output writers to plugins

* Image writers config options

Move scaling to cli
Move draw_transparent to images config
Add config options for cv2 writer
Add Pillow image writer

* Add gif filetype to Pillow. Fix draw transparent for Pillow

* Add Animated GIF writer

standardize opencv/pillow defaults

* [speedup] Pre-encode supported writers in the convert pool (opencv, pillow)

Move scaling to convert pool
Remove dfaker mask

* Fix default writer

* Bugfixes

* Better custom argparse formatting 
scripts/convert.py