ffmpeg - Android using JNI without static variables -



ffmpeg - Android using JNI without static variables -

i created own version of android's mediametadataretriever using source code mediametadataretriever.java basis. version uses ffmpeg retrieve metadata. approach works relies on static variables in c code retain state in between jni calls. means can utilize 1 instance of class @ time or state can corrupted. 2 java functions defined follows:

public class mediametadataretriever { static { system.loadlibrary("metadata_retriever_jni"); } public mediametadataretriever() { } public native void setdatasource(string path) throws illegalargumentexception; public native string extractmetadata(string key);

}

the corresponding c (jni) code code is:

const char *tag = "java_com_example_metadataexample_mediametadataretriever"; static avformatcontext *pformatctx = null; jniexport void jnicall java_com_example_metadataexample_mediametadataretriever_setdatasource(jnienv *env, jclass obj, jstring jpath) { if (pformatctx) { avformat_close_input(&pformatctx); } char duration[30] = "0"; const char *uri; uri = (*env)->getstringutfchars(env, jpath, null); if (avformat_open_input(&pformatctx, uri, null, null) != 0) { __android_log_write(android_log_info, tag, "metadata not retrieved"); (*env)->releasestringutfchars(env, jpath, uri); jnithrowexception(env, "java/lang/illegalargumentexception", null); return; } if (avformat_find_stream_info(pformatctx, null) < 0) { __android_log_write(android_log_info, tag, "metadata not retrieved"); avformat_close_input(&pformatctx); (*env)->releasestringutfchars(env, jpath, uri); jnithrowexception(env, "java/lang/illegalargumentexception", null); return; } (*env)->releasestringutfchars(env, jpath, uri); } jniexport jstring jnicall java_com_example_metadataexample_mediametadataretriever_extractmetadata(jnienv *env, jclass obj, jstring jkey) { const char *key; jstring value = null; key = (*env)->getstringutfchars(env, jkey, null) ; if (!pformatctx) { goto fail; } if (key) { if (av_dict_get(pformatctx->metadata, key, null, av_dict_ignore_suffix)) { value = (*env)->newstringutf(env, av_dict_get(pformatctx->metadata, key, null, av_dict_ignore_suffix)->value); } } fail: (*env)->releasestringutfchars(env, jkey, key); homecoming value; }

sample usage outlines issue be:

mediametadataretriever mmr = new mediametadataretriever(); mmr.setdatasource("one.mp3"); mediametadataretriever mmr2 = new mediametadataretriever(); // line resets info source two.mp3 mmr2.setdatasource("two.mp3"); // should retrieve artist one.mp3 retrieves two.mp3 due static // variable beingness reset in previous statement string artist = mmr.extractmetadata(mediametadataretriever.artist);

can explain how construction code utilize multiple instances of mediametadataretriever without them interfering 1 another? don't want switch code c++ , i'm don't need modify mediametadataretriever.java since code taken line-for-line android framework (which allows multiple instances, see illustration below). appears need re-structure c code i'm unsure how retain state across jni calls without using static variable. in advance.

file file1 = new file(environment.getexternalstoragedirectory(), "music/one.mp3"); file file2 = new file(environment.getexternalstoragedirectory(), "music/two.mp3"); android.media.mediametadataretriever mmr = new android.media.mediametadataretriever(); mmr.setdatasource(file1.tostring()); android.media.mediametadataretriever mmr2 = new android.media.mediametadataretriever(); mmr2.setdatasource(file2.tostring()); // returns artist of one.mp3, not two.mp3, expected. expected behavior // , confirms multiple instances of mediametadataretriever can used simultaneously mmr.extractmetadata(android.media.mediametadataretriever.metadata_key_artist));

restructuring code straight forward. instead of using pformatctx extend interfaces of jni calls can pass around pointer stored in pformatctx before. big guestion how pass around pointers while java doesn't know such datatype? straight forwards soulution utilize ints (for 32 bit systems) or longs (for 64 bit systems) passing pointers , java environment. unfortunately bit in hot water switch between 64 , 32 bit versions of library.

while trying solve problem months ago stumbled on article of clebert suconic. pointed out elegant way passing pointers safely through jni without "hacking" around typecasting. instead proposes utilize java.nio.bytebuffer.

the concept set in nutshell is: suggest create new bytebuffer object of length zero: env->newdirectbytebuffer(mypointer, 0); , pass resulting jobject through jni , forth.

the phone call env->newdirectbytebuffer(mypointer, 0); creates imutable byte buffer object pointing location wanted pass around. fact buffer imutable perfect don't want modify memory location, want store location itself. object encapsulating pointer , can leave pointer size issues jvm.

edit: completeness: pointer can later retrieved calling env->getdirectbufferaddress(mypointer);.

android ffmpeg jni

Comments

Popular posts from this blog

web services - java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.proxy.Enhancer -

Accessing MATLAB's unicode strings from C -

javascript - mongodb won't find my schema method in nested container -