2011-07-28 4 views
0

현재 iSight 카메라에서 이미지 데이터를 가져오고 있습니다. 처리를 위해 Java로 넘겨주고 싶습니다. 원래 jbyteArray에 데이터를 넣고 jbyteArray를 반환하려고했습니다. 이것은 프로세스마다 한 번 작동합니다. 네이티브 함수를 두 번 호출하면 잘못된 메모리 액세스가 발생합니다.(objective-c) JNI에서 jbyteArray를 Java로 전달하는 가장 좋은 방법은 무엇입니까?

objective-c 및 Cocoa로 작업하고 있으므로 JNF_COCOA_ENTER (...) 및 JNF_COCOA_EXIT (...) 함수를 사용해야합니다. 안타깝게도 jbyteArray를 반환 할 수 없다면 JNF_COCOA_EXIT (...)가 호출되지 않기 때문에 발생합니다. 직접 ByteBuffer를 사용하여 JNI 토지에서 Java 토지로 데이터를 전달하는 것이 좋습니다. 불행히도, 내가 사용해온 모든 자료와 참고 자료는 내 뇌가 이해할 수있을만큼 간단하지는 않습니다. 이 순간에 '미안하다'거나 벌써 물어 보았지만 (운이 좋으면 검색 한 적이 있지만) 사과드립니다 ...

1)이 이미지 데이터를 Java로 가져 오는 가장 효율적인 방법은 무엇입니까?

2)이를 수행하기 위해 ByteBuffer 클래스를 어떻게 사용해야합니까? (해당하는 경우)

감사!

답변

2

코드가 도움이 될 수 있습니다. 이러한 매크로가 무엇인지 생각하고 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 

는 전달 된 자바 객체 참조에 대한 자바 측의 메소드 서명입니다 정확히!

관련 문제