LCOV - code coverage report
Current view: top level - lib_dec - jbm_jb4_circularbuffer.c (source / functions) Hit Total Coverage
Test: Coverage on main -- long test vectors @ a21f94bc6bac334fe001a5bad2f7b32b79038097 Lines: 132 138 95.7 %
Date: 2025-11-01 09:50:07 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         864 : ivas_error JB4_CIRCULARBUFFER_Create(
      74             :     JB4_CIRCULARBUFFER_HANDLE *ph )
      75             : {
      76             :     JB4_CIRCULARBUFFER_HANDLE h;
      77             : 
      78         864 :     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         864 :     h->data = NULL;
      84         864 :     h->capacity = 0;
      85         864 :     h->writePos = 0;
      86         864 :     h->readPos = 0;
      87             : 
      88         864 :     *ph = h;
      89             : 
      90         864 :     return IVAS_ERR_OK;
      91             : }
      92             : 
      93             : 
      94             : /* Destroys the circular buffer (FIFO) */
      95         864 : void JB4_CIRCULARBUFFER_Destroy(
      96             :     JB4_CIRCULARBUFFER_HANDLE *ph )
      97             : {
      98             :     JB4_CIRCULARBUFFER_HANDLE h;
      99             : 
     100         864 :     if ( !ph )
     101             :     {
     102           0 :         return;
     103             :     }
     104         864 :     h = *ph;
     105         864 :     if ( !h )
     106             :     {
     107           0 :         return;
     108             :     }
     109             : 
     110         864 :     if ( h->data )
     111             :     {
     112         864 :         free( h->data );
     113             :     }
     114         864 :     free( h );
     115         864 :     *ph = NULL;
     116             : 
     117         864 :     return;
     118             : }
     119             : 
     120             : 
     121             : /* Initializes a circular buffer (FIFO) with a fixed maximum allowed number of elements */
     122         864 : 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         864 :     ++capacity;
     128             : 
     129         864 :     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         864 :     h->capacity = capacity;
     135         864 :     h->writePos = 0;
     136         864 :     h->readPos = 0;
     137             : 
     138         864 :     return IVAS_ERR_OK;
     139             : }
     140             : 
     141             : 
     142     5844528 : int16_t JB4_CIRCULARBUFFER_Enque(
     143             :     JB4_CIRCULARBUFFER_HANDLE h,
     144             :     JB4_CIRCULARBUFFER_ELEMENT element )
     145             : {
     146     5844528 :     if ( JB4_CIRCULARBUFFER_IsFull( h ) )
     147             :     {
     148           0 :         return -1;
     149             :     }
     150             : 
     151     5844528 :     h->data[h->writePos] = element;
     152     5844528 :     ++h->writePos;
     153     5844528 :     if ( h->writePos == h->capacity )
     154             :     {
     155       54237 :         h->writePos = 0;
     156             :     }
     157             : 
     158     5844528 :     return 0;
     159             : }
     160             : 
     161             : 
     162     5637498 : int16_t JB4_CIRCULARBUFFER_Deque(
     163             :     JB4_CIRCULARBUFFER_HANDLE h,
     164             :     JB4_CIRCULARBUFFER_ELEMENT *pElement )
     165             : {
     166     5637498 :     if ( JB4_CIRCULARBUFFER_IsEmpty( h ) )
     167             :     {
     168           0 :         return -1;
     169             :     }
     170             : 
     171     5637498 :     *pElement = h->data[h->readPos];
     172     5637498 :     ++h->readPos;
     173     5637498 :     if ( h->readPos == h->capacity )
     174             :     {
     175       53487 :         h->readPos = 0;
     176             :     }
     177             : 
     178     5637498 :     return 0;
     179             : }
     180             : 
     181             : 
     182             : /* Returns the first element. */
     183     3973803 : JB4_CIRCULARBUFFER_ELEMENT JB4_CIRCULARBUFFER_Front(
     184             :     const JB4_CIRCULARBUFFER_HANDLE h )
     185             : {
     186             :     JB4_CIRCULARBUFFER_ELEMENT ret;
     187             : 
     188     3973803 :     ret = h->data[h->readPos];
     189             : 
     190     3973803 :     return ret;
     191             : }
     192             : 
     193             : /* Returns the last element. */
     194     2191671 : JB4_CIRCULARBUFFER_ELEMENT JB4_CIRCULARBUFFER_Back(
     195             :     const JB4_CIRCULARBUFFER_HANDLE h )
     196             : {
     197             :     JB4_CIRCULARBUFFER_ELEMENT ret;
     198             : 
     199     2191671 :     if ( h->writePos != 0U )
     200             :     {
     201     2172402 :         ret = h->data[h->writePos - 1];
     202             :     }
     203             :     else
     204             :     {
     205       19269 :         ret = h->data[h->capacity - 1];
     206             :     }
     207             : 
     208             : 
     209     2191671 :     return ret;
     210             : }
     211             : 
     212             : 
     213     9344674 : int16_t JB4_CIRCULARBUFFER_IsEmpty(
     214             :     const JB4_CIRCULARBUFFER_HANDLE h )
     215             : {
     216             :     int16_t ret;
     217             : 
     218     9344674 :     if ( h->readPos == h->writePos )
     219             :     {
     220         216 :         ret = 1;
     221             :     }
     222             :     else
     223             :     {
     224     9344458 :         ret = 0;
     225             :     }
     226             : 
     227     9344674 :     return ret;
     228             : }
     229             : 
     230             : 
     231     8036199 : int16_t JB4_CIRCULARBUFFER_IsFull(
     232             :     const JB4_CIRCULARBUFFER_HANDLE h )
     233             : {
     234             :     int16_t ret;
     235             : 
     236     8036199 :     if ( ( ( h->writePos + 1 ) % h->capacity ) == h->readPos )
     237             :     {
     238      333828 :         ret = 1;
     239             :     }
     240             :     else
     241             :     {
     242     7702371 :         ret = 0;
     243             :     }
     244             : 
     245     8036199 :     return ret;
     246             : }
     247             : 
     248             : 
     249     1513537 : uint16_t JB4_CIRCULARBUFFER_Size(
     250             :     const JB4_CIRCULARBUFFER_HANDLE h )
     251             : {
     252             :     uint16_t ret;
     253             : 
     254     1513537 :     if ( h->readPos <= h->writePos )
     255             :     {
     256      156904 :         ret = h->writePos - h->readPos;
     257             :     }
     258             :     else
     259             :     {
     260             :         /* wrap around */
     261     1356633 :         ret = h->writePos + h->capacity - h->readPos;
     262             :     }
     263             : 
     264             : 
     265     1513537 :     return ret;
     266             : }
     267             : 
     268             : 
     269             : /* Calculates statistics over all elements: min element */
     270     2976475 : 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     2976475 :     minEle = h->data[h->readPos];
     279             : 
     280     2976475 :     if ( h->readPos <= h->writePos )
     281             :     {
     282             :         /* no wrap around */
     283             :         /* calc statistics for [readPos;writePos[ */
     284   103071071 :         for ( i = h->readPos; i != h->writePos; ++i )
     285             :         {
     286   102723376 :             if ( h->data[i] < minEle )
     287             :             {
     288      226569 :                 minEle = h->data[i];
     289             :             }
     290             :         }
     291             :     }
     292             :     else
     293             :     {
     294             :         /* wrap around */
     295             :         /* calc statistics for [readPos;capacity[ */
     296   483493431 :         for ( i = h->readPos; i != h->capacity; ++i )
     297             :         {
     298   480864651 :             if ( h->data[i] < minEle )
     299             :             {
     300     3503244 :                 minEle = h->data[i];
     301             :             }
     302             :         }
     303             :         /* calc statistics for [0;writePos[ */
     304   470255793 :         for ( i = 0; i != h->writePos; ++i )
     305             :         {
     306   467627013 :             if ( h->data[i] < minEle )
     307             :             {
     308       94185 :                 minEle = h->data[i];
     309             :             }
     310             :         }
     311             :     }
     312             : 
     313     2976475 :     *pMin = minEle;
     314     2976475 : }
     315             : 
     316             : 
     317             : /* Calculates statistics over all elements: max element */
     318      730485 : 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      730485 :     maxEle = h->data[h->readPos];
     327      730485 :     if ( h->readPos <= h->writePos )
     328             :     {
     329             :         /* no wrap around */
     330             :         /* calc statistics for [readPos;writePos[ */
     331    10128174 :         for ( i = h->readPos; i != h->writePos; ++i )
     332             :         {
     333    10062399 :             if ( h->data[i] > maxEle )
     334             :             {
     335      159312 :                 maxEle = h->data[i];
     336             :             }
     337             :         }
     338             :     }
     339             :     else
     340             :     {
     341             :         /* wrap around */
     342             :         /* calc statistics for [readPos;capacity[ */
     343    63928737 :         for ( i = h->readPos; i != h->capacity; ++i )
     344             :         {
     345    63264027 :             if ( h->data[i] > maxEle )
     346             :             {
     347      643242 :                 maxEle = h->data[i];
     348             :             }
     349             :         }
     350             :         /* calc statistics for [0;writePos[ */
     351    62943858 :         for ( i = 0; i != h->writePos; ++i )
     352             :         {
     353    62279148 :             if ( h->data[i] > maxEle )
     354             :             {
     355      376125 :                 maxEle = h->data[i];
     356             :             }
     357             :         }
     358             :     }
     359             : 
     360      730485 :     *pMax = maxEle;
     361             : 
     362      730485 :     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     1513105 : 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     1513105 :     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     1513105 :     maxElementsSize = 0;
     388     1513105 :     maxElementsCapacity = nElementsToIgnore + 1;
     389     1513105 :     assert( maxElementsCapacity <= JBM_MAX_CIRCULAR_ELEMENTS );
     390     1513105 :     if ( h->readPos <= h->writePos )
     391             :     {
     392             :         /* no wrap around */
     393             :         /* calc statistics for [readPos;writePos[ */
     394    37953849 :         for ( i = h->readPos; i != h->writePos; ++i )
     395             :         {
     396    37797377 :             if ( h->data[i] < minEle )
     397             :             {
     398      120903 :                 minEle = h->data[i];
     399             :             }
     400    37797377 :             JB4_CIRCULARBUFFER_calcPercentile( maxElements, &maxElementsSize, maxElementsCapacity, h->data[i] );
     401             :         }
     402             :     }
     403             :     else
     404             :     {
     405             :         /* wrap around */
     406             :         /* calc statistics for [readPos;capacity[ */
     407   179522238 :         for ( i = h->readPos; i != h->capacity; ++i )
     408             :         {
     409   178165605 :             if ( h->data[i] < minEle )
     410             :             {
     411     1775778 :                 minEle = h->data[i];
     412             :             }
     413   178165605 :             JB4_CIRCULARBUFFER_calcPercentile( maxElements, &maxElementsSize, maxElementsCapacity, h->data[i] );
     414             :         }
     415             :         /* calc statistics for [0;writePos[ */
     416   174004221 :         for ( i = 0; i != h->writePos; ++i )
     417             :         {
     418   172647588 :             if ( h->data[i] < minEle )
     419             :             {
     420       81141 :                 minEle = h->data[i];
     421             :             }
     422   172647588 :             JB4_CIRCULARBUFFER_calcPercentile( maxElements, &maxElementsSize, maxElementsCapacity, h->data[i] );
     423             :         }
     424             :     }
     425             : 
     426     1513105 :     *pPercentile = maxElements[0];
     427     1513105 :     *pMin = minEle;
     428             : 
     429     1513105 :     return;
     430             : }
     431             : 
     432             : 
     433             : /* Calculates percentile by selecting greatest elements. */
     434   388610570 : 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   388610570 :     if ( *size < capacity )
     444             :     {
     445     5067346 :         for ( i = 0; i != *size; ++i )
     446             :         {
     447     3179946 :             if ( newElement <= elements[i] )
     448             :             {
     449             :                 /* insert newElement at index i */
     450     4835772 :                 for ( j = *size; j > i; --j )
     451             :                 {
     452     3018936 :                     elements[j] = elements[j - 1];
     453             :                 }
     454     1816836 :                 elements[i] = newElement;
     455     1816836 :                 ++*size;
     456     1816836 :                 return;
     457             :             }
     458             :         }
     459             :         /* newElement is maximum, just append it */
     460     1887400 :         elements[*size] = newElement;
     461     1887400 :         ++*size;
     462     1887400 :         return;
     463             :     }
     464             : 
     465             :     /* check if newElement is too small to be inserted in elements buffer */
     466   384906334 :     if ( newElement <= elements[0] )
     467             :     {
     468   377439971 :         return;
     469             :     }
     470             : 
     471             :     /* select position to insert newElement to elements */
     472    12662366 :     for ( i = *size - 1; i != 0; --i )
     473             :     {
     474     9336693 :         if ( newElement >= elements[i] )
     475             :         {
     476             :             /* insert newElement at index i */
     477    13462218 :             for ( j = 0; j < i; j++ )
     478             :             {
     479     9321528 :                 elements[j] = elements[1 + j];
     480             :             }
     481     4140690 :             elements[i] = newElement;
     482     4140690 :             return;
     483             :         }
     484             :     }
     485             :     /* newElement is just greater than first on in elements buffer */
     486     3325673 :     elements[0] = newElement;
     487             : 
     488     3325673 :     return;
     489             : }

Generated by: LCOV version 1.14