Java: ¿Cómo se crea un método para extraer los bits de división de un número entero de una matriz de bytes usando una máscara

StackOverflow https://stackoverflow.com/questions/3176705

  •  02-10-2019
  •  | 
  •  

Pregunta

Mientras se trabaja en la decodificación de video streaming algunas normas que he notado una gran cantidad de casos en los que se proporcionan los bits de un valor entero en cualquier cosa de 2-6 bytes, aunque separados por bits reservados, de la siguiente manera:

// 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

Por ejemplo, el valor 185 (10111001 o 0xB9) se almacenaría como sigue en una matriz de dos bytes:

01000110 00100100

Sé que esto es una locura, pero esta es la forma en que estos chicos han codificado el flujo de datos. Puede ser extraído por medio de las siguientes operaciones de bits

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)

Lo que me gustaría ser capaz de hacer es crear un método que aceptar una matriz de bytes de longitud indeterminada y una Int representa una máscara de los bits que constitué el valor que estamos tratando de extracto derivado de la especificación proporcionada. Algo como esto

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;
}

He completado el proyecto que estaba trabajando sobre el uso del enfoque original "manual", pero no estoy convencido de que es tan limpio como podría ser debido a la gran cantidad de estos hechos y de su complejidad. Me gustaría llegar a un método más genérico que podría lograr lo mismo.

Desafortunadamente todavía soy un novato cuando se trata de esta complejidad de desplazamiento de bits y esperaba que alguien podría proporcionar algunos consejos o sugerencias sobre la mejor manera de lograr esto.

Xela

Nota -. Disculpen los errores de sintaxis en el pseudo-código que sólo está diseñado para servir como una explicación del caso de uso

¿Fue útil?

Solución

En realidad, tiendo a pensar que la máscara de enfoque en línea y desplazamiento (si se aplica un poco más limpia que su pseudocódigo) es mejor que tratar de escribir un método de propósito general. Para un desarrollador con experiencia de código de bits ataques de bajo nivel, la lectura de código de máscara-y-cambio debería haber ningún problema. El problema con un método de propósito general a lo largo de las líneas que usted está proponiendo es que va a ser significativamente menos eficiente ... y difícil para el compilador JIT de optimizar.

Por cierto, esta es la forma en que me gustaría escribir el código.

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

Editar

  

todavía me gustaría entender cómo un enfoque de este tipo genérico podría ser codificado sin embargo, como un ejercicio de aprendizaje.

Algo como esto:

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;
    }
}

Como se puede ver, que tendrá un máximo de 32 iteraciones del bucle para darle la respuesta. Por su ejemplo, yo diría que este enfoque es aproximadamente 10 veces más lento que la versión original.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top