def open_mencoder(self): self.mencoder_started = True info = pg_video_info(self.file, intolerant=True) self.width = info['width'] self.height = info['height'] self.fps = info['fps'] self.length = info['length'] check('float|int', self.length) check('float|int', self.fps) self.info('length: %r' % self.length) self.info('fps: %r' % self.fps) self.approx_frames = int(math.ceil(self.length * self.fps)) # TODO: reading non-RGB streams not supported self.info('Reading %dx%d @ %.3f fps ' ' (length %ss, approx %d frames), from %s.' % (self.width, self.height, self.fps, self.length, self.approx_frames, friendly_path(self.config.file))) self.shape = (self.height, self.width, 3) self.dtype = 'uint8' pixel_format = "rgb24" self.temp_dir = tempfile.mkdtemp(prefix='procgraph_fifo_dir') self.fifo_name = os.path.join(self.temp_dir, 'mencoder_fifo') os.mkfifo(self.fifo_name) args = [ self.programs['mencoder'], self.file, '-ovc', 'raw', '-rawvideo', 'w=%d:h=%d:format=%s' % (self.width, self.height, pixel_format), '-of', 'rawvideo', '-vf', 'format=rgb24', '-nosound', '-o', self.fifo_name ] self.tmp_stdout = tempfile.TemporaryFile() self.tmp_stderr = tempfile.TemporaryFile() if self.config.quiet: self.process = subprocess.Popen( args, stdout=self.tmp_stdout.fileno(), stderr=self.tmp_stderr.fileno()) else: self.process = subprocess.Popen(args) self.delta = 1.0 / self.fps if not self.timestamps: msg = ('No timestamps found; using delta = %.2f (%.2f fps).' % (self.delta, self.fps)) self.info(msg) self.stream = open(self.fifo_name, 'r')
def open_mencoder(self): self.mencoder_started = True info = pg_video_info(self.file, intolerant=True) self.width = info['width'] self.height = info['height'] self.fps = info['fps'] self.length = info['length'] check('float|int', self.length) check('float|int', self.fps) self.info('length: %r' % self.length) self.info('fps: %r' % self.fps) self.approx_frames = int(math.ceil(self.length * self.fps)) # TODO: reading non-RGB streams not supported self.info('Reading %dx%d @ %.3f fps ' ' (length %ss, approx %d frames), from %s.' % (self.width, self.height, self.fps, self.length, self.approx_frames, friendly_path(self.config.file))) self.shape = (self.height, self.width, 3) self.dtype = 'uint8' pixel_format = "rgb24" self.temp_dir = tempfile.mkdtemp(prefix='procgraph_fifo_dir') self.fifo_name = os.path.join(self.temp_dir, 'mencoder_fifo') os.mkfifo(self.fifo_name) args = [ self.programs['mencoder'], self.file, '-ovc', 'raw', '-rawvideo', 'w=%d:h=%d:format=%s' % (self.width, self.height, pixel_format), '-of', 'rawvideo', '-vf', 'format=rgb24', '-nosound', '-o', self.fifo_name ] self.tmp_stdout = tempfile.TemporaryFile() self.tmp_stderr = tempfile.TemporaryFile() if self.config.quiet: self.process = subprocess.Popen(args, stdout=self.tmp_stdout.fileno(), stderr=self.tmp_stderr.fileno()) else: self.process = subprocess.Popen(args) self.delta = 1.0 / self.fps if not self.timestamps: msg = ('No timestamps found; using delta = %.2f (%.2f fps).' % (self.delta, self.fps)) self.info(msg) self.stream = open(self.fifo_name, 'r')
def print_stats(self): percentage = 100.0 * self.num_frames_read / self.approx_frames # this assumes constant fps seconds = self.num_frames_read * self.delta seconds_total = self.approx_frames * self.delta self.info('%6d/%d frames, %.1f/%.1f sec (%4.1f%%) of %s' % (self.num_frames_read, self.approx_frames, seconds, seconds_total, percentage, friendly_path(self.file)))
def print_stats(self): if self.approx_frames != 0: percentage = 100.0 * self.num_frames_read / self.approx_frames else: percentage = 0 # this assumes constant fps seconds = self.num_frames_read * self.delta seconds_total = self.approx_frames * self.delta self.info('%6d/%d frames, %.1f/%.1f sec (%4.1f%%) of %s' % (self.num_frames_read, self.approx_frames, seconds, seconds_total, percentage, friendly_path(self.file)))
def finish(self): if self.process is None: msg = 'Finish() before starting to encode.' self.error(msg) raise Exception(msg) return timestamp = self.first_frame_timestamp metadata = self._get_metadata() container = self.config.container vcodec = self.config.vcodec vcodec_params = self.config.vcodec_params self.info('Transcoding %s' % friendly_path(self.filename)) pg_video_convert(self.tmp_filename, self.filename, container=container, vcodec=vcodec, vcodec_params=vcodec_params, timestamp=timestamp, metadata=metadata) # if False: # XXX if os.path.exists(self.tmp_filename): os.unlink(self.tmp_filename) if True: T = self.first_frame_timestamp os.utime(self.filename, (T, T)) self.info('Finished %s' % friendly_path(self.filename)) # TODO: skip mp4 if self.config.crop: base, ext = os.path.splitext(self.filename) cropped = '%s-crop%s' % (base, ext) video_crop(self.filename, cropped) os.rename(cropped, self.filename)
def get_info_for_file(v, index_filename, convert_to_mov=False): """ v: video index_filename: used to create relative paths """ if convert_to_mov: v_mov = os.path.splitext(v)[0] + '.mov' if not os.path.exists(v_mov): print('Creating Final Cut friendly file:\n<- %s\n-> %s' % (friendly_path(v), friendly_path(v_mov))) pg_video_convert(v, v_mov, vcodec='prores', vcodec_params={'profile': 3}) T = os.path.getmtime(v) os.utime(v_mov, (T, T)) else: v_mov = v # convert_to_mov_prores(v, v_mov, profile=2, quiet=False) # v_mp4 = os.path.splitext(v)[0] + '.mp4' # if not os.path.exists(v_mp4): # recode_to_mp4(v, v_mp4) rel_filename = os.path.relpath(v_mov, os.path.dirname(index_filename)) id_video = os.path.splitext(os.path.basename(v))[0] id_format = id_video + '_format' info = pg_video_info(v) info['filename'] = rel_filename info['id_video'] = id_video info['id_format'] = id_format info['filename_abs'] = v_mov return info
def create_event_for_fcpx(dirname, pattern, event_filename=None, event_name=None): """ Creates an index Event for final cut pro X """ if event_filename is None: event_filename = os.path.join(dirname, 'event.fcpxml') if event_name is None: event_name = os.path.basename(dirname) + '-event' filenames = list(locate_files(dirname, pattern)) videos = [get_info_for_file(f, event_filename) for f in filenames] xml_index = fcpx_get_xml_event(videos, event_name) with open(event_filename, 'w') as f: f.write(xml_index.strip()) print('written %s' % friendly_path(event_filename))
def try_initialization(self): # If we don't have at least two frames, continue if len(self.buffer) < 2: return # Get height and width from first image first_image = self.buffer[0][1] self.shape = first_image.shape self.height = self.shape[0] self.width = self.shape[1] if self.height > 8192 or self.width > 8192: msg = 'Mencoder cannot support movies this big (%sx%s)' msg = msg % (self.height, self.width) raise Exception(msg) self.ndim = len(self.shape) # Format for mencoder's rawvideo "format" option if self.ndim == 2: format = 'y8' # @ReservedAssignment else: if self.shape[2] == 3: format = 'rgb24' # @ReservedAssignment elif self.shape[2] == 4: # Note: did not try this yet format = 'rgba' # @ReservedAssignment msg = 'I detected that you are trying to write a transparent' msg += 'video. This does not work well yet (and besides,' msg += 'it is not supported in many applications, like ' msg += 'Keynote). Anyway, the plan is to use mencoder ' msg += 'to write a .AVI with codec "png". This will fail ' msg += 'for now, but perhaps in the future it will be ' msg += '.better' self.error(msg) # guess the fps if we are not given the config if self.config.fps is None: delta = self.buffer[-1][0] - self.buffer[0][0] if delta == 0: timestamps = [x[0] for x in self.buffer] self.debug('Got 0 delta: timestamps: %s' % timestamps) fps = 0 else: fps = (len(self.buffer) - 1) / delta # Check for very wrong results if not (3 < fps < 60): self.error('Detected fps is %.2f; this seems strange to me,' ' so I will use the safe choice fps = %.2f.' % (fps, self.config.fps_safe)) fps = self.config.fps_safe else: fps = self.config.fps # adapt the bitrate to the size of the image vbitrate0 = self.config.firstpass_bitrate shape0 = (640, 480) n1 = self.width * self.height n0 = shape0[0] * shape0[1] vbitrate = vbitrate0 * n1 / n0 self.info('Estimated bitrate %r' % vbitrate) max_bitrate = 90 * 1000 * 1000 if vbitrate > max_bitrate: vbitrate = max_bitrate self.info('Estimated bitrate too high, capping at %s' % vbitrate) self.filename = expand(self.config.file) if os.path.exists(self.filename): self.info('Removing previous version of %s.' % friendly_path(self.filename)) os.unlink(self.filename) self.tmp_filename = '%s-active.avi' % self.filename make_sure_dir_exists(self.filename) self.info('Writing %dx%d %s video stream at %.3f fps to %r.' % (self.width, self.height, format, fps, friendly_path(self.filename))) if format == 'rgba': ovc = ['-ovc', 'lavc', '-lavcopts', 'vcodec=png'] else: ovc = [ '-ovc', 'lavc', '-lavcopts', 'vcodec=%s:vbitrate=%d' % ('mpeg4', vbitrate) ] out = ['-o', self.tmp_filename] args = [ self.programs['mencoder'], '/dev/stdin', '-demuxer', 'rawvideo', '-rawvideo', 'w=%d:h=%d:fps=%f:format=%s' % (self.width, self.height, fps, format) ] + ovc + out # '-v', "0", # verbosity level (1 prints stats \r) # self.debug('$ %s' % " ".join(args)) # Note: mp4 encoding is currently broken in mencoder :-( # so we have to use ffmpeg as a second step. # These would be the options to add: # '-of', 'lavf', '-lavfopts', 'format=mp4' self.tmp_stdout = tempfile.TemporaryFile() self.tmp_stderr = tempfile.TemporaryFile() quiet = self.config.quiet if quiet: # XXX /dev/null not portable # self.debug('stderr: %s' % self.tmp_stderr) # self.debug('stdout: %s' % self.tmp_stdout) # TODO: write error self.process = subprocess.Popen(args, preexec_fn=ignore_sigint, stdin=subprocess.PIPE, stdout=self.tmp_stdout.fileno(), stderr=self.tmp_stderr.fileno()) else: self.process = subprocess.Popen(args=args, stdin=subprocess.PIPE) if self.config.timestamps: self.timestamps_filename = self.filename + '.timestamps' self.timestamps_file = open(self.timestamps_filename, 'w')
def try_initialization(self): # If we don't have at least two frames, continue if len(self.buffer) < 2: return # Get height and width from first image first_image = self.buffer[0][1] self.shape = first_image.shape self.height = self.shape[0] self.width = self.shape[1] if self.height > 8192 or self.width > 8192: msg = 'Mencoder cannot support movies this big (%sx%s)' msg = msg % (self.height, self.width) raise Exception(msg) self.ndim = len(self.shape) # Format for mencoder's rawvideo "format" option if self.ndim == 2: format = 'y8' # @ReservedAssignment else: if self.shape[2] == 3: format = 'rgb24' # @ReservedAssignment elif self.shape[2] == 4: # Note: did not try this yet format = 'rgba' # @ReservedAssignment msg = 'I detected that you are trying to write a transparent' msg += 'video. This does not work well yet (and besides,' msg += 'it is not supported in many applications, like ' msg += 'Keynote). Anyway, the plan is to use mencoder ' msg += 'to write a .AVI with codec "png". This will fail ' msg += 'for now, but perhaps in the future it will be ' msg += '.better' self.error(msg) # guess the fps if we are not given the config if self.config.fps is None: delta = self.buffer[-1][0] - self.buffer[0][0] if delta == 0: timestamps = [x[0] for x in self.buffer] self.debug('Got 0 delta: timestamps: %s' % timestamps) fps = 0 else: fps = (len(self.buffer) - 1) / delta # Check for very wrong results if not (3 < fps < 60): self.error('Detected fps is %.2f; this seems strange to me,' ' so I will use the safe choice fps = %.2f.' % (fps, self.config.fps_safe)) fps = self.config.fps_safe else: fps = self.config.fps # adapt the bitrate to the size of the image vbitrate0 = self.config.firstpass_bitrate shape0 = (640, 480) n1 = self.width * self.height n0 = shape0[0] * shape0[1] vbitrate = vbitrate0 * n1 / n0 self.info('Estimated bitrate %r' % vbitrate) max_bitrate = 90*1000*1000 if vbitrate > max_bitrate: vbitrate = max_bitrate self.info('Estimated bitrate too high, capping at %s' % vbitrate) self.filename = expand(self.config.file) if os.path.exists(self.filename): self.info('Removing previous version of %s.' % friendly_path(self.filename)) os.unlink(self.filename) self.tmp_filename = '%s-active.avi' % self.filename make_sure_dir_exists(self.filename) self.info('Writing %dx%d %s video stream at %.3f fps to %r.' % (self.width, self.height, format, fps, friendly_path(self.filename))) if format == 'rgba': ovc = ['-ovc', 'lavc', '-lavcopts', 'vcodec=png'] else: ovc = ['-ovc', 'lavc', '-lavcopts', 'vcodec=%s:vbitrate=%d' % ('mpeg4', vbitrate)] out = ['-o', self.tmp_filename] args = [ self.programs['mencoder'], '/dev/stdin', '-demuxer', 'rawvideo', '-rawvideo', 'w=%d:h=%d:fps=%f:format=%s' % (self.width, self.height, fps, format) ] + ovc + out # '-v', "0", # verbosity level (1 prints stats \r) # self.debug('$ %s' % " ".join(args)) # Note: mp4 encoding is currently broken in mencoder :-( # so we have to use ffmpeg as a second step. # These would be the options to add: # '-of', 'lavf', '-lavfopts', 'format=mp4' self.tmp_stdout = tempfile.TemporaryFile() self.tmp_stderr = tempfile.TemporaryFile() quiet = self.config.quiet if quiet: # XXX /dev/null not portable # self.debug('stderr: %s' % self.tmp_stderr) # self.debug('stdout: %s' % self.tmp_stdout) # TODO: write error self.process = subprocess.Popen(args, preexec_fn=ignore_sigint, stdin=subprocess.PIPE, stdout=self.tmp_stdout.fileno(), stderr=self.tmp_stderr.fileno()) else: self.process = subprocess.Popen(args=args, stdin=subprocess.PIPE) if self.config.timestamps: self.timestamps_filename = self.filename + '.timestamps' self.timestamps_file = open(self.timestamps_filename, 'w')