# Path: automl_video_ondevice/shot_classification/base_shot_classification.py
# class BaseShotClassificationInference:
#   """Interface that must be implemented for support of different model types."""
# 
#   def __init__(self, frozen_graph_path: str, label_map_path: str,
#                config: ShotClassificationConfig):
#     """Constructor for BaseShotClassificationInference.
# 
#     Args:
#       frozen_graph_path: String value for the file path of frozen graph.
#       label_map_path: String value for the file path of the label map.
#       config: ShotClassificationConfig object with shot classification configs.
#     """
#     raise NotImplementedError()
# 
#   def input_size(self) -> Size:
#     """Calculate / grab optimal input size.
# 
#     The user is expected to ensure the size of their input image is correct.
#     This is in case the user wants to do any acceleration of image resizing
#     themselves.
# 
#     Some inference engines require a specific input image size such as the
#     TFLite models, however some Tensorflow models accept a dynamic input. For
#     a dynamic input, the size outputed will have the dimensions -1, -1.
# 
#     Returns:
#       The expected input size, of the type Size.
#     """
#     return Size(256, 256)
# 
#   def run(self, timestamp: Union[int, float], frame: np.ndarray,
#           annotations: List[ShotClassificationAnnotation]) -> bool:
#     """Run inferencing for a single frame, to calculate annotations.
# 
#     Args:
#       timestamp: Generally an integer representing the microsecond of the frame,
#         however any unique number is also accepted.
#       frame: A numpy array of the shape (h, w, 3), representing an RGB image.
#         Each color channel should be a number [0, 256).
#       annotations: A list to append the output annotations to. For normal use-
#         case, this should be an empty list. The output annotations will be of
#         type ShotClassificationAnnotation.
# 
#     Returns:
#       A boolean, True if successful and False if unsuccessful.
#     """
#     raise NotImplementedError('Shot classification has not been implemented.')
# 
# Path: automl_video_ondevice/shot_classification/config.py
# class ShotClassificationConfig:
#   device: str = ""
# 
#   # Number of highest scoring labels to output.
#   # If max_results is -1 then all labels are used.
#   top_k: int = 5
# 
#   # Only labels with scores > threshold are output.
#   score_threshold: float = 0.0
# 
#   # Outputs duplicate results for several frames.
#   # Predictions from the classification model is done every 25 frames. If
#   # duplicate_results is true then each 25 frame input will return the previous
#   # output, otherwise the output array will be have a single None value.
#   duplicate_results: bool = False
# 
#   # Waits this number of frames before running inference.
#   # This is ignored by the LSTM model.
#   inference_rate: int = 25
# 
#   # Sliding window size.
#   # This is ignored by the LSTM model.
#   sliding_window_size: int = 64
# 
# Path: automl_video_ondevice/types.py
# class ShotClassificationAnnotation:
#   timestamp: float
#   class_name: str
#   confidence_score: float
# 
# Path: automl_video_ondevice/types.py
# class Size:
#   width: int
#   height: int


import copy
import numpy as np
import tensorflow.compat.v1 as tf
import automl_video_ondevice.utils as vot_utils
import tensorflow.contrib.tensorrt as trt  # pylint: disable=g-explicit-tensorflow-version-import,unused-import
from typing import List
from typing import Union
from automl_video_ondevice.shot_classification.base_shot_classification import BaseShotClassificationInference
from automl_video_ondevice.shot_classification.config import ShotClassificationConfig
from automl_video_ondevice.types import ShotClassificationAnnotation
from automl_video_ondevice.types import Size

    self.frames_since_last_inference += 1
    if self.frames_since_last_inference >= self.config.inference_rate or self._is_lstm:
      self.frames_since_last_inference = 0
      with self.graph.as_default():
        # Tensors to feed in.
        feed_dict = {
            'import/video_inputs:0': self.sliding_window,
        }
        if self._is_lstm:
          feed_dict.update({
              'import/raw_inputs/init_lstm_c:0': self.lstm_c,
              'import/raw_inputs/init_lstm_h:0': self.lstm_h
          })

        session_return = self.session.run(
            self._output_nodes, feed_dict=feed_dict)
        if self._is_lstm:
          (probabilities, self.lstm_c, self.lstm_h) = session_return
          score = probabilities
        else:
          (probabilities) = session_return
          score = probabilities[0]

        assert len(self.label_map) == len(score)

        for i in range(len(score)):
          if score[i] < self.config.score_threshold:
            continue


