def frame_copy(n: int, f: VideoFrame) -> VideoFrame: fout = f.copy() frame_data, frame_props = self.get_frame(n, pipe=False) if self.compression_method == 'lzo': frame_data = pickle.loads(lzo.decompress(frame_data)) for p in range(fout.format.num_planes): np.asarray(fout.get_write_array(p))[:] = frame_data[p] for i in frame_props: fout.props[i] = frame_props[i] return fout
def render_raw_videoframe(self, vs_frame: vs.VideoFrame) -> Qt.QPixmap: import ctypes frame_data = vs_frame.get_read_ptr(0) frame_stride = vs_frame.get_stride(0) # frame_itemsize = vs_frame.get_read_array(0).itemsize frame_itemsize = vs_frame.format.bytes_per_sample # powerful spell. do not touch frame_data = ctypes.cast( frame_data, ctypes.POINTER(ctypes.c_char * (frame_itemsize * vs_frame.width * vs_frame.height)))[0] # type: ignore frame_image = Qt.QImage(frame_data, vs_frame.width, vs_frame.height, frame_stride, Qt.QImage.Format_RGB32) frame_pixmap = Qt.QPixmap.fromImage(frame_image) return frame_pixmap
def np_to_frame(array: np.ndarray, frame: vs.VideoFrame, order: tuple = (2, 1, 0)) -> vs.VideoFrame: """ Copies each channel from a numpy array into a vs.VideoFrame. It expects the numpy array to be BGR, with the dimension count (C) last in the shape, so HWC or WHC. :param array: Numpy array to retrieve planes from. :param frame: VapourSynth frame to store retrieved planes. :param order: Specify input order of the numpy array color dimensions. It is most likely 2,1,0 (BGR). :returns: New frame with planes from numpy array """ frame = frame.copy() if list(order) != [0, 1, 2]: array = np.transpose(array[:, :, order], (0, 1, 2)) # `order` to RGB for plane in range(array.shape[-1]): np.copyto( np.asarray(frame.get_write_array(plane)), array[:, :, plane], casting="unsafe" ) return frame
def frame_to_array(f: vs.VideoFrame) -> np.ndarray: """ Simple wrapper to turn a video frame into an numpy array """ global vs_api_below4 if vs_api_below4 is None: vs_api_below4 = vs.__api_version__.api_major < 4 # type: ignore return np.dstack([ f.get_read_array(p) for p in range(f.format.num_planes) # type: ignore ] if vs_api_below4 else f)
def extract_value(vs_frame: vs.VideoFrame, i: int, idx: int) \ -> Union[int, float]: fmt = vs_frame.format if fmt.sample_type == vs.FLOAT and fmt.bytes_per_sample == 2: ptr = ctypes.cast( vs_frame.get_read_ptr(i), ctypes.POINTER(ctypes.c_char * (2 * vs_frame.width * vs_frame.height))) val = unpack('e', ptr.contents[(idx * 2):(idx * 2 + 2)])[0] # type: ignore return cast(float, val) else: ptr = ctypes.cast( vs_frame.get_read_ptr(i), ctypes.POINTER( self.data_types[fmt.sample_type][fmt.bytes_per_sample] * ( # type:ignore vs_frame.width * vs_frame.height))) return ptr.contents[idx] # type: ignore
def _wrap_frame(frame: VideoFrame) -> VideoNode: core = get_proxy_or_core() bc = core.std.BlankClip(width=frame.width, height=frame.height, length=1, fpsnum=1, fpsden=1, format=frame.format.id) return bc.std.ModifyFrame([bc], lambda n, f: frame.copy())
def render_raw_videoframe( self, vs_frame: vs.VideoFrame, vs_frame_alpha: Optional[vs.VideoFrame] = None) -> Qt.QPixmap: # powerful spell. do not touch frame_data_pointer = ctypes.cast( vs_frame.get_read_ptr(0), ctypes.POINTER(ctypes.c_char * (vs_frame.format.bytes_per_sample * vs_frame.width * vs_frame.height)))[0] frame_image = Qt.QImage(frame_data_pointer, vs_frame.width, vs_frame.height, vs_frame.get_stride(0), Qt.QImage.Format_RGB32) if vs_frame_alpha is None: result_pixmap = Qt.QPixmap.fromImage(frame_image) else: alpha_data_pointer = ctypes.cast( vs_frame_alpha.get_read_ptr(0), ctypes.POINTER( ctypes.c_char * (vs_frame_alpha.format.bytes_per_sample * vs_frame_alpha.width * vs_frame_alpha.height)))[0] alpha_image = Qt.QImage(alpha_data_pointer, vs_frame.width, vs_frame.height, vs_frame_alpha.get_stride(0), Qt.QImage.Format_Alpha8) result_image = Qt.QImage(vs_frame.width, vs_frame.height, Qt.QImage.Format_ARGB32_Premultiplied) painter = Qt.QPainter(result_image) painter.setCompositionMode(Qt.QPainter.CompositionMode_Source) painter.drawImage(0, 0, frame_image) painter.setCompositionMode( Qt.QPainter.CompositionMode_DestinationIn) painter.drawImage(0, 0, alpha_image) painter.end() result_pixmap = Qt.QPixmap.fromImage(result_image) return result_pixmap
def render_raw_videoframe( self, vs_frame: vs.VideoFrame, vs_frame_alpha: Optional[vs.VideoFrame] = None) -> Qt.QImage: # powerful spell. do not touch frame_data_pointer = ctypes.cast( vs_frame.get_read_ptr(0), ctypes.POINTER(ctypes.c_char * (vs_frame.format.bytes_per_sample * vs_frame.width * vs_frame.height))) frame_image = Qt.QImage(frame_data_pointer.contents, vs_frame.width, vs_frame.height, vs_frame.get_stride(0), Qt.QImage.Format_RGB32) if vs_frame_alpha is None: return frame_image alpha_data_pointer = ctypes.cast( vs_frame_alpha.get_read_ptr(0), ctypes.POINTER(ctypes.c_char * (vs_frame_alpha.format.bytes_per_sample * vs_frame_alpha.width * vs_frame_alpha.height))) alpha_image = Qt.QImage(alpha_data_pointer.contents, vs_frame.width, vs_frame.height, vs_frame_alpha.get_stride(0), Qt.QImage.Format_Alpha8) result_image = Qt.QImage(vs_frame.width, vs_frame.height, Qt.QImage.Format_ARGB32_Premultiplied) painter = Qt.QPainter(result_image) painter.setCompositionMode(Qt.QPainter.CompositionMode_Source) painter.drawImage(0, 0, frame_image) painter.setCompositionMode(Qt.QPainter.CompositionMode_DestinationIn) painter.drawImage(0, 0, alpha_image) if self.main.CHECKERBOARD_ENABLED: painter.setCompositionMode( Qt.QPainter.CompositionMode_DestinationOver) painter.drawImage(0, 0, self.checkerboard) painter.end() return result_image
def extract_value(vs_frame: vs.VideoFrame, plane: int, pos: Qt.QPoint) -> Union[int, float]: fmt = vs_frame.format stride = vs_frame.get_stride(plane) if fmt.sample_type == vs.FLOAT and fmt.bytes_per_sample == 2: ptr = ctypes.cast( vs_frame.get_read_ptr(plane), ctypes.POINTER(ctypes.c_char * (stride * vs_frame.height))) offset = pos.y() * stride + pos.x() * 2 val = unpack('e', ptr.contents[offset:(offset + 2)])[0] # type: ignore return cast(float, val) else: ptr = ctypes.cast( vs_frame.get_read_ptr(plane), ctypes.POINTER( self.data_types[fmt.sample_type][fmt.bytes_per_sample] * ( # type:ignore stride * vs_frame.height))) logical_stride = stride // fmt.bytes_per_sample idx = pos.y() * logical_stride + pos.x() return ptr.contents[idx] # type: ignore
def extract_plane(buffer: Buffer, offset: int, frame: VideoFrame, planeno: int): """ Extracts the plane with the VapourSynth R37+ array-API. :param buffer: Target buffer :param offset: Where to write it :param frame: The frame :param planeno: The plane number :return: The extracted image. """ arr = frame.get_read_array(planeno) length = len(arr) if length + offset > len(buffer): raise BufferError("Buffer too short.") buffer[offset:offset + length] = arr return len(arr)
def disable_rff(n: int, f: vs.VideoFrame) -> vs.VideoFrame: f = f.copy() f.props["PVSFlagRff"] = 0 return f
def frame_to_np(frame: vs.VideoFrame) -> np.dstack: """ Alternative to cv2.imread() that will directly read images to a numpy array. :param frame: VapourSynth frame from a clip """ return np.dstack([np.asarray(frame.get_read_array(i)) for i in range(frame.format.num_planes)])
def write_subs(self, n: int, f: vs.VideoFrame, clip: vs.VideoNode, sub: str) -> vs.VideoNode: """ Log scene changes to a file. Notes ----- The file is formatted as <frame_number> 0 1 if it's the last frame in the scene, 1 0 if it's the first one Parameters ---------- n: The frame number f: The frame properties clip: The input clip sub: The sub filename Returns ------- vs.VideoNode The same clip as the input """ if f.props["_SceneChangeNext"] == 1 or f.props["_SceneChangePrev"] == 1: img = Image.fromarray(np.array(f.get_read_array(0), copy=False)) if not img.getextrema() == (0, 0): if f.props["_SceneChangePrev"] == 1: frame_time = convert((n * clip.fps_den / clip.fps_num)) img = ImageOps.invert(img) self.sub_count += 1 self.frame_num = n ocr_out = tesserocr.image_to_text( img, lang=self.language, psm=tesserocr.PSM.SINGLE_BLOCK, path=self.tessdata, ) with open(sub, "a") as sub_io: sub_io.write(f""" {self.sub_count} {frame_time} --> {ocr_out} """) elif f.props["_SceneChangeNext"] == 1: frame_time = convert( ((n + 1) * clip.fps_den / clip.fps_num)) with open(sub, "r") as sub_io: lines = sub_io.readlines() with open(sub, "w") as sub_io: for idx, line in enumerate(lines): if (line.strip() == str(self.sub_count) and self.frame_num < n): times = lines[idx + 1].strip() lines[idx + 1] = f"{times} {frame_time}\n" elif (line.strip() == str(self.sub_count - 1) and self.frame_num > n): times = lines[idx + 1].strip() lines[idx + 1] = f"{times} {frame_time}\n" sub_io.writelines(lines) return clip