Milind Deore
Milind Deore

Reputation: 3063

Android native file read from assets folder by tflite BuildFromFile()

I have Android native code (C++ shared object), that want to read model file kept in the assets folder while creating APK.

Tensorflow Lite has two APIs: FromFile and FromBuffer

static std::unique_ptr<FlatBufferModel> BuildFromFile(const char* filename, ErrorReporter* error_reporter);

static std::unique_ptr<FlatBufferModel> BuildFromBuffer(const char* buffer, size_t buffer_size, ErrorReporter* error_reporter);

with following code i can access FromBuffer:

Java code:

private AssetManager mgr;

// Get mgr 
mgr = getResources().getAssets();

C++ code:

AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = (const char*)NULL;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
    AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
    char buf[BUFSIZ];
    int nb_read = 0;
    FILE* out = fopen(filename, "w");
    while ((nb_read = AAsset_read(asset, buf, BUFSIZ)) > 0)
        fwrite(buf, nb_read, 1, out);
    fclose(out);
    AAsset_close(asset);
}
AAssetDir_close(assetDir);

Any ideas, how can access assets folder to use BuildFromFile?

Upvotes: 1

Views: 943

Answers (1)

Lu Wang
Lu Wang

Reputation: 484

I don't think you can use BuildFromFile without copying the asset file to a local file (which is equivalent to what you've done above, and then BuildFromBuffer is more convenient in this case).

If you want to avoid memory copy, here is what you can do:

  1. (Java) Load the model through memory mapping.
    AssetFileDescriptor fileDescriptor = getResources().getAssets().openFd(filePath);\
    FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());\
    FileChannel fileChannel = inputStream.getChannel();\
    long startOffset = fileDescriptor.getStartOffset();\
    long declaredLength = fileDescriptor.getDeclaredLength();\
    MappedByteBuffer modelBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
  1. (Java) Pass the mapped file to C++ through jni, such as defining the following method:
    private static native void initJniWithByteBuffer(ByteBuffer modelBuffer)
  1. (C++) Use the buffer file to initialize you model:
    Java_xxxxxx_initJniWithByteBuffer(JNIEnv* env, jclass thiz, jobject model_buffer) {\
      char* buffer = static_cast<char*>(env->GetDirectBufferAddress(model_buffer));\
      size_t buffer_size = static_cast<size_t>(env->GetDirectBufferCapacity(model_buffer));\
    }

Upvotes: 3

Related Questions