class_docstr: WriteGear handles various powerful Video-Writer Tools that provide us the freedom to do almost anything imaginable with multimedia data.
  
  WriteGear API provides a complete, flexible, and robust wrapper around FFmpeg, a leading multimedia framework. WriteGear can process real-time frames into a lossless
  compressed video-file with any suitable specification (such as bitrate, codec, framerate, resolution, subtitles, etc.). It is powerful enough to perform complex tasks such as
  Live-Streaming (such as for Twitch) and Multiplexing Video-Audio with real-time frames in way fewer lines of code.
  
  Best of all, WriteGear grants users the complete freedom to play with any FFmpeg parameter with its exclusive Custom Commands function without relying on any
  third-party API.
  
  In addition to this, WriteGear also provides flexible access to OpenCV's VideoWriter API tools for video-frames encoding without compression.
  
  ??? tip "Modes of Operation"
  
      WriteGear primarily operates in following modes:
  
      * **Compression Mode**: In this mode, WriteGear utilizes powerful **FFmpeg** inbuilt encoders to encode lossless multimedia files.
                              This mode provides us the ability to exploit almost any parameter available within FFmpeg, effortlessly and flexibly,
                              and while doing that it robustly handles all errors/warnings quietly.
  
      * **Non-Compression Mode**: In this mode, WriteGear utilizes basic **OpenCV's inbuilt VideoWriter API** tools. This mode also supports all
                                  parameters manipulation available within VideoWriter API, but it lacks the ability to manipulate encoding parameters
                                  and other important features like video compression, audio encoding, etc.
class_docstr_tok: ["WriteGear","handles","various","powerful","Video-Writer","Tools","that","provide","us","the","freedom","to","do","almost","anything","imaginable","with","multimedia","data",".","WriteGear","API","provides","a","complete",",","flexible",",","and","robust","wrapper","around","FFmpeg",",","a","leading","multimedia","framework",".","WriteGear","can","process","real-time","frames","into","a","lossless","compressed","video-file","with","any","suitable","specification","(","such","as","bitrate",",","codec",",","framerate",",","resolution",",","subtitles",",","etc.",")",".","It","is","powerful","enough","to","perform","complex","tasks","such","as","Live-Streaming","(","such","as","for","Twitch",")","and","Multiplexing","Video-Audio","with","real-time","frames","in","way","fewer","lines","of","code",".","Best","of","all",",","WriteGear","grants","users","the","complete","freedom","to","play","with","any","FFmpeg","parameter","with","its","exclusive","Custom","Commands","function","without","relying","on","any","third-party","API",".","In","addition","to","this",",","WriteGear","also","provides","flexible","access","to","OpenCV","'s","VideoWriter","API","tools","for","video-frames","encoding","without","compression",".","?","?","?","tip","``","Modes","of","Operation","''","WriteGear","primarily","operates","in","following","modes",":","*","*","*","Compression","Mode","*","*",":","In","this","mode",",","WriteGear","utilizes","powerful","*","*","FFmpeg","*","*","inbuilt","encoders","to","encode","lossless","multimedia","files",".","This","mode","provides","us","the","ability","to","exploit","almost","any","parameter","available","within","FFmpeg",",","effortlessly","and","flexibly",",","and","while","doing","that","it","robustly","handles","all","errors\/warnings","quietly",".","*","*","*","Non-Compression","Mode","*","*",":","In","this","mode",",","WriteGear","utilizes","basic","*","*","OpenCV","'s","inbuilt","VideoWriter","API","*","*","tools",".","This","mode","also","supports","all","parameters","manipulation","available","within","VideoWriter","API",",","but","it","lacks","the","ability","to","manipulate","encoding","parameters","and","other","important","features","like","video","compression",",","audio","encoding",",","etc","."]
docstr: This constructor method initializes the object state and attributes of the WriteGear class.
  
  Parameters:
      output (str): sets the valid filename/path/URL for encoding.
      compression_mode (bool): selects the WriteGear's Primary Mode of Operation.
      custom_ffmpeg (str): assigns the location of custom path/directory for custom FFmpeg executables.
      logging (bool): enables/disables logging.
      output_params (dict): provides the flexibility to control supported internal parameters and FFmpeg properties.
