Unverified Commit 058ada59 authored by janssontoftg's avatar janssontoftg
Browse files

Updated representation for quaternions for PI data

parent 03e3344c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -169,6 +169,7 @@
#define DECODER_FORMAT_SWITCHING                       /* Re-initialize the decoder when the format/subformat of the incoming stream is changed */
#define RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE            /* CR for split rendering codec framesize signalling in Toc Byte*/
#define FIX_SPLIT_RENDERING_ON_DECODER_RESTART         /* Re-configure split rendering on decoder restart */
#define COMPACT_ORIENTATION_PI_DATA

/* ################### Start BE switches ################################# */
/* only BE switches wrt selection floating point code */
+3 −0
Original line number Diff line number Diff line
@@ -51,6 +51,9 @@ enum MASK_BITS
#ifdef REVERSE_ISM_PI_DATA
    MASK_9BIT = 0x1FF,
#endif
#ifdef COMPACT_ORIENTATION_PI_DATA
    MASK_10BIT = 0x3FF,
#endif

};

+125 −19
Original line number Diff line number Diff line
@@ -37,6 +37,9 @@
#endif
#ifdef ISM_PI_DATA
#include <stdlib.h>
#ifdef COMPACT_ORIENTATION_PI_DATA
#include "tools.c"
#endif

#ifndef min
#define min( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) )
@@ -79,6 +82,85 @@ static int16_t ivasPayload_convertToQ15( float value )
    return (int16_t) ( value );
}

#ifdef COMPACT_ORIENTATION_PI_DATA
static uint32_t packQuaternion( IVAS_QUATERNION orientation, uint8_t *buffer )
{
    uint32_t nBytes = 0;
    float q[4], q_max;
    uint16_t max_q_idx, n, k;
    uint32_t lWord;

    q[0] = orientation.w;
    q[1] = orientation.x;
    q[2] = orientation.y;
    q[3] = orientation.z;

    max_q_idx = maximumAbs( q, 4, &q_max );
    if ( q[max_q_idx] < 0 )
    {
        for ( n = 0; n < 4; n++ )
        {
            q[n] = -q[n];
        }
    }
    lWord = max_q_idx << 30;

    k = 1;
    for ( n = 0; n < 4; n++ )
    {
        if ( n == max_q_idx )
        {
            continue;
        }
        lWord |= ( ( (int16_t) ( ( q[n] + 1 ) * 1023 * 0.5f ) & MASK_10BIT ) << ( 30 - k * 10 ) );
        k++;
    }

    buffer[nBytes++] = ( lWord >> 24 ) & MASK_8BIT;
    buffer[nBytes++] = ( lWord >> 16 ) & MASK_8BIT;
    buffer[nBytes++] = ( lWord >> 8 ) & MASK_8BIT;
    buffer[nBytes++] = (lWord) &MASK_8BIT;

    return nBytes;
}


static ivas_error unpackQuaternion( const uint8_t *buffer, IVAS_QUATERNION *orientation )
{
    uint32_t i, k, lWord;
    uint16_t max_q_idx, tmp;
    float q[4], qs;

    lWord = ( buffer[0] ) << 24;
    lWord |= ( buffer[1] ) << 16;
    lWord |= ( buffer[2] ) << 8;
    lWord |= buffer[3];

    max_q_idx = ( lWord >> 30 ) & MASK_2BIT;
    k = 1;
    qs = 0.0f;
    for ( i = 0; i < 4; i++ )
    {
        if ( i == max_q_idx )
        {
            continue;
        }
        tmp = ( lWord >> ( 30 - k * 10 ) ) & MASK_10BIT;
        q[i] = tmp / 1023.0f * 2.0f - 1;
        qs += q[i] * q[i];
        k++;
    }
    q[max_q_idx] = sqrtf( 1 - qs );
    orientation->w = q[0];
    orientation->x = q[1];
    orientation->y = q[2];
    orientation->z = q[3];

    return IVAS_ERR_OK;
}

#endif

