[FFmpeg-devel] [PATCH] QCELP decoder

Michael Niedermayer michaelni
Sat Oct 25 03:00:50 CEST 2008


On Fri, Oct 17, 2008 at 09:46:31AM -0700, Kenan Gillet wrote:
> Hi,
> 
> On Thu, Oct 16, 2008 at 11:51 PM, Diego Biurrun <diego at biurrun.de> wrote:
> > On Thu, Oct 16, 2008 at 03:38:03PM -0700, Kenan Gillet wrote:
> >> On Oct 15, 2008, at 3:09 PM, Michael Niedermayer wrote:
> >>
> >> > cOn Tue, Oct 14, 2008 at 06:59:34PM -0700, Kenan Gillet wrote:
> >> >>
> >> >> --- libavcodec/qcelp.h     (revision 0)
> >> >> +++ libavcodec/qcelp.h     (revision 0)
> >> >> +static float compute_subframe_energy(const float *vector, const
> >> >> int subframeno) {
> >> >> +    int   i;
> >> >> +    float energy = 0;
> >> >> +
> >> >> +    vector += 40 * subframeno;
> >> >> +
> >> >> +    for (i = 0; i < 40; i++)
> >> >> +        energy += vector[i] * vector[i];
> >> >> +
> >> >> +    return energy;
> >> >> +}
> >> >
> >> > IMHO its cleaner not to add subframeno inside the function.
> >> > a simple dot_product(vector, len) should be more readable
> >> > also such a function has a much better chance to be shareable
> >> > between codec, and especially when things like that are optimized its
> >> > better if it isnt needed to be redone for each len and other obscure
> >> > variant
> >>
> >> done, I svn cp libavcodec/acelp_math.c into libavcodec/qcelp_math.c
> >> and made it ff_dot_product.
> >> or is there a better place for that ?
> >
> > If the file is used for both acelp and qcelp, it should not be called
> > qcelp, but celp instead.
> 
> done
> 
> >
> >> Should it be in a different patch ?
> >
> > Smaller patches get reviewed and applied faster.
> 
> round 6 summary:
> - no code change from round 5
> - replace svn cp by svn add to make the patch smaller
> - rename qcelp_math.[ch] into celp_math.[ch]
> - the patch is now broken into:
>     - qcelp-round6-decoder.patch.txt
>     core decoder code
> 
>     - qcelp-round6-doc-glue.patch.txt
>     doc and glue code
> 
>     - qcelp-round6-filters.patch.txt
>     filters functions
> 
>     - qcelp-round6-lsp.patch.txt
>     lsp functions
> 
>     - qcelp-round6-math.patch.txt
>     do_product
> 
> 
> Let me know if I can do anything to ease you reviewing effort.
[...]

> +
> +static const uint16_t qcelp_bits_per_rate[6] = {
> +    0, ///!< for SILENCE rate
> +    sizeof(qcelp_rate_octave_bitmap)  / sizeof(*qcelp_rate_octave_bitmap),
> +    sizeof(qcelp_rate_quarter_bitmap) / sizeof(*qcelp_rate_quarter_bitmap),
> +    sizeof(qcelp_rate_half_bitmap)    / sizeof(*qcelp_rate_half_bitmap),
> +    sizeof(qcelp_rate_full_bitmap)    / sizeof(*qcelp_rate_full_bitmap),
> +    0  ///!< for I_F_Q rate
> +};

FF_ARRAY_ELEMS


