⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qdm2.c

📁 ffmpeg的完整源代码和作者自己写的文档。不但有在Linux的工程哦
💻 C
📖 第 1 页 / 共 5 页
字号:
        }
    } // Loop on B packets

    /* calculate maximum indices for FFT coefficients */
    for (i = 0, j = -1; i < 5; i++)
        if (q->fft_coefs_min_index[i] >= 0) {
            if (j >= 0)
                q->fft_coefs_max_index[j] = q->fft_coefs_min_index[i];
            j = i;
        }
    if (j >= 0)
        q->fft_coefs_max_index[j] = q->fft_coefs_index;
}


static void qdm2_fft_generate_tone (QDM2Context *q, FFTTone *tone)
{
   float level, f[6];
   int i;
   QDM2Complex c;
   const double iscale = 2.0*M_PI / 512.0;

    tone->phase += tone->phase_shift;

    /* calculate current level (maximum amplitude) of tone */
    level = fft_tone_envelope_table[tone->duration][tone->time_index] * tone->level;
    c.im = level * sin(tone->phase*iscale);
    c.re = level * cos(tone->phase*iscale);

    /* generate FFT coefficients for tone */
    if (tone->duration >= 3 || tone->cutoff >= 3) {
        tone->samples_im[0] += c.im;
        tone->samples_re[0] += c.re;
        tone->samples_im[1] -= c.im;
        tone->samples_re[1] -= c.re;
    } else {
        f[1] = -tone->table[4];
        f[0] =  tone->table[3] - tone->table[0];
        f[2] =  1.0 - tone->table[2] - tone->table[3];
        f[3] =  tone->table[1] + tone->table[4] - 1.0;
        f[4] =  tone->table[0] - tone->table[1];
        f[5] =  tone->table[2];
        for (i = 0; i < 2; i++) {
            tone->samples_re[fft_cutoff_index_table[tone->cutoff][i]] += c.re * f[i];
            tone->samples_im[fft_cutoff_index_table[tone->cutoff][i]] += c.im *((tone->cutoff <= i) ? -f[i] : f[i]);
        }
        for (i = 0; i < 4; i++) {
            tone->samples_re[i] += c.re * f[i+2];
            tone->samples_im[i] += c.im * f[i+2];
        }
    }

    /* copy the tone if it has not yet died out */
    if (++tone->time_index < ((1 << (5 - tone->duration)) - 1)) {
      memcpy(&q->fft_tones[q->fft_tone_end], tone, sizeof(FFTTone));
      q->fft_tone_end = (q->fft_tone_end + 1) % 1000;
    }
}


static void qdm2_fft_tone_synthesizer (QDM2Context *q, int sub_packet)
{
    int i, j, ch;
    const double iscale = 0.25 * M_PI;

    for (ch = 0; ch < q->channels; ch++) {
        memset(q->fft.samples_im[ch], 0, q->fft_size * sizeof(float));
        memset(q->fft.samples_re[ch], 0, q->fft_size * sizeof(float));
    }


    /* apply FFT tones with duration 4 (1 FFT period) */
    if (q->fft_coefs_min_index[4] >= 0)
        for (i = q->fft_coefs_min_index[4]; i < q->fft_coefs_max_index[4]; i++) {
            float level;
            QDM2Complex c;

            if (q->fft_coefs[i].sub_packet != sub_packet)
                break;

            ch = (q->channels == 1) ? 0 : q->fft_coefs[i].channel;
            level = (q->fft_coefs[i].exp < 0) ? 0.0 : fft_tone_level_table[q->superblocktype_2_3 ? 0 : 1][q->fft_coefs[i].exp & 63];

            c.re = level * cos(q->fft_coefs[i].phase * iscale);
            c.im = level * sin(q->fft_coefs[i].phase * iscale);
            q->fft.samples_re[ch][q->fft_coefs[i].offset + 0] += c.re;
            q->fft.samples_im[ch][q->fft_coefs[i].offset + 0] += c.im;
            q->fft.samples_re[ch][q->fft_coefs[i].offset + 1] -= c.re;
            q->fft.samples_im[ch][q->fft_coefs[i].offset + 1] -= c.im;
        }

    /* generate existing FFT tones */
    for (i = q->fft_tone_end; i != q->fft_tone_start; ) {
        qdm2_fft_generate_tone(q, &q->fft_tones[q->fft_tone_start]);
        q->fft_tone_start = (q->fft_tone_start + 1) % 1000;
    }

    /* create and generate new FFT tones with duration 0 (long) to 3 (short) */
    for (i = 0; i < 4; i++)
        if (q->fft_coefs_min_index[i] >= 0) {
            for (j = q->fft_coefs_min_index[i]; j < q->fft_coefs_max_index[i]; j++) {
                int offset, four_i;
                FFTTone tone;

                if (q->fft_coefs[j].sub_packet != sub_packet)
                    break;

                four_i = (4 - i);
                offset = q->fft_coefs[j].offset >> four_i;
                ch = (q->channels == 1) ? 0 : q->fft_coefs[j].channel;

                if (offset < q->frequency_range) {
                    if (offset < 2)
                        tone.cutoff = offset;
                    else
                        tone.cutoff = (offset >= 60) ? 3 : 2;

                    tone.level = (q->fft_coefs[j].exp < 0) ? 0.0 : fft_tone_level_table[q->superblocktype_2_3 ? 0 : 1][q->fft_coefs[j].exp & 63];
                    tone.samples_im = &q->fft.samples_im[ch][offset];
                    tone.samples_re = &q->fft.samples_re[ch][offset];
                    tone.table = (float*)fft_tone_sample_table[i][q->fft_coefs[j].offset - (offset << four_i)];
                    tone.phase = 64 * q->fft_coefs[j].phase - (offset << 8) - 128;
                    tone.phase_shift = (2 * q->fft_coefs[j].offset + 1) << (7 - four_i);
                    tone.duration = i;
                    tone.time_index = 0;

                    qdm2_fft_generate_tone(q, &tone);
                }
            }
            q->fft_coefs_min_index[i] = j;
        }
}


