LCOV - code coverage report
Current view: top level - lib_dec - jbm_jb4_circularbuffer.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 132 138 95.7 %
Date: 2025-05-23 08:37:30 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
       4             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
       5             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
       6             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
       7             :    contributors to this repository. All Rights Reserved.
       8             : 
       9             :    This software is protected by copyright law and by international treaties.
      10             :    The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
      11             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
      12             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
      13             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
      14             :    contributors to this repository retain full ownership rights in their respective contributions in
      15             :    the software. This notice grants no license of any kind, including but not limited to patent
      16             :    license, nor is any license granted by implication, estoppel or otherwise.
      17             : 
      18             :    Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
      19             :    contributions.
      20             : 
      21             :    This software is provided "AS IS", without any express or implied warranties. The software is in the
      22             :    development stage. It is intended exclusively for experts who have experience with such software and
      23             :    solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
      24             :    and fitness for a particular purpose are hereby disclaimed and excluded.
      25             : 
      26             :    Any dispute, controversy or claim arising under or in relation to providing this software shall be
      27             :    submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
      28             :    accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
      29             :    the United Nations Convention on Contracts on the International Sales of Goods.
      30             : 
      31             : *******************************************************************************************************/
      32             : 
      33             : /*====================================================================================
      34             :     EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0
      35             :   ====================================================================================*/
      36             : 
      37             : #include <assert.h>
      38             : #include <stdint.h>
      39             : #include "options.h"
      40             : #include "string.h"
      41             : #include "prot.h"
      42             : #ifdef DEBUGGING
      43             : #include "debug.h"
      44             : #endif
      45             : #include "wmc_auto.h"
      46             : /* local includes */
      47             : #include "jbm_jb4_circularbuffer.h"
      48             : 
      49             : 
      50             : /** Calculates percentile by selecting greatest elements.
      51             :  * This function partial sorts all given elements in the given buffer.
      52             :  * @param[in,out] elements ascending sorted buffer of selected greatest elements
      53             :  * @param[in,out] size size of elements buffer
      54             :  * @param[in]     capacity maximum number of elements to buffer
      55             :  * @param[in]     newElement element to insert in buffer if great enough */
      56             : static void JB4_CIRCULARBUFFER_calcPercentile( JB4_CIRCULARBUFFER_ELEMENT *elements, uint16_t *size, const uint16_t capacity, JB4_CIRCULARBUFFER_ELEMENT newElement );
      57             : 
      58             : /** circular buffer (FIFO) with fixed capacity */
      59             : struct JB4_CIRCULARBUFFER
      60             : {
      61             :     /** elements of circular buffer */
      62             :     JB4_CIRCULARBUFFER_ELEMENT *data;
      63             :     /** maximum allowed number of elements plus one free element (to decide between full/empty buffer) */
      64             :     uint16_t capacity;
      65             :     /** position of next enque operation */
      66             :     uint16_t writePos;
      67             :     /** position of next deque operation */
      68             :     uint16_t readPos;
      69             : };
      70             : 
      71             : 
      72             : /* Creates a circular buffer (FIFO) */
      73         840 : ivas_error JB4_CIRCULARBUFFER_Create(
      74             :     JB4_CIRCULARBUFFER_HANDLE *ph )
      75             : {
      76             :     JB4_CIRCULARBUFFER_HANDLE h;
      77             : 
      78         840 :     if ( ( h = malloc( sizeof( struct JB4_CIRCULARBUFFER ) ) ) == NULL )
      79             :     {
      80           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM\n" ) );
      81             :     }
      82             : 
      83         840 :     h->data = NULL;
      84         840 :     h->capacity = 0;
      85         840 :     h->writePos = 0;
      86         840 :     h->readPos = 0;
      87             : 
      88         840 :     *ph = h;
      89             : 
      90         840 :     return IVAS_ERR_OK;
      91             : }
      92             : 
      93             : 
      94             : /* Destroys the circular buffer (FIFO) */
      95         840 : void JB4_CIRCULARBUFFER_Destroy(
      96             :     JB4_CIRCULARBUFFER_HANDLE *ph )
      97             : {
      98             :     JB4_CIRCULARBUFFER_HANDLE h;
      99             : 
     100         840 :     if ( !ph )
     101             :     {
     102           0 :         return;
     103             :     }
     104         840 :     h = *ph;
     105         840 :     if ( !h )
     106             :     {
     107           0 :         return;
     108             :     }
     109             : 
     110         840 :     if ( h->data )
     111             :     {
     112         840 :         free( h->data );
     113             :     }
     114         840 :     free( h );
     115         840 :     *ph = NULL;
     116             : 
     117         840 :     return;
     118             : }
     119             : 
     120             : 
     121             : /* Initializes a circular buffer (FIFO) with a fixed maximum allowed number of elements */
     122         840 : int16_t JB4_CIRCULARBUFFER_Init(
     123             :     JB4_CIRCULARBUFFER_HANDLE h,
     124             :     uint16_t capacity )
     125             : {
     126             :     /* keep one element free to be able to decide between full/empty buffer */
     127         840 :     ++capacity;
     128             : 
     129         840 :     if ( ( h->data = malloc( capacity * sizeof( JB4_CIRCULARBUFFER_ELEMENT ) ) ) == NULL )
     130             :     {
     131           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM\n" ) );
     132             :     }
     133             : 
     134         840 :     h->capacity = capacity;
     135         840 :     h->writePos = 0;
     136         840 :     h->readPos = 0;
     137             : 
     138         840 :     return IVAS_ERR_OK;
     139             : }
     140             : 
     141             : 
     142      558318 : int16_t JB4_CIRCULARBUFFER_Enque(
     143             :     JB4_CIRCULARBUFFER_HANDLE h,
     144             :     JB4_CIRCULARBUFFER_ELEMENT element )
     145             : {
     146      558318 :     if ( JB4_CIRCULARBUFFER_IsFull( h ) )
     147             :     {
     148           0 :         return -1;
     149             :     }
     150             : 
     151      558318 :     h->data[h->writePos] = element;
     152      558318 :     ++h->writePos;
     153      558318 :     if ( h->writePos == h->capacity )
     154             :     {
     155        4692 :         h->writePos = 0;
     156             :     }
     157             : 
     158      558318 :     return 0;
     159             : }
     160             : 
     161             : 
     162      402774 : int16_t JB4_CIRCULARBUFFER_Deque(
     163             :     JB4_CIRCULARBUFFER_HANDLE h,
     164             :     JB4_CIRCULARBUFFER_ELEMENT *pElement )
     165             : {
     166      402774 :     if ( JB4_CIRCULARBUFFER_IsEmpty( h ) )
     167             :     {
     168           0 :         return -1;
     169             :     }
     170             : 
     171      402774 :     *pElement = h->data[h->readPos];
     172      402774 :     ++h->readPos;
     173      402774 :     if ( h->readPos == h->capacity )
     174             :     {
     175        4071 :         h->readPos = 0;
     176             :     }
     177             : 
     178      402774 :     return 0;
     179             : }
     180             : 
     181             : 
     182             : /* Returns the first element. */
     183      336915 : JB4_CIRCULARBUFFER_ELEMENT JB4_CIRCULARBUFFER_Front(
     184             :     const JB4_CIRCULARBUFFER_HANDLE h )
     185             : {
     186             :     JB4_CIRCULARBUFFER_ELEMENT ret;
     187             : 
     188      336915 :     ret = h->data[h->readPos];
     189             : 
     190      336915 :     return ret;
     191             : }
     192             : 
     193             : /* Returns the last element. */
     194      209343 : JB4_CIRCULARBUFFER_ELEMENT JB4_CIRCULARBUFFER_Back(
     195             :     const JB4_CIRCULARBUFFER_HANDLE h )
     196             : {
     197             :     JB4_CIRCULARBUFFER_ELEMENT ret;
     198             : 
     199      209343 :     if ( h->writePos != 0U )
     200             :     {
     201      207684 :         ret = h->data[h->writePos - 1];
     202             :     }
     203             :     else
     204             :     {
     205        1659 :         ret = h->data[h->capacity - 1];
     206             :     }
     207             : 
     208             : 
     209      209343 :     return ret;
     210             : }
     211             : 
     212             : 
     213      759804 : int16_t JB4_CIRCULARBUFFER_IsEmpty(
     214             :     const JB4_CIRCULARBUFFER_HANDLE h )
     215             : {
     216             :     int16_t ret;
     217             : 
     218      759804 :     if ( h->readPos == h->writePos )
     219             :     {
     220         210 :         ret = 1;
     221             :     }
     222             :     else
     223             :     {
     224      759594 :         ret = 0;
     225             :     }
     226             : 
     227      759804 :     return ret;
     228             : }
     229             : 
     230             : 
     231      767661 : int16_t JB4_CIRCULARBUFFER_IsFull(
     232             :     const JB4_CIRCULARBUFFER_HANDLE h )
     233             : {
     234             :     int16_t ret;
     235             : 
     236      767661 :     if ( ( ( h->writePos + 1 ) % h->capacity ) == h->readPos )
     237             :     {
     238       23979 :         ret = 1;
     239             :     }
     240             :     else
     241             :     {
     242      743682 :         ret = 0;
     243             :     }
     244             : 
     245      767661 :     return ret;
     246             : }
     247             : 
     248             : 
     249      146727 : uint16_t JB4_CIRCULARBUFFER_Size(
     250             :     const JB4_CIRCULARBUFFER_HANDLE h )
     251             : {
     252             :     uint16_t ret;
     253             : 
     254      146727 :     if ( h->readPos <= h->writePos )
     255             :     {
     256       52263 :         ret = h->writePos - h->readPos;
     257             :     }
     258             :     else
     259             :     {
     260             :         /* wrap around */
     261       94464 :         ret = h->writePos + h->capacity - h->readPos;
     262             :     }
     263             : 
     264             : 
     265      146727 :     return ret;
     266             : }
     267             : 
     268             : 
     269             : /* Calculates statistics over all elements: min element */
     270      287109 : void JB4_CIRCULARBUFFER_Min(
     271             :     const JB4_CIRCULARBUFFER_HANDLE h,
     272             :     JB4_CIRCULARBUFFER_ELEMENT *pMin )
     273             : {
     274             :     uint16_t i;
     275             :     JB4_CIRCULARBUFFER_ELEMENT minEle;
     276             : 
     277             :     /* init output variable */
     278      287109 :     minEle = h->data[h->readPos];
     279             : 
     280      287109 :     if ( h->readPos <= h->writePos )
     281             :     {
     282             :         /* no wrap around */
     283             :         /* calc statistics for [readPos;writePos[ */
     284    26624025 :         for ( i = h->readPos; i != h->writePos; ++i )
     285             :         {
     286    26495463 :             if ( h->data[i] < minEle )
     287             :             {
     288       13242 :                 minEle = h->data[i];
     289             :             }
     290             :         }
     291             :     }
     292             :     else
     293             :     {
     294             :         /* wrap around */
     295             :         /* calc statistics for [readPos;capacity[ */
     296    25540014 :         for ( i = h->readPos; i != h->capacity; ++i )
     297             :         {
     298    25381467 :             if ( h->data[i] < minEle )
     299             :             {
     300      226500 :                 minEle = h->data[i];
     301             :             }
     302             :         }
     303             :         /* calc statistics for [0;writePos[ */
     304    22766004 :         for ( i = 0; i != h->writePos; ++i )
     305             :         {
     306    22607457 :             if ( h->data[i] < minEle )
     307             :             {
     308        7629 :                 minEle = h->data[i];
     309             :             }
     310             :         }
     311             :     }
     312             : 
     313      287109 :     *pMin = minEle;
     314      287109 : }
     315             : 
     316             : 
     317             : /* Calculates statistics over all elements: max element */
     318       69711 : void JB4_CIRCULARBUFFER_Max(
     319             :     const JB4_CIRCULARBUFFER_HANDLE h,
     320             :     JB4_CIRCULARBUFFER_ELEMENT *pMax )
     321             : {
     322             :     uint16_t i;
     323             :     JB4_CIRCULARBUFFER_ELEMENT maxEle;
     324             : 
     325             :     /* init output variable */
     326       69711 :     maxEle = h->data[h->readPos];
     327       69711 :     if ( h->readPos <= h->writePos )
     328             :     {
     329             :         /* no wrap around */
     330             :         /* calc statistics for [readPos;writePos[ */
     331     2413683 :         for ( i = h->readPos; i != h->writePos; ++i )
     332             :         {
     333     2390577 :             if ( h->data[i] > maxEle )
     334             :             {
     335       78327 :                 maxEle = h->data[i];
     336             :             }
     337             :         }
     338             :     }
     339             :     else
     340             :     {
     341             :         /* wrap around */
     342             :         /* calc statistics for [readPos;capacity[ */
     343     4574217 :         for ( i = h->readPos; i != h->capacity; ++i )
     344             :         {
     345     4527612 :             if ( h->data[i] > maxEle )
     346             :             {
     347       64002 :                 maxEle = h->data[i];
     348             :             }
     349             :         }
     350             :         /* calc statistics for [0;writePos[ */
     351     4165242 :         for ( i = 0; i != h->writePos; ++i )
     352             :         {
     353     4118637 :             if ( h->data[i] > maxEle )
     354             :             {
     355       23772 :                 maxEle = h->data[i];
     356             :             }
     357             :         }
     358             :     }
     359             : 
     360       69711 :     *pMax = maxEle;
     361             : 
     362       69711 :     return;
     363             : }
     364             : 
     365             : #define JBM_MAX_CIRCULAR_ELEMENTS 100
     366             : 
     367             : /* Calculates statistics over a considered fraction of all elements: min element and percentile */
     368      146307 : void JB4_CIRCULARBUFFER_MinAndPercentile(
     369             :     const JB4_CIRCULARBUFFER_HANDLE h,
     370             :     uint16_t nElementsToIgnore,
     371             :     JB4_CIRCULARBUFFER_ELEMENT *pMin,
     372             :     JB4_CIRCULARBUFFER_ELEMENT *pPercentile )
     373             : {
     374             :     uint16_t i;
     375             :     JB4_CIRCULARBUFFER_ELEMENT maxElements[JBM_MAX_CIRCULAR_ELEMENTS];
     376             :     uint16_t maxElementsSize;
     377             :     uint16_t maxElementsCapacity;
     378             :     JB4_CIRCULARBUFFER_ELEMENT minEle;
     379             : 
     380             :     /* init output variables */
     381      146307 :     minEle = h->data[h->readPos];
     382             : 
     383             :     /* To calculate the percentile, a number of elements with the highest values are collected in maxElements in
     384             :      * ascending sorted order. This array has a size of nElementsToIgnore plus one. This additional element is the
     385             :      * lowest of all maxElements, and is called the percentile of all elements. */
     386             : 
     387      146307 :     maxElementsSize = 0;
     388      146307 :     maxElementsCapacity = nElementsToIgnore + 1;
     389      146307 :     assert( maxElementsCapacity <= JBM_MAX_CIRCULAR_ELEMENTS );
     390      146307 :     if ( h->readPos <= h->writePos )
     391             :     {
     392             :         /* no wrap around */
     393             :         /* calc statistics for [readPos;writePos[ */
     394     9792357 :         for ( i = h->readPos; i != h->writePos; ++i )
     395             :         {
     396     9740514 :             if ( h->data[i] < minEle )
     397             :             {
     398        9402 :                 minEle = h->data[i];
     399             :             }
     400     9740514 :             JB4_CIRCULARBUFFER_calcPercentile( maxElements, &maxElementsSize, maxElementsCapacity, h->data[i] );
     401             :         }
     402             :     }
     403             :     else
     404             :     {
     405             :         /* wrap around */
     406             :         /* calc statistics for [readPos;capacity[ */
     407     9953298 :         for ( i = h->readPos; i != h->capacity; ++i )
     408             :         {
     409     9858834 :             if ( h->data[i] < minEle )
     410             :             {
     411      131865 :                 minEle = h->data[i];
     412             :             }
     413     9858834 :             JB4_CIRCULARBUFFER_calcPercentile( maxElements, &maxElementsSize, maxElementsCapacity, h->data[i] );
     414             :         }
     415             :         /* calc statistics for [0;writePos[ */
     416     8854773 :         for ( i = 0; i != h->writePos; ++i )
     417             :         {
     418     8760309 :             if ( h->data[i] < minEle )
     419             :             {
     420        7629 :                 minEle = h->data[i];
     421             :             }
     422     8760309 :             JB4_CIRCULARBUFFER_calcPercentile( maxElements, &maxElementsSize, maxElementsCapacity, h->data[i] );
     423             :         }
     424             :     }
     425             : 
     426      146307 :     *pPercentile = maxElements[0];
     427      146307 :     *pMin = minEle;
     428             : 
     429      146307 :     return;
     430             : }
     431             : 
     432             : 
     433             : /* Calculates percentile by selecting greatest elements. */
     434    28359657 : static void JB4_CIRCULARBUFFER_calcPercentile(
     435             :     JB4_CIRCULARBUFFER_ELEMENT *elements,
     436             :     uint16_t *size,
     437             :     const uint16_t capacity,
     438             :     JB4_CIRCULARBUFFER_ELEMENT newElement )
     439             : {
     440             :     uint16_t i, j;
     441             : 
     442             :     /* insert newElement if elements buffer is not yet full */
     443    28359657 :     if ( *size < capacity )
     444             :     {
     445      489438 :         for ( i = 0; i != *size; ++i )
     446             :         {
     447      305019 :             if ( newElement <= elements[i] )
     448             :             {
     449             :                 /* insert newElement at index i */
     450      453819 :                 for ( j = *size; j > i; --j )
     451             :                 {
     452      283113 :                     elements[j] = elements[j - 1];
     453             :                 }
     454      170706 :                 elements[i] = newElement;
     455      170706 :                 ++*size;
     456      170706 :                 return;
     457             :             }
     458             :         }
     459             :         /* newElement is maximum, just append it */
     460      184419 :         elements[*size] = newElement;
     461      184419 :         ++*size;
     462      184419 :         return;
     463             :     }
     464             : 
     465             :     /* check if newElement is too small to be inserted in elements buffer */
     466    28004532 :     if ( newElement <= elements[0] )
     467             :     {
     468    27320190 :         return;
     469             :     }
     470             : 
     471             :     /* select position to insert newElement to elements */
     472     1164357 :     for ( i = *size - 1; i != 0; --i )
     473             :     {
     474      873756 :         if ( newElement >= elements[i] )
     475             :         {
     476             :             /* insert newElement at index i */
     477     1276929 :             for ( j = 0; j < i; j++ )
     478             :             {
     479      883188 :                 elements[j] = elements[1 + j];
     480             :             }
     481      393741 :             elements[i] = newElement;
     482      393741 :             return;
     483             :         }
     484             :     }
     485             :     /* newElement is just greater than first on in elements buffer */
     486      290601 :     elements[0] = newElement;
     487             : 
     488      290601 :     return;
     489             : }

Generated by: LCOV version 1.14