[FFmpeg-devel] [PATCH] wmapro decoder
Michael Niedermayer
michaelni
Sun Aug 30 23:26:39 CEST 2009
On Sat, Aug 29, 2009 at 11:51:54PM +0200, Sascha Sommer wrote:
> Hi,
>
> new patch attached...
[...]
> +/**
> + * @brief main decoder context
> + */
> +typedef struct WMA3DecodeContext {
> + /* generic decoder variables */
> + AVCodecContext* avctx; ///< codec context for av_log
> + DSPContext dsp; ///< accelerated DSP functions
> + uint8_t frame_data[MAX_FRAMESIZE +
> + FF_INPUT_BUFFER_PADDING_SIZE];///< compressed frame data
> + PutBitContext pb; ///< context for filling the frame_data buffer
> + MDCTContext mdct_ctx[WMAPRO_BLOCK_SIZES]; ///< MDCT context per block size
> + DECLARE_ALIGNED_16(float, tmp[WMAPRO_BLOCK_MAX_SIZE]); ///< IMDCT output buffer
> + float* windows[WMAPRO_BLOCK_SIZES]; ///< windows for the different block sizes
> +
> + /* frame size dependent frame information (set during initialization) */
> + uint32_t decode_flags; ///< used compression features
> + uint8_t len_prefix; ///< frame is prefixed with its length
> + uint8_t dynamic_range_compression; ///< frame contains DRC data
> + uint8_t bits_per_sample; ///< integer audio sample size for the unscaled IMDCT output (used to scale to [-1.0, 1.0])
> + uint16_t samples_per_frame; ///< number of samples to output
> + uint16_t log2_frame_size;
> + int8_t num_channels; ///< number of channels in the stream (same as AVCodecContext.num_channels)
> + int8_t lfe_channel; ///< lfe channel index
> + uint8_t max_num_subframes;
> + uint8_t subframe_len_bits; ///< number of bits used for the subframe length
> + uint8_t max_subframe_len_bit; ///< flag indicating that the subframe is of maximum size when the first subframe length bit is 1
> + uint16_t min_samples_per_subframe;
> + int8_t num_sfb[WMAPRO_BLOCK_SIZES]; ///< scale factor bands per block size
> + int16_t sfb_offsets[WMAPRO_BLOCK_SIZES][MAX_BANDS]; ///< scale factor band offsets (multiples of 4)
> + int8_t sf_offsets[WMAPRO_BLOCK_SIZES][WMAPRO_BLOCK_SIZES][MAX_BANDS]; ///< scale factor resample matrix
> + int16_t subwoofer_cutoffs[WMAPRO_BLOCK_SIZES]; ///< subwoofer cutoff values
> +
> + /* packet decode state */
> + uint8_t packet_sequence_number; ///< current packet number
> + int num_saved_bits; ///< saved number of bits
> + int frame_offset; ///< frame offset in the bit reservoir
> + int subframe_offset; ///< subframe offset in the bit reservoir
> + uint8_t packet_loss; ///< set in case of bitstream error
> +
> + /* frame decode state */
> + uint32_t frame_num; ///< current frame number
unused
[...]
> +/**
> + *@brief Decode the subframe length.
> + *@param s context
> + *@param offset sample offset in the frame
> + *@return decoded subframe length on success, 0 in case of an error
> + */
> +static int decode_subframe_length(WMA3DecodeContext *s, int offset)
> +{
> + int log2_subframe_len = 0;
> + int subframe_len;
> +
> + /** no need to read from the bitstream when only one length is possible */
> + if (offset == s->samples_per_frame - s->min_samples_per_subframe)
> + return s->min_samples_per_subframe;
> +
> + /** 1 bit indicates if the subframe is of maximum length */
> + if (s->max_subframe_len_bit) {
> + if (get_bits1(&s->gb))
> + log2_subframe_len = 1 + get_bits(&s->gb, s->subframe_len_bits-1);
> + } else
> + log2_subframe_len = get_bits(&s->gb, s->subframe_len_bits);
> +
> + subframe_len = s->samples_per_frame / (1 << log2_subframe_len);
subframe_len = s->samples_per_frame >> log2_subframe_len;
and i would guess the names are not good because one would expect
1<<log2_X = X
> +
> + /** sanity check the length */
> + if (subframe_len < s->min_samples_per_subframe
> + || subframe_len > s->samples_per_frame) {
> + av_log(s->avctx, AV_LOG_ERROR, "broken frame: subframe_len %i\n",
> + subframe_len);
> + return 0;
within ffmpeg errors are negative values
> + }
> + return subframe_len;
> +}
> +
> +/**
> + *@brief Decode how the data in the frame is split into subframes.
> + * Every WMA frame contains the encoded data for a fixed number of
> + * samples per channel. The data for every channel might be split
> + * into several subframes. This function will reconstruct the list of
> + * subframes for every channel.
> + *
> + * If the subframes are not evenly split, the algorithm estimates the
> + * channels with the lowest number of total samples.
> + * Afterwards, for each of these channels a bit is read from the
> + * bitstream that indicates if the channel contains a subframe with the
> + * next subframe size that is going to be read from the bitstream or not.
> + * If a channel contains such a subframe, the subframe size gets added to
> + * the channel's subframe list.
> + * The algorithm repeats these steps until the frame is properly divided
> + * between the individual channels.
> + *
> + *@param s context
> + *@return 0 on success, < 0 in case of an error
> + */
> +static int decode_tilehdr(WMA3DecodeContext *s)
> +{
> + uint16_t num_samples[WMAPRO_MAX_CHANNELS];
> + uint8_t contains_subframe[WMAPRO_MAX_CHANNELS];
> + int channels_for_cur_subframe = s->num_channels;
> + int fixed_channel_layout = 0;
> + int min_channel_len = 0;
these could benefit from some doxy
[...]
> @@ -241,6 +838,98 @@
> }
>
> /**
> + *@brief Extract scale factors from the bitstream.
> + *@param s codec context
> + *@return 0 on success, < 0 in case of bitstream errors
> + */
> +static int decode_scale_factors(WMA3DecodeContext* s)
> +{
> + int i;
> +
> + /** should never consume more than 5344 bits
> + * MAX_CHANNELS * (1 + MAX_BANDS * 23)
> + */
> +
> + for (i = 0; i < s->channels_for_cur_subframe; i++) {
> + int c = s->channel_indexes_for_cur_subframe[i];
> + int* sf;
> + int* sf_end = s->channel[c].scale_factors + s->num_bands;
> +
> + /** resample scale factors for the new block size */
> + if (s->channel[c].reuse_sf) {
> + const int8_t* sf_offsets = s->sf_offsets[s->table_idx][s->channel[c].table_idx];
> + int b;
> + for (b = 0; b < s->num_bands; b++)
> + s->channel[c].scale_factors[b] =
> + s->channel[c].saved_scale_factors[*sf_offsets++];
> + }
> +
> + if (!s->channel[c].cur_subframe || get_bits1(&s->gb)) {
> +
> + if (!s->channel[c].reuse_sf) {
> + int val;
> + /** decode DPCM coded scale factors */
> + s->channel[c].scale_factor_step = get_bits(&s->gb, 2) + 1;
> + val = 45 / s->channel[c].scale_factor_step;
> + for (sf = s->channel[c].scale_factors; sf < sf_end; sf++) {
> + val += get_vlc2(&s->gb, sf_vlc.table, SCALEVLCBITS, SCALEMAXDEPTH) - 60;
> + *sf = val;
> + }
> + } else {
> + int i;
> + /** run level decode differences to the resampled factors */
> + for (i = 0; i < s->num_bands; i++) {
> + int idx;
> + int skip;
> + int val;
> + int sign;
> +
> + idx = get_vlc2(&s->gb, sf_rl_vlc.table, VLCBITS, SCALERLMAXDEPTH);
> +
> + if ( !idx ) {
> + uint32_t code = get_bits(&s->gb, 14);
> + val = code >> 6;
> + sign = (code & 1) - 1;
> + skip = (code & 0x3f) >> 1;
> + } else if (idx == 1) {
> + break;
> + } else {
> + skip = scale_rl_run[idx];
> + val = scale_rl_level[idx];
> + sign = get_bits1(&s->gb)-1;
> + }
> +
> + i += skip;
> + if (i >= s->num_bands) {
> + av_log(s->avctx,AV_LOG_ERROR,
> + "invalid scale factor coding\n");
> + return AVERROR_INVALIDDATA;
> + }
> + s->channel[c].scale_factors[i] += (val ^ sign) - sign;
> + }
> + }
> +
> + /** save transmitted scale factors so that they can be reused for
> + the next subframe */
> + memcpy(s->channel[c].saved_scale_factors,
> + s->channel[c].scale_factors, s->num_bands *
> + sizeof(*s->channel[c].saved_scale_factors));
what happens with s->channel[c].scale_factors so that it cant just be used?
[...]
> +
> +/**
> + *@brief Decode a single subframe (block).
> + *@param s codec context
> + *@return 0 on success, < 0 when decoding failed
> + */
> +static int decode_subframe(WMA3DecodeContext *s)
> +{
> + int offset = s->samples_per_frame;
> + int subframe_len = s->samples_per_frame;
> + int i;
> + int total_samples = s->samples_per_frame * s->num_channels;
> + int transmit_coeffs = 0;
> + int cur_subwoofer_cutoff;
> +
> + s->subframe_offset = get_bits_count(&s->gb);
> +
> + /** reset channel context and find the next block offset and size
> + == the next block of the channel with the smallest number of
> + decoded samples
> + */
> + for (i = 0; i < s->num_channels; i++) {
> + s->channel[i].grouped = 0;
> + if (offset > s->channel[i].decoded_samples) {
> + offset = s->channel[i].decoded_samples;
> + subframe_len =
> + s->channel[i].subframe_len[s->channel[i].cur_subframe];
> + }
> + }
> +
> + dprintf(s->avctx,
> + "processing subframe with offset %i len %i\n", offset, subframe_len);
> +
> + /** get a list of all channels that contain the estimated block */
> + s->channels_for_cur_subframe = 0;
> + for (i = 0; i < s->num_channels; i++) {
> + const int cur_subframe = s->channel[i].cur_subframe;
> + /** substract already processed samples */
> + total_samples -= s->channel[i].decoded_samples;
> +
> + /** and count if there are multiple subframes that match our profile */
> + if (offset == s->channel[i].decoded_samples &&
> + subframe_len == s->channel[i].subframe_len[cur_subframe]) {
> + total_samples -= s->channel[i].subframe_len[cur_subframe];
> + s->channel[i].decoded_samples +=
> + s->channel[i].subframe_len[cur_subframe];
> + s->channel_indexes_for_cur_subframe[s->channels_for_cur_subframe] = i;
> + ++s->channels_for_cur_subframe;
> + }
> + }
> +
> + /** check if the frame will be complete after processing the
> + estimated block */
> + if (!total_samples)
> + s->parsed_all_subframes = 1;
> +
> +
> + dprintf(s->avctx, "subframe is part of %i channels\n",
> + s->channels_for_cur_subframe);
> +
> + /** calculate number of scale factor bands and their offsets */
> + s->table_idx = av_log2(s->samples_per_frame/subframe_len);
> + s->num_bands = s->num_sfb[s->table_idx];
> + s->cur_sfb_offsets = s->sfb_offsets[s->table_idx];
> + cur_subwoofer_cutoff = s->subwoofer_cutoffs[s->table_idx];
> +
> + /** configure the decoder for the current subframe */
> + for (i = 0; i < s->channels_for_cur_subframe; i++) {
> + int c = s->channel_indexes_for_cur_subframe[i];
> +
> + s->channel[c].coeffs = &s->channel[c].out[(s->samples_per_frame>>1)
> + + offset];
> + memset(s->channel[c].coeffs, 0,
> + sizeof(*s->channel[c].coeffs) * subframe_len);
IMHO it would be better to do this in a else clause of the if(transmit_coefs)
and before the rle decoding is started
[..]
> + /** interleave samples and write them to the output buffer */
> + for (i = 0; i < s->num_channels; i++) {
> + float* ptr;
> + int incr = s->num_channels;
> + float* iptr = s->channel[i].out;
> + int x;
> +
> + ptr = s->samples + i;
> +
> + for (x = 0; x < s->samples_per_frame; x++) {
> + *ptr = av_clipf(*iptr++, -1.0, 32767.0 / 32768.0);
> + ptr += incr;
> + }
> +
> + /** reuse second half of the IMDCT output for the next frame */
> + memcpy(&s->channel[i].out[0],
> + &s->channel[i].out[s->samples_per_frame],
> + s->samples_per_frame * sizeof(*s->channel[i].out) >> 1);
> + }
did you try to not do several passes over the output buffer?
(maybe its faster ...)
[...]
> +/**
> + *@brief WMA9 decoder
> + */
> +AVCodec wmapro_decoder = {
> + "wmapro",
> + CODEC_TYPE_AUDIO,
> + CODEC_ID_WMAPRO,
> + sizeof(WMA3DecodeContext),
WMA9 decoder, WMAPRO, WMA3DecodeContext
isnt that naming a little inconsistent?
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Old school: Use the lowest level language in which you can solve the problem
conveniently.
New school: Use the highest level language in which the latest supercomputer
can solve the problem without the user falling asleep waiting.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090830/b42f23a7/attachment.pgp>
More information about the ffmpeg-devel
mailing list