static void qdm2_calculate_fft (QDM2Context *q, int channel, int sub_packet)
{
    const int n = 1 << (q->fft_order - 1);
    const int n2 = n >> 1;
    const float gain = (q->channels == 1 && q->nb_channels == 2) ? 0.25f : 0.50f;
    float c, s, f0, f1, f2, f3;
    int i, j;

    /* prerotation (or something like that) */
    for (i=1; i < n2; i++) {
        j  = (n - i);
        c = q->exptab[i].re;
        s = -q->exptab[i].im;
        f0 = (q->fft.samples_re[channel][i] - q->fft.samples_re[channel][j]) * gain;
        f1 = (q->fft.samples_im[channel][i] + q->fft.samples_im[channel][j]) * gain;
        f2 = (q->fft.samples_re[channel][i] + q->fft.samples_re[channel][j]) * gain;
        f3 = (q->fft.samples_im[channel][i] - q->fft.samples_im[channel][j]) * gain;
        q->fft.complex[i].re =  s * f0 - c * f1 + f2;
        q->fft.complex[i].im =  c * f0 + s * f1 + f3;
        q->fft.complex[j].re = -s * f0 + c * f1 + f2;
        q->fft.complex[j].im =  c * f0 + s * f1 - f3;
    }

    q->fft.complex[ 0].re =  q->fft.samples_re[channel][ 0] * gain * 2.0;
    q->fft.complex[ 0].im =  q->fft.samples_re[channel][ 0] * gain * 2.0;
    q->fft.complex[n2].re =  q->fft.samples_re[channel][n2] * gain * 2.0;
    q->fft.complex[n2].im = -q->fft.samples_im[channel][n2] * gain * 2.0;

    ff_fft_permute(&q->fft_ctx, (FFTComplex *) q->fft.complex);
    ff_fft_calc (&q->fft_ctx, (FFTComplex *) q->fft.complex);
    /* add samples to output buffer */
    for (i = 0; i < ((q->fft_frame_size + 15) & ~15); i++)
        q->output_buffer[q->channels * i + channel] += ((float *) q->fft.complex)[i];
}


/**
 * @param q        context
 * @param index    subpacket number
 */
static void qdm2_synthesis_filter (QDM2Context *q, int index)
{
    OUT_INT samples[MPA_MAX_CHANNELS * MPA_FRAME_SIZE];
    int i, k, ch, sb_used, sub_sampling, dither_state = 0;

    /* copy sb_samples */
    sb_used = QDM2_SB_USED(q->sub_sampling);

    for (ch = 0; ch < q->channels; ch++)
        for (i = 0; i < 8; i++)
            for (k=sb_used; k < SBLIMIT; k++)
                q->sb_samples[ch][(8 * index) + i][k] = 0;

    for (ch = 0; ch < q->nb_channels; ch++) {
        OUT_INT *samples_ptr = samples + ch;

        for (i = 0; i < 8; i++) {
            ff_mpa_synth_filter(q->synth_buf[ch], &(q->synth_buf_offset[ch]),
                mpa_window, &dither_state,
                samples_ptr, q->nb_channels,
                q->sb_samples[ch][(8 * index) + i]);
            samples_ptr += 32 * q->nb_channels;
        }
    }

    /* add samples to output buffer */
    sub_sampling = (4 >> q->sub_sampling);

    for (ch = 0; ch < q->channels; ch++)
        for (i = 0; i < q->frame_size; i++)
            q->output_buffer[q->channels * i + ch] += (float)(samples[q->nb_channels * sub_sampling * i + ch] >> (sizeof(OUT_INT)*8-16));
}


/**
 * Init static data (does not depend on specific file)
 *
 * @param q    context
 */