static ivas_error packUnsupportedData( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten )
{
    (void) piData;
@@ -152,19 +234,22 @@ static ivas_error packOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *b
        return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in Orientation PI data" );
    }

    /* Orientation data is 8 bytes, header is 2 bytes */
    if ( maxDataBytes < 8 + 2 )
    /* Orientation data is 4 bytes, header is 2 bytes */
    if ( maxDataBytes < 4 + 2 )
    {
        return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Orientation PI data" );
    }

    buffer[nBytes++] = ( orientation->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */
    buffer[nBytes++] = 8;
    buffer[nBytes++] = 4;
#ifdef COMPACT_ORIENTATION_PI_DATA
    nBytes += packQuaternion( orientation->orientation, &buffer[nBytes] );
#else
    nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.w ) );
    nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.x ) );
    nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.y ) );
    nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.z ) );

#endif
    *nBytesWritten = nBytes;
    return IVAS_ERR_OK;
}
@@ -196,10 +281,14 @@ static ivas_error packISMOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t
    buffer[nBytes++] = (uint8_t) orientation->numObjects * 8;
    for ( n = 0; n < orientation->numObjects; n++ )
    {
#ifdef COMPACT_ORIENTATION_PI_DATA
        nBytes += packQuaternion( orientation->orientation[n], &buffer[nBytes] );
#else
        nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation[n].w ) );
        nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation[n].x ) );
        nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation[n].y ) );
        nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation[n].z ) );
#endif
    }
    *nBytesWritten = nBytes;
    return IVAS_ERR_OK;
@@ -210,17 +299,21 @@ static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataByte
{
    IVAS_PIDATA_ORIENTATION *orientation = (IVAS_PIDATA_ORIENTATION *) piData;

    /* Orientation data is 8 bytes */
    if ( numDataBytes != 8 )
    /* Orientation data is 4 bytes */
    if ( numDataBytes != 4 )
    {
        return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" );
    }

    piData->size = sizeof( IVAS_PIDATA_ORIENTATION );
#ifdef COMPACT_ORIENTATION_PI_DATA
    unpackQuaternion( buffer, &( orientation->orientation ) );
#else
    orientation->orientation.w = FLOAT_FROM_Q15( readInt16( &buffer[0] ) );
    orientation->orientation.x = FLOAT_FROM_Q15( readInt16( &buffer[2] ) );
    orientation->orientation.y = FLOAT_FROM_Q15( readInt16( &buffer[4] ) );
    orientation->orientation.z = FLOAT_FROM_Q15( readInt16( &buffer[6] ) );
#endif

    return IVAS_ERR_OK;
}
@@ -230,22 +323,26 @@ static ivas_error unpackISMOrientation( const uint8_t *buffer, uint32_t numDataB
{
    IVAS_PIDATA_ISM_ORIENTATION *ism_orientation = (IVAS_PIDATA_ISM_ORIENTATION *) piData;

    /* Orientation data is 8 bytes */
    /* Orientation data is 4 bytes */
    uint16_t n;
    if ( numDataBytes % 8 != 0 )
    if ( numDataBytes % 4 != 0 )
    {
        return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" );
    }

    ism_orientation->size = sizeof( IVAS_PIDATA_ISM_ORIENTATION );
    ism_orientation->numObjects = (uint16_t) numDataBytes / 8;
    ism_orientation->numObjects = (uint16_t) numDataBytes / 4;

    for ( n = 0; n < ism_orientation->numObjects; n++ )
    {
#ifdef COMPACT_ORIENTATION_PI_DATA
        unpackQuaternion( &buffer[4 * n], &( ism_orientation->orientation[n] ) );
#else
        ism_orientation->orientation[n].w = FLOAT_FROM_Q15( readInt16( &buffer[8 * n] ) );
        ism_orientation->orientation[n].x = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 2] ) );
        ism_orientation->orientation[n].y = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 4] ) );
        ism_orientation->orientation[n].z = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 6] ) );
#endif
    }
    for ( ; n < IVAS_MAX_NUM_OBJECTS; n++ )
    {
@@ -754,11 +851,11 @@ static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8

    if ( audioFocus->availDirection && audioFocus->availLevel )
    {
        packedSize = 9;
        packedSize = 5;
    }
    else if ( audioFocus->availDirection )
    {
        packedSize = 8;
        packedSize = 4;
    }
    else if ( audioFocus->availLevel )
    {
@@ -778,14 +875,19 @@ static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8
    buffer[nBytes++] = ( audioFocus->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */
    buffer[nBytes++] = packedSize;

    if ( packedSize == 9 || packedSize == 8 )
    if ( packedSize == 5 || packedSize == 4 )
    {
#ifdef COMPACT_ORIENTATION_PI_DATA
        nBytes += packQuaternion( audioFocus->direction, &buffer[nBytes] );
#else

        nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.w ) );
        nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.x ) );
        nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.y ) );
        nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.z ) );
