summaryrefslogtreecommitdiff
path: root/ffmpeg1/libavcodec/vorbis.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffmpeg1/libavcodec/vorbis.c')
-rw-r--r--ffmpeg1/libavcodec/vorbis.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/ffmpeg1/libavcodec/vorbis.c b/ffmpeg1/libavcodec/vorbis.c
new file mode 100644
index 0000000..6eb765d
--- /dev/null
+++ b/ffmpeg1/libavcodec/vorbis.c
@@ -0,0 +1,236 @@
+/**
+ * @file
+ * Common code for Vorbis I encoder and decoder
+ * @author Denes Balatoni ( dbalatoni programozo hu )
+ *
+ * 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
+ * Common code for Vorbis I encoder and decoder
+ * @author Denes Balatoni ( dbalatoni programozo hu )
+ */
+
+#define BITSTREAM_READER_LE
+#include "avcodec.h"
+#include "get_bits.h"
+
+#include "vorbis.h"
+
+
+/* Helper functions */
+
+// x^(1/n)
+unsigned int ff_vorbis_nth_root(unsigned int x, unsigned int n)
+{
+ unsigned int ret = 0, i, j;
+
+ do {
+ ++ret;
+ for (i = 0, j = ret; i < n - 1; i++)
+ j *= ret;
+ } while (j <= x);
+
+ return ret - 1;
+}
+
+// Generate vlc codes from vorbis huffman code lengths
+
+// the two bits[p] > 32 checks should be redundant, all calling code should
+// already ensure that, but since it allows overwriting the stack it seems
+// reasonable to check redundantly.
+int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num)
+{
+ uint32_t exit_at_level[33] = { 404 };
+
+ unsigned i, j, p, code;
+
+#ifdef DEBUG
+ GetBitContext gb;
+#endif
+
+ for (p = 0; (bits[p] == 0) && (p < num); ++p)
+ ;
+ if (p == num)
+ return 0;
+
+ codes[p] = 0;
+ if (bits[p] > 32)
+ return 1;
+ for (i = 0; i < bits[p]; ++i)
+ exit_at_level[i+1] = 1 << i;
+
+#ifdef DEBUG
+ av_log(NULL, AV_LOG_INFO, " %u. of %u code len %d code %d - ", p, num, bits[p], codes[p]);
+ init_get_bits(&gb, (uint8_t *)&codes[p], bits[p]);
+ for (i = 0; i < bits[p]; ++i)
+ av_log(NULL, AV_LOG_INFO, "%s", get_bits1(&gb) ? "1" : "0");
+ av_log(NULL, AV_LOG_INFO, "\n");
+#endif
+
+ ++p;
+
+ for (; p < num; ++p) {
+ if (bits[p] > 32)
+ return 1;
+ if (bits[p] == 0)
+ continue;
+ // find corresponding exit(node which the tree can grow further from)
+ for (i = bits[p]; i > 0; --i)
+ if (exit_at_level[i])
+ break;
+ if (!i) // overspecified tree
+ return 1;
+ code = exit_at_level[i];
+ exit_at_level[i] = 0;
+ // construct code (append 0s to end) and introduce new exits
+ for (j = i + 1 ;j <= bits[p]; ++j)
+ exit_at_level[j] = code + (1 << (j - 1));
+ codes[p] = code;
+
+#ifdef DEBUG
+ av_log(NULL, AV_LOG_INFO, " %d. code len %d code %d - ", p, bits[p], codes[p]);
+ init_get_bits(&gb, (uint8_t *)&codes[p], bits[p]);
+ for (i = 0; i < bits[p]; ++i)
+ av_log(NULL, AV_LOG_INFO, "%s", get_bits1(&gb) ? "1" : "0");
+ av_log(NULL, AV_LOG_INFO, "\n");
+#endif
+
+ }
+
+ //no exits should be left (underspecified tree - ie. unused valid vlcs - not allowed by SPEC)
+ for (p = 1; p < 33; p++)
+ if (exit_at_level[p])
+ return 1;
+
+ return 0;
+}
+
+int ff_vorbis_ready_floor1_list(AVCodecContext *avctx,
+ vorbis_floor1_entry *list, int values)
+{
+ int i;
+ list[0].sort = 0;
+ list[1].sort = 1;
+ for (i = 2; i < values; i++) {
+ int j;
+ list[i].low = 0;
+ list[i].high = 1;
+ list[i].sort = i;
+ for (j = 2; j < i; j++) {
+ int tmp = list[j].x;
+ if (tmp < list[i].x) {
+ if (tmp > list[list[i].low].x)
+ list[i].low = j;
+ } else {
+ if (tmp < list[list[i].high].x)
+ list[i].high = j;
+ }
+ }
+ }
+ for (i = 0; i < values - 1; i++) {
+ int j;
+ for (j = i + 1; j < values; j++) {
+ if (list[i].x == list[j].x) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Duplicate value found in floor 1 X coordinates\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (list[list[i].sort].x > list[list[j].sort].x) {
+ int tmp = list[i].sort;
+ list[i].sort = list[j].sort;
+ list[j].sort = tmp;
+ }
+ }
+ }
+ return 0;
+}
+
+static inline void render_line_unrolled(intptr_t x, int y, int x1,
+ intptr_t sy, int ady, int adx,
+ float *buf)
+{
+ int err = -adx;
+ x -= x1 - 1;
+ buf += x1 - 1;
+ while (++x < 0) {
+ err += ady;
+ if (err >= 0) {
+ err += ady - adx;
+ y += sy;
+ buf[x++] = ff_vorbis_floor1_inverse_db_table[av_clip_uint8(y)];
+ }
+ buf[x] = ff_vorbis_floor1_inverse_db_table[av_clip_uint8(y)];
+ }
+ if (x <= 0) {
+ if (err + ady >= 0)
+ y += sy;
+ buf[x] = ff_vorbis_floor1_inverse_db_table[av_clip_uint8(y)];
+ }
+}
+
+static void render_line(int x0, int y0, int x1, int y1, float *buf)
+{
+ int dy = y1 - y0;
+ int adx = x1 - x0;
+ int ady = FFABS(dy);
+ int sy = dy < 0 ? -1 : 1;
+ buf[x0] = ff_vorbis_floor1_inverse_db_table[av_clip_uint8(y0)];
+ if (ady*2 <= adx) { // optimized common case
+ render_line_unrolled(x0, y0, x1, sy, ady, adx, buf);
+ } else {
+ int base = dy / adx;
+ int x = x0;
+ int y = y0;
+ int err = -adx;
+ ady -= FFABS(base) * adx;
+ while (++x < x1) {
+ y += base;
+ err += ady;
+ if (err >= 0) {
+ err -= adx;
+ y += sy;
+ }
+ buf[x] = ff_vorbis_floor1_inverse_db_table[av_clip_uint8(y)];
+ }
+ }
+}
+
+void ff_vorbis_floor1_render_list(vorbis_floor1_entry * list, int values,
+ uint16_t *y_list, int *flag,
+ int multiplier, float *out, int samples)
+{
+ int lx, ly, i;
+ lx = 0;
+ ly = y_list[0] * multiplier;
+ for (i = 1; i < values; i++) {
+ int pos = list[i].sort;
+ if (flag[pos]) {
+ int x1 = list[pos].x;
+ int y1 = y_list[pos] * multiplier;
+ if (lx < samples)
+ render_line(lx, ly, FFMIN(x1,samples), y1, out);
+ lx = x1;
+ ly = y1;
+ }
+ if (lx >= samples)
+ break;
+ }
+ if (lx < samples)
+ render_line(lx, ly, samples, ly, out);
+}