[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