> +
> +typedef uint16_t qcelp_vector[2];
> +
> +/**
> + * LSP vector quantization tables in x*10000 form
> + *
> + * TIA/EIA/IS-733 tables 2.4.3.2.6.3-1 through 2.4.3.2.6.3-5
> + */
> +
> +static const qcelp_vector qcelp_lspvq1[64]= {
> +{ 327, 118},{ 919, 111},{ 427, 440},{1327, 185},
> +{ 469,  50},{1272,  91},{ 892,  59},{1771, 193},
> +{ 222, 158},{1100, 127},{ 827,  55},{ 978, 791},
> +{ 665,  47},{ 700,1401},{ 670, 859},{1913,1048},
> +{ 471, 215},{1046, 125},{ 645, 298},{1599, 160},
> +{ 593,  39},{1187, 462},{ 749, 341},{1520, 511},
> +{ 290, 792},{ 909, 362},{ 753,  81},{1111,1058},
> +{ 519, 253},{ 828, 839},{ 685, 541},{1421,1258},
> +{ 386, 130},{ 962, 119},{ 542, 387},{1431, 185},
> +{ 526,  51},{1175, 260},{ 831, 167},{1728, 510},
> +{ 273, 437},{1172, 113},{ 771, 144},{1122, 751},
> +{ 619, 119},{ 492,1276},{ 658, 695},{1882, 615},
> +{ 415, 200},{1018,  88},{ 681, 339},{1436, 325},
> +{ 555, 122},{1042, 485},{ 826, 345},{1374, 743},
> +{ 383,1018},{1005, 358},{ 704,  86},{1301, 586},
> +{ 597, 241},{ 832, 621},{ 555, 573},{1504, 839}};
> +
> +static const qcelp_vector qcelp_lspvq2[128]= {
> +{ 255, 293},{ 904, 219},{ 151,1211},{1447, 498},
> +{ 470, 253},{1559, 177},{1547, 994},{2394, 242},
> +{  91, 813},{ 857, 590},{ 934,1326},{1889, 282},
> +{ 813, 472},{1057,1494},{ 450,3315},{2163,1895},
> +{ 538, 532},{1399, 218},{ 146,1552},{1755, 626},
> +{ 822, 202},{1299, 663},{ 706,1732},{2656, 401},
> +{ 418, 745},{ 762,1038},{ 583,1748},{1746,1285},
> +{ 527,1169},{1314, 830},{ 556,2116},{1073,2321},
> +{ 297, 570},{ 981, 403},{ 468,1103},{1740, 243},
> +{ 725, 179},{1255, 474},{1374,1362},{1922, 912},
> +{ 285, 947},{ 930, 700},{ 593,1372},{1909, 576},
> +{ 588, 916},{1110,1116},{ 224,2719},{1633,2220},
> +{ 402, 520},{1061, 448},{ 402,1352},{1499, 775},
> +{ 664, 589},{1081, 727},{ 801,2206},{2165,1157},
> +{ 566, 802},{ 911,1116},{ 306,1703},{1792, 836},
> +{ 655, 999},{1061,1038},{ 298,2089},{1110,1753},
> +{ 361, 311},{ 970, 239},{ 265,1231},{1495, 573},
> +{ 566, 262},{1569, 293},{1341,1144},{2271, 544},
> +{ 214, 877},{ 847, 719},{ 794,1384},{2067, 274},
> +{ 703, 688},{1099,1306},{ 391,2947},{2024,1670},
> +{ 471, 525},{1245, 290},{ 264,1557},{1568, 807},
> +{ 718, 399},{1193, 685},{ 883,1594},{2729, 764},
> +{ 500, 754},{ 809,1108},{ 541,1648},{1523,1385},
> +{ 614,1196},{1209, 847},{ 345,2242},{1442,1747},
> +{ 199, 560},{1092, 194},{ 349,1253},{1653, 507},
> +{ 625, 354},{1376, 431},{1187,1465},{2164, 872},
> +{ 360, 974},{1008, 698},{ 704,1346},{2114, 452},
> +{ 720, 816},{1240,1089},{ 439,2475},{1498,2040},
> +{ 336, 718},{1213, 187},{ 451,1450},{1368, 885},
> +{ 592, 578},{1131, 531},{ 861,1855},{1764,1500},
> +{ 444, 970},{ 935, 903},{ 424,1687},{1633,1102},
> +{ 793, 897},{1060, 897},{ 185,2011},{1205,1855}};
> +
> +static const qcelp_vector qcelp_lspvq3[128]= {
> +{ 225, 283},{1296, 355},{ 543, 343},{2073, 274},
> +{ 204,1099},{1562, 523},{1388, 161},{2784, 274},
> +{ 112, 849},{1870, 175},{1189, 160},{1490,1088},
> +{ 969,1115},{ 659,3322},{1158,1073},{3183,1363},
> +{ 517, 223},{1740, 223},{ 704, 387},{2637, 234},
> +{ 692,1005},{1287,1610},{ 952, 532},{2393, 646},
> +{ 490, 552},{1619, 657},{ 845, 670},{1784,2280},
> +{ 191,1775},{ 272,2868},{ 942, 952},{2628,1479},
> +{ 278, 579},{1565, 218},{ 814, 180},{2379, 187},
> +{ 276,1444},{1199,1223},{1200, 349},{3009, 307},
> +{ 312, 844},{1898, 306},{ 863, 470},{1685,1241},
> +{ 513,1727},{ 711,2233},{1085, 864},{3398, 527},
> +{ 414, 440},{1356, 612},{ 964, 147},{2173, 738},
> +{ 465,1292},{ 877,1749},{1104, 689},{2105,1311},
> +{ 580, 864},{1895, 752},{ 652, 609},{1485,1699},
> +{ 514,1400},{ 386,2131},{ 933, 798},{2473, 986},
> +{ 334, 360},{1375, 398},{ 621, 276},{2183, 280},
> +{ 311,1114},{1382, 807},{1284, 175},{2605, 636},
> +{ 230, 816},{1739, 408},{1074, 176},{1619,1120},
> +{ 784,1371},{ 448,3050},{1189, 880},{3039,1165},
> +{ 424, 241},{1672, 186},{ 815, 333},{2432, 324},
> +{ 584,1029},{1137,1546},{1015, 585},{2198, 995},
> +{ 574, 581},{1746, 647},{ 733, 740},{1938,1737},
> +{ 347,1710},{ 373,2429},{ 787,1061},{2439,1438},
> +{ 185, 536},{1489, 178},{ 703, 216},{2178, 487},
> +{ 154,1421},{1414, 994},{1103, 352},{3072, 473},
> +{ 408, 819},{2055, 168},{ 998, 354},{1917,1140},
> +{ 665,1799},{ 993,2213},{1234, 631},{3003, 762},
> +{ 373, 620},{1518, 425},{ 913, 300},{1966, 836},
> +{ 402,1185},{ 948,1385},{1121, 555},{1802,1509},
> +{ 474, 886},{1888, 610},{ 739, 585},{1231,2379},
> +{ 661,1335},{ 205,2211},{ 823, 822},{2480,1179}};
> +
> +static const qcelp_vector qcelp_lspvq4[64]= {
> +{ 348, 311},{ 812,1145},{ 552, 461},{1826, 263},
> +{ 601, 675},{1730, 172},{1523, 193},{2449, 277},
> +{ 334, 668},{ 805,1441},{1319, 207},{1684, 910},
> +{ 582,1318},{1403,1098},{ 979, 832},{2700,1359},
> +{ 624, 228},{1292, 979},{ 800, 195},{2226, 285},
> +{ 730, 862},{1537, 601},{1115, 509},{2720, 354},
> +{ 218,1167},{1212,1538},{1074, 247},{1674,1710},
> +{ 322,2142},{1263, 777},{ 981, 556},{2119,1710},
> +{ 193, 596},{1035, 957},{ 694, 397},{1997, 253},
> +{ 743, 603},{1584, 321},{1346, 346},{2221, 708},
> +{ 451, 732},{1040,1415},{1184, 230},{1853, 919},
> +{ 310,1661},{1625, 706},{ 856, 843},{2902, 702},
> +{ 467, 348},{1108,1048},{ 859, 306},{1964, 463},
> +{ 560,1013},{1425, 533},{1142, 634},{2391, 879},
> +{ 397,1084},{1345,1700},{ 976, 248},{1887,1189},
> +{ 644,2087},{1262, 603},{ 877, 550},{2203,1307}};
> +
> +static const qcelp_vector qcelp_lspvq5[64]= {
> +{ 360, 222},{ 820,1097},{ 601, 319},{1656, 198},
> +{ 604, 513},{1552, 141},{1391, 155},{2474, 261},
> +{ 269, 785},{1463, 646},{1123, 191},{2015, 223},
> +{ 785, 844},{1202,1011},{ 980, 807},{3014, 793},
> +{ 570, 180},{1135,1382},{ 778, 256},{1901, 179},
> +{ 807, 622},{1461, 458},{1231, 178},{2028, 821},
> +{ 387, 927},{1496,1004},{ 888, 392},{2246, 341},
> +{ 295,1462},{1156, 694},{1022, 473},{2226,1364},
> +{ 210, 478},{1029,1020},{ 722, 181},{1730, 251},
> +{ 730, 488},{1465, 293},{1303, 326},{2595, 387},
> +{ 458, 584},{1569, 742},{1029, 173},{1910, 495},
> +{ 605,1159},{1268, 719},{ 973, 646},{2872, 428},
> +{ 443, 334},{ 835,1465},{ 912, 138},{1716, 442},
> +{ 620, 778},{1316, 450},{1186, 335},{1446,1665},
> +{ 486,1050},{1675,1019},{ 880, 278},{2214, 202},
> +{ 539,1564},{1142, 533},{ 984, 391},{2130,1089}};
> +
> +static const qcelp_vector * const qcelp_lspvq[5] = {
> +    qcelp_lspvq1,
> +    qcelp_lspvq2,
> +    qcelp_lspvq3,
> +    qcelp_lspvq4,
> +    qcelp_lspvq5
> +};

