레이블이 ndk인 게시물을 표시합니다. 모든 게시물 표시
레이블이 ndk인 게시물을 표시합니다. 모든 게시물 표시

2012년 1월 6일 금요일

JNI : Strings and Arrays

출처 : http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jnistring.html


This section explains how to pass string and array data between a program written in the Java programming language and other languages.
Passing Strings
The String object in the Java language, which is represented as jstring in Java Native Interface (JNI), is a 16 bit unicode string. In C a string is by default constructed from 8 bit characters. So, to access a Java language String object passed to a C or C++ function or return a C or C++ string to a Java language method, you need to use JNI conversion functions in your native method implementation.
The GetStringUTFChars function retrieves 8-bit characters from a 16-bit jstring using the Unicode Transformation Format (UTF). UTF represents Unicode as a string of 8 or 16 bit characters without losing any information. The third parameter GetStringUTFChars results the result JNI_TRUE if it made a local copy of the jstring or JNI_FALSE otherwise.
C Version:
  (*env)->GetStringUTFChars(env, name, iscopy)

C++ Version:
  env->GetStringUTFChars(name, iscopy)

The following C JNI function converts an array of C characters to a jstring:
  (*env)->NewStringUTF(env, lastfile)
The example below converts the lastfile[80] C character array to a jstring, which is returned to the calling Java language method:
  static char lastfile[80];

  JNIEXPORT jstring JNICALL Java_ReadFile_lastFile
    (JNIEnv *env, jobject jobj) {
     return((*env)->NewStringUTF(env, lastfile));
  }

To let the Java1 virtual machine know you are finished with the UTF representation, call the ReleaseStringUTFChars conversion function as shown below. The second argument is the original jstring value used to construct the UTF representation, and the third argument is the reference to the local representation of that String.
 (*env)->ReleaseStringUTFChars(env, name, mfile);
