content: """
  Used to compress videos (FPS and dimensions) in the Singularity project.
  Modified from https://github.com/ArrowLuo/CLIP4Clip
  """
  import os
  from os.path import exists, join
  import argparse
  import subprocess
  from multiprocessing import Pool
  import shutil
  try:
      from psutil import cpu_count
  except:
      from multiprocessing import cpu_count
  from functools import partial
  from tqdm import tqdm
  from PIL import Image
  
  
  def resize_image(input_path, output_path, size=224):
      with Image.open(input_path) as img:
          w, h = img.width, img.height
          r = 1. * w / h
          if w > h:
              h = size
              w = r * size
          else:
              h = size / r
              w = size
  
          img_resized = img.resize((int(w), int(h)))
          img_resized.save(output_path)
  
  
  def _compress_images(input_output_pair, size=224):
      """
      Scale and downsample an input image to a given fps and size (shorter side size).
      This also removes the audio from the image.
      """
      input_image_path, output_image_path = input_output_pair
      try:
          resize_image(input_image_path, output_image_path, size)
      except Exception as e:
          print(f"Caught Exception {e}")
  
  
  def _compress_videos(input_output_pair, size=224, fps=3):
      """
      Scale and downsample an input video to a given fps and size (shorter side size).
      This also removes the audio from the video.
      """
      input_file_path, output_file_path = input_output_pair
      try:
          command = ['ffmpeg',
                     '-y',  # (optional) overwrite output file if it exists
                     '-i', input_file_path,
                     '-filter:v',  # no audio
                     f"scale='if(gt(a,1),trunc(oh*a/2)*2,{size})':'if(gt(a,1),{size},trunc(ow*a/2)*2)'",
                     '-map', '0:v',  # no audio
                     '-r', str(fps),  # frames per second
                     # '-g', str(16),
                     output_file_path,
                     ]
          result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
      except Exception as e:
          raise e
  
  
  def _compress(input_output_pair, fps=3, size=224, file_type="image"):
      if file_type == "image":
          _compress_images(input_output_pair, size)
      elif file_type == "video":
          _compress_videos(input_output_pair, size, fps)
  
  
  def prepare_input_output_pairs(input_root, output_root, input_file_list_path=None):
      # filename list in `input_file_list_path` can be created very fast using `ls -U . >> ../video_filenames.txt`
      with open(input_file_list_path, "r") as f:
          filenames = [s.strip() for s in f.readlines()]
      print(f"There are {len(filenames)} video/images files loaded from list.")
      input_file_path_list = []
      output_file_path_list = []
      for e in tqdm(filenames, desc="find un-processed videos/images"):
          input_file_path = join(input_root, e)
          output_file_path = join(output_root, e)
          if not exists(output_file_path):
              input_file_path_list.append(input_file_path)
              output_file_path_list.append(output_file_path)
      return input_file_path_list, output_file_path_list
  
  
  def run_compress():
      parser = argparse.ArgumentParser(description="Compress videos/images for speed-up")
      parser.add_argument("--input_root", type=str, help="input root", required=True)
      parser.add_argument("--input_file_list_path", type=str, required=True, default=None,
                          help="list of video filenames under args.input_root, it can be "
                               "created efficiently with `ls -U /path/to/video >> /path/to/video_filenames.txt`")
      parser.add_argument("--output_root", type=str, help="output root", required=True)
      parser.add_argument("--size", type=int, default=224, help="shorter side size, aspect ratio is kept")
      parser.add_argument("--num_workers", type=int, default=24, help="#workers")
      parser.add_argument("--fps", type=int, default=3, help="fps for output video, ignored if file_type == image")
      parser.add_argument("--file_type", type=str, choices=["image", "video"], help="input file type")
      args = parser.parse_args()
  
      # set paths
      input_root = args.input_root
      output_root = args.output_root
      assert input_root != output_root
      if not exists(output_root):
          os.makedirs(output_root, exist_ok=True)
  
      # prepare and find un-processed
      input_file_path_list, output_file_path_list = prepare_input_output_pairs(
          input_root, output_root, input_file_list_path=args.input_file_list_path,
      )
      print(f"input_file_path_list[:3] {input_file_path_list[:3]}")
      print(f"output_file_path_list[:3] {output_file_path_list[:3]}")
      print("Total videos/images need to process: {}".format(len(input_file_path_list)))
  
      # start parallel jobs
      num_cores = cpu_count()
      num_workers = args.num_workers
      print(f"Begin with {num_cores}-core logical processor, {num_workers} workers")
      compress = partial(_compress, fps=args.fps, size=args.size, file_type=args.file_type)
      input_pairs = list(zip(input_file_path_list, output_file_path_list))
      with Pool(num_workers) as pool, tqdm(total=len(input_file_path_list), desc="re-encoding videos/images") as pbar:
          for idx, _ in enumerate(pool.imap_unordered(compress, input_pairs, chunksize=32)):
              pbar.update(1)
  
      # copy-paste failed files
      print("Compress finished, copy-paste failed files...")
      copy_count = 0
      for input_file_path, output_file_path in zip(input_file_path_list, output_file_path_list):
          if exists(input_file_path):
              if exists(output_file_path) is False or os.path.getsize(output_file_path) < 1.:
                  copy_count += 1
                  shutil.copyfile(input_file_path, output_file_path)
                  print("Copy and replace file: {}".format(output_file_path))
      print(f"copy_count {copy_count}")
  
  
  if __name__ == "__main__":
      run_compress()
  