Issue
I have made android app with jni C++ code.
To read model file while creating apk on android native code(C++), I placed the model file in assets folder. (so file path is my_app/src/main/assets/model.tflite)
Then, I tried to read the model with following code but an error has raised:
Kotlin code:
private val context: Context
get() = getApplication<Application>().applicationContext
asset_manager = context.assets
C++ code:
AAssetManager* mgr = AAssetManager_fromJava(env, asset_manager);
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);
__android_log_print(ANDROID_LOG_INFO, "tag", "file name is: %s", filename); <- file name reading is ok
char buf[BUFSIZ];
int nb_read = 0;
FILE* out = fopen(filename, "w"); <- out has null FILE*
while ((nb_read = AAsset_read(asset, buf, BUFSIZ)) > 0)
fwrite(buf, nb_read, 1, out);
fclose(out);
AAsset_close(asset);
}
AAssetDir_close(assetDir);
logcat :
2022-06-19 22:45:54.449 12180-12180/com.my.first.app I/tag: file name is: model.tflite
2022-06-19 22:45:54.449 12180-12180/com.my.first.app A/libc: FORTIFY: fwrite: null FILE*
2022-06-19 22:45:54.450 12180-12180/com.my.first.app A/libc: Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 12180 (st.app), pid 12180 (st.app)
Why does fopen(filename, "w") return null? It seems that AAssetManager is work.
Solution
Looks like you want to combine this loading code to load the asset into a memory buffer and then use the BuildFromAllocation method:
std::unique_ptr<tflite::Allocation> readAsset(std::string target) {
AAssetManager* mgr = AAssetManager_fromJava(env, asset_manager);
AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = nullptr;
while ((filename = AAssetDir_getNextFileName(assetDir)) != nullptr) {
if (target != filename)
continue;
AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
auto len = AAsset_getLength(asset);
uint8_t *buf = new uint8_t[len];
std::copy_n(AAsset_getBuffer(asset), len, buf);
auto ret = std::make_unique<tflite::Allocation>(buf , len);
AAsset_close(asset);
AAssetDir_close(assetDir);
return ret;
}
AAssetDir_close(assetDir);
return {};
}
and then use it later as:
auto ptr = readAssset("model.tflite");
if (!ptr) {
// do something
}
auto modelPtr = tflite::FlatBufferModel::BuildFromAllocation(ptr, some_error_reporter);
if (!modelPtr) {
// do something
}
Note: this will leak memory, as TFlite takes ownership of the buffer.
Answered By - Botje
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.