docstr_tok: ["This","constructor","method","initializes","the","object","state","and","attributes","of","the","WriteGear","class",".","Parameters",":","output","(","str",")",":","sets","the","valid","filename\/path\/URL","for","encoding",".","compression_mode","(","bool",")",":","selects","the","WriteGear","'s","Primary","Mode","of","Operation",".","custom_ffmpeg","(","str",")",":","assigns","the","location","of","custom","path\/directory","for","custom","FFmpeg","executables",".","logging","(","bool",")",":","enables\/disables","logging",".","output_params","(","dict",")",":","provides","the","flexibility","to","control","supported","internal","parameters","and","FFmpeg","properties","."]
code: def __init__(
      self,
      output="",
      compression_mode=True,
      custom_ffmpeg="",
      logging=False,
      **output_params,
  ):
      """
      This constructor method initializes the object state and attributes of the WriteGear class.
  
      Parameters:
          output (str): sets the valid filename/path/URL for encoding.
          compression_mode (bool): selects the WriteGear's Primary Mode of Operation.
          custom_ffmpeg (str): assigns the location of custom path/directory for custom FFmpeg executables.
          logging (bool): enables/disables logging.
          output_params (dict): provides the flexibility to control supported internal parameters and FFmpeg properties.
      """
      # print current version
      logcurr_vidgear_ver(logging=logging)
  
      # check if user not using depreciated `output_filename` parameter
      assert (
          not "output_filename" in output_params
      ), "[WriteGear:ERROR] :: The `output_filename` parameter has been renamed to `output`. Refer Docs for more info."
  
      # assign parameter values to class variables
      # enables compression if enabled
      self.__compression = (
          compression_mode
          if isinstance(compression_mode, bool)
          else False
      )
      # specifies if machine in-use is running Windows OS or not
      self.__os_windows = True if os.name == "nt" else False
      # enable logging if specified
      self.__logging = logging if isinstance(logging, bool) else False
      # initialize various important class variables
      self.__output_parameters = {}  # handles output parameters
      self.__inputheight = None  # handles input frames height
      self.__inputwidth = None  # handles input frames width
      self.__inputchannels = None  # handles input frames channels
      self.__inputdtype = None  # handles input frames dtype
      self.__process = None  # handles Encoding class/process
      self.__ffmpeg = ""  # handles valid FFmpeg binaries location
      self.__initiate_process = True  # handles initiate one-time process for generating pipeline
      self.__ffmpeg_window_disabler_patch = False  # handles disabling window for ffmpeg subprocess on Windows
      self.__out_file = None  # handles output
      gstpipeline_mode = False  # handles GStreamer Pipeline Mode
  
      # handles output
      if not output:
          # raise error otherwise
          raise ValueError(
              "[WriteGear:ERROR] :: Kindly provide a valid `output` value. Refer Docs for more info."
          )
      else:
          # validate output is a system file/directory
          # and Whether WriteGear has the write rights
          # to specified file/directory or not
          abs_path = os.path.abspath(output)
          if check_WriteAccess(
              os.path.dirname(abs_path),
              is_windows=self.__os_windows,
              logging=self.__logging,
          ):
              # check if given path is directory
              if os.path.isdir(abs_path):
                  # then, auto-assign valid name and adds it to path
                  abs_path = os.path.join(
                      abs_path,
                      "VidGear-{}.mp4".format(
                          time.strftime("%Y%m%d-%H%M%S")
                      ),
                  )
              # assign output file absolute
              # path to class variable if valid
              self.__out_file = abs_path
          else:
              # log note otherwise
              logger.info(
                  "`{}` isn't a valid system path or directory. Skipped!".format(
                      output
                  )
              )
  
      # cleans and reformat output parameters
      self.__output_parameters = {
          str(k).strip(): str(v).strip()
          if not isinstance(v, (list, tuple, int, float))
          else v
          for k, v in output_params.items()
      }
      # log it if specified
      self.__logging and logger.debug(
          "Output Parameters: `{}`".format(self.__output_parameters)
      )
  
      # handles FFmpeg binaries validity
      # in Compression mode
      if self.__compression:
          # log it if specified
          self.__logging and logger.debug(
              "Compression Mode is enabled therefore checking for valid FFmpeg executable."
          )
  
          # handles where to save the downloaded FFmpeg Static Binaries
          # on Windows(if specified)
          __ffmpeg_download_path = self.__output_parameters.pop(
              "-ffmpeg_download_path", ""
          )
          # check if value is valid
          if not isinstance(__ffmpeg_download_path, (str)):
              # reset improper values
              __ffmpeg_download_path = ""
  
          # handle user-defined output resolution (must be a tuple or list)
          # in Compression Mode only.
          self.__output_dimensions = self.__output_parameters.pop(
              "-output_dimensions", None
          )
          # check if value is valid
          if not isinstance(self.__output_dimensions, (list, tuple)):
              # reset improper values
              self.__output_dimensions = None
  
          # handle user defined input framerate of encoding pipeline
          # in Compression Mode only.
          self.__inputframerate = self.__output_parameters.pop(
              "-input_framerate", 0.0
          )
          # check if value is valid
          if not isinstance(self.__inputframerate, (float, int)):
              # reset improper values
              self.__inputframerate = 0.0
          else:
              # must be float
              self.__inputframerate = float(self.__inputframerate)
  
          # handle user-defined input frames pixel-format in Compression Mode only.
          self.__inputpixfmt = self.__output_parameters.pop(
              "-input_pixfmt", None
          )
          # check if value is valid
          if not isinstance(self.__inputpixfmt, str):
              # reset improper values
              self.__inputpixfmt = None
          else:
              # must be exact
              self.__inputpixfmt = self.__inputpixfmt.strip()
  
          # handle user-defined FFmpeg command pre-headers(must be a list)
          # in Compression Mode only.
          self.__ffmpeg_preheaders = self.__output_parameters.pop(
              "-ffpreheaders", []
          )
          # check if value is valid
          if not isinstance(self.__ffmpeg_preheaders, list):
              # reset improper values
              self.__ffmpeg_preheaders = []
  
          # handle the special-case of forced-termination (only for Compression mode)
          disable_force_termination = self.__output_parameters.pop(
              "-disable_force_termination",
              False if ("-i" in self.__output_parameters) else True,
          )
          # check if value is valid
          if isinstance(disable_force_termination, bool):
              self.__forced_termination = not (
                  disable_force_termination
              )
          else:
              # handle improper values
              self.__forced_termination = (
                  True if ("-i" in self.__output_parameters) else False
              )
  
          # handles disabling window for ffmpeg subprocess on Windows OS (only for Compression mode)
          # this patch prevents ffmpeg creation window from opening when building exe files
          ffmpeg_window_disabler_patch = self.__output_parameters.pop(
              "-disable_ffmpeg_window", False
          )
          # check if value is valid
          if not self.__os_windows or logging:
              logger.warning(
                  "Optional `-disable_ffmpeg_window` flag is only available on Windows OS with `logging=False`. Discarding!"
              )
          elif isinstance(ffmpeg_window_disabler_patch, bool):
              self.__ffmpeg_window_disabler_patch = (
                  ffmpeg_window_disabler_patch
              )
          else:
              # handle improper values
              self.__ffmpeg_window_disabler_patch = False
  
          # validate the FFmpeg path/binaries and returns valid executable FFmpeg
          # location/path (also auto-downloads static binaries on Windows OS)
          self.__ffmpeg = get_valid_ffmpeg_path(
              custom_ffmpeg,
              self.__os_windows,
              ffmpeg_download_path=__ffmpeg_download_path,
              logging=self.__logging,
          )
          # check if valid executable FFmpeg location/path
          if self.__ffmpeg:
              # log it if found
              self.__logging and logger.debug(
                  "Found valid FFmpeg executable: `{}`.".format(
                      self.__ffmpeg
                  )
              )
          else:
              # otherwise disable Compression Mode
              # and switch to Non-compression mode
              logger.warning(
                  "Disabling Compression Mode since no valid FFmpeg executable found on this machine!"
              )
              if self.__logging and not self.__os_windows:
                  logger.debug(
                      "Kindly install a working FFmpeg module or provide a valid custom FFmpeg binary path. See docs for more info."
                  )
              # compression mode disabled
              self.__compression = False
      else:
          # handle GStreamer Pipeline Mode (only for Non-compression mode)
          if "-gst_pipeline_mode" in self.__output_parameters:
              # check if value is valid
              if isinstance(
                  self.__output_parameters["-gst_pipeline_mode"], bool
              ):
                  gstpipeline_mode = self.__output_parameters[
                      "-gst_pipeline_mode"
                  ] and check_gstreamer_support(logging=logging)
                  self.__logging and logger.debug(
                      "GStreamer Pipeline Mode successfully activated!"
                  )
              else:
                  # reset improper values
                  gstpipeline_mode = False
                  # log it
                  self.__logging and logger.warning(
                      "GStreamer Pipeline Mode failed to activate!"
                  )
  
      # handle output differently in Compression/Non-compression Modes
      if self.__compression and self.__ffmpeg:
          # check if output falls in exclusive cases
          if self.__out_file is None:
              if (
                  platform.system() == "Linux"
                  and pathlib.Path(output).is_char_device()
              ):
                  # check whether output is a Linux video device path (such as `/dev/video0`)
                  self.__logging and logger.debug(
                      "Path:`{}` is a valid Linux Video Device path.".format(
                          output
                      )
                  )
                  self.__out_file = output
              elif is_valid_url(
                  self.__ffmpeg, url=output, logging=self.__logging
              ):
                  # check whether output is a valid URL instead
                  self.__logging and logger.debug(
                      "URL:`{}` is valid and successfully configured for streaming.".format(
                          output
                      )
                  )
                  self.__out_file = output
              else:
                  # raise error otherwise
                  raise ValueError(
                      "[WriteGear:ERROR] :: output value:`{}` is not supported in Compression Mode.".format(
                          output
                      )
                  )
          # log if forced termination is enabled
          self.__forced_termination and logger.debug(
              "Forced termination is enabled for this FFmpeg process."
          )
          # log Compression is enabled
          self.__logging and logger.debug(
              "Compression Mode with FFmpeg backend is configured properly."
          )
      else:
          # raise error if not valid input
          if self.__out_file is None and not gstpipeline_mode:
              raise ValueError(
                  "[WriteGear:ERROR] :: output value:`{}` is not supported in Non-Compression Mode.".format(
                      output
                  )
              )
  
          # check if GStreamer Pipeline Mode is enabled
          if gstpipeline_mode:
              # enforce GStreamer backend
              self.__output_parameters["-backend"] = "CAP_GSTREAMER"
              # enforce original output value
              self.__out_file = output
  
          # log it
          self.__logging and logger.debug(
              "Non-Compression Mode is successfully configured in GStreamer Pipeline Mode."
          )
  
          # log if Compression is disabled
          logger.critical(
              "Compression Mode is disabled, Activating OpenCV built-in Writer!"
          )
  
file_path: vidgear/vidgear/gears/writegear.py
imports: import os
  import cv2
  import time
  import platform
  import pathlib
  import logging
  import subprocess
  from .helper import capPropId, dict2Args, is_valid_url, logger_handler, check_WriteAccess, get_valid_ffmpeg_path, get_supported_pixfmts, get_supported_vencoders, check_gstreamer_support, logcurr_vidgear_ver
label_desc: Use image node_id 1 to create a new WriteGear object  with example: obj = WriteGear(output, compression_mode, custom_ffmpeg, logging)