diff options
author | Umair Khan <omerjerk@gmail.com> | 2016-08-12 17:51:41 +0530 |
---|---|---|
committer | Thilo Borgmann <thilo.borgmann@mail.de> | 2016-08-22 15:28:19 +0200 |
commit | dcfd24b10c7eaec4b7b1ec2c4abb46808721a71d (patch) | |
tree | e44ecd5913c75c5fd972ee7938b7733bd00510a2 /libavcodec/alsdec.c | |
parent | eabdabb9822ed028cd8aeed94ded784b6364ba78 (diff) | |
download | ffmpeg-dcfd24b10c7eaec4b7b1ec2c4abb46808721a71d.tar.gz |
avcodec/alsdec: Implement floating point sample data decoding
It conforms to the RM22 version of the reference encoder
Signed-off-by: Umair Khan <omerjerk@gmail.com>
Diffstat (limited to 'libavcodec/alsdec.c')
-rw-r--r-- | libavcodec/alsdec.c | 284 |
1 files changed, 282 insertions, 2 deletions
diff --git a/libavcodec/alsdec.c b/libavcodec/alsdec.c index a7e58a242f..16956e2d22 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"); |