Advertisement
Guest User

Untitled

a guest
Oct 20th, 2019
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.12 KB | None | 0 0
  1. #!/usr/bin/env python
  2. import argparse
  3. import os
  4. import shutil
  5. import subprocess
  6. import tempfile
  7.  
  8. import OpenImageIO
  9.  
  10. from arch.path import Sequence
  11.  
  12. IGNORE_EXTNS = [".ifl", ".mov"]
  13.  
  14. MOV_EXTN = "mov"
  15. TEMP_EXTN = "exr"
  16.  
  17.  
  18. def parse_args():
  19. parser = argparse.ArgumentParser(
  20. description='Create video files from a directory of images.'
  21. )
  22. parser.add_argument('directory',
  23. help='The path to a directory containing images.')
  24. return parser.parse_args()
  25.  
  26.  
  27. def create_mov(sequence, directory, framerate):
  28. """
  29. Takes a directory containing one or more image sequences. Creates a .mov for
  30. the passed sequence, assuming that the sequence is in the directory.
  31. :param Sequence sequence: An Arch-style Sequence.
  32. :param str directory: A path to the directory containing the image files
  33. associated with the passed sequence.
  34. :param float framerate: The framerate which should be used when creating the
  35. .mov.
  36. """
  37.  
  38. mov_path = None
  39. temp_dir = None
  40. # check if the image sequence in question consists of DWAA/DWAB exrs. If
  41. # so, create lossless exrs and use those. Otherwise, ffmpeg can use the
  42. # image sequence as it stands.
  43.  
  44. bad_exrs = False
  45.  
  46. if sequence.extension == 'exr':
  47. first_frame_path = os.path.join(directory,
  48. '.'.join([sequence.name,
  49. str(sequence.first_frame),
  50. sequence.extension]
  51. )
  52. )
  53. buf = OpenImageIO.ImageBuf(first_frame_path)
  54. spec = buf.spec()
  55. compression = spec.getattribute('compression')
  56. # TODO: check if these are actually the correct formatting for the
  57. # incompatible compression schemes.
  58. if compression == 'DWAA' or compression == 'DWAB':
  59. bad_exrs = True
  60.  
  61. if bad_exrs:
  62. temp_dir = tempfile.mkdtemp()
  63. temp_path = create_temp_images(sequence, directory, temp_dir)
  64. else:
  65. temp_path = os.path.join(directory, sequence.pattern)
  66.  
  67. if temp_path is not None:
  68. mov_path = os.path.join(
  69. directory,
  70. ".".join([sequence.name, MOV_EXTN])
  71. )
  72. first_frame = sequence.first_frame
  73. # TODO: figure out how to offset frame number
  74. # offset = str(1.0 * first_frame / framerate)
  75.  
  76. ffmpeg_args = ["ffmpeg", "-y",
  77. "-start_number", str(first_frame),
  78. "-framerate", str(framerate),
  79. "-i", temp_path,
  80. # TODO: figure out how to offset frame number
  81. # "-output_ts_offset", offset,
  82. mov_path,
  83. ]
  84.  
  85. proc = subprocess.Popen(ffmpeg_args,
  86. stdout=subprocess.PIPE,
  87. stderr=subprocess.PIPE)
  88. _stdout, _stderr = proc.communicate()
  89.  
  90. if temp_dir is not None:
  91. shutil.rmtree(temp_dir)
  92.  
  93. return mov_path
  94.  
  95.  
  96. def create_temp_images(sequence, input_dir, output_dir):
  97. """
  98. Converts all images in the passed sequence to .exrs, written to output_dir.
  99. :param Sequence sequence: An Arch-style Sequence.
  100. :param str input_dir: A directory which contains the images corresponding
  101. to sequence.
  102. :param str output_dir: A valid directory.
  103. :return str|None: The ffmpeg-ready path to the images or None if no images
  104. were written.
  105. """
  106. # TODO: throw errors
  107. if not os.path.exists(input_dir):
  108. print("The input directory, {}, doesn't exist.".format(input_dir))
  109. elif not os.path.exists(output_dir):
  110. print("The output directory, {}, doesn't exist.".format(output_dir))
  111. else:
  112. extension = sequence.extension
  113. if extension not in IGNORE_EXTNS:
  114. first_frame = sequence.first_frame
  115. last_frame = sequence.last_frame
  116. number_of_zeroes = sequence.padding[2]
  117. # create something which can be used to properly-format frame
  118. # numbers, like '{:0>2d}'.
  119. padding = "{{:0>{}d}}".format(number_of_zeroes)
  120. for frame_number in range(first_frame, last_frame + 1):
  121. frame_pattern = ".".join([sequence.name,
  122. padding.format(frame_number),
  123. extension]
  124. )
  125. frame_path = os.path.join(input_dir, frame_pattern)
  126. write_image(frame_path, output_dir)
  127. # this is the ffmpeg-ready path for the images created,
  128. # i.e. images/live/here/image.%04d.exr.
  129. temp_file_name = ".".join([sequence.name,
  130. "%0{}d".format(number_of_zeroes),
  131. TEMP_EXTN])
  132. return os.path.join(output_dir, temp_file_name)
  133. else:
  134. return None
  135.  
  136.  
  137. def write_image(input_file_path, output_dir):
  138. """
  139. Writes a copy of the passed file as an EXR in the specified directory. The
  140. name of the file will be identical, except the extension.
  141. :param str input_file_path: A path to a valid image file.
  142. :param str output_dir: A path to a valid directory.
  143. """
  144. # generate output filename
  145. input_image_name = os.path.basename(input_file_path)
  146. output_image_name = ".".join([os.path.splitext(input_image_name)[0],
  147. TEMP_EXTN])
  148. output_image_path = os.path.join(output_dir, output_image_name)
  149.  
  150. # create an image buffer
  151. input_buf = OpenImageIO.ImageBuf(input_file_path)
  152. # set the compression to none - this ensures that ffmpeg can read the exrs
  153. input_buf.specmod().attribute("compression", "none")
  154.  
  155. # write the image
  156. if input_buf.has_error:
  157. print("Error: {}".format(input_buf.geterror()))
  158. else:
  159. input_buf.write(output_image_path)
  160.  
  161.  
  162. def main():
  163. args = parse_args()
  164.  
  165. sequences = Sequence.sequences_from_directory(args.directory)
  166.  
  167. for sequence in sequences:
  168. print(create_mov(sequence, args.directory, 24.0))
  169.  
  170.  
  171. if __name__ == "__main__":
  172. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement