From d5c5a1c7e2959a5174522b5ac1d73d5095b8c5a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Fri, 22 Apr 2011 00:45:06 +0300 Subject: doc: Mention that DragonFly BSD requires __BSD_VISIBLE set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting this should fix the FATE build failure on DragonFly BSD, since inet_aton only is visible if __BSD_VISIBLE is set. Alternatively, a line defining __BSD_VISIBLE=1 could be added at the top of os_support.c. For FreeBSD, similar lines are required in libavdevice/bktr.c and libavdevice/oss_audio.c, too. Signed-off-by: Martin Storsjö --- doc/general.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/general.texi b/doc/general.texi index 423402c..edd5e60 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -784,9 +784,9 @@ to configure. BSD make will not build Libav, you need to install and use GNU Make (@file{gmake}). -@subsubsection FreeBSD +@subsubsection FreeBSD, DragonFly BSD -FreeBSD will not compile out-of-the-box due to broken system headers. +These systems will not compile out-of-the-box due to broken system headers. Passing @code{--extra-cflags=-D__BSD_VISIBLE} to configure will work around the problem. This may have unexpected sideeffects, so use it at your own risk. If you care about FreeBSD, please make an attempt at -- cgit v1.1 From 6e4f70a8de69884ce0caa8735d7a88915b4391d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Sun, 23 Jan 2011 01:31:41 +0200 Subject: Add a protocol handler for AES CBC decryption with PKCS7 padding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This can later be extended to support other AES bit sizes, encryption, other crypto algorithms, reading the key from a URL, etc. In order to use it, the key and initialization vector has to be passed via AVOptions. Since such options can't be passed to protocols from the command line, the protocol is currently only for libavformat internal use. Signed-off-by: Martin Storsjö --- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/crypto.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 libavformat/crypto.c diff --git a/libavformat/Makefile b/libavformat/Makefile index 5e029ed..e2e3982 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -312,6 +312,7 @@ OBJS+= avio.o aviobuf.o OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += applehttpproto.o OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o +OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o OBJS-$(CONFIG_FILE_PROTOCOL) += file.o OBJS-$(CONFIG_GOPHER_PROTOCOL) += gopher.o OBJS-$(CONFIG_HTTP_PROTOCOL) += http.o httpauth.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 931947d..f1c3d3b 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -235,6 +235,7 @@ void av_register_all(void) /* protocols */ REGISTER_PROTOCOL (APPLEHTTP, applehttp); REGISTER_PROTOCOL (CONCAT, concat); + REGISTER_PROTOCOL (CRYPTO, crypto); REGISTER_PROTOCOL (FILE, file); REGISTER_PROTOCOL (GOPHER, gopher); REGISTER_PROTOCOL (HTTP, http); diff --git a/libavformat/crypto.c b/libavformat/crypto.c new file mode 100644 index 0000000..ea6012a --- /dev/null +++ b/libavformat/crypto.c @@ -0,0 +1,170 @@ +/* + * Decryption protocol handler + * Copyright (c) 2011 Martin Storsjo + * + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "libavutil/aes.h" +#include "libavutil/avstring.h" +#include "libavutil/opt.h" +#include "internal.h" +#include "url.h" + +#define MAX_BUFFER_BLOCKS 150 +#define BLOCKSIZE 16 + +typedef struct { + const AVClass *class; + URLContext *hd; + uint8_t inbuffer [BLOCKSIZE*MAX_BUFFER_BLOCKS], + outbuffer[BLOCKSIZE*MAX_BUFFER_BLOCKS]; + uint8_t *outptr; + int indata, indata_used, outdata; + int eof; + uint8_t *key; + int keylen; + uint8_t *iv; + int ivlen; + struct AVAES *aes; +} CryptoContext; + +#define OFFSET(x) offsetof(CryptoContext, x) +static const AVOption options[] = { + {"key", "AES decryption key", OFFSET(key), FF_OPT_TYPE_BINARY }, + {"iv", "AES decryption initialization vector", OFFSET(iv), FF_OPT_TYPE_BINARY }, + { NULL } +}; + +static const AVClass crypto_class = { + "crypto", av_default_item_name, options, LIBAVUTIL_VERSION_INT +}; + +static int crypto_open(URLContext *h, const char *uri, int flags) +{ + const char *nested_url; + int ret; + CryptoContext *c = h->priv_data; + + if (!av_strstart(uri, "crypto+", &nested_url) && + !av_strstart(uri, "crypto:", &nested_url)) { + av_log(h, AV_LOG_ERROR, "Unsupported url %s\n", uri); + ret = AVERROR(EINVAL); + goto err; + } + + if (c->keylen < BLOCKSIZE || c->ivlen < BLOCKSIZE) { + av_log(h, AV_LOG_ERROR, "Key or IV not set\n"); + ret = AVERROR(EINVAL); + goto err; + } + if (flags & AVIO_FLAG_WRITE) { + av_log(h, AV_LOG_ERROR, "Only decryption is supported currently\n"); + ret = AVERROR(ENOSYS); + goto err; + } + if ((ret = ffurl_open(&c->hd, nested_url, AVIO_FLAG_READ)) < 0) { + av_log(h, AV_LOG_ERROR, "Unable to open input\n"); + goto err; + } + c->aes = av_mallocz(av_aes_size); + if (!c->aes) { + ret = AVERROR(ENOMEM); + goto err; + } + + av_aes_init(c->aes, c->key, 128, 1); + + h->is_streamed = 1; + + return 0; +err: + av_free(c->key); + av_free(c->iv); + return ret; +} + +static int crypto_read(URLContext *h, uint8_t *buf, int size) +{ + CryptoContext *c = h->priv_data; + int blocks; +retry: + if (c->outdata > 0) { + size = FFMIN(size, c->outdata); + memcpy(buf, c->outptr, size); + c->outptr += size; + c->outdata -= size; + return size; + } + // We avoid using the last block until we've found EOF, + // since we'll remove PKCS7 padding at the end. So make + // sure we've got at least 2 blocks, so we can decrypt + // at least one. + while (c->indata - c->indata_used < 2*BLOCKSIZE) { + int n = ffurl_read(c->hd, c->inbuffer + c->indata, + sizeof(c->inbuffer) - c->indata); + if (n <= 0) { + c->eof = 1; + break; + } + c->indata += n; + } + blocks = (c->indata - c->indata_used) / BLOCKSIZE; + if (!blocks) + return AVERROR_EOF; + if (!c->eof) + blocks--; + av_aes_crypt(c->aes, c->outbuffer, c->inbuffer + c->indata_used, blocks, + c->iv, 1); + c->outdata = BLOCKSIZE * blocks; + c->outptr = c->outbuffer; + c->indata_used += BLOCKSIZE * blocks; + if (c->indata_used >= sizeof(c->inbuffer)/2) { + memmove(c->inbuffer, c->inbuffer + c->indata_used, + c->indata - c->indata_used); + c->indata -= c->indata_used; + c->indata_used = 0; + } + if (c->eof) { + // Remove PKCS7 padding at the end + int padding = c->outbuffer[c->outdata - 1]; + c->outdata -= padding; + } + goto retry; +} + +static int crypto_close(URLContext *h) +{ + CryptoContext *c = h->priv_data; + if (c->hd) + ffurl_close(c->hd); + av_free(c->aes); + av_free(c->key); + av_free(c->iv); + return 0; +} + +URLProtocol ff_crypto_protocol = { + .name = "crypto", + .url_open = crypto_open, + .url_read = crypto_read, + .url_close = crypto_close, + .priv_data_size = sizeof(CryptoContext), + .priv_data_class = &crypto_class, + .flags = URL_PROTOCOL_FLAG_NESTED_SCHEME, +}; -- cgit v1.1 From 84465f2180308a3e998089517e76586563fd6162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Sun, 23 Jan 2011 23:42:18 +0200 Subject: applehttp: Handle AES-128 encrypted streams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should hopefully fix roundup issue 2586. This commit only implements it in the demuxer, not in the protocol handler. If desired, some of the code could be refactored to be shared by both implementations. Signed-off-by: Martin Storsjö --- libavformat/applehttp.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++-- libavformat/version.h | 2 +- 2 files changed, 106 insertions(+), 4 deletions(-) diff --git a/libavformat/applehttp.c b/libavformat/applehttp.c index 90b86a8..2e0e8a1 100644 --- a/libavformat/applehttp.c +++ b/libavformat/applehttp.c @@ -27,6 +27,8 @@ #define _XOPEN_SOURCE 600 #include "libavutil/avstring.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" #include "avformat.h" #include "internal.h" #include @@ -47,9 +49,17 @@ * one anonymous toplevel variant for this, to maintain the structure. */ +enum KeyType { + KEY_NONE, + KEY_AES_128, +}; + struct segment { int duration; char url[MAX_URL_SIZE]; + char key[MAX_URL_SIZE]; + enum KeyType key_type; + uint8_t iv[16]; }; /* @@ -77,6 +87,9 @@ struct variant { int needed, cur_needed; int cur_seq_no; int64_t last_load_time; + + char key_url[MAX_URL_SIZE]; + uint8_t key[16]; }; typedef struct AppleHTTPContext { @@ -160,10 +173,35 @@ static void handle_variant_args(struct variant_info *info, const char *key, } } +struct key_info { + char uri[MAX_URL_SIZE]; + char method[10]; + char iv[35]; +}; + +static void handle_key_args(struct key_info *info, const char *key, + int key_len, char **dest, int *dest_len) +{ + if (!strncmp(key, "METHOD=", key_len)) { + *dest = info->method; + *dest_len = sizeof(info->method); + } else if (!strncmp(key, "URI=", key_len)) { + *dest = info->uri; + *dest_len = sizeof(info->uri); + } else if (!strncmp(key, "IV=", key_len)) { + *dest = info->iv; + *dest_len = sizeof(info->iv); + } +} + static int parse_playlist(AppleHTTPContext *c, const char *url, struct variant *var, AVIOContext *in) { int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0; + enum KeyType key_type = KEY_NONE; + uint8_t iv[16] = ""; + int has_iv = 0; + char key[MAX_URL_SIZE]; char line[1024]; const char *ptr; int close_in = 0; @@ -192,6 +230,19 @@ static int parse_playlist(AppleHTTPContext *c, const char *url, ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, &info); bandwidth = atoi(info.bandwidth); + } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { + struct key_info info = {{0}}; + ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, + &info); + key_type = KEY_NONE; + has_iv = 0; + if (!strcmp(info.method, "AES-128")) + key_type = KEY_AES_128; + if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) { + ff_hex_to_data(iv, info.iv + 2); + has_iv = 1; + } + av_strlcpy(key, info.uri, sizeof(key)); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); @@ -242,6 +293,15 @@ static int parse_playlist(AppleHTTPContext *c, const char *url, goto fail; } seg->duration = duration; + seg->key_type = key_type; + if (has_iv) { + memcpy(seg->iv, iv, sizeof(iv)); + } else { + int seq = var->start_seq_no + var->n_segments; + memset(seg->iv, 0, sizeof(seg->iv)); + AV_WB32(seg->iv + 12, seq); + } + ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); ff_make_absolute_url(seg->url, sizeof(seg->url), url, line); dynarray_add(&var->segments, &var->n_segments, seg); is_segment = 0; @@ -257,6 +317,50 @@ fail: return ret; } +static int open_input(struct variant *var) +{ + struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no]; + if (seg->key_type == KEY_NONE) { + return ffurl_open(&var->input, seg->url, AVIO_FLAG_READ); + } else if (seg->key_type == KEY_AES_128) { + char iv[33], key[33], url[MAX_URL_SIZE]; + int ret; + if (strcmp(seg->key, var->key_url)) { + URLContext *uc; + if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ) == 0) { + if (ffurl_read_complete(uc, var->key, sizeof(var->key)) + != sizeof(var->key)) { + av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", + seg->key); + } + ffurl_close(uc); + } else { + av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n", + seg->key); + } + av_strlcpy(var->key_url, seg->key, sizeof(var->key_url)); + } + ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0); + ff_data_to_hex(key, var->key, sizeof(var->key), 0); + iv[32] = key[32] = '\0'; + if (strstr(seg->url, "://")) + snprintf(url, sizeof(url), "crypto+%s", seg->url); + else + snprintf(url, sizeof(url), "crypto:%s", seg->url); + if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ)) < 0) + return ret; + av_set_string3(var->input->priv_data, "key", key, 0, NULL); + av_set_string3(var->input->priv_data, "iv", iv, 0, NULL); + if ((ret = ffurl_connect(var->input)) < 0) { + ffurl_close(var->input); + var->input = NULL; + return ret; + } + return 0; + } + return AVERROR(ENOSYS); +} + static int read_data(void *opaque, uint8_t *buf, int buf_size) { struct variant *v = opaque; @@ -291,9 +395,7 @@ reload: goto reload; } - ret = ffurl_open(&v->input, - v->segments[v->cur_seq_no - v->start_seq_no]->url, - AVIO_FLAG_READ); + ret = open_input(v); if (ret < 0) return ret; } diff --git a/libavformat/version.h b/libavformat/version.h index 04c5d73..9041f92 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -25,7 +25,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 53 #define LIBAVFORMAT_VERSION_MINOR 0 -#define LIBAVFORMAT_VERSION_MICRO 1 +#define LIBAVFORMAT_VERSION_MICRO 2 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ -- cgit v1.1 From 6ffd7eddb832a21f51661038620ef655640ee83f Mon Sep 17 00:00:00 2001 From: Carl Eugen Hoyos Date: Fri, 22 Apr 2011 19:24:17 +0200 Subject: doc: FLV muxing is supported. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- doc/general.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/general.texi b/doc/general.texi index edd5e60..303159e 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -96,7 +96,7 @@ library: @tab Only embedded audio is decoded. @item FLI/FLC/FLX animation @tab @tab X @tab .fli/.flc files -@item Flash Video (FLV) @tab @tab X +@item Flash Video (FLV) @tab X @tab X @tab Macromedia Flash video files @item framecrc testing format @tab X @tab @item FunCom ISS @tab @tab X -- cgit v1.1 From 15919ee48f507a4ca17147e7247f5cb68f752c2c Mon Sep 17 00:00:00 2001 From: Jason Garrett-Glaser Date: Fri, 22 Apr 2011 17:59:55 -0400 Subject: bswap: use native types for av_bwap16(). This prevents a call to bytestream_get_be16() using a movzwl both before and after the ror instruction, which is obviously inefficient. Arm uses the same trick also. Sintel decoding goes from (avg+SD) 9.856 +/- 0.003 to 9.797 +/- 0.003 sec. Signed-off-by: Ronald S. Bultje --- libavutil/x86/bswap.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavutil/x86/bswap.h b/libavutil/x86/bswap.h index 28e3fec..b60d9cc 100644 --- a/libavutil/x86/bswap.h +++ b/libavutil/x86/bswap.h @@ -29,9 +29,9 @@ #include "libavutil/attributes.h" #define av_bswap16 av_bswap16 -static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +static av_always_inline av_const unsigned av_bswap16(unsigned x) { - __asm__("rorw $8, %0" : "+r"(x)); + __asm__("rorw $8, %w0" : "+r"(x)); return x; } -- cgit v1.1 From 3583d7cffe5173cc02c5476451800efdc767ce15 Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Wed, 20 Apr 2011 17:25:47 +0000 Subject: Fix mov debug (u)int64_t format strings. --- libavformat/mov.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index 76dc8a1..65fcf19 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -588,7 +588,7 @@ static int mov_read_moov(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) { c->fragment.moof_offset = avio_tell(pb) - 8; - av_dlog(c->fc, "moof offset %llx\n", c->fragment.moof_offset); + av_dlog(c->fc, "moof offset %"PRIx64"\n", c->fragment.moof_offset); return mov_read_default(c, pb, atom); } @@ -2367,7 +2367,7 @@ static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) av_log(s, AV_LOG_ERROR, "moov atom not found\n"); return -1; } - av_dlog(mov->fc, "on_parse_exit_offset=%lld\n", avio_tell(pb)); + av_dlog(mov->fc, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); if (pb->seekable && mov->chapter_track > 0) mov_read_chapters(s); @@ -2416,7 +2416,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 || s->pb->eof_reached) return AVERROR_EOF; - av_dlog(s, "read fragments, offset 0x%llx\n", avio_tell(s->pb)); + av_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb)); goto retry; } sc = st->priv_data; -- cgit v1.1 From 785c4418289e5aace9823823a8d19974e40d4b64 Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Wed, 20 Apr 2011 17:47:28 +0000 Subject: Add some debug log messages to AAC extradata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Wed, Apr 20, 2011 at 11:39 AM, Justin Ruggles wrote: > On 04/20/2011 02:26 PM, Alex Converse wrote: > >> --- >>  libavcodec/aacdec.c |   10 +++++++++- >>  1 files changed, 9 insertions(+), 1 deletions(-) >> >> >> >> 0002-Add-some-Debug-log-messages-to-AAC-extradata.patch >> >> >> diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c >> index c9761a1..3ec274f 100644 >> --- a/libavcodec/aacdec.c >> +++ b/libavcodec/aacdec.c >> @@ -79,7 +79,6 @@ >>             Parametric Stereo. >>   */ >> >> - >>  #include "avcodec.h" >>  #include "internal.h" >>  #include "get_bits.h" > > > stray whitespace change > oops, fixed >From 94e8d0eea77480630f84368c97646cabc0f50628 Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Wed, 20 Apr 2011 11:23:34 -0700 Subject: [PATCH] Add some debug log messages to AAC extradata MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------1" This is a multi-part message in MIME format. --------------1 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- libavcodec/aacdec.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c index 3160c66..0c6312f 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aacdec.c @@ -463,6 +463,11 @@ static int decode_audio_specific_config(AACContext *ac, GetBitContext gb; int i; + av_dlog(avctx, "extradata size %d\n", avctx->extradata_size); + for (i = 0; i < avctx->extradata_size; i++) + av_dlog(avctx, "%02x ", avctx->extradata[i]); + av_dlog(avctx, "\n"); + init_get_bits(&gb, data, data_size * 8); if ((i = ff_mpeg4audio_get_config(m4ac, data, data_size)) < 0) @@ -489,6 +494,10 @@ static int decode_audio_specific_config(AACContext *ac, return -1; } + av_dlog(avctx, "AOT %d chan config %d sampling index %d (%d) SBR %d PS %d\n", + m4ac->object_type, m4ac->chan_config, m4ac->sampling_index, + m4ac->sample_rate, m4ac->sbr, m4ac->ps); + return get_bits_count(&gb); } -- cgit v1.1 From cfc2a0cf848e71fcec0861a73b26c2c96a201357 Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Thu, 21 Apr 2011 18:39:04 +0000 Subject: Remove RDFT dependency from AAC decoder. $subj >From 557176d961c70604c2a96d81aff4bd6faa670d8a Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Thu, 21 Apr 2011 12:11:42 -0700 Subject: [PATCH] Remove RDFT dependency from AAC decoder. MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------1" This is a multi-part message in MIME format. --------------1 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit It was used for an old implementation of the SBR filterbank. ./configure --disable-everything --disable-ffplay --enable-decoder=aac works. --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index dd44ba4..c01c551 100755 --- a/configure +++ b/configure @@ -1237,7 +1237,7 @@ mdct_select="fft" rdft_select="fft" # decoders / encoders / hardware accelerators -aac_decoder_select="mdct rdft sinewin" +aac_decoder_select="mdct sinewin" aac_encoder_select="mdct sinewin" aac_latm_decoder_select="aac_decoder aac_latm_parser" ac3_decoder_select="mdct ac3dsp ac3_parser" -- cgit v1.1 From 230c1a90754860719b017a9ea4627dc81f67ff6e Mon Sep 17 00:00:00 2001 From: Nathan Caldwell Date: Wed, 5 Jan 2011 01:32:16 -0700 Subject: aacenc: Finish 3GPP psymodel analysis for non mid/side cases. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is still are still a few sections missing relating to TNS (not present) and mid/side (contains other bugs). Overall this improves quality, and vastly improves rate-control. Signed-off-by: Martin Storsjö --- libavcodec/aacenc.c | 4 +- libavcodec/aacpsy.c | 305 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 303 insertions(+), 6 deletions(-) diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index d4b6112..4ec76d0 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -606,8 +606,10 @@ static int aac_encode_frame(AVCodecContext *avctx, } frame_bits = put_bits_count(&s->pb); - if (frame_bits <= 6144 * avctx->channels - 3) + if (frame_bits <= 6144 * avctx->channels - 3) { + s->psy.bitres.bits = frame_bits / avctx->channels; break; + } s->lambda *= avctx->bit_rate * 1024.0f / avctx->sample_rate / frame_bits; diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c index 4250a5d..98be176 100644 --- a/libavcodec/aacpsy.c +++ b/libavcodec/aacpsy.c @@ -30,7 +30,6 @@ /*********************************** * TODOs: - * thresholds linearization after their modifications for attaining given bitrate * try other bitrate controlling mechanism (maybe use ratecontrol.c?) * control quality for quality-based output **********************************/ @@ -41,10 +40,51 @@ */ #define PSY_3GPP_THR_SPREAD_HI 1.5f // spreading factor for low-to-hi threshold spreading (15 dB/Bark) #define PSY_3GPP_THR_SPREAD_LOW 3.0f // spreading factor for hi-to-low threshold spreading (30 dB/Bark) +/* spreading factor for low-to-hi energy spreading, long block, > 22kbps/channel (20dB/Bark) */ +#define PSY_3GPP_EN_SPREAD_HI_L1 2.0f +/* spreading factor for low-to-hi energy spreading, long block, <= 22kbps/channel (15dB/Bark) */ +#define PSY_3GPP_EN_SPREAD_HI_L2 1.5f +/* spreading factor for low-to-hi energy spreading, short block (15 dB/Bark) */ +#define PSY_3GPP_EN_SPREAD_HI_S 1.5f +/* spreading factor for hi-to-low energy spreading, long block (30dB/Bark) */ +#define PSY_3GPP_EN_SPREAD_LOW_L 3.0f +/* spreading factor for hi-to-low energy spreading, short block (20dB/Bark) */ +#define PSY_3GPP_EN_SPREAD_LOW_S 2.0f #define PSY_3GPP_RPEMIN 0.01f #define PSY_3GPP_RPELEV 2.0f +#define PSY_3GPP_C1 3.0f /* log2(8) */ +#define PSY_3GPP_C2 1.3219281f /* log2(2.5) */ +#define PSY_3GPP_C3 0.55935729f /* 1 - C2 / C1 */ + +#define PSY_SNR_1DB 7.9432821e-1f /* -1dB */ +#define PSY_SNR_25DB 3.1622776e-3f /* -25dB */ + +#define PSY_3GPP_SAVE_SLOPE_L -0.46666667f +#define PSY_3GPP_SAVE_SLOPE_S -0.36363637f +#define PSY_3GPP_SAVE_ADD_L -0.84285712f +#define PSY_3GPP_SAVE_ADD_S -0.75f +#define PSY_3GPP_SPEND_SLOPE_L 0.66666669f +#define PSY_3GPP_SPEND_SLOPE_S 0.81818181f +#define PSY_3GPP_SPEND_ADD_L -0.35f +#define PSY_3GPP_SPEND_ADD_S -0.26111111f +#define PSY_3GPP_CLIP_LO_L 0.2f +#define PSY_3GPP_CLIP_LO_S 0.2f +#define PSY_3GPP_CLIP_HI_L 0.95f +#define PSY_3GPP_CLIP_HI_S 0.75f + +#define PSY_3GPP_AH_THR_LONG 0.5f +#define PSY_3GPP_AH_THR_SHORT 0.63f + +enum { + PSY_3GPP_AH_NONE, + PSY_3GPP_AH_INACTIVE, + PSY_3GPP_AH_ACTIVE +}; + +#define PSY_3GPP_BITS_TO_PE(bits) ((bits) * 1.18f) + /* LAME psy model constants */ #define PSY_LAME_FIR_LEN 21 ///< LAME psy model FIR order #define AAC_BLOCK_SIZE_LONG 1024 ///< long block size @@ -63,6 +103,12 @@ typedef struct AacPsyBand{ float energy; ///< band energy float thr; ///< energy threshold float thr_quiet; ///< threshold in quiet + float nz_lines; ///< number of non-zero spectral lines + float active_lines; ///< number of active spectral lines + float pe; ///< perceptual entropy + float pe_const; ///< constant part of the PE calculation + float norm_fac; ///< normalization factor for linearization + int avoid_holes; ///< hole avoidance flag }AacPsyBand; /** @@ -97,6 +143,15 @@ typedef struct AacPsyCoeffs{ * 3GPP TS26.403-inspired psychoacoustic model specific data */ typedef struct AacPsyContext{ + int chan_bitrate; ///< bitrate per channel + int frame_bits; ///< average bits per frame + int fill_level; ///< bit reservoir fill level + struct { + float min; ///< minimum allowed PE for bit factor calculation + float max; ///< maximum allowed PE for bit factor calculation + float previous; ///< allowed PE of the previous frame + float correction; ///< PE correction factor + } pe; AacPsyCoeffs psy_coef[2][64]; AacPsyChannel *ch; }AacPsyContext; @@ -235,16 +290,33 @@ static av_cold int psy_3gpp_init(FFPsyContext *ctx) { AacPsyContext *pctx; float bark; int i, j, g, start; - float prev, minscale, minath; + float prev, minscale, minath, minsnr, pe_min; + const int chan_bitrate = ctx->avctx->bit_rate / ctx->avctx->channels; + const int bandwidth = ctx->avctx->cutoff ? ctx->avctx->cutoff : ctx->avctx->sample_rate / 2; + const float num_bark = calc_bark((float)bandwidth); ctx->model_priv_data = av_mallocz(sizeof(AacPsyContext)); pctx = (AacPsyContext*) ctx->model_priv_data; + pctx->chan_bitrate = chan_bitrate; + pctx->frame_bits = chan_bitrate * AAC_BLOCK_SIZE_LONG / ctx->avctx->sample_rate; + pctx->pe.min = 8.0f * AAC_BLOCK_SIZE_LONG * bandwidth / (ctx->avctx->sample_rate * 2.0f); + pctx->pe.max = 12.0f * AAC_BLOCK_SIZE_LONG * bandwidth / (ctx->avctx->sample_rate * 2.0f); + ctx->bitres.size = 6144 - pctx->frame_bits; + ctx->bitres.size -= ctx->bitres.size % 8; + pctx->fill_level = ctx->bitres.size; minath = ath(3410, ATH_ADD); for (j = 0; j < 2; j++) { AacPsyCoeffs *coeffs = pctx->psy_coef[j]; const uint8_t *band_sizes = ctx->bands[j]; float line_to_frequency = ctx->avctx->sample_rate / (j ? 256.f : 2048.0f); + float avg_chan_bits = chan_bitrate / ctx->avctx->sample_rate * (j ? 128.0f : 1024.0f); + /* reference encoder uses 2.4% here instead of 60% like the spec says */ + float bark_pe = 0.024f * PSY_3GPP_BITS_TO_PE(avg_chan_bits) / num_bark; + float en_spread_low = j ? PSY_3GPP_EN_SPREAD_LOW_S : PSY_3GPP_EN_SPREAD_LOW_L; + /* High energy spreading for long blocks <= 22kbps/channel and short blocks are the same. */ + float en_spread_hi = (j || (chan_bitrate <= 22.0f)) ? PSY_3GPP_EN_SPREAD_HI_S : PSY_3GPP_EN_SPREAD_HI_L1; + i = 0; prev = 0.0; for (g = 0; g < ctx->num_bands[j]; g++) { @@ -258,6 +330,11 @@ static av_cold int psy_3gpp_init(FFPsyContext *ctx) { float bark_width = coeffs[g+1].barks - coeffs->barks; coeff->spread_low[0] = pow(10.0, -bark_width * PSY_3GPP_THR_SPREAD_LOW); coeff->spread_hi [0] = pow(10.0, -bark_width * PSY_3GPP_THR_SPREAD_HI); + coeff->spread_low[1] = pow(10.0, -bark_width * en_spread_low); + coeff->spread_hi [1] = pow(10.0, -bark_width * en_spread_hi); + pe_min = bark_pe * bark_width; + minsnr = pow(2.0f, pe_min / band_sizes[g]) - 1.5f; + coeff->min_snr = av_clipf(1.0f / minsnr, PSY_SNR_25DB, PSY_SNR_1DB); } start = 0; for (g = 0; g < ctx->num_bands[j]; g++) { @@ -385,6 +462,97 @@ static FFPsyWindowInfo psy_3gpp_window(FFPsyContext *ctx, return wi; } +/* 5.6.1.2 "Calculation of Bit Demand" */ +static int calc_bit_demand(AacPsyContext *ctx, float pe, int bits, int size, + int short_window) +{ + const float bitsave_slope = short_window ? PSY_3GPP_SAVE_SLOPE_S : PSY_3GPP_SAVE_SLOPE_L; + const float bitsave_add = short_window ? PSY_3GPP_SAVE_ADD_S : PSY_3GPP_SAVE_ADD_L; + const float bitspend_slope = short_window ? PSY_3GPP_SPEND_SLOPE_S : PSY_3GPP_SPEND_SLOPE_L; + const float bitspend_add = short_window ? PSY_3GPP_SPEND_ADD_S : PSY_3GPP_SPEND_ADD_L; + const float clip_low = short_window ? PSY_3GPP_CLIP_LO_S : PSY_3GPP_CLIP_LO_L; + const float clip_high = short_window ? PSY_3GPP_CLIP_HI_S : PSY_3GPP_CLIP_HI_L; + float clipped_pe, bit_save, bit_spend, bit_factor, fill_level; + + ctx->fill_level += ctx->frame_bits - bits; + ctx->fill_level = av_clip(ctx->fill_level, 0, size); + fill_level = av_clipf((float)ctx->fill_level / size, clip_low, clip_high); + clipped_pe = av_clipf(pe, ctx->pe.min, ctx->pe.max); + bit_save = (fill_level + bitsave_add) * bitsave_slope; + assert(bit_save <= 0.3f && bit_save >= -0.05000001f); + bit_spend = (fill_level + bitspend_add) * bitspend_slope; + assert(bit_spend <= 0.5f && bit_spend >= -0.1f); + /* The bit factor graph in the spec is obviously incorrect. + * bit_spend + ((bit_spend - bit_spend))... + * The reference encoder subtracts everything from 1, but also seems incorrect. + * 1 - bit_save + ((bit_spend + bit_save))... + * Hopefully below is correct. + */ + bit_factor = 1.0f - bit_save + ((bit_spend - bit_save) / (ctx->pe.max - ctx->pe.min)) * (clipped_pe - ctx->pe.min); + /* NOTE: The reference encoder attempts to center pe max/min around the current pe. */ + ctx->pe.max = FFMAX(pe, ctx->pe.max); + ctx->pe.min = FFMIN(pe, ctx->pe.min); + + return FFMIN(ctx->frame_bits * bit_factor, ctx->frame_bits + size - bits); +} + +static float calc_pe_3gpp(AacPsyBand *band) +{ + float pe, a; + + band->pe = 0.0f; + band->pe_const = 0.0f; + band->active_lines = 0.0f; + if (band->energy > band->thr) { + a = log2f(band->energy); + pe = a - log2f(band->thr); + band->active_lines = band->nz_lines; + if (pe < PSY_3GPP_C1) { + pe = pe * PSY_3GPP_C3 + PSY_3GPP_C2; + a = a * PSY_3GPP_C3 + PSY_3GPP_C2; + band->active_lines *= PSY_3GPP_C3; + } + band->pe = pe * band->nz_lines; + band->pe_const = a * band->nz_lines; + } + + return band->pe; +} + +static float calc_reduction_3gpp(float a, float desired_pe, float pe, + float active_lines) +{ + float thr_avg, reduction; + + thr_avg = powf(2.0f, (a - pe) / (4.0f * active_lines)); + reduction = powf(2.0f, (a - desired_pe) / (4.0f * active_lines)) - thr_avg; + + return FFMAX(reduction, 0.0f); +} + +static float calc_reduced_thr_3gpp(AacPsyBand *band, float min_snr, + float reduction) +{ + float thr = band->thr; + + if (band->energy > thr) { + thr = powf(thr, 0.25f) + reduction; + thr = powf(thr, 4.0f); + + /* This deviates from the 3GPP spec to match the reference encoder. + * It performs min(thr_reduced, max(thr, energy/min_snr)) only for bands + * that have hole avoidance on (active or inactive). It always reduces the + * threshold of bands with hole avoidance off. + */ + if (thr > band->energy * min_snr && band->avoid_holes != PSY_3GPP_AH_NONE) { + thr = FFMAX(band->thr, band->energy * min_snr); + band->avoid_holes = PSY_3GPP_AH_ACTIVE; + } + } + + return thr; +} + /** * Calculate band thresholds as suggested in 3GPP TS26.403 */ @@ -395,18 +563,27 @@ static void psy_3gpp_analyze(FFPsyContext *ctx, int channel, AacPsyChannel *pch = &pctx->ch[channel]; int start = 0; int i, w, g; + float desired_bits, desired_pe, delta_pe, reduction, spread_en[128] = {0}; + float a = 0.0f, active_lines = 0.0f, norm_fac = 0.0f; + float pe = pctx->chan_bitrate > 32000 ? 0.0f : FFMAX(50.0f, 100.0f - pctx->chan_bitrate * 100.0f / 32000.0f); const int num_bands = ctx->num_bands[wi->num_windows == 8]; const uint8_t *band_sizes = ctx->bands[wi->num_windows == 8]; AacPsyCoeffs *coeffs = pctx->psy_coef[wi->num_windows == 8]; + const float avoid_hole_thr = wi->num_windows == 8 ? PSY_3GPP_AH_THR_SHORT : PSY_3GPP_AH_THR_LONG; //calculate energies, initial thresholds and related values - 5.4.2 "Threshold Calculation" for (w = 0; w < wi->num_windows*16; w += 16) { for (g = 0; g < num_bands; g++) { AacPsyBand *band = &pch->band[w+g]; + float form_factor = 0.0f; band->energy = 0.0f; - for (i = 0; i < band_sizes[g]; i++) + for (i = 0; i < band_sizes[g]; i++) { band->energy += coefs[start+i] * coefs[start+i]; + form_factor += sqrtf(fabs(coefs[start+i])); + } band->thr = band->energy * 0.001258925f; + band->nz_lines = form_factor / powf(band->energy / band_sizes[g], 0.25f); + start += band_sizes[g]; } } @@ -414,10 +591,15 @@ static void psy_3gpp_analyze(FFPsyContext *ctx, int channel, for (w = 0; w < wi->num_windows*16; w += 16) { AacPsyBand *bands = &pch->band[w]; //5.4.2.3 "Spreading" & 5.4.3 "Spreaded Energy Calculation" - for (g = 1; g < num_bands; g++) + spread_en[0] = bands[0].energy; + for (g = 1; g < num_bands; g++) { bands[g].thr = FFMAX(bands[g].thr, bands[g-1].thr * coeffs[g].spread_hi[0]); - for (g = num_bands - 2; g >= 0; g--) + spread_en[w+g] = FFMAX(bands[g].energy, spread_en[w+g-1] * coeffs[g].spread_hi[1]); + } + for (g = num_bands - 2; g >= 0; g--) { bands[g].thr = FFMAX(bands[g].thr, bands[g+1].thr * coeffs[g].spread_low[0]); + spread_en[w+g] = FFMAX(spread_en[w+g], spread_en[w+g+1] * coeffs[g].spread_low[1]); + } //5.4.2.4 "Threshold in quiet" for (g = 0; g < num_bands; g++) { AacPsyBand *band = &bands[g]; @@ -426,6 +608,119 @@ static void psy_3gpp_analyze(FFPsyContext *ctx, int channel, if (!(wi->window_type[0] == LONG_STOP_SEQUENCE || (wi->window_type[1] == LONG_START_SEQUENCE && !w))) band->thr = FFMAX(PSY_3GPP_RPEMIN*band->thr, FFMIN(band->thr, PSY_3GPP_RPELEV*pch->prev_band[w+g].thr_quiet)); + + /* 5.6.1.3.1 "Prepatory steps of the perceptual entropy calculation" */ + pe += calc_pe_3gpp(band); + a += band->pe_const; + active_lines += band->active_lines; + + /* 5.6.1.3.3 "Selection of the bands for avoidance of holes" */ + if (spread_en[w+g] * avoid_hole_thr > band->energy || coeffs[g].min_snr > 1.0f) + band->avoid_holes = PSY_3GPP_AH_NONE; + else + band->avoid_holes = PSY_3GPP_AH_INACTIVE; + } + } + + /* 5.6.1.3.2 "Calculation of the desired perceptual entropy" */ + ctx->pe[channel] = pe; + desired_bits = calc_bit_demand(pctx, pe, ctx->bitres.bits, ctx->bitres.size, wi->num_windows == 8); + desired_pe = PSY_3GPP_BITS_TO_PE(desired_bits); + /* NOTE: PE correction is kept simple. During initial testing it had very + * little effect on the final bitrate. Probably a good idea to come + * back and do more testing later. + */ + if (ctx->bitres.bits > 0) + desired_pe *= av_clipf(pctx->pe.previous / PSY_3GPP_BITS_TO_PE(ctx->bitres.bits), + 0.85f, 1.15f); + pctx->pe.previous = PSY_3GPP_BITS_TO_PE(desired_bits); + + if (desired_pe < pe) { + /* 5.6.1.3.4 "First Estimation of the reduction value" */ + for (w = 0; w < wi->num_windows*16; w += 16) { + reduction = calc_reduction_3gpp(a, desired_pe, pe, active_lines); + pe = 0.0f; + a = 0.0f; + active_lines = 0.0f; + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &pch->band[w+g]; + + band->thr = calc_reduced_thr_3gpp(band, coeffs[g].min_snr, reduction); + /* recalculate PE */ + pe += calc_pe_3gpp(band); + a += band->pe_const; + active_lines += band->active_lines; + } + } + + /* 5.6.1.3.5 "Second Estimation of the reduction value" */ + for (i = 0; i < 2; i++) { + float pe_no_ah = 0.0f, desired_pe_no_ah; + active_lines = a = 0.0f; + for (w = 0; w < wi->num_windows*16; w += 16) { + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &pch->band[w+g]; + + if (band->avoid_holes != PSY_3GPP_AH_ACTIVE) { + pe_no_ah += band->pe; + a += band->pe_const; + active_lines += band->active_lines; + } + } + } + desired_pe_no_ah = FFMAX(desired_pe - (pe - pe_no_ah), 0.0f); + if (active_lines > 0.0f) + reduction += calc_reduction_3gpp(a, desired_pe_no_ah, pe_no_ah, active_lines); + + pe = 0.0f; + for (w = 0; w < wi->num_windows*16; w += 16) { + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &pch->band[w+g]; + + if (active_lines > 0.0f) + band->thr = calc_reduced_thr_3gpp(band, coeffs[g].min_snr, reduction); + pe += calc_pe_3gpp(band); + band->norm_fac = band->active_lines / band->thr; + norm_fac += band->norm_fac; + } + } + delta_pe = desired_pe - pe; + if (fabs(delta_pe) > 0.05f * desired_pe) + break; + } + + if (pe < 1.15f * desired_pe) { + /* 6.6.1.3.6 "Final threshold modification by linearization" */ + norm_fac = 1.0f / norm_fac; + for (w = 0; w < wi->num_windows*16; w += 16) { + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &pch->band[w+g]; + + if (band->active_lines > 0.5f) { + float delta_sfb_pe = band->norm_fac * norm_fac * delta_pe; + float thr = band->thr; + + thr *= powf(2.0f, delta_sfb_pe / band->active_lines); + if (thr > coeffs[g].min_snr * band->energy && band->avoid_holes == PSY_3GPP_AH_INACTIVE) + thr = FFMAX(band->thr, coeffs[g].min_snr * band->energy); + band->thr = thr; + } + } + } + } else { + /* 5.6.1.3.7 "Further perceptual entropy reduction" */ + g = num_bands; + while (pe > desired_pe && g--) { + for (w = 0; w < wi->num_windows*16; w+= 16) { + AacPsyBand *band = &pch->band[w+g]; + if (band->avoid_holes != PSY_3GPP_AH_NONE && coeffs[g].min_snr < PSY_SNR_1DB) { + coeffs[g].min_snr = PSY_SNR_1DB; + band->thr = band->energy * PSY_SNR_1DB; + pe += band->active_lines * 1.5f - band->pe; + } + } + } + /* TODO: allow more holes (unused without mid/side) */ } } -- cgit v1.1 From 62582a696b4dbe3d644ea19aa6739bbe592482da Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Sat, 23 Apr 2011 02:02:42 +0200 Subject: cook: Fix small typo in av_log_ask_for_sample message. --- libavcodec/cook.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/cook.c b/libavcodec/cook.c index 282ca10..f1df240 100644 --- a/libavcodec/cook.c +++ b/libavcodec/cook.c @@ -1136,7 +1136,7 @@ static av_cold int cook_decode_init(AVCodecContext *avctx) switch (q->subpacket[s].cookversion) { case MONO: if (q->nb_channels != 1) { - av_log_ask_for_sample(avctx, "Container channels != 1.!\n"); + av_log_ask_for_sample(avctx, "Container channels != 1.\n"); return -1; } av_log(avctx,AV_LOG_DEBUG,"MONO\n"); -- cgit v1.1 From f50d9377252431114e89514cf528825936efcbd9 Mon Sep 17 00:00:00 2001 From: Nathan Caldwell Date: Tue, 5 Apr 2011 01:05:24 -0600 Subject: aacenc: Fix whitespace after last commit. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- libavcodec/aacpsy.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c index 98be176..5aea1fa 100644 --- a/libavcodec/aacpsy.c +++ b/libavcodec/aacpsy.c @@ -100,9 +100,9 @@ enum { * information for single band used by 3GPP TS26.403-inspired psychoacoustic model */ typedef struct AacPsyBand{ - float energy; ///< band energy - float thr; ///< energy threshold - float thr_quiet; ///< threshold in quiet + float energy; ///< band energy + float thr; ///< energy threshold + float thr_quiet; ///< threshold in quiet float nz_lines; ///< number of non-zero spectral lines float active_lines; ///< number of active spectral lines float pe; ///< perceptual entropy @@ -566,43 +566,46 @@ static void psy_3gpp_analyze(FFPsyContext *ctx, int channel, float desired_bits, desired_pe, delta_pe, reduction, spread_en[128] = {0}; float a = 0.0f, active_lines = 0.0f, norm_fac = 0.0f; float pe = pctx->chan_bitrate > 32000 ? 0.0f : FFMAX(50.0f, 100.0f - pctx->chan_bitrate * 100.0f / 32000.0f); - const int num_bands = ctx->num_bands[wi->num_windows == 8]; - const uint8_t *band_sizes = ctx->bands[wi->num_windows == 8]; - AacPsyCoeffs *coeffs = pctx->psy_coef[wi->num_windows == 8]; + const int num_bands = ctx->num_bands[wi->num_windows == 8]; + const uint8_t *band_sizes = ctx->bands[wi->num_windows == 8]; + AacPsyCoeffs *coeffs = pctx->psy_coef[wi->num_windows == 8]; const float avoid_hole_thr = wi->num_windows == 8 ? PSY_3GPP_AH_THR_SHORT : PSY_3GPP_AH_THR_LONG; //calculate energies, initial thresholds and related values - 5.4.2 "Threshold Calculation" for (w = 0; w < wi->num_windows*16; w += 16) { for (g = 0; g < num_bands; g++) { AacPsyBand *band = &pch->band[w+g]; + float form_factor = 0.0f; band->energy = 0.0f; for (i = 0; i < band_sizes[g]; i++) { band->energy += coefs[start+i] * coefs[start+i]; form_factor += sqrtf(fabs(coefs[start+i])); } - band->thr = band->energy * 0.001258925f; + band->thr = band->energy * 0.001258925f; band->nz_lines = form_factor / powf(band->energy / band_sizes[g], 0.25f); - start += band_sizes[g]; + start += band_sizes[g]; } } //modify thresholds and energies - spread, threshold in quiet, pre-echo control for (w = 0; w < wi->num_windows*16; w += 16) { AacPsyBand *bands = &pch->band[w]; + //5.4.2.3 "Spreading" & 5.4.3 "Spreaded Energy Calculation" spread_en[0] = bands[0].energy; for (g = 1; g < num_bands; g++) { - bands[g].thr = FFMAX(bands[g].thr, bands[g-1].thr * coeffs[g].spread_hi[0]); + bands[g].thr = FFMAX(bands[g].thr, bands[g-1].thr * coeffs[g].spread_hi[0]); spread_en[w+g] = FFMAX(bands[g].energy, spread_en[w+g-1] * coeffs[g].spread_hi[1]); } for (g = num_bands - 2; g >= 0; g--) { - bands[g].thr = FFMAX(bands[g].thr, bands[g+1].thr * coeffs[g].spread_low[0]); + bands[g].thr = FFMAX(bands[g].thr, bands[g+1].thr * coeffs[g].spread_low[0]); spread_en[w+g] = FFMAX(spread_en[w+g], spread_en[w+g+1] * coeffs[g].spread_low[1]); } //5.4.2.4 "Threshold in quiet" for (g = 0; g < num_bands; g++) { AacPsyBand *band = &bands[g]; + band->thr_quiet = band->thr = FFMAX(band->thr, coeffs[g].ath); //5.4.2.5 "Pre-echo control" if (!(wi->window_type[0] == LONG_STOP_SEQUENCE || (wi->window_type[1] == LONG_START_SEQUENCE && !w))) -- cgit v1.1 From 046f3cb78903cd04846c49345b473244f095f1a5 Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Sun, 17 Apr 2011 19:44:33 +0200 Subject: vorbis: Rename decoder/encoder files to follow general file naming scheme. --- libavcodec/Makefile | 4 +- libavcodec/twinvq.c | 2 +- libavcodec/vorbis_dec.c | 1668 ----------------------------------------------- libavcodec/vorbis_enc.c | 1116 ------------------------------- libavcodec/vorbisdec.c | 1668 +++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/vorbisenc.c | 1116 +++++++++++++++++++++++++++++++ 6 files changed, 2787 insertions(+), 2787 deletions(-) delete mode 100644 libavcodec/vorbis_dec.c delete mode 100644 libavcodec/vorbis_enc.c create mode 100644 libavcodec/vorbisdec.c create mode 100644 libavcodec/vorbisenc.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 784226f..fad435d 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -386,9 +386,9 @@ OBJS-$(CONFIG_VCR1_ENCODER) += vcr1.o OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdav.o OBJS-$(CONFIG_VMDVIDEO_DECODER) += vmdav.o OBJS-$(CONFIG_VMNC_DECODER) += vmnc.o -OBJS-$(CONFIG_VORBIS_DECODER) += vorbis_dec.o vorbis.o \ +OBJS-$(CONFIG_VORBIS_DECODER) += vorbisdec.o vorbis.o \ vorbis_data.o xiph.o -OBJS-$(CONFIG_VORBIS_ENCODER) += vorbis_enc.o vorbis.o \ +OBJS-$(CONFIG_VORBIS_ENCODER) += vorbisenc.o vorbis.o \ vorbis_data.o OBJS-$(CONFIG_VP3_DECODER) += vp3.o vp3dsp.o OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o vp56dsp.o \ diff --git a/libavcodec/twinvq.c b/libavcodec/twinvq.c index e1a8dc4..985f71c 100644 --- a/libavcodec/twinvq.c +++ b/libavcodec/twinvq.c @@ -234,7 +234,7 @@ static void memset_float(float *buf, float val, int size) * be a multiple of four. * @return the LPC value * - * @todo reuse code from vorbis_dec.c: vorbis_floor0_decode + * @todo reuse code from Vorbis decoder: vorbis_floor0_decode */ static float eval_lpc_spectrum(const float *lsp, float cos_val, int order) { diff --git a/libavcodec/vorbis_dec.c b/libavcodec/vorbis_dec.c deleted file mode 100644 index 5fa7be1..0000000 --- a/libavcodec/vorbis_dec.c +++ /dev/null @@ -1,1668 +0,0 @@ -/** - * @file - * Vorbis I decoder - * @author Denes Balatoni ( dbalatoni programozo hu ) - * - * This file is part of Libav. - * - * Libav 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. - * - * Libav 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 Libav; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#undef V_DEBUG -//#define V_DEBUG -//#define AV_DEBUG(...) av_log(NULL, AV_LOG_INFO, __VA_ARGS__) - -#include - -#define ALT_BITSTREAM_READER_LE -#include "avcodec.h" -#include "get_bits.h" -#include "dsputil.h" -#include "fft.h" -#include "fmtconvert.h" - -#include "vorbis.h" -#include "xiph.h" - -#define V_NB_BITS 8 -#define V_NB_BITS2 11 -#define V_MAX_VLCS (1 << 16) -#define V_MAX_PARTITIONS (1 << 20) - -#ifndef V_DEBUG -#define AV_DEBUG(...) -#endif - -#undef NDEBUG -#include - -typedef struct { - uint_fast8_t dimensions; - uint_fast8_t lookup_type; - uint_fast8_t maxdepth; - VLC vlc; - float *codevectors; - unsigned int nb_bits; -} vorbis_codebook; - -typedef union vorbis_floor_u vorbis_floor_data; -typedef struct vorbis_floor0_s vorbis_floor0; -typedef struct vorbis_floor1_s vorbis_floor1; -struct vorbis_context_s; -typedef -int (* vorbis_floor_decode_func) - (struct vorbis_context_s *, vorbis_floor_data *, float *); -typedef struct { - uint_fast8_t floor_type; - vorbis_floor_decode_func decode; - union vorbis_floor_u { - struct vorbis_floor0_s { - uint_fast8_t order; - uint_fast16_t rate; - uint_fast16_t bark_map_size; - int_fast32_t *map[2]; - uint_fast32_t map_size[2]; - uint_fast8_t amplitude_bits; - uint_fast8_t amplitude_offset; - uint_fast8_t num_books; - uint_fast8_t *book_list; - float *lsp; - } t0; - struct vorbis_floor1_s { - uint_fast8_t partitions; - uint8_t partition_class[32]; - uint_fast8_t class_dimensions[16]; - uint_fast8_t class_subclasses[16]; - uint_fast8_t class_masterbook[16]; - int_fast16_t subclass_books[16][8]; - uint_fast8_t multiplier; - uint_fast16_t x_list_dim; - vorbis_floor1_entry *list; - } t1; - } data; -} vorbis_floor; - -typedef struct { - uint_fast16_t type; - uint_fast32_t begin; - uint_fast32_t end; - unsigned partition_size; - uint_fast8_t classifications; - uint_fast8_t classbook; - int_fast16_t books[64][8]; - uint_fast8_t maxpass; - uint_fast16_t ptns_to_read; - uint8_t *classifs; -} vorbis_residue; - -typedef struct { - uint_fast8_t submaps; - uint_fast16_t coupling_steps; - uint_fast8_t *magnitude; - uint_fast8_t *angle; - uint_fast8_t *mux; - uint_fast8_t submap_floor[16]; - uint_fast8_t submap_residue[16]; -} vorbis_mapping; - -typedef struct { - uint_fast8_t blockflag; - uint_fast16_t windowtype; - uint_fast16_t transformtype; - uint_fast8_t mapping; -} vorbis_mode; - -typedef struct vorbis_context_s { - AVCodecContext *avccontext; - GetBitContext gb; - DSPContext dsp; - FmtConvertContext fmt_conv; - - FFTContext mdct[2]; - uint_fast8_t first_frame; - uint_fast32_t version; - uint_fast8_t audio_channels; - uint_fast32_t audio_samplerate; - uint_fast32_t bitrate_maximum; - uint_fast32_t bitrate_nominal; - uint_fast32_t bitrate_minimum; - uint_fast32_t blocksize[2]; - const float *win[2]; - uint_fast16_t codebook_count; - vorbis_codebook *codebooks; - uint_fast8_t floor_count; - vorbis_floor *floors; - uint_fast8_t residue_count; - vorbis_residue *residues; - uint_fast8_t mapping_count; - vorbis_mapping *mappings; - uint_fast8_t mode_count; - vorbis_mode *modes; - uint_fast8_t mode_number; // mode number for the current packet - uint_fast8_t previous_window; - float *channel_residues; - float *channel_floors; - float *saved; - float scale_bias; // for float->int conversion -} vorbis_context; - -/* Helper functions */ - -#define BARK(x) \ - (13.1f * atan(0.00074f * (x)) + 2.24f * atan(1.85e-8f * (x) * (x)) + 1e-4f * (x)) - -static const char idx_err_str[] = "Index value %d out of range (0 - %d) for %s at %s:%i\n"; -#define VALIDATE_INDEX(idx, limit) \ - if (idx >= limit) {\ - av_log(vc->avccontext, AV_LOG_ERROR,\ - idx_err_str,\ - (int)(idx), (int)(limit - 1), #idx, __FILE__, __LINE__);\ - return -1;\ - } -#define GET_VALIDATED_INDEX(idx, bits, limit) \ - {\ - idx = get_bits(gb, bits);\ - VALIDATE_INDEX(idx, limit)\ - } - -static float vorbisfloat2float(uint_fast32_t val) -{ - double mant = val & 0x1fffff; - long exp = (val & 0x7fe00000L) >> 21; - if (val & 0x80000000) - mant = -mant; - return ldexp(mant, exp - 20 - 768); -} - - -// Free all allocated memory ----------------------------------------- - -static void vorbis_free(vorbis_context *vc) -{ - int_fast16_t i; - - av_freep(&vc->channel_residues); - av_freep(&vc->channel_floors); - av_freep(&vc->saved); - - for (i = 0; i < vc->residue_count; i++) - av_free(vc->residues[i].classifs); - av_freep(&vc->residues); - av_freep(&vc->modes); - - ff_mdct_end(&vc->mdct[0]); - ff_mdct_end(&vc->mdct[1]); - - for (i = 0; i < vc->codebook_count; ++i) { - av_free(vc->codebooks[i].codevectors); - free_vlc(&vc->codebooks[i].vlc); - } - av_freep(&vc->codebooks); - - for (i = 0; i < vc->floor_count; ++i) { - if (vc->floors[i].floor_type == 0) { - av_free(vc->floors[i].data.t0.map[0]); - av_free(vc->floors[i].data.t0.map[1]); - av_free(vc->floors[i].data.t0.book_list); - av_free(vc->floors[i].data.t0.lsp); - } else { - av_free(vc->floors[i].data.t1.list); - } - } - av_freep(&vc->floors); - - for (i = 0; i < vc->mapping_count; ++i) { - av_free(vc->mappings[i].magnitude); - av_free(vc->mappings[i].angle); - av_free(vc->mappings[i].mux); - } - av_freep(&vc->mappings); -} - -// Parse setup header ------------------------------------------------- - -// Process codebooks part - -static int vorbis_parse_setup_hdr_codebooks(vorbis_context *vc) -{ - uint_fast16_t cb; - uint8_t *tmp_vlc_bits; - uint32_t *tmp_vlc_codes; - GetBitContext *gb = &vc->gb; - uint_fast16_t *codebook_multiplicands; - - vc->codebook_count = get_bits(gb, 8) + 1; - - AV_DEBUG(" Codebooks: %d \n", vc->codebook_count); - - vc->codebooks = av_mallocz(vc->codebook_count * sizeof(vorbis_codebook)); - tmp_vlc_bits = av_mallocz(V_MAX_VLCS * sizeof(uint8_t)); - tmp_vlc_codes = av_mallocz(V_MAX_VLCS * sizeof(uint32_t)); - codebook_multiplicands = av_malloc(V_MAX_VLCS * sizeof(*codebook_multiplicands)); - - for (cb = 0; cb < vc->codebook_count; ++cb) { - vorbis_codebook *codebook_setup = &vc->codebooks[cb]; - uint_fast8_t ordered; - uint_fast32_t t, used_entries = 0; - uint_fast32_t entries; - - AV_DEBUG(" %d. Codebook \n", cb); - - if (get_bits(gb, 24) != 0x564342) { - av_log(vc->avccontext, AV_LOG_ERROR, " %"PRIdFAST16". Codebook setup data corrupt. \n", cb); - goto error; - } - - codebook_setup->dimensions=get_bits(gb, 16); - if (codebook_setup->dimensions > 16 || codebook_setup->dimensions == 0) { - av_log(vc->avccontext, AV_LOG_ERROR, " %"PRIdFAST16". Codebook's dimension is invalid (%d). \n", cb, codebook_setup->dimensions); - goto error; - } - entries = get_bits(gb, 24); - if (entries > V_MAX_VLCS) { - av_log(vc->avccontext, AV_LOG_ERROR, " %"PRIdFAST16". Codebook has too many entries (%"PRIdFAST32"). \n", cb, entries); - goto error; - } - - ordered = get_bits1(gb); - - AV_DEBUG(" codebook_dimensions %d, codebook_entries %d \n", codebook_setup->dimensions, entries); - - if (!ordered) { - uint_fast16_t ce; - uint_fast8_t flag; - uint_fast8_t sparse = get_bits1(gb); - - AV_DEBUG(" not ordered \n"); - - if (sparse) { - AV_DEBUG(" sparse \n"); - - used_entries = 0; - for (ce = 0; ce < entries; ++ce) { - flag = get_bits1(gb); - if (flag) { - tmp_vlc_bits[ce] = get_bits(gb, 5) + 1; - ++used_entries; - } else - tmp_vlc_bits[ce] = 0; - } - } else { - AV_DEBUG(" not sparse \n"); - - used_entries = entries; - for (ce = 0; ce < entries; ++ce) - tmp_vlc_bits[ce] = get_bits(gb, 5) + 1; - } - } else { - uint_fast16_t current_entry = 0; - uint_fast8_t current_length = get_bits(gb, 5)+1; - - AV_DEBUG(" ordered, current length: %d \n", current_length); //FIXME - - used_entries = entries; - for (; current_entry < used_entries && current_length <= 32; ++current_length) { - uint_fast16_t i, number; - - AV_DEBUG(" number bits: %d ", ilog(entries - current_entry)); - - number = get_bits(gb, ilog(entries - current_entry)); - - AV_DEBUG(" number: %d \n", number); - - for (i = current_entry; i < number+current_entry; ++i) - if (i < used_entries) - tmp_vlc_bits[i] = current_length; - - current_entry+=number; - } - if (current_entry>used_entries) { - av_log(vc->avccontext, AV_LOG_ERROR, " More codelengths than codes in codebook. \n"); - goto error; - } - } - - codebook_setup->lookup_type = get_bits(gb, 4); - - AV_DEBUG(" lookup type: %d : %s \n", codebook_setup->lookup_type, codebook_setup->lookup_type ? "vq" : "no lookup"); - -// If the codebook is used for (inverse) VQ, calculate codevectors. - - if (codebook_setup->lookup_type == 1) { - uint_fast16_t i, j, k; - uint_fast16_t codebook_lookup_values = ff_vorbis_nth_root(entries, codebook_setup->dimensions); - - float codebook_minimum_value = vorbisfloat2float(get_bits_long(gb, 32)); - float codebook_delta_value = vorbisfloat2float(get_bits_long(gb, 32)); - uint_fast8_t codebook_value_bits = get_bits(gb, 4)+1; - uint_fast8_t codebook_sequence_p = get_bits1(gb); - - AV_DEBUG(" We expect %d numbers for building the codevectors. \n", codebook_lookup_values); - AV_DEBUG(" delta %f minmum %f \n", codebook_delta_value, codebook_minimum_value); - - for (i = 0; i < codebook_lookup_values; ++i) { - codebook_multiplicands[i] = get_bits(gb, codebook_value_bits); - - AV_DEBUG(" multiplicands*delta+minmum : %e \n", (float)codebook_multiplicands[i]*codebook_delta_value+codebook_minimum_value); - AV_DEBUG(" multiplicand %d \n", codebook_multiplicands[i]); - } - -// Weed out unused vlcs and build codevector vector - codebook_setup->codevectors = used_entries ? av_mallocz(used_entries*codebook_setup->dimensions * sizeof(float)) : NULL; - for (j = 0, i = 0; i < entries; ++i) { - uint_fast8_t dim = codebook_setup->dimensions; - - if (tmp_vlc_bits[i]) { - float last = 0.0; - uint_fast32_t lookup_offset = i; - -#ifdef V_DEBUG - av_log(vc->avccontext, AV_LOG_INFO, "Lookup offset %d ,", i); -#endif - - for (k = 0; k < dim; ++k) { - uint_fast32_t multiplicand_offset = lookup_offset % codebook_lookup_values; - codebook_setup->codevectors[j * dim + k] = codebook_multiplicands[multiplicand_offset] * codebook_delta_value + codebook_minimum_value + last; - if (codebook_sequence_p) - last = codebook_setup->codevectors[j * dim + k]; - lookup_offset/=codebook_lookup_values; - } - tmp_vlc_bits[j] = tmp_vlc_bits[i]; - -#ifdef V_DEBUG - av_log(vc->avccontext, AV_LOG_INFO, "real lookup offset %d, vector: ", j); - for (k = 0; k < dim; ++k) - av_log(vc->avccontext, AV_LOG_INFO, " %f ", codebook_setup->codevectors[j * dim + k]); - av_log(vc->avccontext, AV_LOG_INFO, "\n"); -#endif - - ++j; - } - } - if (j != used_entries) { - av_log(vc->avccontext, AV_LOG_ERROR, "Bug in codevector vector building code. \n"); - goto error; - } - entries = used_entries; - } else if (codebook_setup->lookup_type >= 2) { - av_log(vc->avccontext, AV_LOG_ERROR, "Codebook lookup type not supported. \n"); - goto error; - } - -// Initialize VLC table - if (ff_vorbis_len2vlc(tmp_vlc_bits, tmp_vlc_codes, entries)) { - av_log(vc->avccontext, AV_LOG_ERROR, " Invalid code lengths while generating vlcs. \n"); - goto error; - } - codebook_setup->maxdepth = 0; - for (t = 0; t < entries; ++t) - if (tmp_vlc_bits[t] >= codebook_setup->maxdepth) - codebook_setup->maxdepth = tmp_vlc_bits[t]; - - if (codebook_setup->maxdepth > 3 * V_NB_BITS) - codebook_setup->nb_bits = V_NB_BITS2; - else - codebook_setup->nb_bits = V_NB_BITS; - - codebook_setup->maxdepth = (codebook_setup->maxdepth+codebook_setup->nb_bits - 1) / codebook_setup->nb_bits; - - if (init_vlc(&codebook_setup->vlc, codebook_setup->nb_bits, entries, tmp_vlc_bits, sizeof(*tmp_vlc_bits), sizeof(*tmp_vlc_bits), tmp_vlc_codes, sizeof(*tmp_vlc_codes), sizeof(*tmp_vlc_codes), INIT_VLC_LE)) { - av_log(vc->avccontext, AV_LOG_ERROR, " Error generating vlc tables. \n"); - goto error; - } - } - - av_free(tmp_vlc_bits); - av_free(tmp_vlc_codes); - av_free(codebook_multiplicands); - return 0; - -// Error: -error: - av_free(tmp_vlc_bits); - av_free(tmp_vlc_codes); - av_free(codebook_multiplicands); - return -1; -} - -// Process time domain transforms part (unused in Vorbis I) - -static int vorbis_parse_setup_hdr_tdtransforms(vorbis_context *vc) -{ - GetBitContext *gb = &vc->gb; - uint_fast8_t i; - uint_fast8_t vorbis_time_count = get_bits(gb, 6) + 1; - - for (i = 0; i < vorbis_time_count; ++i) { - uint_fast16_t vorbis_tdtransform = get_bits(gb, 16); - - AV_DEBUG(" Vorbis time domain transform %d: %d \n", vorbis_time_count, vorbis_tdtransform); - - if (vorbis_tdtransform) { - av_log(vc->avccontext, AV_LOG_ERROR, "Vorbis time domain transform data nonzero. \n"); - return -1; - } - } - return 0; -} - -// Process floors part - -static int vorbis_floor0_decode(vorbis_context *vc, - vorbis_floor_data *vfu, float *vec); -static void create_map(vorbis_context *vc, uint_fast8_t floor_number); -static int vorbis_floor1_decode(vorbis_context *vc, - vorbis_floor_data *vfu, float *vec); -static int vorbis_parse_setup_hdr_floors(vorbis_context *vc) -{ - GetBitContext *gb = &vc->gb; - int i,j,k; - - vc->floor_count = get_bits(gb, 6) + 1; - - vc->floors = av_mallocz(vc->floor_count * sizeof(vorbis_floor)); - - for (i = 0; i < vc->floor_count; ++i) { - vorbis_floor *floor_setup = &vc->floors[i]; - - floor_setup->floor_type = get_bits(gb, 16); - - AV_DEBUG(" %d. floor type %d \n", i, floor_setup->floor_type); - - if (floor_setup->floor_type == 1) { - int maximum_class = -1; - uint_fast8_t rangebits; - uint_fast32_t rangemax; - uint_fast16_t floor1_values = 2; - - floor_setup->decode = vorbis_floor1_decode; - - floor_setup->data.t1.partitions = get_bits(gb, 5); - - AV_DEBUG(" %d.floor: %d partitions \n", i, floor_setup->data.t1.partitions); - - for (j = 0; j < floor_setup->data.t1.partitions; ++j) { - floor_setup->data.t1.partition_class[j] = get_bits(gb, 4); - if (floor_setup->data.t1.partition_class[j] > maximum_class) - maximum_class = floor_setup->data.t1.partition_class[j]; - - AV_DEBUG(" %d. floor %d partition class %d \n", i, j, floor_setup->data.t1.partition_class[j]); - - } - - AV_DEBUG(" maximum class %d \n", maximum_class); - - for (j = 0; j <= maximum_class; ++j) { - floor_setup->data.t1.class_dimensions[j] = get_bits(gb, 3) + 1; - floor_setup->data.t1.class_subclasses[j] = get_bits(gb, 2); - - AV_DEBUG(" %d floor %d class dim: %d subclasses %d \n", i, j, floor_setup->data.t1.class_dimensions[j], floor_setup->data.t1.class_subclasses[j]); - - if (floor_setup->data.t1.class_subclasses[j]) { - GET_VALIDATED_INDEX(floor_setup->data.t1.class_masterbook[j], 8, vc->codebook_count) - - AV_DEBUG(" masterbook: %d \n", floor_setup->data.t1.class_masterbook[j]); - } - - for (k = 0; k < (1 << floor_setup->data.t1.class_subclasses[j]); ++k) { - int16_t bits = get_bits(gb, 8) - 1; - if (bits != -1) - VALIDATE_INDEX(bits, vc->codebook_count) - floor_setup->data.t1.subclass_books[j][k] = bits; - - AV_DEBUG(" book %d. : %d \n", k, floor_setup->data.t1.subclass_books[j][k]); - } - } - - floor_setup->data.t1.multiplier = get_bits(gb, 2) + 1; - floor_setup->data.t1.x_list_dim = 2; - - for (j = 0; j < floor_setup->data.t1.partitions; ++j) - floor_setup->data.t1.x_list_dim+=floor_setup->data.t1.class_dimensions[floor_setup->data.t1.partition_class[j]]; - - floor_setup->data.t1.list = av_mallocz(floor_setup->data.t1.x_list_dim * sizeof(vorbis_floor1_entry)); - - - rangebits = get_bits(gb, 4); - rangemax = (1 << rangebits); - if (rangemax > vc->blocksize[1] / 2) { - av_log(vc->avccontext, AV_LOG_ERROR, - "Floor value is too large for blocksize: %d (%d)\n", - rangemax, vc->blocksize[1] / 2); - return -1; - } - floor_setup->data.t1.list[0].x = 0; - floor_setup->data.t1.list[1].x = rangemax; - - for (j = 0; j < floor_setup->data.t1.partitions; ++j) { - for (k = 0; k < floor_setup->data.t1.class_dimensions[floor_setup->data.t1.partition_class[j]]; ++k, ++floor1_values) { - floor_setup->data.t1.list[floor1_values].x = get_bits(gb, rangebits); - - AV_DEBUG(" %d. floor1 Y coord. %d \n", floor1_values, floor_setup->data.t1.list[floor1_values].x); - } - } - -// Precalculate order of x coordinates - needed for decode - ff_vorbis_ready_floor1_list(floor_setup->data.t1.list, floor_setup->data.t1.x_list_dim); - } else if (floor_setup->floor_type == 0) { - uint_fast8_t max_codebook_dim = 0; - - floor_setup->decode = vorbis_floor0_decode; - - floor_setup->data.t0.order = get_bits(gb, 8); - floor_setup->data.t0.rate = get_bits(gb, 16); - floor_setup->data.t0.bark_map_size = get_bits(gb, 16); - floor_setup->data.t0.amplitude_bits = get_bits(gb, 6); - /* zero would result in a div by zero later * - * 2^0 - 1 == 0 */ - if (floor_setup->data.t0.amplitude_bits == 0) { - av_log(vc->avccontext, AV_LOG_ERROR, - "Floor 0 amplitude bits is 0.\n"); - return -1; - } - floor_setup->data.t0.amplitude_offset = get_bits(gb, 8); - floor_setup->data.t0.num_books = get_bits(gb, 4) + 1; - - /* allocate mem for booklist */ - floor_setup->data.t0.book_list = - av_malloc(floor_setup->data.t0.num_books); - if (!floor_setup->data.t0.book_list) - return -1; - /* read book indexes */ - { - int idx; - uint_fast8_t book_idx; - for (idx = 0; idx < floor_setup->data.t0.num_books; ++idx) { - GET_VALIDATED_INDEX(book_idx, 8, vc->codebook_count) - floor_setup->data.t0.book_list[idx] = book_idx; - if (vc->codebooks[book_idx].dimensions > max_codebook_dim) - max_codebook_dim = vc->codebooks[book_idx].dimensions; - } - } - - create_map(vc, i); - - /* codebook dim is for padding if codebook dim doesn't * - * divide order+1 then we need to read more data */ - floor_setup->data.t0.lsp = - av_malloc((floor_setup->data.t0.order+1 + max_codebook_dim) - * sizeof(float)); - if (!floor_setup->data.t0.lsp) - return -1; - -#ifdef V_DEBUG /* debug output parsed headers */ - AV_DEBUG("floor0 order: %u\n", floor_setup->data.t0.order); - AV_DEBUG("floor0 rate: %u\n", floor_setup->data.t0.rate); - AV_DEBUG("floor0 bark map size: %u\n", - floor_setup->data.t0.bark_map_size); - AV_DEBUG("floor0 amplitude bits: %u\n", - floor_setup->data.t0.amplitude_bits); - AV_DEBUG("floor0 amplitude offset: %u\n", - floor_setup->data.t0.amplitude_offset); - AV_DEBUG("floor0 number of books: %u\n", - floor_setup->data.t0.num_books); - AV_DEBUG("floor0 book list pointer: %p\n", - floor_setup->data.t0.book_list); - { - int idx; - for (idx = 0; idx < floor_setup->data.t0.num_books; ++idx) { - AV_DEBUG(" Book %d: %u\n", - idx+1, - floor_setup->data.t0.book_list[idx]); - } - } -#endif - } else { - av_log(vc->avccontext, AV_LOG_ERROR, "Invalid floor type!\n"); - return -1; - } - } - return 0; -} - -// Process residues part - -static int vorbis_parse_setup_hdr_residues(vorbis_context *vc) -{ - GetBitContext *gb = &vc->gb; - uint_fast8_t i, j, k; - - vc->residue_count = get_bits(gb, 6)+1; - vc->residues = av_mallocz(vc->residue_count * sizeof(vorbis_residue)); - - AV_DEBUG(" There are %d residues. \n", vc->residue_count); - - for (i = 0; i < vc->residue_count; ++i) { - vorbis_residue *res_setup = &vc->residues[i]; - uint_fast8_t cascade[64]; - uint_fast8_t high_bits; - uint_fast8_t low_bits; - - res_setup->type = get_bits(gb, 16); - - AV_DEBUG(" %d. residue type %d \n", i, res_setup->type); - - res_setup->begin = get_bits(gb, 24); - res_setup->end = get_bits(gb, 24); - res_setup->partition_size = get_bits(gb, 24) + 1; - /* Validations to prevent a buffer overflow later. */ - if (res_setup->begin>res_setup->end || - res_setup->end > vc->avccontext->channels * vc->blocksize[1] / 2 || - (res_setup->end-res_setup->begin) / res_setup->partition_size > V_MAX_PARTITIONS) { - av_log(vc->avccontext, AV_LOG_ERROR, "partition out of bounds: type, begin, end, size, blocksize: %"PRIdFAST16", %"PRIdFAST32", %"PRIdFAST32", %u, %"PRIdFAST32"\n", res_setup->type, res_setup->begin, res_setup->end, res_setup->partition_size, vc->blocksize[1] / 2); - return -1; - } - - res_setup->classifications = get_bits(gb, 6) + 1; - GET_VALIDATED_INDEX(res_setup->classbook, 8, vc->codebook_count) - - res_setup->ptns_to_read = - (res_setup->end - res_setup->begin) / res_setup->partition_size; - res_setup->classifs = av_malloc(res_setup->ptns_to_read * - vc->audio_channels * - sizeof(*res_setup->classifs)); - if (!res_setup->classifs) - return AVERROR(ENOMEM); - - AV_DEBUG(" begin %d end %d part.size %d classif.s %d classbook %d \n", res_setup->begin, res_setup->end, res_setup->partition_size, - res_setup->classifications, res_setup->classbook); - - for (j = 0; j < res_setup->classifications; ++j) { - high_bits = 0; - low_bits = get_bits(gb, 3); - if (get_bits1(gb)) - high_bits = get_bits(gb, 5); - cascade[j] = (high_bits << 3) + low_bits; - - AV_DEBUG(" %d class casscade depth: %d \n", j, ilog(cascade[j])); - } - - res_setup->maxpass = 0; - for (j = 0; j < res_setup->classifications; ++j) { - for (k = 0; k < 8; ++k) { - if (cascade[j]&(1 << k)) { - GET_VALIDATED_INDEX(res_setup->books[j][k], 8, vc->codebook_count) - - AV_DEBUG(" %d class casscade depth %d book: %d \n", j, k, res_setup->books[j][k]); - - if (k>res_setup->maxpass) - res_setup->maxpass = k; - } else { - res_setup->books[j][k] = -1; - } - } - } - } - return 0; -} - -// Process mappings part - -static int vorbis_parse_setup_hdr_mappings(vorbis_context *vc) -{ - GetBitContext *gb = &vc->gb; - uint_fast8_t i, j; - - vc->mapping_count = get_bits(gb, 6)+1; - vc->mappings = av_mallocz(vc->mapping_count * sizeof(vorbis_mapping)); - - AV_DEBUG(" There are %d mappings. \n", vc->mapping_count); - - for (i = 0; i < vc->mapping_count; ++i) { - vorbis_mapping *mapping_setup = &vc->mappings[i]; - - if (get_bits(gb, 16)) { - av_log(vc->avccontext, AV_LOG_ERROR, "Other mappings than type 0 are not compliant with the Vorbis I specification. \n"); - return -1; - } - if (get_bits1(gb)) { - mapping_setup->submaps = get_bits(gb, 4) + 1; - } else { - mapping_setup->submaps = 1; - } - - if (get_bits1(gb)) { - mapping_setup->coupling_steps = get_bits(gb, 8) + 1; - mapping_setup->magnitude = av_mallocz(mapping_setup->coupling_steps * sizeof(uint_fast8_t)); - mapping_setup->angle = av_mallocz(mapping_setup->coupling_steps * sizeof(uint_fast8_t)); - for (j = 0; j < mapping_setup->coupling_steps; ++j) { - GET_VALIDATED_INDEX(mapping_setup->magnitude[j], ilog(vc->audio_channels - 1), vc->audio_channels) - GET_VALIDATED_INDEX(mapping_setup->angle[j], ilog(vc->audio_channels - 1), vc->audio_channels) - } - } else { - mapping_setup->coupling_steps = 0; - } - - AV_DEBUG(" %d mapping coupling steps: %d \n", i, mapping_setup->coupling_steps); - - if (get_bits(gb, 2)) { - av_log(vc->avccontext, AV_LOG_ERROR, "%d. mapping setup data invalid. \n", i); - return -1; // following spec. - } - - if (mapping_setup->submaps>1) { - mapping_setup->mux = av_mallocz(vc->audio_channels * sizeof(uint_fast8_t)); - for (j = 0; j < vc->audio_channels; ++j) - mapping_setup->mux[j] = get_bits(gb, 4); - } - - for (j = 0; j < mapping_setup->submaps; ++j) { - skip_bits(gb, 8); // FIXME check? - GET_VALIDATED_INDEX(mapping_setup->submap_floor[j], 8, vc->floor_count) - GET_VALIDATED_INDEX(mapping_setup->submap_residue[j], 8, vc->residue_count) - - AV_DEBUG(" %d mapping %d submap : floor %d, residue %d \n", i, j, mapping_setup->submap_floor[j], mapping_setup->submap_residue[j]); - } - } - return 0; -} - -// Process modes part - -static void create_map(vorbis_context *vc, uint_fast8_t floor_number) -{ - vorbis_floor *floors = vc->floors; - vorbis_floor0 *vf; - int idx; - int_fast8_t blockflag; - int_fast32_t *map; - int_fast32_t n; //TODO: could theoretically be smaller? - - for (blockflag = 0; blockflag < 2; ++blockflag) { - n = vc->blocksize[blockflag] / 2; - floors[floor_number].data.t0.map[blockflag] = - av_malloc((n+1) * sizeof(int_fast32_t)); // n + sentinel - - map = floors[floor_number].data.t0.map[blockflag]; - vf = &floors[floor_number].data.t0; - - for (idx = 0; idx < n; ++idx) { - map[idx] = floor(BARK((vf->rate * idx) / (2.0f * n)) * - ((vf->bark_map_size) / - BARK(vf->rate / 2.0f))); - if (vf->bark_map_size-1 < map[idx]) - map[idx] = vf->bark_map_size - 1; - } - map[n] = -1; - vf->map_size[blockflag] = n; - } - -#ifdef V_DEBUG - for (idx = 0; idx <= n; ++idx) { - AV_DEBUG("floor0 map: map at pos %d is %d\n", - idx, map[idx]); - } -#endif -} - -static int vorbis_parse_setup_hdr_modes(vorbis_context *vc) -{ - GetBitContext *gb = &vc->gb; - uint_fast8_t i; - - vc->mode_count = get_bits(gb, 6) + 1; - vc->modes = av_mallocz(vc->mode_count * sizeof(vorbis_mode)); - - AV_DEBUG(" There are %d modes.\n", vc->mode_count); - - for (i = 0; i < vc->mode_count; ++i) { - vorbis_mode *mode_setup = &vc->modes[i]; - - mode_setup->blockflag = get_bits1(gb); - mode_setup->windowtype = get_bits(gb, 16); //FIXME check - mode_setup->transformtype = get_bits(gb, 16); //FIXME check - GET_VALIDATED_INDEX(mode_setup->mapping, 8, vc->mapping_count); - - AV_DEBUG(" %d mode: blockflag %d, windowtype %d, transformtype %d, mapping %d \n", i, mode_setup->blockflag, mode_setup->windowtype, mode_setup->transformtype, mode_setup->mapping); - } - return 0; -} - -// Process the whole setup header using the functions above - -static int vorbis_parse_setup_hdr(vorbis_context *vc) -{ - GetBitContext *gb = &vc->gb; - - if ((get_bits(gb, 8) != 'v') || (get_bits(gb, 8) != 'o') || - (get_bits(gb, 8) != 'r') || (get_bits(gb, 8) != 'b') || - (get_bits(gb, 8) != 'i') || (get_bits(gb, 8) != 's')) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (no vorbis signature). \n"); - return -1; - } - - if (vorbis_parse_setup_hdr_codebooks(vc)) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (codebooks). \n"); - return -2; - } - if (vorbis_parse_setup_hdr_tdtransforms(vc)) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (time domain transforms). \n"); - return -3; - } - if (vorbis_parse_setup_hdr_floors(vc)) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (floors). \n"); - return -4; - } - if (vorbis_parse_setup_hdr_residues(vc)) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (residues). \n"); - return -5; - } - if (vorbis_parse_setup_hdr_mappings(vc)) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (mappings). \n"); - return -6; - } - if (vorbis_parse_setup_hdr_modes(vc)) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (modes). \n"); - return -7; - } - if (!get_bits1(gb)) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (framing flag). \n"); - return -8; // framing flag bit unset error - } - - return 0; -} - -// Process the identification header - -static int vorbis_parse_id_hdr(vorbis_context *vc) -{ - GetBitContext *gb = &vc->gb; - uint_fast8_t bl0, bl1; - - if ((get_bits(gb, 8) != 'v') || (get_bits(gb, 8) != 'o') || - (get_bits(gb, 8) != 'r') || (get_bits(gb, 8) != 'b') || - (get_bits(gb, 8) != 'i') || (get_bits(gb, 8) != 's')) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis id header packet corrupt (no vorbis signature). \n"); - return -1; - } - - vc->version = get_bits_long(gb, 32); //FIXME check 0 - vc->audio_channels = get_bits(gb, 8); - if (vc->audio_channels <= 0) { - av_log(vc->avccontext, AV_LOG_ERROR, "Invalid number of channels\n"); - return -1; - } - vc->audio_samplerate = get_bits_long(gb, 32); - if (vc->audio_samplerate <= 0) { - av_log(vc->avccontext, AV_LOG_ERROR, "Invalid samplerate\n"); - return -1; - } - vc->bitrate_maximum = get_bits_long(gb, 32); - vc->bitrate_nominal = get_bits_long(gb, 32); - vc->bitrate_minimum = get_bits_long(gb, 32); - bl0 = get_bits(gb, 4); - bl1 = get_bits(gb, 4); - vc->blocksize[0] = (1 << bl0); - vc->blocksize[1] = (1 << bl1); - if (bl0 > 13 || bl0 < 6 || bl1 > 13 || bl1 < 6 || bl1 < bl0) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis id header packet corrupt (illegal blocksize). \n"); - return -3; - } - // output format int16 - if (vc->blocksize[1] / 2 * vc->audio_channels * 2 > AVCODEC_MAX_AUDIO_FRAME_SIZE) { - av_log(vc->avccontext, AV_LOG_ERROR, "Vorbis channel count makes " - "output packets too large.\n"); - return -4; - } - vc->win[0] = ff_vorbis_vwin[bl0 - 6]; - vc->win[1] = ff_vorbis_vwin[bl1 - 6]; - - if ((get_bits1(gb)) == 0) { - av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis id header packet corrupt (framing flag not set). \n"); - return -2; - } - - vc->channel_residues = av_malloc((vc->blocksize[1] / 2) * vc->audio_channels * sizeof(float)); - vc->channel_floors = av_malloc((vc->blocksize[1] / 2) * vc->audio_channels * sizeof(float)); - vc->saved = av_mallocz((vc->blocksize[1] / 4) * vc->audio_channels * sizeof(float)); - vc->previous_window = 0; - - ff_mdct_init(&vc->mdct[0], bl0, 1, -vc->scale_bias); - ff_mdct_init(&vc->mdct[1], bl1, 1, -vc->scale_bias); - - AV_DEBUG(" vorbis version %d \n audio_channels %d \n audio_samplerate %d \n bitrate_max %d \n bitrate_nom %d \n bitrate_min %d \n blk_0 %d blk_1 %d \n ", - vc->version, vc->audio_channels, vc->audio_samplerate, vc->bitrate_maximum, vc->bitrate_nominal, vc->bitrate_minimum, vc->blocksize[0], vc->blocksize[1]); - -/* - BLK = vc->blocksize[0]; - for (i = 0; i < BLK / 2; ++i) { - vc->win[0][i] = sin(0.5*3.14159265358*(sin(((float)i + 0.5) / (float)BLK*3.14159265358))*(sin(((float)i + 0.5) / (float)BLK*3.14159265358))); - } -*/ - - return 0; -} - -// Process the extradata using the functions above (identification header, setup header) - -static av_cold int vorbis_decode_init(AVCodecContext *avccontext) -{ - vorbis_context *vc = avccontext->priv_data ; - uint8_t *headers = avccontext->extradata; - int headers_len = avccontext->extradata_size; - uint8_t *header_start[3]; - int header_len[3]; - GetBitContext *gb = &(vc->gb); - int hdr_type; - - vc->avccontext = avccontext; - dsputil_init(&vc->dsp, avccontext); - ff_fmt_convert_init(&vc->fmt_conv, avccontext); - - vc->scale_bias = 32768.0f; - - if (!headers_len) { - av_log(avccontext, AV_LOG_ERROR, "Extradata missing.\n"); - return -1; - } - - if (ff_split_xiph_headers(headers, headers_len, 30, header_start, header_len) < 0) { - av_log(avccontext, AV_LOG_ERROR, "Extradata corrupt.\n"); - return -1; - } - - init_get_bits(gb, header_start[0], header_len[0]*8); - hdr_type = get_bits(gb, 8); - if (hdr_type != 1) { - av_log(avccontext, AV_LOG_ERROR, "First header is not the id header.\n"); - return -1; - } - if (vorbis_parse_id_hdr(vc)) { - av_log(avccontext, AV_LOG_ERROR, "Id header corrupt.\n"); - vorbis_free(vc); - return -1; - } - - init_get_bits(gb, header_start[2], header_len[2]*8); - hdr_type = get_bits(gb, 8); - if (hdr_type != 5) { - av_log(avccontext, AV_LOG_ERROR, "Third header is not the setup header.\n"); - vorbis_free(vc); - return -1; - } - if (vorbis_parse_setup_hdr(vc)) { - av_log(avccontext, AV_LOG_ERROR, "Setup header corrupt.\n"); - vorbis_free(vc); - return -1; - } - - if (vc->audio_channels > 8) - avccontext->channel_layout = 0; - else - avccontext->channel_layout = ff_vorbis_channel_layouts[vc->audio_channels - 1]; - - avccontext->channels = vc->audio_channels; - avccontext->sample_rate = vc->audio_samplerate; - avccontext->frame_size = FFMIN(vc->blocksize[0], vc->blocksize[1]) >> 2; - avccontext->sample_fmt = AV_SAMPLE_FMT_S16; - - return 0 ; -} - -// Decode audiopackets ------------------------------------------------- - -// Read and decode floor - -static int vorbis_floor0_decode(vorbis_context *vc, - vorbis_floor_data *vfu, float *vec) -{ - vorbis_floor0 *vf = &vfu->t0; - float *lsp = vf->lsp; - uint_fast32_t amplitude; - uint_fast32_t book_idx; - uint_fast8_t blockflag = vc->modes[vc->mode_number].blockflag; - - amplitude = get_bits(&vc->gb, vf->amplitude_bits); - if (amplitude > 0) { - float last = 0; - uint_fast16_t lsp_len = 0; - uint_fast16_t idx; - vorbis_codebook codebook; - - book_idx = get_bits(&vc->gb, ilog(vf->num_books)); - if (book_idx >= vf->num_books) { - av_log(vc->avccontext, AV_LOG_ERROR, - "floor0 dec: booknumber too high!\n"); - book_idx = 0; - } - AV_DEBUG("floor0 dec: booknumber: %u\n", book_idx); - codebook = vc->codebooks[vf->book_list[book_idx]]; - /* Invalid codebook! */ - if (!codebook.codevectors) - return -1; - - while (lsp_lenorder) { - int vec_off; - - AV_DEBUG("floor0 dec: book dimension: %d\n", codebook.dimensions); - AV_DEBUG("floor0 dec: maximum depth: %d\n", codebook.maxdepth); - /* read temp vector */ - vec_off = get_vlc2(&vc->gb, codebook.vlc.table, - codebook.nb_bits, codebook.maxdepth) - * codebook.dimensions; - AV_DEBUG("floor0 dec: vector offset: %d\n", vec_off); - /* copy each vector component and add last to it */ - for (idx = 0; idx < codebook.dimensions; ++idx) - lsp[lsp_len+idx] = codebook.codevectors[vec_off+idx] + last; - last = lsp[lsp_len+idx-1]; /* set last to last vector component */ - - lsp_len += codebook.dimensions; - } -#ifdef V_DEBUG - /* DEBUG: output lsp coeffs */ - { - int idx; - for (idx = 0; idx < lsp_len; ++idx) - AV_DEBUG("floor0 dec: coeff at %d is %f\n", idx, lsp[idx]); - } -#endif - - /* synthesize floor output vector */ - { - int i; - int order = vf->order; - float wstep = M_PI / vf->bark_map_size; - - for (i = 0; i < order; i++) - lsp[i] = 2.0f * cos(lsp[i]); - - AV_DEBUG("floor0 synth: map_size = %d; m = %d; wstep = %f\n", - vf->map_size, order, wstep); - - i = 0; - while (i < vf->map_size[blockflag]) { - int j, iter_cond = vf->map[blockflag][i]; - float p = 0.5f; - float q = 0.5f; - float two_cos_w = 2.0f * cos(wstep * iter_cond); // needed all times - - /* similar part for the q and p products */ - for (j = 0; j + 1 < order; j += 2) { - q *= lsp[j] - two_cos_w; - p *= lsp[j + 1] - two_cos_w; - } - if (j == order) { // even order - p *= p * (2.0f - two_cos_w); - q *= q * (2.0f + two_cos_w); - } else { // odd order - q *= two_cos_w-lsp[j]; // one more time for q - - /* final step and square */ - p *= p * (4.f - two_cos_w * two_cos_w); - q *= q; - } - - /* calculate linear floor value */ - q = exp((((amplitude*vf->amplitude_offset) / - (((1 << vf->amplitude_bits) - 1) * sqrt(p + q))) - - vf->amplitude_offset) * .11512925f); - - /* fill vector */ - do { - vec[i] = q; ++i; - } while (vf->map[blockflag][i] == iter_cond); - } - } - } else { - /* this channel is unused */ - return 1; - } - - AV_DEBUG(" Floor0 decoded\n"); - - return 0; -} - -static int vorbis_floor1_decode(vorbis_context *vc, - vorbis_floor_data *vfu, float *vec) -{ - vorbis_floor1 *vf = &vfu->t1; - GetBitContext *gb = &vc->gb; - uint_fast16_t range_v[4] = { 256, 128, 86, 64 }; - uint_fast16_t range = range_v[vf->multiplier-1]; - uint_fast16_t floor1_Y[258]; - uint_fast16_t floor1_Y_final[258]; - int floor1_flag[258]; - uint_fast8_t class_; - uint_fast8_t cdim; - uint_fast8_t cbits; - uint_fast8_t csub; - uint_fast8_t cval; - int_fast16_t book; - uint_fast16_t offset; - uint_fast16_t i,j; - int_fast16_t adx, ady, dy, off, predicted; - int_fast32_t err; - - - if (!get_bits1(gb)) // silence - return 1; - -// Read values (or differences) for the floor's points - - floor1_Y[0] = get_bits(gb, ilog(range - 1)); - floor1_Y[1] = get_bits(gb, ilog(range - 1)); - - AV_DEBUG("floor 0 Y %d floor 1 Y %d \n", floor1_Y[0], floor1_Y[1]); - - offset = 2; - for (i = 0; i < vf->partitions; ++i) { - class_ = vf->partition_class[i]; - cdim = vf->class_dimensions[class_]; - cbits = vf->class_subclasses[class_]; - csub = (1 << cbits) - 1; - cval = 0; - - AV_DEBUG("Cbits %d \n", cbits); - - if (cbits) // this reads all subclasses for this partition's class - cval = get_vlc2(gb, vc->codebooks[vf->class_masterbook[class_]].vlc.table, - vc->codebooks[vf->class_masterbook[class_]].nb_bits, 3); - - for (j = 0; j < cdim; ++j) { - book = vf->subclass_books[class_][cval & csub]; - - AV_DEBUG("book %d Cbits %d cval %d bits:%d \n", book, cbits, cval, get_bits_count(gb)); - - cval = cval >> cbits; - if (book > -1) { - floor1_Y[offset+j] = get_vlc2(gb, vc->codebooks[book].vlc.table, - vc->codebooks[book].nb_bits, 3); - } else { - floor1_Y[offset+j] = 0; - } - - AV_DEBUG(" floor(%d) = %d \n", vf->list[offset+j].x, floor1_Y[offset+j]); - } - offset+=cdim; - } - -// Amplitude calculation from the differences - - floor1_flag[0] = 1; - floor1_flag[1] = 1; - floor1_Y_final[0] = floor1_Y[0]; - floor1_Y_final[1] = floor1_Y[1]; - - for (i = 2; i < vf->x_list_dim; ++i) { - uint_fast16_t val, highroom, lowroom, room; - uint_fast16_t high_neigh_offs; - uint_fast16_t low_neigh_offs; - - low_neigh_offs = vf->list[i].low; - high_neigh_offs = vf->list[i].high; - dy = floor1_Y_final[high_neigh_offs] - floor1_Y_final[low_neigh_offs]; // render_point begin - adx = vf->list[high_neigh_offs].x - vf->list[low_neigh_offs].x; - ady = FFABS(dy); - err = ady * (vf->list[i].x - vf->list[low_neigh_offs].x); - off = err / adx; - if (dy < 0) { - predicted = floor1_Y_final[low_neigh_offs] - off; - } else { - predicted = floor1_Y_final[low_neigh_offs] + off; - } // render_point end - - val = floor1_Y[i]; - highroom = range-predicted; - lowroom = predicted; - if (highroom < lowroom) { - room = highroom * 2; - } else { - room = lowroom * 2; // SPEC mispelling - } - if (val) { - floor1_flag[low_neigh_offs] = 1; - floor1_flag[high_neigh_offs] = 1; - floor1_flag[i] = 1; - if (val >= room) { - if (highroom > lowroom) { - floor1_Y_final[i] = val - lowroom + predicted; - } else { - floor1_Y_final[i] = predicted - val + highroom - 1; - } - } else { - if (val & 1) { - floor1_Y_final[i] = predicted - (val + 1) / 2; - } else { - floor1_Y_final[i] = predicted + val / 2; - } - } - } else { - floor1_flag[i] = 0; - floor1_Y_final[i] = predicted; - } - - AV_DEBUG(" Decoded floor(%d) = %d / val %d \n", vf->list[i].x, floor1_Y_final[i], val); - } - -// Curve synth - connect the calculated dots and convert from dB scale FIXME optimize ? - - ff_vorbis_floor1_render_list(vf->list, vf->x_list_dim, floor1_Y_final, floor1_flag, vf->multiplier, vec, vf->list[1].x); - - AV_DEBUG(" Floor decoded\n"); - - return 0; -} - -// Read and decode residue - -static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, - vorbis_residue *vr, - uint_fast8_t ch, - uint_fast8_t *do_not_decode, - float *vec, - uint_fast16_t vlen, - int vr_type) -{ - GetBitContext *gb = &vc->gb; - uint_fast8_t c_p_c = vc->codebooks[vr->classbook].dimensions; - uint_fast16_t ptns_to_read = vr->ptns_to_read; - uint8_t *classifs = vr->classifs; - uint_fast8_t pass; - uint_fast8_t ch_used; - uint_fast8_t i,j,l; - uint_fast16_t k; - - if (vr_type == 2) { - for (j = 1; j < ch; ++j) - do_not_decode[0] &= do_not_decode[j]; // FIXME - clobbering input - if (do_not_decode[0]) - return 0; - ch_used = 1; - } else { - ch_used = ch; - } - - AV_DEBUG(" residue type 0/1/2 decode begin, ch: %d cpc %d \n", ch, c_p_c); - - for (pass = 0; pass <= vr->maxpass; ++pass) { // FIXME OPTIMIZE? - uint_fast16_t voffset; - uint_fast16_t partition_count; - uint_fast16_t j_times_ptns_to_read; - - voffset = vr->begin; - for (partition_count = 0; partition_count < ptns_to_read;) { // SPEC error - if (!pass) { - uint_fast32_t inverse_class = ff_inverse[vr->classifications]; - for (j_times_ptns_to_read = 0, j = 0; j < ch_used; ++j) { - if (!do_not_decode[j]) { - uint_fast32_t temp = get_vlc2(gb, vc->codebooks[vr->classbook].vlc.table, - vc->codebooks[vr->classbook].nb_bits, 3); - - AV_DEBUG("Classword: %d \n", temp); - - assert(vr->classifications > 1 && temp <= 65536); //needed for inverse[] - for (i = 0; i < c_p_c; ++i) { - uint_fast32_t temp2; - - temp2 = (((uint_fast64_t)temp) * inverse_class) >> 32; - if (partition_count + c_p_c - 1 - i < ptns_to_read) - classifs[j_times_ptns_to_read + partition_count + c_p_c - 1 - i] = temp - temp2 * vr->classifications; - temp = temp2; - } - } - j_times_ptns_to_read += ptns_to_read; - } - } - for (i = 0; (i < c_p_c) && (partition_count < ptns_to_read); ++i) { - for (j_times_ptns_to_read = 0, j = 0; j < ch_used; ++j) { - uint_fast16_t voffs; - - if (!do_not_decode[j]) { - uint_fast8_t vqclass = classifs[j_times_ptns_to_read+partition_count]; - int_fast16_t vqbook = vr->books[vqclass][pass]; - - if (vqbook >= 0 && vc->codebooks[vqbook].codevectors) { - uint_fast16_t coffs; - unsigned dim = vc->codebooks[vqbook].dimensions; // not uint_fast8_t: 64bit is slower here on amd64 - uint_fast16_t step = dim == 1 ? vr->partition_size - : FASTDIV(vr->partition_size, dim); - vorbis_codebook codebook = vc->codebooks[vqbook]; - - if (vr_type == 0) { - - voffs = voffset+j*vlen; - for (k = 0; k < step; ++k) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; - for (l = 0; l < dim; ++l) - vec[voffs + k + l * step] += codebook.codevectors[coffs + l]; // FPMATH - } - } else if (vr_type == 1) { - voffs = voffset + j * vlen; - for (k = 0; k < step; ++k) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; - for (l = 0; l < dim; ++l, ++voffs) { - vec[voffs]+=codebook.codevectors[coffs+l]; // FPMATH - - AV_DEBUG(" pass %d offs: %d curr: %f change: %f cv offs.: %d \n", pass, voffs, vec[voffs], codebook.codevectors[coffs+l], coffs); - } - } - } else if (vr_type == 2 && ch == 2 && (voffset & 1) == 0 && (dim & 1) == 0) { // most frequent case optimized - voffs = voffset >> 1; - - if (dim == 2) { - for (k = 0; k < step; ++k) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * 2; - vec[voffs + k ] += codebook.codevectors[coffs ]; // FPMATH - vec[voffs + k + vlen] += codebook.codevectors[coffs + 1]; // FPMATH - } - } else if (dim == 4) { - for (k = 0; k < step; ++k, voffs += 2) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * 4; - vec[voffs ] += codebook.codevectors[coffs ]; // FPMATH - vec[voffs + 1 ] += codebook.codevectors[coffs + 2]; // FPMATH - vec[voffs + vlen ] += codebook.codevectors[coffs + 1]; // FPMATH - vec[voffs + vlen + 1] += codebook.codevectors[coffs + 3]; // FPMATH - } - } else - for (k = 0; k < step; ++k) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; - for (l = 0; l < dim; l += 2, voffs++) { - vec[voffs ] += codebook.codevectors[coffs + l ]; // FPMATH - vec[voffs + vlen] += codebook.codevectors[coffs + l + 1]; // FPMATH - - AV_DEBUG(" pass %d offs: %d curr: %f change: %f cv offs.: %d+%d \n", pass, voffset / ch + (voffs % ch) * vlen, vec[voffset / ch + (voffs % ch) * vlen], codebook.codevectors[coffs + l], coffs, l); - } - } - - } else if (vr_type == 2) { - voffs = voffset; - - for (k = 0; k < step; ++k) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; - for (l = 0; l < dim; ++l, ++voffs) { - vec[voffs / ch + (voffs % ch) * vlen] += codebook.codevectors[coffs + l]; // FPMATH FIXME use if and counter instead of / and % - - AV_DEBUG(" pass %d offs: %d curr: %f change: %f cv offs.: %d+%d \n", pass, voffset / ch + (voffs % ch) * vlen, vec[voffset / ch + (voffs % ch) * vlen], codebook.codevectors[coffs + l], coffs, l); - } - } - } - } - } - j_times_ptns_to_read += ptns_to_read; - } - ++partition_count; - voffset += vr->partition_size; - } - } - } - return 0; -} - -static inline int vorbis_residue_decode(vorbis_context *vc, vorbis_residue *vr, - uint_fast8_t ch, - uint_fast8_t *do_not_decode, - float *vec, uint_fast16_t vlen) -{ - if (vr->type == 2) - return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, 2); - else if (vr->type == 1) - return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, 1); - else if (vr->type == 0) - return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, 0); - else { - av_log(vc->avccontext, AV_LOG_ERROR, " Invalid residue type while residue decode?! \n"); - return -1; - } -} - -void vorbis_inverse_coupling(float *mag, float *ang, int blocksize) -{ - int i; - for (i = 0; i < blocksize; i++) { - if (mag[i] > 0.0) { - if (ang[i] > 0.0) { - ang[i] = mag[i] - ang[i]; - } else { - float temp = ang[i]; - ang[i] = mag[i]; - mag[i] += temp; - } - } else { - if (ang[i] > 0.0) { - ang[i] += mag[i]; - } else { - float temp = ang[i]; - ang[i] = mag[i]; - mag[i] -= temp; - } - } - } -} - -// Decode the audio packet using the functions above - -static int vorbis_parse_audio_packet(vorbis_context *vc) -{ - GetBitContext *gb = &vc->gb; - FFTContext *mdct; - uint_fast8_t previous_window = vc->previous_window; - uint_fast8_t mode_number; - uint_fast8_t blockflag; - uint_fast16_t blocksize; - int_fast32_t i,j; - uint_fast8_t no_residue[255]; - uint_fast8_t do_not_decode[255]; - vorbis_mapping *mapping; - float *ch_res_ptr = vc->channel_residues; - float *ch_floor_ptr = vc->channel_floors; - uint_fast8_t res_chan[255]; - uint_fast8_t res_num = 0; - int_fast16_t retlen = 0; - - if (get_bits1(gb)) { - av_log(vc->avccontext, AV_LOG_ERROR, "Not a Vorbis I audio packet.\n"); - return -1; // packet type not audio - } - - if (vc->mode_count == 1) { - mode_number = 0; - } else { - GET_VALIDATED_INDEX(mode_number, ilog(vc->mode_count-1), vc->mode_count) - } - vc->mode_number = mode_number; - mapping = &vc->mappings[vc->modes[mode_number].mapping]; - - AV_DEBUG(" Mode number: %d , mapping: %d , blocktype %d \n", mode_number, vc->modes[mode_number].mapping, vc->modes[mode_number].blockflag); - - blockflag = vc->modes[mode_number].blockflag; - blocksize = vc->blocksize[blockflag]; - if (blockflag) - skip_bits(gb, 2); // previous_window, next_window - - memset(ch_res_ptr, 0, sizeof(float) * vc->audio_channels * blocksize / 2); //FIXME can this be removed ? - memset(ch_floor_ptr, 0, sizeof(float) * vc->audio_channels * blocksize / 2); //FIXME can this be removed ? - -// Decode floor - - for (i = 0; i < vc->audio_channels; ++i) { - vorbis_floor *floor; - int ret; - if (mapping->submaps > 1) { - floor = &vc->floors[mapping->submap_floor[mapping->mux[i]]]; - } else { - floor = &vc->floors[mapping->submap_floor[0]]; - } - - ret = floor->decode(vc, &floor->data, ch_floor_ptr); - - if (ret < 0) { - av_log(vc->avccontext, AV_LOG_ERROR, "Invalid codebook in vorbis_floor_decode.\n"); - return -1; - } - no_residue[i] = ret; - ch_floor_ptr += blocksize / 2; - } - -// Nonzero vector propagate - - for (i = mapping->coupling_steps - 1; i >= 0; --i) { - if (!(no_residue[mapping->magnitude[i]] & no_residue[mapping->angle[i]])) { - no_residue[mapping->magnitude[i]] = 0; - no_residue[mapping->angle[i]] = 0; - } - } - -// Decode residue - - for (i = 0; i < mapping->submaps; ++i) { - vorbis_residue *residue; - uint_fast8_t ch = 0; - - for (j = 0; j < vc->audio_channels; ++j) { - if ((mapping->submaps == 1) || (i == mapping->mux[j])) { - res_chan[j] = res_num; - if (no_residue[j]) { - do_not_decode[ch] = 1; - } else { - do_not_decode[ch] = 0; - } - ++ch; - ++res_num; - } - } - residue = &vc->residues[mapping->submap_residue[i]]; - vorbis_residue_decode(vc, residue, ch, do_not_decode, ch_res_ptr, blocksize/2); - - ch_res_ptr += ch * blocksize / 2; - } - -// Inverse coupling - - for (i = mapping->coupling_steps - 1; i >= 0; --i) { //warning: i has to be signed - float *mag, *ang; - - mag = vc->channel_residues+res_chan[mapping->magnitude[i]] * blocksize / 2; - ang = vc->channel_residues+res_chan[mapping->angle[i]] * blocksize / 2; - vc->dsp.vorbis_inverse_coupling(mag, ang, blocksize / 2); - } - -// Dotproduct, MDCT - - mdct = &vc->mdct[blockflag]; - - for (j = vc->audio_channels-1;j >= 0; j--) { - ch_floor_ptr = vc->channel_floors + j * blocksize / 2; - ch_res_ptr = vc->channel_residues + res_chan[j] * blocksize / 2; - vc->dsp.vector_fmul(ch_floor_ptr, ch_floor_ptr, ch_res_ptr, blocksize / 2); - mdct->imdct_half(mdct, ch_res_ptr, ch_floor_ptr); - } - -// Overlap/add, save data for next overlapping FPMATH - - retlen = (blocksize + vc->blocksize[previous_window]) / 4; - for (j = 0; j < vc->audio_channels; j++) { - uint_fast16_t bs0 = vc->blocksize[0]; - uint_fast16_t bs1 = vc->blocksize[1]; - float *residue = vc->channel_residues + res_chan[j] * blocksize / 2; - float *saved = vc->saved + j * bs1 / 4; - float *ret = vc->channel_floors + j * retlen; - float *buf = residue; - const float *win = vc->win[blockflag & previous_window]; - - if (blockflag == previous_window) { - vc->dsp.vector_fmul_window(ret, saved, buf, win, blocksize / 4); - } else if (blockflag > previous_window) { - vc->dsp.vector_fmul_window(ret, saved, buf, win, bs0 / 4); - memcpy(ret+bs0/2, buf+bs0/4, ((bs1-bs0)/4) * sizeof(float)); - } else { - memcpy(ret, saved, ((bs1 - bs0) / 4) * sizeof(float)); - vc->dsp.vector_fmul_window(ret + (bs1 - bs0) / 4, saved + (bs1 - bs0) / 4, buf, win, bs0 / 4); - } - memcpy(saved, buf + blocksize / 4, blocksize / 4 * sizeof(float)); - } - - vc->previous_window = blockflag; - return retlen; -} - -// Return the decoded audio packet through the standard api - -static int vorbis_decode_frame(AVCodecContext *avccontext, - void *data, int *data_size, - AVPacket *avpkt) -{ - const uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; - vorbis_context *vc = avccontext->priv_data ; - GetBitContext *gb = &(vc->gb); - const float *channel_ptrs[255]; - int i; - - int_fast16_t len; - - if (!buf_size) - return 0; - - AV_DEBUG("packet length %d \n", buf_size); - - init_get_bits(gb, buf, buf_size*8); - - len = vorbis_parse_audio_packet(vc); - - if (len <= 0) { - *data_size = 0; - return buf_size; - } - - if (!vc->first_frame) { - vc->first_frame = 1; - *data_size = 0; - return buf_size ; - } - - AV_DEBUG("parsed %d bytes %d bits, returned %d samples (*ch*bits) \n", get_bits_count(gb)/8, get_bits_count(gb)%8, len); - - if (vc->audio_channels > 8) { - for (i = 0; i < vc->audio_channels; i++) - channel_ptrs[i] = vc->channel_floors + i * len; - } else { - for (i = 0; i < vc->audio_channels; i++) - channel_ptrs[i] = vc->channel_floors + - len * ff_vorbis_channel_layout_offsets[vc->audio_channels - 1][i]; - } - - vc->fmt_conv.float_to_int16_interleave(data, channel_ptrs, len, - vc->audio_channels); - *data_size = len * 2 * vc->audio_channels; - - return buf_size ; -} - -// Close decoder - -static av_cold int vorbis_decode_close(AVCodecContext *avccontext) -{ - vorbis_context *vc = avccontext->priv_data; - - vorbis_free(vc); - - return 0 ; -} - -AVCodec ff_vorbis_decoder = { - "vorbis", - AVMEDIA_TYPE_AUDIO, - CODEC_ID_VORBIS, - sizeof(vorbis_context), - vorbis_decode_init, - NULL, - vorbis_decode_close, - vorbis_decode_frame, - .long_name = NULL_IF_CONFIG_SMALL("Vorbis"), - .channel_layouts = ff_vorbis_channel_layouts, -}; - diff --git a/libavcodec/vorbis_enc.c b/libavcodec/vorbis_enc.c deleted file mode 100644 index 74933af..0000000 --- a/libavcodec/vorbis_enc.c +++ /dev/null @@ -1,1116 +0,0 @@ -/* - * copyright (c) 2006 Oded Shimon - * - * This file is part of Libav. - * - * Libav 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. - * - * Libav 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 Libav; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * Native Vorbis encoder. - * @author Oded Shimon - */ - -#include -#include "avcodec.h" -#include "dsputil.h" -#include "fft.h" -#include "vorbis.h" -#include "vorbis_enc_data.h" - -#define BITSTREAM_WRITER_LE -#include "put_bits.h" - -#undef NDEBUG -#include - -typedef struct { - int nentries; - uint8_t *lens; - uint32_t *codewords; - int ndimentions; - float min; - float delta; - int seq_p; - int lookup; - int *quantlist; - float *dimentions; - float *pow2; -} vorbis_enc_codebook; - -typedef struct { - int dim; - int subclass; - int masterbook; - int *books; -} vorbis_enc_floor_class; - -typedef struct { - int partitions; - int *partition_to_class; - int nclasses; - vorbis_enc_floor_class *classes; - int multiplier; - int rangebits; - int values; - vorbis_floor1_entry *list; -} vorbis_enc_floor; - -typedef struct { - int type; - int begin; - int end; - int partition_size; - int classifications; - int classbook; - int8_t (*books)[8]; - float (*maxes)[2]; -} vorbis_enc_residue; - -typedef struct { - int submaps; - int *mux; - int *floor; - int *residue; - int coupling_steps; - int *magnitude; - int *angle; -} vorbis_enc_mapping; - -typedef struct { - int blockflag; - int mapping; -} vorbis_enc_mode; - -typedef struct { - int channels; - int sample_rate; - int log2_blocksize[2]; - FFTContext mdct[2]; - const float *win[2]; - int have_saved; - float *saved; - float *samples; - float *floor; // also used for tmp values for mdct - float *coeffs; // also used for residue after floor - float quality; - - int ncodebooks; - vorbis_enc_codebook *codebooks; - - int nfloors; - vorbis_enc_floor *floors; - - int nresidues; - vorbis_enc_residue *residues; - - int nmappings; - vorbis_enc_mapping *mappings; - - int nmodes; - vorbis_enc_mode *modes; - - int64_t sample_count; -} vorbis_enc_context; - -#define MAX_CHANNELS 2 -#define MAX_CODEBOOK_DIM 8 - -#define MAX_FLOOR_CLASS_DIM 4 -#define NUM_FLOOR_PARTITIONS 8 -#define MAX_FLOOR_VALUES (MAX_FLOOR_CLASS_DIM*NUM_FLOOR_PARTITIONS+2) - -#define RESIDUE_SIZE 1600 -#define RESIDUE_PART_SIZE 32 -#define NUM_RESIDUE_PARTITIONS (RESIDUE_SIZE/RESIDUE_PART_SIZE) - -static inline void put_codeword(PutBitContext *pb, vorbis_enc_codebook *cb, - int entry) -{ - assert(entry >= 0); - assert(entry < cb->nentries); - assert(cb->lens[entry]); - put_bits(pb, cb->lens[entry], cb->codewords[entry]); -} - -static int cb_lookup_vals(int lookup, int dimentions, int entries) -{ - if (lookup == 1) - return ff_vorbis_nth_root(entries, dimentions); - else if (lookup == 2) - return dimentions *entries; - return 0; -} - -static void ready_codebook(vorbis_enc_codebook *cb) -{ - int i; - - ff_vorbis_len2vlc(cb->lens, cb->codewords, cb->nentries); - - if (!cb->lookup) { - cb->pow2 = cb->dimentions = NULL; - } else { - int vals = cb_lookup_vals(cb->lookup, cb->ndimentions, cb->nentries); - cb->dimentions = av_malloc(sizeof(float) * cb->nentries * cb->ndimentions); - cb->pow2 = av_mallocz(sizeof(float) * cb->nentries); - for (i = 0; i < cb->nentries; i++) { - float last = 0; - int j; - int div = 1; - for (j = 0; j < cb->ndimentions; j++) { - int off; - if (cb->lookup == 1) - off = (i / div) % vals; // lookup type 1 - else - off = i * cb->ndimentions + j; // lookup type 2 - - cb->dimentions[i * cb->ndimentions + j] = last + cb->min + cb->quantlist[off] * cb->delta; - if (cb->seq_p) - last = cb->dimentions[i * cb->ndimentions + j]; - cb->pow2[i] += cb->dimentions[i * cb->ndimentions + j] * cb->dimentions[i * cb->ndimentions + j]; - div *= vals; - } - cb->pow2[i] /= 2.; - } - } -} - -static void ready_residue(vorbis_enc_residue *rc, vorbis_enc_context *venc) -{ - int i; - assert(rc->type == 2); - rc->maxes = av_mallocz(sizeof(float[2]) * rc->classifications); - for (i = 0; i < rc->classifications; i++) { - int j; - vorbis_enc_codebook * cb; - for (j = 0; j < 8; j++) - if (rc->books[i][j] != -1) - break; - if (j == 8) // zero - continue; - cb = &venc->codebooks[rc->books[i][j]]; - assert(cb->ndimentions >= 2); - assert(cb->lookup); - - for (j = 0; j < cb->nentries; j++) { - float a; - if (!cb->lens[j]) - continue; - a = fabs(cb->dimentions[j * cb->ndimentions]); - if (a > rc->maxes[i][0]) - rc->maxes[i][0] = a; - a = fabs(cb->dimentions[j * cb->ndimentions + 1]); - if (a > rc->maxes[i][1]) - rc->maxes[i][1] = a; - } - } - // small bias - for (i = 0; i < rc->classifications; i++) { - rc->maxes[i][0] += 0.8; - rc->maxes[i][1] += 0.8; - } -} - -static void create_vorbis_context(vorbis_enc_context *venc, - AVCodecContext *avccontext) -{ - vorbis_enc_floor *fc; - vorbis_enc_residue *rc; - vorbis_enc_mapping *mc; - int i, book; - - venc->channels = avccontext->channels; - venc->sample_rate = avccontext->sample_rate; - venc->log2_blocksize[0] = venc->log2_blocksize[1] = 11; - - venc->ncodebooks = FF_ARRAY_ELEMS(cvectors); - venc->codebooks = av_malloc(sizeof(vorbis_enc_codebook) * venc->ncodebooks); - - // codebook 0..14 - floor1 book, values 0..255 - // codebook 15 residue masterbook - // codebook 16..29 residue - for (book = 0; book < venc->ncodebooks; book++) { - vorbis_enc_codebook *cb = &venc->codebooks[book]; - int vals; - cb->ndimentions = cvectors[book].dim; - cb->nentries = cvectors[book].real_len; - cb->min = cvectors[book].min; - cb->delta = cvectors[book].delta; - cb->lookup = cvectors[book].lookup; - cb->seq_p = 0; - - cb->lens = av_malloc(sizeof(uint8_t) * cb->nentries); - cb->codewords = av_malloc(sizeof(uint32_t) * cb->nentries); - memcpy(cb->lens, cvectors[book].clens, cvectors[book].len); - memset(cb->lens + cvectors[book].len, 0, cb->nentries - cvectors[book].len); - - if (cb->lookup) { - vals = cb_lookup_vals(cb->lookup, cb->ndimentions, cb->nentries); - cb->quantlist = av_malloc(sizeof(int) * vals); - for (i = 0; i < vals; i++) - cb->quantlist[i] = cvectors[book].quant[i]; - } else { - cb->quantlist = NULL; - } - ready_codebook(cb); - } - - venc->nfloors = 1; - venc->floors = av_malloc(sizeof(vorbis_enc_floor) * venc->nfloors); - - // just 1 floor - fc = &venc->floors[0]; - fc->partitions = NUM_FLOOR_PARTITIONS; - fc->partition_to_class = av_malloc(sizeof(int) * fc->partitions); - fc->nclasses = 0; - for (i = 0; i < fc->partitions; i++) { - static const int a[] = {0, 1, 2, 2, 3, 3, 4, 4}; - fc->partition_to_class[i] = a[i]; - fc->nclasses = FFMAX(fc->nclasses, fc->partition_to_class[i]); - } - fc->nclasses++; - fc->classes = av_malloc(sizeof(vorbis_enc_floor_class) * fc->nclasses); - for (i = 0; i < fc->nclasses; i++) { - vorbis_enc_floor_class * c = &fc->classes[i]; - int j, books; - c->dim = floor_classes[i].dim; - c->subclass = floor_classes[i].subclass; - c->masterbook = floor_classes[i].masterbook; - books = (1 << c->subclass); - c->books = av_malloc(sizeof(int) * books); - for (j = 0; j < books; j++) - c->books[j] = floor_classes[i].nbooks[j]; - } - fc->multiplier = 2; - fc->rangebits = venc->log2_blocksize[0] - 1; - - fc->values = 2; - for (i = 0; i < fc->partitions; i++) - fc->values += fc->classes[fc->partition_to_class[i]].dim; - - fc->list = av_malloc(sizeof(vorbis_floor1_entry) * fc->values); - fc->list[0].x = 0; - fc->list[1].x = 1 << fc->rangebits; - for (i = 2; i < fc->values; i++) { - static const int a[] = { - 93, 23,372, 6, 46,186,750, 14, 33, 65, - 130,260,556, 3, 10, 18, 28, 39, 55, 79, - 111,158,220,312,464,650,850 - }; - fc->list[i].x = a[i - 2]; - } - ff_vorbis_ready_floor1_list(fc->list, fc->values); - - venc->nresidues = 1; - venc->residues = av_malloc(sizeof(vorbis_enc_residue) * venc->nresidues); - - // single residue - rc = &venc->residues[0]; - rc->type = 2; - rc->begin = 0; - rc->end = 1600; - rc->partition_size = 32; - rc->classifications = 10; - rc->classbook = 15; - rc->books = av_malloc(sizeof(*rc->books) * rc->classifications); - { - static const int8_t a[10][8] = { - { -1, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, 16, -1, -1, -1, -1, -1, }, - { -1, -1, 17, -1, -1, -1, -1, -1, }, - { -1, -1, 18, -1, -1, -1, -1, -1, }, - { -1, -1, 19, -1, -1, -1, -1, -1, }, - { -1, -1, 20, -1, -1, -1, -1, -1, }, - { -1, -1, 21, -1, -1, -1, -1, -1, }, - { 22, 23, -1, -1, -1, -1, -1, -1, }, - { 24, 25, -1, -1, -1, -1, -1, -1, }, - { 26, 27, 28, -1, -1, -1, -1, -1, }, - }; - memcpy(rc->books, a, sizeof a); - } - ready_residue(rc, venc); - - venc->nmappings = 1; - venc->mappings = av_malloc(sizeof(vorbis_enc_mapping) * venc->nmappings); - - // single mapping - mc = &venc->mappings[0]; - mc->submaps = 1; - mc->mux = av_malloc(sizeof(int) * venc->channels); - for (i = 0; i < venc->channels; i++) - mc->mux[i] = 0; - mc->floor = av_malloc(sizeof(int) * mc->submaps); - mc->residue = av_malloc(sizeof(int) * mc->submaps); - for (i = 0; i < mc->submaps; i++) { - mc->floor[i] = 0; - mc->residue[i] = 0; - } - mc->coupling_steps = venc->channels == 2 ? 1 : 0; - mc->magnitude = av_malloc(sizeof(int) * mc->coupling_steps); - mc->angle = av_malloc(sizeof(int) * mc->coupling_steps); - if (mc->coupling_steps) { - mc->magnitude[0] = 0; - mc->angle[0] = 1; - } - - venc->nmodes = 1; - venc->modes = av_malloc(sizeof(vorbis_enc_mode) * venc->nmodes); - - // single mode - venc->modes[0].blockflag = 0; - venc->modes[0].mapping = 0; - - venc->have_saved = 0; - venc->saved = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1]) / 2); - venc->samples = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1])); - venc->floor = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1]) / 2); - venc->coeffs = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1]) / 2); - - venc->win[0] = ff_vorbis_vwin[venc->log2_blocksize[0] - 6]; - venc->win[1] = ff_vorbis_vwin[venc->log2_blocksize[1] - 6]; - - ff_mdct_init(&venc->mdct[0], venc->log2_blocksize[0], 0, 1.0); - ff_mdct_init(&venc->mdct[1], venc->log2_blocksize[1], 0, 1.0); -} - -static void put_float(PutBitContext *pb, float f) -{ - int exp, mant; - uint32_t res = 0; - mant = (int)ldexp(frexp(f, &exp), 20); - exp += 788 - 20; - if (mant < 0) { - res |= (1U << 31); - mant = -mant; - } - res |= mant | (exp << 21); - put_bits32(pb, res); -} - -static void put_codebook_header(PutBitContext *pb, vorbis_enc_codebook *cb) -{ - int i; - int ordered = 0; - - put_bits(pb, 24, 0x564342); //magic - put_bits(pb, 16, cb->ndimentions); - put_bits(pb, 24, cb->nentries); - - for (i = 1; i < cb->nentries; i++) - if (cb->lens[i] < cb->lens[i-1]) - break; - if (i == cb->nentries) - ordered = 1; - - put_bits(pb, 1, ordered); - if (ordered) { - int len = cb->lens[0]; - put_bits(pb, 5, len - 1); - i = 0; - while (i < cb->nentries) { - int j; - for (j = 0; j+i < cb->nentries; j++) - if (cb->lens[j+i] != len) - break; - put_bits(pb, ilog(cb->nentries - i), j); - i += j; - len++; - } - } else { - int sparse = 0; - for (i = 0; i < cb->nentries; i++) - if (!cb->lens[i]) - break; - if (i != cb->nentries) - sparse = 1; - put_bits(pb, 1, sparse); - - for (i = 0; i < cb->nentries; i++) { - if (sparse) - put_bits(pb, 1, !!cb->lens[i]); - if (cb->lens[i]) - put_bits(pb, 5, cb->lens[i] - 1); - } - } - - put_bits(pb, 4, cb->lookup); - if (cb->lookup) { - int tmp = cb_lookup_vals(cb->lookup, cb->ndimentions, cb->nentries); - int bits = ilog(cb->quantlist[0]); - - for (i = 1; i < tmp; i++) - bits = FFMAX(bits, ilog(cb->quantlist[i])); - - put_float(pb, cb->min); - put_float(pb, cb->delta); - - put_bits(pb, 4, bits - 1); - put_bits(pb, 1, cb->seq_p); - - for (i = 0; i < tmp; i++) - put_bits(pb, bits, cb->quantlist[i]); - } -} - -static void put_floor_header(PutBitContext *pb, vorbis_enc_floor *fc) -{ - int i; - - put_bits(pb, 16, 1); // type, only floor1 is supported - - put_bits(pb, 5, fc->partitions); - - for (i = 0; i < fc->partitions; i++) - put_bits(pb, 4, fc->partition_to_class[i]); - - for (i = 0; i < fc->nclasses; i++) { - int j, books; - - put_bits(pb, 3, fc->classes[i].dim - 1); - put_bits(pb, 2, fc->classes[i].subclass); - - if (fc->classes[i].subclass) - put_bits(pb, 8, fc->classes[i].masterbook); - - books = (1 << fc->classes[i].subclass); - - for (j = 0; j < books; j++) - put_bits(pb, 8, fc->classes[i].books[j] + 1); - } - - put_bits(pb, 2, fc->multiplier - 1); - put_bits(pb, 4, fc->rangebits); - - for (i = 2; i < fc->values; i++) - put_bits(pb, fc->rangebits, fc->list[i].x); -} - -static void put_residue_header(PutBitContext *pb, vorbis_enc_residue *rc) -{ - int i; - - put_bits(pb, 16, rc->type); - - put_bits(pb, 24, rc->begin); - put_bits(pb, 24, rc->end); - put_bits(pb, 24, rc->partition_size - 1); - put_bits(pb, 6, rc->classifications - 1); - put_bits(pb, 8, rc->classbook); - - for (i = 0; i < rc->classifications; i++) { - int j, tmp = 0; - for (j = 0; j < 8; j++) - tmp |= (rc->books[i][j] != -1) << j; - - put_bits(pb, 3, tmp & 7); - put_bits(pb, 1, tmp > 7); - - if (tmp > 7) - put_bits(pb, 5, tmp >> 3); - } - - for (i = 0; i < rc->classifications; i++) { - int j; - for (j = 0; j < 8; j++) - if (rc->books[i][j] != -1) - put_bits(pb, 8, rc->books[i][j]); - } -} - -static int put_main_header(vorbis_enc_context *venc, uint8_t **out) -{ - int i; - PutBitContext pb; - uint8_t buffer[50000] = {0}, *p = buffer; - int buffer_len = sizeof buffer; - int len, hlens[3]; - - // identification header - init_put_bits(&pb, p, buffer_len); - put_bits(&pb, 8, 1); //magic - for (i = 0; "vorbis"[i]; i++) - put_bits(&pb, 8, "vorbis"[i]); - put_bits32(&pb, 0); // version - put_bits(&pb, 8, venc->channels); - put_bits32(&pb, venc->sample_rate); - put_bits32(&pb, 0); // bitrate - put_bits32(&pb, 0); // bitrate - put_bits32(&pb, 0); // bitrate - put_bits(&pb, 4, venc->log2_blocksize[0]); - put_bits(&pb, 4, venc->log2_blocksize[1]); - put_bits(&pb, 1, 1); // framing - - flush_put_bits(&pb); - hlens[0] = put_bits_count(&pb) >> 3; - buffer_len -= hlens[0]; - p += hlens[0]; - - // comment header - init_put_bits(&pb, p, buffer_len); - put_bits(&pb, 8, 3); //magic - for (i = 0; "vorbis"[i]; i++) - put_bits(&pb, 8, "vorbis"[i]); - put_bits32(&pb, 0); // vendor length TODO - put_bits32(&pb, 0); // amount of comments - put_bits(&pb, 1, 1); // framing - - flush_put_bits(&pb); - hlens[1] = put_bits_count(&pb) >> 3; - buffer_len -= hlens[1]; - p += hlens[1]; - - // setup header - init_put_bits(&pb, p, buffer_len); - put_bits(&pb, 8, 5); //magic - for (i = 0; "vorbis"[i]; i++) - put_bits(&pb, 8, "vorbis"[i]); - - // codebooks - put_bits(&pb, 8, venc->ncodebooks - 1); - for (i = 0; i < venc->ncodebooks; i++) - put_codebook_header(&pb, &venc->codebooks[i]); - - // time domain, reserved, zero - put_bits(&pb, 6, 0); - put_bits(&pb, 16, 0); - - // floors - put_bits(&pb, 6, venc->nfloors - 1); - for (i = 0; i < venc->nfloors; i++) - put_floor_header(&pb, &venc->floors[i]); - - // residues - put_bits(&pb, 6, venc->nresidues - 1); - for (i = 0; i < venc->nresidues; i++) - put_residue_header(&pb, &venc->residues[i]); - - // mappings - put_bits(&pb, 6, venc->nmappings - 1); - for (i = 0; i < venc->nmappings; i++) { - vorbis_enc_mapping *mc = &venc->mappings[i]; - int j; - put_bits(&pb, 16, 0); // mapping type - - put_bits(&pb, 1, mc->submaps > 1); - if (mc->submaps > 1) - put_bits(&pb, 4, mc->submaps - 1); - - put_bits(&pb, 1, !!mc->coupling_steps); - if (mc->coupling_steps) { - put_bits(&pb, 8, mc->coupling_steps - 1); - for (j = 0; j < mc->coupling_steps; j++) { - put_bits(&pb, ilog(venc->channels - 1), mc->magnitude[j]); - put_bits(&pb, ilog(venc->channels - 1), mc->angle[j]); - } - } - - put_bits(&pb, 2, 0); // reserved - - if (mc->submaps > 1) - for (j = 0; j < venc->channels; j++) - put_bits(&pb, 4, mc->mux[j]); - - for (j = 0; j < mc->submaps; j++) { - put_bits(&pb, 8, 0); // reserved time configuration - put_bits(&pb, 8, mc->floor[j]); - put_bits(&pb, 8, mc->residue[j]); - } - } - - // modes - put_bits(&pb, 6, venc->nmodes - 1); - for (i = 0; i < venc->nmodes; i++) { - put_bits(&pb, 1, venc->modes[i].blockflag); - put_bits(&pb, 16, 0); // reserved window type - put_bits(&pb, 16, 0); // reserved transform type - put_bits(&pb, 8, venc->modes[i].mapping); - } - - put_bits(&pb, 1, 1); // framing - - flush_put_bits(&pb); - hlens[2] = put_bits_count(&pb) >> 3; - - len = hlens[0] + hlens[1] + hlens[2]; - p = *out = av_mallocz(64 + len + len/255); - - *p++ = 2; - p += av_xiphlacing(p, hlens[0]); - p += av_xiphlacing(p, hlens[1]); - buffer_len = 0; - for (i = 0; i < 3; i++) { - memcpy(p, buffer + buffer_len, hlens[i]); - p += hlens[i]; - buffer_len += hlens[i]; - } - - return p - *out; -} - -static float get_floor_average(vorbis_enc_floor * fc, float *coeffs, int i) -{ - int begin = fc->list[fc->list[FFMAX(i-1, 0)].sort].x; - int end = fc->list[fc->list[FFMIN(i+1, fc->values - 1)].sort].x; - int j; - float average = 0; - - for (j = begin; j < end; j++) - average += fabs(coeffs[j]); - return average / (end - begin); -} - -static void floor_fit(vorbis_enc_context *venc, vorbis_enc_floor *fc, - float *coeffs, uint_fast16_t *posts, int samples) -{ - int range = 255 / fc->multiplier + 1; - int i; - float tot_average = 0.; - float averages[MAX_FLOOR_VALUES]; - for (i = 0; i < fc->values; i++) { - averages[i] = get_floor_average(fc, coeffs, i); - tot_average += averages[i]; - } - tot_average /= fc->values; - tot_average /= venc->quality; - - for (i = 0; i < fc->values; i++) { - int position = fc->list[fc->list[i].sort].x; - float average = averages[i]; - int j; - - average = sqrt(tot_average * average) * pow(1.25f, position*0.005f); // MAGIC! - for (j = 0; j < range - 1; j++) - if (ff_vorbis_floor1_inverse_db_table[j * fc->multiplier] > average) - break; - posts[fc->list[i].sort] = j; - } -} - -static int render_point(int x0, int y0, int x1, int y1, int x) -{ - return y0 + (x - x0) * (y1 - y0) / (x1 - x0); -} - -static void floor_encode(vorbis_enc_context *venc, vorbis_enc_floor *fc, - PutBitContext *pb, uint_fast16_t *posts, - float *floor, int samples) -{ - int range = 255 / fc->multiplier + 1; - int coded[MAX_FLOOR_VALUES]; // first 2 values are unused - int i, counter; - - put_bits(pb, 1, 1); // non zero - put_bits(pb, ilog(range - 1), posts[0]); - put_bits(pb, ilog(range - 1), posts[1]); - coded[0] = coded[1] = 1; - - for (i = 2; i < fc->values; i++) { - int predicted = render_point(fc->list[fc->list[i].low].x, - posts[fc->list[i].low], - fc->list[fc->list[i].high].x, - posts[fc->list[i].high], - fc->list[i].x); - int highroom = range - predicted; - int lowroom = predicted; - int room = FFMIN(highroom, lowroom); - if (predicted == posts[i]) { - coded[i] = 0; // must be used later as flag! - continue; - } else { - if (!coded[fc->list[i].low ]) - coded[fc->list[i].low ] = -1; - if (!coded[fc->list[i].high]) - coded[fc->list[i].high] = -1; - } - if (posts[i] > predicted) { - if (posts[i] - predicted > room) - coded[i] = posts[i] - predicted + lowroom; - else - coded[i] = (posts[i] - predicted) << 1; - } else { - if (predicted - posts[i] > room) - coded[i] = predicted - posts[i] + highroom - 1; - else - coded[i] = ((predicted - posts[i]) << 1) - 1; - } - } - - counter = 2; - for (i = 0; i < fc->partitions; i++) { - vorbis_enc_floor_class * c = &fc->classes[fc->partition_to_class[i]]; - int k, cval = 0, csub = 1<subclass; - if (c->subclass) { - vorbis_enc_codebook * book = &venc->codebooks[c->masterbook]; - int cshift = 0; - for (k = 0; k < c->dim; k++) { - int l; - for (l = 0; l < csub; l++) { - int maxval = 1; - if (c->books[l] != -1) - maxval = venc->codebooks[c->books[l]].nentries; - // coded could be -1, but this still works, cause that is 0 - if (coded[counter + k] < maxval) - break; - } - assert(l != csub); - cval |= l << cshift; - cshift += c->subclass; - } - put_codeword(pb, book, cval); - } - for (k = 0; k < c->dim; k++) { - int book = c->books[cval & (csub-1)]; - int entry = coded[counter++]; - cval >>= c->subclass; - if (book == -1) - continue; - if (entry == -1) - entry = 0; - put_codeword(pb, &venc->codebooks[book], entry); - } - } - - ff_vorbis_floor1_render_list(fc->list, fc->values, posts, coded, - fc->multiplier, floor, samples); -} - -static float *put_vector(vorbis_enc_codebook *book, PutBitContext *pb, - float *num) -{ - int i, entry = -1; - float distance = FLT_MAX; - assert(book->dimentions); - for (i = 0; i < book->nentries; i++) { - float * vec = book->dimentions + i * book->ndimentions, d = book->pow2[i]; - int j; - if (!book->lens[i]) - continue; - for (j = 0; j < book->ndimentions; j++) - d -= vec[j] * num[j]; - if (distance > d) { - entry = i; - distance = d; - } - } - put_codeword(pb, book, entry); - return &book->dimentions[entry * book->ndimentions]; -} - -static void residue_encode(vorbis_enc_context *venc, vorbis_enc_residue *rc, - PutBitContext *pb, float *coeffs, int samples, - int real_ch) -{ - int pass, i, j, p, k; - int psize = rc->partition_size; - int partitions = (rc->end - rc->begin) / psize; - int channels = (rc->type == 2) ? 1 : real_ch; - int classes[MAX_CHANNELS][NUM_RESIDUE_PARTITIONS]; - int classwords = venc->codebooks[rc->classbook].ndimentions; - - assert(rc->type == 2); - assert(real_ch == 2); - for (p = 0; p < partitions; p++) { - float max1 = 0., max2 = 0.; - int s = rc->begin + p * psize; - for (k = s; k < s + psize; k += 2) { - max1 = FFMAX(max1, fabs(coeffs[ k / real_ch])); - max2 = FFMAX(max2, fabs(coeffs[samples + k / real_ch])); - } - - for (i = 0; i < rc->classifications - 1; i++) - if (max1 < rc->maxes[i][0] && max2 < rc->maxes[i][1]) - break; - classes[0][p] = i; - } - - for (pass = 0; pass < 8; pass++) { - p = 0; - while (p < partitions) { - if (pass == 0) - for (j = 0; j < channels; j++) { - vorbis_enc_codebook * book = &venc->codebooks[rc->classbook]; - int entry = 0; - for (i = 0; i < classwords; i++) { - entry *= rc->classifications; - entry += classes[j][p + i]; - } - put_codeword(pb, book, entry); - } - for (i = 0; i < classwords && p < partitions; i++, p++) { - for (j = 0; j < channels; j++) { - int nbook = rc->books[classes[j][p]][pass]; - vorbis_enc_codebook * book = &venc->codebooks[nbook]; - float *buf = coeffs + samples*j + rc->begin + p*psize; - if (nbook == -1) - continue; - - assert(rc->type == 0 || rc->type == 2); - assert(!(psize % book->ndimentions)); - - if (rc->type == 0) { - for (k = 0; k < psize; k += book->ndimentions) { - float *a = put_vector(book, pb, &buf[k]); - int l; - for (l = 0; l < book->ndimentions; l++) - buf[k + l] -= a[l]; - } - } else { - int s = rc->begin + p * psize, a1, b1; - a1 = (s % real_ch) * samples; - b1 = s / real_ch; - s = real_ch * samples; - for (k = 0; k < psize; k += book->ndimentions) { - int dim, a2 = a1, b2 = b1; - float vec[MAX_CODEBOOK_DIM], *pv = vec; - for (dim = book->ndimentions; dim--; ) { - *pv++ = coeffs[a2 + b2]; - if ((a2 += samples) == s) { - a2 = 0; - b2++; - } - } - pv = put_vector(book, pb, vec); - for (dim = book->ndimentions; dim--; ) { - coeffs[a1 + b1] -= *pv++; - if ((a1 += samples) == s) { - a1 = 0; - b1++; - } - } - } - } - } - } - } - } -} - -static int apply_window_and_mdct(vorbis_enc_context *venc, const signed short *audio, - int samples) -{ - int i, j, channel; - const float * win = venc->win[0]; - int window_len = 1 << (venc->log2_blocksize[0] - 1); - float n = (float)(1 << venc->log2_blocksize[0]) / 4.; - // FIXME use dsp - - if (!venc->have_saved && !samples) - return 0; - - if (venc->have_saved) { - for (channel = 0; channel < venc->channels; channel++) - memcpy(venc->samples + channel * window_len * 2, - venc->saved + channel * window_len, sizeof(float) * window_len); - } else { - for (channel = 0; channel < venc->channels; channel++) - memset(venc->samples + channel * window_len * 2, 0, - sizeof(float) * window_len); - } - - if (samples) { - for (channel = 0; channel < venc->channels; channel++) { - float * offset = venc->samples + channel*window_len*2 + window_len; - j = channel; - for (i = 0; i < samples; i++, j += venc->channels) - offset[i] = audio[j] / 32768. / n * win[window_len - i - 1]; - } - } else { - for (channel = 0; channel < venc->channels; channel++) - memset(venc->samples + channel * window_len * 2 + window_len, - 0, sizeof(float) * window_len); - } - - for (channel = 0; channel < venc->channels; channel++) - venc->mdct[0].mdct_calc(&venc->mdct[0], venc->coeffs + channel * window_len, - venc->samples + channel * window_len * 2); - - if (samples) { - for (channel = 0; channel < venc->channels; channel++) { - float *offset = venc->saved + channel * window_len; - j = channel; - for (i = 0; i < samples; i++, j += venc->channels) - offset[i] = audio[j] / 32768. / n * win[i]; - } - venc->have_saved = 1; - } else { - venc->have_saved = 0; - } - return 1; -} - -static av_cold int vorbis_encode_init(AVCodecContext *avccontext) -{ - vorbis_enc_context *venc = avccontext->priv_data; - - if (avccontext->channels != 2) { - av_log(avccontext, AV_LOG_ERROR, "Current Libav Vorbis encoder only supports 2 channels.\n"); - return -1; - } - - create_vorbis_context(venc, avccontext); - - if (avccontext->flags & CODEC_FLAG_QSCALE) - venc->quality = avccontext->global_quality / (float)FF_QP2LAMBDA / 10.; - else - venc->quality = 0.03; - venc->quality *= venc->quality; - - avccontext->extradata_size = put_main_header(venc, (uint8_t**)&avccontext->extradata); - - avccontext->frame_size = 1 << (venc->log2_blocksize[0] - 1); - - avccontext->coded_frame = avcodec_alloc_frame(); - avccontext->coded_frame->key_frame = 1; - - return 0; -} - -static int vorbis_encode_frame(AVCodecContext *avccontext, - unsigned char *packets, - int buf_size, void *data) -{ - vorbis_enc_context *venc = avccontext->priv_data; - const signed short *audio = data; - int samples = data ? avccontext->frame_size : 0; - vorbis_enc_mode *mode; - vorbis_enc_mapping *mapping; - PutBitContext pb; - int i; - - if (!apply_window_and_mdct(venc, audio, samples)) - return 0; - samples = 1 << (venc->log2_blocksize[0] - 1); - - init_put_bits(&pb, packets, buf_size); - - put_bits(&pb, 1, 0); // magic bit - - put_bits(&pb, ilog(venc->nmodes - 1), 0); // 0 bits, the mode - - mode = &venc->modes[0]; - mapping = &venc->mappings[mode->mapping]; - if (mode->blockflag) { - put_bits(&pb, 1, 0); - put_bits(&pb, 1, 0); - } - - for (i = 0; i < venc->channels; i++) { - vorbis_enc_floor *fc = &venc->floors[mapping->floor[mapping->mux[i]]]; - uint_fast16_t posts[MAX_FLOOR_VALUES]; - floor_fit(venc, fc, &venc->coeffs[i * samples], posts, samples); - floor_encode(venc, fc, &pb, posts, &venc->floor[i * samples], samples); - } - - for (i = 0; i < venc->channels * samples; i++) - venc->coeffs[i] /= venc->floor[i]; - - for (i = 0; i < mapping->coupling_steps; i++) { - float *mag = venc->coeffs + mapping->magnitude[i] * samples; - float *ang = venc->coeffs + mapping->angle[i] * samples; - int j; - for (j = 0; j < samples; j++) { - float a = ang[j]; - ang[j] -= mag[j]; - if (mag[j] > 0) - ang[j] = -ang[j]; - if (ang[j] < 0) - mag[j] = a; - } - } - - residue_encode(venc, &venc->residues[mapping->residue[mapping->mux[0]]], - &pb, venc->coeffs, samples, venc->channels); - - avccontext->coded_frame->pts = venc->sample_count; - venc->sample_count += avccontext->frame_size; - flush_put_bits(&pb); - return put_bits_count(&pb) >> 3; -} - - -static av_cold int vorbis_encode_close(AVCodecContext *avccontext) -{ - vorbis_enc_context *venc = avccontext->priv_data; - int i; - - if (venc->codebooks) - for (i = 0; i < venc->ncodebooks; i++) { - av_freep(&venc->codebooks[i].lens); - av_freep(&venc->codebooks[i].codewords); - av_freep(&venc->codebooks[i].quantlist); - av_freep(&venc->codebooks[i].dimentions); - av_freep(&venc->codebooks[i].pow2); - } - av_freep(&venc->codebooks); - - if (venc->floors) - for (i = 0; i < venc->nfloors; i++) { - int j; - if (venc->floors[i].classes) - for (j = 0; j < venc->floors[i].nclasses; j++) - av_freep(&venc->floors[i].classes[j].books); - av_freep(&venc->floors[i].classes); - av_freep(&venc->floors[i].partition_to_class); - av_freep(&venc->floors[i].list); - } - av_freep(&venc->floors); - - if (venc->residues) - for (i = 0; i < venc->nresidues; i++) { - av_freep(&venc->residues[i].books); - av_freep(&venc->residues[i].maxes); - } - av_freep(&venc->residues); - - if (venc->mappings) - for (i = 0; i < venc->nmappings; i++) { - av_freep(&venc->mappings[i].mux); - av_freep(&venc->mappings[i].floor); - av_freep(&venc->mappings[i].residue); - av_freep(&venc->mappings[i].magnitude); - av_freep(&venc->mappings[i].angle); - } - av_freep(&venc->mappings); - - av_freep(&venc->modes); - - av_freep(&venc->saved); - av_freep(&venc->samples); - av_freep(&venc->floor); - av_freep(&venc->coeffs); - - ff_mdct_end(&venc->mdct[0]); - ff_mdct_end(&venc->mdct[1]); - - av_freep(&avccontext->coded_frame); - av_freep(&avccontext->extradata); - - return 0 ; -} - -AVCodec ff_vorbis_encoder = { - "vorbis", - AVMEDIA_TYPE_AUDIO, - CODEC_ID_VORBIS, - sizeof(vorbis_enc_context), - vorbis_encode_init, - vorbis_encode_frame, - vorbis_encode_close, - .capabilities= CODEC_CAP_DELAY | CODEC_CAP_EXPERIMENTAL, - .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_NONE}, - .long_name = NULL_IF_CONFIG_SMALL("Vorbis"), -}; diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c new file mode 100644 index 0000000..5fa7be1 --- /dev/null +++ b/libavcodec/vorbisdec.c @@ -0,0 +1,1668 @@ +/** + * @file + * Vorbis I decoder + * @author Denes Balatoni ( dbalatoni programozo hu ) + * + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#undef V_DEBUG +//#define V_DEBUG +//#define AV_DEBUG(...) av_log(NULL, AV_LOG_INFO, __VA_ARGS__) + +#include + +#define ALT_BITSTREAM_READER_LE +#include "avcodec.h" +#include "get_bits.h" +#include "dsputil.h" +#include "fft.h" +#include "fmtconvert.h" + +#include "vorbis.h" +#include "xiph.h" + +#define V_NB_BITS 8 +#define V_NB_BITS2 11 +#define V_MAX_VLCS (1 << 16) +#define V_MAX_PARTITIONS (1 << 20) + +#ifndef V_DEBUG +#define AV_DEBUG(...) +#endif + +#undef NDEBUG +#include + +typedef struct { + uint_fast8_t dimensions; + uint_fast8_t lookup_type; + uint_fast8_t maxdepth; + VLC vlc; + float *codevectors; + unsigned int nb_bits; +} vorbis_codebook; + +typedef union vorbis_floor_u vorbis_floor_data; +typedef struct vorbis_floor0_s vorbis_floor0; +typedef struct vorbis_floor1_s vorbis_floor1; +struct vorbis_context_s; +typedef +int (* vorbis_floor_decode_func) + (struct vorbis_context_s *, vorbis_floor_data *, float *); +typedef struct { + uint_fast8_t floor_type; + vorbis_floor_decode_func decode; + union vorbis_floor_u { + struct vorbis_floor0_s { + uint_fast8_t order; + uint_fast16_t rate; + uint_fast16_t bark_map_size; + int_fast32_t *map[2]; + uint_fast32_t map_size[2]; + uint_fast8_t amplitude_bits; + uint_fast8_t amplitude_offset; + uint_fast8_t num_books; + uint_fast8_t *book_list; + float *lsp; + } t0; + struct vorbis_floor1_s { + uint_fast8_t partitions; + uint8_t partition_class[32]; + uint_fast8_t class_dimensions[16]; + uint_fast8_t class_subclasses[16]; + uint_fast8_t class_masterbook[16]; + int_fast16_t subclass_books[16][8]; + uint_fast8_t multiplier; + uint_fast16_t x_list_dim; + vorbis_floor1_entry *list; + } t1; + } data; +} vorbis_floor; + +typedef struct { + uint_fast16_t type; + uint_fast32_t begin; + uint_fast32_t end; + unsigned partition_size; + uint_fast8_t classifications; + uint_fast8_t classbook; + int_fast16_t books[64][8]; + uint_fast8_t maxpass; + uint_fast16_t ptns_to_read; + uint8_t *classifs; +} vorbis_residue; + +typedef struct { + uint_fast8_t submaps; + uint_fast16_t coupling_steps; + uint_fast8_t *magnitude; + uint_fast8_t *angle; + uint_fast8_t *mux; + uint_fast8_t submap_floor[16]; + uint_fast8_t submap_residue[16]; +} vorbis_mapping; + +typedef struct { + uint_fast8_t blockflag; + uint_fast16_t windowtype; + uint_fast16_t transformtype; + uint_fast8_t mapping; +} vorbis_mode; + +typedef struct vorbis_context_s { + AVCodecContext *avccontext; + GetBitContext gb; + DSPContext dsp; + FmtConvertContext fmt_conv; + + FFTContext mdct[2]; + uint_fast8_t first_frame; + uint_fast32_t version; + uint_fast8_t audio_channels; + uint_fast32_t audio_samplerate; + uint_fast32_t bitrate_maximum; + uint_fast32_t bitrate_nominal; + uint_fast32_t bitrate_minimum; + uint_fast32_t blocksize[2]; + const float *win[2]; + uint_fast16_t codebook_count; + vorbis_codebook *codebooks; + uint_fast8_t floor_count; + vorbis_floor *floors; + uint_fast8_t residue_count; + vorbis_residue *residues; + uint_fast8_t mapping_count; + vorbis_mapping *mappings; + uint_fast8_t mode_count; + vorbis_mode *modes; + uint_fast8_t mode_number; // mode number for the current packet + uint_fast8_t previous_window; + float *channel_residues; + float *channel_floors; + float *saved; + float scale_bias; // for float->int conversion +} vorbis_context; + +/* Helper functions */ + +#define BARK(x) \ + (13.1f * atan(0.00074f * (x)) + 2.24f * atan(1.85e-8f * (x) * (x)) + 1e-4f * (x)) + +static const char idx_err_str[] = "Index value %d out of range (0 - %d) for %s at %s:%i\n"; +#define VALIDATE_INDEX(idx, limit) \ + if (idx >= limit) {\ + av_log(vc->avccontext, AV_LOG_ERROR,\ + idx_err_str,\ + (int)(idx), (int)(limit - 1), #idx, __FILE__, __LINE__);\ + return -1;\ + } +#define GET_VALIDATED_INDEX(idx, bits, limit) \ + {\ + idx = get_bits(gb, bits);\ + VALIDATE_INDEX(idx, limit)\ + } + +static float vorbisfloat2float(uint_fast32_t val) +{ + double mant = val & 0x1fffff; + long exp = (val & 0x7fe00000L) >> 21; + if (val & 0x80000000) + mant = -mant; + return ldexp(mant, exp - 20 - 768); +} + + +// Free all allocated memory ----------------------------------------- + +static void vorbis_free(vorbis_context *vc) +{ + int_fast16_t i; + + av_freep(&vc->channel_residues); + av_freep(&vc->channel_floors); + av_freep(&vc->saved); + + for (i = 0; i < vc->residue_count; i++) + av_free(vc->residues[i].classifs); + av_freep(&vc->residues); + av_freep(&vc->modes); + + ff_mdct_end(&vc->mdct[0]); + ff_mdct_end(&vc->mdct[1]); + + for (i = 0; i < vc->codebook_count; ++i) { + av_free(vc->codebooks[i].codevectors); + free_vlc(&vc->codebooks[i].vlc); + } + av_freep(&vc->codebooks); + + for (i = 0; i < vc->floor_count; ++i) { + if (vc->floors[i].floor_type == 0) { + av_free(vc->floors[i].data.t0.map[0]); + av_free(vc->floors[i].data.t0.map[1]); + av_free(vc->floors[i].data.t0.book_list); + av_free(vc->floors[i].data.t0.lsp); + } else { + av_free(vc->floors[i].data.t1.list); + } + } + av_freep(&vc->floors); + + for (i = 0; i < vc->mapping_count; ++i) { + av_free(vc->mappings[i].magnitude); + av_free(vc->mappings[i].angle); + av_free(vc->mappings[i].mux); + } + av_freep(&vc->mappings); +} + +// Parse setup header ------------------------------------------------- + +// Process codebooks part + +static int vorbis_parse_setup_hdr_codebooks(vorbis_context *vc) +{ + uint_fast16_t cb; + uint8_t *tmp_vlc_bits; + uint32_t *tmp_vlc_codes; + GetBitContext *gb = &vc->gb; + uint_fast16_t *codebook_multiplicands; + + vc->codebook_count = get_bits(gb, 8) + 1; + + AV_DEBUG(" Codebooks: %d \n", vc->codebook_count); + + vc->codebooks = av_mallocz(vc->codebook_count * sizeof(vorbis_codebook)); + tmp_vlc_bits = av_mallocz(V_MAX_VLCS * sizeof(uint8_t)); + tmp_vlc_codes = av_mallocz(V_MAX_VLCS * sizeof(uint32_t)); + codebook_multiplicands = av_malloc(V_MAX_VLCS * sizeof(*codebook_multiplicands)); + + for (cb = 0; cb < vc->codebook_count; ++cb) { + vorbis_codebook *codebook_setup = &vc->codebooks[cb]; + uint_fast8_t ordered; + uint_fast32_t t, used_entries = 0; + uint_fast32_t entries; + + AV_DEBUG(" %d. Codebook \n", cb); + + if (get_bits(gb, 24) != 0x564342) { + av_log(vc->avccontext, AV_LOG_ERROR, " %"PRIdFAST16". Codebook setup data corrupt. \n", cb); + goto error; + } + + codebook_setup->dimensions=get_bits(gb, 16); + if (codebook_setup->dimensions > 16 || codebook_setup->dimensions == 0) { + av_log(vc->avccontext, AV_LOG_ERROR, " %"PRIdFAST16". Codebook's dimension is invalid (%d). \n", cb, codebook_setup->dimensions); + goto error; + } + entries = get_bits(gb, 24); + if (entries > V_MAX_VLCS) { + av_log(vc->avccontext, AV_LOG_ERROR, " %"PRIdFAST16". Codebook has too many entries (%"PRIdFAST32"). \n", cb, entries); + goto error; + } + + ordered = get_bits1(gb); + + AV_DEBUG(" codebook_dimensions %d, codebook_entries %d \n", codebook_setup->dimensions, entries); + + if (!ordered) { + uint_fast16_t ce; + uint_fast8_t flag; + uint_fast8_t sparse = get_bits1(gb); + + AV_DEBUG(" not ordered \n"); + + if (sparse) { + AV_DEBUG(" sparse \n"); + + used_entries = 0; + for (ce = 0; ce < entries; ++ce) { + flag = get_bits1(gb); + if (flag) { + tmp_vlc_bits[ce] = get_bits(gb, 5) + 1; + ++used_entries; + } else + tmp_vlc_bits[ce] = 0; + } + } else { + AV_DEBUG(" not sparse \n"); + + used_entries = entries; + for (ce = 0; ce < entries; ++ce) + tmp_vlc_bits[ce] = get_bits(gb, 5) + 1; + } + } else { + uint_fast16_t current_entry = 0; + uint_fast8_t current_length = get_bits(gb, 5)+1; + + AV_DEBUG(" ordered, current length: %d \n", current_length); //FIXME + + used_entries = entries; + for (; current_entry < used_entries && current_length <= 32; ++current_length) { + uint_fast16_t i, number; + + AV_DEBUG(" number bits: %d ", ilog(entries - current_entry)); + + number = get_bits(gb, ilog(entries - current_entry)); + + AV_DEBUG(" number: %d \n", number); + + for (i = current_entry; i < number+current_entry; ++i) + if (i < used_entries) + tmp_vlc_bits[i] = current_length; + + current_entry+=number; + } + if (current_entry>used_entries) { + av_log(vc->avccontext, AV_LOG_ERROR, " More codelengths than codes in codebook. \n"); + goto error; + } + } + + codebook_setup->lookup_type = get_bits(gb, 4); + + AV_DEBUG(" lookup type: %d : %s \n", codebook_setup->lookup_type, codebook_setup->lookup_type ? "vq" : "no lookup"); + +// If the codebook is used for (inverse) VQ, calculate codevectors. + + if (codebook_setup->lookup_type == 1) { + uint_fast16_t i, j, k; + uint_fast16_t codebook_lookup_values = ff_vorbis_nth_root(entries, codebook_setup->dimensions); + + float codebook_minimum_value = vorbisfloat2float(get_bits_long(gb, 32)); + float codebook_delta_value = vorbisfloat2float(get_bits_long(gb, 32)); + uint_fast8_t codebook_value_bits = get_bits(gb, 4)+1; + uint_fast8_t codebook_sequence_p = get_bits1(gb); + + AV_DEBUG(" We expect %d numbers for building the codevectors. \n", codebook_lookup_values); + AV_DEBUG(" delta %f minmum %f \n", codebook_delta_value, codebook_minimum_value); + + for (i = 0; i < codebook_lookup_values; ++i) { + codebook_multiplicands[i] = get_bits(gb, codebook_value_bits); + + AV_DEBUG(" multiplicands*delta+minmum : %e \n", (float)codebook_multiplicands[i]*codebook_delta_value+codebook_minimum_value); + AV_DEBUG(" multiplicand %d \n", codebook_multiplicands[i]); + } + +// Weed out unused vlcs and build codevector vector + codebook_setup->codevectors = used_entries ? av_mallocz(used_entries*codebook_setup->dimensions * sizeof(float)) : NULL; + for (j = 0, i = 0; i < entries; ++i) { + uint_fast8_t dim = codebook_setup->dimensions; + + if (tmp_vlc_bits[i]) { + float last = 0.0; + uint_fast32_t lookup_offset = i; + +#ifdef V_DEBUG + av_log(vc->avccontext, AV_LOG_INFO, "Lookup offset %d ,", i); +#endif + + for (k = 0; k < dim; ++k) { + uint_fast32_t multiplicand_offset = lookup_offset % codebook_lookup_values; + codebook_setup->codevectors[j * dim + k] = codebook_multiplicands[multiplicand_offset] * codebook_delta_value + codebook_minimum_value + last; + if (codebook_sequence_p) + last = codebook_setup->codevectors[j * dim + k]; + lookup_offset/=codebook_lookup_values; + } + tmp_vlc_bits[j] = tmp_vlc_bits[i]; + +#ifdef V_DEBUG + av_log(vc->avccontext, AV_LOG_INFO, "real lookup offset %d, vector: ", j); + for (k = 0; k < dim; ++k) + av_log(vc->avccontext, AV_LOG_INFO, " %f ", codebook_setup->codevectors[j * dim + k]); + av_log(vc->avccontext, AV_LOG_INFO, "\n"); +#endif + + ++j; + } + } + if (j != used_entries) { + av_log(vc->avccontext, AV_LOG_ERROR, "Bug in codevector vector building code. \n"); + goto error; + } + entries = used_entries; + } else if (codebook_setup->lookup_type >= 2) { + av_log(vc->avccontext, AV_LOG_ERROR, "Codebook lookup type not supported. \n"); + goto error; + } + +// Initialize VLC table + if (ff_vorbis_len2vlc(tmp_vlc_bits, tmp_vlc_codes, entries)) { + av_log(vc->avccontext, AV_LOG_ERROR, " Invalid code lengths while generating vlcs. \n"); + goto error; + } + codebook_setup->maxdepth = 0; + for (t = 0; t < entries; ++t) + if (tmp_vlc_bits[t] >= codebook_setup->maxdepth) + codebook_setup->maxdepth = tmp_vlc_bits[t]; + + if (codebook_setup->maxdepth > 3 * V_NB_BITS) + codebook_setup->nb_bits = V_NB_BITS2; + else + codebook_setup->nb_bits = V_NB_BITS; + + codebook_setup->maxdepth = (codebook_setup->maxdepth+codebook_setup->nb_bits - 1) / codebook_setup->nb_bits; + + if (init_vlc(&codebook_setup->vlc, codebook_setup->nb_bits, entries, tmp_vlc_bits, sizeof(*tmp_vlc_bits), sizeof(*tmp_vlc_bits), tmp_vlc_codes, sizeof(*tmp_vlc_codes), sizeof(*tmp_vlc_codes), INIT_VLC_LE)) { + av_log(vc->avccontext, AV_LOG_ERROR, " Error generating vlc tables. \n"); + goto error; + } + } + + av_free(tmp_vlc_bits); + av_free(tmp_vlc_codes); + av_free(codebook_multiplicands); + return 0; + +// Error: +error: + av_free(tmp_vlc_bits); + av_free(tmp_vlc_codes); + av_free(codebook_multiplicands); + return -1; +} + +// Process time domain transforms part (unused in Vorbis I) + +static int vorbis_parse_setup_hdr_tdtransforms(vorbis_context *vc) +{ + GetBitContext *gb = &vc->gb; + uint_fast8_t i; + uint_fast8_t vorbis_time_count = get_bits(gb, 6) + 1; + + for (i = 0; i < vorbis_time_count; ++i) { + uint_fast16_t vorbis_tdtransform = get_bits(gb, 16); + + AV_DEBUG(" Vorbis time domain transform %d: %d \n", vorbis_time_count, vorbis_tdtransform); + + if (vorbis_tdtransform) { + av_log(vc->avccontext, AV_LOG_ERROR, "Vorbis time domain transform data nonzero. \n"); + return -1; + } + } + return 0; +} + +// Process floors part + +static int vorbis_floor0_decode(vorbis_context *vc, + vorbis_floor_data *vfu, float *vec); +static void create_map(vorbis_context *vc, uint_fast8_t floor_number); +static int vorbis_floor1_decode(vorbis_context *vc, + vorbis_floor_data *vfu, float *vec); +static int vorbis_parse_setup_hdr_floors(vorbis_context *vc) +{ + GetBitContext *gb = &vc->gb; + int i,j,k; + + vc->floor_count = get_bits(gb, 6) + 1; + + vc->floors = av_mallocz(vc->floor_count * sizeof(vorbis_floor)); + + for (i = 0; i < vc->floor_count; ++i) { + vorbis_floor *floor_setup = &vc->floors[i]; + + floor_setup->floor_type = get_bits(gb, 16); + + AV_DEBUG(" %d. floor type %d \n", i, floor_setup->floor_type); + + if (floor_setup->floor_type == 1) { + int maximum_class = -1; + uint_fast8_t rangebits; + uint_fast32_t rangemax; + uint_fast16_t floor1_values = 2; + + floor_setup->decode = vorbis_floor1_decode; + + floor_setup->data.t1.partitions = get_bits(gb, 5); + + AV_DEBUG(" %d.floor: %d partitions \n", i, floor_setup->data.t1.partitions); + + for (j = 0; j < floor_setup->data.t1.partitions; ++j) { + floor_setup->data.t1.partition_class[j] = get_bits(gb, 4); + if (floor_setup->data.t1.partition_class[j] > maximum_class) + maximum_class = floor_setup->data.t1.partition_class[j]; + + AV_DEBUG(" %d. floor %d partition class %d \n", i, j, floor_setup->data.t1.partition_class[j]); + + } + + AV_DEBUG(" maximum class %d \n", maximum_class); + + for (j = 0; j <= maximum_class; ++j) { + floor_setup->data.t1.class_dimensions[j] = get_bits(gb, 3) + 1; + floor_setup->data.t1.class_subclasses[j] = get_bits(gb, 2); + + AV_DEBUG(" %d floor %d class dim: %d subclasses %d \n", i, j, floor_setup->data.t1.class_dimensions[j], floor_setup->data.t1.class_subclasses[j]); + + if (floor_setup->data.t1.class_subclasses[j]) { + GET_VALIDATED_INDEX(floor_setup->data.t1.class_masterbook[j], 8, vc->codebook_count) + + AV_DEBUG(" masterbook: %d \n", floor_setup->data.t1.class_masterbook[j]); + } + + for (k = 0; k < (1 << floor_setup->data.t1.class_subclasses[j]); ++k) { + int16_t bits = get_bits(gb, 8) - 1; + if (bits != -1) + VALIDATE_INDEX(bits, vc->codebook_count) + floor_setup->data.t1.subclass_books[j][k] = bits; + + AV_DEBUG(" book %d. : %d \n", k, floor_setup->data.t1.subclass_books[j][k]); + } + } + + floor_setup->data.t1.multiplier = get_bits(gb, 2) + 1; + floor_setup->data.t1.x_list_dim = 2; + + for (j = 0; j < floor_setup->data.t1.partitions; ++j) + floor_setup->data.t1.x_list_dim+=floor_setup->data.t1.class_dimensions[floor_setup->data.t1.partition_class[j]]; + + floor_setup->data.t1.list = av_mallocz(floor_setup->data.t1.x_list_dim * sizeof(vorbis_floor1_entry)); + + + rangebits = get_bits(gb, 4); + rangemax = (1 << rangebits); + if (rangemax > vc->blocksize[1] / 2) { + av_log(vc->avccontext, AV_LOG_ERROR, + "Floor value is too large for blocksize: %d (%d)\n", + rangemax, vc->blocksize[1] / 2); + return -1; + } + floor_setup->data.t1.list[0].x = 0; + floor_setup->data.t1.list[1].x = rangemax; + + for (j = 0; j < floor_setup->data.t1.partitions; ++j) { + for (k = 0; k < floor_setup->data.t1.class_dimensions[floor_setup->data.t1.partition_class[j]]; ++k, ++floor1_values) { + floor_setup->data.t1.list[floor1_values].x = get_bits(gb, rangebits); + + AV_DEBUG(" %d. floor1 Y coord. %d \n", floor1_values, floor_setup->data.t1.list[floor1_values].x); + } + } + +// Precalculate order of x coordinates - needed for decode + ff_vorbis_ready_floor1_list(floor_setup->data.t1.list, floor_setup->data.t1.x_list_dim); + } else if (floor_setup->floor_type == 0) { + uint_fast8_t max_codebook_dim = 0; + + floor_setup->decode = vorbis_floor0_decode; + + floor_setup->data.t0.order = get_bits(gb, 8); + floor_setup->data.t0.rate = get_bits(gb, 16); + floor_setup->data.t0.bark_map_size = get_bits(gb, 16); + floor_setup->data.t0.amplitude_bits = get_bits(gb, 6); + /* zero would result in a div by zero later * + * 2^0 - 1 == 0 */ + if (floor_setup->data.t0.amplitude_bits == 0) { + av_log(vc->avccontext, AV_LOG_ERROR, + "Floor 0 amplitude bits is 0.\n"); + return -1; + } + floor_setup->data.t0.amplitude_offset = get_bits(gb, 8); + floor_setup->data.t0.num_books = get_bits(gb, 4) + 1; + + /* allocate mem for booklist */ + floor_setup->data.t0.book_list = + av_malloc(floor_setup->data.t0.num_books); + if (!floor_setup->data.t0.book_list) + return -1; + /* read book indexes */ + { + int idx; + uint_fast8_t book_idx; + for (idx = 0; idx < floor_setup->data.t0.num_books; ++idx) { + GET_VALIDATED_INDEX(book_idx, 8, vc->codebook_count) + floor_setup->data.t0.book_list[idx] = book_idx; + if (vc->codebooks[book_idx].dimensions > max_codebook_dim) + max_codebook_dim = vc->codebooks[book_idx].dimensions; + } + } + + create_map(vc, i); + + /* codebook dim is for padding if codebook dim doesn't * + * divide order+1 then we need to read more data */ + floor_setup->data.t0.lsp = + av_malloc((floor_setup->data.t0.order+1 + max_codebook_dim) + * sizeof(float)); + if (!floor_setup->data.t0.lsp) + return -1; + +#ifdef V_DEBUG /* debug output parsed headers */ + AV_DEBUG("floor0 order: %u\n", floor_setup->data.t0.order); + AV_DEBUG("floor0 rate: %u\n", floor_setup->data.t0.rate); + AV_DEBUG("floor0 bark map size: %u\n", + floor_setup->data.t0.bark_map_size); + AV_DEBUG("floor0 amplitude bits: %u\n", + floor_setup->data.t0.amplitude_bits); + AV_DEBUG("floor0 amplitude offset: %u\n", + floor_setup->data.t0.amplitude_offset); + AV_DEBUG("floor0 number of books: %u\n", + floor_setup->data.t0.num_books); + AV_DEBUG("floor0 book list pointer: %p\n", + floor_setup->data.t0.book_list); + { + int idx; + for (idx = 0; idx < floor_setup->data.t0.num_books; ++idx) { + AV_DEBUG(" Book %d: %u\n", + idx+1, + floor_setup->data.t0.book_list[idx]); + } + } +#endif + } else { + av_log(vc->avccontext, AV_LOG_ERROR, "Invalid floor type!\n"); + return -1; + } + } + return 0; +} + +// Process residues part + +static int vorbis_parse_setup_hdr_residues(vorbis_context *vc) +{ + GetBitContext *gb = &vc->gb; + uint_fast8_t i, j, k; + + vc->residue_count = get_bits(gb, 6)+1; + vc->residues = av_mallocz(vc->residue_count * sizeof(vorbis_residue)); + + AV_DEBUG(" There are %d residues. \n", vc->residue_count); + + for (i = 0; i < vc->residue_count; ++i) { + vorbis_residue *res_setup = &vc->residues[i]; + uint_fast8_t cascade[64]; + uint_fast8_t high_bits; + uint_fast8_t low_bits; + + res_setup->type = get_bits(gb, 16); + + AV_DEBUG(" %d. residue type %d \n", i, res_setup->type); + + res_setup->begin = get_bits(gb, 24); + res_setup->end = get_bits(gb, 24); + res_setup->partition_size = get_bits(gb, 24) + 1; + /* Validations to prevent a buffer overflow later. */ + if (res_setup->begin>res_setup->end || + res_setup->end > vc->avccontext->channels * vc->blocksize[1] / 2 || + (res_setup->end-res_setup->begin) / res_setup->partition_size > V_MAX_PARTITIONS) { + av_log(vc->avccontext, AV_LOG_ERROR, "partition out of bounds: type, begin, end, size, blocksize: %"PRIdFAST16", %"PRIdFAST32", %"PRIdFAST32", %u, %"PRIdFAST32"\n", res_setup->type, res_setup->begin, res_setup->end, res_setup->partition_size, vc->blocksize[1] / 2); + return -1; + } + + res_setup->classifications = get_bits(gb, 6) + 1; + GET_VALIDATED_INDEX(res_setup->classbook, 8, vc->codebook_count) + + res_setup->ptns_to_read = + (res_setup->end - res_setup->begin) / res_setup->partition_size; + res_setup->classifs = av_malloc(res_setup->ptns_to_read * + vc->audio_channels * + sizeof(*res_setup->classifs)); + if (!res_setup->classifs) + return AVERROR(ENOMEM); + + AV_DEBUG(" begin %d end %d part.size %d classif.s %d classbook %d \n", res_setup->begin, res_setup->end, res_setup->partition_size, + res_setup->classifications, res_setup->classbook); + + for (j = 0; j < res_setup->classifications; ++j) { + high_bits = 0; + low_bits = get_bits(gb, 3); + if (get_bits1(gb)) + high_bits = get_bits(gb, 5); + cascade[j] = (high_bits << 3) + low_bits; + + AV_DEBUG(" %d class casscade depth: %d \n", j, ilog(cascade[j])); + } + + res_setup->maxpass = 0; + for (j = 0; j < res_setup->classifications; ++j) { + for (k = 0; k < 8; ++k) { + if (cascade[j]&(1 << k)) { + GET_VALIDATED_INDEX(res_setup->books[j][k], 8, vc->codebook_count) + + AV_DEBUG(" %d class casscade depth %d book: %d \n", j, k, res_setup->books[j][k]); + + if (k>res_setup->maxpass) + res_setup->maxpass = k; + } else { + res_setup->books[j][k] = -1; + } + } + } + } + return 0; +} + +// Process mappings part + +static int vorbis_parse_setup_hdr_mappings(vorbis_context *vc) +{ + GetBitContext *gb = &vc->gb; + uint_fast8_t i, j; + + vc->mapping_count = get_bits(gb, 6)+1; + vc->mappings = av_mallocz(vc->mapping_count * sizeof(vorbis_mapping)); + + AV_DEBUG(" There are %d mappings. \n", vc->mapping_count); + + for (i = 0; i < vc->mapping_count; ++i) { + vorbis_mapping *mapping_setup = &vc->mappings[i]; + + if (get_bits(gb, 16)) { + av_log(vc->avccontext, AV_LOG_ERROR, "Other mappings than type 0 are not compliant with the Vorbis I specification. \n"); + return -1; + } + if (get_bits1(gb)) { + mapping_setup->submaps = get_bits(gb, 4) + 1; + } else { + mapping_setup->submaps = 1; + } + + if (get_bits1(gb)) { + mapping_setup->coupling_steps = get_bits(gb, 8) + 1; + mapping_setup->magnitude = av_mallocz(mapping_setup->coupling_steps * sizeof(uint_fast8_t)); + mapping_setup->angle = av_mallocz(mapping_setup->coupling_steps * sizeof(uint_fast8_t)); + for (j = 0; j < mapping_setup->coupling_steps; ++j) { + GET_VALIDATED_INDEX(mapping_setup->magnitude[j], ilog(vc->audio_channels - 1), vc->audio_channels) + GET_VALIDATED_INDEX(mapping_setup->angle[j], ilog(vc->audio_channels - 1), vc->audio_channels) + } + } else { + mapping_setup->coupling_steps = 0; + } + + AV_DEBUG(" %d mapping coupling steps: %d \n", i, mapping_setup->coupling_steps); + + if (get_bits(gb, 2)) { + av_log(vc->avccontext, AV_LOG_ERROR, "%d. mapping setup data invalid. \n", i); + return -1; // following spec. + } + + if (mapping_setup->submaps>1) { + mapping_setup->mux = av_mallocz(vc->audio_channels * sizeof(uint_fast8_t)); + for (j = 0; j < vc->audio_channels; ++j) + mapping_setup->mux[j] = get_bits(gb, 4); + } + + for (j = 0; j < mapping_setup->submaps; ++j) { + skip_bits(gb, 8); // FIXME check? + GET_VALIDATED_INDEX(mapping_setup->submap_floor[j], 8, vc->floor_count) + GET_VALIDATED_INDEX(mapping_setup->submap_residue[j], 8, vc->residue_count) + + AV_DEBUG(" %d mapping %d submap : floor %d, residue %d \n", i, j, mapping_setup->submap_floor[j], mapping_setup->submap_residue[j]); + } + } + return 0; +} + +// Process modes part + +static void create_map(vorbis_context *vc, uint_fast8_t floor_number) +{ + vorbis_floor *floors = vc->floors; + vorbis_floor0 *vf; + int idx; + int_fast8_t blockflag; + int_fast32_t *map; + int_fast32_t n; //TODO: could theoretically be smaller? + + for (blockflag = 0; blockflag < 2; ++blockflag) { + n = vc->blocksize[blockflag] / 2; + floors[floor_number].data.t0.map[blockflag] = + av_malloc((n+1) * sizeof(int_fast32_t)); // n + sentinel + + map = floors[floor_number].data.t0.map[blockflag]; + vf = &floors[floor_number].data.t0; + + for (idx = 0; idx < n; ++idx) { + map[idx] = floor(BARK((vf->rate * idx) / (2.0f * n)) * + ((vf->bark_map_size) / + BARK(vf->rate / 2.0f))); + if (vf->bark_map_size-1 < map[idx]) + map[idx] = vf->bark_map_size - 1; + } + map[n] = -1; + vf->map_size[blockflag] = n; + } + +#ifdef V_DEBUG + for (idx = 0; idx <= n; ++idx) { + AV_DEBUG("floor0 map: map at pos %d is %d\n", + idx, map[idx]); + } +#endif +} + +static int vorbis_parse_setup_hdr_modes(vorbis_context *vc) +{ + GetBitContext *gb = &vc->gb; + uint_fast8_t i; + + vc->mode_count = get_bits(gb, 6) + 1; + vc->modes = av_mallocz(vc->mode_count * sizeof(vorbis_mode)); + + AV_DEBUG(" There are %d modes.\n", vc->mode_count); + + for (i = 0; i < vc->mode_count; ++i) { + vorbis_mode *mode_setup = &vc->modes[i]; + + mode_setup->blockflag = get_bits1(gb); + mode_setup->windowtype = get_bits(gb, 16); //FIXME check + mode_setup->transformtype = get_bits(gb, 16); //FIXME check + GET_VALIDATED_INDEX(mode_setup->mapping, 8, vc->mapping_count); + + AV_DEBUG(" %d mode: blockflag %d, windowtype %d, transformtype %d, mapping %d \n", i, mode_setup->blockflag, mode_setup->windowtype, mode_setup->transformtype, mode_setup->mapping); + } + return 0; +} + +// Process the whole setup header using the functions above + +static int vorbis_parse_setup_hdr(vorbis_context *vc) +{ + GetBitContext *gb = &vc->gb; + + if ((get_bits(gb, 8) != 'v') || (get_bits(gb, 8) != 'o') || + (get_bits(gb, 8) != 'r') || (get_bits(gb, 8) != 'b') || + (get_bits(gb, 8) != 'i') || (get_bits(gb, 8) != 's')) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (no vorbis signature). \n"); + return -1; + } + + if (vorbis_parse_setup_hdr_codebooks(vc)) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (codebooks). \n"); + return -2; + } + if (vorbis_parse_setup_hdr_tdtransforms(vc)) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (time domain transforms). \n"); + return -3; + } + if (vorbis_parse_setup_hdr_floors(vc)) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (floors). \n"); + return -4; + } + if (vorbis_parse_setup_hdr_residues(vc)) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (residues). \n"); + return -5; + } + if (vorbis_parse_setup_hdr_mappings(vc)) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (mappings). \n"); + return -6; + } + if (vorbis_parse_setup_hdr_modes(vc)) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (modes). \n"); + return -7; + } + if (!get_bits1(gb)) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis setup header packet corrupt (framing flag). \n"); + return -8; // framing flag bit unset error + } + + return 0; +} + +// Process the identification header + +static int vorbis_parse_id_hdr(vorbis_context *vc) +{ + GetBitContext *gb = &vc->gb; + uint_fast8_t bl0, bl1; + + if ((get_bits(gb, 8) != 'v') || (get_bits(gb, 8) != 'o') || + (get_bits(gb, 8) != 'r') || (get_bits(gb, 8) != 'b') || + (get_bits(gb, 8) != 'i') || (get_bits(gb, 8) != 's')) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis id header packet corrupt (no vorbis signature). \n"); + return -1; + } + + vc->version = get_bits_long(gb, 32); //FIXME check 0 + vc->audio_channels = get_bits(gb, 8); + if (vc->audio_channels <= 0) { + av_log(vc->avccontext, AV_LOG_ERROR, "Invalid number of channels\n"); + return -1; + } + vc->audio_samplerate = get_bits_long(gb, 32); + if (vc->audio_samplerate <= 0) { + av_log(vc->avccontext, AV_LOG_ERROR, "Invalid samplerate\n"); + return -1; + } + vc->bitrate_maximum = get_bits_long(gb, 32); + vc->bitrate_nominal = get_bits_long(gb, 32); + vc->bitrate_minimum = get_bits_long(gb, 32); + bl0 = get_bits(gb, 4); + bl1 = get_bits(gb, 4); + vc->blocksize[0] = (1 << bl0); + vc->blocksize[1] = (1 << bl1); + if (bl0 > 13 || bl0 < 6 || bl1 > 13 || bl1 < 6 || bl1 < bl0) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis id header packet corrupt (illegal blocksize). \n"); + return -3; + } + // output format int16 + if (vc->blocksize[1] / 2 * vc->audio_channels * 2 > AVCODEC_MAX_AUDIO_FRAME_SIZE) { + av_log(vc->avccontext, AV_LOG_ERROR, "Vorbis channel count makes " + "output packets too large.\n"); + return -4; + } + vc->win[0] = ff_vorbis_vwin[bl0 - 6]; + vc->win[1] = ff_vorbis_vwin[bl1 - 6]; + + if ((get_bits1(gb)) == 0) { + av_log(vc->avccontext, AV_LOG_ERROR, " Vorbis id header packet corrupt (framing flag not set). \n"); + return -2; + } + + vc->channel_residues = av_malloc((vc->blocksize[1] / 2) * vc->audio_channels * sizeof(float)); + vc->channel_floors = av_malloc((vc->blocksize[1] / 2) * vc->audio_channels * sizeof(float)); + vc->saved = av_mallocz((vc->blocksize[1] / 4) * vc->audio_channels * sizeof(float)); + vc->previous_window = 0; + + ff_mdct_init(&vc->mdct[0], bl0, 1, -vc->scale_bias); + ff_mdct_init(&vc->mdct[1], bl1, 1, -vc->scale_bias); + + AV_DEBUG(" vorbis version %d \n audio_channels %d \n audio_samplerate %d \n bitrate_max %d \n bitrate_nom %d \n bitrate_min %d \n blk_0 %d blk_1 %d \n ", + vc->version, vc->audio_channels, vc->audio_samplerate, vc->bitrate_maximum, vc->bitrate_nominal, vc->bitrate_minimum, vc->blocksize[0], vc->blocksize[1]); + +/* + BLK = vc->blocksize[0]; + for (i = 0; i < BLK / 2; ++i) { + vc->win[0][i] = sin(0.5*3.14159265358*(sin(((float)i + 0.5) / (float)BLK*3.14159265358))*(sin(((float)i + 0.5) / (float)BLK*3.14159265358))); + } +*/ + + return 0; +} + +// Process the extradata using the functions above (identification header, setup header) + +static av_cold int vorbis_decode_init(AVCodecContext *avccontext) +{ + vorbis_context *vc = avccontext->priv_data ; + uint8_t *headers = avccontext->extradata; + int headers_len = avccontext->extradata_size; + uint8_t *header_start[3]; + int header_len[3]; + GetBitContext *gb = &(vc->gb); + int hdr_type; + + vc->avccontext = avccontext; + dsputil_init(&vc->dsp, avccontext); + ff_fmt_convert_init(&vc->fmt_conv, avccontext); + + vc->scale_bias = 32768.0f; + + if (!headers_len) { + av_log(avccontext, AV_LOG_ERROR, "Extradata missing.\n"); + return -1; + } + + if (ff_split_xiph_headers(headers, headers_len, 30, header_start, header_len) < 0) { + av_log(avccontext, AV_LOG_ERROR, "Extradata corrupt.\n"); + return -1; + } + + init_get_bits(gb, header_start[0], header_len[0]*8); + hdr_type = get_bits(gb, 8); + if (hdr_type != 1) { + av_log(avccontext, AV_LOG_ERROR, "First header is not the id header.\n"); + return -1; + } + if (vorbis_parse_id_hdr(vc)) { + av_log(avccontext, AV_LOG_ERROR, "Id header corrupt.\n"); + vorbis_free(vc); + return -1; + } + + init_get_bits(gb, header_start[2], header_len[2]*8); + hdr_type = get_bits(gb, 8); + if (hdr_type != 5) { + av_log(avccontext, AV_LOG_ERROR, "Third header is not the setup header.\n"); + vorbis_free(vc); + return -1; + } + if (vorbis_parse_setup_hdr(vc)) { + av_log(avccontext, AV_LOG_ERROR, "Setup header corrupt.\n"); + vorbis_free(vc); + return -1; + } + + if (vc->audio_channels > 8) + avccontext->channel_layout = 0; + else + avccontext->channel_layout = ff_vorbis_channel_layouts[vc->audio_channels - 1]; + + avccontext->channels = vc->audio_channels; + avccontext->sample_rate = vc->audio_samplerate; + avccontext->frame_size = FFMIN(vc->blocksize[0], vc->blocksize[1]) >> 2; + avccontext->sample_fmt = AV_SAMPLE_FMT_S16; + + return 0 ; +} + +// Decode audiopackets ------------------------------------------------- + +// Read and decode floor + +static int vorbis_floor0_decode(vorbis_context *vc, + vorbis_floor_data *vfu, float *vec) +{ + vorbis_floor0 *vf = &vfu->t0; + float *lsp = vf->lsp; + uint_fast32_t amplitude; + uint_fast32_t book_idx; + uint_fast8_t blockflag = vc->modes[vc->mode_number].blockflag; + + amplitude = get_bits(&vc->gb, vf->amplitude_bits); + if (amplitude > 0) { + float last = 0; + uint_fast16_t lsp_len = 0; + uint_fast16_t idx; + vorbis_codebook codebook; + + book_idx = get_bits(&vc->gb, ilog(vf->num_books)); + if (book_idx >= vf->num_books) { + av_log(vc->avccontext, AV_LOG_ERROR, + "floor0 dec: booknumber too high!\n"); + book_idx = 0; + } + AV_DEBUG("floor0 dec: booknumber: %u\n", book_idx); + codebook = vc->codebooks[vf->book_list[book_idx]]; + /* Invalid codebook! */ + if (!codebook.codevectors) + return -1; + + while (lsp_lenorder) { + int vec_off; + + AV_DEBUG("floor0 dec: book dimension: %d\n", codebook.dimensions); + AV_DEBUG("floor0 dec: maximum depth: %d\n", codebook.maxdepth); + /* read temp vector */ + vec_off = get_vlc2(&vc->gb, codebook.vlc.table, + codebook.nb_bits, codebook.maxdepth) + * codebook.dimensions; + AV_DEBUG("floor0 dec: vector offset: %d\n", vec_off); + /* copy each vector component and add last to it */ + for (idx = 0; idx < codebook.dimensions; ++idx) + lsp[lsp_len+idx] = codebook.codevectors[vec_off+idx] + last; + last = lsp[lsp_len+idx-1]; /* set last to last vector component */ + + lsp_len += codebook.dimensions; + } +#ifdef V_DEBUG + /* DEBUG: output lsp coeffs */ + { + int idx; + for (idx = 0; idx < lsp_len; ++idx) + AV_DEBUG("floor0 dec: coeff at %d is %f\n", idx, lsp[idx]); + } +#endif + + /* synthesize floor output vector */ + { + int i; + int order = vf->order; + float wstep = M_PI / vf->bark_map_size; + + for (i = 0; i < order; i++) + lsp[i] = 2.0f * cos(lsp[i]); + + AV_DEBUG("floor0 synth: map_size = %d; m = %d; wstep = %f\n", + vf->map_size, order, wstep); + + i = 0; + while (i < vf->map_size[blockflag]) { + int j, iter_cond = vf->map[blockflag][i]; + float p = 0.5f; + float q = 0.5f; + float two_cos_w = 2.0f * cos(wstep * iter_cond); // needed all times + + /* similar part for the q and p products */ + for (j = 0; j + 1 < order; j += 2) { + q *= lsp[j] - two_cos_w; + p *= lsp[j + 1] - two_cos_w; + } + if (j == order) { // even order + p *= p * (2.0f - two_cos_w); + q *= q * (2.0f + two_cos_w); + } else { // odd order + q *= two_cos_w-lsp[j]; // one more time for q + + /* final step and square */ + p *= p * (4.f - two_cos_w * two_cos_w); + q *= q; + } + + /* calculate linear floor value */ + q = exp((((amplitude*vf->amplitude_offset) / + (((1 << vf->amplitude_bits) - 1) * sqrt(p + q))) + - vf->amplitude_offset) * .11512925f); + + /* fill vector */ + do { + vec[i] = q; ++i; + } while (vf->map[blockflag][i] == iter_cond); + } + } + } else { + /* this channel is unused */ + return 1; + } + + AV_DEBUG(" Floor0 decoded\n"); + + return 0; +} + +static int vorbis_floor1_decode(vorbis_context *vc, + vorbis_floor_data *vfu, float *vec) +{ + vorbis_floor1 *vf = &vfu->t1; + GetBitContext *gb = &vc->gb; + uint_fast16_t range_v[4] = { 256, 128, 86, 64 }; + uint_fast16_t range = range_v[vf->multiplier-1]; + uint_fast16_t floor1_Y[258]; + uint_fast16_t floor1_Y_final[258]; + int floor1_flag[258]; + uint_fast8_t class_; + uint_fast8_t cdim; + uint_fast8_t cbits; + uint_fast8_t csub; + uint_fast8_t cval; + int_fast16_t book; + uint_fast16_t offset; + uint_fast16_t i,j; + int_fast16_t adx, ady, dy, off, predicted; + int_fast32_t err; + + + if (!get_bits1(gb)) // silence + return 1; + +// Read values (or differences) for the floor's points + + floor1_Y[0] = get_bits(gb, ilog(range - 1)); + floor1_Y[1] = get_bits(gb, ilog(range - 1)); + + AV_DEBUG("floor 0 Y %d floor 1 Y %d \n", floor1_Y[0], floor1_Y[1]); + + offset = 2; + for (i = 0; i < vf->partitions; ++i) { + class_ = vf->partition_class[i]; + cdim = vf->class_dimensions[class_]; + cbits = vf->class_subclasses[class_]; + csub = (1 << cbits) - 1; + cval = 0; + + AV_DEBUG("Cbits %d \n", cbits); + + if (cbits) // this reads all subclasses for this partition's class + cval = get_vlc2(gb, vc->codebooks[vf->class_masterbook[class_]].vlc.table, + vc->codebooks[vf->class_masterbook[class_]].nb_bits, 3); + + for (j = 0; j < cdim; ++j) { + book = vf->subclass_books[class_][cval & csub]; + + AV_DEBUG("book %d Cbits %d cval %d bits:%d \n", book, cbits, cval, get_bits_count(gb)); + + cval = cval >> cbits; + if (book > -1) { + floor1_Y[offset+j] = get_vlc2(gb, vc->codebooks[book].vlc.table, + vc->codebooks[book].nb_bits, 3); + } else { + floor1_Y[offset+j] = 0; + } + + AV_DEBUG(" floor(%d) = %d \n", vf->list[offset+j].x, floor1_Y[offset+j]); + } + offset+=cdim; + } + +// Amplitude calculation from the differences + + floor1_flag[0] = 1; + floor1_flag[1] = 1; + floor1_Y_final[0] = floor1_Y[0]; + floor1_Y_final[1] = floor1_Y[1]; + + for (i = 2; i < vf->x_list_dim; ++i) { + uint_fast16_t val, highroom, lowroom, room; + uint_fast16_t high_neigh_offs; + uint_fast16_t low_neigh_offs; + + low_neigh_offs = vf->list[i].low; + high_neigh_offs = vf->list[i].high; + dy = floor1_Y_final[high_neigh_offs] - floor1_Y_final[low_neigh_offs]; // render_point begin + adx = vf->list[high_neigh_offs].x - vf->list[low_neigh_offs].x; + ady = FFABS(dy); + err = ady * (vf->list[i].x - vf->list[low_neigh_offs].x); + off = err / adx; + if (dy < 0) { + predicted = floor1_Y_final[low_neigh_offs] - off; + } else { + predicted = floor1_Y_final[low_neigh_offs] + off; + } // render_point end + + val = floor1_Y[i]; + highroom = range-predicted; + lowroom = predicted; + if (highroom < lowroom) { + room = highroom * 2; + } else { + room = lowroom * 2; // SPEC mispelling + } + if (val) { + floor1_flag[low_neigh_offs] = 1; + floor1_flag[high_neigh_offs] = 1; + floor1_flag[i] = 1; + if (val >= room) { + if (highroom > lowroom) { + floor1_Y_final[i] = val - lowroom + predicted; + } else { + floor1_Y_final[i] = predicted - val + highroom - 1; + } + } else { + if (val & 1) { + floor1_Y_final[i] = predicted - (val + 1) / 2; + } else { + floor1_Y_final[i] = predicted + val / 2; + } + } + } else { + floor1_flag[i] = 0; + floor1_Y_final[i] = predicted; + } + + AV_DEBUG(" Decoded floor(%d) = %d / val %d \n", vf->list[i].x, floor1_Y_final[i], val); + } + +// Curve synth - connect the calculated dots and convert from dB scale FIXME optimize ? + + ff_vorbis_floor1_render_list(vf->list, vf->x_list_dim, floor1_Y_final, floor1_flag, vf->multiplier, vec, vf->list[1].x); + + AV_DEBUG(" Floor decoded\n"); + + return 0; +} + +// Read and decode residue + +static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, + vorbis_residue *vr, + uint_fast8_t ch, + uint_fast8_t *do_not_decode, + float *vec, + uint_fast16_t vlen, + int vr_type) +{ + GetBitContext *gb = &vc->gb; + uint_fast8_t c_p_c = vc->codebooks[vr->classbook].dimensions; + uint_fast16_t ptns_to_read = vr->ptns_to_read; + uint8_t *classifs = vr->classifs; + uint_fast8_t pass; + uint_fast8_t ch_used; + uint_fast8_t i,j,l; + uint_fast16_t k; + + if (vr_type == 2) { + for (j = 1; j < ch; ++j) + do_not_decode[0] &= do_not_decode[j]; // FIXME - clobbering input + if (do_not_decode[0]) + return 0; + ch_used = 1; + } else { + ch_used = ch; + } + + AV_DEBUG(" residue type 0/1/2 decode begin, ch: %d cpc %d \n", ch, c_p_c); + + for (pass = 0; pass <= vr->maxpass; ++pass) { // FIXME OPTIMIZE? + uint_fast16_t voffset; + uint_fast16_t partition_count; + uint_fast16_t j_times_ptns_to_read; + + voffset = vr->begin; + for (partition_count = 0; partition_count < ptns_to_read;) { // SPEC error + if (!pass) { + uint_fast32_t inverse_class = ff_inverse[vr->classifications]; + for (j_times_ptns_to_read = 0, j = 0; j < ch_used; ++j) { + if (!do_not_decode[j]) { + uint_fast32_t temp = get_vlc2(gb, vc->codebooks[vr->classbook].vlc.table, + vc->codebooks[vr->classbook].nb_bits, 3); + + AV_DEBUG("Classword: %d \n", temp); + + assert(vr->classifications > 1 && temp <= 65536); //needed for inverse[] + for (i = 0; i < c_p_c; ++i) { + uint_fast32_t temp2; + + temp2 = (((uint_fast64_t)temp) * inverse_class) >> 32; + if (partition_count + c_p_c - 1 - i < ptns_to_read) + classifs[j_times_ptns_to_read + partition_count + c_p_c - 1 - i] = temp - temp2 * vr->classifications; + temp = temp2; + } + } + j_times_ptns_to_read += ptns_to_read; + } + } + for (i = 0; (i < c_p_c) && (partition_count < ptns_to_read); ++i) { + for (j_times_ptns_to_read = 0, j = 0; j < ch_used; ++j) { + uint_fast16_t voffs; + + if (!do_not_decode[j]) { + uint_fast8_t vqclass = classifs[j_times_ptns_to_read+partition_count]; + int_fast16_t vqbook = vr->books[vqclass][pass]; + + if (vqbook >= 0 && vc->codebooks[vqbook].codevectors) { + uint_fast16_t coffs; + unsigned dim = vc->codebooks[vqbook].dimensions; // not uint_fast8_t: 64bit is slower here on amd64 + uint_fast16_t step = dim == 1 ? vr->partition_size + : FASTDIV(vr->partition_size, dim); + vorbis_codebook codebook = vc->codebooks[vqbook]; + + if (vr_type == 0) { + + voffs = voffset+j*vlen; + for (k = 0; k < step; ++k) { + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; + for (l = 0; l < dim; ++l) + vec[voffs + k + l * step] += codebook.codevectors[coffs + l]; // FPMATH + } + } else if (vr_type == 1) { + voffs = voffset + j * vlen; + for (k = 0; k < step; ++k) { + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; + for (l = 0; l < dim; ++l, ++voffs) { + vec[voffs]+=codebook.codevectors[coffs+l]; // FPMATH + + AV_DEBUG(" pass %d offs: %d curr: %f change: %f cv offs.: %d \n", pass, voffs, vec[voffs], codebook.codevectors[coffs+l], coffs); + } + } + } else if (vr_type == 2 && ch == 2 && (voffset & 1) == 0 && (dim & 1) == 0) { // most frequent case optimized + voffs = voffset >> 1; + + if (dim == 2) { + for (k = 0; k < step; ++k) { + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * 2; + vec[voffs + k ] += codebook.codevectors[coffs ]; // FPMATH + vec[voffs + k + vlen] += codebook.codevectors[coffs + 1]; // FPMATH + } + } else if (dim == 4) { + for (k = 0; k < step; ++k, voffs += 2) { + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * 4; + vec[voffs ] += codebook.codevectors[coffs ]; // FPMATH + vec[voffs + 1 ] += codebook.codevectors[coffs + 2]; // FPMATH + vec[voffs + vlen ] += codebook.codevectors[coffs + 1]; // FPMATH + vec[voffs + vlen + 1] += codebook.codevectors[coffs + 3]; // FPMATH + } + } else + for (k = 0; k < step; ++k) { + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; + for (l = 0; l < dim; l += 2, voffs++) { + vec[voffs ] += codebook.codevectors[coffs + l ]; // FPMATH + vec[voffs + vlen] += codebook.codevectors[coffs + l + 1]; // FPMATH + + AV_DEBUG(" pass %d offs: %d curr: %f change: %f cv offs.: %d+%d \n", pass, voffset / ch + (voffs % ch) * vlen, vec[voffset / ch + (voffs % ch) * vlen], codebook.codevectors[coffs + l], coffs, l); + } + } + + } else if (vr_type == 2) { + voffs = voffset; + + for (k = 0; k < step; ++k) { + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; + for (l = 0; l < dim; ++l, ++voffs) { + vec[voffs / ch + (voffs % ch) * vlen] += codebook.codevectors[coffs + l]; // FPMATH FIXME use if and counter instead of / and % + + AV_DEBUG(" pass %d offs: %d curr: %f change: %f cv offs.: %d+%d \n", pass, voffset / ch + (voffs % ch) * vlen, vec[voffset / ch + (voffs % ch) * vlen], codebook.codevectors[coffs + l], coffs, l); + } + } + } + } + } + j_times_ptns_to_read += ptns_to_read; + } + ++partition_count; + voffset += vr->partition_size; + } + } + } + return 0; +} + +static inline int vorbis_residue_decode(vorbis_context *vc, vorbis_residue *vr, + uint_fast8_t ch, + uint_fast8_t *do_not_decode, + float *vec, uint_fast16_t vlen) +{ + if (vr->type == 2) + return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, 2); + else if (vr->type == 1) + return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, 1); + else if (vr->type == 0) + return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, 0); + else { + av_log(vc->avccontext, AV_LOG_ERROR, " Invalid residue type while residue decode?! \n"); + return -1; + } +} + +void vorbis_inverse_coupling(float *mag, float *ang, int blocksize) +{ + int i; + for (i = 0; i < blocksize; i++) { + if (mag[i] > 0.0) { + if (ang[i] > 0.0) { + ang[i] = mag[i] - ang[i]; + } else { + float temp = ang[i]; + ang[i] = mag[i]; + mag[i] += temp; + } + } else { + if (ang[i] > 0.0) { + ang[i] += mag[i]; + } else { + float temp = ang[i]; + ang[i] = mag[i]; + mag[i] -= temp; + } + } + } +} + +// Decode the audio packet using the functions above + +static int vorbis_parse_audio_packet(vorbis_context *vc) +{ + GetBitContext *gb = &vc->gb; + FFTContext *mdct; + uint_fast8_t previous_window = vc->previous_window; + uint_fast8_t mode_number; + uint_fast8_t blockflag; + uint_fast16_t blocksize; + int_fast32_t i,j; + uint_fast8_t no_residue[255]; + uint_fast8_t do_not_decode[255]; + vorbis_mapping *mapping; + float *ch_res_ptr = vc->channel_residues; + float *ch_floor_ptr = vc->channel_floors; + uint_fast8_t res_chan[255]; + uint_fast8_t res_num = 0; + int_fast16_t retlen = 0; + + if (get_bits1(gb)) { + av_log(vc->avccontext, AV_LOG_ERROR, "Not a Vorbis I audio packet.\n"); + return -1; // packet type not audio + } + + if (vc->mode_count == 1) { + mode_number = 0; + } else { + GET_VALIDATED_INDEX(mode_number, ilog(vc->mode_count-1), vc->mode_count) + } + vc->mode_number = mode_number; + mapping = &vc->mappings[vc->modes[mode_number].mapping]; + + AV_DEBUG(" Mode number: %d , mapping: %d , blocktype %d \n", mode_number, vc->modes[mode_number].mapping, vc->modes[mode_number].blockflag); + + blockflag = vc->modes[mode_number].blockflag; + blocksize = vc->blocksize[blockflag]; + if (blockflag) + skip_bits(gb, 2); // previous_window, next_window + + memset(ch_res_ptr, 0, sizeof(float) * vc->audio_channels * blocksize / 2); //FIXME can this be removed ? + memset(ch_floor_ptr, 0, sizeof(float) * vc->audio_channels * blocksize / 2); //FIXME can this be removed ? + +// Decode floor + + for (i = 0; i < vc->audio_channels; ++i) { + vorbis_floor *floor; + int ret; + if (mapping->submaps > 1) { + floor = &vc->floors[mapping->submap_floor[mapping->mux[i]]]; + } else { + floor = &vc->floors[mapping->submap_floor[0]]; + } + + ret = floor->decode(vc, &floor->data, ch_floor_ptr); + + if (ret < 0) { + av_log(vc->avccontext, AV_LOG_ERROR, "Invalid codebook in vorbis_floor_decode.\n"); + return -1; + } + no_residue[i] = ret; + ch_floor_ptr += blocksize / 2; + } + +// Nonzero vector propagate + + for (i = mapping->coupling_steps - 1; i >= 0; --i) { + if (!(no_residue[mapping->magnitude[i]] & no_residue[mapping->angle[i]])) { + no_residue[mapping->magnitude[i]] = 0; + no_residue[mapping->angle[i]] = 0; + } + } + +// Decode residue + + for (i = 0; i < mapping->submaps; ++i) { + vorbis_residue *residue; + uint_fast8_t ch = 0; + + for (j = 0; j < vc->audio_channels; ++j) { + if ((mapping->submaps == 1) || (i == mapping->mux[j])) { + res_chan[j] = res_num; + if (no_residue[j]) { + do_not_decode[ch] = 1; + } else { + do_not_decode[ch] = 0; + } + ++ch; + ++res_num; + } + } + residue = &vc->residues[mapping->submap_residue[i]]; + vorbis_residue_decode(vc, residue, ch, do_not_decode, ch_res_ptr, blocksize/2); + + ch_res_ptr += ch * blocksize / 2; + } + +// Inverse coupling + + for (i = mapping->coupling_steps - 1; i >= 0; --i) { //warning: i has to be signed + float *mag, *ang; + + mag = vc->channel_residues+res_chan[mapping->magnitude[i]] * blocksize / 2; + ang = vc->channel_residues+res_chan[mapping->angle[i]] * blocksize / 2; + vc->dsp.vorbis_inverse_coupling(mag, ang, blocksize / 2); + } + +// Dotproduct, MDCT + + mdct = &vc->mdct[blockflag]; + + for (j = vc->audio_channels-1;j >= 0; j--) { + ch_floor_ptr = vc->channel_floors + j * blocksize / 2; + ch_res_ptr = vc->channel_residues + res_chan[j] * blocksize / 2; + vc->dsp.vector_fmul(ch_floor_ptr, ch_floor_ptr, ch_res_ptr, blocksize / 2); + mdct->imdct_half(mdct, ch_res_ptr, ch_floor_ptr); + } + +// Overlap/add, save data for next overlapping FPMATH + + retlen = (blocksize + vc->blocksize[previous_window]) / 4; + for (j = 0; j < vc->audio_channels; j++) { + uint_fast16_t bs0 = vc->blocksize[0]; + uint_fast16_t bs1 = vc->blocksize[1]; + float *residue = vc->channel_residues + res_chan[j] * blocksize / 2; + float *saved = vc->saved + j * bs1 / 4; + float *ret = vc->channel_floors + j * retlen; + float *buf = residue; + const float *win = vc->win[blockflag & previous_window]; + + if (blockflag == previous_window) { + vc->dsp.vector_fmul_window(ret, saved, buf, win, blocksize / 4); + } else if (blockflag > previous_window) { + vc->dsp.vector_fmul_window(ret, saved, buf, win, bs0 / 4); + memcpy(ret+bs0/2, buf+bs0/4, ((bs1-bs0)/4) * sizeof(float)); + } else { + memcpy(ret, saved, ((bs1 - bs0) / 4) * sizeof(float)); + vc->dsp.vector_fmul_window(ret + (bs1 - bs0) / 4, saved + (bs1 - bs0) / 4, buf, win, bs0 / 4); + } + memcpy(saved, buf + blocksize / 4, blocksize / 4 * sizeof(float)); + } + + vc->previous_window = blockflag; + return retlen; +} + +// Return the decoded audio packet through the standard api + +static int vorbis_decode_frame(AVCodecContext *avccontext, + void *data, int *data_size, + AVPacket *avpkt) +{ + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; + vorbis_context *vc = avccontext->priv_data ; + GetBitContext *gb = &(vc->gb); + const float *channel_ptrs[255]; + int i; + + int_fast16_t len; + + if (!buf_size) + return 0; + + AV_DEBUG("packet length %d \n", buf_size); + + init_get_bits(gb, buf, buf_size*8); + + len = vorbis_parse_audio_packet(vc); + + if (len <= 0) { + *data_size = 0; + return buf_size; + } + + if (!vc->first_frame) { + vc->first_frame = 1; + *data_size = 0; + return buf_size ; + } + + AV_DEBUG("parsed %d bytes %d bits, returned %d samples (*ch*bits) \n", get_bits_count(gb)/8, get_bits_count(gb)%8, len); + + if (vc->audio_channels > 8) { + for (i = 0; i < vc->audio_channels; i++) + channel_ptrs[i] = vc->channel_floors + i * len; + } else { + for (i = 0; i < vc->audio_channels; i++) + channel_ptrs[i] = vc->channel_floors + + len * ff_vorbis_channel_layout_offsets[vc->audio_channels - 1][i]; + } + + vc->fmt_conv.float_to_int16_interleave(data, channel_ptrs, len, + vc->audio_channels); + *data_size = len * 2 * vc->audio_channels; + + return buf_size ; +} + +// Close decoder + +static av_cold int vorbis_decode_close(AVCodecContext *avccontext) +{ + vorbis_context *vc = avccontext->priv_data; + + vorbis_free(vc); + + return 0 ; +} + +AVCodec ff_vorbis_decoder = { + "vorbis", + AVMEDIA_TYPE_AUDIO, + CODEC_ID_VORBIS, + sizeof(vorbis_context), + vorbis_decode_init, + NULL, + vorbis_decode_close, + vorbis_decode_frame, + .long_name = NULL_IF_CONFIG_SMALL("Vorbis"), + .channel_layouts = ff_vorbis_channel_layouts, +}; + diff --git a/libavcodec/vorbisenc.c b/libavcodec/vorbisenc.c new file mode 100644 index 0000000..74933af --- /dev/null +++ b/libavcodec/vorbisenc.c @@ -0,0 +1,1116 @@ +/* + * copyright (c) 2006 Oded Shimon + * + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Native Vorbis encoder. + * @author Oded Shimon + */ + +#include +#include "avcodec.h" +#include "dsputil.h" +#include "fft.h" +#include "vorbis.h" +#include "vorbis_enc_data.h" + +#define BITSTREAM_WRITER_LE +#include "put_bits.h" + +#undef NDEBUG +#include + +typedef struct { + int nentries; + uint8_t *lens; + uint32_t *codewords; + int ndimentions; + float min; + float delta; + int seq_p; + int lookup; + int *quantlist; + float *dimentions; + float *pow2; +} vorbis_enc_codebook; + +typedef struct { + int dim; + int subclass; + int masterbook; + int *books; +} vorbis_enc_floor_class; + +typedef struct { + int partitions; + int *partition_to_class; + int nclasses; + vorbis_enc_floor_class *classes; + int multiplier; + int rangebits; + int values; + vorbis_floor1_entry *list; +} vorbis_enc_floor; + +typedef struct { + int type; + int begin; + int end; + int partition_size; + int classifications; + int classbook; + int8_t (*books)[8]; + float (*maxes)[2]; +} vorbis_enc_residue; + +typedef struct { + int submaps; + int *mux; + int *floor; + int *residue; + int coupling_steps; + int *magnitude; + int *angle; +} vorbis_enc_mapping; + +typedef struct { + int blockflag; + int mapping; +} vorbis_enc_mode; + +typedef struct { + int channels; + int sample_rate; + int log2_blocksize[2]; + FFTContext mdct[2]; + const float *win[2]; + int have_saved; + float *saved; + float *samples; + float *floor; // also used for tmp values for mdct + float *coeffs; // also used for residue after floor + float quality; + + int ncodebooks; + vorbis_enc_codebook *codebooks; + + int nfloors; + vorbis_enc_floor *floors; + + int nresidues; + vorbis_enc_residue *residues; + + int nmappings; + vorbis_enc_mapping *mappings; + + int nmodes; + vorbis_enc_mode *modes; + + int64_t sample_count; +} vorbis_enc_context; + +#define MAX_CHANNELS 2 +#define MAX_CODEBOOK_DIM 8 + +#define MAX_FLOOR_CLASS_DIM 4 +#define NUM_FLOOR_PARTITIONS 8 +#define MAX_FLOOR_VALUES (MAX_FLOOR_CLASS_DIM*NUM_FLOOR_PARTITIONS+2) + +#define RESIDUE_SIZE 1600 +#define RESIDUE_PART_SIZE 32 +#define NUM_RESIDUE_PARTITIONS (RESIDUE_SIZE/RESIDUE_PART_SIZE) + +static inline void put_codeword(PutBitContext *pb, vorbis_enc_codebook *cb, + int entry) +{ + assert(entry >= 0); + assert(entry < cb->nentries); + assert(cb->lens[entry]); + put_bits(pb, cb->lens[entry], cb->codewords[entry]); +} + +static int cb_lookup_vals(int lookup, int dimentions, int entries) +{ + if (lookup == 1) + return ff_vorbis_nth_root(entries, dimentions); + else if (lookup == 2) + return dimentions *entries; + return 0; +} + +static void ready_codebook(vorbis_enc_codebook *cb) +{ + int i; + + ff_vorbis_len2vlc(cb->lens, cb->codewords, cb->nentries); + + if (!cb->lookup) { + cb->pow2 = cb->dimentions = NULL; + } else { + int vals = cb_lookup_vals(cb->lookup, cb->ndimentions, cb->nentries); + cb->dimentions = av_malloc(sizeof(float) * cb->nentries * cb->ndimentions); + cb->pow2 = av_mallocz(sizeof(float) * cb->nentries); + for (i = 0; i < cb->nentries; i++) { + float last = 0; + int j; + int div = 1; + for (j = 0; j < cb->ndimentions; j++) { + int off; + if (cb->lookup == 1) + off = (i / div) % vals; // lookup type 1 + else + off = i * cb->ndimentions + j; // lookup type 2 + + cb->dimentions[i * cb->ndimentions + j] = last + cb->min + cb->quantlist[off] * cb->delta; + if (cb->seq_p) + last = cb->dimentions[i * cb->ndimentions + j]; + cb->pow2[i] += cb->dimentions[i * cb->ndimentions + j] * cb->dimentions[i * cb->ndimentions + j]; + div *= vals; + } + cb->pow2[i] /= 2.; + } + } +} + +static void ready_residue(vorbis_enc_residue *rc, vorbis_enc_context *venc) +{ + int i; + assert(rc->type == 2); + rc->maxes = av_mallocz(sizeof(float[2]) * rc->classifications); + for (i = 0; i < rc->classifications; i++) { + int j; + vorbis_enc_codebook * cb; + for (j = 0; j < 8; j++) + if (rc->books[i][j] != -1) + break; + if (j == 8) // zero + continue; + cb = &venc->codebooks[rc->books[i][j]]; + assert(cb->ndimentions >= 2); + assert(cb->lookup); + + for (j = 0; j < cb->nentries; j++) { + float a; + if (!cb->lens[j]) + continue; + a = fabs(cb->dimentions[j * cb->ndimentions]); + if (a > rc->maxes[i][0]) + rc->maxes[i][0] = a; + a = fabs(cb->dimentions[j * cb->ndimentions + 1]); + if (a > rc->maxes[i][1]) + rc->maxes[i][1] = a; + } + } + // small bias + for (i = 0; i < rc->classifications; i++) { + rc->maxes[i][0] += 0.8; + rc->maxes[i][1] += 0.8; + } +} + +static void create_vorbis_context(vorbis_enc_context *venc, + AVCodecContext *avccontext) +{ + vorbis_enc_floor *fc; + vorbis_enc_residue *rc; + vorbis_enc_mapping *mc; + int i, book; + + venc->channels = avccontext->channels; + venc->sample_rate = avccontext->sample_rate; + venc->log2_blocksize[0] = venc->log2_blocksize[1] = 11; + + venc->ncodebooks = FF_ARRAY_ELEMS(cvectors); + venc->codebooks = av_malloc(sizeof(vorbis_enc_codebook) * venc->ncodebooks); + + // codebook 0..14 - floor1 book, values 0..255 + // codebook 15 residue masterbook + // codebook 16..29 residue + for (book = 0; book < venc->ncodebooks; book++) { + vorbis_enc_codebook *cb = &venc->codebooks[book]; + int vals; + cb->ndimentions = cvectors[book].dim; + cb->nentries = cvectors[book].real_len; + cb->min = cvectors[book].min; + cb->delta = cvectors[book].delta; + cb->lookup = cvectors[book].lookup; + cb->seq_p = 0; + + cb->lens = av_malloc(sizeof(uint8_t) * cb->nentries); + cb->codewords = av_malloc(sizeof(uint32_t) * cb->nentries); + memcpy(cb->lens, cvectors[book].clens, cvectors[book].len); + memset(cb->lens + cvectors[book].len, 0, cb->nentries - cvectors[book].len); + + if (cb->lookup) { + vals = cb_lookup_vals(cb->lookup, cb->ndimentions, cb->nentries); + cb->quantlist = av_malloc(sizeof(int) * vals); + for (i = 0; i < vals; i++) + cb->quantlist[i] = cvectors[book].quant[i]; + } else { + cb->quantlist = NULL; + } + ready_codebook(cb); + } + + venc->nfloors = 1; + venc->floors = av_malloc(sizeof(vorbis_enc_floor) * venc->nfloors); + + // just 1 floor + fc = &venc->floors[0]; + fc->partitions = NUM_FLOOR_PARTITIONS; + fc->partition_to_class = av_malloc(sizeof(int) * fc->partitions); + fc->nclasses = 0; + for (i = 0; i < fc->partitions; i++) { + static const int a[] = {0, 1, 2, 2, 3, 3, 4, 4}; + fc->partition_to_class[i] = a[i]; + fc->nclasses = FFMAX(fc->nclasses, fc->partition_to_class[i]); + } + fc->nclasses++; + fc->classes = av_malloc(sizeof(vorbis_enc_floor_class) * fc->nclasses); + for (i = 0; i < fc->nclasses; i++) { + vorbis_enc_floor_class * c = &fc->classes[i]; + int j, books; + c->dim = floor_classes[i].dim; + c->subclass = floor_classes[i].subclass; + c->masterbook = floor_classes[i].masterbook; + books = (1 << c->subclass); + c->books = av_malloc(sizeof(int) * books); + for (j = 0; j < books; j++) + c->books[j] = floor_classes[i].nbooks[j]; + } + fc->multiplier = 2; + fc->rangebits = venc->log2_blocksize[0] - 1; + + fc->values = 2; + for (i = 0; i < fc->partitions; i++) + fc->values += fc->classes[fc->partition_to_class[i]].dim; + + fc->list = av_malloc(sizeof(vorbis_floor1_entry) * fc->values); + fc->list[0].x = 0; + fc->list[1].x = 1 << fc->rangebits; + for (i = 2; i < fc->values; i++) { + static const int a[] = { + 93, 23,372, 6, 46,186,750, 14, 33, 65, + 130,260,556, 3, 10, 18, 28, 39, 55, 79, + 111,158,220,312,464,650,850 + }; + fc->list[i].x = a[i - 2]; + } + ff_vorbis_ready_floor1_list(fc->list, fc->values); + + venc->nresidues = 1; + venc->residues = av_malloc(sizeof(vorbis_enc_residue) * venc->nresidues); + + // single residue + rc = &venc->residues[0]; + rc->type = 2; + rc->begin = 0; + rc->end = 1600; + rc->partition_size = 32; + rc->classifications = 10; + rc->classbook = 15; + rc->books = av_malloc(sizeof(*rc->books) * rc->classifications); + { + static const int8_t a[10][8] = { + { -1, -1, -1, -1, -1, -1, -1, -1, }, + { -1, -1, 16, -1, -1, -1, -1, -1, }, + { -1, -1, 17, -1, -1, -1, -1, -1, }, + { -1, -1, 18, -1, -1, -1, -1, -1, }, + { -1, -1, 19, -1, -1, -1, -1, -1, }, + { -1, -1, 20, -1, -1, -1, -1, -1, }, + { -1, -1, 21, -1, -1, -1, -1, -1, }, + { 22, 23, -1, -1, -1, -1, -1, -1, }, + { 24, 25, -1, -1, -1, -1, -1, -1, }, + { 26, 27, 28, -1, -1, -1, -1, -1, }, + }; + memcpy(rc->books, a, sizeof a); + } + ready_residue(rc, venc); + + venc->nmappings = 1; + venc->mappings = av_malloc(sizeof(vorbis_enc_mapping) * venc->nmappings); + + // single mapping + mc = &venc->mappings[0]; + mc->submaps = 1; + mc->mux = av_malloc(sizeof(int) * venc->channels); + for (i = 0; i < venc->channels; i++) + mc->mux[i] = 0; + mc->floor = av_malloc(sizeof(int) * mc->submaps); + mc->residue = av_malloc(sizeof(int) * mc->submaps); + for (i = 0; i < mc->submaps; i++) { + mc->floor[i] = 0; + mc->residue[i] = 0; + } + mc->coupling_steps = venc->channels == 2 ? 1 : 0; + mc->magnitude = av_malloc(sizeof(int) * mc->coupling_steps); + mc->angle = av_malloc(sizeof(int) * mc->coupling_steps); + if (mc->coupling_steps) { + mc->magnitude[0] = 0; + mc->angle[0] = 1; + } + + venc->nmodes = 1; + venc->modes = av_malloc(sizeof(vorbis_enc_mode) * venc->nmodes); + + // single mode + venc->modes[0].blockflag = 0; + venc->modes[0].mapping = 0; + + venc->have_saved = 0; + venc->saved = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1]) / 2); + venc->samples = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1])); + venc->floor = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1]) / 2); + venc->coeffs = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1]) / 2); + + venc->win[0] = ff_vorbis_vwin[venc->log2_blocksize[0] - 6]; + venc->win[1] = ff_vorbis_vwin[venc->log2_blocksize[1] - 6]; + + ff_mdct_init(&venc->mdct[0], venc->log2_blocksize[0], 0, 1.0); + ff_mdct_init(&venc->mdct[1], venc->log2_blocksize[1], 0, 1.0); +} + +static void put_float(PutBitContext *pb, float f) +{ + int exp, mant; + uint32_t res = 0; + mant = (int)ldexp(frexp(f, &exp), 20); + exp += 788 - 20; + if (mant < 0) { + res |= (1U << 31); + mant = -mant; + } + res |= mant | (exp << 21); + put_bits32(pb, res); +} + +static void put_codebook_header(PutBitContext *pb, vorbis_enc_codebook *cb) +{ + int i; + int ordered = 0; + + put_bits(pb, 24, 0x564342); //magic + put_bits(pb, 16, cb->ndimentions); + put_bits(pb, 24, cb->nentries); + + for (i = 1; i < cb->nentries; i++) + if (cb->lens[i] < cb->lens[i-1]) + break; + if (i == cb->nentries) + ordered = 1; + + put_bits(pb, 1, ordered); + if (ordered) { + int len = cb->lens[0]; + put_bits(pb, 5, len - 1); + i = 0; + while (i < cb->nentries) { + int j; + for (j = 0; j+i < cb->nentries; j++) + if (cb->lens[j+i] != len) + break; + put_bits(pb, ilog(cb->nentries - i), j); + i += j; + len++; + } + } else { + int sparse = 0; + for (i = 0; i < cb->nentries; i++) + if (!cb->lens[i]) + break; + if (i != cb->nentries) + sparse = 1; + put_bits(pb, 1, sparse); + + for (i = 0; i < cb->nentries; i++) { + if (sparse) + put_bits(pb, 1, !!cb->lens[i]); + if (cb->lens[i]) + put_bits(pb, 5, cb->lens[i] - 1); + } + } + + put_bits(pb, 4, cb->lookup); + if (cb->lookup) { + int tmp = cb_lookup_vals(cb->lookup, cb->ndimentions, cb->nentries); + int bits = ilog(cb->quantlist[0]); + + for (i = 1; i < tmp; i++) + bits = FFMAX(bits, ilog(cb->quantlist[i])); + + put_float(pb, cb->min); + put_float(pb, cb->delta); + + put_bits(pb, 4, bits - 1); + put_bits(pb, 1, cb->seq_p); + + for (i = 0; i < tmp; i++) + put_bits(pb, bits, cb->quantlist[i]); + } +} + +static void put_floor_header(PutBitContext *pb, vorbis_enc_floor *fc) +{ + int i; + + put_bits(pb, 16, 1); // type, only floor1 is supported + + put_bits(pb, 5, fc->partitions); + + for (i = 0; i < fc->partitions; i++) + put_bits(pb, 4, fc->partition_to_class[i]); + + for (i = 0; i < fc->nclasses; i++) { + int j, books; + + put_bits(pb, 3, fc->classes[i].dim - 1); + put_bits(pb, 2, fc->classes[i].subclass); + + if (fc->classes[i].subclass) + put_bits(pb, 8, fc->classes[i].masterbook); + + books = (1 << fc->classes[i].subclass); + + for (j = 0; j < books; j++) + put_bits(pb, 8, fc->classes[i].books[j] + 1); + } + + put_bits(pb, 2, fc->multiplier - 1); + put_bits(pb, 4, fc->rangebits); + + for (i = 2; i < fc->values; i++) + put_bits(pb, fc->rangebits, fc->list[i].x); +} + +static void put_residue_header(PutBitContext *pb, vorbis_enc_residue *rc) +{ + int i; + + put_bits(pb, 16, rc->type); + + put_bits(pb, 24, rc->begin); + put_bits(pb, 24, rc->end); + put_bits(pb, 24, rc->partition_size - 1); + put_bits(pb, 6, rc->classifications - 1); + put_bits(pb, 8, rc->classbook); + + for (i = 0; i < rc->classifications; i++) { + int j, tmp = 0; + for (j = 0; j < 8; j++) + tmp |= (rc->books[i][j] != -1) << j; + + put_bits(pb, 3, tmp & 7); + put_bits(pb, 1, tmp > 7); + + if (tmp > 7) + put_bits(pb, 5, tmp >> 3); + } + + for (i = 0; i < rc->classifications; i++) { + int j; + for (j = 0; j < 8; j++) + if (rc->books[i][j] != -1) + put_bits(pb, 8, rc->books[i][j]); + } +} + +static int put_main_header(vorbis_enc_context *venc, uint8_t **out) +{ + int i; + PutBitContext pb; + uint8_t buffer[50000] = {0}, *p = buffer; + int buffer_len = sizeof buffer; + int len, hlens[3]; + + // identification header + init_put_bits(&pb, p, buffer_len); + put_bits(&pb, 8, 1); //magic + for (i = 0; "vorbis"[i]; i++) + put_bits(&pb, 8, "vorbis"[i]); + put_bits32(&pb, 0); // version + put_bits(&pb, 8, venc->channels); + put_bits32(&pb, venc->sample_rate); + put_bits32(&pb, 0); // bitrate + put_bits32(&pb, 0); // bitrate + put_bits32(&pb, 0); // bitrate + put_bits(&pb, 4, venc->log2_blocksize[0]); + put_bits(&pb, 4, venc->log2_blocksize[1]); + put_bits(&pb, 1, 1); // framing + + flush_put_bits(&pb); + hlens[0] = put_bits_count(&pb) >> 3; + buffer_len -= hlens[0]; + p += hlens[0]; + + // comment header + init_put_bits(&pb, p, buffer_len); + put_bits(&pb, 8, 3); //magic + for (i = 0; "vorbis"[i]; i++) + put_bits(&pb, 8, "vorbis"[i]); + put_bits32(&pb, 0); // vendor length TODO + put_bits32(&pb, 0); // amount of comments + put_bits(&pb, 1, 1); // framing + + flush_put_bits(&pb); + hlens[1] = put_bits_count(&pb) >> 3; + buffer_len -= hlens[1]; + p += hlens[1]; + + // setup header + init_put_bits(&pb, p, buffer_len); + put_bits(&pb, 8, 5); //magic + for (i = 0; "vorbis"[i]; i++) + put_bits(&pb, 8, "vorbis"[i]); + + // codebooks + put_bits(&pb, 8, venc->ncodebooks - 1); + for (i = 0; i < venc->ncodebooks; i++) + put_codebook_header(&pb, &venc->codebooks[i]); + + // time domain, reserved, zero + put_bits(&pb, 6, 0); + put_bits(&pb, 16, 0); + + // floors + put_bits(&pb, 6, venc->nfloors - 1); + for (i = 0; i < venc->nfloors; i++) + put_floor_header(&pb, &venc->floors[i]); + + // residues + put_bits(&pb, 6, venc->nresidues - 1); + for (i = 0; i < venc->nresidues; i++) + put_residue_header(&pb, &venc->residues[i]); + + // mappings + put_bits(&pb, 6, venc->nmappings - 1); + for (i = 0; i < venc->nmappings; i++) { + vorbis_enc_mapping *mc = &venc->mappings[i]; + int j; + put_bits(&pb, 16, 0); // mapping type + + put_bits(&pb, 1, mc->submaps > 1); + if (mc->submaps > 1) + put_bits(&pb, 4, mc->submaps - 1); + + put_bits(&pb, 1, !!mc->coupling_steps); + if (mc->coupling_steps) { + put_bits(&pb, 8, mc->coupling_steps - 1); + for (j = 0; j < mc->coupling_steps; j++) { + put_bits(&pb, ilog(venc->channels - 1), mc->magnitude[j]); + put_bits(&pb, ilog(venc->channels - 1), mc->angle[j]); + } + } + + put_bits(&pb, 2, 0); // reserved + + if (mc->submaps > 1) + for (j = 0; j < venc->channels; j++) + put_bits(&pb, 4, mc->mux[j]); + + for (j = 0; j < mc->submaps; j++) { + put_bits(&pb, 8, 0); // reserved time configuration + put_bits(&pb, 8, mc->floor[j]); + put_bits(&pb, 8, mc->residue[j]); + } + } + + // modes + put_bits(&pb, 6, venc->nmodes - 1); + for (i = 0; i < venc->nmodes; i++) { + put_bits(&pb, 1, venc->modes[i].blockflag); + put_bits(&pb, 16, 0); // reserved window type + put_bits(&pb, 16, 0); // reserved transform type + put_bits(&pb, 8, venc->modes[i].mapping); + } + + put_bits(&pb, 1, 1); // framing + + flush_put_bits(&pb); + hlens[2] = put_bits_count(&pb) >> 3; + + len = hlens[0] + hlens[1] + hlens[2]; + p = *out = av_mallocz(64 + len + len/255); + + *p++ = 2; + p += av_xiphlacing(p, hlens[0]); + p += av_xiphlacing(p, hlens[1]); + buffer_len = 0; + for (i = 0; i < 3; i++) { + memcpy(p, buffer + buffer_len, hlens[i]); + p += hlens[i]; + buffer_len += hlens[i]; + } + + return p - *out; +} + +static float get_floor_average(vorbis_enc_floor * fc, float *coeffs, int i) +{ + int begin = fc->list[fc->list[FFMAX(i-1, 0)].sort].x; + int end = fc->list[fc->list[FFMIN(i+1, fc->values - 1)].sort].x; + int j; + float average = 0; + + for (j = begin; j < end; j++) + average += fabs(coeffs[j]); + return average / (end - begin); +} + +static void floor_fit(vorbis_enc_context *venc, vorbis_enc_floor *fc, + float *coeffs, uint_fast16_t *posts, int samples) +{ + int range = 255 / fc->multiplier + 1; + int i; + float tot_average = 0.; + float averages[MAX_FLOOR_VALUES]; + for (i = 0; i < fc->values; i++) { + averages[i] = get_floor_average(fc, coeffs, i); + tot_average += averages[i]; + } + tot_average /= fc->values; + tot_average /= venc->quality; + + for (i = 0; i < fc->values; i++) { + int position = fc->list[fc->list[i].sort].x; + float average = averages[i]; + int j; + + average = sqrt(tot_average * average) * pow(1.25f, position*0.005f); // MAGIC! + for (j = 0; j < range - 1; j++) + if (ff_vorbis_floor1_inverse_db_table[j * fc->multiplier] > average) + break; + posts[fc->list[i].sort] = j; + } +} + +static int render_point(int x0, int y0, int x1, int y1, int x) +{ + return y0 + (x - x0) * (y1 - y0) / (x1 - x0); +} + +static void floor_encode(vorbis_enc_context *venc, vorbis_enc_floor *fc, + PutBitContext *pb, uint_fast16_t *posts, + float *floor, int samples) +{ + int range = 255 / fc->multiplier + 1; + int coded[MAX_FLOOR_VALUES]; // first 2 values are unused + int i, counter; + + put_bits(pb, 1, 1); // non zero + put_bits(pb, ilog(range - 1), posts[0]); + put_bits(pb, ilog(range - 1), posts[1]); + coded[0] = coded[1] = 1; + + for (i = 2; i < fc->values; i++) { + int predicted = render_point(fc->list[fc->list[i].low].x, + posts[fc->list[i].low], + fc->list[fc->list[i].high].x, + posts[fc->list[i].high], + fc->list[i].x); + int highroom = range - predicted; + int lowroom = predicted; + int room = FFMIN(highroom, lowroom); + if (predicted == posts[i]) { + coded[i] = 0; // must be used later as flag! + continue; + } else { + if (!coded[fc->list[i].low ]) + coded[fc->list[i].low ] = -1; + if (!coded[fc->list[i].high]) + coded[fc->list[i].high] = -1; + } + if (posts[i] > predicted) { + if (posts[i] - predicted > room) + coded[i] = posts[i] - predicted + lowroom; + else + coded[i] = (posts[i] - predicted) << 1; + } else { + if (predicted - posts[i] > room) + coded[i] = predicted - posts[i] + highroom - 1; + else + coded[i] = ((predicted - posts[i]) << 1) - 1; + } + } + + counter = 2; + for (i = 0; i < fc->partitions; i++) { + vorbis_enc_floor_class * c = &fc->classes[fc->partition_to_class[i]]; + int k, cval = 0, csub = 1<subclass; + if (c->subclass) { + vorbis_enc_codebook * book = &venc->codebooks[c->masterbook]; + int cshift = 0; + for (k = 0; k < c->dim; k++) { + int l; + for (l = 0; l < csub; l++) { + int maxval = 1; + if (c->books[l] != -1) + maxval = venc->codebooks[c->books[l]].nentries; + // coded could be -1, but this still works, cause that is 0 + if (coded[counter + k] < maxval) + break; + } + assert(l != csub); + cval |= l << cshift; + cshift += c->subclass; + } + put_codeword(pb, book, cval); + } + for (k = 0; k < c->dim; k++) { + int book = c->books[cval & (csub-1)]; + int entry = coded[counter++]; + cval >>= c->subclass; + if (book == -1) + continue; + if (entry == -1) + entry = 0; + put_codeword(pb, &venc->codebooks[book], entry); + } + } + + ff_vorbis_floor1_render_list(fc->list, fc->values, posts, coded, + fc->multiplier, floor, samples); +} + +static float *put_vector(vorbis_enc_codebook *book, PutBitContext *pb, + float *num) +{ + int i, entry = -1; + float distance = FLT_MAX; + assert(book->dimentions); + for (i = 0; i < book->nentries; i++) { + float * vec = book->dimentions + i * book->ndimentions, d = book->pow2[i]; + int j; + if (!book->lens[i]) + continue; + for (j = 0; j < book->ndimentions; j++) + d -= vec[j] * num[j]; + if (distance > d) { + entry = i; + distance = d; + } + } + put_codeword(pb, book, entry); + return &book->dimentions[entry * book->ndimentions]; +} + +static void residue_encode(vorbis_enc_context *venc, vorbis_enc_residue *rc, + PutBitContext *pb, float *coeffs, int samples, + int real_ch) +{ + int pass, i, j, p, k; + int psize = rc->partition_size; + int partitions = (rc->end - rc->begin) / psize; + int channels = (rc->type == 2) ? 1 : real_ch; + int classes[MAX_CHANNELS][NUM_RESIDUE_PARTITIONS]; + int classwords = venc->codebooks[rc->classbook].ndimentions; + + assert(rc->type == 2); + assert(real_ch == 2); + for (p = 0; p < partitions; p++) { + float max1 = 0., max2 = 0.; + int s = rc->begin + p * psize; + for (k = s; k < s + psize; k += 2) { + max1 = FFMAX(max1, fabs(coeffs[ k / real_ch])); + max2 = FFMAX(max2, fabs(coeffs[samples + k / real_ch])); + } + + for (i = 0; i < rc->classifications - 1; i++) + if (max1 < rc->maxes[i][0] && max2 < rc->maxes[i][1]) + break; + classes[0][p] = i; + } + + for (pass = 0; pass < 8; pass++) { + p = 0; + while (p < partitions) { + if (pass == 0) + for (j = 0; j < channels; j++) { + vorbis_enc_codebook * book = &venc->codebooks[rc->classbook]; + int entry = 0; + for (i = 0; i < classwords; i++) { + entry *= rc->classifications; + entry += classes[j][p + i]; + } + put_codeword(pb, book, entry); + } + for (i = 0; i < classwords && p < partitions; i++, p++) { + for (j = 0; j < channels; j++) { + int nbook = rc->books[classes[j][p]][pass]; + vorbis_enc_codebook * book = &venc->codebooks[nbook]; + float *buf = coeffs + samples*j + rc->begin + p*psize; + if (nbook == -1) + continue; + + assert(rc->type == 0 || rc->type == 2); + assert(!(psize % book->ndimentions)); + + if (rc->type == 0) { + for (k = 0; k < psize; k += book->ndimentions) { + float *a = put_vector(book, pb, &buf[k]); + int l; + for (l = 0; l < book->ndimentions; l++) + buf[k + l] -= a[l]; + } + } else { + int s = rc->begin + p * psize, a1, b1; + a1 = (s % real_ch) * samples; + b1 = s / real_ch; + s = real_ch * samples; + for (k = 0; k < psize; k += book->ndimentions) { + int dim, a2 = a1, b2 = b1; + float vec[MAX_CODEBOOK_DIM], *pv = vec; + for (dim = book->ndimentions; dim--; ) { + *pv++ = coeffs[a2 + b2]; + if ((a2 += samples) == s) { + a2 = 0; + b2++; + } + } + pv = put_vector(book, pb, vec); + for (dim = book->ndimentions; dim--; ) { + coeffs[a1 + b1] -= *pv++; + if ((a1 += samples) == s) { + a1 = 0; + b1++; + } + } + } + } + } + } + } + } +} + +static int apply_window_and_mdct(vorbis_enc_context *venc, const signed short *audio, + int samples) +{ + int i, j, channel; + const float * win = venc->win[0]; + int window_len = 1 << (venc->log2_blocksize[0] - 1); + float n = (float)(1 << venc->log2_blocksize[0]) / 4.; + // FIXME use dsp + + if (!venc->have_saved && !samples) + return 0; + + if (venc->have_saved) { + for (channel = 0; channel < venc->channels; channel++) + memcpy(venc->samples + channel * window_len * 2, + venc->saved + channel * window_len, sizeof(float) * window_len); + } else { + for (channel = 0; channel < venc->channels; channel++) + memset(venc->samples + channel * window_len * 2, 0, + sizeof(float) * window_len); + } + + if (samples) { + for (channel = 0; channel < venc->channels; channel++) { + float * offset = venc->samples + channel*window_len*2 + window_len; + j = channel; + for (i = 0; i < samples; i++, j += venc->channels) + offset[i] = audio[j] / 32768. / n * win[window_len - i - 1]; + } + } else { + for (channel = 0; channel < venc->channels; channel++) + memset(venc->samples + channel * window_len * 2 + window_len, + 0, sizeof(float) * window_len); + } + + for (channel = 0; channel < venc->channels; channel++) + venc->mdct[0].mdct_calc(&venc->mdct[0], venc->coeffs + channel * window_len, + venc->samples + channel * window_len * 2); + + if (samples) { + for (channel = 0; channel < venc->channels; channel++) { + float *offset = venc->saved + channel * window_len; + j = channel; + for (i = 0; i < samples; i++, j += venc->channels) + offset[i] = audio[j] / 32768. / n * win[i]; + } + venc->have_saved = 1; + } else { + venc->have_saved = 0; + } + return 1; +} + +static av_cold int vorbis_encode_init(AVCodecContext *avccontext) +{ + vorbis_enc_context *venc = avccontext->priv_data; + + if (avccontext->channels != 2) { + av_log(avccontext, AV_LOG_ERROR, "Current Libav Vorbis encoder only supports 2 channels.\n"); + return -1; + } + + create_vorbis_context(venc, avccontext); + + if (avccontext->flags & CODEC_FLAG_QSCALE) + venc->quality = avccontext->global_quality / (float)FF_QP2LAMBDA / 10.; + else + venc->quality = 0.03; + venc->quality *= venc->quality; + + avccontext->extradata_size = put_main_header(venc, (uint8_t**)&avccontext->extradata); + + avccontext->frame_size = 1 << (venc->log2_blocksize[0] - 1); + + avccontext->coded_frame = avcodec_alloc_frame(); + avccontext->coded_frame->key_frame = 1; + + return 0; +} + +static int vorbis_encode_frame(AVCodecContext *avccontext, + unsigned char *packets, + int buf_size, void *data) +{ + vorbis_enc_context *venc = avccontext->priv_data; + const signed short *audio = data; + int samples = data ? avccontext->frame_size : 0; + vorbis_enc_mode *mode; + vorbis_enc_mapping *mapping; + PutBitContext pb; + int i; + + if (!apply_window_and_mdct(venc, audio, samples)) + return 0; + samples = 1 << (venc->log2_blocksize[0] - 1); + + init_put_bits(&pb, packets, buf_size); + + put_bits(&pb, 1, 0); // magic bit + + put_bits(&pb, ilog(venc->nmodes - 1), 0); // 0 bits, the mode + + mode = &venc->modes[0]; + mapping = &venc->mappings[mode->mapping]; + if (mode->blockflag) { + put_bits(&pb, 1, 0); + put_bits(&pb, 1, 0); + } + + for (i = 0; i < venc->channels; i++) { + vorbis_enc_floor *fc = &venc->floors[mapping->floor[mapping->mux[i]]]; + uint_fast16_t posts[MAX_FLOOR_VALUES]; + floor_fit(venc, fc, &venc->coeffs[i * samples], posts, samples); + floor_encode(venc, fc, &pb, posts, &venc->floor[i * samples], samples); + } + + for (i = 0; i < venc->channels * samples; i++) + venc->coeffs[i] /= venc->floor[i]; + + for (i = 0; i < mapping->coupling_steps; i++) { + float *mag = venc->coeffs + mapping->magnitude[i] * samples; + float *ang = venc->coeffs + mapping->angle[i] * samples; + int j; + for (j = 0; j < samples; j++) { + float a = ang[j]; + ang[j] -= mag[j]; + if (mag[j] > 0) + ang[j] = -ang[j]; + if (ang[j] < 0) + mag[j] = a; + } + } + + residue_encode(venc, &venc->residues[mapping->residue[mapping->mux[0]]], + &pb, venc->coeffs, samples, venc->channels); + + avccontext->coded_frame->pts = venc->sample_count; + venc->sample_count += avccontext->frame_size; + flush_put_bits(&pb); + return put_bits_count(&pb) >> 3; +} + + +static av_cold int vorbis_encode_close(AVCodecContext *avccontext) +{ + vorbis_enc_context *venc = avccontext->priv_data; + int i; + + if (venc->codebooks) + for (i = 0; i < venc->ncodebooks; i++) { + av_freep(&venc->codebooks[i].lens); + av_freep(&venc->codebooks[i].codewords); + av_freep(&venc->codebooks[i].quantlist); + av_freep(&venc->codebooks[i].dimentions); + av_freep(&venc->codebooks[i].pow2); + } + av_freep(&venc->codebooks); + + if (venc->floors) + for (i = 0; i < venc->nfloors; i++) { + int j; + if (venc->floors[i].classes) + for (j = 0; j < venc->floors[i].nclasses; j++) + av_freep(&venc->floors[i].classes[j].books); + av_freep(&venc->floors[i].classes); + av_freep(&venc->floors[i].partition_to_class); + av_freep(&venc->floors[i].list); + } + av_freep(&venc->floors); + + if (venc->residues) + for (i = 0; i < venc->nresidues; i++) { + av_freep(&venc->residues[i].books); + av_freep(&venc->residues[i].maxes); + } + av_freep(&venc->residues); + + if (venc->mappings) + for (i = 0; i < venc->nmappings; i++) { + av_freep(&venc->mappings[i].mux); + av_freep(&venc->mappings[i].floor); + av_freep(&venc->mappings[i].residue); + av_freep(&venc->mappings[i].magnitude); + av_freep(&venc->mappings[i].angle); + } + av_freep(&venc->mappings); + + av_freep(&venc->modes); + + av_freep(&venc->saved); + av_freep(&venc->samples); + av_freep(&venc->floor); + av_freep(&venc->coeffs); + + ff_mdct_end(&venc->mdct[0]); + ff_mdct_end(&venc->mdct[1]); + + av_freep(&avccontext->coded_frame); + av_freep(&avccontext->extradata); + + return 0 ; +} + +AVCodec ff_vorbis_encoder = { + "vorbis", + AVMEDIA_TYPE_AUDIO, + CODEC_ID_VORBIS, + sizeof(vorbis_enc_context), + vorbis_encode_init, + vorbis_encode_frame, + vorbis_encode_close, + .capabilities= CODEC_CAP_DELAY | CODEC_CAP_EXPERIMENTAL, + .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("Vorbis"), +}; -- cgit v1.1 From 75e8fba8232108c075a8b24bd7f17b7c5869c7bc Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Sat, 23 Apr 2011 14:14:22 +0200 Subject: Remove stray libavcore and _g binary references. --- .gitignore | 2 -- Changelog | 1 - 2 files changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index eac1758..3d5e38b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ *.ho *-example *-test -*_g config.* doc/*.1 doc/*.html @@ -17,7 +16,6 @@ ffplay ffprobe ffserver libavcodec/libavcodec* -libavcore/libavcore* libavdevice/libavdevice* libavfilter/libavfilter* libavformat/libavformat* diff --git a/Changelog b/Changelog index f38ef9e..00777e4 100644 --- a/Changelog +++ b/Changelog @@ -27,7 +27,6 @@ version 0.7_beta1: - RTP depacketization of QDM2 - ANSI/ASCII art playback system - Lego Mindstorms RSO de/muxer -- libavcore added - SubRip subtitle file muxer and demuxer - Chinese AVS encoding via libxavs - ffprobe -show_packets option added -- cgit v1.1 From ff3be572efde575c2b5ee621a84920ac9a5b9b8f Mon Sep 17 00:00:00 2001 From: Brad Date: Sun, 27 Mar 2011 21:05:22 -0400 Subject: patcheck: Allow overiding grep program(s) through environment variables. patcheck hardcodes the binary names for grep/egrep. This makes overriding the binary names a pain, e.g. when calling a GNU version of grep on BSD systems. Signed-off-by: Diego Biurrun --- tools/patcheck | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/tools/patcheck b/tools/patcheck index e21a9f6..d81a489 100755 --- a/tools/patcheck +++ b/tools/patcheck @@ -8,9 +8,11 @@ if [ $# = 0 ]; then exit fi +GREP=grep +EGREP=egrep TMP=patcheck.tmp OPT="-nH" -#FILES=`grep '^+++' $* | sed 's/+++ //g'` +#FILES=`$GREP '^+++' $* | sed 's/+++ //g'` echo patCHeck 1e10.0 echo This tool is intended to help a human check/review patches it is very far from @@ -27,7 +29,7 @@ hiegrep(){ arg="$1" msg="$2" shift 2 - grep $OPT '^+' $* | grep -v ':+++'| egrep --color=always -- "$arg"> $TMP && printf "\n$msg\n" + $GREP $OPT '^+' $* | $GREP -v ':+++'| $EGREP --color=always -- "$arg"> $TMP && printf "\n$msg\n" cat $TMP } @@ -36,7 +38,7 @@ hiegrep2(){ varg="$2" msg="$3" shift 3 - grep $OPT '^+' $* | grep -v ':+++' | egrep -v -- "$varg" | egrep --color=always -- "$arg" > $TMP && printf "\n$msg\n" + $GREP $OPT '^+' $* | $GREP -v ':+++' | $EGREP -v -- "$varg" | $EGREP --color=always -- "$arg" > $TMP && printf "\n$msg\n" cat $TMP } @@ -60,7 +62,7 @@ hiegrep '\+= *1 *;' 'can be simplified to ++' $* hiegrep '-= *1 *;' 'can be simplified to --' $* hiegrep '((!|=)= *(0|NULL)[^0-9a-z]|[^0-9a-z](0|NULL) *(!|=)=)' 'x==0 / x!=0 can be simplified to !x / x' $* -egrep $OPT '^\+ *(const *|)static' $*| egrep --color=always '[^=]= *(0|NULL)[^0-9a-zA-Z]'> $TMP && printf '\nuseless 0 init\n' +$EGREP $OPT '^\+ *(const *|)static' $*| $EGREP --color=always '[^=]= *(0|NULL)[^0-9a-zA-Z]'> $TMP && printf '\nuseless 0 init\n' cat $TMP hiegrep '# *ifdef * (HAVE|CONFIG)_' 'ifdefs that should be #if' $* @@ -89,7 +91,7 @@ hiegrep2 '\.sample_fmts *= *\(' 'const' 'missing const for sample_fmts array' $* hiegrep2 '\.supported_framerates *= *\(' 'const' 'missing const for supported_framerates array' $* hiegrep2 '\.channel_layouts *= *\(' 'const' 'missing const for channel_layouts array' $* -#egrep $OPT '^\+.*const ' $*| grep -v 'static'> $TMP && printf '\nnon static const\n' +#$EGREP $OPT '^\+.*const ' $*| $GREP -v 'static'> $TMP && printf '\nnon static const\n' #cat $TMP hiegrep2 "$ERE_TYPES" '(static|av_|ff_|typedef|:\+[^a-zA-Z_])' 'Non static with no ff_/av_ prefix' $* @@ -104,58 +106,58 @@ hiegrep ':\+ *{ *$' '{ should be on the same line as the related previous state rm $TMP -for i in `grep -H '^+.*@param' $*| sed 's/^\([^:]*\):.*@param\(\[.*\]\|\) *\([a-zA-Z0-9_]*\) .*$/\1:\3/'` ; do +for i in `$GREP -H '^+.*@param' $*| sed 's/^\([^:]*\):.*@param\(\[.*\]\|\) *\([a-zA-Z0-9_]*\) .*$/\1:\3/'` ; do doxpar=`echo $i | sed 's/^.*:\(.*\)$/\1/'` file=`echo $i | sed 's/^\([^:]*\):.*$/\1/'` - grep " *$doxpar *[),]" $file | grep -v '@param' >/dev/null || grep --color=always "@param *$doxpar" $file >>$TMP + $GREP " *$doxpar *[),]" $file | $GREP -v '@param' >/dev/null || $GREP --color=always "@param *$doxpar" $file >>$TMP done if test -e $TMP ; then printf '\nmismatching doxy params\n' cat $TMP fi -egrep -B2 $OPT '^(\+|) *('"$ERE_TYPES"'|# *define)' $* | egrep -A2 --color=always '(:|-)\+[^/]*/(\*([^*]|$)|/([^/]|$))' > $TMP && printf "\n Non doxy comments\n" +$EGREP -B2 $OPT '^(\+|) *('"$ERE_TYPES"'|# *define)' $* | $EGREP -A2 --color=always '(:|-)\+[^/]*/(\*([^*]|$)|/([^/]|$))' > $TMP && printf "\n Non doxy comments\n" cat $TMP rm $TMP for i in \ - `egrep -H '^\+ *'"$ERE_TYPES" $* |\ - grep -v '(' | egrep -v '\Wgoto\W' |\ + `$EGREP -H '^\+ *'"$ERE_TYPES" $* |\ + $GREP -v '(' | $EGREP -v '\Wgoto\W' |\ xargs -d '\n' -n 1 |\ - grep -o '[* ][* ]*[a-zA-Z][0-9a-zA-Z_]* *[,;=]' |\ + $GREP -o '[* ][* ]*[a-zA-Z][0-9a-zA-Z_]* *[,;=]' |\ sed 's/.[* ]*\([a-zA-Z][0-9a-zA-Z_]*\) *[,;=]/\1/'` \ ; do - echo $i | grep '^NULL$' && continue - egrep $i' *(\+|-|\*|/|\||&|%|)=[^=]' $* >/dev/null || echo "possibly never written:"$i >> $TMP - egrep '(=|\(|return).*'$i'(==|[^=])*$' $* >/dev/null || echo "possibly never read :"$i >> $TMP - egrep -o $i' *((\+|-|\*|/|\||&|%|)=[^=]|\+\+|--) *(0x|)[0-9]*(;|)' $* |\ - egrep -v $i' *= *(0x|)[0-9]{1,};'>/dev/null || echo "possibly constant :"$i >> $TMP + echo $i | $GREP '^NULL$' && continue + $EGREP $i' *(\+|-|\*|/|\||&|%|)=[^=]' $* >/dev/null || echo "possibly never written:"$i >> $TMP + $EGREP '(=|\(|return).*'$i'(==|[^=])*$' $* >/dev/null || echo "possibly never read :"$i >> $TMP + $EGREP -o $i' *((\+|-|\*|/|\||&|%|)=[^=]|\+\+|--) *(0x|)[0-9]*(;|)' $* |\ + $EGREP -v $i' *= *(0x|)[0-9]{1,};'>/dev/null || echo "possibly constant :"$i >> $TMP done if test -e $TMP ; then printf '\npossibly unused variables\n' cat $TMP fi -grep '^+++ .*Changelog' $* >/dev/null || printf "\nMissing changelog entry (ignore if minor change)\n" +$GREP '^+++ .*Changelog' $* >/dev/null || printf "\nMissing changelog entry (ignore if minor change)\n" -cat $* | tr '\n' '@' | egrep --color=always -o '(fprintf|av_log|printf)\([^)]*\)[+ ;@]*\1' >$TMP && printf "\nMergeable calls\n" +cat $* | tr '\n' '@' | $EGREP --color=always -o '(fprintf|av_log|printf)\([^)]*\)[+ ;@]*\1' >$TMP && printf "\nMergeable calls\n" cat $TMP | tr '@' '\n' -cat $* | tr '\n' '@' | egrep --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *[<>]=? *[0-9]* *\) * \1 *= *[0-9]* *;[ @\\+]*else *if *\( *\1 *[<>]=? *[0-9]* *\) *\1 *= *[0-9]* *;' >$TMP && printf "\nav_clip / av_clip_uint8 / av_clip_int16 / ...\n" +cat $* | tr '\n' '@' | $EGREP --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *[<>]=? *[0-9]* *\) * \1 *= *[0-9]* *;[ @\\+]*else *if *\( *\1 *[<>]=? *[0-9]* *\) *\1 *= *[0-9]* *;' >$TMP && printf "\nav_clip / av_clip_uint8 / av_clip_int16 / ...\n" cat $TMP | tr '@' '\n' -cat $* | tr '\n' '@' | egrep --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *[<>]=? *([A-Za-z0-9_]*) *\)[ @\\+]*(\1|\2) *= *(\1|\2) *;' >$TMP && printf "\nFFMIN/FFMAX\n" +cat $* | tr '\n' '@' | $EGREP --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *[<>]=? *([A-Za-z0-9_]*) *\)[ @\\+]*(\1|\2) *= *(\1|\2) *;' >$TMP && printf "\nFFMIN/FFMAX\n" cat $TMP | tr '@' '\n' -cat $* | tr '\n' '@' | egrep --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *\)[ @\\+]*av_free(p|) *\( *(&|) *\1[^-.]' >$TMP && printf "\nav_free(NULL) is safe\n" +cat $* | tr '\n' '@' | $EGREP --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *\)[ @\\+]*av_free(p|) *\( *(&|) *\1[^-.]' >$TMP && printf "\nav_free(NULL) is safe\n" cat $TMP | tr '@' '\n' -cat $* | tr '\n' '@' | egrep --color=always -o '[^a-zA-Z0-9_]([a-zA-Z0-9_]*) *= *av_malloc *\([^)]*\)[ @;\\+]*memset *\( *\1' >$TMP && printf "\nav_mallocz()\n" +cat $* | tr '\n' '@' | $EGREP --color=always -o '[^a-zA-Z0-9_]([a-zA-Z0-9_]*) *= *av_malloc *\([^)]*\)[ @;\\+]*memset *\( *\1' >$TMP && printf "\nav_mallocz()\n" cat $TMP | tr '@' '\n' # doesnt work -#cat $* | tr '\n' '@' | egrep -o '[^a-zA-Z_0-9]([a-zA-Z][a-zA-Z_0-9]*) *=[^=].*\1' | egrep -o '[^a-zA-Z_0-9]([a-zA-Z][a-zA-Z_0-9]*) *=[^=].*\1 *=[^=]' >$TMP && printf "\nPossibly written 2x before read\n" +#cat $* | tr '\n' '@' | $EGREP -o '[^a-zA-Z_0-9]([a-zA-Z][a-zA-Z_0-9]*) *=[^=].*\1' | $EGREP -o '[^a-zA-Z_0-9]([a-zA-Z][a-zA-Z_0-9]*) *=[^=].*\1 *=[^=]' >$TMP && printf "\nPossibly written 2x before read\n" #cat $TMP | tr '@' '\n' exit @@ -163,7 +165,7 @@ exit TODO/idea list: for all demuxers & muxers - grep for "avctx->priv_data" + $EGREP for "avctx->priv_data" vertical align = /* and * align -- cgit v1.1 From 6252040e773c30efa21c743124d5e813320a0ec2 Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Tue, 19 Apr 2011 00:16:24 +0200 Subject: Replace `` by $() syntax in shell scripts. $() is easier to nest and POSIX, which we require in other places. --- tools/clean-diff | 2 +- tools/patcheck | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/clean-diff b/tools/clean-diff index 98e26a7..4600702 100755 --- a/tools/clean-diff +++ b/tools/clean-diff @@ -1,6 +1,6 @@ #!/bin/sh sed '/^+[^+]/!s/ /TaBBaT/g' |\ - expand -t `seq -s , 9 8 200` |\ + expand -t $(seq -s , 9 8 200) |\ sed 's/TaBBaT/ /g' |\ sed '/^+[^+]/s/ * $//' |\ tr -d '\015' |\ diff --git a/tools/patcheck b/tools/patcheck index d81a489..a8c0cc8 100755 --- a/tools/patcheck +++ b/tools/patcheck @@ -12,7 +12,7 @@ GREP=grep EGREP=egrep TMP=patcheck.tmp OPT="-nH" -#FILES=`$GREP '^+++' $* | sed 's/+++ //g'` +#FILES=$($GREP '^+++' $* | sed 's/+++ //g') echo patCHeck 1e10.0 echo This tool is intended to help a human check/review patches it is very far from @@ -43,7 +43,7 @@ hiegrep2(){ } hiegrep '[[:space:]]$' 'trailing whitespace' $* -hiegrep "`echo x | tr 'x' '\t'`" 'tabs' $* +hiegrep "$(echo x | tr 'x' '\t')" 'tabs' $* #hiegrep ':\+$' 'Empty lines' $* hiegrep ';;' 'double ;' $* hiegrep2 '\b_[a-zA-Z0-9_]{1,}' '__(asm|attribute)([^a-zA-Z0-9]|$)' 'reserved identifer' $* @@ -106,9 +106,9 @@ hiegrep ':\+ *{ *$' '{ should be on the same line as the related previous state rm $TMP -for i in `$GREP -H '^+.*@param' $*| sed 's/^\([^:]*\):.*@param\(\[.*\]\|\) *\([a-zA-Z0-9_]*\) .*$/\1:\3/'` ; do - doxpar=`echo $i | sed 's/^.*:\(.*\)$/\1/'` - file=`echo $i | sed 's/^\([^:]*\):.*$/\1/'` +for i in $($GREP -H '^+.*@param' $*| sed 's/^\([^:]*\):.*@param\(\[.*\]\|\) *\([a-zA-Z0-9_]*\) .*$/\1:\3/') ; do + doxpar=$(echo $i | sed 's/^.*:\(.*\)$/\1/') + file=$(echo $i | sed 's/^\([^:]*\):.*$/\1/') $GREP " *$doxpar *[),]" $file | $GREP -v '@param' >/dev/null || $GREP --color=always "@param *$doxpar" $file >>$TMP done if test -e $TMP ; then @@ -121,11 +121,11 @@ cat $TMP rm $TMP for i in \ - `$EGREP -H '^\+ *'"$ERE_TYPES" $* |\ + $($EGREP -H '^\+ *'"$ERE_TYPES" $* |\ $GREP -v '(' | $EGREP -v '\Wgoto\W' |\ xargs -d '\n' -n 1 |\ $GREP -o '[* ][* ]*[a-zA-Z][0-9a-zA-Z_]* *[,;=]' |\ - sed 's/.[* ]*\([a-zA-Z][0-9a-zA-Z_]*\) *[,;=]/\1/'` \ + sed 's/.[* ]*\([a-zA-Z][0-9a-zA-Z_]*\) *[,;=]/\1/') \ ; do echo $i | $GREP '^NULL$' && continue $EGREP $i' *(\+|-|\*|/|\||&|%|)=[^=]' $* >/dev/null || echo "possibly never written:"$i >> $TMP -- cgit v1.1 From 43fb279f5643225799841f512d2dad4690186165 Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Sat, 23 Apr 2011 16:39:03 +0200 Subject: Replace more FFmpeg instances by Libav or ffmpeg. --- doc/general.texi | 2 +- doc/issue_tracker.txt | 2 +- ffserver.c | 2 +- libavcodec/avcodec.h | 6 +++--- libavcodec/dca.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/general.texi b/doc/general.texi index 303159e..e68e83e 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -268,7 +268,7 @@ library: @section Image Formats -FFmpeg can read and write images for each frame of a video sequence. The +Libav can read and write images for each frame of a video sequence. The following image formats are supported: @multitable @columnfractions .4 .1 .1 .4 diff --git a/doc/issue_tracker.txt b/doc/issue_tracker.txt index 5a15a9b..e5733ec 100644 --- a/doc/issue_tracker.txt +++ b/doc/issue_tracker.txt @@ -39,7 +39,7 @@ NOTE: issue = (bug report || patch || feature request) Type: ----- bug - An error, flaw, mistake, failure, or fault in FFmpeg or libav* that + An error, flaw, mistake, failure, or fault in ffmpeg or libav* that prevents it from behaving as intended. feature request diff --git a/ffserver.c b/ffserver.c index d341182..9cb65da 100644 --- a/ffserver.c +++ b/ffserver.c @@ -2265,7 +2265,7 @@ static int http_prepare_data(HTTPContext *c) /* * HACK to avoid mpeg ps muxer to spit many underflow errors - * Default value from FFmpeg + * Default value from Libav * Try to set it use configuration option */ c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 14f00bb..ec31f66 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -960,7 +960,7 @@ typedef struct AVPanScan{ int64_t reordered_opaque;\ \ /**\ - * hardware accelerator private data (FFmpeg allocated)\ + * hardware accelerator private data (Libav-allocated)\ * - encoding: unused\ * - decoding: Set by libavcodec\ */\ @@ -2633,8 +2633,8 @@ typedef struct AVCodecContext { * Hardware accelerator context. * For some hardware accelerators, a global context needs to be * provided by the user. In that case, this holds display-dependent - * data FFmpeg cannot instantiate itself. Please refer to the - * FFmpeg HW accelerator documentation to know how to fill this + * data Libav cannot instantiate itself. Please refer to the + * Libav HW accelerator documentation to know how to fill this * is. e.g. for VA API, this is a struct vaapi_context. * - encoding: unused * - decoding: Set by user diff --git a/libavcodec/dca.c b/libavcodec/dca.c index e3c6466..525832f 100644 --- a/libavcodec/dca.c +++ b/libavcodec/dca.c @@ -1798,7 +1798,7 @@ static int dca_decode_frame(AVCodecContext * avctx, /* There is nothing that prevents a dts frame to change channel configuration - but FFmpeg doesn't support that so only set the channels if it is previously + but Libav doesn't support that so only set the channels if it is previously unset. Ideally during the first probe for channels the crc should be checked and only set avctx->channels when the crc is ok. Right now the decoder could set the channels based on a broken first frame.*/ -- cgit v1.1 From 3a50894eaaad3d5a7ec9bad99c08ecb8305c51c1 Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Sat, 23 Apr 2011 16:40:01 +0200 Subject: Refer to ff* tools by their lowercase names. --- doc/faq.texi | 4 ++-- doc/ffmpeg.texi | 26 ++++++++++++-------------- doc/ffprobe.texi | 6 +++--- doc/ffserver.texi | 12 ++++++------ 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/doc/faq.texi b/doc/faq.texi index a29af1e..3d7a275 100644 --- a/doc/faq.texi +++ b/doc/faq.texi @@ -280,7 +280,7 @@ Just create an "input.avs" text file with this single line ... @example DirectShowSource("C:\path to your file\yourfile.asf") @end example -... and then feed that text file to FFmpeg: +... and then feed that text file to ffmpeg: @example ffmpeg -i input.avs @end example @@ -348,7 +348,7 @@ ffmpeg -f u16le -acodec pcm_s16le -ac 2 -ar 44100 -i all.a \ rm temp[12].[av] all.[av] @end example -@section FFmpeg does not adhere to the -maxrate setting, some frames are bigger than maxrate/fps. +@section The ffmpeg program does not respect the -maxrate setting, some frames are bigger than maxrate/fps. Read the MPEG spec about video buffer verifier. diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 38da918..62282b2 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -22,17 +22,15 @@ ffmpeg [[infile options][@option{-i} @var{infile}]]... @{[outfile options] @var{ @chapter Description @c man begin DESCRIPTION -FFmpeg is a very fast video and audio converter. It can also grab from -a live audio/video source. +ffmpeg is a very fast video and audio converter that can also grab from +a live audio/video source. It can also convert between arbitrary sample +rates and resize video on the fly with a high quality polyphase filter. The command line interface is designed to be intuitive, in the sense -that FFmpeg tries to figure out all parameters that can possibly be +that ffmpeg tries to figure out all parameters that can possibly be derived automatically. You usually only have to specify the target bitrate you want. -FFmpeg can also convert from any sample rate to any other, and resize -video on the fly with a high quality polyphase filter. - As a general rule, options are applied to the next specified file. Therefore, order is important, and you can have the same option on the command line multiple times. Each occurrence is @@ -61,7 +59,7 @@ ffmpeg -r 1 -i input.m2v -r 24 output.avi The format option may be needed for raw input files. -By default, FFmpeg tries to convert as losslessly as possible: It +By default ffmpeg tries to convert as losslessly as possible: It uses the same audio and video parameters for the outputs as the one specified for the inputs. @@ -486,7 +484,7 @@ Use 'frames' B-frames (supported for MPEG-1, MPEG-2 and MPEG-4). macroblock decision @table @samp @item 0 -FF_MB_DECISION_SIMPLE: Use mb_cmp (cannot change it yet in FFmpeg). +FF_MB_DECISION_SIMPLE: Use mb_cmp (cannot change it yet in ffmpeg). @item 1 FF_MB_DECISION_BITS: Choose the one which needs the fewest bits. @item 2 @@ -868,22 +866,22 @@ It allows almost lossless encoding. @section Video and Audio grabbing -FFmpeg can grab video and audio from devices given that you specify the input -format and device. +If you specify the input format and device then ffmpeg can grab video +and audio directly. @example ffmpeg -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg @end example Note that you must activate the right video source and channel before -launching FFmpeg with any TV viewer such as xawtv +launching ffmpeg with any TV viewer such as xawtv (@url{http://linux.bytesex.org/xawtv/}) by Gerd Knorr. You also have to set the audio recording levels correctly with a standard mixer. @section X11 grabbing -FFmpeg can grab the X11 display. +Grab the X11 display with ffmpeg via @example ffmpeg -f x11grab -s cif -r 25 -i :0.0 /tmp/out.mpg @@ -901,7 +899,7 @@ variable. 10 is the x-offset and 20 the y-offset for the grabbing. @section Video and Audio file format conversion -FFmpeg can use any supported file format and protocol as input: +Any supported file format and protocol can serve as input to ffmpeg: Examples: @itemize @@ -921,7 +919,7 @@ It will use the files: The Y files use twice the resolution of the U and V files. They are raw files, without header. They can be generated by all decent video decoders. You must specify the size of the image with the @option{-s} option -if FFmpeg cannot guess it. +if ffmpeg cannot guess it. @item You can input from a raw YUV420P file: diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi index b775f55..1509022 100644 --- a/doc/ffprobe.texi +++ b/doc/ffprobe.texi @@ -22,7 +22,7 @@ ffprobe [options] [@file{input_file}] @chapter Description @c man begin DESCRIPTION -FFprobe gathers information from multimedia streams and prints it in +ffprobe gathers information from multimedia streams and prints it in human- and machine-readable fashion. For example it can be used to check the format of the container used @@ -33,7 +33,7 @@ If a filename is specified in input, ffprobe will try to open and probe the file content. If the file cannot be opened or recognized as a multimedia file, a positive exit code is returned. -FFprobe may be employed both as a standalone application or in +ffprobe may be employed both as a standalone application or in combination with a textual filter, which may perform more sophisticated processing, e.g. statistical processing or plotting. @@ -41,7 +41,7 @@ Options are used to list some of the formats supported by ffprobe or for specifying which information to display, and for setting how ffprobe will show it. -FFprobe output is designed to be easily parsable by a textual filter, +ffprobe output is designed to be easily parsable by a textual filter, and consists of one or more sections of the form: @example [SECTION] diff --git a/doc/ffserver.texi b/doc/ffserver.texi index 021b237..e5c9d40 100644 --- a/doc/ffserver.texi +++ b/doc/ffserver.texi @@ -22,12 +22,12 @@ ffserver [options] @chapter Description @c man begin DESCRIPTION -FFserver is a streaming server for both audio and video. It supports +ffserver is a streaming server for both audio and video. It supports several live feeds, streaming from files and time shifting on live feeds (you can seek to positions in the past on each live feed, provided you specify a big enough feed storage in ffserver.conf). -FFserver runs in daemon mode by default; that is, it puts itself in +ffserver runs in daemon mode by default; that is, it puts itself in the background and detaches from its TTY, unless it is launched in debug mode or a NoDaemon option is specified in the configuration file. @@ -39,7 +39,7 @@ information. @section How does it work? -FFserver receives prerecorded files or FFM streams from some ffmpeg +ffserver receives prerecorded files or FFM streams from some ffmpeg instance as input, then streams them over RTP/RTSP/HTTP. An ffserver instance will listen on some port as specified in the @@ -57,7 +57,7 @@ file. @section Status stream -FFserver supports an HTTP interface which exposes the current status +ffserver supports an HTTP interface which exposes the current status of the server. Simply point your browser to the address of the special status stream @@ -249,8 +249,8 @@ For example: @samp{http://localhost:8080/test.asf?date=2002-07-26T23:05:00}. Use @file{configfile} instead of @file{/etc/ffserver.conf}. @item -n Enable no-launch mode. This option disables all the Launch directives -within the various sections. FFserver will not launch any -ffmpeg instance, so you will have to launch them manually. +within the various sections. Since ffserver will not launch +any ffmpeg instances, you will have to launch them manually. @item -d Enable debug mode. This option increases log verbosity, directs log messages to stdout and causes ffserver to run in the foreground -- cgit v1.1 From 89b503b55f2b2713f1c3cc8981102c1a7b663281 Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Sat, 23 Apr 2011 15:19:17 +0200 Subject: Lowercase all ff* program names. --- doc/ffmpeg.texi | 6 +++--- doc/ffplay.texi | 4 ++-- doc/ffprobe.texi | 6 +++--- doc/ffserver.texi | 6 +++--- ffmpeg.c | 4 ++-- ffplay.c | 4 ++-- ffprobe.c | 4 ++-- ffserver.c | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 62282b2..0d12f65 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -1,8 +1,8 @@ \input texinfo @c -*- texinfo -*- -@settitle FFmpeg Documentation +@settitle ffmpeg Documentation @titlepage -@center @titlefont{FFmpeg Documentation} +@center @titlefont{ffmpeg Documentation} @end titlepage @top @@ -1046,7 +1046,7 @@ file to which you want to add them. @ignore @setfilename ffmpeg -@settitle FFmpeg video converter +@settitle ffmpeg video converter @c man begin SEEALSO ffplay(1), ffprobe(1), ffserver(1) and the Libav HTML documentation diff --git a/doc/ffplay.texi b/doc/ffplay.texi index 6199e6d..e5de3d2 100644 --- a/doc/ffplay.texi +++ b/doc/ffplay.texi @@ -1,8 +1,8 @@ \input texinfo @c -*- texinfo -*- -@settitle FFplay Documentation +@settitle ffplay Documentation @titlepage -@center @titlefont{FFplay Documentation} +@center @titlefont{ffplay Documentation} @end titlepage @top diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi index 1509022..5e856e6 100644 --- a/doc/ffprobe.texi +++ b/doc/ffprobe.texi @@ -1,8 +1,8 @@ \input texinfo @c -*- texinfo -*- -@settitle FFprobe Documentation +@settitle ffprobe Documentation @titlepage -@center @titlefont{FFprobe Documentation} +@center @titlefont{ffprobe Documentation} @end titlepage @top @@ -119,7 +119,7 @@ with name "STREAM". @ignore @setfilename ffprobe -@settitle FFprobe media prober +@settitle ffprobe media prober @c man begin SEEALSO ffmpeg(1), ffplay(1), ffserver(1) and the Libav HTML documentation diff --git a/doc/ffserver.texi b/doc/ffserver.texi index e5c9d40..d247016 100644 --- a/doc/ffserver.texi +++ b/doc/ffserver.texi @@ -1,8 +1,8 @@ \input texinfo @c -*- texinfo -*- -@settitle FFserver Documentation +@settitle ffserver Documentation @titlepage -@center @titlefont{FFserver Documentation} +@center @titlefont{ffserver Documentation} @end titlepage @top @@ -261,7 +261,7 @@ rather than as a daemon. @ignore @setfilename ffserver -@settitle FFserver video server +@settitle ffserver video server @c man begin SEEALSO diff --git a/ffmpeg.c b/ffmpeg.c index 886d5da..d54785d 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -1,5 +1,5 @@ /* - * FFmpeg main + * ffmpeg main * Copyright (c) 2000-2003 Fabrice Bellard * * This file is part of Libav. @@ -78,7 +78,7 @@ #include "libavutil/avassert.h" -const char program_name[] = "FFmpeg"; +const char program_name[] = "ffmpeg"; const int program_birth_year = 2000; /* select an input stream for an output stream */ diff --git a/ffplay.c b/ffplay.c index 766d5ca..18010ef 100644 --- a/ffplay.c +++ b/ffplay.c @@ -1,5 +1,5 @@ /* - * FFplay : Simple Media Player based on the Libav libraries + * ffplay : Simple Media Player based on the Libav libraries * Copyright (c) 2003 Fabrice Bellard * * This file is part of Libav. @@ -55,7 +55,7 @@ #include #include -const char program_name[] = "FFplay"; +const char program_name[] = "ffplay"; const int program_birth_year = 2003; //#define DEBUG diff --git a/ffprobe.c b/ffprobe.c index cc3699b..6e26c11 100644 --- a/ffprobe.c +++ b/ffprobe.c @@ -1,5 +1,5 @@ /* - * FFprobe : Simple Media Prober based on the Libav libraries + * ffprobe : Simple Media Prober based on the Libav libraries * Copyright (c) 2007-2010 Stefano Sabatini * * This file is part of Libav. @@ -28,7 +28,7 @@ #include "libavdevice/avdevice.h" #include "cmdutils.h" -const char program_name[] = "FFprobe"; +const char program_name[] = "ffprobe"; const int program_birth_year = 2007; static int do_show_format = 0; diff --git a/ffserver.c b/ffserver.c index 9cb65da..829eb2e 100644 --- a/ffserver.c +++ b/ffserver.c @@ -59,7 +59,7 @@ #include "cmdutils.h" -const char program_name[] = "FFserver"; +const char program_name[] = "ffserver"; const int program_birth_year = 2000; static const OptionDef options[]; -- cgit v1.1 From 9261e6cf3fe579fa02a96761c8e81a77bb3d8b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 20 Apr 2011 15:36:37 +0300 Subject: rtp: Rename the open/close functions to alloc/free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids clashes if we internally want to override the global open function. Signed-off-by: Martin Storsjö --- libavformat/rdt.c | 4 ++-- libavformat/rtpdec.h | 4 ++-- libavformat/rtpdec_amr.c | 8 ++++---- libavformat/rtpdec_asf.c | 4 ++-- libavformat/rtpdec_h264.c | 4 ++-- libavformat/rtpdec_latm.c | 4 ++-- libavformat/rtpdec_mpeg4.c | 8 ++++---- libavformat/rtpdec_qcelp.c | 4 ++-- libavformat/rtpdec_qdm2.c | 4 ++-- libavformat/rtpdec_qt.c | 4 ++-- libavformat/rtpdec_svq3.c | 4 ++-- libavformat/rtpdec_vp8.c | 4 ++-- libavformat/rtpdec_xiph.c | 8 ++++---- libavformat/rtsp.c | 6 +++--- 14 files changed, 35 insertions(+), 35 deletions(-) diff --git a/libavformat/rdt.c b/libavformat/rdt.c index dfb31d1..bc3c17b 100644 --- a/libavformat/rdt.c +++ b/libavformat/rdt.c @@ -551,8 +551,8 @@ static RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \ .codec_type = t, \ .codec_id = CODEC_ID_NONE, \ .parse_sdp_a_line = rdt_parse_sdp_line, \ - .open = rdt_new_context, \ - .close = rdt_free_context, \ + .alloc = rdt_new_context, \ + .free = rdt_free_context, \ .parse_packet = rdt_parse_packet \ } diff --git a/libavformat/rtpdec.h b/libavformat/rtpdec.h index da53efc..a4d21aa 100644 --- a/libavformat/rtpdec.h +++ b/libavformat/rtpdec.h @@ -126,8 +126,8 @@ struct RTPDynamicProtocolHandler_s { int st_index, PayloadContext *priv_data, const char *line); ///< Parse the a= line from the sdp field - PayloadContext *(*open) (void); ///< allocate any data needed by the rtp parsing for this dynamic data. - void (*close)(PayloadContext *protocol_data); ///< free any data needed by the rtp parsing for this dynamic data. + PayloadContext *(*alloc) (void); ///< allocate any data needed by the rtp parsing for this dynamic data. + void (*free)(PayloadContext *protocol_data); ///< free any data needed by the rtp parsing for this dynamic data. DynamicPayloadPacketHandlerProc parse_packet; ///< parse handler for this dynamic packet. struct RTPDynamicProtocolHandler_s *next; diff --git a/libavformat/rtpdec_amr.c b/libavformat/rtpdec_amr.c index 802e7c1..b7ff3aa 100644 --- a/libavformat/rtpdec_amr.c +++ b/libavformat/rtpdec_amr.c @@ -191,8 +191,8 @@ RTPDynamicProtocolHandler ff_amr_nb_dynamic_handler = { .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = CODEC_ID_AMR_NB, .parse_sdp_a_line = amr_parse_sdp_line, - .open = amr_new_context, - .close = amr_free_context, + .alloc = amr_new_context, + .free = amr_free_context, .parse_packet = amr_handle_packet, }; @@ -201,8 +201,8 @@ RTPDynamicProtocolHandler ff_amr_wb_dynamic_handler = { .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = CODEC_ID_AMR_WB, .parse_sdp_a_line = amr_parse_sdp_line, - .open = amr_new_context, - .close = amr_free_context, + .alloc = amr_new_context, + .free = amr_free_context, .parse_packet = amr_handle_packet, }; diff --git a/libavformat/rtpdec_asf.c b/libavformat/rtpdec_asf.c index a8326cf..ecacc0e 100644 --- a/libavformat/rtpdec_asf.c +++ b/libavformat/rtpdec_asf.c @@ -286,8 +286,8 @@ RTPDynamicProtocolHandler ff_ms_rtp_ ## n ## _handler = { \ .codec_type = t, \ .codec_id = CODEC_ID_NONE, \ .parse_sdp_a_line = asfrtp_parse_sdp_line, \ - .open = asfrtp_new_context, \ - .close = asfrtp_free_context, \ + .alloc = asfrtp_new_context, \ + .free = asfrtp_free_context, \ .parse_packet = asfrtp_parse_packet, \ } diff --git a/libavformat/rtpdec_h264.c b/libavformat/rtpdec_h264.c index 4c9b8ba..effdc1f 100644 --- a/libavformat/rtpdec_h264.c +++ b/libavformat/rtpdec_h264.c @@ -398,7 +398,7 @@ RTPDynamicProtocolHandler ff_h264_dynamic_handler = { .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = CODEC_ID_H264, .parse_sdp_a_line = parse_h264_sdp_line, - .open = h264_new_context, - .close = h264_free_context, + .alloc = h264_new_context, + .free = h264_free_context, .parse_packet = h264_handle_packet }; diff --git a/libavformat/rtpdec_latm.c b/libavformat/rtpdec_latm.c index 5bf4c19..bde34b7 100644 --- a/libavformat/rtpdec_latm.c +++ b/libavformat/rtpdec_latm.c @@ -181,7 +181,7 @@ RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler = { .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = CODEC_ID_AAC, .parse_sdp_a_line = latm_parse_sdp_line, - .open = latm_new_context, - .close = latm_free_context, + .alloc = latm_new_context, + .free = latm_free_context, .parse_packet = latm_parse_packet }; diff --git a/libavformat/rtpdec_mpeg4.c b/libavformat/rtpdec_mpeg4.c index 9f2fcb3..7a63cc3 100644 --- a/libavformat/rtpdec_mpeg4.c +++ b/libavformat/rtpdec_mpeg4.c @@ -235,8 +235,8 @@ RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = { .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = CODEC_ID_MPEG4, .parse_sdp_a_line = parse_sdp_line, - .open = NULL, - .close = NULL, + .alloc = NULL, + .free = NULL, .parse_packet = NULL }; @@ -245,7 +245,7 @@ RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = { .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = CODEC_ID_AAC, .parse_sdp_a_line = parse_sdp_line, - .open = new_context, - .close = free_context, + .alloc = new_context, + .free = free_context, .parse_packet = aac_parse_packet }; diff --git a/libavformat/rtpdec_qcelp.c b/libavformat/rtpdec_qcelp.c index cc16ec1..325683c 100644 --- a/libavformat/rtpdec_qcelp.c +++ b/libavformat/rtpdec_qcelp.c @@ -223,7 +223,7 @@ RTPDynamicProtocolHandler ff_qcelp_dynamic_handler = { .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = CODEC_ID_QCELP, .static_payload_id = 12, - .open = qcelp_new_context, - .close = qcelp_free_context, + .alloc = qcelp_new_context, + .free = qcelp_free_context, .parse_packet = qcelp_parse_packet }; diff --git a/libavformat/rtpdec_qdm2.c b/libavformat/rtpdec_qdm2.c index 0d744be..7f5f077 100644 --- a/libavformat/rtpdec_qdm2.c +++ b/libavformat/rtpdec_qdm2.c @@ -309,7 +309,7 @@ RTPDynamicProtocolHandler ff_qdm2_dynamic_handler = { .enc_name = "X-QDM", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = CODEC_ID_NONE, - .open = qdm2_extradata_new, - .close = qdm2_extradata_free, + .alloc = qdm2_extradata_new, + .free = qdm2_extradata_free, .parse_packet = qdm2_parse_packet, }; diff --git a/libavformat/rtpdec_qt.c b/libavformat/rtpdec_qt.c index a295ba7..8dd2968 100644 --- a/libavformat/rtpdec_qt.c +++ b/libavformat/rtpdec_qt.c @@ -244,8 +244,8 @@ RTPDynamicProtocolHandler ff_ ## m ## _rtp_ ## n ## _handler = { \ .enc_name = s, \ .codec_type = t, \ .codec_id = CODEC_ID_NONE, \ - .open = qt_rtp_new, \ - .close = qt_rtp_free, \ + .alloc = qt_rtp_new, \ + .free = qt_rtp_free, \ .parse_packet = qt_rtp_parse_packet, \ } diff --git a/libavformat/rtpdec_svq3.c b/libavformat/rtpdec_svq3.c index 8c0926212..3314342 100644 --- a/libavformat/rtpdec_svq3.c +++ b/libavformat/rtpdec_svq3.c @@ -128,7 +128,7 @@ RTPDynamicProtocolHandler ff_svq3_dynamic_handler = { .enc_name = "X-SV3V-ES", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = CODEC_ID_NONE, // see if (config_packet) above - .open = svq3_extradata_new, - .close = svq3_extradata_free, + .alloc = svq3_extradata_new, + .free = svq3_extradata_free, .parse_packet = svq3_parse_packet, }; diff --git a/libavformat/rtpdec_vp8.c b/libavformat/rtpdec_vp8.c index 9e50cc4..026728e 100644 --- a/libavformat/rtpdec_vp8.c +++ b/libavformat/rtpdec_vp8.c @@ -148,7 +148,7 @@ RTPDynamicProtocolHandler ff_vp8_dynamic_handler = { .enc_name = "VP8", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = CODEC_ID_VP8, - .open = vp8_new_context, - .close = vp8_free_context, + .alloc = vp8_new_context, + .free = vp8_free_context, .parse_packet = vp8_handle_packet, }; diff --git a/libavformat/rtpdec_xiph.c b/libavformat/rtpdec_xiph.c index 4d8e834..a7f36ef 100644 --- a/libavformat/rtpdec_xiph.c +++ b/libavformat/rtpdec_xiph.c @@ -389,8 +389,8 @@ RTPDynamicProtocolHandler ff_theora_dynamic_handler = { .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = CODEC_ID_THEORA, .parse_sdp_a_line = xiph_parse_sdp_line, - .open = xiph_new_context, - .close = xiph_free_context, + .alloc = xiph_new_context, + .free = xiph_free_context, .parse_packet = xiph_handle_packet }; @@ -399,7 +399,7 @@ RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = { .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = CODEC_ID_VORBIS, .parse_sdp_a_line = xiph_parse_sdp_line, - .open = xiph_new_context, - .close = xiph_free_context, + .alloc = xiph_new_context, + .free = xiph_free_context, .parse_packet = xiph_handle_packet }; diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 58f7ddc..14111e6 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -132,8 +132,8 @@ static void init_rtp_handler(RTPDynamicProtocolHandler *handler, return; codec->codec_id = handler->codec_id; rtsp_st->dynamic_handler = handler; - if (handler->open) - rtsp_st->dynamic_protocol_context = handler->open(); + if (handler->alloc) + rtsp_st->dynamic_protocol_context = handler->alloc(); } /* parse the rtpmap description: /[/] */ @@ -526,7 +526,7 @@ void ff_rtsp_close_streams(AVFormatContext *s) rtsp_st = rt->rtsp_streams[i]; if (rtsp_st) { if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context) - rtsp_st->dynamic_handler->close( + rtsp_st->dynamic_handler->free( rtsp_st->dynamic_protocol_context); av_free(rtsp_st); } -- cgit v1.1 From b1ac139d89b9fc55b70ad3411af2f75fe8b17805 Mon Sep 17 00:00:00 2001 From: Kirill Gavrilov Date: Wed, 20 Apr 2011 14:36:44 +0300 Subject: Handle unicode file names on windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All file names should be in UTF-8 within libavformat. This is handled by mapping the open() function to an internal one in os_support.h for windows. fopen() could be overridden in the same way, but if that would be used from ffmpeg.c, it would add a dependency on an ff prefixed internal lavf function. Signed-off-by: Martin Storsjö --- cmdutils.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ libavformat/os_support.c | 28 +++++++++++++++++++++ libavformat/os_support.h | 5 ++++ libavformat/version.h | 2 +- 4 files changed, 97 insertions(+), 1 deletion(-) diff --git a/cmdutils.c b/cmdutils.c index f1cbd55..f25f61d 100644 --- a/cmdutils.c +++ b/cmdutils.c @@ -155,6 +155,66 @@ static const OptionDef* find_option(const OptionDef *po, const char *name){ return po; } +#if defined(_WIN32) && !defined(__MINGW32CE__) +/* Will be leaked on exit */ +static char** win32_argv_utf8 = NULL; +static int win32_argc = 0; + +/** + * Prepare command line arguments for executable. + * For Windows - perform wide-char to UTF-8 conversion. + * Input arguments should be main() function arguments. + * @param argc_ptr Arguments number (including executable) + * @param argv_ptr Arguments list. + */ +static void prepare_app_arguments(int *argc_ptr, char ***argv_ptr) +{ + char *argstr_flat; + wchar_t **argv_w; + int i, buffsize = 0, offset = 0; + + if (win32_argv_utf8) { + *argc_ptr = win32_argc; + *argv_ptr = win32_argv_utf8; + return; + } + + win32_argc = 0; + argv_w = CommandLineToArgvW(GetCommandLineW(), &win32_argc); + if (win32_argc <= 0 || !argv_w) + return; + + /* determine the UTF-8 buffer size (including NULL-termination symbols) */ + for (i = 0; i < win32_argc; i++) + buffsize += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, + NULL, 0, NULL, NULL); + + win32_argv_utf8 = av_mallocz(sizeof(char*) * (win32_argc + 1) + buffsize); + argstr_flat = (char*)win32_argv_utf8 + sizeof(char*) * (win32_argc + 1); + if (win32_argv_utf8 == NULL) { + LocalFree(argv_w); + return; + } + + for (i = 0; i < win32_argc; i++) { + win32_argv_utf8[i] = &argstr_flat[offset]; + offset += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, + &argstr_flat[offset], + buffsize - offset, NULL, NULL); + } + win32_argv_utf8[i] = NULL; + LocalFree(argv_w); + + *argc_ptr = win32_argc; + *argv_ptr = win32_argv_utf8; +} +#else +static inline void prepare_app_arguments(int *argc_ptr, char ***argv_ptr) +{ + /* nothing to do */ +} +#endif /* WIN32 && !__MINGW32CE__ */ + void parse_options(int argc, char **argv, const OptionDef *options, void (* parse_arg_function)(const char*)) { @@ -162,6 +222,9 @@ void parse_options(int argc, char **argv, const OptionDef *options, int optindex, handleoptions=1; const OptionDef *po; + /* perform system-dependent conversions for arguments list */ + prepare_app_arguments(&argc, &argv); + /* parse options */ optindex = 1; while (optindex < argc) { diff --git a/libavformat/os_support.c b/libavformat/os_support.c index 5a3a1bb..05577b7 100644 --- a/libavformat/os_support.c +++ b/libavformat/os_support.c @@ -28,6 +28,34 @@ #include "avformat.h" #include "os_support.h" +#if defined(_WIN32) && !defined(__MINGW32CE__) +#include + +#undef open +int ff_win32_open(const char *filename_utf8, int oflag, int pmode) +{ + int fd; + int num_chars; + wchar_t *filename_w; + + /* convert UTF-8 to wide chars */ + num_chars = MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, NULL, 0); + if (num_chars <= 0) + return -1; + filename_w = av_mallocz(sizeof(wchar_t) * num_chars); + MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, filename_w, num_chars); + + fd = _wopen(filename_w, oflag, pmode); + av_freep(&filename_w); + + /* filename maybe be in CP_ACP */ + if (fd == -1 && !(oflag & O_CREAT)) + return open(filename_utf8, oflag, pmode); + + return fd; +} +#endif + #if CONFIG_NETWORK #include #include diff --git a/libavformat/os_support.h b/libavformat/os_support.h index dc01e64..521e997 100644 --- a/libavformat/os_support.h +++ b/libavformat/os_support.h @@ -45,6 +45,11 @@ static inline int is_dos_path(const char *path) return 0; } +#if defined(_WIN32) && !defined(__MINGW32CE__) +int ff_win32_open(const char *filename, int oflag, int pmode); +#define open ff_win32_open +#endif + #if CONFIG_NETWORK #if !HAVE_SOCKLEN_T typedef int socklen_t; diff --git a/libavformat/version.h b/libavformat/version.h index 9041f92..22b5dc9 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -25,7 +25,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 53 #define LIBAVFORMAT_VERSION_MINOR 0 -#define LIBAVFORMAT_VERSION_MICRO 2 +#define LIBAVFORMAT_VERSION_MICRO 3 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ -- cgit v1.1