#endif
    }
    if ( packedSize == 9 || packedSize == 1 )
    if ( packedSize == 5 || packedSize == 1 )
    {
        buffer[nBytes++] = ( (uint8_t) audioFocus->flvl & MASK_4BIT ) << 4;
    }
@@ -798,15 +900,15 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat
{
    IVAS_PIDATA_AUDIO_FOCUS *audioFocus = (IVAS_PIDATA_AUDIO_FOCUS *) piData;

    /* Audio Focus data is either 1, 8 or 9 bytes */
    if ( numDataBytes != 1 && numDataBytes != 8 && numDataBytes != 9 )
    /* Audio Focus data is either 1, 4 or 5 bytes */
    if ( numDataBytes != 1 && numDataBytes != 4 && numDataBytes != 5 )
    {
        return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack PI data of type Audio Focus" );
    }

    piData->size = sizeof( IVAS_PIDATA_AUDIO_FOCUS );
    audioFocus->availDirection = ( numDataBytes >= 8 );
    audioFocus->availLevel = ( numDataBytes == 1 || numDataBytes == 9 );
    audioFocus->availDirection = ( numDataBytes >= 4 );
    audioFocus->availLevel = ( numDataBytes == 1 || numDataBytes == 5 );

    if ( numDataBytes == 1 )
    {
@@ -814,14 +916,18 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat
    }
    else
    {
#ifdef COMPACT_ORIENTATION_PI_DATA
        unpackQuaternion( buffer, &( audioFocus->direction ) );
#else
        audioFocus->direction.w = FLOAT_FROM_Q15( readInt16( &buffer[0] ) );
        audioFocus->direction.x = FLOAT_FROM_Q15( readInt16( &buffer[2] ) );
        audioFocus->direction.y = FLOAT_FROM_Q15( readInt16( &buffer[4] ) );
        audioFocus->direction.z = FLOAT_FROM_Q15( readInt16( &buffer[6] ) );
#endif

        if ( numDataBytes == 9 )
        if ( numDataBytes == 5 )
        {
            audioFocus->flvl = ( buffer[8] >> 4 );
            audioFocus->flvl = ( buffer[4] >> 4 );
        }
    }

+31 −13
Original line number Diff line number Diff line
@@ -748,16 +748,28 @@ def packNoPiData(bitstrm: BitStream, data: any = None):

def unpackOrientations(bitstrm: ConstBitStream, piSize: int) -> list[ORIENTATION]:
    assert (
        piSize % 8
        piSize % 4
    ) == 0 and piSize <= 32, "Incorrect PI Data Size for list[ORIENTATION]"
    orientations = list()
    q = [(float)]*4
    qs = 0
    while piSize > 0:
        w = bitstrm.read(16).int / 32768.0
        x = bitstrm.read(16).int / 32768.0
        y = bitstrm.read(16).int / 32768.0
        z = bitstrm.read(16).int / 32768.0
        max_q_idx = bitstrm.read(2).uint
        for i in range(0,4):
            if i == max_q_idx:
                continue
            tmp = bitstrm.read(10).uint
            q[i] = (tmp / 1023.0) * 2.0 - 1.0
            qs = qs + q[i]**2
        
        q[max_q_idx] = (1 - qs)**0.5
            
        w = q[0]
        x = q[1]
        y = q[2]
        z = q[3]
        orientations.append(ORIENTATION(w, x, y, z))
        piSize -= 8
        piSize -= 4
    return orientations


@@ -767,10 +779,16 @@ def packOrientations(bitstrm: BitStream, data: any):
        assert (
            type(orientation) == ORIENTATION
        ), "Orientation PI Data expects a data of type list[ORIENTATION]"
        bitstrm.append(f"intbe:16={q15(orientation.w)}")
        bitstrm.append(f"intbe:16={q15(orientation.x)}")
        bitstrm.append(f"intbe:16={q15(orientation.y)}")
        bitstrm.append(f"intbe:16={q15(orientation.z)}")
        q = [orientation.w, orientation.x, orientation.y, orientation.z]
        max_q = max(q, key=abs)
        max_q_idx = q.index(max_q)
        if max_q < 0:
            q = [-x for x in q]
        bitstrm.append(f"uint:2={max_q_idx}")
        for i in range(0,4):
            if i == max_q_idx:
                continue
            bitstrm.append(f"uint:10={(int)((q[i]+1)*1023*1/2)}")


def unpackPositions(bitstrm: ConstBitStream, piSize: int) -> list[POSITION]:
@@ -799,7 +817,7 @@ def packPositions(bitstrm: BitStream, data: any):


def unpackOrientation(bitstrm: ConstBitStream, piSize: int) -> ORIENTATION:
    assert piSize == 8, "Incorrect PI Data Size for ORIENTATION"
    assert piSize == 4, "Incorrect PI Data Size for ORIENTATION"
    orientations = unpackOrientations(bitstrm, piSize)
    assert len(orientations) == 1
    return orientations[0]
@@ -983,8 +1001,8 @@ def unpackAudioFocus(bitstrm: ConstBitStream, piSize: int) -> AUDIO_FOCUS:
        level = bitstrm.read(4).uint
        _ = bitstrm.read(4)
    else:
        direction = unpackOrientation(bitstrm, 8)
        if piSize == 9:
        direction = unpackOrientation(bitstrm, 4)
        if piSize == 5:
            level = bitstrm.read(4).uint
            _ = bitstrm.read(4)

+22 −32
Original line number Diff line number Diff line
@@ -182,12 +182,17 @@ def generateRequests(startTs: int, endTs: int) -> dict:
def generatePiData(startTs: int, endTs: int) -> dict:
    data = dict()

    someOrientation = lambda: ORIENTATION(
        w=2 * random.random() - 1.0,
        x=2 * random.random() - 1.0,
        y=2 * random.random() - 1.0,
        z=2 * random.random() - 1.0,
    )
    def random_unit_quaternion():
        w = 2*random.random() - 1.0
        x = 2*random.random() - 1.0
        y = 2*random.random() - 1.0
        z = 2*random.random() - 1.0
        n = (w*w + x*x + y*y + z*z)**0.5
        if n == 0.0:
            return random_unit_quaternion()
        return ORIENTATION(w/n, x/n, y/n, z/n)

    someOrientation = lambda: random_unit_quaternion()
    somePosition = lambda: POSITION(
        x=random.randint(-32788, 32767) / 100.0,
        y=random.randint(-32788, 32767) / 100.0,
@@ -209,23 +214,8 @@ def generatePiData(startTs: int, endTs: int) -> dict:
    someDIG = lambda: DIEGETIC_TYPE(
        isDigetic=[bool(random.getrandbits(1)) for _ in range(random.randint(1, 5))]
    )
    someAuFocusDirLvl = lambda: AUDIO_FOCUS(
        ORIENTATION(
            w=2 * random.random() - 1.0,
            x=2 * random.random() - 1.0,
            y=2 * random.random() - 1.0,
            z=2 * random.random() - 1.0,
        ),
        level=AUDIO_FOCUS_LEVEL(random.randint(0, 15)),
    )
    someAuFocusDir = lambda: AUDIO_FOCUS(
        ORIENTATION(
            w=2 * random.random() - 1.0,
            x=2 * random.random() - 1.0,
            y=2 * random.random() - 1.0,
            z=2 * random.random() - 1.0,
        )
    )
    someAuFocusDirLvl = lambda: AUDIO_FOCUS(random_unit_quaternion(),level=AUDIO_FOCUS_LEVEL(random.randint(0, 15)),)
    someAuFocusDir = lambda: AUDIO_FOCUS(random_unit_quaternion())
    someAuFocusLvl = lambda: AUDIO_FOCUS(level=AUDIO_FOCUS_LEVEL(random.randint(0, 15)))
    someAuFocusList = [someAuFocusDirLvl, someAuFocusDir, someAuFocusLvl]
    someLatency = lambda: PI_LATENCY(
@@ -273,7 +263,7 @@ def generatePiData(startTs: int, endTs: int) -> dict:
    someNumISM = lambda : ISM_NUM(num=random.randint(1, 4))
    someISMIds = lambda num_ism : ISM_ID(ids=[int(random.getrandbits(8)) for _ in range(num_ism)])
    someISMGains = lambda num_ism : ISM_GAIN(gains=[random.choice([int(random.randint(-24,12)), -128]) for _ in range(num_ism)]) # -128 corresponds to -Inf
    someISMOrientations = lambda num_ism : [ORIENTATION(w=2*random.random()-1.0, x=2*random.random()-1.0, y=2*random.random()-1.0, z=2*random.random()-1.0) for _ in range(num_ism)]
    someISMOrientations = lambda num_ism : [random_unit_quaternion() for _ in range(num_ism)]
    someISMPositions = lambda num_ism : [POSITION( x=random.randint(-32788, 32767)/100.0, y=random.randint(-32788, 32767)/100.0, z=random.randint(-32788, 32767)/100.0) for _ in range(num_ism)]
    someISMDistanceAttenuations = lambda num_ism : [DISTANCE_ATTENUATION(ref_dist=random.randint(1,64)/10.0, max_dist=random.randint(1,64), roll_off=random.randint(0,40)/10.0) for _ in range(num_ism)]
    someISMDirectivities = lambda num_ism : [DIRECTIVITY(inner_ang=random.randint(0,24)*15, outer_ang=random.randint(0,24)*15, outer_att=random.choice([random.randint(-30,0)*3, -128])) for _ in range(num_ism)] # -128 corresponds to -Inf
@@ -322,10 +312,10 @@ def isEqualFrame(refFrame: bytes, dutFrame: bytes):


def isEqualOrientation(ref: ORIENTATION, dut: ORIENTATION):
    assert abs(ref.w - dut.w) < 0.0001, "Scene Orientation PI Data mismatch in w"
    assert abs(ref.x - dut.x) < 0.0001, "Scene Orientation PI Data mismatch in x"
    assert abs(ref.y - dut.y) < 0.0001, "Scene Orientation PI Data mismatch in y"
    assert abs(ref.z - dut.z) < 0.0001, "Scene Orientation PI Data mismatch in z"
    assert abs(abs(ref.w) - abs(dut.w)) < 0.01, "Scene Orientation PI Data mismatch in w"
    assert abs(abs(ref.x) - abs(dut.x)) < 0.01, "Scene Orientation PI Data mismatch in x"
    assert abs(abs(ref.y) - abs(dut.y)) < 0.01, "Scene Orientation PI Data mismatch in y"
    assert abs(abs(ref.z) - abs(dut.z)) < 0.01, "Scene Orientation PI Data mismatch in z"


def isEqualPosition(ref: POSITION, dut: POSITION):
@@ -392,16 +382,16 @@ def isEqualAudioFocus(ref: AUDIO_FOCUS, dut: AUDIO_FOCUS):
        assert dut.direction is not None, "Audio Focus PI Data missing direction"
    if ref.direction is not None and dut.direction is not None:
        assert (
            abs(ref.direction["w"] - dut.direction.w) < 0.0001
            abs(abs(ref.direction["w"]) - abs(dut.direction.w)) < 0.01
        ), "Audio Focus PI Data mismatch in direction w"
        assert (
            abs(ref.direction["x"] - dut.direction.x) < 0.0001
            abs(abs(ref.direction["x"]) - abs(dut.direction.x)) < 0.01
        ), "Audio Focus PI Data mismatch in direction x"
        assert (
            abs(ref.direction["y"] - dut.direction.y) < 0.0001
            abs(abs(ref.direction["y"]) - abs(dut.direction.y)) < 0.01
        ), "Audio Focus PI Data mismatch in direction y"
        assert (
            abs(ref.direction["z"] - dut.direction.z) < 0.0001
            abs(abs(ref.direction["z"]) - abs(dut.direction.z)) < 0.01
        ), "Audio Focus PI Data mismatch in direction z"
    assert ref.level == dut.level, "Audio Focus PI Data mismatch in level"