code: def perspective_transform_and_shake(
      video_path: str,
      output_path: Optional[str] = None,
      sigma: float = 50.0,
      shake_radius: float = 0.0,
      seed: Optional[int] = None,
      metadata: Optional[List[Dict[str, Any]]] = None,
  ) -> str:
      """
      Apply a perspective transform to the video so it looks like it was taken
      as a photo from another device (e.g. taking a video from your phone of a
      video on a computer). Also has a shake factor to mimic the shakiness of
      someone holding a phone.
  
      @param video_path: the path to the video to be augmented
  
      @param output_path: the path in which the resulting video will be stored.
          If not passed in, the original video file will be overwritten
  
      @param sigma: the standard deviation of the distribution of destination coordinates.
          The larger the sigma value, the more intense the transform
  
      @param shake_radius: determines the amount by which to "shake" the video; the larger
          the radius, the more intense the shake.
  
      @param seed: if provided, this will set the random seed to ensure consistency
          between runs
  
      @param metadata: if set to be a list, metadata about the function execution
          including its name, the source & dest duration, fps, etc. will be appended
          to the inputted list. If set to None, no metadata will be appended or returned
  
      @returns: the path to the augmented video
      """
      func_kwargs = helpers.get_func_kwargs(
          metadata, locals(), video_path
      )
  
      perspective_func = functools.partial(
          imaugs.perspective_transform, sigma=sigma, seed=seed
      )
  
      duration = float(helpers.get_video_info(video_path)["duration"])
      rng = (
          np.random.RandomState(seed) if seed is not None else np.random
      )
  
      def get_dx_dy(frame_number: int) -> Dict:
          u = math.sin(frame_number / duration * math.pi) ** 2
          return {
              "dx": u * rng.normal(0, shake_radius),
              "dy": u * rng.normal(0, shake_radius),
          }
  
      vdutils.apply_to_each_frame(
          perspective_func, video_path, output_path, get_dx_dy
      )
  
      if metadata is not None:
          helpers.get_metadata(
              metadata=metadata,
              function_name="perspective_transform_and_shake",
              **func_kwargs,
          )
  
      return output_path or video_path
  
imports: import functools
  import math
  import os
  import shutil
  import tempfile
  from typing import Any, Callable, Dict, List, Optional, Tuple, Union
  import numpy
  from augly import audio, image, utils
  from augly.audio import utils
  from augly.video import helpers, utils
  from augly.video.augmenters import cv2, ffmpeg
label_desc: Use image node_id 32 for calling a global function with example usage: perspective_transform_and_shake(video_path, output_path, sigma, shake_radius, seed, metadata) and returns: unknown, dict