Introduce new file read path
This commit is contained in:
1 parent
cb242f664a
commit
726f482c33
6 files changed
+141
-49
No files matched your search
@@ -1,4 +1,13 @@
|
||||
#include <jni.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define LOG_TAG "mmap_utils"
|
||||
|
||||
#include "ehviewer.h"
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_hippo_Native_getFd(JNIEnv *env, jclass clazz, jobject fileDescriptor) {
|
||||
@@ -13,4 +22,22 @@ Java_com_hippo_Native_getFd(JNIEnv *env, jclass clazz, jobject fileDescriptor) {
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_hippo_Native_mapFd(JNIEnv *env, jclass clazz, jint fd, jlong capability) {
|
||||
void *addr = mmap(0, capability, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
if (addr != MAP_FAILED) {
|
||||
return (*env)->NewDirectByteBuffer(env, addr, capability);
|
||||
} else {
|
||||
LOGE("%s%s", "mmap failed with error ", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_hippo_Native_unmapDirectByteBuffer(JNIEnv *env, jclass clazz, jobject buffer) {
|
||||
void *addr = (*env)->GetDirectBufferAddress(env, buffer);
|
||||
size_t size = (*env)->GetDirectBufferCapacity(env, buffer);
|
||||
if (munmap(addr, size)) LOGE("munmap addr:%p, size%d failed!", addr, size);
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
package com.hippo
|
||||
|
||||
import java.io.FileDescriptor
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
object Native {
|
||||
fun initialize() {
|
||||
@@ -26,4 +27,10 @@ object Native {
|
||||
|
||||
@JvmStatic
|
||||
external fun getFd(fd: FileDescriptor?): Int
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
external fun mapFd(fd: Int, capability: Long): ByteBuffer?
|
||||
|
||||
@JvmStatic
|
||||
external fun unmapDirectByteBuffer(buffer: ByteBuffer)
|
||||
}
|
||||
@@ -21,16 +21,20 @@ import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hippo.Native;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.EhDB;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.client.EhCacheKeyFactory;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.gallery.PageLoader2;
|
||||
import com.hippo.image.Image;
|
||||
import com.hippo.io.UniFileInputStreamPipe;
|
||||
import com.hippo.io.UniFileOutputStreamPipe;
|
||||
import com.hippo.streampipe.InputStreamPipe;
|
||||
import com.hippo.streampipe.OutputStreamPipe;
|
||||
import com.hippo.unifile.RawFile;
|
||||
import com.hippo.unifile.UniFile;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
import com.hippo.yorozuya.IOUtils;
|
||||
@@ -43,6 +47,9 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.Locale;
|
||||
|
||||
import coil.disk.DiskCache;
|
||||
@@ -261,6 +268,7 @@ public final class SpiderDen {
|
||||
}
|
||||
return new OutputStreamPipe() {
|
||||
private OutputStream os = null;
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
editor.commit();
|
||||
@@ -382,4 +390,94 @@ public final class SpiderDen {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Image.ByteBufferSource getImageSource(int index) {
|
||||
if (mMode == SpiderQueen.MODE_READ) {
|
||||
String key = EhCacheKeyFactory.getImageKey(mGid, index);
|
||||
if (sCache != null) {
|
||||
var snapshot = sCache.get(key);
|
||||
if (snapshot != null) {
|
||||
try {
|
||||
var file = new RandomAccessFile(snapshot.getData().toFile(), "rw");
|
||||
var chan = file.getChannel();
|
||||
var map = chan.map(FileChannel.MapMode.PRIVATE, 0, file.length());
|
||||
return new Image.ByteBufferSource() {
|
||||
@NonNull
|
||||
@Override
|
||||
public ByteBuffer getByteBuffer() {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
chan.close();
|
||||
file.close();
|
||||
snapshot.close();
|
||||
}
|
||||
};
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
UniFile dir = getDownloadDir();
|
||||
if (dir == null) {
|
||||
return null;
|
||||
}
|
||||
UniFile file = findImageFile(dir, index);
|
||||
if (file != null && mMode == SpiderQueen.MODE_DOWNLOAD) {
|
||||
if (copyFromCacheToDownloadDir(index)) {
|
||||
file = findImageFile(dir, index);
|
||||
}
|
||||
}
|
||||
if (file instanceof RawFile rawFile) {
|
||||
try {
|
||||
var file2 = new RandomAccessFile(rawFile.mFile, "rw");
|
||||
var chan = file2.getChannel();
|
||||
var map = chan.map(FileChannel.MapMode.PRIVATE, 0, file2.length());
|
||||
return new Image.ByteBufferSource() {
|
||||
@NonNull
|
||||
@Override
|
||||
public ByteBuffer getByteBuffer() {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
chan.close();
|
||||
file2.close();
|
||||
}
|
||||
};
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (file != null) {
|
||||
try {
|
||||
var pfd = EhApplication.getApplication().getContentResolver().openFileDescriptor(file.getUri(), "rw");
|
||||
var map = Native.mapFd(pfd.getFd(), pfd.getStatSize());
|
||||
if (map != null) {
|
||||
return new Image.ByteBufferSource() {
|
||||
@NonNull
|
||||
@Override
|
||||
public ByteBuffer getByteBuffer() {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
Native.unmapDirectByteBuffer(map);
|
||||
pfd.close();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
pfd.close();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.hippo.ehviewer.spider;
|
||||
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.ImageDecoder;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
@@ -1623,8 +1622,8 @@ public final class SpiderQueen implements Runnable {
|
||||
continue;
|
||||
}
|
||||
|
||||
InputStreamPipe pipe = mSpiderDen.openInputStreamPipe(index);
|
||||
if (pipe == null) {
|
||||
Image.ByteBufferSource src = mSpiderDen.getImageSource(index);
|
||||
if (src == null) {
|
||||
resetDecodeIndex();
|
||||
// Can't find the file, it might be removed from cache,
|
||||
// Reset it state and request it
|
||||
@@ -1633,35 +1632,11 @@ public final class SpiderQueen implements Runnable {
|
||||
continue;
|
||||
}
|
||||
|
||||
Image image = null;
|
||||
Image image = Image.decode(src);
|
||||
String error = null;
|
||||
InputStream is;
|
||||
|
||||
try {
|
||||
is = pipe.open();
|
||||
} catch (IOException e) {
|
||||
// Can't open pipe
|
||||
error = GetText.getString(R.string.error_reading_failed);
|
||||
is = null;
|
||||
pipe.close();
|
||||
pipe.release();
|
||||
}
|
||||
|
||||
if (is != null) {
|
||||
try {
|
||||
image = Image.decode(((FileInputStream) is));
|
||||
} catch (ImageDecoder.DecodeException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (image == null) {
|
||||
error = GetText.getString(R.string.error_decoding_failed);
|
||||
}
|
||||
if (image == null) {
|
||||
error = GetText.getString(R.string.error_decoding_failed);
|
||||
}
|
||||
|
||||
// Notify
|
||||
|
||||
@@ -19,16 +19,13 @@ package com.hippo.image
|
||||
|
||||
import android.graphics.ColorSpace
|
||||
import android.graphics.ImageDecoder
|
||||
import android.graphics.ImageDecoder.DecodeException
|
||||
import android.graphics.ImageDecoder.ImageInfo
|
||||
import android.graphics.ImageDecoder.Source
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import com.hippo.ehviewer.EhApplication
|
||||
import java.io.FileInputStream
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.channels.FileChannel
|
||||
import kotlin.math.min
|
||||
|
||||
class Image private constructor(source: Source, private var releaseCall: (() -> Unit)? = null) {
|
||||
@@ -79,18 +76,6 @@ class Image private constructor(source: Source, private var releaseCall: (() ->
|
||||
) ColorSpace.Named.DISPLAY_P3 else ColorSpace.Named.SRGB
|
||||
)
|
||||
|
||||
@Throws(DecodeException::class)
|
||||
@JvmStatic
|
||||
fun decode(stream: FileInputStream): Image {
|
||||
val src = ImageDecoder.createSource(
|
||||
stream.channel.map(
|
||||
FileChannel.MapMode.READ_ONLY, 0,
|
||||
stream.available().toLong()
|
||||
)
|
||||
)
|
||||
return Image(src)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun decode(src: ByteBufferSource): Image? {
|
||||
val directBuffer = src.getByteBuffer()
|
||||
|
||||
@@ -32,11 +32,11 @@ import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
|
||||
class RawFile extends UniFile {
|
||||
public class RawFile extends UniFile {
|
||||
|
||||
private static final String TAG = RawFile.class.getSimpleName();
|
||||
|
||||
private File mFile;
|
||||
public File mFile;
|
||||
|
||||
RawFile(UniFile parent, File file) {
|
||||
super(parent);
|
||||
|
||||
Reference in new issue
Block a user