blob: 9167c9c05c2e27d71027248819b40078f631a9f8 [file] [log] [blame]
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: frkoenig@google.com (Fritz Koenig)
#include <assert.h>
#include <jni.h>
#include <string.h>
#ifdef HAVE_LIBYUV
#include <cstdlib>
#include "libyuv.h"
#endif
#include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h"
#include "vpx_ports/mem_ops.h"
#ifdef NDEBUG
# define printf(fmt, ...)
#else
# ifdef __ANDROID__
# include <android/log.h>
# define printf(fmt, ...) \
__android_log_print(ANDROID_LOG_DEBUG, "LIBVPX_ENC", fmt, ##__VA_ARGS__)
# else
# define printf(fmt, ...) \
printf(fmt "\n", ##__VA_ARGS__)
# endif
#endif
#ifdef HAVE_LIBYUV
#define align_buffer_64(var, size) \
uint8* var; \
uint8* var##_mem; \
var##_mem = reinterpret_cast<uint8*>(malloc((size) + 63)); \
var = reinterpret_cast<uint8*> \
((reinterpret_cast<intptr_t>(var##_mem) + 63) & ~63);
#define free_aligned_buffer_64(var) \
free(var##_mem); \
var = 0;
#endif
#define FUNC(RETURN_TYPE, NAME, ...) \
extern "C" { \
JNIEXPORT RETURN_TYPE Java_com_google_libvpx_LibVpxEnc_ ## NAME \
(JNIEnv * env, jobject thiz, ##__VA_ARGS__);\
} \
JNIEXPORT RETURN_TYPE Java_com_google_libvpx_LibVpxEnc_ ## NAME \
(JNIEnv * env, jobject thiz, ##__VA_ARGS__)\
#define STRING_RETURN(JNI_NAME, LIBVPX_NAME) \
FUNC(jstring, JNI_NAME) { \
printf(#JNI_NAME); \
return env->NewStringUTF(LIBVPX_NAME()); \
}
static const struct codec_item {
const char *name;
const vpx_codec_iface_t *iface;
unsigned int fourcc;
} codecs[] = {
{"vp8", &vpx_codec_vp8_cx_algo, 0x30385056},
};
#define SET_ENC_CTL_PARAM(JNI_NAME, CTL_NAME, TYPE) \
FUNC(int, vpxCodecEncCtlSet ##JNI_NAME, jlong jctx, jint jparam) { \
printf("vpxCodecEncCtlSet" #JNI_NAME); \
printf("Setting control parameter " #CTL_NAME " to %d", jparam); \
vpx_codec_ctx_t *ctx = reinterpret_cast<vpx_codec_ctx_t *>(jctx); \
return vpx_codec_control(ctx, VP8E_SET_ ##CTL_NAME, (TYPE)jparam); \
}
SET_ENC_CTL_PARAM(CpuUsed, CPUUSED, int)
SET_ENC_CTL_PARAM(EnableAutoAltRef, ENABLEAUTOALTREF, unsigned int)
SET_ENC_CTL_PARAM(NoiseSensitivity, NOISE_SENSITIVITY, unsigned int)
SET_ENC_CTL_PARAM(Sharpness, SHARPNESS, unsigned int)
SET_ENC_CTL_PARAM(StaticThreshold, STATIC_THRESHOLD, unsigned int)
SET_ENC_CTL_PARAM(TokenPartitions, TOKEN_PARTITIONS, vp8e_token_partitions)
SET_ENC_CTL_PARAM(ARNRMaxFrames, ARNR_MAXFRAMES, unsigned int)
SET_ENC_CTL_PARAM(ARNRStrength, ARNR_STRENGTH, unsigned int)
SET_ENC_CTL_PARAM(ARNRType, ARNR_TYPE, unsigned int)
SET_ENC_CTL_PARAM(Tuning, TUNING, vp8e_tuning)
SET_ENC_CTL_PARAM(CQLevel, CQ_LEVEL, unsigned int)
SET_ENC_CTL_PARAM(MaxIntraBitratePct, MAX_INTRA_BITRATE_PCT, unsigned int)
FUNC(void, vpxCodecEncInit, jlong jctx, jlong jcfg) {
printf("vpxCodecEncInit");
vpx_codec_ctx_t *ctx = reinterpret_cast<vpx_codec_ctx_t *>(jctx);
vpx_codec_enc_cfg_t *cfg = reinterpret_cast<vpx_codec_enc_cfg_t *>(jcfg);
const struct codec_item *codec = codecs;
vpx_codec_enc_init(ctx, codec->iface, cfg, 0);
}
FUNC(jboolean, vpxCodecEncode, jlong jctx, jbyteArray jframe,
jint fmt, jlong pts, jlong duration,
jlong flags, jlong deadline) {
printf("vpxCodecEncode");
jboolean success = true;
jbyte *frame = env->GetByteArrayElements(jframe, 0);
vpx_codec_ctx_t *ctx = reinterpret_cast<vpx_codec_ctx_t *>(jctx);
vpx_image_t *img = vpx_img_wrap(NULL,
(vpx_img_fmt)fmt,
ctx->config.enc->g_w,
ctx->config.enc->g_h,
0,
reinterpret_cast<unsigned char *>(frame));
if (img) {
vpx_codec_encode(ctx, img, pts, duration, flags, deadline);
vpx_img_free(img);
} else {
success = false;
}
env->ReleaseByteArrayElements(jframe, frame, 0);
return success;
}
#ifdef HAVE_LIBYUV
FUNC(jboolean, vpxCodecHaveLibyuv) {
return true;
}
bool convertEncode(vpx_codec_ctx_t *ctx, const uint8 *frame, int64_t pts,
long duration, long flags, long deadline, long fourcc,
int size) {
printf("convertEncode");
bool success = true;
const int width = ctx->config.enc->g_w;
const int height = ctx->config.enc->g_h;
const int dst_y_stride = (width + 1) & ~1;
const int dst_uv_stride = (width + 1) / 2;
const int dst_uv_size = dst_uv_stride * ((height + 1) / 2);
align_buffer_64(dst_y, (dst_y_stride * height) + (2 * dst_uv_size));
uint8 *dst_u = dst_y + (dst_y_stride * height);
uint8 *dst_v = dst_u + dst_uv_size;
int rv = libyuv::ConvertToI420(frame, size,
dst_y, dst_y_stride,
dst_u, dst_uv_stride,
dst_v, dst_uv_stride,
0, 0,
width, height,
dst_y_stride, height,
libyuv::kRotate0, fourcc);
if (rv != 0)
success = false;
if (success) {
vpx_image_t *img = vpx_img_wrap(NULL,
VPX_IMG_FMT_I420,
ctx->config.enc->g_w,
ctx->config.enc->g_h,
0,
dst_y);
if (img) {
vpx_codec_encode(ctx, img, pts, duration, flags, deadline);
vpx_img_free(img);
} else {
success = false;
}
}
free_aligned_buffer_64(dst_y);
return success;
}
FUNC(jboolean, vpxCodecConvertByteEncode, jlong jctx, jbyteArray jframe,
jlong pts, jlong duration,
jlong flags, jlong deadline,
jlong fourcc, jint size) {
printf("vpxCodecConvertByteEncode");
vpx_codec_ctx_t *const ctx = reinterpret_cast<vpx_codec_ctx_t *>(jctx);
jbyte *frame = env->GetByteArrayElements(jframe, 0);
jboolean success = convertEncode(ctx, reinterpret_cast<uint8 *>(frame), pts,
duration, flags, deadline, fourcc, size);
env->ReleaseByteArrayElements(jframe, frame, 0);
return success;
}
FUNC(jboolean, vpxCodecConvertIntEncode, jlong jctx, jintArray jframe,
jlong pts, jlong duration,
jlong flags, jlong deadline,
jlong fourcc, jint size) {
printf("vpxCodecConvertIntEncode");
vpx_codec_ctx_t *const ctx = reinterpret_cast<vpx_codec_ctx_t *>(jctx);
jint *frame = env->GetIntArrayElements(jframe, 0);
jboolean success = convertEncode(ctx, reinterpret_cast<uint8 *>(frame), pts,
duration, flags, deadline, fourcc, size);
env->ReleaseIntArrayElements(jframe, frame, 0);
return success;
}
#else
FUNC(jboolean, vpxCodecHaveLibyuv) {
return false;
}
FUNC(jboolean, vpxCodecConvertByteEncode, jlong jctx, jbyteArray jframe,
jlong pts, jlong duration,
jlong flags, jlong deadline,
jlong fourcc, jint size) {
printf("vpxCodecConvertEncode byte Stub");
return false;
}
FUNC(jboolean, vpxCodecConvertIntEncode, jlong jctx, jintArray jframe,
jlong pts, jlong duration,
jlong flags, jlong deadline,
jlong fourcc, jint size) {
printf("vpxCodecConvertEncode int Stub");
return false;
}
#endif
FUNC(jobject, vpxCodecEncGetCxData, jlong jctx) {
printf("vpxCodecEncGetCxData");
const vpx_codec_cx_pkt_t *pkt;
vpx_codec_iter_t iter = NULL;
vpx_codec_ctx_t *ctx = reinterpret_cast<vpx_codec_ctx_t *>(jctx);
jclass arrayListClass = env->FindClass("java/util/ArrayList");
assert(arrayListClass != NULL);
jmethodID alInitMethodId = env->GetMethodID(arrayListClass, "<init>", "()V");
assert(alInitMethodId != NULL);
jobject arrayList = env->NewObject(arrayListClass, alInitMethodId);
jmethodID alAddMethodId = env->GetMethodID(arrayListClass,
"add", "(Ljava/lang/Object;)Z");
assert(alAddMethodId != NULL);
jclass codecCxPkt = env->FindClass("com/google/libvpx/VpxCodecCxPkt");
assert(codecCxPkt != NULL);
jmethodID cxInitMethodId = env->GetMethodID(codecCxPkt, "<init>", "(J)V");
assert(cxInitMethodId != NULL);
jfieldID bufferId = env->GetFieldID(codecCxPkt, "buffer", "[B");
assert(bufferId != NULL);
jfieldID ptsId = env->GetFieldID(codecCxPkt, "pts", "J");
assert(ptsId != NULL);
jfieldID durationId = env->GetFieldID(codecCxPkt, "duration", "J");
assert(durationId != NULL);
jfieldID flagsId = env->GetFieldID(codecCxPkt, "flags", "I");
assert(flagsId != NULL);
jfieldID partitionId = env->GetFieldID(codecCxPkt, "partitionId", "I");
assert(partitionId != NULL);
while ((pkt = vpx_codec_get_cx_data(ctx, &iter))) {
printf("vpxCodecEncGetCxData : Data found!");
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
jobject cxPkt = env->NewObject(codecCxPkt,
cxInitMethodId,
(jlong)pkt->data.frame.sz);
env->SetLongField(cxPkt, ptsId, pkt->data.frame.pts);
env->SetLongField(cxPkt, durationId, pkt->data.frame.duration);
env->SetIntField(cxPkt, flagsId, pkt->data.frame.flags);
env->SetIntField(cxPkt, partitionId, pkt->data.frame.partition_id);
jobject jba = env->GetObjectField(cxPkt, bufferId);
assert(jba != NULL);
env->SetByteArrayRegion((jbyteArray)jba, 0, pkt->data.frame.sz,
reinterpret_cast<jbyte *>(pkt->data.frame.buf));
env->CallBooleanMethod(arrayList, alAddMethodId, cxPkt);
env->DeleteLocalRef(cxPkt);
}
}
return arrayList;
}