ByteBuffer.allocateDirect()创建的对象offset默认不为0

在做图片相关开发,发现从相机抓到的jpg图片不能打开,通过hexdump命令打开发现图片二进制最前面多了四个0,后面才是jpg的图片头(ffd8),于是就开始追查下图片保存的代码。很快找到了,图片在保存前是ByteBuffer数据,转换成ByteArray后才写入的文件,转换的代码如下:

val pos = byteBuffer.position()
val limit = byteBuffer.limit()
val byteArray = byteBuffer.array().sliceArray(pos until limit)

看起来貌似没有问题,但是看了下camera2的官方样例ByteBuffer转ByteArray的代码如下:

val size = currentBuffer.remaining()
val byteArray = ByteArray(size)
currentBuffer.get(byteArray)

这个时候数据position为0,两种实现看起来没有区别,但是当我调试时发现ByteBuffer中存储数据的数组中(byteBuffer.array())的数据前四个字节为0,这也解释通了为什么保存的图片前面数据为0了,但是第二种方法为什么取到的值从第五位开始了呢?调试发现它取值时索引值加了offset,而此对象offset值正好为4,也就是说很明确的标明了前四个字节不是有效数据,所以得出结论,从ByteBuffer中取数据时不要直接从array中取,要通过get函数获取。

接下来我们继续看这个偏移是怎么来的,我这里的ByteBuffer对象是自己创建出来的空对象,用来拷贝相机回调的数据,我惊奇的发现创建出来的一个空对象offset里面的值竟然就是4。

//此对象offset值为4
val byteBuffer = ByteBuffer.allocateDirect(128)


//这种方法创建出来的offset为0
val byteBuffer = ByteBuffer.allocate(128)

下面是创建对象的相关源码:

/******* ByteBuffer.java ********/

public static ByteBuffer allocateDirect(int capacity) {
        // Android-changed: Android's DirectByteBuffers carry a MemoryRef.
        // return new DirectByteBuffer(capacity);
        DirectByteBuffer.MemoryRef memoryRef = new DirectByteBuffer.MemoryRef(capacity);
        return new DirectByteBuffer(capacity, memoryRef);
    }



/****** DirectByteBuffer.java *********/

DirectByteBuffer(int capacity, MemoryRef memoryRef) {
        super(-1, 0, capacity, capacity, memoryRef.buffer, memoryRef.offset);
        // Only have references to java objects, no need for a cleaner since the GC will do all
        // the work.
        this.memoryRef = memoryRef;
        this.address = memoryRef.allocatedAddress + memoryRef.offset;
        cleaner = null;
        this.isReadOnly = false;
    }


MemoryRef(int capacity) {
            VMRuntime runtime = VMRuntime.getRuntime();
            buffer = (byte[]) runtime.newNonMovableArray(byte.class, capacity + 7);
            allocatedAddress = runtime.addressOf(buffer);
            // Offset is set to handle the alignment: http://b/16449607
            offset = (int) (((allocatedAddress + 7) & ~(long) 7) - allocatedAddress);
            isAccessible = true;
            isFreed = false;
            originalBufferObject = null;
        }

从这段代码可以知道offset的值来源于 这行代码:

offset = (int) (((allocatedAddress + 7) & ~(long) 7) - allocatedAddress);

查看了一些资料得知这行代码目的是对起始地址做8个字节的对齐,也可以自行调试验证。至此困惑解决,搜索上面代码时看到这篇文章,讲的更详细(之前一直搜offset为4相关关键词搜不到相关文章),供参考:

ByteBuffer 中的字节对齐 | 假装在香港

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值