def get_video_frames(
    video_path: str,
    width: int,
    height: int,
    skip_frames_start: int,
    skip_frames_end: int,
    max_num_frames: int,
    frame_sample_step: Optional[int],
) -> torch.FloatTensor:
    """
    Extract and preprocess video frames from a video file for VAE processing.

    Args:
        video_path (`str`): Path to input video file
        width (`int`): Target frame width for decoding
        height (`int`): Target frame height for decoding
        skip_frames_start (`int`): Number of frames to skip at video start
        skip_frames_end (`int`): Number of frames to skip at video end
        max_num_frames (`int`): Maximum allowed number of output frames
        frame_sample_step (`Optional[int]`):
            Frame sampling step size. If None, automatically calculated as:
            (total_frames - skipped_frames) // max_num_frames

    Returns:
        `torch.FloatTensor`: Preprocessed frames in `[F, C, H, W]` format where:
        - `F`: Number of frames (adjusted to 4k + 1 for VAE compatibility)
        - `C`: Channels (3 for RGB)
        - `H`: Frame height
        - `W`: Frame width
    """
    with decord.bridge.use_torch():
        video_reader = decord.VideoReader(uri=video_path, width=width, height=height)
        video_num_frames = len(video_reader)
        start_frame = min(skip_frames_start, video_num_frames)
        end_frame = max(0, video_num_frames - skip_frames_end)

        if end_frame <= start_frame:
            indices = [start_frame]
        elif end_frame - start_frame <= max_num_frames:
            indices = list(range(start_frame, end_frame))
        else:
            step = frame_sample_step or (end_frame - start_frame) // max_num_frames
            indices = list(range(start_frame, end_frame, step))

        frames = video_reader.get_batch(indices=indices)
        frames = frames[:max_num_frames].float()  # ensure that we don't go over the limit

        # Choose first (4k + 1) frames as this is how many is required by the VAE
        selected_num_frames = frames.size(0)
        remainder = (3 + selected_num_frames) % 4
        if remainder != 0:
            frames = frames[:-remainder]
        assert frames.size(0) % 4 == 1

        # Normalize the frames
        transform = T.Lambda(lambda x: x / 255.0 * 2.0 - 1.0)
        frames = torch.stack(tuple(map(transform, frames)), dim=0)

        return frames.permute(0, 3, 1, 2).contiguous()  # [F, C, H, W]

    Extract and preprocess video frames from a video file for VAE processing.

    Args:
        video_path (`str`): Path to input video file
        width (`int`): Target frame width for decoding
        height (`int`): Target frame height for decoding
        skip_frames_start (`int`): Number of frames to skip at video start
        skip_frames_end (`int`): Number of frames to skip at video end
        max_num_frames (`int`): Maximum allowed number of output frames
        frame_sample_step (`Optional[int]`):
            Frame sampling step size. If None, automatically calculated as:
            (total_frames - skipped_frames) // max_num_frames

    Returns:
        `torch.FloatTensor`: Preprocessed frames in `[F, C, H, W]` format where:
        - `F`: Number of frames (adjusted to 4k + 1 for VAE compatibility)
        - `C`: Channels (3 for RGB)
        - `H`: Frame height
        - `W`: Frame width
    
examples/community/cogvideox_ddim_inversion.py