If your native code can work with Unicode, without needing the intermediate UTF representation, call the GetStringChars function to retrieve the unicode string, and release the reference with a call toReleaseStringChars:
  JNIEXPORT jbyteArray JNICALL Java_ReadFile_loadFile
    (JNIEnv * env, jobject jobj, jstring name) {
      caddr_t m;
      jbyteArray jb;
      struct stat finfo;
      jboolean iscopy;
      const jchar *mfile = (*env)->GetStringChars(env, 
  name, &iscopy);
  //...
      (*env)->ReleaseStringChars(env, name, mfile);

Passing Arrays
In the example presented in the last section, the loadFile native method returns the contents of a file in a byte array, which is a primitive type in the Java programming language. You can retrieve and create primitive types in the Java language by calling the appropriate TypeArray function.
For example, to create a new array of floats, call NewFloatArray, or to create a new array of bytes, call NewByteArray. This naming scheme extends to retrieving elements from, adding elements to, and changing elements in the array. To get a new array of bytes, call GetByteArrayElements. To add elements to or change elements in the array, call Set<type>ArrayElements.
The GetByteArrayElements function affects the entire array. To work on a portion of the array, call GetByteArrayRegion instead. There is only a Set<type>ArrayRegion function for changing array elements. However the region could be of size 1, which is equivalent to the non-existent Set<type>ArrayElements.
Native
Code Type
Functions used
jbooleanNewBooleanArray
GetBooleanArrayElements
GetBooleanArrayRegion/SetBooleanArrayRegion
ReleaseBooleanArrayElements
jbyteNewByteArray
GetByteArrayElements
GetByteArrayRegion/SetByteArrayRegion
ReleaseByteArrayElements
jcharNewCharArray
GetCharArrayElements
GetCharArrayRegion/SetCharArrayRegion
ReleaseCharArrayElements
jdoubleNewDoubleArray
GetDoubleArrayElements
GetDoubleArrayRegion/SetDoubleArrayRegion
ReleaseDoubleArrayElements
jfloatNewFloatArray
GetFloatArrayElements
GetFloatArrayRegion/SetFloatArrayRegion
ReleaseFloatArrayElements
jintNewIntArray
GetIntArrayElements
GetIntArrayRegion/SetIntArrayRegion
ReleaseIntArrayElements
jlongNewLongArray
GetLongArrayElements
GetLongArrayRegion/SetLongArrayRegion
ReleaseLongArrayElements
jobjectNewObjectArray
GetObjectArrayElement/SetObjectArrayElement
jshortNewShortArray
GetShortArrayElements
GetShortArrayRegion/SetShortArrayRegion
ReleaseShortArrayElements
In the loadFile native method from the example in the previous section, the entire array is updated by specifying a region that is the size of the file being read in:
  jbyteArray jb;

  jb=(*env)->NewByteArray(env, finfo.st_size);
  (*env)->SetByteArrayRegion(env, jb, 0, 
  finfo.st_size, (jbyte *)m);
  close(fd);

The array is returned to the calling Java language method, which in turn, garbage collects the reference to the array when it is no longer used. The array can be explicitly freed with the following call.
  (*env)-> ReleaseByteArrayElements(env, jb, 
                                        (jbyte *)m, 0);
The last argument to the ReleaseByteArrayElements function above can have the following values:
  • 0: Updates to the array from within the C code are reflected in the Java language copy.
  • JNI_COMMIT: The Java language copy is updated, but the local jbyteArray is not freed.
  • JNI_ABORT: Changes are not copied back, but the jbyteArray is freed. The value is used only if the array is obtained with a get mode of JNI_TRUE meaning the array is a copy.
Pinning Array
When retrieving an array, you can specify if this is a copy (JNI_TRUE) or a reference to the array residing in your Java language program (JNI_FALSE). If you use a reference to the array, you will want the array to stay where it is in the Java heap and not get moved by the garbage collector when it compacts heap memory. To prevent the array references from being moved, the Java virtual machine pins the array into memory. Pinning the array ensures that when the array is released, the correct elements are updated in the Java VM.
In the loadfile native method example from the previous section, the array is not explicitly released. One way to ensure the array is garbage collected when it is no longer needed is to call a Java language method, pass the byte array instead, and then free the local array copy. This technique is shown in the section on Multi-Dimensional ArraysObject Arrays
You can store any Java language object in an array with the NewObjectArray and SetObjectArrayElement function calls. The main difference between an object array and an array of primitive types is that when constructing a jobjectarray type, the Java language class is used as a parameter.
This next C++ example shows how to call NewObjectArray to create an array of String objects. The size of the array is set to five, the class definition is returned from a call to FindClass, and the elements of the array are initialized with an empty string. The elements of the array are updated by calling SetObjectArrayElement with the position and value to put in the array.
  #include <jni.h>
  #include "ArrayHandler.h"

  JNIEXPORT jobjectArray JNICALL 
               Java_ArrayHandler_returnArray
  (JNIEnv *env, jobject jobj){

    jobjectArray ret;
    int i;

    char *message[5]= {"first", 
 "second", 
 "third", 
 "fourth", 
 "fifth"};

    ret= (jobjectArray)env->NewObjectArray(5,
         env->FindClass("java/lang/String"),
         env->NewStringUTF(""));

    for(i=0;i<5;i++) {
        env->SetObjectArrayElement(
  ret,i,env->NewStringUTF(env, message[i]));
    }
    return(ret);
  }

The Java class that calls this native method is as follows:
  public class ArrayHandler {
    public native String[] returnArray();
    static{
        System.loadLibrary("nativelib");
    }

    public static void main(String args[]) {
        String ar[];
        ArrayHandler ah= new ArrayHandler();
        ar = ah.returnArray();
        for (int i=0; i<5; i++) {
           System.out.println("array element"+i+ 
                                 "=" + ar[i]);
        }
    }
  }

Multi-Dimensional Arrays
You might need to call existing numerical and mathematical libraries such as the linear algebra library CLAPACK/LAPACK or other matrix crunching programs from your Java language program using native methods. Many of these libraries and programs use two-dimensional and higher order arrays.
In the Java programming language, any array that has more than one dimension is treated as an array of arrays. For example, a two-dimensional integer array is handled as an array of integer arrays. The array is read horizontally, or what is also termed as row order.
Other languages such as FORTRAN use column ordering so extra care is needed if your program hands a Java language array to a FORTRAN function. Also, the array elements in an application written in the Java programming language are not guaranteed to be contigous in memory. Some numerical libraries use the knowledge that the array elements are stored next to each other in memory to perform speed optimizations, so you might need to make an additional local copy of the array to pass to those functions.
The next example passes a two-dimensional array to a native method which then extracts the elements, performs a calculation, and calls a Java language method to return the results.
The array is passed as an object array that contains an array of jints. The individual elements are extracted by first retrieving a jintArray instance from the object array by calling GetObjectArrayElement, and then extracting the elements from the jintArray row.
The example uses a fixed size matrix. If you do not know the size of the array being used, the GetArrayLength(array) function returns the size of the outermost array. You will need to call theGetArrayLength(array) function on each dimension of the array to discover the total size of the array.
The new array sent back to the program written in the Java langauge is built in reverse. First, a jintArray instance is created and that instance is set in the object array by calling SetObjectArrayElement.
public class ArrayManipulation {
  private int arrayResults[][];
  Boolean lock=new Boolean(true);
  int arraySize=-1;

  public native void manipulateArray(
  int[][] multiplier, Boolean lock);

  static{
    System.loadLibrary("nativelib");
  }
 
  public void sendArrayResults(int results[][]) {
    arraySize=results.length;
    arrayResults=new int[results.length][];
    System.arraycopy(results,0,arrayResults,
                       0,arraySize);
  }

  public void displayArray() {
    for (int i=0; i<arraySize; i++) {
      for(int j=0; j <arrayResults[i].length;j++) {
        System.out.println("array element "+i+","+j+ 
          "= "  + arrayResults[i][j]);
      }
    }
  }

  public static void main(String args[]) {
    int[][] ar = new int[3][3];
    int count=3;
    for(int i=0;i<3;i++) {
      for(int j=0;j<3;j++) {
        ar[i][j]=count;
      }
      count++;
    }
    ArrayManipulation am= new ArrayManipulation();
    am.manipulateArray(ar, am.lock);
    am.displayArray();
  }
}

#include <jni.h>
#include <iostream.h>
#include "ArrayManipulation.h"

JNIEXPORT void 
     JNICALL Java_ArrayManipulation_manipulateArray
(JNIEnv *env, jobject jobj, jobjectArray elements, 
                            jobject lock){

  jobjectArray ret;
  int i,j;
  jint arraysize;
  int asize;
  jclass cls;
  jmethodID mid;
  jfieldID fid;
  long localArrayCopy[3][3];
  long localMatrix[3]={4,4,4};

  for(i=0; i<3; i++) {
     jintArray oneDim= 
 (jintArray)env->GetObjectArrayElement(
                      elements, i);
     jint *element=env->GetIntArrayElements(oneDim, 0);
     for(j=0; j<3; j++) {
        localArrayCopy[i][j]= element[j];
     }
  }

// With the C++ copy of the array, 
// process the array with LAPACK, BLAS, etc.

  for (i=0;i<3;i++) {
    for (j=0; j<3 ; j++) {
      localArrayCopy[i][j]=
        localArrayCopy[i][j]*localMatrix[i];
     }
  }

// Create array to send back
  jintArray row= (jintArray)env->NewIntArray(3);
  ret=(jobjectArray)env->NewObjectArray(
 3, env->GetObjectClass(row), 0);

  for(i=0;i<3;i++) {
    row= (jintArray)env->NewIntArray(3);
    env->SetIntArrayRegion((jintArray)row,(
 jsize)0,3,(jint *)localArrayCopy[i]);
    env->SetObjectArrayElement(ret,i,row);
  }

  cls=env->GetObjectClass(jobj);
  mid=env->GetMethodID(cls, "sendArrayResults", 
                            "([[I)V");
  if (mid == 0) {
    cout <<"Can't find method sendArrayResults";
    return;
  }

  env->ExceptionClear();
  env->MonitorEnter(lock);
  env->CallVoidMethod(jobj, mid, ret);
  env->MonitorExit(lock);
  if(env->ExceptionOccurred()) {
    cout << "error occured copying array back" << endl;
    env->ExceptionDescribe();
    env->ExceptionClear();
  }
  fid=env->GetFieldID(cls, "arraySize",  "I");
  if (fid == 0) {
    cout <<"Can't find field arraySize";
    return;
  }
  asize=env->GetIntField(jobj,fid);
  if(!env->ExceptionOccurred()) {
    cout<< "Java array size=" << asize << endl;
  } else {
    env->ExceptionClear();
  }
  return;
}

_______
1 As used on this web site, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.

2012년 1월 2일 월요일

Import STL libraries to the Android NDK code

출처 : http://www.41post.com/3527/programming/import-stl-libraries-to-android-ndk-code


Import STL libraries to the Android NDK code

Import STL libraries to the Android NDK code thumbnail
This is a quick tip for those who are beginning to write native Android code. As one may have noticed, it isn’t possible to use containers like,stringvectorlist inside the NDK samples. These are all part of the STL(Standard Template Library), and are expected to be available when writing C++ code.
To add STL to your NDK code, locate the Application.mk file inside your project’s jni folder. If it isn’t there, create it. Please note that the Application.mk is not theAndroid.mk file! The Android.mk file instructs the compiler and the JNI on how NDK code should be handled. The Application.mk, works similarly as the Android manifest file for your NDK code, allowing the programmer to add permissions and define other applications’ properties, like such as ‘enabling’ the STL support.
After creating the Application.mk, add this line of code:
  1. APP_STL := stlport_static  
Now at the .c or .cpp file or at the header of the class where STL needs to be included, add the following:
  1. //to use strings  
  2. #include <string>  
  3.   
  4. //to use vectors  
  5. #include <vector>  
  6.   
  7. //and so on...  
  8.   
  9. /* add this line, to avoiding writing 'std::' every time a string (or any 
  10. other container) is declared.*/  
  11. using namespace std;  
This was tested using Android NDK, Revision 5b, released in January 2011. I don’t know if works on previous version of the NDK.

2011년 12월 27일 화요일

error: 'UINT64_C' was not declared in this scope 문제 해결하기

출처 : http://frontjang.tistory.com/213

ffmpeg을 컴파일하는 도중 다음과 같은 오류가 나올경우 컴파일 옵션에 CXXFLAGS=-D__STDC_CONSTANT_MACROS 
을 추가해 주면 된다. 아니면 헤더파일에 아래 항목을 추가해 줄수도 있다. ffmpeg 뿐 아니라 다른 프로젝트에서도 이 방법을 사용할 수 있다.

#ifdef __cplusplus
#define __STDC_CONSTANT_MACROS
#ifdef _STDINT_H
  #undef _STDINT_H
#endif
# include <stdint.h>
#endif

출처 : Issue 11 - ffmpegsource - 'UINT64_C' was not declared in this scope - An FFmpeg based source library and Avisynth plugin for easy frame accurate access - Google Project Hosting

2011년 12월 22일 목요일

FFmpeg 가지고 H.263 인코딩하기..

출처 : http://iamlow.tistory.com/entry/FFmpeg-%EA%B0%80%EC%A7%80%EA%B3%A0-H263-%EC%9D%B8%EC%BD%94%EB%94%A9%ED%95%98%EA%B8%B0

이 글도 테스트 과정을 적었다.

0. 환경은 MPEG4 테스트와 동일

1. 설정도 동일하다. 그러나 실행시켜 보면 아래와 같은 메시지가 나타난다.

[h263 @ 0x91a3020] warning, clipping 1 dct coefficients to -127..127

2. 코드 검색

  $ grep -R "dct coefficients to" ../../*
../../libavcodec/mpegvideo_enc.c:        av_log(s->avctx, AV_LOG_INFO, "warning, clipping %d dct coefficients to %d..%d\n", overflow, minlevel, maxlevel);

3. 코드를 보자
  $ vi ../../libavcodec/mpegvideo_enc.c

1461     if(overflow && s->avctx->mb_decision == FF_MB_DECISION_SIMPLE)
1462         av_log(s->avctx, AV_LOG_INFO, "warning, clipping %d dct coefficients to %d..%d\n", overflow, minlevel, maxlevel);

 - ctags를 활용하여 "FF_MB_DECISION_SIMPLE" 추적..

2030     /**     
2031      * macroblock decision mode
2032      * - encoding: Set by user.
2033      * - decoding: unused
2034      */
2035     int mb_decision;
2036 #define FF_MB_DECISION_SIMPLE 0        ///< uses mb_cmp
2037 #define FF_MB_DECISION_BITS   1        ///< chooses the one which needs the fewest bits
2038 #define FF_MB_DECISION_RD     2        ///< rate distortion

  - mb_cmp 라는 주석을 보고 또 추적..  

1836      * macroblock comparison function (not supported yet)
1837      * - encoding: Set by user.
1838      * - decoding: unused
1839      */
1840     int mb_cmp;

  - not supported yet 이란다...
    avctx->mb_decision = FF_MB_DECISION_SIMPLE;
    avctx->mb_cmp = -127 ~ ... 127 설정;

   테스트 결과 not supported yet 이 검증됨...ㅋㅋ

  - FFmpeg 홈페이지에도 아래와 같은 문구가 있음.
`-mbd mode'
macroblock decision
`0'
FF_MB_DECISION_SIMPLE: Use mb_cmp (cannot change it yet in ffmpeg).
`1'
FF_MB_DECISION_BITS: Choose the one which needs the fewest bits.
`2'
FF_MB_DECISION_RD: rate distortion
 
4. MB_DECISION 이 뭔가 인터넷 검색...
   매크로블럭을 결정하는 방법들 이라는데.. 영상처리와 관련된 약간은 난이도가 있는 부분인듯하다..
  FF_MB_DECISION_BITS ==> 잘 모르겠음..
  FF_MB_DECISION_RD ==> 이 녀석이 화질이 가장 좋다고 하나, 처리하는데 시간이 오래 걸린덴다.. (모든 MB를 검색하여 가장 좋은 MB 모드를 설정한다고 한다.) 인터넷에 검색하니 약자로 RDO(Rate-distortion Optimization) 라고 불린다.

 아래처럼 설정하면 경고메시지가 사라지고 정상동작한다.
 avctx->mb_decision = FF_MB_DECISION_BITS; // or FF_MB_DECISION_RD;

이상!!!
그리고 비트레이트가 딱 떨어지게 영상이 인코딩되지는 않는다.
* 참고로.. 영상확인은 VLC 플레이어를 사용하여 정상적으로 인코딩 되었는지 확인했다..