[FFmpeg-cvslog] avcodec/alsdec: Implement floating point sample data decoding
Umair Khan
git at videolan.org
Mon Aug 22 16:30:29 EEST 2016
ffmpeg | branch: master | Umair Khan <omerjerk at gmail.com> | Fri Aug 12 18:09:41 2016 +0530| [dcfd24b10c7eaec4b7b1ec2c4abb46808721a71d] | committer: Thilo Borgmann
avcodec/alsdec: Implement floating point sample data decoding
It conforms to the RM22 version of the reference encoder
Signed-off-by: Umair Khan <omerjerk at gmail.com>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=dcfd24b10c7eaec4b7b1ec2c4abb46808721a71d
---
Changelog | 1 +
libavcodec/Makefile | 2 +-
libavcodec/alsdec.c | 284 +++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 284 insertions(+), 3 deletions(-)
diff --git a/Changelog b/Changelog
index 7e88e64..71abe8c 100644
--- a/Changelog
+++ b/Changelog
@@ -16,6 +16,7 @@ version <next>:
- crystalizer audio filter
- acrusher audio filter
- bitplanenoise video filter
+- floating point support in als decoder
version 3.1:
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 16c9fcf..a6e79ce 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -163,7 +163,7 @@ OBJS-$(CONFIG_ALAC_DECODER) += alac.o alac_data.o alacdsp.o
OBJS-$(CONFIG_ALAC_ENCODER) += alacenc.o alac_data.o
OBJS-$(CONFIG_ALIAS_PIX_DECODER) += aliaspixdec.o
OBJS-$(CONFIG_ALIAS_PIX_ENCODER) += aliaspixenc.o
-OBJS-$(CONFIG_ALS_DECODER) += alsdec.o bgmc.o mpeg4audio.o
+OBJS-$(CONFIG_ALS_DECODER) += alsdec.o bgmc.o mlz.o mpeg4audio.o
OBJS-$(CONFIG_AMRNB_DECODER) += amrnbdec.o celp_filters.o \
celp_math.o acelp_filters.o \
acelp_vectors.o \
diff --git a/libavcodec/alsdec.c b/libavcodec/alsdec.c
index a7e58a2..16956e2 100644
--- a/libavcodec/alsdec.c
+++ b/libavcodec/alsdec.c
@@ -35,8 +35,12 @@
#include "bgmc.h"
#include "bswapdsp.h"
#include "internal.h"
+#include "mlz.h"
#include "libavutil/samplefmt.h"
#include "libavutil/crc.h"
+#include "libavutil/softfloat_ieee754.h"
+#include "libavutil/intfloat.h"
+#include "libavutil/intreadwrite.h"
#include <stdint.h>
@@ -225,6 +229,14 @@ typedef struct ALSDecContext {
int32_t **raw_samples; ///< decoded raw samples for each channel
int32_t *raw_buffer; ///< contains all decoded raw samples including carryover samples
uint8_t *crc_buffer; ///< buffer of byte order corrected samples used for CRC check
+ MLZ* mlz; ///< masked lz decompression structure
+ SoftFloat_IEEE754 *acf; ///< contains common multiplier for all channels
+ int *last_acf_mantissa; ///< contains the last acf mantissa data of common multiplier for all channels
+ int *shift_value; ///< value by which the binary point is to be shifted for all channels
+ int *last_shift_value; ///< contains last shift value for all channels
+ int **raw_mantissa; ///< decoded mantissa bits of the difference signal
+ unsigned char *larray; ///< buffer to store the output of masked lz decompression
+ int *nbits; ///< contains the number of bits to read for masked lz decompression for all samples
} ALSDecContext;
@@ -441,7 +453,6 @@ static int check_specific_config(ALSDecContext *ctx)
} \
}
- MISSING_ERR(sconf->floating, "Floating point decoding", AVERROR_PATCHWELCOME);
MISSING_ERR(sconf->rlslms, "Adaptive RLS-LMS prediction", AVERROR_PATCHWELCOME);
return error;
@@ -1356,6 +1367,238 @@ static int revert_channel_correlation(ALSDecContext *ctx, ALSBlockData *bd,
}
+/** multiply two softfloats and handle the rounding off
+ */
+static SoftFloat_IEEE754 multiply(SoftFloat_IEEE754 a, SoftFloat_IEEE754 b) {
+ uint64_t mantissa_temp;
+ uint64_t mask_64;
+ int cutoff_bit_count;
+ unsigned char last_2_bits;
+ unsigned int mantissa;
+ int32_t sign;
+ uint32_t return_val = 0;
+ int bit_count = 48;
+
+ sign = a.sign ^ b.sign;
+
+ // Multiply mantissa bits in a 64-bit register
+ mantissa_temp = (uint64_t)a.mant * (uint64_t)b.mant;
+ mask_64 = (uint64_t)0x1 << 47;
+
+ // Count the valid bit count
+ while (!(mantissa_temp & mask_64) && mask_64) {
+ bit_count--;
+ mask_64 >>= 1;
+ }
+
+ // Round off
+ cutoff_bit_count = bit_count - 24;
+ if (cutoff_bit_count > 0) {
+ last_2_bits = (unsigned char)(((unsigned int)mantissa_temp >> (cutoff_bit_count - 1)) & 0x3 );
+ if ((last_2_bits == 0x3) || ((last_2_bits == 0x1) && ((unsigned int)mantissa_temp & ((0x1UL << (cutoff_bit_count - 1)) - 1)))) {
+ // Need to round up
+ mantissa_temp += (uint64_t)0x1 << cutoff_bit_count;
+ }
+ }
+
+ mantissa = (unsigned int)(mantissa_temp >> cutoff_bit_count);
+
+ // Need one more shift?
+ if (mantissa & 0x01000000ul) {
+ bit_count++;
+ mantissa >>= 1;
+ }
+
+ if (!sign) {
+ return_val = 0x80000000U;
+ }
+
+ return_val |= (a.exp + b.exp + bit_count - 47) << 23;
+ return_val |= mantissa;
+ return av_bits2sf_ieee754(return_val);
+}
+
+
+/** Read and decode the floating point sample data
+ */
+static int read_diff_float_data(ALSDecContext *ctx, unsigned int ra_frame) {
+ AVCodecContext *avctx = ctx->avctx;
+ GetBitContext *gb = &ctx->gb;
+ SoftFloat_IEEE754 *acf = ctx->acf;
+ int *shift_value = ctx->shift_value;
+ int *last_shift_value = ctx->last_shift_value;
+ int *last_acf_mantissa = ctx->last_acf_mantissa;
+ int **raw_mantissa = ctx->raw_mantissa;
+ int *nbits = ctx->nbits;
+ unsigned char *larray = ctx->larray;
+ int frame_length = ctx->cur_frame_length;
+ SoftFloat_IEEE754 scale = av_int2sf_ieee754(0x1u, 23);
+ unsigned int partA_flag;
+ unsigned int highest_byte;
+ unsigned int shift_amp;
+ uint32_t tmp_32;
+ int use_acf;
+ int nchars;
+ int i;
+ int c;
+ long k;
+ long nbits_aligned;
+ unsigned long acc;
+ unsigned long j;
+ uint32_t sign;
+ uint32_t e;
+ uint32_t mantissa;
+
+ skip_bits_long(gb, 32); //num_bytes_diff_float
+ use_acf = get_bits1(gb);
+
+ if (ra_frame) {
+ memset(last_acf_mantissa, 0, avctx->channels * sizeof(*last_acf_mantissa));
+ memset(last_shift_value, 0, avctx->channels * sizeof(*last_shift_value) );
+ ff_mlz_flush_dict(ctx->mlz);
+ }
+
+ for (c = 0; c < avctx->channels; ++c) {
+ if (use_acf) {
+ //acf_flag
+ if (get_bits1(gb)) {
+ tmp_32 = get_bits(gb, 23);
+ last_acf_mantissa[c] = tmp_32;
+ } else {
+ tmp_32 = last_acf_mantissa[c];
+ }
+ acf[c] = av_bits2sf_ieee754(tmp_32);
+ } else {
+ acf[c] = FLOAT_1;
+ }
+
+ highest_byte = get_bits(gb, 2);
+ partA_flag = get_bits1(gb);
+ shift_amp = get_bits1(gb);
+
+ if (shift_amp) {
+ shift_value[c] = get_bits(gb, 8);
+ last_shift_value[c] = shift_value[c];
+ } else {
+ shift_value[c] = last_shift_value[c];
+ }
+
+ if (partA_flag) {
+ if (!get_bits1(gb)) { //uncompressed
+ for (i = 0; i < frame_length; ++i) {
+ if (ctx->raw_samples[c][i] == 0) {
+ ctx->raw_mantissa[c][i] = get_bits_long(gb, 32);
+ }
+ }
+ } else { //compressed
+ nchars = 0;
+ for (i = 0; i < frame_length; ++i) {
+ if (ctx->raw_samples[c][i] == 0) {
+ nchars += 4;
+ }
+ }
+
+ tmp_32 = ff_mlz_decompression(ctx->mlz, gb, nchars, larray);
+ if(tmp_32 != nchars) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "Error in MLZ decompression (%d, %d).\n", tmp_32, nchars);
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (i = 0; i < frame_length; ++i) {
+ ctx->raw_mantissa[c][i] = AV_RB32(larray);
+ }
+ }
+ }
+
+ //decode part B
+ if (highest_byte) {
+ for (i = 0; i < frame_length; ++i) {
+ if (ctx->raw_samples[c][i] != 0) {
+ //The following logic is taken from Tabel 14.45 and 14.46 from the ISO spec
+ if (av_cmp_sf_ieee754(acf[c], FLOAT_1)) {
+ nbits[i] = 23 - av_log2(abs(ctx->raw_samples[c][i]));
+ } else {
+ nbits[i] = 23;
+ }
+ nbits[i] = FFMIN(nbits[i], highest_byte*8);
+ }
+ }
+
+ if (!get_bits1(gb)) { //uncompressed
+ for (i = 0; i < frame_length; ++i) {
+ if (ctx->raw_samples[c][i] != 0) {
+ raw_mantissa[c][i] = get_bits(gb, nbits[i]);
+ }
+ }
+ } else { //compressed
+ nchars = 0;
+ for (i = 0; i < frame_length; ++i) {
+ if (ctx->raw_samples[c][i]) {
+ nchars += (int) nbits[i] / 8;
+ if (nbits[i] & 7) {
+ ++nchars;
+ }
+ }
+ }
+
+ tmp_32 = ff_mlz_decompression(ctx->mlz, gb, nchars, larray);
+ if(tmp_32 != nchars) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "Error in MLZ decompression (%d, %d).\n", tmp_32, nchars);
+ return AVERROR_INVALIDDATA;
+ }
+
+ j = 0;
+ for (i = 0; i < frame_length; ++i) {
+ if (ctx->raw_samples[c][i]) {
+ if (nbits[i] & 7) {
+ nbits_aligned = 8 * ((unsigned int)(nbits[i] / 8) + 1);
+ } else {
+ nbits_aligned = nbits[i];
+ }
+ acc = 0;
+ for (k = 0; k < nbits_aligned/8; ++k) {
+ acc = (acc << 8) + larray[j++];
+ }
+ acc >>= (nbits_aligned - nbits[i]);
+ raw_mantissa[c][i] = acc;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < frame_length; ++i) {
+ SoftFloat_IEEE754 pcm_sf = av_int2sf_ieee754(ctx->raw_samples[c][i], 0);
+ pcm_sf = av_div_sf_ieee754(pcm_sf, scale);
+
+ if (ctx->raw_samples[c][i] != 0) {
+ if (!av_cmp_sf_ieee754(acf[c], FLOAT_1)) {
+ pcm_sf = multiply(acf[c], pcm_sf);
+ }
+
+ sign = pcm_sf.sign;
+ e = pcm_sf.exp;
+ mantissa = (pcm_sf.mant | 0x800000) + raw_mantissa[c][i];
+
+ while(mantissa >= 0x1000000) {
+ e++;
+ mantissa >>= 1;
+ }
+
+ if (mantissa) e += (shift_value[c] - 127);
+ mantissa &= 0x007fffffUL;
+
+ tmp_32 = (sign << 31) | ((e + EXP_BIAS) << 23) | (mantissa);
+ ctx->raw_samples[c][i] = tmp_32;
+ } else {
+ ctx->raw_samples[c][i] = raw_mantissa[c][i] & 0x007fffffUL;
+ }
+ }
+ align_get_bits(gb);
+ }
+ return 0;
+}
+
+
/** Read the frame data.
*/
static int read_frame_data(ALSDecContext *ctx, unsigned int ra_frame)
@@ -1497,7 +1740,9 @@ static int read_frame_data(ALSDecContext *ctx, unsigned int ra_frame)
sizeof(*ctx->raw_samples[c]) * sconf->max_order);
}
- // TODO: read_diff_float_data
+ if (sconf->floating) {
+ read_diff_float_data(ctx, ra_frame);
+ }
if (get_bits_left(gb) < 0) {
av_log(ctx->avctx, AV_LOG_ERROR, "Overread %d\n", -get_bits_left(gb));
@@ -1667,6 +1912,14 @@ static av_cold int decode_end(AVCodecContext *avctx)
av_freep(&ctx->chan_data_buffer);
av_freep(&ctx->reverted_channels);
av_freep(&ctx->crc_buffer);
+ av_freep(&ctx->mlz);
+ av_freep(&ctx->acf);
+ av_freep(&ctx->last_acf_mantissa);
+ av_freep(&ctx->shift_value);
+ av_freep(&ctx->last_shift_value);
+ av_freep(&ctx->raw_mantissa);
+ av_freep(&ctx->larray);
+ av_freep(&ctx->nbits);
return 0;
}
@@ -1678,6 +1931,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
{
unsigned int c;
unsigned int channel_size;
+ unsigned int i;
int num_buffers, ret;
ALSDecContext *ctx = avctx->priv_data;
ALSSpecificConfig *sconf = &ctx->sconf;
@@ -1803,6 +2057,32 @@ static av_cold int decode_init(AVCodecContext *avctx)
ctx->raw_buffer = av_mallocz_array(avctx->channels * channel_size, sizeof(*ctx->raw_buffer));
ctx->raw_samples = av_malloc_array(avctx->channels, sizeof(*ctx->raw_samples));
+ if (sconf->floating) {
+ ctx->acf = av_malloc_array(avctx->channels, sizeof(*ctx->acf));
+ ctx->shift_value = av_malloc_array(avctx->channels, sizeof(*ctx->shift_value));
+ ctx->last_shift_value = av_malloc_array(avctx->channels, sizeof(*ctx->last_shift_value));
+ ctx->last_acf_mantissa = av_malloc_array(avctx->channels, sizeof(*ctx->last_acf_mantissa));
+ ctx->raw_mantissa = av_malloc_array(avctx->channels, sizeof(*ctx->raw_mantissa));
+
+ ctx->larray = av_malloc_array(ctx->cur_frame_length * 4, sizeof(*ctx->larray));
+ ctx->nbits = av_malloc_array(ctx->cur_frame_length, sizeof(*ctx->nbits));
+ ctx->mlz = av_malloc(sizeof(*ctx->mlz));
+
+ if (!ctx->mlz || !ctx->acf || !ctx->shift_value || !ctx->last_shift_value
+ || !ctx->last_acf_mantissa || !ctx->raw_mantissa) {
+ av_log(avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n");
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ ff_mlz_init_dict(avctx, ctx->mlz);
+ ff_mlz_flush_dict(ctx->mlz);
+
+ for (c = 0; c < avctx->channels; ++c) {
+ ctx->raw_mantissa[c] = av_mallocz_array(ctx->cur_frame_length, sizeof(**ctx->raw_mantissa));
+ }
+ }
+
// allocate previous raw sample buffer
if (!ctx->prev_raw_samples || !ctx->raw_buffer|| !ctx->raw_samples) {
av_log(avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n");
More information about the ffmpeg-cvslog
mailing list