ok


> +
> +
> +/**
> + * the final gain scalefactor before clipping into a usable output float
> + */
> +#define QCELP_SCALE 8192.
> +

> +/**
> + * table for computing Ga (decoded linear codebook gain magnitude)
> + *
> + * TIA/EIA/IS-733 2.4.6.2.1-3
> + */
> +
> +static const float qcelp_g12ga[61] = {
> +    1.000/QCELP_SCALE,   1.125/QCELP_SCALE,   1.250/QCELP_SCALE,   1.375/QCELP_SCALE,
> +    1.625/QCELP_SCALE,   1.750/QCELP_SCALE,   2.000/QCELP_SCALE,   2.250/QCELP_SCALE,
> +    2.500/QCELP_SCALE,   2.875/QCELP_SCALE,   3.125/QCELP_SCALE,   3.500/QCELP_SCALE,
> +    4.000/QCELP_SCALE,   4.500/QCELP_SCALE,   5.000/QCELP_SCALE,   5.625/QCELP_SCALE,
> +    6.250/QCELP_SCALE,   7.125/QCELP_SCALE,   8.000/QCELP_SCALE,   8.875/QCELP_SCALE,
> +   10.000/QCELP_SCALE,  11.250/QCELP_SCALE,  12.625/QCELP_SCALE,  14.125/QCELP_SCALE,
> +   15.875/QCELP_SCALE,  17.750/QCELP_SCALE,  20.000/QCELP_SCALE,  22.375/QCELP_SCALE,
> +   25.125/QCELP_SCALE,  28.125/QCELP_SCALE,  31.625/QCELP_SCALE,  35.500/QCELP_SCALE,
> +   39.750/QCELP_SCALE,  44.625/QCELP_SCALE,  50.125/QCELP_SCALE,  56.250/QCELP_SCALE,
> +   63.125/QCELP_SCALE,  70.750/QCELP_SCALE,  79.375/QCELP_SCALE,  89.125/QCELP_SCALE,
> +  100.000/QCELP_SCALE, 112.250/QCELP_SCALE, 125.875/QCELP_SCALE, 141.250/QCELP_SCALE,
> +  158.500/QCELP_SCALE, 177.875/QCELP_SCALE, 199.500/QCELP_SCALE, 223.875/QCELP_SCALE,
> +  251.250/QCELP_SCALE, 281.875/QCELP_SCALE, 316.250/QCELP_SCALE, 354.875/QCELP_SCALE,
> +  398.125/QCELP_SCALE, 446.625/QCELP_SCALE, 501.125/QCELP_SCALE, 563.375/QCELP_SCALE,
> +  631.000/QCELP_SCALE, 708.000/QCELP_SCALE, 794.375/QCELP_SCALE, 891.250/QCELP_SCALE,
> + 1000.000/QCELP_SCALE};

