코드가 도움이 될 수 있습니다. 이러한 매크로가 무엇인지 생각하고 Java와 코코아 문제를 서로 분리하는 방법을 생각해 보면 어렵지 않습니다.
당신이 기억해야하는 것은 JNF_COCOA_ENTER 및 JNF_COCOA_EXIT 당신을 위해 두 가지 일을 할 것입니다 :
그들은 내부에 정의 된 변수는 외부에서 사용할 수 없습니다 그래서 (로컬 범위를 설정 - 이것은 당신이 할 수 있도록 "바보"입니다 당신이 만지지 말아야 할 변수가있는 것들)과 자동 릴리즈 풀을 설정하기 때문에 스코프가 사라지면 그 범위 내에서 "autoreleased"된 코코아 객체는 사라질 것입니다. (이것은 로컬 스코프가 유용하거나 도움이되는 이유 중 일부입니다.) 자바에서 코코아 예외를 잡을 수 있도록 예외 파싱을 수행합니다.
즉, 다음 코드는 법적으로, 메모리 액세스 및 데이터 소유권을 관리하는 데 매우주의해야합니다. 가능한 경우 Java 소유권과 Objective-C 소유권을 혼합하거나 객체가 소유권을 관리하도록하지 말고 Java 객체가 GCed 될 때 정리하십시오.
jbyteArray bytes;
JNF_COCOA_ENTER(env);
// Assign and full the bytes array here, doing any requisite transformations.
// Remember to COPY any data out of COCOA objects, as references will be dead soon!
JNF_COCOA_EXIT(env);
return bytes;
C에서 Java 개체를 사용하는 것은 복잡하지만 작동하지 않습니다. 여전히 메서드 호출의 수는 중요하지 않으며 뒤로 점프하고 네 번째 점은 시간이 많이 소요되므로이 메서드를 자주 호출하거나 시간이 중요한 경우 가능한 한 기본 형식을 사용하십시오.
델리게이트에서 데이터를 코코아에서 자바로 푸시해야하는 경우, 상황은 좀 더 복잡하지만 작동하지 않습니다. 다음은 QTCubed라는 프로젝트의 세그먼트입니다. 정확히 그 일을합니다. didOutputVideoFrame은 델리게이트 메소드이며,이 객체는 메소드 인 JNI로부터 타겟 Java Object Reference와 Java Environment로 초기화되어야합니다 (MUST). 초기화가되면 위임 객체로 설정되고 카메라에서 업데이트를받습니다. 당신은 실행중인 응용 프로그램이 있으면
protected void pushFrame(byte[] frameData, int formatInt, int width, int height, float frameRate);
protected void pushFrame(short[] frameData, int formatInt, int width, int height, float frameRate);
protected void pushFrame(int[] frameData, int formatInt, int width, int height, float frameRate);
는, 사용 장비는 당신이 참조를 폐기하고 있는지 확인하려면 다음 여기에
@implementation QTKitCaptureDecompressedVideoOutput
- (QTKitCaptureDecompressedVideoOutput *)initWithEnv:(JNIEnv *) env javaObject:(jobject) javaObjectRef {
[super init];
// Save a reference to the VM
(*env)->GetJavaVM(env,&g_vm);
// Create a global reference to this object so we can access it later
objectRef = (*env)->NewGlobalRef(env,javaObjectRef);
return self;
}
- (void)captureOutput:(QTCaptureOutput *)captureOutput didOutputVideoFrame:(CVImageBufferRef)videoFrame withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection {
// Move into Java to deliver the data
JNIEnv *env;
(*g_vm)->AttachCurrentThread (g_vm, (void **) &env, NULL);
void * rawData = [sampleBuffer bytesForAllSamples];
int length = [sampleBuffer lengthForAllSamples];
QTFormatDescription * formatDescription = [sampleBuffer formatDescription];
QTTime duration = [sampleBuffer duration];
float frameDuration = duration.timeValue/duration.timeScale;
float fps = 1/frameDuration;
jint format = [formatDescription formatType];
NSValue * pixelSize = [formatDescription attributeForKey:QTFormatDescriptionVideoEncodedPixelsSizeAttribute];
NSSize size = [pixelSize sizeValue];
jint width = size.width;
jint height = size.height;
//NSLog(@"Outputting frame sized %d x %d of length %d with format: %#x",width,height,length,format);
switch (format) {
// 8 bit codecs
case kCVPixelFormatType_1Monochrome:
case kCVPixelFormatType_2Indexed:
case kCVPixelFormatType_4Indexed:
case kCVPixelFormatType_8Indexed:
case kCVPixelFormatType_1IndexedGray_WhiteIsZero:
case kCVPixelFormatType_2IndexedGray_WhiteIsZero:
case kCVPixelFormatType_4IndexedGray_WhiteIsZero:
case kCVPixelFormatType_8IndexedGray_WhiteIsZero:
case kCVPixelFormatType_422YpCbCr8:
case kCVPixelFormatType_4444YpCbCrA8:
case kCVPixelFormatType_4444YpCbCrA8R:
case kCVPixelFormatType_444YpCbCr8:
case kCVPixelFormatType_420YpCbCr8Planar:
case kCVPixelFormatType_422YpCbCr_4A_8BiPlanar:
case kCVPixelFormatType_24RGB:
case kCVPixelFormatType_24BGR:
default:
{
// Re-use the existing array if possible
if (byteFrameData == nil || (*env)->GetArrayLength(env,byteFrameData) < length) {
// Clean up the previously allocated global reference
if (byteFrameData != nil) {
(*env)->DeleteGlobalRef(env,byteFrameData);
byteFrameData = nil;
}
// Create an appropriately sized byte array to hold the data
byteFrameData = (*env)->NewGlobalRef(env,(*env)->NewByteArray(env,length));
}
if (byteFrameData) {
// Copy the raw data into the byteArray
(*env)->SetByteArrayRegion(env,byteFrameData,0,length,rawData);
// Get the class reference for our object
jclass classRef = (*env)->GetObjectClass(env,objectRef);
// Get the pushFrame methodId
jmethodID methodId = (*env)->GetMethodID(env,classRef,"pushFrame","([BIIIF)V");
// Call pushFrame with the byte array
(*env)->CallVoidMethod(env,objectRef,methodId,byteFrameData,format,width,height,fps);
}
break;
}
// 16 bit (short) storage of values
case kCVPixelFormatType_16BE555:
case kCVPixelFormatType_16LE555:
case kCVPixelFormatType_16LE5551:
case kCVPixelFormatType_16BE565:
case kCVPixelFormatType_16LE565:
case kCVPixelFormatType_16Gray:
case kCVPixelFormatType_422YpCbCr16:
case kCVPixelFormatType_422YpCbCr10:
case kCVPixelFormatType_444YpCbCr10:
{
// Re-use the existing array if possible
if (shortFrameData == nil || (*env)->GetArrayLength(env,shortFrameData) < length/2) {
// Clean up the previously allocated global reference
if (shortFrameData != nil) {
(*env)->DeleteGlobalRef(env,shortFrameData);
shortFrameData = nil;
}
// Create an appropriately sized byte array to hold the data
shortFrameData = (*env)->NewGlobalRef(env,(*env)->NewShortArray(env,length/2));
}
if (shortFrameData) {
// Copy the raw data into the byteArray
(*env)->SetShortArrayRegion(env,shortFrameData,0,length/2,rawData);
// Get the class reference for our object
jclass classRef = (*env)->GetObjectClass(env,objectRef);
// Get the pushFrame methodId
jmethodID methodId = (*env)->GetMethodID(env,classRef,"pushFrame","([SIIIF)V");
// Call pushFrame with the short array
(*env)->CallVoidMethod(env,objectRef,methodId,shortFrameData,format,width,height,fps);
}
break;
}
// 32 bit (int) storage of values
case kCVPixelFormatType_32ABGR:
case kCVPixelFormatType_32AlphaGray:
case kCVPixelFormatType_32ARGB:
case kCVPixelFormatType_32BGRA:
case kCVPixelFormatType_32RGBA:
{
// Re-use the existing array if possible
if (intFrameData == nil || (*env)->GetArrayLength(env,intFrameData) < length/4) {
// Clean up the previously allocated global reference
if (intFrameData != nil) {
(*env)->DeleteGlobalRef(env,intFrameData);
intFrameData = nil;
}
// Create an appropriately sized byte array to hold the data
intFrameData = (*env)->NewGlobalRef(env,(*env)->NewIntArray(env,length/4));
}
if (intFrameData) {
// Copy the raw data into the byteArray
(*env)->SetByteArrayRegion(env,intFrameData,0,length/4,rawData);
// Get the class reference for our object
jclass classRef = (*env)->GetObjectClass(env,objectRef);
// Get the pushFrame methodId
jmethodID methodId = (*env)->GetMethodID(env,classRef,"pushFrame","([IIIIF)V");
// Call pushFrame with the int array
(*env)->CallVoidMethod(env,objectRef,methodId,intFrameData,format,width,height,fps);
}
break;
}
}
// Detatch from Java
(*g_vm)->DetachCurrentThread (g_vm);
}
/* Clean up java references so they can be properly GCed in java */
- (void) dealloc {
// Attach to java so we can release references
JNIEnv *env;
(*g_vm)->AttachCurrentThread (g_vm, (void **) &env, NULL);
// release the references we hold
if (objectRef != nil) {
(*env)->DeleteGlobalRef(env,objectRef);
objectRef = nil;
}
if (byteFrameData != nil) {
(*env)->DeleteGlobalRef(env,byteFrameData);
byteFrameData = nil;
}
if (shortFrameData != nil) {
(*env)->DeleteGlobalRef(env,shortFrameData);
shortFrameData = nil;
}
if (intFrameData != nil) {
(*env)->DeleteGlobalRef(env,intFrameData);
intFrameData = nil;
}
// Detatch from Java
(*g_vm)->DetachCurrentThread (g_vm);
g_vm = nil;
[super dealloc];
}
@end
는 전달 된 자바 객체 참조에 대한 자바 측의 메소드 서명입니다 정확히!