def ffmpeg_subtitles_filter(stream, subtitle_path, start_ms): font_dir = current_app.config.get('FF_FONT_DIR', None) font_name = current_app.config.get('FF_FONT_NAME', None) font_size = current_app.config.get('FF_FONT_SIZE', 24) stream = ffmpeg.setpts(stream, 'PTS+%f/TB' % (start_ms / 1000)) sargs = {'force_style': 'Fontsize=%d' % font_size} if font_dir is not None: sargs['fontsdir'] = str(font_dir) if font_name is not None: sargs['force_style'] += ',FontName=%s' % font_name stream = ffmpeg.filter_(stream, 'subtitles', str(subtitle_path), **sargs) stream = ffmpeg.setpts(stream, 'PTS-STARTPTS') return stream
def speed_up(video_download, speed=args.speed): """Speeds up a video using ffmpeg. Works as a youtube_dl progress hook. The original video will be deleted. The speed multiplier is the 'speed' constant. Args: video_download -- dict with a 'status' key and a 'filename' key. """ if not video_download['status'] == 'finished': return # filename, file_extension = os.path.splitext(video_download['filename']) # filename_no_extension = video_download['filename'][:-len(file_extension)] filename = Path(video_download['filename']) out_name = filename.with_stem( filename.stem.replace("'", '') + f'-{speed}x').name speedup_folder = filename.parents[1] / 'speedup' speedup_folder.mkdir(exist_ok=True) out_filename = speedup_folder / out_name stream = ffmpeg.input(str(filename)) stream = ffmpeg.setpts(stream, f'(1/{speed})*PTS') stream = ffmpeg.output(stream, str(out_filename)) # if not args.verbose: # stream = stream.global_args('-hide_banner') # # stream = stream.global_args('-loglevel', 'warning') ffmpeg.run(stream) if not args.keep_original_parts: filename.unlink()
def cut(video, audio, arg): st, end = arg video = ffmpeg.trim(video, start=st, end=end) video = ffmpeg.setpts(video, 'PTS-STARTPTS') audio = ffmpeg.filter(audio, 'atrim', start=st, end=end) audio = ffmpeg.filter(audio, 'asetpts', 'PTS-STARTPTS') return video, audio
def _estublish_cmd(self, scenes: List[Scene]): inputfile = self.input_media_path.as_posix() outputfile = self.output_media_path.as_posix() stream = ffmpeg.input(inputfile) video_streams = list() audio_streams = list() for scene in scenes: start = scene.get_startat() duration = scene.get_interval() v_clip_stream = ffmpeg.trim( stream, start=start, duration=duration) v_clip_stream = ffmpeg.setpts(v_clip_stream, 'PTS-STARTPTS') a_clip_stream = ffmpeg.filter_( stream, 'atrim', start=start, duration=duration) a_clip_stream = ffmpeg.filter_( a_clip_stream, 'asetpts', 'PTS-STARTPTS') video_streams.append(v_clip_stream) audio_streams.append(a_clip_stream) v_stream = ffmpeg.concat( *video_streams, n=len(video_streams), v=1, a=0) a_stream = ffmpeg.concat( *audio_streams, n=len(audio_streams), v=0, a=1) stream = ffmpeg.output( v_stream, a_stream, outputfile, **self.CONFIG_720P) # ffmpeg.view(stream) # Debug self.stream = stream return ' '.join(ffmpeg.compile(stream))
def process(inputfile, day): duration = videoInf(inputfile) #find and sets presentation timestamps for 1min video pts = str(1 / duration) + "*PTS" stream = ffmpeg.input(inputfile) stream = ffmpeg.setpts(stream, pts) #merge the stream with music track audio = ffmpeg.input('../audio/track1.mp3') stream = ffmpeg.output(audio, stream, day + 'twim.mp4') ffmpeg.run(stream)
def speed(video, audio, arg): video = ffmpeg.setpts(video, '{}*PTS'.format(arg)) if arg < 0.5: video = ffmpeg.filter(video, 'minterpolate', mi_mode='mci', mc_mode='aobmc', vsbmc=1, fps=120) audio = ffmpeg.filter(audio, 'asetpts', '{}*PTS'.format(arg)) return video, audio
def run(self, item: VideoItem): print("Start exporting file") metadata = iExecutor.get_metadata(item) video = VideoFile(item.filepath) video.set_index(metadata.start_i) video_width = video.get_frame_width() video_height = video.get_frame_height() timeframes = video.get_timeframe_range(metadata.end_i) timeframes = np.array(timeframes) bbs = metadata.bb_fields.get_bbs_as_arrs() if bbs is None or len(bbs) == 0: raise SkipSignal("No bounding box fields for this item") collision_locations = metadata.bb_fields.collision_locations if not metadata.start_i: raise SkipSignal(f"Metadata is not clipped") if not metadata.end_i: raise SkipSignal(f"Metadata is not clipped") begin = metadata.start_i end = metadata.end_i time_begin = timeframes[0] time_end = timeframes[-1] headers = [FRAME, ID, CLASS, X1, Y1, X2, Y2, HAS_COLLISION] dtype = [ (FRAME, np.int), (ID, np.int), (CLASS, np.object), (X1, np.float), (Y1, np.float), (X2, np.float), (Y2, np.float), (HAS_COLLISION, np.int), ] data = np.array(bbs, dtype=dtype) #data = np.array([*zip(frames, bbs[ID], bbs[CLASS], # bbs[X1], bbs[Y1], bbs[X2], bbs[Y2], bbs[HAS_COLLISION])]) # Sort data by object id data = np.sort(data, order=ID) # Group data by object id _, unique_indices = np.unique(data[ID], return_index=True) data = np.split(data, unique_indices[1:], axis=0) interp_data = [] n_frames = int((time_end - time_begin) * self.target_fps / 1000) interp_time = time_begin + np.arange(n_frames) * (time_end - time_begin) / (n_frames - 1) for unique_object in data: if unique_object.shape[0] == 0: continue # Sort data by frame unique_object = np.sort(unique_object, order=FRAME) # Deal with holes interp_frame = np.arange(n_frames) holes, = np.where((unique_object[FRAME][1:] - unique_object[FRAME][:-1]) != 1) # Need +1 to have correct index for insertion holes = holes + 1 label_id = unique_object[ID][0] label_class = unique_object[CLASS][0] label_collision = unique_object[HAS_COLLISION][0] nan_frame = (0, label_id, label_class, np.nan, np.nan, np.nan, np.nan, label_collision) time = timeframes[unique_object[FRAME]] unique_object = np.insert(unique_object, holes, nan_frame, axis=0) time = np.insert(time, holes, np.nan) interp_x1 = np.interp(interp_time, time, unique_object['x1s'], left=float('nan'), right=float('nan')) interp_x1 = interp_x1.clip(0, video_width - 1) interp_y1 = np.interp(interp_time, time, unique_object['y1s'], left=float('nan'), right=float('nan')) interp_y1 = interp_y1.clip(0, video_height - 1) interp_x2 = np.interp(interp_time, time, unique_object['x2s'], left=float('nan'), right=float('nan')) interp_x2 = interp_x2.clip(0, video_width - 1) interp_y2 = np.interp(interp_time, time, unique_object['y2s'], left=float('nan'), right=float('nan')) interp_y2 = interp_y2.clip(0, video_height - 1) interp_data += [ (frame, label_id, label_class, x1, y1, x2, y2, label_collision) for (frame, x1, y1, x2, y2) in zip(interp_frame, interp_x1, interp_y1, interp_x2, interp_y2) ] # Sort data by frame interp_data = np.array(interp_data, dtype=dtype) nan_mask = np.array([list(row) for row in interp_data[['x1s','x2s','y1s','y2s']]]) nan_mask = np.any(np.isnan(nan_mask), axis=1) interp_data = interp_data[~nan_mask] interp_data = interp_data[np.argsort(interp_data['frames']), ...] interp_data['x1s'] = np.round(interp_data['x1s']) interp_data['y1s'] = np.round(interp_data['y1s']) interp_data['x2s'] = np.round(interp_data['x2s']) interp_data['y2s'] = np.round(interp_data['y2s']) directory = STORAGE_DIR_POSITIVES if len(collision_locations) else STORAGE_DIR_NEGATIVES filename = str(metadata.id) + ".csv" np.savetxt(directory / filename, interp_data, delimiter=',', fmt='%d,%d,%s,%d,%d,%d,%d,%d', comments='') stream = ffmpeg.input(item.filepath) stream = stream.trim(start_frame=begin, end_frame=end, duration=5) stream = ffmpeg.filter(stream, 'fps', fps=self.target_fps, round='near') stream = ffmpeg.setpts(stream, expr='PTS-STARTPTS') stream = stream.output(str(STORAGE_DIR_VIDEOS / (str(metadata.id) + '.mp4'))) stream = ffmpeg.overwrite_output(stream) try: stream.run() except KeyboardInterrupt: # Prevent corrupting video stream.run() raise print(f"Done exporting file {filename}") return item
def run(self, item: VideoItem): print("Start exporting file") metadata = iExecutor.get_metadata(item) bbs = metadata.bb_fields.to_json() if bbs is None or len(bbs) == 0: raise StopSignal("No bounding box fields for this item") # First, we trim the last seconds before the first collision if not metadata.accident_locations or len( metadata.accident_locations) == 0: # TODO: This should be a negative raise StopSignal(f"No accident locations labelled for {item.id}") if not metadata.start_i: raise StopSignal(f"Metadata is not clipped") collision_frame = np.min(metadata.accident_locations) info = ffmpeg.probe(item.filepath) streams = [ stream for stream in info.get('streams', []) if stream.get('codec_type') == 'video' ] if len(streams) > 1: raise StopSignal( f"Video {item.id} has multiple video streams. Could not determine FPS" ) if len(streams) < 1: raise StopSignal( f"Video {item.id} has no video streams. Could not determine FPS" ) fps = float(streams[0]['nb_frames']) / float(streams[0]['duration']) headers = [FRAME, ID, CLASS, X1, Y1, X2, Y2, HAS_COLLISION] #dtype = [ # (FRAME, np.uint), # (ID, np.uint), # (CLASS, np.object), # (X1, np.uint), # (Y1, np.uint), # (X2, np.uint), # (Y2, np.uint), # (HAS_COLLISION, np.uint), #] begin = int(collision_frame - np.floor(self.clip_len_s * fps)) if begin + self.len_thresh_s * fps < 0: # We are under the minimum threshold raise StopSignal( f"Video {item.id} is shorter than {self.len_thresh_s}s") begin = max(begin, 0) normalized_frames = np.array(bbs[FRAME]).astype(np.int) - begin data = np.array([ *zip(normalized_frames, bbs[ID], bbs[CLASS], bbs[X1], bbs[Y1], bbs[X2], bbs[Y2], bbs[HAS_COLLISION]) ], dtype=str) data = data[np.logical_and( normalized_frames >= 0, normalized_frames <= collision_frame - begin), ...] # Sort data by frame data = data[np.argsort(data[:, 0].astype(int)), ...] # Group data by frame _, unique_indices = np.unique(data[:, 0].astype(np.int), return_index=True) data = np.array(np.split(data, unique_indices[1:], axis=0)) # Mask for downsampling fps n_input_frames = collision_frame - begin n_output_frames = round(n_input_frames * (self.target_fps / fps)) sample_interval = float(n_input_frames) / n_output_frames # select frames to sample mask = np.round(np.arange(n_output_frames) * sample_interval).astype(int) mask = np.minimum(mask, data.shape[0] - 1) # Duplicate frames # n_duplicate = n_input_frames - n_output_frames # dup_mask = mask[::n_output_frames // n_duplicate][:n_duplicate] # mask = np.sort(np.concatenate((mask, dup_mask))) data = data[mask] flatten = lambda x: [z for y in x for z in y] data = flatten(data) directory = STORAGE_DIR_POSITIVES if np.any( bbs[HAS_COLLISION]) else STORAGE_DIR_NEGATIVES filename = str(metadata.id) + ".csv" np.savetxt(directory / filename, data, delimiter=',', fmt='%s,%s,%s,%s,%s,%s,%s,%s', comments='') stream = ffmpeg.input(item.filepath) stream = stream.trim(start_frame=begin + metadata.start_i, end_frame=collision_frame + metadata.start_i, duration=self.clip_len_s) stream = ffmpeg.filter(stream, 'fps', fps=self.target_fps, round='near') stream = ffmpeg.setpts(stream, expr='PTS-STARTPTS') stream = stream.output( str(STORAGE_DIR_VIDEOS / (str(metadata.id) + '.mp4'))) stream = ffmpeg.overwrite_output(stream) stream.run() print(f"Done exporting file {filename}") return item
difference = video_start - dive_start_adjusted start_offset = -1 * (difference.total_seconds()) print "Start Offset: %s " % (start_offset) dive_profile = dive_data['dive_profile'] annotator = Annotator(dive_profile, diver_name=diver_name) generate_plot_overlay(dive_profile) stream = ffmpeg.input(video_source, acodec='aac') audio = stream["a"].filter_("aecho", 0.8, 0.9, 1000, 0.3) stream2 = ffmpeg.input('lines.mov') stream2 = ffmpeg.setpts(stream2, 'PTS+%s/TB' % (start_offset - 1)) for i in xrange(0, len(dive_profile)): string = annotator.next() if (i + 1) < len(dive_profile): enable_str = 'between(t,%s,%s)' % (i + start_offset, i + 1 + start_offset) else: enable_str = 'gte(t,%s)' % (i + start_offset) stream = ffmpeg.drawtext(stream, string, x=50, y=50, fontfile=fontfile, fontsize=70, escape_text=False, shadowcolor='Black',