this fits in a uint16_t when the numbers are multiplied by 8


> +

> +/**
> + * circular codebook for rate 1 frames
> + * TIA/EIA/IS-733 2.4.6.1-2
> + */
> +static const int16_t qcelp_rate_full_codebook[128] = {
> +     10,  -65,  - 59,  12,  110,   34, -134,  157,
> +    104,  -84,  -34, -115,   23, -101,    3,   45,

the space before 59 looks odd


[...]
> +/**
> + * Verify the samplerate and the number of channels.
> + * Initialize the speech codec according to the specification.
> + *
> + * TIA/EIA/IS-733 2.4.9
> + */
> +static int qcelp_decode_init(AVCodecContext *avctx) {
> +    QCELPContext *q = avctx->priv_data;
> +    int i;
> +
> +    avctx->sample_fmt = SAMPLE_FMT_FLT;
> +
> +    for (i = 0; i < 10; i++)
> +        q->prev_lspf[i] = (i + 1) / 11.;
> +
> +    return 0;
> +}

"Verify the samplerate and the number of channels." ?
i cant see what this comment means in relation to this function


> +
> +/**
> + * Decodes the 10 quantized LSP frequencies from the LSPV/LSP
> + * transmission codes of any framerate and check for badly received packets.
> + *
> + * @return 0 on success, -1 if the packet is badly received
> + *
> + * TIA/EIA/IS-733 2.4.3.2.6.2-2, 2.4.8.7.3
> + */
> +static int decode_lspf(QCELPContext *q, float *lspf) {
> +    int i;
> +    float tmp_lspf;
> +
> +    if (q->framerate == RATE_OCTAVE ||
> +        q->framerate == I_F_Q) {

> +        float smooth;
> +        float erasure_coeff = 1.0;
> +        const float *predictors = (q->prev_framerate != RATE_OCTAVE ||
> +                                   q->prev_framerate != I_F_Q ? q->prev_lspf
> +                                                              : q->predictor_lspf);
> +

> +        if (q->framerate == RATE_OCTAVE) {
> +            q->octave_count++;
> +            smooth = (q->octave_count < 10 ? .875 : 0.1);
> +        } else {
> +            if (q->erasure_count > 1)
> +                erasure_coeff = (q->erasure_count < 4 ? 0.9 : 0.7);
> +            smooth = 0.125;
> +        }

i think it would be more readable if erasure_coeff would be set to 1 in a
else here instead of above, its not used in the RATE_OCTAVE case anyway


> +
> +        for (i = 0; i < 10; i++) {
> +            lspf[i] = (i + 1) / 11.;
> +            if (q->framerate == RATE_OCTAVE) {
> +                q->predictor_lspf[i]  =
> +                             lspf[i] += (q->lspv[i] ?  QCELP_LSP_SPREAD_FACTOR
> +                                                    : -QCELP_LSP_SPREAD_FACTOR)
> +                                      + (predictors[i] - lspf[i]) * QCELP_LSP_OCTAVE_PREDICTOR;
> +            } else {
> +                q->predictor_lspf[i] = (predictors[i] - lspf[i]) * erasure_coeff;
> +                lspf[i] += QCELP_LSP_OCTAVE_PREDICTOR * q->predictor_lspf[i];
> +            }
> +        }

the for () can be split and the 2 put under te if/else above
i belive this would be more readable and faster


[...]
> +/**
> + * Computes the scaled codebook vector Cdn From INDEX and GAIN
> + * for all rates.
> + *
> + * The specification lacks some information here.
> + *
> + * TIA/EIA/IS-733 has an omission on the codebook index determination
> + * formula for RATE_FULL and RATE_HALF frames at section 2.4.8.1.1. It says
> + * you have to subtract the decoded index parameter from the given scaled
> + * codebook vector index 'n' to get the desired circular codebook index, but
> + * it does not mention that you have to clamp 'n' to [0-9] in order to get
> + * RI-compliant results.
> + *
> + * The reason for this mistake seems to be the fact they forgot to mention you
> + * have to do these calculations per codebook subframe and adjust given
> + * equation values accordingly.
> + *
> + * @param q the context
> + * @param gain array holding the 4 pitch subframe gain values
> + * other than RATE_FULL or RATE_HALF
> + * @param cdn_vector array for the generated scaled codebook vector
> + */
> +static void compute_svector(const QCELPContext *q, const float *gain, float *cdn_vector) {
> +    int      i,j;
> +    uint16_t cbseed;
> +    float    rnd[160];
> +
> +    switch (q->framerate) {
> +    case RATE_FULL:
> +        for (i = 0; i < 16; i++)
> +            for (j = 0; j < 10; j++)
> +                *cdn_vector++ = gain[i] * qcelp_rate_full_codebook[(j - q->cindex[i]) & 127]
> +                              * QCELP_RATE_FULL_CODEBOOK_RATIO;
> +        break;
> +    case RATE_HALF:
> +        for (i = 0; i < 4; i++)
> +            for (j = 0; j < 40; j++)
> +                *cdn_vector++ = gain[i] * qcelp_rate_half_codebook[(j - q->cindex[i]) & 127]
> +                              * QCELP_RATE_HALF_CODEBOOK_RATIO;
> +        break;
> +    case RATE_QUARTER:
> +        cbseed = (0x0003 & q->lspv[4])<<14 |
> +                 (0x003F & q->lspv[3])<< 8 |
> +                 (0x0060 & q->lspv[2])<< 1 |
> +                 (0x0007 & q->lspv[1])<< 3 |
> +                 (0x0038 & q->lspv[0])>> 3 ;

> +        for (i = 0; i < 160; i++) {
> +            cbseed = 521 * cbseed + 259;
> +            rnd[i] = (QCELP_SQRT1887 / 32768.0) * (int16_t)cbseed;
> +

> +            // FIR filter
> +            cdn_vector[i] = qcelp_rnd_fir_coefs[1] * rnd[i];
> +            for (j = 1; j < 22 && !(i-j+1); j++)
> +                cdn_vector[i] += qcelp_rnd_fir_coefs[j]*rnd[i-j];

the rnd array can be made larger by ~22 entries to avoid !(i-j+1) check
it can also be optimized to
for()
    cdn_vector[i] += qcelp_rnd_fir_coefs[j]*(rnd[i-j] + rnd[i+j])


> +
> +            cdn_vector[i] *= gain[i/20];

division is slow, the loop can be split to avoid that


> +        }
> +        break;
> +    case RATE_OCTAVE:
> +        cbseed = q->first16bits;
> +        for (i = 0; i < 8; i++)
> +            for (j = 0; j < 20; j++) {
> +                cbseed = 521 * cbseed + 259;
> +                cdn_vector[20*i+j] = gain[i]
> +                                   * (QCELP_SQRT1887 / 32768.0) * (int16_t)cbseed;
> +            }

gain[i] * (QCELP_SQRT1887 / 32768.0)
can be calculated outside of the loop


> +        break;
> +    case I_F_Q:

> +        cbseed = 44; // random codebook index
> +        for (i = 0; i < 160; i++)
> +            cdn_vector[i] = gain[i/40] * qcelp_rate_full_codebook[(i-cbseed) & 127]
> +                          * QCELP_RATE_FULL_CODEBOOK_RATIO;

the loop can be split to avoid the /40


> +        break;
> +    }
> +}
> +

> +/**
> + * Apply generic gain control.
> + *
> + * @param v_out output vector
> + * @param v_in vector to control gain of
> + * @param v_gain gain-controlled vector
> + *
> + * TIA/EIA/IS-733 2.4.8.3-2/3/4/5, 2.4.8.6
> + */
> +static void apply_gain_ctrl(float *v_out, const float *v_in, const float *v_gain) {
> +    int   i, j, len;
> +    float scalefactor;
> +
> +    for (i = 0, j = 0; i < 4; i++) {
> +        scalefactor = sqrt(ff_dot_product(v_in  + j, v_in  + j, 40) /
> +                           ff_dot_product(v_gain + j, v_gain + j, 40));

verical align
and a 1/0 issue (no i am not sure if it can happen but you said
IIRC it can be 0)


> +        if (scalefactor)
> +            for (len = j + 40; j < len; j++)
> +                v_out[j] = scalefactor * v_gain[j];
> +    }
> +}
> +
> +/**
> + * Apply filter in pitch-subframe steps.
> + *
> + * @param memory buffer for the previous state of the filter
> + *        - must be able to contain 303 elements
> + *        - the 143 fist elements are from the previous state
> + *        - the next 160 are for output
> + * @param v_in input filter vector
> + * @param gain per-subframe gain array, each element is between 0.0 and 2.0
> + * @param lag per-subframe lag array, each element is
> + *        - between 16 and 143 if its corresponding pfrac is 0,
> + *        - between 16 and 139 otherwise
> + * @param pfrac per-subframe boolean array, 1 if the lag is fractional, 0 otherwise
> + *
> + * @return filter output vector
> + */
> +static const float *do_pitchfilter(float memory[303], const float v_in[160],
> +                                   const float gain[4], const uint8_t *lag, const uint8_t pfrac[4]) {
> +    int         i, j;
> +    float       *v_lag, *v_out;
> +    const float *v_len;
> +
> +    v_out = memory + 143; // output vector start at memory[143]
> +
> +    for (i = 0; i < 4; i++)
> +        if (gain[i]) {
> +            v_lag = memory + 143 + 40 * i - lag[i];
> +            for (v_len = v_in + 40; v_in < v_len; v_in++) {
> +                if (pfrac[i]) { // If is a fractional lag...

> +                    for (j = -4, *v_out = 0.; j < 4; j++)
> +                        *v_out += qcelp_hammsinc_table[j + 4] * v_lag[j];

for(j=0; j<4; j++)
    *v_out += qcelp_hammsinc_table[j] * (v_lag[foo] + v_lag[bar]);


[...]
> +/**
> + * Interpolates LSP frequencies and computes LPC coefficients
> + * for a given framerate & pitch subframe.
> + *
> + * TIA/EIA/IS-733 2.4.3.3.4
> + *
> + * @param q the context
> + * @param curr_lspf LSP frequencies vector of the current frame
> + * @param lpc float vector for the resulting LPC
> + * @param subframe_num frame number in decoded stream
> + */
> +void interpolate_lpc(QCELPContext *q, const float *curr_lspf, float *lpc, const int subframe_num) {
> +    float interpolated_lspf[10];
> +
> +    switch (q->framerate) {
> +    case RATE_FULL:
> +    case RATE_HALF:
> +    case RATE_QUARTER:
> +        interpolate_lspf(interpolated_lspf, 0.25 * (subframe_num + 1),
> +                         curr_lspf, q->prev_lspf);
> +        qcelp_lspf2lpc(interpolated_lspf, lpc);
> +        break;
> +    case RATE_OCTAVE:
> +        if (!subframe_num) {
> +            interpolate_lspf(interpolated_lspf, 0.625, curr_lspf, q->prev_lspf);
> +            qcelp_lspf2lpc(interpolated_lspf, lpc);
> +        }
> +        break;
> +    case I_F_Q:
> +        if (!subframe_num)
> +            qcelp_lspf2lpc(curr_lspf, lpc);
> +        break;
> +    }
> +}

somehow iam thinking code like 

if(q->framerate >= RATE_QUARTER)

would be nice ...


[...]
> +static int qcelp_decode_frame(AVCodecContext *avctx,
> +                              void *data, int *data_size,
> +                              uint8_t *buf, const int buf_size) {
> +    QCELPContext      *q = avctx->priv_data;
> +    const QCELPBitmap *bitmaps = NULL;
> +    float             *outbuffer = data;
> +    int               i;
> +    float             qtzd_lspf[10], lpc[10];
> +    float             *formant_mem;
> +
> +    if (determine_framerate(avctx, q, buf_size, &buf) < 0) {
> +        av_log(avctx, AV_LOG_ERROR, "Frame #%d: Unknown framerate, unsupported size: %d.\n",
> +               avctx->frame_number, buf_size);
> +        return -1;
> +    }
> +

> +    if (q->framerate == RATE_OCTAVE &&
> +       (q->first16bits = (buf[0] << 8) + buf[1]) == 0xFFFF) {

AV_RB16()


> +        warn_insufficient_frame_quality(avctx, "Framerate is 1/8 and first 16 bits are on.");
> +        goto erasure;
> +    }
> +
> +    bitmaps = qcelp_unpacking_bitmaps_per_rate[q->framerate];
> +    if (bitmaps) {
> +        uint8_t *unpacked_data = (uint8_t *)q;
> +        const QCELPBitmap *bitmaps_end = bitmaps + qcelp_bits_per_rate[q->framerate];
> +
> +        init_get_bits(&q->gb, buf, 8 * buf_size);
> +

> +        memset(q->cbsign, 0, 71 * sizeof(uint8_t));

q->reserved - q->cbsign + 1
71 is fragile ...


> +        for (; bitmaps < bitmaps_end; bitmaps++)
> +            unpacked_data[bitmaps[0].index] |= get_bits1(&q->gb) << bitmaps[0].bitpos;

maybe
for (; bitmaps < bitmaps_end; bitmaps++)
    unpacked_data[bitmaps[0].index] |= get_bits(&q->gb, bitmaps[0].len) << bitmaps[0].bitpos;

would lead to shorter tables and faster reading ...


[...]
> +    for (i = 0; i < 160; i++)
> +        *outbuffer++ = av_clipf(*formant_mem++, -8192., 8191.75);

is this cliping needed?


[...]
> Index: libavcodec/qcelp_lsp.c
> ===================================================================
> --- libavcodec/qcelp_lsp.c	(revision 0)
> +++ libavcodec/qcelp_lsp.c	(revision 0)
> @@ -0,0 +1,98 @@
> +/*
> + * QCELP decoder
> + * Copyright (c) 2007 Reynaldo H. Verdejo Pinochet
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +/**
> + * @file qcelp_lsp.c
> + * QCELP decoder
> + * @author Reynaldo H. Verdejo Pinochet
> + */
> +
> +#include <math.h>
> +#include <string.h>
> +
> +#include "dsputil.h"
> +
> +/**
> + * Linear convolution of two vectors v1 and [1, cos, 1]
> + *
> + * @param v_out the result of the convolution,
> + *              needs to be able to hold v_in_len + 2 elements
> + * @param v_in the input vector
> + * @param cos
> + * @param v_in_len the dimension of v_in assumed to be in  {2,4,6,8,10}
> + */
> +static void convolve(float *v_out, const float *v_in, const float cos, const int v_in_len) {
> +    int   i;
> +
> +    v_out[0] = v_in[0];
> +    v_out[1] = v_in[1] + v_in[0] * cos;
> +    for (i = 2; i < v_in_len; i++) {
> +        v_out[i] = v_in[i]
> +                 + v_in[i - 1] * cos
> +                 + v_in[i - 2];
> +    }
> +    v_out[v_in_len    ] = v_in[v_in_len - 1] * cos + v_in[v_in_len - 2];
> +    v_out[v_in_len + 1] = v_in[v_in_len - 1];
> +}
> +
> +/**
> + * Computes the Pa and Qa coefficients needed for LSP to LPC conversion.
> + *
> + * TIA/EIA/IS-733 2.4.3.3.5-1/2
> + */
> +static void lsp2poly(float *poly, const float *lspf, float *v_in, float *v_buf, const int odd) {
> +    int   i;
> +    float *v1 = v_in, *v2 = v_buf;
> +
> +    for (i = 0; i < 10; i += 2) {
> +        convolve(v2, v1, -2 * cos(M_PI * lspf[i + odd]), i + 2);
> +        FFSWAP(float *, v1, v2);
> +    }
> +    memcpy(poly, v1 + 1, 5 * sizeof(float));
> +}
> +
> +/**
> + * Reconstructs LPC coefficients from the line spectral pair frequencies.
> + *
> + * TIA/EIA/IS-733 2.4.3.3.5
> + */
> +void qcelp_lspf2lpc(const float *lspf, float *lpc) {
> +    float pa[5],qa[5];
> +    float v1[12], v2[12];
> +    float beta = 0.9883;
> +    int   i;
> +
> +    v1[0] = 0.5;
> +    v1[1] = 0.5;
> +    lsp2poly(pa, lspf, v1, v2, 0);
> +
> +    v1[0] =  0.5;
> +    v1[1] = -0.5;
> +    lsp2poly(qa, lspf, v1, v2, 1);
> +
> +    for (i = 0; i < 5; i++) {
> +        lpc[i] = -(pa[i] + qa[i]) * beta;
> +        beta *= 0.9883;
> +    }
> +    for (i = 5; i < 10; i++) {
> +        lpc[i] = -(pa[9-i] - qa[9-i]) * beta;
> +        beta *= 0.9883;
> +    }
> +}

we have some float lsp code in ffmpeg already (in wma&vorbis), i would
prefer to avoid adding more duplicated code.
If there are problems with merging the different implementations then this
should be discussed, maybe there is a problem that would leave us
no choice than adding this but until such problem is found this is not good.


> Index: libavcodec/celp_math.c
> ===================================================================
> --- libavcodec/celp_math.c	(revision 0)
> +++ libavcodec/celp_math.c	(revision 0)
> @@ -0,0 +1,40 @@
> +/*
[...]
> + */
> +
> +/**
> + * returns the dot product.
> + * @param a input data array
> + * @param b input data array
> + * @param length number of elements
> + *
> + * @return dot product = sum of elementwise products
> + */
> +float ff_dot_product(const float* a, const float* b, int length)
> +{
> +    float sum = 0;
> +    int i;
> +
> +    for(i=0; i<length; i++)
> +        sum += (a[i] * b[i]);
> +
> +    return sum;
> +}

superflous () and a dot product is not a celp specific thing
the doxy belongs in the header not the c file


[...]
> Index: libavformat/mov.c
> ===================================================================
> --- libavformat/mov.c	(revision 15630)
> +++ libavformat/mov.c	(working copy)
> @@ -987,6 +987,10 @@
>  #endif
>      /* no ifdef since parameters are always those */
>      case CODEC_ID_QCELP:
> +        st->need_parsing = AVSTREAM_PARSE_FULL;
> +        st->codec->frame_size= 160;
> +        st->codec->channels= 1; /* really needed */
> +        break;
>      case CODEC_ID_AMR_NB:
>      case CODEC_ID_AMR_WB:
>          st->codec->frame_size= sc->samples_per_frame;

ok

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

The educated differ from the uneducated as much as the living from the
dead. -- Aristotle 
-------------- 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/20081025/c563ba88/attachment.pgp>



More information about the ffmpeg-devel mailing list