diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c index 3e68ef2dcc..16632b8d09 100644 --- a/libavcodec/dnxhdenc.c +++ b/libavcodec/dnxhdenc.c @@ -651,9 +651,60 @@ static int dnxhd_find_qscale(DNXHDEncContext *ctx) return 0; } -static int dnxhd_rc_cmp(const void *a, const void *b) +#define BUCKET_BITS 8 +#define RADIX_PASSES 4 +#define NBUCKETS (1 << BUCKET_BITS) + +static inline int get_bucket(int value, int shift) +{ + value >>= shift; + value &= NBUCKETS - 1; + return NBUCKETS - 1 - value; +} + +static void radix_count(const RCCMPEntry *data, int size, int buckets[RADIX_PASSES][NBUCKETS]) +{ + int i, j; + memset(buckets, 0, sizeof(buckets[0][0]) * RADIX_PASSES * NBUCKETS); + for (i = 0; i < size; i++) { + int v = data[i].value; + for (j = 0; j < RADIX_PASSES; j++) { + buckets[j][get_bucket(v, 0)]++; + v >>= BUCKET_BITS; + } + assert(!v); + } + for (j = 0; j < RADIX_PASSES; j++) { + int offset = size; + for (i = NBUCKETS - 1; i >= 0; i--) + buckets[j][i] = offset -= buckets[j][i]; + assert(!buckets[j][0]); + } +} + +static void radix_sort_pass(RCCMPEntry *dst, const RCCMPEntry *data, int size, int buckets[NBUCKETS], int pass) +{ + int shift = pass * BUCKET_BITS; + int i; + for (i = 0; i < size; i++) { + int v = get_bucket(data[i].value, shift); + int pos = buckets[v]++; + dst[pos] = data[i]; + } +} + +static void radix_sort(RCCMPEntry *data, int size) { - return ((const RCCMPEntry *)b)->value - ((const RCCMPEntry *)a)->value; + int buckets[RADIX_PASSES][NBUCKETS]; + RCCMPEntry *tmp = av_malloc(sizeof(*tmp) * size); + radix_count(data, size, buckets); + radix_sort_pass(tmp, data, size, buckets[0], 0); + radix_sort_pass(data, tmp, size, buckets[1], 1); + if (buckets[2][NBUCKETS - 1] || buckets[3][NBUCKETS - 1]) { + radix_sort_pass(tmp, data, size, buckets[2], 2); + radix_sort_pass(data, tmp, size, buckets[3], 3); + } + av_free(tmp); } static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx) @@ -682,7 +733,7 @@ static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx) if (!ret) { if (RC_VARIANCE) avctx->execute(avctx, dnxhd_mb_var_thread, (void**)&ctx->thread[0], NULL, avctx->thread_count, sizeof(void*)); - qsort(ctx->mb_cmp, ctx->m.mb_num, sizeof(RCEntry), dnxhd_rc_cmp); + radix_sort(ctx->mb_cmp, ctx->m.mb_num); for (x = 0; x < ctx->m.mb_num && max_bits > ctx->frame_bits; x++) { int mb = ctx->mb_cmp[x].mb; max_bits -= ctx->mb_rc[ctx->qscale][mb].bits - ctx->mb_rc[ctx->qscale+1][mb].bits;