static void qdm2_init(QDM2Context *q) {
    static int inited = 0;

    if (inited != 0)
        return;
    inited = 1;

    qdm2_init_vlc();
    ff_mpa_synth_init(mpa_window);
    softclip_table_init();
    rnd_table_init();
    init_noise_samples();

    av_log(NULL, AV_LOG_DEBUG, "init done\n");
}


#if 0
static void dump_context(QDM2Context *q)
{
    int i;
#define PRINT(a,b) av_log(NULL,AV_LOG_DEBUG," %s = %d\n", a, b);
    PRINT("compressed_data",q->compressed_data);
    PRINT("compressed_size",q->compressed_size);
    PRINT("frame_size",q->frame_size);
    PRINT("checksum_size",q->checksum_size);
    PRINT("channels",q->channels);
    PRINT("nb_channels",q->nb_channels);
    PRINT("fft_frame_size",q->fft_frame_size);
    PRINT("fft_size",q->fft_size);
    PRINT("sub_sampling",q->sub_sampling);
    PRINT("fft_order",q->fft_order);
    PRINT("group_order",q->group_order);
    PRINT("group_size",q->group_size);
    PRINT("sub_packet",q->sub_packet);
    PRINT("frequency_range",q->frequency_range);
    PRINT("has_errors",q->has_errors);
    PRINT("fft_tone_end",q->fft_tone_end);
    PRINT("fft_tone_start",q->fft_tone_start);
    PRINT("fft_coefs_index",q->fft_coefs_index);
    PRINT("coeff_per_sb_select",q->coeff_per_sb_select);
    PRINT("cm_table_select",q->cm_table_select);
    PRINT("noise_idx",q->noise_idx);

    for (i = q->fft_tone_start; i < q->fft_tone_end; i++)
    {
    FFTTone *t = &q->fft_tones[i];

    av_log(NULL,AV_LOG_DEBUG,"Tone (%d) dump:\n", i);
    av_log(NULL,AV_LOG_DEBUG,"  level = %f\n", t->level);
//  PRINT(" level", t->level);
    PRINT(" phase", t->phase);
    PRINT(" phase_shift", t->phase_shift);
    PRINT(" duration", t->duration);
    PRINT(" samples_im", t->samples_im);
    PRINT(" samples_re", t->samples_re);
    PRINT(" table", t->table);
    }

}
#endif


/**
 * Init parameters from codec extradata
 */
static int qdm2_decode_init(AVCodecContext *avctx)
{
    QDM2Context *s = avctx->priv_data;
    uint8_t *extradata;
    int extradata_size;
    int tmp_val, tmp, size;
    int i;
    float alpha;

    /* extradata parsing

    Structure:
    wave {
        frma (QDM2)
        QDCA
        QDCP
    }

    32  size (including this field)
    32  tag (=frma)
    32  type (=QDM2 or QDMC)

    32  size (including this field, in bytes)
    32  tag (=QDCA) // maybe mandatory parameters
    32  unknown (=1)
    32  channels (=2)
    32  samplerate (=44100)
    32  bitrate (=96000)
    32  block size (=4096)
    32  frame size (=256) (for one channel)
    32  packet size (=1300)

    32  size (including this field, in bytes)
    32  tag (=QDCP) // maybe some tuneable parameters
    32  float1 (=1.0)
    32  zero ?
    32  float2 (=1.0)
    32  float3 (=1.0)
    32  unknown (27)
    32  unknown (8)
    32  zero ?
    */

    if (!avctx->extradata || (avctx->extradata_size < 48)) {
        av_log(avctx, AV_LOG_ERROR, "extradata missing or truncated\n");
        return -1;
    }

    extradata = avctx->extradata;
    extradata_size = avctx->extradata_size;

    while (extradata_size > 7) {
        if (!memcmp(extradata, "frmaQDM", 7))
            break;
        extradata++;
        extradata_size--;
    }

    if (extradata_size < 12) {
        av_log(avctx, AV_LOG_ERROR, "not enough extradata (%i)\n",
               extradata_size);
        return -1;
    }

    if (memcmp(extradata, "frmaQDM", 7)) {
        av_log(avctx, AV_LOG_ERROR, "invalid headers, QDM? not found\n");
        return -1;
    }

    if (extradata[7] == 'C') {
//        s->is_qdmc = 1;
        av_log(avctx, AV_LOG_ERROR, "stream is QDMC version 1, which is not supported\n");
        return -1;
    }

    extradata += 8;
    extradata_size -= 8;

    size = AV_RB32(extradata);

    if(size > extradata_size){
        av_log(avctx, AV_LOG_ERROR, "extradata size too small, %i < %i\n",
               extradata_size, size);
        return -1;
    }

    extradata += 4;
    av_log(avctx, AV_LOG_DEBUG, "size: %d\n", size);
    if (AV_RB32(extradata) != MKBETAG('Q','D','C','A')) {
        av_log(avctx, AV_LOG_ERROR, "invalid extradata

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -