/*
 *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "sdk/android/src/jni/encoded_image.h"

#include "api/video/encoded_image.h"
#include "rtc_base/ref_counted_object.h"
#include "rtc_base/time_utils.h"
#include "sdk/android/generated_video_jni/EncodedImage_jni.h"
#include "sdk/android/native_api/jni/java_types.h"
#include "sdk/android/src/jni/jni_helpers.h"
#include "sdk/android/src/jni/scoped_java_ref_counted.h"

namespace webrtc {
namespace jni {

namespace {

class JavaEncodedImageBuffer : public EncodedImageBufferInterface {
 public:
  JavaEncodedImageBuffer(JNIEnv* env,
                         const JavaRef<jobject>& j_encoded_image,
                         const uint8_t* payload,
                         size_t size)
      : j_encoded_image_(ScopedJavaRefCounted::Adopt(env, j_encoded_image)),
        data_(const_cast<uint8_t*>(payload)),
        size_(size) {}

  const uint8_t* data() const override { return data_; }
  uint8_t* data() override { return data_; }
  size_t size() const override { return size_; }

 private:
  // The Java object owning the buffer.
  const ScopedJavaRefCounted j_encoded_image_;

  // TODO(bugs.webrtc.org/9378): Make const, and delete above const_cast.
  uint8_t* const data_;
  size_t const size_;
};
}  // namespace

ScopedJavaLocalRef<jobject> NativeToJavaFrameType(JNIEnv* env,
                                                  VideoFrameType frame_type) {
  return Java_FrameType_fromNativeIndex(env, static_cast<int>(frame_type));
}

ScopedJavaLocalRef<jobject> NativeToJavaEncodedImage(
    JNIEnv* jni,
    const EncodedImage& image) {
  ScopedJavaLocalRef<jobject> buffer = NewDirectByteBuffer(
      jni, const_cast<uint8_t*>(image.data()), image.size());
  ScopedJavaLocalRef<jobject> frame_type =
      NativeToJavaFrameType(jni, image._frameType);
  ScopedJavaLocalRef<jobject> qp;
  if (image.qp_ != -1)
    qp = NativeToJavaInteger(jni, image.qp_);
  // TODO(bugs.webrtc.org/9378): Keep a reference to the C++ EncodedImage data,
  // and use the releaseCallback to manage lifetime.
  return Java_EncodedImage_Constructor(
      jni, buffer, /*supportsRetain=*/true,
      /*releaseCallback=*/ScopedJavaGlobalRef<jobject>(nullptr),
      static_cast<int>(image._encodedWidth),
      static_cast<int>(image._encodedHeight),
      image.capture_time_ms_ * rtc::kNumNanosecsPerMillisec, frame_type,
      static_cast<jint>(image.rotation_), image._completeFrame, qp);
}

ScopedJavaLocalRef<jobjectArray> NativeToJavaFrameTypeArray(
    JNIEnv* env,
    const std::vector<VideoFrameType>& frame_types) {
  return NativeToJavaObjectArray(
      env, frame_types, org_webrtc_EncodedImage_00024FrameType_clazz(env),
      &NativeToJavaFrameType);
}

EncodedImage JavaToNativeEncodedImage(JNIEnv* env,
                                      const JavaRef<jobject>& j_encoded_image) {
  const JavaRef<jobject>& j_buffer =
      Java_EncodedImage_getBuffer(env, j_encoded_image);
  const uint8_t* buffer =
      static_cast<uint8_t*>(env->GetDirectBufferAddress(j_buffer.obj()));
  const size_t buffer_size = env->GetDirectBufferCapacity(j_buffer.obj());

  EncodedImage frame;
  if (Java_EncodedImage_maybeRetain(env, j_encoded_image)) {
    frame.SetEncodedData(new rtc::RefCountedObject<JavaEncodedImageBuffer>(
        env, j_encoded_image, buffer, buffer_size));
  } else {
    // Encoder doesn't support retain/release, so make a copy.
    frame.SetEncodedData(EncodedImageBuffer::Create(buffer, buffer_size));
  }

  frame._encodedWidth = Java_EncodedImage_getEncodedWidth(env, j_encoded_image);
  frame._encodedHeight =
      Java_EncodedImage_getEncodedHeight(env, j_encoded_image);
  frame.rotation_ =
      (VideoRotation)Java_EncodedImage_getRotation(env, j_encoded_image);
  frame._completeFrame =
      Java_EncodedImage_getCompleteFrame(env, j_encoded_image);

  frame.qp_ = JavaToNativeOptionalInt(
                  env, Java_EncodedImage_getQp(env, j_encoded_image))
                  .value_or(-1);

  frame._frameType =
      (VideoFrameType)Java_EncodedImage_getFrameType(env, j_encoded_image);
  return frame;
}

int64_t GetJavaEncodedImageCaptureTimeNs(
    JNIEnv* env,
    const JavaRef<jobject>& j_encoded_image) {
  return Java_EncodedImage_getCaptureTimeNs(env, j_encoded_image);
}

}  // namespace jni
}  // namespace webrtc
