Last active
October 24, 2020 14:12
-
-
Save kepocnhh/554e688edbcfa150cf8348733e3529b0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Deal with Apple's deprecated 'AssertMacros.h' from Carbon-framework */ | |
#if defined(__APPLE__) && !defined(__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES) | |
# define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 | |
#endif | |
/* Intel's compiler complains if a variable which was never initialised is | |
* cast to void, which is a common idiom which we use to indicate that we | |
* are aware a variable isn't used. So we just silence that warning. | |
* See: https://github.com/swig/swig/issues/192 for more discussion. | |
*/ | |
#ifdef __INTEL_COMPILER | |
# pragma warning disable 592 | |
#endif | |
/* Fix for jlong on 64-bit x86 Solaris */ | |
#if defined(__x86_64) | |
# ifdef _LP64 | |
# undef _LP64 | |
# endif | |
#endif | |
#include <jni.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <x264.h> | |
#include "x264.h" | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
static void log( | |
JNIEnv *env, | |
jclass cls, | |
const char* message | |
) { | |
jmethodID mid = (*env)->GetStaticMethodID(env, cls, "log", "(Ljava/lang/String;)V"); | |
jstring m = (*env)->NewStringUTF(env, message); | |
(*env)->CallStaticVoidMethod(env, cls, mid, m); | |
} | |
typedef struct { | |
x264_t* x264_encoder; | |
x264_param_t x264_param; | |
x264_picture_t picture_in; | |
} EncoderContext; | |
static void releaseEncoderContext(EncoderContext* encoder_context) { | |
x264_t* x264_encoder = encoder_context->x264_encoder; | |
x264_nal_t *pp_nal; | |
int pi_nal; | |
x264_picture_t pic_out; | |
while (x264_encoder_delayed_frames(x264_encoder)) { | |
x264_encoder_encode(x264_encoder, &pp_nal, &pi_nal, NULL, &pic_out); | |
} | |
x264_encoder_close(x264_encoder); | |
encoder_context->x264_encoder = NULL; | |
free(encoder_context); | |
} | |
jlong JNICALL Java_org_videolan_x264_x264JNI_encoderStart(JNIEnv *env, jclass ignored) { | |
EncoderContext* encoder_context = (EncoderContext*) malloc(sizeof(EncoderContext)); | |
x264_param_t* x264_param = malloc(sizeof(x264_param_t)); | |
//ultrafast,superfast,veryfast,faster,fast,medium,slow,slower,veryslow,placebo | |
//film,animation,grain,stillimage,psnr,ssim,fastdecode,zerolatency,touhou | |
x264_param_default_preset(x264_param, "medium", "zerolatency"); // todo | |
int width = 640; | |
int height = 360; | |
x264_param->i_width = width; | |
x264_param->i_height = height; | |
x264_param->rc.i_bitrate = 500; // todo Kbps or bps? | |
x264_param->rc.i_rc_method = X264_RC_ABR; | |
int fps = 30; | |
x264_param->i_fps_num = fps; | |
x264_param->i_fps_den = 1; | |
x264_param->i_keyint_max = fps * 2; // todo gop? | |
x264_param->b_repeat_headers = 0; | |
//baseline,main,high,high10,high422,high444 | |
int apply_profile_result = x264_param_apply_profile(x264_param, "high"); // todo | |
if (apply_profile_result < 0) { | |
return 0; // todo | |
} | |
encoder_context->x264_param = *x264_param; | |
x264_t* x264_encoder = x264_encoder_open(x264_param); | |
if (x264_encoder == NULL) { | |
return 0; // todo | |
} | |
encoder_context->x264_encoder = x264_encoder; | |
x264_picture_t* picture_in = (x264_picture_t*) malloc(sizeof(x264_picture_t)); | |
int csp = X264_CSP_YV12; | |
x264_picture_alloc(picture_in, csp, width, height); | |
picture_in->img.i_csp = csp; // todo | |
picture_in->i_type = X264_TYPE_AUTO; | |
picture_in->img.i_stride[0] = width; | |
encoder_context->picture_in = *picture_in; | |
return (long) encoder_context; | |
} | |
void JNICALL Java_org_videolan_x264_x264JNI_encoderStop( | |
JNIEnv *env, | |
jclass ignored, | |
jlong encoder_context_pointer | |
) { | |
EncoderContext* encoder_context = (EncoderContext*) encoder_context_pointer; | |
releaseEncoderContext(encoder_context); | |
} | |
JNIEXPORT jbyteArray JNICALL Java_org_videolan_x264_x264JNI_encode( | |
JNIEnv *env, | |
jclass cls, | |
jlong encoder_context_pointer, | |
jbyteArray decoded, | |
jlong time | |
) { | |
EncoderContext* encoder_context = (EncoderContext*) encoder_context_pointer; | |
if (encoder_context == NULL) { | |
log(env, cls, "encoder_context == NULL"); | |
return NULL; | |
} | |
jbyte* input_frame = (*env)->GetByteArrayElements(env, decoded, NULL); | |
if (input_frame == NULL) { | |
log(env, cls, "input_frame == NULL"); | |
return NULL; | |
} | |
x264_nal_t* pp_nal; | |
int pi_nal; | |
x264_picture_t picture_out; | |
encoder_context->picture_in.i_pts = time; // todo | |
encoder_context->picture_in.img.plane[0] = (uint8_t *) input_frame; // todo | |
int y_size = encoder_context->x264_param.i_width * encoder_context->x264_param.i_height; | |
switch (encoder_context->picture_in.img.i_csp) { | |
case X264_CSP_YV12: | |
encoder_context->picture_in.img.i_plane = 3; | |
encoder_context->picture_in.img.plane[1] = encoder_context->picture_in.img.plane[0] + y_size; | |
encoder_context->picture_in.img.i_stride[1] = encoder_context->x264_param.i_width / 2; | |
encoder_context->picture_in.img.plane[2] = encoder_context->picture_in.img.plane[1] + y_size / 4; | |
encoder_context->picture_in.img.i_stride[2] = encoder_context->x264_param.i_width / 2; | |
break; | |
default: | |
log(env, cls, "csp not supported"); | |
return NULL; | |
} | |
int frame_size = x264_encoder_encode( | |
encoder_context->x264_encoder, | |
&pp_nal, | |
&pi_nal, | |
&encoder_context->picture_in, | |
&picture_out | |
); | |
(*env)->ReleaseByteArrayElements(env, decoded, input_frame, JNI_ABORT); | |
if (frame_size < 0) { | |
log(env, cls, "frame_size < 0"); | |
return NULL; // todo | |
} | |
if (frame_size == 0) { | |
log(env, cls, "frame_size == 0"); | |
return NULL; | |
} | |
if (pi_nal < 0) { | |
log(env, cls, "pi_nal < 0"); | |
return NULL; // todo | |
} | |
if (pi_nal == 0) { | |
log(env, cls, "pi_nal == 0"); | |
return NULL; | |
} | |
jbyteArray output_frame = (*env)->NewByteArray(env, frame_size); | |
if (output_frame == NULL) { | |
log(env, cls, "output_frame == NULL"); | |
return NULL; | |
} | |
int offset = 4; | |
jbyte* source = (jbyte*) pp_nal[0].p_payload; | |
source += offset; | |
(*env)->SetByteArrayRegion( | |
env, | |
output_frame, | |
0, | |
frame_size - offset, | |
source | |
); | |
return output_frame; | |
} | |
#ifdef __cplusplus | |
} | |
#endif | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment