gpt4 book ai didi

android - 加载/显示位图的最快方式;重用位图的最佳方式

转载 作者:太空狗 更新时间:2023-10-29 15:10:24 25 4
gpt4 key购买 nike

我需要以每秒不同的帧数显示图像,最大 FPS 为 30。图像来自 SD 卡,并且都具有相同的大小:480 x 640。我创建了 3 种可能的解决方案,但每个都有问题:

以下结果是 30 FPS。

我。不重复使用位图

  • 很多 GC 调用:aprox。 每秒 30 次 GC
  • CPU 负载:达到92%

    private Bitmap bitmap;

    private void startAnimation1() {
    TimerTask updateImage = new UpdateImage1();
    timer.scheduleAtFixedRate(updateImage, 0, 1000 / FPS);
    }

    class UpdateImage1 extends TimerTask {
    @Override
    public void run() {
    try {
    if (i == IMAGES_NR) {
    i = 0;
    }
    bitmap = BitmapFactory.decodeStream(new FileInputStream(framesFiles[i]), null, null);
    i++;
    } catch (FileNotFoundException e) {
    System.out.println("Exception 1: " + e.getMessage());
    }

    runOnUiThread(new Runnable() {
    @Override
    public void run() {
    imgView.setImageBitmap(bitmap);
    }
    });
    }
    }

二。通过 BitmapFactory.Options.inBitmap 重用位图

  • GC 调用较低 - 每秒 1 或 2 次
  • CPU 负载:达到84%

运行动画一段时间后,应用程序崩溃了:

06-20 15:08:58.158: WARN/System.err(7880): java.lang.ArrayIndexOutOfBoundsException: length=-5131855; regionStart=0; regionLength=1024
06-20 15:08:58.158: WARN/System.err(7880): at java.util.Arrays.checkOffsetAndCount(Arrays.java:1731)
06-20 15:08:58.158: WARN/System.err(7880): at java.io.BufferedInputStream.read(BufferedInputStream.java:273)
06-20 15:08:58.158: WARN/System.err(7880): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
06-20 15:08:58.158: WARN/System.err(7880): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:587)
06-20 15:08:58.158: WARN/System.err(7880): at com.example.SendPreviewOptimization.MyActivity$UpdateImage2.run(MyActivity.java:148)
06-20 15:08:58.158: WARN/System.err(7880): at java.util.Timer$TimerImpl.run(Timer.java:284)
06-20 15:08:58.168: DEBUG/skia(7880): ---- read threw an exception
06-20 15:08:58.168: DEBUG/skia(7880): --- decoder->decode returned false
06-20 15:08:58.168: WARN/System.err(7880): java.lang.IllegalArgumentException: Problem decoding into existing bitmap
06-20 15:08:58.168: WARN/System.err(7880): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:590)
06-20 15:08:58.168: WARN/System.err(7880): at com.example.SendPreviewOptimization.MyActivity$UpdateImage2.run(MyActivity.java:148)
06-20 15:08:58.168: WARN/System.err(7880): at java.util.Timer$TimerImpl.run(Timer.java:284)
06-20 15:08:58.178: ERROR/msm8960.hwcomposer(330): prepareBypass: Unable to setup bypass due to non-pmem memory
06-20 15:08:58.198: ASSERT/libc(7880): Fatal signal 11 (SIGSEGV) at 0xffd1d447 (code=1)
06-20 15:08:58.238: ERROR/msm8960.hwcomposer(330): prepareBypass: Unable to setup bypass due to non-pmem memory
06-20 15:08:58.498: ERROR/MP-Decision(1448): DOWN Ld:25 Ns:1.100000 Ts:190 rq:0.000000 seq:194.000000
06-20 15:08:58.708: INFO/DEBUG(27660): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***



private static BitmapFactory.Options bitmapOptions;
private FileInputStream in;

private void startAnimation2() {
bitmapOptions = new BitmapFactory.Options();
// setup bitmap reuse options:
bitmapOptions.inPurgeable = true;
bitmapOptions.inInputShareable = true;
bitmapOptions.inBitmap = reusableBitmap;
bitmapOptions.inMutable = true;
bitmapOptions.inSampleSize = 1;

TimerTask updateImage = new UpdateImage2();
timer.scheduleAtFixedRate(updateImage, 0, 1000 / FPS);
}

class UpdateImage2 extends TimerTask {
@Override
public void run() {
try {
if (i == IMAGES_NR) {
i = 0;
}

//** version 1:
in = new FileInputStream(framesFiles[i]);
//decode into existing bitmap
BitmapFactory.decodeStream(in, null, bitmapOptions);
in.close();

//** version 2:
//BitmapFactory.decodeFile(framesFiles[i].getAbsolutePath(), bitmapOptions);

i++;
} catch (Exception e) {
System.out.println("Exception 2: " + e.getMessage());
}
runOnUiThread(new Runnable() {
@Override
public void run() {
imgView.setImageBitmap(reusableBitmap);
}
});
}
}

III.选项 III:使用缓冲区(使 Bytebuffer 更高效的一件事是使用直接内存。)

  • 这个选项我无法让它工作:(

    private ByteBuffer buffer;
    private byte[] b;
    private IntBuffer mPixels;

    private void startAnimation3() {
    buffer = ByteBuffer.allocate(480 * 640 * 6);
    b = new byte[480 * 640 * 6];
    TimerTask updateImage = new UpdateImage3();
    timer.scheduleAtFixedRate(updateImage, 0, 1000 / FPS);
    }

    class UpdateImage3 extends TimerTask {
    public void run() {
    try {
    if (i == IMAGES_NR) {
    i = 0;
    }
    FileInputStream frameInputStream = new FileInputStream(framesFiles[i]);
    frameInputStream.read(b);
    buffer.wrap(b);
    buffer.position(0);
    reusableBitmap.copyPixelsFromBuffer(buffer);
    frameInputStream.close();
    i++;
    } catch (Exception e) {
    System.out.println("Exception 3: " + e.getMessage());
    }
    runOnUiThread(new Runnable() {
    @Override
    public void run() {
    imgView.setImageBitmap(reusableBitmap);
    }
    });
    }
    }

    private ByteBuffer copyToBuffer(Bitmap bitmap) {
    int size = bitmap.getHeight() * bitmap.getRowBytes();
    ByteBuffer buffer = ByteBuffer.allocateDirect(size);
    bitmap.copyPixelsToBuffer(buffer);
    return buffer;
    }

在上述每个解决方案中,我在 logcat 中收到很多

ERROR/msm8960.hwcomposer(330): prepareBypass: Unable to setup bypass due to non-pmem memory

我不知 Prop 体是什么意思。

我以前没有使用过位图重用,不知道哪个是最好的解决方案。

我在这里添加了我创建的项目:https://www.dropbox.com/sh/3xov369u1bmjpd1/qBQax4t48D还有 2 帧/图像。

对 Neron T 的回答

我试过那个库:

    //Option IV:
private AQuery aquery;

private void startAnimation4() {
aquery = new AQuery(this);
aquery.id(R.id.imgView);

TimerTask updateImage = new UpdateImage4();
timer.scheduleAtFixedRate(updateImage, 0, 1000 / FPS);
}

class UpdateImage4 extends TimerTask {
public void run() {
try {
if (i == 29) {
i = 0;
}
runOnUiThread(new Runnable() {
@Override
public void run() {
//load image from file, down sample to target width of 300 pixels
aquery.image(framesFiles[i],300);
}
});
i++;
} catch (Exception e) {
System.out.println("Exception 4: " + e.getMessage());
}
}
}

它没有像我预期的那样工作 - 我在每张照片前都有一个闪烁的效果。我想首先它会清除图片,然后再添加一张新图片:(

最佳答案

请注意,您不能从不是 UIThread(主线程)的线程内部修改 View ,请尝试使用 AsyncTasks。使用图像而无需考虑太多的简单方法是使用像 Android Query 这样的框架,看看 here .

如果您想手动检查 thisthis .

关于android - 加载/显示位图的最快方式;重用位图的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17210524/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com