简体   繁体   English

Java:如何创建使用掩码从字节数组中提取整数拆分位的方法

[英]Java: How do I create a Method to extract an Integer's split bits from a byte array using a mask

While working on decoding some video streaming standards I have noticed a lot of instances where the bits of an Integer value are provided in anything from 2-6 bytes but separated by reserved bits, as follows: 在解码某些视频流标准时,我注意到很多情况下,整数值的位以2-6字节的任何形式提供,但由保留位分隔,如下所示:

// Specification (16 bits)
// -----------------------
// Reserved         1  bit
// Value A [6-7]    2  bit
// Reserved         2  bit
// Value A [4-5]    2  bit
// Reserved         3  bit
// Value A [0-3]    4  bit
// Reserved         2  bit

For Example, the value 185 ( 10111001 or 0xB9 ) would be stored as follows in a two byte array: 例如,值185( 101110010xB9 )将如下存储在两个字节的数组中:

01000110 00100100

I know this is nuts, but this is the way these guys have coded their data stream. 我知道这很麻烦,但这就是这些家伙编码其数据流的方式。 It can be extracted using the following bit operations 可以使用以下位操作将其提取

int w = 0;
w |= (0x60 & data[0]) >>> 5;  // extract the first 2 bits shifted to the front
w <<= 2;                      // bump them up 2 bits for the next section
w |= (0x06 & data[0]) >>> 1;  // extract the next 2 bits shifted to the front
w <<= 4;                      // bump them up 4 bits for the last section
w |= (0x3C & data[0]) >>> 2;  // extract the last 4 bits shifted to the front

// w now will equal 10111001 (185)

What I would like to be able to do is create a method that would accept a byte array of undetermined length and an Int representing a mask of the bits that constitue the value we are trying to extract derived from the specification provided. 我想做的是创建一个方法,该方法将接受长度不确定的字节数组和一个Int,该Int表示构成我们试图提取的值的位的掩码,这些值构成自提供的规范。 Something like this 像这样

public static void testMethod() {

    byte[] data = new byte[] {0x46, 0x24}; // 01000110 00100100 
    int mask = 0x663C;                     // 01100110 00111100
    int x = readIntFromMaskedBytes(data, mask);

}

public static int readIntFromMaskedBytes(byte[] data, int mask) {
    int result = 0;

    // use the mask to extract the marks bits from each
    // byte and shift them appropriately to form an int

    return result;
}

I have completed the project I was working on using the original "manual" approach, but I am not satisfied that it is as clean as it could be due to the sheer number of these occurrences and their complexity. 我已经完成了使用原始的“手动”方法进行的项目,但是由于这些事件的数量之多及其复杂性,我不满意它是否像它那样干净。 I would love to come up with a more generic method that could accomplish the same thing. 我很想提出一种更通用的方法来完成同样的事情。

Unfortunately I'm still a newbie when it comes to this complexity of bit shifting and I was hoping someone could provide some advice or suggestions on how best to accomplish this. 不幸的是,当涉及到移位的复杂性时,我仍然是一个新手,我希望有人可以就如何最好地实现这一点提供一些建议。

Xela Xela

Note - Excuse any syntax errors in the pseudo-code above it is only design to serve as an explanation of the use case. 注–请原谅上面伪代码中的任何语法错误,仅是为了解释用例。

Actually, I tend to think that the inline mask and shift approach (if implemented a bit more cleanly than your pseudocode) is better than trying to write a general purpose method. 实际上,我倾向于认为内联掩码和移位方法(如果比伪代码更清晰地实现)比尝试编写通用方法更好。 For an experienced developer of low-level bit bashing code, reading mask-and-shift code should be no problem. 对于有经验的低级位重击代码的开发人员来说,阅读掩码移位代码应该没有问题。 The trouble with a general purpose method along the lines you are proposing is that it will be significantly less efficient ... and difficult for the JIT compiler to optimize. 按照您的提议,使用通用方法的麻烦在于效率会大大降低,而且JIT编译器难以优化。

BTW, this is how I'd write the code. 顺便说一句,这就是我编写代码的方式。

// extract and assemble xxxx from yyyy 
int w = ((0x003C & data[0]) >> 2) | 
        ((0x0600 & data[0]) >> 6) | 
        ((0x6000 & data[0]) >> 7);

EDIT 编辑

I would still like to understand how such a generic approach could be coded though, as a learning exercise. 我仍然想了解如何将这种通用方法编码为学习练习。

Something like this: 像这样:

public static int readIntFromMaskedBytes(int data, int mask) {
    int result = 0;
    int shift = 0;
    while (mask != 0) {
        if (mask & 1) {
            result |= (data & 1) << shift++;
        }
        data >>>= 1;
        mask >>>= 1;
    }
}

As you can see, that will take up to 32 loop iterations to give you the answer. 如您所见,这将需要多达32个循环迭代才能给出答案。 For your example, I'd say this approach is roughly 10 times slower than the original version. 对于您的示例,我想说这种方法比原始版本慢大约10倍。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM