docstr: Add video data to summary.
  
  Note that this requires the ``moviepy`` package.
  
  Args:
      tag (string): Data identifier
      vid_tensor (torch.Tensor): Video data, the pixel value should in [0, 1]
      global_step (int): Global step value to record
      fps (float or int): Frames per second
  Shape:
      vid_tensor: :math:`(B, C, T, H, W)`. (if following tensorboardX format)
      vid_tensor: :math:`(T, H, W, C)`. (if following visdom format)
      B = batches, C = colors (1, 3, or 4), T = time frames, H = height, W = width
docstr_tok: ["Add","video","data","to","summary",".","Note","that","this","requires","the","``","moviepy","``","package",".","Args",":","tag","(","string",")",":","Data","identifier","vid_tensor","(","torch.Tensor",")",":","Video","data",",","the","pixel","value","should","in","[","0",",","1","]","global_step","(","int",")",":","Global","step","value","to","record","fps","(","float","or","int",")",":","Frames","per","second","Shape",":","vid_tensor",":",":","math",":","`","(","B",",","C",",","T",",","H",",","W",")","`",".","(","if","following","tensorboardX","format",")","vid_tensor",":",":","math",":","`","(","T",",","H",",","W",",","C",")","`",".","(","if","following","visdom","format",")","B","=","batches",",","C","=","colors","(","1",",","3",",","or","4",")",",","T","=","time","frames",",","H","=","height",",","W","=","width"]
code: def add_video(self, tag, vid_tensor, global_step=None, fps=4):
      """Add video data to summary.
  
      Note that this requires the ``moviepy`` package.
  
      Args:
          tag (string): Data identifier
          vid_tensor (torch.Tensor): Video data, the pixel value should in [0, 1]
          global_step (int): Global step value to record
          fps (float or int): Frames per second
      Shape:
          vid_tensor: :math:`(B, C, T, H, W)`. (if following tensorboardX format)
          vid_tensor: :math:`(T, H, W, C)`. (if following visdom format)
          B = batches, C = colors (1, 3, or 4), T = time frames, H = height, W = width
      """
      shape = vid_tensor.shape
      # A batch of videos (tensorboardX format) is a 5D tensor
      if len(shape) > 4:
          for i in range(shape[0]):
              # Reshape each video to Visdom's (T x H x W x C) and write each video
              # TODO: reverse the logic here, shoudl do the permutation in numpy
              if isinstance(vid_tensor, np.ndarray):
                  import torch
  
                  ind_vid = torch.from_numpy(
                      vid_tensor[i, :, :, :, :]
                  ).permute(1, 2, 3, 0)
              else:
                  ind_vid = vid_tensor[i, :, :, :, :].permute(
                      1, 2, 3, 0
                  )
              scale_factor = 255
              # Visdom looks for .ndim attr, this is something raw Tensors don't have
              # Cast to Numpy array to get .ndim attr
              ind_vid = ind_vid.numpy()
              ind_vid = (ind_vid * scale_factor).astype(np.uint8)
              assert ind_vid.shape[3] in [
                  1,
                  3,
                  4,
              ], "Visdom requires the last dimension to be color, which can be 1 (grayscale), 3 (RGB) or 4 (RGBA)"
              self.vis.video(tensor=ind_vid, opts={"fps": fps})
      else:
          self.vis.video(tensor=vid_tensor, opts={"fps": fps})
  
imports: import gc
  import numpy
  import math
  import json
  import time
  from .summary import compute_curve
  from .utils import figure_to_image
  from .x2num import make_np
label_desc: Use image node_id 9 for calling the VisdomWriter obj's underlying member method code with example usage: obj.add_video(tag, vid_tensor, global_step, fps) without return types