class_docstr: VideoRecorder renders a nice movie of a rollout, frame by frame.
  
  It comes with an ``enabled`` option, so you can still use the same code on episodes where you don't want to record video.
  
  Note:
      You are responsible for calling :meth:`close` on a created VideoRecorder, or else you may leak an encoder process.
class_docstr_tok: ["VideoRecorder","renders","a","nice","movie","of","a","rollout",",","frame","by","frame",".","It","comes","with","an","``","enabled","``","option",",","so","you","can","still","use","the","same","code","on","episodes","where","you","do","n't","want","to","record","video",".","Note",":","You","are","responsible","for","calling",":","meth",":","`","close","`","on","a","created","VideoRecorder",",","or","else","you","may","leak","an","encoder","process","."]
docstr: Video recorder renders a nice movie of a rollout, frame by frame.
  
  Args:
      env (Env): Environment to take video of.
      path (Optional[str]): Path to the video file; will be randomly chosen if omitted.
      metadata (Optional[dict]): Contents to save to the metadata file.
      enabled (bool): Whether to actually record video, or just no-op (for convenience)
      base_path (Optional[str]): Alternatively, path to the video file without extension, which will be added.
  
  Raises:
      Error: You can pass at most one of `path` or `base_path`
      Error: Invalid path given that must have a particular file extension
docstr_tok: ["Video","recorder","renders","a","nice","movie","of","a","rollout",",","frame","by","frame",".","Args",":","env","(","Env",")",":","Environment","to","take","video","of",".","path","(","Optional","[","str","]",")",":","Path","to","the","video","file",";","will","be","randomly","chosen","if","omitted",".","metadata","(","Optional","[","dict","]",")",":","Contents","to","save","to","the","metadata","file",".","enabled","(","bool",")",":","Whether","to","actually","record","video",",","or","just","no-op","(","for","convenience",")","base_path","(","Optional","[","str","]",")",":","Alternatively",",","path","to","the","video","file","without","extension",",","which","will","be","added",".","Raises",":","Error",":","You","can","pass","at","most","one","of","`","path","`","or","`","base_path","`","Error",":","Invalid","path","given","that","must","have","a","particular","file","extension"]
code: def __init__(
      self,
      env,
      path: Optional[str] = None,
      metadata: Optional[dict] = None,
      enabled: bool = True,
      base_path: Optional[str] = None,
  ):
      """Video recorder renders a nice movie of a rollout, frame by frame.
  
      Args:
          env (Env): Environment to take video of.
          path (Optional[str]): Path to the video file; will be randomly chosen if omitted.
          metadata (Optional[dict]): Contents to save to the metadata file.
          enabled (bool): Whether to actually record video, or just no-op (for convenience)
          base_path (Optional[str]): Alternatively, path to the video file without extension, which will be added.
  
      Raises:
          Error: You can pass at most one of `path` or `base_path`
          Error: Invalid path given that must have a particular file extension
      """
      try:
          # check that moviepy is now installed
          import moviepy  # noqa: F401
      except ImportError:
          raise error.DependencyNotInstalled(
              "MoviePy is not installed, run `pip install moviepy`"
          )
  
      self._async = env.metadata.get("semantics.async")
      self.enabled = enabled
      self._closed = False
  
      self.render_history = []
      self.env = env
  
      self.render_mode = env.render_mode
  
      if (
          "rgb_array_list" != self.render_mode
          and "rgb_array" != self.render_mode
      ):
          logger.warn(
              f"Disabling video recorder because environment {env} was not initialized with any compatible video "
              "mode between `rgb_array` and `rgb_array_list`"
          )
          # Disable since the environment has not been initialized with a compatible `render_mode`
          self.enabled = False
  
      # Don't bother setting anything else if not enabled
      if not self.enabled:
          return
  
      if path is not None and base_path is not None:
          raise error.Error(
              "You can pass at most one of `path` or `base_path`."
          )
  
      required_ext = ".mp4"
      if path is None:
          if base_path is not None:
              # Base path given, append ext
              path = base_path + required_ext
          else:
              # Otherwise, just generate a unique filename
              with tempfile.NamedTemporaryFile(
                  suffix=required_ext
              ) as f:
                  path = f.name
      self.path = path
  
      path_base, actual_ext = os.path.splitext(self.path)
  
      if actual_ext != required_ext:
          raise error.Error(
              f"Invalid path given: {self.path} -- must have file extension {required_ext}."
          )
  
      self.frames_per_sec = env.metadata.get("render_fps", 30)
  
      self.broken = False
  
      # Dump metadata
      self.metadata = metadata or {}
      self.metadata["content_type"] = "video/mp4"
      self.metadata_path = f"{path_base}.meta.json"
      self.write_metadata()
  
      logger.info(f"Starting new video recorder writing to {self.path}")
      self.recorded_frames = []
  
file_path: gym/gym/wrappers/monitoring/video_recorder.py
imports: import json
  import os
  import os.path
  import tempfile
  from typing import List, Optional
  from gym import error, logger
label_desc: Use image node_id 1 to create a new VideoRecorder object  with example: obj = VideoRecorder(env, path, metadata, enabled, base_path)