# Path: automl_video_ondevice/shot_classification/base_shot_classification.py
# class BaseShotClassificationInference:
#   """Interface that must be implemented for support of different model types."""
# 
#   def __init__(self, frozen_graph_path: str, label_map_path: str,
#                config: ShotClassificationConfig):
#     """Constructor for BaseShotClassificationInference.
# 
#     Args:
#       frozen_graph_path: String value for the file path of frozen graph.
#       label_map_path: String value for the file path of the label map.
#       config: ShotClassificationConfig object with shot classification configs.
#     """
#     raise NotImplementedError()
# 
#   def input_size(self) -> Size:
#     """Calculate / grab optimal input size.
# 
#     The user is expected to ensure the size of their input image is correct.
#     This is in case the user wants to do any acceleration of image resizing
#     themselves.
# 
#     Some inference engines require a specific input image size such as the
#     TFLite models, however some Tensorflow models accept a dynamic input. For
#     a dynamic input, the size outputed will have the dimensions -1, -1.
# 
#     Returns:
#       The expected input size, of the type Size.
#     """
#     return Size(256, 256)
# 
#   def run(self, timestamp: Union[int, float], frame: np.ndarray,
#           annotations: List[ShotClassificationAnnotation]) -> bool:
#     """Run inferencing for a single frame, to calculate annotations.
# 
#     Args:
#       timestamp: Generally an integer representing the microsecond of the frame,
#         however any unique number is also accepted.
#       frame: A numpy array of the shape (h, w, 3), representing an RGB image.
#         Each color channel should be a number [0, 256).
#       annotations: A list to append the output annotations to. For normal use-
#         case, this should be an empty list. The output annotations will be of
#         type ShotClassificationAnnotation.
# 
#     Returns:
#       A boolean, True if successful and False if unsuccessful.
#     """
#     raise NotImplementedError('Shot classification has not been implemented.')
# 
# Path: automl_video_ondevice/shot_classification/config.py
# class ShotClassificationConfig:
#   device: str = ""
# 
#   # Number of highest scoring labels to output.
#   # If max_results is -1 then all labels are used.
#   top_k: int = 5
# 
#   # Only labels with scores > threshold are output.
#   score_threshold: float = 0.0
# 
#   # Outputs duplicate results for several frames.
#   # Predictions from the classification model is done every 25 frames. If
#   # duplicate_results is true then each 25 frame input will return the previous
#   # output, otherwise the output array will be have a single None value.
#   duplicate_results: bool = False
# 
#   # Waits this number of frames before running inference.
#   # This is ignored by the LSTM model.
#   inference_rate: int = 25
# 
#   # Sliding window size.
#   # This is ignored by the LSTM model.
#   sliding_window_size: int = 64
# 
# Path: automl_video_ondevice/types.py
# class ShotClassificationAnnotation:
#   timestamp: float
#   class_name: str
#   confidence_score: float
# 
# Path: automl_video_ondevice/types.py
# class Size:
#   width: int
#   height: int


# Path: automl_video_ondevice/shot_classification/tf_shot_classification.py
import copy
import numpy as np
import tensorflow.compat.v1 as tf
import automl_video_ondevice.utils as vot_utils
import tensorflow.contrib.tensorrt as trt  # pylint: disable=g-explicit-tensorflow-version-import,unused-import
from typing import List
from typing import Union
from automl_video_ondevice.shot_classification.base_shot_classification import BaseShotClassificationInference
from automl_video_ondevice.shot_classification.config import ShotClassificationConfig
from automl_video_ondevice.types import ShotClassificationAnnotation
from automl_video_ondevice.types import Size


    self.frames_since_last_inference += 1
    if self.frames_since_last_inference >= self.config.inference_rate or self._is_lstm:
      self.frames_since_last_inference = 0
      with self.graph.as_default():
        # Tensors to feed in.
        feed_dict = {
            'import/video_inputs:0': self.sliding_window,
        }
        if self._is_lstm:
          feed_dict.update({
              'import/raw_inputs/init_lstm_c:0': self.lstm_c,
              'import/raw_inputs/init_lstm_h:0': self.lstm_h
          })

        session_return = self.session.run(
            self._output_nodes, feed_dict=feed_dict)
        if self._is_lstm:
          (probabilities, self.lstm_c, self.lstm_h) = session_return
          score = probabilities
        else:
          (probabilities) = session_return
          score = probabilities[0]

        assert len(self.label_map) == len(score)

        for i in range(len(score)):
          if score[i] < self.config.score_threshold:
            continue


          annotation = ShotClassificationAnnotation(