/**
   * encode a buffer and add in RTP input
   *
   * @param data
   */
  private void encode(byte[] data) {
    // Set timestamp
    timeStamp = SystemClock.uptimeMillis() - videoStartTime;

    // Encode frame
    byte[] encoded;
    if (frameBuffer.dataSrcWidth != 0 && frameBuffer.dataSrcHeight != 0) {
      encoded =
          NativeH264Encoder.ResizeAndEncodeFrame(
              data, timeStamp, mirroring, frameBuffer.dataSrcWidth, frameBuffer.dataSrcHeight);
    } else {
      encoded =
          NativeH264Encoder.EncodeFrame(data, timeStamp, mirroring, frameBuffer.dataScaleFactor);
    }
    int encodeResult = NativeH264Encoder.getLastEncodeStatus();
    if ((encodeResult == 0) && (encoded.length > 0)) {
      // Send SPS/PPS if IDR or first frame
      if (!nalInit || isIdrFrame(encoded)) {
        rtpInput.addFrame(sps, timeStamp);
        rtpInput.addFrame(pps, timeStamp);
        nalInit = true;
      }

      VideoOrientation videoOrientation = null;
      if (orientationHeaderId > 0) {
        videoOrientation =
            new VideoOrientation(
                orientationHeaderId, CameraOptions.convert(cameraId), mOrientation);
      }
      rtpInput.addFrame(encoded, timeStamp, videoOrientation);
    }
  }
  /** Close the player */
  public void close() {
    if (!opened) {
      // Already closed
      return;
    }
    // Close the RTP layer
    rtpInput.close();
    rtpSender.stopSession();

    try {
      // Close the video encoder
      NativeH264Encoder.DeinitEncoder();
    } catch (UnsatisfiedLinkError e) {
      if (logger.isActivated()) {
        logger.error("Can't close correctly the encoder", e);
      }
    }

    // Player is closed
    opened = false;
    notifyPlayerEventClosed();
    listeners.clear();
  }
  /**
   * Open the player
   *
   * @param remoteHost Remote host
   * @param remotePort Remote port
   */
  public void open(String remoteHost, int remotePort) {
    if (opened) {
      // Already opened
      return;
    }

    // Check video codec
    if (selectedVideoCodec == null) {
      notifyPlayerEventError("Video codec not selected");
      return;
    }

    // Init video encoder
    try {
      NativeH264EncoderParams nativeH264EncoderParams = new NativeH264EncoderParams();

      // Codec dimensions
      nativeH264EncoderParams.setFrameWidth(selectedVideoCodec.getWidth());
      nativeH264EncoderParams.setFrameHeight(selectedVideoCodec.getHeight());
      nativeH264EncoderParams.setFrameRate(selectedVideoCodec.getFramerate());
      nativeH264EncoderParams.setBitRate(selectedVideoCodec.getBitrate());

      // Codec profile and level
      nativeH264EncoderParams.setProfilesAndLevel(selectedVideoCodec.getCodecParams());

      // Codec settings optimization
      nativeH264EncoderParams.setEncMode(NativeH264EncoderParams.ENCODING_MODE_STREAMING);
      nativeH264EncoderParams.setSceneDetection(false);

      if (logger.isActivated()) {
        logger.info(
            "Init H264Encoder "
                + selectedVideoCodec.getCodecParams()
                + " "
                + selectedVideoCodec.getWidth()
                + "x"
                + selectedVideoCodec.getHeight()
                + " "
                + selectedVideoCodec.getFramerate()
                + " "
                + selectedVideoCodec.getBitrate());
      }
      int result = NativeH264Encoder.InitEncoder(nativeH264EncoderParams);
      if (result != 0) {
        notifyPlayerEventError("Encoder init failed with error code " + result);
        return;
      }
    } catch (UnsatisfiedLinkError e) {
      notifyPlayerEventError(e.getMessage());
      return;
    }

    // Init the RTP layer
    try {
      releasePort();
      rtpSender = new VideoRtpSender(videoFormat, localRtpPort);
      rtpInput = new MediaRtpInput();
      rtpInput.open();
      if (videoRenderer != null) {
        // The video renderer is supposed to be opened and so we used its RTP stream
        if (logger.isActivated()) {
          logger.debug("Player shares the renderer RTP stream");
        }
        rtpSender.prepareSession(
            rtpInput, remoteHost, remotePort, videoRenderer.getRtpInputStream(), this);
      } else {
        // The video renderer doesn't exist and so we create a new RTP stream
        rtpSender.prepareSession(rtpInput, remoteHost, remotePort, this);
      }

    } catch (Exception e) {
      notifyPlayerEventError(e.getMessage());
      return;
    }

    // Player is opened
    opened = true;
    notifyPlayerEventOpened();
  }