LCOV - code coverage report
Current view: top level - lib_dec - jbm_jb4_circularbuffer.c (source / functions) Hit Total Coverage
Test: Coverage on main @ fec202a8f89be4a2f278a9fc377bfb58b58fab11 Lines: 132 138 95.7 %
Date: 2025-09-14 08:49:17 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      297320 : ivas_error JB4_CIRCULARBUFFER_Create(
      74             :     JB4_CIRCULARBUFFER_HANDLE *ph )
      75             : {
      76             :     JB4_CIRCULARBUFFER_HANDLE h;
      77             : 
      78      297320 :     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      297320 :     h->data = NULL;
      84      297320 :     h->capacity = 0;
      85      297320 :     h->writePos = 0;
      86      297320 :     h->readPos = 0;
      87             : 
      88      297320 :     *ph = h;
      89             : 
      90      297320 :     return IVAS_ERR_OK;
      91             : }
      92             : 
      93             : 
      94             : /* Destroys the circular buffer (FIFO) */
      95      297320 : void JB4_CIRCULARBUFFER_Destroy(
      96             :     JB4_CIRCULARBUFFER_HANDLE *ph )
      97             : {
      98             :     JB4_CIRCULARBUFFER_HANDLE h;
      99             : 
     100      297320 :     if ( !ph )
     101             :     {
     102           0 :         return;
     103             :     }
     104      297320 :     h = *ph;
     105      297320 :     if ( !h )
     106             :     {
     107           0 :         return;
     108             :     }
     109             : 
     110      297320 :     if ( h->data )
     111             :     {
     112      297320 :         free( h->data );
     113             :     }
     114      297320 :     free( h );
     115      297320 :     *ph = NULL;
     116             : 
     117      297320 :     return;
     118             : }
     119             : 
     120             : 
     121             : /* Initializes a circular buffer (FIFO) with a fixed maximum allowed number of elements */
     122      297320 : 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      297320 :     ++capacity;
     128             : 
     129      297320 :     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      297320 :     h->capacity = capacity;
     135      297320 :     h->writePos = 0;
     136      297320 :     h->readPos = 0;
     137             : 
     138      297320 :     return IVAS_ERR_OK;
     139             : }
     140             : 
     141             : 
     142    13715662 : int16_t JB4_CIRCULARBUFFER_Enque(
     143             :     JB4_CIRCULARBUFFER_HANDLE h,
     144             :     JB4_CIRCULARBUFFER_ELEMENT element )
     145             : {
     146    13715662 :     if ( JB4_CIRCULARBUFFER_IsFull( h ) )
     147             :     {
     148           0 :         return -1;
     149             :     }
     150             : 
     151    13715662 :     h->data[h->writePos] = element;
     152    13715662 :     ++h->writePos;
     153    13715662 :     if ( h->writePos == h->capacity )
     154             :     {
     155       25670 :         h->writePos = 0;
     156             :     }
     157             : 
     158    13715662 :     return 0;
     159             : }
     160             : 
     161             : 
     162     2528578 : int16_t JB4_CIRCULARBUFFER_Deque(
     163             :     JB4_CIRCULARBUFFER_HANDLE h,
     164             :     JB4_CIRCULARBUFFER_ELEMENT *pElement )
     165             : {
     166     2528578 :     if ( JB4_CIRCULARBUFFER_IsEmpty( h ) )
     167             :     {
     168           0 :         return -1;
     169             :     }
     170             : 
     171     2528578 :     *pElement = h->data[h->readPos];
     172     2528578 :     ++h->readPos;
     173     2528578 :     if ( h->readPos == h->capacity )
     174             :     {
     175       24449 :         h->readPos = 0;
     176             :     }
     177             : 
     178     2528578 :     return 0;
     179             : }
     180             : 
     181             : 
     182             : /* Returns the first element. */
     183     5867700 : JB4_CIRCULARBUFFER_ELEMENT JB4_CIRCULARBUFFER_Front(
     184             :     const JB4_CIRCULARBUFFER_HANDLE h )
     185             : {
     186             :     JB4_CIRCULARBUFFER_ELEMENT ret;
     187             : 
     188     5867700 :     ret = h->data[h->readPos];
     189             : 
     190     5867700 :     return ret;
     191             : }
     192             : 
     193             : /* Returns the last element. */
     194     5134077 : JB4_CIRCULARBUFFER_ELEMENT JB4_CIRCULARBUFFER_Back(
     195             :     const JB4_CIRCULARBUFFER_HANDLE h )
     196             : {
     197             :     JB4_CIRCULARBUFFER_ELEMENT ret;
     198             : 
     199     5134077 :     if ( h->writePos != 0U )
     200             :     {
     201     5124971 :         ret = h->data[h->writePos - 1];
     202             :     }
     203             :     else
     204             :     {
     205        9106 :         ret = h->data[h->capacity - 1];
     206             :     }
     207             : 
     208             : 
     209     5134077 :     return ret;
     210             : }
     211             : 
     212             : 
     213    11730425 : int16_t JB4_CIRCULARBUFFER_IsEmpty(
     214             :     const JB4_CIRCULARBUFFER_HANDLE h )
     215             : {
     216             :     int16_t ret;
     217             : 
     218    11730425 :     if ( h->readPos == h->writePos )
     219             :     {
     220      148312 :         ret = 1;
     221             :     }
     222             :     else
     223             :     {
     224    11582113 :         ret = 0;
     225             :     }
     226             : 
     227    11730425 :     return ret;
     228             : }
     229             : 
     230             : 
     231    18849739 : int16_t JB4_CIRCULARBUFFER_IsFull(
     232             :     const JB4_CIRCULARBUFFER_HANDLE h )
     233             : {
     234             :     int16_t ret;
     235             : 
     236    18849739 :     if ( ( ( h->writePos + 1 ) % h->capacity ) == h->readPos )
     237             :     {
     238      215957 :         ret = 1;
     239             :     }
     240             :     else
     241             :     {
     242    18633782 :         ret = 0;
     243             :     }
     244             : 
     245    18849739 :     return ret;
     246             : }
     247             : 
     248             : 
     249     4065402 : uint16_t JB4_CIRCULARBUFFER_Size(
     250             :     const JB4_CIRCULARBUFFER_HANDLE h )
     251             : {
     252             :     uint16_t ret;
     253             : 
     254     4065402 :     if ( h->readPos <= h->writePos )
     255             :     {
     256     3459333 :         ret = h->writePos - h->readPos;
     257             :     }
     258             :     else
     259             :     {
     260             :         /* wrap around */
     261      606069 :         ret = h->writePos + h->capacity - h->readPos;
     262             :     }
     263             : 
     264             : 
     265     4065402 :     return ret;
     266             : }
     267             : 
     268             : 
     269             : /* Calculates statistics over all elements: min element */
     270     7366966 : 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     7366966 :     minEle = h->data[h->readPos];
     279             : 
     280     7366966 :     if ( h->readPos <= h->writePos )
     281             :     {
     282             :         /* no wrap around */
     283             :         /* calc statistics for [readPos;writePos[ */
     284   202120531 :         for ( i = h->readPos; i != h->writePos; ++i )
     285             :         {
     286   195889261 :             if ( h->data[i] < minEle )
     287             :             {
     288     3970461 :                 minEle = h->data[i];
     289             :             }
     290             :         }
     291             :     }
     292             :     else
     293             :     {
     294             :         /* wrap around */
     295             :         /* calc statistics for [readPos;capacity[ */
     296   203556492 :         for ( i = h->readPos; i != h->capacity; ++i )
     297             :         {
     298   202420796 :             if ( h->data[i] < minEle )
     299             :             {
     300     1401940 :                 minEle = h->data[i];
     301             :             }
     302             :         }
     303             :         /* calc statistics for [0;writePos[ */
     304   195309288 :         for ( i = 0; i != h->writePos; ++i )
     305             :         {
     306   194173592 :             if ( h->data[i] < minEle )
     307             :             {
     308       39326 :                 minEle = h->data[i];
     309             :             }
     310             :         }
     311             :     }
     312             : 
     313     7366966 :     *pMin = minEle;
     314     7366966 : }
     315             : 
     316             : 
     317             : /* Calculates statistics over all elements: max element */
     318     1686569 : 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     1686569 :     maxEle = h->data[h->readPos];
     327     1686569 :     if ( h->readPos <= h->writePos )
     328             :     {
     329             :         /* no wrap around */
     330             :         /* calc statistics for [readPos;writePos[ */
     331    32991980 :         for ( i = h->readPos; i != h->writePos; ++i )
     332             :         {
     333    31603576 :             if ( h->data[i] > maxEle )
     334             :             {
     335     4531601 :                 maxEle = h->data[i];
     336             :             }
     337             :         }
     338             :     }
     339             :     else
     340             :     {
     341             :         /* wrap around */
     342             :         /* calc statistics for [readPos;capacity[ */
     343    29017432 :         for ( i = h->readPos; i != h->capacity; ++i )
     344             :         {
     345    28719267 :             if ( h->data[i] > maxEle )
     346             :             {
     347      281080 :                 maxEle = h->data[i];
     348             :             }
     349             :         }
     350             :         /* calc statistics for [0;writePos[ */
     351    27961192 :         for ( i = 0; i != h->writePos; ++i )
     352             :         {
     353    27663027 :             if ( h->data[i] > maxEle )
     354             :             {
     355      150035 :                 maxEle = h->data[i];
     356             :             }
     357             :         }
     358             :     }
     359             : 
     360     1686569 :     *pMax = maxEle;
     361             : 
     362     1686569 :     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     3879782 : 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     3879782 :     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     3879782 :     maxElementsSize = 0;
     388     3879782 :     maxElementsCapacity = nElementsToIgnore + 1;
     389     3879782 :     assert( maxElementsCapacity <= JBM_MAX_CIRCULAR_ELEMENTS );
     390     3879782 :     if ( h->readPos <= h->writePos )
     391             :     {
     392             :         /* no wrap around */
     393             :         /* calc statistics for [readPos;writePos[ */
     394    96566742 :         for ( i = h->readPos; i != h->writePos; ++i )
     395             :         {
     396    93293029 :             if ( h->data[i] < minEle )
     397             :             {
     398     2193797 :                 minEle = h->data[i];
     399             :             }
     400    93293029 :             JB4_CIRCULARBUFFER_calcPercentile( maxElements, &maxElementsSize, maxElementsCapacity, h->data[i] );
     401             :         }
     402             :     }
     403             :     else
     404             :     {
     405             :         /* wrap around */
     406             :         /* calc statistics for [readPos;capacity[ */
     407    76143969 :         for ( i = h->readPos; i != h->capacity; ++i )
     408             :         {
     409    75537900 :             if ( h->data[i] < minEle )
     410             :             {
     411      728287 :                 minEle = h->data[i];
     412             :             }
     413    75537900 :             JB4_CIRCULARBUFFER_calcPercentile( maxElements, &maxElementsSize, maxElementsCapacity, h->data[i] );
     414             :         }
     415             :         /* calc statistics for [0;writePos[ */
     416    72807893 :         for ( i = 0; i != h->writePos; ++i )
     417             :         {
     418    72201824 :             if ( h->data[i] < minEle )
     419             :             {
     420       34978 :                 minEle = h->data[i];
     421             :             }
     422    72201824 :             JB4_CIRCULARBUFFER_calcPercentile( maxElements, &maxElementsSize, maxElementsCapacity, h->data[i] );
     423             :         }
     424             :     }
     425             : 
     426     3879782 :     *pPercentile = maxElements[0];
     427     3879782 :     *pMin = minEle;
     428             : 
     429     3879782 :     return;
     430             : }
     431             : 
     432             : 
     433             : /* Calculates percentile by selecting greatest elements. */
     434   241032753 : 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   241032753 :     if ( *size < capacity )
     444             :     {
     445    13190495 :         for ( i = 0; i != *size; ++i )
     446             :         {
     447     7890084 :             if ( newElement <= elements[i] )
     448             :             {
     449             :                 /* insert newElement at index i */
     450     8987176 :                 for ( j = *size; j > i; --j )
     451             :                 {
     452     5459593 :                     elements[j] = elements[j - 1];
     453             :                 }
     454     3527583 :                 elements[i] = newElement;
     455     3527583 :                 ++*size;
     456     3527583 :                 return;
     457             :             }
     458             :         }
     459             :         /* newElement is maximum, just append it */
     460     5300411 :         elements[*size] = newElement;
     461     5300411 :         ++*size;
     462     5300411 :         return;
     463             :     }
     464             : 
     465             :     /* check if newElement is too small to be inserted in elements buffer */
     466   232204759 :     if ( newElement <= elements[0] )
     467             :     {
     468   209493048 :         return;
     469             :     }
     470             : 
     471             :     /* select position to insert newElement to elements */
     472    26751787 :     for ( i = *size - 1; i != 0; --i )
     473             :     {
     474    17469529 :         if ( newElement >= elements[i] )
     475             :         {
     476             :             /* insert newElement at index i */
     477    51451615 :             for ( j = 0; j < i; j++ )
     478             :             {
     479    38022162 :                 elements[j] = elements[1 + j];
     480             :             }
     481    13429453 :             elements[i] = newElement;
     482    13429453 :             return;
     483             :         }
     484             :     }
     485             :     /* newElement is just greater than first on in elements buffer */
     486     9282258 :     elements[0] = newElement;
     487             : 
     488     9282258 :     return;
     489             : }

Generated by: LCOV version 1.14