class_docstr: Glue together encoder transform, entropy model and decoder transform
docstr: Args:
      video: a batch of video clips with shape [B, T, C, H, W], where B is batch
          size, T is number of frames in the video, C=3 (RGB).
  
  Returns:
      A tuple of:
          2. reconstructions_frames: reconstruction of the 'decompressed' video.
              Shape is same as the original, [B, T, C, H, W].
          5. bottleneck_output: a list (possibly empty) containing any additional
              outputs from the bottleneck module, e.g. to compute rate.
docstr_tok: ["Args",":","video",":","a","batch","of","video","clips","with","shape","[","B",",","T",",","C",",","H",",","W","]",",","where","B","is","batch","size",",","T","is","number","of","frames","in","the","video",",","C=3","(","RGB",")",".","Returns",":","A","tuple","of",":","2.","reconstructions_frames",":","reconstruction","of","the","'decompressed","'","video",".","Shape","is","same","as","the","original",",","[","B",",","T",",","C",",","H",",","W","]",".","5.","bottleneck_output",":","a","list","(","possibly","empty",")","containing","any","additional","outputs","from","the","bottleneck","module",",","e.g",".","to","compute","rate","."]
code: def forward(self, video: VideoData) -> Tuple[Tensor, list]:
      """
      Args:
          video: a batch of video clips with shape [B, T, C, H, W], where B is batch
              size, T is number of frames in the video, C=3 (RGB).
  
      Returns:
          A tuple of:
              2. reconstructions_frames: reconstruction of the 'decompressed' video.
                  Shape is same as the original, [B, T, C, H, W].
              5. bottleneck_output: a list (possibly empty) containing any additional
                  outputs from the bottleneck module, e.g. to compute rate.
      """
      video.validate_shape()
      if not self.training:
          video_shape = video.spatial_shape
          inputs = self._pad(video.video_tensor, video_shape)
      else:
          video_shape = None
          inputs = video.video_tensor
  
      scenes = Scenes(
          self.analysis_transform(inputs)
      )  # [B, T, C_emb, H_emb, W_emb]
  
      cache = memoize.create_cache()
  
      # code and decode in a differentiable way
      res = self.encode_and_decode_scenes(
          scenes, cache=cache
      )  # yields NetworkOut
      rec_scenes = []
      likelihoods = []
      for r in res:
          rec_scenes.append(r.reconstruction)
          likelihoods.append(r.likelihood)
  
      reconstructions_embeddings = torch.stack(
          rec_scenes, dim=1
      )  # [B, T, C, H, W]
      likelihoods = torch.stack(likelihoods)  # [T, ...]
  
      reconstructions_frames = self.synthesis_transform(
          reconstructions_embeddings, video.shape
      )
      if not self.training:
          assert video_shape is not None, "frames_shape not found"
          h, w = video_shape
          reconstructions_frames = reconstructions_frames[..., :h, :w]
  
      return (
          reconstructions_frames,
          [likelihoods],  # bottleneck output
      )
  
imports: import itertools
  import math
  from typing import Generator, List, NamedTuple, Optional, Sequence, Tuple, Union
  import torch
  import torch.nn
  import utils.memoize
  from datamodules.video_data_api import Scenes, VideoData
  from neural.entropy_model import PreviousLatent, VCTEntropyModel
  from torch import Tensor
label_desc: Use image node_id 10 for calling the VCTPipeline obj's underlying member method code with example usage: obj.forward(video) and returns: reconstructions_frames,  list