簡體   English   中英

將位填充(位移?)添加到存儲在字節數組中的 10 位值

[英]Add bit padding (bit shifting?) to 10bit values stored in a byte array

我正在尋找一種有效的方法來左移( << )10 位值,這些值使用 C++/Win32 存儲在字節數組中。

我通過 UDP 接收未壓縮的 4:2:2 10 位視頻 stream,由於位的打包,數據存儲在無符號字符數組中。

始終發送數據,以便像素組在字節邊界上完成(在這種情況下,以 10 位深度采樣的 4 個像素使用 5 個字節):

位包裝

我正在使用的渲染器( Media Foundation Enhanced Video Renderer )要求將 10 位值放入16 位 WORD 中,右側有 6 個填充位,雖然這很煩人,但我認為這是為了幫助他們確保 1 字節 memory alignment:

帶填充的 10 位表示

將每個 10 位值左移 6 次(並在需要時移動到新數組)的有效方法是什么? 雖然我會收到不同長度的數據,但它們總是由這 40 位塊組成。

我確信一個粗略的循環可以滿足一些位掩碼(?),但這對我來說聽起來很昂貴,我必須處理 1500 個數據包/秒,每個數據包有大約 1200 字節的有效負載。

為清晰起見進行編輯

示例輸入:

unsigned char byteArray[5] = {0b01110101, 0b01111010, 0b00001010, 0b11111010, 0b00000110}

所需的 Output:

WORD wordArray[4] = {0b0111010101000000, 0b1110100000000000, 0b1010111110000000, 0b1000000110000000}

(或字節數組中的相同結果數據)

這可以完成工作:

void ProcessPGroup(const uint8_t byteArrayIn[5], uint16_t twoByteArrayOut[4])
{
    twoByteArrayOut[0] = (((uint16_t)byteArrayIn[0] & 0b11111111u) << (0 + 8)) | (((uint16_t)byteArrayIn[1] & 0b11000000u) << 0);
    twoByteArrayOut[1] = (((uint16_t)byteArrayIn[1] & 0b00111111u) << (2 + 8)) | (((uint16_t)byteArrayIn[2] & 0b11110000u) << 2);
    twoByteArrayOut[2] = (((uint16_t)byteArrayIn[2] & 0b00001111u) << (4 + 8)) | (((uint16_t)byteArrayIn[3] & 0b11111100u) << 4);
    twoByteArrayOut[3] = (((uint16_t)byteArrayIn[3] & 0b00000011u) << (6 + 8)) | (((uint16_t)byteArrayIn[4] & 0b11111111u) << 6);
}

不要被上面 function 簽名中的[5][4]值混淆。 他們什么都不做,只是告訴你,用戶,這是每個數組中強制性的、預期的元素數量。 請在此處查看我的答案: 將數組作為參數傳遞給 C 中的 function 傳遞更短的數組將導致未定義的行為並且是一個錯誤!

完整的測試代碼( 在這里下載):

測試.cpp

/*

GS
17 Mar. 2021

To compile and run:
    mkdir -p bin && g++ -Wall -Wextra -Werror -ggdb -std=c++17 -o bin/test \
    test.cpp && bin/test

*/

#include <bitset>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <iostream>

// Get the number of elements in any C array
// - Usage example: [my own answer]:
//   https://arduino.stackexchange.com/questions/80236/initializing-array-of-structs/80289#80289
#define ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))

/// \brief      Process a packed video P group, which is 4 pixels of 10 bits each (exactly 5 uint8_t
///             bytes) into a uint16_t 4-element array (1 element per pixel).
/// \details    Each group of 10-bits for a pixel will be placed into a 16-bit word, with all 10
///             bits left-shifted to the far left edge, leaving 6 empty (zero) bits in the right
///             side of the word.
/// \param[in]  byteArrayIn  5 bytes of 10-bit pixel data for exactly 4 pixels; any array size < 5
///                        will result in undefined behavior! So, ensure you pass the proper array
///                        size in!
/// \param[out] twoByteArrayOut  The output array into which the 4 pixels will be packed, 10 bits per
///                        16-bit word, all 10 bits shifted to the left edge; any array size < 4
///                        will result in undefined behavior!
/// \return     None
void ProcessPGroup(const uint8_t byteArrayIn[5], uint16_t twoByteArrayOut[4])
{
    twoByteArrayOut[0] = (((uint16_t)byteArrayIn[0] & 0b11111111u) << (0 + 8)) | (((uint16_t)byteArrayIn[1] & 0b11000000u) << 0);
    twoByteArrayOut[1] = (((uint16_t)byteArrayIn[1] & 0b00111111u) << (2 + 8)) | (((uint16_t)byteArrayIn[2] & 0b11110000u) << 2);
    twoByteArrayOut[2] = (((uint16_t)byteArrayIn[2] & 0b00001111u) << (4 + 8)) | (((uint16_t)byteArrayIn[3] & 0b11111100u) << 4);
    twoByteArrayOut[3] = (((uint16_t)byteArrayIn[3] & 0b00000011u) << (6 + 8)) | (((uint16_t)byteArrayIn[4] & 0b11111111u) << 6);
}

// Reference: https://stackoverflow.com/questions/7349689/how-to-print-using-cout-a-number-in-binary-form/7349767
void PrintArrayAsBinary(const uint16_t* twoByteArray, size_t len)
{
    std::cout << "{\n";
    for (size_t i = 0; i < len; i++)
    {
        std::cout << std::bitset<16>(twoByteArray[i]);
        if (i < len - 1)
        {
            std::cout << ",";
        }
        std::cout << std::endl;
    }
    std::cout << "}\n";
}

int main()
{
    printf("Processing 10-bit video data example\n");

    constexpr uint8_t TEST_BYTE_ARRAY_INPUT[5] = {0b01110101, 0b01111010, 0b00001010, 0b11111010, 0b00000110};
    constexpr uint16_t TEST_TWO_BYTE_ARRAY_OUTPUT[4] = {
        0b0111010101000000, 0b1110100000000000, 0b1010111110000000, 0b1000000110000000};

    uint16_t twoByteArrayOut[4];
    ProcessPGroup(TEST_BYTE_ARRAY_INPUT, twoByteArrayOut);

    if (std::memcmp(twoByteArrayOut, TEST_TWO_BYTE_ARRAY_OUTPUT, sizeof(TEST_TWO_BYTE_ARRAY_OUTPUT)) == 0)
    {
        printf("TEST PASSED!\n");
    }
    else
    {
        printf("TEST ==FAILED!==\n");

        std::cout << "expected = \n";
        PrintArrayAsBinary(TEST_TWO_BYTE_ARRAY_OUTPUT, ARRAY_LEN(TEST_TWO_BYTE_ARRAY_OUTPUT));

        std::cout << "actual = \n";
        PrintArrayAsBinary(twoByteArrayOut, ARRAY_LEN(twoByteArrayOut));
    }

    return 0;
}

樣品運行和 output:

$ mkdir -p bin && g++ -Wall -Wextra -Werror -ggdb -std=c++17 \
-o bin/test test.cpp && bin/test
Processing 10-bit video data example
TEST PASSED!

我現在也將此代碼放入我的eRCaGuy_hello_world 存儲庫中: cpp/process_10_bit_video_data.cpp

參考:

  1. 如何打印(使用 cout)二進制形式的數字?
  2. [我的回答] 將數組作為參數傳遞給 C 中的 function
  3. [我的eRCaGuy_hello_world 存儲庫] ARRAY_LEN()宏:參見實用程序.h
  4. https://en.cppreference.com/w/cpp/string/byte/memcmp

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM