mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
audioconvert: optimize mask calculation
find_suitable_mask() had complexity O(n^2) on the number of bits. For common case like 2-channel audio the mask was calculated in about 4k loop cycles. Optimize both n_bits_set() and find_suitable_mask() to O(n) where n is the number of bits set in the mask. https://bugzilla.gnome.org/show_bug.cgi?id=772864
This commit is contained in:
parent
1820c18b0f
commit
ca7e31f80d
1 changed files with 21 additions and 21 deletions
|
@ -302,41 +302,41 @@ gst_audio_convert_transform_caps (GstBaseTransform * btrans,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Count the number of bits set
|
||||||
|
* Optimized for the common case, assuming that the number of channels
|
||||||
|
* (i.e. bits set) is small
|
||||||
|
*/
|
||||||
static gint
|
static gint
|
||||||
n_bits_set (guint64 x)
|
n_bits_set (guint64 x)
|
||||||
{
|
{
|
||||||
gint i;
|
gint c;
|
||||||
gint c = 0;
|
|
||||||
guint64 y = 1;
|
|
||||||
|
|
||||||
for (i = 0; i < 64; i++) {
|
for (c = 0; x; c++)
|
||||||
if (x & y)
|
x &= x - 1;
|
||||||
c++;
|
|
||||||
y <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reduce the mask to the n_chans lowest set bits
|
||||||
|
*
|
||||||
|
* The algorithm clears the n_chans lowest set bits and subtracts the
|
||||||
|
* result from the original mask to get the desired mask.
|
||||||
|
* It is optimized for the common case where n_chans is a small
|
||||||
|
* number. In the worst case, however, it stops after 64 iterations.
|
||||||
|
*/
|
||||||
static guint64
|
static guint64
|
||||||
find_suitable_mask (guint64 mask, gint n_chans)
|
find_suitable_mask (guint64 mask, gint n_chans)
|
||||||
{
|
{
|
||||||
guint64 intersection;
|
guint64 x = mask;
|
||||||
gint i;
|
|
||||||
|
|
||||||
i = 0;
|
for (; x && n_chans; n_chans--)
|
||||||
|
x &= x - 1;
|
||||||
|
|
||||||
g_assert (n_bits_set (mask) >= n_chans);
|
g_assert (x || n_chans == 0);
|
||||||
|
/* assertion fails if mask contained less bits than n_chans
|
||||||
|
* or n_chans was < 0 */
|
||||||
|
|
||||||
intersection = mask;
|
return mask - x;
|
||||||
do {
|
|
||||||
intersection = intersection & ((~G_GUINT64_CONSTANT (0)) >> i);
|
|
||||||
i++;
|
|
||||||
} while (n_bits_set (intersection) > n_chans && i < 64);
|
|
||||||
|
|
||||||
if (i < 64)
|
|
||||||
return intersection;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in a new issue