From 8b50a8d32f92173b2e9ea754704177d02471c014 Mon Sep 17 00:00:00 2001 From: Joey Armstrong Date: Fri, 27 Apr 2012 17:00:00 -0400 Subject: [PATCH 001/159] bug 748130: Replace FORCE dependencies, repacks are a conditional force. r=ted --- config/config.mk | 4 ++- js/src/config/config.mk | 4 ++- mobile/android/base/locales/Makefile.in | 36 ++++++++++++++++++++----- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/config/config.mk b/config/config.mk index 2d799f41eb21..6a5ba195a17c 100644 --- a/config/config.mk +++ b/config/config.mk @@ -713,7 +713,9 @@ endif # WINNT/OS2 AB_CD = $(MOZ_UI_LOCALE) ifndef L10NBASEDIR -L10NBASEDIR = $(error L10NBASEDIR not defined by configure) + L10NBASEDIR = $(error L10NBASEDIR not defined by configure) +else + IS_LANGUAGE_REPACK = 1 endif EXPAND_LOCALE_SRCDIR = $(if $(filter en-US,$(AB_CD)),$(topsrcdir)/$(1)/en-US,$(call core_realpath,$(L10NBASEDIR))/$(AB_CD)/$(subst /locales,,$(1))) diff --git a/js/src/config/config.mk b/js/src/config/config.mk index 2d799f41eb21..6a5ba195a17c 100644 --- a/js/src/config/config.mk +++ b/js/src/config/config.mk @@ -713,7 +713,9 @@ endif # WINNT/OS2 AB_CD = $(MOZ_UI_LOCALE) ifndef L10NBASEDIR -L10NBASEDIR = $(error L10NBASEDIR not defined by configure) + L10NBASEDIR = $(error L10NBASEDIR not defined by configure) +else + IS_LANGUAGE_REPACK = 1 endif EXPAND_LOCALE_SRCDIR = $(if $(filter en-US,$(AB_CD)),$(topsrcdir)/$(1)/en-US,$(call core_realpath,$(L10NBASEDIR))/$(AB_CD)/$(subst /locales,,$(1))) diff --git a/mobile/android/base/locales/Makefile.in b/mobile/android/base/locales/Makefile.in index 685174e32f63..94fe6be370c1 100644 --- a/mobile/android/base/locales/Makefile.in +++ b/mobile/android/base/locales/Makefile.in @@ -54,14 +54,21 @@ BRANDPATH = $(call core_abspath,$(DEPTH)/dist/bin/chrome/$(AB_CD)/locale/brandin else BRANDPATH = $(call core_abspath,$(DIST)/xpi-stage/$(XPI_NAME)/chrome/$(AB_CD)/locale/branding/brand.dtd) endif +$(warnIfEmpty,AB_CD) # todo: $(errorIfEmpty ) DEFINES += -DAB_CD=$(AB_CD) -libs realchrome:: ../res/values/strings.xml ; +dir-res-values := ../res/values +strings-xml := $(dir-res-values)/strings.xml +strings-xml-in := $(srcdir)/../strings.xml.in + +GARBAGE += $(strings-xml) + +libs realchrome:: $(strings-xml) chrome-%:: AB_CD=$* chrome-%:: - @$(MAKE) ../res/values-$(AB_rCD)/strings.xml AB_CD=$* + @$(MAKE) $(dir-res-values)-$(AB_rCD)/strings.xml AB_CD=$* # setup the path to bookmarks.inc. copied and tweaked version of MERGE_FILE from config/config.mk MOBILE_LOCALE_SRCDIR = $(if $(filter en-US,$(AB_CD)),$(topsrcdir)/mobile/locales/en-US,$(call core_realpath,$(L10NBASEDIR))/$(AB_CD)/mobile) @@ -75,14 +82,31 @@ else BOOKMARKSPATH = $(call core_abspath,$(MOBILE_LOCALE_SRCDIR)/profile/bookmarks.inc) endif -%/strings.xml: FORCE - $(NSINSTALL) -D $* - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \ +# Determine the ../res/values[-*]/ path +strings-xml-bypath = $(filter %/strings.xml,$(MAKECMDGOALS)) +ifeq (,$(strip $(strings-xml-bypath))) + strings-xml-bypath = $(strings-xml) +endif +dir-strings-xml = $(patsubst %/,%,$(dir $(strings-xml-bypath))) + +strings-xml-preqs =\ + $(strings-xml-in) \ + $(BRANDPATH) \ + $(STRINGSPATH) \ + $(SYNCSTRINGSPATH) \ + $(BOOKMARKSPATH) \ + $(if $(IS_LANGUAGE_REPACK),FORCE) \ + $(NULL) + +$(dir-strings-xml)/strings.xml: $(strings-xml-preqs) + $(NSINSTALL) -D $(dir-strings-xml) + $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ + $(DEFINES) \ -DBRANDPATH="$(BRANDPATH)" \ -DSTRINGSPATH="$(STRINGSPATH)" \ -DSYNCSTRINGSPATH="$(SYNCSTRINGSPATH)" \ -DBOOKMARKSPATH="$(BOOKMARKSPATH)" \ - $(srcdir)/../strings.xml.in \ + $< \ > $@ include $(topsrcdir)/config/rules.mk From eb0a17535a82c7835b14f13b7daf49e8852ba5b7 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 30 Apr 2012 10:19:17 -0400 Subject: [PATCH 002/159] Bug 749357 - TiledThebesLayerOGL can draw un-rendered areas of tiles. r=chrislord --- gfx/layers/opengl/ReusableTileStoreOGL.cpp | 13 ++++++----- gfx/layers/opengl/ReusableTileStoreOGL.h | 3 +++ gfx/layers/opengl/TiledThebesLayerOGL.cpp | 25 +++++++++++++++------- gfx/layers/opengl/TiledThebesLayerOGL.h | 6 ++---- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/gfx/layers/opengl/ReusableTileStoreOGL.cpp b/gfx/layers/opengl/ReusableTileStoreOGL.cpp index 485d41e1d608..125cf5334a77 100644 --- a/gfx/layers/opengl/ReusableTileStoreOGL.cpp +++ b/gfx/layers/opengl/ReusableTileStoreOGL.cpp @@ -122,8 +122,8 @@ ReusableTileStoreOGL::HarvestTiles(TiledLayerBufferOGL* aVideoMemoryTiledBuffer, TiledTexture removedTile; if (aVideoMemoryTiledBuffer->RemoveTile(nsIntPoint(x, y), removedTile)) { ReusableTiledTextureOGL* reusedTile = - new ReusableTiledTextureOGL(removedTile, tileRegion, tileSize, - aOldResolution); + new ReusableTiledTextureOGL(removedTile, nsIntPoint(x, y), tileRegion, + tileSize, aOldResolution); mTiles.AppendElement(reusedTile); } #ifdef GFX_TILEDLAYER_PREF_WARNINGS @@ -196,12 +196,11 @@ ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer, // semi-transparent layers. // Similarly, if we have multiple tiles covering the same area, we will // end up with rendering artifacts if the aLayer isn't opaque. - nsIntRect tileRect = tile->mTileRegion.GetBounds(); - uint16_t tileStartX = tileRect.x % tile->mTileSize; - uint16_t tileStartY = tileRect.y % tile->mTileSize; - nsIntRect textureRect(tileStartX, tileStartY, tileRect.width, tileRect.height); + uint16_t tileStartX = tile->mTileOrigin.x % tile->mTileSize; + uint16_t tileStartY = tile->mTileOrigin.y % tile->mTileSize; + nsIntPoint tileOffset(tile->mTileOrigin.x - tileStartX, tile->mTileOrigin.y - tileStartY); nsIntSize textureSize(tile->mTileSize, tile->mTileSize); - aLayer->RenderTile(tile->mTexture, transform, aRenderOffset, tileRect, textureRect, textureSize); + aLayer->RenderTile(tile->mTexture, transform, aRenderOffset, tile->mTileRegion, tileOffset, textureSize); } } diff --git a/gfx/layers/opengl/ReusableTileStoreOGL.h b/gfx/layers/opengl/ReusableTileStoreOGL.h index a0688c08995f..347d16368ab1 100644 --- a/gfx/layers/opengl/ReusableTileStoreOGL.h +++ b/gfx/layers/opengl/ReusableTileStoreOGL.h @@ -23,10 +23,12 @@ class ReusableTiledTextureOGL { public: ReusableTiledTextureOGL(TiledTexture aTexture, + const nsIntPoint& aTileOrigin, const nsIntRegion& aTileRegion, uint16_t aTileSize, gfxSize aResolution) : mTexture(aTexture) + , mTileOrigin(aTileOrigin) , mTileRegion(aTileRegion) , mTileSize(aTileSize) , mResolution(aResolution) @@ -35,6 +37,7 @@ public: ~ReusableTiledTextureOGL() {} TiledTexture mTexture; + const nsIntPoint mTileOrigin; const nsIntRegion mTileRegion; uint16_t mTileSize; gfxSize mResolution; diff --git a/gfx/layers/opengl/TiledThebesLayerOGL.cpp b/gfx/layers/opengl/TiledThebesLayerOGL.cpp index 9fe53e0b6ad1..2739f600bfd6 100644 --- a/gfx/layers/opengl/TiledThebesLayerOGL.cpp +++ b/gfx/layers/opengl/TiledThebesLayerOGL.cpp @@ -184,8 +184,8 @@ void TiledThebesLayerOGL::RenderTile(TiledTexture aTile, const gfx3DMatrix& aTransform, const nsIntPoint& aOffset, - nsIntRect aScreenRect, - nsIntRect aTextureRect, + nsIntRegion aScreenRegion, + nsIntPoint aTextureOffset, nsIntSize aTextureBounds) { gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, aTile.mTextureHandle); @@ -200,11 +200,16 @@ TiledThebesLayerOGL::RenderTile(TiledTexture aTile, program->SetLayerOpacity(GetEffectiveOpacity()); program->SetLayerTransform(aTransform); program->SetRenderOffset(aOffset); - program->SetLayerQuadRect(aScreenRect); - mOGLManager->BindAndDrawQuadWithTextureRect(program, - aTextureRect, - aTextureBounds); + nsIntRegionRectIterator it(aScreenRegion); + for (const nsIntRect* rect = it.Next(); rect != nsnull; rect = it.Next()) { + nsIntRect textureRect(rect->x - aTextureOffset.x, rect->y - aTextureOffset.y, + rect->width, rect->height); + program->SetLayerQuadRect(*rect); + mOGLManager->BindAndDrawQuadWithTextureRect(program, + textureRect, + aTextureBounds); + } } void @@ -244,9 +249,13 @@ TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOf GetTile(nsIntPoint(mVideoMemoryTiledBuffer.RoundDownToTileEdge(x), mVideoMemoryTiledBuffer.RoundDownToTileEdge(y))); if (tileTexture != mVideoMemoryTiledBuffer.GetPlaceholderTile()) { + nsIntRegion tileDrawRegion = nsIntRegion(nsIntRect(x, y, w, h)); + tileDrawRegion.And(tileDrawRegion, mValidRegion); + + nsIntPoint tileOffset(x - tileStartX, y - tileStartY); uint16_t tileSize = mVideoMemoryTiledBuffer.GetTileLength(); - RenderTile(tileTexture, GetEffectiveTransform(), aOffset, nsIntRect(x,y,w,h), - nsIntRect(tileStartX, tileStartY, w, h), nsIntSize(tileSize, tileSize)); + RenderTile(tileTexture, GetEffectiveTransform(), aOffset, tileDrawRegion, + tileOffset, nsIntSize(tileSize, tileSize)); } tileY++; y += h; diff --git a/gfx/layers/opengl/TiledThebesLayerOGL.h b/gfx/layers/opengl/TiledThebesLayerOGL.h index 5511684a909f..2e9b98cf0125 100644 --- a/gfx/layers/opengl/TiledThebesLayerOGL.h +++ b/gfx/layers/opengl/TiledThebesLayerOGL.h @@ -131,13 +131,11 @@ public: void ProcessUploadQueue(); // Renders a single given tile. - // XXX This currently takes an nsIntRect, but should actually take an - // nsIntRegion and iterate over each rectangle in the region. void RenderTile(TiledTexture aTile, const gfx3DMatrix& aTransform, const nsIntPoint& aOffset, - nsIntRect aScreenRect, - nsIntRect aTextureRect, + nsIntRegion aScreenRegion, + nsIntPoint aTextureOffset, nsIntSize aTextureBounds); private: From 1720f144261b2e4f586f755994830945461fc8e4 Mon Sep 17 00:00:00 2001 From: Christian Holler Date: Mon, 30 Apr 2012 10:23:12 -0400 Subject: [PATCH 003/159] Bug 749768 - Disable valgrind for jit-tests when running with AddressSanitizer, r=khuey --- js/src/Makefile.in | 6 +++++- js/src/config/autoconf.mk.in | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 2a84a85d8f21..96ec5c8f5002 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -606,10 +606,14 @@ ifneq ($(OS_ARCH),WINNT) # FIXME: this should be made work on Windows too. #check:: check-malloc-function-usage FIXME: disable on JM until closer to merge time. endif +ifndef MOZ_ASAN +JITTESTPARAMS="--valgrind" +endif + JITFLAGS = ,m,am,amd,n,mn,amn,amdn,mdn check-jit-test:: $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \ - --valgrind --no-slow --no-progress --tinderbox --jitflags=$(JITFLAGS) $(DIST)/bin/js$(BIN_SUFFIX) + --no-slow --no-progress --tinderbox --jitflags=$(JITFLAGS) $(JITTESTPARAMS) $(DIST)/bin/js$(BIN_SUFFIX) check:: check-jit-test diff --git a/js/src/config/autoconf.mk.in b/js/src/config/autoconf.mk.in index 35d50a269c4f..969977de79b2 100644 --- a/js/src/config/autoconf.mk.in +++ b/js/src/config/autoconf.mk.in @@ -337,6 +337,8 @@ HAVE_LINUX_PERF_EVENT_H = @HAVE_LINUX_PERF_EVENT_H@ MOZ_METRO = @MOZ_METRO@ +MOZ_ASAN = @MOZ_ASAN@ + # We only want to do the pymake sanity on Windows, other os's can cope ifeq ($(HOST_OS_ARCH),WINNT) # Ensure invariants between GNU Make and pymake From e02d58544d4697c0d19602c205338cc386a8fbbc Mon Sep 17 00:00:00 2001 From: Mark Capella Date: Mon, 30 Apr 2012 23:44:43 +0900 Subject: [PATCH 004/159] Bug 748716 - don't export ApplicationAccessibleWrap.h, r=surkov --- accessible/src/base/Makefile.in | 16 ++++++++++++++++ accessible/src/mac/Makefile.in | 1 - accessible/src/msaa/Makefile.in | 1 - accessible/src/other/Makefile.in | 1 - 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/accessible/src/base/Makefile.in b/accessible/src/base/Makefile.in index b034b9d071d5..613254810f07 100644 --- a/accessible/src/base/Makefile.in +++ b/accessible/src/base/Makefile.in @@ -114,4 +114,20 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) LOCAL_INCLUDES += \ -I$(srcdir)/../atk \ $(NULL) +else +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +LOCAL_INCLUDES += \ + -I$(srcdir)/../msaa \ + $(NULL) +else +ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa) +LOCAL_INCLUDES += \ + -I$(srcdir)/../mac \ + $(NULL) +else +LOCAL_INCLUDES += \ + -I$(srcdir)/../other \ + $(NULL) +endif +endif endif diff --git a/accessible/src/mac/Makefile.in b/accessible/src/mac/Makefile.in index 0849fd2bf45d..dae6b9259aaa 100644 --- a/accessible/src/mac/Makefile.in +++ b/accessible/src/mac/Makefile.in @@ -62,7 +62,6 @@ CMMSRCS = nsAccessNodeWrap.mm \ EXPORTS = \ - ApplicationAccessibleWrap.h \ ARIAGridAccessibleWrap.h \ nsAccessNodeWrap.h \ nsTextAccessibleWrap.h \ diff --git a/accessible/src/msaa/Makefile.in b/accessible/src/msaa/Makefile.in index bf0d9fdde56f..ffc3bc37563f 100644 --- a/accessible/src/msaa/Makefile.in +++ b/accessible/src/msaa/Makefile.in @@ -78,7 +78,6 @@ CPPSRCS = \ $(NULL) EXPORTS = \ - ApplicationAccessibleWrap.h \ ARIAGridAccessibleWrap.h \ nsAccessNodeWrap.h \ nsAccessibleWrap.h \ diff --git a/accessible/src/other/Makefile.in b/accessible/src/other/Makefile.in index d26eccdfe135..c19eed06a24e 100644 --- a/accessible/src/other/Makefile.in +++ b/accessible/src/other/Makefile.in @@ -54,7 +54,6 @@ CPPSRCS = \ $(NULL) EXPORTS = \ - ApplicationAccessibleWrap.h \ ARIAGridAccessibleWrap.h \ nsAccessNodeWrap.h \ nsTextAccessibleWrap.h \ From 6fa85ed098cf3223451b927e27bca1b691867300 Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Mon, 30 Apr 2012 16:13:26 +0100 Subject: [PATCH 005/159] Bug 747779 - Fix raw type Iterator warning in ProfileMigrator.java. r=kats Using an untyped Iterator causes warnings (and thus, build errors) in Java 7. --- mobile/android/base/ProfileMigrator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/android/base/ProfileMigrator.java b/mobile/android/base/ProfileMigrator.java index df588ba0b6b0..3351d3cbd5ed 100644 --- a/mobile/android/base/ProfileMigrator.java +++ b/mobile/android/base/ProfileMigrator.java @@ -541,9 +541,9 @@ public class ProfileMigrator { File cacheFile = GeckoAppShell.getCacheDir(mContext); File[] files = cacheFile.listFiles(); if (files != null) { - Iterator cacheFiles = Arrays.asList(files).iterator(); + Iterator cacheFiles = Arrays.asList(files).iterator(); while (cacheFiles.hasNext()) { - File libFile = (File)cacheFiles.next(); + File libFile = cacheFiles.next(); if (libFile.getName().endsWith(".so")) { libFile.delete(); } From f034ce66d336afd1666aad23345de2fd78f5e516 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 30 Apr 2012 18:17:44 +0200 Subject: [PATCH 006/159] Bug 750267 - Remove tools/elf-dynstr-gc. r=ted --- tools/elf-dynstr-gc/Makefile.in | 56 -- tools/elf-dynstr-gc/elf-gc-dynstr.c | 1243 --------------------------- 2 files changed, 1299 deletions(-) delete mode 100644 tools/elf-dynstr-gc/Makefile.in delete mode 100644 tools/elf-dynstr-gc/elf-gc-dynstr.c diff --git a/tools/elf-dynstr-gc/Makefile.in b/tools/elf-dynstr-gc/Makefile.in deleted file mode 100644 index cd2fa5f1f4e1..000000000000 --- a/tools/elf-dynstr-gc/Makefile.in +++ /dev/null @@ -1,56 +0,0 @@ -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is Mozilla Source Code. -# -# The Initial Developer of the Original Code is -# Christopher Blizzard. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either of the GNU General Public License Version 2 or later (the "GPL"), -# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** - -DEPTH = ../.. -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -SIMPLE_PROGRAMS = elf-gc-dynstr - -LOCAL_INCLUDES = $(GLIB_CFLAGS) -EXTRA_LIBS = $(GLIB_LIBS) - -include $(topsrcdir)/config/rules.mk - -#elf-gc-dynstr: elf-gc-dynstr.c -# gcc `glib-config --cflags` -g elf-gc-dynstr.c -o elf-gc-dynstr `glib-config --libs` - -#clean: - #rm -f elf-gc-dynstr core *~ diff --git a/tools/elf-dynstr-gc/elf-gc-dynstr.c b/tools/elf-dynstr-gc/elf-gc-dynstr.c deleted file mode 100644 index dcc34734ce2a..000000000000 --- a/tools/elf-dynstr-gc/elf-gc-dynstr.c +++ /dev/null @@ -1,1243 +0,0 @@ -/* elf_gc_dynst - * - * This is a program that removes unreferenced strings from the .dynstr - * section in ELF shared objects. It also shrinks the .dynstr section and - * relocates all symbols after it. - * - * This program was written and copyrighted by: - * Alexander Larsson - * - * - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org Code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2001 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -Elf32_Ehdr *elf_header = NULL; -#define FILE_OFFSET(offset) ((unsigned char *)(elf_header) + (offset)) - -struct dynamic_symbol { - Elf32_Word old_index; - Elf32_Word new_index; - char *string; -}; - -GHashTable *used_dynamic_symbols = NULL; -/* Data is dynamic_symbols, hashes on old_index */ -Elf32_Word hole_index; -Elf32_Word hole_end; -Elf32_Word hole_len; - -Elf32_Addr hole_addr_start; -Elf32_Addr hole_addr_remap_start; -Elf32_Addr hole_addr_remap_end; - -int need_byteswap; - -unsigned char machine_type; - -Elf32_Word -read_word(Elf32_Word w) -{ - if (need_byteswap) - w = GUINT32_SWAP_LE_BE(w); - return w; -} - -Elf32_Sword -read_sword(Elf32_Sword w) -{ - if (need_byteswap) - w = (Elf32_Sword)GUINT32_SWAP_LE_BE((guint32)w); - return w; -} - -void -write_word(Elf32_Word *ptr, Elf32_Word w) -{ - if (need_byteswap) - w = GUINT32_SWAP_LE_BE(w); - *ptr = w; -} - -Elf32_Half -read_half(Elf32_Half h) -{ - if (need_byteswap) - h = GUINT16_SWAP_LE_BE(h); - return h; -} - -void -write_half(Elf32_Half *ptr, Elf32_Half h) -{ - if (need_byteswap) - h = GUINT16_SWAP_LE_BE(h); - *ptr = h; -} - -void -setup_byteswapping(unsigned char ei_data) -{ - need_byteswap = 0; -#if G_BYTE_ORDER == G_BIG_ENDIAN - if (ei_data == ELFDATA2LSB) - need_byteswap = 1; -#endif -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - if (ei_data == ELFDATA2MSB) - need_byteswap = 1; -#endif -} - - -Elf32_Shdr * -elf_find_section_num(int section_index) -{ - Elf32_Shdr *section; - Elf32_Word sectionsize; - - section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff)); - sectionsize = read_half(elf_header->e_shentsize); - - section = (Elf32_Shdr *)((char *)section + sectionsize*section_index); - - return section; -} - -Elf32_Shdr * -elf_find_section_named(char *name) -{ - Elf32_Shdr *section; - Elf32_Shdr *strtab_section; - Elf32_Word sectionsize; - int numsections; - char *strtab; - int i = 0; - - section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff)); - - strtab_section = elf_find_section_num(read_half(elf_header->e_shstrndx)); - - strtab = (char *)FILE_OFFSET(read_word(strtab_section->sh_offset)); - - sectionsize = read_half(elf_header->e_shentsize); - numsections = read_half(elf_header->e_shnum); - - for (i=0;ish_name)], name) == 0) { - return section; - } - section = (Elf32_Shdr *)((char *)section + sectionsize); - } - return NULL; -} - - -Elf32_Shdr * -elf_find_section(Elf32_Word sh_type) -{ - Elf32_Shdr *section; - Elf32_Word sectionsize; - int numsections; - int i = 0; - - section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff)); - sectionsize = read_half(elf_header->e_shentsize); - numsections = read_half(elf_header->e_shnum); - - for (i=0;ish_type) == sh_type) { - return section; - } - section = (Elf32_Shdr *)((char *)section + sectionsize); - } - return NULL; -} - -Elf32_Shdr * -elf_find_next_higher_section(Elf32_Word offset) -{ - Elf32_Shdr *section; - Elf32_Shdr *higher; - Elf32_Word sectionsize; - int numsections; - int i = 0; - - section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff)); - sectionsize = read_half(elf_header->e_shentsize); - numsections = read_half(elf_header->e_shnum); - - higher = NULL; - - for (i=0;ish_offset) >= offset) { - if (higher == NULL) { - higher = section; - } else if (read_word(section->sh_offset) < read_word(higher->sh_offset)) { - higher = section; - } - } - - section = (Elf32_Shdr *)((char *)section + sectionsize); - } - - return higher; -} - -Elf32_Word -vma_to_offset(Elf32_Addr addr) -{ - Elf32_Shdr *section; - Elf32_Shdr *higher; - Elf32_Word sectionsize; - int numsections; - int i = 0; - - section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff)); - sectionsize = read_half(elf_header->e_shentsize); - numsections = read_half(elf_header->e_shnum); - - higher = NULL; - - for (i=0;i= read_word(section->sh_addr)) && - (addr < read_word(section->sh_addr) + read_word(section->sh_size)) ) { - return read_word(section->sh_offset) + (addr - read_word(section->sh_addr)); - } - - section = (Elf32_Shdr *)((char *)section + sectionsize); - } - - fprintf(stderr, "Warning, unable to convert address %d (0x%x) to file offset\n", - addr, addr); - return 0; -} - - -void -find_segment_addr_min_max(Elf32_Word file_offset, - Elf32_Addr *start, Elf32_Addr *end) -{ - Elf32_Phdr *segment; - Elf32_Word segmentsize; - int numsegments; - int i = 0; - - segment = (Elf32_Phdr *)FILE_OFFSET(read_word(elf_header->e_phoff)); - segmentsize = read_half(elf_header->e_phentsize); - numsegments = read_half(elf_header->e_phnum); - - for (i=0;i= read_word(segment->p_offset)) && - (file_offset < read_word(segment->p_offset) + read_word(segment->p_filesz))) { - *start = read_word(segment->p_vaddr); - *end = read_word(segment->p_vaddr) + read_word(segment->p_memsz); - return; - } - - segment = (Elf32_Phdr *)((char *)segment + segmentsize); - } - fprintf(stderr, "Error: Couldn't find segment in find_segment_addr_min_max()\n"); -} - -void * -dynamic_find_tag(Elf32_Shdr *dynamic, Elf32_Sword d_tag) -{ - int i; - Elf32_Dyn *element; - - element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset)); - for (i=0; read_sword(element[i].d_tag) != DT_NULL; i++) { - if (read_sword(element[i].d_tag) == d_tag) { - return FILE_OFFSET(read_word(element[i].d_un.d_ptr)); - } - } - - return NULL; -} - -Elf32_Word -fixup_offset(Elf32_Word offset) -{ - if (offset >= hole_index) { - return offset - hole_len; - } - return offset; -} - -Elf32_Word -fixup_size(Elf32_Word offset, Elf32_Word size) -{ - /* Note: Doesn't handle the cases where the hole and the size intersect - partially. */ - - if ( (hole_index >= offset) && - (hole_index < offset + size)){ - return size - hole_len; - } - - return size; -} - -Elf32_Addr -fixup_addr(Elf32_Addr addr) -{ - if (addr == 0) - return 0; - - /* - if ( (addr < hole_addr_remap_start) || - (addr >= hole_addr_remap_end)) - return addr; - */ - - if (addr >= hole_addr_start) { - return addr - hole_len; - } - return addr; -} - -Elf32_Word -fixup_addr_size(Elf32_Addr addr, Elf32_Word size) -{ - /* Note: Doesn't handle the cases where the hole and the size intersect - partially. */ - /* - if ( (addr < hole_addr_remap_start) || - (addr >= hole_addr_remap_end)) - return size; - */ - if ( (hole_addr_start >= addr) && - (hole_addr_start < addr + size)){ - return size - hole_len; - } - - return size; -} - -void -possibly_add_string(int name_idx, const char *name) -{ - struct dynamic_symbol *dynamic_symbol; - if (name_idx != 0) { - dynamic_symbol = g_hash_table_lookup(used_dynamic_symbols, (gpointer) name_idx); - - if (dynamic_symbol == NULL) { - - dynamic_symbol = g_new(struct dynamic_symbol, 1); - - dynamic_symbol->old_index = name_idx; - dynamic_symbol->new_index = 0; - dynamic_symbol->string = g_strdup(name); - - g_hash_table_insert(used_dynamic_symbols, (gpointer)name_idx, dynamic_symbol); - /*printf("added dynamic string: %s (%d)\n", dynamic_symbol->string, name_idx);*/ - } - } -} - -Elf32_Word -fixup_string(Elf32_Word old_idx) -{ - struct dynamic_symbol *dynamic_symbol; - - if (old_idx == 0) - return 0; - - dynamic_symbol = g_hash_table_lookup(used_dynamic_symbols, (gpointer) old_idx); - - if (dynamic_symbol == NULL) { - fprintf(stderr, "AAAAAAAAAAAARGH!? Unknown string found in fixup (index: %d)!\n", old_idx); - return 0; - } - - return dynamic_symbol->new_index; -} - - - -void -add_strings_from_dynsym(Elf32_Shdr *dynsym, char *strtab) -{ - Elf32_Sym *symbol; - Elf32_Sym *symbol_end; - Elf32_Word entry_size; - - - symbol = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset)); - symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset) + read_word(dynsym->sh_size)); - entry_size = read_word(dynsym->sh_entsize); - - while (symbol < symbol_end) { - int name_idx; - struct dynamic_symbol *dynamic_symbol; - - name_idx = read_word(symbol->st_name); - possibly_add_string(name_idx, &strtab[name_idx]); - - - symbol = (Elf32_Sym *)((char *)symbol + entry_size); - } -} - - -void -fixup_strings_in_dynsym(Elf32_Shdr *dynsym) -{ - Elf32_Sym *symbol; - Elf32_Sym *symbol_end; - Elf32_Word entry_size; - - - symbol = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset)); - symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset) + read_word(dynsym->sh_size)); - entry_size = read_word(dynsym->sh_entsize); - - while (symbol < symbol_end) { - struct dynamic_symbol *dynamic_symbol; - - write_word(&symbol->st_name, - fixup_string(read_word(symbol->st_name))); - - symbol = (Elf32_Sym *)((char *)symbol + entry_size); - } -} - - -void -add_strings_from_dynamic(Elf32_Shdr *dynamic, char *strtab) -{ - int i; - int name_idx; - Elf32_Dyn *element; - Elf32_Word entry_size; - - entry_size = read_word(dynamic->sh_entsize); - - - element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset)); - while (read_sword(element->d_tag) != DT_NULL) { - - switch(read_sword(element->d_tag)) { - case DT_NEEDED: - case DT_SONAME: - case DT_RPATH: - name_idx = read_word(element->d_un.d_val); - /*if (name_idx) printf("d_tag: %d\n", element->d_tag);*/ - possibly_add_string(name_idx, &strtab[name_idx]); - break; - default: - ; - /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/ - } - - element = (Elf32_Dyn *)((char *)element + entry_size); - } - -} - -void -fixup_strings_in_dynamic(Elf32_Shdr *dynamic) -{ - int i; - int name_idx; - Elf32_Dyn *element; - Elf32_Word entry_size; - - entry_size = read_word(dynamic->sh_entsize); - - element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset)); - while (read_sword(element->d_tag) != DT_NULL) { - - switch(read_sword(element->d_tag)) { - case DT_NEEDED: - case DT_SONAME: - case DT_RPATH: - write_word(&element->d_un.d_val, - fixup_string(read_word(element->d_un.d_val))); - break; - default: - ; - /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/ - } - - element = (Elf32_Dyn *)((char *)element + entry_size); - } - -} - - -void -add_strings_from_ver_d(Elf32_Shdr *ver_d, char *strtab) -{ - Elf32_Verdaux *veraux; - Elf32_Verdef *verdef; - int num_aux; - int name_idx; - int i; - int cont; - - verdef = (Elf32_Verdef *)FILE_OFFSET(read_word(ver_d->sh_offset)); - - do { - num_aux = read_half(verdef->vd_cnt); - veraux = (Elf32_Verdaux *)((char *)verdef + read_word(verdef->vd_aux)); - for (i=0; ivda_name); - possibly_add_string(name_idx, &strtab[name_idx]); - veraux = (Elf32_Verdaux *)((char *)veraux + read_word(veraux->vda_next)); - } - - cont = read_word(verdef->vd_next) != 0; - verdef = (Elf32_Verdef *)((char *)verdef + read_word(verdef->vd_next)); - } while (cont); - -} - -void -fixup_strings_in_ver_d(Elf32_Shdr *ver_d) -{ - Elf32_Verdaux *veraux; - Elf32_Verdef *verdef; - int num_aux; - int name_idx; - int i; - int cont; - - verdef = (Elf32_Verdef *)FILE_OFFSET(read_word(ver_d->sh_offset)); - - do { - num_aux = read_half(verdef->vd_cnt); - veraux = (Elf32_Verdaux *)((char *)verdef + read_word(verdef->vd_aux)); - for (i=0; ivda_name, - fixup_string(read_word(veraux->vda_name))); - veraux = (Elf32_Verdaux *)((char *)veraux + read_word(veraux->vda_next)); - } - - cont = read_word(verdef->vd_next) != 0; - verdef = (Elf32_Verdef *)((char *)verdef + read_word(verdef->vd_next)); - } while (cont); - -} - -void -add_strings_from_ver_r(Elf32_Shdr *ver_r, char *strtab) -{ - Elf32_Vernaux *veraux; - Elf32_Verneed *verneed; - int num_aux; - int name_idx; - int i; - int cont; - - verneed = (Elf32_Verneed *)FILE_OFFSET(read_word(ver_r->sh_offset)); - - do { - name_idx = read_word(verneed->vn_file); - possibly_add_string(name_idx, &strtab[name_idx]); - num_aux = read_half(verneed->vn_cnt); - veraux = (Elf32_Vernaux *)((char *)verneed + read_word(verneed->vn_aux)); - for (i=0; ivna_name); - possibly_add_string(name_idx, &strtab[name_idx]); - veraux = (Elf32_Vernaux *)((char *)veraux + read_word(veraux->vna_next)); - } - - cont = read_word(verneed->vn_next) != 0; - verneed = (Elf32_Verneed *)((char *)verneed + read_word(verneed->vn_next)); - } while (cont); -} - -void -fixup_strings_in_ver_r(Elf32_Shdr *ver_r) -{ - Elf32_Vernaux *veraux; - Elf32_Verneed *verneed; - int num_aux; - int name_idx; - int i; - int cont; - - verneed = (Elf32_Verneed *)FILE_OFFSET(read_word(ver_r->sh_offset)); - - do { - write_word(&verneed->vn_file, - fixup_string(read_word(verneed->vn_file))); - num_aux = read_half(verneed->vn_cnt); - veraux = (Elf32_Vernaux *)((char *)verneed + read_word(verneed->vn_aux)); - for (i=0; ivna_name, - fixup_string(read_word(veraux->vna_name))); - veraux = (Elf32_Vernaux *)((char *)veraux + read_word(veraux->vna_next)); - } - - cont = read_word(verneed->vn_next) != 0; - verneed = (Elf32_Verneed *)((char *)verneed + read_word(verneed->vn_next)); - } while (cont); -} - -gboolean sum_size(gpointer key, - struct dynamic_symbol *sym, - int *size) -{ - *size += strlen(sym->string) + 1; - return 1; -} - -struct index_n_dynstr { - int index; - unsigned char *dynstr; -}; - -gboolean output_string(gpointer key, - struct dynamic_symbol *sym, - struct index_n_dynstr *x) -{ - sym->new_index = x->index; - memcpy(x->dynstr + x->index, sym->string, strlen(sym->string) + 1); - x->index += strlen(sym->string) + 1; - return 1; -} - - -unsigned char * -generate_new_dynstr(Elf32_Word *size_out) -{ - int size; - unsigned char *new_dynstr; - struct index_n_dynstr x; - - size = 1; /* first a zero */ - g_hash_table_foreach (used_dynamic_symbols, - (GHFunc)sum_size, - &size); - - - new_dynstr = g_malloc(size); - - new_dynstr[0] = 0; - x.index = 1; - x.dynstr = new_dynstr; - g_hash_table_foreach (used_dynamic_symbols, - (GHFunc)output_string, - &x); - - *size_out = size; - return new_dynstr; -} - -void -remap_sections(void) -{ - Elf32_Shdr *section; - Elf32_Word sectionsize; - int numsections; - int i = 0; - - section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff)); - sectionsize = read_half(elf_header->e_shentsize); - numsections = read_half(elf_header->e_shnum); - - for (i=0;ish_size, - fixup_size(read_word(section->sh_offset), - read_word(section->sh_size))); - write_word(§ion->sh_offset, - fixup_offset(read_word(section->sh_offset))); - write_word(§ion->sh_addr, - fixup_addr(read_word(section->sh_addr))); - - section = (Elf32_Shdr *)((char *)section + sectionsize); - } -} - - -void -remap_segments(void) -{ - Elf32_Phdr *segment; - Elf32_Word segmentsize; - Elf32_Word p_align; - int numsegments; - int i = 0; - - segment = (Elf32_Phdr *)FILE_OFFSET(read_word(elf_header->e_phoff)); - segmentsize = read_half(elf_header->e_phentsize); - numsegments = read_half(elf_header->e_phnum); - - for (i=0;ip_filesz, - fixup_size(read_word(segment->p_offset), - read_word(segment->p_filesz))); - write_word(&segment->p_offset, - fixup_offset(read_word(segment->p_offset))); - - write_word(&segment->p_memsz, - fixup_addr_size(read_word(segment->p_vaddr), - read_word(segment->p_memsz))); - write_word(&segment->p_vaddr, - fixup_addr(read_word(segment->p_vaddr))); - write_word(&segment->p_paddr, - read_word(segment->p_vaddr)); - - /* Consistancy checking: */ - p_align = read_word(segment->p_align); - if (p_align > 1) { - if ((read_word(segment->p_vaddr) - read_word(segment->p_offset))%p_align != 0) { - fprintf(stderr, "Warning, creating non-aligned segment addr: %x offset: %x allign: %x\n", - read_word(segment->p_vaddr), read_word(segment->p_offset), p_align); - } - } - - segment = (Elf32_Phdr *)((char *)segment + segmentsize); - } -} - -void -remap_elf_header(void) -{ - write_word(&elf_header->e_phoff, - fixup_offset(read_word(elf_header->e_phoff))); - write_word(&elf_header->e_shoff, - fixup_offset(read_word(elf_header->e_shoff))); - - write_word(&elf_header->e_entry, - fixup_addr(read_word(elf_header->e_entry))); -} - -void -remap_symtab(Elf32_Shdr *symtab) -{ - Elf32_Sym *symbol; - Elf32_Sym *symbol_end; - Elf32_Word entry_size; - - symbol = (Elf32_Sym *)FILE_OFFSET(read_word(symtab->sh_offset)); - symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(symtab->sh_offset) + - read_word(symtab->sh_size)); - entry_size = read_word(symtab->sh_entsize); - - while (symbol < symbol_end) { - write_word(&symbol->st_value, - fixup_addr(read_word(symbol->st_value))); - symbol = (Elf32_Sym *)((char *)symbol + entry_size); - } -} - - -/* Ugly global variables: */ -Elf32_Addr got_data_start = 0; -Elf32_Addr got_data_end = 0; - - -void -remap_rel_section(Elf32_Rel *rel, Elf32_Word size, Elf32_Word entry_size) -{ - Elf32_Rel *rel_end; - Elf32_Word offset; - Elf32_Addr *addr; - Elf32_Word type; - - rel_end = (Elf32_Rel *)((char *)rel + size); - - while (rel < rel_end) { - type = ELF32_R_TYPE(read_word(rel->r_info)); - switch (machine_type) { - case EM_386: - if ((type == R_386_RELATIVE) || (type == R_386_JMP_SLOT)) { - /* We need to relocate the data this is pointing to too. */ - offset = vma_to_offset(read_word(rel->r_offset)); - - addr = (Elf32_Addr *)FILE_OFFSET(offset); - write_word(addr, - fixup_addr(read_word(*addr))); - } - write_word(&rel->r_offset, - fixup_addr(read_word(rel->r_offset))); - break; - case EM_PPC: - /* The PPC always uses RELA relocations */ - break; - } - - - rel = (Elf32_Rel *)((char *)rel + entry_size); - } -} - -void -remap_rela_section(Elf32_Rela *rela, Elf32_Word size, Elf32_Word entry_size) -{ - Elf32_Rela *rela_end; - Elf32_Addr *addr; - Elf32_Word offset; - Elf32_Word type; - Elf32_Word bitmask; - - rela_end = (Elf32_Rela *)((char *)rela + size); - - while (rela < rela_end) { - type = ELF32_R_TYPE(read_word(rela->r_info)); - switch (machine_type) { - case EM_386: - if ((type == R_386_RELATIVE) || (type == R_386_JMP_SLOT)) { - /* We need to relocate the data this is pointing to too. */ - offset = vma_to_offset(read_word(rela->r_offset)); - - addr = (Elf32_Addr *)FILE_OFFSET(offset); - write_word(addr, - fixup_addr(read_word(*addr))); - } - write_word(&rela->r_offset, - fixup_addr(read_word(rela->r_offset))); - break; - case EM_PPC: - switch (type) { - case R_PPC_RELATIVE: - write_word((Elf32_Word *)&rela->r_addend, - fixup_addr(read_word(rela->r_addend))); - /* Fall through for 32bit offset fixup */ - case R_PPC_ADDR32: - case R_PPC_GLOB_DAT: - case R_PPC_JMP_SLOT: - write_word(&rela->r_offset, - fixup_addr(read_word(rela->r_offset))); - break; - case R_PPC_NONE: - break; - default: - fprintf(stderr, "Warning, unhandled PPC relocation type %d\n", type); - } - - break; - } - - rela = (Elf32_Rela *)((char *)rela + entry_size); - } -} - -void -remap_i386_got(void) -{ - Elf32_Shdr *got_section; - Elf32_Addr *got; - Elf32_Addr *got_end; - Elf32_Word entry_size; - - got_section = elf_find_section_named(".got"); - if (got_section == NULL) { - fprintf(stderr, "Warning, no .got section\n"); - return; - } - - got_data_start = read_word(got_section->sh_offset); - got_data_end = got_data_start + read_word(got_section->sh_size); - - got = (Elf32_Addr *)FILE_OFFSET(got_data_start); - got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end); - entry_size = read_word(got_section->sh_entsize); - - write_word(got, - fixup_addr(read_word(*got))); /* Pointer to .dynamic */ -} - -void -remap_ppc_got(void) -{ - Elf32_Shdr *got_section; - Elf32_Addr *got; - Elf32_Addr *got_end; - Elf32_Word entry_size; - - got_section = elf_find_section_named(".got"); - if (got_section == NULL) { - fprintf(stderr, "Warning, no .got section\n"); - return; - } - - got_data_start = read_word(got_section->sh_offset); - got_data_end = got_data_start + read_word(got_section->sh_size); - - got = (Elf32_Addr *)FILE_OFFSET(got_data_start); - got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end); - entry_size = read_word(got_section->sh_entsize); - - /* Skip reserved part. - * Note that this should really be found by finding the - * _GLOBAL_OFFSET_TABLE symbol, as it could (according to - * the spec) point to the middle of the got. - */ - got = (Elf32_Addr *)((char *)got + entry_size); /* Skip blrl instruction */ - write_word(got, - fixup_addr(read_word(*got))); /* Pointer to .dynamic */ -} - - -Elf32_Word -get_dynamic_val(Elf32_Shdr *dynamic, Elf32_Sword tag) -{ - Elf32_Dyn *element; - Elf32_Word entry_size; - - entry_size = read_word(dynamic->sh_entsize); - - element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset)); - while (read_sword(element->d_tag) != DT_NULL) { - if (read_sword(element->d_tag) == tag) { - return read_word(element->d_un.d_val); - } - element = (Elf32_Dyn *)((char *)element + entry_size); - } - return 0; -} - -void -remap_dynamic(Elf32_Shdr *dynamic, Elf32_Word new_dynstr_size) -{ - Elf32_Dyn *element; - Elf32_Word entry_size; - Elf32_Word rel_size; - Elf32_Word rel_entry_size; - Elf32_Rel *rel; - Elf32_Rela *rela; - int jmprel_overlaps; - Elf32_Word rel_start, rel_end, jmprel_start, jmprel_end; - - entry_size = read_word(dynamic->sh_entsize); - - /* Find out if REL/RELA and JMPREL overlaps: */ - if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) { - rel_start = get_dynamic_val(dynamic, DT_REL); - rel_end = rel_start + get_dynamic_val(dynamic, DT_RELSZ); - } else { - rel_start = get_dynamic_val(dynamic, DT_RELA); - rel_end = rel_start + get_dynamic_val(dynamic, DT_RELASZ); - } - jmprel_start = get_dynamic_val(dynamic, DT_JMPREL); - - jmprel_overlaps = 0; - if ((jmprel_start >= rel_start) && (jmprel_start < rel_end)) - jmprel_overlaps = 1; - - element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset)); - while (read_sword(element->d_tag) != DT_NULL) { - switch(read_sword(element->d_tag)) { - case DT_STRSZ: - write_word(&element->d_un.d_val, new_dynstr_size); - break; - case DT_PLTGOT: - case DT_HASH: - case DT_STRTAB: - case DT_INIT: - case DT_FINI: - case DT_VERDEF: - case DT_VERNEED: - case DT_VERSYM: - write_word(&element->d_un.d_ptr, - fixup_addr(read_word(element->d_un.d_ptr))); - break; - case DT_JMPREL: - rel_size = get_dynamic_val(dynamic, DT_PLTRELSZ); - if (!jmprel_overlaps) { - if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) { - rel_entry_size = get_dynamic_val(dynamic, DT_RELENT); - rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr))); - remap_rel_section(rel, rel_size, rel_entry_size); - } else { - rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT); - rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr))); - remap_rela_section(rela, rel_size, rel_entry_size); - } - } - write_word(&element->d_un.d_ptr, - fixup_addr(read_word(element->d_un.d_ptr))); - break; - case DT_REL: - rel_size = get_dynamic_val(dynamic, DT_RELSZ); - rel_entry_size = get_dynamic_val(dynamic, DT_RELENT); - rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr))); - remap_rel_section(rel, rel_size, rel_entry_size); - - write_word(&element->d_un.d_ptr, - fixup_addr(read_word(element->d_un.d_ptr))); - break; - case DT_RELA: - rel_size = get_dynamic_val(dynamic, DT_RELASZ); - rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT); - rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr))); - remap_rela_section(rela, rel_size, rel_entry_size); - - write_word(&element->d_un.d_ptr, - fixup_addr(read_word(element->d_un.d_ptr))); - break; - default: - /*printf("unhandled d_tag: %d (0x%x)\n", read_sword(element->d_tag), read_sword(element->d_tag));*/ - break; - } - - element = (Elf32_Dyn *)((char *)element + entry_size); - } -} - -void -align_hole(Elf32_Word *start, Elf32_Word *end) -{ - Elf32_Word len; - Elf32_Word align; - Elf32_Shdr *section; - Elf32_Word sectionsize; - int numsections; - int i = 0; - int unaligned; - - len = *end - *start; - align = 0; - - sectionsize = read_half(elf_header->e_shentsize); - numsections = read_half(elf_header->e_shnum); - do { - section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff)); - unaligned = 0; - - for (i=0;ish_addralign) > 1) && - ( (read_word(section->sh_offset) - len + align)%read_word(section->sh_addralign) != 0) ) { - unaligned = 1; - } - - section = (Elf32_Shdr *)((char *)section + sectionsize); - } - - if (unaligned) { - align++; - } - - } while (unaligned); - - *start += align; -} - -int -main(int argc, char *argv[]) -{ - int fd; - unsigned char *mapping; - Elf32_Word size; - struct stat statbuf; - Elf32_Shdr *dynamic; - Elf32_Shdr *dynsym; - Elf32_Shdr *symtab; - Elf32_Shdr *dynstr; - Elf32_Shdr *hash; - Elf32_Shdr *higher_section; - Elf32_Word dynstr_index; - Elf32_Shdr *ver_r; - Elf32_Shdr *ver_d; - char *dynstr_data; - unsigned char *new_dynstr; - Elf32_Word old_dynstr_size; - Elf32_Word new_dynstr_size; - - if (argc != 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); - return 1; - } - - fd = open(argv[1], O_RDWR); - if (fd == -1) { - fprintf(stderr, "Cannot open file %s\n", argv[1]); - return 1; - } - - if (fstat(fd, &statbuf) == -1) { - fprintf(stderr, "Cannot stat file %s\n", argv[1]); - return 1; - } - - size = statbuf.st_size; - - mapping = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - - if (mapping == (unsigned char *)-1) { - fprintf(stderr, "Cannot mmap file %s\n", argv[1]); - return 1; - } - - used_dynamic_symbols = g_hash_table_new(g_direct_hash, g_direct_equal); - - elf_header = (Elf32_Ehdr *)mapping; - - if (strncmp((void *)elf_header, ELFMAG, SELFMAG)!=0) { - fprintf(stderr, "Not an ELF file\n"); - return 1; - } - - if (elf_header->e_ident[EI_VERSION] != EV_CURRENT) { - fprintf(stderr, "Wrong ELF file version\n"); - return 1; - } - - if (elf_header->e_ident[EI_CLASS] != ELFCLASS32) { - fprintf(stderr, "Only 32bit ELF files supported\n"); - return 1; - } - - setup_byteswapping(elf_header->e_ident[EI_DATA]); - - machine_type = read_half(elf_header->e_machine); - if ( (machine_type != EM_386) && - (machine_type != EM_PPC) ) { - fprintf(stderr, "Unsupported architecture. Supported are: x86, ppc\n"); - return 1; - } - - if (read_half(elf_header->e_type) != ET_DYN) { - fprintf(stderr, "Not an ELF shared object\n"); - return 1; - } - - dynamic = elf_find_section(SHT_DYNAMIC); - dynsym = elf_find_section(SHT_DYNSYM); - symtab = elf_find_section(SHT_SYMTAB); - dynstr_index = read_word(dynsym->sh_link); - dynstr = elf_find_section_num(dynstr_index); - dynstr_data = (char *)FILE_OFFSET(read_word(dynstr->sh_offset)); - old_dynstr_size = read_word(dynstr->sh_size); - ver_d = elf_find_section(SHT_GNU_verdef); - ver_r = elf_find_section(SHT_GNU_verneed); - hash = elf_find_section(SHT_HASH); - - /* Generate hash table with all used strings: */ - - add_strings_from_dynsym(dynsym, dynstr_data); - add_strings_from_dynamic(dynamic, dynstr_data); - if (ver_d && (read_word(ver_d->sh_link) == dynstr_index)) - add_strings_from_ver_d(ver_d, dynstr_data); - if (ver_r && (read_word(ver_r->sh_link) == dynstr_index)) - add_strings_from_ver_r(ver_r, dynstr_data); - - /* Generate new dynstr section from the used strings hashtable: */ - - new_dynstr = generate_new_dynstr(&new_dynstr_size); - /* - printf("New dynstr size: %d\n", new_dynstr_size); - printf("Old dynstr size: %d\n", old_dynstr_size); - */ - - if (new_dynstr_size >= old_dynstr_size) { - fprintf(stderr, "Couldn't GC any strings, exiting.\n"); - return 0; - } - - /* Fixup all references: */ - fixup_strings_in_dynsym(dynsym); - fixup_strings_in_dynamic(dynamic); - if (ver_d && (read_word(ver_d->sh_link) == dynstr_index)) - fixup_strings_in_ver_d(ver_d); - if (ver_r && (read_word(ver_r->sh_link) == dynstr_index)) - fixup_strings_in_ver_r(ver_r); - - /* Copy over the new dynstr: */ - memcpy(dynstr_data, new_dynstr, new_dynstr_size); - memset(dynstr_data + new_dynstr_size, ' ', old_dynstr_size-new_dynstr_size); - - /* Compact the dynstr section and the file: */ - - /* 1. Set up the data for the fixup_offset() function: */ - hole_index = read_word(dynstr->sh_offset) + new_dynstr_size; - higher_section = elf_find_next_higher_section(hole_index); - hole_end = read_word(higher_section->sh_offset); - - align_hole(&hole_index, &hole_end); - hole_len = hole_end - hole_index; - - hole_addr_start = hole_index; /* TODO: Fix this to something better */ - - find_segment_addr_min_max(read_word(dynstr->sh_offset), - &hole_addr_remap_start, &hole_addr_remap_end); - - /* - printf("Hole remap: 0x%lx - 0x%lx\n", hole_addr_remap_start, hole_addr_remap_end); - - printf("hole: %lu - %lu (%lu bytes)\n", hole_index, hole_end, hole_len); - printf("hole: 0x%lx - 0x%lx (0x%lx bytes)\n", hole_index, hole_end, hole_len); - */ - - /* 2. Change all section and segment sizes and offsets: */ - remap_symtab(dynsym); - if (symtab) - remap_symtab(symtab); - - if (machine_type == EM_386) - remap_i386_got(); - if (machine_type == EM_PPC) - remap_ppc_got(); - - remap_dynamic(dynamic, new_dynstr_size); - remap_sections(); /* After this line the section headers are wrong */ - remap_segments(); - remap_elf_header(); - - /* 3. Do the real compacting. */ - - memmove(mapping + hole_index, - mapping + hole_index + hole_len, - size - (hole_index + hole_len)); - - munmap(mapping, size); - - ftruncate(fd, size - hole_len); - close(fd); - - return 0; -} - - - From 2f50458bc12a8e19e07cc5707f80c21230f67df3 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 30 Apr 2012 18:17:46 +0200 Subject: [PATCH 007/159] Bug 750290 - Remove tools/leaky. r=dbaron --- config/autoconf.mk.in | 1 - configure.in | 10 - js/src/config/autoconf.mk.in | 1 - js/src/configure.in | 1 - toolkit/toolkit-makefiles.sh | 6 - toolkit/toolkit-tiers.mk | 4 - tools/leaky/LibPreload.cpp | 54 --- tools/leaky/Makefile.in | 124 ------ tools/leaky/Makefile.linux | 100 ----- tools/leaky/ShowLibs.cpp | 73 ---- tools/leaky/TestLeaky.cpp | 131 ------ tools/leaky/TestPreload.cpp | 57 --- tools/leaky/TestPreload.h | 39 -- tools/leaky/bfd.cpp | 126 ------ tools/leaky/close-over.gif | Bin 88 -> 0 bytes tools/leaky/close.gif | Bin 88 -> 0 bytes tools/leaky/coff.cpp | 130 ------ tools/leaky/config.h | 60 --- tools/leaky/dict.cpp | 112 ----- tools/leaky/dict.h | 67 --- tools/leaky/elf.cpp | 165 -------- tools/leaky/leaky.cpp | 784 ----------------------------------- tools/leaky/leaky.css | 53 --- tools/leaky/leaky.h | 194 --------- tools/leaky/leaky.html | 224 ---------- tools/leaky/leaky.js | 39 -- tools/leaky/libmalloc.cpp | 608 --------------------------- tools/leaky/libmalloc.h | 106 ----- tools/leaky/open-over.gif | Bin 85 -> 0 bytes tools/leaky/open.gif | Bin 85 -> 0 bytes tools/leaky/strset.cpp | 72 ---- tools/leaky/strset.h | 52 --- 32 files changed, 3393 deletions(-) delete mode 100644 tools/leaky/LibPreload.cpp delete mode 100644 tools/leaky/Makefile.in delete mode 100644 tools/leaky/Makefile.linux delete mode 100644 tools/leaky/ShowLibs.cpp delete mode 100644 tools/leaky/TestLeaky.cpp delete mode 100644 tools/leaky/TestPreload.cpp delete mode 100644 tools/leaky/TestPreload.h delete mode 100644 tools/leaky/bfd.cpp delete mode 100644 tools/leaky/close-over.gif delete mode 100644 tools/leaky/close.gif delete mode 100644 tools/leaky/coff.cpp delete mode 100644 tools/leaky/config.h delete mode 100644 tools/leaky/dict.cpp delete mode 100644 tools/leaky/dict.h delete mode 100644 tools/leaky/elf.cpp delete mode 100644 tools/leaky/leaky.cpp delete mode 100644 tools/leaky/leaky.css delete mode 100644 tools/leaky/leaky.h delete mode 100644 tools/leaky/leaky.html delete mode 100644 tools/leaky/leaky.js delete mode 100644 tools/leaky/libmalloc.cpp delete mode 100644 tools/leaky/libmalloc.h delete mode 100644 tools/leaky/open-over.gif delete mode 100644 tools/leaky/open.gif delete mode 100644 tools/leaky/strset.cpp delete mode 100644 tools/leaky/strset.h diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index 5b43f8faea57..a979255820b0 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -111,7 +111,6 @@ MOZ_DEBUG_LDFLAGS=@MOZ_DEBUG_LDFLAGS@ MOZ_EXTENSIONS = @MOZ_EXTENSIONS@ MOZ_JSDEBUGGER = @MOZ_JSDEBUGGER@ MOZ_IPDL_TESTS = @MOZ_IPDL_TESTS@ -MOZ_LEAKY = @MOZ_LEAKY@ MOZ_MEMORY = @MOZ_MEMORY@ MOZ_PROFILING = @MOZ_PROFILING@ MOZ_ENABLE_PROFILER_SPS = @MOZ_ENABLE_PROFILER_SPS@ diff --git a/configure.in b/configure.in index d49d37c74e3e..bee2ab1a112b 100644 --- a/configure.in +++ b/configure.in @@ -6471,15 +6471,6 @@ MOZ_ARG_ENABLE_BOOL(update-packaging, MOZ_UPDATE_PACKAGING= ) AC_SUBST(MOZ_UPDATE_PACKAGING) -dnl ======================================================== -dnl leaky -dnl ======================================================== -MOZ_ARG_ENABLE_BOOL(leaky, -[ --enable-leaky Build leaky memory tool], - MOZ_LEAKY=1, - MOZ_LEAKY=) - - dnl ======================================================== dnl build the tests by default dnl ======================================================== @@ -8416,7 +8407,6 @@ AC_SUBST(WARNINGS_AS_ERRORS) AC_SUBST(MOZ_EXTENSIONS) AC_SUBST(MOZ_JSDEBUGGER) AC_SUBST(MOZ_LOG_REFCNT) -AC_SUBST(MOZ_LEAKY) AC_SUBST(MOZ_ENABLE_PROFILER_SPS) AC_SUBST(MOZ_JPROF) AC_SUBST(MOZ_SHARK) diff --git a/js/src/config/autoconf.mk.in b/js/src/config/autoconf.mk.in index 969977de79b2..528b09690c31 100644 --- a/js/src/config/autoconf.mk.in +++ b/js/src/config/autoconf.mk.in @@ -82,7 +82,6 @@ MOZ_DEBUG_FLAGS = @MOZ_DEBUG_FLAGS@ MOZ_DEBUG_LDFLAGS=@MOZ_DEBUG_LDFLAGS@ MOZ_EXTENSIONS = @MOZ_EXTENSIONS@ MOZ_JSDEBUGGER = @MOZ_JSDEBUGGER@ -MOZ_LEAKY = @MOZ_LEAKY@ MOZ_MEMORY = @MOZ_MEMORY@ MOZ_PROFILING = @MOZ_PROFILING@ MOZ_JPROF = @MOZ_JPROF@ diff --git a/js/src/configure.in b/js/src/configure.in index 11ec82d3c4b6..96fa2a67142d 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -4813,7 +4813,6 @@ AC_SUBST(MOZ_DEBUG_DISABLE_DEFS) AC_SUBST(MOZ_DEBUG_FLAGS) AC_SUBST(MOZ_DEBUG_LDFLAGS) AC_SUBST(WARNINGS_AS_ERRORS) -AC_SUBST(MOZ_LEAKY) AC_SUBST(MOZ_JPROF) AC_SUBST(MOZ_SHARK) AC_SUBST(MOZ_CALLGRIND) diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index f487ab57b6d0..1fc3125a9b2c 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -1531,12 +1531,6 @@ if [ "$MOZ_JPROF" ]; then " fi -if [ "$MOZ_LEAKY" ]; then - add_makefiles " - tools/leaky/Makefile - " -fi - if [ "$NS_TRACE_MALLOC" ]; then add_makefiles " tools/trace-malloc/Makefile diff --git a/toolkit/toolkit-tiers.mk b/toolkit/toolkit-tiers.mk index e58f675be601..9f89574d608c 100644 --- a/toolkit/toolkit-tiers.mk +++ b/toolkit/toolkit-tiers.mk @@ -265,10 +265,6 @@ tier_platform_dirs += toolkit/system/dbus endif endif -ifdef MOZ_LEAKY -tier_platform_dirs += tools/leaky -endif - ifdef MOZ_MAPINFO tier_platform_dirs += tools/codesighs endif diff --git a/tools/leaky/LibPreload.cpp b/tools/leaky/LibPreload.cpp deleted file mode 100644 index a976e331a0a0..000000000000 --- a/tools/leaky/LibPreload.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Kipp E.B. Hickman (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "TestPreload.h" -#include "config.h" -#include - -// This is a fake implementation of malloc that layers on top of the -// native platforms malloc routine (ideally using weak symbols). What -// it does if given a specail size request it returns a fake address -// result, otherwise it uses the underlying malloc. -void* malloc(size_t aSize) -{ - if (aSize == LD_PRELOAD_TEST_MALLOC_SIZE) { - return (void*) LD_PRELOAD_TEST_VALUE; - } - else { - return REAL_MALLOC(aSize); - } -} diff --git a/tools/leaky/Makefile.in b/tools/leaky/Makefile.in deleted file mode 100644 index b8b9198ff025..000000000000 --- a/tools/leaky/Makefile.in +++ /dev/null @@ -1,124 +0,0 @@ -#! gmake -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is mozilla.org Code. -# -# The Initial Developer of the Original Code is -# Kipp E.B. Hickman. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either of the GNU General Public License Version 2 or later (the "GPL"), -# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** - -DEPTH = ../.. -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -SIMPLE_PROGRAMS = TestLeaky TestPreload ShowLibs - -PROGRAM = leaky - -CPPSRCS = \ - bfd.cpp \ - coff.cpp \ - dict.cpp \ - elf.cpp \ - leaky.cpp \ - strset.cpp \ - $(NULL) - - -LIBS = \ - -lbfd \ - -liberty \ - $(NULL) - -RESOURCES = \ - leaky.css \ - leaky.js \ - open.gif \ - open-over.gif \ - close.gif \ - close-over.gif \ - $(NULL) - -RESOURCES := $(addprefix $(srcdir)/, $(RESOURCES)) - -# Stuff to build the library used to wrap malloc -LIBMALLOC_CPPSRCS = libmalloc.cpp -LIBMALLOC_OBJECTS = $(LIBMALLOC_CPPSRCS:.cpp=.o) -LIBMALLOC = libleaky.so - -# Stuff to build test programs -LIBPRELOAD_CPPSRCS = LibPreload.cpp -LIBPRELOAD_OBJECTS = $(LIBPRELOAD_CPPSRCS:.cpp=.o) -LIBPRELOAD = libpreload.so - -# include $(topsrcdir)/config/config.mk - -OTHER_LIBRARIES = $(LIBMALLOC) $(LIBPRELOAD) -TARGETS := $(PROGRAM) $(SIMPLE_PROGRAMS) $(OTHER_LIBRARIES) - -include $(topsrcdir)/config/rules.mk - -# Make sure all depends on files that rules.mk doesn't know about. -all:: $(OTHER_LIBRARIES) - -# Make sure install depends on files that rules.mk doesn't know about. -libs:: $(OTHER_LIBRARIES) - -# Make sure libs depends on files that rules.mk doesn't know about. -libs:: $(OTHER_LIBRARIES) - -clobber:: - rm -f $(LIBMALLOC_OBJECTS) $(LIBPRELOAD_OBJECTS) - rm -f $(LIBMALLOC) $(LIBPRELOAD) - rm -f $(SIMPLE_PROGRAMS:=.o) - -clean:: - rm -f $(LIBMALLOC_OBJECTS) $(LIBPRELOAD_OBJECTS) - -$(LIBMALLOC): $(LIBMALLOC_OBJECTS) - rm -f $@ - $(MKSHLIB) $(LIBMALLOC_OBJECTS) - -$(LIBPRELOAD): $(LIBPRELOAD_OBJECTS) - $(MKSHLIB) $(LIBPRELOAD_OBJECTS) - -test: - @echo LIBMALLOC = $(LIBMALLOC) - @echo LIBPRELOAD = $(LIBPRELOAD) - @echo TARGETS = $(TARGETS) - -libs:: $(OTHER_LIBRARIES) $(RESOURCES) - $(INSTALL) -m 555 $(OTHER_LIBRARIES) $(DIST)/lib - $(INSTALL) $(RESOURCES) $(DIST)/bin/res/leaky diff --git a/tools/leaky/Makefile.linux b/tools/leaky/Makefile.linux deleted file mode 100644 index 63505d6a2523..000000000000 --- a/tools/leaky/Makefile.linux +++ /dev/null @@ -1,100 +0,0 @@ -#! gmake -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Kipp E.B. Hickman. -# Portions created by the Initial Developer are Copyright (C) 1999 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** - -CXX = c++ -OPTIMIZER = -g -CXXFLAGS = $(OPTIMIZER) -Wall -Wp,-MD,.deps-$< -CXXF = $(CXX) $(CXXFLAGS) - -MKSHLIB = $(CXX) -shared - -# Stuff to build the leaky executable -LEAKY_CPPSRCS = \ - bfd.cpp \ - coff.cpp \ - dict.cpp \ - elf.cpp \ - leaky.cpp \ - strset.cpp \ - $(NULL) -LEAKY_OBJECTS = $(LEAKY_CPPSRCS:.cpp=.o) -LEAKY_LIBS = -lbfd -liberty - -# Stuff to build the library used to wrap malloc -LIBMALLOC_CPPSRCS = libmalloc.cpp -LIBMALLOC_OBJECTS = $(LIBMALLOC_CPPSRCS:.cpp=.o) -LIBMALLOC = libleaky.so - -# Stuff to build test programs -LIBPRELOAD = libpreload.so - -TARGETS = leaky $(LIBMALLOC) TestLeaky TestPreload $(LIBPRELOAD) ShowLibs - -.SUFFIXES: .cpp - -default all: $(TARGETS) - -clean: - rm -f core malloc-log malloc-map *.o .deps* - -clobber: clean - rm -f $(TARGETS) - -.cpp.o: - $(CXXF) -c $< - -leaky: $(LEAKY_OBJECTS) - $(CXXF) -o $@ $(LEAKY_OBJECTS) $(LEAKY_LIBS) - -$(LIBMALLOC): $(LIBMALLOC_OBJECTS) - rm -f $@ - $(MKSHLIB) -o $@ $(LIBMALLOC_OBJECTS) - -TestLeaky: TestLeaky.cpp - $(CXXF) -o $@ TestLeaky.cpp - -TestPreload: TestPreload.cpp - $(CXXF) -o $@ TestPreload.cpp - -$(LIBPRELOAD): LibPreload.o - $(MKSHLIB) -o $@ LibPreload.o - -ShowLibs: ShowLibs.cpp - $(CXXF) -o $@ ShowLibs.cpp - --include .deps-* diff --git a/tools/leaky/ShowLibs.cpp b/tools/leaky/ShowLibs.cpp deleted file mode 100644 index 88fe49a60ca9..000000000000 --- a/tools/leaky/ShowLibs.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include -#include - -#ifdef linux -#include -#endif - -// A simple test program that dumps out the loaded shared -// libraries. This is essential for leaky to work properly when shared -// libraries are used. -static void ShowLibs(struct r_debug* rd) -{ - link_map* map = rd->r_map; - while (NULL != map) { - printf("addr=%08x name=%s prev=%p next=%p\n", map->l_addr, map->l_name, - map->l_prev, map->l_next); - map = map->l_next; - } -} - -int main(int argc, char** argv) -{ - void* h = dlopen("/usr/X11R6/lib/libX11.so", RTLD_LAZY); -#ifdef linux - printf("Direct r_debug libs:\n"); - ShowLibs(&_r_debug); - - printf("_DYNAMICE r_debug libs:\n"); - ElfW(Dyn)* dp; - for (dp = _DYNAMIC; dp->d_tag != DT_NULL; dp++) { - if (dp->d_tag == DT_DEBUG) { - struct r_debug* rd = (struct r_debug*) dp->d_un.d_ptr; - ShowLibs(rd); - } - } -#endif - return 0; -} diff --git a/tools/leaky/TestLeaky.cpp b/tools/leaky/TestLeaky.cpp deleted file mode 100644 index 37200043c48d..000000000000 --- a/tools/leaky/TestLeaky.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include -#include - -void s1(int, int) -{ - malloc(100); -} - -void s2() -{ - s1(1, 2); - malloc(100); -} - -void s3() -{ - s2(); - malloc(100); - malloc(200); -} - -void s4() -{ - s3(); - char* cp = new char[300]; - cp = cp; -} - -// Test that mutually recrusive methods don't foul up the graph output -void s6(int recurse); - -void s5(int recurse) -{ - malloc(100); - if (recurse > 0) { - s6(recurse - 1); - } -} - -void s6(int recurse) -{ - malloc(100); - if (recurse > 0) { - s5(recurse - 1); - } -} - -// Test that two pathways through the same node don't cause replicated -// descdendants (A -> B -> C, X -> B -> D shouldn't produce a graph -// that shows A -> B -> D!) - -void C() -{ - malloc(10); -} - -void D() -{ - malloc(10); -} - -void B(int way) -{ - malloc(10); - if (way) { - C(); - C(); - C(); - } else { - D(); - } -} - -void A() -{ - malloc(10); - B(1); -} - -void X() -{ - malloc(10); - B(0); -} - -int main() -{ - s1(1, 2); - s2(); - s3(); - s4(); - s5(10); - A(); - X(); -} diff --git a/tools/leaky/TestPreload.cpp b/tools/leaky/TestPreload.cpp deleted file mode 100644 index 9ce7a0f94d01..000000000000 --- a/tools/leaky/TestPreload.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "TestPreload.h" -#include -#include - -// This is a simple test program that verifies that you can use -// LD_PRELOAD to override the implementation of malloc for your -// system. It depends on PreloadLib.cpp providing an alternate -// implementation of malloc that has a special hack to return a -// constant address given a particular size request. - -int main(int argc, char** argv) -{ - char* p = (char*) malloc(LD_PRELOAD_TEST_MALLOC_SIZE); - if (p == (char*)LD_PRELOAD_TEST_VALUE) { - printf("LD_PRELOAD worked - we are using our malloc\n"); - } - else { - printf("LD_PRELOAD failed\n"); - } - return 0; -} diff --git a/tools/leaky/TestPreload.h b/tools/leaky/TestPreload.h deleted file mode 100644 index 05ba7ac7697a..000000000000 --- a/tools/leaky/TestPreload.h +++ /dev/null @@ -1,39 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#define LD_PRELOAD_TEST_MALLOC_SIZE 0x12345 - -#define LD_PRELOAD_TEST_VALUE 0x12345 diff --git a/tools/leaky/bfd.cpp b/tools/leaky/bfd.cpp deleted file mode 100644 index 38fd7ad20824..000000000000 --- a/tools/leaky/bfd.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "leaky.h" - -#ifdef USE_BFD -#include -#include -#include - -extern "C" { - char *cplus_demangle (const char *mangled, int options); -} - -void leaky::ReadSymbols(const char *aFileName, u_long aBaseAddress) -{ - static bfd_boolean kDynamic = (bfd_boolean) false; - - static int firstTime = 1; - if (firstTime) { - firstTime = 0; - bfd_init (); - } - - bfd* lib = bfd_openr(aFileName, NULL); - if (NULL == lib) { - return; - } - char **matching; - if (!bfd_check_format_matches(lib, bfd_object, &matching)) { - bfd_close(lib); - return; - } - - asymbol* store; - store = bfd_make_empty_symbol(lib); - - // read mini symbols - PTR minisyms; - unsigned int size; - long symcount = bfd_read_minisymbols(lib, kDynamic, &minisyms, &size); - - int initialSymbols = usefulSymbols; - if (NULL == externalSymbols) { - externalSymbols = (Symbol*) malloc(sizeof(Symbol) * 10000); - numExternalSymbols = 10000; - } - Symbol* sp = externalSymbols + usefulSymbols; - Symbol* lastSymbol = externalSymbols + numExternalSymbols; - - // Scan symbols - bfd_byte* from = (bfd_byte *) minisyms; - bfd_byte* fromend = from + symcount * size; - for (; from < fromend; from += size) { - asymbol *sym; - sym = bfd_minisymbol_to_symbol(lib, kDynamic, (const PTR) from, store); - - symbol_info syminfo; - bfd_get_symbol_info (lib, sym, &syminfo); - -// if ((syminfo.type == 'T') || (syminfo.type == 't')) { - const char* nm = bfd_asymbol_name(sym); - if (nm && nm[0]) { - char* dnm = NULL; - if (strncmp("__thunk", nm, 7)) { - dnm = cplus_demangle(nm, 1); - } - sp->Init(dnm ? dnm : nm, syminfo.value + aBaseAddress); - sp++; - if (sp >= lastSymbol) { - long n = numExternalSymbols + 10000; - externalSymbols = (Symbol*) - realloc(externalSymbols, (size_t) (sizeof(Symbol) * n)); - lastSymbol = externalSymbols + n; - sp = externalSymbols + numExternalSymbols; - numExternalSymbols = n; - } - } -// } - } - - - bfd_close(lib); - - int interesting = sp - externalSymbols; - if (!quiet) { - printf("%s provided %d symbols\n", aFileName, - interesting - initialSymbols); - } - usefulSymbols = interesting; -} - -#endif /* USE_BFD */ diff --git a/tools/leaky/close-over.gif b/tools/leaky/close-over.gif deleted file mode 100644 index 50497965b4041933750ac0d113da8e79b01c9901..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88 zcmZ?wbhEHbL;7|i(b|38QY2Z}#g7(pBz5CKxlz%0ulb&IcYuUN~R b#2cLL`=)%iz3DzdEp2YZfu#J&3=Gx)T%{JR diff --git a/tools/leaky/close.gif b/tools/leaky/close.gif deleted file mode 100644 index 37efcd41d20347f4fa9a6806c19dafe9cc89b3f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88 zcmZ?wbhEHbL;7|i&wV#Nv&69yE2vM_?!Iv@h1mVsH8L+Tb^<6g0r cIf*woTlY=*W_#6rf?C?#hyzLalNlJS0a>yZpa1{> diff --git a/tools/leaky/coff.cpp b/tools/leaky/coff.cpp deleted file mode 100644 index a20ab3e83e54..000000000000 --- a/tools/leaky/coff.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "leaky.h" - -#ifdef USE_COFF - -#define LANGUAGE_C -#include -#include -#include -#include -#include -#include -#include - -#ifdef IRIX4 -extern "C" { - extern char *demangle(char const* in); -}; -#else -#include -#endif - -static char *Demangle(char *rawName) -{ -#ifdef IRIX4 - return strdup(demangle(rawName)); -#else - char namebuf[4000]; - demangle(rawName, namebuf); - return strdup(namebuf); -#endif -} - -void leaky::readSymbols(const char *fileName) -{ - LDFILE *ldptr; - - ldptr = ldopen(fileName, NULL); - if (!ldptr) { - fprintf(stderr, "%s: unable to open \"%s\"\n", applicationName, - fileName); - exit(-1); - } - if (PSYMTAB(ldptr) == 0) { - fprintf(stderr, "%s: \"%s\": has no symbol table\n", applicationName, - fileName); - exit(-1); - } - - long isymMax = SYMHEADER(ldptr).isymMax; - long iextMax = SYMHEADER(ldptr).iextMax; - long iMax = isymMax + iextMax; - - long alloced = 10000; - Symbol* syms = (Symbol*) malloc(sizeof(Symbol) * 10000); - Symbol* sp = syms; - Symbol* last = syms + alloced; - SYMR symr; - - for (long isym = 0; isym < iMax; isym++) { - if (ldtbread(ldptr, isym, &symr) != SUCCESS) { - fprintf(stderr, "%s: can't read symbol #%d\n", applicationName, - isym); - exit(-1); - } - if (isym < isymMax) { - if ((symr.st == stStaticProc) - || ((symr.st == stProc) && - ((symr.sc == scText) || (symr.sc == scAbs))) - || ((symr.st == stBlock) && - (symr.sc == scText))) { - // Text symbol. Set name field to point to the symbol name - sp->name = Demangle(ldgetname(ldptr, &symr)); - sp->address = symr.value; - sp++; - if (sp >= last) { - long n = alloced + 10000; - syms = (Symbol*) - realloc(syms, (size_t) (sizeof(Symbol) * n)); - last = syms + n; - sp = syms + alloced; - alloced = n; - } - } - } - } - - int interesting = sp - syms; - if (!quiet) { - printf("Total of %d symbols\n", interesting); - } - usefulSymbols = interesting; - externalSymbols = syms; -} - -#endif /* USE_COFF */ diff --git a/tools/leaky/config.h b/tools/leaky/config.h deleted file mode 100644 index 48c2d0c2665b..000000000000 --- a/tools/leaky/config.h +++ /dev/null @@ -1,60 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef config_h___ -#define config_h___ - -#define MAX_STACK_CRAWL 200 - -#include - -#if defined(linux) || defined(NTO) -#define USE_BFD -#undef NEED_WRAPPERS - -#define REAL_MALLOC(_x) __libc_malloc(_x) -#define REAL_REALLOC(_x,_y) __libc_realloc(_x,_y) -#define REAL_FREE(_x) __libc_free(_x) - -extern "C" { - void* __libc_malloc(size_t); - void* __libc_realloc(void*, size_t); - void __libc_free(void*); -} - -#endif /* linux */ - -#endif /* config_h___ */ diff --git a/tools/leaky/dict.cpp b/tools/leaky/dict.cpp deleted file mode 100644 index d3474bc7e0ca..000000000000 --- a/tools/leaky/dict.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Kipp E.B. Hickman (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include -#include "dict.h" - -#ifdef __QNXNTO__ -/* Need definition of NULL */ -#include -#endif - -MallocDict::MallocDict(int nb) -{ - numBuckets = nb; - buckets = (MallocDictEntry**) calloc(numBuckets, sizeof(MallocDictEntry*)); - rewind(); -} - -void MallocDict::rewind(void) -{ - iterNextBucket = -1; - iterNextEntry = 0; -} - -malloc_log_entry* MallocDict::next(void) -{ - if (iterNextEntry) { - iterNextEntry = iterNextEntry->next; - } - while (!iterNextEntry) { - iterNextBucket++; - if (iterNextBucket >= numBuckets) { - return 0; - } - iterNextEntry = buckets[iterNextBucket]; - } - return iterNextEntry->logEntry; -} - -malloc_log_entry** MallocDict::find(u_long addr) -{ - u_long hash = addr % numBuckets; - MallocDictEntry* mde = buckets[hash]; - while (mde) { - if (mde->addr == addr) { - return &mde->logEntry; - } - mde = mde->next; - } - return 0; -} - -void MallocDict::add(u_long addr, malloc_log_entry *lep) -{ - u_long hash = addr % numBuckets; - MallocDictEntry** mdep = &buckets[hash]; - MallocDictEntry* mde = new MallocDictEntry; - mde->addr = addr; - mde->logEntry = lep; - mde->next = *mdep; - *mdep = mde; -} - -void MallocDict::remove(u_long addr) -{ - u_long hash = addr % numBuckets; - MallocDictEntry** mdep = &buckets[hash]; - MallocDictEntry* mde; - - while (NULL != (mde = *mdep)) { - if (mde->addr == addr) { - *mdep = mde->next; -/*XXX delete mde; */ - return; - } - mdep = &mde->next; - } -} diff --git a/tools/leaky/dict.h b/tools/leaky/dict.h deleted file mode 100644 index e1f32cf22eb3..000000000000 --- a/tools/leaky/dict.h +++ /dev/null @@ -1,67 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef __dict_h_ -#define __dict_h_ - -#include -#include "libmalloc.h" - -// key is u_long -// value is malloc_log_entry* -struct MallocDict { - MallocDict(int buckets); - - void rewind(void); - malloc_log_entry* next(void); - - malloc_log_entry** find(u_long addr); - void add(u_long addr, malloc_log_entry *log); - void remove(u_long addr); - - struct MallocDictEntry { - u_long addr; - malloc_log_entry* logEntry; - MallocDictEntry* next; - } **buckets; - - int numBuckets; - - int iterNextBucket; - MallocDictEntry* iterNextEntry; -}; - -#endif /* __dict_h_ */ diff --git a/tools/leaky/elf.cpp b/tools/leaky/elf.cpp deleted file mode 100644 index 98fc0bf0e2fa..000000000000 --- a/tools/leaky/elf.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "leaky.h" - -#ifdef USE_ELF - -#include "leaky.h" -#include -#include -#include -#include -#include -#include - -void leaky::readSymbols(const char *fileName) -{ - int fd = ::open(fileName, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "%s: unable to open \"%s\"\n", applicationName, - fileName); - exit(-1); - } - - elf_version(EV_CURRENT); - Elf *elf = elf_begin(fd, ELF_C_READ, 0); - if (!elf) { - fprintf(stderr, "%s: \"%s\": has no symbol table\n", applicationName, - fileName); - exit(-1); - } - - long alloced = 10000; - Symbol* syms = (Symbol*) malloc(sizeof(Symbol) * 10000); - Symbol* sp = syms; - Symbol* last = syms + alloced; - - // Get each of the relevant sections and add them to the list of - // symbols. - Elf32_Ehdr *ehdr = elf32_getehdr(elf); - if (!ehdr) { - fprintf(stderr, "%s: elf library lossage\n", applicationName); - exit(-1); - } -#if 0 - Elf32_Half ndx = ehdr->e_shstrndx; -#endif - - Elf_Scn *scn = 0; - int strtabndx = -1; - for (int i = 1; (scn = elf_nextscn(elf, scn)) != 0; i++) { - Elf32_Shdr *shdr = elf32_getshdr(scn); -#if 0 - char *name = elf_strptr(elf, ndx, (size_t) shdr->sh_name); - printf("Section %s (%d 0x%x)\n", name ? name : "(null)", - shdr->sh_type, shdr->sh_type); -#endif - if (shdr->sh_type == SHT_STRTAB) { - /* We assume here that string tables preceed symbol tables... */ - strtabndx = i; - continue; - } -#if 0 - if (shdr->sh_type == SHT_DYNAMIC) { - /* Dynamic */ - Elf_Data *data = elf_getdata(scn, 0); - if (!data || !data->d_size) { - printf("No data..."); - continue; - } - - Elf32_Dyn *dyn = (Elf32_Dyn*) data->d_buf; - Elf32_Dyn *lastdyn = - (Elf32_Dyn*) ((char*) data->d_buf + data->d_size); - for (; dyn < lastdyn; dyn++) { - printf("tag=%d value=0x%x\n", dyn->d_tag, dyn->d_un.d_val); - } - } else -#endif - if ((shdr->sh_type == SHT_SYMTAB) || - (shdr->sh_type == SHT_DYNSYM)) { - /* Symbol table */ - Elf_Data *data = elf_getdata(scn, 0); - if (!data || !data->d_size) { - printf("No data..."); - continue; - } - - /* In theory we now have the symbols... */ - Elf32_Sym *esym = (Elf32_Sym*) data->d_buf; - Elf32_Sym *lastsym = - (Elf32_Sym*) ((char*) data->d_buf + data->d_size); - for (; esym < lastsym; esym++) { -#if 0 - char *nm = elf_strptr(elf, strtabndx, (size_t)esym->st_name); - printf("%20s 0x%08x %02x %02x\n", - nm, esym->st_value, ELF32_ST_BIND(esym->st_info), - ELF32_ST_TYPE(esym->st_info)); -#endif - if ((esym->st_value == 0) || - (ELF32_ST_BIND(esym->st_info) == STB_WEAK) || - (ELF32_ST_BIND(esym->st_info) == STB_NUM) || - (ELF32_ST_TYPE(esym->st_info) != STT_FUNC)) { - continue; - } -#if 1 - char *nm = elf_strptr(elf, strtabndx, (size_t)esym->st_name); -#endif - sp->name = nm ? strdup(nm) : "(no name)"; - sp->address = esym->st_value; - sp++; - if (sp >= last) { - long n = alloced + 10000; - syms = (Symbol*) - realloc(syms, (size_t) (sizeof(Symbol) * n)); - last = syms + n; - sp = syms + alloced; - alloced = n; - } - } - } - } - - int interesting = sp - syms; - if (!quiet) { - printf("Total of %d symbols\n", interesting); - } - usefulSymbols = interesting; - externalSymbols = syms; -} - -#endif /* USE_ELF */ diff --git a/tools/leaky/leaky.cpp b/tools/leaky/leaky.cpp deleted file mode 100644 index 6eabbdc25edc..000000000000 --- a/tools/leaky/leaky.cpp +++ /dev/null @@ -1,784 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "leaky.h" -#include "dict.h" - -#include -#include -#include -#include -#include -#include -#ifndef NTO -#include -#endif -#include -#include -#include - -#ifdef NTO -#include -#endif - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif - -static const u_int DefaultBuckets = 10007; // arbitrary, but prime -static const u_int MaxBuckets = 1000003; // arbitrary, but prime - -//---------------------------------------------------------------------- - -int main(int argc, char** argv) -{ - leaky* l = new leaky; - - l->initialize(argc, argv); - l->open(); - return 0; -} - -leaky::leaky() -{ - applicationName = NULL; - logFile = NULL; - progFile = NULL; - - dumpLeaks = FALSE; - dumpGraph = FALSE; - dumpHTML = FALSE; - quiet = FALSE; - dumpEntireLog = FALSE; - showAddress = FALSE; - stackDepth = 100000; - dumpRefcnts = false; - - mappedLogFile = -1; - firstLogEntry = lastLogEntry = 0; - buckets = DefaultBuckets; - dict = NULL; - refcntDict = NULL; - - mallocs = 0; - reallocs = 0; - frees = 0; - totalMalloced = 0; - errors = 0; - totalLeaked = 0; - - sfd = -1; - externalSymbols = 0; - usefulSymbols = 0; - numExternalSymbols = 0; - lowestSymbolAddr = 0; - highestSymbolAddr = 0; - - loadMap = NULL; -} - -leaky::~leaky() -{ - delete dict; -} - -void leaky::usageError() -{ - fprintf(stderr, - "Usage: %s [-aAEdfgqxR] [-e name] [-s depth] [-h hash-buckets] [-r root|-i symbol] prog log\n", - (char*) applicationName); - exit(-1); -} - -void leaky::initialize(int argc, char** argv) -{ - applicationName = argv[0]; - applicationName = strrchr(applicationName, '/'); - if (!applicationName) { - applicationName = argv[0]; - } else { - applicationName++; - } - - int arg; - int errflg = 0; - while ((arg = getopt(argc, argv, "adEe:gh:i:r:Rs:tqx")) != -1) { - switch (arg) { - case '?': - errflg++; - break; - case 'a': - dumpEntireLog = TRUE; - break; - case 'A': - showAddress = TRUE; - break; - case 'd': - dumpLeaks = TRUE; - if (dumpGraph) errflg++; - break; - case 'R': - dumpRefcnts = true; - break; - case 'e': - exclusions.add(optarg); - break; - case 'g': - dumpGraph = TRUE; - if (dumpLeaks) errflg++; - break; - case 'r': - roots.add(optarg); - if (!includes.IsEmpty()) { - errflg++; - } - break; - case 'i': - includes.add(optarg); - if (!roots.IsEmpty()) { - errflg++; - } - break; - case 'h': - buckets = atoi(optarg); - if ((buckets < 0) || (buckets > MaxBuckets)) { - buckets = MaxBuckets; - fprintf(stderr, "%s: buckets is invalid, using %d\n", - (char*) applicationName, - buckets); - } - break; - case 's': - stackDepth = atoi(optarg); - if (stackDepth < 2) { - stackDepth = 2; - } - break; - case 'x': - dumpHTML = TRUE; - break; - case 'q': - quiet = TRUE; - break; - } - } - if (errflg || ((argc - optind) < 2)) { - usageError(); - } - progFile = argv[optind++]; - logFile = argv[optind]; - - dict = new MallocDict(buckets); - if (dumpRefcnts) { - refcntDict = new MallocDict(buckets); - } -} - -static void* mapFile(int fd, u_int flags, off_t* sz) -{ - struct stat sb; - if (fstat(fd, &sb) < 0) { - perror("fstat"); - exit(-1); - } - void* base = mmap(0, (int)sb.st_size, flags, MAP_PRIVATE, fd, 0); - if (!base) { - perror("mmap"); - exit(-1); - } - *sz = sb.st_size; - return base; -} - -void leaky::LoadMap() -{ - malloc_map_entry mme; - char name[1000]; - - int fd = ::open("malloc-map", O_RDONLY); - if (fd < 0) { - perror("open: malloc-map"); - exit(-1); - } - for (;;) { - int nb = read(fd, &mme, sizeof(mme)); - if (nb != sizeof(mme)) break; - nb = read(fd, name, mme.nameLen); - if (nb != (int)mme.nameLen) break; - name[mme.nameLen] = 0; - if (!quiet) { - printf("%s @ %lx\n", name, mme.address); - } - - LoadMapEntry* lme = new LoadMapEntry; - lme->address = mme.address; - lme->name = strdup(name); - lme->next = loadMap; - loadMap = lme; - } - close(fd); -} - -void leaky::open() -{ - LoadMap(); - - setupSymbols(progFile); - - // open up the log file - mappedLogFile = ::open(logFile, O_RDONLY); - if (mappedLogFile < 0) { - perror("open"); - exit(-1); - } - off_t size; - firstLogEntry = (malloc_log_entry*) mapFile(mappedLogFile, PROT_READ, &size); - lastLogEntry = (malloc_log_entry*)((char*)firstLogEntry + size); - - analyze(); - - if (dumpLeaks || dumpEntireLog || dumpRefcnts) { - dumpLog(); - } - else if (dumpGraph) { - buildLeakGraph(); - dumpLeakGraph(); - } - exit(0); -} - -//---------------------------------------------------------------------- - - -static ptrdiff_t symbolOrder(void const* a, void const* b) -{ - Symbol const* ap = (Symbol const *)a; - Symbol const* bp = (Symbol const *)b; - return ap->address - bp->address; -} - -void leaky::ReadSharedLibrarySymbols() -{ - LoadMapEntry* lme = loadMap; - while (NULL != lme) { - ReadSymbols(lme->name, lme->address); - lme = lme->next; - } -} - -void leaky::setupSymbols(const char *fileName) -{ - // Read in symbols from the program - ReadSymbols(fileName, 0); - - // Read in symbols from the .so's - ReadSharedLibrarySymbols(); - - if (!quiet) { - printf("A total of %d symbols were loaded\n", usefulSymbols); - } - - // Now sort them - qsort(externalSymbols, usefulSymbols, sizeof(Symbol), symbolOrder); - lowestSymbolAddr = externalSymbols[0].address; - highestSymbolAddr = externalSymbols[usefulSymbols-1].address; -} - -// Binary search the table, looking for a symbol that covers this -// address. -Symbol* leaky::findSymbol(u_long addr) -{ - u_int base = 0; - u_int limit = usefulSymbols - 1; - Symbol* end = &externalSymbols[limit]; - while (base <= limit) { - u_int midPoint = (base + limit)>>1; - Symbol* sp = &externalSymbols[midPoint]; - if (addr < sp->address) { - if (midPoint == 0) { - return NULL; - } - limit = midPoint - 1; - } else { - if (sp+1 < end) { - if (addr < (sp+1)->address) { - return sp; - } - } else { - return sp; - } - base = midPoint + 1; - } - } - return NULL; -} - -//---------------------------------------------------------------------- - -bool leaky::excluded(malloc_log_entry* lep) -{ - if (exclusions.IsEmpty()) { - return false; - } - - char** pcp = &lep->pcs[0]; - u_int n = lep->numpcs; - for (u_int i = 0; i < n; i++, pcp++) { - Symbol* sp = findSymbol((u_long) *pcp); - if (sp && exclusions.contains(sp->name)) { - return true; - } - } - return false; -} - -bool leaky::included(malloc_log_entry* lep) -{ - if (includes.IsEmpty()) { - return true; - } - - char** pcp = &lep->pcs[0]; - u_int n = lep->numpcs; - for (u_int i = 0; i < n; i++, pcp++) { - Symbol* sp = findSymbol((u_long) *pcp); - if (sp && includes.contains(sp->name)) { - return true; - } - } - return false; -} - -//---------------------------------------------------------------------- - -void leaky::displayStackTrace(FILE* out, malloc_log_entry* lep) -{ - char** pcp = &lep->pcs[0]; - u_int n = (lep->numpcs < stackDepth) ? lep->numpcs : stackDepth; - for (u_int i = 0; i < n; i++, pcp++) { - u_long addr = (u_long) *pcp; - Symbol* sp = findSymbol(addr); - if (sp) { - fputs(sp->name, out); - if (showAddress) { - fprintf(out, "[%p]", (char*)addr); - } - } - else { - fprintf(out, "<%p>", (char*)addr); - } - fputc(' ', out); - } - fputc('\n', out); -} - -char* typeFromLog[] = { - "malloc", - "realloc", - "free", - "new", - "delete", - "addref", - "release" -}; - -void leaky::dumpEntryToLog(malloc_log_entry* lep) -{ - printf("%-10s %08lx %5ld ", - typeFromLog[lep->type], - lep->address, lep->size); - if (IsRefcnt(lep)) { - printf("%08ld", lep->oldaddress); - } - else { - printf("%08lx", lep->oldaddress); - } - printf(" --> "); - displayStackTrace(stdout, lep); -} - -bool leaky::ShowThisEntry(malloc_log_entry* lep) -{ - if ((!dumpRefcnts || IsRefcnt(lep)) && !excluded(lep) && included(lep)) { - return true; - } - return false; -} - -void leaky::dumpLog() -{ - if (dumpRefcnts) { - malloc_log_entry* lep; - refcntDict->rewind(); - while (NULL != (lep = refcntDict->next())) { - if (ShowThisEntry(lep)) { - // Now we get slow... - u_long addr = lep->address; - malloc_log_entry* lep2 = firstLogEntry; - while (lep2 < lastLogEntry) { - if (lep2->address == addr) { - dumpEntryToLog(lep2); - } - lep2 = (malloc_log_entry*) &lep2->pcs[lep2->numpcs]; - } - } - } - } - else { - if (dumpEntireLog) { - malloc_log_entry* lep = firstLogEntry; - while (lep < lastLogEntry) { - if (ShowThisEntry(lep)) { - dumpEntryToLog(lep); - } - lep = (malloc_log_entry*) &lep->pcs[lep->numpcs]; - } - } else { - malloc_log_entry* lep; - dict->rewind(); - while (NULL != (lep = dict->next())) { - if (ShowThisEntry(lep)) { - dumpEntryToLog(lep); - } - } - } - } -} - -//---------------------------------------------------------------------- - -void leaky::insertAddress(u_long address, malloc_log_entry* lep) -{ - malloc_log_entry** lepp = dict->find(address); - if (lepp) { - assert(*lepp); - if (!quiet) { - printf("Address %lx allocated twice\n", address); - displayStackTrace(stdout, lep); - } - errors++; - } else { - dict->add(address, lep); - } -} - -void leaky::removeAddress(u_long address, malloc_log_entry* lep) -{ - malloc_log_entry** lepp = dict->find(address); - if (!lepp) { - if (!quiet) { - printf("Free of unallocated %lx\n", address); - displayStackTrace(stdout, lep); - } - errors++; - } else { - dict->remove(address); - } -} - -void leaky::analyze() -{ - malloc_log_entry* lep = firstLogEntry; - while (lep < lastLogEntry) { - switch (lep->type) { - case malloc_log_malloc: - case malloc_log_new: - mallocs++; - if (lep->address) { - totalMalloced += lep->size; - insertAddress((u_long) lep->address, lep); - } - break; - - case malloc_log_realloc: - if (lep->oldaddress) { - removeAddress((u_long) lep->oldaddress, lep); - } - if (lep->address) { - insertAddress((u_long) lep->address, lep); - } - reallocs++; - break; - - case malloc_log_free: - case malloc_log_delete: - if (lep->address) { - removeAddress((u_long) lep->address, lep); - } - frees++; - break; - case malloc_log_addref: - if (dumpRefcnts) { - if (lep->size == 0) { - // Initial addref - u_long addr = (u_long) lep->address; - malloc_log_entry** lepp = refcntDict->find(addr); - if (!lepp) { - refcntDict->add(addr, lep); - } - } - } - break; - case malloc_log_release: - if (dumpRefcnts) { - if (lep->oldaddress == 0) { - // Final release - u_long addr = (u_long) lep->address; - malloc_log_entry** lepp = refcntDict->find(addr); - if (lepp) { - refcntDict->remove(addr); - } - } - } - break; - } - lep = (malloc_log_entry*) &lep->pcs[lep->numpcs]; - } - - dict->rewind(); - while (NULL != (lep = dict->next())) { - totalLeaked += lep->size; - } - - if (!quiet) { - printf("# of mallocs = %ld\n", mallocs); - printf("# of reallocs = %ld\n", reallocs); - printf("# of frees = %ld\n", frees); - printf("# of errors = %ld\n", errors); - printf("Total bytes allocated = %ld\n", totalMalloced); - printf("Total bytes leaked = %ld\n", totalLeaked); - printf("Average bytes per malloc = %g\n", - float(totalMalloced)/mallocs); - } -} - -void leaky::buildLeakGraph() -{ - // For each leak - malloc_log_entry* lep; - dict->rewind(); - while (NULL != (lep = dict->next())) { - if (ShowThisEntry(lep)) { - char** basepcp = &lep->pcs[0]; - char** pcp = &lep->pcs[lep->numpcs - 1]; - - // Find root for this allocation - Symbol* sym = findSymbol((u_long) *pcp); - TreeNode* node = sym->root; - if (!node) { - sym->root = node = new TreeNode(sym); - - // Add root to list of roots - if (roots.IsEmpty()) { - node->nextRoot = rootList; - rootList = node; - } - } - pcp--; - - // Build tree underneath the root - for (; pcp >= basepcp; pcp--) { - // Share nodes in the tree until there is a divergence - sym = findSymbol((u_long) *pcp); - if (!sym) { - break; - } - TreeNode* nextNode = node->GetDirectDescendant(sym); - if (!nextNode) { - // Make a new node at the point of divergence - nextNode = node->AddDescendant(sym); - } - - // See if the symbol is to be a user specified root. If it is, - // and we haven't already stuck it on the root-list do so now. - if (!sym->root && !roots.IsEmpty() && roots.contains(sym->name)) { - sym->root = nextNode; - nextNode->nextRoot = rootList; - rootList = nextNode; - } - - if (pcp == basepcp) { - nextNode->bytesLeaked += lep->size; - } - else { - node->descendantBytesLeaked += lep->size; - } - - node = nextNode; - } - } - } -} - -Symbol* leaky::findLeakGraphRoot(Symbol* aStart, Symbol* aEnd) -{ - while (aStart < aEnd) { - if (aStart->root) { - return aStart; - } - aStart++; - } - return NULL; -} - -void leaky::dumpLeakGraph() -{ - if (dumpHTML) { - printf("Leaky Graph\n"); - printf("\n"); - printf("\n"); - printf("
\n"); - printf("Key:
\n"); - printf("Bytes directly leaked
\n"); - printf("Bytes leaked by descendants
\n"); - } - -#if 0 - Symbol* base = externalSymbols; - Symbol* end = externalSymbols + usefulSymbols; - while (base < end) { - Symbol* sym = findLeakGraphRoot(base, end); - if (!sym) break; - dumpLeakTree(sym->root, 0); - base = sym + 1; - } -#else - TreeNode* root = rootList; - while (root) { - dumpLeakTree(root, 0); - root = root->nextRoot; - } -#endif - if (dumpHTML) { - printf("\n"); - } -} - -void leaky::dumpLeakTree(TreeNode* aNode, int aIndent) -{ - Symbol* sym = aNode->symbol; - if (dumpHTML) { - printf("
\n"); - if (aNode->HasDescendants()) { - printf("", - aIndent > 1 ? "close" : "open"); - } - printf("%s%ld", - sym->name, - aNode->bytesLeaked); - printf("%ld\n", - aNode->descendantBytesLeaked); - } - else { - indentBy(aIndent); - printf("%s bytesLeaked=%ld (%ld from kids)\n", - sym->name, - aNode->bytesLeaked, - aNode->descendantBytesLeaked); - } - - TreeNode* node = aNode->descendants; - int kidNum = 0; - while (node) { - sym = node->symbol; - dumpLeakTree(node, aIndent + 1); - kidNum++; - node = node->nextSibling; - } - - if (dumpHTML) { - printf("
"); - } -} - -//---------------------------------------------------------------------- - -TreeNode* TreeNode::freeList; - -void* TreeNode::operator new(size_t size) CPP_THROW_NEW -{ - if (!freeList) { - TreeNode* newNodes = (TreeNode*) new char[sizeof(TreeNode) * 5000]; - if (!newNodes) { - return NULL; - } - TreeNode* n = newNodes; - TreeNode* end = newNodes + 5000 - 1; - while (n < end) { - n->nextSibling = n + 1; - n++; - } - n->nextSibling = NULL; - freeList = newNodes; - } - - TreeNode* rv = freeList; - freeList = rv->nextSibling; - - return (void*) rv; -} - -void TreeNode::operator delete(void* ptr) -{ - TreeNode* node = (TreeNode*) ptr; - if (node) { - node->nextSibling = freeList; - freeList = node; - } -} - -TreeNode* TreeNode::GetDirectDescendant(Symbol* aSymbol) -{ - TreeNode* node = descendants; - while (node) { - if (node->symbol == aSymbol) { - return node; - } - node = node->nextSibling; - } - return NULL; -} - -TreeNode* TreeNode::AddDescendant(Symbol* aSymbol) -{ - TreeNode* node = new TreeNode(aSymbol); - node->nextSibling = descendants; - descendants = node; - return node; -} diff --git a/tools/leaky/leaky.css b/tools/leaky/leaky.css deleted file mode 100644 index a4c832aff32c..000000000000 --- a/tools/leaky/leaky.css +++ /dev/null @@ -1,53 +0,0 @@ -body { - background-color: white; - line-height: 1.1; - margin: 1em; - font-size: 10pt; - font-family: "Arial", "Times New Roman", "Times Roman", serif; -} - -body > .n, body > .n > .n, body > .n > .n > .n { - display: block; -} - -.key { - display: block; - margin: 1em; - border: 2px solid green; - width: 50%; - margin: 0 auto 1em auto; - font-size: 130%; -} - -.key .b, .key .d { - margin: 0 0 0 2em; - padding: 0; -} - -.n { - display: none; - margin: 0 0 0 1em; - white-space: nowrap; -} - -.n.e { - background-color: rgb(180,180,180); -} - -.s { - display: inline; - margin-left: 5px; -} - -.b { - display: inline; - background-color: yellow; - margin: 0 1em 0 1em; - padding: 0 5px; -} - -.d { - display: inline; - background-color: khaki; - padding: 0 5px; -} diff --git a/tools/leaky/leaky.h b/tools/leaky/leaky.h deleted file mode 100644 index d64a7e88066b..000000000000 --- a/tools/leaky/leaky.h +++ /dev/null @@ -1,194 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef __leaky_h_ -#define __leaky_h_ - -#include "config.h" -#include -#include -#include -#include "dict.h" -#include "strset.h" -#include "xpcom-config.h" // for CPP_NEW_THROW - -typedef unsigned int u_int; - -struct Symbol; - -struct TreeNode { - TreeNode(Symbol* aSymbol) { - symbol = aSymbol; - nextSibling = NULL; - descendants = NULL; - nextRoot = NULL; - bytesLeaked = 0; - descendantBytesLeaked = 0; - } - - TreeNode* GetDirectDescendant(Symbol* aSymbol); - - bool HasDescendants() const { - return NULL != descendants; - } - - TreeNode* AddDescendant(Symbol* aSymbol); - - TreeNode* descendants; - TreeNode* nextSibling; - TreeNode* nextRoot; - Symbol* symbol; - - u_long bytesLeaked; - u_long descendantBytesLeaked; - - void* operator new(size_t size) CPP_THROW_NEW ; - void operator delete(void* ptr); - - static TreeNode* freeList; -}; - -struct Symbol { - char* name; - u_long address; - TreeNode* root; - - void Init(const char* aName, u_long aAddress) { - name = aName ? strdup(aName) : (char *)""; - address = aAddress; - root = NULL; - } -}; - -struct LoadMapEntry { - char* name; // name of .so - u_long address; // base address where it was mapped in - LoadMapEntry* next; -}; - -struct leaky { - leaky(); - ~leaky(); - - void initialize(int argc, char** argv); - void open(); - - char* applicationName; - char* logFile; - char* progFile; - - int dumpLeaks; - int dumpGraph; - int dumpHTML; - int quiet; - int dumpEntireLog; - int showAddress; - bool dumpRefcnts; - u_int stackDepth; - - int mappedLogFile; - malloc_log_entry* firstLogEntry; - malloc_log_entry* lastLogEntry; - u_int buckets; - MallocDict* dict; - MallocDict* refcntDict; - - u_long mallocs; - u_long reallocs; - u_long frees; - u_long totalMalloced; - u_long errors; - u_long totalLeaked; - - int sfd; - Symbol* externalSymbols; - u_int usefulSymbols; - u_int numExternalSymbols; - StrSet exclusions; - u_long lowestSymbolAddr; - u_long highestSymbolAddr; - - LoadMapEntry* loadMap; - - TreeNode* rootList; - - StrSet roots; - StrSet includes; - - void usageError(); - - void LoadMap(); - - void analyze(); - - void dumpLog(); - void dumpEntryToLog(malloc_log_entry* lep); - -#if 0 - void dumpToTree(); - void dumpEntryToTree(FILE* fp, malloc_log_entry* lep); -#endif - - void insertAddress(u_long address, malloc_log_entry* lep); - void removeAddress(u_long address, malloc_log_entry* lep); - - void displayStackTrace(FILE* out, malloc_log_entry* lep); - - void ReadSymbols(const char* fileName, u_long aBaseAddress); - void ReadSharedLibrarySymbols(); - void setupSymbols(const char* fileName); - Symbol* findSymbol(u_long address); - bool excluded(malloc_log_entry* lep); - bool included(malloc_log_entry* lep); - - void buildLeakGraph(); - Symbol* findLeakGraphRoot(Symbol* aStart, Symbol* aEnd); - void dumpLeakGraph(); - void dumpLeakTree(TreeNode* aNode, int aIndent); - - bool ShowThisEntry(malloc_log_entry* lep); - - bool IsRefcnt(malloc_log_entry* lep) const { - return (lep->type == malloc_log_addref) || - (lep->type == malloc_log_release); - } - - static void indentBy(int aCount) { - while (--aCount >= 0) fputs(" ", stdout); - } -}; - -#endif /* __leaky_h_ */ diff --git a/tools/leaky/leaky.html b/tools/leaky/leaky.html deleted file mode 100644 index ea03a22a8cc5..000000000000 --- a/tools/leaky/leaky.html +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - Leaky - - - -
Leaky
- -

Leaky is a program which will help you find memory leaks, and as of -late, help you debug reference count problems with xpcom objects. -

Get the Source -

Leaky is not currently part of the default SeaMonkey module, -
you will need to explicitly pull the source: -
  -

  cvs checkout mozilla/tools/leaky
-If there is enough demand, we can make this part of the default SeaMonkey -module. -

Building it -
  -

  ./configure --enable-leaky
-Top-of-tree build should Just Build It and leaky will show up in dist/bin. -

Using Leaky -

After it has been built, you can use TestPreload and TestMalloc and -ShowLibs to debug your implementation. -

By setting the LIBMALLOC_LOG environment variable you control -how much information is logged during the programs execution. See libmalloc.h -for a definition of the values to use. If you are using LD_PRELOAD, -here is one way to run your program: -

env LD_PRELOAD=/full/path/to/libleaky.so LIBMALLOC_LOG=1 -my-program
-The debugging malloc library creates two files, malloc-log and -malloc-map. -The malloc-log file can be quite large for large programs (e.g. mozilla) -so be prepared to have a lot of disk space. The malloc-map is tiny. -

Once your program has completed execution you can use leaky to look -for memory leaks, or at least use it to dump the log. For memory leaks, -you use leaky like this: -

leaky -d <program-name-goes-here> malloc-log
-Leaky will then display all of the call sites where memory was leaked. -To look at the entire log file contents, not just the leaks add "-a" to -the arguments: -
leaky -d -a <program-name-goes-here> malloc-log
-For debugging reference count issues, here is what I do: -
    -
  1. -Set LIBMALLOC_LOG to "8"
  2. - -
  3. -Modify your source code so that your class::Addref and class::Release methods -call __log_addref and __log_release, as appropriate. See libmalloc.h for -their signatures. If you are using mozilla, you no longer need to modify -your source code with a debug build. See - -xpcom/doc/MemoryTools.html for more info. - -
  4. - -
  5. -Run your program so that you get the log data. Its often convenient to -run your program in the debugger and then set a breakpoint at an interesting -location where you think some object is being leaked or over-freed. Then -when the debugger gets there tell it to execute DumpAddressMap. In gdb -you do this:
  6. - -
        -
      (gdb) p DumpAddressMap()
    - -
  7. -Then use leaky to capture the addref and release calls to a log file:
  8. - -
        -
      leaky -d -a <program-name-goes-here> malloc-log > log
    - -
  9. -Then use "grep" to search the log for a specific object by grepping for -its memory address...
  10. - -
  11. -On a typical *short* run of mozilla, I'll end up with a malloc-log file -of around 5 to 10 megabytes and the resulting converted log file will be -10 to 20 times that so be prepared to have a lot of disk space. It helps -a great deal to narrow down your problem space to reduce the log file size...
  12. -
- -


Leaky now has a "graph" output option. If you do this: -

  leaky -gqx <program-name-goes-here>  malloc-log | sed -e 's/&/&/g' > /tmp/GQ0.html
-Then leaky will make a graph of the leaks [-g] and output that graph in -xml format (currently actually html...) [-x]. I use sed to make it legitimate -html and off it goes to a file. -

If you throw file at viewer (recursion is cool) then it will present -you with a treeview of the leaks that you can click on to open/close sections. -Enjoy! -

Command Line Options -
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-adump the entire log. This means all malloc's, free's, new's, delete's, -addref's or release's will be displayed
-ddump leaks (only one of -d, -R or -g can be used at a time)
-Rdump refcnts
  
-gdisplay a graph of leaks
-xwhen displaying the graph with -g, use html output that can be fed -into an html4+css+dom compliant viewer (like mozilla :-)
-r symboldefine a root for the graph dump. nodes in the graph above symbol will -be hidden, thus reducing the depth of the graph making it easier to find -deeper leaks.
  
-e symbolexclude leaks that include symbol from treatment
-i symbolinclude leaks that include symbol for treatment. If an includes are -defined than only leaks which include the symbols will be processed. excludes -will still apply to this reduced set of leaks
  
-Ashow the address in the stack crawls, not just the symobls
-h numset the size of the hash buckets used by leaksy dictionaries to <num>
-s depthset the depth of the stack crawls shown when displaying stack crawls -(any of the dumping modes except -g)
-qmake leaky quiet (don't dump the information about symbols being read -and from which libraries)
- -

Porting to non-Intel/Linux -
  -

Initial version works only on x86 linux. To work on other platforms -you will need to: -

    -
  1. -Implement CrawlStack() in libmalloc.cpp
  2. - -
  3. -Implement DumpAddressMap() in libmalloc.cpp and in ShowLibs.cpp
  4. - -
  5. -Either support LD_PRELOAD in your dynamic linker, or
  6. - -
    produce a library that wraps your libc malloc (see config.h for some -clues) -
  7. -Implement symbol table reading code (see coff.cpp, elf.cpp and bfd.cpp -for examples; at the time of writing this document only bfd.cpp was known -to work)
  8. -
- -
Last modified: Sun Sep 26 13:15:33 PDT 1999 -
Send comments to Kipp Hickman -
  - - diff --git a/tools/leaky/leaky.js b/tools/leaky/leaky.js deleted file mode 100644 index 32209afb14c7..000000000000 --- a/tools/leaky/leaky.js +++ /dev/null @@ -1,39 +0,0 @@ -var lastIn; -function I(event) { - var it = event.target; - if (it) { - var s = it.src; - s = s.replace("-over", ""); // just in case - s = s.replace(".gif", "-over.gif"); - it.src = s; - lastIn = it; - } -} -function O(event) { - var it = lastIn; - if (it) { - var s = it.src; - s = s.replace("-over", ""); - it.src = s; - lastIn = null; - } -} -function C(event) { - var it = event.target; - if (!it) return; - var kids = it.parentNode.childNodes; - if (!kids) return; - for (var i = 0; i < kids.length; i++) { - var kid = kids[i]; - if ((kid.nodeType == Node.ELEMENT_NODE) && (kid.tagName == "DIV")) { - var d = kid.style.display; - if ((d == "") || (d == null) || (d == "none")) { - it.src = it.src.replace("close", "open"); - kid.style.display = "block"; - } else { - kid.style.display = "none"; - it.src = it.src.replace("open", "close"); - } - } - } -} diff --git a/tools/leaky/libmalloc.cpp b/tools/leaky/libmalloc.cpp deleted file mode 100644 index a82278be466c..000000000000 --- a/tools/leaky/libmalloc.cpp +++ /dev/null @@ -1,608 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "libmalloc.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef NTO -#include -extern r_debug _r_debug; -#else -#include -#endif - -#ifdef NTO -#define JB_BP 0x08 -#include -#endif - -extern "C" { -#ifdef NEED_WRAPPERS - void* __wrap_malloc(size_t); - void* __wrap_realloc(void*, size_t); - void __wrap_free(void*); - void* __wrap___builtin_new(size_t); - void __wrap___builtin_delete(void*); - void* __wrap___builtin_vec_new(size_t); - void __wrap___builtin_vec_delete(void*); - void* __wrap_PR_Malloc(size_t); - void* __wrap_PR_Calloc(size_t, size_t); - void* __wrap_PR_Realloc(void*, size_t); - void __wrap_PR_Free(void*); -#endif -} - -static int gLogFD = -1; -static u_long gFlags; -static int gFillCount = 0; - -#define MARKER0 0xFFFFFFFF -#define MARKER1 0xEEEEEEEE -#define MARKER2_0 0xD8D8D8D8 -#define MARKER2_1 0xE8E8E8E8 - -#define PATTERN_BYTE 0xFE -#define FREE_PATTERN_BYTE 0xDE - -struct Header { - u_long marker0; - size_t rawSize; // user requested size - size_t size; // size rounded up - u_long marker1; -}; - -struct Trailer { - u_long marker2[2]; -}; - -//---------------------------------------------------------------------- - -#if defined(i386) -static void CrawlStack(malloc_log_entry* me, jmp_buf jb) -{ -#ifdef NTO - u_long* bp = (u_long*) (jb[0].__savearea[JB_BP]); -#else - u_long* bp = (u_long*) (jb[0].__jmpbuf[JB_BP]); -#endif - u_long numpcs = 0; - int skip = 2; - while (numpcs < MAX_STACK_CRAWL) { - u_long* nextbp = (u_long*) *bp++; - u_long pc = *bp; - if ((pc < 0x08000000) || (pc > 0x7fffffff) || (nextbp < bp)) { - break; - } - if (--skip < 0) { - me->pcs[numpcs++] = (char*) pc; - } - bp = nextbp; - } - me->numpcs = numpcs; -} -#endif - -//---------------------------------------------------------------------- - -#if defined(linux) || defined(NTO) -static void DumpAddressMap() -{ - int mfd = open("malloc-map", O_CREAT|O_WRONLY|O_TRUNC, 0666); - if (mfd >= 0) { - malloc_map_entry mme; - link_map* map = _r_debug.r_map; - while (NULL != map) { - if (0 != map->l_addr) { - mme.nameLen = strlen(map->l_name); - mme.address = map->l_addr; - write(mfd, &mme, sizeof(mme)); - write(mfd, map->l_name, mme.nameLen); -#if 0 - write(1, map->l_name, mme.nameLen); - write(1, "\n", 1); -#endif - } - map = map->l_next; - } - close(mfd); - } -} -#endif - -//---------------------------------------------------------------------- - -static int Verify(Header* h) -{ - // Sanity check the header first - if ((h->marker0 != MARKER0) || - (h->marker1 != MARKER1) || - (h->rawSize > h->size)) { - DumpAddressMap(); - abort(); - } - - // Sanity check the trailer second - Trailer* t = (Trailer*) ((char*)(h + 1) + h->size); - if ((t->marker2[0] != MARKER2_0) || - (t->marker2[1] != MARKER2_1)) { - DumpAddressMap(); - abort(); - } - - // Verify there were no overruns - size_t fill = h->size - h->rawSize; - if (0 != fill) { - unsigned char* cp = ((unsigned char*)(h + 1)) + h->rawSize; - unsigned char* end = cp + fill; - while (cp < end) { - unsigned char ch = *cp++; - if (ch != PATTERN_BYTE) { - DumpAddressMap(); - abort(); - } - } - } - return 1; -} - -static void -Log(int aType, void* aAddr, size_t aSize, void* aOldAddr) -{ - malloc_log_entry me; - - me.type = (u_long) aType; - me.address = (u_long) aAddr; - me.size = (u_long) aSize; - me.oldaddress = (u_long) aOldAddr; - - jmp_buf jb; - setjmp(jb); - CrawlStack(&me, jb); - - write(gLogFD, &me, sizeof(me) - MAX_STACK_CRAWL*sizeof(char*) + - me.numpcs*sizeof(char*)); -} - -static void* -MallocHook(size_t aSize, u_long aLogType) -{ - size_t roundedSize = aSize; - roundedSize = ((roundedSize + 4 + gFillCount) >> 2) << 2; - - void* ptr = REAL_MALLOC(sizeof(Header) + roundedSize + sizeof(Trailer)); - - if (NULL != ptr) { - Header* h = (Header*) ptr; - h->rawSize = aSize; - h->size = roundedSize; - h->marker0 = MARKER0; - h->marker1 = MARKER1; - - ptr = (void*) ((char*)(h+1)); - - // Fill new memory with a pattern to help detect overruns and - // usage of un-written memory - memset(ptr, PATTERN_BYTE, roundedSize); - - Trailer* t = (Trailer*) ((char*)ptr + roundedSize); - t->marker2[0] = MARKER2_0; - t->marker2[1] = MARKER2_1; - - if (LIBMALLOC_LOG & gFlags) { - Log(aLogType, ptr, aSize, 0); - } - } - - return ptr; -} - -static void -FreeHook(void* aAddr, u_long aLogType) -{ - if (0 == aAddr) { - return; - } - if (LIBMALLOC_LOG & gFlags) { - Log(aLogType, aAddr, 0, 0); - } - Header* h = (Header*) ((char*)aAddr - sizeof(Header)); - if (Verify(h)) { - // Munge the header so that a dup-free will fail the verify - h->marker0 = 0xDEADBEEF; - h->marker1 = 0xDEADBEEF; - - // Munge the body of the allocation so that if the user - // still has a live reference they get messed up - void* ptr = (void*) ((char*)(h+1)); - memset(ptr, FREE_PATTERN_BYTE, h->rawSize); - - if (0 == (LIBMALLOC_NOFREE & gFlags)) { - REAL_FREE(h); - } - } - else { - if (0 == (LIBMALLOC_NOFREE & gFlags)) { - REAL_FREE(aAddr); - } - } -} - -static void* -ReallocHook(void* aOldAddr, size_t aSize) -{ - if (0 == aOldAddr) { - return MallocHook(aSize, malloc_log_malloc); - } - Header* oldh = (Header*) ((char*)aOldAddr - sizeof(Header)); - if (!Verify(oldh)) { - return REAL_REALLOC(aOldAddr, aSize); - } - size_t oldSize = oldh->rawSize; - - size_t roundedSize = aSize; - roundedSize = ((roundedSize + 4) >> 2) << 2; - - void* ptr = REAL_MALLOC(sizeof(Header) + roundedSize + sizeof(Trailer)); - - if (NULL != ptr) { - Header* h = (Header*) ptr; - h->rawSize = aSize; - h->size = roundedSize; - h->marker0 = MARKER0; - h->marker1 = MARKER1; - - ptr = (void*) ((char*)(h+1)); - - Trailer* t = (Trailer*) ((char*)ptr + roundedSize); - t->marker2[0] = MARKER2_0; - t->marker2[1] = MARKER2_1; - - // Copy old memory into new memory (don't copy too much!) - size_t copy = oldSize; - if (copy > aSize) copy = aSize; - memcpy(ptr, aOldAddr, copy); - - // Fill any uncopied memory with the overrun pattern - size_t fill = roundedSize - copy; - if (0 != fill) { - memset((char*)ptr + copy, PATTERN_BYTE, fill); - } - - if (0 == (LIBMALLOC_NOFREE & gFlags)) { - REAL_FREE(oldh); - } - else { - // Mark the old header so that a verify will fail if the caller - // dup free's it. - oldh->marker0 = 0xDEADBEEF; - oldh->marker1 = 0xDEADBEEF; - - // Munge the body of the old allocation so that if the user - // still has a live reference they get messed up - void* optr = (void*) ((char*)(oldh+1)); - memset(optr, FREE_PATTERN_BYTE, oldh->rawSize); - } - - if (LIBMALLOC_LOG & gFlags) { - Log(malloc_log_realloc, ptr, aSize, aOldAddr); - } - } - return ptr; -} - -u_long -SetMallocFlags(u_long aFlags) -{ - u_long old = gFlags; - gFlags = aFlags; - - if ((-1 == gLogFD) && ((LIBMALLOC_LOG|LIBMALLOC_LOG_RC) & gFlags)) { - gLogFD = open("malloc-log", O_CREAT|O_WRONLY|O_TRUNC, 0666); - if (gLogFD < 0) { - gFlags &= ~LIBMALLOC_LOG; - printf("unable to create malloc-log: %d\n", errno); - } - } - if ((gLogFD >= 0) && (0 == ((LIBMALLOC_LOG|LIBMALLOC_LOG_RC) & gFlags))) { - close(gLogFD); - gLogFD = -1; - } -#ifndef NTO - if (LIBMALLOC_CHECK & gFlags) { - mallopt(M_CHECK_ACTION, 1); - } -#endif - - // Try to guarantee that the address map is always dumped - atexit(DumpAddressMap); - - return old; -} - -static int gFirstTime = 1; - -static void Init() -{ - gFirstTime = 0; - u_long flags = 0; - char* s = getenv("LIBMALLOC_LOG"); - if (s) { - flags = atoi(s); - if (LIBMALLOC_LOG & flags) { - char m1[] = "dbgmalloc: enabled memory logging\n"; - write(1, m1, sizeof(m1)-1); - } - if (LIBMALLOC_LOG_RC & flags) { - char m2[] = "dbgmalloc: enabled refcnt logging\n"; - write(1, m2, sizeof(m2)-1); - } - if (LIBMALLOC_NOFREE & flags) { - char m3[] = "dbgmalloc: disabled free\n"; - write(1, m3, sizeof(m3)-1); - } - } - SetMallocFlags(flags); - s = getenv("LIBMALLOC_FILL"); - if (s) { - gFillCount = atoi(s); - char m4[] = "dbgmalloc: adding extra memory fill "; - write(1, m4, sizeof(m4)-1); - write(1, s, strlen(s)); - write(1, "\n", 1); - } -} - -//---------------------------------------------------------------------- - -#ifdef NEED_WRAPPERS -void* __wrap_malloc(size_t aSize) -{ - if (gFirstTime) { - Init(); - } - return MallocHook(aSize, malloc_log_malloc); -} - -void* __wrap_realloc(void* aPtr, size_t aSize) -{ - if (gFirstTime) { - Init(); - } - return ReallocHook(aPtr, aSize); -} - -void __wrap_free(void* aPtr) -{ - if (gFirstTime) { - Init(); - } - FreeHook(aPtr, malloc_log_free); -} - -void* __wrap___builtin_new(size_t aSize) -{ - if (gFirstTime) { - Init(); - } - return MallocHook(aSize, malloc_log_new); -} - -void __wrap___builtin_delete(void* aPtr) -{ - if (gFirstTime) { - Init(); - } - FreeHook(aPtr, malloc_log_delete); -} - -void* __wrap___builtin_vec_new(size_t aSize) -{ - if (gFirstTime) { - Init(); - } - return MallocHook(aSize, malloc_log_new); -} - -void __wrap___builtin_vec_delete(void* aPtr) -{ - if (gFirstTime) { - Init(); - } - FreeHook(aPtr, malloc_log_delete); -} - -void* __wrap_PR_Malloc(size_t aSize) -{ - if (gFirstTime) { - Init(); - } - return MallocHook(aSize, malloc_log_malloc); -} - -void* __wrap_PR_Calloc(size_t aSize, size_t aBsize) -{ - if (gFirstTime) { - Init(); - } - size_t size = aSize*aBsize; - void* ptr = MallocHook(size, malloc_log_malloc); - if (NULL != ptr) { - memset(ptr, 0, size); - } - return ptr; -} - -void* __wrap_PR_Realloc(void* aPtr, size_t aSize) -{ - if (gFirstTime) { - Init(); - } - return ReallocHook(aPtr, aSize); -} - -void __wrap_PR_Free(void* aPtr) -{ - if (gFirstTime) { - Init(); - } - FreeHook(aPtr, malloc_log_free); -} -#endif - -//---------------------------------------- - -// Strong symbols so that libc references are routed to us - -void* malloc(size_t aSize) -{ - if (gFirstTime) { - Init(); - } - return MallocHook(aSize, malloc_log_malloc); -} - -void* realloc(void* aPtr, size_t aSize) -{ - if (gFirstTime) { - Init(); - } - return ReallocHook(aPtr, aSize); -} - -void free(void* aPtr) -{ - if (gFirstTime) { - Init(); - } - FreeHook(aPtr, malloc_log_free); -} - -void* calloc(size_t aSize, size_t aBsize) -{ - if (gFirstTime) { - Init(); - } - size_t size = aSize*aBsize; - void* ptr = MallocHook(size, malloc_log_malloc); - if (NULL != ptr) { - memset(ptr, 0, size); - } - return ptr; -} - -void cfree(void* ptr) -{ - if (gFirstTime) { - Init(); - } - FreeHook(ptr, malloc_log_free); -} - -void* memalign(size_t alignment, size_t size) -{ - ::abort(); -} - -void* valloc(size_t size) -{ - ::abort(); -} - -void* pvalloc(size_t size) -{ - ::abort(); -} - -void* __builtin_new(size_t aSize) -{ - if (gFirstTime) { - Init(); - } - return MallocHook(aSize, malloc_log_new); -} - -void __builtin_delete(void* aPtr) -{ - if (gFirstTime) { - Init(); - } - FreeHook(aPtr, malloc_log_delete); -} - -void* __builtin_vec_new(size_t aSize) -{ - if (gFirstTime) { - Init(); - } - return MallocHook(aSize, malloc_log_new); -} - -void __builtin_vec_delete(void* aPtr) -{ - if (gFirstTime) { - Init(); - } - FreeHook(aPtr, malloc_log_delete); -} - -void -__log_addref(void* p, int oldrc, int newrc) -{ - if (gFirstTime) { - Init(); - } - if (LIBMALLOC_LOG_RC & gFlags) { - Log(malloc_log_addref, p, size_t(oldrc), (void*)newrc); - } -} - -void -__log_release(void* p, int oldrc, int newrc) -{ - if (gFirstTime) { - Init(); - } - if (LIBMALLOC_LOG_RC & gFlags) { - Log(malloc_log_release, p, size_t(oldrc), (void*)newrc); - } -} diff --git a/tools/leaky/libmalloc.h b/tools/leaky/libmalloc.h deleted file mode 100644 index d7d3010221e9..000000000000 --- a/tools/leaky/libmalloc.h +++ /dev/null @@ -1,106 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Kipp E.B. Hickman (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef libmalloc_h___ -#define libmalloc_h___ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include "config.h" - -typedef unsigned long u_long; - -// Format of a malloc log entry. This is what's written out to the -// "malloc-log" file. -struct malloc_log_entry { - u_long type; - u_long address; - u_long size; - u_long oldaddress; - u_long numpcs; - char* pcs[MAX_STACK_CRAWL]; -}; - -// type's -#define malloc_log_malloc 0 -#define malloc_log_realloc 1 -#define malloc_log_free 2 -#define malloc_log_new 3 -#define malloc_log_delete 4 -#define malloc_log_addref 5 -#define malloc_log_release 6 - -// Format of a malloc map entry; after this struct is nameLen+1 bytes of -// name data. -struct malloc_map_entry { - u_long nameLen; - u_long address; // base address -}; - -// A method that can be called if you want to programmatically control -// the malloc logging. Note that you must link with the library to do -// this (or use dlsym after dynamically loading the library...) -extern u_long SetMallocFlags(u_long flags); - -// The environment variable LIBMALLOC_LOG should be set to an integer -// value whose meaning is as follows: - -// Enable logging -#define LIBMALLOC_LOG 0x1 - -// Don't free memory when set -#define LIBMALLOC_NOFREE 0x2 - -// Check heap for corruption after every malloc/free/realloc -#define LIBMALLOC_CHECK 0x4 - -// Log reference count calls (addref/release) -#define LIBMALLOC_LOG_RC 0x8 - -void __log_addref(void* p, int oldrc, int newrc); -void __log_release(void* p, int oldrc, int newrc); - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif - -#endif /* libmalloc_h___ */ diff --git a/tools/leaky/open-over.gif b/tools/leaky/open-over.gif deleted file mode 100644 index b4e423f7be292a98a523315b9f1682b1654f5ee8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85 zcmZ?wbhEHbL;7|i(b|38QY2Z}#g7(pBz5CKxlz%0eF>&`#j6Q0Z* YNg29Kfj6$zdRth{U|$))t;%2x01PSL;7|i&wV#Nv&69yE2vM_?!Iv@h1mVsG{W7nO3x+grD aIg*~pb{v{@&2WK%+p_O-0)DG7SOWkjoECEc diff --git a/tools/leaky/strset.cpp b/tools/leaky/strset.cpp deleted file mode 100644 index 29f222cac1a3..000000000000 --- a/tools/leaky/strset.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Kipp E.B. Hickman. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "strset.h" -#include -#include - -StrSet::StrSet() -{ - strings = 0; - numstrings = 0; -} - -void StrSet::add(const char* s) -{ - if (strings) { - strings = (char**) realloc(strings, (numstrings + 1) * sizeof(char*)); - } else { - strings = (char**) malloc(sizeof(char*)); - } - strings[numstrings] = strdup(s); - numstrings++; -} - -int StrSet::contains(const char* s) -{ - char** sp = strings; - int i = numstrings; - - while (--i >= 0) { - char *ss = *sp++; - if (ss[0] == s[0]) { - if (strcmp(ss, s) == 0) { - return 1; - } - } - } - return 0; -} diff --git a/tools/leaky/strset.h b/tools/leaky/strset.h deleted file mode 100644 index 5db833547e61..000000000000 --- a/tools/leaky/strset.h +++ /dev/null @@ -1,52 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Kipp E.B. Hickman (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef __strset_h_ -#define __strset_h_ - -struct StrSet { - StrSet(); - - void add(const char* string); - int contains(const char* string); - bool IsEmpty() const { return 0 == numstrings; } - - char** strings; - int numstrings; -}; - -#endif /* __strset_h_ */ From aff6d429ca5ad9eec40d2f772f2ded328563cdef Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Mon, 30 Apr 2012 12:18:48 -0400 Subject: [PATCH 008/159] Bug 742849 - Disable AvailableMemoryTracker for 64-bit Windows processes. r=bsmedberg --- xpcom/base/AvailableMemoryTracker.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/xpcom/base/AvailableMemoryTracker.cpp b/xpcom/base/AvailableMemoryTracker.cpp index 281aa004a43b..75fd12a5202e 100644 --- a/xpcom/base/AvailableMemoryTracker.cpp +++ b/xpcom/base/AvailableMemoryTracker.cpp @@ -501,6 +501,7 @@ namespace AvailableMemoryTracker { void Activate() { +#if defined(_M_IX86) MOZ_ASSERT(sInitialized); MOZ_ASSERT(!sHooksActive); @@ -527,21 +528,26 @@ void Activate() NS_RegisterMemoryReporter(new NumLowVirtualMemoryEventsMemoryReporter()); } sHooksActive = true; +#endif } void Init() { + // Do nothing on x86-64, because nsWindowsDllInterceptor is not thread-safe + // on 64-bit. (On 32-bit, it's probably thread-safe.) Even if we run Init() + // before any other of our threads are running, another process may have + // started a remote thread which could call VirtualAlloc! + // + // Moreover, the benefit of this code is less clear when we're a 64-bit + // process, because we aren't going to run out of virtual memory, and the + // system is likely to have a fair bit of physical memory. + +#if defined(_M_IX86) // Don't register the hooks if we're a build instrumented for PGO: If we're // an instrumented build, the compiler adds function calls all over the place // which may call VirtualAlloc; this makes it hard to prevent // VirtualAllocHook from reentering itself. - if (!PR_GetEnv("MOZ_PGO_INSTRUMENTED")) { - // Careful, this is not thread-safe! AddHook sets up the trampoline before - // writing to the out param, and anyway, it writes to the function - // non-atomically. So this must happen before any other threads which - // might call VirtualAlloc, MapViewOfFile, or CreateDIBSection start up. - sKernel32Intercept.Init("Kernel32.dll"); sKernel32Intercept.AddHook("VirtualAlloc", reinterpret_cast(VirtualAllocHook), @@ -557,6 +563,7 @@ void Init() } sInitialized = true; +#endif } } // namespace AvailableMemoryTracker From 19998115273964573127cf8bc60cc5e991593c0c Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Mon, 30 Apr 2012 12:30:00 -0400 Subject: [PATCH 009/159] Bug 750253: Reorder generation of quickstubs header/cpp to avoid unnecessary rebuilds. r=ted --- js/xpconnect/src/qsgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/xpconnect/src/qsgen.py b/js/xpconnect/src/qsgen.py index 07ce7fae2dc1..b4aac888f4b7 100644 --- a/js/xpconnect/src/qsgen.py +++ b/js/xpconnect/src/qsgen.py @@ -1417,9 +1417,9 @@ def main(): conf, interfaces = readConfigFile(filename, includePath=includePath, cachedir=options.cachedir) - writeHeaderFile(options.header_output, conf.name) writeStubFile(options.stub_output, options.header_output, conf, interfaces) + writeHeaderFile(options.header_output, conf.name) if options.makedepend_output is not None: writeMakeDependOutput(options.makedepend_output) except Exception, exc: From 2d07fe18c178d3805840f01471e77ec5ebda453d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabrice=20Desr=C3=A9?= Date: Mon, 30 Apr 2012 09:32:57 -0700 Subject: [PATCH 010/159] Bug 749695 - building with --disable-jemalloc fails [r=mwu] --- mozglue/build/Makefile.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/mozglue/build/Makefile.in b/mozglue/build/Makefile.in index 6379ee4594a8..375728a5c194 100644 --- a/mozglue/build/Makefile.in +++ b/mozglue/build/Makefile.in @@ -83,11 +83,9 @@ endif endif ifeq (Android,$(OS_TARGET)) -ifdef MOZ_MEMORY # To properly wrap jemalloc's pthread_atfork call. EXTRA_DSO_LDOPTS += -Wl,--wrap=pthread_atfork CPPSRCS += BionicGlue.cpp -endif SHARED_LIBRARY_LIBS += $(call EXPAND_LIBNAME_PATH,android,$(DEPTH)/other-licenses/android) endif From b1feec2eac50c91ff47ee45be4590231f2f84342 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 30 Apr 2012 09:46:27 +0200 Subject: [PATCH 011/159] Bug 749795 - Use neglected code that properly obtains private browsing mode in plugins. r=josh --- dom/plugins/ipc/PluginModuleChild.cpp | 3 +-- dom/plugins/test/mochitest/test_privatemode.xul | 11 +++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index 7f8029f9e677..696279b1f127 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -1126,8 +1126,7 @@ _getvalue(NPP aNPP, case NPNVasdEnabledBool: // Intentional fall-through case NPNVisOfflineBool: // Intentional fall-through case NPNVSupportsXEmbedBool: // Intentional fall-through - case NPNVSupportsWindowless: // Intentional fall-through - case NPNVprivateModeBool: { + case NPNVSupportsWindowless: { // Intentional fall-through NPError result; bool value; PluginModuleChild::current()-> diff --git a/dom/plugins/test/mochitest/test_privatemode.xul b/dom/plugins/test/mochitest/test_privatemode.xul index 239b53793b60..f137c8c005d0 100644 --- a/dom/plugins/test/mochitest/test_privatemode.xul +++ b/dom/plugins/test/mochitest/test_privatemode.xul @@ -65,6 +65,17 @@ function runTests() { is(state1, true, "Private mode state reported incorrectly."); is(state2, true, "Private mode state reported incorrectly."); + var officialState1, officialState2; + try { + officialState1 = pluginElement1.queryPrivateModeState(); + officialState2 = pluginElement2.queryPrivateModeState(); + } catch (e) { + exceptionThrown = true; + } + is(exceptionThrown, false, "Exception thrown getting private mode state."); + is(officialState1, state1, "Private mode reported and queried is inconsistent."); + is(officialState2, state2, "Private mode reported and queried is inconsistent."); + // reset preference states privateBrowsing.privateBrowsingEnabled = false; prefs.setBoolPref("browser.privatebrowsing.keep_current_session", keepCurrentSession); From 4d163ec0b5f5afc53bf1df61f88e63424ea0e79f Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 30 Apr 2012 13:08:16 -0400 Subject: [PATCH 012/159] Bug 749527 - Remove text formats in clipboard when copying an image. r=ehsan. --- dom/base/nsGlobalWindowCommands.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/base/nsGlobalWindowCommands.cpp b/dom/base/nsGlobalWindowCommands.cpp index 87b76c3217e3..04c85dc26ca3 100644 --- a/dom/base/nsGlobalWindowCommands.cpp +++ b/dom/base/nsGlobalWindowCommands.cpp @@ -565,8 +565,8 @@ nsClipboardImageCommands::DoClipboardCommand(const char *aCommandName, nsIConten return aEdit->CopyImage(nsIContentViewerEdit::COPY_IMAGE_TEXT); if (!nsCRT::strcmp(sCopyImageContentsString, aCommandName)) return aEdit->CopyImage(nsIContentViewerEdit::COPY_IMAGE_DATA); - - PRInt32 copyFlags = nsIContentViewerEdit::COPY_IMAGE_ALL; + PRInt32 copyFlags = nsIContentViewerEdit::COPY_IMAGE_DATA | + nsIContentViewerEdit::COPY_IMAGE_HTML; if (aParams) aParams->GetLongValue("imageCopy", ©Flags); return aEdit->CopyImage(copyFlags); From 993fcccb96e7e9eddf0b5cddfb1ffdd08701d35f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabrice=20Desr=C3=A9?= Date: Mon, 30 Apr 2012 10:27:57 -0700 Subject: [PATCH 013/159] Bug 742626 - Allow indexedDB parent directory to not be the default profile directory [r=bent] --- dom/indexedDB/IDBFactory.cpp | 5 ++++- xpcom/io/nsAppDirectoryServiceDefs.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp index f1436d6a7a2f..d7db64c2ab0f 100644 --- a/dom/indexedDB/IDBFactory.cpp +++ b/dom/indexedDB/IDBFactory.cpp @@ -186,7 +186,10 @@ IDBFactory::GetDirectory(nsIFile** aDirectory) { nsresult rv; if (XRE_GetProcessType() == GeckoProcessType_Default) { - rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aDirectory); + rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR, aDirectory); + if (NS_FAILED(rv)) { + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aDirectory); + } NS_ENSURE_SUCCESS(rv, rv); rv = (*aDirectory)->Append(NS_LITERAL_STRING("indexedDB")); NS_ENSURE_SUCCESS(rv, rv); diff --git a/xpcom/io/nsAppDirectoryServiceDefs.h b/xpcom/io/nsAppDirectoryServiceDefs.h index 0ae992fbec95..4f7ad653897a 100644 --- a/xpcom/io/nsAppDirectoryServiceDefs.h +++ b/xpcom/io/nsAppDirectoryServiceDefs.h @@ -119,4 +119,6 @@ #define NS_APP_INSTALL_CLEANUP_DIR "XPIClnupD" //location of xpicleanup.dat xpicleanup.exe #define NS_APP_STORAGE_50_FILE "UStor" // sqlite database used as mozStorage profile db + +#define NS_APP_INDEXEDDB_PARENT_DIR "indexedDBPDir" #endif From f87d6740b5a365369e19a465f3e689bb9276a76f Mon Sep 17 00:00:00 2001 From: Avi Halachmi Date: Sat, 31 Mar 2012 16:08:00 +0300 Subject: [PATCH 014/159] Bug 702463 - Smooth scrolling should use refresh observer instead of a timer. r=roc --- layout/generic/nsGfxScrollFrame.cpp | 87 +++++++++++++++++++---------- layout/generic/nsGfxScrollFrame.h | 4 +- 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index c9241352870a..de4720a933c0 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1333,17 +1333,19 @@ NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame) const double kCurrentVelocityWeighting = 0.25; const double kStopDecelerationWeighting = 0.4; -class nsGfxScrollFrameInner::AsyncScroll { +// AsyncScroll has ref counting. +class nsGfxScrollFrameInner::AsyncScroll : public nsARefreshObserver { public: typedef mozilla::TimeStamp TimeStamp; typedef mozilla::TimeDuration TimeDuration; - AsyncScroll(): - mIsFirstIteration(true) - {} + AsyncScroll() + : mIsFirstIteration(true) + , mCallee(nsnull) + {} ~AsyncScroll() { - if (mScrollTimer) mScrollTimer->Cancel(); + RemoveObserver(); } nsPoint PositionAt(TimeStamp aTime); @@ -1357,7 +1359,6 @@ public: return aTime > mStartTime + mDuration; // XXX or if we've hit the wall } - nsCOMPtr mScrollTimer; TimeStamp mStartTime; // mPrevStartTime holds previous 3 timestamps for intervals averaging (to @@ -1403,6 +1404,51 @@ protected: nscoord aDestination); void InitDuration(nsIAtom *aOrigin); + +// The next section is observer/callback management +// Bodies of WillRefresh and RefreshDriver contain nsGfxScrollFrameInner specific code. +public: + NS_INLINE_DECL_REFCOUNTING(AsyncScroll) + + /* + * Set a refresh observer for smooth scroll iterations (and start observing). + * Should be used at most once during the lifetime of this object. + * Return value: true on success, false otherwise. + */ + bool SetRefreshObserver(nsGfxScrollFrameInner *aCallee) { + NS_ASSERTION(aCallee && !mCallee, "AsyncScroll::SetRefreshObserver - Invalid usage."); + + if (!RefreshDriver(aCallee)->AddRefreshObserver(this, Flush_Display)) { + return false; + } + + mCallee = aCallee; + return true; + } + + virtual void WillRefresh(mozilla::TimeStamp aTime) { + // The callback may release "this". + // We don't access members after returning, so no need for KungFuDeathGrip. + nsGfxScrollFrameInner::AsyncScrollCallback(mCallee, aTime); + } + +private: + nsGfxScrollFrameInner *mCallee; + + nsRefreshDriver* RefreshDriver(nsGfxScrollFrameInner* aCallee) { + return aCallee->mOuter->PresContext()->RefreshDriver(); + } + + /* + * The refresh driver doesn't hold a reference to its observers, + * so releasing this object can (and is) used to remove the observer on DTOR. + * Currently, this object is released once the scrolling ends. + */ + void RemoveObserver() { + if (mCallee) { + RefreshDriver(mCallee)->RemoveRefreshObserver(this, Flush_Display); + } + } }; nsPoint @@ -1616,7 +1662,6 @@ nsGfxScrollFrameInner::~nsGfxScrollFrameInner() delete gScrollFrameActivityTracker; gScrollFrameActivityTracker = nsnull; } - delete mAsyncScroll; if (mScrollActivityTimer) { mScrollActivityTimer->Cancel(); @@ -1651,28 +1696,23 @@ nsGfxScrollFrameInner::ClampScrollPosition(const nsPoint& aPt) const } /* - * Callback function from timer used in nsGfxScrollFrameInner::ScrollTo + * Callback function from AsyncScroll, used in nsGfxScrollFrameInner::ScrollTo */ void -nsGfxScrollFrameInner::AsyncScrollCallback(nsITimer *aTimer, void* anInstance) +nsGfxScrollFrameInner::AsyncScrollCallback(void* anInstance, mozilla::TimeStamp aTime) { nsGfxScrollFrameInner* self = static_cast(anInstance); if (!self || !self->mAsyncScroll) return; if (self->mAsyncScroll->mIsSmoothScroll) { - TimeStamp now = TimeStamp::Now(); - nsPoint destination = self->mAsyncScroll->PositionAt(now); - if (self->mAsyncScroll->IsFinished(now)) { - delete self->mAsyncScroll; + nsPoint destination = self->mAsyncScroll->PositionAt(aTime); + if (self->mAsyncScroll->IsFinished(aTime)) { self->mAsyncScroll = nsnull; } - self->ScrollToImpl(destination); } else { - delete self->mAsyncScroll; self->mAsyncScroll = nsnull; - self->ScrollToImpl(self->mDestination); } } @@ -1695,7 +1735,6 @@ nsGfxScrollFrameInner::ScrollToWithOrigin(nsPoint aScrollPosition, if (aMode == nsIScrollableFrame::INSTANT) { // Asynchronous scrolling is not allowed, so we'll kill any existing // async-scrolling process and do an instant scroll - delete mAsyncScroll; mAsyncScroll = nsnull; ScrollToImpl(mDestination); return; @@ -1714,22 +1753,12 @@ nsGfxScrollFrameInner::ScrollToWithOrigin(nsPoint aScrollPosition, } } else { mAsyncScroll = new AsyncScroll; - mAsyncScroll->mScrollTimer = do_CreateInstance("@mozilla.org/timer;1"); - if (!mAsyncScroll->mScrollTimer) { - delete mAsyncScroll; + if (!mAsyncScroll->SetRefreshObserver(this)) { mAsyncScroll = nsnull; - // allocation failed. Scroll the normal way. + // Observer setup failed. Scroll the normal way. ScrollToImpl(mDestination); return; } - if (isSmoothScroll) { - mAsyncScroll->mScrollTimer->InitWithFuncCallback( - AsyncScrollCallback, this, 1000 / 60, - nsITimer::TYPE_REPEATING_SLACK); - } else { - mAsyncScroll->mScrollTimer->InitWithFuncCallback( - AsyncScrollCallback, this, 0, nsITimer::TYPE_ONE_SHOT); - } } mAsyncScroll->mIsSmoothScroll = isSmoothScroll; diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index c0f679f6c957..23f49770cb18 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -186,7 +186,7 @@ protected: public: nsPoint RestrictToDevPixels(const nsPoint& aPt, nsIntPoint* aPtDevPx, bool aShouldClamp) const; nsPoint ClampScrollPosition(const nsPoint& aPt) const; - static void AsyncScrollCallback(nsITimer *aTimer, void* anInstance); + static void AsyncScrollCallback(void* anInstance, mozilla::TimeStamp aTime); void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode) { ScrollToWithOrigin(aScrollPosition, aMode, nsGkAtoms::other); }; @@ -295,7 +295,7 @@ public: nsIBox* mScrollCornerBox; nsIBox* mResizerBox; nsContainerFrame* mOuter; - AsyncScroll* mAsyncScroll; + nsRefPtr mAsyncScroll; nsTArray mListeners; nsRect mScrollPort; // Where we're currently scrolling to, if we're scrolling asynchronously. From 4a14801895e3170a77da520eb4fa1bb7be013b90 Mon Sep 17 00:00:00 2001 From: Jared Wein Date: Mon, 30 Apr 2012 13:44:55 -0400 Subject: [PATCH 015/159] Bug 702463 - Increasing the timeout of the tests due to the presence of multiple refresh drivers. r=ehsan --- content/events/test/test_bug350471.xul | 4 ++-- content/events/test/test_bug574663.html | 4 ++-- .../tests/test_selection_move_commands.xul | 2 +- .../libeditor/html/tests/test_bug549262.html | 20 +++++++++---------- layout/generic/test/test_bug633762.html | 2 +- .../content/tests/chrome/test_mousescroll.xul | 4 ++-- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/content/events/test/test_bug350471.xul b/content/events/test/test_bug350471.xul index de71c6abb410..630491dc6be8 100644 --- a/content/events/test/test_bug350471.xul +++ b/content/events/test/test_bug350471.xul @@ -182,7 +182,7 @@ function testDefaultHandling(aWin, andThen) { exec(); else andThen(); - }, 0); + }, 20); } ["horizontal", "vertical"].forEach(function(aAxis) { @@ -253,7 +253,7 @@ window.onload = function () { win.close(); SimpleTest.finish(); }); - }, 0); + }, 20); } } diff --git a/content/events/test/test_bug574663.html b/content/events/test/test_bug574663.html index 16678c103744..b878e14dd637 100644 --- a/content/events/test/test_bug574663.html +++ b/content/events/test/test_bug574663.html @@ -93,8 +93,8 @@ function runTest() { } // Revert the effect. sendTouchpadScrollMotion(scrollbox, -1, ctrlKey, isMomentum); - setTimeout(nextTest, 0); - }, 0); + setTimeout(nextTest, 20); + }, 20); } nextTest(); }, win); diff --git a/editor/libeditor/base/tests/test_selection_move_commands.xul b/editor/libeditor/base/tests/test_selection_move_commands.xul index d9aa6bd3c439..c73c866f28a2 100644 --- a/editor/libeditor/base/tests/test_selection_move_commands.xul +++ b/editor/libeditor/base/tests/test_selection_move_commands.xul @@ -18,7 +18,7 @@ function runTest() { function execNext() { try { tests.next(); - setTimeout(execNext, 0); + setTimeout(execNext, 20); } catch (e) {} } execNext(); diff --git a/editor/libeditor/html/tests/test_bug549262.html b/editor/libeditor/html/tests/test_bug549262.html index bff267bdfd68..ce7917a71872 100644 --- a/editor/libeditor/html/tests/test_bug549262.html +++ b/editor/libeditor/html/tests/test_bug549262.html @@ -94,16 +94,16 @@ SimpleTest.waitForFocus(function() { win.close(); SpecialPowers.clearUserPref(smoothScrollPref); SimpleTest.finish(); - }, 0); - }, 0); - }, 0); - }, 0); - }, 0); - }, 0); - }, 0); - }, 0); - }, 0); - }, 0); + }, 20); + }, 20); + }, 20); + }, 20); + }, 20); + }, 20); + }, 20); + }, 20); + }, 20); + }, 20); }, win); diff --git a/layout/generic/test/test_bug633762.html b/layout/generic/test/test_bug633762.html index 2a6354901987..c85b8117759e 100644 --- a/layout/generic/test/test_bug633762.html +++ b/layout/generic/test/test_bug633762.html @@ -36,7 +36,7 @@ function runTests() { // send up arrow key event sendKey("UP"); - setTimeout("finish();", 0); + setTimeout("finish();", 20); } function finish() { diff --git a/toolkit/content/tests/chrome/test_mousescroll.xul b/toolkit/content/tests/chrome/test_mousescroll.xul index ef315aeb26ec..8bde82676ebc 100644 --- a/toolkit/content/tests/chrome/test_mousescroll.xul +++ b/toolkit/content/tests/chrome/test_mousescroll.xul @@ -161,8 +161,8 @@ function testRichListbox(id, andThen) helper(); else andThen(); - }, 0); - }, 0); + }, 20); + }, 20); } // richlistbox currently uses native XUL scrolling, so the "line" From 3529eb4647ffb1da729e9b875f28e6d843cbc63f Mon Sep 17 00:00:00 2001 From: Brian Nicholson Date: Mon, 30 Apr 2012 10:57:09 -0700 Subject: [PATCH 016/159] Bug 746697 - Create nsApplicationCacheService to wrap nsOfflineCacheDevice. r=honzab --- netwerk/build/nsNetModule.cpp | 5 +- netwerk/cache/Makefile.in | 1 + netwerk/cache/nsApplicationCacheService.cpp | 125 ++++++++++++++++++++ netwerk/cache/nsApplicationCacheService.h | 19 +++ netwerk/cache/nsCacheService.cpp | 12 ++ netwerk/cache/nsCacheService.h | 6 + netwerk/cache/nsDiskCacheDeviceSQL.cpp | 36 ++---- netwerk/cache/nsDiskCacheDeviceSQL.h | 27 ++++- 8 files changed, 198 insertions(+), 33 deletions(-) create mode 100644 netwerk/cache/nsApplicationCacheService.cpp create mode 100644 netwerk/cache/nsApplicationCacheService.h diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index d7aadc0788c2..5810304efcb1 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -60,6 +60,7 @@ #include "nsCacheService.h" #include "nsDiskCacheDeviceSQL.h" #include "nsApplicationCache.h" +#include "nsApplicationCacheService.h" #include "nsMimeTypes.h" #include "nsNetStrings.h" #include "nsDNSPrefetch.h" @@ -215,7 +216,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsNestedAboutURI) NS_GENERIC_FACTORY_CONSTRUCTOR(nsAboutCacheEntry) #endif -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsOfflineCacheDevice, nsOfflineCacheDevice::GetInstance) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsApplicationCacheService) NS_GENERIC_FACTORY_CONSTRUCTOR(nsApplicationCacheNamespace) NS_GENERIC_FACTORY_CONSTRUCTOR(nsApplicationCache) @@ -902,7 +903,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = { { &kNS_SOCKS4SOCKETPROVIDER_CID, false, NULL, nsSOCKSSocketProvider::CreateV4 }, { &kNS_UDPSOCKETPROVIDER_CID, false, NULL, nsUDPSocketProviderConstructor }, { &kNS_CACHESERVICE_CID, false, NULL, nsCacheService::Create }, - { &kNS_APPLICATIONCACHESERVICE_CID, false, NULL, nsOfflineCacheDeviceConstructor }, + { &kNS_APPLICATIONCACHESERVICE_CID, false, NULL, nsApplicationCacheServiceConstructor }, { &kNS_APPLICATIONCACHENAMESPACE_CID, false, NULL, nsApplicationCacheNamespaceConstructor }, { &kNS_APPLICATIONCACHE_CID, false, NULL, nsApplicationCacheConstructor }, #ifdef NECKO_COOKIES diff --git a/netwerk/cache/Makefile.in b/netwerk/cache/Makefile.in index 929e5e9dd19e..f0d11e9aa7c1 100644 --- a/netwerk/cache/Makefile.in +++ b/netwerk/cache/Makefile.in @@ -80,6 +80,7 @@ CPPSRCS = \ nsDiskCacheMap.cpp \ nsDiskCacheStreams.cpp \ nsDeleteDir.cpp \ + nsApplicationCacheService.cpp \ $(NULL) LOCAL_INCLUDES = \ diff --git a/netwerk/cache/nsApplicationCacheService.cpp b/netwerk/cache/nsApplicationCacheService.cpp new file mode 100644 index 000000000000..ae9887e2096e --- /dev/null +++ b/netwerk/cache/nsApplicationCacheService.cpp @@ -0,0 +1,125 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsDiskCache.h" +#include "nsDiskCacheDeviceSQL.h" +#include "nsCacheService.h" +#include "nsApplicationCacheService.h" + +#include "nsNetUtil.h" + +using namespace mozilla; + +static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID); + +NS_IMPL_ISUPPORTS1(nsApplicationCacheService, nsIApplicationCacheService) + +nsApplicationCacheService::nsApplicationCacheService() +{ + nsCOMPtr serv = do_GetService(kCacheServiceCID); + mCacheService = nsCacheService::GlobalInstance(); +} + +NS_IMETHODIMP +nsApplicationCacheService::CreateApplicationCache(const nsACString &group, + nsIApplicationCache **out) +{ + if (!mCacheService) + return NS_ERROR_UNEXPECTED; + + nsRefPtr device; + nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device)); + NS_ENSURE_SUCCESS(rv, rv); + return device->CreateApplicationCache(group, out); +} + +NS_IMETHODIMP +nsApplicationCacheService::GetApplicationCache(const nsACString &clientID, + nsIApplicationCache **out) +{ + if (!mCacheService) + return NS_ERROR_UNEXPECTED; + + nsRefPtr device; + nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device)); + NS_ENSURE_SUCCESS(rv, rv); + return device->GetApplicationCache(clientID, out); +} + +NS_IMETHODIMP +nsApplicationCacheService::GetActiveCache(const nsACString &group, + nsIApplicationCache **out) +{ + if (!mCacheService) + return NS_ERROR_UNEXPECTED; + + nsRefPtr device; + nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device)); + NS_ENSURE_SUCCESS(rv, rv); + return device->GetActiveCache(group, out); +} + +NS_IMETHODIMP +nsApplicationCacheService::DeactivateGroup(const nsACString &group) +{ + if (!mCacheService) + return NS_ERROR_UNEXPECTED; + + nsRefPtr device; + nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device)); + NS_ENSURE_SUCCESS(rv, rv); + return device->DeactivateGroup(group); +} + +NS_IMETHODIMP +nsApplicationCacheService::ChooseApplicationCache(const nsACString &key, + nsIApplicationCache **out) +{ + if (!mCacheService) + return NS_ERROR_UNEXPECTED; + + nsRefPtr device; + nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device)); + NS_ENSURE_SUCCESS(rv, rv); + return device->ChooseApplicationCache(key, out); +} + +NS_IMETHODIMP +nsApplicationCacheService::CacheOpportunistically(nsIApplicationCache* cache, + const nsACString &key) +{ + if (!mCacheService) + return NS_ERROR_UNEXPECTED; + + nsRefPtr device; + nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device)); + NS_ENSURE_SUCCESS(rv, rv); + return device->CacheOpportunistically(cache, key); +} + +NS_IMETHODIMP +nsApplicationCacheService::GetGroups(PRUint32 *count, + char ***keys) +{ + if (!mCacheService) + return NS_ERROR_UNEXPECTED; + + nsRefPtr device; + nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device)); + NS_ENSURE_SUCCESS(rv, rv); + return device->GetGroups(count, keys); +} + +NS_IMETHODIMP +nsApplicationCacheService::GetGroupsTimeOrdered(PRUint32 *count, + char ***keys) +{ + if (!mCacheService) + return NS_ERROR_UNEXPECTED; + + nsRefPtr device; + nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device)); + NS_ENSURE_SUCCESS(rv, rv); + return device->GetGroupsTimeOrdered(count, keys); +} diff --git a/netwerk/cache/nsApplicationCacheService.h b/netwerk/cache/nsApplicationCacheService.h new file mode 100644 index 000000000000..4fcf13837eaa --- /dev/null +++ b/netwerk/cache/nsApplicationCacheService.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _nsApplicationCacheService_h_ +#define _nsApplicationCacheService_h_ + +class nsApplicationCacheService : public nsIApplicationCacheService +{ +public: + nsApplicationCacheService(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIAPPLICATIONCACHESERVICE +private: + nsRefPtr mCacheService; +}; + +#endif // _nsApplicationCacheService_h_ diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp index 687bb9b26d90..b987d4522eb2 100644 --- a/netwerk/cache/nsCacheService.cpp +++ b/netwerk/cache/nsCacheService.cpp @@ -1589,6 +1589,18 @@ nsCacheService::CreateDiskDevice() return NS_OK; } +nsresult +nsCacheService::GetOfflineDevice(nsOfflineCacheDevice **aDevice) +{ + if (!mOfflineDevice) { + nsresult rv = CreateOfflineDevice(); + NS_ENSURE_SUCCESS(rv, rv); + } + + NS_ADDREF(*aDevice = mOfflineDevice); + return NS_OK; +} + nsresult nsCacheService::CreateOfflineDevice() { diff --git a/netwerk/cache/nsCacheService.h b/netwerk/cache/nsCacheService.h index 713726de2262..9244d90eea0f 100644 --- a/netwerk/cache/nsCacheService.h +++ b/netwerk/cache/nsCacheService.h @@ -143,6 +143,12 @@ public: static bool IsStorageEnabledForPolicy_Locked(nsCacheStoragePolicy policy); + /** + * Methods called by nsApplicationCacheService + */ + + nsresult GetOfflineDevice(nsOfflineCacheDevice ** aDevice); + // This method may be called to release an object while the cache service // lock is being held. If a non-null target is specified and the target // does not correspond to the current thread, then the release will be diff --git a/netwerk/cache/nsDiskCacheDeviceSQL.cpp b/netwerk/cache/nsDiskCacheDeviceSQL.cpp index 702e353983c1..26ffee305bde 100644 --- a/netwerk/cache/nsDiskCacheDeviceSQL.cpp +++ b/netwerk/cache/nsDiskCacheDeviceSQL.cpp @@ -73,7 +73,6 @@ using namespace mozilla; static const char OFFLINE_CACHE_DEVICE_ID[] = { "offline" }; -static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID); #define LOG(args) CACHE_LOG_DEBUG(args) @@ -821,7 +820,7 @@ private: * nsOfflineCacheDevice */ -NS_IMPL_THREADSAFE_ISUPPORTS1(nsOfflineCacheDevice, nsIApplicationCacheService) +NS_IMPL_THREADSAFE_ISUPPORTS0(nsOfflineCacheDevice) nsOfflineCacheDevice::nsOfflineCacheDevice() : mDB(nsnull) @@ -985,23 +984,6 @@ nsOfflineCacheDevice::DeleteData(nsCacheEntry *entry) * nsCacheDevice implementation */ -/* static */ -nsOfflineCacheDevice * -nsOfflineCacheDevice::GetInstance() -{ - nsresult rv; - nsCOMPtr serv = do_GetService(kCacheServiceCID, &rv); - NS_ENSURE_SUCCESS(rv, nsnull); - - nsICacheService *iservice = static_cast(serv.get()); - nsCacheService *cacheService = static_cast(iservice); - rv = cacheService->CreateOfflineDevice(); - NS_ENSURE_SUCCESS(rv, nsnull); - - NS_IF_ADDREF(cacheService->mOfflineDevice); - return cacheService->mOfflineDevice; -} - // This struct is local to nsOfflineCacheDevice::Init, but ISO C++98 doesn't // allow a template (mozilla::ArrayLength) to be instantiated based on a local // type. Boo-urns! @@ -2055,7 +2037,7 @@ nsOfflineCacheDevice::GetUsage(const nsACString &clientID, return NS_OK; } -NS_IMETHODIMP +nsresult nsOfflineCacheDevice::GetGroups(PRUint32 *count, char ***keys) { @@ -2065,7 +2047,7 @@ nsOfflineCacheDevice::GetGroups(PRUint32 *count, return RunSimpleQuery(mStatement_EnumerateGroups, 0, count, keys); } -NS_IMETHODIMP +nsresult nsOfflineCacheDevice::GetGroupsTimeOrdered(PRUint32 *count, char ***keys) { @@ -2113,7 +2095,7 @@ nsOfflineCacheDevice::RunSimpleQuery(mozIStorageStatement * statement, return NS_OK; } -NS_IMETHODIMP +nsresult nsOfflineCacheDevice::CreateApplicationCache(const nsACString &group, nsIApplicationCache **out) { @@ -2151,7 +2133,7 @@ nsOfflineCacheDevice::CreateApplicationCache(const nsACString &group, return NS_OK; } -NS_IMETHODIMP +nsresult nsOfflineCacheDevice::GetApplicationCache(const nsACString &clientID, nsIApplicationCache **out) { @@ -2186,7 +2168,7 @@ nsOfflineCacheDevice::GetApplicationCache(const nsACString &clientID, return NS_OK; } -NS_IMETHODIMP +nsresult nsOfflineCacheDevice::GetActiveCache(const nsACString &group, nsIApplicationCache **out) { @@ -2199,7 +2181,7 @@ nsOfflineCacheDevice::GetActiveCache(const nsACString &group, return NS_OK; } -NS_IMETHODIMP +nsresult nsOfflineCacheDevice::DeactivateGroup(const nsACString &group) { nsCString *active = nsnull; @@ -2248,7 +2230,7 @@ nsOfflineCacheDevice::CanUseCache(nsIURI *keyURI, const nsCString &clientID) } -NS_IMETHODIMP +nsresult nsOfflineCacheDevice::ChooseApplicationCache(const nsACString &key, nsIApplicationCache **out) { @@ -2321,7 +2303,7 @@ nsOfflineCacheDevice::ChooseApplicationCache(const nsACString &key, return NS_OK; } -NS_IMETHODIMP +nsresult nsOfflineCacheDevice::CacheOpportunistically(nsIApplicationCache* cache, const nsACString &key) { diff --git a/netwerk/cache/nsDiskCacheDeviceSQL.h b/netwerk/cache/nsDiskCacheDeviceSQL.h index 6fee2c91b792..a4b8345b5de8 100644 --- a/netwerk/cache/nsDiskCacheDeviceSQL.h +++ b/netwerk/cache/nsDiskCacheDeviceSQL.h @@ -89,20 +89,17 @@ private: }; class nsOfflineCacheDevice : public nsCacheDevice - , public nsIApplicationCacheService + , public nsISupports { public: nsOfflineCacheDevice(); NS_DECL_ISUPPORTS - NS_DECL_NSIAPPLICATIONCACHESERVICE /** * nsCacheDevice methods */ - static nsOfflineCacheDevice *GetInstance(); - virtual nsresult Init(); virtual nsresult Shutdown(); @@ -174,6 +171,28 @@ public: nsresult GetGroupForCache(const nsCSubstring &clientID, nsCString &out); + nsresult CreateApplicationCache(const nsACString &group, + nsIApplicationCache **out); + + nsresult GetApplicationCache(const nsACString &clientID, + nsIApplicationCache **out); + + nsresult GetActiveCache(const nsACString &group, + nsIApplicationCache **out); + + nsresult DeactivateGroup(const nsACString &group); + + nsresult ChooseApplicationCache(const nsACString &key, + nsIApplicationCache **out); + + nsresult CacheOpportunistically(nsIApplicationCache* cache, + const nsACString &key); + + nsresult GetGroups(PRUint32 *count,char ***keys); + + nsresult GetGroupsTimeOrdered(PRUint32 *count, + char ***keys); + /** * Preference accessors */ From 1dff62b86ce7c3f04593492f9d52b844ac8cc056 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Mon, 30 Apr 2012 14:27:15 -0400 Subject: [PATCH 017/159] Bug 748440 - Part 1: Add heap-committed-unused and heap-committed-unused-ratio memory reporters, and rename some JS memory reporters to match. Also add back the js-gc-heap memory reporter. r=njn --HG-- rename : browser/components/privatebrowsing/test/unit/test_privatebrowsing_telemetry.js => browser/components/privatebrowsing/test/unit/test_privatebrowsing_autostart.js rename : browser/components/privatebrowsing/test/unit/test_privatebrowsingwrapper_telemetry.js => browser/components/privatebrowsing/test/unit/test_privatebrowsingwrapper_autostart.js rename : security/manager/ssl/src/TransportSecurityInfo.cpp => security/manager/ssl/src/nsNSSIOLayer.cpp rename : security/manager/ssl/src/TransportSecurityInfo.h => security/manager/ssl/src/nsNSSIOLayer.h extra : rebase_source : 237a72f9b82f0e39dd0f15afa6056f231dc58358 --- js/public/MemoryMetrics.h | 2 - js/src/MemoryMetrics.cpp | 8 ---- js/xpconnect/src/XPCJSRuntime.cpp | 40 ++++++++++++++----- xpcom/base/nsIMemoryReporter.idl | 2 + xpcom/base/nsMemoryReporterManager.cpp | 53 +++++++++++++++++--------- 5 files changed, 68 insertions(+), 37 deletions(-) diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h index a523d37d911a..e81133fbd6e5 100644 --- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -122,7 +122,6 @@ struct RuntimeStats , gcHeapChunkDirtyDecommitted(0) , gcHeapArenaUnused(0) , gcHeapChunkAdmin(0) - , gcHeapFragmentationPercentage(0) , totalObjects(0) , totalShapes(0) , totalScripts(0) @@ -154,7 +153,6 @@ struct RuntimeStats size_t gcHeapChunkDirtyDecommitted; size_t gcHeapArenaUnused; size_t gcHeapChunkAdmin; - size_t gcHeapFragmentationPercentage; size_t totalObjects; size_t totalShapes; size_t totalScripts; diff --git a/js/src/MemoryMetrics.cpp b/js/src/MemoryMetrics.cpp index 41a1fbd16503..2a44f1fe2de4 100644 --- a/js/src/MemoryMetrics.cpp +++ b/js/src/MemoryMetrics.cpp @@ -282,14 +282,6 @@ CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats) rtStats->gcHeapChunkCleanDecommitted - rtStats->gcHeapChunkDirtyDecommitted; - // Why 10000x? 100x because it's a percentage, and another 100x - // because nsIMemoryReporter requires that for percentage amounts so - // they can be fractional. - rtStats->gcHeapFragmentationPercentage = (rtStats->gcHeapChunkCleanUnused + - rtStats->gcHeapChunkDirtyUnused + - rtStats->gcHeapArenaUnused) * 10000 / - rtStats->gcHeapCommitted; - return true; } diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index c577fd5a3da4..325db2041dd0 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -1249,6 +1249,22 @@ GetCompartmentName(JSCompartment *c, bool getAddress, nsCString &name) } } +static PRInt64 +GetGCChunkTotalBytes() +{ + JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime(); + return PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * js::gc::ChunkSize; +} + +// Telemetry relies on this memory reporter being a single-reporter (rather +// than part of the "js" multi-reporter, which is too slow to run during a +// telemetry ping). +NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap, + "js-gc-heap", + KIND_OTHER, + nsIMemoryReporter::UNITS_BYTES, + GetGCChunkTotalBytes, + "Memory used by the garbage-collected JavaScript heap.") static PRInt64 GetJSSystemCompartmentCount() { @@ -1766,7 +1782,7 @@ public: "useful data but currently isn't. This is the sum of all " "compartments' 'gc-heap/arena-unused' numbers."); - REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-unused"), + REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed-unused"), nsIMemoryReporter::KIND_OTHER, rtStats.gcHeapUnused, "Amount of the GC heap that's committed, but that is " @@ -1774,6 +1790,19 @@ public: "bookkeeping. Equal to 'gc-heap-chunk-dirty-unused' + " "'gc-heap-chunk-clean-unused' + 'gc-heap-arena-unused'."); + // Why 10000x? 100x because it's a percentage, and another 100x + // because nsIMemoryReporter requires that for UNITS_PERCENTAGE + // reporters so we can get two decimal places out of the integer value. + REPORT(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed-unused-ratio"), + nsIMemoryReporter::KIND_OTHER, + nsIMemoryReporter::UNITS_PERCENTAGE, + (PRInt64) 10000 * rtStats.gcHeapUnused / + ((double) rtStats.gcHeapCommitted - rtStats.gcHeapUnused), + "Ratio of committed, unused bytes to allocated bytes; i.e. " + "'gc-heap-committed-unused' / 'gc-heap-allocated'. This " + "measures the overhead of the GC heap allocator relative to the " + "amount of memory allocated."); + REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed"), nsIMemoryReporter::KIND_OTHER, rtStats.gcHeapCommitted, @@ -1787,14 +1816,6 @@ public: "bookkeeping. This is calculated as 'gc-heap-committed' " "- 'gc-heap-unused'."); - REPORT(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-fragmentation"), - nsIMemoryReporter::KIND_OTHER, - nsIMemoryReporter::UNITS_PERCENTAGE, - rtStats.gcHeapFragmentationPercentage, - "Fraction of the committed part of the main JSRuntime's " - "garbage-collected heap that is unused. Computed as " - "'gc-heap-unused' / 'gc-heap-committed'."); - REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-decommitted"), nsIMemoryReporter::KIND_OTHER, rtStats.gcHeapChunkCleanDecommitted + rtStats.gcHeapChunkDirtyDecommitted, @@ -2007,6 +2028,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) JS_SetAccumulateTelemetryCallback(mJSRuntime, AccumulateTelemetryCallback); js::SetActivityCallback(mJSRuntime, ActivityCallback, this); + NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap)); NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount)); NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount)); NS_RegisterMemoryMultiReporter(new JSMemoryMultiReporter); diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index ef7acd664888..c327a355f2be 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -197,6 +197,8 @@ interface nsIMemoryReporter : nsISupports * This allows a fractional percentage to be shown even though |amount| is * an integer. E.g. if the actual percentage is 12.34%, |amount| should * be 1234. + * + * Values greater than 100% are allowed. */ const PRInt32 UNITS_BYTES = 0; const PRInt32 UNITS_COUNT = 1; diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 78b187fb6042..9ae1dae9d426 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -366,7 +366,7 @@ NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(PageFaultsHard, #define HAVE_HEAP_ALLOCATED_REPORTERS 1 -static PRInt64 GetHeapUnallocated() +static PRInt64 GetHeapUnused() { jemalloc_stats_t stats; jemalloc_stats(&stats); @@ -387,11 +387,19 @@ static PRInt64 GetHeapCommitted() return (PRInt64) stats.committed; } -static PRInt64 GetHeapCommittedFragmentation() +static PRInt64 GetHeapCommittedUnused() { jemalloc_stats_t stats; jemalloc_stats(&stats); - return (PRInt64) (10000 * (1 - stats.allocated / (double)stats.committed)); + return stats.committed - stats.allocated; +} + +static PRInt64 GetHeapCommittedUnusedRatio() +{ + jemalloc_stats_t stats; + jemalloc_stats(&stats); + return (PRInt64) 10000 * (stats.committed - stats.allocated) / + ((double)stats.allocated); } static PRInt64 GetHeapDirty() @@ -413,15 +421,24 @@ NS_MEMORY_REPORTER_IMPLEMENT(HeapCommitted, "memory and is unable to decommit it because a small part of that block is " "currently in use.") -NS_MEMORY_REPORTER_IMPLEMENT(HeapCommittedFragmentation, - "heap-committed-fragmentation", +NS_MEMORY_REPORTER_IMPLEMENT(HeapCommittedUnused, + "heap-committed-unused", + KIND_OTHER, + UNITS_BYTES, + GetHeapCommittedUnused, + "Committed bytes which do not correspond to an active allocation; i.e., " + "'heap-committed' - 'heap-allocated'. Although the allocator will waste some " + "space under any circumstances, a large value here may indicate that the " + "heap is highly fragmented.") + +NS_MEMORY_REPORTER_IMPLEMENT(HeapCommittedUnusedRatio, + "heap-committed-unused-ratio", KIND_OTHER, UNITS_PERCENTAGE, - GetHeapCommittedFragmentation, - "Fraction of committed bytes which do not correspond to an active " - "allocation; i.e., 1 - (heap-allocated / heap-committed). Although the " - "allocator will waste some space under any circumstances, a large value here " - "may indicate that the heap is highly fragmented.") + GetHeapCommittedUnusedRatio, + "Ratio of committed, unused bytes to allocated bytes; i.e., " + "'heap-committed-unused' / 'heap-allocated'. This measures the overhead " + "of the heap allocator relative to amount of memory allocated.") NS_MEMORY_REPORTER_IMPLEMENT(HeapDirty, "heap-dirty", @@ -438,7 +455,7 @@ NS_MEMORY_REPORTER_IMPLEMENT(HeapDirty, #define HAVE_HEAP_ALLOCATED_REPORTERS 1 -static PRInt64 GetHeapUnallocated() +static PRInt64 GetHeapUnused() { struct mstats stats = mstats(); return stats.bytes_total - stats.bytes_used; @@ -489,14 +506,14 @@ NS_MEMORY_REPORTER_IMPLEMENT(HeapZone0Used, #endif #ifdef HAVE_HEAP_ALLOCATED_REPORTERS -NS_MEMORY_REPORTER_IMPLEMENT(HeapUnallocated, - "heap-unallocated", +NS_MEMORY_REPORTER_IMPLEMENT(HeapUnused, + "heap-unused", KIND_OTHER, UNITS_BYTES, - GetHeapUnallocated, + GetHeapUnused, "Memory mapped by the heap allocator that is not part of an active " - "allocation. Much of this memory may be uncommitted -- that is, it does " - "not take up space in physical memory or in the swap file.") + "allocation. Much of this memory may be uncommitted -- that is, it does not " + "take up space in physical memory or in the swap file.") NS_MEMORY_REPORTER_IMPLEMENT(HeapAllocated, "heap-allocated", @@ -566,7 +583,7 @@ nsMemoryReporterManager::Init() #ifdef HAVE_HEAP_ALLOCATED_REPORTERS REGISTER(HeapAllocated); - REGISTER(HeapUnallocated); + REGISTER(HeapUnused); #endif #ifdef HAVE_EXPLICIT_REPORTER @@ -589,7 +606,7 @@ nsMemoryReporterManager::Init() #if defined(HAVE_JEMALLOC_STATS) REGISTER(HeapCommitted); - REGISTER(HeapCommittedFragmentation); + REGISTER(HeapCommittedUnusedRatio); REGISTER(HeapDirty); #elif defined(HAVE_HEAP_ZONE0_REPORTERS) REGISTER(HeapZone0Committed); From 613652a1c9b65925a037c69a8fd51ddd2c20da28 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Mon, 30 Apr 2012 14:27:16 -0400 Subject: [PATCH 018/159] Bug 748440 - Part 2: Report heap-committed-unused{,-ratio} in telemetry. r=taras --HG-- extra : rebase_source : 5c864364d48a51697330b11a6ea2bcc5849d6394 --- .../telemetry/TelemetryHistograms.h | 4 +- toolkit/components/telemetry/TelemetryPing.js | 104 +++++++++++------- .../tests/unit/test_TelemetryPing.js | 13 +++ 3 files changed, 81 insertions(+), 40 deletions(-) diff --git a/toolkit/components/telemetry/TelemetryHistograms.h b/toolkit/components/telemetry/TelemetryHistograms.h index 8955dcf69074..bda9faab4493 100644 --- a/toolkit/components/telemetry/TelemetryHistograms.h +++ b/toolkit/components/telemetry/TelemetryHistograms.h @@ -96,11 +96,13 @@ HISTOGRAM(TELEMETRY_PING, 1, 3000, 10, EXPONENTIAL, "Time taken to submit teleme HISTOGRAM_BOOLEAN(TELEMETRY_SUCCESS, "Successful telemetry submission") HISTOGRAM(MEMORY_JS_COMPARTMENTS_SYSTEM, 1, 1000, 50, EXPONENTIAL, "Total JavaScript compartments used for add-ons and internals.") HISTOGRAM(MEMORY_JS_COMPARTMENTS_USER, 1, 1000, 50, EXPONENTIAL, "Total JavaScript compartments used for web pages") -HISTOGRAM(MEMORY_JS_GC_HEAP_COMMITTED, 1024, 512 * 1024, 50, EXPONENTIAL, "Committed memory used by the garbage-collected JavaScript heap (KB)") +HISTOGRAM(MEMORY_JS_GC_HEAP, 1024, 512 * 1024, 50, EXPONENTIAL, "Memory used by the garbage-collected JavaScript heap (KB)") HISTOGRAM(MEMORY_RESIDENT, 32 * 1024, 1024 * 1024, 50, EXPONENTIAL, "Resident memory size (KB)") HISTOGRAM(MEMORY_STORAGE_SQLITE, 1024, 512 * 1024, 50, EXPONENTIAL, "Memory used by SQLite (KB)") HISTOGRAM(MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED, 1024, 1024 * 1024, 50, EXPONENTIAL, "Memory used for uncompressed, in-use content images (KB)") HISTOGRAM(MEMORY_HEAP_ALLOCATED, 1024, 1024 * 1024, 50, EXPONENTIAL, "Heap memory allocated (KB)") +HISTOGRAM(MEMORY_HEAP_COMMITTED_UNUSED, 1024, 512 * 1024, 50, EXPONENTIAL, "Committed, unused heap memory (KB)") +HISTOGRAM(MEMORY_HEAP_COMMITTED_UNUSED_RATIO, 1, 100, 25, LINEAR, "Ratio of committed, unused memory to allocated memory in the heap (percentage).") HISTOGRAM(MEMORY_EXPLICIT, 1024, 1024 * 1024, 50, EXPONENTIAL, "Explicit memory allocations (KB)") HISTOGRAM(GHOST_WINDOWS, 1, 128, 8, EXPONENTIAL, "Number of ghost windows") #if defined(XP_MACOSX) diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index 7d458731415f..e7935b94f656 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -54,9 +54,21 @@ const PREF_ENABLED = "toolkit.telemetry.enabled"; const TELEMETRY_INTERVAL = 60000; // Delay before intializing telemetry (ms) const TELEMETRY_DELAY = 60000; -// about:memory values to turn into histograms + +// MEM_HISTOGRAMS lists the memory reporters we turn into histograms. +// +// Note that we currently handle only vanilla memory reporters, not memory +// multi-reporters. +// +// test_TelemetryPing.js relies on some of these memory reporters +// being here. If you remove any of the following histograms from +// MEM_HISTOGRAMS, you'll have to modify test_TelemetryPing.js: +// +// * MEMORY_JS_GC_HEAP, and +// * MEMORY_JS_COMPARTMENTS_SYSTEM. +// const MEM_HISTOGRAMS = { - "js-main-runtime-gc-heap-committed": "MEMORY_JS_GC_HEAP_COMMITTED", + "js-gc-heap": "MEMORY_JS_GC_HEAP", "js-compartments-system": "MEMORY_JS_COMPARTMENTS_SYSTEM", "js-compartments-user": "MEMORY_JS_COMPARTMENTS_USER", "explicit": "MEMORY_EXPLICIT", @@ -65,12 +77,15 @@ const MEM_HISTOGRAMS = { "images-content-used-uncompressed": "MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED", "heap-allocated": "MEMORY_HEAP_ALLOCATED", + "heap-committed-unused": "MEMORY_HEAP_COMMITTED_UNUSED", + "heap-committed-unused-ratio": "MEMORY_HEAP_COMMITTED_UNUSED_RATIO", "page-faults-hard": "PAGE_FAULTS_HARD", "low-memory-events-virtual": "LOW_MEMORY_EVENTS_VIRTUAL", "low-memory-events-commit-space": "LOW_MEMORY_EVENTS_COMMIT_SPACE", "low-memory-events-physical": "LOW_MEMORY_EVENTS_PHYSICAL", "ghost-windows": "GHOST_WINDOWS" }; + // Seconds of idle time before pinging. // On idle-daily a gather-telemetry notification is fired, during it probes can // start asynchronous tasks to gather data. On the next idle the data is sent. @@ -370,49 +385,60 @@ TelemetryPing.prototype = { let e = mgr.enumerateReporters(); while (e.hasMoreElements()) { let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter); - let id, mrPath, mrAmount, mrUnits; + let id = MEM_HISTOGRAMS[mr.path]; + if (!id) { + continue; + } + + // Reading mr.amount might throw an exception. If so, just ignore that + // memory reporter; we're not getting useful data out of it. try { - mrPath = mr.path; - id = MEM_HISTOGRAMS[mrPath]; - if (!id) { - continue; - } - mrAmount = mr.amount; - mrUnits = mr.units; - } catch (ex) { - continue; + this.handleMemoryReport(id, mr.path, mr.units, mr.amount); } - - let val; - if (mrUnits == Ci.nsIMemoryReporter.UNITS_BYTES) { - val = Math.floor(mrAmount / 1024); + catch (e) { } - else if (mrUnits == Ci.nsIMemoryReporter.UNITS_COUNT) { - val = mrAmount; - } - else if (mrUnits == Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE) { - // If the reporter gives us a cumulative count, we'll report the - // difference in its value between now and our previous ping. - - if (!(mrPath in this._prevValues)) { - // If this is the first time we're reading this reporter, store its - // current value but don't report it in the telemetry ping, so we - // ignore the effect startup had on the reporter. - this._prevValues[mrPath] = mrAmount; - continue; - } - - val = mrAmount - this._prevValues[mrPath]; - this._prevValues[mrPath] = mrAmount; - } - else { - NS_ASSERT(false, "Can't handle memory reporter with units " + mrUnits); - continue; - } - this.addValue(mrPath, id, val); } }, + handleMemoryReport: function handleMemoryReport(id, path, units, amount) { + if (amount == -1) { + return; + } + + let val; + if (units == Ci.nsIMemoryReporter.UNITS_BYTES) { + val = Math.floor(amount / 1024); + } + else if (units == Ci.nsIMemoryReporter.UNITS_PERCENTAGE) { + // UNITS_PERCENTAGE amounts are 100x greater than their raw value. + val = Math.floor(amount / 100); + } + else if (units == Ci.nsIMemoryReporter.UNITS_COUNT) { + val = amount; + } + else if (units == Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE) { + // If the reporter gives us a cumulative count, we'll report the + // difference in its value between now and our previous ping. + + if (!(path in this._prevValues)) { + // If this is the first time we're reading this reporter, store its + // current value but don't report it in the telemetry ping, so we + // ignore the effect startup had on the reporter. + this._prevValues[path] = amount; + return; + } + + val = amount - this._prevValues[path]; + this._prevValues[path] = amount; + } + else { + NS_ASSERT(false, "Can't handle memory reporter with units " + units); + return; + } + + this.addValue(path, id, val); + }, + /** * Return true if we're interested in having a STARTUP_* histogram for * the given histogram name. diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js index b89ff88586df..e88b0873fe42 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js @@ -186,6 +186,19 @@ function checkHistograms(request, response) { do_check_eq(uneval(tc), uneval(expected_tc)); + // The ping should include data from memory reporters. We can't check that + // this data is correct, because we can't control the values returned by the + // memory reporters. But we can at least check that the data is there. + // + // It's important to check for the presence of reporters with a mix of units, + // because TelemetryPing has separate logic for each one. But we can't + // currently check UNITS_COUNT_CUMULATIVE or UNITS_PERCENTAGE because + // Telemetry doesn't touch a memory reporter with these units that's + // available on all platforms. + + do_check_true('MEMORY_JS_GC_HEAP' in payload.histograms); // UNITS_BYTES + do_check_true('MEMORY_JS_COMPARTMENTS_SYSTEM' in payload.histograms); // UNITS_COUNT + do_check_true(("mainThread" in payload.slowSQL) && ("otherThreads" in payload.slowSQL)); gFinished = true; From 3ea4cf1424e268d441d4423e73a6815b9b4b17c8 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Mon, 30 Apr 2012 11:38:09 -0700 Subject: [PATCH 019/159] Back out 28cfc474ab58 (bug 742626) for xpcshell bustage --- dom/indexedDB/IDBFactory.cpp | 5 +---- xpcom/io/nsAppDirectoryServiceDefs.h | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp index d7db64c2ab0f..f1436d6a7a2f 100644 --- a/dom/indexedDB/IDBFactory.cpp +++ b/dom/indexedDB/IDBFactory.cpp @@ -186,10 +186,7 @@ IDBFactory::GetDirectory(nsIFile** aDirectory) { nsresult rv; if (XRE_GetProcessType() == GeckoProcessType_Default) { - rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR, aDirectory); - if (NS_FAILED(rv)) { - rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aDirectory); - } + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aDirectory); NS_ENSURE_SUCCESS(rv, rv); rv = (*aDirectory)->Append(NS_LITERAL_STRING("indexedDB")); NS_ENSURE_SUCCESS(rv, rv); diff --git a/xpcom/io/nsAppDirectoryServiceDefs.h b/xpcom/io/nsAppDirectoryServiceDefs.h index 4f7ad653897a..0ae992fbec95 100644 --- a/xpcom/io/nsAppDirectoryServiceDefs.h +++ b/xpcom/io/nsAppDirectoryServiceDefs.h @@ -119,6 +119,4 @@ #define NS_APP_INSTALL_CLEANUP_DIR "XPIClnupD" //location of xpicleanup.dat xpicleanup.exe #define NS_APP_STORAGE_50_FILE "UStor" // sqlite database used as mozStorage profile db - -#define NS_APP_INDEXEDDB_PARENT_DIR "indexedDBPDir" #endif From 135d41b731f3607beb1b10620b1ded3d421c8871 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Thu, 19 Apr 2012 12:28:13 -0700 Subject: [PATCH 020/159] Bug 746703 - Set targetSdkVersion to 14 in AndroidManifest.xml to disable legacy menu button [r=blassey] --- mobile/android/base/AndroidManifest.xml.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mobile/android/base/AndroidManifest.xml.in b/mobile/android/base/AndroidManifest.xml.in index d4c52adb3b04..033c16eccb97 100644 --- a/mobile/android/base/AndroidManifest.xml.in +++ b/mobile/android/base/AndroidManifest.xml.in @@ -10,7 +10,7 @@ #endif > + android:targetSdkVersion="14"/> #include ../sync/manifests/SyncAndroidManifest_permissions.xml.in @@ -58,7 +58,7 @@ @@ -165,7 +165,7 @@ Date: Mon, 30 Apr 2012 14:51:05 -0400 Subject: [PATCH 021/159] Bug 749107 - Set the texture unit before binding the tile texture and change the texture ordering in ImageLayer to leave texture unit 0 bound. r=jmuizelaar --- gfx/layers/opengl/ImageLayerOGL.cpp | 10 +++++----- gfx/layers/opengl/TiledThebesLayerOGL.cpp | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/gfx/layers/opengl/ImageLayerOGL.cpp b/gfx/layers/opengl/ImageLayerOGL.cpp index 781ddc286d08..4e4a199743eb 100644 --- a/gfx/layers/opengl/ImageLayerOGL.cpp +++ b/gfx/layers/opengl/ImageLayerOGL.cpp @@ -265,16 +265,16 @@ ImageLayerOGL::RenderLayer(int, } gl()->MakeCurrent(); - gl()->fActiveTexture(LOCAL_GL_TEXTURE0); - gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[0].GetTextureID()); + gl()->fActiveTexture(LOCAL_GL_TEXTURE2); + gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[2].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); gl()->fActiveTexture(LOCAL_GL_TEXTURE1); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[1].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); - gl()->fActiveTexture(LOCAL_GL_TEXTURE2); - gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[2].GetTextureID()); + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); + gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[0].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); - + YCbCrTextureLayerProgram *program = mOGLManager->GetYCbCrLayerProgram(); program->Activate(); diff --git a/gfx/layers/opengl/TiledThebesLayerOGL.cpp b/gfx/layers/opengl/TiledThebesLayerOGL.cpp index 2739f600bfd6..4239c6ffccea 100644 --- a/gfx/layers/opengl/TiledThebesLayerOGL.cpp +++ b/gfx/layers/opengl/TiledThebesLayerOGL.cpp @@ -216,6 +216,7 @@ void TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset) { gl()->MakeCurrent(); + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); ProcessUploadQueue(); // Render old tiles to fill in gaps we haven't had the time to render yet. From 05fb8bb993b7ad2d90b8a9064d37bc9ad5dee172 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 30 Apr 2012 12:01:11 -0700 Subject: [PATCH 022/159] Bug 737075 - unmark gray strongly held observers implemented in JS. r=bsmedberg, smaug --- content/base/src/nsCCUncollectableMarker.cpp | 5 +++++ xpcom/ds/Makefile.in | 1 + xpcom/ds/nsObserverList.cpp | 11 +++++++++++ xpcom/ds/nsObserverList.h | 4 ++++ xpcom/ds/nsObserverService.cpp | 18 ++++++++++++++++++ xpcom/ds/nsObserverService.h | 4 ++++ 6 files changed, 43 insertions(+) diff --git a/content/base/src/nsCCUncollectableMarker.cpp b/content/base/src/nsCCUncollectableMarker.cpp index 7b98ee210df0..432fec70f88a 100644 --- a/content/base/src/nsCCUncollectableMarker.cpp +++ b/content/base/src/nsCCUncollectableMarker.cpp @@ -62,6 +62,7 @@ #include "nsFrameLoader.h" #include "nsGenericElement.h" #include "xpcpublic.h" +#include "nsObserverService.h" static bool sInited = 0; PRUint32 nsCCUncollectableMarker::sGeneration = 0; @@ -373,6 +374,10 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic, if (cleanupJS) { nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(sGeneration); MarkMessageManagers(); + + nsCOMPtr obs = mozilla::services::GetObserverService(); + static_cast(obs.get())->UnmarkGrayStrongObservers(); + previousWasJSCleanup = true; } else if (previousWasJSCleanup) { previousWasJSCleanup = false; diff --git a/xpcom/ds/Makefile.in b/xpcom/ds/Makefile.in index 955648db116d..bc5e037060a6 100644 --- a/xpcom/ds/Makefile.in +++ b/xpcom/ds/Makefile.in @@ -101,6 +101,7 @@ EXPORTS = \ nsIByteBuffer.h \ nsIUnicharBuffer.h \ nsMathUtils.h \ + nsObserverList.h \ nsObserverService.h \ nsStaticNameTable.h \ nsStaticAtom.h \ diff --git a/xpcom/ds/nsObserverList.cpp b/xpcom/ds/nsObserverList.cpp index 2a05ba10479c..f6aa7c83c586 100644 --- a/xpcom/ds/nsObserverList.cpp +++ b/xpcom/ds/nsObserverList.cpp @@ -40,6 +40,7 @@ #include "nsAutoPtr.h" #include "nsCOMArray.h" #include "nsISimpleEnumerator.h" +#include "xpcpublic.h" nsresult nsObserverList::AddObserver(nsIObserver* anObserver, bool ownsWeak) @@ -131,6 +132,16 @@ nsObserverList::NotifyObservers(nsISupports *aSubject, } } +void +nsObserverList::UnmarkGrayStrongObservers() +{ + for (PRUint32 i = 0; i < mObservers.Length(); ++i) { + if (!mObservers[i].isWeakRef) { + xpc_TryUnmarkWrappedGrayObject(mObservers[i].asObserver()); + } + } +} + NS_IMPL_ISUPPORTS1(nsObserverEnumerator, nsISimpleEnumerator) nsObserverEnumerator::nsObserverEnumerator(nsObserverList* aObserverList) diff --git a/xpcom/ds/nsObserverList.h b/xpcom/ds/nsObserverList.h index e45df0dede19..7583a1862e9b 100644 --- a/xpcom/ds/nsObserverList.h +++ b/xpcom/ds/nsObserverList.h @@ -91,6 +91,10 @@ public: // The array is filled in last-added-first order. void FillObserverArray(nsCOMArray &aArray); + // Unmark any strongly held observers implemented in JS so the cycle + // collector will not traverse them. + void UnmarkGrayStrongObservers(); + private: nsTArray mObservers; }; diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index aa84f2ba06d0..b4a18c104cbd 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -190,3 +190,21 @@ NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports *aSubject, return NS_OK; } +static PLDHashOperator +UnmarkGrayObserverEntry(nsObserverList* aObserverList, void* aClosure) +{ + if (aObserverList) { + aObserverList->UnmarkGrayStrongObservers(); + } + return PL_DHASH_NEXT; +} + +NS_IMETHODIMP +nsObserverService::UnmarkGrayStrongObservers() +{ + NS_ENSURE_VALIDCALL + + mObserverTopicTable.EnumerateEntries(UnmarkGrayObserverEntry, nsnull); + + return NS_OK; +} diff --git a/xpcom/ds/nsObserverService.h b/xpcom/ds/nsObserverService.h index b1eb739e7a23..76f6ef8e42f9 100644 --- a/xpcom/ds/nsObserverService.h +++ b/xpcom/ds/nsObserverService.h @@ -62,6 +62,10 @@ public: static nsresult Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + // Unmark any strongly held observers implemented in JS so the cycle + // collector will not traverse them. + NS_IMETHOD UnmarkGrayStrongObservers(); + private: ~nsObserverService(void); From 88586d9abc88594365f16368893670298b421608 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 30 Apr 2012 15:50:50 -0400 Subject: [PATCH 023/159] Bug 738641 - Account for rounding errors when reporting page size from JS to Java. r=Cwiiis --- mobile/android/chrome/content/browser.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 8aec57227cd4..3bf426c43fbd 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1924,8 +1924,13 @@ Tab.prototype = { * Avoid sending page sizes of less than screen size before we hit DOMContentLoaded, because * this causes the page size to jump around wildly during page load. After the page is loaded, * send updates regardless of page size; we'll zoom to fit the content as needed. + * + * Also, we need to compare the page size returned from getPageSize (in CSS pixels) to the floored + * screen size in CSS pixels because the page size returned from getPageSize may also be floored. */ - if (doc.readyState === 'complete' || (pageWidth >= gScreenWidth && pageHeight >= gScreenHeight)) { + let pageLargerThanScreen = (cssPageWidth >= Math.floor(viewport.cssWidth)) + && (cssPageHeight >= Math.floor(viewport.cssHeight)); + if (doc.readyState === 'complete' || pageLargerThanScreen) { viewport.cssPageWidth = cssPageWidth; viewport.cssPageHeight = cssPageHeight; viewport.pageWidth = pageWidth; From f8175383ec2f62c82f3085f01127a397fd1eb16b Mon Sep 17 00:00:00 2001 From: Mark Finkle Date: Mon, 30 Apr 2012 16:17:29 -0400 Subject: [PATCH 024/159] Bug 750195 - java.lang.NullPointerException: at org.mozilla.gecko.GeckoApp.onDestroy(GeckoApp.java) r=bnicholson --- mobile/android/base/GeckoApp.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 851654ba4b53..dc5b7d3ae4dd 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -2043,7 +2043,8 @@ abstract public class GeckoApp GeckoAppShell.unregisterGeckoEventListener("Session:StatePurged", GeckoApp.mAppContext); GeckoAppShell.unregisterGeckoEventListener("Bookmark:Insert", GeckoApp.mAppContext); - mFavicons.close(); + if (mFavicons != null) + mFavicons.close(); if (SmsManager.getInstance() != null) { SmsManager.getInstance().stop(); @@ -2053,11 +2054,11 @@ abstract public class GeckoApp super.onDestroy(); - mBatteryReceiver.unregisterFor(mAppContext); + if (mBatteryReceiver != null) + mBatteryReceiver.unregisterFor(mAppContext); - if (mAboutHomeContent != null) { + if (mAboutHomeContent != null) mAboutHomeContent.onDestroy(); - } ((GeckoApplication) getApplication()).removeApplicationLifecycleCallbacks(this); } From ef1fcb3e2c2d9b98b01626196b543a1c78ee8615 Mon Sep 17 00:00:00 2001 From: Mark Finkle Date: Mon, 30 Apr 2012 16:17:31 -0400 Subject: [PATCH 025/159] Bug 750159 - Sometimes we get 'browser is null' errors in onLocationChange so remove the need for the browser r=mbrubeck --- mobile/android/chrome/content/browser.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 3bf426c43fbd..51d18251d2e0 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2208,15 +2208,10 @@ Tab.prototype = { if (contentWin != contentWin.top) return; - let browser = BrowserApp.getBrowserForWindow(contentWin); - let uri = browser.currentURI.spec; - let documentURI = ""; - let contentType = ""; + let uri = aLocationURI.spec; + let documentURI = contentWin.document.documentURIObject.spec; + let contentType = contentWin.document.contentType; let sameDocument = (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) != 0; - if (browser.contentDocument) { - documentURI = browser.contentDocument.documentURIObject.spec; - contentType = browser.contentDocument.contentType; - } // Reset state of click-to-play plugin notifications. this.clickToPlayPluginDoorhangerShown = false; From ab7dfdbd800c01581dc05303495da5be0973f6f7 Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Mon, 30 Apr 2012 13:40:27 -0700 Subject: [PATCH 026/159] Bug 743153 - Use ContentUris.parseId instead of RepoUtils.getAndroidIdFromUri. r=rnewman, a=blocking-fennec (dependency) --- .../android/AndroidBrowserBookmarksDataAccessor.java | 3 ++- .../android/AndroidBrowserRepositorySession.java | 3 ++- .../repositories/android/PasswordsRepositorySession.java | 6 +++++- .../android/base/sync/repositories/android/RepoUtils.java | 8 -------- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java index adf54f77403f..eab76f2f0960 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java @@ -16,6 +16,7 @@ import org.mozilla.gecko.sync.repositories.NullCursorException; import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord; import org.mozilla.gecko.sync.repositories.domain.Record; +import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -249,7 +250,7 @@ public class AndroidBrowserBookmarksDataAccessor extends AndroidBrowserRepositor record.title = AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.get(guid); record.type = "folder"; record.androidParentID = parentId; - return(RepoUtils.getAndroidIdFromUri(insert(record))); + return ContentUris.parseId(insert(record)); } @Override diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java b/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java index 3b6e779a2f77..4fb586debf8d 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java @@ -26,6 +26,7 @@ import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSince import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate; import org.mozilla.gecko.sync.repositories.domain.Record; +import android.content.ContentUris; import android.database.Cursor; import android.net.Uri; @@ -533,7 +534,7 @@ public abstract class AndroidBrowserRepositorySession extends StoreTrackingRepos protected Record insert(Record record) throws NoGuidForIdException, NullCursorException, ParentNotFoundException { Record toStore = prepareRecord(record); Uri recordURI = dbHelper.insert(toStore); - long id = RepoUtils.getAndroidIdFromUri(recordURI); + long id = ContentUris.parseId(recordURI); Logger.debug(LOG_TAG, "Inserted as " + id); toStore.androidID = id; diff --git a/mobile/android/base/sync/repositories/android/PasswordsRepositorySession.java b/mobile/android/base/sync/repositories/android/PasswordsRepositorySession.java index 1a7ee18666a0..3218147ff550 100644 --- a/mobile/android/base/sync/repositories/android/PasswordsRepositorySession.java +++ b/mobile/android/base/sync/repositories/android/PasswordsRepositorySession.java @@ -28,6 +28,7 @@ import org.mozilla.gecko.sync.repositories.domain.PasswordRecord; import org.mozilla.gecko.sync.repositories.domain.Record; import android.content.ContentProviderClient; +import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -445,7 +446,10 @@ public class PasswordsRepositorySession extends // record.timeLastUsed = now(); ContentValues cv = getContentValues(record); Uri insertedUri = passwordsProvider.insert(BrowserContractHelpers.PASSWORDS_CONTENT_URI, cv); - record.androidID = RepoUtils.getAndroidIdFromUri(insertedUri); + if (insertedUri == null) { + throw new RemoteException(); // Not much to be done here, save throw. + } + record.androidID = ContentUris.parseId(insertedUri); return record; } diff --git a/mobile/android/base/sync/repositories/android/RepoUtils.java b/mobile/android/base/sync/repositories/android/RepoUtils.java index a6cb5a65174f..daa4a2ec37b0 100644 --- a/mobile/android/base/sync/repositories/android/RepoUtils.java +++ b/mobile/android/base/sync/repositories/android/RepoUtils.java @@ -119,14 +119,6 @@ public class RepoUtils { } } - // Returns android id from the URI that we get after inserting a - // bookmark into the local Android store. - public static long getAndroidIdFromUri(Uri uri) { - String path = uri.getPath(); - int lastSlash = path.lastIndexOf('/'); - return Long.parseLong(path.substring(lastSlash + 1)); - } - //Create a HistoryRecord object from a cursor on a row with a Moz History record in it public static HistoryRecord historyFromMirrorCursor(Cursor cur) { From 5b3bee23a4d03a17cde57e56adc6165f428b14a8 Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Mon, 30 Apr 2012 13:40:30 -0700 Subject: [PATCH 027/159] Bug 713524 - Batch bookmark inserts. r=rnewman, a=blocking-fennec --- mobile/android/base/sync/Utils.java | 63 ++-- .../Server11RepositorySession.java | 2 + ...roidBrowserBookmarksRepositorySession.java | 143 +++++++-- .../AndroidBrowserHistoryDataAccessor.java | 46 +-- ...ndroidBrowserHistoryRepositorySession.java | 51 ++- .../AndroidBrowserRepositoryDataAccessor.java | 53 ++++ .../AndroidBrowserRepositorySession.java | 34 +- .../android/BookmarksInsertionManager.java | 298 ++++++++++++++++++ mobile/android/sync/java-sources.mn | 2 +- 9 files changed, 569 insertions(+), 123 deletions(-) create mode 100644 mobile/android/base/sync/repositories/android/BookmarksInsertionManager.java diff --git a/mobile/android/base/sync/Utils.java b/mobile/android/base/sync/Utils.java index e5d89a209fde..9df412493f7d 100644 --- a/mobile/android/base/sync/Utils.java +++ b/mobile/android/base/sync/Utils.java @@ -1,40 +1,6 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Android Sync Client. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Jason Voll - * Richard Newman - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko.sync; @@ -46,6 +12,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -309,4 +276,26 @@ public class Utils { } return out; } + + // Because TextUtils.join is not stubbed. + public static String toDelimitedString(String delimiter, Collection items) { + if (items == null || items.size() == 0) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + int i = 0; + int c = items.size(); + for (String string : items) { + sb.append(string); + if (++i < c) { + sb.append(delimiter); + } + } + return sb.toString(); + } + + public static String toCommaSeparatedString(Collection items) { + return toDelimitedString(", ", items); + } } diff --git a/mobile/android/base/sync/repositories/Server11RepositorySession.java b/mobile/android/base/sync/repositories/Server11RepositorySession.java index 93b3da1c3ec4..aa739391e8ce 100644 --- a/mobile/android/base/sync/repositories/Server11RepositorySession.java +++ b/mobile/android/base/sync/repositories/Server11RepositorySession.java @@ -223,6 +223,8 @@ public class Server11RepositorySession extends RepositorySession { } private String flattenIDs(String[] guids) { + // Consider using Utils.toDelimitedString if and when the signature changes + // to Collection guids. if (guids.length == 0) { return ""; } diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java index 7df2559180c0..fde1dc609262 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java @@ -5,6 +5,7 @@ package org.mozilla.gecko.sync.repositories.android; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -29,15 +30,20 @@ import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelega import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord; import org.mozilla.gecko.sync.repositories.domain.Record; +import android.content.ContentUris; import android.content.Context; import android.database.Cursor; +import android.net.Uri; -public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepositorySession { +public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepositorySession + implements BookmarksInsertionManager.BookmarkInserter { public static final int DEFAULT_DELETION_FLUSH_THRESHOLD = 50; + public static final int DEFAULT_INSERTION_FLUSH_THRESHOLD = 50; + // TODO: synchronization for these. - private HashMap guidToID = new HashMap(); - private HashMap idToGuid = new HashMap(); + private HashMap parentGuidToIDMap = new HashMap(); + private HashMap parentIDToGuidMap = new HashMap(); /** * Some notes on reparenting/reordering. @@ -101,6 +107,7 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo private AndroidBrowserBookmarksDataAccessor dataAccessor; protected BookmarksDeletionManager deletionManager; + protected BookmarksInsertionManager insertionManager; /** * An array of known-special GUIDs. @@ -227,13 +234,13 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo } private String getGUIDForID(long androidID) { - String guid = idToGuid.get(androidID); + String guid = parentIDToGuidMap.get(androidID); trace(" " + androidID + " => " + guid); return guid; } private long getIDForGUID(String guid) { - Long id = guidToID.get(guid); + Long id = parentGuidToIDMap.get(guid); if (id == null) { Logger.warn(LOG_TAG, "Couldn't find local ID for GUID " + guid); return -1; @@ -419,7 +426,7 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo if (androidParentGUID == null) { Logger.debug(LOG_TAG, "No parent GUID for record " + recordGUID + " with parent " + androidParentID); // If the parent has been stored and somehow has a null GUID, throw an error. - if (idToGuid.containsKey(androidParentID)) { + if (parentIDToGuidMap.containsKey(androidParentID)) { Logger.error(LOG_TAG, "Have the parent android ID for the record but the parent's GUID wasn't found."); throw new NoGuidForIdException(null); } @@ -480,7 +487,7 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo return null; } - long androidID = guidToID.get(recordGUID); + long androidID = parentGuidToIDMap.get(recordGUID); JSONArray childArray = getChildrenArray(androidID, persist); if (childArray == null) { return null; @@ -512,7 +519,7 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo Logger.debug(LOG_TAG, "Ignoring record with guid: " + bmk.guid + " and type: " + bmk.type); return true; } - + @Override public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException { // Check for the existence of special folders @@ -534,7 +541,7 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo delegate.onBeginFailed(e); return; } - + // To deal with parent mapping of bookmarks we have to do some // hairy stuff. Here's the setup for it. @@ -542,15 +549,15 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo // Fake our root. Logger.debug(LOG_TAG, "Tracking places root as ID 0."); - idToGuid.put(0L, "places"); - guidToID.put("places", 0L); + parentIDToGuidMap.put(0L, "places"); + parentGuidToIDMap.put("places", 0L); try { cur.moveToFirst(); while (!cur.isAfterLast()) { String guid = getGUID(cur); long id = RepoUtils.getLongFromCursor(cur, BrowserContract.Bookmarks._ID); - guidToID.put(guid, id); - idToGuid.put(id, guid); + parentGuidToIDMap.put(guid, id); + parentIDToGuidMap.put(id, guid); Logger.debug(LOG_TAG, "GUID " + guid + " maps to " + id); cur.moveToNext(); } @@ -558,14 +565,88 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo cur.close(); } deletionManager = new BookmarksDeletionManager(dataAccessor, DEFAULT_DELETION_FLUSH_THRESHOLD); + + // We just crawled the database enumerating all folders; we'll start the + // insertion manager with exactly these folders as the known parents (the + // collection is copied) in the manager constructor. + insertionManager = new BookmarksInsertionManager(DEFAULT_INSERTION_FLUSH_THRESHOLD, parentGuidToIDMap.keySet(), this); + Logger.debug(LOG_TAG, "Done with initial setup of bookmarks session."); super.begin(delegate); } + /** + * Implement method of BookmarksInsertionManager.BookmarkInserter. + */ + @Override + public boolean insertFolder(BookmarkRecord record) { + // A folder that is *not* deleted needs its androidID updated, so that + // updateBookkeeping can re-parent, etc. + Record toStore = prepareRecord(record); + try { + Uri recordURI = dbHelper.insert(toStore); + if (recordURI == null) { + delegate.onRecordStoreFailed(new RuntimeException("Got null URI inserting folder with guid " + toStore.guid + ".")); + return false; + } + toStore.androidID = ContentUris.parseId(recordURI); + Logger.debug(LOG_TAG, "Inserted folder with guid " + toStore.guid + " as androidID " + toStore.androidID); + + updateBookkeeping(toStore); + } catch (Exception e) { + delegate.onRecordStoreFailed(e); + return false; + } + trackRecord(toStore); + delegate.onRecordStoreSucceeded(toStore); + return true; + } + + /** + * Implement method of BookmarksInsertionManager.BookmarkInserter. + */ + @Override + public void bulkInsertNonFolders(Collection records) { + // All of these records are *not* deleted and *not* folders, so we don't + // need to update androidID at all! + // TODO: persist records that fail to insert for later retry. + ArrayList toStores = new ArrayList(records.size()); + for (Record record : records) { + toStores.add(prepareRecord(record)); + } + + try { + int stored = dataAccessor.bulkInsert(toStores); + if (stored != toStores.size()) { + // Something failed; most pessimistic action is to declare that all insertions failed. + // TODO: perform the bulkInsert in a transaction and rollback unless all insertions succeed? + for (Record failed : toStores) { + delegate.onRecordStoreFailed(new RuntimeException("Possibly failed to bulkInsert non-folder with guid " + failed.guid + ".")); + } + return; + } + } catch (NullCursorException e) { + delegate.onRecordStoreFailed(e); // TODO: include which records failed. + return; + } + + // Success For All! + for (Record succeeded : toStores) { + try { + updateBookkeeping(succeeded); + } catch (Exception e) { + Logger.warn(LOG_TAG, "Got exception updating bookkeeping of non-folder with guid " + succeeded.guid + ".", e); + } + trackRecord(succeeded); + delegate.onRecordStoreSucceeded(succeeded); + } + } + @Override public void finish(RepositorySessionFinishDelegate delegate) throws InactiveSessionException { - // Allow this to be GCed. + // Allow these to be GCed. deletionManager = null; + insertionManager = null; // Override finish to do this check; make sure all records // needing re-parenting have been re-parented. @@ -671,8 +752,8 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo * @param bmk */ private void handleParenting(BookmarkRecord bmk) { - if (guidToID.containsKey(bmk.parentID)) { - bmk.androidParentID = guidToID.get(bmk.parentID); + if (parentGuidToIDMap.containsKey(bmk.parentID)) { + bmk.androidParentID = parentGuidToIDMap.get(bmk.parentID); // Might as well set a basic position from the downloaded children array. JSONArray children = parentToChildArray.get(bmk.parentID); @@ -684,7 +765,7 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo } } else { - bmk.androidParentID = guidToID.get("unfiled"); + bmk.androidParentID = parentGuidToIDMap.get("unfiled"); ArrayList children; if (missingParentToChildren.containsKey(bmk.parentID)) { children = missingParentToChildren.get(bmk.parentID); @@ -719,8 +800,8 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo // Mappings between ID and GUID. // TODO: update our persisted children arrays! // TODO: if our Android ID just changed, replace parents for all of our children. - guidToID.put(bmk.guid, bmk.androidID); - idToGuid.put(bmk.androidID, bmk.guid); + parentGuidToIDMap.put(bmk.guid, bmk.androidID); + parentIDToGuidMap.put(bmk.androidID, bmk.guid); JSONArray childArray = bmk.children; @@ -742,6 +823,15 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo } } + @Override + protected void insert(Record record) throws NoGuidForIdException, NullCursorException, ParentNotFoundException { + try { + insertionManager.enqueueRecord((BookmarkRecord) record); + } catch (Exception e) { + throw new NullCursorException(e); + } + } + @Override protected void storeRecordDeletion(final Record record, final Record existingRecord) { if (SPECIAL_GUIDS_MAP.containsKey(record.guid)) { @@ -755,10 +845,18 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo deletionManager.deleteRecord(bookmarkRecord.guid, isFolder, parentGUID); } - protected void flushDeletions() { + protected void flushQueues() { + long now = now(); + Logger.debug(LOG_TAG, "Applying remaining insertions."); + try { + insertionManager.finishUp(); + Logger.debug(LOG_TAG, "Done applying remaining insertions."); + } catch (Exception e) { + Logger.warn(LOG_TAG, "Unable to apply remaining insertions.", e); + } + Logger.debug(LOG_TAG, "Applying deletions."); try { - long now = now(); untrackGUIDs(deletionManager.flushAll(getIDForGUID("unfiled"), now)); Logger.debug(LOG_TAG, "Done applying deletions."); } catch (Exception e) { @@ -769,7 +867,7 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo @SuppressWarnings("unchecked") private void finishUp() { try { - flushDeletions(); + flushQueues(); Logger.debug(LOG_TAG, "Have " + parentToChildArray.size() + " folders whose children might need repositioning."); for (Entry entry : parentToChildArray.entrySet()) { String guid = entry.getKey(); @@ -824,6 +922,7 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo try { // Clear our queued deletions. deletionManager.clear(); + insertionManager.clear(); super.run(); } catch (Exception ex) { delegate.onWipeFailed(ex); diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataAccessor.java b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataAccessor.java index 85b903881ca1..c72605d9e6e4 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataAccessor.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataAccessor.java @@ -18,7 +18,6 @@ import org.mozilla.gecko.sync.repositories.domain.Record; import android.content.ContentValues; import android.content.Context; -import android.database.Cursor; import android.net.Uri; public class AndroidBrowserHistoryDataAccessor extends @@ -108,17 +107,15 @@ public class AndroidBrowserHistoryDataAccessor extends * This inserts all the records (using ContentProvider.bulkInsert), * then inserts all the visit information (using the data extender's * bulkInsert, which internally uses a single database - * transaction), and then optionally updates the androidID of - * each record. + * transaction). * * @param records - * The records to insert. - * @param fetchFreshAndroidIDs - * true to update the androidID of each - * record; false to invalidate them all. + * the records to insert. + * @return + * the number of records actually inserted. * @throws NullCursorException */ - public void bulkInsert(ArrayList records, boolean fetchFreshAndroidIDs) throws NullCursorException { + public int bulkInsert(ArrayList records) throws NullCursorException { if (records.isEmpty()) { Logger.debug(LOG_TAG, "No records to insert, returning."); } @@ -149,37 +146,6 @@ public class AndroidBrowserHistoryDataAccessor extends } // Then update the history visits. dataExtender.bulkInsert(records); - - // And finally patch up the androidIDs. - if (!fetchFreshAndroidIDs) { - return; - } - - // We do this here to save a few loops. - String guidIn = RepoUtils.computeSQLInClause(guids.length, BrowserContract.History.GUID); - Cursor cursor = queryHelper.safeQuery("", GUID_AND_ID, guidIn, guids, null); - int guidIndex = cursor.getColumnIndexOrThrow(BrowserContract.History.GUID); - int androidIDIndex = cursor.getColumnIndexOrThrow(BrowserContract.History._ID); - - try { - cursor.moveToFirst(); - while (!cursor.isAfterLast()) { - String guid = cursor.getString(guidIndex); - int androidID = cursor.getInt(androidIDIndex); - cursor.moveToNext(); - - Record record = guidToRecord.get(guid); - if (record == null) { - // Should never happen! - Logger.warn(LOG_TAG, "Failed to update androidID for record with guid " + guid + "."); - continue; - } - record.androidID = androidID; - } - } finally { - if (cursor != null) { - cursor.close(); - } - } + return inserted; } } diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryRepositorySession.java b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryRepositorySession.java index 66b7e53bc69c..df7a559b1202 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryRepositorySession.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryRepositorySession.java @@ -127,13 +127,19 @@ public class AndroidBrowserHistoryRepositorySession extends AndroidBrowserReposi @Override public void abort() { - ((AndroidBrowserHistoryDataAccessor) dbHelper).closeExtender(); + if (dbHelper != null) { + ((AndroidBrowserHistoryDataAccessor) dbHelper).closeExtender(); + dbHelper = null; + } super.abort(); } @Override public void finish(final RepositorySessionFinishDelegate delegate) throws InactiveSessionException { - ((AndroidBrowserHistoryDataAccessor) dbHelper).closeExtender(); + if (dbHelper != null) { + ((AndroidBrowserHistoryDataAccessor) dbHelper).closeExtender(); + dbHelper = null; + } super.finish(delegate); } @@ -148,17 +154,10 @@ public class AndroidBrowserHistoryRepositorySession extends AndroidBrowserReposi * * @param record * A Record with a GUID that is not present locally. - * @return The Record to be inserted. Warning: the - * androidID is not valid! It will be set after the - * records are flushed to the database. */ @Override - protected Record insert(Record record) throws NoGuidForIdException, NullCursorException, ParentNotFoundException { - HistoryRecord toStore = (HistoryRecord) prepareRecord(record); - toStore.androidID = -111; // Hopefully this special value will make it easy to catch future errors. - updateBookkeeping(toStore); // Does not use androidID -- just GUID -> String map. - enqueueNewRecord(toStore); - return toStore; + protected void insert(Record record) throws NoGuidForIdException, NullCursorException, ParentNotFoundException { + enqueueNewRecord((HistoryRecord) prepareRecord(record)); } /** @@ -198,7 +197,33 @@ public class AndroidBrowserHistoryRepositorySession extends AndroidBrowserReposi recordsBuffer = new ArrayList(); Logger.debug(LOG_TAG, "Flushing " + outgoing.size() + " records to database."); // TODO: move bulkInsert to AndroidBrowserDataAccessor? - ((AndroidBrowserHistoryDataAccessor) dbHelper).bulkInsert(outgoing, false); // Don't need to update any androidIDs. + int inserted = ((AndroidBrowserHistoryDataAccessor) dbHelper).bulkInsert(outgoing); + if (inserted != outgoing.size()) { + // Something failed; most pessimistic action is to declare that all insertions failed. + // TODO: perform the bulkInsert in a transaction and rollback unless all insertions succeed? + for (HistoryRecord failed : outgoing) { + delegate.onRecordStoreFailed(new RuntimeException("Failed to insert history item with guid " + failed.guid + ".")); + } + return; + } + + // All good, everybody succeeded. + for (HistoryRecord succeeded : outgoing) { + try { + // Does not use androidID -- just GUID -> String map. + updateBookkeeping(succeeded); + } catch (NoGuidForIdException e) { + // Should not happen. + throw new NullCursorException(e); + } catch (ParentNotFoundException e) { + // Should not happen. + throw new NullCursorException(e); + } catch (NullCursorException e) { + throw e; + } + trackRecord(succeeded); + delegate.onRecordStoreSucceeded(succeeded); // At this point, we are really inserted. + } } @Override @@ -209,7 +234,7 @@ public class AndroidBrowserHistoryRepositorySession extends AndroidBrowserReposi synchronized (recordsBufferMonitor) { try { flushNewRecords(); - } catch (NullCursorException e) { + } catch (Exception e) { Logger.warn(LOG_TAG, "Error flushing records to database.", e); } } diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java b/mobile/android/base/sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java index dfce61855ae5..0252612498bb 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java @@ -4,6 +4,8 @@ package org.mozilla.gecko.sync.repositories.android; +import java.util.List; + import org.mozilla.gecko.db.BrowserContract; import org.mozilla.gecko.sync.Logger; import org.mozilla.gecko.sync.repositories.NullCursorException; @@ -177,4 +179,55 @@ public abstract class AndroidBrowserRepositoryDataAccessor { } Logger.warn(LOG_TAG, "Unexpectedly updated " + updated + " rows for guid " + guid); } + + /** + * Insert records. + *

+ * This inserts all the records (using ContentProvider.bulkInsert), + * but does not update the androidID of each record. + * + * @param records + * the records to insert. + * @return + * the number of records actually inserted. + * @throws NullCursorException + */ + public int bulkInsert(List records) throws NullCursorException { + if (records.isEmpty()) { + Logger.debug(LOG_TAG, "No records to insert, returning."); + } + + int size = records.size(); + ContentValues[] cvs = new ContentValues[size]; + int index = 0; + for (Record record : records) { + try { + cvs[index] = getContentValues(record); + index += 1; + } catch (Exception e) { + Logger.warn(LOG_TAG, "Got exception in getContentValues for record with guid " + record.guid, e); + } + } + + if (index != size) { + // bulkInsert treats null ContentValues as blank rows, which we don't want + // to insert into the database. + // We expect exceptions in getContentValues to be exceedingly rare, so we + // re-allocate in the (rare) error case and maintain a fast path for the + // success case. + size = index; + ContentValues[] temp = new ContentValues[size]; + System.arraycopy(cvs, 0, temp, 0, size); // No java.util.Arrays.copyOf in older Android SDKs. + } + + int inserted = context.getContentResolver().bulkInsert(getUri(), cvs); + if (inserted == size) { + Logger.debug(LOG_TAG, "Inserted " + inserted + " records, as expected."); + } else { + Logger.debug(LOG_TAG, "Inserted " + + inserted + " records but expected " + + size + " records."); + } + return inserted; + } } diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java b/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java index 4fb586debf8d..81af3d72713d 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java @@ -22,6 +22,7 @@ import org.mozilla.gecko.sync.repositories.Repository; import org.mozilla.gecko.sync.repositories.StoreTrackingRepositorySession; import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate; import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate; +import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate; import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate; import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate; import org.mozilla.gecko.sync.repositories.domain.Record; @@ -53,9 +54,9 @@ import android.net.Uri; * */ public abstract class AndroidBrowserRepositorySession extends StoreTrackingRepositorySession { + public static final String LOG_TAG = "BrowserRepoSession"; protected AndroidBrowserRepositoryDataAccessor dbHelper; - public static final String LOG_TAG = "BrowserRepoSession"; private HashMap recordToGuid; public AndroidBrowserRepositorySession(Repository repository) { @@ -148,6 +149,13 @@ public abstract class AndroidBrowserRepositorySession extends StoreTrackingRepos deferredDelegate.onBeginSucceeded(this); } + @Override + public void finish(RepositorySessionFinishDelegate delegate) throws InactiveSessionException { + dbHelper = null; + recordToGuid = null; + super.finish(delegate); + } + protected abstract String buildRecordString(Record record); protected void checkDatabase() throws ProfileDatabaseException, NullCursorException { @@ -353,6 +361,8 @@ public abstract class AndroidBrowserRepositorySession extends StoreTrackingRepos this.fetchSince(0, delegate); } + protected int storeCount = 0; + @Override public void store(final Record record) throws NoStoreDelegateException { if (delegate == null) { @@ -363,6 +373,9 @@ public abstract class AndroidBrowserRepositorySession extends StoreTrackingRepos throw new IllegalArgumentException("Null record passed to AndroidBrowserRepositorySession.store()."); } + storeCount += 1; + Logger.debug(LOG_TAG, "Storing record with GUID " + record.guid + " (stored " + storeCount + " records this session)."); + // Store Runnables *must* complete synchronously. It's OK, they // run on a background thread. Runnable command = new Runnable() { @@ -457,9 +470,7 @@ public abstract class AndroidBrowserRepositorySession extends StoreTrackingRepos if (existingRecord == null) { // The record is new. trace("No match. Inserting."); - Record inserted = insert(record); - trackRecord(inserted); - delegate.onRecordStoreSucceeded(inserted); + insert(record); return; } @@ -531,16 +542,19 @@ public abstract class AndroidBrowserRepositorySession extends StoreTrackingRepos delegate.onRecordStoreSucceeded(record); } - protected Record insert(Record record) throws NoGuidForIdException, NullCursorException, ParentNotFoundException { + protected void insert(Record record) throws NoGuidForIdException, NullCursorException, ParentNotFoundException { Record toStore = prepareRecord(record); Uri recordURI = dbHelper.insert(toStore); - long id = ContentUris.parseId(recordURI); - Logger.debug(LOG_TAG, "Inserted as " + id); + if (recordURI == null) { + throw new NullCursorException(new RuntimeException("Got null URI inserting record with guid " + record.guid)); + } + toStore.androidID = ContentUris.parseId(recordURI); - toStore.androidID = id; updateBookkeeping(toStore); - Logger.debug(LOG_TAG, "insert() returning record " + toStore.guid); - return toStore; + trackRecord(toStore); + delegate.onRecordStoreSucceeded(toStore); + + Logger.debug(LOG_TAG, "Inserted record with guid " + toStore.guid + " as androidID " + toStore.androidID); } protected Record replace(Record newRecord, Record existingRecord) throws NoGuidForIdException, NullCursorException, ParentNotFoundException { diff --git a/mobile/android/base/sync/repositories/android/BookmarksInsertionManager.java b/mobile/android/base/sync/repositories/android/BookmarksInsertionManager.java new file mode 100644 index 000000000000..683ee3df8633 --- /dev/null +++ b/mobile/android/base/sync/repositories/android/BookmarksInsertionManager.java @@ -0,0 +1,298 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.sync.repositories.android; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import org.mozilla.gecko.sync.Logger; +import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord; + +/** + * Queue up insertions: + *

    + *
  • Folder inserts where the parent is known. Do these immediately, because + * they allow other records to be inserted. Requires bookkeeping updates. On + * insert, flush the next set.
  • + *
  • Regular inserts where the parent is known. These can happen whenever. + * Batch for speed.
  • + *
  • Records where the parent is not known. These can be flushed out when the + * parent is known, or entered as orphans. This can be a queue earlier in the + * process, so they don't get assigned to Unsorted. Feed into the main batch + * when the parent arrives.
  • + *
+ *

+ * Deletions are always done at the end so that orphaning is minimized, and + * that's why we are batching folders and non-folders separately. + *

+ * Updates are always applied as they arrive. + *

+ * Note that this class is not thread safe. This should be fine: call it only + * from within a store runnable. + */ +public class BookmarksInsertionManager { + public static final String LOG_TAG = "BookmarkInsert"; + public static boolean DEBUG = false; + + protected final int flushThreshold; + protected final BookmarkInserter inserter; + + /** + * Folders that have been successfully inserted. + */ + private final Set insertedFolders = new HashSet(); + + /** + * Non-folders waiting for bulk insertion. + *

+ * We write in insertion order to keep things easy to debug. + */ + private final Set nonFoldersToWrite = new LinkedHashSet(); + + /** + * Map from parent folder GUID to child records (folders and non-folders) + * waiting to be enqueued after parent folder is inserted. + */ + private final Map> recordsWaitingForParent = new HashMap>(); + + /** + * Create an instance to be used for tracking insertions in a bookmarks + * repository session. + * + * @param flushThreshold + * When this many non-folder records have been stored for insertion, + * an incremental flush occurs. + * @param insertedFolders + * The GUIDs of all the folders already inserted into the database. + * @param inserter + * The BookmarkInsert to use. + */ + public BookmarksInsertionManager(int flushThreshold, Collection insertedFolders, BookmarkInserter inserter) { + this.flushThreshold = flushThreshold; + this.insertedFolders.addAll(insertedFolders); + this.inserter = inserter; + } + + protected void addRecordWithUnwrittenParent(BookmarkRecord record) { + Set destination = recordsWaitingForParent.get(record.parentID); + if (destination == null) { + destination = new LinkedHashSet(); + recordsWaitingForParent.put(record.parentID, destination); + } + destination.add(record); + } + + /** + * If record is a folder, insert it immediately; if it is a + * non-folder, enqueue it. Then do the same for any records waiting for this record. + * + * @param record + * the BookmarkRecord to enqueue. + */ + protected void recursivelyEnqueueRecordAndChildren(BookmarkRecord record) { + if (record.isFolder()) { + if (!inserter.insertFolder(record)) { + Logger.warn(LOG_TAG, "Folder with known parent with guid " + record.parentID + " failed to insert!"); + return; + } + Logger.debug(LOG_TAG, "Folder with known parent with guid " + record.parentID + " inserted; adding to inserted folders."); + insertedFolders.add(record.guid); + } else { + Logger.debug(LOG_TAG, "Non-folder has known parent with guid " + record.parentID + "; adding to insertion queue."); + nonFoldersToWrite.add(record); + } + + // Now process record's children. + Set waiting = recordsWaitingForParent.remove(record.guid); + if (waiting == null) { + return; + } + for (BookmarkRecord waiter : waiting) { + recursivelyEnqueueRecordAndChildren(waiter); + } + } + + /** + * Enqueue a folder. + * + * @param record + * the folder to enqueue. + */ + protected void enqueueFolder(BookmarkRecord record) { + Logger.debug(LOG_TAG, "Inserting folder with guid " + record.guid); + + if (!insertedFolders.contains(record.parentID)) { + Logger.debug(LOG_TAG, "Folder has unknown parent with guid " + record.parentID + "; keeping until we see the parent."); + addRecordWithUnwrittenParent(record); + return; + } + + // Parent is known; add as much of the tree as this roots. + recursivelyEnqueueRecordAndChildren(record); + flushNonFoldersIfNecessary(); + } + + /** + * Enqueue a non-folder. + * + * @param record + * the non-folder to enqueue. + */ + protected void enqueueNonFolder(BookmarkRecord record) { + Logger.debug(LOG_TAG, "Inserting non-folder with guid " + record.guid); + + if (!insertedFolders.contains(record.parentID)) { + Logger.debug(LOG_TAG, "Non-folder has unknown parent with guid " + record.parentID + "; keeping until we see the parent."); + addRecordWithUnwrittenParent(record); + return; + } + + // Parent is known; add to insertion queue and maybe write. + Logger.debug(LOG_TAG, "Non-folder has known parent with guid " + record.parentID + "; adding to insertion queue."); + nonFoldersToWrite.add(record); + flushNonFoldersIfNecessary(); + } + + /** + * Enqueue a bookmark record for eventual insertion. + * + * @param record + * the BookmarkRecord to enqueue. + */ + public void enqueueRecord(BookmarkRecord record) { + if (record.isFolder()) { + enqueueFolder(record); + } else { + enqueueNonFolder(record); + } + if (DEBUG) { + dumpState(); + } + } + + /** + * Flush non-folders; empties the insertion queue entirely. + */ + protected void flushNonFolders() { + inserter.bulkInsertNonFolders(nonFoldersToWrite); // All errors are handled in bulkInsertNonFolders. + nonFoldersToWrite.clear(); + } + + /** + * Flush non-folder insertions if there are many of them; empties the + * insertion queue entirely. + */ + protected void flushNonFoldersIfNecessary() { + int num = nonFoldersToWrite.size(); + if (num < flushThreshold) { + Logger.debug(LOG_TAG, "Incremental flush called with " + num + " < " + flushThreshold + " non-folders; not flushing."); + return; + } + Logger.debug(LOG_TAG, "Incremental flush called with " + num + " non-folders; flushing."); + flushNonFolders(); + } + + /** + * Insert all remaining folders followed by all remaining non-folders, + * regardless of whether parent records have been successfully inserted. + */ + public void finishUp() { + // Iterate through all waiting records, writing the folders and collecting + // the non-folders for bulk insertion. + int numFolders = 0; + int numNonFolders = 0; + for (Set records : recordsWaitingForParent.values()) { + for (BookmarkRecord record : records) { + if (!record.isFolder()) { + numNonFolders += 1; + nonFoldersToWrite.add(record); + continue; + } + + numFolders += 1; + if (!inserter.insertFolder(record)) { + Logger.warn(LOG_TAG, "Folder with known parent with guid " + record.parentID + " failed to insert!"); + continue; + } + + Logger.debug(LOG_TAG, "Folder with known parent with guid " + record.parentID + " inserted; adding to inserted folders."); + insertedFolders.add(record.guid); + } + } + recordsWaitingForParent.clear(); + flushNonFolders(); + + Logger.debug(LOG_TAG, "finishUp inserted " + + numFolders + " folders without known parents and " + + numNonFolders + " non-folders without known parents."); + if (DEBUG) { + dumpState(); + } + } + + public void clear() { + this.insertedFolders.clear(); + this.nonFoldersToWrite.clear(); + this.recordsWaitingForParent.clear(); + } + + // For debugging. + public boolean isClear() { + return nonFoldersToWrite.isEmpty() && recordsWaitingForParent.isEmpty(); + } + + // For debugging. + public void dumpState() { + ArrayList readies = new ArrayList(); + for (BookmarkRecord record : nonFoldersToWrite) { + readies.add(record.guid); + } + String ready = Utils.toCommaSeparatedString(new ArrayList(readies)); + + ArrayList waits = new ArrayList(); + for (Set recs : recordsWaitingForParent.values()) { + for (BookmarkRecord rec : recs) { + waits.add(rec.guid); + } + } + String waiting = Utils.toCommaSeparatedString(waits); + String known = Utils.toCommaSeparatedString(insertedFolders); + + Logger.debug(LOG_TAG, "Q=(" + ready + "), W = (" + waiting + "), P=(" + known + ")"); + } + + public interface BookmarkInserter { + /** + * Insert a single folder. + *

+ * All exceptions should be caught and all delegate callbacks invoked here. + * + * @param record + * the record to insert. + * @return + * true if the folder was inserted; false otherwise. + */ + public boolean insertFolder(BookmarkRecord record); + + /** + * Insert many non-folders. Each non-folder's parent was already present in + * the database before this BookmarkInsertionsManager was + * created, or had insertFolder called with it as argument (and + * possibly was not inserted). + *

+ * All exceptions should be caught and all delegate callbacks invoked here. + * + * @param record + * the record to insert. + */ + public void bulkInsertNonFolders(Collection records); + } +} diff --git a/mobile/android/sync/java-sources.mn b/mobile/android/sync/java-sources.mn index df3566801048..a754cef2a552 100644 --- a/mobile/android/sync/java-sources.mn +++ b/mobile/android/sync/java-sources.mn @@ -1 +1 @@ -sync/AlreadySyncingException.java sync/CollectionKeys.java sync/CommandProcessor.java sync/CommandRunner.java sync/CredentialsSource.java sync/crypto/CryptoException.java sync/crypto/CryptoInfo.java sync/crypto/HKDF.java sync/crypto/HMACVerificationException.java sync/crypto/KeyBundle.java sync/crypto/MissingCryptoInputException.java sync/crypto/NoKeyBundleException.java sync/crypto/PersistedCrypto5Keys.java sync/CryptoRecord.java sync/DelayedWorkTracker.java sync/delegates/ClientsDataDelegate.java sync/delegates/FreshStartDelegate.java sync/delegates/GlobalSessionCallback.java sync/delegates/InfoCollectionsDelegate.java sync/delegates/KeyUploadDelegate.java sync/delegates/MetaGlobalDelegate.java sync/delegates/WipeServerDelegate.java sync/EngineSettings.java sync/ExtendedJSONObject.java sync/GlobalSession.java sync/HTTPFailureException.java sync/InfoCollections.java sync/jpake/BigIntegerHelper.java sync/jpake/Gx3OrGx4IsZeroOrOneException.java sync/jpake/IncorrectZkpException.java sync/jpake/JPakeClient.java sync/jpake/JPakeCrypto.java sync/jpake/JPakeJson.java sync/jpake/JPakeNoActivePairingException.java sync/jpake/JPakeNumGenerator.java sync/jpake/JPakeNumGeneratorRandom.java sync/jpake/JPakeParty.java sync/jpake/JPakeRequest.java sync/jpake/JPakeRequestDelegate.java sync/jpake/JPakeResponse.java sync/jpake/stage/CompleteStage.java sync/jpake/stage/ComputeFinalStage.java sync/jpake/stage/ComputeKeyVerificationStage.java sync/jpake/stage/ComputeStepOneStage.java sync/jpake/stage/ComputeStepTwoStage.java sync/jpake/stage/DecryptDataStage.java sync/jpake/stage/DeleteChannel.java sync/jpake/stage/GetChannelStage.java sync/jpake/stage/GetRequestStage.java sync/jpake/stage/JPakeStage.java sync/jpake/stage/PutRequestStage.java sync/jpake/stage/VerifyPairingStage.java sync/jpake/Zkp.java sync/KeyBundleProvider.java sync/Logger.java sync/MetaGlobal.java sync/MetaGlobalException.java sync/MetaGlobalMissingEnginesException.java sync/MetaGlobalNotSetException.java sync/middleware/Crypto5MiddlewareRepository.java sync/middleware/Crypto5MiddlewareRepositorySession.java sync/middleware/MiddlewareRepository.java sync/middleware/MiddlewareRepositorySession.java sync/net/BaseResource.java sync/net/CompletedEntity.java sync/net/ConnectionMonitorThread.java sync/net/HandleProgressException.java sync/net/HttpResponseObserver.java sync/net/Resource.java sync/net/ResourceDelegate.java sync/net/SyncResourceDelegate.java sync/net/SyncResponse.java sync/net/SyncStorageCollectionRequest.java sync/net/SyncStorageCollectionRequestDelegate.java sync/net/SyncStorageRecordRequest.java sync/net/SyncStorageRequest.java sync/net/SyncStorageRequestDelegate.java sync/net/SyncStorageRequestIncrementalDelegate.java sync/net/SyncStorageResponse.java sync/net/TLSSocketFactory.java sync/net/WBOCollectionRequestDelegate.java sync/net/WBORequestDelegate.java sync/NoCollectionKeysSetException.java sync/NodeAuthenticationException.java sync/NonArrayJSONException.java sync/NonObjectJSONException.java sync/NullClusterURLException.java sync/PersistedMetaGlobal.java sync/PrefsSource.java sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java sync/repositories/android/AndroidBrowserBookmarksRepository.java sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java sync/repositories/android/AndroidBrowserHistoryDataAccessor.java sync/repositories/android/AndroidBrowserHistoryDataExtender.java sync/repositories/android/AndroidBrowserHistoryRepository.java sync/repositories/android/AndroidBrowserHistoryRepositorySession.java sync/repositories/android/AndroidBrowserRepository.java sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java sync/repositories/android/AndroidBrowserRepositorySession.java sync/repositories/android/BookmarksDeletionManager.java sync/repositories/android/BrowserContractHelpers.java sync/repositories/android/CachedSQLiteOpenHelper.java sync/repositories/android/ClientsDatabase.java sync/repositories/android/ClientsDatabaseAccessor.java sync/repositories/android/FennecControlHelper.java sync/repositories/android/FennecTabsRepository.java sync/repositories/android/FormHistoryRepositorySession.java sync/repositories/android/PasswordsRepositorySession.java sync/repositories/android/RepoUtils.java sync/repositories/BookmarkNeedsReparentingException.java sync/repositories/BookmarksRepository.java sync/repositories/ConstrainedServer11Repository.java sync/repositories/delegates/DeferrableRepositorySessionCreationDelegate.java sync/repositories/delegates/DeferredRepositorySessionBeginDelegate.java sync/repositories/delegates/DeferredRepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/DeferredRepositorySessionFinishDelegate.java sync/repositories/delegates/DeferredRepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionBeginDelegate.java sync/repositories/delegates/RepositorySessionCleanDelegate.java sync/repositories/delegates/RepositorySessionCreationDelegate.java sync/repositories/delegates/RepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/RepositorySessionFinishDelegate.java sync/repositories/delegates/RepositorySessionGuidsSinceDelegate.java sync/repositories/delegates/RepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionWipeDelegate.java sync/repositories/domain/BookmarkRecord.java sync/repositories/domain/BookmarkRecordFactory.java sync/repositories/domain/ClientRecord.java sync/repositories/domain/ClientRecordFactory.java sync/repositories/domain/FormHistoryRecord.java sync/repositories/domain/HistoryRecord.java sync/repositories/domain/HistoryRecordFactory.java sync/repositories/domain/PasswordRecord.java sync/repositories/domain/Record.java sync/repositories/domain/TabsRecord.java sync/repositories/HashSetStoreTracker.java sync/repositories/HistoryRepository.java sync/repositories/IdentityRecordFactory.java sync/repositories/InactiveSessionException.java sync/repositories/InvalidBookmarkTypeException.java sync/repositories/InvalidRequestException.java sync/repositories/InvalidSessionTransitionException.java sync/repositories/MultipleRecordsForGuidException.java sync/repositories/NoContentProviderException.java sync/repositories/NoGuidForIdException.java sync/repositories/NoStoreDelegateException.java sync/repositories/NullCursorException.java sync/repositories/ParentNotFoundException.java sync/repositories/ProfileDatabaseException.java sync/repositories/RecordFactory.java sync/repositories/RecordFilter.java sync/repositories/Repository.java sync/repositories/RepositorySession.java sync/repositories/RepositorySessionBundle.java sync/repositories/Server11Repository.java sync/repositories/Server11RepositorySession.java sync/repositories/StoreTracker.java sync/repositories/StoreTrackingRepositorySession.java sync/setup/activities/AccountActivity.java sync/setup/activities/ActivityUtils.java sync/setup/activities/SetupFailureActivity.java sync/setup/activities/SetupSuccessActivity.java sync/setup/activities/SetupSyncActivity.java sync/setup/Constants.java sync/setup/InvalidSyncKeyException.java sync/setup/SyncAccounts.java sync/setup/SyncAuthenticatorService.java sync/stage/AbstractNonRepositorySyncStage.java sync/stage/AndroidBrowserBookmarksServerSyncStage.java sync/stage/AndroidBrowserHistoryServerSyncStage.java sync/stage/CheckPreconditionsStage.java sync/stage/CompletedStage.java sync/stage/EnsureClusterURLStage.java sync/stage/EnsureCrypto5KeysStage.java sync/stage/FennecTabsServerSyncStage.java sync/stage/FetchInfoCollectionsStage.java sync/stage/FetchMetaGlobalStage.java sync/stage/FormHistoryServerSyncStage.java sync/stage/GlobalSyncStage.java sync/stage/NoSuchStageException.java sync/stage/NoSyncIDException.java sync/stage/PasswordsServerSyncStage.java sync/stage/ServerSyncStage.java sync/stage/SyncClientsEngineStage.java sync/StubActivity.java sync/syncadapter/SyncAdapter.java sync/syncadapter/SyncService.java sync/SyncConfiguration.java sync/SyncConfigurationException.java sync/SyncException.java sync/synchronizer/ConcurrentRecordConsumer.java sync/synchronizer/RecordConsumer.java sync/synchronizer/RecordsChannel.java sync/synchronizer/RecordsChannelDelegate.java sync/synchronizer/RecordsConsumerDelegate.java sync/synchronizer/SerialRecordConsumer.java sync/synchronizer/SessionNotBegunException.java sync/synchronizer/Synchronizer.java sync/synchronizer/SynchronizerDelegate.java sync/synchronizer/SynchronizerSession.java sync/synchronizer/SynchronizerSessionDelegate.java sync/synchronizer/UnbundleError.java sync/synchronizer/UnexpectedSessionException.java sync/SynchronizerConfiguration.java sync/SynchronizerConfigurations.java sync/ThreadPool.java sync/UnexpectedJSONException.java sync/UnknownSynchronizerConfigurationVersionException.java sync/Utils.java +sync/AlreadySyncingException.java sync/CollectionKeys.java sync/CommandProcessor.java sync/CommandRunner.java sync/CredentialsSource.java sync/crypto/CryptoException.java sync/crypto/CryptoInfo.java sync/crypto/HKDF.java sync/crypto/HMACVerificationException.java sync/crypto/KeyBundle.java sync/crypto/MissingCryptoInputException.java sync/crypto/NoKeyBundleException.java sync/crypto/PersistedCrypto5Keys.java sync/CryptoRecord.java sync/DelayedWorkTracker.java sync/delegates/ClientsDataDelegate.java sync/delegates/FreshStartDelegate.java sync/delegates/GlobalSessionCallback.java sync/delegates/InfoCollectionsDelegate.java sync/delegates/KeyUploadDelegate.java sync/delegates/MetaGlobalDelegate.java sync/delegates/WipeServerDelegate.java sync/EngineSettings.java sync/ExtendedJSONObject.java sync/GlobalSession.java sync/HTTPFailureException.java sync/InfoCollections.java sync/jpake/BigIntegerHelper.java sync/jpake/Gx3OrGx4IsZeroOrOneException.java sync/jpake/IncorrectZkpException.java sync/jpake/JPakeClient.java sync/jpake/JPakeCrypto.java sync/jpake/JPakeJson.java sync/jpake/JPakeNoActivePairingException.java sync/jpake/JPakeNumGenerator.java sync/jpake/JPakeNumGeneratorRandom.java sync/jpake/JPakeParty.java sync/jpake/JPakeRequest.java sync/jpake/JPakeRequestDelegate.java sync/jpake/JPakeResponse.java sync/jpake/stage/CompleteStage.java sync/jpake/stage/ComputeFinalStage.java sync/jpake/stage/ComputeKeyVerificationStage.java sync/jpake/stage/ComputeStepOneStage.java sync/jpake/stage/ComputeStepTwoStage.java sync/jpake/stage/DecryptDataStage.java sync/jpake/stage/DeleteChannel.java sync/jpake/stage/GetChannelStage.java sync/jpake/stage/GetRequestStage.java sync/jpake/stage/JPakeStage.java sync/jpake/stage/PutRequestStage.java sync/jpake/stage/VerifyPairingStage.java sync/jpake/Zkp.java sync/KeyBundleProvider.java sync/Logger.java sync/MetaGlobal.java sync/MetaGlobalException.java sync/MetaGlobalMissingEnginesException.java sync/MetaGlobalNotSetException.java sync/middleware/Crypto5MiddlewareRepository.java sync/middleware/Crypto5MiddlewareRepositorySession.java sync/middleware/MiddlewareRepository.java sync/middleware/MiddlewareRepositorySession.java sync/net/BaseResource.java sync/net/CompletedEntity.java sync/net/ConnectionMonitorThread.java sync/net/HandleProgressException.java sync/net/HttpResponseObserver.java sync/net/Resource.java sync/net/ResourceDelegate.java sync/net/SyncResourceDelegate.java sync/net/SyncResponse.java sync/net/SyncStorageCollectionRequest.java sync/net/SyncStorageCollectionRequestDelegate.java sync/net/SyncStorageRecordRequest.java sync/net/SyncStorageRequest.java sync/net/SyncStorageRequestDelegate.java sync/net/SyncStorageRequestIncrementalDelegate.java sync/net/SyncStorageResponse.java sync/net/TLSSocketFactory.java sync/net/WBOCollectionRequestDelegate.java sync/net/WBORequestDelegate.java sync/NoCollectionKeysSetException.java sync/NodeAuthenticationException.java sync/NonArrayJSONException.java sync/NonObjectJSONException.java sync/NullClusterURLException.java sync/PersistedMetaGlobal.java sync/PrefsSource.java sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java sync/repositories/android/AndroidBrowserBookmarksRepository.java sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java sync/repositories/android/AndroidBrowserHistoryDataAccessor.java sync/repositories/android/AndroidBrowserHistoryDataExtender.java sync/repositories/android/AndroidBrowserHistoryRepository.java sync/repositories/android/AndroidBrowserHistoryRepositorySession.java sync/repositories/android/AndroidBrowserRepository.java sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java sync/repositories/android/AndroidBrowserRepositorySession.java sync/repositories/android/BookmarksDeletionManager.java sync/repositories/android/BookmarksInsertionManager.java sync/repositories/android/BrowserContractHelpers.java sync/repositories/android/CachedSQLiteOpenHelper.java sync/repositories/android/ClientsDatabase.java sync/repositories/android/ClientsDatabaseAccessor.java sync/repositories/android/FennecControlHelper.java sync/repositories/android/FennecTabsRepository.java sync/repositories/android/FormHistoryRepositorySession.java sync/repositories/android/PasswordsRepositorySession.java sync/repositories/android/RepoUtils.java sync/repositories/BookmarkNeedsReparentingException.java sync/repositories/BookmarksRepository.java sync/repositories/ConstrainedServer11Repository.java sync/repositories/delegates/DeferrableRepositorySessionCreationDelegate.java sync/repositories/delegates/DeferredRepositorySessionBeginDelegate.java sync/repositories/delegates/DeferredRepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/DeferredRepositorySessionFinishDelegate.java sync/repositories/delegates/DeferredRepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionBeginDelegate.java sync/repositories/delegates/RepositorySessionCleanDelegate.java sync/repositories/delegates/RepositorySessionCreationDelegate.java sync/repositories/delegates/RepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/RepositorySessionFinishDelegate.java sync/repositories/delegates/RepositorySessionGuidsSinceDelegate.java sync/repositories/delegates/RepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionWipeDelegate.java sync/repositories/domain/BookmarkRecord.java sync/repositories/domain/BookmarkRecordFactory.java sync/repositories/domain/ClientRecord.java sync/repositories/domain/ClientRecordFactory.java sync/repositories/domain/FormHistoryRecord.java sync/repositories/domain/HistoryRecord.java sync/repositories/domain/HistoryRecordFactory.java sync/repositories/domain/PasswordRecord.java sync/repositories/domain/Record.java sync/repositories/domain/TabsRecord.java sync/repositories/HashSetStoreTracker.java sync/repositories/HistoryRepository.java sync/repositories/IdentityRecordFactory.java sync/repositories/InactiveSessionException.java sync/repositories/InvalidBookmarkTypeException.java sync/repositories/InvalidRequestException.java sync/repositories/InvalidSessionTransitionException.java sync/repositories/MultipleRecordsForGuidException.java sync/repositories/NoContentProviderException.java sync/repositories/NoGuidForIdException.java sync/repositories/NoStoreDelegateException.java sync/repositories/NullCursorException.java sync/repositories/ParentNotFoundException.java sync/repositories/ProfileDatabaseException.java sync/repositories/RecordFactory.java sync/repositories/RecordFilter.java sync/repositories/Repository.java sync/repositories/RepositorySession.java sync/repositories/RepositorySessionBundle.java sync/repositories/Server11Repository.java sync/repositories/Server11RepositorySession.java sync/repositories/StoreTracker.java sync/repositories/StoreTrackingRepositorySession.java sync/setup/activities/AccountActivity.java sync/setup/activities/ActivityUtils.java sync/setup/activities/SetupFailureActivity.java sync/setup/activities/SetupSuccessActivity.java sync/setup/activities/SetupSyncActivity.java sync/setup/Constants.java sync/setup/InvalidSyncKeyException.java sync/setup/SyncAccounts.java sync/setup/SyncAuthenticatorService.java sync/stage/AbstractNonRepositorySyncStage.java sync/stage/AndroidBrowserBookmarksServerSyncStage.java sync/stage/AndroidBrowserHistoryServerSyncStage.java sync/stage/CheckPreconditionsStage.java sync/stage/CompletedStage.java sync/stage/EnsureClusterURLStage.java sync/stage/EnsureCrypto5KeysStage.java sync/stage/FennecTabsServerSyncStage.java sync/stage/FetchInfoCollectionsStage.java sync/stage/FetchMetaGlobalStage.java sync/stage/FormHistoryServerSyncStage.java sync/stage/GlobalSyncStage.java sync/stage/NoSuchStageException.java sync/stage/NoSyncIDException.java sync/stage/PasswordsServerSyncStage.java sync/stage/ServerSyncStage.java sync/stage/SyncClientsEngineStage.java sync/StubActivity.java sync/syncadapter/SyncAdapter.java sync/syncadapter/SyncService.java sync/SyncConfiguration.java sync/SyncConfigurationException.java sync/SyncException.java sync/synchronizer/ConcurrentRecordConsumer.java sync/synchronizer/RecordConsumer.java sync/synchronizer/RecordsChannel.java sync/synchronizer/RecordsChannelDelegate.java sync/synchronizer/RecordsConsumerDelegate.java sync/synchronizer/SerialRecordConsumer.java sync/synchronizer/SessionNotBegunException.java sync/synchronizer/Synchronizer.java sync/synchronizer/SynchronizerDelegate.java sync/synchronizer/SynchronizerSession.java sync/synchronizer/SynchronizerSessionDelegate.java sync/synchronizer/UnbundleError.java sync/synchronizer/UnexpectedSessionException.java sync/SynchronizerConfiguration.java sync/SynchronizerConfigurations.java sync/ThreadPool.java sync/UnexpectedJSONException.java sync/UnknownSynchronizerConfigurationVersionException.java sync/Utils.java From ad538f6a375370fa4c8b8969f4d84883767bc2b3 Mon Sep 17 00:00:00 2001 From: Richard Newman Date: Mon, 30 Apr 2012 13:40:34 -0700 Subject: [PATCH 028/159] Bug 749857 - Don't upload history records without URI or visits. r=liuche, a=blocking-fennec --- .../sync/repositories/android/RepoUtils.java | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/mobile/android/base/sync/repositories/android/RepoUtils.java b/mobile/android/base/sync/repositories/android/RepoUtils.java index daa4a2ec37b0..9c00af623a98 100644 --- a/mobile/android/base/sync/repositories/android/RepoUtils.java +++ b/mobile/android/base/sync/repositories/android/RepoUtils.java @@ -119,20 +119,42 @@ public class RepoUtils { } } - //Create a HistoryRecord object from a cursor on a row with a Moz History record in it + /** + * Create a HistoryRecord object from a cursor row. + * + * @return a HistoryRecord, or null if this row would produce + * an invalid record (e.g., with a null URI or no visits). + */ public static HistoryRecord historyFromMirrorCursor(Cursor cur) { + final String guid = getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); + if (guid == null) { + Logger.debug(LOG_TAG, "Skipping history record with null GUID."); + return null; + } - String guid = getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); - String collection = "history"; - long lastModified = getLongFromCursor(cur, BrowserContract.SyncColumns.DATE_MODIFIED); - boolean deleted = getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1 ? true : false; - HistoryRecord rec = new HistoryRecord(guid, collection, lastModified, deleted); + final String historyURI = getStringFromCursor(cur, BrowserContract.History.URL); + if (historyURI == null || (historyURI.length() == 0)) { + Logger.debug(LOG_TAG, "Skipping history record " + guid + " with null or empty URI."); + return null; + } - rec.title = getStringFromCursor(cur, BrowserContract.History.TITLE); - rec.histURI = getStringFromCursor(cur, BrowserContract.History.URL); - rec.androidID = getLongFromCursor(cur, BrowserContract.History._ID); + final long visitCount = getLongFromCursor(cur, BrowserContract.History.VISITS); + if (visitCount <= 0) { + Logger.debug(LOG_TAG, "Skipping history record " + guid + " with <= 0 visit count."); + return null; + } + + final String collection = "history"; + final long lastModified = getLongFromCursor(cur, BrowserContract.SyncColumns.DATE_MODIFIED); + final boolean deleted = getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1 ? true : false; + + final HistoryRecord rec = new HistoryRecord(guid, collection, lastModified, deleted); + + rec.androidID = getLongFromCursor(cur, BrowserContract.History._ID); rec.fennecDateVisited = getLongFromCursor(cur, BrowserContract.History.DATE_LAST_VISITED); - rec.fennecVisitCount = getLongFromCursor(cur, BrowserContract.History.VISITS); + rec.fennecVisitCount = visitCount; + rec.histURI = historyURI; + rec.title = getStringFromCursor(cur, BrowserContract.History.TITLE); return logHistory(rec); } From 1f645ea274c02a5d2c00c5602635256a4851bcfd Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 30 Apr 2012 13:51:55 -0700 Subject: [PATCH 029/159] Bug 750476 - Fix comment in gc/Barrier.h (r=NPOTB) --- js/src/gc/Barrier.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 552db76d6895..65ce7478d072 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -140,12 +140,10 @@ * and jsid, respectively. * * One additional note: not all object writes need to be barriered. Writes to - * newly allocated objects do not need a barrier as long as the GC is not - * allowed to run in between the allocation and the write. In these cases, we - * use the "obj->field.init(value)" method instead of "obj->field = value". - * We use the init naming idiom in many places to signify that a field is being - * assigned for the first time, and that no GCs have taken place between the - * object allocation and the assignment. + * newly allocated objects do not need a pre-barrier. In these cases, we use + * the "obj->field.init(value)" method instead of "obj->field = value". We use + * the init naming idiom in many places to signify that a field is being + * assigned for the first time. */ struct JSXML; From 3eb6a4c206c5de4e71af2a30f664657dae51d9f2 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 19 Apr 2012 18:18:31 +1200 Subject: [PATCH 030/159] b=634719 Add a helper to get the nsDragService r=roc --HG-- extra : rebase_source : cd811aee525b1675b47573e313f6804112d78ef0 --- widget/gtk2/nsDragService.cpp | 9 +++++++++ widget/gtk2/nsDragService.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/widget/gtk2/nsDragService.cpp b/widget/gtk2/nsDragService.cpp index b166b8245717..a67ff82018f4 100644 --- a/widget/gtk2/nsDragService.cpp +++ b/widget/gtk2/nsDragService.cpp @@ -179,6 +179,15 @@ nsDragService::~nsDragService() NS_IMPL_ISUPPORTS_INHERITED2(nsDragService, nsBaseDragService, nsIDragSessionGTK, nsIObserver) +/* static */ nsDragService* +nsDragService::GetInstance() +{ + static const nsIID iid = NS_DRAGSERVICE_CID; + nsCOMPtr dragService = do_GetService(iid); + return static_cast(dragService.get()); + // We rely on XPCOM keeping a reference to the service. +} + // nsIObserver NS_IMETHODIMP diff --git a/widget/gtk2/nsDragService.h b/widget/gtk2/nsDragService.h index 1a073572419a..0f9ab6bbdcbf 100644 --- a/widget/gtk2/nsDragService.h +++ b/widget/gtk2/nsDragService.h @@ -98,6 +98,8 @@ public: NS_IMETHOD TargetSetTimeCallback (nsIDragSessionGTKTimeCB aCallback); + static nsDragService* GetInstance(); + // END PUBLIC API // These methods are public only so that they can be called from functions From c42f5a38872e348884c3076989438b074b1c8f8d Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 19 Apr 2012 18:18:31 +1200 Subject: [PATCH 031/159] b=497498 schedule event dispatch in response to GTK drag target signals to avoid running the event loop at unexpected times r=roc --HG-- extra : rebase_source : 881ad7c0efa85174347059a9f53b3a5bd4c76696 --- widget/gtk2/nsDragService.cpp | 238 ++++++++++++++++++++++++++- widget/gtk2/nsDragService.h | 91 ++++++++++- widget/gtk2/nsWindow.cpp | 299 +++++++--------------------------- widget/gtk2/nsWindow.h | 35 +--- 4 files changed, 389 insertions(+), 274 deletions(-) diff --git a/widget/gtk2/nsDragService.cpp b/widget/gtk2/nsDragService.cpp index a67ff82018f4..93e97c14688c 100644 --- a/widget/gtk2/nsDragService.cpp +++ b/widget/gtk2/nsDragService.cpp @@ -127,6 +127,7 @@ invisibleSourceDragDataGet(GtkWidget *aWidget, gpointer aData); nsDragService::nsDragService() + : mTaskSource(0) { // We have to destroy the hidden widget before the event loop stops // running. @@ -162,9 +163,6 @@ nsDragService::nsDragService() sDragLm = PR_NewLogModule("nsDragService"); PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::nsDragService")); mGrabWidget = 0; - mTargetWidget = 0; - mTargetDragContext = 0; - mTargetTime = 0; mCanDrop = false; mTargetDragDataReceived = false; mTargetDragData = 0; @@ -174,6 +172,9 @@ nsDragService::nsDragService() nsDragService::~nsDragService() { PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::~nsDragService")); + if (mTaskSource) + g_source_remove(mTaskSource); + } NS_IMPL_ISUPPORTS_INHERITED2(nsDragService, nsBaseDragService, @@ -1131,7 +1132,8 @@ nsDragService::GetTargetDragData(GdkAtom aFlavor) { PR_LOG(sDragLm, PR_LOG_DEBUG, ("getting data flavor %d\n", aFlavor)); PR_LOG(sDragLm, PR_LOG_DEBUG, ("mLastWidget is %p and mLastContext is %p\n", - mTargetWidget, mTargetDragContext)); + mTargetWidget.get(), + mTargetDragContext.get())); // reset our target data areas TargetResetData(); gtk_drag_get_data(mTargetWidget, mTargetDragContext, aFlavor, mTargetTime); @@ -1702,3 +1704,231 @@ invisibleSourceDragEnd(GtkWidget *aWidget, dragService->SourceEndDragSession(aContext, MOZ_GTK_DRAG_RESULT_SUCCESS); } +// The following methods handle responding to GTK drag destination signals and +// tracking state between these signals. +// +// In general, GTK does not expect us to run the event loop while handling its +// drag destination signals, however our drag event handlers may run the +// event loop, most often to fetch information about the drag data. +// +// GTK, for example, uses the return value from drag-motion signals to +// determine whether drag-leave signals should be sent. If an event loop is +// run during drag-motion the XdndLeave message can get processed but when GTK +// receives the message it does not yet know that it needs to send the +// drag-leave signal to our widget. +// +// After a drag-drop signal, we need to reply with gtk_drag_finish(). +// However, gtk_drag_finish should happen after the drag-drop signal handler +// returns so that when the Motif drag protocol is used, the +// XmTRANSFER_SUCCESS during gtk_drag_finish is sent after the XmDROP_START +// reply sent on return from the drag-drop signal handler. +// +// Therefore we reply to the signals immediately and schedule a task to +// dispatch the Gecko events, which may run the event loop. +// +// Action in response to drag-leave signals is also delayed until the event +// loop runs again so that we find out whether a drag-drop signal follows. +// +// A single task is scheduled to manage responses to all three GTK signals. +// If further signals are received while the task is scheduled, the scheduled +// response is updated, sometimes effectively compressing successive signals. +// +// No Gecko drag events are dispatched (during nested event loops) while other +// Gecko drag events are in flight. This helps event handlers that may not +// expect nested events, while accessing an event's dataTransfer for example. + +gboolean +nsDragService::ScheduleMotionEvent(nsWindow *aWindow, + GdkDragContext *aDragContext, + nsIntPoint aWindowPoint, guint aTime) +{ + if (mScheduledTask == eDragTaskMotion) { + // The drag source has sent another motion message before we've + // replied to the previous. That shouldn't happen with Xdnd. The + // spec for Motif drags is less clear, but we'll just update the + // scheduled task with the new position reply only to the most + // recent message. + NS_WARNING("Drag Motion message received before previous reply was sent"); + } + + // Returning TRUE means we'll reply with a status message, unless we first + // get a leave. + return Schedule(eDragTaskMotion, aWindow, aDragContext, + aWindowPoint, aTime); +} + +void +nsDragService::ScheduleLeaveEvent() +{ + // We don't know at this stage whether a drop signal will immediately + // follow. If the drop signal gets sent it will happen before we return + // to the main loop and the scheduled leave task will be replaced. + if (!Schedule(eDragTaskLeave, nsnull, NULL, nsIntPoint(), 0)) { + NS_WARNING("Drag leave after drop"); + } +} + +gboolean +nsDragService::ScheduleDropEvent(nsWindow *aWindow, + GdkDragContext *aDragContext, + nsIntPoint aWindowPoint, guint aTime) +{ + if (!Schedule(eDragTaskDrop, aWindow, + aDragContext, aWindowPoint, aTime)) { + NS_WARNING("Additional drag drop ignored"); + return FALSE; + } + + SetDragEndPoint(aWindowPoint + aWindow->WidgetToScreenOffset()); + + // We'll reply with gtk_drag_finish(). + return TRUE; +} + +gboolean +nsDragService::Schedule(DragTask aTask, nsWindow *aWindow, + GdkDragContext *aDragContext, + nsIntPoint aWindowPoint, guint aTime) +{ + // If we haven't yet run a scheduled drop task, just say that + // we are not ready to receive another drop. + if (mScheduledTask == eDragTaskDrop) + return FALSE; + + // If there is an existing leave or motion task scheduled, then that + // will be replaced. When the new task is run, it will dispatch + // any necessary leave or motion events. + + mScheduledTask = aTask; + mPendingWindow = aWindow; + mPendingDragContext = aDragContext; + mPendingWindowPoint = aWindowPoint; + mPendingTime = aTime; + + if (!mTaskSource) { + // High priority is used here because the native events involved have + // already waited at default priority. Perhaps a lower than default + // priority could be used for motion tasks because there is a chance + // that a leave or drop is waiting, but managing different priorities + // may not be worth the effort. Motion tasks shouldn't queue up as + // they should be throttled based on replies. + mTaskSource = + g_idle_add_full(G_PRIORITY_HIGH, TaskDispatchCallback, this, NULL); + } + return TRUE; +} + +gboolean +nsDragService::TaskDispatchCallback(gpointer data) +{ + nsRefPtr dragService = static_cast(data); + return dragService->RunScheduledTask(); +} + +gboolean +nsDragService::RunScheduledTask() +{ + if (mTargetWindow && mTargetWindow != mPendingWindow) { + mTargetWindow->OnDragLeave(); + } + + // It is possible that the pending state has been updated during dispatch + // of the leave event. That's fine. + + // Now we collect the pending state because, from this point on, we want + // to use the same state for all events dispatched. All state is updated + // so that when other tasks are scheduled during dispatch here, this + // task is considered to have already been run. + bool positionHasChanged = + mPendingWindow != mTargetWindow || + mPendingWindowPoint != mTargetWindowPoint; + DragTask task = mScheduledTask; + mScheduledTask = eDragTaskNone; + mTargetWindow = mPendingWindow.forget(); + mTargetWindowPoint = mPendingWindowPoint; + + if (task == eDragTaskLeave) { + // Nothing more to do + // Returning false removes the task source from the event loop. + mTaskSource = 0; + return FALSE; + } + + // This may be the start of a destination drag session. + StartDragSession(); + + // mTargetWidget may be NULL if the window has been destroyed. + // (The leave event is not scheduled if a drop task is still scheduled.) + // We still reply appropriately to indicate that the drop will or didn't + // succeeed. + mTargetWidget = mTargetWindow->GetMozContainerWidget(); + mTargetDragContext.steal(mPendingDragContext); + mTargetTime = mPendingTime; + + // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model + // (as at 27 December 2010) indicates that a "drop" event should only be + // fired (at the current target element) if the current drag operation is + // not none. The current drag operation will only be set to a non-none + // value during a "dragover" event. + // + // If the user has ended the drag before any dragover events have been + // sent, then the spec recommends skipping the drop (because the current + // drag operation is none). However, here we assume that, by releasing + // the mouse button, the user has indicated that they want to drop, so we + // proceed with the drop where possible. + // + // In order to make the events appear to content in the same way as if the + // spec is being followed we make sure to dispatch a "dragover" event with + // appropriate coordinates and check canDrop before the "drop" event. + // + // When the Xdnd protocol is used for source/destination communication (as + // should be the case with GTK source applications) a dragover event + // should have already been sent during the drag-motion signal, which + // would have already been received because XdndDrop messages do not + // contain a position. However, we can't assume the same when the Motif + // protocol is used. + if (task == eDragTaskMotion || positionHasChanged) { + nsWindow::UpdateDragStatus(mTargetDragContext, this); + mTargetWindow-> + DispatchDragMotionEvents(this, mTargetWindowPoint, mTargetTime); + + if (task == eDragTaskMotion) { + // Reply to tell the source whether we can drop and what + // action would be taken. + TargetEndDragMotion(mTargetWidget, mTargetDragContext, mTargetTime); + } + } + + if (task == eDragTaskDrop) { + gboolean success = mTargetWindow-> + DispatchDragDropEvent(this, mTargetWindowPoint, mTargetTime); + + // Perhaps we should set the del parameter to TRUE when the drag + // action is move, but we don't know whether the data was successfully + // transferred. + gtk_drag_finish(mTargetDragContext, success, + /* del = */ FALSE, mTargetTime); + + // This drag is over, so clear out our reference to the previous + // window. + mTargetWindow = nsnull; + // Make sure to end the drag session. If this drag started in a + // different app, we won't get a drag_end signal to end it from. + EndDragSession(true); + } + + // We're done with the drag context. + mTargetWidget = NULL; + mTargetDragContext = NULL; + + // If we got another drag signal while running the sheduled task, that + // must have happened while running a nested event loop. Leave the task + // source on the event loop. + if (mScheduledTask != eDragTaskNone) + return TRUE; + + // We have no task scheduled. + // Returning false removes the task source from the event loop. + mTaskSource = 0; + return FALSE; +} diff --git a/widget/gtk2/nsDragService.h b/widget/gtk2/nsDragService.h index 0f9ab6bbdcbf..a883667b9eb5 100644 --- a/widget/gtk2/nsDragService.h +++ b/widget/gtk2/nsDragService.h @@ -46,6 +46,30 @@ #include "nsIObserver.h" #include +class nsWindow; + +#ifndef HAVE_NSGOBJECTREFTRAITS +#define HAVE_NSGOBJECTREFTRAITS +template +class nsGObjectRefTraits : public nsPointerRefTraits { +public: + static void Release(T *aPtr) { g_object_unref(aPtr); } + static void AddRef(T *aPtr) { g_object_ref(aPtr); } +}; +#endif + +#ifndef HAVE_NSAUTOREFTRAITS_GTKWIDGET +#define HAVE_NSAUTOREFTRAITS_GTKWIDGET +template <> +class nsAutoRefTraits : public nsGObjectRefTraits { }; +#endif + +#ifndef HAVE_NSAUTOREFTRAITS_GDKDRAGCONTEXT +#define HAVE_NSAUTOREFTRAITS_GDKDRAGCONTEXT +template <> +class nsAutoRefTraits : + public nsGObjectRefTraits { }; +#endif /** * Native GTK DragService wrapper @@ -100,6 +124,25 @@ public: static nsDragService* GetInstance(); + // Methods called from nsWindow to handle responding to GTK drag + // destination signals + + gboolean ScheduleMotionEvent(nsWindow *aWindow, + GdkDragContext *aDragContext, + nsIntPoint aWindowPoint, + guint aTime); + void ScheduleLeaveEvent(); + gboolean ScheduleDropEvent(nsWindow *aWindow, + GdkDragContext *aDragContext, + nsIntPoint aWindowPoint, + guint aTime); + + nsWindow* GetMostRecentDestWindow() + { + return mScheduledTask == eDragTaskNone ? mTargetWindow + : mPendingWindow; + } + // END PUBLIC API // These methods are public only so that they can be called from functions @@ -118,14 +161,47 @@ public: private: - // target side vars + // mScheduledTask indicates what signal has been received from GTK and + // so what needs to be dispatched when the scheduled task is run. It is + // eDragTaskNone when there is no task scheduled (but the + // previous task may still not have finished running). + enum DragTask { + eDragTaskNone, + eDragTaskMotion, + eDragTaskLeave, + eDragTaskDrop + }; + DragTask mScheduledTask; + // mTaskSource is the GSource id for the task that is either scheduled + // or currently running. It is 0 if no task is scheduled or running. + guint mTaskSource; - // the last widget that was the target of a drag - GtkWidget *mTargetWidget; - GdkDragContext *mTargetDragContext; + // target/destination side vars + // These variables keep track of the state of the current drag. + + // mPendingWindow, mPendingWindowPoint, mPendingDragContext, and + // mPendingTime, carry information from the GTK signal that will be used + // when the scheduled task is run. mPendingWindow and mPendingDragContext + // will be NULL if the scheduled task is eDragTaskLeave. + nsRefPtr mPendingWindow; + nsIntPoint mPendingWindowPoint; + nsCountedRef mPendingDragContext; + guint mPendingTime; + + // mTargetWindow and mTargetWindowPoint record the position of the last + // eDragTaskMotion or eDragTaskDrop task that was run or is still running. + // mTargetWindow is cleared once the drag has completed or left. + nsRefPtr mTargetWindow; + nsIntPoint mTargetWindowPoint; + // mTargetWidget and mTargetDragContext are set only while dispatching + // motion or drop events. mTime records the corresponding timestamp. + nsCountedRef mTargetWidget; + nsCountedRef mTargetDragContext; guint mTargetTime; + // is it OK to drop on us? bool mCanDrop; + // have we received our drag data? bool mTargetDragDataReceived; // last data received and its length @@ -161,6 +237,13 @@ private: PRInt32 aYOffset, const nsIntRect &dragRect); + gboolean Schedule(DragTask aTask, nsWindow *aWindow, + GdkDragContext *aDragContext, + nsIntPoint aWindowPoint, guint aTime); + + // Callback for g_idle_add_full() to run mScheduledTask. + static gboolean TaskDispatchCallback(gpointer data); + gboolean RunScheduledTask(); }; #endif // nsDragService_h__ diff --git a/widget/gtk2/nsWindow.cpp b/widget/gtk2/nsWindow.cpp index c88fe0435f54..f5d9406a2f18 100644 --- a/widget/gtk2/nsWindow.cpp +++ b/widget/gtk2/nsWindow.cpp @@ -272,9 +272,6 @@ static void drag_data_received_event_cb(GtkWidget *aWidget, /* initialization static functions */ static nsresult initialize_prefs (void); -// this is the last window that had a drag event happen on it. -nsWindow *nsWindow::sLastDragMotionWindow = NULL; - // Time of the last button release event. We use it to detect when the // drag ended before we could properly setup drag and drop. static guint32 sLastButtonReleaseTime = 0; @@ -433,9 +430,6 @@ nsWindow::nsWindow() nsWindow::~nsWindow() { LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this)); - if (sLastDragMotionWindow == this) { - sLastDragMotionWindow = NULL; - } delete[] mTransparencyBitmap; mTransparencyBitmap = nsnull; @@ -687,6 +681,11 @@ nsWindow::Destroy(void) gRollupListener = nsnull; } + nsDragService *dragService = nsDragService::GetInstance(); + if (this == dragService->GetMostRecentDestWindow()) { + dragService->ScheduleLeaveEvent(); + } + NativeShow(false); if (mIMModule) { @@ -715,11 +714,6 @@ nsWindow::Destroy(void) // the surface after its X Window. mThebesSurface = nsnull; - if (mDragLeaveTimer) { - mDragLeaveTimer->Cancel(); - mDragLeaveTimer = nsnull; - } - GtkWidget *owningWidget = GetMozContainerWidget(); if (mShell) { gtk_widget_destroy(mShell); @@ -3309,35 +3303,6 @@ nsWindow::ThemeChanged() } } -void -nsWindow::CheckNeedDragLeave(nsWindow* aInnerMostWidget, - nsIDragService* aDragService, - GdkDragContext *aDragContext, - nscoord aX, nscoord aY) -{ - // check to see if there was a drag motion window already in place - if (sLastDragMotionWindow) { - // same as the last window so no need for dragleave event - if (sLastDragMotionWindow == aInnerMostWidget) { - UpdateDragStatus(aDragContext, aDragService); - return; - } - - // send a dragleave event to the last window that got a motion event - nsRefPtr kungFuDeathGrip = sLastDragMotionWindow; - sLastDragMotionWindow->OnDragLeave(); - } - - // Make sure that the drag service knows we're now dragging - aDragService->StartDragSession(); - - // update our drag status - UpdateDragStatus(aDragContext, aDragService); - - // set the last window to the innerMostWidget - sLastDragMotionWindow = aInnerMostWidget; -} - void nsWindow::DispatchDragMotionEvents(nsDragService *aDragService, const nsIntPoint& aWindowPoint, guint aTime) @@ -3386,170 +3351,6 @@ nsWindow::DispatchDragEvent(PRUint32 aMsg, const nsIntPoint& aRefPoint, DispatchEvent(&event, status); } -gboolean -nsWindow::OnDragMotionEvent(GtkWidget *aWidget, - GdkDragContext *aDragContext, - gint aX, - gint aY, - guint aTime, - gpointer aData) -{ - LOGDRAG(("nsWindow::OnDragMotionSignal\n")); - - // get our drag context - nsCOMPtr dragService = do_GetService(kCDragServiceCID); - nsDragService *dragServiceGTK = - static_cast(dragService.get()); - - // first, figure out which internal widget this drag motion actually - // happened on - nscoord retx = 0; - nscoord rety = 0; - - GdkWindow *innerWindow = get_inner_gdk_window(gtk_widget_get_window(aWidget), aX, aY, - &retx, &rety); - nsRefPtr innerMostWidget = get_window_for_gdk_window(innerWindow); - - if (!innerMostWidget) - innerMostWidget = this; - - // clear any drag leave timer that might be pending so that it - // doesn't get processed when we actually go out to get data. - if (mDragLeaveTimer) { - mDragLeaveTimer->Cancel(); - mDragLeaveTimer = nsnull; - } - - CheckNeedDragLeave(innerMostWidget, dragService, aDragContext, retx, rety); - - // update the drag context - dragServiceGTK->TargetSetLastContext(aWidget, aDragContext, aTime); - - innerMostWidget-> - DispatchDragMotionEvents(dragServiceGTK, nsIntPoint(retx, rety), aTime); - - // Reply to tell the source whether we can drop and what action would be - // taken. - dragServiceGTK->TargetEndDragMotion(aWidget, aDragContext, aTime); - - // and unset our context - dragServiceGTK->TargetSetLastContext(0, 0, 0); - - return TRUE; -} - -void -nsWindow::OnDragLeaveEvent(GtkWidget *aWidget, - GdkDragContext *aDragContext, - guint aTime, - gpointer aData) -{ - // XXX Do we want to pass this on only if the event's subwindow is null? - - LOGDRAG(("nsWindow::OnDragLeaveSignal(%p)\n", (void*)this)); - - if (mDragLeaveTimer) { - return; - } - - // create a fast timer - we're delaying the drag leave until the - // next mainloop in hopes that we might be able to get a drag drop - // signal - mDragLeaveTimer = do_CreateInstance("@mozilla.org/timer;1"); - NS_ASSERTION(mDragLeaveTimer, "Failed to create drag leave timer!"); - // fire this baby asafp, but not too quickly... see bug 216800 ;-) - mDragLeaveTimer->InitWithFuncCallback(DragLeaveTimerCallback, - (void *)this, - 20, nsITimer::TYPE_ONE_SHOT); -} - -gboolean -nsWindow::OnDragDropEvent(GtkWidget *aWidget, - GdkDragContext *aDragContext, - gint aX, - gint aY, - guint aTime, - gpointer aData) - -{ - LOGDRAG(("nsWindow::OnDragDropSignal\n")); - - // get our drag context - nsCOMPtr dragService = do_GetService(kCDragServiceCID); - nsDragService *dragServiceGTK = static_cast(dragService.get()); - - dragServiceGTK->SetDragEndPoint(nsIntPoint(aX, aY) + WidgetToScreenOffset()); - - nscoord retx = 0; - nscoord rety = 0; - - GdkWindow *innerWindow = get_inner_gdk_window(gtk_widget_get_window(aWidget), aX, aY, - &retx, &rety); - nsRefPtr innerMostWidget = get_window_for_gdk_window(innerWindow); - - if (!innerMostWidget) - innerMostWidget = this; - - // clear any drag leave timer that might be pending so that it - // doesn't get processed when we actually go out to get data. - if (mDragLeaveTimer) { - mDragLeaveTimer->Cancel(); - mDragLeaveTimer = nsnull; - } - - CheckNeedDragLeave(innerMostWidget, dragService, aDragContext, retx, rety); - - // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model - // (as at 27 December 2010) indicates that a "drop" event should only be - // fired (at the current target element) if the current drag operation is - // not none. The current drag operation will only be set to a non-none - // value during a "dragover" event. - // - // If the user has ended the drag before any dragover events have been - // sent, then the spec recommends skipping the drop (because the current - // drag operation is none). However, here we assume that, by releasing - // the mouse button, the user has indicated that they want to drop, so we - // proceed with the drop where possible. - // - // In order to make the events appear to content in the same way as if the - // spec is being followed we make sure to dispatch a "dragover" event with - // appropriate coordinates and check canDrop before the "drop" event. - // - // When the Xdnd protocol is used for source/destination communication (as - // should be the case with GTK source applications) a dragover event - // should have already been sent during the drag-motion signal, which - // would have already been received because XdndDrop messages do not - // contain a position. However, we can't assume the same when the Motif - // protocol is used. - - dragServiceGTK->TargetSetLastContext(aWidget, aDragContext, aTime); - - innerMostWidget-> - DispatchDragMotionEvents(dragServiceGTK, nsIntPoint(retx, rety), aTime); - - gboolean success = innerMostWidget-> - DispatchDragDropEvent(dragServiceGTK, nsIntPoint(retx, rety), aTime); - - // before we unset the context we need to do a drop_finish - - gdk_drop_finish(aDragContext, success, aTime); - - // after a drop takes place we need to make sure that the drag - // service doesn't think that it still has a context. if the other - // way ( besides the drop ) to end a drag event is during the leave - // event and and that case is handled in that handler. - dragServiceGTK->TargetSetLastContext(0, 0, 0); - - // clear the sLastDragMotion window - sLastDragMotionWindow = 0; - - // Make sure to end the drag session. If this drag started in a - // different app, we won't get a drag_end signal to end it from. - dragService->EndDragSession(true); - - return TRUE; -} - void nsWindow::OnDragDataReceivedEvent(GtkWidget *aWidget, GdkDragContext *aDragContext, @@ -5910,7 +5711,7 @@ nsWindow::InitDragEvent(nsDragEvent &aEvent) // drag context. Gtk gets this from a combination of the key settings // and what the source is offering. -void +/* static */ void nsWindow::UpdateDragStatus(GdkDragContext *aDragContext, nsIDragService *aDragService) { @@ -5973,9 +5774,24 @@ drag_motion_event_cb(GtkWidget *aWidget, } } - return window->OnDragMotionEvent(aWidget, - aDragContext, - aX, aY, aTime, aData); + // figure out which internal widget this drag motion actually happened on + nscoord retx = 0; + nscoord rety = 0; + + GdkWindow *innerWindow = + get_inner_gdk_window(gtk_widget_get_window(aWidget), aX, aY, + &retx, &rety); + nsRefPtr innerMostWindow = get_window_for_gdk_window(innerWindow); + + if (!innerMostWindow) { + innerMostWindow = window; + } + + LOGDRAG(("nsWindow drag-motion signal for %p\n", (void*)innerMostWindow)); + + return nsDragService::GetInstance()-> + ScheduleMotionEvent(innerMostWindow, aDragContext, + nsIntPoint(aX, aY), aTime); } static void @@ -5988,7 +5804,27 @@ drag_leave_event_cb(GtkWidget *aWidget, if (!window) return; - window->OnDragLeaveEvent(aWidget, aDragContext, aTime, aData); + nsDragService *dragService = nsDragService::GetInstance(); + + nsWindow *mostRecentDragWindow = dragService->GetMostRecentDestWindow(); + if (!mostRecentDragWindow) { + NS_WARNING("Spurious drag leave signal"); + return; + } + + GtkWidget *mozContainer = mostRecentDragWindow->GetMozContainerWidget(); + if (aWidget != mozContainer) + { + // When the drag moves between widgets, GTK can send leave signal for + // the old widget after the motion or drop signal for the new widget. + // We'll send the leave event when the motion or drop event is run. + return; + } + + LOGDRAG(("nsWindow drag-leave signal for %p\n", + (void*)mostRecentDragWindow)); + + dragService->ScheduleLeaveEvent(); } @@ -6004,9 +5840,24 @@ drag_drop_event_cb(GtkWidget *aWidget, if (!window) return FALSE; - return window->OnDragDropEvent(aWidget, - aDragContext, - aX, aY, aTime, aData); + // figure out which internal widget this drag motion actually happened on + nscoord retx = 0; + nscoord rety = 0; + + GdkWindow *innerWindow = + get_inner_gdk_window(gtk_widget_get_window(aWidget), aX, aY, + &retx, &rety); + nsRefPtr innerMostWindow = get_window_for_gdk_window(innerWindow); + + if (!innerMostWindow) { + innerMostWindow = window; + } + + LOGDRAG(("nsWindow drag-drop signal for %p\n", (void*)innerMostWindow)); + + return nsDragService::GetInstance()-> + ScheduleDropEvent(innerMostWindow, aDragContext, + nsIntPoint(aX, aY), aTime); } static void @@ -6041,30 +5892,6 @@ initialize_prefs(void) return NS_OK; } -void -nsWindow::FireDragLeaveTimer(void) -{ - LOGDRAG(("nsWindow::FireDragLeaveTimer(%p)\n", (void*)this)); - - mDragLeaveTimer = nsnull; - - // clean up any pending drag motion window info - if (sLastDragMotionWindow) { - nsRefPtr kungFuDeathGrip = sLastDragMotionWindow; - // send our leave signal - sLastDragMotionWindow->OnDragLeave(); - sLastDragMotionWindow = 0; - } -} - -/* static */ -void -nsWindow::DragLeaveTimerCallback(nsITimer *aTimer, void *aClosure) -{ - nsRefPtr window = static_cast(aClosure); - window->FireDragLeaveTimer(); -} - static GdkWindow * get_inner_gdk_window (GdkWindow *aWindow, gint x, gint y, diff --git a/widget/gtk2/nsWindow.h b/widget/gtk2/nsWindow.h index 11b1c963505b..d8e35e1bfd94 100644 --- a/widget/gtk2/nsWindow.h +++ b/widget/gtk2/nsWindow.h @@ -237,22 +237,6 @@ public: GdkEventVisibility *aEvent); void OnWindowStateEvent(GtkWidget *aWidget, GdkEventWindowState *aEvent); - gboolean OnDragMotionEvent(GtkWidget *aWidget, - GdkDragContext *aDragContext, - gint aX, - gint aY, - guint aTime, - gpointer aData); - void OnDragLeaveEvent(GtkWidget * aWidget, - GdkDragContext *aDragContext, - guint aTime, - gpointer aData); - gboolean OnDragDropEvent(GtkWidget *aWidget, - GdkDragContext *aDragContext, - gint aX, - gint aY, - guint aTime, - gpointer aData); void OnDragDataReceivedEvent(GtkWidget *aWidget, GdkDragContext *aDragContext, gint aX, @@ -297,11 +281,6 @@ public: void ThemeChanged(void); - void CheckNeedDragLeave(nsWindow* aInnerMostWidget, - nsIDragService* aDragService, - GdkDragContext *aDragContext, - nscoord aX, nscoord aY); - #ifdef MOZ_X11 Window mOldFocusWindow; #endif /* MOZ_X11 */ @@ -312,6 +291,9 @@ public: NS_IMETHOD BeginMoveDrag(nsMouseEvent* aEvent); MozContainer* GetMozContainer() { return mContainer; } + // GetMozContainerWidget returns the MozContainer even for undestroyed + // descendant windows + GtkWidget* GetMozContainerWidget(); GdkWindow* GetGdkWindow() { return mGdkWindow; } bool IsDestroyed() { return mIsDestroyed; } @@ -324,6 +306,8 @@ public: gboolean DispatchDragDropEvent(nsDragService *aDragService, const nsIntPoint& aWindowPoint, guint aTime); + static void UpdateDragStatus (GdkDragContext *aDragContext, + nsIDragService *aDragService); // If this dispatched the keydown event actually, this returns TRUE, // otherwise, FALSE. bool DispatchKeyDownEvent(GdkEventKey *aEvent, @@ -393,7 +377,6 @@ protected: private: void DestroyChildWindows(); void GetToplevelWidget(GtkWidget **aWidget); - GtkWidget *GetMozContainerWidget(); nsWindow *GetContainerWindow(); void SetUrgencyHint(GtkWidget *top_window, bool state); void *SetupPluginPort(void); @@ -493,13 +476,8 @@ private: gchar* mTransparencyBitmap; // all of our DND stuff - // this is the last window that had a drag event happen on it. - static nsWindow *sLastDragMotionWindow; void InitDragEvent (nsDragEvent &aEvent); - void UpdateDragStatus (GdkDragContext *aDragContext, - nsIDragService *aDragService); - nsCOMPtr mDragLeaveTimer; float mLastMotionPressure; // Remember the last sizemode so that we can restore it when @@ -508,9 +486,6 @@ private: static bool DragInProgress(void); - void FireDragLeaveTimer (void); - static void DragLeaveTimerCallback (nsITimer *aTimer, void *aClosure); - void DispatchMissedButtonReleases(GdkEventCrossing *aGdkEvent); /** From 657ea8347a1e2a0058de1cc48bfda19cb0f2fc07 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 19 Apr 2012 18:18:31 +1200 Subject: [PATCH 032/159] b=497498 move drag event dispatch logic from nsWindow to nsDragService r=roc --HG-- extra : rebase_source : ec52cbad0d1efff13c989e8b5061f7fc3445b92b --- widget/gtk2/nsDragService.cpp | 47 +++++++++++++++++++++++++--- widget/gtk2/nsDragService.h | 2 ++ widget/gtk2/nsWindow.cpp | 59 ----------------------------------- widget/gtk2/nsWindow.h | 7 ----- 4 files changed, 44 insertions(+), 71 deletions(-) diff --git a/widget/gtk2/nsDragService.cpp b/widget/gtk2/nsDragService.cpp index 93e97c14688c..ae08071662c4 100644 --- a/widget/gtk2/nsDragService.cpp +++ b/widget/gtk2/nsDragService.cpp @@ -1829,7 +1829,18 @@ gboolean nsDragService::RunScheduledTask() { if (mTargetWindow && mTargetWindow != mPendingWindow) { - mTargetWindow->OnDragLeave(); + PR_LOG(sDragLm, PR_LOG_DEBUG, + ("nsDragService: dispatch drag leave (%p)\n", + mTargetWindow.get())); + mTargetWindow-> + DispatchDragEvent(NS_DRAGDROP_EXIT, mTargetWindowPoint, 0); + + if (!mSourceNode) { + // The drag that was initiated in a different app. End the drag + // session, since we're done with it for now (until the user drags + // back into this app). + EndDragSession(false); + } } // It is possible that the pending state has been updated during dispatch @@ -1889,8 +1900,7 @@ nsDragService::RunScheduledTask() // protocol is used. if (task == eDragTaskMotion || positionHasChanged) { nsWindow::UpdateDragStatus(mTargetDragContext, this); - mTargetWindow-> - DispatchDragMotionEvents(this, mTargetWindowPoint, mTargetTime); + DispatchMotionEvents(); if (task == eDragTaskMotion) { // Reply to tell the source whether we can drop and what @@ -1900,8 +1910,7 @@ nsDragService::RunScheduledTask() } if (task == eDragTaskDrop) { - gboolean success = mTargetWindow-> - DispatchDragDropEvent(this, mTargetWindowPoint, mTargetTime); + gboolean success = DispatchDropEvent(); // Perhaps we should set the del parameter to TRUE when the drag // action is move, but we don't know whether the data was successfully @@ -1932,3 +1941,31 @@ nsDragService::RunScheduledTask() mTaskSource = 0; return FALSE; } + +void +nsDragService::DispatchMotionEvents() +{ + mCanDrop = false; + + FireDragEventAtSource(NS_DRAGDROP_DRAG); + + mTargetWindow-> + DispatchDragEvent(NS_DRAGDROP_OVER, mTargetWindowPoint, mTargetTime); +} + +// Returns true if the drop was successful +gboolean +nsDragService::DispatchDropEvent() +{ + // We need to check IsDestroyed here because the nsRefPtr + // only protects this from being deleted, it does NOT protect + // against nsView::~nsView() calling Destroy() on it, bug 378273. + if (mTargetWindow->IsDestroyed()) + return FALSE; + + PRUint32 msg = mCanDrop ? NS_DRAGDROP_DROP : NS_DRAGDROP_EXIT; + + mTargetWindow->DispatchDragEvent(msg, mTargetWindowPoint, mTargetTime); + + return mCanDrop; +} diff --git a/widget/gtk2/nsDragService.h b/widget/gtk2/nsDragService.h index a883667b9eb5..9ea56a0ab363 100644 --- a/widget/gtk2/nsDragService.h +++ b/widget/gtk2/nsDragService.h @@ -244,6 +244,8 @@ private: // Callback for g_idle_add_full() to run mScheduledTask. static gboolean TaskDispatchCallback(gpointer data); gboolean RunScheduledTask(); + void DispatchMotionEvents(); + gboolean DispatchDropEvent(); }; #endif // nsDragService_h__ diff --git a/widget/gtk2/nsWindow.cpp b/widget/gtk2/nsWindow.cpp index f5d9406a2f18..a39f280acdd1 100644 --- a/widget/gtk2/nsWindow.cpp +++ b/widget/gtk2/nsWindow.cpp @@ -3303,37 +3303,6 @@ nsWindow::ThemeChanged() } } -void -nsWindow::DispatchDragMotionEvents(nsDragService *aDragService, - const nsIntPoint& aWindowPoint, guint aTime) -{ - aDragService->SetCanDrop(false); - - aDragService->FireDragEventAtSource(NS_DRAGDROP_DRAG); - - DispatchDragEvent(NS_DRAGDROP_OVER, aWindowPoint, aTime); -} - -// Returns true if the drop was successful -gboolean -nsWindow::DispatchDragDropEvent(nsDragService *aDragService, - const nsIntPoint& aWindowPoint, guint aTime) -{ - // We need to check mIsDestroyed here because the nsRefPtr - // only protects this from being deleted, it does NOT protect - // against nsView::~nsView() calling Destroy() on it, bug 378670. - if (mIsDestroyed) - return FALSE; - - bool canDrop; - aDragService->GetCanDrop(&canDrop); - PRUint32 msg = canDrop ? NS_DRAGDROP_DROP : NS_DRAGDROP_EXIT; - - DispatchDragEvent(msg, aWindowPoint, aTime); - - return canDrop; -} - void nsWindow::DispatchDragEvent(PRUint32 aMsg, const nsIntPoint& aRefPoint, guint aTime) @@ -3371,34 +3340,6 @@ nsWindow::OnDragDataReceivedEvent(GtkWidget *aWidget, aSelectionData, aInfo, aTime); } -void -nsWindow::OnDragLeave(void) -{ - LOGDRAG(("nsWindow::OnDragLeave(%p)\n", (void*)this)); - - DispatchDragEvent(NS_DRAGDROP_EXIT, nsIntPoint(0, 0), 0); - - nsCOMPtr dragService = do_GetService(kCDragServiceCID); - - if (dragService) { - nsCOMPtr currentDragSession; - dragService->GetCurrentSession(getter_AddRefs(currentDragSession)); - - if (currentDragSession) { - nsCOMPtr sourceNode; - currentDragSession->GetSourceNode(getter_AddRefs(sourceNode)); - - if (!sourceNode) { - // We're leaving a window while doing a drag that was - // initiated in a different app. End the drag session, - // since we're done with it for now (until the user - // drags back into mozilla). - dragService->EndDragSession(false); - } - } - } -} - static void GetBrandName(nsXPIDLString& brandName) { diff --git a/widget/gtk2/nsWindow.h b/widget/gtk2/nsWindow.h index d8e35e1bfd94..ac2fecffa06b 100644 --- a/widget/gtk2/nsWindow.h +++ b/widget/gtk2/nsWindow.h @@ -245,7 +245,6 @@ public: guint aInfo, guint aTime, gpointer aData); - void OnDragLeave(void); private: void NativeResize(PRInt32 aWidth, @@ -300,12 +299,6 @@ public: void DispatchDragEvent(PRUint32 aMsg, const nsIntPoint& aRefPoint, guint aTime); - void DispatchDragMotionEvents(nsDragService *aDragService, - const nsIntPoint& aPoint, - guint aTime); - gboolean DispatchDragDropEvent(nsDragService *aDragService, - const nsIntPoint& aWindowPoint, - guint aTime); static void UpdateDragStatus (GdkDragContext *aDragContext, nsIDragService *aDragService); // If this dispatched the keydown event actually, this returns TRUE, From fddba909e37134d4b6432638d6b90a3cf15e6120 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 19 Apr 2012 18:18:31 +1200 Subject: [PATCH 033/159] b=497498 move nsWindow::UpdateDragStatus to nsDragService::UpdateDragAction r=enndeakin --HG-- extra : rebase_source : e8198557c42f804cbe7ef758c8d8048af45722ec --- widget/gtk2/nsDragService.cpp | 44 ++++++++++++++++++++++++++++++++++- widget/gtk2/nsDragService.h | 1 + widget/gtk2/nsWindow.cpp | 37 ----------------------------- 3 files changed, 44 insertions(+), 38 deletions(-) diff --git a/widget/gtk2/nsDragService.cpp b/widget/gtk2/nsDragService.cpp index ae08071662c4..57f78d0fb157 100644 --- a/widget/gtk2/nsDragService.cpp +++ b/widget/gtk2/nsDragService.cpp @@ -62,6 +62,10 @@ #include "nsCRT.h" #include "mozilla/Services.h" +#if defined(MOZ_WIDGET_GTK2) +#include "gtk2compat.h" +#endif + #include "gfxASurface.h" #include "gfxXlibSurface.h" #include "gfxContext.h" @@ -1899,7 +1903,7 @@ nsDragService::RunScheduledTask() // contain a position. However, we can't assume the same when the Motif // protocol is used. if (task == eDragTaskMotion || positionHasChanged) { - nsWindow::UpdateDragStatus(mTargetDragContext, this); + UpdateDragAction(); DispatchMotionEvents(); if (task == eDragTaskMotion) { @@ -1942,6 +1946,44 @@ nsDragService::RunScheduledTask() return FALSE; } +// This will update the drag action based on the information in the +// drag context. Gtk gets this from a combination of the key settings +// and what the source is offering. + +void +nsDragService::UpdateDragAction() +{ + // This doesn't look right. dragSession.dragAction is used by + // nsContentUtils::SetDataTransferInEvent() to set the initial + // dataTransfer.dropEffect, so GdkDragContext::suggested_action would be + // more appropriate. GdkDragContext::actions should be used to set + // dataTransfer.effectAllowed, which doesn't currently happen with + // external sources. + + // default is to do nothing + int action = nsIDragService::DRAGDROP_ACTION_NONE; + GdkDragAction gdkAction = gdk_drag_context_get_actions(mTargetDragContext); + + // set the default just in case nothing matches below + if (gdkAction & GDK_ACTION_DEFAULT) + action = nsIDragService::DRAGDROP_ACTION_MOVE; + + // first check to see if move is set + if (gdkAction & GDK_ACTION_MOVE) + action = nsIDragService::DRAGDROP_ACTION_MOVE; + + // then fall to the others + else if (gdkAction & GDK_ACTION_LINK) + action = nsIDragService::DRAGDROP_ACTION_LINK; + + // copy is ctrl + else if (gdkAction & GDK_ACTION_COPY) + action = nsIDragService::DRAGDROP_ACTION_COPY; + + // update the drag information + SetDragAction(action); +} + void nsDragService::DispatchMotionEvents() { diff --git a/widget/gtk2/nsDragService.h b/widget/gtk2/nsDragService.h index 9ea56a0ab363..6d40a3035b0c 100644 --- a/widget/gtk2/nsDragService.h +++ b/widget/gtk2/nsDragService.h @@ -244,6 +244,7 @@ private: // Callback for g_idle_add_full() to run mScheduledTask. static gboolean TaskDispatchCallback(gpointer data); gboolean RunScheduledTask(); + void UpdateDragAction(); void DispatchMotionEvents(); gboolean DispatchDropEvent(); }; diff --git a/widget/gtk2/nsWindow.cpp b/widget/gtk2/nsWindow.cpp index a39f280acdd1..bda8251470f9 100644 --- a/widget/gtk2/nsWindow.cpp +++ b/widget/gtk2/nsWindow.cpp @@ -5648,43 +5648,6 @@ nsWindow::InitDragEvent(nsDragEvent &aEvent) KeymapWrapper::InitInputEvent(aEvent, modifierState); } -// This will update the drag action based on the information in the -// drag context. Gtk gets this from a combination of the key settings -// and what the source is offering. - -/* static */ void -nsWindow::UpdateDragStatus(GdkDragContext *aDragContext, - nsIDragService *aDragService) -{ - // default is to do nothing - int action = nsIDragService::DRAGDROP_ACTION_NONE; - GdkDragAction gdkAction = gdk_drag_context_get_actions(aDragContext); - - // set the default just in case nothing matches below - if (gdkAction & GDK_ACTION_DEFAULT) - action = nsIDragService::DRAGDROP_ACTION_MOVE; - - // first check to see if move is set - if (gdkAction & GDK_ACTION_MOVE) - action = nsIDragService::DRAGDROP_ACTION_MOVE; - - // then fall to the others - else if (gdkAction & GDK_ACTION_LINK) - action = nsIDragService::DRAGDROP_ACTION_LINK; - - // copy is ctrl - else if (gdkAction & GDK_ACTION_COPY) - action = nsIDragService::DRAGDROP_ACTION_COPY; - - // update the drag information - nsCOMPtr session; - aDragService->GetCurrentSession(getter_AddRefs(session)); - - if (session) - session->SetDragAction(action); -} - - static gboolean drag_motion_event_cb(GtkWidget *aWidget, GdkDragContext *aDragContext, From 8b437d0f6bb0d27fe07f0c00b099b8fd2df94478 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 19 Apr 2012 18:18:31 +1200 Subject: [PATCH 034/159] b=497498 remove nsIDragSessionGTK r=roc --HG-- extra : rebase_source : a8029599d50bfff6ca10cce73a35fb8854e868ab --- widget/Makefile.in | 1 - widget/gtk2/nsDragService.cpp | 52 ++++----------------- widget/gtk2/nsDragService.h | 24 +++------- widget/gtk2/nsWindow.cpp | 10 ++-- widget/nsIDragSessionGTK.h | 86 ----------------------------------- 5 files changed, 17 insertions(+), 156 deletions(-) delete mode 100644 widget/nsIDragSessionGTK.h diff --git a/widget/Makefile.in b/widget/Makefile.in index 4a3405b5c0b0..c5cb63ebe86d 100644 --- a/widget/Makefile.in +++ b/widget/Makefile.in @@ -125,7 +125,6 @@ endif ifneq (,$(filter qt gtk2,$(MOZ_WIDGET_TOOLKIT))) EXPORTS += \ - nsIDragSessionGTK.h \ nsIPrintDialogService.h \ $(NULL) endif diff --git a/widget/gtk2/nsDragService.cpp b/widget/gtk2/nsDragService.cpp index 57f78d0fb157..4f4a416dc101 100644 --- a/widget/gtk2/nsDragService.cpp +++ b/widget/gtk2/nsDragService.cpp @@ -181,8 +181,7 @@ nsDragService::~nsDragService() } -NS_IMPL_ISUPPORTS_INHERITED2(nsDragService, nsBaseDragService, - nsIDragSessionGTK, nsIObserver) +NS_IMPL_ISUPPORTS_INHERITED1(nsDragService, nsBaseDragService, nsIObserver) /* static */ nsDragService* nsDragService::GetInstance() @@ -1014,36 +1013,14 @@ nsDragService::IsDataFlavorSupported(const char *aDataFlavor, return NS_OK; } -// nsIDragSessionGTK - -NS_IMETHODIMP -nsDragService::TargetSetLastContext(GtkWidget *aWidget, - GdkDragContext *aContext, - guint aTime) -{ - PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::TargetSetLastContext")); - mTargetWidget = aWidget; - mTargetDragContext = aContext; - mTargetTime = aTime; - return NS_OK; -} - -NS_IMETHODIMP -nsDragService::TargetStartDragMotion(void) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsDragService::TargetEndDragMotion(GtkWidget *aWidget, - GdkDragContext *aContext, - guint aTime) +void +nsDragService::ReplyToDragMotion() { PR_LOG(sDragLm, PR_LOG_DEBUG, - ("nsDragService::TargetEndDragMotion %d", mCanDrop)); + ("nsDragService::ReplyToDragMotion %d", mCanDrop)); + GdkDragAction action = (GdkDragAction)0; if (mCanDrop) { - GdkDragAction action; // notify the dragger if we can drop switch (mDragAction) { case DRAGDROP_ACTION_COPY: @@ -1056,16 +1033,12 @@ nsDragService::TargetEndDragMotion(GtkWidget *aWidget, action = GDK_ACTION_MOVE; break; } - gdk_drag_status(aContext, action, aTime); - } - else { - gdk_drag_status(aContext, (GdkDragAction)0, aTime); } - return NS_OK; + gdk_drag_status(mTargetDragContext, action, mTargetTime); } -NS_IMETHODIMP +void nsDragService::TargetDataReceived(GtkWidget *aWidget, GdkDragContext *aContext, gint aX, @@ -1087,17 +1060,8 @@ nsDragService::TargetDataReceived(GtkWidget *aWidget, ("Failed to get data. selection data len was %d\n", aSelectionData->length)); } - return NS_OK; } - -NS_IMETHODIMP -nsDragService::TargetSetTimeCallback(nsIDragSessionGTKTimeCB aCallback) -{ - return NS_OK; -} - - bool nsDragService::IsTargetContextList(void) { @@ -1909,7 +1873,7 @@ nsDragService::RunScheduledTask() if (task == eDragTaskMotion) { // Reply to tell the source whether we can drop and what // action would be taken. - TargetEndDragMotion(mTargetWidget, mTargetDragContext, mTargetTime); + ReplyToDragMotion(); } } diff --git a/widget/gtk2/nsDragService.h b/widget/gtk2/nsDragService.h index 6d40a3035b0c..7a6faea4ca27 100644 --- a/widget/gtk2/nsDragService.h +++ b/widget/gtk2/nsDragService.h @@ -42,7 +42,6 @@ #define nsDragService_h__ #include "nsBaseDragService.h" -#include "nsIDragSessionGTK.h" #include "nsIObserver.h" #include @@ -76,7 +75,6 @@ class nsAutoRefTraits : */ class nsDragService : public nsBaseDragService, - public nsIDragSessionGTK, public nsIObserver { public: @@ -103,16 +101,12 @@ public: PRUint32 aItemIndex); NS_IMETHOD IsDataFlavorSupported (const char *aDataFlavor, bool *_retval); - // nsIDragSessionGTK + // Methods called from nsWindow to handle responding to GTK drag + // destination signals - NS_IMETHOD TargetSetLastContext (GtkWidget *aWidget, - GdkDragContext *aContext, - guint aTime); - NS_IMETHOD TargetStartDragMotion (void); - NS_IMETHOD TargetEndDragMotion (GtkWidget *aWidget, - GdkDragContext *aContext, - guint aTime); - NS_IMETHOD TargetDataReceived (GtkWidget *aWidget, + static nsDragService* GetInstance(); + + void TargetDataReceived (GtkWidget *aWidget, GdkDragContext *aContext, gint aX, gint aY, @@ -120,13 +114,6 @@ public: guint aInfo, guint32 aTime); - NS_IMETHOD TargetSetTimeCallback (nsIDragSessionGTKTimeCB aCallback); - - static nsDragService* GetInstance(); - - // Methods called from nsWindow to handle responding to GTK drag - // destination signals - gboolean ScheduleMotionEvent(nsWindow *aWindow, GdkDragContext *aDragContext, nsIntPoint aWindowPoint, @@ -246,6 +233,7 @@ private: gboolean RunScheduledTask(); void UpdateDragAction(); void DispatchMotionEvents(); + void ReplyToDragMotion(); gboolean DispatchDropEvent(); }; diff --git a/widget/gtk2/nsWindow.cpp b/widget/gtk2/nsWindow.cpp index bda8251470f9..34d64f970ef7 100644 --- a/widget/gtk2/nsWindow.cpp +++ b/widget/gtk2/nsWindow.cpp @@ -55,7 +55,6 @@ #include "nsWidgetsCID.h" #include "nsDragService.h" -#include "nsIDragSessionGTK.h" #include "nsGtkKeyUtils.h" #include "nsGtkCursors.h" @@ -3332,12 +3331,9 @@ nsWindow::OnDragDataReceivedEvent(GtkWidget *aWidget, { LOGDRAG(("nsWindow::OnDragDataReceived(%p)\n", (void*)this)); - // get our drag context - nsCOMPtr dragService = do_GetService(kCDragServiceCID); - nsCOMPtr dragSessionGTK = do_QueryInterface(dragService); - - dragSessionGTK->TargetDataReceived(aWidget, aDragContext, aX, aY, - aSelectionData, aInfo, aTime); + nsDragService::GetInstance()-> + TargetDataReceived(aWidget, aDragContext, aX, aY, + aSelectionData, aInfo, aTime); } static void diff --git a/widget/nsIDragSessionGTK.h b/widget/nsIDragSessionGTK.h deleted file mode 100644 index 435e11ad447d..000000000000 --- a/widget/nsIDragSessionGTK.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Christopher Blizzard . - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Christopher Blizzard - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef nsIDragSessionGTK_h_ -#define nsIDragSessionGTK_h_ - -#include "nsISupports.h" - -#include - -typedef void (*nsIDragSessionGTKTimeCB)(guint32 *aTime); - -#define NS_IDRAGSESSIONGTK_IID \ -{ 0xa6b49c42, 0x1dd1, 0x11b2, { 0xb2, 0xdf, 0xc1, 0xd6, 0x1d, 0x67, 0x45, 0xcf } } - -class nsIDragSessionGTK : public nsISupports { -public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDRAGSESSIONGTK_IID) - - // Thse are all target methods - that is when the mozilla is a - // target of a drag. Any methods related to when mozilla starts a - // drag are elsewhere. - - // this sets the last drag context used where mozilla is the target - // of a drag - NS_IMETHOD TargetSetLastContext (GtkWidget *aWidget, - GdkDragContext *aContext, - guint aTime) = 0; - // this is called at the beginning of a drag motion event - NS_IMETHOD TargetStartDragMotion (void) = 0; - // this is called at the end of a drag motion event - NS_IMETHOD TargetEndDragMotion (GtkWidget *aWidget, - GdkDragContext *aContext, - guint aTime) = 0; - // this is called when data is received after being sent above - NS_IMETHOD TargetDataReceived (GtkWidget *aWidget, - GdkDragContext *aContext, - gint aX, - gint aY, - GtkSelectionData *aSelection_data, - guint aInfo, - guint32 aTime) = 0; - // this sets a callback for time related fun - NS_IMETHOD TargetSetTimeCallback (nsIDragSessionGTKTimeCB aCallback) = 0; - -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsIDragSessionGTK, NS_IDRAGSESSIONGTK_IID) - -#endif /* nsIDragSessionGTK_h_ */ From 93c7e9aad7f8a1466d4702d3e9c5cc7da7e19ab1 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 19 Apr 2012 18:18:31 +1200 Subject: [PATCH 035/159] b=634719 don't start a new source drag session until the previous has completed r=roc --HG-- extra : rebase_source : 1165a447cf141b5ec34446e6e95ab66f815168f7 --- widget/gtk2/nsDragService.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/widget/gtk2/nsDragService.cpp b/widget/gtk2/nsDragService.cpp index 4f4a416dc101..57cfc4661642 100644 --- a/widget/gtk2/nsDragService.cpp +++ b/widget/gtk2/nsDragService.cpp @@ -317,6 +317,14 @@ nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode, PRUint32 aActionType) { PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::InvokeDragSession")); + + // If the previous source drag has not yet completed, signal handlers need + // to be removed from mGrabWidget and dragend needs to be dispatched to + // the source node, but we can't call EndDragSession yet because we don't + // know whether or not the drag succeeded. + if (mSourceNode) + return NS_ERROR_NOT_AVAILABLE; + nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode, aArrayTransferables, aRegion, aActionType); From 47da1662bc764b5c7b1f28b9e124beecdb47dc19 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 19 Apr 2012 18:18:31 +1200 Subject: [PATCH 036/159] b=634719 schedule event dispatch in response to GTK drag end signals to avoid running the event loop at unexpected times and dispatch leave events in the right order r=roc --HG-- extra : rebase_source : 32b86a8d4bc691bf3c1f2d9e1ca13eab68fa4810 --- widget/gtk2/nsDragService.cpp | 43 +++++++++++++++++++++++++---------- widget/gtk2/nsDragService.h | 3 ++- widget/gtk2/nsWindow.cpp | 6 ++++- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/widget/gtk2/nsDragService.cpp b/widget/gtk2/nsDragService.cpp index 57cfc4661642..f86487702840 100644 --- a/widget/gtk2/nsDragService.cpp +++ b/widget/gtk2/nsDragService.cpp @@ -1336,8 +1336,10 @@ nsDragService::SourceEndDragSession(GdkDragContext *aContext, // this just releases the list of data items that we provide mSourceDataItems = nsnull; - if (!mDoingDrag) - return; // EndDragSession() was already called on drop or drag-failed + if (!mDoingDrag || mScheduledTask == eDragTaskSourceEnd) + // EndDragSession() was already called on drop + // or SourceEndDragSession on drag-failed + return; if (mEndDragPoint.x < 0) { // We don't have a drag end point, so guess @@ -1390,8 +1392,8 @@ nsDragService::SourceEndDragSession(GdkDragContext *aContext, mDataTransfer->SetDropEffectInt(dropEffect); } - // Inform the drag session that we're ending the drag. - EndDragSession(true); + // Schedule the appropriate drag end dom events. + Schedule(eDragTaskSourceEnd, nsnull, NULL, nsIntPoint(), 0); } static void @@ -1680,11 +1682,11 @@ invisibleSourceDragEnd(GtkWidget *aWidget, dragService->SourceEndDragSession(aContext, MOZ_GTK_DRAG_RESULT_SUCCESS); } -// The following methods handle responding to GTK drag destination signals and +// The following methods handle responding to GTK drag signals and // tracking state between these signals. // // In general, GTK does not expect us to run the event loop while handling its -// drag destination signals, however our drag event handlers may run the +// drag signals, however our drag event handlers may run the // event loop, most often to fetch information about the drag data. // // GTK, for example, uses the return value from drag-motion signals to @@ -1699,6 +1701,14 @@ invisibleSourceDragEnd(GtkWidget *aWidget, // XmTRANSFER_SUCCESS during gtk_drag_finish is sent after the XmDROP_START // reply sent on return from the drag-drop signal handler. // +// Similarly drag-end for a successful drag and drag-failed are not good +// times to run a nested event loop as gtk_drag_drop_finished() and +// gtk_drag_source_info_destroy() don't gtk_drag_clear_source_info() or remove +// drop_timeout until after at least the first of these signals is sent. +// Processing other events (e.g. a slow GDK_DROP_FINISHED reply, or the drop +// timeout) could cause gtk_drag_drop_finished to be called again with the +// same GtkDragSourceInfo, which won't like being destroyed twice. +// // Therefore we reply to the signals immediately and schedule a task to // dispatch the Gecko events, which may run the event loop. // @@ -1766,15 +1776,19 @@ nsDragService::Schedule(DragTask aTask, nsWindow *aWindow, GdkDragContext *aDragContext, nsIntPoint aWindowPoint, guint aTime) { - // If we haven't yet run a scheduled drop task, just say that - // we are not ready to receive another drop. - if (mScheduledTask == eDragTaskDrop) - return FALSE; - // If there is an existing leave or motion task scheduled, then that // will be replaced. When the new task is run, it will dispatch // any necessary leave or motion events. + // If aTask is eDragTaskSourceEnd, then it will replace even a scheduled + // drop event (which could happen if the drop event has not been processed + // within the allowed time). Otherwise, if we haven't yet run a scheduled + // drop or end task, just say that we are not ready to receive another + // drop. + if (mScheduledTask == eDragTaskSourceEnd || + (mScheduledTask == eDragTaskDrop && aTask != eDragTaskSourceEnd)) + return FALSE; + mScheduledTask = aTask; mPendingWindow = aWindow; mPendingDragContext = aDragContext; @@ -1834,7 +1848,12 @@ nsDragService::RunScheduledTask() mTargetWindow = mPendingWindow.forget(); mTargetWindowPoint = mPendingWindowPoint; - if (task == eDragTaskLeave) { + if (task == eDragTaskLeave || task == eDragTaskSourceEnd) { + if (task == eDragTaskSourceEnd) { + // Dispatch drag end events. + EndDragSession(true); + } + // Nothing more to do // Returning false removes the task source from the event loop. mTaskSource = 0; diff --git a/widget/gtk2/nsDragService.h b/widget/gtk2/nsDragService.h index 7a6faea4ca27..144dbaa1bc45 100644 --- a/widget/gtk2/nsDragService.h +++ b/widget/gtk2/nsDragService.h @@ -156,7 +156,8 @@ private: eDragTaskNone, eDragTaskMotion, eDragTaskLeave, - eDragTaskDrop + eDragTaskDrop, + eDragTaskSourceEnd }; DragTask mScheduledTask; // mTaskSource is the GSource id for the task that is either scheduled diff --git a/widget/gtk2/nsWindow.cpp b/widget/gtk2/nsWindow.cpp index 34d64f970ef7..c8963b4b774b 100644 --- a/widget/gtk2/nsWindow.cpp +++ b/widget/gtk2/nsWindow.cpp @@ -5708,7 +5708,11 @@ drag_leave_event_cb(GtkWidget *aWidget, nsWindow *mostRecentDragWindow = dragService->GetMostRecentDestWindow(); if (!mostRecentDragWindow) { - NS_WARNING("Spurious drag leave signal"); + // This can happen when the target will not accept a drop. A GTK drag + // source sends the leave message to the destination before the + // drag-failed signal on the source widget, but the leave message goes + // via the X server, and so doesn't get processed at least until the + // event loop runs again. return; } From bf73ed712090822155c305382416380878aa9f61 Mon Sep 17 00:00:00 2001 From: Sriram Ramasubramanian Date: Mon, 30 Apr 2012 14:09:41 -0700 Subject: [PATCH 037/159] Bug 750349: Recycle Listener for TabsTray. [r=mfinkle] --- mobile/android/base/TabsTray.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mobile/android/base/TabsTray.java b/mobile/android/base/TabsTray.java index 81aa684d7c5c..ef0de8bc5944 100644 --- a/mobile/android/base/TabsTray.java +++ b/mobile/android/base/TabsTray.java @@ -20,6 +20,7 @@ import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AbsListView.RecyclerListener; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.ImageButton; @@ -62,6 +63,13 @@ public class TabsTray extends GeckoActivity implements Tabs.OnTabsChangedListene mList = (ListView) findViewById(R.id.list); mList.setItemsCanFocus(true); + mList.setRecyclerListener(new RecyclerListener() { + @Override + public void onMovedToScrapHeap(View view) { + ((ImageView) view.findViewById(R.id.thumbnail)).setImageDrawable(null); + } + }); + mListContainer = (TabsListContainer) findViewById(R.id.list_container); ImageButton addTab = (ImageButton) findViewById(R.id.add_tab); From 2eacf185a54d87e659a09bc77ee31fabf291caaf Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 30 Apr 2012 17:05:53 -0400 Subject: [PATCH 038/159] Bug 750146 - Do not call back on the nsTextEditorState if the restore selection event has been revoked; r=bzbarsky --HG-- extra : rebase_source : b37d85e9c2e628b15b23bbedc2eee74d66d8fa46 --- content/html/content/src/nsTextEditorState.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/content/html/content/src/nsTextEditorState.cpp b/content/html/content/src/nsTextEditorState.cpp index d6f3cedb2874..e2c648108231 100644 --- a/content/html/content/src/nsTextEditorState.cpp +++ b/content/html/content/src/nsTextEditorState.cpp @@ -84,6 +84,10 @@ public: } NS_IMETHOD Run() { + if (!mTextEditorState) { + return NS_OK; + } + if (mFrame) { // SetSelectionRange leads to Selection::AddRange which flushes Layout - // need to block script to avoid nested PrepareEditor calls (bug 642800). @@ -105,6 +109,7 @@ public: // Let the text editor tell us we're no longer relevant - avoids use of nsWeakFrame void Revoke() { mFrame = nsnull; + mTextEditorState = nsnull; } private: From d3e93afe9339c751ae63aeccc83022f1bf09d0d2 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 30 Apr 2012 17:43:12 -0400 Subject: [PATCH 039/159] Bug 736123 - kill GetVendor() and EGLUtils.h - r=jrmuizel Was only returning "Android" instead of something useful. --- gfx/gl/EGLUtils.h | 42 --------------------------------- gfx/gl/GLContextProviderEGL.cpp | 11 --------- gfx/gl/Makefile.in | 1 - widget/android/GfxInfo.cpp | 5 ++-- 4 files changed, 2 insertions(+), 57 deletions(-) delete mode 100644 gfx/gl/EGLUtils.h diff --git a/gfx/gl/EGLUtils.h b/gfx/gl/EGLUtils.h deleted file mode 100644 index e8d93be6ab87..000000000000 --- a/gfx/gl/EGLUtils.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -namespace mozilla { -namespace gl { - -const char* -GetVendor(); - -} -} diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index dc567dfb5da2..aff41ae17887 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -140,7 +140,6 @@ public: #include "GLLibraryEGL.h" #include "nsDebug.h" #include "nsThreadUtils.h" -#include "EGLUtils.h" #include "nsIWidget.h" @@ -1514,16 +1513,6 @@ CreateSurfaceForWindow(nsIWidget *aWidget, EGLConfig config) return surface; } -const char* -GetVendor() -{ - if (!sEGLLibrary.EnsureInitialized()) { - return nsnull; - } - - return reinterpret_cast(sEGLLibrary.fQueryString(EGL_DISPLAY(), LOCAL_EGL_VENDOR)); -} - already_AddRefed GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget) { diff --git a/gfx/gl/Makefile.in b/gfx/gl/Makefile.in index 1ac02472d8af..46ea339c03a5 100644 --- a/gfx/gl/Makefile.in +++ b/gfx/gl/Makefile.in @@ -52,7 +52,6 @@ EXPORTS = \ GLContextProvider.h \ GLContextProviderImpl.h \ GLLibraryLoader.h \ - EGLUtils.h \ ForceDiscreteGPUHelperCGL.h \ $(NULL) diff --git a/widget/android/GfxInfo.cpp b/widget/android/GfxInfo.cpp index 31b051c63af3..f7b6cc6abce9 100644 --- a/widget/android/GfxInfo.cpp +++ b/widget/android/GfxInfo.cpp @@ -38,7 +38,6 @@ #include "mozilla/FunctionTimer.h" #include "prenv.h" #include "prprf.h" -#include "EGLUtils.h" #include "nsHashKeys.h" #include "AndroidBridge.h" @@ -92,11 +91,11 @@ GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams) nsresult GfxInfo::Init() { - mAdapterDescription.AssignASCII(mozilla::gl::GetVendor()); + mAdapterDescription.AssignLiteral(""); // we may append to it below if (mozilla::AndroidBridge::Bridge()) { nsAutoString str; - mAdapterDescription.Append(NS_LITERAL_STRING(", Model: '")); + mAdapterDescription.Append(NS_LITERAL_STRING("Model: '")); if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MODEL", str)) { mAdapterDeviceID = str; mAdapterDescription.Append(str); From c25e00d46c111c1afa3622d5e4e3ef70f14e2de8 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 30 Apr 2012 17:43:12 -0400 Subject: [PATCH 040/159] Bug 736123 - blacklist Adreno renderers for WebGL - r=joe --- content/canvas/src/WebGLContextValidate.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/content/canvas/src/WebGLContextValidate.cpp b/content/canvas/src/WebGLContextValidate.cpp index fea1da2d9008..365c09ef3d1e 100644 --- a/content/canvas/src/WebGLContextValidate.cpp +++ b/content/canvas/src/WebGLContextValidate.cpp @@ -518,6 +518,20 @@ WebGLContext::InitAndValidateGL() return false; } +#ifdef ANDROID + // bug 736123, blacklist WebGL on Adreno because they do not implement + // glTexSubImage2D in a way that is safe to expose to WebGL + // We don't rely on GfxInfo for this blacklisting, because GfxInfo on Android doesn't know + // about GL strings and GL strings are the only way I know to detect Adreno (EGL Vendor only + // says 'Android'), and it is not convenient to have to create a GL context before GfxInfo::Init() + // is first called. + if (gl->Renderer() == gl::GLContext::RendererAdreno200 || + gl->Renderer() == gl::GLContext::RendererAdreno205) + { + return false; + } +#endif + mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false); mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false); From 3e01d03f6d4a2b5cf521beea4f266f4b199024ec Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 30 Apr 2012 17:43:12 -0400 Subject: [PATCH 041/159] Bug 748654 - drop patch making us use mozalloc in angle - r=jgilbert --- gfx/angle/Makefile.in | 2 -- gfx/angle/src/compiler/preprocessor/atom.c | 18 ++++++++++++------ gfx/angle/src/libEGL/Makefile.in | 2 -- gfx/angle/src/libGLESv2/Makefile.in | 2 -- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in index 4a41ad5f9ada..e2f7cfb8417e 100644 --- a/gfx/angle/Makefile.in +++ b/gfx/angle/Makefile.in @@ -140,8 +140,6 @@ DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD -DCOMPILER_IMPLEMENTATION DEFINES += -DANGLE_DISABLE_TRACE DEFINES += -DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0 -EXTRA_DSO_LDOPTS = $(MOZALLOC_LIB) - ifdef MOZ_ANGLE # libEGL depends on (links against!) libGLESv2! diff --git a/gfx/angle/src/compiler/preprocessor/atom.c b/gfx/angle/src/compiler/preprocessor/atom.c index 29ea03786209..e59480bedd0c 100644 --- a/gfx/angle/src/compiler/preprocessor/atom.c +++ b/gfx/angle/src/compiler/preprocessor/atom.c @@ -53,8 +53,6 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "compiler/compilerdebug.h" #include "compiler/preprocessor/slglobals.h" -#include "../../../../../memory/mozalloc/mozalloc.h" - #undef malloc #undef realloc #undef free @@ -325,13 +323,21 @@ static int GrowAtomTable(AtomTable *atable, int size) if (atable->size < size) { if (atable->amap) { - newmap = moz_xrealloc(atable->amap, sizeof(int)*size); - newrev = moz_xrealloc(atable->arev, sizeof(int)*size); + newmap = realloc(atable->amap, sizeof(int)*size); + newrev = realloc(atable->arev, sizeof(int)*size); } else { - newmap = moz_xmalloc(sizeof(int)*size); - newrev = moz_xmalloc(sizeof(int)*size); + newmap = malloc(sizeof(int)*size); + newrev = malloc(sizeof(int)*size); atable->size = 0; } + if (!newmap || !newrev) { + /* failed to grow -- error */ + if (newmap) + atable->amap = newmap; + if (newrev) + atable->arev = newrev; + return -1; + } memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int)); memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int)); atable->amap = newmap; diff --git a/gfx/angle/src/libEGL/Makefile.in b/gfx/angle/src/libEGL/Makefile.in index 60282c9677e4..987d022fa0b0 100644 --- a/gfx/angle/src/libEGL/Makefile.in +++ b/gfx/angle/src/libEGL/Makefile.in @@ -166,5 +166,3 @@ EXTRA_DSO_LDOPTS = "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3 dwmapi.lib \ delayimp.lib \ /delayload:dwmapi.dll - -EXTRA_DSO_LDOPTS += $(MOZALLOC_LIB) diff --git a/gfx/angle/src/libGLESv2/Makefile.in b/gfx/angle/src/libGLESv2/Makefile.in index 8ab7dda1deaa..35974b70c580 100644 --- a/gfx/angle/src/libGLESv2/Makefile.in +++ b/gfx/angle/src/libGLESv2/Makefile.in @@ -175,5 +175,3 @@ include $(topsrcdir)/config/rules.mk EXTRA_DSO_LDOPTS = "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3d9.lib" \ "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3dx9.lib" \ "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/D3DCompiler.lib" - -EXTRA_DSO_LDOPTS += $(MOZALLOC_LIB) From 8252eb1d007af0ae9234347c73ef36dcf0941023 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 30 Apr 2012 17:43:12 -0400 Subject: [PATCH 042/159] Bug 748654 - manually abort on allocation failure - r=jgilbert --- gfx/angle/src/compiler/preprocessor/atom.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/gfx/angle/src/compiler/preprocessor/atom.c b/gfx/angle/src/compiler/preprocessor/atom.c index e59480bedd0c..1ed3ee84ab1f 100644 --- a/gfx/angle/src/compiler/preprocessor/atom.c +++ b/gfx/angle/src/compiler/preprocessor/atom.c @@ -331,12 +331,7 @@ static int GrowAtomTable(AtomTable *atable, int size) atable->size = 0; } if (!newmap || !newrev) { - /* failed to grow -- error */ - if (newmap) - atable->amap = newmap; - if (newrev) - atable->arev = newrev; - return -1; + abort(); } memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int)); memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int)); From 6d6be3fa98cba462114893d56a780e8cecc92d43 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 30 Apr 2012 17:43:12 -0400 Subject: [PATCH 043/159] Bug 743748 - Reenable ANGLE shader translation on Android - r=jgilbert --- content/canvas/src/WebGLContextGL.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 2a658cd733f5..1f0e2e45ea21 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -4566,17 +4566,6 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj) ShShaderOutput targetShaderSourceLanguage = gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT; bool useShaderSourceTranslation = true; -#ifdef ANDROID - // see bug 709947. On Android, we can't use the ESSL backend because of strange crashes (might be - // an allocator mismatch). So we use the GLSL backend, and discard the output, instead just passing - // the original WebGL shader source to the GL (since that's ESSL already). The problem is that means - // we can't use shader translations on Android, in particular we can't use long identifier shortening, - // which means we can't reach 100% conformance. We need to fix that by debugging the ESSL backend - // memory crashes. - targetShaderSourceLanguage = SH_GLSL_OUTPUT; - useShaderSourceTranslation = false; -#endif - #if defined(USE_ANGLE) if (shader->NeedsTranslation() && mShaderValidation) { ShHandle compiler = 0; From 448bfb52b598c5b3b3554cc14e6389b6843a897c Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 18 Apr 2012 10:27:32 -0400 Subject: [PATCH 044/159] Bug 743830 - Added 'gfx.xrender.enabled' pref (true by default). The pref is fetched in gfPlatformGtk.cpp and can be accessed through gfxPlatformGtk::UseXRender(). UseXRender is used in GLContextProviderGLX to set mUseTextureFromPixmap. r=jmuizelaar --HG-- extra : rebase_source : 805947a2164aeb2dc71cc33086ac0bd201df3583 --- gfx/gl/GLContextProviderGLX.cpp | 21 +++++++++++++++------ gfx/gl/GLXLibrary.h | 6 +++--- gfx/thebes/gfxPlatformGtk.cpp | 11 +++++++++-- gfx/thebes/gfxPlatformGtk.h | 7 ++++++- modules/libpref/src/init/all.js | 6 ++++++ 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index 07b140b11e4b..679397e8d25f 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -63,6 +63,10 @@ #include "gfxCrashReporterUtils.h" +#ifdef MOZ_WIDGET_GTK2 +#include "gfxPlatformGtk.h" +#endif + namespace mozilla { namespace gl { @@ -251,8 +255,13 @@ GLXLibrary::EnsureInitialized() GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_texturefrompixmap, (GLLibraryLoader::PlatformLookupFunction)&xGetProcAddress)) { - mHasTextureFromPixmap = true; +#ifdef MOZ_WIDGET_GTK2 + mUseTextureFromPixmap = gfxPlatformGtk::UseXRender(); +#else + mUseTextureFromPixmap = true; +#endif } else { + mUseTextureFromPixmap = false; NS_WARNING("Texture from pixmap disabled"); } @@ -278,7 +287,7 @@ GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface) return false; } - if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib || !mHasTextureFromPixmap) { + if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib || !mUseTextureFromPixmap) { return false; } @@ -328,7 +337,7 @@ GLXLibrary::CreatePixmap(gfxASurface* aSurface) void GLXLibrary::DestroyPixmap(GLXPixmap aPixmap) { - if (!mHasTextureFromPixmap) { + if (!mUseTextureFromPixmap) { return; } @@ -339,7 +348,7 @@ GLXLibrary::DestroyPixmap(GLXPixmap aPixmap) void GLXLibrary::BindTexImage(GLXPixmap aPixmap) { - if (!mHasTextureFromPixmap) { + if (!mUseTextureFromPixmap) { return; } @@ -352,7 +361,7 @@ GLXLibrary::BindTexImage(GLXPixmap aPixmap) void GLXLibrary::ReleaseTexImage(GLXPixmap aPixmap) { - if (!mHasTextureFromPixmap) { + if (!mUseTextureFromPixmap) { return; } @@ -843,7 +852,7 @@ TRY_AGAIN_NO_SHARING: bool TextureImageSupportsGetBackingSurface() { - return sGLXLibrary.HasTextureFromPixmap(); + return sGLXLibrary.UseTextureFromPixmap(); } virtual already_AddRefed diff --git a/gfx/gl/GLXLibrary.h b/gfx/gl/GLXLibrary.h index 000b98fabdd5..ab17649e778a 100644 --- a/gfx/gl/GLXLibrary.h +++ b/gfx/gl/GLXLibrary.h @@ -49,7 +49,7 @@ class GLXLibrary { public: GLXLibrary() : mInitialized(false), mTriedInitializing(false), - mHasTextureFromPixmap(false), mDebug(false), + mUseTextureFromPixmap(false), mDebug(false), mHasRobustness(false), mOGLLibrary(nsnull) {} void xDestroyContext(Display* display, GLXContext context); @@ -121,7 +121,7 @@ public: void BindTexImage(GLXPixmap aPixmap); void ReleaseTexImage(GLXPixmap aPixmap); - bool HasTextureFromPixmap() { return mHasTextureFromPixmap; } + bool UseTextureFromPixmap() { return mUseTextureFromPixmap; } bool HasRobustness() { return mHasRobustness; } bool SupportsTextureFromPixmap(gfxASurface* aSurface); @@ -230,7 +230,7 @@ private: bool mInitialized; bool mTriedInitializing; - bool mHasTextureFromPixmap; + bool mUseTextureFromPixmap; bool mDebug; bool mHasRobustness; PRLibrary *mOGLLibrary; diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp index 2a106d3fbbdd..86d1ce6801e0 100644 --- a/gfx/thebes/gfxPlatformGtk.cpp +++ b/gfx/thebes/gfxPlatformGtk.cpp @@ -67,6 +67,7 @@ #include #include "gfxXlibSurface.h" #include "cairo-xlib.h" +#include "mozilla/Preferences.h" /* Undefine the Status from Xlib since it will conflict with system headers on OSX */ #if defined(__APPLE__) && defined(Status) @@ -104,14 +105,20 @@ static void do_gdk_drawable_unref (void *data) g_object_unref (d); } +#ifdef MOZ_X11 + bool gfxPlatformGtk::sUseXRender = true; +#endif + gfxPlatformGtk::gfxPlatformGtk() { if (!sFontconfigUtils) sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils(); +#ifdef MOZ_X11 + sUseXRender = mozilla::Preferences::GetBool("gfx.xrender.enabled"); +#endif #ifndef MOZ_PANGO FT_Init_FreeType(&gPlatformFTLibrary); - gPlatformFonts = new FontTable(); gPlatformFonts->Init(100); gPlatformFontAliases = new FontTable(); @@ -178,7 +185,7 @@ gfxPlatformGtk::CreateOffscreenSurface(const gfxIntSize& size, imageFormat = GetOffscreenFormat(); } - if (UseClientSideRendering()) { + if (!UseXRender()) { // We're not going to use XRender, so we don't need to // search for a render format newSurface = new gfxImageSurface(size, imageFormat); diff --git a/gfx/thebes/gfxPlatformGtk.h b/gfx/thebes/gfxPlatformGtk.h index 2ec617c19c1f..8df64f49d2ee 100644 --- a/gfx/thebes/gfxPlatformGtk.h +++ b/gfx/thebes/gfxPlatformGtk.h @@ -129,7 +129,7 @@ public: static PRInt32 GetDPI(); - static bool UseClientSideRendering() { + static bool UseXRender() { #if defined(MOZ_X11) && defined(MOZ_PLATFORM_MAEMO) // XRender is not accelerated on the Maemo at the moment, and // X server pixman is out of our control; it's likely to be @@ -141,6 +141,8 @@ public: // rendering, but until we have the ability to featuer test // this, we'll only disable this for maemo. return true; +#elif defined(MOZ_X11) + return sUseXRender; #else return false; #endif @@ -153,6 +155,9 @@ protected: private: virtual qcms_profile *GetPlatformCMSOutputProfile(); +#ifdef MOZ_X11 + static bool sUseXRender; +#endif }; #endif /* GFX_PLATFORM_GTK_H */ diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index c082a3300ae5..444adf7b5795 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -3469,6 +3469,12 @@ pref("layers.acceleration.draw-fps", false); pref("layers.offmainthreadcomposition.enabled", false); +#ifdef MOZ_X11 +#ifdef MOZ_WIDGET_GTK2 +pref("gfx.xrender.enabled",true); +#endif +#endif + #ifdef XP_WIN // Whether to disable the automatic detection and use of direct2d. #ifdef MOZ_E10S_COMPAT From b7932b3e6611bd96f8cad744921d49e20c2b7d06 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Mon, 30 Apr 2012 15:47:42 -0700 Subject: [PATCH 045/159] Bug 750356: fix signed/unsigned comparison build warnings in ReusableTileStoreOGL.cpp. r=chrislord --- gfx/layers/opengl/ReusableTileStoreOGL.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gfx/layers/opengl/ReusableTileStoreOGL.cpp b/gfx/layers/opengl/ReusableTileStoreOGL.cpp index 125cf5334a77..7e22aa9b2875 100644 --- a/gfx/layers/opengl/ReusableTileStoreOGL.cpp +++ b/gfx/layers/opengl/ReusableTileStoreOGL.cpp @@ -13,7 +13,7 @@ ReusableTileStoreOGL::~ReusableTileStoreOGL() return; mContext->MakeCurrent(); - for (int i = 0; i < mTiles.Length(); i++) + for (PRUint32 i = 0; i < mTiles.Length(); i++) mContext->fDeleteTextures(1, &mTiles[i]->mTexture.mTextureHandle); mTiles.Clear(); } @@ -36,7 +36,7 @@ ReusableTileStoreOGL::HarvestTiles(TiledLayerBufferOGL* aVideoMemoryTiledBuffer, // Iterate over existing harvested tiles and release any that are contained // within the new valid region, or that fall outside of the layer. mContext->MakeCurrent(); - for (int i = 0; i < mTiles.Length();) { + for (PRUint32 i = 0; i < mTiles.Length();) { ReusableTiledTextureOGL* tile = mTiles[i]; nsIntRect tileRect; @@ -163,7 +163,7 @@ ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer, const nsIntPoint& aRenderOffset) { // Render old tiles to fill in gaps we haven't had the time to render yet. - for (size_t i = 0; i < mTiles.Length(); i++) { + for (PRUint32 i = 0; i < mTiles.Length(); i++) { ReusableTiledTextureOGL* tile = mTiles[i]; // Work out the scaling factor in case of resolution differences. From 799eae8b6779c81e9dab8b20e003cb2f051d77f2 Mon Sep 17 00:00:00 2001 From: Masatoshi Kimura Date: Mon, 30 Apr 2012 15:49:15 -0700 Subject: [PATCH 046/159] Bug 750023 - Add a null check in nsXMLHttpRequest::CreatePartialBlob. r=smaug --- content/base/crashtests/crashtests.list | 1 + .../base/crashtests/xhr_abortinprogress.html | 23 +++++++++++++++++++ content/base/src/nsXMLHttpRequest.cpp | 5 ++++ 3 files changed, 29 insertions(+) create mode 100644 content/base/crashtests/xhr_abortinprogress.html diff --git a/content/base/crashtests/crashtests.list b/content/base/crashtests/crashtests.list index 7e3304e7dfdc..21e8d505769c 100644 --- a/content/base/crashtests/crashtests.list +++ b/content/base/crashtests/crashtests.list @@ -107,3 +107,4 @@ load 713417.html load 713417-2.html load 715056.html load 741163-1.html +HTTP(..) load xhr_abortinprogress.html diff --git a/content/base/crashtests/xhr_abortinprogress.html b/content/base/crashtests/xhr_abortinprogress.html new file mode 100644 index 000000000000..5345e9bf2539 --- /dev/null +++ b/content/base/crashtests/xhr_abortinprogress.html @@ -0,0 +1,23 @@ + + + + diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 0b48aabdec90..2de0c15f9950 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -1033,6 +1033,11 @@ nsXMLHttpRequest::CreatePartialBlob() return NS_OK; } + // mBuilder can be null if the request has been canceled + if (!mBuilder) { + return NS_OK; + } + nsCAutoString contentType; if (mLoadTotal == mLoadTransferred) { mChannel->GetContentType(contentType); From 9bf329bcdd20b6669a63b1b8408df7f854dd9a3a Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 30 Apr 2012 15:54:16 -0700 Subject: [PATCH 047/159] Bug 750424 - Make nsXULPrototypeNode an nsISupports (r=smaug) --- content/xul/content/src/nsXULElement.cpp | 23 +++++++++++-------- content/xul/content/src/nsXULElement.h | 17 +++----------- .../document/src/nsXULPrototypeDocument.cpp | 3 +-- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index b3e2781cc981..ff7c50a5d6c0 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -371,8 +371,7 @@ NS_TrustedNewXULElement(nsIContent** aResult, already_AddRefed aNod NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULElement, nsStyledElement) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mPrototype, - nsXULPrototypeElement) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrototype) { nsXULSlots* slots = static_cast(tmp->GetExistingSlots()); if (slots) { @@ -2526,7 +2525,7 @@ nsXULElement::RecompileScriptEventListeners() } NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeNode) -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXULPrototypeNode) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULPrototypeNode) if (tmp->mType == nsXULPrototypeNode::eType_Element) { static_cast(tmp)->Unlink(); } @@ -2534,7 +2533,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXULPrototypeNode) static_cast(tmp)->UnlinkJSObjects(); } NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXULPrototypeNode) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeNode) if (tmp->mType == nsXULPrototypeNode::eType_Element) { nsXULPrototypeElement *elem = static_cast(tmp); @@ -2550,14 +2549,13 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXULPrototypeNode) } } for (i = 0; i < elem->mChildren.Length(); ++i) { - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(elem->mChildren[i].get(), - nsXULPrototypeNode, - "mChildren[i]") + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildren[i]"); + cb.NoteXPCOMChild(elem->mChildren[i]); } } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(nsXULPrototypeNode) +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXULPrototypeNode) if (tmp->mType == nsXULPrototypeNode::eType_Element) { nsXULPrototypeElement *elem = static_cast(tmp); @@ -2577,8 +2575,13 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(nsXULPrototypeNode) "mScriptObject.mObject") } NS_IMPL_CYCLE_COLLECTION_TRACE_END -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXULPrototypeNode, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXULPrototypeNode, Release) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULPrototypeNode) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULPrototypeNode) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPrototypeNode) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END //---------------------------------------------------------------------- // diff --git a/content/xul/content/src/nsXULElement.h b/content/xul/content/src/nsXULElement.h index 958546c5844d..551c6dc70b1c 100644 --- a/content/xul/content/src/nsXULElement.h +++ b/content/xul/content/src/nsXULElement.h @@ -187,14 +187,14 @@ public: */ -class nsXULPrototypeNode +class nsXULPrototypeNode : public nsISupports { public: enum Type { eType_Element, eType_Script, eType_Text, eType_PI }; Type mType; - nsAutoRefCnt mRefCnt; + NS_DECL_CYCLE_COLLECTING_ISUPPORTS virtual ~nsXULPrototypeNode() {} virtual nsresult Serialize(nsIObjectOutputStream* aStream, @@ -210,17 +210,6 @@ public: virtual PRUint32 ClassSize() = 0; #endif - void AddRef() { - ++mRefCnt; - NS_LOG_ADDREF(this, mRefCnt, ClassName(), ClassSize()); - } - void Release() - { - --mRefCnt; - NS_LOG_RELEASE(this, mRefCnt, ClassName()); - if (mRefCnt == 0) - delete this; - } /** * The prototype document must call ReleaseSubtree when it is going * away. This makes the parents through the tree stop owning their @@ -231,7 +220,7 @@ public: */ virtual void ReleaseSubtree() { } - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsXULPrototypeNode) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsXULPrototypeNode) protected: nsXULPrototypeNode(Type aType) diff --git a/content/xul/document/src/nsXULPrototypeDocument.cpp b/content/xul/document/src/nsXULPrototypeDocument.cpp index e0321082db2f..7c0c980af922 100644 --- a/content/xul/document/src/nsXULPrototypeDocument.cpp +++ b/content/xul/document/src/nsXULPrototypeDocument.cpp @@ -204,8 +204,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeDocument) if (nsCCUncollectableMarker::InGeneration(cb, tmp->mCCGeneration)) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mRoot, - nsXULPrototypeElement) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot) NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mGlobalObject"); cb.NoteXPCOMChild(static_cast(tmp->mGlobalObject)); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager, From 25461c0da2caeeb7cb83326168d7d3e000a67af4 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 30 Apr 2012 16:00:10 -0700 Subject: [PATCH 048/159] Bug 750416 - Fix error in restoreValueArray in JS GC (r=igor) --- js/src/jit-test/tests/gc/incremental-02.js | 30 ++++++++++++++++++++++ js/src/jsgcmark.cpp | 16 +++++++----- 2 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 js/src/jit-test/tests/gc/incremental-02.js diff --git a/js/src/jit-test/tests/gc/incremental-02.js b/js/src/jit-test/tests/gc/incremental-02.js new file mode 100644 index 000000000000..4e317a42df91 --- /dev/null +++ b/js/src/jit-test/tests/gc/incremental-02.js @@ -0,0 +1,30 @@ +var objs; + +function init() +{ + objs = new Object(); + var x = new Object(); + objs.root = x; + x.a = new Object(); + x.b = new Object(); + + /* + * Clears out the arena lists. Otherwise all the objects above + * would be considered to be created during the incremental GC. + */ + gc(); +} + +/* + * Use eval here so that the interpreter frames end up higher on the + * stack, which avoids them being seen later on by the conservative + * scanner. + */ +eval("init()"); + +gcslice(0); +selectforgc(objs.root); +gcslice(1); +delete objs.root.b; +delete objs.root.a; +gcslice(); diff --git a/js/src/jsgcmark.cpp b/js/src/jsgcmark.cpp index 412f855b4e81..acb44a3a44ea 100644 --- a/js/src/jsgcmark.cpp +++ b/js/src/jsgcmark.cpp @@ -963,15 +963,17 @@ GCMarker::restoreValueArray(JSObject *obj, void **vpp, void **endp) HeapSlot *vp = obj->fixedSlots(); unsigned nfixed = obj->numFixedSlots(); unsigned nslots = obj->slotSpan(); - if (start < nfixed) { - *vpp = vp + start; - *endp = vp + Min(nfixed, nslots); - } else if (start < nslots) { - *vpp = obj->slots + start - nfixed; - *endp = obj->slots + nslots - nfixed; + if (start < nslots) { + if (start < nfixed) { + *vpp = vp + start; + *endp = vp + Min(nfixed, nslots); + } else { + *vpp = obj->slots + start - nfixed; + *endp = obj->slots + nslots - nfixed; + } } else { /* The object shrunk, in which case no scanning is needed. */ - *vpp = *endp = obj->slots; + *vpp = *endp = vp; } } From f1399a7c63c5aa211ff7e923f9e27a22b1fcbab3 Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Mon, 30 Apr 2012 14:11:12 -0700 Subject: [PATCH 049/159] Bug 750130 - Telemetry doorhanger appears then disappears when onLocationChange is fired during startup. r=bnicholson --- mobile/android/chrome/content/browser.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 51d18251d2e0..893dab289145 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -416,7 +416,10 @@ var BrowserApp = { link: { label: learnMoreLabel, url: learnMoreUrl - } + }, + // We're adding this doorhanger during startup, before the initial onLocationChange + // event fires, so we need to set persistence to make sure it doesn't disappear. + persistence: 1 }; NativeWindow.doorhanger.show(message, "telemetry-optin", buttons, this.selectedTab.id, options); }, From 4b5cc3352d267594ab7a592da071493e37e56582 Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Mon, 30 Apr 2012 16:20:22 -0700 Subject: [PATCH 050/159] Bug 674225 - Add the opus draft-11 source to the tree. - r=derf This is the IETF Opus audio codec reference implementation. The source was copied into the tree using the included update.sh script, from a checkout of the v0.9.9 git tag, which corresponds to the source code published in https://tools.ietf.org/id/draft-ietf-codec-opus-11.txt --- media/libopus/COPYING | 27 + media/libopus/README_MOZILLA | 11 + media/libopus/celt/_kiss_fft_guts.h | 176 + media/libopus/celt/arch.h | 208 ++ media/libopus/celt/bands.c | 1297 ++++++++ media/libopus/celt/bands.h | 95 + media/libopus/celt/celt.c | 2847 +++++++++++++++++ media/libopus/celt/celt.h | 117 + media/libopus/celt/celt_lpc.c | 188 ++ media/libopus/celt/celt_lpc.h | 53 + media/libopus/celt/cwrs.c | 644 ++++ media/libopus/celt/cwrs.h | 48 + media/libopus/celt/ecintrin.h | 102 + media/libopus/celt/entcode.c | 88 + media/libopus/celt/entcode.h | 116 + media/libopus/celt/entdec.c | 249 ++ media/libopus/celt/entdec.h | 100 + media/libopus/celt/entenc.c | 294 ++ media/libopus/celt/entenc.h | 110 + media/libopus/celt/fixed_debug.h | 511 +++ media/libopus/celt/fixed_generic.h | 126 + media/libopus/celt/float_cast.h | 138 + media/libopus/celt/kiss_fft.c | 722 +++++ media/libopus/celt/kiss_fft.h | 152 + media/libopus/celt/laplace.c | 133 + media/libopus/celt/laplace.h | 48 + media/libopus/celt/mathops.c | 201 ++ media/libopus/celt/mathops.h | 226 ++ media/libopus/celt/mdct.c | 332 ++ media/libopus/celt/mdct.h | 67 + media/libopus/celt/mfrngcod.h | 48 + media/libopus/celt/modes.c | 430 +++ media/libopus/celt/modes.h | 83 + media/libopus/celt/os_support.h | 89 + media/libopus/celt/pitch.c | 385 +++ media/libopus/celt/pitch.h | 48 + media/libopus/celt/quant_bands.c | 567 ++++ media/libopus/celt/quant_bands.h | 60 + media/libopus/celt/rate.c | 638 ++++ media/libopus/celt/rate.h | 101 + media/libopus/celt/stack_alloc.h | 145 + media/libopus/celt/static_modes_fixed.h | 595 ++++ media/libopus/celt/static_modes_float.h | 599 ++++ media/libopus/celt/vq.c | 431 +++ media/libopus/celt/vq.h | 73 + media/libopus/celt_sources.mk | 16 + media/libopus/include/opus.h | 514 +++ media/libopus/include/opus_custom.h | 213 ++ media/libopus/include/opus_defines.h | 442 +++ media/libopus/include/opus_multistream.h | 164 + media/libopus/include/opus_types.h | 159 + media/libopus/opus_sources.mk | 5 + media/libopus/silk/A2NLSF.c | 252 ++ media/libopus/silk/API.h | 138 + media/libopus/silk/CNG.c | 167 + media/libopus/silk/HP_variable_cutoff.c | 77 + media/libopus/silk/Inlines.h | 188 ++ media/libopus/silk/LPC_analysis_filter.c | 85 + media/libopus/silk/LPC_inv_pred_gain.c | 154 + media/libopus/silk/LP_variable_cutoff.c | 135 + media/libopus/silk/MacroCount.h | 719 +++++ media/libopus/silk/MacroDebug.h | 569 ++++ media/libopus/silk/NLSF2A.c | 178 ++ media/libopus/silk/NLSF_VQ.c | 68 + media/libopus/silk/NLSF_VQ_weights_laroia.c | 80 + media/libopus/silk/NLSF_decode.c | 101 + media/libopus/silk/NLSF_del_dec_quant.c | 207 ++ media/libopus/silk/NLSF_encode.c | 128 + media/libopus/silk/NLSF_stabilize.c | 142 + media/libopus/silk/NLSF_unpack.c | 55 + media/libopus/silk/NSQ.c | 439 +++ media/libopus/silk/NSQ_del_dec.c | 705 ++++ media/libopus/silk/PLC.c | 416 +++ media/libopus/silk/PLC.h | 62 + media/libopus/silk/SigProc_FIX.h | 594 ++++ media/libopus/silk/VAD.c | 331 ++ media/libopus/silk/VQ_WMat_EC.c | 111 + media/libopus/silk/ana_filt_bank_1.c | 74 + media/libopus/silk/biquad_alt.c | 78 + media/libopus/silk/bwexpander.c | 51 + media/libopus/silk/bwexpander_32.c | 50 + media/libopus/silk/check_control_input.c | 106 + media/libopus/silk/code_signs.c | 115 + media/libopus/silk/control.h | 139 + media/libopus/silk/control_SNR.c | 81 + media/libopus/silk/control_audio_bandwidth.c | 119 + media/libopus/silk/control_codec.c | 411 +++ media/libopus/silk/debug.c | 170 + media/libopus/silk/debug.h | 287 ++ media/libopus/silk/dec_API.c | 373 +++ media/libopus/silk/decode_core.c | 230 ++ media/libopus/silk/decode_frame.c | 125 + media/libopus/silk/decode_indices.c | 151 + media/libopus/silk/decode_parameters.c | 115 + media/libopus/silk/decode_pitch.c | 77 + media/libopus/silk/decode_pulses.c | 115 + media/libopus/silk/decoder_set_fs.c | 108 + media/libopus/silk/define.h | 240 ++ media/libopus/silk/enc_API.c | 530 +++ media/libopus/silk/encode_indices.c | 181 ++ media/libopus/silk/encode_pulses.c | 199 ++ media/libopus/silk/errors.h | 98 + .../silk/fixed/LTP_analysis_filter_FIX.c | 85 + media/libopus/silk/fixed/LTP_scale_ctrl_FIX.c | 53 + .../silk/fixed/apply_sine_window_FIX.c | 101 + media/libopus/silk/fixed/autocorr_FIX.c | 76 + media/libopus/silk/fixed/burg_modified_FIX.c | 269 ++ media/libopus/silk/fixed/corrMatrix_FIX.c | 156 + media/libopus/silk/fixed/encode_frame_FIX.c | 372 +++ media/libopus/silk/fixed/find_LPC_FIX.c | 145 + media/libopus/silk/fixed/find_LTP_FIX.c | 244 ++ .../libopus/silk/fixed/find_pitch_lags_FIX.c | 137 + .../libopus/silk/fixed/find_pred_coefs_FIX.c | 136 + media/libopus/silk/fixed/k2a_FIX.c | 53 + media/libopus/silk/fixed/k2a_Q16_FIX.c | 53 + media/libopus/silk/fixed/main_FIX.h | 254 ++ .../silk/fixed/noise_shape_analysis_FIX.c | 437 +++ .../silk/fixed/pitch_analysis_core_FIX.c | 745 +++++ media/libopus/silk/fixed/prefilter_FIX.c | 204 ++ media/libopus/silk/fixed/process_gains_FIX.c | 117 + .../silk/fixed/regularize_correlations_FIX.c | 47 + .../silk/fixed/residual_energy16_FIX.c | 103 + .../libopus/silk/fixed/residual_energy_FIX.c | 91 + media/libopus/silk/fixed/schur64_FIX.c | 77 + media/libopus/silk/fixed/schur_FIX.c | 92 + media/libopus/silk/fixed/solve_LS_FIX.c | 245 ++ media/libopus/silk/fixed/structs_FIX.h | 133 + media/libopus/silk/fixed/vector_ops_FIX.c | 127 + .../silk/fixed/warped_autocorrelation_FIX.c | 88 + .../silk/float/LPC_analysis_filter_FLP.c | 249 ++ .../silk/float/LPC_inv_pred_gain_FLP.c | 76 + .../silk/float/LTP_analysis_filter_FLP.c | 75 + media/libopus/silk/float/LTP_scale_ctrl_FLP.c | 52 + media/libopus/silk/float/SigProc_FLP.h | 206 ++ .../silk/float/apply_sine_window_FLP.c | 81 + .../libopus/silk/float/autocorrelation_FLP.c | 52 + media/libopus/silk/float/burg_modified_FLP.c | 186 ++ media/libopus/silk/float/bwexpander_FLP.c | 49 + media/libopus/silk/float/corrMatrix_FLP.c | 93 + media/libopus/silk/float/encode_frame_FLP.c | 372 +++ media/libopus/silk/float/energy_FLP.c | 60 + media/libopus/silk/float/find_LPC_FLP.c | 104 + media/libopus/silk/float/find_LTP_FLP.c | 132 + .../libopus/silk/float/find_pitch_lags_FLP.c | 131 + .../libopus/silk/float/find_pred_coefs_FLP.c | 116 + media/libopus/silk/float/inner_product_FLP.c | 60 + media/libopus/silk/float/k2a_FLP.c | 53 + media/libopus/silk/float/levinsondurbin_FLP.c | 81 + media/libopus/silk/float/main_FLP.h | 309 ++ .../silk/float/noise_shape_analysis_FLP.c | 363 +++ .../silk/float/pitch_analysis_core_FLP.c | 630 ++++ media/libopus/silk/float/prefilter_FLP.c | 206 ++ media/libopus/silk/float/process_gains_FLP.c | 103 + .../silk/float/regularize_correlations_FLP.c | 48 + .../libopus/silk/float/residual_energy_FLP.c | 117 + .../silk/float/scale_copy_vector_FLP.c | 57 + media/libopus/silk/float/scale_vector_FLP.c | 56 + media/libopus/silk/float/schur_FLP.c | 70 + media/libopus/silk/float/solve_LS_FLP.c | 207 ++ media/libopus/silk/float/sort_FLP.c | 83 + media/libopus/silk/float/structs_FLP.h | 131 + .../silk/float/warped_autocorrelation_FLP.c | 73 + media/libopus/silk/float/wrappers_FLP.c | 200 ++ media/libopus/silk/gain_quant.c | 141 + media/libopus/silk/init_decoder.c | 56 + media/libopus/silk/init_encoder.c | 60 + media/libopus/silk/inner_prod_aligned.c | 47 + media/libopus/silk/interpolate.c | 51 + media/libopus/silk/lin2log.c | 46 + media/libopus/silk/log2lin.c | 56 + media/libopus/silk/macros.h | 136 + media/libopus/silk/main.h | 434 +++ media/libopus/silk/pitch_est_defines.h | 92 + media/libopus/silk/pitch_est_tables.c | 99 + media/libopus/silk/process_NLSFs.c | 105 + media/libopus/silk/quant_LTP_gains.c | 107 + media/libopus/silk/resampler.c | 215 ++ media/libopus/silk/resampler_down2.c | 74 + media/libopus/silk/resampler_down2_3.c | 98 + media/libopus/silk/resampler_private.h | 88 + media/libopus/silk/resampler_private_AR2.c | 55 + .../libopus/silk/resampler_private_IIR_FIR.c | 103 + .../libopus/silk/resampler_private_down_FIR.c | 189 ++ media/libopus/silk/resampler_private_up2_HQ.c | 113 + media/libopus/silk/resampler_rom.c | 104 + media/libopus/silk/resampler_rom.h | 68 + media/libopus/silk/resampler_structs.h | 57 + media/libopus/silk/shell_coder.c | 151 + media/libopus/silk/sigm_Q15.c | 76 + media/libopus/silk/sort.c | 154 + media/libopus/silk/stereo_LR_to_MS.c | 219 ++ media/libopus/silk/stereo_MS_to_LR.c | 85 + media/libopus/silk/stereo_decode_pred.c | 73 + media/libopus/silk/stereo_encode_pred.c | 62 + media/libopus/silk/stereo_find_predictor.c | 79 + media/libopus/silk/stereo_quant_pred.c | 73 + media/libopus/silk/structs.h | 324 ++ media/libopus/silk/sum_sqr_shift.c | 85 + media/libopus/silk/table_LSF_cos.c | 70 + media/libopus/silk/tables.h | 120 + media/libopus/silk/tables_LTP.c | 272 ++ media/libopus/silk/tables_NLSF_CB_NB_MB.c | 159 + media/libopus/silk/tables_NLSF_CB_WB.c | 198 ++ media/libopus/silk/tables_gain.c | 63 + media/libopus/silk/tables_other.c | 138 + media/libopus/silk/tables_pitch_lag.c | 69 + media/libopus/silk/tables_pulses_per_block.c | 264 ++ media/libopus/silk/tuning_parameters.h | 168 + media/libopus/silk/typedef.h | 102 + media/libopus/silk_sources.mk | 138 + media/libopus/src/opus.c | 47 + media/libopus/src/opus_decoder.c | 936 ++++++ media/libopus/src/opus_encoder.c | 1543 +++++++++ media/libopus/src/opus_multistream.c | 853 +++++ media/libopus/src/opus_private.h | 86 + media/libopus/src/repacketizer.c | 208 ++ media/libopus/update.sh | 59 + 217 files changed, 44544 insertions(+) create mode 100644 media/libopus/COPYING create mode 100644 media/libopus/README_MOZILLA create mode 100644 media/libopus/celt/_kiss_fft_guts.h create mode 100644 media/libopus/celt/arch.h create mode 100644 media/libopus/celt/bands.c create mode 100644 media/libopus/celt/bands.h create mode 100644 media/libopus/celt/celt.c create mode 100644 media/libopus/celt/celt.h create mode 100644 media/libopus/celt/celt_lpc.c create mode 100644 media/libopus/celt/celt_lpc.h create mode 100644 media/libopus/celt/cwrs.c create mode 100644 media/libopus/celt/cwrs.h create mode 100644 media/libopus/celt/ecintrin.h create mode 100644 media/libopus/celt/entcode.c create mode 100644 media/libopus/celt/entcode.h create mode 100644 media/libopus/celt/entdec.c create mode 100644 media/libopus/celt/entdec.h create mode 100644 media/libopus/celt/entenc.c create mode 100644 media/libopus/celt/entenc.h create mode 100644 media/libopus/celt/fixed_debug.h create mode 100644 media/libopus/celt/fixed_generic.h create mode 100644 media/libopus/celt/float_cast.h create mode 100644 media/libopus/celt/kiss_fft.c create mode 100644 media/libopus/celt/kiss_fft.h create mode 100644 media/libopus/celt/laplace.c create mode 100644 media/libopus/celt/laplace.h create mode 100644 media/libopus/celt/mathops.c create mode 100644 media/libopus/celt/mathops.h create mode 100644 media/libopus/celt/mdct.c create mode 100644 media/libopus/celt/mdct.h create mode 100644 media/libopus/celt/mfrngcod.h create mode 100644 media/libopus/celt/modes.c create mode 100644 media/libopus/celt/modes.h create mode 100644 media/libopus/celt/os_support.h create mode 100644 media/libopus/celt/pitch.c create mode 100644 media/libopus/celt/pitch.h create mode 100644 media/libopus/celt/quant_bands.c create mode 100644 media/libopus/celt/quant_bands.h create mode 100644 media/libopus/celt/rate.c create mode 100644 media/libopus/celt/rate.h create mode 100644 media/libopus/celt/stack_alloc.h create mode 100644 media/libopus/celt/static_modes_fixed.h create mode 100644 media/libopus/celt/static_modes_float.h create mode 100644 media/libopus/celt/vq.c create mode 100644 media/libopus/celt/vq.h create mode 100644 media/libopus/celt_sources.mk create mode 100644 media/libopus/include/opus.h create mode 100644 media/libopus/include/opus_custom.h create mode 100644 media/libopus/include/opus_defines.h create mode 100644 media/libopus/include/opus_multistream.h create mode 100644 media/libopus/include/opus_types.h create mode 100644 media/libopus/opus_sources.mk create mode 100644 media/libopus/silk/A2NLSF.c create mode 100644 media/libopus/silk/API.h create mode 100644 media/libopus/silk/CNG.c create mode 100644 media/libopus/silk/HP_variable_cutoff.c create mode 100644 media/libopus/silk/Inlines.h create mode 100644 media/libopus/silk/LPC_analysis_filter.c create mode 100644 media/libopus/silk/LPC_inv_pred_gain.c create mode 100644 media/libopus/silk/LP_variable_cutoff.c create mode 100644 media/libopus/silk/MacroCount.h create mode 100644 media/libopus/silk/MacroDebug.h create mode 100644 media/libopus/silk/NLSF2A.c create mode 100644 media/libopus/silk/NLSF_VQ.c create mode 100644 media/libopus/silk/NLSF_VQ_weights_laroia.c create mode 100644 media/libopus/silk/NLSF_decode.c create mode 100644 media/libopus/silk/NLSF_del_dec_quant.c create mode 100644 media/libopus/silk/NLSF_encode.c create mode 100644 media/libopus/silk/NLSF_stabilize.c create mode 100644 media/libopus/silk/NLSF_unpack.c create mode 100644 media/libopus/silk/NSQ.c create mode 100644 media/libopus/silk/NSQ_del_dec.c create mode 100644 media/libopus/silk/PLC.c create mode 100644 media/libopus/silk/PLC.h create mode 100644 media/libopus/silk/SigProc_FIX.h create mode 100644 media/libopus/silk/VAD.c create mode 100644 media/libopus/silk/VQ_WMat_EC.c create mode 100644 media/libopus/silk/ana_filt_bank_1.c create mode 100644 media/libopus/silk/biquad_alt.c create mode 100644 media/libopus/silk/bwexpander.c create mode 100644 media/libopus/silk/bwexpander_32.c create mode 100644 media/libopus/silk/check_control_input.c create mode 100644 media/libopus/silk/code_signs.c create mode 100644 media/libopus/silk/control.h create mode 100644 media/libopus/silk/control_SNR.c create mode 100644 media/libopus/silk/control_audio_bandwidth.c create mode 100644 media/libopus/silk/control_codec.c create mode 100644 media/libopus/silk/debug.c create mode 100644 media/libopus/silk/debug.h create mode 100644 media/libopus/silk/dec_API.c create mode 100644 media/libopus/silk/decode_core.c create mode 100644 media/libopus/silk/decode_frame.c create mode 100644 media/libopus/silk/decode_indices.c create mode 100644 media/libopus/silk/decode_parameters.c create mode 100644 media/libopus/silk/decode_pitch.c create mode 100644 media/libopus/silk/decode_pulses.c create mode 100644 media/libopus/silk/decoder_set_fs.c create mode 100644 media/libopus/silk/define.h create mode 100644 media/libopus/silk/enc_API.c create mode 100644 media/libopus/silk/encode_indices.c create mode 100644 media/libopus/silk/encode_pulses.c create mode 100644 media/libopus/silk/errors.h create mode 100644 media/libopus/silk/fixed/LTP_analysis_filter_FIX.c create mode 100644 media/libopus/silk/fixed/LTP_scale_ctrl_FIX.c create mode 100644 media/libopus/silk/fixed/apply_sine_window_FIX.c create mode 100644 media/libopus/silk/fixed/autocorr_FIX.c create mode 100644 media/libopus/silk/fixed/burg_modified_FIX.c create mode 100644 media/libopus/silk/fixed/corrMatrix_FIX.c create mode 100644 media/libopus/silk/fixed/encode_frame_FIX.c create mode 100644 media/libopus/silk/fixed/find_LPC_FIX.c create mode 100644 media/libopus/silk/fixed/find_LTP_FIX.c create mode 100644 media/libopus/silk/fixed/find_pitch_lags_FIX.c create mode 100644 media/libopus/silk/fixed/find_pred_coefs_FIX.c create mode 100644 media/libopus/silk/fixed/k2a_FIX.c create mode 100644 media/libopus/silk/fixed/k2a_Q16_FIX.c create mode 100644 media/libopus/silk/fixed/main_FIX.h create mode 100644 media/libopus/silk/fixed/noise_shape_analysis_FIX.c create mode 100644 media/libopus/silk/fixed/pitch_analysis_core_FIX.c create mode 100644 media/libopus/silk/fixed/prefilter_FIX.c create mode 100644 media/libopus/silk/fixed/process_gains_FIX.c create mode 100644 media/libopus/silk/fixed/regularize_correlations_FIX.c create mode 100644 media/libopus/silk/fixed/residual_energy16_FIX.c create mode 100644 media/libopus/silk/fixed/residual_energy_FIX.c create mode 100644 media/libopus/silk/fixed/schur64_FIX.c create mode 100644 media/libopus/silk/fixed/schur_FIX.c create mode 100644 media/libopus/silk/fixed/solve_LS_FIX.c create mode 100644 media/libopus/silk/fixed/structs_FIX.h create mode 100644 media/libopus/silk/fixed/vector_ops_FIX.c create mode 100644 media/libopus/silk/fixed/warped_autocorrelation_FIX.c create mode 100644 media/libopus/silk/float/LPC_analysis_filter_FLP.c create mode 100644 media/libopus/silk/float/LPC_inv_pred_gain_FLP.c create mode 100644 media/libopus/silk/float/LTP_analysis_filter_FLP.c create mode 100644 media/libopus/silk/float/LTP_scale_ctrl_FLP.c create mode 100644 media/libopus/silk/float/SigProc_FLP.h create mode 100644 media/libopus/silk/float/apply_sine_window_FLP.c create mode 100644 media/libopus/silk/float/autocorrelation_FLP.c create mode 100644 media/libopus/silk/float/burg_modified_FLP.c create mode 100644 media/libopus/silk/float/bwexpander_FLP.c create mode 100644 media/libopus/silk/float/corrMatrix_FLP.c create mode 100644 media/libopus/silk/float/encode_frame_FLP.c create mode 100644 media/libopus/silk/float/energy_FLP.c create mode 100644 media/libopus/silk/float/find_LPC_FLP.c create mode 100644 media/libopus/silk/float/find_LTP_FLP.c create mode 100644 media/libopus/silk/float/find_pitch_lags_FLP.c create mode 100644 media/libopus/silk/float/find_pred_coefs_FLP.c create mode 100644 media/libopus/silk/float/inner_product_FLP.c create mode 100644 media/libopus/silk/float/k2a_FLP.c create mode 100644 media/libopus/silk/float/levinsondurbin_FLP.c create mode 100644 media/libopus/silk/float/main_FLP.h create mode 100644 media/libopus/silk/float/noise_shape_analysis_FLP.c create mode 100644 media/libopus/silk/float/pitch_analysis_core_FLP.c create mode 100644 media/libopus/silk/float/prefilter_FLP.c create mode 100644 media/libopus/silk/float/process_gains_FLP.c create mode 100644 media/libopus/silk/float/regularize_correlations_FLP.c create mode 100644 media/libopus/silk/float/residual_energy_FLP.c create mode 100644 media/libopus/silk/float/scale_copy_vector_FLP.c create mode 100644 media/libopus/silk/float/scale_vector_FLP.c create mode 100644 media/libopus/silk/float/schur_FLP.c create mode 100644 media/libopus/silk/float/solve_LS_FLP.c create mode 100644 media/libopus/silk/float/sort_FLP.c create mode 100644 media/libopus/silk/float/structs_FLP.h create mode 100644 media/libopus/silk/float/warped_autocorrelation_FLP.c create mode 100644 media/libopus/silk/float/wrappers_FLP.c create mode 100644 media/libopus/silk/gain_quant.c create mode 100644 media/libopus/silk/init_decoder.c create mode 100644 media/libopus/silk/init_encoder.c create mode 100644 media/libopus/silk/inner_prod_aligned.c create mode 100644 media/libopus/silk/interpolate.c create mode 100644 media/libopus/silk/lin2log.c create mode 100644 media/libopus/silk/log2lin.c create mode 100644 media/libopus/silk/macros.h create mode 100644 media/libopus/silk/main.h create mode 100644 media/libopus/silk/pitch_est_defines.h create mode 100644 media/libopus/silk/pitch_est_tables.c create mode 100644 media/libopus/silk/process_NLSFs.c create mode 100644 media/libopus/silk/quant_LTP_gains.c create mode 100644 media/libopus/silk/resampler.c create mode 100644 media/libopus/silk/resampler_down2.c create mode 100644 media/libopus/silk/resampler_down2_3.c create mode 100644 media/libopus/silk/resampler_private.h create mode 100644 media/libopus/silk/resampler_private_AR2.c create mode 100644 media/libopus/silk/resampler_private_IIR_FIR.c create mode 100644 media/libopus/silk/resampler_private_down_FIR.c create mode 100644 media/libopus/silk/resampler_private_up2_HQ.c create mode 100644 media/libopus/silk/resampler_rom.c create mode 100644 media/libopus/silk/resampler_rom.h create mode 100644 media/libopus/silk/resampler_structs.h create mode 100644 media/libopus/silk/shell_coder.c create mode 100644 media/libopus/silk/sigm_Q15.c create mode 100644 media/libopus/silk/sort.c create mode 100644 media/libopus/silk/stereo_LR_to_MS.c create mode 100644 media/libopus/silk/stereo_MS_to_LR.c create mode 100644 media/libopus/silk/stereo_decode_pred.c create mode 100644 media/libopus/silk/stereo_encode_pred.c create mode 100644 media/libopus/silk/stereo_find_predictor.c create mode 100644 media/libopus/silk/stereo_quant_pred.c create mode 100644 media/libopus/silk/structs.h create mode 100644 media/libopus/silk/sum_sqr_shift.c create mode 100644 media/libopus/silk/table_LSF_cos.c create mode 100644 media/libopus/silk/tables.h create mode 100644 media/libopus/silk/tables_LTP.c create mode 100644 media/libopus/silk/tables_NLSF_CB_NB_MB.c create mode 100644 media/libopus/silk/tables_NLSF_CB_WB.c create mode 100644 media/libopus/silk/tables_gain.c create mode 100644 media/libopus/silk/tables_other.c create mode 100644 media/libopus/silk/tables_pitch_lag.c create mode 100644 media/libopus/silk/tables_pulses_per_block.c create mode 100644 media/libopus/silk/tuning_parameters.h create mode 100644 media/libopus/silk/typedef.h create mode 100644 media/libopus/silk_sources.mk create mode 100644 media/libopus/src/opus.c create mode 100644 media/libopus/src/opus_decoder.c create mode 100644 media/libopus/src/opus_encoder.c create mode 100644 media/libopus/src/opus_multistream.c create mode 100644 media/libopus/src/opus_private.h create mode 100644 media/libopus/src/repacketizer.c create mode 100755 media/libopus/update.sh diff --git a/media/libopus/COPYING b/media/libopus/COPYING new file mode 100644 index 000000000000..240ee0916548 --- /dev/null +++ b/media/libopus/COPYING @@ -0,0 +1,27 @@ +Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic, + Jean-Marc Valin, Timothy B. Terriberry, + CSIRO, Gregory Maxwell, Mark Borgerding, + Erik de Castro Lopo + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/media/libopus/README_MOZILLA b/media/libopus/README_MOZILLA new file mode 100644 index 000000000000..5c618ce8ded4 --- /dev/null +++ b/media/libopus/README_MOZILLA @@ -0,0 +1,11 @@ +IETF Opus audio codec reference implementation. + +The source in this directory was copied from an opus +repository checkout by running the ./update.sh script. +Any changes made to this version of the source should +be reflected in that script, e.g. by applying patch +files after the copy step. + +The upstream repository is https://git.xiph.org/opus.git + +The git tag/revision used was v0.9.9. diff --git a/media/libopus/celt/_kiss_fft_guts.h b/media/libopus/celt/_kiss_fft_guts.h new file mode 100644 index 000000000000..637ce2a0f34d --- /dev/null +++ b/media/libopus/celt/_kiss_fft_guts.h @@ -0,0 +1,176 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.*/ + +#ifndef KISS_FFT_GUTS_H +#define KISS_FFT_GUTS_H + +#define MIN(a,b) ((a)<(b) ? (a):(b)) +#define MAX(a,b) ((a)>(b) ? (a):(b)) + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#include "arch.h" + + +# define SAMPPROD long long +#define SAMP_MAX 2147483647 +#define TWID_MAX 32767 +#define TRIG_UPSCALE 1 + +#define SAMP_MIN -SAMP_MAX + + +# define S_MUL(a,b) MULT16_32_Q15(b, a) + +# define C_MUL(m,a,b) \ + do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0) + +# define C_MULC(m,a,b) \ + do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = SUB32(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0) + +# define C_MUL4(m,a,b) \ + do{ (m).r = SHR(SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)),2); \ + (m).i = SHR(ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)),2); }while(0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = S_MUL( (c).r , s ) ;\ + (c).i = S_MUL( (c).i , s ) ; }while(0) + +# define DIVSCALAR(x,k) \ + (x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +#define C_ADD( res, a,b)\ + do {(res).r=ADD32((a).r,(b).r); (res).i=ADD32((a).i,(b).i); \ + }while(0) +#define C_SUB( res, a,b)\ + do {(res).r=SUB32((a).r,(b).r); (res).i=SUB32((a).i,(b).i); \ + }while(0) +#define C_ADDTO( res , a)\ + do {(res).r = ADD32((res).r, (a).r); (res).i = ADD32((res).i,(a).i);\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {(res).r = ADD32((res).r,(a).r); (res).i = SUB32((res).i,(a).i); \ + }while(0) + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) +#define C_MULC(m,a,b) \ + do{ (m).r = (a).r*(b).r + (a).i*(b).i;\ + (m).i = (a).i*(b).r - (a).r*(b).i; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#ifndef C_ADD +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) +#endif /* C_ADD defined */ + +#ifdef FIXED_POINT +/*# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) +# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/ +# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase)) +# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase)) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5f)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5f) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) + +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\ + (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\ +}while(0) + +#endif /* KISS_FFT_GUTS_H */ diff --git a/media/libopus/celt/arch.h b/media/libopus/celt/arch.h new file mode 100644 index 000000000000..48428c23f16d --- /dev/null +++ b/media/libopus/celt/arch.h @@ -0,0 +1,208 @@ +/* Copyright (c) 2003-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions for CELT +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#include "opus_types.h" + +# if !defined(__GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define __GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define __GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#define CELT_SIG_SCALE 32768.f + +#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__); +#ifdef ENABLE_ASSERTIONS +#include +#include +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +static inline void _celt_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +#define celt_assert(cond) {if (!(cond)) {celt_fatal("assertion failed: " #cond);}} +#define celt_assert2(cond, message) {if (!(cond)) {celt_fatal("assertion failed: " #cond "\n" message);}} +#else +#define celt_assert(cond) +#define celt_assert2(cond, message) +#endif + +#define IMUL32(a,b) ((a)*(b)) + +#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */ +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */ +#define UADD32(a,b) ((a)+(b)) +#define USUB32(a,b) ((a)-(b)) + +#define PRINT_MIPS(file) + +#ifdef FIXED_POINT + +typedef opus_int16 opus_val16; +typedef opus_int32 opus_val32; + +typedef opus_val32 celt_sig; +typedef opus_val16 celt_norm; +typedef opus_val32 celt_ener; + +#define Q15ONE 32767 + +#define SIG_SHIFT 12 + +#define NORM_SCALING 16384 + +#define DB_SHIFT 10 + +#define EPSILON 1 +#define VERY_LARGE16 ((opus_val16)32767) +#define Q15_ONE ((opus_val16)32767) + +#define SCALEIN(a) (a) +#define SCALEOUT(a) (a) + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef ARM5E_ASM +#include "fixed_arm5e.h" +#elif defined (ARM4_ASM) +#include "fixed_arm4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#elif defined (TI_C5X_ASM) +#include "fixed_c5x.h" +#elif defined (TI_C6X_ASM) +#include "fixed_c6x.h" +#endif + +#endif + +#else /* FIXED_POINT */ + +typedef float opus_val16; +typedef float opus_val32; + +typedef float celt_sig; +typedef float celt_norm; +typedef float celt_ener; + +#define Q15ONE 1.0f + +#define NORM_SCALING 1.f + +#define EPSILON 1e-15f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((opus_val16)1.f) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) + +#define ROUND16(a,shift) (a) +#define HALF16(x) (.5f*(x)) +#define HALF32(x) (.5f*(x)) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b)) +#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b)) + +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_Q16(a,b) ((a)*(b)) + +#define MULT32_32_Q31(a,b) ((a)*(b)) + +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) + +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b)) +#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b)) + +#define SCALEIN(a) ((a)*CELT_SIG_SCALE) +#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE)) + +#endif /* !FIXED_POINT */ + +#ifndef GLOBAL_STACK_SIZE +#ifdef FIXED_POINT +#define GLOBAL_STACK_SIZE 100000 +#else +#define GLOBAL_STACK_SIZE 100000 +#endif +#endif + +#endif /* ARCH_H */ diff --git a/media/libopus/celt/bands.c b/media/libopus/celt/bands.c new file mode 100644 index 000000000000..68b362613842 --- /dev/null +++ b/media/libopus/celt/bands.c @@ -0,0 +1,1297 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2009 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "bands.h" +#include "modes.h" +#include "vq.h" +#include "cwrs.h" +#include "stack_alloc.h" +#include "os_support.h" +#include "mathops.h" +#include "rate.h" + +opus_uint32 celt_lcg_rand(opus_uint32 seed) +{ + return 1664525 * seed + 1013904223; +} + +/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness + with this approximation is important because it has an impact on the bit allocation */ +static opus_int16 bitexact_cos(opus_int16 x) +{ + opus_int32 tmp; + opus_int16 x2; + tmp = (4096+((opus_int32)(x)*(x)))>>13; + celt_assert(tmp<=32767); + x2 = tmp; + x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2))))); + celt_assert(x2<=32766); + return 1+x2; +} + +static int bitexact_log2tan(int isin,int icos) +{ + int lc; + int ls; + lc=EC_ILOG(icos); + ls=EC_ILOG(isin); + icos<<=15-lc; + isin<<=15-ls; + return (ls-lc)*(1<<11) + +FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932) + -FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932); +} + +#ifdef FIXED_POINT +/* Compute the amplitude (sqrt energy) in each of the bands */ +void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int M) +{ + int i, c, N; + const opus_int16 *eBands = m->eBands; + N = M*m->shortMdctSize; + c=0; do { + for (i=0;i 0) + { + int shift = celt_ilog2(maxval)-10; + j=M*eBands[i]; do { + sum = MAC16_16(sum, EXTRACT16(VSHR32(X[j+c*N],shift)), + EXTRACT16(VSHR32(X[j+c*N],shift))); + } while (++jnbEBands] = EPSILON+VSHR32(EXTEND32(celt_sqrt(sum)),-shift); + } else { + bandE[i+c*m->nbEBands] = EPSILON; + } + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + i=0; do { + opus_val16 g; + int j,shift; + opus_val16 E; + shift = celt_zlog2(bandE[i+c*m->nbEBands])-13; + E = VSHR32(bandE[i+c*m->nbEBands], shift); + g = EXTRACT16(celt_rcp(SHL32(E,3))); + j=M*eBands[i]; do { + X[j+c*N] = MULT16_16_Q15(VSHR32(freq[j+c*N],shift-1),g); + } while (++jeBands; + N = M*m->shortMdctSize; + c=0; do { + for (i=0;inbEBands] = celt_sqrt(sum); + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + for (i=0;inbEBands]); + for (j=M*eBands[i];jeBands; + N = M*m->shortMdctSize; + celt_assert2(C<=2, "denormalise_bands() not implemented for >2 channels"); + c=0; do { + celt_sig * restrict f; + const celt_norm * restrict x; + f = freq+c*N; + x = X+c*N; + for (i=0;inbEBands],1); + j=M*eBands[i]; + band_end = M*eBands[i+1]; + do { + *f++ = SHL32(MULT16_32_Q15(*x, g),2); + x++; + } while (++jeBands[i+1]-m->eBands[i]; + /* depth in 1/8 bits */ + depth = (1+pulses[i])/((m->eBands[i+1]-m->eBands[i])<>1; + t = SHL32(t, (7-shift)<<1); + sqrt_1 = celt_rsqrt_norm(t); + } +#else + thresh = .5f*celt_exp2(-.125f*depth); + sqrt_1 = celt_rsqrt(N0<nbEBands+i]; + prev2 = prev2logE[c*m->nbEBands+i]; + if (C==1) + { + prev1 = MAX16(prev1,prev1logE[m->nbEBands+i]); + prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]); + } + Ediff = EXTEND32(logE[c*m->nbEBands+i])-EXTEND32(MIN16(prev1,prev2)); + Ediff = MAX16(0, Ediff); + +#ifdef FIXED_POINT + if (Ediff < 16384) + r = 2*MIN16(16383,SHR32(celt_exp2(-EXTRACT16(Ediff)),1)); + else + r = 0; + if (LM==3) + r = MULT16_16_Q14(23170, MIN32(23169, r)); + r = SHR16(MIN16(thresh, r),1); + r = SHR32(MULT16_16_Q15(sqrt_1, r),shift); +#else + /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because + short blocks don't have the same energy as long */ + r = 2.f*celt_exp2(-Ediff); + if (LM==3) + r *= 1.41421356f; + r = MIN16(thresh, r); + r = r*sqrt_1; +#endif + X = X_+c*size+(m->eBands[i]<nbEBands]))-13; +#endif + left = VSHR32(bandE[i],shift); + right = VSHR32(bandE[i+m->nbEBands],shift); + norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right)); + a1 = DIV32_16(SHL32(EXTEND32(left),14),norm); + a2 = DIV32_16(SHL32(EXTEND32(right),14),norm); + for (j=0;j>1; + kr = celt_ilog2(Er)>>1; +#endif + t = VSHR32(El, (kl-7)<<1); + lgain = celt_rsqrt_norm(t); + t = VSHR32(Er, (kr-7)<<1); + rgain = celt_rsqrt_norm(t); + +#ifdef FIXED_POINT + if (kl < 7) + kl = 7; + if (kr < 7) + kr = 7; +#endif + + for (j=0;jeBands; + int decision; + int hf_sum=0; + + celt_assert(end>0); + + N0 = M*m->shortMdctSize; + + if (M*(eBands[end]-eBands[end-1]) <= 8) + return SPREAD_NONE; + c=0; do { + for (i=0;im->nbEBands-4) + hf_sum += 32*(tcount[1]+tcount[0])/N; + tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N); + sum += tmp*256; + nbBands++; + } + } while (++cnbEBands+end); + *hf_average = (*hf_average+hf_sum)>>1; + hf_sum = *hf_average; + if (*tapset_decision==2) + hf_sum += 4; + else if (*tapset_decision==0) + hf_sum -= 4; + if (hf_sum > 22) + *tapset_decision=2; + else if (hf_sum > 18) + *tapset_decision=1; + else + *tapset_decision=0; + } + /*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/ + celt_assert(nbBands>0); /*M*(eBands[end]-eBands[end-1]) <= 8 assures this*/ + sum /= nbBands; + /* Recursive averaging */ + sum = (sum+*average)>>1; + *average = sum; + /* Hysteresis */ + sum = (3*sum + (((3-last_decision)<<7) + 64) + 2)>>2; + if (sum < 80) + { + decision = SPREAD_AGGRESSIVE; + } else if (sum < 256) + { + decision = SPREAD_NORMAL; + } else if (sum < 384) + { + decision = SPREAD_LIGHT; + } else { + decision = SPREAD_NONE; + } +#ifdef FUZZING + decision = rand()&0x3; + *tapset_decision=rand()%3; +#endif + return decision; +} + +#ifdef MEASURE_NORM_MSE + +float MSE[30] = {0}; +int nbMSEBands = 0; +int MSECount[30] = {0}; + +void dump_norm_mse(void) +{ + int i; + for (i=0;inbEBands;i++) + { + int j; + int c; + float g; + if (bandE0[i]<10 || (C==2 && bandE0[i+m->nbEBands]<1)) + continue; + c=0; do { + g = bandE[i+c*m->nbEBands]/(1e-15+bandE0[i+c*m->nbEBands]); + for (j=M*m->eBands[i];jeBands[i+1];j++) + MSE[i] += (g*X[j+c*N]-X0[j+c*N])*(g*X[j+c*N]-X0[j+c*N]); + } while (++cnbEBands; +} + +#endif + +/* Indexing table for converting from natural Hadamard to ordery Hadamard + This is essentially a bit-reversed Gray, on top of which we've added + an inversion of the order because we want the DC at the end rather than + the beginning. The lines are for N=2, 4, 8, 16 */ +static const int ordery_table[] = { + 1, 0, + 3, 0, 2, 1, + 7, 0, 4, 3, 6, 1, 5, 2, + 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5, +}; + +static void deinterleave_hadamard(celt_norm *X, int N0, int stride, int hadamard) +{ + int i,j; + VARDECL(celt_norm, tmp); + int N; + SAVE_STACK; + N = N0*stride; + ALLOC(tmp, N, celt_norm); + celt_assert(stride>0); + if (hadamard) + { + const int *ordery = ordery_table+stride-2; + for (i=0;i>= 1; + for (i=0;i>1)) { + qn = 1; + } else { + qn = exp2_table8[qb&0x7]>>(14-(qb>>BITRES)); + qn = (qn+1)>>1<<1; + } + celt_assert(qn <= 256); + return qn; +} + +/* This function is responsible for encoding and decoding a band for both + the mono and stereo case. Even in the mono case, it can split the band + in two and transmit the energy difference with the two half-bands. It + can be called recursively so bands can end up being split in 8 parts. */ +static unsigned quant_band(int encode, const CELTMode *m, int i, celt_norm *X, celt_norm *Y, + int N, int b, int spread, int B, int intensity, int tf_change, celt_norm *lowband, ec_ctx *ec, + opus_int32 *remaining_bits, int LM, celt_norm *lowband_out, const celt_ener *bandE, int level, + opus_uint32 *seed, opus_val16 gain, celt_norm *lowband_scratch, int fill) +{ + const unsigned char *cache; + int q; + int curr_bits; + int stereo, split; + int imid=0, iside=0; + int N0=N; + int N_B=N; + int N_B0; + int B0=B; + int time_divide=0; + int recombine=0; + int inv = 0; + opus_val16 mid=0, side=0; + int longBlocks; + unsigned cm=0; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !encode; +#endif + + longBlocks = B0==1; + + N_B /= B; + N_B0 = N_B; + + split = stereo = Y != NULL; + + /* Special case for one sample */ + if (N==1) + { + int c; + celt_norm *x = X; + c=0; do { + int sign=0; + if (*remaining_bits>=1<0) + recombine = tf_change; + /* Band recombining to increase frequency resolution */ + + if (lowband && (recombine || ((N_B&1) == 0 && tf_change<0) || B0>1)) + { + int j; + for (j=0;j>k, 1<>k, 1<>4]<<2; + } + B>>=recombine; + N_B<<=recombine; + + /* Increasing the time resolution */ + while ((N_B&1) == 0 && tf_change<0) + { + if (encode) + haar1(X, N_B, B); + if (lowband) + haar1(lowband, N_B, B); + fill |= fill<>= 1; + time_divide++; + tf_change++; + } + B0=B; + N_B0 = N_B; + + /* Reorganize the samples in time order instead of frequency order */ + if (B0>1) + { + if (encode) + deinterleave_hadamard(X, N_B>>recombine, B0<>recombine, B0<cache.bits + m->cache.index[(LM+1)*m->nbEBands+i]; + if (!stereo && LM != -1 && b > cache[cache[0]]+12 && N>2) + { + N >>= 1; + Y = X+N; + split = 1; + LM -= 1; + if (B==1) + fill = (fill&1)|(fill<<1); + B = (B+1)>>1; + } + + if (split) + { + int qn; + int itheta=0; + int mbits, sbits, delta; + int qalloc; + int pulse_cap; + int offset; + int orig_fill; + opus_int32 tell; + + /* Decide on the resolution to give to the split parameter theta */ + pulse_cap = m->logN[i]+LM*(1<>1) - (stereo&&N==2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET); + qn = compute_qn(N, b, offset, pulse_cap, stereo); + if (stereo && i>=intensity) + qn = 1; + if (encode) + { + /* theta is the atan() of the ratio between the (normalized) + side and mid. With just that parameter, we can re-scale both + mid and side because we know that 1) they have unit norm and + 2) they are orthogonal. */ + itheta = stereo_itheta(X, Y, stereo, N); + } + tell = ec_tell_frac(ec); + if (qn!=1) + { + if (encode) + itheta = (itheta*qn+8192)>>14; + + /* Entropy coding of the angle. We use a uniform pdf for the + time split, a step for stereo, and a triangular one for the rest. */ + if (stereo && N>2) + { + int p0 = 3; + int x = itheta; + int x0 = qn/2; + int ft = p0*(x0+1) + x0; + /* Use a probability of p0 up to itheta=8192 and then use 1 after */ + if (encode) + { + ec_encode(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + } else { + int fs; + fs=ec_decode(ec,ft); + if (fs<(x0+1)*p0) + x=fs/p0; + else + x=x0+1+(fs-(x0+1)*p0); + ec_dec_update(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + itheta = x; + } + } else if (B0>1 || stereo) { + /* Uniform pdf */ + if (encode) + ec_enc_uint(ec, itheta, qn+1); + else + itheta = ec_dec_uint(ec, qn+1); + } else { + int fs=1, ft; + ft = ((qn>>1)+1)*((qn>>1)+1); + if (encode) + { + int fl; + + fs = itheta <= (qn>>1) ? itheta + 1 : qn + 1 - itheta; + fl = itheta <= (qn>>1) ? itheta*(itheta + 1)>>1 : + ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + + ec_encode(ec, fl, fl+fs, ft); + } else { + /* Triangular pdf */ + int fl=0; + int fm; + fm = ec_decode(ec, ft); + + if (fm < ((qn>>1)*((qn>>1) + 1)>>1)) + { + itheta = (isqrt32(8*(opus_uint32)fm + 1) - 1)>>1; + fs = itheta + 1; + fl = itheta*(itheta + 1)>>1; + } + else + { + itheta = (2*(qn + 1) + - isqrt32(8*(opus_uint32)(ft - fm - 1) + 1))>>1; + fs = qn + 1 - itheta; + fl = ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + } + + ec_dec_update(ec, fl, fl+fs, ft); + } + } + itheta = (opus_int32)itheta*16384/qn; + if (encode && stereo) + { + if (itheta==0) + intensity_stereo(m, X, Y, bandE, i, N); + else + stereo_split(X, Y, N); + } + /* NOTE: Renormalising X and Y *may* help fixed-point a bit at very high rate. + Let's do that at higher complexity */ + } else if (stereo) { + if (encode) + { + inv = itheta > 8192; + if (inv) + { + int j; + for (j=0;j2< 2< 8192; + *remaining_bits -= qalloc+sbits; + + x2 = c ? Y : X; + y2 = c ? X : Y; + if (sbits) + { + if (encode) + { + /* Here we only need to encode a sign for the side */ + sign = x2[0]*y2[1] - x2[1]*y2[0] < 0; + ec_enc_bits(ec, sign, 1); + } else { + sign = ec_dec_bits(ec, 1); + } + } + sign = 1-2*sign; + /* We use orig_fill here because we want to fold the side, but if + itheta==16384, we'll have cleared the low bits of fill. */ + cm = quant_band(encode, m, i, x2, NULL, N, mbits, spread, B, intensity, tf_change, lowband, ec, remaining_bits, LM, lowband_out, NULL, level, seed, gain, lowband_scratch, orig_fill); + /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse), + and there's no need to worry about mixing with the other channel. */ + y2[0] = -sign*x2[1]; + y2[1] = sign*x2[0]; + if (resynth) + { + celt_norm tmp; + X[0] = MULT16_16_Q15(mid, X[0]); + X[1] = MULT16_16_Q15(mid, X[1]); + Y[0] = MULT16_16_Q15(side, Y[0]); + Y[1] = MULT16_16_Q15(side, Y[1]); + tmp = X[0]; + X[0] = SUB16(tmp,Y[0]); + Y[0] = ADD16(tmp,Y[0]); + tmp = X[1]; + X[1] = SUB16(tmp,Y[1]); + Y[1] = ADD16(tmp,Y[1]); + } + } else { + /* "Normal" split code */ + celt_norm *next_lowband2=NULL; + celt_norm *next_lowband_out1=NULL; + int next_level=0; + opus_int32 rebalance; + + /* Give more bits to low-energy MDCTs than they would otherwise deserve */ + if (B0>1 && !stereo && (itheta&0x3fff)) + { + if (itheta > 8192) + /* Rough approximation for pre-echo masking */ + delta -= delta>>(4-LM); + else + /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */ + delta = IMIN(0, delta + (N<>(5-LM))); + } + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + *remaining_bits -= qalloc; + + if (lowband && !stereo) + next_lowband2 = lowband+N; /* >32-bit split case */ + + /* Only stereo needs to pass on lowband_out. Otherwise, it's + handled at the end */ + if (stereo) + next_lowband_out1 = lowband_out; + else + next_level = level+1; + + rebalance = *remaining_bits; + if (mbits >= sbits) + { + /* In stereo mode, we do not apply a scaling to the mid because we need the normalized + mid for folding later */ + cm = quant_band(encode, m, i, X, NULL, N, mbits, spread, B, intensity, tf_change, + lowband, ec, remaining_bits, LM, next_lowband_out1, + NULL, next_level, seed, stereo ? Q15ONE : MULT16_16_P15(gain,mid), lowband_scratch, fill); + rebalance = mbits - (rebalance-*remaining_bits); + if (rebalance > 3<>B)<<((B0>>1)&(stereo-1)); + } else { + /* For a stereo split, the high bits of fill are always zero, so no + folding will be done to the side. */ + cm = quant_band(encode, m, i, Y, NULL, N, sbits, spread, B, intensity, tf_change, + next_lowband2, ec, remaining_bits, LM, NULL, + NULL, next_level, seed, MULT16_16_P15(gain,side), NULL, fill>>B)<<((B0>>1)&(stereo-1)); + rebalance = sbits - (rebalance-*remaining_bits); + if (rebalance > 3< 0) + { + *remaining_bits += curr_bits; + q--; + curr_bits = pulses2bits(m, i, LM, q); + *remaining_bits -= curr_bits; + } + + if (q!=0) + { + int K = get_pulses(q); + + /* Finally do the actual quantization */ + if (encode) + { + cm = alg_quant(X, N, K, spread, B, ec +#ifdef RESYNTH + , gain +#endif + ); + } else { + cm = alg_unquant(X, N, K, spread, B, ec, gain); + } + } else { + /* If there's no pulse, fill the band anyway */ + int j; + if (resynth) + { + unsigned cm_mask; + /*B can be as large as 16, so this shift might overflow an int on a + 16-bit platform; use a long to get defined behavior.*/ + cm_mask = (unsigned)(1UL<>20); + } + cm = cm_mask; + } else { + /* Folded spectrum */ + for (j=0;j1) + interleave_hadamard(X, N_B>>recombine, B0<>= 1; + N_B <<= 1; + cm |= cm>>B; + haar1(X, N_B, B); + } + + for (k=0;k>k, 1<eBands; + celt_norm * restrict norm, * restrict norm2; + VARDECL(celt_norm, _norm); + VARDECL(celt_norm, lowband_scratch); + int B; + int M; + int lowband_offset; + int update_lowband = 1; + int C = Y_ != NULL ? 2 : 1; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !encode; +#endif + SAVE_STACK; + + M = 1<nbEBands], celt_norm); + ALLOC(lowband_scratch, M*(eBands[m->nbEBands]-eBands[m->nbEBands-1]), celt_norm); + norm = _norm; + norm2 = norm + M*eBands[m->nbEBands]; + + lowband_offset = 0; + for (i=start;i= M*eBands[start] && (update_lowband || lowband_offset==0)) + lowband_offset = i; + + tf_change = tf_res[i]; + if (i>=m->effEBands) + { + X=norm; + if (Y_!=NULL) + Y = norm; + } + + /* Get a conservative estimate of the collapse_mask's for the bands we're + going to be folding from. */ + if (lowband_offset != 0 && (spread!=SPREAD_AGGRESSIVE || B>1 || tf_change<0)) + { + int fold_start; + int fold_end; + int fold_i; + /* This ensures we never repeat spectral content within one band */ + effective_lowband = IMAX(M*eBands[start], M*eBands[lowband_offset]-N); + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband); + fold_end = lowband_offset-1; + while(M*eBands[++fold_end] < effective_lowband+N); + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; + y_cm |= collapse_masks[fold_i*C+C-1]; + } while (++fold_i(N< +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +#ifndef OPUS_VERSION +#define OPUS_VERSION "unknown" +#endif + +#ifdef CUSTOM_MODES +#define OPUS_CUSTOM_NOSTATIC +#else +#define OPUS_CUSTOM_NOSTATIC static inline +#endif + +static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0}; +/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */ +static const unsigned char spread_icdf[4] = {25, 23, 2, 0}; + +static const unsigned char tapset_icdf[3]={2,1,0}; + +#ifdef CUSTOM_MODES +static const unsigned char toOpusTable[20] = { + 0xE0, 0xE8, 0xF0, 0xF8, + 0xC0, 0xC8, 0xD0, 0xD8, + 0xA0, 0xA8, 0xB0, 0xB8, + 0x00, 0x00, 0x00, 0x00, + 0x80, 0x88, 0x90, 0x98, +}; + +static const unsigned char fromOpusTable[16] = { + 0x80, 0x88, 0x90, 0x98, + 0x40, 0x48, 0x50, 0x58, + 0x20, 0x28, 0x30, 0x38, + 0x00, 0x08, 0x10, 0x18 +}; + +static inline int toOpus(unsigned char c) +{ + int ret=0; + if (c<0xA0) + ret = toOpusTable[c>>3]; + if (ret == 0) + return -1; + else + return ret|(c&0x7); +} + +static inline int fromOpus(unsigned char c) +{ + if (c<0x80) + return -1; + else + return fromOpusTable[(c>>3)-16] | (c&0x7); +} +#endif /* CUSTOM_MODES */ + +#define COMBFILTER_MAXPERIOD 1024 +#define COMBFILTER_MINPERIOD 15 + +static int resampling_factor(opus_int32 rate) +{ + int ret; + switch (rate) + { + case 48000: + ret = 1; + break; + case 24000: + ret = 2; + break; + case 16000: + ret = 3; + break; + case 12000: + ret = 4; + break; + case 8000: + ret = 6; + break; + default: +#ifndef CUSTOM_MODES + celt_assert(0); +#endif + ret = 0; + break; + } + return ret; +} + +/** Encoder state + @brief Encoder state + */ +struct OpusCustomEncoder { + const OpusCustomMode *mode; /**< Mode used by the encoder */ + int overlap; + int channels; + int stream_channels; + + int force_intra; + int clip; + int disable_pf; + int complexity; + int upsample; + int start, end; + + opus_int32 bitrate; + int vbr; + int signalling; + int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */ + int loss_rate; + + /* Everything beyond this point gets cleared on a reset */ +#define ENCODER_RESET_START rng + + opus_uint32 rng; + int spread_decision; + opus_val32 delayedIntra; + int tonal_average; + int lastCodedBands; + int hf_average; + int tapset_decision; + + int prefilter_period; + opus_val16 prefilter_gain; + int prefilter_tapset; +#ifdef RESYNTH + int prefilter_period_old; + opus_val16 prefilter_gain_old; + int prefilter_tapset_old; +#endif + int consec_transient; + + opus_val32 preemph_memE[2]; + opus_val32 preemph_memD[2]; + + /* VBR-related parameters */ + opus_int32 vbr_reservoir; + opus_int32 vbr_drift; + opus_int32 vbr_offset; + opus_int32 vbr_count; + +#ifdef RESYNTH + celt_sig syn_mem[2][2*MAX_PERIOD]; +#endif + + celt_sig in_mem[1]; /* Size = channels*mode->overlap */ + /* celt_sig prefilter_mem[], Size = channels*COMBFILTER_PERIOD */ + /* celt_sig overlap_mem[], Size = channels*mode->overlap */ + /* opus_val16 oldEBands[], Size = 2*channels*mode->nbEBands */ +}; + +int celt_encoder_get_size(int channels) +{ + CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_encoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTEncoder) + + (2*channels*mode->overlap-1)*sizeof(celt_sig) + + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) + + 3*channels*mode->nbEBands*sizeof(opus_val16); + return size; +} + +#ifdef CUSTOM_MODES +CELTEncoder *opus_custom_encoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTEncoder *st = (CELTEncoder *)opus_alloc(opus_custom_encoder_get_size(mode, channels)); + /* init will handle the NULL case */ + ret = opus_custom_encoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_encoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels) +{ + int ret; + ret = opus_custom_encoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels); + if (ret != OPUS_OK) + return ret; + st->upsample = resampling_factor(sampling_rate); + return OPUS_OK; +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL || mode==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_encoder_get_size(mode, channels)); + + st->mode = mode; + st->overlap = mode->overlap; + st->stream_channels = st->channels = channels; + + st->upsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; + + st->constrained_vbr = 1; + st->clip = 1; + + st->bitrate = OPUS_BITRATE_MAX; + st->vbr = 0; + st->force_intra = 0; + st->complexity = 5; + + opus_custom_encoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_encoder_destroy(CELTEncoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + +static inline opus_val16 SIG2WORD16(celt_sig x) +{ +#ifdef FIXED_POINT + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +#else + return (opus_val16)x; +#endif +} + +static int transient_analysis(const opus_val32 * restrict in, int len, int C, + int overlap) +{ + int i; + VARDECL(opus_val16, tmp); + opus_val32 mem0=0,mem1=0; + int is_transient = 0; + int block; + int N; + VARDECL(opus_val16, bins); + SAVE_STACK; + ALLOC(tmp, len, opus_val16); + + block = overlap/2; + N=len/block; + ALLOC(bins, N, opus_val16); + if (C==1) + { + for (i=0;i=3) + is_transient=1; + conseq = 0; + for (j=i+1;j=7) + is_transient=1; + } + RESTORE_STACK; +#ifdef FUZZING + is_transient = rand()&0x1; +#endif + return is_transient; +} + +/** Apply window and compute the MDCT for all sub-frames and + all channels in a frame */ +static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * restrict in, celt_sig * restrict out, int C, int LM) +{ + if (C==1 && !shortBlocks) + { + const int overlap = OVERLAP(mode); + clt_mdct_forward(&mode->mdct, in, out, mode->window, overlap, mode->maxLM-LM, 1); + } else { + const int overlap = OVERLAP(mode); + int N = mode->shortMdctSize<shortMdctSize; + B = shortBlocks; + } + c=0; do { + for (b=0;bmdct, in+c*(B*N+overlap)+b*N, &out[b+c*N*B], mode->window, overlap, shortBlocks ? mode->maxLM : mode->maxLM-LM, B); + } + } while (++cshortMdctSize<shortMdctSize; + B = shortBlocks; + } + /* Prevents problems from the imdct doing the overlap-add */ + OPUS_CLEAR(x, overlap); + + for (b=0;bmdct, &X[b+c*N2*B], x+N2*b, mode->window, overlap, shortBlocks ? mode->maxLM : mode->maxLM-LM, B); + } + + for (j=0;j>LM;j++) + L2 = MAC16_16(L2, tmp[(j<eBands[len]-m->eBands[len-1])<eBands[i+1]-m->eBands[i])<eBands[i]<eBands[i]<>LM); + best_L1 = L1; + /*printf ("%f ", L1);*/ + for (k=0;k>(LM-k), 1<<(LM-k)); + else + haar1(tmp, N>>k, 1<>LM); + + if (L1 < best_L1) + { + best_L1 = L1; + best_level = k+1; + } + } + /*printf ("%d ", isTransient ? LM-best_level : best_level);*/ + if (isTransient) + metric[i] = best_level; + else + metric[i] = -best_level; + *tf_sum += metric[i]; + } + /*printf("\n");*/ + /* NOTE: Future optimized implementations could detect extreme transients and set + tf_select = 1 but so far we have not found a reliable way of making this useful */ + tf_select = 0; + + cost0 = 0; + cost1 = isTransient ? 0 : lambda; + /* Viterbi forward pass */ + for (i=1;i=0;i--) + { + if (tf_res[i+1] == 1) + tf_res[i] = path1[i+1]; + else + tf_res[i] = path0[i+1]; + } + RESTORE_STACK; +#ifdef FUZZING + tf_select = rand()&0x1; + tf_res[0] = rand()&0x1; + for (i=1;istorage*8; + tell = ec_tell(enc); + logp = isTransient ? 2 : 4; + /* Reserve space to code the tf_select decision. */ + tf_select_rsv = LM>0 && tell+logp+1 <= budget; + budget -= tf_select_rsv; + curr = tf_changed = 0; + for (i=start;istorage*8; + tell = ec_tell(dec); + logp = isTransient ? 2 : 4; + tf_select_rsv = LM>0 && tell+logp+1<=budget; + budget -= tf_select_rsv; + tf_changed = curr = 0; + for (i=start;inbEBands;i++) + { + int N; + N=(m->eBands[i+1]-m->eBands[i])<cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2; + } +} + +static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X, + const opus_val16 *bandLogE, int end, int LM, int C, int N0) +{ + int i; + opus_val32 diff=0; + int c; + int trim_index = 5; + if (C==2) + { + opus_val16 sum = 0; /* Q10 */ + /* Compute inter-channel correlation for low frequencies */ + for (i=0;i<8;i++) + { + int j; + opus_val32 partial = 0; + for (j=m->eBands[i]<eBands[i+1]< QCONST16(.995f,10)) + trim_index-=4; + else if (sum > QCONST16(.92f,10)) + trim_index-=3; + else if (sum > QCONST16(.85f,10)) + trim_index-=2; + else if (sum > QCONST16(.8f,10)) + trim_index-=1; + } + + /* Estimate spectral tilt */ + c=0; do { + for (i=0;inbEBands]*(opus_int32)(2+2*i-m->nbEBands); + } + } while (++c QCONST16(2.f, DB_SHIFT)) + trim_index--; + if (diff > QCONST16(8.f, DB_SHIFT)) + trim_index--; + if (diff < -QCONST16(4.f, DB_SHIFT)) + trim_index++; + if (diff < -QCONST16(10.f, DB_SHIFT)) + trim_index++; + + if (trim_index<0) + trim_index = 0; + if (trim_index>10) + trim_index = 10; +#ifdef FUZZING + trim_index = rand()%11; +#endif + return trim_index; +} + +static int stereo_analysis(const CELTMode *m, const celt_norm *X, + int LM, int N0) +{ + int i; + int thetas; + opus_val32 sumLR = EPSILON, sumMS = EPSILON; + + /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */ + for (i=0;i<13;i++) + { + int j; + for (j=m->eBands[i]<eBands[i+1]<eBands[13]<<(LM+1))+thetas, sumMS) + > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR); +} + +int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) +{ + int i, c, N; + opus_int32 bits; + ec_enc _enc; + VARDECL(celt_sig, in); + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + VARDECL(opus_val16, bandLogE); + VARDECL(int, fine_quant); + VARDECL(opus_val16, error); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *prefilter_mem; + opus_val16 *oldBandE, *oldLogE, *oldLogE2; + int shortBlocks=0; + int isTransient=0; + const int CC = st->channels; + const int C = st->stream_channels; + int LM, M; + int tf_select; + int nbFilledBytes, nbAvailableBytes; + int effEnd; + int codedBands; + int tf_sum; + int alloc_trim; + int pitch_index=COMBFILTER_MINPERIOD; + opus_val16 gain1 = 0; + int intensity=0; + int dual_stereo=0; + int effectiveBytes; + opus_val16 pf_threshold; + int dynalloc_logp; + opus_int32 vbr_rate; + opus_int32 total_bits; + opus_int32 total_boost; + opus_int32 balance; + opus_int32 tell; + int prefilter_tapset=0; + int pf_on; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence=0; + ALLOC_STACK; + + if (nbCompressedBytes<2 || pcm==NULL) + return OPUS_BAD_ARG; + + frame_size *= st->upsample; + for (LM=0;LM<=st->mode->maxLM;LM++) + if (st->mode->shortMdctSize<st->mode->maxLM) + return OPUS_BAD_ARG; + M=1<mode->shortMdctSize; + + prefilter_mem = st->in_mem+CC*(st->overlap); + oldBandE = (opus_val16*)(st->in_mem+CC*(2*st->overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + CC*st->mode->nbEBands; + oldLogE2 = oldLogE + CC*st->mode->nbEBands; + + if (enc==NULL) + { + tell=1; + nbFilledBytes=0; + } else { + tell=ec_tell(enc); + nbFilledBytes=(tell+4)>>3; + } + +#ifdef CUSTOM_MODES + if (st->signalling && enc==NULL) + { + int tmp = (st->mode->effEBands-st->end)>>1; + st->end = IMAX(1, st->mode->effEBands-tmp); + compressed[0] = tmp<<5; + compressed[0] |= LM<<3; + compressed[0] |= (C==2)<<2; + /* Convert "standard mode" to Opus header */ + if (st->mode->Fs==48000 && st->mode->shortMdctSize==120) + { + int c0 = toOpus(compressed[0]); + if (c0<0) + return OPUS_BAD_ARG; + compressed[0] = c0; + } + compressed++; + nbCompressedBytes--; + } +#else + celt_assert(st->signalling==0); +#endif + + /* Can't produce more than 1275 output bytes */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275); + nbAvailableBytes = nbCompressedBytes - nbFilledBytes; + + if (st->vbr && st->bitrate!=OPUS_BITRATE_MAX) + { + opus_int32 den=st->mode->Fs>>BITRES; + vbr_rate=(st->bitrate*frame_size+(den>>1))/den; +#ifdef CUSTOM_MODES + if (st->signalling) + vbr_rate -= 8<>(3+BITRES); + } else { + opus_int32 tmp; + vbr_rate = 0; + tmp = st->bitrate*frame_size; + if (tell>1) + tmp += tell; + if (st->bitrate!=OPUS_BITRATE_MAX) + nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes, + (tmp+4*st->mode->Fs)/(8*st->mode->Fs)-!!st->signalling)); + effectiveBytes = nbCompressedBytes; + } + + if (enc==NULL) + { + ec_enc_init(&_enc, compressed, nbCompressedBytes); + enc = &_enc; + } + + if (vbr_rate>0) + { + /* Computes the max bit-rate allowed in VBR mode to avoid violating the + target rate and buffering. + We must do this up front so that bust-prevention logic triggers + correctly if we don't have enough bits. */ + if (st->constrained_vbr) + { + opus_int32 vbr_bound; + opus_int32 max_allowed; + /* We could use any multiple of vbr_rate as bound (depending on the + delay). + This is clamped to ensure we use at least two bytes if the encoder + was entirely empty, but to allow 0 in hybrid mode. */ + vbr_bound = vbr_rate; + max_allowed = IMIN(IMAX(tell==1?2:0, + (vbr_rate+vbr_bound-st->vbr_reservoir)>>(BITRES+3)), + nbAvailableBytes); + if(max_allowed < nbAvailableBytes) + { + nbCompressedBytes = nbFilledBytes+max_allowed; + nbAvailableBytes = max_allowed; + ec_enc_shrink(enc, nbCompressedBytes); + } + } + } + total_bits = nbCompressedBytes*8; + + effEnd = st->end; + if (effEnd > st->mode->effEBands) + effEnd = st->mode->effEBands; + + ALLOC(in, CC*(N+st->overlap), celt_sig); + + /* Find pitch period and gain */ + { + VARDECL(celt_sig, _pre); + celt_sig *pre[2]; + SAVE_STACK; + ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig); + + pre[0] = _pre; + pre[1] = _pre + (N+COMBFILTER_MAXPERIOD); + + silence = 1; + c=0; do { + int count = 0; + const opus_val16 * restrict pcmp = pcm+c; + celt_sig * restrict inp = in+c*(N+st->overlap)+st->overlap; + + for (i=0;iclip) + x = MAX32(-65536.f, MIN32(65536.f,x)); +#endif + if (++count==st->upsample) + { + count=0; + pcmp+=CC; + } else { + x = 0; + } + /* Apply pre-emphasis */ + tmp = MULT16_16(st->mode->preemph[2], x); + *inp = tmp + st->preemph_memE[c]; + st->preemph_memE[c] = MULT16_32_Q15(st->mode->preemph[1], *inp) + - MULT16_32_Q15(st->mode->preemph[0], tmp); + silence = silence && *inp == 0; + inp++; + } + OPUS_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD); + OPUS_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+st->overlap)+st->overlap, N); + } while (++c0) + { + effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2); + total_bits=nbCompressedBytes*8; + nbAvailableBytes=2; + ec_enc_shrink(enc, nbCompressedBytes); + } + /* Pretend we've filled all the remaining bits with zeros + (that's what the initialiser did anyway) */ + tell = nbCompressedBytes*8; + enc->nbits_total+=tell-ec_tell(enc); + } + if (nbAvailableBytes>12*C && st->start==0 && !silence && !st->disable_pf && st->complexity >= 5) + { + VARDECL(opus_val16, pitch_buf); + ALLOC(pitch_buf, (COMBFILTER_MAXPERIOD+N)>>1, opus_val16); + + pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC); + pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N, + COMBFILTER_MAXPERIOD-COMBFILTER_MINPERIOD, &pitch_index); + pitch_index = COMBFILTER_MAXPERIOD-pitch_index; + + gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD, + N, &pitch_index, st->prefilter_period, st->prefilter_gain); + if (pitch_index > COMBFILTER_MAXPERIOD-2) + pitch_index = COMBFILTER_MAXPERIOD-2; + gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1); + if (st->loss_rate>2) + gain1 = HALF32(gain1); + if (st->loss_rate>4) + gain1 = HALF32(gain1); + if (st->loss_rate>8) + gain1 = 0; + prefilter_tapset = st->tapset_decision; + } else { + gain1 = 0; + } + + /* Gain threshold for enabling the prefilter/postfilter */ + pf_threshold = QCONST16(.2f,15); + + /* Adjusting the threshold based on rate and continuity */ + if (abs(pitch_index-st->prefilter_period)*10>pitch_index) + pf_threshold += QCONST16(.2f,15); + if (nbAvailableBytes<25) + pf_threshold += QCONST16(.1f,15); + if (nbAvailableBytes<35) + pf_threshold += QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.4f,15)) + pf_threshold -= QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.55f,15)) + pf_threshold -= QCONST16(.1f,15); + + /* Hard threshold at 0.2 */ + pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15)); + if (gain1start==0 && tell+16<=total_bits) + ec_enc_bit_logp(enc, 0, 1); + gain1 = 0; + pf_on = 0; + } else { + /*This block is not gated by a total bits check only because + of the nbAvailableBytes check above.*/ + int qg; + int octave; + + if (ABS16(gain1-st->prefilter_gain)prefilter_gain; + +#ifdef FIXED_POINT + qg = ((gain1+1536)>>10)/3-1; +#else + qg = (int)floor(.5f+gain1*32/3)-1; +#endif + qg = IMAX(0, IMIN(7, qg)); + ec_enc_bit_logp(enc, 1, 1); + pitch_index += 1; + octave = EC_ILOG(pitch_index)-5; + ec_enc_uint(enc, octave, 6); + ec_enc_bits(enc, pitch_index-(16<mode->shortMdctSize-st->mode->overlap; + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + OPUS_COPY(in+c*(N+st->overlap), st->in_mem+c*(st->overlap), st->overlap); + if (offset) + comb_filter(in+c*(N+st->overlap)+st->overlap, pre[c]+COMBFILTER_MAXPERIOD, + st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain, + st->prefilter_tapset, st->prefilter_tapset, NULL, 0); + + comb_filter(in+c*(N+st->overlap)+st->overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset, + st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1, + st->prefilter_tapset, prefilter_tapset, st->mode->window, st->mode->overlap); + OPUS_COPY(st->in_mem+c*(st->overlap), in+c*(N+st->overlap)+N, st->overlap); + + if (N>COMBFILTER_MAXPERIOD) + { + OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD); + } else { + OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N); + OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N); + } + } while (++c0 && ec_tell(enc)+3<=total_bits) + { + if (st->complexity > 1) + { + isTransient = transient_analysis(in, N+st->overlap, CC, + st->overlap); + if (isTransient) + shortBlocks = M; + } + ec_enc_bit_logp(enc, isTransient, 3); + } + + ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(bandE,st->mode->nbEBands*CC, celt_ener); + ALLOC(bandLogE,st->mode->nbEBands*CC, opus_val16); + /* Compute MDCTs */ + compute_mdcts(st->mode, shortBlocks, in, freq, CC, LM); + + if (CC==2&&C==1) + { + for (i=0;iupsample != 1) + { + c=0; do + { + int bound = N/st->upsample; + for (i=0;iupsample; + for (;imode, freq, bandE, effEnd, C, M); + + amp2Log2(st->mode, effEnd, st->end, bandE, bandLogE, C); + + /* Band normalisation */ + normalise_bands(st->mode, freq, X, bandE, effEnd, C, M); + + ALLOC(tf_res, st->mode->nbEBands, int); + tf_select = tf_analysis(st->mode, effEnd, C, isTransient, tf_res, effectiveBytes, X, N, LM, &tf_sum); + for (i=effEnd;iend;i++) + tf_res[i] = tf_res[effEnd-1]; + + ALLOC(error, C*st->mode->nbEBands, opus_val16); + quant_coarse_energy(st->mode, st->start, st->end, effEnd, bandLogE, + oldBandE, total_bits, error, enc, + C, LM, nbAvailableBytes, st->force_intra, + &st->delayedIntra, st->complexity >= 4, st->loss_rate); + + tf_encode(st->start, st->end, isTransient, tf_res, LM, tf_select, enc); + + st->spread_decision = SPREAD_NORMAL; + if (ec_tell(enc)+4<=total_bits) + { + if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + } else { + st->spread_decision = spreading_decision(st->mode, X, + &st->tonal_average, st->spread_decision, &st->hf_average, + &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M); + } + ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5); + } + + ALLOC(cap, st->mode->nbEBands, int); + ALLOC(offsets, st->mode->nbEBands, int); + + init_caps(st->mode,cap,LM,C); + for (i=0;imode->nbEBands;i++) + offsets[i] = 0; + /* Dynamic allocation code */ + /* Make sure that dynamic allocation can't make us bust the budget */ + if (effectiveBytes > 50 && LM>=1) + { + int t1, t2; + if (LM <= 1) + { + t1 = 3; + t2 = 5; + } else { + t1 = 2; + t2 = 4; + } + for (i=st->start+1;iend-1;i++) + { + opus_val32 d2; + d2 = 2*bandLogE[i]-bandLogE[i-1]-bandLogE[i+1]; + if (C==2) + d2 = HALF32(d2 + 2*bandLogE[i+st->mode->nbEBands]- + bandLogE[i-1+st->mode->nbEBands]-bandLogE[i+1+st->mode->nbEBands]); +#ifdef FUZZING + if((rand()&0xF)==0) + { + offsets[i] += 1; + if((rand()&0x3)==0) + offsets[i] += 1+(rand()&0x3); + } +#else + if (d2 > SHL16(t1,DB_SHIFT)) + offsets[i] += 1; + if (d2 > SHL16(t2,DB_SHIFT)) + offsets[i] += 1; +#endif + } + } + dynalloc_logp = 6; + total_bits<<=BITRES; + total_boost = 0; + tell = ec_tell_frac(enc); + for (i=st->start;iend;i++) + { + int width, quanta; + int dynalloc_loop_logp; + int boost; + int j; + width = C*(st->mode->eBands[i+1]-st->mode->eBands[i])<mode, X, bandLogE, + st->end, LM, C, N); + ec_enc_icdf(enc, alloc_trim, trim_icdf, 7); + tell = ec_tell_frac(enc); + } + + /* Variable bitrate */ + if (vbr_rate>0) + { + opus_val16 alpha; + opus_int32 delta; + /* The target rate in 8th bits per frame */ + opus_int32 target; + opus_int32 min_allowed; + int lm_diff = st->mode->maxLM - LM; + + target = vbr_rate + (st->vbr_offset>>lm_diff) - ((40*C+20)<end-st->start)) + target = 7*target/4; + else if (tf_sum < -(st->end-st->start)) + target = 3*target/2; + else if (M > 1) + target-=(target+14)/28; + + /* The current offset is removed from the target and the space used + so far is added*/ + target=target+tell; + + /* In VBR mode the frame size must not be reduced so much that it would + result in the encoder running out of bits. + The margin of 2 bytes ensures that none of the bust-prevention logic + in the decoder will have triggered so far. */ + min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)) + 2 - nbFilledBytes; + + nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3); + nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes); + nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes) - nbFilledBytes; + + /* By how much did we "miss" the target on that frame */ + delta = target - vbr_rate; + + target=nbAvailableBytes<<(BITRES+3); + + /*If the frame is silent we don't adjust our drift, otherwise + the encoder will shoot to very high rates after hitting a + span of silence, but we do allow the bitres to refill. + This means that we'll undershoot our target in CVBR/VBR modes + on files with lots of silence. */ + if(silence) + { + nbAvailableBytes = 2; + target = 2*8<vbr_count < 970) + { + st->vbr_count++; + alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16)); + } else + alpha = QCONST16(.001f,15); + /* How many bits have we used in excess of what we're allowed */ + if (st->constrained_vbr) + st->vbr_reservoir += target - vbr_rate; + /*printf ("%d\n", st->vbr_reservoir);*/ + + /* Compute the offset we need to apply in order to reach the target */ + st->vbr_drift += (opus_int32)MULT16_32_Q15(alpha,(delta*(1<vbr_offset-st->vbr_drift); + st->vbr_offset = -st->vbr_drift; + /*printf ("%d\n", st->vbr_drift);*/ + + if (st->constrained_vbr && st->vbr_reservoir < 0) + { + /* We're under the min value -- increase rate */ + int adjust = (-st->vbr_reservoir)/(8<vbr_reservoir = 0; + /*printf ("+%d\n", adjust);*/ + } + nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes); + /* This moves the raw bits to take into account the new compressed size */ + ec_enc_shrink(enc, nbCompressedBytes); + } + if (C==2) + { + int effectiveRate; + + /* Always use MS for 2.5 ms frames until we can do a better analysis */ + if (LM!=0) + dual_stereo = stereo_analysis(st->mode, X, LM, N); + + /* Account for coarse energy */ + effectiveRate = (8*effectiveBytes - 80)>>LM; + + /* effectiveRate in kb/s */ + effectiveRate = 2*effectiveRate/5; + if (effectiveRate<35) + intensity = 8; + else if (effectiveRate<50) + intensity = 12; + else if (effectiveRate<68) + intensity = 16; + else if (effectiveRate<84) + intensity = 18; + else if (effectiveRate<102) + intensity = 19; + else if (effectiveRate<130) + intensity = 20; + else + intensity = 100; + intensity = IMIN(st->end,IMAX(st->start, intensity)); + } + + /* Bit allocation */ + ALLOC(fine_quant, st->mode->nbEBands, int); + ALLOC(pulses, st->mode->nbEBands, int); + ALLOC(fine_priority, st->mode->nbEBands, int); + + /* bits = packet size - where we are - safety*/ + bits = (((opus_int32)nbCompressedBytes*8)<=2&&bits>=((LM+2)<mode, st->start, st->end, offsets, cap, + alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses, + fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands); + st->lastCodedBands = codedBands; + + quant_fine_energy(st->mode, st->start, st->end, oldBandE, error, fine_quant, enc, C); + +#ifdef MEASURE_NORM_MSE + float X0[3000]; + float bandE0[60]; + c=0; do + for (i=0;imode->nbEBands;i++) + bandE0[i] = bandE[i]; +#endif + + /* Residual quantisation */ + ALLOC(collapse_masks, C*st->mode->nbEBands, unsigned char); + quant_all_bands(1, st->mode, st->start, st->end, X, C==2 ? X+N : NULL, collapse_masks, + bandE, pulses, shortBlocks, st->spread_decision, dual_stereo, intensity, tf_res, + nbCompressedBytes*(8<rng); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = st->consec_transient<2; +#ifdef FUZZING + anti_collapse_on = rand()&0x1; +#endif + ec_enc_bits(enc, anti_collapse_on, 1); + } + quant_energy_finalise(st->mode, st->start, st->end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C); + + if (silence) + { + for (i=0;imode->nbEBands;i++) + oldBandE[i] = -QCONST16(28.f,DB_SHIFT); + } + +#ifdef RESYNTH + /* Re-synthesis of the coded audio if required */ + { + celt_sig *out_mem[2]; + celt_sig *overlap_mem[2]; + + log2Amp(st->mode, st->start, st->end, bandE, oldBandE, C); + if (silence) + { + for (i=0;imode->nbEBands;i++) + bandE[i] = 0; + } + +#ifdef MEASURE_NORM_MSE + measure_norm_mse(st->mode, X, X0, bandE, bandE0, M, N, C); +#endif + if (anti_collapse_on) + { + anti_collapse(st->mode, X, collapse_masks, LM, C, CC, N, + st->start, st->end, oldBandE, oldLogE, oldLogE2, pulses, st->rng); + } + + /* Synthesis */ + denormalise_bands(st->mode, X, freq, bandE, effEnd, C, M); + + OPUS_MOVE(st->syn_mem[0], st->syn_mem[0]+N, MAX_PERIOD); + if (CC==2) + OPUS_MOVE(st->syn_mem[1], st->syn_mem[1]+N, MAX_PERIOD); + + c=0; do + for (i=0;imode->eBands[st->start];i++) + freq[c*N+i] = 0; + while (++cmode->eBands[st->end];isyn_mem[0]+MAX_PERIOD; + if (CC==2) + out_mem[1] = st->syn_mem[1]+MAX_PERIOD; + + overlap_mem[0] = prefilter_mem+CC*COMBFILTER_MAXPERIOD; + if (CC==2) + overlap_mem[1] = overlap_mem[0] + st->overlap; + + compute_inv_mdcts(st->mode, shortBlocks, freq, out_mem, overlap_mem, CC, LM); + + c=0; do { + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, st->mode->shortMdctSize, + st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset, + st->mode->window, st->overlap); + if (LM!=0) + comb_filter(out_mem[c]+st->mode->shortMdctSize, out_mem[c]+st->mode->shortMdctSize, st->prefilter_period, pitch_index, N-st->mode->shortMdctSize, + st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset, + st->mode->window, st->mode->overlap); + } while (++cupsample, st->mode->preemph, st->preemph_memD); + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + st->prefilter_period = pitch_index; + st->prefilter_gain = gain1; + st->prefilter_tapset = prefilter_tapset; +#ifdef RESYNTH + if (LM!=0) + { + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + if (CC==2&&C==1) { + for (i=0;imode->nbEBands;i++) + oldBandE[st->mode->nbEBands+i]=oldBandE[i]; + } + + if (!isTransient) + { + for (i=0;imode->nbEBands;i++) + oldLogE2[i] = oldLogE[i]; + for (i=0;imode->nbEBands;i++) + oldLogE[i] = oldBandE[i]; + } else { + for (i=0;imode->nbEBands;i++) + oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); + } + /* In case start or end were to change */ + c=0; do + { + for (i=0;istart;i++) + { + oldBandE[c*st->mode->nbEBands+i]=0; + oldLogE[c*st->mode->nbEBands+i]=oldLogE2[c*st->mode->nbEBands+i]=-QCONST16(28.f,DB_SHIFT); + } + for (i=st->end;imode->nbEBands;i++) + { + oldBandE[c*st->mode->nbEBands+i]=0; + oldLogE[c*st->mode->nbEBands+i]=oldLogE2[c*st->mode->nbEBands+i]=-QCONST16(28.f,DB_SHIFT); + } + } while (++cconsec_transient++; + else + st->consec_transient=0; + st->rng = enc->rng; + + /* If there's any room left (can only happen for very high rates), + it's already filled with zeros */ + ec_enc_done(enc); + +#ifdef CUSTOM_MODES + if (st->signalling) + nbCompressedBytes++; +#endif + + RESTORE_STACK; + if (ec_get_error(enc)) + return OPUS_INTERNAL_ERROR; + else + return nbCompressedBytes; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_encode(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_encode_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + int j, ret, C, N; + VARDECL(opus_int16, in); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + ALLOC(in, C*N, opus_int16); + + for (j=0;jchannels; + N=frame_size; + ALLOC(in, C*N, celt_sig); + for (j=0;j10) + goto bad_arg; + st->complexity = value; + } + break; + case CELT_SET_START_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<0 || value>=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_PREDICTION_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>2) + goto bad_arg; + st->disable_pf = value<=1; + st->force_intra = value==0; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>100) + goto bad_arg; + st->loss_rate = value; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->constrained_vbr = value; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->vbr = value; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<=500 && value!=OPUS_BITRATE_MAX) + goto bad_arg; + value = IMIN(value, 260000*st->channels); + st->bitrate = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *oldBandE, *oldLogE, *oldLogE2; + oldBandE = (opus_val16*)(st->in_mem+st->channels*(2*st->overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + st->channels*st->mode->nbEBands; + oldLogE2 = oldLogE + st->channels*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->ENCODER_RESET_START, + opus_custom_encoder_get_size(st->mode, st->channels)- + ((char*)&st->ENCODER_RESET_START - (char*)st)); + for (i=0;ichannels*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + st->vbr_offset = 0; + st->delayedIntra = 1; + st->spread_decision = SPREAD_NORMAL; + st->tonal_average = 256; + st->hf_average = 0; + st->tapset_decision = 0; + } + break; +#ifdef CUSTOM_MODES + case CELT_SET_INPUT_CLIPPING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->clip = value; + } + break; +#endif + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} + +/**********************************************************************/ +/* */ +/* DECODER */ +/* */ +/**********************************************************************/ +#define DECODE_BUFFER_SIZE 2048 + +/** Decoder state + @brief Decoder state + */ +struct OpusCustomDecoder { + const OpusCustomMode *mode; + int overlap; + int channels; + int stream_channels; + + int downsample; + int start, end; + int signalling; + + /* Everything beyond this point gets cleared on a reset */ +#define DECODER_RESET_START rng + + opus_uint32 rng; + int error; + int last_pitch_index; + int loss_count; + int postfilter_period; + int postfilter_period_old; + opus_val16 postfilter_gain; + opus_val16 postfilter_gain_old; + int postfilter_tapset; + int postfilter_tapset_old; + + celt_sig preemph_memD[2]; + + celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */ + /* opus_val16 lpc[], Size = channels*LPC_ORDER */ + /* opus_val16 oldEBands[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = 2*mode->nbEBands */ + /* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */ +}; + +int celt_decoder_get_size(int channels) +{ + const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_decoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTDecoder) + + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig) + + channels*LPC_ORDER*sizeof(opus_val16) + + 4*2*mode->nbEBands*sizeof(opus_val16); + return size; +} + +#ifdef CUSTOM_MODES +CELTDecoder *opus_custom_decoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTDecoder *st = (CELTDecoder *)opus_alloc(opus_custom_decoder_get_size(mode, channels)); + ret = opus_custom_decoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_decoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels) +{ + int ret; + ret = opus_custom_decoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels); + if (ret != OPUS_OK) + return ret; + st->downsample = resampling_factor(sampling_rate); + if (st->downsample==0) + return OPUS_BAD_ARG; + else + return OPUS_OK; +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_decoder_get_size(mode, channels)); + + st->mode = mode; + st->overlap = mode->overlap; + st->stream_channels = st->channels = channels; + + st->downsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; + + st->loss_count = 0; + + opus_custom_decoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_decoder_destroy(CELTDecoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + +static void celt_decode_lost(CELTDecoder * restrict st, opus_val16 * restrict pcm, int N, int LM) +{ + int c; + int pitch_index; + int overlap = st->mode->overlap; + opus_val16 fade = Q15ONE; + int i, len; + const int C = st->channels; + int offset; + celt_sig *out_mem[2]; + celt_sig *decode_mem[2]; + celt_sig *overlap_mem[2]; + opus_val16 *lpc; + opus_val32 *out_syn[2]; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + SAVE_STACK; + + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+st->overlap); + out_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE-MAX_PERIOD; + overlap_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE; + } while (++c_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*C); + oldBandE = lpc+C*LPC_ORDER; + oldLogE = oldBandE + 2*st->mode->nbEBands; + oldLogE2 = oldLogE + 2*st->mode->nbEBands; + backgroundLogE = oldLogE2 + 2*st->mode->nbEBands; + + out_syn[0] = out_mem[0]+MAX_PERIOD-N; + if (C==2) + out_syn[1] = out_mem[1]+MAX_PERIOD-N; + + len = N+st->mode->overlap; + + if (st->loss_count >= 5 || st->start!=0) + { + /* Noise-based PLC/CNG */ + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + opus_uint32 seed; + int effEnd; + + effEnd = st->end; + if (effEnd > st->mode->effEBands) + effEnd = st->mode->effEBands; + + ALLOC(freq, C*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ + ALLOC(bandE, st->mode->nbEBands*C, celt_ener); + + if (st->loss_count >= 5) + log2Amp(st->mode, st->start, st->end, bandE, backgroundLogE, C); + else { + /* Energy decay */ + opus_val16 decay = st->loss_count==0 ? QCONST16(1.5f, DB_SHIFT) : QCONST16(.5f, DB_SHIFT); + c=0; do + { + for (i=st->start;iend;i++) + oldBandE[c*st->mode->nbEBands+i] -= decay; + } while (++cmode, st->start, st->end, bandE, oldBandE, C); + } + seed = st->rng; + for (c=0;cmode->eBands[st->start]<start;imode->effEBands;i++) + { + int j; + int boffs; + int blen; + boffs = N*c+(st->mode->eBands[i]<mode->eBands[i+1]-st->mode->eBands[i])<>20); + } + renormalise_vector(X+boffs, blen, Q15ONE); + } + for (i=(st->mode->eBands[st->end]<rng = seed; + + denormalise_bands(st->mode, X, freq, bandE, st->mode->effEBands, C, 1<mode->eBands[st->start]<mode->eBands[effEnd]<downsample!=1) + bound = IMIN(bound, N/st->downsample); + for (i=bound;imode, 0, freq, out_syn, overlap_mem, C, LM); + } else { + /* Pitch-based PLC */ + if (st->loss_count == 0) + { + opus_val16 pitch_buf[DECODE_BUFFER_SIZE>>1]; + /* Corresponds to a min pitch of 67 Hz. It's possible to save CPU in this + search by using only part of the decode buffer */ + int poffset = 720; + pitch_downsample(decode_mem, pitch_buf, DECODE_BUFFER_SIZE, C); + /* Max pitch is 100 samples (480 Hz) */ + pitch_search(pitch_buf+((poffset)>>1), pitch_buf, DECODE_BUFFER_SIZE-poffset, + poffset-100, &pitch_index); + pitch_index = poffset-pitch_index; + st->last_pitch_index = pitch_index; + } else { + pitch_index = st->last_pitch_index; + fade = QCONST16(.8f,15); + } + + c=0; do { + VARDECL(opus_val32, e); + opus_val16 exc[MAX_PERIOD]; + opus_val32 ac[LPC_ORDER+1]; + opus_val16 decay = 1; + opus_val32 S1=0; + opus_val16 mem[LPC_ORDER]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + ALLOC(e, MAX_PERIOD+2*st->mode->overlap, opus_val32); + + offset = MAX_PERIOD-pitch_index; + for (i=0;iloss_count == 0) + { + _celt_autocorr(exc, ac, st->mode->window, st->mode->overlap, + LPC_ORDER, MAX_PERIOD); + + /* Noise floor -40 dB */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Lag windowing */ + for (i=1;i<=LPC_ORDER;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(.008f*i)*(.008f*i); +#endif + } + + _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER); + } + for (i=0;i E2) + E1 = E2; + decay = celt_sqrt(frac_div32(SHR(E1,1),E2)); + } + + /* Copy excitation, taking decay into account */ + for (i=0;imode->overlap;i++) + { + opus_val16 tmp; + if (offset+i >= MAX_PERIOD) + { + offset -= pitch_index; + decay = MULT16_16_Q15(decay, decay); + } + e[i] = SHL32(EXTEND32(MULT16_16_Q15(decay, exc[offset+i])), SIG_SHIFT); + tmp = ROUND16(out_mem[c][offset+i],SIG_SHIFT); + S1 += SHR32(MULT16_16(tmp,tmp),8); + } + for (i=0;imode->overlap;i++) + e[i] = MULT16_32_Q15(fade, e[i]); + celt_iir(e, lpc+c*LPC_ORDER, e, len+st->mode->overlap, LPC_ORDER, mem); + + { + opus_val32 S2=0; + for (i=0;i SHR32(S2,2))) +#else + /* Float test is written this way to catch NaNs at the same time */ + if (!(S1 > 0.2f*S2)) +#endif + { + for (i=0;ipostfilter_period, st->postfilter_period, st->overlap, + st->postfilter_gain, st->postfilter_gain, st->postfilter_tapset, st->postfilter_tapset, + NULL, 0); + + for (i=0;imode->overlap-N;i++) + out_mem[c][i] = out_mem[c][N+i]; + + /* Apply TDAC to the concealed audio so that it blends with the + previous and next frames */ + for (i=0;imode->window[i], e[N+overlap-1-i]) + + MULT16_32_Q15(st->mode->window[overlap-i-1], e[N+i ]); + out_mem[c][MAX_PERIOD+i] = MULT16_32_Q15(st->mode->window[overlap-i-1], tmp); + out_mem[c][MAX_PERIOD+overlap-i-1] = MULT16_32_Q15(st->mode->window[i], tmp); + } + for (i=0;ipostfilter_period, st->postfilter_period, st->overlap, + -st->postfilter_gain, -st->postfilter_gain, st->postfilter_tapset, st->postfilter_tapset, + NULL, 0); + for (i=0;idownsample, st->mode->preemph, st->preemph_memD); + + st->loss_count++; + + RESTORE_STACK; +} + +int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_val16 * restrict pcm, int frame_size, ec_dec *dec) +{ + int c, i, N; + int spread_decision; + opus_int32 bits; + ec_dec _dec; + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + VARDECL(int, fine_quant); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *out_mem[2]; + celt_sig *decode_mem[2]; + celt_sig *overlap_mem[2]; + celt_sig *out_syn[2]; + opus_val16 *lpc; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + + int shortBlocks; + int isTransient; + int intra_ener; + const int CC = st->channels; + int LM, M; + int effEnd; + int codedBands; + int alloc_trim; + int postfilter_pitch; + opus_val16 postfilter_gain; + int intensity=0; + int dual_stereo=0; + opus_int32 total_bits; + opus_int32 balance; + opus_int32 tell; + int dynalloc_logp; + int postfilter_tapset; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence; + int C = st->stream_channels; + ALLOC_STACK; + + frame_size *= st->downsample; + + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+st->overlap); + out_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE-MAX_PERIOD; + overlap_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE; + } while (++c_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*CC); + oldBandE = lpc+CC*LPC_ORDER; + oldLogE = oldBandE + 2*st->mode->nbEBands; + oldLogE2 = oldLogE + 2*st->mode->nbEBands; + backgroundLogE = oldLogE2 + 2*st->mode->nbEBands; + +#ifdef CUSTOM_MODES + if (st->signalling && data!=NULL) + { + int data0=data[0]; + /* Convert "standard mode" to Opus header */ + if (st->mode->Fs==48000 && st->mode->shortMdctSize==120) + { + data0 = fromOpus(data0); + if (data0<0) + return OPUS_INVALID_PACKET; + } + st->end = IMAX(1, st->mode->effEBands-2*(data0>>5)); + LM = (data0>>3)&0x3; + C = 1 + ((data0>>2)&0x1); + data++; + len--; + if (LM>st->mode->maxLM) + return OPUS_INVALID_PACKET; + if (frame_size < st->mode->shortMdctSize<mode->shortMdctSize<mode->maxLM;LM++) + if (st->mode->shortMdctSize<st->mode->maxLM) + return OPUS_BAD_ARG; + } + M=1<1275 || pcm==NULL) + return OPUS_BAD_ARG; + + N = M*st->mode->shortMdctSize; + + effEnd = st->end; + if (effEnd > st->mode->effEBands) + effEnd = st->mode->effEBands; + + ALLOC(freq, IMAX(CC,C)*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ + ALLOC(bandE, st->mode->nbEBands*C, celt_ener); + c=0; do + for (i=0;imode->eBands[st->start];i++) + X[c*N+i] = 0; + while (++cmode->eBands[effEnd];idownsample; + } + + if (dec == NULL) + { + ec_dec_init(&_dec,(unsigned char*)data,len); + dec = &_dec; + } + + if (C==1) + { + for (i=0;imode->nbEBands;i++) + oldBandE[i]=MAX16(oldBandE[i],oldBandE[st->mode->nbEBands+i]); + } + + total_bits = len*8; + tell = ec_tell(dec); + + if (tell >= total_bits) + silence = 1; + else if (tell==1) + silence = ec_dec_bit_logp(dec, 15); + else + silence = 0; + if (silence) + { + /* Pretend we've read all the remaining bits */ + tell = len*8; + dec->nbits_total+=tell-ec_tell(dec); + } + + postfilter_gain = 0; + postfilter_pitch = 0; + postfilter_tapset = 0; + if (st->start==0 && tell+16 <= total_bits) + { + if(ec_dec_bit_logp(dec, 1)) + { + int qg, octave; + octave = ec_dec_uint(dec, 6); + postfilter_pitch = (16< 0 && tell+3 <= total_bits) + { + isTransient = ec_dec_bit_logp(dec, 3); + tell = ec_tell(dec); + } + else + isTransient = 0; + + if (isTransient) + shortBlocks = M; + else + shortBlocks = 0; + + /* Decode the global flags (first symbols in the stream) */ + intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0; + /* Get band energies */ + unquant_coarse_energy(st->mode, st->start, st->end, oldBandE, + intra_ener, dec, C, LM); + + ALLOC(tf_res, st->mode->nbEBands, int); + tf_decode(st->start, st->end, isTransient, tf_res, LM, dec); + + tell = ec_tell(dec); + spread_decision = SPREAD_NORMAL; + if (tell+4 <= total_bits) + spread_decision = ec_dec_icdf(dec, spread_icdf, 5); + + ALLOC(pulses, st->mode->nbEBands, int); + ALLOC(cap, st->mode->nbEBands, int); + ALLOC(offsets, st->mode->nbEBands, int); + ALLOC(fine_priority, st->mode->nbEBands, int); + + init_caps(st->mode,cap,LM,C); + + dynalloc_logp = 6; + total_bits<<=BITRES; + tell = ec_tell_frac(dec); + for (i=st->start;iend;i++) + { + int width, quanta; + int dynalloc_loop_logp; + int boost; + width = C*(st->mode->eBands[i+1]-st->mode->eBands[i])<0) + dynalloc_logp = IMAX(2, dynalloc_logp-1); + } + + ALLOC(fine_quant, st->mode->nbEBands, int); + alloc_trim = tell+(6<=2&&bits>=((LM+2)<mode, st->start, st->end, offsets, cap, + alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses, + fine_quant, fine_priority, C, LM, dec, 0, 0); + + unquant_fine_energy(st->mode, st->start, st->end, oldBandE, fine_quant, dec, C); + + /* Decode fixed codebook */ + ALLOC(collapse_masks, C*st->mode->nbEBands, unsigned char); + quant_all_bands(0, st->mode, st->start, st->end, X, C==2 ? X+N : NULL, collapse_masks, + NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res, + len*(8<rng); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = ec_dec_bits(dec, 1); + } + + unquant_energy_finalise(st->mode, st->start, st->end, oldBandE, + fine_quant, fine_priority, len*8-ec_tell(dec), dec, C); + + if (anti_collapse_on) + anti_collapse(st->mode, X, collapse_masks, LM, C, CC, N, + st->start, st->end, oldBandE, oldLogE, oldLogE2, pulses, st->rng); + + log2Amp(st->mode, st->start, st->end, bandE, oldBandE, C); + + if (silence) + { + for (i=0;imode->nbEBands;i++) + { + bandE[i] = 0; + oldBandE[i] = -QCONST16(28.f,DB_SHIFT); + } + } + /* Synthesis */ + denormalise_bands(st->mode, X, freq, bandE, effEnd, C, M); + + OPUS_MOVE(decode_mem[0], decode_mem[0]+N, DECODE_BUFFER_SIZE-N); + if (CC==2) + OPUS_MOVE(decode_mem[1], decode_mem[1]+N, DECODE_BUFFER_SIZE-N); + + c=0; do + for (i=0;imode->eBands[st->start];i++) + freq[c*N+i] = 0; + while (++cmode->eBands[effEnd]; + if (st->downsample!=1) + bound = IMIN(bound, N/st->downsample); + for (i=bound;imode, shortBlocks, freq, out_syn, overlap_mem, CC, LM); + + c=0; do { + st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD); + st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, st->mode->shortMdctSize, + st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset, + st->mode->window, st->overlap); + if (LM!=0) + comb_filter(out_syn[c]+st->mode->shortMdctSize, out_syn[c]+st->mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-st->mode->shortMdctSize, + st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset, + st->mode->window, st->mode->overlap); + + } while (++cpostfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + st->postfilter_period = postfilter_pitch; + st->postfilter_gain = postfilter_gain; + st->postfilter_tapset = postfilter_tapset; + if (LM!=0) + { + st->postfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + } + + if (C==1) { + for (i=0;imode->nbEBands;i++) + oldBandE[st->mode->nbEBands+i]=oldBandE[i]; + } + + /* In case start or end were to change */ + if (!isTransient) + { + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE2[i] = oldLogE[i]; + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i] = oldBandE[i]; + for (i=0;i<2*st->mode->nbEBands;i++) + backgroundLogE[i] = MIN16(backgroundLogE[i] + M*QCONST16(0.001f,DB_SHIFT), oldBandE[i]); + } else { + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); + } + c=0; do + { + for (i=0;istart;i++) + { + oldBandE[c*st->mode->nbEBands+i]=0; + oldLogE[c*st->mode->nbEBands+i]=oldLogE2[c*st->mode->nbEBands+i]=-QCONST16(28.f,DB_SHIFT); + } + for (i=st->end;imode->nbEBands;i++) + { + oldBandE[c*st->mode->nbEBands+i]=0; + oldLogE[c*st->mode->nbEBands+i]=oldLogE2[c*st->mode->nbEBands+i]=-QCONST16(28.f,DB_SHIFT); + } + } while (++c<2); + st->rng = dec->rng; + + deemphasis(out_syn, pcm, N, CC, st->downsample, st->mode->preemph, st->preemph_memD); + st->loss_count = 0; + RESTORE_STACK; + if (ec_tell(dec) > 8*len) + return OPUS_INTERNAL_ERROR; + if(ec_get_error(dec)) + st->error = 1; + return frame_size/st->downsample; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_decode(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size) +{ + return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_decode_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size) +{ + int j, ret, C, N; + VARDECL(opus_int16, out); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + + ALLOC(out, C*N, opus_int16); + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL); + if (ret>0) + for (j=0;jchannels; + N = frame_size; + ALLOC(out, C*N, celt_sig); + + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL); + + if (ret>0) + for (j=0;j=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case CELT_GET_AND_CLEAR_ERROR_REQUEST: + { + int *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value=st->error; + st->error = 0; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + int *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->overlap/st->downsample; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *lpc, *oldBandE, *oldLogE, *oldLogE2; + lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*st->channels); + oldBandE = lpc+st->channels*LPC_ORDER; + oldLogE = oldBandE + 2*st->mode->nbEBands; + oldLogE2 = oldLogE + 2*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->DECODER_RESET_START, + opus_custom_decoder_get_size(st->mode, st->channels)- + ((char*)&st->DECODER_RESET_START - (char*)st)); + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + } + break; + case OPUS_GET_PITCH_REQUEST: + { + int *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->postfilter_period; + } + break; +#ifdef OPUS_BUILD + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; +#endif + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} + + + +const char *opus_strerror(int error) +{ + static const char *error_strings[8] = { + "success", + "invalid argument", + "buffer too small", + "internal error", + "corrupted stream", + "request not implemented", + "invalid state", + "memory allocation failed" + }; + if (error > 0 || error < -7) + return "unknown error"; + else + return error_strings[-error]; +} + +const char *opus_get_version_string(void) +{ + return "libopus " OPUS_VERSION +#ifdef FUZZING + "-fuzzing" +#endif + ; +} diff --git a/media/libopus/celt/celt.h b/media/libopus/celt/celt.h new file mode 100644 index 000000000000..234a17b2fc5b --- /dev/null +++ b/media/libopus/celt/celt.h @@ -0,0 +1,117 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/** + @file celt.h + @brief Contains all the functions for encoding and decoding audio + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CELT_H +#define CELT_H + +#include "opus_types.h" +#include "opus_defines.h" +#include "opus_custom.h" +#include "entenc.h" +#include "entdec.h" +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CELTEncoder OpusCustomEncoder +#define CELTDecoder OpusCustomDecoder +#define CELTMode OpusCustomMode + +#define _celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr))) + +/* Encoder/decoder Requests */ + +#define CELT_SET_PREDICTION_REQUEST 10002 +/** Controls the use of interframe prediction. + 0=Independent frames + 1=Short term interframe prediction allowed + 2=Long term prediction allowed + */ +#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x) + +#define CELT_SET_INPUT_CLIPPING_REQUEST 10004 +#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x) + +#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007 +#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x) + +#define CELT_SET_CHANNELS_REQUEST 10008 +#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x) + + +/* Internal */ +#define CELT_SET_START_BAND_REQUEST 10010 +#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x) + +#define CELT_SET_END_BAND_REQUEST 10012 +#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x) + +#define CELT_GET_MODE_REQUEST 10015 +/** Get the CELTMode used by an encoder or decoder */ +#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, _celt_check_mode_ptr_ptr(x) + +#define CELT_SET_SIGNALLING_REQUEST 10016 +#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x) + + + +/* Encoder stuff */ + +int celt_encoder_get_size(int channels); + +int celt_encode_with_ec(OpusCustomEncoder * restrict st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels); + + + +/* Decoder stuff */ + +int celt_decoder_get_size(int channels); + + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels); + +int celt_decode_with_ec(OpusCustomDecoder * restrict st, const unsigned char *data, int len, opus_val16 * restrict pcm, int frame_size, ec_dec *dec); + +#define celt_encoder_ctl opus_custom_encoder_ctl +#define celt_decoder_ctl opus_custom_decoder_ctl + +#ifdef __cplusplus +} +#endif + +#endif /* CELT_H */ diff --git a/media/libopus/celt/celt_lpc.c b/media/libopus/celt/celt_lpc.c new file mode 100644 index 000000000000..f6cadf440786 --- /dev/null +++ b/media/libopus/celt/celt_lpc.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" + +void _celt_lpc( + opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */ +const opus_val32 *ac, /* in: [0...p] autocorrelation values */ +int p +) +{ + int i, j; + opus_val32 r; + opus_val32 error = ac[0]; +#ifdef FIXED_POINT + opus_val32 lpc[LPC_ORDER]; +#else + float *lpc = _lpc; +#endif + + for (i = 0; i < p; i++) + lpc[i] = 0; + if (ac[0] != 0) + { + for (i = 0; i < p; i++) { + /* Sum up this iteration's reflection coefficient */ + opus_val32 rr = 0; + for (j = 0; j < i; j++) + rr += MULT32_32_Q31(lpc[j],ac[i - j]); + rr += SHR32(ac[i + 1],3); + r = -frac_div32(SHL32(rr,3), error); + /* Update LPC coefficients and total error */ + lpc[i] = SHR32(r,3); + for (j = 0; j < (i+1)>>1; j++) + { + opus_val32 tmp1, tmp2; + tmp1 = lpc[j]; + tmp2 = lpc[i-1-j]; + lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2); + lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1); + } + + error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error); + /* Bail out once we get 30 dB gain */ +#ifdef FIXED_POINT + if (error=1;j--) + { + mem[j]=mem[j-1]; + } + mem[0] = x[i]; + y[i] = ROUND16(sum, SIG_SHIFT); + } +} + +void celt_iir(const opus_val32 *x, + const opus_val16 *den, + opus_val32 *y, + int N, + int ord, + opus_val16 *mem) +{ + int i,j; + for (i=0;i=1;j--) + { + mem[j]=mem[j-1]; + } + mem[0] = ROUND16(sum,SIG_SHIFT); + y[i] = sum; + } +} + +void _celt_autocorr( + const opus_val16 *x, /* in: [0...n-1] samples x */ + opus_val32 *ac, /* out: [0...lag-1] ac values */ + const opus_val16 *window, + int overlap, + int lag, + int n + ) +{ + opus_val32 d; + int i; + VARDECL(opus_val16, xx); + SAVE_STACK; + ALLOC(xx, n, opus_val16); + celt_assert(n>0); + celt_assert(overlap>=0); + for (i=0;i=0) + { + for (i = lag, d = 0; i < n; i++) + d += xx[i] * xx[i-lag]; + ac[lag] = d; + /*printf ("%f ", ac[lag]);*/ + lag--; + } + /*printf ("\n");*/ + ac[0] += 10; + + RESTORE_STACK; +} diff --git a/media/libopus/celt/celt_lpc.h b/media/libopus/celt/celt_lpc.h new file mode 100644 index 000000000000..fd762cd78a01 --- /dev/null +++ b/media/libopus/celt/celt_lpc.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PLC_H +#define PLC_H + +#include "arch.h" + +#define LPC_ORDER 24 + +void _celt_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p); + +void celt_fir(const opus_val16 *x, + const opus_val16 *num, + opus_val16 *y, + int N, + int ord, + opus_val16 *mem); + +void celt_iir(const opus_val32 *x, + const opus_val16 *den, + opus_val32 *y, + int N, + int ord, + opus_val16 *mem); + +void _celt_autocorr(const opus_val16 *x, opus_val32 *ac, const opus_val16 *window, int overlap, int lag, int n); + +#endif /* PLC_H */ diff --git a/media/libopus/celt/cwrs.c b/media/libopus/celt/cwrs.c new file mode 100644 index 000000000000..91be9800f942 --- /dev/null +++ b/media/libopus/celt/cwrs.c @@ -0,0 +1,644 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "os_support.h" +#include "cwrs.h" +#include "mathops.h" +#include "arch.h" + +#ifdef CUSTOM_MODES + +/*Guaranteed to return a conservatively large estimate of the binary logarithm + with frac bits of fractional precision. + Tested for all possible 32-bit inputs with frac=4, where the maximum + overestimation is 0.06254243 bits.*/ +int log2_frac(opus_uint32 val, int frac) +{ + int l; + l=EC_ILOG(val); + if(val&(val-1)){ + /*This is (val>>l-16), but guaranteed to round up, even if adding a bias + before the shift would cause overflow (e.g., for 0xFFFFxxxx).*/ + if(l>16)val=(val>>(l-16))+(((val&((1<<(l-16))-1))+(1<<(l-16))-1)>>(l-16)); + else val<<=16-l; + l=(l-1)<>16); + l+=b<>b; + val=(val*val+0x7FFF)>>15; + } + while(frac-->0); + /*If val is not exactly 0x8000, then we have to round up the remainder.*/ + return l+(val>0x8000); + } + /*Exact powers of two require no rounding.*/ + else return (l-1)<0); + celt_assert(_d<=54); + shift=EC_ILOG(_d^(_d-1)); + inv=INV_TABLE[(_d-1)>>shift]; + shift--; + one=1<>shift)-(_c>>shift)+ + ((_a*(_b&mask)+one-(_c&mask))>>shift)-1)*inv&MASK32; +} + +#endif /* SMALL_FOOTPRINT */ + +/*Although derived separately, the pulse vector coding scheme is equivalent to + a Pyramid Vector Quantizer \cite{Fis86}. + Some additional notes about an early version appear at + http://people.xiph.org/~tterribe/notes/cwrs.html, but the codebook ordering + and the definitions of some terms have evolved since that was written. + + The conversion from a pulse vector to an integer index (encoding) and back + (decoding) is governed by two related functions, V(N,K) and U(N,K). + + V(N,K) = the number of combinations, with replacement, of N items, taken K + at a time, when a sign bit is added to each item taken at least once (i.e., + the number of N-dimensional unit pulse vectors with K pulses). + One way to compute this is via + V(N,K) = K>0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1, + where choose() is the binomial function. + A table of values for N<10 and K<10 looks like: + V[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 2, 2, 2, 2, 2, 2, 2, 2, 2}, + {1, 4, 8, 12, 16, 20, 24, 28, 32, 36}, + {1, 6, 18, 38, 66, 102, 146, 198, 258, 326}, + {1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992}, + {1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290}, + {1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436}, + {1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598}, + {1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688}, + {1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146} + }; + + U(N,K) = the number of such combinations wherein N-1 objects are taken at + most K-1 at a time. + This is given by + U(N,K) = sum(k=0...K-1,V(N-1,k)) + = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0. + The latter expression also makes clear that U(N,K) is half the number of such + combinations wherein the first object is taken at least once. + Although it may not be clear from either of these definitions, U(N,K) is the + natural function to work with when enumerating the pulse vector codebooks, + not V(N,K). + U(N,K) is not well-defined for N=0, but with the extension + U(0,K) = K>0 ? 0 : 1, + the function becomes symmetric: U(N,K) = U(K,N), with a similar table: + U[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {0, 1, 3, 5, 7, 9, 11, 13, 15, 17}, + {0, 1, 5, 13, 25, 41, 61, 85, 113, 145}, + {0, 1, 7, 25, 63, 129, 231, 377, 575, 833}, + {0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649}, + {0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073}, + {0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081}, + {0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545}, + {0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729} + }; + + With this extension, V(N,K) may be written in terms of U(N,K): + V(N,K) = U(N,K) + U(N,K+1) + for all N>=0, K>=0. + Thus U(N,K+1) represents the number of combinations where the first element + is positive or zero, and U(N,K) represents the number of combinations where + it is negative. + With a large enough table of U(N,K) values, we could write O(N) encoding + and O(min(N*log(K),N+K)) decoding routines, but such a table would be + prohibitively large for small embedded devices (K may be as large as 32767 + for small N, and N may be as large as 200). + + Both functions obey the same recurrence relation: + V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1), + U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1), + for all N>0, K>0, with different initial conditions at N=0 or K=0. + This allows us to construct a row of one of the tables above given the + previous row or the next row. + Thus we can derive O(NK) encoding and decoding routines with O(K) memory + using only addition and subtraction. + + When encoding, we build up from the U(2,K) row and work our way forwards. + When decoding, we need to start at the U(N,K) row and work our way backwards, + which requires a means of computing U(N,K). + U(N,K) may be computed from two previous values with the same N: + U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2) + for all N>1, and since U(N,K) is symmetric, a similar relation holds for two + previous values with the same K: + U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K) + for all K>1. + This allows us to construct an arbitrary row of the U(N,K) table by starting + with the first two values, which are constants. + This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K) + multiplications. + Similar relations can be derived for V(N,K), but are not used here. + + For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree + polynomial for fixed N. + The first few are + U(1,K) = 1, + U(2,K) = 2*K-1, + U(3,K) = (2*K-2)*K+1, + U(4,K) = (((4*K-6)*K+8)*K-3)/3, + U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3, + and + V(1,K) = 2, + V(2,K) = 4*K, + V(3,K) = 4*K*K+2, + V(4,K) = 8*(K*K+2)*K/3, + V(5,K) = ((4*K*K+20)*K*K+6)/3, + for all K>0. + This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for + small N (and indeed decoding is also O(N) for N<3). + + @ARTICLE{Fis86, + author="Thomas R. Fischer", + title="A Pyramid Vector Quantizer", + journal="IEEE Transactions on Information Theory", + volume="IT-32", + number=4, + pages="568--583", + month=Jul, + year=1986 + }*/ + +#ifndef SMALL_FOOTPRINT +/*Compute U(2,_k). + Note that this may be called with _k=32768 (maxK[2]+1).*/ +static inline unsigned ucwrs2(unsigned _k){ + celt_assert(_k>0); + return _k+(_k-1); +} + +/*Compute V(2,_k).*/ +static inline opus_uint32 ncwrs2(int _k){ + celt_assert(_k>0); + return 4*(opus_uint32)_k; +} + +/*Compute U(3,_k). + Note that this may be called with _k=32768 (maxK[3]+1).*/ +static inline opus_uint32 ucwrs3(unsigned _k){ + celt_assert(_k>0); + return (2*(opus_uint32)_k-2)*_k+1; +} + +/*Compute V(3,_k).*/ +static inline opus_uint32 ncwrs3(int _k){ + celt_assert(_k>0); + return 2*(2*(unsigned)_k*(opus_uint32)_k+1); +} + +/*Compute U(4,_k).*/ +static inline opus_uint32 ucwrs4(int _k){ + celt_assert(_k>0); + return imusdiv32odd(2*_k,(2*_k-3)*(opus_uint32)_k+4,3,1); +} + +/*Compute V(4,_k).*/ +static inline opus_uint32 ncwrs4(int _k){ + celt_assert(_k>0); + return ((_k*(opus_uint32)_k+2)*_k)/3<<3; +} + +#endif /* SMALL_FOOTPRINT */ + +/*Computes the next row/column of any recurrence that obeys the relation + u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static inline void unext(opus_uint32 *_ui,unsigned _len,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_len); + _ui[j-1]=_ui0; +} + +/*Computes the previous row/column of any recurrence that obeys the relation + u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static inline void uprev(opus_uint32 *_ui,unsigned _n,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_n); + _ui[j-1]=_ui0; +} + +/*Compute V(_n,_k), as well as U(_n,0..._k+1). + _u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/ +static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){ + opus_uint32 um2; + unsigned len; + unsigned k; + len=_k+2; + /*We require storage at least 3 values (e.g., _k>0).*/ + celt_assert(len>=3); + _u[0]=0; + _u[1]=um2=1; +#ifndef SMALL_FOOTPRINT + /*_k>52 doesn't work in the false branch due to the limits of INV_TABLE, + but _k isn't tested here because k<=52 for n=7*/ + if(_n<=6) +#endif + { + /*If _n==0, _u[0] should be 1 and the rest should be 0.*/ + /*If _n==1, _u[i] should be 1 for i>1.*/ + celt_assert(_n>=2); + /*If _k==0, the following do-while loop will overflow the buffer.*/ + celt_assert(_k>0); + k=2; + do _u[k]=(k<<1)-1; + while(++k=len)break; + _u[k]=um1=imusdiv32odd(n2m1,um2,um1,(k-1)>>1)+um1; + } + } +#endif /* SMALL_FOOTPRINT */ + return _u[_k]+_u[_k+1]; +} + +#ifndef SMALL_FOOTPRINT + +/*Returns the _i'th combination of _k elements (at most 32767) chosen from a + set of size 1 with associated sign bits. + _y: Returns the vector of pulses.*/ +static inline void cwrsi1(int _k,opus_uint32 _i,int *_y){ + int s; + s=-(int)_i; + _y[0]=(_k+s)^s; +} + +/*Returns the _i'th combination of _k elements (at most 32767) chosen from a + set of size 2 with associated sign bits. + _y: Returns the vector of pulses.*/ +static inline void cwrsi2(int _k,opus_uint32 _i,int *_y){ + opus_uint32 p; + int s; + int yj; + p=ucwrs2(_k+1U); + s=-(_i>=p); + _i-=p&s; + yj=_k; + _k=(_i+1)>>1; + p=_k?ucwrs2(_k):0; + _i-=p; + yj-=_k; + _y[0]=(yj+s)^s; + cwrsi1(_k,_i,_y+1); +} + +/*Returns the _i'th combination of _k elements (at most 32767) chosen from a + set of size 3 with associated sign bits. + _y: Returns the vector of pulses.*/ +static void cwrsi3(int _k,opus_uint32 _i,int *_y){ + opus_uint32 p; + int s; + int yj; + p=ucwrs3(_k+1U); + s=-(_i>=p); + _i-=p&s; + yj=_k; + /*Finds the maximum _k such that ucwrs3(_k)<=_i (tested for all + _i<2147418113=U(3,32768)).*/ + _k=_i>0?(isqrt32(2*_i-1)+1)>>1:0; + p=_k?ucwrs3(_k):0; + _i-=p; + yj-=_k; + _y[0]=(yj+s)^s; + cwrsi2(_k,_i,_y+1); +} + +/*Returns the _i'th combination of _k elements (at most 1172) chosen from a set + of size 4 with associated sign bits. + _y: Returns the vector of pulses.*/ +static void cwrsi4(int _k,opus_uint32 _i,int *_y){ + opus_uint32 p; + int s; + int yj; + int kl; + int kr; + p=ucwrs4(_k+1); + s=-(_i>=p); + _i-=p&s; + yj=_k; + /*We could solve a cubic for k here, but the form of the direct solution does + not lend itself well to exact integer arithmetic. + Instead we do a binary search on U(4,K).*/ + kl=0; + kr=_k; + for(;;){ + _k=(kl+kr)>>1; + p=_k?ucwrs4(_k):0; + if(p<_i){ + if(_k>=kr)break; + kl=_k+1; + } + else if(p>_i)kr=_k-1; + else break; + } + _i-=p; + yj-=_k; + _y[0]=(yj+s)^s; + cwrsi3(_k,_i,_y+1); +} + +#endif /* SMALL_FOOTPRINT */ + +/*Returns the _i'th combination of _k elements chosen from a set of size _n + with associated sign bits. + _y: Returns the vector of pulses. + _u: Must contain entries [0..._k+1] of row _n of U() on input. + Its contents will be destructively modified.*/ +static void cwrsi(int _n,int _k,opus_uint32 _i,int *_y,opus_uint32 *_u){ + int j; + celt_assert(_n>0); + j=0; + do{ + opus_uint32 p; + int s; + int yj; + p=_u[_k+1]; + s=-(_i>=p); + _i-=p&s; + yj=_k; + p=_u[_k]; + while(p>_i)p=_u[--_k]; + _i-=p; + yj-=_k; + _y[j]=(yj+s)^s; + uprev(_u,_k+2,0); + } + while(++j<_n); +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 1 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline opus_uint32 icwrs1(const int *_y,int *_k){ + *_k=abs(_y[0]); + return _y[0]<0; +} + +#ifndef SMALL_FOOTPRINT + +/*Returns the index of the given combination of K elements chosen from a set + of size 2 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline opus_uint32 icwrs2(const int *_y,int *_k){ + opus_uint32 i; + int k; + i=icwrs1(_y+1,&k); + i+=k?ucwrs2(k):0; + k+=abs(_y[0]); + if(_y[0]<0)i+=ucwrs2(k+1U); + *_k=k; + return i; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 3 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline opus_uint32 icwrs3(const int *_y,int *_k){ + opus_uint32 i; + int k; + i=icwrs2(_y+1,&k); + i+=k?ucwrs3(k):0; + k+=abs(_y[0]); + if(_y[0]<0)i+=ucwrs3(k+1U); + *_k=k; + return i; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 4 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline opus_uint32 icwrs4(const int *_y,int *_k){ + opus_uint32 i; + int k; + i=icwrs3(_y+1,&k); + i+=k?ucwrs4(k):0; + k+=abs(_y[0]); + if(_y[0]<0)i+=ucwrs4(k+1); + *_k=k; + return i; +} + +#endif /* SMALL_FOOTPRINT */ + +/*Returns the index of the given combination of K elements chosen from a set + of size _n with associated sign bits. + _y: The vector of pulses, whose sum of absolute values must be _k. + _nc: Returns V(_n,_k).*/ +static inline opus_uint32 icwrs(int _n,int _k,opus_uint32 *_nc,const int *_y, + opus_uint32 *_u){ + opus_uint32 i; + int j; + int k; + /*We can't unroll the first two iterations of the loop unless _n>=2.*/ + celt_assert(_n>=2); + _u[0]=0; + for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1; + i=icwrs1(_y+_n-1,&k); + j=_n-2; + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + while(j-->0){ + unext(_u,_k+2,0); + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + } + *_nc=_u[k]+_u[k+1]; + return i; +} + +#ifdef CUSTOM_MODES +void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + if (_n==1) + { + for (k=1;k<=_maxk;k++) + _bits[k] = 1<<_frac; + } + else { + VARDECL(opus_uint32,u); + SAVE_STACK; + ALLOC(u,_maxk+2U,opus_uint32); + ncwrs_urow(_n,_maxk,u); + for(k=1;k<=_maxk;k++) + _bits[k]=log2_frac(u[k]+u[k+1],_frac); + RESTORE_STACK; + } +} +#endif /* CUSTOM_MODES */ + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + opus_uint32 i; + celt_assert(_k>0); +#ifndef SMALL_FOOTPRINT + switch(_n){ + case 2:{ + i=icwrs2(_y,&_k); + ec_enc_uint(_enc,i,ncwrs2(_k)); + }break; + case 3:{ + i=icwrs3(_y,&_k); + ec_enc_uint(_enc,i,ncwrs3(_k)); + }break; + case 4:{ + i=icwrs4(_y,&_k); + ec_enc_uint(_enc,i,ncwrs4(_k)); + }break; + default: + { +#endif + VARDECL(opus_uint32,u); + opus_uint32 nc; + SAVE_STACK; + ALLOC(u,_k+2U,opus_uint32); + i=icwrs(_n,_k,&nc,_y,u); + ec_enc_uint(_enc,i,nc); + RESTORE_STACK; +#ifndef SMALL_FOOTPRINT + } + break; + } +#endif +} + +void decode_pulses(int *_y,int _n,int _k,ec_dec *_dec) +{ + celt_assert(_k>0); +#ifndef SMALL_FOOTPRINT + switch(_n){ + case 2:cwrsi2(_k,ec_dec_uint(_dec,ncwrs2(_k)),_y);break; + case 3:cwrsi3(_k,ec_dec_uint(_dec,ncwrs3(_k)),_y);break; + case 4:cwrsi4(_k,ec_dec_uint(_dec,ncwrs4(_k)),_y);break; + default: + { +#endif + VARDECL(opus_uint32,u); + SAVE_STACK; + ALLOC(u,_k+2U,opus_uint32); + cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u); + RESTORE_STACK; +#ifndef SMALL_FOOTPRINT + } + break; + } +#endif +} diff --git a/media/libopus/celt/cwrs.h b/media/libopus/celt/cwrs.h new file mode 100644 index 000000000000..7712394361da --- /dev/null +++ b/media/libopus/celt/cwrs.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CWRS_H +#define CWRS_H + +#include "arch.h" +#include "stack_alloc.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef CUSTOM_MODES +int log2_frac(opus_uint32 val, int frac); +#endif + +void get_required_bits(opus_int16 *bits, int N, int K, int frac); + +void encode_pulses(const int *_y, int N, int K, ec_enc *enc); + +void decode_pulses(int *_y, int N, int K, ec_dec *dec); + +#endif /* CWRS_H */ diff --git a/media/libopus/celt/ecintrin.h b/media/libopus/celt/ecintrin.h new file mode 100644 index 000000000000..8f501c21f7db --- /dev/null +++ b/media/libopus/celt/ecintrin.h @@ -0,0 +1,102 @@ +/* Copyright (c) 2003-2008 Timothy B. Terriberry + Copyright (c) 2008 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*Some common macros for potential platform-specific optimization.*/ +#include "opus_types.h" +#include +#include +#include "arch.h" +#if !defined(_ecintrin_H) +# define _ecintrin_H (1) + +/*Some specific platforms may have optimized intrinsic or inline assembly + versions of these functions which can substantially improve performance. + We define macros for them to allow easy incorporation of these non-ANSI + features.*/ + +/*Note that we do not provide a macro for abs(), because it is provided as a + library function, which we assume is translated into an intrinsic to avoid + the function call overhead and then implemented in the smartest way for the + target platform. + With modern gcc (4.x), this is true: it uses cmov instructions if the + architecture supports it and branchless bit-twiddling if it does not (the + speed difference between the two approaches is not measurable). + Interestingly, the bit-twiddling method was patented in 2000 (US 6,073,150) + by Sun Microsystems, despite prior art dating back to at least 1996: + http://web.archive.org/web/19961201174141/www.x86.org/ftp/articles/pentopt/PENTOPT.TXT + On gcc 3.x, however, our assumption is not true, as abs() is translated to a + conditional jump, which is horrible on deeply piplined architectures (e.g., + all consumer architectures for the past decade or more) when the sign cannot + be reliably predicted.*/ + +/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if + given an appropriate architecture, but the branchless bit-twiddling versions + are just as fast, and do not require any special target architecture. + Earlier gcc versions (3.x) compiled both code to the same assembly + instructions, because of the way they represented ((_b)>(_a)) internally.*/ +# define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a)))) + +/*Count leading zeros. + This macro should only be used for implementing ec_ilog(), if it is defined. + All other code should use EC_ILOG() instead.*/ +#if defined(_MSC_VER) +# include +/*In _DEBUG mode this is not an intrinsic by default.*/ +# pragma intrinsic(_BitScanReverse) + +static __inline int ec_bsr(unsigned long _x){ + unsigned long ret; + _BitScanReverse(&ret,_x); + return (int)ret; +} +# define EC_CLZ0 (1) +# define EC_CLZ(_x) (-ec_bsr(_x)) +#elif defined(ENABLE_TI_DSPLIB) +# include "dsplib.h" +# define EC_CLZ0 (31) +# define EC_CLZ(_x) (_lnorm(_x)) +#elif __GNUC_PREREQ(3,4) +# if INT_MAX>=2147483647 +# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clz(_x)) +# elif LONG_MAX>=2147483647L +# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clzl(_x)) +# endif +#endif + +#if defined(EC_CLZ) +/*Note that __builtin_clz is not defined when _x==0, according to the gcc + documentation (and that of the BSR instruction that implements it on x86). + The majority of the time we can never pass it zero. + When we need to, it can be special cased.*/ +# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x)) +#else +int ec_ilog(opus_uint32 _v); +# define EC_ILOG(_x) (ec_ilog(_x)) +#endif +#endif diff --git a/media/libopus/celt/entcode.c b/media/libopus/celt/entcode.c new file mode 100644 index 000000000000..0d9c7fc522e7 --- /dev/null +++ b/media/libopus/celt/entcode.c @@ -0,0 +1,88 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "entcode.h" +#include "arch.h" + +#if !defined(EC_CLZ) +int ec_ilog(opus_uint32 _v){ + /*On a Pentium M, this branchless version tested as the fastest on + 1,000,000,000 random 32-bit integers, edging out a similar version with + branches, and a 256-entry LUT version.*/ + int ret; + int m; + ret=!!_v; + m=!!(_v&0xFFFF0000)<<4; + _v>>=m; + ret|=m; + m=!!(_v&0xFF00)<<3; + _v>>=m; + ret|=m; + m=!!(_v&0xF0)<<2; + _v>>=m; + ret|=m; + m=!!(_v&0xC)<<1; + _v>>=m; + ret|=m; + ret+=!!(_v&0x2); + return ret; +} +#endif + +opus_uint32 ec_tell_frac(ec_ctx *_this){ + opus_uint32 nbits; + opus_uint32 r; + int l; + int i; + /*To handle the non-integral number of bits still left in the encoder/decoder + state, we compute the worst-case number of bits of val that must be + encoded to ensure that the value is inside the range for any possible + subsequent bits. + The computation here is independent of val itself (the decoder does not + even track that value), even though the real number of bits used after + ec_enc_done() may be 1 smaller if rng is a power of two and the + corresponding trailing bits of val are all zeros. + If we did try to track that special case, then coding a value with a + probability of 1/(1<nbits_total<rng); + r=_this->rng>>(l-16); + for(i=BITRES;i-->0;){ + int b; + r=r*r>>15; + b=(int)(r>>16); + l=l<<1|b; + r>>=b; + } + return nbits-l; +} diff --git a/media/libopus/celt/entcode.h b/media/libopus/celt/entcode.h new file mode 100644 index 000000000000..2792ada9d133 --- /dev/null +++ b/media/libopus/celt/entcode.h @@ -0,0 +1,116 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "opus_types.h" + +#if !defined(_entcode_H) +# define _entcode_H (1) +# include +# include +# include "ecintrin.h" + +/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a + larger type, you can speed up the decoder by using it here.*/ +typedef opus_uint32 ec_window; +typedef struct ec_ctx ec_ctx; +typedef struct ec_ctx ec_enc; +typedef struct ec_ctx ec_dec; + +# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT) + +/*The number of bits to use for the range-coded part of unsigned integers.*/ +# define EC_UINT_BITS (8) + +/*The resolution of fractional-precision bit usage measurements, i.e., + 3 => 1/8th bits.*/ +# define BITRES 3 + +/*The entropy encoder/decoder context. + We use the same structure for both, so that common functions like ec_tell() + can be used on either one.*/ +struct ec_ctx{ + /*Buffered input/output.*/ + unsigned char *buf; + /*The size of the buffer.*/ + opus_uint32 storage; + /*The offset at which the last byte containing raw bits was read/written.*/ + opus_uint32 end_offs; + /*Bits that will be read from/written at the end.*/ + ec_window end_window; + /*Number of valid bits in end_window.*/ + int nend_bits; + /*The total number of whole bits read/written. + This does not include partial bits currently in the range coder.*/ + int nbits_total; + /*The offset at which the next range coder byte will be read/written.*/ + opus_uint32 offs; + /*The number of values in the current range.*/ + opus_uint32 rng; + /*In the decoder: the difference between the top of the current range and + the input value, minus one. + In the encoder: the low end of the current range.*/ + opus_uint32 val; + /*In the decoder: the saved normalization factor from ec_decode(). + In the encoder: the number of oustanding carry propagating symbols.*/ + opus_uint32 ext; + /*A buffered input/output symbol, awaiting carry propagation.*/ + int rem; + /*Nonzero if an error occurred.*/ + int error; +}; + +static inline opus_uint32 ec_range_bytes(ec_ctx *_this){ + return _this->offs; +} + +static inline unsigned char *ec_get_buffer(ec_ctx *_this){ + return _this->buf; +} + +static inline int ec_get_error(ec_ctx *_this){ + return _this->error; +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +static inline int ec_tell(ec_ctx *_this){ + return _this->nbits_total-EC_ILOG(_this->rng); +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits scaled by 2**BITRES. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +opus_uint32 ec_tell_frac(ec_ctx *_this); + +#endif diff --git a/media/libopus/celt/entdec.c b/media/libopus/celt/entdec.c new file mode 100644 index 000000000000..8ba09864bce1 --- /dev/null +++ b/media/libopus/celt/entdec.c @@ -0,0 +1,249 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "os_support.h" +#include "arch.h" +#include "entdec.h" +#include "mfrngcod.h" + +/*A range decoder. + This is an entropy decoder based upon \cite{Mar79}, which is itself a + rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}. + It is very similar to arithmetic encoding, except that encoding is done with + digits in any base, instead of with bits, and so it is faster when using + larger bases (i.e.: a byte). + The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$ + is the base, longer than the theoretical optimum, but to my knowledge there + is no published justification for this claim. + This only seems true when using near-infinite precision arithmetic so that + the process is carried out with no rounding errors. + + IBM (the author's employer) never sought to patent the idea, and to my + knowledge the algorithm is unencumbered by any patents, though its + performance is very competitive with proprietary arithmetic coding. + The two are based on very similar ideas, however. + An excellent description of implementation details is available at + http://www.arturocampos.com/ac_range.html + A recent work \cite{MNW98} which proposes several changes to arithmetic + encoding for efficiency actually re-discovers many of the principles + behind range encoding, and presents a good theoretical analysis of them. + + End of stream is handled by writing out the smallest number of bits that + ensures that the stream will be correctly decoded regardless of the value of + any subsequent bits. + ec_tell() can be used to determine how many bits were needed to decode + all the symbols thus far; other data can be packed in the remaining bits of + the input buffer. + @PHDTHESIS{Pas76, + author="Richard Clark Pasco", + title="Source coding algorithms for fast data compression", + school="Dept. of Electrical Engineering, Stanford University", + address="Stanford, CA", + month=May, + year=1976 + } + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video & Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_read_byte(ec_dec *_this){ + return _this->offs<_this->storage?_this->buf[_this->offs++]:0; +} + +static int ec_read_byte_from_end(ec_dec *_this){ + return _this->end_offs<_this->storage? + _this->buf[_this->storage-++(_this->end_offs)]:0; +} + +/*Normalizes the contents of val and rng so that rng lies entirely in the + high-order symbol.*/ +static void ec_dec_normalize(ec_dec *_this){ + /*If the range is too small, rescale it and input some bits.*/ + while(_this->rng<=EC_CODE_BOT){ + int sym; + _this->nbits_total+=EC_SYM_BITS; + _this->rng<<=EC_SYM_BITS; + /*Use up the remaining bits from our last symbol.*/ + sym=_this->rem; + /*Read the next value from the input.*/ + _this->rem=ec_read_byte(_this); + /*Take the rest of the bits we need from this new symbol.*/ + sym=(sym<rem)>>(EC_SYM_BITS-EC_CODE_EXTRA); + /*And subtract them from val, capped to be less than EC_CODE_TOP.*/ + _this->val=((_this->val<buf=_buf; + _this->storage=_storage; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits. + The final value after the ec_dec_normalize() call will be the same as in + the encoder, but we have to compensate for the bits that are added there.*/ + _this->nbits_total=EC_CODE_BITS+1 + -((EC_CODE_BITS-EC_CODE_EXTRA)/EC_SYM_BITS)*EC_SYM_BITS; + _this->offs=0; + _this->rng=1U<rem=ec_read_byte(_this); + _this->val=_this->rng-1-(_this->rem>>(EC_SYM_BITS-EC_CODE_EXTRA)); + _this->error=0; + /*Normalize the interval.*/ + ec_dec_normalize(_this); +} + +unsigned ec_decode(ec_dec *_this,unsigned _ft){ + unsigned s; + _this->ext=_this->rng/_ft; + s=(unsigned)(_this->val/_this->ext); + return _ft-EC_MINI(s+1,_ft); +} + +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){ + unsigned s; + _this->ext=_this->rng>>_bits; + s=(unsigned)(_this->val/_this->ext); + return (1U<<_bits)-EC_MINI(s+1U,1U<<_bits); +} + +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 s; + s=IMUL32(_this->ext,_ft-_fh); + _this->val-=s; + _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s; + ec_dec_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + int ret; + r=_this->rng; + d=_this->val; + s=r>>_logp; + ret=dval=d-s; + _this->rng=ret?s:r-s; + ec_dec_normalize(_this); + return ret; +} + +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + opus_uint32 t; + int ret; + s=_this->rng; + d=_this->val; + r=s>>_ftb; + ret=-1; + do{ + t=s; + s=IMUL32(r,_icdf[++ret]); + } + while(dval=d-s; + _this->rng=t-s; + ec_dec_normalize(_this); + return ret; +} + +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){ + unsigned ft; + unsigned s; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + opus_uint32 t; + ftb-=EC_UINT_BITS; + ft=(unsigned)(_ft>>ftb)+1; + s=ec_decode(_this,ft); + ec_dec_update(_this,s,s+1,ft); + t=(opus_uint32)s<error=1; + return _ft; + } + else{ + _ft++; + s=ec_decode(_this,(unsigned)_ft); + ec_dec_update(_this,s,s+1,(unsigned)_ft); + return s; + } +} + +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){ + ec_window window; + int available; + opus_uint32 ret; + window=_this->end_window; + available=_this->nend_bits; + if((unsigned)available<_bits){ + do{ + window|=(ec_window)ec_read_byte_from_end(_this)<>=_bits; + available-=_bits; + _this->end_window=window; + _this->nend_bits=available; + _this->nbits_total+=_bits; + return ret; +} diff --git a/media/libopus/celt/entdec.h b/media/libopus/celt/entdec.h new file mode 100644 index 000000000000..719fdb24145b --- /dev/null +++ b/media/libopus/celt/entdec.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_entdec_H) +# define _entdec_H (1) +# include +# include "entcode.h" + +/*Initializes the decoder. + _buf: The input buffer to use. + Return: 0 on success, or a negative value on error.*/ +void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage); + +/*Calculates the cumulative frequency for the next symbol. + This can then be fed into the probability model to determine what that + symbol is, and the additional frequency information required to advance to + the next symbol. + This function cannot be called more than once without a corresponding call to + ec_dec_update(), or decoding will not proceed correctly. + _ft: The total frequency of the symbols in the alphabet the next symbol was + encoded with. + Return: A cumulative frequency representing the encoded symbol. + If the cumulative frequency of all the symbols before the one that + was encoded was fl, and the cumulative frequency of all the symbols + up to and including the one encoded is fh, then the returned value + will fall in the range [fl,fh).*/ +unsigned ec_decode(ec_dec *_this,unsigned _ft); + +/*Equivalent to ec_decode() with _ft==1<<_bits.*/ +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits); + +/*Advance the decoder past the next symbol using the frequency information the + symbol was encoded with. + Exactly one call to ec_decode() must have been made so that all necessary + intermediate calculations are performed. + _fl: The cumulative frequency of all symbols that come before the symbol + decoded. + _fh: The cumulative frequency of all symbols up to and including the symbol + decoded. + Together with _fl, this defines the range [_fl,_fh) in which the value + returned above must fall. + _ft: The total frequency of the symbols in the alphabet the symbol decoded + was encoded in. + This must be the same as passed to the preceding call to ec_decode().*/ +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/* Decode a bit that has a 1/(1<<_logp) probability of being a one */ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp); + +/*Decodes a symbol given an "inverse" CDF table. + No call to ec_dec_update() is necessary after this call. + _icdf: The "inverse" CDF, such that symbol s falls in the range + [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution. + Return: The decoded symbol s.*/ +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb); + +/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream. + The bits must have been encoded with ec_enc_uint(). + No call to ec_dec_update() is necessary after this call. + _ft: The number of integers that can be decoded (one more than the max). + This must be at least one, and no more than 2**32-1. + Return: The decoded bits.*/ +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft); + +/*Extracts a sequence of raw bits from the stream. + The bits must have been encoded with ec_enc_bits(). + No call to ec_dec_update() is necessary after this call. + _ftb: The number of bits to extract. + This must be between 0 and 25, inclusive. + Return: The decoded bits.*/ +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb); + +#endif diff --git a/media/libopus/celt/entenc.c b/media/libopus/celt/entenc.c new file mode 100644 index 000000000000..3913d8e855a9 --- /dev/null +++ b/media/libopus/celt/entenc.c @@ -0,0 +1,294 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if defined(HAVE_CONFIG_H) +# include "config.h" +#endif +#include "os_support.h" +#include "arch.h" +#include "entenc.h" +#include "mfrngcod.h" + +/*A range encoder. + See entdec.c and the references for implementation details \cite{Mar79,MNW98}. + + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video \& Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_write_byte(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->offs++]=(unsigned char)_value; + return 0; +} + +static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value; + return 0; +} + +/*Outputs a symbol, with a carry bit. + If there is a potential to propagate a carry over several symbols, they are + buffered until it can be determined whether or not an actual carry will + occur. + If the counter for the buffered symbols overflows, then the stream becomes + undecodable. + This gives a theoretical limit of a few billion symbols in a single packet on + 32-bit systems. + The alternative is to truncate the range in order to force a carry, but + requires similar carry tracking in the decoder, needlessly slowing it down.*/ +static void ec_enc_carry_out(ec_enc *_this,int _c){ + if(_c!=EC_SYM_MAX){ + /*No further carry propagation possible, flush buffer.*/ + int carry; + carry=_c>>EC_SYM_BITS; + /*Don't output a byte on the first write. + This compare should be taken care of by branch-prediction thereafter.*/ + if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry); + if(_this->ext>0){ + unsigned sym; + sym=(EC_SYM_MAX+carry)&EC_SYM_MAX; + do _this->error|=ec_write_byte(_this,sym); + while(--(_this->ext)>0); + } + _this->rem=_c&EC_SYM_MAX; + } + else _this->ext++; +} + +static void ec_enc_normalize(ec_enc *_this){ + /*If the range is too small, output some bits and rescale it.*/ + while(_this->rng<=EC_CODE_BOT){ + ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT)); + /*Move the next-to-high-order symbol into the high-order position.*/ + _this->val=(_this->val<rng<<=EC_SYM_BITS; + _this->nbits_total+=EC_SYM_BITS; + } +} + +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){ + _this->buf=_buf; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits.*/ + _this->nbits_total=EC_CODE_BITS+1; + _this->offs=0; + _this->rng=EC_CODE_TOP; + _this->rem=-1; + _this->val=0; + _this->ext=0; + _this->storage=_size; + _this->error=0; +} + +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 r; + r=_this->rng/_ft; + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,(_ft-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,(_ft-_fh)); + ec_enc_normalize(_this); +} + +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){ + opus_uint32 r; + r=_this->rng>>_bits; + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,((1U<<_bits)-_fh)); + ec_enc_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){ + opus_uint32 r; + opus_uint32 s; + opus_uint32 l; + r=_this->rng; + l=_this->val; + s=r>>_logp; + r-=s; + if(_val)_this->val=l+r; + _this->rng=_val?s:r; + ec_enc_normalize(_this); +} + +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + r=_this->rng>>_ftb; + if(_s>0){ + _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]); + _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]); + } + else _this->rng-=IMUL32(r,_icdf[_s]); + ec_enc_normalize(_this); +} + +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){ + unsigned ft; + unsigned fl; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + ftb-=EC_UINT_BITS; + ft=(_ft>>ftb)+1; + fl=(unsigned)(_fl>>ftb); + ec_encode(_this,fl,fl+1,ft); + ec_enc_bits(_this,_fl&(((opus_uint32)1<end_window; + used=_this->nend_bits; + celt_assert(_bits>0); + if(used+_bits>EC_WINDOW_SIZE){ + do{ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + while(used>=EC_SYM_BITS); + } + window|=(ec_window)_fl<end_window=window; + _this->nend_bits=used; + _this->nbits_total+=_bits; +} + +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){ + int shift; + unsigned mask; + celt_assert(_nbits<=EC_SYM_BITS); + shift=EC_SYM_BITS-_nbits; + mask=((1<<_nbits)-1)<offs>0){ + /*The first byte has been finalized.*/ + _this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<rem>=0){ + /*The first byte is still awaiting carry propagation.*/ + _this->rem=(_this->rem&~mask)|_val<rng<=(EC_CODE_TOP>>_nbits)){ + /*The renormalization loop has never been run.*/ + _this->val=(_this->val&~((opus_uint32)mask<error=-1; +} + +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){ + celt_assert(_this->offs+_this->end_offs<=_size); + OPUS_MOVE(_this->buf+_size-_this->end_offs, + _this->buf+_this->storage-_this->end_offs,_this->end_offs); + _this->storage=_size; +} + +void ec_enc_done(ec_enc *_this){ + ec_window window; + int used; + opus_uint32 msk; + opus_uint32 end; + int l; + /*We output the minimum number of bits that ensures that the symbols encoded + thus far will be decoded correctly regardless of the bits that follow.*/ + l=EC_CODE_BITS-EC_ILOG(_this->rng); + msk=(EC_CODE_TOP-1)>>l; + end=(_this->val+msk)&~msk; + if((end|msk)>=_this->val+_this->rng){ + l++; + msk>>=1; + end=(_this->val+msk)&~msk; + } + while(l>0){ + ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT)); + end=(end<rem>=0||_this->ext>0)ec_enc_carry_out(_this,0); + /*If we have buffered extra bits, flush them as well.*/ + window=_this->end_window; + used=_this->nend_bits; + while(used>=EC_SYM_BITS){ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + /*Clear any excess space and add any remaining extra bits to the last byte.*/ + if(!_this->error){ + OPUS_CLEAR(_this->buf+_this->offs, + _this->storage-_this->offs-_this->end_offs); + if(used>0){ + /*If there's no range coder data at all, give up.*/ + if(_this->end_offs>=_this->storage)_this->error=-1; + else{ + l=-l; + /*If we've busted, don't add too many extra bits to the last byte; it + would corrupt the range coder data, and that's more important.*/ + if(_this->offs+_this->end_offs>=_this->storage&&lerror=-1; + } + _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window; + } + } + } +} diff --git a/media/libopus/celt/entenc.h b/media/libopus/celt/entenc.h new file mode 100644 index 000000000000..d65d734ce528 --- /dev/null +++ b/media/libopus/celt/entenc.h @@ -0,0 +1,110 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_entenc_H) +# define _entenc_H (1) +# include +# include "entcode.h" + +/*Initializes the encoder. + _buf: The buffer to store output bytes in. + _size: The size of the buffer, in chars.*/ +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size); +/*Encodes a symbol given its frequency information. + The frequency information must be discernable by the decoder, assuming it + has read only the previous symbols from the stream. + It is allowable to change the frequency information, or even the entire + source alphabet, so long as the decoder can tell from the context of the + previously encoded information that it is supposed to do so as well. + _fl: The cumulative frequency of all symbols that come before the one to be + encoded. + _fh: The cumulative frequency of all symbols up to and including the one to + be encoded. + Together with _fl, this defines the range [_fl,_fh) in which the + decoded value will fall. + _ft: The sum of the frequencies of all the symbols*/ +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/*Equivalent to ec_encode() with _ft==1<<_bits.*/ +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits); + +/* Encode a bit that has a 1/(1<<_logp) probability of being a one */ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp); + +/*Encodes a symbol given an "inverse" CDF table. + _s: The index of the symbol to encode. + _icdf: The "inverse" CDF, such that symbol _s falls in the range + [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution.*/ +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb); + +/*Encodes a raw unsigned integer in the stream. + _fl: The integer to encode. + _ft: The number of integers that can be encoded (one more than the max). + This must be at least one, and no more than 2**32-1.*/ +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft); + +/*Encodes a sequence of raw bits in the stream. + _fl: The bits to encode. + _ftb: The number of bits to encode. + This must be between 1 and 25, inclusive.*/ +void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb); + +/*Overwrites a few bits at the very start of an existing stream, after they + have already been encoded. + This makes it possible to have a few flags up front, where it is easy for + decoders to access them without parsing the whole stream, even if their + values are not determined until late in the encoding process, without having + to buffer all the intermediate symbols in the encoder. + In order for this to work, at least _nbits bits must have already been + encoded using probabilities that are an exact power of two. + The encoder can verify the number of encoded bits is sufficient, but cannot + check this latter condition. + _val: The bits to encode (in the least _nbits significant bits). + They will be decoded in order from most-significant to least. + _nbits: The number of bits to overwrite. + This must be no more than 8.*/ +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits); + +/*Compacts the data to fit in the target size. + This moves up the raw bits at the end of the current buffer so they are at + the end of the new buffer size. + The caller must ensure that the amount of data that's already been written + will fit in the new size. + _size: The number of bytes in the new buffer. + This must be large enough to contain the bits already written, and + must be no larger than the existing size.*/ +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size); + +/*Indicates that there are no more symbols to encode. + All reamining output bytes are flushed to the output buffer. + ec_enc_init() must be called before the encoder can be used again.*/ +void ec_enc_done(ec_enc *_this); + +#endif diff --git a/media/libopus/celt/fixed_debug.h b/media/libopus/celt/fixed_debug.h new file mode 100644 index 000000000000..bce02961b20f --- /dev/null +++ b/media/libopus/celt/fixed_debug.h @@ -0,0 +1,511 @@ +/* Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2009 Xiph.Org Foundation */ +/** + @file fixed_debug.h + @brief Fixed-point operations with debugging +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_DEBUG_H +#define FIXED_DEBUG_H + +#include + +#ifdef CELT_C +long long celt_mips=0; +#else +extern long long celt_mips; +#endif + +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16)) + +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768) +#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL) +#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1)) + +#define SHR(a,b) SHR32(a,b) +#define PSHR(a,b) PSHR32(a,b) + +static inline short NEG16(int x) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "NEG16: input is not short: %d\n", (int)x); + } + res = -x; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "NEG16: output is not short: %d\n", (int)res); + celt_mips++; + return res; +} +static inline int NEG32(long long x) +{ + long long res; + if (!VERIFY_INT(x)) + { + fprintf (stderr, "NEG16: input is not int: %d\n", (int)x); + } + res = -x; + if (!VERIFY_INT(res)) + fprintf (stderr, "NEG16: output is not int: %d\n", (int)res); + celt_mips+=2; + return res; +} + +#define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__) +static inline short EXTRACT16_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); + } + res = x; + celt_mips++; + return res; +} + +#define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__) +static inline int EXTEND32_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); + } + res = x; + celt_mips++; + return res; +} + +#define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__) +static inline short SHR16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); + } + res = a>>shift; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); + celt_mips++; + return res; +} +#define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__) +static inline short SHL16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); + } + res = a<>shift; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); + } + celt_mips+=2; + return res; +} +static inline int SHL32(long long a, int shift) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift); + } + res = a<>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a)))) +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +//#define SHR(a,shift) ((a) >> (shift)) +//#define SHL(a,shift) ((a) << (shift)) + +#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__) +static inline short ADD16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = a+b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); + } + celt_mips++; + return res; +} + +#define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__) +static inline short SUB16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = a-b; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); + celt_mips++; + return res; +} + +#define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__) +static inline int ADD32_(long long a, long long b, char *file, int line) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a+b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); + } + celt_mips+=2; + return res; +} + +#define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__) +static inline int SUB32_(long long a, long long b, char *file, int line) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a-b; + if (!VERIFY_INT(res)) + fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line); + celt_mips+=2; + return res; +} + +#undef UADD32 +#define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__) +static inline unsigned int UADD32_(unsigned long long a, unsigned long long b, char *file, int line) +{ + long long res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "UADD32: inputs are not int: %u %u in %s: line %d\n", (unsigned)a, (unsigned)b, file, line); + } + res = a+b; + if (!VERIFY_UINT(res)) + { + fprintf (stderr, "UADD32: output is not int: %u in %s: line %d\n", (unsigned)res, file, line); + } + celt_mips+=2; + return res; +} + +#undef USUB32 +#define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__) +static inline unsigned int USUB32_(unsigned long long a, unsigned long long b, char *file, int line) +{ + long long res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + /*fprintf (stderr, "USUB32: inputs are not int: %llu %llu in %s: line %d\n", (unsigned)a, (unsigned)b, file, line);*/ + } + res = a-b; + if (!VERIFY_UINT(res)) + { + /*fprintf (stderr, "USUB32: output is not int: %llu - %llu = %llu in %s: line %d\n", a, b, res, file, line);*/ + } + celt_mips+=2; + return res; +} + +/* result fits in 16 bits */ +static inline short MULT16_16_16(int a, int b) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b); + } + res = a*b; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res); + celt_mips++; + return res; +} + +#define MULT16_16(a, b) MULT16_16_(a, b, __FILE__, __LINE__) +static inline int MULT16_16_(int a, int b, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = ((long long)a)*b; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line); + celt_mips++; + return res; +} + +#define MAC16_16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_16((a),(b)))) + +#define MULT16_32_QX(a, b, Q) MULT16_32_QX_(a, b, Q, __FILE__, __LINE__) +static inline int MULT16_32_QX_(int a, long long b, int Q, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + } + if (ABS32(b)>=((opus_val32)(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + res = (((long long)a)*(long long)b) >> Q; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); + if (Q==15) + celt_mips+=3; + else + celt_mips+=4; + return res; +} + +#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b)))) + +static inline int SATURATE(int a, int b) +{ + if (a>b) + a=b; + if (a<-b) + a = -b; + celt_mips+=3; + return a; +} + +static inline int MULT16_16_Q11_32(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 11; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res); + celt_mips+=3; + return res; +} +static inline short MULT16_16_Q13(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 13; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res); + celt_mips+=3; + return res; +} +static inline short MULT16_16_Q14(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 14; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res); + celt_mips+=3; + return res; +} + +#define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__) +static inline short MULT16_16_Q15_(int a, int b, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = ((long long)a)*b; + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line); + } + celt_mips+=1; + return res; +} + +static inline short MULT16_16_P13(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 4096; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 13; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res); + celt_mips+=4; + return res; +} +static inline short MULT16_16_P14(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 8192; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 14; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res); + celt_mips+=4; + return res; +} +static inline short MULT16_16_P15(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 16384; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 15; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res); + celt_mips+=2; + return res; +} + +#define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__) + +static inline int DIV32_16_(long long a, long long b, char *file, int line) +{ + long long res; + if (b==0) + { + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); + return 0; + } + if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a/b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); + if (res>32767) + res = 32767; + if (res<-32768) + res = -32768; + } + celt_mips+=35; + return res; +} + +#define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__) +static inline int DIV32_(long long a, long long b, char *file, int line) +{ + long long res; + if (b==0) + { + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); + return 0; + } + + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a/b; + if (!VERIFY_INT(res)) + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); + celt_mips+=70; + return res; +} + +#undef PRINT_MIPS +#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0); + +#endif diff --git a/media/libopus/celt/fixed_generic.h b/media/libopus/celt/fixed_generic.h new file mode 100644 index 000000000000..7561b6fed07c --- /dev/null +++ b/media/libopus/celt/fixed_generic.h @@ -0,0 +1,126 @@ +/* Copyright (C) 2007-2009 Xiph.Org Foundation + Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2008 CSIRO */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_GENERIC_H +#define FIXED_GENERIC_H + +/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */ +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15)) + +/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15)) + +/** Compile-time conversion of float constant to 16-bit value */ +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Compile-time conversion of float constant to 32-bit value */ +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Negate a 16-bit value */ +#define NEG16(x) (-(x)) +/** Negate a 32-bit value */ +#define NEG32(x) (-(x)) + +/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */ +#define EXTRACT16(x) ((opus_val16)(x)) +/** Change a 16-bit value into a 32-bit value */ +#define EXTEND32(x) ((opus_val32)(x)) + +/** Arithmetic shift-right of a 16-bit value */ +#define SHR16(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 16-bit value */ +#define SHL16(a,shift) ((opus_int16)((opus_uint16)(a)<<(shift))) +/** Arithmetic shift-right of a 32-bit value */ +#define SHR32(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 32-bit value */ +#define SHL32(a,shift) ((opus_int32)((opus_uint32)(a)<<(shift))) + +/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */ +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +/** 32-bit arithmetic shift right where the argument can be negative */ +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +/** "RAW" macros, should not be used outside of this header file */ +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) SHL32(a,shift) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */ +#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a)))) +/** Divide by two */ +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +/** Add two 16-bit values */ +#define ADD16(a,b) ((opus_val16)((opus_val16)(a)+(opus_val16)(b))) +/** Subtract two 16-bit values */ +#define SUB16(a,b) ((opus_val16)(a)-(opus_val16)(b)) +/** Add two 32-bit values */ +#define ADD32(a,b) ((opus_val32)(a)+(opus_val32)(b)) +/** Subtract two 32-bit values */ +#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b)) + +/** 16x16 multiplication where the result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b)))) + +/* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */ +/** 16x16 multiplication where the result fits in 32 bits */ +#define MULT16_16(a,b) (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b))) + +/** 16x16 multiply-add where the result fits in 32 bits */ +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +/** 16x32 multiply-add, followed by a 15-bit shift right. Results fits in 32 bits */ +#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */ +#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b)))) + +/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */ +#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b))) + +#endif diff --git a/media/libopus/celt/float_cast.h b/media/libopus/celt/float_cast.h new file mode 100644 index 000000000000..079307a066a7 --- /dev/null +++ b/media/libopus/celt/float_cast.h @@ -0,0 +1,138 @@ +/* Copyright (C) 2001 Erik de Castro Lopo */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Version 1.1 */ + +#ifndef FLOAT_CAST_H +#define FLOAT_CAST_H + + +#include "arch.h" + +/*============================================================================ +** On Intel Pentium processors (especially PIII and probably P4), converting +** from float to int is very slow. To meet the C specs, the code produced by +** most C compilers targeting Pentium needs to change the FPU rounding mode +** before the float to int conversion is performed. +** +** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It +** is this flushing of the pipeline which is so slow. +** +** Fortunately the ISO C99 specifications define the functions lrint, lrintf, +** llrint and llrintf which fix this problem as a side effect. +** +** On Unix-like systems, the configure process should have detected the +** presence of these functions. If they weren't found we have to replace them +** here with a standard C cast. +*/ + +/* +** The C99 prototypes for lrint and lrintf are as follows: +** +** long int lrintf (float x) ; +** long int lrint (double x) ; +*/ + +/* The presence of the required functions are detected during the configure +** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in +** the config.h file. +*/ + +#if (HAVE_LRINTF) + +/* These defines enable functionality introduced with the 1999 ISO C +** standard. They must be defined before the inclusion of math.h to +** engage them. If optimisation is enabled, these functions will be +** inlined. With optimisation switched off, you have to link in the +** maths library using -lm. +*/ + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrintf(x) + +#elif (defined(HAVE_LRINT)) + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrint(x) + +#elif (defined (WIN64) || defined (_WIN64)) + #include + + __inline long int float2int(float value) + { + return _mm_cvtss_si32(_mm_load_ss(&value)); + } +#elif (defined (WIN32) || defined (_WIN32)) + #include + + /* Win32 doesn't seem to have these functions. + ** Therefore implement inline versions of these functions here. + */ + + __inline long int + float2int (float flt) + { int intgr; + + _asm + { fld flt + fistp intgr + } ; + + return intgr ; + } + +#else + +#if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) + /* supported by gcc in C99 mode, but not by all other compilers */ + #warning "Don't have the functions lrint() and lrintf ()." + #warning "Replacing these functions with a standard C cast." +#endif /* __STDC_VERSION__ >= 199901L */ + #include + #define float2int(flt) ((int)(floor(.5+flt))) +#endif + +static inline opus_int16 FLOAT2INT16(float x) +{ + x = x*CELT_SIG_SCALE; + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return (opus_int16)float2int(x); +} + +#endif /* FLOAT_CAST_H */ diff --git a/media/libopus/celt/kiss_fft.c b/media/libopus/celt/kiss_fft.c new file mode 100644 index 000000000000..f6b909444135 --- /dev/null +++ b/media/libopus/celt/kiss_fft.c @@ -0,0 +1,722 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + Lots of modifications by Jean-Marc Valin + Copyright (c) 2005-2007, Xiph.Org Foundation + Copyright (c) 2008, Xiph.Org Foundation, CSIRO + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.*/ + +/* This code is originally from Mark Borgerding's KISS-FFT but has been + heavily modified to better suit Opus */ + +#ifndef SKIP_CONFIG_H +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +#endif + +#include "_kiss_fft_guts.h" +#include "arch.h" +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" +#include "os_support.h" + +/* The guts header contains all the multiplication and addition macros that are defined for + complex numbers. It also delares the kf_ internal functions. +*/ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx * Fout2; + const kiss_twiddle_cpx * tw1; + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jr = SHR(Fout->r, 1);Fout->i = SHR(Fout->i, 1); + Fout2->r = SHR(Fout2->r, 1);Fout2->i = SHR(Fout2->i, 1); + C_MUL (t, *Fout2 , *tw1); + tw1 += fstride; + C_SUB( *Fout2 , *Fout , t ); + C_ADDTO( *Fout , t ); + ++Fout2; + ++Fout; + } + } +} + +static void ki_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx * Fout2; + const kiss_twiddle_cpx * tw1; + kiss_fft_cpx t; + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jtwiddles; + for (j=0;jr = PSHR(Fout->r, 2); + Fout->i = PSHR(Fout->i, 2); + C_SUB( scratch[5] , *Fout, scratch[1] ); + C_ADDTO(*Fout, scratch[1]); + C_ADD( scratch[3] , scratch[0] , scratch[2] ); + C_SUB( scratch[4] , scratch[0] , scratch[2] ); + Fout[m2].r = PSHR(Fout[m2].r, 2); + Fout[m2].i = PSHR(Fout[m2].i, 2); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; + ++Fout; + } + } +} + +static void ki_bfly4( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + const kiss_twiddle_cpx *tw1,*tw2,*tw3; + kiss_fft_cpx scratch[6]; + const size_t m2=2*m; + const size_t m3=3*m; + int i, j; + + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for (j=0;jtwiddles[fstride*m]; + for (i=0;itwiddles; + k=m; + do { + C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + } while(--k); + } +} + +static void ki_bfly3( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + int i, k; + const size_t m2 = 2*m; + const kiss_twiddle_cpx *tw1,*tw2; + kiss_fft_cpx scratch[5]; + kiss_twiddle_cpx epi3; + + kiss_fft_cpx * Fout_beg = Fout; + epi3 = st->twiddles[fstride*m]; + for (i=0;itwiddles; + k=m; + do{ + + C_MULC(scratch[1],Fout[m] , *tw1); + C_MULC(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , -epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + }while(--k); + } +} + +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx * twiddles = st->twiddles; + const kiss_twiddle_cpx *tw; + kiss_twiddle_cpx ya,yb; + kiss_fft_cpx * Fout_beg = Fout; + + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + tw=st->twiddles; + + for (i=0;ir += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); + scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); + scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} + +static void ki_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx * twiddles = st->twiddles; + const kiss_twiddle_cpx *tw; + kiss_twiddle_cpx ya,yb; + kiss_fft_cpx * Fout_beg = Fout; + + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + tw=st->twiddles; + + for (i=0;ir += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = -S_MUL(scratch[10].i,ya.i) - S_MUL(scratch[9].i,yb.i); + scratch[6].i = S_MUL(scratch[10].r,ya.i) + S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = S_MUL(scratch[10].i,yb.i) - S_MUL(scratch[9].i,ya.i); + scratch[12].i = -S_MUL(scratch[10].r,yb.i) + S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} + +#endif + + +#ifdef CUSTOM_MODES + +static +void compute_bitrev_table( + int Fout, + opus_int16 *f, + const size_t fstride, + int in_stride, + opus_int16 * factors, + const kiss_fft_state *st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j32000 || (opus_int32)p*(opus_int32)p > n) + p = n; /* no more factors, skip to end */ + } + n /= p; +#ifdef RADIX_TWO_ONLY + if (p!=2 && p != 4) +#else + if (p>5) +#endif + { + return 0; + } + *facbuf++ = p; + *facbuf++ = n; + } while (n > 1); + return 1; +} + +static void compute_twiddles(kiss_twiddle_cpx *twiddles, int nfft) +{ + int i; +#ifdef FIXED_POINT + for (i=0;i= memneeded) + st = (kiss_fft_state*)mem; + *lenmem = memneeded; + } + if (st) { + opus_int16 *bitrev; + kiss_twiddle_cpx *twiddles; + + st->nfft=nfft; +#ifndef FIXED_POINT + st->scale = 1./nfft; +#endif + if (base != NULL) + { + st->twiddles = base->twiddles; + st->shift = 0; + while (nfft<shift != base->nfft && st->shift < 32) + st->shift++; + if (st->shift>=32) + goto fail; + } else { + st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft); + compute_twiddles(twiddles, nfft); + st->shift = -1; + } + if (!kf_factor(nfft,st->factors)) + { + goto fail; + } + + /* bitrev */ + st->bitrev = bitrev = (opus_int16*)KISS_FFT_MALLOC(sizeof(opus_int16)*nfft); + if (st->bitrev==NULL) + goto fail; + compute_bitrev_table(0, bitrev, 1,1, st->factors,st); + } + return st; +fail: + opus_fft_free(st); + return NULL; +} + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem ) +{ + return opus_fft_alloc_twiddles(nfft, mem, lenmem, NULL); +} + +void opus_fft_free(const kiss_fft_state *cfg) +{ + if (cfg) + { + opus_free((opus_int16*)cfg->bitrev); + if (cfg->shift < 0) + opus_free((kiss_twiddle_cpx*)cfg->twiddles); + opus_free((kiss_fft_state*)cfg); + } +} + +#endif /* CUSTOM_MODES */ + +void opus_fft(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + int m2, m; + int p; + int L; + int fstride[MAXFACTORS]; + int i; + int shift; + + /* st->shift can be -1 */ + shift = st->shift>0 ? st->shift : 0; + + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + { + fout[st->bitrev[i]] = fin[i]; +#ifndef FIXED_POINT + fout[st->bitrev[i]].r *= st->scale; + fout[st->bitrev[i]].i *= st->scale; +#endif + } + + fstride[0] = 1; + L=0; + do { + p = st->factors[2*L]; + m = st->factors[2*L+1]; + fstride[L+1] = fstride[L]*p; + L++; + } while(m!=1); + m = st->factors[2*L-1]; + for (i=L-1;i>=0;i--) + { + if (i!=0) + m2 = st->factors[2*i-1]; + else + m2 = 1; + switch (st->factors[2*i]) + { + case 2: + kf_bfly2(fout,fstride[i]<shift can be -1 */ + shift = st->shift>0 ? st->shift : 0; + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + fout[st->bitrev[i]] = fin[i]; + + fstride[0] = 1; + L=0; + do { + p = st->factors[2*L]; + m = st->factors[2*L+1]; + fstride[L+1] = fstride[L]*p; + L++; + } while(m!=1); + m = st->factors[2*L-1]; + for (i=L-1;i>=0;i--) + { + if (i!=0) + m2 = st->factors[2*i-1]; + else + m2 = 1; + switch (st->factors[2*i]) + { + case 2: + ki_bfly2(fout,fstride[i]< +#include +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ATTENTION! + If you would like a : + -- a utility that will handle the caching of fft objects + -- real-only (no imaginary time component ) FFT + -- a multi-dimensional FFT + -- a command-line utility to perform ffts + -- a command-line utility to perform fast-convolution filtering + + Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c + in the tools/ directory. +*/ + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) +#else +#define KISS_FFT_MALLOC opus_alloc +#endif + +#ifdef FIXED_POINT +#include "arch.h" + +# define kiss_fft_scalar opus_int32 +# define kiss_twiddle_scalar opus_int16 + + +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# define kiss_twiddle_scalar float +# define KF_SUFFIX _celt_single +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct { + kiss_twiddle_scalar r; + kiss_twiddle_scalar i; +}kiss_twiddle_cpx; + +#define MAXFACTORS 8 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +typedef struct kiss_fft_state{ + int nfft; +#ifndef FIXED_POINT + kiss_fft_scalar scale; +#endif + int shift; + opus_int16 factors[2*MAXFACTORS]; + const opus_int16 *bitrev; + const kiss_twiddle_cpx *twiddles; +} kiss_fft_state; + +/*typedef struct kiss_fft_state* kiss_fft_cfg;*/ + +/** + * opus_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base); + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem); + +/** + * opus_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void opus_fft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); +void opus_ifft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +void opus_fft_free(const kiss_fft_state *cfg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/media/libopus/celt/laplace.c b/media/libopus/celt/laplace.c new file mode 100644 index 000000000000..536731305c25 --- /dev/null +++ b/media/libopus/celt/laplace.c @@ -0,0 +1,133 @@ +/* Copyright (c) 2007 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "laplace.h" +#include "mathops.h" + +/* The minimum probability of an energy delta (out of 32768). */ +#define LAPLACE_LOG_MINP (0) +#define LAPLACE_MINP (1<>15; +} + +void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay) +{ + unsigned fl; + int val = *value; + fl = 0; + if (val) + { + int s; + int i; + s = -(val<0); + val = (val+s)^s; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay); + /* Search the decaying part of the PDF.*/ + for (i=1; fs > 0 && i < val; i++) + { + fs *= 2; + fl += fs+2*LAPLACE_MINP; + fs = (fs*(opus_int32)decay)>>15; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (!fs) + { + int di; + int ndi_max; + ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP; + ndi_max = (ndi_max-s)>>1; + di = IMIN(val - i, ndi_max - 1); + fl += (2*di+1+s)*LAPLACE_MINP; + fs = IMIN(LAPLACE_MINP, 32768-fl); + *value = (i+di+s)^s; + } + else + { + fs += LAPLACE_MINP; + fl += fs&~s; + } + celt_assert(fl+fs<=32768); + celt_assert(fs>0); + } + ec_encode_bin(enc, fl, fl+fs, 15); +} + +int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay) +{ + int val=0; + unsigned fl; + unsigned fm; + fm = ec_decode_bin(dec, 15); + fl = 0; + if (fm >= fs) + { + val++; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP; + /* Search the decaying part of the PDF.*/ + while(fs > LAPLACE_MINP && fm >= fl+2*fs) + { + fs *= 2; + fl += fs; + fs = ((fs-2*LAPLACE_MINP)*(opus_int32)decay)>>15; + fs += LAPLACE_MINP; + val++; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (fs <= LAPLACE_MINP) + { + int di; + di = (fm-fl)>>(LAPLACE_LOG_MINP+1); + val += di; + fl += 2*di*LAPLACE_MINP; + } + if (fm < fl+fs) + val = -val; + else + fl += fs; + } + celt_assert(fl<32768); + celt_assert(fs>0); + celt_assert(fl<=fm); + celt_assert(fm>1; + b=1U<>=1; + bshift--; + } + while(bshift>=0); + return g; +} + +#ifdef FIXED_POINT + +opus_val32 frac_div32(opus_val32 a, opus_val32 b) +{ + opus_val16 rcp; + opus_val32 result, rem; + int shift = celt_ilog2(b)-29; + a = VSHR32(a,shift); + b = VSHR32(b,shift); + /* 16-bit reciprocal */ + rcp = ROUND16(celt_rcp(ROUND16(b,16)),3); + result = SHL32(MULT16_32_Q15(rcp, a),2); + rem = a-MULT32_32_Q31(result, b); + result += SHL32(MULT16_32_Q15(rcp, rem),2); + return result; +} + +/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */ +opus_val16 celt_rsqrt_norm(opus_val32 x) +{ + opus_val16 n; + opus_val16 r; + opus_val16 r2; + opus_val16 y; + /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */ + n = x-32768; + /* Get a rough initial guess for the root. + The optimal minimax quadratic approximation (using relative error) is + r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485). + Coefficients here, and the final result r, are Q14.*/ + r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713)))); + /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14. + We can compute the result from n and r using Q15 multiplies with some + adjustment, carefully done to avoid overflow. + Range of y is [-1564,1594]. */ + r2 = MULT16_16_Q15(r, r); + y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1); + /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5). + This yields the Q14 reciprocal square root of the Q16 x, with a maximum + relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a + peak absolute error of 2.26591/16384. */ + return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y, + SUB16(MULT16_16_Q15(y, 12288), 16384)))); +} + +/** Sqrt approximation (QX input, QX/2 output) */ +opus_val32 celt_sqrt(opus_val32 x) +{ + int k; + opus_val16 n; + opus_val32 rt; + static const opus_val16 C[5] = {23175, 11561, -3011, 1699, -664}; + if (x==0) + return 0; + k = (celt_ilog2(x)>>1)-7; + x = VSHR32(x, 2*k); + n = x-32768; + rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], + MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4]))))))))); + rt = VSHR32(rt,7-k); + return rt; +} + +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static inline opus_val16 _celt_cos_pi_2(opus_val16 x) +{ + opus_val16 x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2 + )))))))); +} + +#undef L1 +#undef L2 +#undef L3 +#undef L4 + +opus_val16 celt_cos_norm(opus_val32 x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x0, "celt_rcp() only defined for positive values"); + i = celt_ilog2(x); + /* n is Q15 with range [0,1). */ + n = VSHR32(x,i-15)-32768; + /* Start with a linear approximation: + r = 1.8823529411764706-0.9411764705882353*n. + The coefficients and the result are Q14 in the range [15420,30840].*/ + r = ADD16(30840, MULT16_16_Q15(-15420, n)); + /* Perform two Newton iterations: + r -= r*((r*n)-1.Q15) + = r*((r*n)+(r-1.Q15)). */ + r = SUB16(r, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))); + /* We subtract an extra 1 in the second iteration to avoid overflow; it also + neatly compensates for truncation error in the rest of the process. */ + r = SUB16(r, ADD16(1, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))))); + /* r is now the Q15 solution to 2/(n+1), with a maximum relative error + of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute + error of 1.24665/32768. */ + return VSHR32(EXTEND32(r),i-16); +} + +#endif diff --git a/media/libopus/celt/mathops.h b/media/libopus/celt/mathops.h new file mode 100644 index 000000000000..4944391b5d13 --- /dev/null +++ b/media/libopus/celt/mathops.h @@ -0,0 +1,226 @@ +/* Copyright (c) 2002-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file mathops.h + @brief Various math functions +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef MATHOPS_H +#define MATHOPS_H + +#include "arch.h" +#include "entcode.h" +#include "os_support.h" + +/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */ +#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15) + +unsigned isqrt32(opus_uint32 _val); + +#ifndef FIXED_POINT + +#define PI 3.141592653f +#define celt_sqrt(x) ((float)sqrt(x)) +#define celt_rsqrt(x) (1.f/celt_sqrt(x)) +#define celt_rsqrt_norm(x) (celt_rsqrt(x)) +#define celt_cos_norm(x) ((float)cos((.5f*PI)*(x))) +#define celt_rcp(x) (1.f/(x)) +#define celt_div(a,b) ((a)/(b)) +#define frac_div32(a,b) ((float)(a)/(b)) + +#ifdef FLOAT_APPROX + +/* Note: This assumes radix-2 floating point with the exponent at bits 23..30 and an offset of 127 + denorm, +/- inf and NaN are *not* handled */ + +/** Base-2 log approximation (log2(x)). */ +static inline float celt_log2(float x) +{ + int integer; + float frac; + union { + float f; + opus_uint32 i; + } in; + in.f = x; + integer = (in.i>>23)-127; + in.i -= integer<<23; + frac = in.f - 1.5f; + frac = -0.41445418f + frac*(0.95909232f + + frac*(-0.33951290f + frac*0.16541097f)); + return 1+integer+frac; +} + +/** Base-2 exponential approximation (2^x). */ +static inline float celt_exp2(float x) +{ + int integer; + float frac; + union { + float f; + opus_uint32 i; + } res; + integer = floor(x); + if (integer < -50) + return 0; + frac = x-integer; + /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */ + res.f = 0.99992522f + frac * (0.69583354f + + frac * (0.22606716f + 0.078024523f*frac)); + res.i = (res.i + (integer<<23)) & 0x7fffffff; + return res.f; +} + +#else +#define celt_log2(x) ((float)(1.442695040888963387*log(x))) +#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x))) +#endif + +#endif + +#ifdef FIXED_POINT + +#include "os_support.h" + +#ifndef OVERRIDE_CELT_ILOG2 +/** Integer log in base2. Undefined for zero and negative numbers */ +static inline opus_int16 celt_ilog2(opus_int32 x) +{ + celt_assert2(x>0, "celt_ilog2() only defined for strictly positive numbers"); + return EC_ILOG(x)-1; +} +#endif + +#ifndef OVERRIDE_CELT_MAXABS16 +static inline opus_val16 celt_maxabs16(opus_val16 *x, int len) +{ + int i; + opus_val16 maxval = 0; + for (i=0;i14) + return 0x7f000000; + else if (integer < -15) + return 0; + frac = SHL16(x-SHL16(integer,10),4); + frac = ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac)))))); + return VSHR32(EXTEND32(frac), -integer-2); +} + +opus_val32 celt_rcp(opus_val32 x); + +#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b)) + +opus_val32 frac_div32(opus_val32 a, opus_val32 b); + +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +/* Atan approximation using a 4th order polynomial. Input is in Q15 format + and normalized by pi/4. Output is in Q15 format */ +static inline opus_val16 celt_atan01(opus_val16 x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +#undef M1 +#undef M2 +#undef M3 +#undef M4 + +/* atan2() approximation valid for positive input values */ +static inline opus_val16 celt_atan2p(opus_val16 y, opus_val16 x) +{ + if (y < x) + { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(y),15),x); + if (arg >= 32767) + arg = 32767; + return SHR16(celt_atan01(EXTRACT16(arg)),1); + } else { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(x),15),y); + if (arg >= 32767) + arg = 32767; + return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1); + } +} + +#endif /* FIXED_POINT */ +#endif /* MATHOPS_H */ diff --git a/media/libopus/celt/mdct.c b/media/libopus/celt/mdct.c new file mode 100644 index 000000000000..72011305c71b --- /dev/null +++ b/media/libopus/celt/mdct.c @@ -0,0 +1,332 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "mdct.h" +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +#ifdef CUSTOM_MODES + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift) +{ + int i; + int N4; + kiss_twiddle_scalar *trig; +#if defined(FIXED_POINT) + int N2=N>>1; +#endif + l->n = N; + N4 = N>>2; + l->maxshift = maxshift; + for (i=0;i<=maxshift;i++) + { + if (i==0) + l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0); + else + l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0]); +#ifndef ENABLE_TI_DSPLIB55 + if (l->kfft[i]==NULL) + return 0; +#endif + } + l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N4+1)*sizeof(kiss_twiddle_scalar)); + if (l->trig==NULL) + return 0; + /* We have enough points that sine isn't necessary */ +#if defined(FIXED_POINT) + for (i=0;i<=N4;i++) + trig[i] = TRIG_UPSCALE*celt_cos_norm(DIV32(ADD32(SHL32(EXTEND32(i),17),N2),N)); +#else + for (i=0;i<=N4;i++) + trig[i] = (kiss_twiddle_scalar)cos(2*PI*i/N); +#endif + return 1; +} + +void clt_mdct_clear(mdct_lookup *l) +{ + int i; + for (i=0;i<=l->maxshift;i++) + opus_fft_free(l->kfft[i]); + opus_free((kiss_twiddle_scalar*)l->trig); +} + +#endif /* CUSTOM_MODES */ + +/* Forward MDCT trashes the input array */ +void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * restrict out, + const opus_val16 *window, int overlap, int shift, int stride) +{ + int i; + int N, N2, N4; + kiss_twiddle_scalar sine; + VARDECL(kiss_fft_scalar, f); + SAVE_STACK; + N = l->n; + N >>= shift; + N2 = N>>1; + N4 = N>>2; + ALLOC(f, N2, kiss_fft_scalar); + /* sin(x) ~= x here */ +#ifdef FIXED_POINT + sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N; +#else + sine = (kiss_twiddle_scalar)2*PI*(.125f)/N; +#endif + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * restrict xp1 = in+(overlap>>1); + const kiss_fft_scalar * restrict xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * restrict yp = f; + const opus_val16 * restrict wp1 = window+(overlap>>1); + const opus_val16 * restrict wp2 = window+(overlap>>1)-1; + for(i=0;i<(overlap>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2); + *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;itrig[0]; + for(i=0;ikfft[shift], (kiss_fft_cpx *)f, (kiss_fft_cpx *)in); + + /* Post-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * restrict fp = in; + kiss_fft_scalar * restrict yp1 = out; + kiss_fft_scalar * restrict yp2 = out+stride*(N2-1); + const kiss_twiddle_scalar *t = &l->trig[0]; + /* Temp pointers to make it really clear to the compiler what we're doing */ + for(i=0;in; + N >>= shift; + N2 = N>>1; + N4 = N>>2; + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N2, kiss_fft_scalar); + /* sin(x) ~= x here */ +#ifdef FIXED_POINT + sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N; +#else + sine = (kiss_twiddle_scalar)2*PI*(.125f)/N; +#endif + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * restrict xp1 = in; + const kiss_fft_scalar * restrict xp2 = in+stride*(N2-1); + kiss_fft_scalar * restrict yp = f2; + const kiss_twiddle_scalar *t = &l->trig[0]; + for(i=0;ikfft[shift], (kiss_fft_cpx *)f2, (kiss_fft_cpx *)f); + + /* Post-rotate */ + { + kiss_fft_scalar * restrict fp = f; + const kiss_twiddle_scalar *t = &l->trig[0]; + + for(i=0;i>1; + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * restrict fp1 = f2+N4-1; + kiss_fft_scalar * restrict xp1 = out+N2-1; + kiss_fft_scalar * restrict yp1 = out+N4-overlap/2; + const opus_val16 * restrict wp1 = window; + const opus_val16 * restrict wp2 = window+overlap-1; + for(i = 0; i< N4-overlap/2; i++) + { + *xp1 = *fp1; + xp1--; + fp1--; + } + for(; i < N4; i++) + { + kiss_fft_scalar x1; + x1 = *fp1--; + *yp1++ +=-MULT16_32_Q15(*wp1, x1); + *xp1-- += MULT16_32_Q15(*wp2, x1); + wp1++; + wp2--; + } + } + { + kiss_fft_scalar * restrict fp2 = f2+N4; + kiss_fft_scalar * restrict xp2 = out+N2; + kiss_fft_scalar * restrict yp2 = out+N-1-(N4-overlap/2); + const opus_val16 * restrict wp1 = window; + const opus_val16 * restrict wp2 = window+overlap-1; + for(i = 0; i< N4-overlap/2; i++) + { + *xp2 = *fp2; + xp2++; + fp2++; + } + for(; i < N4; i++) + { + kiss_fft_scalar x2; + x2 = *fp2++; + *yp2-- = MULT16_32_Q15(*wp1, x2); + *xp2++ = MULT16_32_Q15(*wp2, x2); + wp1++; + wp2--; + } + } + RESTORE_STACK; +} diff --git a/media/libopus/celt/mdct.h b/media/libopus/celt/mdct.h new file mode 100644 index 000000000000..bba627cc3b87 --- /dev/null +++ b/media/libopus/celt/mdct.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef MDCT_H +#define MDCT_H + +#include "kiss_fft.h" +#include "arch.h" + +typedef struct { + int n; + int maxshift; + const kiss_fft_state *kfft[4]; + const kiss_twiddle_scalar * restrict trig; +} mdct_lookup; + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift); +void clt_mdct_clear(mdct_lookup *l); + +/** Compute a forward MDCT and scale by 4/N, trashes the input array */ +void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar *out, + const opus_val16 *window, int overlap, int shift, int stride); + +/** Compute a backward MDCT (no scaling) and performs weighted overlap-add + (scales implicitly by 1/2) */ +void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar *out, + const opus_val16 * restrict window, int overlap, int shift, int stride); + +#endif diff --git a/media/libopus/celt/mfrngcod.h b/media/libopus/celt/mfrngcod.h new file mode 100644 index 000000000000..6af128a662a7 --- /dev/null +++ b/media/libopus/celt/mfrngcod.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2001-2008 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_mfrngcode_H) +# define _mfrngcode_H (1) +# include "entcode.h" + +/*Constants used by the entropy encoder/decoder.*/ + +/*The number of bits to output at a time.*/ +# define EC_SYM_BITS (8) +/*The total number of bits in each of the state registers.*/ +# define EC_CODE_BITS (32) +/*The maximum symbol value.*/ +# define EC_SYM_MAX ((1U<>EC_SYM_BITS) +/*The number of bits available for the last, partial symbol in the code field.*/ +# define EC_CODE_EXTRA ((EC_CODE_BITS-2)%EC_SYM_BITS+1) +#endif diff --git a/media/libopus/celt/modes.c b/media/libopus/celt/modes.c new file mode 100644 index 000000000000..64b02262b63c --- /dev/null +++ b/media/libopus/celt/modes.c @@ -0,0 +1,430 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt.h" +#include "modes.h" +#include "rate.h" +#include "os_support.h" +#include "stack_alloc.h" +#include "quant_bands.h" + +static const opus_int16 eband5ms[] = { +/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100 +}; + +/* Alternate tuning (partially derived from Vorbis) */ +#define BITALLOC_SIZE 11 +/* Bit allocation table in units of 1/32 bit/sample (0.1875 dB SNR) */ +static const unsigned char band_allocation[] = { +/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, 0, 0, 0, +110,100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0, +118,110,103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15, 4, 0, 0, 0, 0, +126,119,112,104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0, +134,127,120,114,103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10, 1, +144,137,130,124,113,107,101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1, +152,145,138,132,123,117,111,105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1, +162,155,148,142,133,127,121,115,108,102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1, +172,165,158,152,143,137,131,125,118,112,106,100, 94, 87, 81, 75, 69, 63, 56, 45, 20, +200,200,200,200,200,200,200,200,198,193,188,183,178,173,168,163,158,153,148,129,104, +}; + +#ifndef CUSTOM_MODES_ONLY + #ifdef FIXED_POINT + #include "static_modes_fixed.h" + #else + #include "static_modes_float.h" + #endif +#endif /* CUSTOM_MODES_ONLY */ + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +#ifdef CUSTOM_MODES + +/* Defining 25 critical bands for the full 0-20 kHz audio bandwidth + Taken from http://ccrma.stanford.edu/~jos/bbt/Bark_Frequency_Scale.html */ +#define BARK_BANDS 25 +static const opus_int16 bark_freq[BARK_BANDS+1] = { + 0, 100, 200, 300, 400, + 510, 630, 770, 920, 1080, + 1270, 1480, 1720, 2000, 2320, + 2700, 3150, 3700, 4400, 5300, + 6400, 7700, 9500, 12000, 15500, + 20000}; + +static opus_int16 *compute_ebands(opus_int32 Fs, int frame_size, int res, int *nbEBands) +{ + opus_int16 *eBands; + int i, j, lin, low, high, nBark, offset=0; + + /* All modes that have 2.5 ms short blocks use the same definition */ + if (Fs == 400*(opus_int32)frame_size) + { + *nbEBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1; + eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+1)); + for (i=0;i<*nbEBands+1;i++) + eBands[i] = eband5ms[i]; + return eBands; + } + /* Find the number of critical bands supported by our sampling rate */ + for (nBark=1;nBark= Fs) + break; + + /* Find where the linear part ends (i.e. where the spacing is more than min_width */ + for (lin=0;lin= res) + break; + + low = (bark_freq[lin]+res/2)/res; + high = nBark-lin; + *nbEBands = low+high; + eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2)); + + if (eBands==NULL) + return NULL; + + /* Linear spacing (min_width) */ + for (i=0;i0) + offset = eBands[low-1]*res - bark_freq[lin-1]; + /* Spacing follows critical bands */ + for (i=0;i frame_size) + eBands[*nbEBands] = frame_size; + for (i=1;i<*nbEBands-1;i++) + { + if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1]) + { + eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2; + } + } + /* Remove any empty bands. */ + for (i=j=0;i<*nbEBands;i++) + if(eBands[i+1]>eBands[j]) + eBands[++j]=eBands[i+1]; + *nbEBands=j; + + for (i=1;i<*nbEBands;i++) + { + /* Every band must be smaller than the last band. */ + celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]); + /* Each band must be no larger than twice the size of the previous one. */ + celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1])); + } + + return eBands; +} + +static void compute_allocation_table(CELTMode *mode) +{ + int i, j; + unsigned char *allocVectors; + int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1; + + mode->nbAllocVectors = BITALLOC_SIZE; + allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands)); + if (allocVectors==NULL) + return; + + /* Check for standard mode */ + if (mode->Fs == 400*(opus_int32)mode->shortMdctSize) + { + for (i=0;inbEBands;i++) + allocVectors[i] = band_allocation[i]; + mode->allocVectors = allocVectors; + return; + } + /* If not the standard mode, interpolate */ + /* Compute per-codec-band allocation from per-critical-band matrix */ + for (i=0;inbEBands;j++) + { + int k; + for (k=0;k mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize) + break; + } + if (k>maxBands-1) + allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1]; + else { + opus_int32 a0, a1; + a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1]; + a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize; + allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1] + + a1*band_allocation[i*maxBands+k])/(a0+a1); + } + } + } + + /*printf ("\n"); + for (i=0;inbEBands;j++) + printf ("%d ", allocVectors[i*mode->nbEBands+j]); + printf ("\n"); + } + exit(0);*/ + + mode->allocVectors = allocVectors; +} + +#endif /* CUSTOM_MODES */ + +CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error) +{ + int i; +#ifdef CUSTOM_MODES + CELTMode *mode=NULL; + int res; + opus_val16 *window; + opus_int16 *logN; + int LM; + ALLOC_STACK; +#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA) + if (global_stack==NULL) + goto failure; +#endif +#endif + +#ifndef CUSTOM_MODES_ONLY + for (i=0;iFs && + (frame_size<shortMdctSize*static_mode_list[i]->nbShortMdcts) + { + if (error) + *error = OPUS_OK; + return (CELTMode*)static_mode_list[i]; + } + } + } +#endif /* CUSTOM_MODES_ONLY */ + +#ifndef CUSTOM_MODES + if (error) + *error = OPUS_BAD_ARG; + return NULL; +#else + + /* The good thing here is that permutation of the arguments will automatically be invalid */ + + if (Fs < 8000 || Fs > 96000) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + /* Frames of less than 1ms are not supported. */ + if ((opus_int32)frame_size*1000 < Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0) + { + LM = 3; + } else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0) + { + LM = 2; + } else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0) + { + LM = 1; + } else + { + LM = 0; + } + + /* Shorts longer than 3.3ms are not supported. */ + if ((opus_int32)(frame_size>>LM)*300 > Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + mode = opus_alloc(sizeof(CELTMode)); + if (mode==NULL) + goto failure; + mode->Fs = Fs; + + /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis + is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should + approximate that. */ + if(Fs < 12000) /* 8 kHz */ + { + mode->preemph[0] = QCONST16(0.3500061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(3.6765136719f, 13); + } else if(Fs < 24000) /* 16 kHz */ + { + mode->preemph[0] = QCONST16(0.6000061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(2.2598876953f, 13); + } else if(Fs < 40000) /* 32 kHz */ + { + mode->preemph[0] = QCONST16(0.7799987793f, 15); + mode->preemph[1] = -QCONST16(0.1000061035f, 15); + mode->preemph[2] = QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(1.3333740234f, 13); + } else /* 48 kHz */ + { + mode->preemph[0] = QCONST16(0.8500061035f, 15); + mode->preemph[1] = QCONST16(0.0f, 15); + mode->preemph[2] = QCONST16(1.f, SIG_SHIFT); + mode->preemph[3] = QCONST16(1.f, 13); + } + + mode->maxLM = LM; + mode->nbShortMdcts = 1<shortMdctSize = frame_size/mode->nbShortMdcts; + res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize); + + mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands); + if (mode->eBands==NULL) + goto failure; + + mode->effEBands = mode->nbEBands; + while (mode->eBands[mode->effEBands] > mode->shortMdctSize) + mode->effEBands--; + + /* Overlap must be divisible by 4 */ + mode->overlap = ((mode->shortMdctSize>>2)<<2); + + compute_allocation_table(mode); + if (mode->allocVectors==NULL) + goto failure; + + window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16)); + if (window==NULL) + goto failure; + +#ifndef FIXED_POINT + for (i=0;ioverlap;i++) + window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)); +#else + for (i=0;ioverlap;i++) + window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)))); +#endif + mode->window = window; + + logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16)); + if (logN==NULL) + goto failure; + + for (i=0;inbEBands;i++) + logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES); + mode->logN = logN; + + compute_pulse_cache(mode, mode->maxLM); + + if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts, + mode->maxLM) == 0) + goto failure; + + if (error) + *error = OPUS_OK; + + return mode; +failure: + if (error) + *error = OPUS_ALLOC_FAIL; + if (mode!=NULL) + opus_custom_mode_destroy(mode); + return NULL; +#endif /* !CUSTOM_MODES */ +} + +#ifdef CUSTOM_MODES +void opus_custom_mode_destroy(CELTMode *mode) +{ + if (mode == NULL) + return; +#ifndef CUSTOM_MODES_ONLY + { + int i; + for (i=0;ieBands); + opus_free((opus_int16*)mode->allocVectors); + + opus_free((opus_val16*)mode->window); + opus_free((opus_int16*)mode->logN); + + opus_free((opus_int16*)mode->cache.index); + opus_free((unsigned char*)mode->cache.bits); + opus_free((unsigned char*)mode->cache.caps); + clt_mdct_clear(&mode->mdct); + + opus_free((CELTMode *)mode); +} +#endif diff --git a/media/libopus/celt/modes.h b/media/libopus/celt/modes.h new file mode 100644 index 000000000000..8583a3ec6407 --- /dev/null +++ b/media/libopus/celt/modes.h @@ -0,0 +1,83 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef MODES_H +#define MODES_H + +#include "opus_types.h" +#include "celt.h" +#include "arch.h" +#include "mdct.h" +#include "entenc.h" +#include "entdec.h" + +#define MAX_PERIOD 1024 + +#ifndef OVERLAP +#define OVERLAP(mode) ((mode)->overlap) +#endif + +#ifndef FRAMESIZE +#define FRAMESIZE(mode) ((mode)->mdctSize) +#endif + +typedef struct { + int size; + const opus_int16 *index; + const unsigned char *bits; + const unsigned char *caps; +} PulseCache; + +/** Mode definition (opaque) + @brief Mode definition + */ +struct OpusCustomMode { + opus_int32 Fs; + int overlap; + + int nbEBands; + int effEBands; + opus_val16 preemph[4]; + const opus_int16 *eBands; /**< Definition for each "pseudo-critical band" */ + + int maxLM; + int nbShortMdcts; + int shortMdctSize; + + int nbAllocVectors; /**< Number of lines in the matrix below */ + const unsigned char *allocVectors; /**< Number of bits in each band for several rates */ + const opus_int16 *logN; + + const opus_val16 *window; + mdct_lookup mdct; + PulseCache cache; +}; + + +#endif diff --git a/media/libopus/celt/os_support.h b/media/libopus/celt/os_support.h new file mode 100644 index 000000000000..2484f0b2f751 --- /dev/null +++ b/media/libopus/celt/os_support.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OS_SUPPORT_H +#define OS_SUPPORT_H + +#ifdef CUSTOM_SUPPORT +# include "custom_support.h" +#endif + +#include +#include +#include + +/** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */ +#ifndef OVERRIDE_OPUS_ALLOC +static inline void *opus_alloc (size_t size) +{ + return malloc(size); +} +#endif + +/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */ +#ifndef OVERRIDE_OPUS_ALLOC_SCRATCH +static inline void *opus_alloc_scratch (size_t size) +{ + /* Scratch space doesn't need to be cleared */ + return opus_alloc(size); +} +#endif + +/** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */ +#ifndef OVERRIDE_OPUS_FREE +static inline void opus_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_COPY +#define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_MOVE +#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Set n elements of dst to zero, starting at address s */ +#ifndef OVERRIDE_OPUS_CLEAR +#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst)))) +#endif + +/*#ifdef __GNUC__ +#pragma GCC poison printf sprintf +#pragma GCC poison malloc free realloc calloc +#endif*/ + +#endif /* OS_SUPPORT_H */ + diff --git a/media/libopus/celt/pitch.c b/media/libopus/celt/pitch.c new file mode 100644 index 000000000000..b40790261cba --- /dev/null +++ b/media/libopus/celt/pitch.c @@ -0,0 +1,385 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file pitch.c + @brief Pitch analysis + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pitch.h" +#include "os_support.h" +#include "modes.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "celt_lpc.h" + +static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len, + int max_pitch, int *best_pitch +#ifdef FIXED_POINT + , int yshift, opus_val32 maxcorr +#endif + ) +{ + int i, j; + opus_val32 Syy=1; + opus_val16 best_num[2]; + opus_val32 best_den[2]; +#ifdef FIXED_POINT + int xshift; + + xshift = celt_ilog2(maxcorr)-14; +#endif + + best_num[0] = -1; + best_num[1] = -1; + best_den[0] = 0; + best_den[1] = 0; + best_pitch[0] = 0; + best_pitch[1] = 1; + for (j=0;j0) + { + opus_val16 num; + opus_val32 xcorr16; + xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift)); + num = MULT16_16_Q15(xcorr16,xcorr16); + if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy)) + { + if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy)) + { + best_num[1] = best_num[0]; + best_den[1] = best_den[0]; + best_pitch[1] = best_pitch[0]; + best_num[0] = num; + best_den[0] = Syy; + best_pitch[0] = i; + } else { + best_num[1] = num; + best_den[1] = Syy; + best_pitch[1] = i; + } + } + } + Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift); + Syy = MAX32(1, Syy); + } +} + +void pitch_downsample(celt_sig * restrict x[], opus_val16 * restrict x_lp, + int len, int C) +{ + int i; + opus_val32 ac[5]; + opus_val16 tmp=Q15ONE; + opus_val16 lpc[4], mem[4]={0,0,0,0}; + for (i=1;i>1;i++) + x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), SIG_SHIFT+3); + x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), SIG_SHIFT+3); + if (C==2) + { + for (i=1;i>1;i++) + x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), SIG_SHIFT+3); + x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), SIG_SHIFT+3); + } + + _celt_autocorr(x_lp, ac, NULL, 0, + 4, len>>1); + + /* Noise floor -40 dB */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Lag windowing */ + for (i=1;i<=4;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(.008f*i)*(.008f*i); +#endif + } + + _celt_lpc(lpc, ac, 4); + for (i=0;i<4;i++) + { + tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp); + lpc[i] = MULT16_16_Q15(lpc[i], tmp); + } + celt_fir(x_lp, lpc, x_lp, len>>1, 4, mem); + + mem[0]=0; + lpc[0]=QCONST16(.8f,12); + celt_fir(x_lp, lpc, x_lp, len>>1, 1, mem); + +} + +void pitch_search(const opus_val16 * restrict x_lp, opus_val16 * restrict y, + int len, int max_pitch, int *pitch) +{ + int i, j; + int lag; + int best_pitch[2]={0,0}; + VARDECL(opus_val16, x_lp4); + VARDECL(opus_val16, y_lp4); + VARDECL(opus_val32, xcorr); +#ifdef FIXED_POINT + opus_val32 maxcorr=1; + int shift=0; +#endif + int offset; + + SAVE_STACK; + + celt_assert(len>0); + celt_assert(max_pitch>0); + lag = len+max_pitch; + + ALLOC(x_lp4, len>>2, opus_val16); + ALLOC(y_lp4, lag>>2, opus_val16); + ALLOC(xcorr, max_pitch>>1, opus_val32); + + /* Downsample by 2 again */ + for (j=0;j>2;j++) + x_lp4[j] = x_lp[2*j]; + for (j=0;j>2;j++) + y_lp4[j] = y[2*j]; + +#ifdef FIXED_POINT + shift = celt_ilog2(MAX16(1, MAX16(celt_maxabs16(x_lp4, len>>2), celt_maxabs16(y_lp4, lag>>2))))-11; + if (shift>0) + { + for (j=0;j>2;j++) + x_lp4[j] = SHR16(x_lp4[j], shift); + for (j=0;j>2;j++) + y_lp4[j] = SHR16(y_lp4[j], shift); + /* Use double the shift for a MAC */ + shift *= 2; + } else { + shift = 0; + } +#endif + + /* Coarse search with 4x decimation */ + + for (i=0;i>2;i++) + { + opus_val32 sum = 0; + for (j=0;j>2;j++) + sum = MAC16_16(sum, x_lp4[j],y_lp4[i+j]); + xcorr[i] = MAX32(-1, sum); +#ifdef FIXED_POINT + maxcorr = MAX32(maxcorr, sum); +#endif + } + find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch +#ifdef FIXED_POINT + , 0, maxcorr +#endif + ); + + /* Finer search with 2x decimation */ +#ifdef FIXED_POINT + maxcorr=1; +#endif + for (i=0;i>1;i++) + { + opus_val32 sum=0; + xcorr[i] = 0; + if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2) + continue; + for (j=0;j>1;j++) + sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift); + xcorr[i] = MAX32(-1, sum); +#ifdef FIXED_POINT + maxcorr = MAX32(maxcorr, sum); +#endif + } + find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch +#ifdef FIXED_POINT + , shift, maxcorr +#endif + ); + + /* Refine by pseudo-interpolation */ + if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1) + { + opus_val32 a, b, c; + a = xcorr[best_pitch[0]-1]; + b = xcorr[best_pitch[0]]; + c = xcorr[best_pitch[0]+1]; + if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a)) + offset = 1; + else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c)) + offset = -1; + else + offset = 0; + } else { + offset = 0; + } + *pitch = 2*best_pitch[0]-offset; + + RESTORE_STACK; +} + +static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}; +opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod, + int N, int *T0_, int prev_period, opus_val16 prev_gain) +{ + int k, i, T, T0; + opus_val16 g, g0; + opus_val16 pg; + opus_val32 xy,xx,yy; + opus_val32 xcorr[3]; + opus_val32 best_xy, best_yy; + int offset; + int minperiod0; + + minperiod0 = minperiod; + maxperiod /= 2; + minperiod /= 2; + *T0_ /= 2; + prev_period /= 2; + N /= 2; + x += maxperiod; + if (*T0_>=maxperiod) + *T0_=maxperiod-1; + + T = T0 = *T0_; + xx=xy=yy=0; + for (i=0;i>1; + t = VSHR32(x2y2, 2*(sh-7)); + g = g0 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1); + } +#else + g = g0 = xy/celt_sqrt(1+xx*yy); +#endif + /* Look for any pitch at T/k */ + for (k=2;k<=15;k++) + { + int T1, T1b; + opus_val16 g1; + opus_val16 cont=0; + T1 = (2*T0+k)/(2*k); + if (T1 < minperiod) + break; + /* Look for another strong correlation at T1b */ + if (k==2) + { + if (T1+T0>maxperiod) + T1b = T0; + else + T1b = T0+T1; + } else + { + T1b = (2*second_check[k]*T0+k)/(2*k); + } + xy=yy=0; + for (i=0;i>1; + t = VSHR32(x2y2, 2*(sh-7)); + g1 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1); + } +#else + g1 = xy/celt_sqrt(1+2.f*xx*1.f*yy); +#endif + if (abs(T1-prev_period)<=1) + cont = prev_gain; + else if (abs(T1-prev_period)<=2 && 5*k*k < T0) + cont = HALF32(prev_gain); + else + cont = 0; + if (g1 > QCONST16(.3f,15) + MULT16_16_Q15(QCONST16(.4f,15),g0)-cont) + { + best_xy = xy; + best_yy = yy; + T = T1; + g = g1; + } + } + if (best_yy <= best_xy) + pg = Q15ONE; + else + pg = SHR32(frac_div32(best_xy,best_yy+1),16); + + for (k=0;k<3;k++) + { + int T1 = T+k-1; + xy = 0; + for (i=0;i MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0])) + offset = 1; + else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2])) + offset = -1; + else + offset = 0; + if (pg > g) + pg = g; + *T0_ = 2*T+offset; + + if (*T0_ +#include "os_support.h" +#include "arch.h" +#include "mathops.h" +#include "stack_alloc.h" +#include "rate.h" + +#ifdef FIXED_POINT +/* Mean energy in each band quantized in Q6 */ +static const signed char eMeans[25] = { + 103,100, 92, 85, 81, + 77, 72, 70, 78, 75, + 73, 71, 78, 74, 69, + 72, 70, 74, 76, 71, + 60, 60, 60, 60, 60 +}; +#else +/* Mean energy in each band quantized in Q6 and converted back to float */ +static const opus_val16 eMeans[25] = { + 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f, + 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f, + 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f, + 4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f, + 3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f +}; +#endif +/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */ +#ifdef FIXED_POINT +static const opus_val16 pred_coef[4] = {29440, 26112, 21248, 16384}; +static const opus_val16 beta_coef[4] = {30147, 22282, 12124, 6554}; +static const opus_val16 beta_intra = 4915; +#else +static const opus_val16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.}; +static const opus_val16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.}; +static const opus_val16 beta_intra = 4915/32768.; +#endif + +/*Parameters of the Laplace-like probability models used for the coarse energy. + There is one pair of parameters for each frame size, prediction type + (inter/intra), and band number. + The first number of each pair is the probability of 0, and the second is the + decay rate, both in Q8 precision.*/ +static const unsigned char e_prob_model[4][2][42] = { + /*120 sample frames.*/ + { + /*Inter*/ + { + 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, + 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, + 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11 + }, + /*Intra*/ + { + 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, + 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, + 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50 + } + }, + /*240 sample frames.*/ + { + /*Inter*/ + { + 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, + 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, + 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9 + }, + /*Intra*/ + { + 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, + 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, + 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45 + } + }, + /*480 sample frames.*/ + { + /*Inter*/ + { + 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, + 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, + 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10 + }, + /*Intra*/ + { + 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, + 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, + 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42 + } + }, + /*960 sample frames.*/ + { + /*Inter*/ + { + 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, + 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, + 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15 + }, + /*Intra*/ + { + 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, + 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, + 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40 + } + } +}; + +static const unsigned char small_energy_icdf[3]={2,1,0}; + +static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBands, int start, int end, int len, int C) +{ + int c, i; + opus_val32 dist = 0; + c=0; do { + for (i=start;inbEBands]; + oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); +#ifdef FIXED_POINT + f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7); + decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT), + SUB32((opus_val32)oldEBands[i+c*m->nbEBands],max_decay))); +#else + f = x-coef*oldE-prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (int)floor(.5f+f); + decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay; +#endif + /* Prevent the energy from going down too quickly (e.g. for bands + that have just one bin) */ + if (qi < 0 && x < decay_bound) + { + qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT); + if (qi > 0) + qi = 0; + } + qi0 = qi; + /* If we don't have enough bits to encode all the energy, just assume + something safe. */ + tell = ec_tell(enc); + bits_left = budget-tell-3*C*(end-i); + if (i!=start && bits_left < 30) + { + if (bits_left < 24) + qi = IMIN(1, qi); + if (bits_left < 16) + qi = IMAX(-1, qi); + } + if (budget-tell >= 15) + { + int pi; + pi = 2*IMIN(i,20); + ec_laplace_encode(enc, &qi, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell >= 2) + { + qi = IMAX(-1, IMIN(qi, 1)); + ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2); + } + else if(budget-tell >= 1) + { + qi = IMIN(0, qi); + ec_enc_bit_logp(enc, -qi, 1); + } + else + qi = -1; + error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT); + badness += abs(qi0-qi); + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } + return badness; +} + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, int nbAvailableBytes, + int force_intra, opus_val32 *delayedIntra, int two_pass, int loss_rate) +{ + int intra; + opus_val16 max_decay; + VARDECL(opus_val16, oldEBands_intra); + VARDECL(opus_val16, error_intra); + ec_enc enc_start_state; + opus_uint32 tell; + int badness1=0; + opus_int32 intra_bias; + opus_val32 new_distortion; + SAVE_STACK; + + intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C); + intra_bias = (opus_int32)((budget**delayedIntra*loss_rate)/(C*512)); + new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C); + + tell = ec_tell(enc); + if (tell+3 > budget) + two_pass = intra = 0; + + /* Encode the global flags using a simple probability model + (first symbols in the stream) */ + +#ifdef FIXED_POINT + max_decay = MIN32(QCONST16(16.f,DB_SHIFT), SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3)); +#else + max_decay = MIN32(16.f, .125f*nbAvailableBytes); +#endif + + enc_start_state = *enc; + + ALLOC(oldEBands_intra, C*m->nbEBands, opus_val16); + ALLOC(error_intra, C*m->nbEBands, opus_val16); + OPUS_COPY(oldEBands_intra, oldEBands, C*m->nbEBands); + + if (two_pass || intra) + { + badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget, + tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay); + } + + if (!intra) + { + unsigned char *intra_buf; + ec_enc enc_intra_state; + opus_int32 tell_intra; + opus_uint32 nstart_bytes; + opus_uint32 nintra_bytes; + int badness2; + VARDECL(unsigned char, intra_bits); + + tell_intra = ec_tell_frac(enc); + + enc_intra_state = *enc; + + nstart_bytes = ec_range_bytes(&enc_start_state); + nintra_bytes = ec_range_bytes(&enc_intra_state); + intra_buf = ec_get_buffer(&enc_intra_state) + nstart_bytes; + ALLOC(intra_bits, nintra_bytes-nstart_bytes, unsigned char); + /* Copy bits from intra bit-stream */ + OPUS_COPY(intra_bits, intra_buf, nintra_bytes - nstart_bytes); + + *enc = enc_start_state; + + badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget, + tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay); + + if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ((opus_int32)ec_tell_frac(enc))+intra_bias > tell_intra))) + { + *enc = enc_intra_state; + /* Copy intra bits to bit-stream */ + OPUS_COPY(intra_buf, intra_bits, nintra_bytes - nstart_bytes); + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + intra = 1; + } + } else { + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + } + + if (intra) + *delayedIntra = new_distortion; + else + *delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra), + new_distortion); + + RESTORE_STACK; +} + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C) +{ + int i, c; + + /* Encode finer resolution */ + for (i=start;inbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]); +#else + q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac); +#endif + if (q2 > frac-1) + q2 = frac-1; + if (q2<0) + q2 = 0; + ec_enc_bits(enc, q2, fine_quant[i]); +#ifdef FIXED_POINT + offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT)); +#else + offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f; +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + /*printf ("%f ", error[i] - offset);*/ + } while (++c < C); + } +} + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = error[i+c*m->nbEBands]<0 ? 0 : 1; + ec_enc_bits(enc, q2, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM) +{ + const unsigned char *prob_model = e_prob_model[LM][intra]; + int i, c; + opus_val32 prev[2] = {0, 0}; + opus_val16 coef; + opus_val16 beta; + opus_int32 budget; + opus_int32 tell; + + if (intra) + { + coef = 0; + beta = beta_intra; + } else { + beta = beta_coef[LM]; + coef = pred_coef[LM]; + } + + budget = dec->storage*8; + + /* Decode at a fixed coarse resolution */ + for (i=start;i=15) + { + int pi; + pi = 2*IMIN(i,20); + qi = ec_laplace_decode(dec, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell>=2) + { + qi = ec_dec_icdf(dec, small_energy_icdf, 2); + qi = (qi>>1)^-(qi&1); + } + else if(budget-tell>=1) + { + qi = -ec_dec_bit_logp(dec, 1); + } + else + qi = -1; + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); + tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } +} + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C) +{ + int i, c; + /* Decode finer resolution */ + for (i=start;inbEBands] += offset; + } while (++c < C); + } +} + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = ec_dec_bits(dec, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} + +void log2Amp(const CELTMode *m, int start, int end, + celt_ener *eBands, const opus_val16 *oldEBands, int C) +{ + int c, i; + c=0; + do { + for (i=0;inbEBands] = 0; + for (;inbEBands], + SHL16((opus_val16)eMeans[i],6)); + eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(lg),4); + } + for (;inbEBands;i++) + eBands[i+c*m->nbEBands] = 0; + } while (++c < C); +} + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C) +{ + int c, i; + c=0; + do { + for (i=0;inbEBands] = + celt_log2(SHL32(bandE[i+c*m->nbEBands],2)) + - SHL16((opus_val16)eMeans[i],6); + for (i=effEnd;inbEBands+i] = -QCONST16(14.f,DB_SHIFT); + } while (++c < C); +} diff --git a/media/libopus/celt/quant_bands.h b/media/libopus/celt/quant_bands.h new file mode 100644 index 000000000000..b913e0b622ea --- /dev/null +++ b/media/libopus/celt/quant_bands.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef QUANT_BANDS +#define QUANT_BANDS + +#include "arch.h" +#include "modes.h" +#include "entenc.h" +#include "entdec.h" +#include "mathops.h" + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C); + +void log2Amp(const CELTMode *m, int start, int end, + celt_ener *eBands, const opus_val16 *oldEBands, int C); + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, + int nbAvailableBytes, int force_intra, opus_val32 *delayedIntra, + int two_pass, int loss_rate); + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C); + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C); + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM); + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C); + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C); + +#endif /* QUANT_BANDS */ diff --git a/media/libopus/celt/rate.c b/media/libopus/celt/rate.c new file mode 100644 index 000000000000..b39a94402459 --- /dev/null +++ b/media/libopus/celt/rate.c @@ -0,0 +1,638 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "modes.h" +#include "cwrs.h" +#include "arch.h" +#include "os_support.h" + +#include "entcode.h" +#include "rate.h" + +static const unsigned char LOG2_FRAC_TABLE[24]={ + 0, + 8,13, + 16,19,21,23, + 24,26,27,28,29,30,31,32, + 32,33,34,34,35,36,36,37,37 +}; + +#ifdef CUSTOM_MODES + +/*Determines if V(N,K) fits in a 32-bit unsigned integer. + N and K are themselves limited to 15 bits.*/ +static int fits_in32(int _n, int _k) +{ + static const opus_int16 maxN[15] = { + 32767, 32767, 32767, 1476, 283, 109, 60, 40, + 29, 24, 20, 18, 16, 14, 13}; + static const opus_int16 maxK[15] = { + 32767, 32767, 32767, 32767, 1172, 238, 95, 53, + 36, 27, 22, 18, 16, 15, 13}; + if (_n>=14) + { + if (_k>=14) + return 0; + else + return _n <= maxN[_k]; + } else { + return _k <= maxK[_n]; + } +} + +void compute_pulse_cache(CELTMode *m, int LM) +{ + int C; + int i; + int j; + int curr=0; + int nbEntries=0; + int entryN[100], entryK[100], entryI[100]; + const opus_int16 *eBands = m->eBands; + PulseCache *cache = &m->cache; + opus_int16 *cindex; + unsigned char *bits; + unsigned char *cap; + + cindex = opus_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2)); + cache->index = cindex; + + /* Scan for all unique band sizes */ + for (i=0;i<=LM+1;i++) + { + for (j=0;jnbEBands;j++) + { + int k; + int N = (eBands[j+1]-eBands[j])<>1; + cindex[i*m->nbEBands+j] = -1; + /* Find other bands that have the same size */ + for (k=0;k<=i;k++) + { + int n; + for (n=0;nnbEBands && (k!=i || n>1) + { + cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n]; + break; + } + } + } + if (cache->index[i*m->nbEBands+j] == -1 && N!=0) + { + int K; + entryN[nbEntries] = N; + K = 0; + while (fits_in32(N,get_pulses(K+1)) && KnbEBands+j] = curr; + entryI[nbEntries] = curr; + + curr += K+1; + nbEntries++; + } + } + } + bits = opus_alloc(sizeof(unsigned char)*curr); + cache->bits = bits; + cache->size = curr; + /* Compute the cache for all unique sizes */ + for (i=0;icaps = cap = opus_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands); + for (i=0;i<=LM;i++) + { + for (C=1;C<=2;C++) + { + for (j=0;jnbEBands;j++) + { + int N0; + int max_bits; + N0 = m->eBands[j+1]-m->eBands[j]; + /* N=1 bands only have a sign bit and fine bits. */ + if (N0<1 are even, including custom modes.*/ + if (N0 > 2) + { + N0>>=1; + LM0--; + } + /* N0=1 bands can't be split down to N<2. */ + else if (N0 <= 1) + { + LM0=IMIN(i,1); + N0<<=LM0; + } + /* Compute the cost for the lowest-level PVQ of a fully split + band. */ + pcache = bits + cindex[(LM0+1)*m->nbEBands+j]; + max_bits = pcache[pcache[0]]+1; + /* Add in the cost of coding regular splits. */ + N = N0; + for(k=0;klogN[j]+((LM0+k)<>1)-QTHETA_OFFSET; + /* The number of qtheta bits we'll allocate if the remainder + is to be max_bits. + The average measured cost for theta is 0.89701 times qb, + approximated here as 459/512. */ + num=459*(opus_int32)((2*N-1)*offset+max_bits); + den=((opus_int32)(2*N-1)<<9)-459; + qb = IMIN((num+(den>>1))/den, 57); + celt_assert(qb >= 0); + max_bits += qb; + N <<= 1; + } + /* Add in the cost of a stereo split, if necessary. */ + if (C==2) + { + max_bits <<= 1; + offset = ((m->logN[j]+(i<>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET); + ndof = 2*N-1-(N==2); + /* The average measured cost for theta with the step PDF is + 0.95164 times qb, approximated here as 487/512. */ + num = (N==2?512:487)*(opus_int32)(max_bits+ndof*offset); + den = ((opus_int32)ndof<<9)-(N==2?512:487); + qb = IMIN((num+(den>>1))/den, (N==2?64:61)); + celt_assert(qb >= 0); + max_bits += qb; + } + /* Add the fine bits we'll use. */ + /* Compensate for the extra DoF in stereo */ + ndof = C*N + ((C==2 && N>2) ? 1 : 0); + /* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = ((m->logN[j] + (i<>1)-FINE_OFFSET; + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += 1<>2; + /* The number of fine bits we'll allocate if the remainder is + to be max_bits. */ + num = max_bits+ndof*offset; + den = (ndof-1)<>1))/den, MAX_FINE_BITS); + celt_assert(qb >= 0); + max_bits += C*qb<eBands[j+1]-m->eBands[j])<= 0); + celt_assert(max_bits < 256); + *cap++ = (unsigned char)max_bits; + } + } + } +} + +#endif /* CUSTOM_MODES */ + +#define ALLOC_STEPS 6 + +static inline int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start, + const int *bits1, const int *bits2, const int *thresh, const int *cap, opus_int32 total, opus_int32 *_balance, + int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits, + int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev) +{ + opus_int32 psum; + int lo, hi; + int i, j; + int logM; + int stereo; + int codedBands=-1; + int alloc_floor; + opus_int32 left, percoeff; + int done; + int balance; + SAVE_STACK; + + alloc_floor = C<1; + + logM = LM<>1; + psum = 0; + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + (mid*(opus_int32)bits2[j]>>ALLOC_STEPS); + if (tmp >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(tmp, cap[j]); + } else { + if (tmp >= alloc_floor) + psum += alloc_floor; + } + } + if (psum > total) + hi = mid; + else + lo = mid; + } + psum = 0; + /*printf ("interp bisection gave %d\n", lo);*/ + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + (lo*bits2[j]>>ALLOC_STEPS); + if (tmp < thresh[j] && !done) + { + if (tmp >= alloc_floor) + tmp = alloc_floor; + else + tmp = 0; + } else + done = 1; + /* Don't allocate more than we can actually use */ + tmp = IMIN(tmp, cap[j]); + bits[j] = tmp; + psum += tmp; + } + + /* Decide which bands to skip, working backwards from the end. */ + for (codedBands=end;;codedBands--) + { + int band_width; + int band_bits; + int rem; + j = codedBands-1; + /* Never skip the first band, nor a band that has been boosted by + dynalloc. + In the first case, we'd be coding a bit to signal we're going to waste + all the other bits. + In the second case, we'd be coding a bit to redistribute all the bits + we just signaled should be cocentrated in this band. */ + if (j<=skip_start) + { + /* Give the bit we reserved to end skipping back. */ + total += skip_rsv; + break; + } + /*Figure out how many left-over bits we would be adding to this band. + This can include bits we've stolen back from higher, skipped bands.*/ + left = total-psum; + percoeff = left/(m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0); + band_width = m->eBands[codedBands]-m->eBands[j]; + band_bits = (int)(bits[j] + percoeff*band_width + rem); + /*Only code a skip decision if we're above the threshold for this band. + Otherwise it is force-skipped. + This ensures that we have enough bits to code the skip flag.*/ + if (band_bits >= IMAX(thresh[j], alloc_floor+(1< ((j>4) +#endif + { + ec_enc_bit_logp(ec, 1, 1); + break; + } + ec_enc_bit_logp(ec, 0, 1); + } else if (ec_dec_bit_logp(ec, 1)) { + break; + } + /*We used a bit to skip this band.*/ + psum += 1< 0) + intensity_rsv = LOG2_FRAC_TABLE[j-start]; + psum += intensity_rsv; + if (band_bits >= alloc_floor) + { + /*If we have enough for a fine energy bit per channel, use it.*/ + psum += alloc_floor; + bits[j] = alloc_floor; + } else { + /*Otherwise this band gets nothing at all.*/ + bits[j] = 0; + } + } + + celt_assert(codedBands > start); + /* Code the intensity and dual stereo parameters. */ + if (intensity_rsv > 0) + { + if (encode) + { + *intensity = IMIN(*intensity, codedBands); + ec_enc_uint(ec, *intensity-start, codedBands+1-start); + } + else + *intensity = start+ec_dec_uint(ec, codedBands+1-start); + } + else + *intensity = 0; + if (*intensity <= start) + { + total += dual_stereo_rsv; + dual_stereo_rsv = 0; + } + if (dual_stereo_rsv > 0) + { + if (encode) + ec_enc_bit_logp(ec, *dual_stereo, 1); + else + *dual_stereo = ec_dec_bit_logp(ec, 1); + } + else + *dual_stereo = 0; + + /* Allocate the remaining bits */ + left = total-psum; + percoeff = left/(m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + for (j=start;jeBands[j+1]-m->eBands[j])); + for (j=start;jeBands[j+1]-m->eBands[j]); + bits[j] += tmp; + left -= tmp; + } + /*for (j=0;j= 0); + N0 = m->eBands[j+1]-m->eBands[j]; + N=N0<1) + { + excess = IMAX(bits[j]-cap[j],0); + bits[j] -= excess; + + /* Compensate for the extra DoF in stereo */ + den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0)); + + NClogN = den*(m->logN[j] + logM); + + /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = (NClogN>>1)-den*FINE_OFFSET; + + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += den<>2; + + /* Changing the offset for allocating the second and third + fine energy bit */ + if (bits[j] + offset < den*2<>2; + else if (bits[j] + offset < den*3<>3; + + /* Divide with rounding */ + ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1))) / (den< (bits[j]>>BITRES)) + ebits[j] = bits[j] >> stereo >> BITRES; + + /* More than that is useless because that's about as far as PVQ can go */ + ebits[j] = IMIN(ebits[j], MAX_FINE_BITS); + + /* If we rounded down or capped this band, make it a candidate for the + final fine energy pass */ + fine_priority[j] = ebits[j]*(den<= bits[j]+offset; + + /* Remove the allocated fine bits; the rest are assigned to PVQ */ + bits[j] -= C*ebits[j]< 0) + { + int extra_fine; + int extra_bits; + extra_fine = IMIN(excess>>(stereo+BITRES),MAX_FINE_BITS-ebits[j]); + ebits[j] += extra_fine; + extra_bits = extra_fine*C<= excess-balance; + excess -= extra_bits; + } + balance = excess; + + celt_assert(bits[j] >= 0); + celt_assert(ebits[j] >= 0); + } + /* Save any remaining bits over the cap for the rebalancing in + quant_all_bands(). */ + *_balance = balance; + + /* The skipped bands use all their bits for fine energy. */ + for (;j> stereo >> BITRES; + celt_assert(C*ebits[j]<nbEBands; + skip_start = start; + /* Reserve a bit to signal the end of manually skipped bands. */ + skip_rsv = total >= 1<total) + intensity_rsv = 0; + else + { + total -= intensity_rsv; + dual_stereo_rsv = total>=1<eBands[j+1]-m->eBands[j])<>4); + /* Tilt of the allocation curve */ + trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1) + *(1<<(LM+BITRES))>>6; + /* Giving less resolution to single-coefficient bands because they get + more benefit from having one coarse value per coefficient*/ + if ((m->eBands[j+1]-m->eBands[j])<nbAllocVectors - 1; + do + { + int done = 0; + int psum = 0; + int mid = (lo+hi) >> 1; + for (j=end;j-->start;) + { + int bitsj; + int N = m->eBands[j+1]-m->eBands[j]; + bitsj = C*N*m->allocVectors[mid*len+j]<>2; + if (bitsj > 0) + bitsj = IMAX(0, bitsj + trim_offset[j]); + bitsj += offsets[j]; + if (bitsj >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(bitsj, cap[j]); + } else { + if (bitsj >= C< total) + hi = mid - 1; + else + lo = mid + 1; + /*printf ("lo = %d, hi = %d\n", lo, hi);*/ + } + while (lo <= hi); + hi = lo--; + /*printf ("interp between %d and %d\n", lo, hi);*/ + for (j=start;jeBands[j+1]-m->eBands[j]; + bits1j = C*N*m->allocVectors[lo*len+j]<>2; + bits2j = hi>=m->nbAllocVectors ? + cap[j] : C*N*m->allocVectors[hi*len+j]<>2; + if (bits1j > 0) + bits1j = IMAX(0, bits1j + trim_offset[j]); + if (bits2j > 0) + bits2j = IMAX(0, bits2j + trim_offset[j]); + if (lo > 0) + bits1j += offsets[j]; + bits2j += offsets[j]; + if (offsets[j]>0) + skip_start = j; + bits2j = IMAX(0,bits2j-bits1j); + bits1[j] = bits1j; + bits2[j] = bits2j; + } + codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap, + total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv, + pulses, ebits, fine_priority, C, LM, ec, encode, prev); + RESTORE_STACK; + return codedBands; +} + diff --git a/media/libopus/celt/rate.h b/media/libopus/celt/rate.h new file mode 100644 index 000000000000..30c3cc1aeb07 --- /dev/null +++ b/media/libopus/celt/rate.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef RATE_H +#define RATE_H + +#define MAX_PSEUDO 40 +#define LOG_MAX_PSEUDO 6 + +#define MAX_PULSES 128 + +#define MAX_FINE_BITS 8 + +#define FINE_OFFSET 21 +#define QTHETA_OFFSET 4 +#define QTHETA_OFFSET_TWOPHASE 16 + +#include "cwrs.h" +#include "modes.h" + +void compute_pulse_cache(CELTMode *m, int LM); + +static inline int get_pulses(int i) +{ + return i<8 ? i : (8 + (i&7)) << ((i>>3)-1); +} + +static inline int bits2pulses(const CELTMode *m, int band, int LM, int bits) +{ + int i; + int lo, hi; + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + + lo = 0; + hi = cache[0]; + bits--; + for (i=0;i>1; + /* OPT: Make sure this is implemented with a conditional move */ + if (cache[mid] >= bits) + hi = mid; + else + lo = mid; + } + if (bits- (lo == 0 ? -1 : cache[lo]) <= cache[hi]-bits) + return lo; + else + return hi; +} + +static inline int pulses2bits(const CELTMode *m, int band, int LM, int pulses) +{ + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + return pulses == 0 ? 0 : cache[pulses]+1; +} + +/** Compute the pulse allocation, i.e. how many pulses will go in each + * band. + @param m mode + @param offsets Requested increase or decrease in the number of bits for + each band + @param total Number of bands + @param pulses Number of pulses per band (returned) + @return Total number of bits allocated +*/ +int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stero, + opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev); + +#endif diff --git a/media/libopus/celt/stack_alloc.h b/media/libopus/celt/stack_alloc.h new file mode 100644 index 000000000000..be01e20fba6f --- /dev/null +++ b/media/libopus/celt/stack_alloc.h @@ -0,0 +1,145 @@ +/* Copyright (C) 2002-2003 Jean-Marc Valin + Copyright (C) 2007-2009 Xiph.Org Foundation */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STACK_ALLOC_H +#define STACK_ALLOC_H + +#ifdef USE_ALLOCA +# ifdef WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + +#if defined(VAR_ARRAYS) + +#define VARDECL(type, var) +#define ALLOC(var, size, type) type var[size] +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK + +#elif defined(USE_ALLOCA) + +#define VARDECL(type, var) type *var + +# ifdef WIN32 +# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size))) +# else +# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size))) +# endif + +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK + +#else + +#ifdef CELT_C +char *global_stack=0; +#else +extern char *global_stack; +#endif /* CELT_C */ + +#ifdef ENABLE_VALGRIND + +#include + +#ifdef CELT_C +char *global_stack_top=0; +#else +extern char *global_stack_top; +#endif /* CELT_C */ + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char)))) +#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)) +#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack; + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char)))) +#define RESTORE_STACK (global_stack = _saved_stack) +#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? opus_alloc_scratch(GLOBAL_STACK_SIZE) : global_stack); _saved_stack = global_stack; + +#endif /* ENABLE_VALGRIND */ + +#include "os_support.h" +#define VARDECL(type, var) type *var +#define ALLOC(var, size, type) var = PUSH(global_stack, size, type) +#define SAVE_STACK char *_saved_stack = global_stack; + +#endif /* VAR_ARRAYS */ + +#endif /* STACK_ALLOC_H */ diff --git a/media/libopus/celt/static_modes_fixed.h b/media/libopus/celt/static_modes_fixed.h new file mode 100644 index 000000000000..216df9e605f2 --- /dev/null +++ b/media/libopus/celt/static_modes_fixed.h @@ -0,0 +1,595 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +2, 20, 55, 108, 178, +266, 372, 494, 635, 792, +966, 1157, 1365, 1590, 1831, +2089, 2362, 2651, 2956, 3276, +3611, 3961, 4325, 4703, 5094, +5499, 5916, 6346, 6788, 7241, +7705, 8179, 8663, 9156, 9657, +10167, 10684, 11207, 11736, 12271, +12810, 13353, 13899, 14447, 14997, +15547, 16098, 16648, 17197, 17744, +18287, 18827, 19363, 19893, 20418, +20936, 21447, 21950, 22445, 22931, +23407, 23874, 24330, 24774, 25208, +25629, 26039, 26435, 26819, 27190, +27548, 27893, 28224, 28541, 28845, +29135, 29411, 29674, 29924, 30160, +30384, 30594, 30792, 30977, 31151, +31313, 31463, 31602, 31731, 31849, +31958, 32057, 32148, 32229, 32303, +32370, 32429, 32481, 32528, 32568, +32604, 32634, 32661, 32683, 32701, +32717, 32729, 32740, 32748, 32754, +32758, 32762, 32764, 32766, 32767, +32767, 32767, 32767, 32767, 32767, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, +82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, +41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, +41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, +318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, +305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, +240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, +31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, +51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, +66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, +64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, +94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, +124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, +97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, +142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, +28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, +153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, +229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, +166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, +86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, +25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, +185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, +110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, +74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, +163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, +228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, +90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, +87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, +106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, +224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, +182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, +178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, +240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, +160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, +138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, +204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, +185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, +207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, +188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, +204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, +140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{32767, 0}, {32766, -429}, +{32757, -858}, {32743, -1287}, +{32724, -1715}, {32698, -2143}, +{32667, -2570}, {32631, -2998}, +{32588, -3425}, {32541, -3851}, +{32488, -4277}, {32429, -4701}, +{32364, -5125}, {32295, -5548}, +{32219, -5971}, {32138, -6393}, +{32051, -6813}, {31960, -7231}, +{31863, -7650}, {31760, -8067}, +{31652, -8481}, {31539, -8895}, +{31419, -9306}, {31294, -9716}, +{31165, -10126}, {31030, -10532}, +{30889, -10937}, {30743, -11340}, +{30592, -11741}, {30436, -12141}, +{30274, -12540}, {30107, -12935}, +{29936, -13328}, {29758, -13718}, +{29577, -14107}, {29390, -14493}, +{29197, -14875}, {29000, -15257}, +{28797, -15635}, {28590, -16010}, +{28379, -16384}, {28162, -16753}, +{27940, -17119}, {27714, -17484}, +{27482, -17845}, {27246, -18205}, +{27006, -18560}, {26760, -18911}, +{26510, -19260}, {26257, -19606}, +{25997, -19947}, {25734, -20286}, +{25466, -20621}, {25194, -20952}, +{24918, -21281}, {24637, -21605}, +{24353, -21926}, {24063, -22242}, +{23770, -22555}, {23473, -22865}, +{23171, -23171}, {22866, -23472}, +{22557, -23769}, {22244, -24063}, +{21927, -24352}, {21606, -24636}, +{21282, -24917}, {20954, -25194}, +{20622, -25465}, {20288, -25733}, +{19949, -25997}, {19607, -26255}, +{19261, -26509}, {18914, -26760}, +{18561, -27004}, {18205, -27246}, +{17846, -27481}, {17485, -27713}, +{17122, -27940}, {16755, -28162}, +{16385, -28378}, {16012, -28590}, +{15636, -28797}, {15258, -28999}, +{14878, -29197}, {14494, -29389}, +{14108, -29576}, {13720, -29757}, +{13329, -29934}, {12937, -30107}, +{12540, -30274}, {12142, -30435}, +{11744, -30592}, {11342, -30743}, +{10939, -30889}, {10534, -31030}, +{10127, -31164}, {9718, -31294}, +{9307, -31418}, {8895, -31537}, +{8482, -31652}, {8067, -31759}, +{7650, -31862}, {7233, -31960}, +{6815, -32051}, {6393, -32138}, +{5973, -32219}, {5549, -32294}, +{5127, -32364}, {4703, -32429}, +{4278, -32487}, {3852, -32541}, +{3426, -32588}, {2999, -32630}, +{2572, -32667}, {2144, -32698}, +{1716, -32724}, {1287, -32742}, +{860, -32757}, {430, -32766}, +{0, -32767}, {-429, -32766}, +{-858, -32757}, {-1287, -32743}, +{-1715, -32724}, {-2143, -32698}, +{-2570, -32667}, {-2998, -32631}, +{-3425, -32588}, {-3851, -32541}, +{-4277, -32488}, {-4701, -32429}, +{-5125, -32364}, {-5548, -32295}, +{-5971, -32219}, {-6393, -32138}, +{-6813, -32051}, {-7231, -31960}, +{-7650, -31863}, {-8067, -31760}, +{-8481, -31652}, {-8895, -31539}, +{-9306, -31419}, {-9716, -31294}, +{-10126, -31165}, {-10532, -31030}, +{-10937, -30889}, {-11340, -30743}, +{-11741, -30592}, {-12141, -30436}, +{-12540, -30274}, {-12935, -30107}, +{-13328, -29936}, {-13718, -29758}, +{-14107, -29577}, {-14493, -29390}, +{-14875, -29197}, {-15257, -29000}, +{-15635, -28797}, {-16010, -28590}, +{-16384, -28379}, {-16753, -28162}, +{-17119, -27940}, {-17484, -27714}, +{-17845, -27482}, {-18205, -27246}, +{-18560, -27006}, {-18911, -26760}, +{-19260, -26510}, {-19606, -26257}, +{-19947, -25997}, {-20286, -25734}, +{-20621, -25466}, {-20952, -25194}, +{-21281, -24918}, {-21605, -24637}, +{-21926, -24353}, {-22242, -24063}, +{-22555, -23770}, {-22865, -23473}, +{-23171, -23171}, {-23472, -22866}, +{-23769, -22557}, {-24063, -22244}, +{-24352, -21927}, {-24636, -21606}, +{-24917, -21282}, {-25194, -20954}, +{-25465, -20622}, {-25733, -20288}, +{-25997, -19949}, {-26255, -19607}, +{-26509, -19261}, {-26760, -18914}, +{-27004, -18561}, {-27246, -18205}, +{-27481, -17846}, {-27713, -17485}, +{-27940, -17122}, {-28162, -16755}, +{-28378, -16385}, {-28590, -16012}, +{-28797, -15636}, {-28999, -15258}, +{-29197, -14878}, {-29389, -14494}, +{-29576, -14108}, {-29757, -13720}, +{-29934, -13329}, {-30107, -12937}, +{-30274, -12540}, {-30435, -12142}, +{-30592, -11744}, {-30743, -11342}, +{-30889, -10939}, {-31030, -10534}, +{-31164, -10127}, {-31294, -9718}, +{-31418, -9307}, {-31537, -8895}, +{-31652, -8482}, {-31759, -8067}, +{-31862, -7650}, {-31960, -7233}, +{-32051, -6815}, {-32138, -6393}, +{-32219, -5973}, {-32294, -5549}, +{-32364, -5127}, {-32429, -4703}, +{-32487, -4278}, {-32541, -3852}, +{-32588, -3426}, {-32630, -2999}, +{-32667, -2572}, {-32698, -2144}, +{-32724, -1716}, {-32742, -1287}, +{-32757, -860}, {-32766, -430}, +{-32767, 0}, {-32766, 429}, +{-32757, 858}, {-32743, 1287}, +{-32724, 1715}, {-32698, 2143}, +{-32667, 2570}, {-32631, 2998}, +{-32588, 3425}, {-32541, 3851}, +{-32488, 4277}, {-32429, 4701}, +{-32364, 5125}, {-32295, 5548}, +{-32219, 5971}, {-32138, 6393}, +{-32051, 6813}, {-31960, 7231}, +{-31863, 7650}, {-31760, 8067}, +{-31652, 8481}, {-31539, 8895}, +{-31419, 9306}, {-31294, 9716}, +{-31165, 10126}, {-31030, 10532}, +{-30889, 10937}, {-30743, 11340}, +{-30592, 11741}, {-30436, 12141}, +{-30274, 12540}, {-30107, 12935}, +{-29936, 13328}, {-29758, 13718}, +{-29577, 14107}, {-29390, 14493}, +{-29197, 14875}, {-29000, 15257}, +{-28797, 15635}, {-28590, 16010}, +{-28379, 16384}, {-28162, 16753}, +{-27940, 17119}, {-27714, 17484}, +{-27482, 17845}, {-27246, 18205}, +{-27006, 18560}, {-26760, 18911}, +{-26510, 19260}, {-26257, 19606}, +{-25997, 19947}, {-25734, 20286}, +{-25466, 20621}, {-25194, 20952}, +{-24918, 21281}, {-24637, 21605}, +{-24353, 21926}, {-24063, 22242}, +{-23770, 22555}, {-23473, 22865}, +{-23171, 23171}, {-22866, 23472}, +{-22557, 23769}, {-22244, 24063}, +{-21927, 24352}, {-21606, 24636}, +{-21282, 24917}, {-20954, 25194}, +{-20622, 25465}, {-20288, 25733}, +{-19949, 25997}, {-19607, 26255}, +{-19261, 26509}, {-18914, 26760}, +{-18561, 27004}, {-18205, 27246}, +{-17846, 27481}, {-17485, 27713}, +{-17122, 27940}, {-16755, 28162}, +{-16385, 28378}, {-16012, 28590}, +{-15636, 28797}, {-15258, 28999}, +{-14878, 29197}, {-14494, 29389}, +{-14108, 29576}, {-13720, 29757}, +{-13329, 29934}, {-12937, 30107}, +{-12540, 30274}, {-12142, 30435}, +{-11744, 30592}, {-11342, 30743}, +{-10939, 30889}, {-10534, 31030}, +{-10127, 31164}, {-9718, 31294}, +{-9307, 31418}, {-8895, 31537}, +{-8482, 31652}, {-8067, 31759}, +{-7650, 31862}, {-7233, 31960}, +{-6815, 32051}, {-6393, 32138}, +{-5973, 32219}, {-5549, 32294}, +{-5127, 32364}, {-4703, 32429}, +{-4278, 32487}, {-3852, 32541}, +{-3426, 32588}, {-2999, 32630}, +{-2572, 32667}, {-2144, 32698}, +{-1716, 32724}, {-1287, 32742}, +{-860, 32757}, {-430, 32766}, +{0, 32767}, {429, 32766}, +{858, 32757}, {1287, 32743}, +{1715, 32724}, {2143, 32698}, +{2570, 32667}, {2998, 32631}, +{3425, 32588}, {3851, 32541}, +{4277, 32488}, {4701, 32429}, +{5125, 32364}, {5548, 32295}, +{5971, 32219}, {6393, 32138}, +{6813, 32051}, {7231, 31960}, +{7650, 31863}, {8067, 31760}, +{8481, 31652}, {8895, 31539}, +{9306, 31419}, {9716, 31294}, +{10126, 31165}, {10532, 31030}, +{10937, 30889}, {11340, 30743}, +{11741, 30592}, {12141, 30436}, +{12540, 30274}, {12935, 30107}, +{13328, 29936}, {13718, 29758}, +{14107, 29577}, {14493, 29390}, +{14875, 29197}, {15257, 29000}, +{15635, 28797}, {16010, 28590}, +{16384, 28379}, {16753, 28162}, +{17119, 27940}, {17484, 27714}, +{17845, 27482}, {18205, 27246}, +{18560, 27006}, {18911, 26760}, +{19260, 26510}, {19606, 26257}, +{19947, 25997}, {20286, 25734}, +{20621, 25466}, {20952, 25194}, +{21281, 24918}, {21605, 24637}, +{21926, 24353}, {22242, 24063}, +{22555, 23770}, {22865, 23473}, +{23171, 23171}, {23472, 22866}, +{23769, 22557}, {24063, 22244}, +{24352, 21927}, {24636, 21606}, +{24917, 21282}, {25194, 20954}, +{25465, 20622}, {25733, 20288}, +{25997, 19949}, {26255, 19607}, +{26509, 19261}, {26760, 18914}, +{27004, 18561}, {27246, 18205}, +{27481, 17846}, {27713, 17485}, +{27940, 17122}, {28162, 16755}, +{28378, 16385}, {28590, 16012}, +{28797, 15636}, {28999, 15258}, +{29197, 14878}, {29389, 14494}, +{29576, 14108}, {29757, 13720}, +{29934, 13329}, {30107, 12937}, +{30274, 12540}, {30435, 12142}, +{30592, 11744}, {30743, 11342}, +{30889, 10939}, {31030, 10534}, +{31164, 10127}, {31294, 9718}, +{31418, 9307}, {31537, 8895}, +{31652, 8482}, {31759, 8067}, +{31862, 7650}, {31960, 7233}, +{32051, 6815}, {32138, 6393}, +{32219, 5973}, {32294, 5549}, +{32364, 5127}, {32429, 4703}, +{32487, 4278}, {32541, 3852}, +{32588, 3426}, {32630, 2999}, +{32667, 2572}, {32698, 2144}, +{32724, 1716}, {32742, 1287}, +{32757, 860}, {32766, 430}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +0, 120, 240, 360, 30, 150, 270, 390, 60, 180, 300, 420, 90, 210, 330, +450, 15, 135, 255, 375, 45, 165, 285, 405, 75, 195, 315, 435, 105, 225, +345, 465, 5, 125, 245, 365, 35, 155, 275, 395, 65, 185, 305, 425, 95, +215, 335, 455, 20, 140, 260, 380, 50, 170, 290, 410, 80, 200, 320, 440, +110, 230, 350, 470, 10, 130, 250, 370, 40, 160, 280, 400, 70, 190, 310, +430, 100, 220, 340, 460, 25, 145, 265, 385, 55, 175, 295, 415, 85, 205, +325, 445, 115, 235, 355, 475, 1, 121, 241, 361, 31, 151, 271, 391, 61, +181, 301, 421, 91, 211, 331, 451, 16, 136, 256, 376, 46, 166, 286, 406, +76, 196, 316, 436, 106, 226, 346, 466, 6, 126, 246, 366, 36, 156, 276, +396, 66, 186, 306, 426, 96, 216, 336, 456, 21, 141, 261, 381, 51, 171, +291, 411, 81, 201, 321, 441, 111, 231, 351, 471, 11, 131, 251, 371, 41, +161, 281, 401, 71, 191, 311, 431, 101, 221, 341, 461, 26, 146, 266, 386, +56, 176, 296, 416, 86, 206, 326, 446, 116, 236, 356, 476, 2, 122, 242, +362, 32, 152, 272, 392, 62, 182, 302, 422, 92, 212, 332, 452, 17, 137, +257, 377, 47, 167, 287, 407, 77, 197, 317, 437, 107, 227, 347, 467, 7, +127, 247, 367, 37, 157, 277, 397, 67, 187, 307, 427, 97, 217, 337, 457, +22, 142, 262, 382, 52, 172, 292, 412, 82, 202, 322, 442, 112, 232, 352, +472, 12, 132, 252, 372, 42, 162, 282, 402, 72, 192, 312, 432, 102, 222, +342, 462, 27, 147, 267, 387, 57, 177, 297, 417, 87, 207, 327, 447, 117, +237, 357, 477, 3, 123, 243, 363, 33, 153, 273, 393, 63, 183, 303, 423, +93, 213, 333, 453, 18, 138, 258, 378, 48, 168, 288, 408, 78, 198, 318, +438, 108, 228, 348, 468, 8, 128, 248, 368, 38, 158, 278, 398, 68, 188, +308, 428, 98, 218, 338, 458, 23, 143, 263, 383, 53, 173, 293, 413, 83, +203, 323, 443, 113, 233, 353, 473, 13, 133, 253, 373, 43, 163, 283, 403, +73, 193, 313, 433, 103, 223, 343, 463, 28, 148, 268, 388, 58, 178, 298, +418, 88, 208, 328, 448, 118, 238, 358, 478, 4, 124, 244, 364, 34, 154, +274, 394, 64, 184, 304, 424, 94, 214, 334, 454, 19, 139, 259, 379, 49, +169, 289, 409, 79, 199, 319, 439, 109, 229, 349, 469, 9, 129, 249, 369, +39, 159, 279, 399, 69, 189, 309, 429, 99, 219, 339, 459, 24, 144, 264, +384, 54, 174, 294, 414, 84, 204, 324, 444, 114, 234, 354, 474, 14, 134, +254, 374, 44, 164, 284, 404, 74, 194, 314, 434, 104, 224, 344, 464, 29, +149, 269, 389, 59, 179, 299, 419, 89, 209, 329, 449, 119, 239, 359, 479, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +0, 60, 120, 180, 15, 75, 135, 195, 30, 90, 150, 210, 45, 105, 165, +225, 5, 65, 125, 185, 20, 80, 140, 200, 35, 95, 155, 215, 50, 110, +170, 230, 10, 70, 130, 190, 25, 85, 145, 205, 40, 100, 160, 220, 55, +115, 175, 235, 1, 61, 121, 181, 16, 76, 136, 196, 31, 91, 151, 211, +46, 106, 166, 226, 6, 66, 126, 186, 21, 81, 141, 201, 36, 96, 156, +216, 51, 111, 171, 231, 11, 71, 131, 191, 26, 86, 146, 206, 41, 101, +161, 221, 56, 116, 176, 236, 2, 62, 122, 182, 17, 77, 137, 197, 32, +92, 152, 212, 47, 107, 167, 227, 7, 67, 127, 187, 22, 82, 142, 202, +37, 97, 157, 217, 52, 112, 172, 232, 12, 72, 132, 192, 27, 87, 147, +207, 42, 102, 162, 222, 57, 117, 177, 237, 3, 63, 123, 183, 18, 78, +138, 198, 33, 93, 153, 213, 48, 108, 168, 228, 8, 68, 128, 188, 23, +83, 143, 203, 38, 98, 158, 218, 53, 113, 173, 233, 13, 73, 133, 193, +28, 88, 148, 208, 43, 103, 163, 223, 58, 118, 178, 238, 4, 64, 124, +184, 19, 79, 139, 199, 34, 94, 154, 214, 49, 109, 169, 229, 9, 69, +129, 189, 24, 84, 144, 204, 39, 99, 159, 219, 54, 114, 174, 234, 14, +74, 134, 194, 29, 89, 149, 209, 44, 104, 164, 224, 59, 119, 179, 239, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +0, 30, 60, 90, 15, 45, 75, 105, 5, 35, 65, 95, 20, 50, 80, +110, 10, 40, 70, 100, 25, 55, 85, 115, 1, 31, 61, 91, 16, 46, +76, 106, 6, 36, 66, 96, 21, 51, 81, 111, 11, 41, 71, 101, 26, +56, 86, 116, 2, 32, 62, 92, 17, 47, 77, 107, 7, 37, 67, 97, +22, 52, 82, 112, 12, 42, 72, 102, 27, 57, 87, 117, 3, 33, 63, +93, 18, 48, 78, 108, 8, 38, 68, 98, 23, 53, 83, 113, 13, 43, +73, 103, 28, 58, 88, 118, 4, 34, 64, 94, 19, 49, 79, 109, 9, +39, 69, 99, 24, 54, 84, 114, 14, 44, 74, 104, 29, 59, 89, 119, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +0, 15, 30, 45, 5, 20, 35, 50, 10, 25, 40, 55, 1, 16, 31, +46, 6, 21, 36, 51, 11, 26, 41, 56, 2, 17, 32, 47, 7, 22, +37, 52, 12, 27, 42, 57, 3, 18, 33, 48, 8, 23, 38, 53, 13, +28, 43, 58, 4, 19, 34, 49, 9, 24, 39, 54, 14, 29, 44, 59, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +-1, /* shift */ +{4, 120, 4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +1, /* shift */ +{4, 60, 4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +2, /* shift */ +{4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +3, /* shift */ +{4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[481] = { +32767, 32767, 32767, 32767, 32766, +32763, 32762, 32759, 32757, 32753, +32751, 32747, 32743, 32738, 32733, +32729, 32724, 32717, 32711, 32705, +32698, 32690, 32683, 32676, 32667, +32658, 32650, 32640, 32631, 32620, +32610, 32599, 32588, 32577, 32566, +32554, 32541, 32528, 32515, 32502, +32487, 32474, 32459, 32444, 32429, +32413, 32397, 32381, 32364, 32348, +32331, 32313, 32294, 32277, 32257, +32239, 32219, 32200, 32180, 32159, +32138, 32118, 32096, 32074, 32051, +32029, 32006, 31984, 31960, 31936, +31912, 31888, 31863, 31837, 31812, +31786, 31760, 31734, 31707, 31679, +31652, 31624, 31596, 31567, 31539, +31508, 31479, 31450, 31419, 31388, +31357, 31326, 31294, 31262, 31230, +31198, 31164, 31131, 31097, 31063, +31030, 30994, 30959, 30924, 30889, +30853, 30816, 30779, 30743, 30705, +30668, 30629, 30592, 30553, 30515, +30475, 30435, 30396, 30356, 30315, +30274, 30233, 30191, 30149, 30107, +30065, 30022, 29979, 29936, 29891, +29847, 29803, 29758, 29713, 29668, +29622, 29577, 29529, 29483, 29436, +29390, 29341, 29293, 29246, 29197, +29148, 29098, 29050, 29000, 28949, +28899, 28848, 28797, 28746, 28694, +28642, 28590, 28537, 28485, 28432, +28378, 28324, 28271, 28217, 28162, +28106, 28051, 27995, 27940, 27884, +27827, 27770, 27713, 27657, 27598, +27540, 27481, 27423, 27365, 27305, +27246, 27187, 27126, 27066, 27006, +26945, 26883, 26822, 26760, 26698, +26636, 26574, 26510, 26448, 26383, +26320, 26257, 26191, 26127, 26062, +25997, 25931, 25866, 25800, 25734, +25667, 25601, 25533, 25466, 25398, +25330, 25262, 25194, 25125, 25056, +24987, 24917, 24848, 24778, 24707, +24636, 24566, 24495, 24424, 24352, +24280, 24208, 24135, 24063, 23990, +23917, 23842, 23769, 23695, 23622, +23546, 23472, 23398, 23322, 23246, +23171, 23095, 23018, 22942, 22866, +22788, 22711, 22634, 22557, 22478, +22400, 22322, 22244, 22165, 22085, +22006, 21927, 21846, 21766, 21687, +21606, 21524, 21443, 21363, 21282, +21199, 21118, 21035, 20954, 20870, +20788, 20705, 20621, 20538, 20455, +20371, 20286, 20202, 20118, 20034, +19947, 19863, 19777, 19692, 19606, +19520, 19434, 19347, 19260, 19174, +19088, 18999, 18911, 18825, 18737, +18648, 18560, 18472, 18384, 18294, +18205, 18116, 18025, 17936, 17846, +17757, 17666, 17576, 17485, 17395, +17303, 17212, 17122, 17030, 16937, +16846, 16755, 16662, 16569, 16477, +16385, 16291, 16198, 16105, 16012, +15917, 15824, 15730, 15636, 15541, +15447, 15352, 15257, 15162, 15067, +14973, 14875, 14781, 14685, 14589, +14493, 14396, 14300, 14204, 14107, +14010, 13914, 13815, 13718, 13621, +13524, 13425, 13328, 13230, 13133, +13033, 12935, 12836, 12738, 12638, +12540, 12441, 12341, 12241, 12142, +12044, 11943, 11843, 11744, 11643, +11542, 11442, 11342, 11241, 11139, +11039, 10939, 10836, 10736, 10635, +10534, 10431, 10330, 10228, 10127, +10024, 9921, 9820, 9718, 9614, +9512, 9410, 9306, 9204, 9101, +8998, 8895, 8791, 8689, 8585, +8481, 8377, 8274, 8171, 8067, +7962, 7858, 7753, 7650, 7545, +7441, 7336, 7231, 7129, 7023, +6917, 6813, 6709, 6604, 6498, +6393, 6288, 6182, 6077, 5973, +5867, 5760, 5656, 5549, 5445, +5339, 5232, 5127, 5022, 4914, +4809, 4703, 4596, 4490, 4384, +4278, 4171, 4065, 3958, 3852, +3745, 3640, 3532, 3426, 3318, +3212, 3106, 2998, 2891, 2786, +2679, 2570, 2465, 2358, 2251, +2143, 2037, 1929, 1823, 1715, +1609, 1501, 1393, 1287, 1180, +1073, 964, 858, 751, 644, +535, 429, 322, 214, 107, +0, }; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{27853, 0, 4096, 8192, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/media/libopus/celt/static_modes_float.h b/media/libopus/celt/static_modes_float.h new file mode 100644 index 000000000000..5d7e7b8e684c --- /dev/null +++ b/media/libopus/celt/static_modes_float.h @@ -0,0 +1,599 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f, +0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f, +0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f, +0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f, +0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f, +0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f, +0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f, +0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f, +0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f, +0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f, +0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f, +0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f, +0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f, +0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f, +0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f, +0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f, +0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f, +0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f, +0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f, +0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f, +0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f, +0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f, +0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f, +0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.0000000f, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, +82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, +41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, +41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, +318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, +305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, +240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, +31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, +51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, +66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, +64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, +94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, +124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, +97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, +142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, +28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, +153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, +229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, +166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, +86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, +25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, +185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, +110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, +74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, +163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, +228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, +90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, +87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, +106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, +224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, +182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, +178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, +240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, +160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, +138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, +204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, +185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, +207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, +188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, +204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, +140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{1.0000000f, -0.0000000f}, {0.99991433f, -0.013089596f}, +{0.99965732f, -0.026176948f}, {0.99922904f, -0.039259816f}, +{0.99862953f, -0.052335956f}, {0.99785892f, -0.065403129f}, +{0.99691733f, -0.078459096f}, {0.99580493f, -0.091501619f}, +{0.99452190f, -0.10452846f}, {0.99306846f, -0.11753740f}, +{0.99144486f, -0.13052619f}, {0.98965139f, -0.14349262f}, +{0.98768834f, -0.15643447f}, {0.98555606f, -0.16934950f}, +{0.98325491f, -0.18223553f}, {0.98078528f, -0.19509032f}, +{0.97814760f, -0.20791169f}, {0.97534232f, -0.22069744f}, +{0.97236992f, -0.23344536f}, {0.96923091f, -0.24615329f}, +{0.96592583f, -0.25881905f}, {0.96245524f, -0.27144045f}, +{0.95881973f, -0.28401534f}, {0.95501994f, -0.29654157f}, +{0.95105652f, -0.30901699f}, {0.94693013f, -0.32143947f}, +{0.94264149f, -0.33380686f}, {0.93819134f, -0.34611706f}, +{0.93358043f, -0.35836795f}, {0.92880955f, -0.37055744f}, +{0.92387953f, -0.38268343f}, {0.91879121f, -0.39474386f}, +{0.91354546f, -0.40673664f}, {0.90814317f, -0.41865974f}, +{0.90258528f, -0.43051110f}, {0.89687274f, -0.44228869f}, +{0.89100652f, -0.45399050f}, {0.88498764f, -0.46561452f}, +{0.87881711f, -0.47715876f}, {0.87249601f, -0.48862124f}, +{0.86602540f, -0.50000000f}, {0.85940641f, -0.51129309f}, +{0.85264016f, -0.52249856f}, {0.84572782f, -0.53361452f}, +{0.83867057f, -0.54463904f}, {0.83146961f, -0.55557023f}, +{0.82412619f, -0.56640624f}, {0.81664156f, -0.57714519f}, +{0.80901699f, -0.58778525f}, {0.80125381f, -0.59832460f}, +{0.79335334f, -0.60876143f}, {0.78531693f, -0.61909395f}, +{0.77714596f, -0.62932039f}, {0.76884183f, -0.63943900f}, +{0.76040597f, -0.64944805f}, {0.75183981f, -0.65934582f}, +{0.74314483f, -0.66913061f}, {0.73432251f, -0.67880075f}, +{0.72537437f, -0.68835458f}, {0.71630194f, -0.69779046f}, +{0.70710678f, -0.70710678f}, {0.69779046f, -0.71630194f}, +{0.68835458f, -0.72537437f}, {0.67880075f, -0.73432251f}, +{0.66913061f, -0.74314483f}, {0.65934582f, -0.75183981f}, +{0.64944805f, -0.76040597f}, {0.63943900f, -0.76884183f}, +{0.62932039f, -0.77714596f}, {0.61909395f, -0.78531693f}, +{0.60876143f, -0.79335334f}, {0.59832460f, -0.80125381f}, +{0.58778525f, -0.80901699f}, {0.57714519f, -0.81664156f}, +{0.56640624f, -0.82412619f}, {0.55557023f, -0.83146961f}, +{0.54463904f, -0.83867057f}, {0.53361452f, -0.84572782f}, +{0.52249856f, -0.85264016f}, {0.51129309f, -0.85940641f}, +{0.50000000f, -0.86602540f}, {0.48862124f, -0.87249601f}, +{0.47715876f, -0.87881711f}, {0.46561452f, -0.88498764f}, +{0.45399050f, -0.89100652f}, {0.44228869f, -0.89687274f}, +{0.43051110f, -0.90258528f}, {0.41865974f, -0.90814317f}, +{0.40673664f, -0.91354546f}, {0.39474386f, -0.91879121f}, +{0.38268343f, -0.92387953f}, {0.37055744f, -0.92880955f}, +{0.35836795f, -0.93358043f}, {0.34611706f, -0.93819134f}, +{0.33380686f, -0.94264149f}, {0.32143947f, -0.94693013f}, +{0.30901699f, -0.95105652f}, {0.29654157f, -0.95501994f}, +{0.28401534f, -0.95881973f}, {0.27144045f, -0.96245524f}, +{0.25881905f, -0.96592583f}, {0.24615329f, -0.96923091f}, +{0.23344536f, -0.97236992f}, {0.22069744f, -0.97534232f}, +{0.20791169f, -0.97814760f}, {0.19509032f, -0.98078528f}, +{0.18223553f, -0.98325491f}, {0.16934950f, -0.98555606f}, +{0.15643447f, -0.98768834f}, {0.14349262f, -0.98965139f}, +{0.13052619f, -0.99144486f}, {0.11753740f, -0.99306846f}, +{0.10452846f, -0.99452190f}, {0.091501619f, -0.99580493f}, +{0.078459096f, -0.99691733f}, {0.065403129f, -0.99785892f}, +{0.052335956f, -0.99862953f}, {0.039259816f, -0.99922904f}, +{0.026176948f, -0.99965732f}, {0.013089596f, -0.99991433f}, +{6.1230318e-17f, -1.0000000f}, {-0.013089596f, -0.99991433f}, +{-0.026176948f, -0.99965732f}, {-0.039259816f, -0.99922904f}, +{-0.052335956f, -0.99862953f}, {-0.065403129f, -0.99785892f}, +{-0.078459096f, -0.99691733f}, {-0.091501619f, -0.99580493f}, +{-0.10452846f, -0.99452190f}, {-0.11753740f, -0.99306846f}, +{-0.13052619f, -0.99144486f}, {-0.14349262f, -0.98965139f}, +{-0.15643447f, -0.98768834f}, {-0.16934950f, -0.98555606f}, +{-0.18223553f, -0.98325491f}, {-0.19509032f, -0.98078528f}, +{-0.20791169f, -0.97814760f}, {-0.22069744f, -0.97534232f}, +{-0.23344536f, -0.97236992f}, {-0.24615329f, -0.96923091f}, +{-0.25881905f, -0.96592583f}, {-0.27144045f, -0.96245524f}, +{-0.28401534f, -0.95881973f}, {-0.29654157f, -0.95501994f}, +{-0.30901699f, -0.95105652f}, {-0.32143947f, -0.94693013f}, +{-0.33380686f, -0.94264149f}, {-0.34611706f, -0.93819134f}, +{-0.35836795f, -0.93358043f}, {-0.37055744f, -0.92880955f}, +{-0.38268343f, -0.92387953f}, {-0.39474386f, -0.91879121f}, +{-0.40673664f, -0.91354546f}, {-0.41865974f, -0.90814317f}, +{-0.43051110f, -0.90258528f}, {-0.44228869f, -0.89687274f}, +{-0.45399050f, -0.89100652f}, {-0.46561452f, -0.88498764f}, +{-0.47715876f, -0.87881711f}, {-0.48862124f, -0.87249601f}, +{-0.50000000f, -0.86602540f}, {-0.51129309f, -0.85940641f}, +{-0.52249856f, -0.85264016f}, {-0.53361452f, -0.84572782f}, +{-0.54463904f, -0.83867057f}, {-0.55557023f, -0.83146961f}, +{-0.56640624f, -0.82412619f}, {-0.57714519f, -0.81664156f}, +{-0.58778525f, -0.80901699f}, {-0.59832460f, -0.80125381f}, +{-0.60876143f, -0.79335334f}, {-0.61909395f, -0.78531693f}, +{-0.62932039f, -0.77714596f}, {-0.63943900f, -0.76884183f}, +{-0.64944805f, -0.76040597f}, {-0.65934582f, -0.75183981f}, +{-0.66913061f, -0.74314483f}, {-0.67880075f, -0.73432251f}, +{-0.68835458f, -0.72537437f}, {-0.69779046f, -0.71630194f}, +{-0.70710678f, -0.70710678f}, {-0.71630194f, -0.69779046f}, +{-0.72537437f, -0.68835458f}, {-0.73432251f, -0.67880075f}, +{-0.74314483f, -0.66913061f}, {-0.75183981f, -0.65934582f}, +{-0.76040597f, -0.64944805f}, {-0.76884183f, -0.63943900f}, +{-0.77714596f, -0.62932039f}, {-0.78531693f, -0.61909395f}, +{-0.79335334f, -0.60876143f}, {-0.80125381f, -0.59832460f}, +{-0.80901699f, -0.58778525f}, {-0.81664156f, -0.57714519f}, +{-0.82412619f, -0.56640624f}, {-0.83146961f, -0.55557023f}, +{-0.83867057f, -0.54463904f}, {-0.84572782f, -0.53361452f}, +{-0.85264016f, -0.52249856f}, {-0.85940641f, -0.51129309f}, +{-0.86602540f, -0.50000000f}, {-0.87249601f, -0.48862124f}, +{-0.87881711f, -0.47715876f}, {-0.88498764f, -0.46561452f}, +{-0.89100652f, -0.45399050f}, {-0.89687274f, -0.44228869f}, +{-0.90258528f, -0.43051110f}, {-0.90814317f, -0.41865974f}, +{-0.91354546f, -0.40673664f}, {-0.91879121f, -0.39474386f}, +{-0.92387953f, -0.38268343f}, {-0.92880955f, -0.37055744f}, +{-0.93358043f, -0.35836795f}, {-0.93819134f, -0.34611706f}, +{-0.94264149f, -0.33380686f}, {-0.94693013f, -0.32143947f}, +{-0.95105652f, -0.30901699f}, {-0.95501994f, -0.29654157f}, +{-0.95881973f, -0.28401534f}, {-0.96245524f, -0.27144045f}, +{-0.96592583f, -0.25881905f}, {-0.96923091f, -0.24615329f}, +{-0.97236992f, -0.23344536f}, {-0.97534232f, -0.22069744f}, +{-0.97814760f, -0.20791169f}, {-0.98078528f, -0.19509032f}, +{-0.98325491f, -0.18223553f}, {-0.98555606f, -0.16934950f}, +{-0.98768834f, -0.15643447f}, {-0.98965139f, -0.14349262f}, +{-0.99144486f, -0.13052619f}, {-0.99306846f, -0.11753740f}, +{-0.99452190f, -0.10452846f}, {-0.99580493f, -0.091501619f}, +{-0.99691733f, -0.078459096f}, {-0.99785892f, -0.065403129f}, +{-0.99862953f, -0.052335956f}, {-0.99922904f, -0.039259816f}, +{-0.99965732f, -0.026176948f}, {-0.99991433f, -0.013089596f}, +{-1.0000000f, -1.2246064e-16f}, {-0.99991433f, 0.013089596f}, +{-0.99965732f, 0.026176948f}, {-0.99922904f, 0.039259816f}, +{-0.99862953f, 0.052335956f}, {-0.99785892f, 0.065403129f}, +{-0.99691733f, 0.078459096f}, {-0.99580493f, 0.091501619f}, +{-0.99452190f, 0.10452846f}, {-0.99306846f, 0.11753740f}, +{-0.99144486f, 0.13052619f}, {-0.98965139f, 0.14349262f}, +{-0.98768834f, 0.15643447f}, {-0.98555606f, 0.16934950f}, +{-0.98325491f, 0.18223553f}, {-0.98078528f, 0.19509032f}, +{-0.97814760f, 0.20791169f}, {-0.97534232f, 0.22069744f}, +{-0.97236992f, 0.23344536f}, {-0.96923091f, 0.24615329f}, +{-0.96592583f, 0.25881905f}, {-0.96245524f, 0.27144045f}, +{-0.95881973f, 0.28401534f}, {-0.95501994f, 0.29654157f}, +{-0.95105652f, 0.30901699f}, {-0.94693013f, 0.32143947f}, +{-0.94264149f, 0.33380686f}, {-0.93819134f, 0.34611706f}, +{-0.93358043f, 0.35836795f}, {-0.92880955f, 0.37055744f}, +{-0.92387953f, 0.38268343f}, {-0.91879121f, 0.39474386f}, +{-0.91354546f, 0.40673664f}, {-0.90814317f, 0.41865974f}, +{-0.90258528f, 0.43051110f}, {-0.89687274f, 0.44228869f}, +{-0.89100652f, 0.45399050f}, {-0.88498764f, 0.46561452f}, +{-0.87881711f, 0.47715876f}, {-0.87249601f, 0.48862124f}, +{-0.86602540f, 0.50000000f}, {-0.85940641f, 0.51129309f}, +{-0.85264016f, 0.52249856f}, {-0.84572782f, 0.53361452f}, +{-0.83867057f, 0.54463904f}, {-0.83146961f, 0.55557023f}, +{-0.82412619f, 0.56640624f}, {-0.81664156f, 0.57714519f}, +{-0.80901699f, 0.58778525f}, {-0.80125381f, 0.59832460f}, +{-0.79335334f, 0.60876143f}, {-0.78531693f, 0.61909395f}, +{-0.77714596f, 0.62932039f}, {-0.76884183f, 0.63943900f}, +{-0.76040597f, 0.64944805f}, {-0.75183981f, 0.65934582f}, +{-0.74314483f, 0.66913061f}, {-0.73432251f, 0.67880075f}, +{-0.72537437f, 0.68835458f}, {-0.71630194f, 0.69779046f}, +{-0.70710678f, 0.70710678f}, {-0.69779046f, 0.71630194f}, +{-0.68835458f, 0.72537437f}, {-0.67880075f, 0.73432251f}, +{-0.66913061f, 0.74314483f}, {-0.65934582f, 0.75183981f}, +{-0.64944805f, 0.76040597f}, {-0.63943900f, 0.76884183f}, +{-0.62932039f, 0.77714596f}, {-0.61909395f, 0.78531693f}, +{-0.60876143f, 0.79335334f}, {-0.59832460f, 0.80125381f}, +{-0.58778525f, 0.80901699f}, {-0.57714519f, 0.81664156f}, +{-0.56640624f, 0.82412619f}, {-0.55557023f, 0.83146961f}, +{-0.54463904f, 0.83867057f}, {-0.53361452f, 0.84572782f}, +{-0.52249856f, 0.85264016f}, {-0.51129309f, 0.85940641f}, +{-0.50000000f, 0.86602540f}, {-0.48862124f, 0.87249601f}, +{-0.47715876f, 0.87881711f}, {-0.46561452f, 0.88498764f}, +{-0.45399050f, 0.89100652f}, {-0.44228869f, 0.89687274f}, +{-0.43051110f, 0.90258528f}, {-0.41865974f, 0.90814317f}, +{-0.40673664f, 0.91354546f}, {-0.39474386f, 0.91879121f}, +{-0.38268343f, 0.92387953f}, {-0.37055744f, 0.92880955f}, +{-0.35836795f, 0.93358043f}, {-0.34611706f, 0.93819134f}, +{-0.33380686f, 0.94264149f}, {-0.32143947f, 0.94693013f}, +{-0.30901699f, 0.95105652f}, {-0.29654157f, 0.95501994f}, +{-0.28401534f, 0.95881973f}, {-0.27144045f, 0.96245524f}, +{-0.25881905f, 0.96592583f}, {-0.24615329f, 0.96923091f}, +{-0.23344536f, 0.97236992f}, {-0.22069744f, 0.97534232f}, +{-0.20791169f, 0.97814760f}, {-0.19509032f, 0.98078528f}, +{-0.18223553f, 0.98325491f}, {-0.16934950f, 0.98555606f}, +{-0.15643447f, 0.98768834f}, {-0.14349262f, 0.98965139f}, +{-0.13052619f, 0.99144486f}, {-0.11753740f, 0.99306846f}, +{-0.10452846f, 0.99452190f}, {-0.091501619f, 0.99580493f}, +{-0.078459096f, 0.99691733f}, {-0.065403129f, 0.99785892f}, +{-0.052335956f, 0.99862953f}, {-0.039259816f, 0.99922904f}, +{-0.026176948f, 0.99965732f}, {-0.013089596f, 0.99991433f}, +{-1.8369095e-16f, 1.0000000f}, {0.013089596f, 0.99991433f}, +{0.026176948f, 0.99965732f}, {0.039259816f, 0.99922904f}, +{0.052335956f, 0.99862953f}, {0.065403129f, 0.99785892f}, +{0.078459096f, 0.99691733f}, {0.091501619f, 0.99580493f}, +{0.10452846f, 0.99452190f}, {0.11753740f, 0.99306846f}, +{0.13052619f, 0.99144486f}, {0.14349262f, 0.98965139f}, +{0.15643447f, 0.98768834f}, {0.16934950f, 0.98555606f}, +{0.18223553f, 0.98325491f}, {0.19509032f, 0.98078528f}, +{0.20791169f, 0.97814760f}, {0.22069744f, 0.97534232f}, +{0.23344536f, 0.97236992f}, {0.24615329f, 0.96923091f}, +{0.25881905f, 0.96592583f}, {0.27144045f, 0.96245524f}, +{0.28401534f, 0.95881973f}, {0.29654157f, 0.95501994f}, +{0.30901699f, 0.95105652f}, {0.32143947f, 0.94693013f}, +{0.33380686f, 0.94264149f}, {0.34611706f, 0.93819134f}, +{0.35836795f, 0.93358043f}, {0.37055744f, 0.92880955f}, +{0.38268343f, 0.92387953f}, {0.39474386f, 0.91879121f}, +{0.40673664f, 0.91354546f}, {0.41865974f, 0.90814317f}, +{0.43051110f, 0.90258528f}, {0.44228869f, 0.89687274f}, +{0.45399050f, 0.89100652f}, {0.46561452f, 0.88498764f}, +{0.47715876f, 0.87881711f}, {0.48862124f, 0.87249601f}, +{0.50000000f, 0.86602540f}, {0.51129309f, 0.85940641f}, +{0.52249856f, 0.85264016f}, {0.53361452f, 0.84572782f}, +{0.54463904f, 0.83867057f}, {0.55557023f, 0.83146961f}, +{0.56640624f, 0.82412619f}, {0.57714519f, 0.81664156f}, +{0.58778525f, 0.80901699f}, {0.59832460f, 0.80125381f}, +{0.60876143f, 0.79335334f}, {0.61909395f, 0.78531693f}, +{0.62932039f, 0.77714596f}, {0.63943900f, 0.76884183f}, +{0.64944805f, 0.76040597f}, {0.65934582f, 0.75183981f}, +{0.66913061f, 0.74314483f}, {0.67880075f, 0.73432251f}, +{0.68835458f, 0.72537437f}, {0.69779046f, 0.71630194f}, +{0.70710678f, 0.70710678f}, {0.71630194f, 0.69779046f}, +{0.72537437f, 0.68835458f}, {0.73432251f, 0.67880075f}, +{0.74314483f, 0.66913061f}, {0.75183981f, 0.65934582f}, +{0.76040597f, 0.64944805f}, {0.76884183f, 0.63943900f}, +{0.77714596f, 0.62932039f}, {0.78531693f, 0.61909395f}, +{0.79335334f, 0.60876143f}, {0.80125381f, 0.59832460f}, +{0.80901699f, 0.58778525f}, {0.81664156f, 0.57714519f}, +{0.82412619f, 0.56640624f}, {0.83146961f, 0.55557023f}, +{0.83867057f, 0.54463904f}, {0.84572782f, 0.53361452f}, +{0.85264016f, 0.52249856f}, {0.85940641f, 0.51129309f}, +{0.86602540f, 0.50000000f}, {0.87249601f, 0.48862124f}, +{0.87881711f, 0.47715876f}, {0.88498764f, 0.46561452f}, +{0.89100652f, 0.45399050f}, {0.89687274f, 0.44228869f}, +{0.90258528f, 0.43051110f}, {0.90814317f, 0.41865974f}, +{0.91354546f, 0.40673664f}, {0.91879121f, 0.39474386f}, +{0.92387953f, 0.38268343f}, {0.92880955f, 0.37055744f}, +{0.93358043f, 0.35836795f}, {0.93819134f, 0.34611706f}, +{0.94264149f, 0.33380686f}, {0.94693013f, 0.32143947f}, +{0.95105652f, 0.30901699f}, {0.95501994f, 0.29654157f}, +{0.95881973f, 0.28401534f}, {0.96245524f, 0.27144045f}, +{0.96592583f, 0.25881905f}, {0.96923091f, 0.24615329f}, +{0.97236992f, 0.23344536f}, {0.97534232f, 0.22069744f}, +{0.97814760f, 0.20791169f}, {0.98078528f, 0.19509032f}, +{0.98325491f, 0.18223553f}, {0.98555606f, 0.16934950f}, +{0.98768834f, 0.15643447f}, {0.98965139f, 0.14349262f}, +{0.99144486f, 0.13052619f}, {0.99306846f, 0.11753740f}, +{0.99452190f, 0.10452846f}, {0.99580493f, 0.091501619f}, +{0.99691733f, 0.078459096f}, {0.99785892f, 0.065403129f}, +{0.99862953f, 0.052335956f}, {0.99922904f, 0.039259816f}, +{0.99965732f, 0.026176948f}, {0.99991433f, 0.013089596f}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +0, 120, 240, 360, 30, 150, 270, 390, 60, 180, 300, 420, 90, 210, 330, +450, 15, 135, 255, 375, 45, 165, 285, 405, 75, 195, 315, 435, 105, 225, +345, 465, 5, 125, 245, 365, 35, 155, 275, 395, 65, 185, 305, 425, 95, +215, 335, 455, 20, 140, 260, 380, 50, 170, 290, 410, 80, 200, 320, 440, +110, 230, 350, 470, 10, 130, 250, 370, 40, 160, 280, 400, 70, 190, 310, +430, 100, 220, 340, 460, 25, 145, 265, 385, 55, 175, 295, 415, 85, 205, +325, 445, 115, 235, 355, 475, 1, 121, 241, 361, 31, 151, 271, 391, 61, +181, 301, 421, 91, 211, 331, 451, 16, 136, 256, 376, 46, 166, 286, 406, +76, 196, 316, 436, 106, 226, 346, 466, 6, 126, 246, 366, 36, 156, 276, +396, 66, 186, 306, 426, 96, 216, 336, 456, 21, 141, 261, 381, 51, 171, +291, 411, 81, 201, 321, 441, 111, 231, 351, 471, 11, 131, 251, 371, 41, +161, 281, 401, 71, 191, 311, 431, 101, 221, 341, 461, 26, 146, 266, 386, +56, 176, 296, 416, 86, 206, 326, 446, 116, 236, 356, 476, 2, 122, 242, +362, 32, 152, 272, 392, 62, 182, 302, 422, 92, 212, 332, 452, 17, 137, +257, 377, 47, 167, 287, 407, 77, 197, 317, 437, 107, 227, 347, 467, 7, +127, 247, 367, 37, 157, 277, 397, 67, 187, 307, 427, 97, 217, 337, 457, +22, 142, 262, 382, 52, 172, 292, 412, 82, 202, 322, 442, 112, 232, 352, +472, 12, 132, 252, 372, 42, 162, 282, 402, 72, 192, 312, 432, 102, 222, +342, 462, 27, 147, 267, 387, 57, 177, 297, 417, 87, 207, 327, 447, 117, +237, 357, 477, 3, 123, 243, 363, 33, 153, 273, 393, 63, 183, 303, 423, +93, 213, 333, 453, 18, 138, 258, 378, 48, 168, 288, 408, 78, 198, 318, +438, 108, 228, 348, 468, 8, 128, 248, 368, 38, 158, 278, 398, 68, 188, +308, 428, 98, 218, 338, 458, 23, 143, 263, 383, 53, 173, 293, 413, 83, +203, 323, 443, 113, 233, 353, 473, 13, 133, 253, 373, 43, 163, 283, 403, +73, 193, 313, 433, 103, 223, 343, 463, 28, 148, 268, 388, 58, 178, 298, +418, 88, 208, 328, 448, 118, 238, 358, 478, 4, 124, 244, 364, 34, 154, +274, 394, 64, 184, 304, 424, 94, 214, 334, 454, 19, 139, 259, 379, 49, +169, 289, 409, 79, 199, 319, 439, 109, 229, 349, 469, 9, 129, 249, 369, +39, 159, 279, 399, 69, 189, 309, 429, 99, 219, 339, 459, 24, 144, 264, +384, 54, 174, 294, 414, 84, 204, 324, 444, 114, 234, 354, 474, 14, 134, +254, 374, 44, 164, 284, 404, 74, 194, 314, 434, 104, 224, 344, 464, 29, +149, 269, 389, 59, 179, 299, 419, 89, 209, 329, 449, 119, 239, 359, 479, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +0, 60, 120, 180, 15, 75, 135, 195, 30, 90, 150, 210, 45, 105, 165, +225, 5, 65, 125, 185, 20, 80, 140, 200, 35, 95, 155, 215, 50, 110, +170, 230, 10, 70, 130, 190, 25, 85, 145, 205, 40, 100, 160, 220, 55, +115, 175, 235, 1, 61, 121, 181, 16, 76, 136, 196, 31, 91, 151, 211, +46, 106, 166, 226, 6, 66, 126, 186, 21, 81, 141, 201, 36, 96, 156, +216, 51, 111, 171, 231, 11, 71, 131, 191, 26, 86, 146, 206, 41, 101, +161, 221, 56, 116, 176, 236, 2, 62, 122, 182, 17, 77, 137, 197, 32, +92, 152, 212, 47, 107, 167, 227, 7, 67, 127, 187, 22, 82, 142, 202, +37, 97, 157, 217, 52, 112, 172, 232, 12, 72, 132, 192, 27, 87, 147, +207, 42, 102, 162, 222, 57, 117, 177, 237, 3, 63, 123, 183, 18, 78, +138, 198, 33, 93, 153, 213, 48, 108, 168, 228, 8, 68, 128, 188, 23, +83, 143, 203, 38, 98, 158, 218, 53, 113, 173, 233, 13, 73, 133, 193, +28, 88, 148, 208, 43, 103, 163, 223, 58, 118, 178, 238, 4, 64, 124, +184, 19, 79, 139, 199, 34, 94, 154, 214, 49, 109, 169, 229, 9, 69, +129, 189, 24, 84, 144, 204, 39, 99, 159, 219, 54, 114, 174, 234, 14, +74, 134, 194, 29, 89, 149, 209, 44, 104, 164, 224, 59, 119, 179, 239, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +0, 30, 60, 90, 15, 45, 75, 105, 5, 35, 65, 95, 20, 50, 80, +110, 10, 40, 70, 100, 25, 55, 85, 115, 1, 31, 61, 91, 16, 46, +76, 106, 6, 36, 66, 96, 21, 51, 81, 111, 11, 41, 71, 101, 26, +56, 86, 116, 2, 32, 62, 92, 17, 47, 77, 107, 7, 37, 67, 97, +22, 52, 82, 112, 12, 42, 72, 102, 27, 57, 87, 117, 3, 33, 63, +93, 18, 48, 78, 108, 8, 38, 68, 98, 23, 53, 83, 113, 13, 43, +73, 103, 28, 58, 88, 118, 4, 34, 64, 94, 19, 49, 79, 109, 9, +39, 69, 99, 24, 54, 84, 114, 14, 44, 74, 104, 29, 59, 89, 119, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +0, 15, 30, 45, 5, 20, 35, 50, 10, 25, 40, 55, 1, 16, 31, +46, 6, 21, 36, 51, 11, 26, 41, 56, 2, 17, 32, 47, 7, 22, +37, 52, 12, 27, 42, 57, 3, 18, 33, 48, 8, 23, 38, 53, 13, +28, 43, 58, 4, 19, 34, 49, 9, 24, 39, 54, 14, 29, 44, 59, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +0.002083333f, /* scale */ +-1, /* shift */ +{4, 120, 4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +0.004166667f, /* scale */ +1, /* shift */ +{4, 60, 4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +0.008333333f, /* scale */ +2, /* shift */ +{4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +0.016666667f, /* scale */ +3, /* shift */ +{4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[481] = { +1.0000000f, 0.99999465f, 0.99997858f, 0.99995181f, 0.99991433f, +0.99986614f, 0.99980724f, 0.99973764f, 0.99965732f, 0.99956631f, +0.99946459f, 0.99935216f, 0.99922904f, 0.99909521f, 0.99895068f, +0.99879546f, 0.99862953f, 0.99845292f, 0.99826561f, 0.99806761f, +0.99785892f, 0.99763955f, 0.99740949f, 0.99716875f, 0.99691733f, +0.99665524f, 0.99638247f, 0.99609903f, 0.99580493f, 0.99550016f, +0.99518473f, 0.99485864f, 0.99452190f, 0.99417450f, 0.99381646f, +0.99344778f, 0.99306846f, 0.99267850f, 0.99227791f, 0.99186670f, +0.99144486f, 0.99101241f, 0.99056934f, 0.99011566f, 0.98965139f, +0.98917651f, 0.98869104f, 0.98819498f, 0.98768834f, 0.98717112f, +0.98664333f, 0.98610497f, 0.98555606f, 0.98499659f, 0.98442657f, +0.98384600f, 0.98325491f, 0.98265328f, 0.98204113f, 0.98141846f, +0.98078528f, 0.98014159f, 0.97948742f, 0.97882275f, 0.97814760f, +0.97746197f, 0.97676588f, 0.97605933f, 0.97534232f, 0.97461487f, +0.97387698f, 0.97312866f, 0.97236992f, 0.97160077f, 0.97082121f, +0.97003125f, 0.96923091f, 0.96842019f, 0.96759909f, 0.96676764f, +0.96592582f, 0.96507367f, 0.96421118f, 0.96333837f, 0.96245523f, +0.96156180f, 0.96065806f, 0.95974403f, 0.95881973f, 0.95788517f, +0.95694034f, 0.95598526f, 0.95501995f, 0.95404440f, 0.95305864f, +0.95206267f, 0.95105651f, 0.95004016f, 0.94901364f, 0.94797697f, +0.94693013f, 0.94587315f, 0.94480604f, 0.94372882f, 0.94264149f, +0.94154406f, 0.94043656f, 0.93931897f, 0.93819133f, 0.93705365f, +0.93590592f, 0.93474818f, 0.93358042f, 0.93240268f, 0.93121493f, +0.93001722f, 0.92880955f, 0.92759193f, 0.92636438f, 0.92512690f, +0.92387953f, 0.92262225f, 0.92135509f, 0.92007809f, 0.91879121f, +0.91749449f, 0.91618795f, 0.91487161f, 0.91354545f, 0.91220952f, +0.91086382f, 0.90950836f, 0.90814316f, 0.90676824f, 0.90538363f, +0.90398929f, 0.90258528f, 0.90117161f, 0.89974828f, 0.89831532f, +0.89687273f, 0.89542055f, 0.89395877f, 0.89248742f, 0.89100652f, +0.88951606f, 0.88801610f, 0.88650661f, 0.88498764f, 0.88345918f, +0.88192125f, 0.88037390f, 0.87881711f, 0.87725090f, 0.87567531f, +0.87409035f, 0.87249599f, 0.87089232f, 0.86927933f, 0.86765699f, +0.86602540f, 0.86438453f, 0.86273437f, 0.86107503f, 0.85940641f, +0.85772862f, 0.85604161f, 0.85434547f, 0.85264014f, 0.85092572f, +0.84920218f, 0.84746955f, 0.84572781f, 0.84397704f, 0.84221721f, +0.84044838f, 0.83867056f, 0.83688375f, 0.83508799f, 0.83328325f, +0.83146961f, 0.82964704f, 0.82781562f, 0.82597530f, 0.82412620f, +0.82226820f, 0.82040144f, 0.81852589f, 0.81664154f, 0.81474847f, +0.81284665f, 0.81093620f, 0.80901698f, 0.80708914f, 0.80515262f, +0.80320752f, 0.80125378f, 0.79929149f, 0.79732067f, 0.79534125f, +0.79335335f, 0.79135691f, 0.78935204f, 0.78733867f, 0.78531691f, +0.78328674f, 0.78124818f, 0.77920122f, 0.77714595f, 0.77508232f, +0.77301043f, 0.77093026f, 0.76884183f, 0.76674517f, 0.76464026f, +0.76252720f, 0.76040593f, 0.75827656f, 0.75613907f, 0.75399349f, +0.75183978f, 0.74967807f, 0.74750833f, 0.74533054f, 0.74314481f, +0.74095112f, 0.73874950f, 0.73653993f, 0.73432251f, 0.73209718f, +0.72986405f, 0.72762307f, 0.72537438f, 0.72311787f, 0.72085359f, +0.71858162f, 0.71630192f, 0.71401459f, 0.71171956f, 0.70941701f, +0.70710677f, 0.70478900f, 0.70246363f, 0.70013079f, 0.69779041f, +0.69544260f, 0.69308738f, 0.69072466f, 0.68835458f, 0.68597709f, +0.68359229f, 0.68120013f, 0.67880072f, 0.67639404f, 0.67398011f, +0.67155892f, 0.66913059f, 0.66669509f, 0.66425240f, 0.66180265f, +0.65934581f, 0.65688191f, 0.65441092f, 0.65193298f, 0.64944801f, +0.64695613f, 0.64445727f, 0.64195160f, 0.63943902f, 0.63691954f, +0.63439328f, 0.63186019f, 0.62932037f, 0.62677377f, 0.62422055f, +0.62166055f, 0.61909394f, 0.61652065f, 0.61394081f, 0.61135435f, +0.60876139f, 0.60616195f, 0.60355593f, 0.60094349f, 0.59832457f, +0.59569929f, 0.59306758f, 0.59042957f, 0.58778523f, 0.58513460f, +0.58247766f, 0.57981452f, 0.57714518f, 0.57446961f, 0.57178793f, +0.56910013f, 0.56640624f, 0.56370623f, 0.56100023f, 0.55828818f, +0.55557020f, 0.55284627f, 0.55011641f, 0.54738067f, 0.54463901f, +0.54189157f, 0.53913828f, 0.53637921f, 0.53361450f, 0.53084398f, +0.52806787f, 0.52528601f, 0.52249852f, 0.51970543f, 0.51690688f, +0.51410279f, 0.51129310f, 0.50847793f, 0.50565732f, 0.50283139f, +0.49999997f, 0.49716321f, 0.49432122f, 0.49147383f, 0.48862118f, +0.48576340f, 0.48290042f, 0.48003216f, 0.47715876f, 0.47428025f, +0.47139677f, 0.46850813f, 0.46561448f, 0.46271584f, 0.45981235f, +0.45690383f, 0.45399042f, 0.45107214f, 0.44814915f, 0.44522124f, +0.44228868f, 0.43935137f, 0.43640926f, 0.43346247f, 0.43051104f, +0.42755511f, 0.42459449f, 0.42162932f, 0.41865964f, 0.41568558f, +0.41270697f, 0.40972393f, 0.40673661f, 0.40374494f, 0.40074884f, +0.39774844f, 0.39474390f, 0.39173501f, 0.38872193f, 0.38570469f, +0.38268343f, 0.37965796f, 0.37662842f, 0.37359496f, 0.37055739f, +0.36751585f, 0.36447038f, 0.36142122f, 0.35836797f, 0.35531089f, +0.35225000f, 0.34918544f, 0.34611704f, 0.34304493f, 0.33996926f, +0.33688983f, 0.33380680f, 0.33072019f, 0.32763015f, 0.32453650f, +0.32143936f, 0.31833890f, 0.31523503f, 0.31212767f, 0.30901696f, +0.30590306f, 0.30278577f, 0.29966524f, 0.29654150f, 0.29341470f, +0.29028464f, 0.28715147f, 0.28401522f, 0.28087605f, 0.27773376f, +0.27458861f, 0.27144052f, 0.26828940f, 0.26513541f, 0.26197859f, +0.25881907f, 0.25565666f, 0.25249152f, 0.24932367f, 0.24615327f, +0.24298012f, 0.23980436f, 0.23662604f, 0.23344530f, 0.23026206f, +0.22707623f, 0.22388809f, 0.22069744f, 0.21750443f, 0.21430908f, +0.21111156f, 0.20791165f, 0.20470953f, 0.20150520f, 0.19829884f, +0.19509024f, 0.19187955f, 0.18866692f, 0.18545227f, 0.18223552f, +0.17901681f, 0.17579631f, 0.17257380f, 0.16934945f, 0.16612328f, +0.16289546f, 0.15966577f, 0.15643437f, 0.15320141f, 0.14996669f, +0.14673037f, 0.14349260f, 0.14025329f, 0.13701235f, 0.13376995f, +0.13052612f, 0.12728101f, 0.12403442f, 0.12078650f, 0.11753740f, +0.11428693f, 0.11103523f, 0.10778234f, 0.10452842f, 0.10127326f, +0.098017137f, 0.094759842f, 0.091501652f, 0.088242363f, 0.084982129f, +0.081721103f, 0.078459084f, 0.075196224f, 0.071932560f, 0.068668243f, +0.065403073f, 0.062137201f, 0.058870665f, 0.055603617f, 0.052335974f, +0.049067651f, 0.045798921f, 0.042529582f, 0.039259788f, 0.035989573f, +0.032719092f, 0.029448142f, 0.026176876f, 0.022905329f, 0.019633657f, +0.016361655f, 0.013089478f, 0.0098171604f, 0.0065449764f, 0.0032724839f, +-4.3711390e-08f, }; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{0.85000610f, 0.0000000f, 1.0000000f, 1.0000000f, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/media/libopus/celt/vq.c b/media/libopus/celt/vq.c new file mode 100644 index 000000000000..c743f9d74d32 --- /dev/null +++ b/media/libopus/celt/vq.c @@ -0,0 +1,431 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "cwrs.h" +#include "vq.h" +#include "arch.h" +#include "os_support.h" +#include "bands.h" +#include "rate.h" + +static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s) +{ + int i; + celt_norm *Xptr; + Xptr = X; + for (i=0;i=0;i--) + { + celt_norm x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(SHR32(MULT16_16(c,x2) + MULT16_16(s,x1), 15)); + *Xptr-- = EXTRACT16(SHR32(MULT16_16(c,x1) - MULT16_16(s,x2), 15)); + } +} + +static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread) +{ + static const int SPREAD_FACTOR[3]={15,10,5}; + int i; + opus_val16 c, s; + opus_val16 gain, theta; + int stride2=0; + int factor; + /*int i; + if (len>=30) + { + for (i=0;i=len || spread==SPREAD_NONE) + return; + factor = SPREAD_FACTOR[spread-1]; + + gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K)); + theta = HALF16(MULT16_16_Q15(gain,gain)); + + c = celt_cos_norm(EXTEND32(theta)); + s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */ + + if (len>=8*stride) + { + stride2 = 1; + /* This is just a simple way of computing sqrt(len/stride) with rounding. + It's basically incrementing long as (stride2+0.5)^2 < len/stride. + I _think_ it is bit-exact */ + while ((stride2*stride2+stride2)*stride + (stride>>2) < len) + stride2++; + } + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + extract_collapse_mask().*/ + len /= stride; + for (i=0;i=30) + { + for (i=0;i>1; +#endif + t = VSHR32(Ryy, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + i=0; + do + X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1)); + while (++i < N); +} + +static unsigned extract_collapse_mask(int *iy, int N, int B) +{ + unsigned collapse_mask; + int N0; + int i; + if (B<=1) + return 1; + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + exp_rotation().*/ + N0 = N/B; + collapse_mask = 0; + i=0; do { + int j; + j=0; do { + collapse_mask |= (iy[i*N0+j]!=0)<0, "alg_quant() needs at least one pulse"); + celt_assert2(N>1, "alg_quant() needs at least two dimensions"); + + ALLOC(y, N, celt_norm); + ALLOC(iy, N, int); + ALLOC(signx, N, opus_val16); + + exp_rotation(X, N, 1, B, K, spread); + + /* Get rid of the sign */ + sum = 0; + j=0; do { + if (X[j]>0) + signx[j]=1; + else { + signx[j]=-1; + X[j]=-X[j]; + } + iy[j] = 0; + y[j] = 0; + } while (++j (N>>1)) + { + opus_val16 rcp; + j=0; do { + sum += X[j]; + } while (++j EPSILON && sum < 64)) +#endif + { + X[0] = QCONST16(1.f,14); + j=1; do + X[j]=0; + while (++j=1, "Allocated too many pulses in the quick pass"); + + /* This should never happen, but just in case it does (e.g. on silence) + we fill the first bin with pulses. */ +#ifdef FIXED_POINT_DEBUG + celt_assert2(pulsesLeft<=N+3, "Not enough pulses in the quick pass"); +#endif + if (pulsesLeft > N+3) + { + opus_val16 tmp = (opus_val16)pulsesLeft; + yy = MAC16_16(yy, tmp, tmp); + yy = MAC16_16(yy, tmp, y[0]); + iy[0] += pulsesLeft; + pulsesLeft=0; + } + + s = 1; + for (i=0;i= best_num/best_den, but that way + we can do it without any division */ + /* OPT: Make sure to use conditional moves here */ + if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num)) + { + best_den = Ryy; + best_num = Rxy; + best_id = j; + } + } while (++j0, "alg_unquant() needs at least one pulse"); + celt_assert2(N>1, "alg_unquant() needs at least two dimensions"); + ALLOC(iy, N, int); + decode_pulses(iy, N, K, dec); + Ryy = 0; + i=0; + do { + Ryy = MAC16_16(Ryy, iy[i], iy[i]); + } while (++i < N); + normalise_residual(iy, X, N, Ryy, gain); + exp_rotation(X, N, -1, B, K, spread); + collapse_mask = extract_collapse_mask(iy, N, B); + RESTORE_STACK; + return collapse_mask; +} + +void renormalise_vector(celt_norm *X, int N, opus_val16 gain) +{ + int i; +#ifdef FIXED_POINT + int k; +#endif + opus_val32 E = EPSILON; + opus_val16 g; + opus_val32 t; + celt_norm *xptr = X; + for (i=0;i>1; +#endif + t = VSHR32(E, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + xptr = X; + for (i=0;i + *

  • audio_frame is the audio data in opus_int16 (or float for opus_encode_float())
  • + *
  • frame_size is the duration of the frame in samples (per channel)
  • + *
  • packet is the byte array to which the compressed data is written
  • + *
  • max_packet is the maximum number of bytes that can be written in the packet (1276 bytes is recommended)
  • + * + * + * opus_encode() and opus_encode_frame() return the number of bytes actually written to the packet. + * The return value can be negative, which indicates that an error has occurred. If the return value + * is 1 byte, then the packet does not need to be transmitted (DTX). + * + * Once the encoder state if no longer needed, it can be destroyed with + * + * @code + * opus_encoder_destroy(enc); + * @endcode + * + * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(), + * then no action is required aside from potentially freeing the memory that was manually + * allocated for it (calling free(enc) for the example above) + * + */ + +/** Opus encoder state. + * This contains the complete state of an Opus encoder. + * It is position independent and can be freely copied. + * @see opus_encoder_create,opus_encoder_init + */ +typedef struct OpusEncoder OpusEncoder; + +OPUS_EXPORT int opus_encoder_get_size(int channels); + +/** + */ + +/** Allocates and initializes an encoder state. + * There are three coding modes: + * + * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice + * signals. It enhances the input signal by high-pass filtering and + * emphasizing formants and harmonics. Optionally it includes in-band + * forward error correction to protect against packet loss. Use this + * mode for typical VoIP applications. Because of the enhancement, + * even at high bitrates the output may sound different from the input. + * + * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most + * non-voice signals like music. Use this mode for music and mixed + * (music/voice) content, broadcast, and applications requiring less + * than 15 ms of coding delay. + * + * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that + * disables the speech-optimized mode in exchange for slightly reduced delay. + * + * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution). + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * @param [in] channels int: Number of channels (1/2) in input signal + * @param [in] application int: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @param [out] error int*: @ref errorcodes + * @note Regardless of the sampling rate and number channels selected, the Opus encoder + * can switch to a lower audio audio bandwidth or number of channels if the bitrate + * selected is too low. This also means that it is safe to always use 48 kHz stereo input + * and let the encoder optimize the encoding. + */ +OPUS_EXPORT OpusEncoder *opus_encoder_create( + opus_int32 Fs, + int channels, + int application, + int *error +); + +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be the size returned by opus_encoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_encoder_create(),opus_encoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * @param [in] channels int: Number of channels (1/2) in input signal + * @param [in] application int: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @retval OPUS_OK Success or @ref errorcodes + */ +OPUS_EXPORT int opus_encoder_init( + OpusEncoder *st, + opus_int32 Fs, + int channels, + int application +); + +/** Encodes an Opus frame. + * The passed frame_size must an opus frame size for the encoder's sampling rate. + * For example, at 48kHz the permitted values are 120, 240, 480, or 960. + * Passing in a duration of less than 10ms (480 samples at 48kHz) will + * prevent the encoder from using the LPC or hybrid modes. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm opus_int16*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] data char*: Output payload (at least max_data_bytes long) + * @param [in] max_data_bytes int: Allocated memory for payload; don't use for controlling bitrate + * @returns length of the data payload (in bytes) or @ref errorcodes + */ +OPUS_EXPORT int opus_encode( + OpusEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + int max_data_bytes +); + +/** Encodes an Opus frame from floating point input. + * The passed frame_size must an opus frame size for the encoder's sampling rate. + * For example, at 48kHz the permitted values are 120, 240, 480, or 960. + * Passing in a duration of less than 10ms (480 samples at 48kHz) will + * prevent the encoder from using the LPC or hybrid modes. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm float*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(float) + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] data char*: Output payload (at least max_data_bytes long) + * @param [in] max_data_bytes int: Allocated memory for payload; don't use for controlling bitrate + * @returns length of the data payload (in bytes) or @ref errorcodes + */ +OPUS_EXPORT int opus_encode_float( + OpusEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + int max_data_bytes +); + +/** Frees an OpusEncoder allocated by opus_encoder_create. + * @param[in] st OpusEncoder*: State to be freed. + */ +OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st); + +/** Perform a CTL function on an Opus encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see encoderctls + */ +OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...); +/**@}*/ + +/** @defgroup opusdecoder Opus Decoder + * @{ + * + * + * The decoding process also starts with creating a decoder + * state. This can be done with: + * @code + * int error; + * OpusDecoder *dec; + * dec = opus_decoder_create(Fs, channels, &error); + * @endcode + * where + * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000 + * @li channels is the number of channels (1 or 2) + * @li error will hold the error code in case or failure (or OPUS_OK on success) + * @li the return value is a newly created decoder state to be used for decoding + * + * While opus_decoder_create() allocates memory for the state, it's also possible + * to initialize pre-allocated memory: + * @code + * int size; + * int error; + * OpusDecoder *dec; + * size = opus_decoder_get_size(channels); + * dec = malloc(size); + * error = opus_decoder_init(dec, Fs, channels); + * @endcode + * where opus_decoder_get_size() returns the required size for the decoder state. Note that + * future versions of this code may change the size, so no assuptions should be made about it. + * + * The decoder state is always continuous in memory and only a shallow copy is sufficient + * to copy it (e.g. memcpy()) + * + * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data: + * @code + * frame_size = opus_decode(enc, packet, len, decoded, max_size); + * @endcode + * where + * + * @li packet is the byte array containing the compressed data + * @li len is the exact number of bytes contained in the packet + * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float()) + * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array + * + * opus_decode() and opus_decode_frame() return the number of samples ()per channel) decoded from the packet. + * If that value is negative, then an error has occured. This can occur if the packet is corrupted or if the audio + * buffer is too small to hold the decoded audio. + +*/ + +/** Opus decoder state. + * This contains the complete state of an Opus decoder. + * It is position independent and can be freely copied. + * @see opus_decoder_create,opus_decoder_init + */ +typedef struct OpusDecoder OpusDecoder; + +/** Gets the size of an OpusDecoder structure. + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_EXPORT int opus_decoder_get_size(int channels); + +/** Allocates and initializes a decoder state. + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * @param [in] channels int: Number of channels (1/2) in input signal + * @param [out] error int*: OPUS_OK Success or @ref errorcodes + */ +OPUS_EXPORT OpusDecoder *opus_decoder_create( + opus_int32 Fs, + int channels, + int *error +); + +/** Initializes a previously allocated decoder state. + * The state must be the size returned by opus_decoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusDecoder*: Decoder state. + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * @param [in] channels int: Number of channels (1/2) in input signal + * @retval OPUS_OK Success or @ref errorcodes + */ +OPUS_EXPORT int opus_decoder_init( + OpusDecoder *st, + opus_int32 Fs, + int channels +); + +/** Decode an Opus frame + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload* + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in *pcm, + * if less than the maximum frame size (120ms) some frames can not be decoded + * @param [in] decode_fec int: Flag (0/1) to request that any in-band forward error correction data be + * decoded. If no such data is available the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref errorcodes + */ +OPUS_EXPORT int opus_decode( + OpusDecoder *st, + const unsigned char *data, + int len, + opus_int16 *pcm, + int frame_size, + int decode_fec +); + +/** Decode an opus frame with floating point output + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in *pcm, + * if less than the maximum frame size (120ms) some frames can not be decoded + * @param [in] decode_fec int: Flag (0/1) to request that any in-band forward error correction data be + * decoded. If no such data is available the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref errorcodes + */ +OPUS_EXPORT int opus_decode_float( + OpusDecoder *st, + const unsigned char *data, + int len, + float *pcm, + int frame_size, + int decode_fec +); + +/** Perform a CTL function on an Opus decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see genericctls + */ +OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...); + +/** Frees an OpusDecoder allocated by opus_decoder_create. + * @param[in] st OpusDecoder*: State to be freed. + */ +OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st); + +/** Parse an opus packet into one or more frames. + * Opus_decode will perform this operation internally so most applications do + * not need to use this function. + * This function does not copy the frames, the returned pointers are pointers into + * the input packet. + * @param [in] data char*: Opus packet to be parsed + * @param [in] len int: size of data + * @param [out] out_toc char*: TOC pointer + * @param [out] frames char*[48] encapsulated frames + * @param [out] size short[48] sizes of the encapsulated frames + * @param [out] payload_offset int*: returns the position of the payload within the packet (in bytes) + * @returns number of frames + */ +OPUS_EXPORT int opus_packet_parse( + const unsigned char *data, + int len, + unsigned char *out_toc, + const unsigned char *frames[48], + short size[48], + int *payload_offset +); + +/** Gets the bandwidth of an Opus packet. + * @param [in] data char*: Opus packet + * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass) + * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass) + * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass) + * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass) + * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass) + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT int opus_packet_get_bandwidth(const unsigned char *data); + +/** Gets the number of samples per frame from an Opus packet. + * @param [in] data char*: Opus packet + * @param [in] Fs opus_int32: Sampling rate in Hz + * @returns Number of samples per frame + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs); + +/** Gets the number of channels from an Opus packet. + * @param [in] data char*: Opus packet + * @returns Number of channels + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT int opus_packet_get_nb_channels(const unsigned char *data); + +/** Gets the number of frames in an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len int: Length of packet + * @returns Number of frames + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT int opus_packet_get_nb_frames(const unsigned char packet[], int len); + +/** Gets the number of samples of an Opus packet. + * @param [in] dec OpusDecoder*: Decoder state + * @param [in] packet char*: Opus packet + * @param [in] len int: Length of packet + * @returns Number of samples + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], int len); +/**@}*/ + +/** @defgroup repacketizer Repacketizer + * @{ + * + * The repacketizer can be used to merge multiple Opus packets into a single packet + * or alternatively to split Opus packets that have previously been merged. + * + */ + +typedef struct OpusRepacketizer OpusRepacketizer; + +OPUS_EXPORT int opus_repacketizer_get_size(void); + +OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp); + +OPUS_EXPORT OpusRepacketizer *opus_repacketizer_create(void); + +OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp); + +OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, int len); + +OPUS_EXPORT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, int maxlen); + +OPUS_EXPORT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp); + +OPUS_EXPORT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, int maxlen); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_H */ diff --git a/media/libopus/include/opus_custom.h b/media/libopus/include/opus_custom.h new file mode 100644 index 000000000000..a497d79087c1 --- /dev/null +++ b/media/libopus/include/opus_custom.h @@ -0,0 +1,213 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/** + @file celt.h + @brief Contains all the functions for encoding and decoding audio + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OPUS_CUSTOM_H +#define OPUS_CUSTOM_H + + +#include "opus_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CUSTOM_MODES +#define OPUS_CUSTOM_EXPORT OPUS_EXPORT +#define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT +#else +#define OPUS_CUSTOM_EXPORT +#ifdef CELT_C +#define OPUS_CUSTOM_EXPORT_STATIC static inline +#else +#define OPUS_CUSTOM_EXPORT_STATIC +#endif +#endif + +/** Contains the state of an encoder. One encoder state is needed + for each stream. It is initialised once at the beginning of the + stream. Do *not* re-initialise the state for every frame. + @brief Encoder state + */ +typedef struct OpusCustomEncoder OpusCustomEncoder; + +/** State of the decoder. One decoder state is needed for each stream. + It is initialised once at the beginning of the stream. Do *not* + re-initialise the state for every frame */ +typedef struct OpusCustomDecoder OpusCustomDecoder; + +/** The mode contains all the information necessary to create an + encoder. Both the encoder and decoder need to be initialised + with exactly the same mode, otherwise the quality will be very + bad */ +typedef struct OpusCustomMode OpusCustomMode; + +/** Creates a new mode struct. This will be passed to an encoder or + decoder. The mode MUST NOT BE DESTROYED until the encoders and + decoders that use it are destroyed as well. + @param Fs Sampling rate (32000 to 96000 Hz) + @param frame_size Number of samples (per channel) to encode in each + packet (even values; 64 - 512) + @param error Returned error code (if NULL, no error will be returned) + @return A newly created mode +*/ +OPUS_CUSTOM_EXPORT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error); + +/** Destroys a mode struct. Only call this after all encoders and + decoders using this mode are destroyed as well. + @param mode Mode to be destroyed +*/ +OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode); + +/* Encoder */ + +OPUS_CUSTOM_EXPORT_STATIC int opus_custom_encoder_get_size(const OpusCustomMode *mode, int channels); + +/** Creates a new encoder state. Each stream needs its own encoder + state (can't be shared across simultaneous streams). + @param mode Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + @param channels Number of channels + @param error Returns an error code + @return Newly created encoder state. +*/ +OPUS_CUSTOM_EXPORT OpusCustomEncoder *opus_custom_encoder_create(const OpusCustomMode *mode, int channels, int *error); + +OPUS_CUSTOM_EXPORT_STATIC int opus_custom_encoder_init(OpusCustomEncoder *st, const OpusCustomMode *mode, int channels); + +/** Destroys a an encoder state. + @param st Encoder state to be destroyed + */ +OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st); + +/** Encodes a frame of audio. + @param st Encoder state + @param pcm PCM audio in float format, with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynmaic range. There must be exactly + * frame_size samples per channel. + @param compressed The compressed data is written here. This may not alias pcm or + * optional_synthesis. + @param nbCompressedBytes Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + @return Number of bytes written to "compressed". Will be the same as + * "nbCompressedBytes" unless the stream is VBR and will never be larger. + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. +*/ +OPUS_CUSTOM_EXPORT int opus_custom_encode_float(OpusCustomEncoder *st, const float *pcm, int frame_size, unsigned char *compressed, int maxCompressedBytes); + +/** Encodes a frame of audio. + @param st Encoder state + @param pcm PCM audio in signed 16-bit format (native endian). There must be + * exactly frame_size samples per channel. + @param compressed The compressed data is written here. This may not alias pcm or + * optional_synthesis. + @param nbCompressedBytes Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + @return Number of bytes written to "compressed". Will be the same as + * "nbCompressedBytes" unless the stream is VBR and will never be larger. + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT int opus_custom_encode(OpusCustomEncoder *st, const opus_int16 *pcm, int frame_size, unsigned char *compressed, int maxCompressedBytes); + +/** Query and set encoder parameters + @param st Encoder state + @param request Parameter to change or query + @param value Pointer to a 32-bit int value + @return Error code +*/ +OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * restrict st, int request, ...); + +/* Decoder */ + +OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_get_size(const OpusCustomMode *mode, int channels); + +/** Creates a new decoder state. Each stream needs its own decoder state (can't + be shared across simultaneous streams). + @param mode Contains all the information about the characteristics of the + stream (must be the same characteristics as used for the encoder) + @param channels Number of channels + @param error Returns an error code + @return Newly created decoder state. + */ +OPUS_CUSTOM_EXPORT OpusCustomDecoder *opus_custom_decoder_create(const OpusCustomMode *mode, int channels, int *error); + +OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init(OpusCustomDecoder *st, const OpusCustomMode *mode, int channels); + +/** Destroys a a decoder state. + @param st Decoder state to be destroyed + */ +OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st); + +/** Decodes a frame of audio. + @param st Decoder state + @param data Compressed data produced by an encoder + @param len Number of bytes to read from "data". This MUST be exactly the number + of bytes returned by the encoder. Using a larger value WILL NOT WORK. + @param pcm One frame (frame_size samples per channel) of decoded PCM will be + returned here in float format. + @return Error code. + */ +OPUS_CUSTOM_EXPORT int opus_custom_decode_float(OpusCustomDecoder *st, const unsigned char *data, int len, float *pcm, int frame_size); + +/** Decodes a frame of audio. + @param st Decoder state + @param data Compressed data produced by an encoder + @param len Number of bytes to read from "data". This MUST be exactly the number + of bytes returned by the encoder. Using a larger value WILL NOT WORK. + @param pcm One frame (frame_size samples per channel) of decoded PCM will be + returned here in 16-bit PCM format (native endian). + @return Error code. + */ +OPUS_CUSTOM_EXPORT int opus_custom_decode(OpusCustomDecoder *st, const unsigned char *data, int len, opus_int16 *pcm, int frame_size); + +/** Query and set decoder parameters + @param st Decoder state + @param request Parameter to change or query + @param value Pointer to a 32-bit int value + @return Error code + */ +OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * restrict st, int request, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_CUSTOM_H */ diff --git a/media/libopus/include/opus_defines.h b/media/libopus/include/opus_defines.h new file mode 100644 index 000000000000..883f9d120a2f --- /dev/null +++ b/media/libopus/include/opus_defines.h @@ -0,0 +1,442 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file opus_defines.h + * @brief Opus reference implementation constants + */ + +#ifndef OPUS_DEFINES_H +#define OPUS_DEFINES_H + +#include "opus_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup errorcodes Error codes + * @{ + */ +/** No error @hideinitializer*/ +#define OPUS_OK 0 +/** One or more invalid/out of range arguments @hideinitializer*/ +#define OPUS_BAD_ARG -1 +/** The mode struct passed is invalid @hideinitializer*/ +#define OPUS_BUFFER_TOO_SMALL -2 +/** An internal error was detected @hideinitializer*/ +#define OPUS_INTERNAL_ERROR -3 +/** The compressed data passed is corrupted @hideinitializer*/ +#define OPUS_INVALID_PACKET -4 +/** Invalid/unsupported request number @hideinitializer*/ +#define OPUS_UNIMPLEMENTED -5 +/** An encoder or decoder structure is invalid or already freed @hideinitializer*/ +#define OPUS_INVALID_STATE -6 +/** Memory allocation has failed @hideinitializer*/ +#define OPUS_ALLOC_FAIL -7 +/**@}*/ + +/** @cond OPUS_INTERNAL_DOC */ +/**Export control for opus functions */ + +#if defined(__GNUC__) && defined(OPUS_BUILD) +# define OPUS_EXPORT __attribute__ ((visibility ("default"))) +#elif defined(WIN32) +# ifdef OPUS_BUILD +# define OPUS_EXPORT __declspec(dllexport) +# else +# define OPUS_EXPORT __declspec(dllimport) +# endif +#else +# define OPUS_EXPORT +#endif + +/** These are the actual Encoder CTL ID numbers. + * They should not be used directly by applications. */ +#define OPUS_SET_APPLICATION_REQUEST 4000 +#define OPUS_GET_APPLICATION_REQUEST 4001 +#define OPUS_SET_BITRATE_REQUEST 4002 +#define OPUS_GET_BITRATE_REQUEST 4003 +#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004 +#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005 +#define OPUS_SET_VBR_REQUEST 4006 +#define OPUS_GET_VBR_REQUEST 4007 +#define OPUS_SET_BANDWIDTH_REQUEST 4008 +#define OPUS_GET_BANDWIDTH_REQUEST 4009 +#define OPUS_SET_COMPLEXITY_REQUEST 4010 +#define OPUS_GET_COMPLEXITY_REQUEST 4011 +#define OPUS_SET_INBAND_FEC_REQUEST 4012 +#define OPUS_GET_INBAND_FEC_REQUEST 4013 +#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014 +#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015 +#define OPUS_SET_DTX_REQUEST 4016 +#define OPUS_GET_DTX_REQUEST 4017 +#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020 +#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021 +#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022 +#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023 +#define OPUS_SET_SIGNAL_REQUEST 4024 +#define OPUS_GET_SIGNAL_REQUEST 4025 +#define OPUS_GET_LOOKAHEAD_REQUEST 4027 +/* #define OPUS_RESET_STATE 4028 */ +#define OPUS_GET_FINAL_RANGE_REQUEST 4031 +#define OPUS_GET_PITCH_REQUEST 4033 + +/* Macros to trigger compilation errors when the wrong types are provided to a CTL */ +#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) +#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr))) +#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr))) +/** @endcond */ + +/** @defgroup ctlvalues Pre-defined values for CTL interface + * @see genericctls, encoderctls + * @{ + */ +/* Values for the various encoder CTLs */ +#define OPUS_AUTO -1000 /**int: 0-10, inclusive + * @hideinitializer */ +#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x) +/** Gets the encoder's complexity configuration, @see OPUS_SET_COMPLEXITY + * @param[out] x int*: 0-10, inclusive + * @hideinitializer */ +#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x) + +/** Configures the bitrate in the encoder. + * Rates from 500 to 512000 bits per second are meaningful as well as the + * special values OPUS_BITRATE_AUTO and OPUS_BITRATE_MAX. + * The value OPUS_BITRATE_MAX can be used to cause the codec to use as much rate + * as it can, which is useful for controlling the rate by adjusting the output + * buffer size. + * @param[in] x opus_int32: bitrate in bits per second. + * @hideinitializer */ +#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x) +/** Gets the encoder's bitrate configuration, @see OPUS_SET_BITRATE + * @param[out] x opus_int32*: bitrate in bits per second. + * @hideinitializer */ +#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x) + +/** Configures VBR in the encoder. + * The following values are currently supported: + * - 0 CBR + * - 1 VBR (default) + * The configured bitrate may not be met exactly because frames must + * be an integer number of bytes in length. + * @warning Only the MDCT mode of Opus can provide hard CBR behavior. + * @param[in] x int: 0; 1 (default) + * @hideinitializer */ +#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x) +/** Gets the encoder's VBR configuration, @see OPUS_SET_VBR + * @param[out] x int*: 0; 1 + * @hideinitializer */ +#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x) + +/** Configures constrained VBR in the encoder. + * The following values are currently supported: + * - 0 Unconstrained VBR (default) + * - 1 Maximum one frame buffering delay assuming transport with a serialization speed of the nominal bitrate + * This setting is irrelevant when the encoder is in CBR mode. + * @warning Only the MDCT mode of Opus currently heeds the constraint. + * Speech mode ignores it completely, hybrid mode may fail to obey it + * if the LPC layer uses more bitrate than the constraint would have + * permitted. + * @param[in] x int: 0 (default); 1 + * @hideinitializer */ +#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x) +/** Gets the encoder's constrained VBR configuration @see OPUS_SET_VBR_CONSTRAINT + * @param[out] x int*: 0; 1 + * @hideinitializer */ +#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x) + +/** Configures mono/stereo forcing in the encoder. + * This is useful when the caller knows that the input signal is currently a mono + * source embedded in a stereo stream. + * @param[in] x int: OPUS_AUTO (default); 1 (forced mono); 2 (forced stereo) + * @hideinitializer */ +#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x) +/** Gets the encoder's forced channel configuration, @see OPUS_SET_FORCE_CHANNELS + * @param[out] x int*: OPUS_AUTO; 0; 1 + * @hideinitializer */ +#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's maximum bandpass allowed, @see OPUS_GET_MAX_BANDWIDTH + * The supported values are: + * - OPUS_BANDWIDTH_NARROWBAND 4kHz passband + * - OPUS_BANDWIDTH_MEDIUMBAND 6kHz passband + * - OPUS_BANDWIDTH_WIDEBAND 8kHz passband + * - OPUS_BANDWIDTH_SUPERWIDEBAND 12kHz passband + * - OPUS_BANDWIDTH_FULLBAND 20kHz passband (default) + * @param[in] x int: Bandwidth value + * @hideinitializer */ +#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Gets the encoder's configured maximum bandpass allowed, @see OPUS_SET_MAX_BANDWIDTH + * @param[out] x int*: Bandwidth value + * @hideinitializer */ +#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's bandpass, @see OPUS_GET_BANDWIDTH + * The supported values are: + * - OPUS_AUTO (default) + * - OPUS_BANDWIDTH_NARROWBAND 4kHz passband + * - OPUS_BANDWIDTH_MEDIUMBAND 6kHz passband + * - OPUS_BANDWIDTH_WIDEBAND 8kHz passband + * - OPUS_BANDWIDTH_SUPERWIDEBAND 12kHz passband + * - OPUS_BANDWIDTH_FULLBAND 20kHz passband + * @param[in] x int: Bandwidth value + * @hideinitializer */ +#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Configures the type of signal being encoded. + * This is a hint which helps the encoder's mode selection. + * The supported values are: + * - OPUS_SIGNAL_AUTO (default) + * - OPUS_SIGNAL_VOICE + * - OPUS_SIGNAL_MUSIC + * @param[in] x int: Signal type + * @hideinitializer */ +#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal type, @see OPUS_SET_SIGNAL + * + * @param[out] x int*: Signal type + * @hideinitializer */ +#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x) + + +/** Configures the encoder's intended application. + * The initial value is a mandatory argument to the encoder_create function. + * The supported values are: + * - OPUS_APPLICATION_VOIP Process signal for improved speech intelligibility + * - OPUS_APPLICATION_AUDIO Favor faithfulness to the original input + * - OPUS_APPLICATION_RESTRICTED_LOWDELAY Configure the minimum possible coding delay + * + * @param[in] x int: Application value + * @hideinitializer */ +#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured application, @see OPUS_SET_APPLICATION + * + * @param[out] x int*: Application value + * @hideinitializer */ +#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x) + +/** Gets the total samples of delay added by the entire codec. + * This can be queried by the encoder and then the provided number of samples can be + * skipped on from the start of the decoder's output to provide time aligned input + * and output. From the perspective of a decoding application the real data begins this many + * samples late. + * + * The decoder contribution to this delay is identical for all decoders, but the + * encoder portion of the delay may vary from implementation to implementation, + * version to version, or even depend on the encoder's initial configuration. + * Applications needing delay compensation should call this CTL rather than + * hard-coding a value. + * @param[out] x int*: Number of lookahead samples + * @hideinitializer */ +#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of inband forward error correction. + * @note This is only applicable to the LPC layer + * + * @param[in] x int: FEC flag, 0 (disabled) is default + * @hideinitializer */ +#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of inband forward error correction, @see OPUS_SET_INBAND_FEC + * + * @param[out] x int*: FEC flag + * @hideinitializer */ +#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's expected packet loss percentage. + * Higher values with trigger progressively more loss resistant behavior in the encoder + * at the expense of quality at a given bitrate in the lossless case, but greater quality + * under loss. + * + * @param[in] x int: Loss percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured packet loss percentage, @see OPUS_SET_PACKET_LOSS_PERC + * + * @param[out] x int*: Loss percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of discontinuous transmission. + * @note This is only applicable to the LPC layer + * + * @param[in] x int: DTX flag, 0 (disabled) is default + * @hideinitializer */ +#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of discontinuous transmission, @see OPUS_SET_DTX + * + * @param[out] x int*: DTX flag + * @hideinitializer */ +#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x) +/**@}*/ + +/** @defgroup genericctls Generic CTLs + * + * These macros are used with the \c opus_decoder_ctl and + * \c opus_encoder_ctl calls to generate a particular + * request. + * + * When called on an \c OpusDecoder they apply to that + * particular decoder instance. When called on an + * \c OpusEncoder they apply to the corresponding setting + * on that encoder instance, if present. + * + * Some usage examples: + * + * @code + * int ret; + * opus_int32 pitch; + * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch)); + * if (ret == OPUS_OK) return ret; + * + * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE); + * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE); + * + * opus_int32 enc_bw, dec_bw; + * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw)); + * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw)); + * if (enc_bw != dec_bw) { + * printf("packet bandwidth mismatch!\n"); + * } + * @endcode + * + * @see opusencoder, opus_decoder_ctl, opus_encoder_ctl + * @{ + */ + +/** Resets the codec state to be equivalent to a freshly initialized state. + * This should be called when switching streams in order to prevent + * the back to back decoding from giving different results from + * one at a time decoding. + * @hideinitializer */ +#define OPUS_RESET_STATE 4028 + +/** Gets the final state of the codec's entropy coder. + * This is used for testing purposes, + * The encoder and decoder state should be identical after coding a payload + * (assuming no data corruption or software bugs) + * + * @param[out] x opus_uint32*: Entropy coder state + * + * @hideinitializer */ +#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x) + +/** Gets the pitch of the last decoded frame, if available. + * This can be used for any post-processing algorithm requiring the use of pitch, + * e.g. time stretching/shortening. If the last frame was not voiced, or if the + * pitch was not coded in the frame, then zero is returned. + * + * This CTL is only implemented for decoder instances. + * + * @param[out] x opus_int32*: pitch period at 48 kHz (or 0 if not available) + * + * @hideinitializer */ +#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x) + +/** Gets the encoder's configured bandpass or the decoder's last bandpass, @see OPUS_SET_BANDWIDTH + * @param[out] x int*: Bandwidth value + * @hideinitializer */ +#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup libinfo Opus library information functions + * @{ + */ + +/** Converts an opus error code into a human readable string. + * + * @param[in] error int: Error number + * @returns Error string + */ +OPUS_EXPORT const char *opus_strerror(int error); + +/** Gets the libopus version string. + * + * @returns Version string + */ +OPUS_EXPORT const char *opus_get_version_string(void); +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_DEFINES_H */ diff --git a/media/libopus/include/opus_multistream.h b/media/libopus/include/opus_multistream.h new file mode 100644 index 000000000000..1fdb881c93e2 --- /dev/null +++ b/media/libopus/include/opus_multistream.h @@ -0,0 +1,164 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file opus_multistream.h + * @brief Opus reference implementation multistream API + */ + +#ifndef OPUS_MULTISTREAM_H +#define OPUS_MULTISTREAM_H + +#include "opus.h" + +typedef struct OpusMSEncoder OpusMSEncoder; +typedef struct OpusMSDecoder OpusMSDecoder; + +#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr))) +#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr))) + +#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120 +#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122 + +#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y) +#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y) + +/** Allocate and initialize a multistream encoder state object. + * Call opus_multistream_encoder_destroy() to release + * this object when finished. */ +OPUS_EXPORT OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, /**< Sampling rate of input signal (Hz) */ + int channels, /**< Number of channels in the input signal */ + int streams, /**< Total number of streams to encode from the input */ + int coupled_streams, /**< Number of coupled (stereo) streams to encode */ + unsigned char *mapping, /**< Encoded mapping between channels and streams */ + int application, /**< Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO) */ + int *error /**< Error code */ +); + +/** Initialize an already allocated multistream encoder state. */ +OPUS_EXPORT int opus_multistream_encoder_init( + OpusMSEncoder *st, /**< Encoder state */ + opus_int32 Fs, /**< Sampling rate of input signal (Hz) */ + int channels, /**< Number of channels in the input signal */ + int streams, /**< Total number of streams to encode from the input */ + int coupled_streams, /**< Number of coupled (stereo) streams to encode */ + unsigned char *mapping, /**< Encoded mapping between channels and streams */ + int application /**< Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO) */ +); + +/** Returns length of the data payload (in bytes) or a negative error code */ +OPUS_EXPORT int opus_multistream_encode( + OpusMSEncoder *st, /**< Encoder state */ + const opus_int16 *pcm, /**< Input signal as interleaved samples. Length is frame_size*channels */ + int frame_size, /**< Number of samples per frame of input signal */ + unsigned char *data, /**< Output buffer for the compressed payload (no more than max_data_bytes long) */ + int max_data_bytes /**< Allocated memory for payload; don't use for controlling bitrate */ +); + +/** Returns length of the data payload (in bytes) or a negative error code. */ +OPUS_EXPORT int opus_multistream_encode_float( + OpusMSEncoder *st, /**< Encoder state */ + const float *pcm, /**< Input signal interleaved in channel order. length is frame_size*channels */ + int frame_size, /**< Number of samples per frame of input signal */ + unsigned char *data, /**< Output buffer for the compressed payload (no more than max_data_bytes long) */ + int max_data_bytes /**< Allocated memory for payload; don't use for controlling bitrate */ + ); + +/** Gets the size of an OpusMSEncoder structure. + * @returns size + */ +OPUS_EXPORT opus_int32 opus_multistream_encoder_get_size( + int streams, /**< Total number of coded streams */ + int coupled_streams /**< Number of coupled (stereo) streams */ +); + +/** Deallocate a multstream encoder state */ +OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st); + +/** Get or set options on a multistream encoder state */ +OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...); + +/** Allocate and initialize a multistream decoder state object. + * Call opus_multistream_decoder_destroy() to release + * this object when finished. */ +OPUS_EXPORT OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, /**< Sampling rate to decode at (Hz) */ + int channels, /**< Number of channels to decode */ + int streams, /**< Total number of coded streams in the multistream */ + int coupled_streams, /**< Number of coupled (stereo) streams in the multistream */ + unsigned char *mapping, /**< Stream to channel mapping table */ + int *error /**< Error code */ +); + +/** Intialize a previously allocated decoder state object. */ +OPUS_EXPORT int opus_multistream_decoder_init( + OpusMSDecoder *st, /**< Encoder state */ + opus_int32 Fs, /**< Sample rate of input signal (Hz) */ + int channels, /**< Number of channels in the input signal */ + int streams, /**< Total number of coded streams */ + int coupled_streams, /**< Number of coupled (stereo) streams */ + unsigned char *mapping /**< Stream to channel mapping table */ +); + +/** Returns the number of samples decoded or a negative error code */ +OPUS_EXPORT int opus_multistream_decode( + OpusMSDecoder *st, /**< Decoder state */ + const unsigned char *data, /**< Input payload. Use a NULL pointer to indicate packet loss */ + int len, /**< Number of bytes in payload */ + opus_int16 *pcm, /**< Output signal, samples interleaved in channel order . length is frame_size*channels */ + int frame_size, /**< Number of samples per frame of input signal */ + int decode_fec /**< Flag (0/1) to request that any in-band forward error correction data be */ + /**< decoded. If no such data is available the frame is decoded as if it were lost. */ +); + +/** Returns the number of samples decoded or a negative error code */ +OPUS_EXPORT int opus_multistream_decode_float( + OpusMSDecoder *st, /**< Decoder state */ + const unsigned char *data, /**< Input payload buffer. Use a NULL pointer to indicate packet loss */ + int len, /**< Number of payload bytes in data */ + float *pcm, /**< Buffer for the output signal (interleaved iin channel order). length is frame_size*channels */ + int frame_size, /**< Number of samples per frame of input signal */ + int decode_fec /**< Flag (0/1) to request that any in-band forward error correction data be */ + /**< decoded. If no such data is available the frame is decoded as if it were lost. */ +); + +/** Gets the size of an OpusMSDecoder structure. + * @returns size + */ +OPUS_EXPORT opus_int32 opus_multistream_decoder_get_size( + int streams, /**< Total number of coded streams */ + int coupled_streams /**< Number of coupled (stereo) streams */ +); + +/** Get or set options on a multistream decoder state */ +OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...); + +/** Deallocate a multistream decoder state object */ +OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st); + +#endif /* OPUS_MULTISTREAM_H */ diff --git a/media/libopus/include/opus_types.h b/media/libopus/include/opus_types.h new file mode 100644 index 000000000000..b001eb47656e --- /dev/null +++ b/media/libopus/include/opus_types.h @@ -0,0 +1,159 @@ +/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */ +/* Modified by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* opus_types.h taken from libogg */ + +/** + @file opus_types.h + @brief Opus reference implementation types +*/ +#ifndef OPUS_TYPES_H +#define OPUS_TYPES_H + +/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */ +#if (defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H)) +#include + + typedef int16_t opus_int16; + typedef uint16_t opus_uint16; + typedef int32_t opus_int32; + typedef uint32_t opus_uint32; +#elif defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t opus_int32; + typedef _G_uint32_t opus_uint32; + typedef _G_int16 opus_int16; + typedef _G_uint16 opus_uint16; +# elif defined(__MINGW32__) + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; +# elif defined(__MWERKS__) + typedef int opus_int32; + typedef unsigned int opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; +# else + /* MSVC/Borland */ + typedef __int32 opus_int32; + typedef unsigned __int32 opus_uint32; + typedef __int16 opus_int16; + typedef unsigned __int16 opus_uint16; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 opus_int16; + typedef UInt16 opus_uint16; + typedef SInt32 opus_int32; + typedef UInt32 opus_uint32; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t opus_int16; + typedef u_int16_t opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16 opus_int16; + typedef u_int16 opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int opus_int32; + typedef unsigned opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short opus_int16; + typedef unsigned short opus_uint16; + typedef signed int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef long opus_int32; + typedef unsigned long opus_uint32; + +#elif defined(CONFIG_TI_C6X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#else + + /* Give up, take a reasonable guess */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#endif + +#define opus_int int /* used for counters etc; at least 16 bits */ +#define opus_int64 long long +#define opus_int8 signed char + +#define opus_uint unsigned int /* used for counters etc; at least 16 bits */ +#define opus_uint64 unsigned long long +#define opus_uint8 unsigned char + +#endif /* OPUS_TYPES_H */ diff --git a/media/libopus/opus_sources.mk b/media/libopus/opus_sources.mk new file mode 100644 index 000000000000..384b036ab133 --- /dev/null +++ b/media/libopus/opus_sources.mk @@ -0,0 +1,5 @@ +OPUS_SOURCES = src/opus.c \ +src/opus_decoder.c \ +src/opus_encoder.c \ +src/opus_multistream.c \ +src/repacketizer.c diff --git a/media/libopus/silk/A2NLSF.c b/media/libopus/silk/A2NLSF.c new file mode 100644 index 000000000000..b6e2b41e7300 --- /dev/null +++ b/media/libopus/silk/A2NLSF.c @@ -0,0 +1,252 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* Conversion between prediction filter coefficients and NLSFs */ +/* Requires the order to be an even number */ +/* A piecewise linear approximation maps LSF <-> cos(LSF) */ +/* Therefore the result is not accurate NLSFs, but the two */ +/* functions are accurate inverses of each other */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "tables.h" + +/* Number of binary divisions, when not in low complexity mode */ +#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */ +#define MAX_ITERATIONS_A2NLSF_FIX 30 + +/* Helper function for A2NLSF(..) */ +/* Transforms polynomials from cos(n*f) to cos(f)^n */ +static inline void silk_A2NLSF_trans_poly( + opus_int32 *p, /* I/O Polynomial */ + const opus_int dd /* I Polynomial order (= filter order / 2 ) */ +) +{ + opus_int k, n; + + for( k = 2; k <= dd; k++ ) { + for( n = dd; n > k; n-- ) { + p[ n - 2 ] -= p[ n ]; + } + p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 ); + } +} +/* Helper function for A2NLSF(..) */ +/* Polynomial evaluation */ +static inline opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16 */ + opus_int32 *p, /* I Polynomial, Q16 */ + const opus_int32 x, /* I Evaluation point, Q12 */ + const opus_int dd /* I Order */ +) +{ + opus_int n; + opus_int32 x_Q16, y32; + + y32 = p[ dd ]; /* Q16 */ + x_Q16 = silk_LSHIFT( x, 4 ); + for( n = dd - 1; n >= 0; n-- ) { + y32 = silk_SMLAWW( p[ n ], y32, x_Q16 ); /* Q16 */ + } + return y32; +} + +static inline void silk_A2NLSF_init( + const opus_int32 *a_Q16, + opus_int32 *P, + opus_int32 *Q, + const opus_int dd +) +{ + opus_int k; + + /* Convert filter coefs to even and odd polynomials */ + P[dd] = silk_LSHIFT( 1, 16 ); + Q[dd] = silk_LSHIFT( 1, 16 ); + for( k = 0; k < dd; k++ ) { + P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; /* Q16 */ + Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; /* Q16 */ + } + + /* Divide out zeros as we have that for even filter orders, */ + /* z = 1 is always a root in Q, and */ + /* z = -1 is always a root in P */ + for( k = dd; k > 0; k-- ) { + P[ k - 1 ] -= P[ k ]; + Q[ k - 1 ] += Q[ k ]; + } + + /* Transform polynomials from cos(n*f) to cos(f)^n */ + silk_A2NLSF_trans_poly( P, dd ); + silk_A2NLSF_trans_poly( Q, dd ); +} + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +) +{ + opus_int i, k, m, dd, root_ix, ffrac; + opus_int32 xlo, xhi, xmid; + opus_int32 ylo, yhi, ymid, thr; + opus_int32 nom, den; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 *PQ[ 2 ]; + opus_int32 *p; + + /* Store pointers to array */ + PQ[ 0 ] = P; + PQ[ 1 ] = Q; + + dd = silk_RSHIFT( d, 1 ); + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + + /* Find roots, alternating between P and Q */ + p = P; /* Pointer to polynomial */ + + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Loop counter */ + i = 0; /* Counter for bandwidth expansions applied */ + thr = 0; + while( 1 ) { + /* Evaluate polynomial */ + xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */ + yhi = silk_A2NLSF_eval_poly( p, xhi, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) { + if( yhi == 0 ) { + /* If the root lies exactly at the end of the current */ + /* interval, look for the next root in the next interval */ + thr = 1; + } else { + thr = 0; + } + /* Binary division */ + ffrac = -256; + for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) { + /* Evaluate polynomial */ + xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 ); + ymid = silk_A2NLSF_eval_poly( p, xmid, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) { + /* Reduce frequency */ + xhi = xmid; + yhi = ymid; + } else { + /* Increase frequency */ + xlo = xmid; + ylo = ymid; + ffrac = silk_ADD_RSHIFT( ffrac, 128, m ); + } + } + + /* Interpolate */ + if( silk_abs( ylo ) < 65536 ) { + /* Avoid dividing by zero */ + den = ylo - yhi; + nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 ); + if( den != 0 ) { + ffrac += silk_DIV32( nom, den ); + } + } else { + /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */ + ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) ); + } + NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX ); + + silk_assert( NLSF[ root_ix ] >= 0 ); + + root_ix++; /* Next root */ + if( root_ix >= d ) { + /* Found all roots */ + break; + } + /* Alternate pointer to polynomial */ + p = PQ[ root_ix & 1 ]; + + /* Evaluate polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/ + ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 ); + } else { + /* Increment loop counter */ + k++; + xlo = xhi; + ylo = yhi; + thr = 0; + + if( k > LSF_COS_TAB_SZ_FIX ) { + i++; + if( i > MAX_ITERATIONS_A2NLSF_FIX ) { + /* Set NLSFs to white spectrum and exit */ + NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 ); + for( k = 1; k < d; k++ ) { + NLSF[ k ] = (opus_int16)silk_SMULBB( k + 1, NLSF[ 0 ] ); + } + return; + } + + /* Error: Apply progressively more bandwidth expansion and run again */ + silk_bwexpander_32( a_Q16, d, 65536 - silk_SMULBB( 10 + i, i ) ); /* 10_Q16 = 0.00015*/ + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + p = P; /* Pointer to polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Reset loop counter */ + } + } + } +} diff --git a/media/libopus/silk/API.h b/media/libopus/silk/API.h new file mode 100644 index 000000000000..1bb39adc3b4a --- /dev/null +++ b/media/libopus/silk/API.h @@ -0,0 +1,138 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_API_H +#define SILK_API_H + +#include "control.h" +#include "typedef.h" +#include "errors.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SILK_MAX_FRAMES_PER_PACKET 3 + +/* Struct for TOC (Table of Contents) */ +typedef struct { + opus_int VADFlag; /* Voice activity for packet */ + opus_int VADFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Voice activity for each frame in packet */ + opus_int inbandFECFlag; /* Flag indicating if packet contains in-band FEC */ +} silk_TOC_struct; + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk encoder state */ +/***********************************************/ +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +); + +/*************************/ +/* Init or reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */ +); + +/****************************************/ +/* Decoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk decoder state */ +/***********************************************/ +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +); + +/*************************/ +/* Init or Reset decoder */ +/*************************/ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +); + +/******************/ +/* Decode a frame */ +/******************/ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut /* O Number of samples decoded */ +); + +/**************************************/ +/* Get table of contents for a packet */ +/**************************************/ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/media/libopus/silk/CNG.c b/media/libopus/silk/CNG.c new file mode 100644 index 000000000000..261cdb170b13 --- /dev/null +++ b/media/libopus/silk/CNG.c @@ -0,0 +1,167 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Generates excitation for CNG LPC synthesis */ +static inline void silk_CNG_exc( + opus_int32 residual_Q10[], /* O CNG residual signal Q10 */ + opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */ + opus_int32 Gain_Q16, /* I Gain to apply */ + opus_int length, /* I Length */ + opus_int32 *rand_seed /* I/O Seed to random index generator */ +) +{ + opus_int32 seed; + opus_int i, idx, exc_mask; + + exc_mask = CNG_BUF_MASK_MAX; + while( exc_mask > length ) { + exc_mask = silk_RSHIFT( exc_mask, 1 ); + } + + seed = *rand_seed; + for( i = 0; i < length; i++ ) { + seed = silk_RAND( seed ); + idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask ); + silk_assert( idx >= 0 ); + silk_assert( idx <= CNG_BUF_MASK_MAX ); + residual_Q10[ i ] = (opus_int16)silk_SAT16( silk_SMULWW( exc_buf_Q14[ idx ], Gain_Q16 >> 4 ) ); + } + *rand_seed = seed; +} + +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + opus_int i, NLSF_step_Q15, NLSF_acc_Q15; + + NLSF_step_Q15 = silk_DIV32_16( silk_int16_MAX, psDec->LPC_order + 1 ); + NLSF_acc_Q15 = 0; + for( i = 0; i < psDec->LPC_order; i++ ) { + NLSF_acc_Q15 += NLSF_step_Q15; + psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15; + } + psDec->sCNG.CNG_smth_Gain_Q16 = 0; + psDec->sCNG.rand_seed = 3176576; +} + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +) +{ + opus_int i, subfr; + opus_int32 sum_Q6, max_Gain_Q16; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; + opus_int32 CNG_sig_Q10[ MAX_FRAME_LENGTH + MAX_LPC_ORDER ]; + silk_CNG_struct *psCNG = &psDec->sCNG; + + if( psDec->fs_kHz != psCNG->fs_kHz ) { + /* Reset state */ + silk_CNG_Reset( psDec ); + + psCNG->fs_kHz = psDec->fs_kHz; + } + if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) { + /* Update CNG parameters */ + + /* Smoothing of LSF's */ + for( i = 0; i < psDec->LPC_order; i++ ) { + psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( psDec->prevNLSF_Q15[ i ] - psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 ); + } + /* Find the subframe with the highest gain */ + max_Gain_Q16 = 0; + subfr = 0; + for( i = 0; i < psDec->nb_subfr; i++ ) { + if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) { + max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ]; + subfr = i; + } + } + /* Update CNG excitation buffer with excitation from this subframe */ + silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) ); + silk_memcpy( psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) ); + + /* Smooth gains */ + for( i = 0; i < psDec->nb_subfr; i++ ) { + psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 ); + } + } + + /* Add CNG when packet is lost or during DTX */ + if( psDec->lossCnt ) { + + /* Generate CNG excitation */ + silk_CNG_exc( CNG_sig_Q10 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, psCNG->CNG_smth_Gain_Q16, length, &psCNG->rand_seed ); + + /* Convert CNG NLSF to filter representation */ + silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order ); + + /* Generate CNG signal, by synthesis filtering */ + silk_memcpy( CNG_sig_Q10, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + for( i = 0; i < length; i++ ) { + silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + sum_Q6 = silk_RSHIFT( psDec->LPC_order, 1 ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + if( psDec->LPC_order == 16 ) { + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] ); + } + + /* Update states */ + CNG_sig_Q10[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q10[ MAX_LPC_ORDER + i ], sum_Q6, 4 ); + + frame[ i ] = silk_ADD_SAT16( frame[ i ], silk_RSHIFT_ROUND( sum_Q6, 6 ) ); + } + silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q10[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + } else { + silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) ); + } +} diff --git a/media/libopus/silk/HP_variable_cutoff.c b/media/libopus/silk/HP_variable_cutoff.c new file mode 100644 index 000000000000..6eec9c1babb5 --- /dev/null +++ b/media/libopus/silk/HP_variable_cutoff.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +) +{ + opus_int quality_Q15; + opus_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7; + silk_encoder_state *psEncC1 = &state_Fxx[ 0 ].sCmn; + + /* Adaptive cutoff frequency: estimate low end of pitch frequency range */ + if( psEncC1->prevSignalType == TYPE_VOICED ) { + /* difference, in log domain */ + pitch_freq_Hz_Q16 = silk_DIV32_16( silk_LSHIFT( silk_MUL( psEncC1->fs_kHz, 1000 ), 16 ), psEncC1->prevLag ); + pitch_freq_log_Q7 = silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 ); + + /* adjustment based on quality */ + quality_Q15 = psEncC1->input_quality_bands_Q15[ 0 ]; + pitch_freq_log_Q7 = silk_SMLAWB( pitch_freq_log_Q7, silk_SMULWB( silk_LSHIFT( -quality_Q15, 2 ), quality_Q15 ), + pitch_freq_log_Q7 - ( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ) ) ); + + /* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */ + delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT( psEncC1->variable_HP_smth1_Q15, 8 ); + if( delta_freq_Q7 < 0 ) { + /* less smoothing for decreasing pitch frequency, to track something close to the minimum */ + delta_freq_Q7 = silk_MUL( delta_freq_Q7, 3 ); + } + + /* limit delta, to reduce impact of outliers in pitch estimation */ + delta_freq_Q7 = silk_LIMIT_32( delta_freq_Q7, -SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) ); + + /* update smoother */ + psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB( psEncC1->variable_HP_smth1_Q15, + silk_SMULBB( psEncC1->speech_activity_Q8, delta_freq_Q7 ), SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) ); + + /* limit frequency range */ + psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32( psEncC1->variable_HP_smth1_Q15, + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ), + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MAX_CUTOFF_HZ ), 8 ) ); + } +} diff --git a/media/libopus/silk/Inlines.h b/media/libopus/silk/Inlines.h new file mode 100644 index 000000000000..8458c97c6394 --- /dev/null +++ b/media/libopus/silk/Inlines.h @@ -0,0 +1,188 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/*! \file silk_Inlines.h + * \brief silk_Inlines.h defines inline signal processing functions. + */ + +#ifndef SILK_FIX_INLINES_H +#define SILK_FIX_INLINES_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* count leading zeros of opus_int64 */ +static inline opus_int32 silk_CLZ64( opus_int64 in ) +{ + opus_int32 in_upper; + + in_upper = (opus_int32)silk_RSHIFT64(in, 32); + if (in_upper == 0) { + /* Search in the lower 32 bits */ + return 32 + silk_CLZ32( (opus_int32) in ); + } else { + /* Search in the upper 32 bits */ + return silk_CLZ32( in_upper ); + } +} + +/* get number of leading zeros and fractional part (the bits right after the leading one */ +static inline void silk_CLZ_FRAC( + opus_int32 in, /* I input */ + opus_int32 *lz, /* O number of leading zeros */ + opus_int32 *frac_Q7 /* O the 7 bits right after the leading one */ +) +{ + opus_int32 lzeros = silk_CLZ32(in); + + * lz = lzeros; + * frac_Q7 = silk_ROR32(in, 24 - lzeros) & 0x7f; +} + +/* Approximation of square root */ +/* Accuracy: < +/- 10% for output values > 15 */ +/* < +/- 2.5% for output values > 120 */ +static inline opus_int32 silk_SQRT_APPROX( opus_int32 x ) +{ + opus_int32 y, lz, frac_Q7; + + if( x <= 0 ) { + return 0; + } + + silk_CLZ_FRAC(x, &lz, &frac_Q7); + + if( lz & 1 ) { + y = 32768; + } else { + y = 46214; /* 46214 = sqrt(2) * 32768 */ + } + + /* get scaling right */ + y >>= silk_RSHIFT(lz, 1); + + /* increment using fractional part of input */ + y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7)); + + return y; +} + +/* Divide two int32 values and return result as int32 in a given Q-domain */ +static inline opus_int32 silk_DIV32_varQ( /* O returns a good approximation of "(a32 << Qres) / b32" */ + const opus_int32 a32, /* I numerator (Q0) */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (>= 0) */ +) +{ + opus_int a_headrm, b_headrm, lshift; + opus_int32 b32_inv, a32_nrm, b32_nrm, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres >= 0 ); + + /* Compute number of bits head room and normalize inputs */ + a_headrm = silk_CLZ32( silk_abs(a32) ) - 1; + a32_nrm = silk_LSHIFT(a32, a_headrm); /* Q: a_headrm */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation */ + /* It's OK to overflow because the final value of a32_nrm should always be small */ + a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw( silk_SMMUL(b32_nrm, result), 3 )); /* Q: a_headrm */ + + /* Refinement */ + result = silk_SMLAWB(result, a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Convert to Qres domain */ + lshift = 29 + a_headrm - b_headrm - Qres; + if( lshift < 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + } else { + /* Avoid undefined result */ + return 0; + } + } +} + +/* Invert int32 value and return result as int32 in a given Q-domain */ +static inline opus_int32 silk_INVERSE32_varQ( /* O returns a good approximation of "(1 << Qres) / b32" */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (> 0) */ +) +{ + opus_int b_headrm, lshift; + opus_int32 b32_inv, b32_nrm, err_Q32, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres > 0 ); + + /* Compute number of bits head room and normalize input */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation from one */ + err_Q32 = silk_LSHIFT( (1<<29) - silk_SMULWB(b32_nrm, b32_inv), 3 ); /* Q32 */ + + /* Refinement */ + result = silk_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */ + + /* Convert to Qres domain */ + lshift = 61 - b_headrm - Qres; + if( lshift <= 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + }else{ + /* Avoid undefined result */ + return 0; + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_INLINES_H */ diff --git a/media/libopus/silk/LPC_analysis_filter.c b/media/libopus/silk/LPC_analysis_filter.c new file mode 100644 index 000000000000..e1a9d91765ee --- /dev/null +++ b/media/libopus/silk/LPC_analysis_filter.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/*******************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first d output samples are set to zero */ +/*******************************************/ + +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d /* I Filter order */ +) +{ + opus_int ix, j; + opus_int32 out32_Q12, out32; + const opus_int16 *in_ptr; + + silk_assert( d >= 6 ); + silk_assert( (d & 1) == 0 ); + silk_assert( d <= len ); + + for( ix = d; ix < len; ix++ ) { + in_ptr = &in[ ix - 1 ]; + + out32_Q12 = silk_SMULBB( in_ptr[ 0 ], B[ 0 ] ); + /* Allowing wrap around so that two wraps can cancel each other. The rare + cases where the result wraps around can only be triggered by invalid streams*/ + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -1 ], B[ 1 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -2 ], B[ 2 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -3 ], B[ 3 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -4 ], B[ 4 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -5 ], B[ 5 ] ); + for( j = 6; j < d; j += 2 ) { + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j ], B[ j ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j - 1 ], B[ j + 1 ] ); + } + + /* Subtract prediction */ + out32_Q12 = silk_SUB32_ovflw( silk_LSHIFT( (opus_int32)in_ptr[ 1 ], 12 ), out32_Q12 ); + + /* Scale to Q0 */ + out32 = silk_RSHIFT_ROUND( out32_Q12, 12 ); + + /* Saturate output */ + out[ ix ] = (opus_int16)silk_SAT16( out32 ); + } + + /* Set first d output samples to zero */ + silk_memset( out, 0, d * sizeof( opus_int16 ) ); +} diff --git a/media/libopus/silk/LPC_inv_pred_gain.c b/media/libopus/silk/LPC_inv_pred_gain.c new file mode 100644 index 000000000000..db529d14e528 --- /dev/null +++ b/media/libopus/silk/LPC_inv_pred_gain.c @@ -0,0 +1,154 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +#define QA 24 +#define A_LIMIT SILK_FIX_CONST( 0.99975, QA ) + +#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q))) + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static opus_int32 LPC_inverse_pred_gain_QA( /* O Returns inverse prediction gain in energy domain, Q30 */ + opus_int32 A_QA[ 2 ][ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k, n, mult2Q; + opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA; + opus_int32 *Aold_QA, *Anew_QA; + + Anew_QA = A_QA[ order & 1 ]; + + invGain_Q30 = 1 << 30; + for( k = order - 1; k > 0; k-- ) { + /* Check for stability */ + if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( Anew_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) ); + + /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */ + mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) ); + rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 ); + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + + /* Swap pointers */ + Aold_QA = Anew_QA; + Anew_QA = A_QA[ k & 1 ]; + + /* Update AR coefficient */ + for( n = 0; n < k; n++ ) { + tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 ); + Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q ); + } + } + + /* Check for stability */ + if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( Anew_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= 1<<30 ); + + return invGain_Q30; +} + +/* For input in Q12 domain */ +opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k; + opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ]; + opus_int32 *Anew_QA; + opus_int32 DC_resp = 0; + + Anew_QA = Atmp_QA[ order & 1 ]; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + DC_resp += (opus_int32)A_Q12[ k ]; + Anew_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 ); + } + /* If the DC is unstable, we don't even need to do the full calculations */ + if( DC_resp >= 4096 ) { + return 0; + } + return LPC_inverse_pred_gain_QA( Atmp_QA, order ); +} + +#ifdef FIXED_POINT + +/* For input in Q24 domain */ +opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int32 *A_Q24, /* I Prediction coefficients [order] */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k; + opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ]; + opus_int32 *Anew_QA; + + Anew_QA = Atmp_QA[ order & 1 ]; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + Anew_QA[ k ] = silk_RSHIFT32( A_Q24[ k ], 24 - QA ); + } + + return LPC_inverse_pred_gain_QA( Atmp_QA, order ); +} +#endif diff --git a/media/libopus/silk/LP_variable_cutoff.c b/media/libopus/silk/LP_variable_cutoff.c new file mode 100644 index 000000000000..44f541ec9f48 --- /dev/null +++ b/media/libopus/silk/LP_variable_cutoff.c @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. +*/ + +#include "main.h" + +/* Helper function, interpolates the filter taps */ +static inline void silk_LP_interpolate_filter_taps( + opus_int32 B_Q28[ TRANSITION_NB ], + opus_int32 A_Q28[ TRANSITION_NA ], + const opus_int ind, + const opus_int32 fac_Q16 +) +{ + opus_int nb, na; + + if( ind < TRANSITION_INT_NUM - 1 ) { + if( fac_Q16 > 0 ) { + if( fac_Q16 < 32768 ) { /* fac_Q16 is in range of a 16-bit int */ + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 ); + } + } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */ + silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) ); + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 - ( 1 << 16 ) ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 - ( 1 << 16 ) ); + } + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) ); + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) ); + } +} + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting psEncC->mode <> 0; */ +/* Deactivate by setting psEncC->mode = 0; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0; + opus_int ind = 0; + + silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES ); + + /* Run filter if needed */ + if( psLP->mode != 0 ) { + /* Calculate index and interpolation factor for interpolation */ +#if( TRANSITION_INT_STEPS == 64 ) + fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 ); +#else + fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES ); +#endif + ind = silk_RSHIFT( fac_Q16, 16 ); + fac_Q16 -= silk_LSHIFT( ind, 16 ); + + silk_assert( ind >= 0 ); + silk_assert( ind < TRANSITION_INT_NUM ); + + /* Interpolate filter coefficients */ + silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); + + /* Update transition frame number for next frame */ + psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES ); + + /* ARMA low-pass filtering */ + silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 ); + silk_biquad_alt( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length, 1); + } +} diff --git a/media/libopus/silk/MacroCount.h b/media/libopus/silk/MacroCount.h new file mode 100644 index 000000000000..509c9c2da10e --- /dev/null +++ b/media/libopus/silk/MacroCount.h @@ -0,0 +1,719 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SIGPROCFIX_API_MACROCOUNT_H +#define SIGPROCFIX_API_MACROCOUNT_H +#include + +#ifdef silk_MACRO_COUNT +#define varDefine opus_int64 ops_count = 0; + +extern opus_int64 ops_count; + +static inline opus_int64 silk_SaveCount(){ + return(ops_count); +} + +static inline opus_int64 silk_SaveResetCount(){ + opus_int64 ret; + + ret = ops_count; + ops_count = 0; + return(ret); +} + +static inline silk_PrintCount(){ + printf("ops_count = %d \n ", (opus_int32)ops_count); +} + +#undef silk_MUL +static inline opus_int32 silk_MUL(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} + +#undef silk_MUL_uint +static inline opus_uint32 silk_MUL_uint(opus_uint32 a32, opus_uint32 b32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} +#undef silk_MLA +static inline opus_int32 silk_MLA(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_MLA_uint +static inline opus_int32 silk_MLA_uint(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_SMULWB +static inline opus_int32 silk_SMULWB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 5; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + return ret; +} +#undef silk_SMLAWB +static inline opus_int32 silk_SMLAWB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 5; + ret = ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))); + return ret; +} + +#undef silk_SMULWT +static inline opus_int32 silk_SMULWT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + return ret; +} +#undef silk_SMLAWT +static inline opus_int32 silk_SMLAWT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + return ret; +} + +#undef silk_SMULBB +static inline opus_int32 silk_SMULBB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (opus_int32)((opus_int16)a32) * (opus_int32)((opus_int16)b32); + return ret; +} +#undef silk_SMLABB +static inline opus_int32 silk_SMLABB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + return ret; +} + +#undef silk_SMULBT +static inline opus_int32 silk_SMULBT(opus_int32 a32, opus_int32 b32 ){ + opus_int32 ret; + ops_count += 4; + ret = ((opus_int32)((opus_int16)a32)) * (b32 >> 16); + return ret; +} + +#undef silk_SMLABT +static inline opus_int32 silk_SMLABT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + return ret; +} + +#undef silk_SMULTT +static inline opus_int32 silk_SMULTT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (a32 >> 16) * (b32 >> 16); + return ret; +} + +#undef silk_SMLATT +static inline opus_int32 silk_SMLATT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (b32 >> 16) * (c32 >> 16); + return ret; +} + + +/* multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)*/ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw silk_MLA + +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw silk_SMLABB + +#undef silk_SMLABT_ovflw +#define silk_SMLABT_ovflw silk_SMLABT + +#undef silk_SMLATT_ovflw +#define silk_SMLATT_ovflw silk_SMLATT + +#undef silk_SMLAWB_ovflw +#define silk_SMLAWB_ovflw silk_SMLAWB + +#undef silk_SMLAWT_ovflw +#define silk_SMLAWT_ovflw silk_SMLAWT + +#undef silk_SMULL +static inline opus_int64 silk_SMULL(opus_int32 a32, opus_int32 b32){ + opus_int64 ret; + ops_count += 8; + ret = ((opus_int64)(a32) * /*(opus_int64)*/(b32)); + return ret; +} + +#undef silk_SMLAL +static inline opus_int64 silk_SMLAL(opus_int64 a64, opus_int32 b32, opus_int32 c32){ + opus_int64 ret; + ops_count += 8; + ret = a64 + ((opus_int64)(b32) * /*(opus_int64)*/(c32)); + return ret; +} +#undef silk_SMLALBB +static inline opus_int64 silk_SMLALBB(opus_int64 a64, opus_int16 b16, opus_int16 c16){ + opus_int64 ret; + ops_count += 4; + ret = a64 + ((opus_int64)(b16) * /*(opus_int64)*/(c16)); + return ret; +} + +#undef SigProcFIX_CLZ16 +static inline opus_int32 SigProcFIX_CLZ16(opus_int16 in16) +{ + opus_int32 out32 = 0; + ops_count += 10; + if( in16 == 0 ) { + return 16; + } + /* test nibbles */ + if( in16 & 0xFF00 ) { + if( in16 & 0xF000 ) { + in16 >>= 12; + } else { + out32 += 4; + in16 >>= 8; + } + } else { + if( in16 & 0xFFF0 ) { + out32 += 8; + in16 >>= 4; + } else { + out32 += 12; + } + } + /* test bits and return */ + if( in16 & 0xC ) { + if( in16 & 0x8 ) + return out32 + 0; + else + return out32 + 1; + } else { + if( in16 & 0xE ) + return out32 + 2; + else + return out32 + 3; + } +} + +#undef SigProcFIX_CLZ32 +static inline opus_int32 SigProcFIX_CLZ32(opus_int32 in32) +{ + /* test highest 16 bits and convert to opus_int16 */ + ops_count += 2; + if( in32 & 0xFFFF0000 ) { + return SigProcFIX_CLZ16((opus_int16)(in32 >> 16)); + } else { + return SigProcFIX_CLZ16((opus_int16)in32) + 16; + } +} + +#undef silk_DIV32 +static inline opus_int32 silk_DIV32(opus_int32 a32, opus_int32 b32){ + ops_count += 64; + return a32 / b32; +} + +#undef silk_DIV32_16 +static inline opus_int32 silk_DIV32_16(opus_int32 a32, opus_int32 b32){ + ops_count += 32; + return a32 / b32; +} + +#undef silk_SAT8 +static inline opus_int8 silk_SAT8(opus_int64 a){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))); + return(tmp); +} + +#undef silk_SAT16 +static inline opus_int16 silk_SAT16(opus_int64 a){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))); + return(tmp); +} +#undef silk_SAT32 +static inline opus_int32 silk_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))); + return(tmp); +} +#undef silk_POS_SAT32 +static inline opus_int32 silk_POS_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : (a)); + return(tmp); +} + +#undef silk_ADD_POS_SAT8 +static inline opus_int8 silk_ADD_POS_SAT8(opus_int64 a, opus_int64 b){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))); + return(tmp); +} +#undef silk_ADD_POS_SAT16 +static inline opus_int16 silk_ADD_POS_SAT16(opus_int64 a, opus_int64 b){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_ADD_POS_SAT32 +static inline opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_ADD_POS_SAT64 +static inline opus_int64 silk_ADD_POS_SAT64(opus_int64 a, opus_int64 b){ + opus_int64 tmp; + ops_count += 1; + tmp = ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_LSHIFT8 +static inline opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){ + opus_int8 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT16 +static inline opus_int16 silk_LSHIFT16(opus_int16 a, opus_int32 shift){ + opus_int16 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT32 +static inline opus_int32 silk_LSHIFT32(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT64 +static inline opus_int64 silk_LSHIFT64(opus_int64 a, opus_int shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_ovflw +static inline opus_int32 silk_LSHIFT_ovflw(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_uint +static inline opus_uint32 silk_LSHIFT_uint(opus_uint32 a, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} + +#undef silk_RSHIFT8 +static inline opus_int8 silk_RSHIFT8(opus_int8 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT16 +static inline opus_int16 silk_RSHIFT16(opus_int16 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT32 +static inline opus_int32 silk_RSHIFT32(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT64 +static inline opus_int64 silk_RSHIFT64(opus_int64 a, opus_int64 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_RSHIFT_uint +static inline opus_uint32 silk_RSHIFT_uint(opus_uint32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_ADD_LSHIFT +static inline opus_int32 silk_ADD_LSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT32 +static inline opus_int32 silk_ADD_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT_uint +static inline opus_uint32 silk_ADD_LSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_RSHIFT +static inline opus_int32 silk_ADD_RSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT32 +static inline opus_int32 silk_ADD_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT_uint +static inline opus_uint32 silk_ADD_RSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_SUB_LSHIFT32 +static inline opus_int32 silk_SUB_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_SUB_RSHIFT32 +static inline opus_int32 silk_SUB_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b >> shift); + return ret; /* shift > 0*/ +} + +#undef silk_RSHIFT_ROUND +static inline opus_int32 silk_RSHIFT_ROUND(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 3; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_RSHIFT_ROUND64 +static inline opus_int64 silk_RSHIFT_ROUND64(opus_int64 a, opus_int32 shift){ + opus_int64 ret; + ops_count += 6; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_abs_int64 +static inline opus_int64 silk_abs_int64(opus_int64 a){ + ops_count += 1; + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN*/ +} + +#undef silk_abs_int32 +static inline opus_int32 silk_abs_int32(opus_int32 a){ + ops_count += 1; + return abs(a); +} + + +#undef silk_min +static silk_min(a, b){ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_max +static silk_max(a, b){ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_sign +static silk_sign(a){ + ops_count += 1; + return ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )); +} + +#undef silk_ADD16 +static inline opus_int16 silk_ADD16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD32 +static inline opus_int32 silk_ADD32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD64 +static inline opus_int64 silk_ADD64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a + b; + return ret; +} + +#undef silk_SUB16 +static inline opus_int16 silk_SUB16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB32 +static inline opus_int32 silk_SUB32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB64 +static inline opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a - b; + return ret; +} + +#undef silk_ADD_SAT16 +static inline opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + /* Nb will be counted in AKP_add32 and silk_SAT16*/ + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_ADD_SAT32 +static inline opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){ + opus_int32 res; + ops_count += 1; + res = ((((a32) + (b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + return res; +} + +#undef silk_ADD_SAT64 +static inline opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + return res; +} + +#undef silk_SUB_SAT16 +static inline opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + silk_assert(0); + /* Nb will be counted in sub-macros*/ + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_SUB_SAT32 +static inline opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) { + opus_int32 res; + ops_count += 1; + res = ((((a32)-(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + return res; +} + +#undef silk_SUB_SAT64 +static inline opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + + return res; +} + +#undef silk_SMULWW +static inline opus_int32 silk_SMULWW(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)); + return ret; +} + +#undef silk_SMLAWW +static inline opus_int32 silk_SMLAWW(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)); + return ret; +} + +#undef silk_min_int +static inline opus_int silk_min_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +#undef silk_min_16 +static inline opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_32 +static inline opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_64 +static inline opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +#undef silk_max_int +static inline opus_int silk_max_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_16 +static inline opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_32 +static inline opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + +#undef silk_max_64 +static inline opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + + +#undef silk_LIMIT_int +static inline opus_int silk_LIMIT_int(opus_int a, opus_int limit1, opus_int limit2) +{ + opus_int ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + + return(ret); +} + +#undef silk_LIMIT_16 +static inline opus_int16 silk_LIMIT_16(opus_int16 a, opus_int16 limit1, opus_int16 limit2) +{ + opus_int16 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + +return(ret); +} + + +#undef silk_LIMIT_32 +static inline opus_int silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2) +{ + opus_int32 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + return(ret); +} + +#else +#define exVarDefine +#define varDefine +#define silk_SaveCount() + +#endif +#endif + diff --git a/media/libopus/silk/MacroDebug.h b/media/libopus/silk/MacroDebug.h new file mode 100644 index 000000000000..9d7e1f8a9b7f --- /dev/null +++ b/media/libopus/silk/MacroDebug.h @@ -0,0 +1,569 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef MACRO_DEBUG_H +#define MACRO_DEBUG_H + +/* Redefine macro functions with extensive assertion in DEBUG mode. + As functions can't be undefined, this file can't work with SigProcFIX_MacroCount.h */ + +#if 0 && defined (_DEBUG) && !defined (silk_MACRO_COUNT) + +#undef silk_ADD16 +static inline opus_int16 silk_ADD16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + + ret = a + b; + silk_assert( ret == silk_ADD_SAT16( a, b )); + return ret; +} + +#undef silk_ADD32 +static inline opus_int32 silk_ADD32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + + ret = a + b; + silk_assert( ret == silk_ADD_SAT32( a, b )); + return ret; +} + +#undef silk_ADD64 +static inline opus_int64 silk_ADD64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + + ret = a + b; + silk_assert( ret == silk_ADD_SAT64( a, b )); + return ret; +} + +#undef silk_SUB16 +static inline opus_int16 silk_SUB16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + + ret = a - b; + silk_assert( ret == silk_SUB_SAT16( a, b )); + return ret; +} + +#undef silk_SUB32 +static inline opus_int32 silk_SUB32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + + ret = a - b; + silk_assert( ret == silk_SUB_SAT32( a, b )); + return ret; +} + +#undef silk_SUB64 +static inline opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + + ret = a - b; + silk_assert( ret == silk_SUB_SAT64( a, b )); + return ret; +} + +#undef silk_ADD_SAT16 +static inline opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + silk_assert( res == silk_SAT16( (opus_int32)a16 + (opus_int32)b16 ) ); + return res; +} + +#undef silk_ADD_SAT32 +static inline opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){ + opus_int32 res; + res = ((((a32) + (b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + silk_assert( res == silk_SAT32( (opus_int64)a32 + (opus_int64)b32 ) ); + return res; +} + +#undef silk_ADD_SAT64 +static inline opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + if( res != a64 + b64 ) { + /* Check that we saturated to the correct extreme value */ + silk_assert( ( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ); + } else { + /* Saturation not necessary */ + silk_assert( res == a64 + b64 ); + } + return res; +} + +#undef silk_SUB_SAT16 +static inline opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + silk_assert( res == silk_SAT16( (opus_int32)a16 - (opus_int32)b16 ) ); + return res; +} + +#undef silk_SUB_SAT32 +static inline opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) { + opus_int32 res; + res = ((((a32)-(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + silk_assert( res == silk_SAT32( (opus_int64)a32 - (opus_int64)b32 ) ); + return res; +} + +#undef silk_SUB_SAT64 +static inline opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + + if( res != a64 - b64 ) { + /* Check that we saturated to the correct extreme value */ + silk_assert( ( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ); + } else { + /* Saturation not necessary */ + silk_assert( res == a64 - b64 ); + } + return res; +} + +#undef silk_MUL +static inline opus_int32 silk_MUL(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + opus_int64 ret64; + ret = a32 * b32; + ret64 = (opus_int64)a32 * (opus_int64)b32; + silk_assert((opus_int64)ret == ret64 ); /* Check output overflow */ + return ret; +} + +#undef silk_MUL_uint +static inline opus_uint32 silk_MUL_uint(opus_uint32 a32, opus_uint32 b32){ + opus_uint32 ret; + ret = a32 * b32; + silk_assert((opus_uint64)ret == (opus_uint64)a32 * (opus_uint64)b32); /* Check output overflow */ + return ret; +} + +#undef silk_MLA +static inline opus_int32 silk_MLA(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ret = a32 + b32 * c32; + silk_assert((opus_int64)ret == (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32); /* Check output overflow */ + return ret; +} + +#undef silk_MLA_uint +static inline opus_int32 silk_MLA_uint(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32){ + opus_uint32 ret; + ret = a32 + b32 * c32; + silk_assert((opus_int64)ret == (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32); /* Check output overflow */ + return ret; +} + +#undef silk_SMULWB +static inline opus_int32 silk_SMULWB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + silk_assert((opus_int64)ret == ((opus_int64)a32 * (opus_int16)b32) >> 16); + return ret; +} + +#undef silk_SMLAWB +static inline opus_int32 silk_SMLAWB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ret = silk_ADD32( a32, silk_SMULWB( b32, c32 ) ); + silk_assert(silk_ADD32( a32, silk_SMULWB( b32, c32 ) ) == silk_ADD_SAT32( a32, silk_SMULWB( b32, c32 ) )); + return ret; +} + +#undef silk_SMULWT +static inline opus_int32 silk_SMULWT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + silk_assert((opus_int64)ret == ((opus_int64)a32 * (b32 >> 16)) >> 16); + return ret; +} + +#undef silk_SMLAWT +static inline opus_int32 silk_SMLAWT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + silk_assert((opus_int64)ret == (opus_int64)a32 + (((opus_int64)b32 * (c32 >> 16)) >> 16)); + return ret; +} + +#undef silk_SMULL +static inline opus_int64 silk_SMULL(opus_int64 a64, opus_int64 b64){ + opus_int64 ret64; + ret64 = a64 * b64; + if( b64 != 0 ) { + silk_assert( a64 == (ret64 / b64) ); + } else if( a64 != 0 ) { + silk_assert( b64 == (ret64 / a64) ); + } + return ret64; +} + +/* no checking needed for silk_SMULBB */ +#undef silk_SMLABB +static inline opus_int32 silk_SMLABB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + silk_assert((opus_int64)ret == (opus_int64)a32 + (opus_int64)b32 * (opus_int16)c32); + return ret; +} + +/* no checking needed for silk_SMULBT */ +#undef silk_SMLABT +static inline opus_int32 silk_SMLABT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + silk_assert((opus_int64)ret == (opus_int64)a32 + (opus_int64)b32 * (c32 >> 16)); + return ret; +} + +/* no checking needed for silk_SMULTT */ +#undef silk_SMLATT +static inline opus_int32 silk_SMLATT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ret = a32 + (b32 >> 16) * (c32 >> 16); + silk_assert((opus_int64)ret == (opus_int64)a32 + (b32 >> 16) * (c32 >> 16)); + return ret; +} + +#undef silk_SMULWW +static inline opus_int32 silk_SMULWW(opus_int32 a32, opus_int32 b32){ + opus_int32 ret, tmp1, tmp2; + opus_int64 ret64; + + ret = silk_SMULWB( a32, b32 ); + tmp1 = silk_RSHIFT_ROUND( b32, 16 ); + tmp2 = silk_MUL( a32, tmp1 ); + + silk_assert( (opus_int64)tmp2 == (opus_int64) a32 * (opus_int64) tmp1 ); + + tmp1 = ret; + ret = silk_ADD32( tmp1, tmp2 ); + silk_assert( silk_ADD32( tmp1, tmp2 ) == silk_ADD_SAT32( tmp1, tmp2 ) ); + + ret64 = silk_RSHIFT64( silk_SMULL( a32, b32 ), 16 ); + silk_assert( (opus_int64)ret == ret64 ); + + return ret; +} + +#undef silk_SMLAWW +static inline opus_int32 silk_SMLAWW(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret, tmp; + + tmp = silk_SMULWW( b32, c32 ); + ret = silk_ADD32( a32, tmp ); + silk_assert( ret == silk_ADD_SAT32( a32, tmp ) ); + return ret; +} + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw(a32, b32, c32) ((a32) + ((b32) * (c32))) +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* no checking needed for silk_SMULL + no checking needed for silk_SMLAL + no checking needed for silk_SMLALBB + no checking needed for SigProcFIX_CLZ16 + no checking needed for SigProcFIX_CLZ32*/ + +#undef silk_DIV32 +static inline opus_int32 silk_DIV32(opus_int32 a32, opus_int32 b32){ + silk_assert( b32 != 0 ); + return a32 / b32; +} + +#undef silk_DIV32_16 +static inline opus_int32 silk_DIV32_16(opus_int32 a32, opus_int32 b32){ + silk_assert( b32 != 0 ); + silk_assert( b32 <= silk_int16_MAX ); + silk_assert( b32 >= silk_int16_MIN ); + return a32 / b32; +} + +/* no checking needed for silk_SAT8 + no checking needed for silk_SAT16 + no checking needed for silk_SAT32 + no checking needed for silk_POS_SAT32 + no checking needed for silk_ADD_POS_SAT8 + no checking needed for silk_ADD_POS_SAT16 + no checking needed for silk_ADD_POS_SAT32 + no checking needed for silk_ADD_POS_SAT64 */ + +#undef silk_LSHIFT8 +static inline opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){ + opus_int8 ret; + ret = a << shift; + silk_assert(shift >= 0); + silk_assert(shift < 8); + silk_assert((opus_int64)ret == ((opus_int64)a) << shift); + return ret; +} + +#undef silk_LSHIFT16 +static inline opus_int16 silk_LSHIFT16(opus_int16 a, opus_int32 shift){ + opus_int16 ret; + ret = a << shift; + silk_assert(shift >= 0); + silk_assert(shift < 16); + silk_assert((opus_int64)ret == ((opus_int64)a) << shift); + return ret; +} + +#undef silk_LSHIFT32 +static inline opus_int32 silk_LSHIFT32(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ret = a << shift; + silk_assert(shift >= 0); + silk_assert(shift < 32); + silk_assert((opus_int64)ret == ((opus_int64)a) << shift); + return ret; +} + +#undef silk_LSHIFT64 +static inline opus_int64 silk_LSHIFT64(opus_int64 a, opus_int shift){ + silk_assert(shift >= 0); + silk_assert(shift < 64); + return a << shift; +} + +#undef silk_LSHIFT_ovflw +static inline opus_int32 silk_LSHIFT_ovflw(opus_int32 a, opus_int32 shift){ + silk_assert(shift >= 0); /* no check for overflow */ + return a << shift; +} + +#undef silk_LSHIFT_uint +static inline opus_uint32 silk_LSHIFT_uint(opus_uint32 a, opus_int32 shift){ + opus_uint32 ret; + ret = a << shift; + silk_assert(shift >= 0); + silk_assert((opus_int64)ret == ((opus_int64)a) << shift); + return ret; +} + +#undef silk_RSHIFT8 +static inline opus_int8 silk_RSHIFT8(opus_int8 a, opus_int32 shift){ + silk_assert(shift >= 0); + silk_assert(shift < 8); + return a >> shift; +} + +#undef silk_RSHIFT16 +static inline opus_int16 silk_RSHIFT16(opus_int16 a, opus_int32 shift){ + silk_assert(shift >= 0); + silk_assert(shift < 16); + return a >> shift; +} + +#undef silk_RSHIFT32 +static inline opus_int32 silk_RSHIFT32(opus_int32 a, opus_int32 shift){ + silk_assert(shift >= 0); + silk_assert(shift < 32); + return a >> shift; +} + +#undef silk_RSHIFT64 +static inline opus_int64 silk_RSHIFT64(opus_int64 a, opus_int64 shift){ + silk_assert(shift >= 0); + silk_assert(shift <= 63); + return a >> shift; +} + +#undef silk_RSHIFT_uint +static inline opus_uint32 silk_RSHIFT_uint(opus_uint32 a, opus_int32 shift){ + silk_assert(shift >= 0); + silk_assert(shift <= 32); + return a >> shift; +} + +#undef silk_ADD_LSHIFT +static inline opus_int32 silk_ADD_LSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + silk_assert(shift >= 0); + silk_assert(shift <= 31); + ret = a + (b << shift); + silk_assert((opus_int64)ret == (opus_int64)a + (((opus_int64)b) << shift)); + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT32 +static inline opus_int32 silk_ADD_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + silk_assert(shift >= 0); + silk_assert(shift <= 31); + ret = a + (b << shift); + silk_assert((opus_int64)ret == (opus_int64)a + (((opus_int64)b) << shift)); + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT_uint +static inline opus_uint32 silk_ADD_LSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + silk_assert(shift >= 0); + silk_assert(shift <= 32); + ret = a + (b << shift); + silk_assert((opus_int64)ret == (opus_int64)a + (((opus_int64)b) << shift)); + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_RSHIFT +static inline opus_int32 silk_ADD_RSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + silk_assert(shift >= 0); + silk_assert(shift <= 31); + ret = a + (b >> shift); + silk_assert((opus_int64)ret == (opus_int64)a + (((opus_int64)b) >> shift)); + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT32 +static inline opus_int32 silk_ADD_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + silk_assert(shift >= 0); + silk_assert(shift <= 31); + ret = a + (b >> shift); + silk_assert((opus_int64)ret == (opus_int64)a + (((opus_int64)b) >> shift)); + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT_uint +static inline opus_uint32 silk_ADD_RSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + silk_assert(shift >= 0); + silk_assert(shift <= 32); + ret = a + (b >> shift); + silk_assert((opus_int64)ret == (opus_int64)a + (((opus_int64)b) >> shift)); + return ret; /* shift > 0 */ +} + +#undef silk_SUB_LSHIFT32 +static inline opus_int32 silk_SUB_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + silk_assert(shift >= 0); + silk_assert(shift <= 31); + ret = a - (b << shift); + silk_assert((opus_int64)ret == (opus_int64)a - (((opus_int64)b) << shift)); + return ret; /* shift >= 0 */ +} + +#undef silk_SUB_RSHIFT32 +static inline opus_int32 silk_SUB_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + silk_assert(shift >= 0); + silk_assert(shift <= 31); + ret = a - (b >> shift); + silk_assert((opus_int64)ret == (opus_int64)a - (((opus_int64)b) >> shift)); + return ret; /* shift > 0 */ +} + +#undef silk_RSHIFT_ROUND +static inline opus_int32 silk_RSHIFT_ROUND(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + silk_assert(shift > 0); /* the marco definition can't handle a shift of zero */ + silk_assert(shift < 32); + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + silk_assert((opus_int64)ret == ((opus_int64)a + ((opus_int64)1 << (shift - 1))) >> shift); + return ret; +} + +#undef silk_RSHIFT_ROUND64 +static inline opus_int64 silk_RSHIFT_ROUND64(opus_int64 a, opus_int32 shift){ + opus_int64 ret; + silk_assert(shift > 0); /* the marco definition can't handle a shift of zero */ + silk_assert(shift < 64); + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +/* silk_abs is used on floats also, so doesn't work... */ +/*#undef silk_abs +static inline opus_int32 silk_abs(opus_int32 a){ + silk_assert(a != 0x80000000); + return (((a) > 0) ? (a) : -(a)); // Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN +}*/ + +#undef silk_abs_int64 +static inline opus_int64 silk_abs_int64(opus_int64 a){ + silk_assert(a != 0x8000000000000000); + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +} + +#undef silk_abs_int32 +static inline opus_int32 silk_abs_int32(opus_int32 a){ + silk_assert(a != 0x80000000); + return abs(a); +} + +#undef silk_CHECK_FIT8 +static inline opus_int8 silk_CHECK_FIT8( opus_int64 a ){ + opus_int8 ret; + ret = (opus_int8)a; + silk_assert( (opus_int64)ret == a ); + return( ret ); +} + +#undef silk_CHECK_FIT16 +static inline opus_int16 silk_CHECK_FIT16( opus_int64 a ){ + opus_int16 ret; + ret = (opus_int16)a; + silk_assert( (opus_int64)ret == a ); + return( ret ); +} + +#undef silk_CHECK_FIT32 +static inline opus_int32 silk_CHECK_FIT32( opus_int64 a ){ + opus_int32 ret; + ret = (opus_int32)a; + silk_assert( (opus_int64)ret == a ); + return( ret ); +} + +/* no checking for silk_NSHIFT_MUL_32_32 + no checking for silk_NSHIFT_MUL_16_16 + no checking needed for silk_min + no checking needed for silk_max + no checking needed for silk_sign +*/ + +#endif +#endif /* MACRO_DEBUG_H */ diff --git a/media/libopus/silk/NLSF2A.c b/media/libopus/silk/NLSF2A.c new file mode 100644 index 000000000000..e7fd5e67d08f --- /dev/null +++ b/media/libopus/silk/NLSF2A.c @@ -0,0 +1,178 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* conversion between prediction filter coefficients and LSFs */ +/* order should be even */ +/* a piecewise linear approximation maps LSF <-> cos(LSF) */ +/* therefore the result is not accurate LSFs, but the two */ +/* functions are accurate inverses of each other */ + +#include "SigProc_FIX.h" +#include "tables.h" + +#define QA 16 + +/* helper function for NLSF2A(..) */ +static inline void silk_NLSF2A_find_poly( + opus_int32 *out, /* O intermediate polynomial, QA [dd+1] */ + const opus_int32 *cLSF, /* I vector of interleaved 2*cos(LSFs), QA [d] */ + opus_int dd /* I polynomial order (= 1/2 * filter order) */ +) +{ + opus_int k, n; + opus_int32 ftmp; + + out[0] = silk_LSHIFT( 1, QA ); + out[1] = -cLSF[0]; + for( k = 1; k < dd; k++ ) { + ftmp = cLSF[2*k]; /* QA*/ + out[k+1] = silk_LSHIFT( out[k-1], 1 ) - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[k] ), QA ); + for( n = k; n > 1; n-- ) { + out[n] += out[n-2] - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[n-1] ), QA ); + } + out[1] -= ftmp; + } +} + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d /* I filter order (should be even) */ +) +{ + /* This ordering was found to maximize quality. It improves numerical accuracy of + silk_NLSF2A_find_poly() compared to "standard" ordering. */ + static const unsigned char ordering16[16] = { + 0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1 + }; + static const unsigned char ordering10[10] = { + 0, 9, 6, 3, 4, 5, 8, 1, 2, 7 + }; + const unsigned char *ordering; + opus_int k, i, dd; + opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta; + opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ]; + opus_int32 maxabs, absval, idx=0, sc_Q16; + + silk_assert( LSF_COS_TAB_SZ_FIX == 128 ); + silk_assert( d==10||d==16 ); + + /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */ + ordering = d == 16 ? ordering16 : ordering10; + for( k = 0; k < d; k++ ) { + silk_assert(NLSF[k] >= 0 ); + + /* f_int on a scale 0-127 (rounded down) */ + f_int = silk_RSHIFT( NLSF[k], 15 - 7 ); + + /* f_frac, range: 0..255 */ + f_frac = NLSF[k] - silk_LSHIFT( f_int, 15 - 7 ); + + silk_assert(f_int >= 0); + silk_assert(f_int < LSF_COS_TAB_SZ_FIX ); + + /* Read start and end value from table */ + cos_val = silk_LSFCosTab_FIX_Q12[ f_int ]; /* Q12 */ + delta = silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val; /* Q12, with a range of 0..200 */ + + /* Linear interpolation */ + cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND( silk_LSHIFT( cos_val, 8 ) + silk_MUL( delta, f_frac ), 20 - QA ); /* QA */ + } + + dd = silk_RSHIFT( d, 1 ); + + /* generate even and odd polynomials using convolution */ + silk_NLSF2A_find_poly( P, &cos_LSF_QA[ 0 ], dd ); + silk_NLSF2A_find_poly( Q, &cos_LSF_QA[ 1 ], dd ); + + /* convert even and odd polynomials to opus_int32 Q12 filter coefs */ + for( k = 0; k < dd; k++ ) { + Ptmp = P[ k+1 ] + P[ k ]; + Qtmp = Q[ k+1 ] - Q[ k ]; + + /* the Ptmp and Qtmp values at this stage need to fit in int32 */ + a32_QA1[ k ] = -Qtmp - Ptmp; /* QA+1 */ + a32_QA1[ d-k-1 ] = Qtmp - Ptmp; /* QA+1 */ + } + + /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */ + for( i = 0; i < 10; i++ ) { + /* Find maximum absolute value and its index */ + maxabs = 0; + for( k = 0; k < d; k++ ) { + absval = silk_abs( a32_QA1[k] ); + if( absval > maxabs ) { + maxabs = absval; + idx = k; + } + } + maxabs = silk_RSHIFT_ROUND( maxabs, QA + 1 - 12 ); /* QA+1 -> Q12 */ + + if( maxabs > silk_int16_MAX ) { + /* Reduce magnitude of prediction coefficients */ + maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */ + sc_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ), + silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) ); + silk_bwexpander_32( a32_QA1, d, sc_Q16 ); + } else { + break; + } + } + + if( i == 10 ) { + /* Reached the last iteration, clip the coefficients */ + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ) ); /* QA+1 -> Q12 */ + a32_QA1[ k ] = silk_LSHIFT( (opus_int32)a_Q12[ k ], QA + 1 - 12 ); + } + } else { + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ + } + } + + for( i = 0; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) { + if( silk_LPC_inverse_pred_gain( a_Q12, d ) < SILK_FIX_CONST( 1.0 / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */ + /* on the unscaled coefficients, convert to Q12 and measure again */ + silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) ); + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ + } + } else { + break; + } + } +} + diff --git a/media/libopus/silk/NLSF_VQ.c b/media/libopus/silk/NLSF_VQ.c new file mode 100644 index 000000000000..45108834386b --- /dev/null +++ b/media/libopus/silk/NLSF_VQ.c @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q26[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +) +{ + opus_int i, m; + opus_int32 diff_Q15, sum_error_Q30, sum_error_Q26; + + silk_assert( LPC_order <= 16 ); + silk_assert( ( LPC_order & 1 ) == 0 ); + + /* Loop over codebook */ + for( i = 0; i < K; i++ ) { + sum_error_Q26 = 0; + for( m = 0; m < LPC_order; m += 2 ) { + /* Compute weighted squared quantization error for index m */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/ + sum_error_Q30 = silk_SMULBB( diff_Q15, diff_Q15 ); + + /* Compute weighted squared quantization error for index m + 1 */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[m + 1], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/ + sum_error_Q30 = silk_SMLABB( sum_error_Q30, diff_Q15, diff_Q15 ); + + sum_error_Q26 = silk_ADD_RSHIFT32( sum_error_Q26, sum_error_Q30, 4 ); + + silk_assert( sum_error_Q26 >= 0 ); + silk_assert( sum_error_Q30 >= 0 ); + } + err_Q26[ i ] = sum_error_Q26; + } +} diff --git a/media/libopus/silk/NLSF_VQ_weights_laroia.c b/media/libopus/silk/NLSF_VQ_weights_laroia.c new file mode 100644 index 000000000000..8e8be43cbe45 --- /dev/null +++ b/media/libopus/silk/NLSF_VQ_weights_laroia.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "define.h" +#include "SigProc_FIX.h" + +/* +R. Laroia, N. Phamdo and N. Farvardin, "Robust and Efficient Quantization of Speech LSP +Parameters Using Structured Vector Quantization", Proc. IEEE Int. Conf. Acoust., Speech, +Signal Processing, pp. 641-644, 1991. +*/ + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +) +{ + opus_int k; + opus_int32 tmp1_int, tmp2_int; + + silk_assert( D > 0 ); + silk_assert( ( D & 1 ) == 0 ); + + /* First value */ + tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 ); + tmp1_int = silk_DIV32_16( 1 << ( 15 + NLSF_W_Q ), tmp1_int ); + tmp2_int = silk_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], 1 ); + tmp2_int = silk_DIV32_16( 1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ 0 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ 0 ] > 0 ); + + /* Main loop */ + for( k = 1; k < D - 1; k += 2 ) { + tmp1_int = silk_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], 1 ); + tmp1_int = silk_DIV32_16( 1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ k ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k ] > 0 ); + + tmp2_int = silk_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], 1 ); + tmp2_int = silk_DIV32_16( 1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ k + 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k + 1 ] > 0 ); + } + + /* Last value */ + tmp1_int = silk_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], 1 ); + tmp1_int = silk_DIV32_16( 1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ D - 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ D - 1 ] > 0 ); +} diff --git a/media/libopus/silk/NLSF_decode.c b/media/libopus/silk/NLSF_decode.c new file mode 100644 index 000000000000..f2c2dec7db1c --- /dev/null +++ b/media/libopus/silk/NLSF_decode.c @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Predictive dequantizer for NLSF residuals */ +static inline void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */ + opus_int16 x_Q10[], /* O Output [ order ] */ + const opus_int8 indices[], /* I Quantization indices [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, out_Q10, pred_Q10; + + out_Q10 = 0; + for( i = order-1; i >= 0; i-- ) { + pred_Q10 = silk_RSHIFT( silk_SMULBB( out_Q10, (opus_int16)pred_coef_Q8[ i ] ), 8 ); + out_Q10 = silk_LSHIFT( indices[ i ], 10 ); + if( out_Q10 > 0 ) { + out_Q10 = silk_SUB16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( out_Q10 < 0 ) { + out_Q10 = silk_ADD16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out_Q10 = silk_SMLAWB( pred_Q10, out_Q10, quant_step_size_Q16 ); + x_Q10[ i ] = out_Q10; + } +} + + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +) +{ + opus_int i; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int16 W_tmp_QW[ MAX_LPC_ORDER ]; + opus_int32 W_tmp_Q9, NLSF_Q15_tmp; + const opus_uint8 *pCB_element; + + /* Decode first stage */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + pNLSF_Q15[ i ] = silk_LSHIFT( (opus_int16)pCB_element[ i ], 7 ); + } + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] ); + + /* Predictive residual dequantizer */ + silk_NLSF_residual_dequant( res_Q10, &NLSFIndices[ 1 ], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order ); + + /* Weights from codebook vector */ + silk_NLSF_VQ_weights_laroia( W_tmp_QW, pNLSF_Q15, psNLSF_CB->order ); + + /* Apply inverse square-rooted weights and add to output */ + for( i = 0; i < psNLSF_CB->order; i++ ) { + W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) ); + NLSF_Q15_tmp = silk_ADD32( pNLSF_Q15[ i ], silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), W_tmp_Q9 ) ); + pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 ); + } + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); +} diff --git a/media/libopus/silk/NLSF_del_dec_quant.c b/media/libopus/silk/NLSF_del_dec_quant.c new file mode 100644 index 000000000000..d2eef3cb9b80 --- /dev/null +++ b/media/libopus/silk/NLSF_del_dec_quant.c @@ -0,0 +1,207 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10; + opus_int pred_Q10, diff_Q10, out0_Q10, out1_Q10, rate0_Q5, rate1_Q5; + opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25, pred_coef_Q16; + opus_int ind_sort[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int8 ind[ NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ]; + opus_int16 prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_Q25[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_min_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_max_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + const opus_uint8 *rates_Q5; + + silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 ); /* must be power of two */ + + nStates = 1; + RD_Q25[ 0 ] = 0; + prev_out_Q10[ 0 ] = 0; + for( i = order - 1; ; i-- ) { + rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ]; + pred_coef_Q16 = silk_LSHIFT( (opus_int32)pred_coef_Q8[ i ], 8 ); + in_Q10 = x_Q10[ i ]; + for( j = 0; j < nStates; j++ ) { + pred_Q10 = silk_SMULWB( pred_coef_Q16, prev_out_Q10[ j ] ); + res_Q10 = silk_SUB16( in_Q10, pred_Q10 ); + ind_tmp = silk_SMULWB( inv_quant_step_size_Q6, res_Q10 ); + ind_tmp = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 ); + ind[ j ][ i ] = (opus_int8)ind_tmp; + + /* compute outputs for ind_tmp and ind_tmp + 1 */ + out0_Q10 = silk_LSHIFT( ind_tmp, 10 ); + out1_Q10 = silk_ADD16( out0_Q10, 1024 ); + if( ind_tmp > 0 ) { + out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( ind_tmp == 0 ) { + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( ind_tmp == -1 ) { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out0_Q10 = silk_SMULWB( out0_Q10, quant_step_size_Q16 ); + out1_Q10 = silk_SMULWB( out1_Q10, quant_step_size_Q16 ); + out0_Q10 = silk_ADD16( out0_Q10, pred_Q10 ); + out1_Q10 = silk_ADD16( out1_Q10, pred_Q10 ); + prev_out_Q10[ j ] = out0_Q10; + prev_out_Q10[ j + nStates ] = out1_Q10; + + /* compute RD for ind_tmp and ind_tmp + 1 */ + if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = 280; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp ); + rate1_Q5 = silk_ADD16( rate0_Q5, 43 ); + } + } else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = 280; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp ); + rate1_Q5 = silk_SUB16( rate0_Q5, 43 ); + } + } else { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } + RD_tmp_Q25 = RD_Q25[ j ]; + diff_Q10 = silk_SUB16( in_Q10, out0_Q10 ); + RD_Q25[ j ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 ); + diff_Q10 = silk_SUB16( in_Q10, out1_Q10 ); + RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 ); + } + + if( nStates < NLSF_QUANT_DEL_DEC_STATES ) { + /* double number of states and copy */ + for( j = 0; j < nStates; j++ ) { + ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1; + } + nStates = silk_LSHIFT( nStates, 1 ); + for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] = ind[ j - nStates ][ i ]; + } + } else if( i > 0 ) { + /* sort lower and upper half of RD_Q25, pairwise */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) { + RD_max_Q25[ j ] = RD_Q25[ j ]; + RD_min_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + RD_Q25[ j ] = RD_min_Q25[ j ]; + RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ]; + /* swap prev_out values */ + out0_Q10 = prev_out_Q10[ j ]; + prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10; + ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES; + } else { + RD_min_Q25[ j ] = RD_Q25[ j ]; + RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + ind_sort[ j ] = j; + } + } + /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */ + /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */ + while( 1 ) { + min_max_Q25 = silk_int32_MAX; + max_min_Q25 = 0; + ind_min_max = 0; + ind_max_min = 0; + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_max_Q25 > RD_max_Q25[ j ] ) { + min_max_Q25 = RD_max_Q25[ j ]; + ind_min_max = j; + } + if( max_min_Q25 < RD_min_Q25[ j ] ) { + max_min_Q25 = RD_min_Q25[ j ]; + ind_max_min = j; + } + } + if( min_max_Q25 >= max_min_Q25 ) { + break; + } + /* copy ind_min_max to ind_max_min */ + ind_sort[ ind_max_min ] = ind_sort[ ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES; + RD_Q25[ ind_max_min ] = RD_Q25[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + RD_min_Q25[ ind_max_min ] = 0; + RD_max_Q25[ ind_min_max ] = silk_int32_MAX; + silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) ); + } + /* increment index if it comes from the upper half */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + } + } else { /* i == 0 */ + break; + } + } + + /* last sample: find winner, copy indices and return RD value */ + ind_tmp = 0; + min_Q25 = silk_int32_MAX; + for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_Q25 > RD_Q25[ j ] ) { + min_Q25 = RD_Q25[ j ]; + ind_tmp = j; + } + } + for( j = 0; j < order; j++ ) { + indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ]; + silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( indices[ j ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + } + indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( min_Q25 >= 0 ); + return min_Q25; +} diff --git a/media/libopus/silk/NLSF_encode.c b/media/libopus/silk/NLSF_encode.c new file mode 100644 index 000000000000..5b204416dff6 --- /dev/null +++ b/media/libopus/silk/NLSF_encode.c @@ -0,0 +1,128 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/***********************/ +/* NLSF vector encoder */ +/***********************/ +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +) +{ + opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7; + opus_int32 W_tmp_Q9; + opus_int32 err_Q26[ NLSF_VQ_MAX_VECTORS ]; + opus_int32 RD_Q25[ NLSF_VQ_MAX_SURVIVORS ]; + opus_int tempIndices1[ NLSF_VQ_MAX_SURVIVORS ]; + opus_int8 tempIndices2[ NLSF_VQ_MAX_SURVIVORS * MAX_LPC_ORDER ]; + opus_int16 res_Q15[ MAX_LPC_ORDER ]; + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ]; + opus_int16 W_tmp_QW[ MAX_LPC_ORDER ]; + opus_int16 W_adj_Q5[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + const opus_uint8 *pCB_element, *iCDF_ptr; + + silk_assert( nSurvivors <= NLSF_VQ_MAX_SURVIVORS ); + silk_assert( signalType >= 0 && signalType <= 2 ); + silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 ); + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); + + /* First stage: VQ */ + silk_NLSF_VQ( err_Q26, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->nVectors, psNLSF_CB->order ); + + /* Sort the quantization errors */ + silk_insertion_sort_increasing( err_Q26, tempIndices1, psNLSF_CB->nVectors, nSurvivors ); + + /* Loop over survivors */ + for( s = 0; s < nSurvivors; s++ ) { + ind1 = tempIndices1[ s ]; + + /* Residual after first stage */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 ); + res_Q15[ i ] = pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ]; + } + + /* Weights from codebook vector */ + silk_NLSF_VQ_weights_laroia( W_tmp_QW, NLSF_tmp_Q15, psNLSF_CB->order ); + + /* Apply square-rooted weights */ + for( i = 0; i < psNLSF_CB->order; i++ ) { + W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) ); + res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( res_Q15[ i ], W_tmp_Q9 ), 14 ); + } + + /* Modify input weights accordingly */ + for( i = 0; i < psNLSF_CB->order; i++ ) { + W_adj_Q5[ i ] = silk_DIV32_16( silk_LSHIFT( (opus_int32)pW_QW[ i ], 5 ), W_tmp_QW[ i ] ); + } + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 ); + + /* Trellis quantizer */ + RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], res_Q10, W_adj_Q5, pred_Q8, ec_ix, + psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order ); + + /* Add rate for first stage */ + iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ]; + if( ind1 == 0 ) { + prob_Q8 = 256 - iCDF_ptr[ ind1 ]; + } else { + prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ]; + } + bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 ); + RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) ); + } + + /* Find the lowest rate-distortion error */ + silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 ); + + NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ]; + silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) ); + + /* Decode */ + silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB ); + + return RD_Q25[ 0 ]; +} diff --git a/media/libopus/silk/NLSF_stabilize.c b/media/libopus/silk/NLSF_stabilize.c new file mode 100644 index 000000000000..d818ff087086 --- /dev/null +++ b/media/libopus/silk/NLSF_stabilize.c @@ -0,0 +1,142 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* NLSF stabilizer: */ +/* */ +/* - Moves NLSFs futher apart if they are too close */ +/* - Moves NLSFs away from borders if they are too close */ +/* - High effort to achieve a modification with minimum */ +/* Euclidean distance to input vector */ +/* - Output are sorted NLSF coefficients */ +/* */ + +#include "SigProc_FIX.h" + +/* Constant Definitions */ +#define MAX_LOOPS 20 + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +) +{ + opus_int i, I=0, k, loops; + opus_int16 center_freq_Q15; + opus_int32 diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15; + + /* This is necessary to ensure an output within range of a opus_int16 */ + silk_assert( NDeltaMin_Q15[L] >= 1 ); + + for( loops = 0; loops < MAX_LOOPS; loops++ ) { + /**************************/ + /* Find smallest distance */ + /**************************/ + /* First element */ + min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0]; + I = 0; + /* Middle elements */ + for( i = 1; i <= L-1; i++ ) { + diff_Q15 = NLSF_Q15[i] - ( NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = i; + } + } + /* Last element */ + diff_Q15 = ( 1 << 15 ) - ( NLSF_Q15[L-1] + NDeltaMin_Q15[L] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = L; + } + + /***************************************************/ + /* Now check if the smallest distance non-negative */ + /***************************************************/ + if( min_diff_Q15 >= 0 ) { + return; + } + + if( I == 0 ) { + /* Move away from lower limit */ + NLSF_Q15[0] = NDeltaMin_Q15[0]; + + } else if( I == L) { + /* Move away from higher limit */ + NLSF_Q15[L-1] = ( 1 << 15 ) - NDeltaMin_Q15[L]; + + } else { + /* Find the lower extreme for the location of the current center frequency */ + min_center_Q15 = 0; + for( k = 0; k < I; k++ ) { + min_center_Q15 += NDeltaMin_Q15[k]; + } + min_center_Q15 += silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Find the upper extreme for the location of the current center frequency */ + max_center_Q15 = 1 << 15; + for( k = L; k > I; k-- ) { + max_center_Q15 -= NDeltaMin_Q15[k]; + } + max_center_Q15 -= silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Move apart, sorted by value, keeping the same center frequency */ + center_freq_Q15 = (opus_int16)silk_LIMIT_32( silk_RSHIFT_ROUND( (opus_int32)NLSF_Q15[I-1] + (opus_int32)NLSF_Q15[I], 1 ), + min_center_Q15, max_center_Q15 ); + NLSF_Q15[I-1] = center_freq_Q15 - silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + NLSF_Q15[I] = NLSF_Q15[I-1] + NDeltaMin_Q15[I]; + } + } + + /* Safe and simple fall back method, which is less ideal than the above */ + if( loops == MAX_LOOPS ) + { + /* Insertion sort (fast for already almost sorted arrays): */ + /* Best case: O(n) for an already sorted array */ + /* Worst case: O(n^2) for an inversely sorted array */ + silk_insertion_sort_increasing_all_values_int16( &NLSF_Q15[0], L ); + + /* First NLSF should be no less than NDeltaMin[0] */ + NLSF_Q15[0] = silk_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] ); + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) + NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] ); + + /* Keep NDeltaMin distance between the NLSFs */ + for( i = L-2; i >= 0; i-- ) + NLSF_Q15[i] = silk_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] ); + } +} diff --git a/media/libopus/silk/NLSF_unpack.c b/media/libopus/silk/NLSF_unpack.c new file mode 100644 index 000000000000..9db49265050a --- /dev/null +++ b/media/libopus/silk/NLSF_unpack.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +) +{ + opus_int i; + opus_uint8 entry; + const opus_uint8 *ec_sel_ptr; + + ec_sel_ptr = &psNLSF_CB->ec_sel[ CB1_index * psNLSF_CB->order / 2 ]; + for( i = 0; i < psNLSF_CB->order; i += 2 ) { + entry = *ec_sel_ptr++; + ec_ix [ i ] = silk_SMULBB( silk_RSHIFT( entry, 1 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i ] = psNLSF_CB->pred_Q8[ i + ( entry & 1 ) * ( psNLSF_CB->order - 1 ) ]; + ec_ix [ i + 1 ] = silk_SMULBB( silk_RSHIFT( entry, 5 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i + 1 ] = psNLSF_CB->pred_Q8[ i + ( silk_RSHIFT( entry, 4 ) & 1 ) * ( psNLSF_CB->order - 1 ) + 1 ]; + } +} + diff --git a/media/libopus/silk/NSQ.c b/media/libopus/silk/NSQ.c new file mode 100644 index 000000000000..0c2abaf884d9 --- /dev/null +++ b/media/libopus/silk/NSQ.c @@ -0,0 +1,439 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +static inline void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int32 x_Q3[], /* I input in Q3 */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +); + +static inline void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder /* I Prediction filter order */ +); + +void silk_NSQ( + const silk_encoder_state *psEncC, /* I/O Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int k, lag, start_idx, LSF_interpolation_flag; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + opus_int32 sLTP_Q15[ 2 * MAX_FRAME_LENGTH ]; + opus_int16 sLTP[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 x_sc_Q10[ MAX_SUB_FRAME_LENGTH ]; + + NSQ->rand_seed = psIndices->Seed; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + /* Set up pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + silk_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + } + } + + silk_nsq_scale_states( psEncC, NSQ, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType ); + + silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10, + offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder ); + + x_Q3 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech and noise shaping signals */ + /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[ psEncC->ltp_mem_length ], psEncC->frame_length * sizeof( opus_int16 ) ) */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); +} + +/***********************************/ +/* silk_noise_shape_quantizer */ +/***********************************/ +static inline void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder /* I Prediction filter order */ +) +{ + opus_int i, j; + opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13; + opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20; + opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + /* Set up short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + + for( i = 0; i < length; i++ ) { + /* Generate dither */ + NSQ->rand_seed = silk_RAND( NSQ->rand_seed ); + + /* Short-term prediction */ + silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( predictLPCOrder, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ 0 ], a_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -1 ], a_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], a_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -3 ], a_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], a_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -5 ], a_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], a_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -7 ], a_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + if( predictLPCOrder == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -10 ], a_Q12[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -11 ], a_Q12[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -12 ], a_Q12[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -13 ], a_Q12[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -14 ], a_Q12[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -15 ], a_Q12[ 15 ] ); + } + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } else { + LTP_pred_Q13 = 0; + } + + /* Noise shape feedback */ + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + tmp2 = psLPC_Q14[ 0 ]; + tmp1 = NSQ->sAR2_Q14[ 0 ]; + NSQ->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q12 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp2, AR_shp_Q13[ 0 ] ); + for( j = 2; j < shapingLPCOrder; j += 2 ) { + tmp2 = NSQ->sAR2_Q14[ j - 1 ]; + NSQ->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp1, AR_shp_Q13[ j - 1 ] ); + tmp1 = NSQ->sAR2_Q14[ j + 0 ]; + NSQ->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp2, AR_shp_Q13[ j ] ); + } + NSQ->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q12 = silk_LSHIFT32( n_AR_Q12, 1 ); /* Q11 -> Q12 */ + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 ); + + n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ); + n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 ); + + silk_assert( lag > 0 || signalType != TYPE_VOICED ); + + /* Combine prediction and noise shaping signals */ + tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */ + tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 ); + shp_lag_ptr++; + + tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */ + tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */ + } else { + tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */ + } + + r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( NSQ->rand_seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* Q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 ); + + if( rd2_Q20 < rd1_Q20 ) { + q1_Q10 = q2_Q10; + } + + pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 ); + + /* Excitation */ + exc_Q14 = silk_LSHIFT( q1_Q10, 4 ); + if ( NSQ->rand_seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 ); + xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 ); + + /* Scale XQ back to normal level before saving */ + xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) ); + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = xq_Q14; + sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, n_AR_Q12, 2 ); + NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14; + + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 ); + sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] ); + } + + /* Update LPC synth buffer */ + silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); +} + +static inline void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int32 x_Q3[], /* I input in Q3 */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Calculate gain adjustment factor */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + } else { + gain_adj_Q16 = 1 << 16; + } + + /* Scale input */ + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( gain_adj_Q16 != 1 << 16 ) { + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + } +} diff --git a/media/libopus/silk/NSQ_del_dec.c b/media/libopus/silk/NSQ_del_dec.c new file mode 100644 index 000000000000..d4ee0fbc818a --- /dev/null +++ b/media/libopus/silk/NSQ_del_dec.c @@ -0,0 +1,705 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 RandState[ DECISION_DELAY ]; + opus_int32 Q_Q10[ DECISION_DELAY ]; + opus_int32 Xq_Q14[ DECISION_DELAY ]; + opus_int32 Pred_Q15[ DECISION_DELAY ]; + opus_int32 Shape_Q14[ DECISION_DELAY ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_AR_Q14; + opus_int32 Seed; + opus_int32 SeedInit; + opus_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + opus_int32 Q_Q10; + opus_int32 RD_Q10; + opus_int32 xq_Q14; + opus_int32 LF_AR_Q14; + opus_int32 sLTP_shp_Q14; + opus_int32 LPC_exc_Q14; +} NSQ_sample_struct; + +static inline void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int32 x_Q3[], /* I Input in Q3 */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static inline void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +); + +void silk_NSQ_del_dec( + const silk_encoder_state *psEncC, /* I/O Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int last_smple_idx, smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + opus_int32 sLTP_Q15[ 2 * MAX_FRAME_LENGTH ]; + opus_int16 sLTP[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + opus_int32 x_sc_Q10[ MAX_SUB_FRAME_LENGTH ]; + opus_int32 delayedGain_Q10[ DECISION_DELAY ]; + NSQ_del_dec_struct psDelDec[ MAX_DEL_DEC_STATES ]; + NSQ_del_dec_struct *psDD; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psIndices->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14; + psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ]; + silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + for( k = 0; k < psEncC->nb_subfr; k++ ) { + decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ i ].RD_Q10; + Winner_ind = i; + } + } + for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) { + if( i != Winner_ind ) { + psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 ); + silk_assert( psDelDec[ i ].RD_Q10 >= 0 ); + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + silk_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, + psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], + Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder, + psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay ); + + x_Q3 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ k ].RD_Q10; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + psIndices->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[psEncC->ltp_mem_length], psEncC->frame_length * sizeof( opus_int16 ) ) */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static inline void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; + NSQ_sample_struct psSampleState[ MAX_DEL_DEC_STATES ][ 2 ]; + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + + silk_assert( nStatesDelayedDecision > 0 ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q14 = silk_RSHIFT( predictLPCOrder, 1 ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ 0 ], a_Q12[ 0 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -1 ], a_Q12[ 1 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -2 ], a_Q12[ 2 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -3 ], a_Q12[ 3 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -4 ], a_Q12[ 4 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -5 ], a_Q12[ 5 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -6 ], a_Q12[ 6 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -7 ], a_Q12[ 7 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + if( predictLPCOrder == 16 ) { + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -10 ], a_Q12[ 10 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -11 ], a_Q12[ 11 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -12 ], a_Q12[ 12 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -13 ], a_Q12[ 13 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -14 ], a_Q12[ 14 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -15 ], a_Q12[ 15 ] ); + } + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK; /* Index to newest samples */ + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK; /* Index to decisionDelay old samples */ + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ]; + for( k = 0; k < nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } +} + +static inline void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int32 x_Q3[], /* I Input in Q3 */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, k, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; + NSQ_del_dec_struct *psDD; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Calculate gain adjustment factor */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + } else { + gain_adj_Q16 = 1 << 16; + } + + /* Scale input */ + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( gain_adj_Q16 != 1 << 16 ) { + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] ); + psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] ); + } + } + } +} diff --git a/media/libopus/silk/PLC.c b/media/libopus/silk/PLC.c new file mode 100644 index 000000000000..0a5d132a247c --- /dev/null +++ b/media/libopus/silk/PLC.c @@ -0,0 +1,416 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "PLC.h" + +#define NB_ATT 2 +static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ +static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ +static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ + +static inline void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +); + +static inline void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 signal[] /* O LPC residual signal */ +); + + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 ); + psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.subfr_length = 20; + psDec->sPLC.nb_subfr = 2; +} + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost /* I Loss flag */ +) +{ + /* PLC control function */ + if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { + silk_PLC_Reset( psDec ); + psDec->sPLC.fs_kHz = psDec->fs_kHz; + } + + if( lost ) { + /****************************/ + /* Generate Signal */ + /****************************/ + silk_PLC_conceal( psDec, psDecCtrl, frame ); + + psDec->lossCnt++; + } else { + /****************************/ + /* Update state */ + /****************************/ + silk_PLC_update( psDec, psDecCtrl ); + } +} + +/**************************************************/ +/* Update state of PLC */ +/**************************************************/ +static inline void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +) +{ + opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; + opus_int i, j; + silk_PLC_struct *psPLC; + + psPLC = &psDec->sPLC; + + /* Update parameters used in case of packet loss */ + psDec->prevSignalType = psDec->indices.signalType; + LTP_Gain_Q14 = 0; + if( psDec->indices.signalType == TYPE_VOICED ) { + /* Find the parameters for the last subframe which contains a pitch pulse */ + for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) { + if( j == psDec->nb_subfr ) { + break; + } + temp_LTP_Gain_Q14 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ]; + } + if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { + LTP_Gain_Q14 = temp_LTP_Gain_Q14; + silk_memcpy( psPLC->LTPCoef_Q14, + &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ], + LTP_ORDER * sizeof( opus_int16 ) ); + + psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 ); + } + } + + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; + + /* Limit LT coefs */ + if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { + opus_int scale_Q10; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); + scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); + } + } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { + opus_int scale_Q14; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); + scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); + } + } + } else { + psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 ); + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 )); + } + + /* Save LPC coeficients */ + silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; + + /* Save last two gains */ + silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) ); + + psPLC->subfr_length = psDec->subfr_length; + psPLC->nb_subfr = psDec->nb_subfr; +} + +static inline void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[] /* O LPC residual signal */ +) +{ + opus_int i, j, k; + opus_int lag, idx, sLTP_buf_idx, shift1, shift2; + opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; + opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; + opus_int32 LPC_pred_Q10, LTP_pred_Q12; + opus_int16 rand_scale_Q14; + opus_int16 *B_Q14, *exc_buf_ptr; + opus_int32 *sLPC_Q14_ptr; + opus_int16 exc_buf[ 2 * MAX_SUB_FRAME_LENGTH ]; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; + opus_int16 sLTP[ MAX_FRAME_LENGTH ]; + opus_int32 sLTP_Q14[ 2 * MAX_FRAME_LENGTH ]; + silk_PLC_struct *psPLC = &psDec->sPLC; + opus_int32 prevGain_Q10[2]; + + prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); + prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); + + if( psDec->first_frame_after_reset ) { + silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); + } + + /* Find random noise component */ + /* Scale previous excitation signal */ + exc_buf_ptr = exc_buf; + for( k = 0; k < 2; k++ ) { + for( i = 0; i < psPLC->subfr_length; i++ ) { + exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( + silk_SMULWW( psDec->exc_Q14[ i + ( k + psPLC->nb_subfr - 2 ) * psPLC->subfr_length ], prevGain_Q10[ k ] ), 8 ) ); + } + exc_buf_ptr += psPLC->subfr_length; + } + /* Find the subframe with lowest energy of the last two and use that as random noise generator */ + silk_sum_sqr_shift( &energy1, &shift1, exc_buf, psPLC->subfr_length ); + silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psPLC->subfr_length ], psPLC->subfr_length ); + + if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { + /* First sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } else { + /* Second sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } + + /* Set up Gain to random noise component */ + B_Q14 = psPLC->LTPCoef_Q14; + rand_scale_Q14 = psPLC->randScale_Q14; + + /* Set up attenuation gains */ + harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + if( psDec->prevSignalType == TYPE_VOICED ) { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } else { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } + + /* LPC concealment. Apply BWE to previous LPC */ + silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* First Lost frame */ + if( psDec->lossCnt == 0 ) { + rand_scale_Q14 = 1 << 14; + + /* Reduce random noise Gain for voiced frames */ + if( psDec->prevSignalType == TYPE_VOICED ) { + for( i = 0; i < LTP_ORDER; i++ ) { + rand_scale_Q14 -= B_Q14[ i ]; + } + rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ + rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); + } else { + /* Reduce random noise for unvoiced frames with high LPC gain */ + opus_int32 invGain_Q30, down_scale_Q30; + + invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order ); + + down_scale_Q30 = silk_min_32( silk_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); + down_scale_Q30 = silk_max_32( silk_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); + down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); + + rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); + } + } + + rand_seed = psPLC->rand_seed; + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + sLTP_buf_idx = psDec->ltp_mem_length; + + /* Rewhiten LTP state */ + idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + silk_assert( idx > 0 ); + silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order ); + /* Scale LTP state */ + inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); + inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); + for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { + sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); + } + + /***************************/ + /* LTP synthesis filtering */ + /***************************/ + for( k = 0; k < psDec->nb_subfr; k++ ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q12 = 2; + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + rand_seed = silk_RAND( rand_seed ); + idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; + sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); + sLTP_buf_idx++; + } + + /* Gradually reduce LTP gain */ + for( j = 0; j < LTP_ORDER; j++ ) { + B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); + } + /* Gradually reduce excitation gain */ + rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); + + /* Slowly increase pitch lag */ + psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); + psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + } + + /***************************/ + /* LPC synthesis filtering */ + /***************************/ + sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ + for( i = 0; i < psDec->frame_length; i++ ) { + /* partly unrolled */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + for( j = 10; j < psDec->LPC_order; j++ ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 ); + + /* Scale with Gain */ + frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) ); + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + /**************************************/ + /* Update states */ + /**************************************/ + psPLC->rand_seed = rand_seed; + psPLC->randScale_Q14 = rand_scale_Q14; + for( i = 0; i < MAX_NB_SUBFR; i++ ) { + psDecCtrl->pitchL[ i ] = lag; + } +} + +/* Glues concealed frames with new good recieved frames */ +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +) +{ + opus_int i, energy_shift; + opus_int32 energy; + silk_PLC_struct *psPLC; + psPLC = &psDec->sPLC; + + if( psDec->lossCnt ) { + /* Calculate energy in concealed residual */ + silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); + + psPLC->last_frame_lost = 1; + } else { + if( psDec->sPLC.last_frame_lost ) { + /* Calculate residual in decoded signal if last frame was lost */ + silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); + + /* Normalize energies */ + if( energy_shift > psPLC->conc_energy_shift ) { + psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); + } else if( energy_shift < psPLC->conc_energy_shift ) { + energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); + } + + /* Fade in the energy difference */ + if( energy > psPLC->conc_energy ) { + opus_int32 frac_Q24, LZ; + opus_int32 gain_Q16, slope_Q16; + + LZ = silk_CLZ32( psPLC->conc_energy ); + LZ = LZ - 1; + psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); + energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); + + frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); + + gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); + slope_Q16 = silk_DIV32_16( ( 1 << 16 ) - gain_Q16, length ); + /* Make slope 4x steeper to avoid missing onsets after DTX */ + slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); + + for( i = 0; i < length; i++ ) { + frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); + gain_Q16 += slope_Q16; + if( gain_Q16 > 1 << 16 ) { + break; + } + } + } + } + psPLC->last_frame_lost = 0; + } +} diff --git a/media/libopus/silk/PLC.h b/media/libopus/silk/PLC.h new file mode 100644 index 000000000000..6233fa6d8228 --- /dev/null +++ b/media/libopus/silk/PLC.h @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_PLC_H +#define SILK_PLC_H + +#include "main.h" + +#define BWE_COEF 0.99 +#define V_PITCH_GAIN_START_MIN_Q14 11469 /* 0.7 in Q14 */ +#define V_PITCH_GAIN_START_MAX_Q14 15565 /* 0.95 in Q14 */ +#define MAX_PITCH_LAG_MS 18 +#define SA_THRES_Q8 50 +#define RAND_BUF_SIZE 128 +#define RAND_BUF_MASK ( RAND_BUF_SIZE - 1 ) +#define LOG2_INV_LPC_GAIN_HIGH_THRES 3 /* 2^3 = 8 dB LPC gain */ +#define LOG2_INV_LPC_GAIN_LOW_THRES 8 /* 2^8 = 24 dB LPC gain */ +#define PITCH_DRIFT_FAC_Q16 655 /* 0.01 in Q16 */ + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost /* I Loss flag */ +); + +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +); + +#endif + diff --git a/media/libopus/silk/SigProc_FIX.h b/media/libopus/silk/SigProc_FIX.h new file mode 100644 index 000000000000..02d9b78bfd23 --- /dev/null +++ b/media/libopus/silk/SigProc_FIX.h @@ -0,0 +1,594 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_H +#define SILK_SIGPROC_FIX_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*#define silk_MACRO_COUNT */ /* Used to enable WMOPS counting */ + +#define SILK_MAX_ORDER_LPC 16 /* max order of the LPC analysis in schur() and k2a() */ + +#include /* for abs() */ +#include /* for memset(), memcpy(), memmove() */ +#include "typedef.h" +#include "resampler_structs.h" +#include "macros.h" + + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/*! + * Initialize/reset the resampler state for a given pair of input/output sampling rates +*/ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +); + +/*! + * Resampler: convert from one sampling rate to another + */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! +* Downsample 2x, mediocre quality +*/ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ len ] */ + const opus_int16 *in, /* I Input signal [ floor(len/2) ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * Downsample by a factor 2/3, low quality +*/ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * second order ARMA filter; + * slower than biquad() but uses more precise coefficients + * can handle (slowly) varying coefficients + */ +void silk_biquad_alt( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len, /* I signal length (must be even) */ + opus_int stride /* I Operate on interleaved signal if > 1 */ +); + +/* Variable order MA prediction error filter. */ +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d /* I Filter order */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +); + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +); + +/* For input in Q24 domain */ +opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int32 *A_Q24, /* I Prediction coefficients [order] */ + const opus_int order /* I Prediction order */ +); + +/* Split signal in two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +); + +/********************************************************************/ +/* SCALAR FUNCTIONS */ +/********************************************************************/ + +/* Approximation of 128 * log2() (exact inverse of approx 2^() below) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +); + +/* Approximation of a sigmoid function */ +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +); + +/* Approximation of 2^() (exact inverse of approx log2() above) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +); + +/* Function that returns the maximum absolut value of the input vector */ +opus_int16 silk_int16_array_maxabs( /* O Maximum absolute value, max: 2^15-1 */ + const opus_int16 *vec, /* I Input vector [len] */ + const opus_int32 len /* I Length of input vector */ +); + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* every other sample of window is linearly interpolated, for speed */ +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount /* I Number of correlation taps to compute */ +); + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +); + +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q15, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr /* I number of 5 ms subframes */ +); + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +); + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d /* I filter order (should be even) */ +); + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +); + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +); + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +); + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceeding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D /* I Order */ +); + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +); + +/* Some for the LTP related function requires Q26 to work.*/ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +); + +/********************************************************************/ +/* INLINE ARM MATH */ +/********************************************************************/ + +/* return sum( inVec1[i] * inVec2[i] ) */ +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +); + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +); + +opus_int64 silk_inner_prod16_aligned_64( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating + left. Output is 32bit int. + Note: contemporary compilers recognize the C expression below and + compile it into a 'ror' instruction if available. No need for inline ASM! */ +static inline opus_int32 silk_ROR32( opus_int32 a32, opus_int rot ) +{ + opus_uint32 x = (opus_uint32) a32; + opus_uint32 r = (opus_uint32) rot; + opus_uint32 m = (opus_uint32) -rot; + if( rot == 0 ) { + return a32; + } else if( rot < 0 ) { + return (opus_int32) ((x << m) | (x >> (32 - m))); + } else { + return (opus_int32) ((x << (32 - r)) | (x >> r)); + } +} + +/* Allocate opus_int16 alligned to 4-byte memory address */ +#if EMBEDDED_ARM +#define silk_DWORD_ALIGN __attribute__((aligned(4))) +#else +#define silk_DWORD_ALIGN +#endif + +/* Useful Macros that can be adjusted to other platforms */ +#define silk_memcpy(dest, src, size) memcpy((dest), (src), (size)) +#define silk_memset(dest, src, size) memset((dest), (src), (size)) +#define silk_memmove(dest, src, size) memmove((dest), (src), (size)) + +/* Fixed point macros */ + +/* (a32 * b32) output have to be 32bit int */ +#define silk_MUL(a32, b32) ((a32) * (b32)) + +/* (a32 * b32) output have to be 32bit uint */ +#define silk_MUL_uint(a32, b32) silk_MUL(a32, b32) + +/* a32 + (b32 * c32) output have to be 32bit int */ +#define silk_MLA(a32, b32, c32) silk_ADD32((a32),((b32) * (c32))) + +/* a32 + (b32 * c32) output have to be 32bit uint */ +#define silk_MLA_uint(a32, b32, c32) silk_MLA(a32, b32, c32) + +/* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16)) + +/* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMLATT(a32, b32, c32) silk_ADD32((a32),((b32) >> 16) * ((c32) >> 16)) + +#define silk_SMLALBB(a64, b16, c16) silk_ADD64((a64),(opus_int64)((opus_int32)(b16) * (opus_int32)(c16))) + +/* (a32 * b32) */ +#define silk_SMULL(a32, b32) ((opus_int64)(a32) * /*(opus_int64)*/(b32)) + +/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define silk_ADD32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) + (opus_uint32)(b))) +/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define silk_SUB32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) - (opus_uint32)(b))) + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#define silk_MLA_ovflw(a32, b32, c32) silk_ADD32_ovflw((a32), (opus_uint32)(b32) * (opus_uint32)(c32)) +#define silk_SMLABB_ovflw(a32, b32, c32) (silk_ADD32_ovflw((a32) , ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))) + +#define silk_DIV32_16(a32, b16) ((opus_int32)((a32) / (b16))) +#define silk_DIV32(a32, b32) ((opus_int32)((a32) / (b32))) + +/* These macros enables checking for overflow in silk_API_Debug.h*/ +#define silk_ADD16(a, b) ((a) + (b)) +#define silk_ADD32(a, b) ((a) + (b)) +#define silk_ADD64(a, b) ((a) + (b)) + +#define silk_SUB16(a, b) ((a) - (b)) +#define silk_SUB32(a, b) ((a) - (b)) +#define silk_SUB64(a, b) ((a) - (b)) + +#define silk_SAT8(a) ((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))) +#define silk_SAT16(a) ((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))) +#define silk_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))) + +#define silk_CHECK_FIT8(a) (a) +#define silk_CHECK_FIT16(a) (a) +#define silk_CHECK_FIT32(a) (a) + +#define silk_ADD_SAT16(a, b) (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a), (b) ) ) +#define silk_ADD_SAT64(a, b) ((((a) + (b)) & 0x8000000000000000LL) == 0 ? \ + ((((a) & (b)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a)+(b)) ) + +#define silk_SUB_SAT16(a, b) (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a), (b) ) ) +#define silk_SUB_SAT64(a, b) ((((a)-(b)) & 0x8000000000000000LL) == 0 ? \ + (( (a) & ((b)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a)-(b)) : \ + ((((a)^0x8000000000000000LL) & (b) & 0x8000000000000000LL) ? silk_int64_MAX : (a)-(b)) ) + +/* Saturation for positive input values */ +#define silk_POS_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : (a)) + +/* Add with saturation for positive input values */ +#define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT32(a, b) ((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT64(a, b) ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b))) + +#define silk_LSHIFT8(a, shift) ((opus_int8)((opus_uint8)(a)<<(shift))) /* shift >= 0, shift < 8 */ +#define silk_LSHIFT16(a, shift) ((opus_int16)((opus_uint16)(a)<<(shift))) /* shift >= 0, shift < 16 */ +#define silk_LSHIFT32(a, shift) ((opus_int32)((opus_uint32)(a)<<(shift))) /* shift >= 0, shift < 32 */ +#define silk_LSHIFT64(a, shift) ((opus_int64)((opus_uint64)(a)<<(shift))) /* shift >= 0, shift < 64 */ +#define silk_LSHIFT(a, shift) silk_LSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +#define silk_RSHIFT8(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 8 */ +#define silk_RSHIFT16(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 16 */ +#define silk_RSHIFT32(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 32 */ +#define silk_RSHIFT64(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 64 */ +#define silk_RSHIFT(a, shift) silk_RSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +/* saturates before shifting */ +#define silk_LSHIFT_SAT16(a, shift) (silk_LSHIFT16( silk_LIMIT( (a), silk_RSHIFT16( silk_int16_MIN, (shift) ), \ + silk_RSHIFT16( silk_int16_MAX, (shift) ) ), (shift) )) +#define silk_LSHIFT_SAT32(a, shift) (silk_LSHIFT32( silk_LIMIT( (a), silk_RSHIFT32( silk_int32_MIN, (shift) ), \ + silk_RSHIFT32( silk_int32_MAX, (shift) ) ), (shift) )) + +#define silk_LSHIFT_ovflw(a, shift) ((opus_int32)((opus_uint32)(a) << (shift))) /* shift >= 0, allowed to overflow */ +#define silk_LSHIFT_uint(a, shift) ((a) << (shift)) /* shift >= 0 */ +#define silk_RSHIFT_uint(a, shift) ((a) >> (shift)) /* shift >= 0 */ + +#define silk_ADD_LSHIFT(a, b, shift) ((a) + silk_LSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT32(a, b, shift) silk_ADD32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT_uint(a, b, shift) ((a) + silk_LSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT(a, b, shift) ((a) + silk_RSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT32(a, b, shift) silk_ADD32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT_uint(a, b, shift) ((a) + silk_RSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_SUB_LSHIFT32(a, b, shift) silk_SUB32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_SUB_RSHIFT32(a, b, shift) silk_SUB32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ + +/* Requires that shift > 0 */ +#define silk_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) +#define silk_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) + +/* Number of rightshift required to fit the multiplication */ +#define silk_NSHIFT_MUL_32_32(a, b) ( -(31- (32-silk_CLZ32(silk_abs(a)) + (32-silk_CLZ32(silk_abs(b))))) ) +#define silk_NSHIFT_MUL_16_16(a, b) ( -(15- (16-silk_CLZ16(silk_abs(a)) + (16-silk_CLZ16(silk_abs(b))))) ) + + +#define silk_min(a, b) (((a) < (b)) ? (a) : (b)) +#define silk_max(a, b) (((a) > (b)) ? (a) : (b)) + +/* Macro to convert floating-point constants to fixed-point */ +#define SILK_FIX_CONST( C, Q ) ((opus_int32)((C) * ((opus_int64)1 << (Q)) + 0.5)) + +/* silk_min() versions with typecast in the function call */ +static inline opus_int silk_min_int(opus_int a, opus_int b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static inline opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static inline opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static inline opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +static inline opus_int silk_max_int(opus_int a, opus_int b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static inline opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static inline opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static inline opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + return (((a) > (b)) ? (a) : (b)); +} + +#define silk_LIMIT( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + +#define silk_LIMIT_int silk_LIMIT +#define silk_LIMIT_16 silk_LIMIT +#define silk_LIMIT_32 silk_LIMIT + +#define silk_abs(a) (((a) > 0) ? (a) : -(a)) /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +#define silk_abs_int(a) (((a) ^ ((a) >> (8 * sizeof(a) - 1))) - ((a) >> (8 * sizeof(a) - 1))) +#define silk_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31)) +#define silk_abs_int64(a) (((a) > 0) ? (a) : -(a)) + +#define silk_sign(a) ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )) + +#define silk_sqrt(a) (sqrt(a)) + +/* PSEUDO-RANDOM GENERATOR */ +/* Make sure to store the result as the seed for the next call (also in between */ +/* frames), otherwise result won't be random at all. When only using some of the */ +/* bits, take the most significant bits by right-shifting. */ +#define silk_RAND(seed) (silk_MLA_ovflw(907633515, (seed), 196314165)) + +/* Add some multiplication functions that can be easily mapped to ARM. */ + +/* silk_SMMUL: Signed top word multiply. + ARMv6 2 instruction cycles. + ARMv3M+ 3 instruction cycles. use SMULL and ignore LSB registers.(except xM)*/ +/*#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT(silk_SMLAL(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)), 16)*/ +/* the following seems faster on x86 */ +#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT64(silk_SMULL((a32), (b32)), 32) + +#include "Inlines.h" +#include "MacroCount.h" +#include "MacroDebug.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FIX_H */ diff --git a/media/libopus/silk/VAD.c b/media/libopus/silk/VAD.c new file mode 100644 index 000000000000..d88db82f2ce7 --- /dev/null +++ b/media/libopus/silk/VAD.c @@ -0,0 +1,331 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main.h" + +/* Silk VAD noise level estimation */ +static inline void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/**********************************/ +/* Initialization of the Silk VAD */ +/**********************************/ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int b, ret = 0; + + /* reset state memory */ + silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) ); + + /* init noise levels */ + /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 ); + } + + /* Initialize state */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NL[ b ] = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] ); + psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] ); + } + psSilk_VAD->counter = 15; + + /* init smoothed energy-to-noise ratio*/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256; /* 100 * 256 --> 20 dB SNR */ + } + + return( ret ); +} + +/* Weighting factors for tilt measure */ +static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +opus_int silk_VAD_GetSA_Q8( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +) +{ + opus_int SA_Q15, pSNR_dB_Q7, input_tilt; + opus_int decimated_framelength, dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + opus_int32 sumSquared, smooth_coef_Q16; + opus_int16 HPstateTmp; + opus_int16 X[ VAD_N_BANDS ][ MAX_FRAME_LENGTH / 2 ]; + opus_int32 Xnrg[ VAD_N_BANDS ]; + opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + opus_int32 speech_nrg, x_tmp; + opus_int ret = 0; + silk_VAD_state *psSilk_VAD = &psEncC->sVAD; + + /* Safety checks */ + silk_assert( VAD_N_BANDS == 4 ); + silk_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + silk_assert( psEncC->frame_length <= 512 ); + silk_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], &X[ 0 ][ 0 ], &X[ 3 ][ 0 ], psEncC->frame_length ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + silk_ana_filt_bank_1( &X[ 0 ][ 0 ], &psSilk_VAD->AnaState1[ 0 ], &X[ 0 ][ 0 ], &X[ 2 ][ 0 ], silk_RSHIFT( psEncC->frame_length, 1 ) ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + silk_ana_filt_bank_1( &X[ 0 ][ 0 ], &psSilk_VAD->AnaState2[ 0 ], &X[ 0 ][ 0 ], &X[ 1 ][ 0 ], silk_RSHIFT( psEncC->frame_length, 2 ) ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 ); + X[ 0 ][ decimated_framelength - 1 ] = silk_RSHIFT( X[ 0 ][ decimated_framelength - 1 ], 1 ); + HPstateTmp = X[ 0 ][ decimated_framelength - 1 ]; + for( i = decimated_framelength - 1; i > 0; i-- ) { + X[ 0 ][ i - 1 ] = silk_RSHIFT( X[ 0 ][ i - 1 ], 1 ); + X[ 0 ][ i ] -= X[ 0 ][ i - 1 ]; + } + X[ 0 ][ 0 ] -= psSilk_VAD->HPstate; + psSilk_VAD->HPstate = HPstateTmp; + + /*************************************/ + /* Calculate the energy in each band */ + /*************************************/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Find the decimated framelength in the non-uniformly divided bands */ + decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 ); + dec_subframe_offset = 0; + + /* Compute energy per sub-frame */ + /* initialize with summed energy of last subframe */ + Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ]; + for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) { + sumSquared = 0; + for( i = 0; i < dec_subframe_length; i++ ) { + /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = silk_RSHIFT( X[ b ][ i + dec_subframe_offset ], 3 ); + sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + silk_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD ); + + /***********************************************/ + /* Signal-plus-noise to noise ratio estimation */ + /***********************************************/ + sumSquared = 0; + input_tilt = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ]; + if( speech_nrg > 0 ) { + /* Divide, with sufficient resolution */ + if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( 1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 ); + + /**************************************************/ + /* Scale the sigmoid output based on power levels */ + /**************************************************/ + speech_nrg = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Accumulate signal-without-noise energies, higher frequency bands have more weight */ + speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = silk_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 32768 ) { + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 ); + } else { + speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 ); + } + + /* square-root */ + speech_nrg = silk_SQRT_APPROX( speech_nrg ); + SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 */ + psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( SA_Q15, SA_Q15 ) ); + + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + smooth_coef_Q16 >>= 1; + } + + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ], + NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 ); + + /* signal to noise ratio in dB per band */ + SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + return( ret ); +} + +/**************************/ +/* Noise level estimation */ +/**************************/ +static inline void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int k; + opus_int32 nl, nrg, inv_nrg; + opus_int coef, min_coef; + + /* Initially faster smoothing */ + if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */ + min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 ); + } else { + min_coef = 0; + } + + for( k = 0; k < VAD_N_BANDS; k++ ) { + /* Get old noise level estimate for current band */ + nl = psSilk_VAD->NL[ k ]; + silk_assert( nl >= 0 ); + + /* Add bias */ + nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] ); + silk_assert( nrg > 0 ); + + /* Invert energies */ + inv_nrg = silk_DIV32( silk_int32_MAX, nrg ); + silk_assert( inv_nrg >= 0 ); + + /* Less update when subband energy is high */ + if( nrg > silk_LSHIFT( nl, 3 ) ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3; + } else if( nrg < nl ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16; + } else { + coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 ); + } + + /* Initially faster smoothing */ + coef = silk_max_int( coef, min_coef ); + + /* Smooth inverse energies */ + psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef ); + silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 ); + + /* Compute noise level by inverting again */ + nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] ); + silk_assert( nl >= 0 ); + + /* Limit noise levels (guarantee 7 bits of head room) */ + nl = silk_min( nl, 0x00FFFFFF ); + + /* Store as part of state */ + psSilk_VAD->NL[ k ] = nl; + } + + /* Increment frame counter */ + psSilk_VAD->counter++; +} diff --git a/media/libopus/silk/VQ_WMat_EC.c b/media/libopus/silk/VQ_WMat_EC.c new file mode 100644 index 000000000000..4505a8615fb9 --- /dev/null +++ b/media/libopus/silk/VQ_WMat_EC.c @@ -0,0 +1,111 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void silk_VQ_WMat_EC( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + opus_int L /* I number of vectors in codebook */ +) +{ + opus_int k; + const opus_int8 *cb_row_Q7; + opus_int16 diff_Q14[ 5 ]; + opus_int32 sum1_Q14, sum2_Q16; + + /* Loop over codebook */ + *rate_dist_Q14 = silk_int32_MAX; + cb_row_Q7 = cb_Q7; + for( k = 0; k < L; k++ ) { + diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 ); + diff_Q14[ 1 ] = in_Q14[ 1 ] - silk_LSHIFT( cb_row_Q7[ 1 ], 7 ); + diff_Q14[ 2 ] = in_Q14[ 2 ] - silk_LSHIFT( cb_row_Q7[ 2 ], 7 ); + diff_Q14[ 3 ] = in_Q14[ 3 ] - silk_LSHIFT( cb_row_Q7[ 3 ], 7 ); + diff_Q14[ 4 ] = in_Q14[ 4 ] - silk_LSHIFT( cb_row_Q7[ 4 ], 7 ); + + /* Weighted rate */ + sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] ); + + silk_assert( sum1_Q14 >= 0 ); + + /* first row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 1 ], diff_Q14[ 1 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 2 ], diff_Q14[ 2 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 3 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 4 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] ); + + /* second row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] ); + + /* third row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] ); + + /* fourth row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] ); + + /* last row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] ); + + silk_assert( sum1_Q14 >= 0 ); + + /* find best */ + if( sum1_Q14 < *rate_dist_Q14 ) { + *rate_dist_Q14 = sum1_Q14; + *ind = (opus_int8)k; + } + + /* Go to next cbk vector */ + cb_row_Q7 += LTP_ORDER; + } +} diff --git a/media/libopus/silk/ana_filt_bank_1.c b/media/libopus/silk/ana_filt_bank_1.c new file mode 100644 index 000000000000..bad630e60d02 --- /dev/null +++ b/media/libopus/silk/ana_filt_bank_1.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Coefficients for 2-band filter bank based on first-order allpass filters */ +static opus_int16 A_fb1_20 = 5394 << 1; +static opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */ + +/* Split signal into two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +) +{ + opus_int k, N2 = silk_RSHIFT( N, 1 ); + opus_int32 in32, X, Y, out_1, out_2; + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < N2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, A_fb1_21 ); + out_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, A_fb1_20 ); + out_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add/subtract, convert back to int16 and store to output */ + outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) ); + outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) ); + } +} diff --git a/media/libopus/silk/biquad_alt.c b/media/libopus/silk/biquad_alt.c new file mode 100644 index 000000000000..91a75b65b71a --- /dev/null +++ b/media/libopus/silk/biquad_alt.c @@ -0,0 +1,78 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * silk_biquad_alt.c * + * * + * Second order ARMA filter * + * Can handle slowly varying filter coefficients * + * */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Second order ARMA filter, alternative implementation */ +void silk_biquad_alt( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len, /* I signal length (must be even) */ + opus_int stride /* I Operate on interleaved signal if > 1 */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14; + + /* Negate A_Q28 values and split in two parts */ + A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */ + A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k * stride ]; + out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 ); + + S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval); + + S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval ); + + /* Scale back to Q0 and saturate */ + out[ k * stride ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) ); + } +} diff --git a/media/libopus/silk/bwexpander.c b/media/libopus/silk/bwexpander.c new file mode 100644 index 000000000000..279a9852b223 --- /dev/null +++ b/media/libopus/silk/bwexpander.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + /* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below. */ + /* Bias in silk_SMULWB can lead to unstable filters */ + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ i ] ), 16 ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ d - 1 ] ), 16 ); +} diff --git a/media/libopus/silk/bwexpander_32.c b/media/libopus/silk/bwexpander_32.c new file mode 100644 index 000000000000..24963621ef57 --- /dev/null +++ b/media/libopus/silk/bwexpander_32.c @@ -0,0 +1,50 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = silk_SMULWW( chirp_Q16, ar[ i ] ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = silk_SMULWW( chirp_Q16, ar[ d - 1 ] ); +} + diff --git a/media/libopus/silk/check_control_input.c b/media/libopus/silk/check_control_input.c new file mode 100644 index 000000000000..35888c9a204b --- /dev/null +++ b/media/libopus/silk/check_control_input.c @@ -0,0 +1,106 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "control.h" +#include "errors.h" + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + silk_assert( encControl != NULL ); + + if( ( ( encControl->API_sampleRate != 8000 ) && + ( encControl->API_sampleRate != 12000 ) && + ( encControl->API_sampleRate != 16000 ) && + ( encControl->API_sampleRate != 24000 ) && + ( encControl->API_sampleRate != 32000 ) && + ( encControl->API_sampleRate != 44100 ) && + ( encControl->API_sampleRate != 48000 ) ) || + ( ( encControl->desiredInternalSampleRate != 8000 ) && + ( encControl->desiredInternalSampleRate != 12000 ) && + ( encControl->desiredInternalSampleRate != 16000 ) ) || + ( ( encControl->maxInternalSampleRate != 8000 ) && + ( encControl->maxInternalSampleRate != 12000 ) && + ( encControl->maxInternalSampleRate != 16000 ) ) || + ( ( encControl->minInternalSampleRate != 8000 ) && + ( encControl->minInternalSampleRate != 12000 ) && + ( encControl->minInternalSampleRate != 16000 ) ) || + ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) || + ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) || + ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) { + silk_assert( 0 ); + return SILK_ENC_FS_NOT_SUPPORTED; + } + if( encControl->payloadSize_ms != 10 && + encControl->payloadSize_ms != 20 && + encControl->payloadSize_ms != 40 && + encControl->payloadSize_ms != 60 ) { + silk_assert( 0 ); + return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_LOSS_RATE; + } + if( encControl->useDTX < 0 || encControl->useDTX > 1 ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_DTX_SETTING; + } + if( encControl->useCBR < 0 || encControl->useCBR > 1 ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_CBR_SETTING; + } + if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_INBAND_FEC_SETTING; + } + if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal > encControl->nChannelsAPI ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->complexity < 0 || encControl->complexity > 10 ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_COMPLEXITY_SETTING; + } + + return SILK_NO_ERROR; +} diff --git a/media/libopus/silk/code_signs.c b/media/libopus/silk/code_signs.c new file mode 100644 index 000000000000..c0b940adfcbf --- /dev/null +++ b/media/libopus/silk/code_signs.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*#define silk_enc_map(a) ((a) > 0 ? 1 : 0)*/ +/*#define silk_dec_map(a) ((a) > 0 ? 1 : -1)*/ +/* shifting avoids if-statement */ +#define silk_enc_map(a) ( silk_RSHIFT( (a), 15 ) + 1 ) +#define silk_dec_map(a) ( silk_LSHIFT( (a), 1 ) - 1 ) + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + const opus_int8 *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] != 0 ) { + ec_enc_icdf( psRangeEnc, silk_enc_map( q_ptr[ j ]), icdf, 8 ); + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + opus_int *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] > 0 ) { + /* attach sign */ +#if 0 + /* conditional implementation */ + if( ec_dec_icdf( psRangeDec, icdf, 8 ) == 0 ) { + q_ptr[ j ] = -q_ptr[ j ]; + } +#else + /* implementation with shift, subtraction, multiplication */ + q_ptr[ j ] *= silk_dec_map( ec_dec_icdf( psRangeDec, icdf, 8 ) ); +#endif + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} diff --git a/media/libopus/silk/control.h b/media/libopus/silk/control.h new file mode 100644 index 000000000000..a29c9ccfaeff --- /dev/null +++ b/media/libopus/silk/control.h @@ -0,0 +1,139 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_CONTROL_H +#define SILK_CONTROL_H + +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decoder API flags */ +#define FLAG_DECODE_NORMAL 0 +#define FLAG_PACKET_LOST 1 +#define FLAG_DECODE_LBRR 2 + +/***********************************************/ +/* Structure for controlling encoder operation */ +/***********************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 maxInternalSampleRate; + + /* I: Minimum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 minInternalSampleRate; + + /* I: Soft request for internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 desiredInternalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* I: Bitrate during active speech in bits/second; internally limited */ + opus_int32 bitRate; + + /* I: Uplink packet loss in percent (0-100) */ + opus_int packetLossPercentage; + + /* I: Complexity mode; 0 is lowest, 10 is highest complexity */ + opus_int complexity; + + /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */ + opus_int useInBandFEC; + + /* I: Flag to enable discontinuous transmission (DTX); 0/1 */ + opus_int useDTX; + + /* I: Flag to use constant bitrate */ + opus_int useCBR; + + /* I: Maximum number of bits allowed for the frame */ + opus_int maxBits; + + /* I: Causes a smooth downmix to mono */ + opus_int toMono; + + /* I: Opus encoder is allowing us to switch bandwidth */ + opus_int opusCanSwitch; + + /* O: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* O: Flag that bandwidth switching is allowed (because low voice activity) */ + opus_int allowBandwidthSwitch; + + /* O: Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */ + opus_int inWBmodeWithoutVariableLP; + + /* O: Stereo width */ + opus_int stereoWidth_Q14; + + /* O: Tells the Opus encoder we're ready to switch */ + opus_int switchReady; + +} silk_EncControlStruct; + +/**************************************************************************/ +/* Structure for controlling decoder operation and reading decoder status */ +/**************************************************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */ + opus_int prevPitchLag; +} silk_DecControlStruct; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/media/libopus/silk/control_SNR.c b/media/libopus/silk/control_SNR.c new file mode 100644 index 000000000000..3dbafb0ce5b0 --- /dev/null +++ b/media/libopus/silk/control_SNR.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +) +{ + opus_int k, ret = SILK_NO_ERROR; + opus_int32 frac_Q6; + const opus_int32 *rateTable; + + /* Set bitrate/coding quality */ + TargetRate_bps = silk_LIMIT( TargetRate_bps, MIN_TARGET_RATE_BPS, MAX_TARGET_RATE_BPS ); + if( TargetRate_bps != psEncC->TargetRate_bps ) { + psEncC->TargetRate_bps = TargetRate_bps; + + /* If new TargetRate_bps, translate to SNR_dB value */ + if( psEncC->fs_kHz == 8 ) { + rateTable = silk_TargetRate_table_NB; + } else if( psEncC->fs_kHz == 12 ) { + rateTable = silk_TargetRate_table_MB; + } else { + rateTable = silk_TargetRate_table_WB; + } + + /* Reduce bitrate for 10 ms modes in these calculations */ + if( psEncC->nb_subfr == 2 ) { + TargetRate_bps -= REDUCE_BITRATE_10_MS_BPS; + } + + /* Find bitrate interval in table and interpolate */ + for( k = 1; k < TARGET_RATE_TAB_SZ; k++ ) { + if( TargetRate_bps <= rateTable[ k ] ) { + frac_Q6 = silk_DIV32( silk_LSHIFT( TargetRate_bps - rateTable[ k - 1 ], 6 ), + rateTable[ k ] - rateTable[ k - 1 ] ); + psEncC->SNR_dB_Q7 = silk_LSHIFT( silk_SNR_table_Q1[ k - 1 ], 6 ) + silk_MUL( frac_Q6, silk_SNR_table_Q1[ k ] - silk_SNR_table_Q1[ k - 1 ] ); + break; + } + } + + /* Reduce coding quality whenever LBRR is enabled, to free up some bits */ + if( psEncC->LBRR_enabled ) { + psEncC->SNR_dB_Q7 = silk_SMLABB( psEncC->SNR_dB_Q7, 12 - psEncC->LBRR_GainIncreases, SILK_FIX_CONST( -0.25, 7 ) ); + } + } + + return ret; +} diff --git a/media/libopus/silk/control_audio_bandwidth.c b/media/libopus/silk/control_audio_bandwidth.c new file mode 100644 index 000000000000..a8541f6e0348 --- /dev/null +++ b/media/libopus/silk/control_audio_bandwidth.c @@ -0,0 +1,119 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + opus_int fs_kHz; + opus_int32 fs_Hz; + + fs_kHz = psEncC->fs_kHz; + fs_Hz = silk_SMULBB( fs_kHz, 1000 ); + if( fs_Hz == 0 ) { + /* Encoder has just been initialized */ + fs_Hz = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) { + /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */ + fs_Hz = psEncC->API_fs_Hz; + fs_Hz = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz ); + fs_Hz = silk_max( fs_Hz, psEncC->minInternal_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else { + /* State machine for the internal sampling rate switching */ + if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + } + if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) { + /* Check if we should switch down */ + if( silk_SMULBB( psEncC->fs_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz ) + { + /* Switch down */ + if( psEncC->sLP.mode == 0 ) { + /* New transition */ + psEncC->sLP.transition_frame_no = TRANSITION_FRAMES; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + } + if( encControl->opusCanSwitch ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + + /* Switch to a lower sample frequency */ + fs_kHz = psEncC->fs_kHz == 16 ? 12 : 8; + } else { + if( psEncC->sLP.transition_frame_no <= 0 ) { + encControl->switchReady = 1; + } else { + /* Direction: down (at double speed) */ + psEncC->sLP.mode = -2; + } + } + } + else + /* Check if we should switch up */ + if( silk_SMULBB( psEncC->fs_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz ) + { + /* Switch up */ + if( encControl->opusCanSwitch ) { + /* Switch to a higher sample frequency */ + fs_kHz = psEncC->fs_kHz == 8 ? 12 : 16; + + /* New transition */ + psEncC->sLP.transition_frame_no = 0; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + + /* Direction: up */ + psEncC->sLP.mode = 1; + } else { + if( psEncC->sLP.mode == 0 ) { + encControl->switchReady = 1; + } else { + /* Direction: up */ + psEncC->sLP.mode = 1; + } + } + } + } + } + + return fs_kHz; +} diff --git a/media/libopus/silk/control_codec.c b/media/libopus/silk/control_codec.c new file mode 100644 index 000000000000..5a997018b5aa --- /dev/null +++ b/media/libopus/silk/control_codec.c @@ -0,0 +1,411 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#else +#include "main_FLP.h" +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#endif +#include "tuning_parameters.h" +#include "pitch_est_defines.h" + +opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +); + +opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +); + +opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +); + +static inline opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const opus_int32 TargetRate_bps /* I */ +); + + +/* Control encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +) +{ + opus_int fs_kHz, ret = 0; + + psEnc->sCmn.useDTX = encControl->useDTX; + psEnc->sCmn.useCBR = encControl->useCBR; + psEnc->sCmn.API_fs_Hz = encControl->API_sampleRate; + psEnc->sCmn.maxInternal_fs_Hz = encControl->maxInternalSampleRate; + psEnc->sCmn.minInternal_fs_Hz = encControl->minInternalSampleRate; + psEnc->sCmn.desiredInternal_fs_Hz = encControl->desiredInternalSampleRate; + psEnc->sCmn.useInBandFEC = encControl->useInBandFEC; + psEnc->sCmn.nChannelsAPI = encControl->nChannelsAPI; + psEnc->sCmn.nChannelsInternal = encControl->nChannelsInternal; + psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch; + psEnc->sCmn.channelNb = channelNb; + + if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 0 ) { + if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) { + /* Change in API sampling rate in the middle of encoding a packet */ + ret += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz ); + } + return ret; + } + + /* Beyond this point we know that there are no previously coded frames in the payload buffer */ + + /********************************************/ + /* Determine internal sampling rate */ + /********************************************/ + fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl ); + if( force_fs_kHz ) { + fs_kHz = force_fs_kHz; + } + /********************************************/ + /* Prepare resampler and buffered data */ + /********************************************/ + ret += silk_setup_resamplers( psEnc, fs_kHz ); + + /********************************************/ + /* Set internal sampling frequency */ + /********************************************/ + ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms ); + + /********************************************/ + /* Set encoding complexity */ + /********************************************/ + ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity ); + + /********************************************/ + /* Set packet loss rate measured by farend */ + /********************************************/ + psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage; + + /********************************************/ + /* Set LBRR usage */ + /********************************************/ + ret += silk_setup_LBRR( &psEnc->sCmn, TargetRate_bps ); + + psEnc->sCmn.controlled_since_last_payload = 1; + + return ret; +} + +opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + opus_int32 nSamples_temp; + + if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz ) + { + if( psEnc->sCmn.fs_kHz == 0 ) { + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 ); + } else { + /* Allocate worst case space for temporary upsampling, 8 to 48 kHz, so a factor 6 */ + opus_int16 x_buf_API_fs_Hz[ ( 2 * MAX_FRAME_LENGTH_MS + LA_SHAPE_MS ) * MAX_API_FS_KHZ ]; + silk_resampler_state_struct temp_resampler_state; +#ifdef FIXED_POINT + opus_int16 *x_bufFIX = psEnc->x_buf; +#else + opus_int16 x_bufFIX[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ]; +#endif + + nSamples_temp = silk_LSHIFT( psEnc->sCmn.frame_length, 1 ) + LA_SHAPE_MS * psEnc->sCmn.fs_kHz; + +#ifndef FIXED_POINT + silk_float2short_array( x_bufFIX, psEnc->x_buf, nSamples_temp ); +#endif + + /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */ + ret += silk_resampler_init( &temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 ); + + /* Temporary resampling of x_buf data to API_fs_Hz */ + ret += silk_resampler( &temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, nSamples_temp ); + + /* Calculate number of samples that has been temporarily upsampled */ + nSamples_temp = silk_DIV32_16( nSamples_temp * psEnc->sCmn.API_fs_Hz, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ) ); + + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 ); + + /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */ + ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, nSamples_temp ); + +#ifndef FIXED_POINT + silk_short2float_array( psEnc->x_buf, x_bufFIX, ( 2 * MAX_FRAME_LENGTH_MS + LA_SHAPE_MS ) * fs_kHz ); +#endif + } + } + + psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz; + + return ret; +} + +opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + + /* Set packet size */ + if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) { + if( ( PacketSize_ms != 10 ) && + ( PacketSize_ms != 20 ) && + ( PacketSize_ms != 40 ) && + ( PacketSize_ms != 60 ) ) { + ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( PacketSize_ms <= 10 ) { + psEnc->sCmn.nFramesPerPacket = 1; + psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1; + psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } else { + psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS ); + psEnc->sCmn.nb_subfr = MAX_NB_SUBFR; + psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } + } + psEnc->sCmn.PacketSize_ms = PacketSize_ms; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + } + + /* Set internal sampling frequency */ + silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + silk_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 ); + if( psEnc->sCmn.fs_kHz != fs_kHz ) { + /* reset part of the state */ + silk_memset( &psEnc->sShape, 0, sizeof( psEnc->sShape ) ); + silk_memset( &psEnc->sPrefilt, 0, sizeof( psEnc->sPrefilt ) ); + silk_memset( &psEnc->sCmn.sNSQ, 0, sizeof( psEnc->sCmn.sNSQ ) ); + silk_memset( psEnc->sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) ); + psEnc->sCmn.inputBufIx = 0; + psEnc->sCmn.nFramesEncoded = 0; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + + /* Initialize non-zero parameters */ + psEnc->sCmn.prevLag = 100; + psEnc->sCmn.first_frame_after_reset = 1; + psEnc->sPrefilt.lagPrev = 100; + psEnc->sShape.LastGainIndex = 10; + psEnc->sCmn.sNSQ.lagPrev = 100; + psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + + psEnc->sCmn.fs_kHz = fs_kHz; + if( psEnc->sCmn.fs_kHz == 8 ) { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_WB; + } + psEnc->sCmn.subfr_length = SUB_FRAME_LENGTH_MS * fs_kHz; + psEnc->sCmn.frame_length = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr ); + psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + psEnc->sCmn.la_pitch = silk_SMULBB( LA_PITCH_MS, fs_kHz ); + psEnc->sCmn.max_pitch_lag = silk_SMULBB( 18, fs_kHz ); + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + } else { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + } + if( psEnc->sCmn.fs_kHz == 16 ) { + psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_WB, 9 ); + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_MB, 9 ); + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else { + psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_NB, 9 ); + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } + } + + /* Check that settings are valid */ + silk_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length ); + + return ret; +} + +opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +) +{ + opus_int ret = 0; + + /* Set encoding complexity */ + silk_assert( Complexity >= 0 && Complexity <= 10 ); + if( Complexity < 2 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 8; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->LTPQuantLowComplexity = 1; + psEncC->NLSF_MSVQ_Survivors = 2; + psEncC->warping_Q16 = 0; + } else if( Complexity < 4 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 ); + psEncC->pitchEstimationLPCOrder = 8; + psEncC->shapingLPCOrder = 10; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = 4; + psEncC->warping_Q16 = 0; + } else if( Complexity < 6 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.74, 16 ); + psEncC->pitchEstimationLPCOrder = 10; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 1; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = 8; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else if( Complexity < 8 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.72, 16 ); + psEncC->pitchEstimationLPCOrder = 12; + psEncC->shapingLPCOrder = 14; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 3; + psEncC->useInterpolatedNLSFs = 1; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = 16; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else { + psEncC->pitchEstimationComplexity = SILK_PE_MAX_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.7, 16 ); + psEncC->pitchEstimationLPCOrder = 16; + psEncC->shapingLPCOrder = 16; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES; + psEncC->useInterpolatedNLSFs = 1; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = 32; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } + + /* Do not allow higher pitch estimation LPC order than predict LPC order */ + psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder ); + psEncC->shapeWinLength = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape; + psEncC->Complexity = Complexity; + + silk_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER ); + silk_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER ); + silk_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES ); + silk_assert( psEncC->warping_Q16 <= 32767 ); + silk_assert( psEncC->la_shape <= LA_SHAPE_MAX ); + silk_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX ); + silk_assert( psEncC->NLSF_MSVQ_Survivors <= NLSF_VQ_MAX_SURVIVORS ); + + return ret; +} + +static inline opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const opus_int32 TargetRate_bps /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + opus_int32 LBRR_rate_thres_bps; + + psEncC->LBRR_enabled = 0; + if( psEncC->useInBandFEC && psEncC->PacketLoss_perc > 0 ) { + if( psEncC->fs_kHz == 8 ) { + LBRR_rate_thres_bps = LBRR_NB_MIN_RATE_BPS; + } else if( psEncC->fs_kHz == 12 ) { + LBRR_rate_thres_bps = LBRR_MB_MIN_RATE_BPS; + } else { + LBRR_rate_thres_bps = LBRR_WB_MIN_RATE_BPS; + } + LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, 125 - silk_min( psEncC->PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) ); + + if( TargetRate_bps > LBRR_rate_thres_bps ) { + /* Set gain increase for coding LBRR excitation */ + psEncC->LBRR_enabled = 1; + psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 ); + } + } + + return ret; +} diff --git a/media/libopus/silk/debug.c b/media/libopus/silk/debug.c new file mode 100644 index 000000000000..5dfcaa9a0101 --- /dev/null +++ b/media/libopus/silk/debug.c @@ -0,0 +1,170 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "debug.h" +#include "SigProc_FIX.h" + +#if SILK_TIC_TOC + +#ifdef _WIN32 + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else /* Linux or Mac*/ +#include +#endif + +unsigned long silk_GetHighResolutionTime(void) /* O time in usec*/ +{ + /* Returns a time counter in microsec */ + /* the resolution is platform dependent */ + /* but is typically 1.62 us resolution */ + LARGE_INTEGER lpPerformanceCount; + LARGE_INTEGER lpFrequency; + QueryPerformanceCounter(&lpPerformanceCount); + QueryPerformanceFrequency(&lpFrequency); + return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart); +} +#else /* Linux or Mac*/ +unsigned long GetHighResolutionTime(void) /* O time in usec*/ +{ + struct timeval tv; + gettimeofday(&tv, 0); + return((tv.tv_sec*1000000)+(tv.tv_usec)); +} +#endif + +int silk_Timer_nTimers = 0; +int silk_Timer_depth_ctr = 0; +char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef WIN32 +LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +#ifdef WIN32 +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + LARGE_INTEGER lpFrequency; + LARGE_INTEGER lpPerformanceCount1, lpPerformanceCount2; + int del = 0x7FFFFFFF; + double avg, sum_avg; + /* estimate overhead of calling performance counters */ + for( k = 0; k < 1000; k++ ) { + QueryPerformanceCounter(&lpPerformanceCount1); + QueryPerformanceCounter(&lpPerformanceCount2); + lpPerformanceCount2.QuadPart -= lpPerformanceCount1.QuadPart; + if( (int)lpPerformanceCount2.LowPart < del ) + del = lpPerformanceCount2.LowPart; + } + QueryPerformanceFrequency(&lpFrequency); + /* print results to file */ + sum_avg = 0.0f; + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + sum_avg += (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart * silk_Timer_cnt[k]; + } + } + fp = fopen(file_name, "w"); + fprintf(fp, " min avg %% max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + avg = (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart; + fprintf(fp, "%8.2f", (1e6 * (silk_max_64(silk_Timer_min[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%12.2f %6.2f", avg, 100.0 * avg / sum_avg * silk_Timer_cnt[k]); + fprintf(fp, "%12.2f", (1e6 * (silk_max_64(silk_Timer_max[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#else +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + /* print results to file */ + fp = fopen(file_name, "w"); + fprintf(fp, " min avg max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) + { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + fprintf(fp, "%d ", silk_Timer_min[k]); + fprintf(fp, "%f ", (double)silk_Timer_sum[k] / (double)silk_Timer_cnt[k]); + fprintf(fp, "%d ", silk_Timer_max[k]); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#endif + +#endif /* SILK_TIC_TOC */ + +#if SILK_DEBUG +FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +int silk_debug_store_count = 0; +#endif /* SILK_DEBUG */ + diff --git a/media/libopus/silk/debug.h b/media/libopus/silk/debug.h new file mode 100644 index 000000000000..5a6b1a159874 --- /dev/null +++ b/media/libopus/silk/debug.h @@ -0,0 +1,287 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_DEBUG_H +#define SILK_DEBUG_H + +#ifdef _WIN32 +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include "typedef.h" +#include /* file writing */ +#include /* strcpy, strcmp */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +unsigned long GetHighResolutionTime(void); /* O time in usec*/ + +/* make SILK_DEBUG dependent on compiler's _DEBUG */ +#if defined _WIN32 + #ifdef _DEBUG + #define SILK_DEBUG 1 + #else + #define SILK_DEBUG 0 + #endif + + /* overrule the above */ + #if 0 + /* #define NO_ASSERTS*/ + #undef SILK_DEBUG + #define SILK_DEBUG 1 + #endif +#else + #define SILK_DEBUG 0 +#endif + +/* Flag for using timers */ +#define SILK_TIC_TOC 0 + + +#if SILK_TIC_TOC + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#pragma warning( disable : 4996 ) /* stop bitching about strcpy in TIC()*/ +#else /* Linux or Mac*/ +#include +#endif + +/*********************************/ +/* timer functions for profiling */ +/*********************************/ +/* example: */ +/* */ +/* TIC(LPC) */ +/* do_LPC(in_vec, order, acoef); // do LPC analysis */ +/* TOC(LPC) */ +/* */ +/* and call the following just before exiting (from main) */ +/* */ +/* silk_TimerSave("silk_TimingData.txt"); */ +/* */ +/* results are now in silk_TimingData.txt */ + +void silk_TimerSave(char *file_name); + +/* max number of timers (in different locations) */ +#define silk_NUM_TIMERS_MAX 50 +/* max length of name tags in TIC(..), TOC(..) */ +#define silk_NUM_TIMERS_MAX_TAG_LEN 30 + +extern int silk_Timer_nTimers; +extern int silk_Timer_depth_ctr; +extern char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef _WIN32 +extern LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +extern unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +extern unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +/* WARNING: TIC()/TOC can measure only up to 0.1 seconds at a time */ +#ifdef _WIN32 +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + QueryPerformanceCounter(&silk_Timer_start[ID]); \ +} +#else +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + silk_Timer_start[ID] = GetHighResolutionTime(); \ +} +#endif + +#ifdef _WIN32 +#define TOC(TAG_NAME) { \ + LARGE_INTEGER lpPerformanceCount; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + QueryPerformanceCounter(&lpPerformanceCount); \ + lpPerformanceCount.QuadPart -= silk_Timer_start[ID].QuadPart; \ + if((lpPerformanceCount.QuadPart < 100000000) && \ + (lpPerformanceCount.QuadPart >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = lpPerformanceCount.QuadPart; \ + } \ + silk_Timer_depth_ctr--; \ +} +#else +#define TOC(TAG_NAME) { \ + unsigned long endTime; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + endTime = GetHighResolutionTime(); \ + endTime -= silk_Timer_start[ID]; \ + if((endTime < 100000000) && \ + (endTime >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += endTime; \ + if( endTime > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = endTime; \ + if( endTime < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = endTime; \ + } \ + silk_Timer_depth_ctr--; \ +} +#endif + +#else /* SILK_TIC_TOC */ + +/* define macros as empty strings */ +#define TIC(TAG_NAME) +#define TOC(TAG_NAME) +#define silk_TimerSave(FILE_NAME) + +#endif /* SILK_TIC_TOC */ + + +#if SILK_DEBUG +/************************************/ +/* write data to file for debugging */ +/************************************/ +/* Example: DEBUG_STORE_DATA(testfile.pcm, &RIN[0], 160*sizeof(opus_int16)); */ + +#define silk_NUM_STORES_MAX 100 +extern FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +extern int silk_debug_store_count; + +/* Faster way of storing the data */ +#define DEBUG_STORE_DATA( FILE_NAME, DATA_PTR, N_BYTES ) { \ + static opus_int init = 0, cnt = 0; \ + static FILE **fp; \ + if (init == 0) { \ + init = 1; \ + cnt = silk_debug_store_count++; \ + silk_debug_store_fp[ cnt ] = fopen(#FILE_NAME, "wb"); \ + } \ + fwrite((DATA_PTR), (N_BYTES), 1, silk_debug_store_fp[ cnt ]); \ +} + +/* Call this at the end of main() */ +#define SILK_DEBUG_STORE_CLOSE_FILES { \ + opus_int i; \ + for( i = 0; i < silk_debug_store_count; i++ ) { \ + fclose( silk_debug_store_fp[ i ] ); \ + } \ +} + +/* micro sec */ +#define silk_GETTIME(void) time = (opus_int64) silk_GetHighResolutionTime(); + +#else /* SILK_DEBUG */ + +/* define macros as empty strings */ +#define DEBUG_STORE_DATA(FILE_NAME, DATA_PTR, N_BYTES) +#define SILK_DEBUG_STORE_CLOSE_FILES + +#endif /* SILK_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_DEBUG_H */ diff --git a/media/libopus/silk/dec_API.c b/media/libopus/silk/dec_API.c new file mode 100644 index 000000000000..8c9ed24a560e --- /dev/null +++ b/media/libopus/silk/dec_API.c @@ -0,0 +1,373 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "API.h" +#include "main.h" + +/************************/ +/* Decoder Super Struct */ +/************************/ +typedef struct { + silk_decoder_state channel_state[ DECODER_NUM_CHANNELS ]; + stereo_dec_state sStereo; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int prev_decode_only_middle; +} silk_decoder; + +/*********************/ +/* Decoder functions */ +/*********************/ + +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *decSizeBytes = sizeof( silk_decoder ); + + return ret; +} + +/* Reset decoder state */ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +) +{ + opus_int n, ret = SILK_NO_ERROR; + silk_decoder_state *channel_state = ((silk_decoder *)decState)->channel_state; + + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } + + return ret; +} + +/* Decode a frame */ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut /* O Number of samples decoded */ +) +{ + opus_int i, n, decode_only_middle = 0, ret = SILK_NO_ERROR; + opus_int32 nSamplesOutDec, LBRR_symbol; + opus_int16 samplesOut1_tmp[ 2 ][ MAX_FS_KHZ * MAX_FRAME_LENGTH_MS + 2 ]; + opus_int16 samplesOut2_tmp[ MAX_API_FS_KHZ * MAX_FRAME_LENGTH_MS ]; + opus_int32 MS_pred_Q13[ 2 ] = { 0 }; + opus_int16 *resample_out_ptr; + silk_decoder *psDec = ( silk_decoder * )decState; + silk_decoder_state *channel_state = psDec->channel_state; + opus_int has_side; + opus_int stereo_to_mono; + + /**********************************/ + /* Test if first frame in payload */ + /**********************************/ + if( newPacketFlag ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + channel_state[ n ].nFramesDecoded = 0; /* Used to count frames in packet */ + } + } + + /* If Mono -> Stereo transition in bitstream: init state of second channel */ + if( decControl->nChannelsInternal > psDec->nChannelsInternal ) { + ret += silk_init_decoder( &channel_state[ 1 ] ); + } + + stereo_to_mono = decControl->nChannelsInternal == 1 && psDec->nChannelsInternal == 2 && + ( decControl->internalSampleRate == 1000*channel_state[ 0 ].fs_kHz ); + + if( channel_state[ 0 ].nFramesDecoded == 0 ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + opus_int fs_kHz_dec; + if( decControl->payloadSize_ms == 0 ) { + /* Assuming packet loss, use 10 ms */ + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 2; + } else if( decControl->payloadSize_ms == 10 ) { + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 2; + } else if( decControl->payloadSize_ms == 20 ) { + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 4; + } else if( decControl->payloadSize_ms == 40 ) { + channel_state[ n ].nFramesPerPacket = 2; + channel_state[ n ].nb_subfr = 4; + } else if( decControl->payloadSize_ms == 60 ) { + channel_state[ n ].nFramesPerPacket = 3; + channel_state[ n ].nb_subfr = 4; + } else { + silk_assert( 0 ); + return SILK_DEC_INVALID_FRAME_SIZE; + } + fs_kHz_dec = ( decControl->internalSampleRate >> 10 ) + 1; + if( fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16 ) { + silk_assert( 0 ); + return SILK_DEC_INVALID_SAMPLING_FREQUENCY; + } + ret += silk_decoder_set_fs( &channel_state[ n ], fs_kHz_dec, decControl->API_sampleRate ); + } + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 && ( psDec->nChannelsAPI == 1 || psDec->nChannelsInternal == 1 ) ) { + silk_memset( psDec->sStereo.pred_prev_Q13, 0, sizeof( psDec->sStereo.pred_prev_Q13 ) ); + silk_memset( psDec->sStereo.sSide, 0, sizeof( psDec->sStereo.sSide ) ); + silk_memcpy( &channel_state[ 1 ].resampler_state, &channel_state[ 0 ].resampler_state, sizeof( silk_resampler_state_struct ) ); + } + psDec->nChannelsAPI = decControl->nChannelsAPI; + psDec->nChannelsInternal = decControl->nChannelsInternal; + + if( decControl->API_sampleRate > MAX_API_FS_KHZ * 1000 || decControl->API_sampleRate < 8000 ) { + ret = SILK_DEC_INVALID_SAMPLING_FREQUENCY; + return( ret ); + } + + if( lostFlag != FLAG_PACKET_LOST && channel_state[ 0 ].nFramesDecoded == 0 ) { + /* First decoder call for this payload */ + /* Decode VAD flags and LBRR flag */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].VAD_flags[ i ] = ec_dec_bit_logp(psRangeDec, 1); + } + channel_state[ n ].LBRR_flag = ec_dec_bit_logp(psRangeDec, 1); + } + /* Decode LBRR flags */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + silk_memset( channel_state[ n ].LBRR_flags, 0, sizeof( channel_state[ n ].LBRR_flags ) ); + if( channel_state[ n ].LBRR_flag ) { + if( channel_state[ n ].nFramesPerPacket == 1 ) { + channel_state[ n ].LBRR_flags[ 0 ] = 1; + } else { + LBRR_symbol = ec_dec_icdf( psRangeDec, silk_LBRR_flags_iCDF_ptr[ channel_state[ n ].nFramesPerPacket - 2 ], 8 ) + 1; + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].LBRR_flags[ i ] = silk_RSHIFT( LBRR_symbol, i ) & 1; + } + } + } + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + /* Regular decoding: skip all LBRR data */ + for( i = 0; i < channel_state[ 0 ].nFramesPerPacket; i++ ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( channel_state[ n ].LBRR_flags[ i ] ) { + opus_int pulses[ MAX_FRAME_LENGTH ]; + opus_int condCoding; + + if( decControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + if( channel_state[ 1 ].LBRR_flags[ i ] == 0 ) { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && channel_state[ n ].LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_decode_indices( &channel_state[ n ], psRangeDec, i, 1, condCoding ); + silk_decode_pulses( psRangeDec, pulses, channel_state[ n ].indices.signalType, + channel_state[ n ].indices.quantOffsetType, channel_state[ n ].frame_length ); + } + } + } + } + } + + /* Get MS predictor index */ + if( decControl->nChannelsInternal == 2 ) { + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 0 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 1 ) ) + { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + /* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */ + if( ( lostFlag == FLAG_DECODE_NORMAL && channel_state[ 1 ].VAD_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 1 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) ) + { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } else { + decode_only_middle = 0; + } + } else { + for( n = 0; n < 2; n++ ) { + MS_pred_Q13[ n ] = psDec->sStereo.pred_prev_Q13[ n ]; + } + } + } + + /* Reset side channel decoder prediction memory for first frame with side coding */ + if( decControl->nChannelsInternal == 2 && decode_only_middle == 0 && psDec->prev_decode_only_middle == 1 ) { + silk_memset( psDec->channel_state[ 1 ].outBuf, 0, sizeof(psDec->channel_state[ 1 ].outBuf) ); + silk_memset( psDec->channel_state[ 1 ].sLPC_Q14_buf, 0, sizeof(psDec->channel_state[ 1 ].sLPC_Q14_buf) ); + psDec->channel_state[ 1 ].lagPrev = 100; + psDec->channel_state[ 1 ].LastGainIndex = 10; + psDec->channel_state[ 1 ].prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psDec->channel_state[ 1 ].first_frame_after_reset = 1; + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + has_side = !decode_only_middle; + } else { + has_side = !psDec->prev_decode_only_middle + || (decControl->nChannelsInternal == 2 && lostFlag == FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[ channel_state[1].nFramesDecoded ] == 1 ); + } + /* Call decoder for one frame */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( n == 0 || has_side ) { + opus_int FrameIndex; + opus_int condCoding; + + FrameIndex = channel_state[ 0 ].nFramesDecoded - n; + /* Use independent coding if no previous frame available */ + if( FrameIndex <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( lostFlag == FLAG_DECODE_LBRR ) { + condCoding = channel_state[ n ].LBRR_flags[ FrameIndex - 1 ] ? CODE_CONDITIONALLY : CODE_INDEPENDENTLY; + } else if( n > 0 && psDec->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding); + } else { + silk_memset( &samplesOut1_tmp[ n ][ 2 ], 0, nSamplesOutDec * sizeof( opus_int16 ) ); + } + channel_state[ n ].nFramesDecoded++; + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 ) { + /* Convert Mid/Side to Left/Right */ + silk_stereo_MS_to_LR( &psDec->sStereo, samplesOut1_tmp[ 0 ], samplesOut1_tmp[ 1 ], MS_pred_Q13, channel_state[ 0 ].fs_kHz, nSamplesOutDec ); + } else { + /* Buffering */ + silk_memcpy( samplesOut1_tmp[ 0 ], psDec->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psDec->sStereo.sMid, &samplesOut1_tmp[ 0 ][ nSamplesOutDec ], 2 * sizeof( opus_int16 ) ); + } + + /* Number of output samples */ + *nSamplesOut = silk_DIV32( nSamplesOutDec * decControl->API_sampleRate, silk_SMULBB( channel_state[ 0 ].fs_kHz, 1000 ) ); + + /* Set up pointers to temp buffers */ + if( decControl->nChannelsAPI == 2 ) { + resample_out_ptr = samplesOut2_tmp; + } else { + resample_out_ptr = samplesOut; + } + + for( n = 0; n < silk_min( decControl->nChannelsAPI, decControl->nChannelsInternal ); n++ ) { + + /* Resample decoded signal to API_sampleRate */ + ret += silk_resampler( &channel_state[ n ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ n ][ 1 ], nSamplesOutDec ); + + /* Interleave if stereo output and stereo stream */ + if( decControl->nChannelsAPI == 2 ) { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ n + 2 * i ] = resample_out_ptr[ i ]; + } + } + } + + /* Create two channel output from mono stream */ + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 1 ) { + if ( stereo_to_mono ){ + /* Resample right channel for newly collapsed stereo just in case + we weren't doing collapsing when switching to mono */ + ret += silk_resampler( &channel_state[ 1 ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ 0 ][ 1 ], nSamplesOutDec ); + + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = resample_out_ptr[ i ]; + } + } else { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = samplesOut[ 0 + 2 * i ]; + } + } + } + + /* Export pitch lag, measured at 48 kHz sampling rate */ + if( channel_state[ 0 ].prevSignalType == TYPE_VOICED ) { + int mult_tab[ 3 ] = { 6, 4, 3 }; + decControl->prevPitchLag = channel_state[ 0 ].lagPrev * mult_tab[ ( channel_state[ 0 ].fs_kHz - 8 ) >> 2 ]; + } else { + decControl->prevPitchLag = 0; + } + + if( lostFlag == FLAG_PACKET_LOST ) { + /* On packet loss, remove the gain clamping to prevent having the energy "bounce back" + if we lose packets when the energy is going down */ + for ( i = 0; i < psDec->nChannelsInternal; i++ ) + psDec->channel_state[ i ].LastGainIndex = 10; + } else { + psDec->prev_decode_only_middle = decode_only_middle; + } + return ret; +} + +/* Getting table of contents for a packet */ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +) +{ + opus_int i, flags, ret = SILK_NO_ERROR; + + if( nBytesIn < 1 ) { + return -1; + } + if( nFramesPerPayload < 0 || nFramesPerPayload > 3 ) { + return -1; + } + + silk_memset( Silk_TOC, 0, sizeof( Silk_TOC ) ); + + /* For stereo, extract the flags for the mid channel */ + flags = silk_RSHIFT( payload[ 0 ], 7 - nFramesPerPayload ) & ( silk_LSHIFT( 1, nFramesPerPayload + 1 ) - 1 ); + + Silk_TOC->inbandFECFlag = flags & 1; + for( i = nFramesPerPayload - 1; i >= 0 ; i-- ) { + flags = silk_RSHIFT( flags, 1 ); + Silk_TOC->VADFlags[ i ] = flags & 1; + Silk_TOC->VADFlag |= flags & 1; + } + + return ret; +} diff --git a/media/libopus/silk/decode_core.c b/media/libopus/silk/decode_core.c new file mode 100644 index 000000000000..ff3ab795dbc1 --- /dev/null +++ b/media/libopus/silk/decode_core.c @@ -0,0 +1,230 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/**********************************************************/ +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +/**********************************************************/ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int pulses[ MAX_FRAME_LENGTH ] /* I Pulse signal */ +) +{ + opus_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType; + opus_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ]; + opus_int16 sLTP[ MAX_FRAME_LENGTH ]; + opus_int32 sLTP_Q15[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10; + opus_int32 *pred_lag_ptr, *pexc_Q14, *pres_Q14; + opus_int32 res_Q14[ MAX_SUB_FRAME_LENGTH ]; + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + MAX_LPC_ORDER ]; + + silk_assert( psDec->prev_gain_Q16 != 0 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psDec->indices.signalType >> 1 ][ psDec->indices.quantOffsetType ]; + + if( psDec->indices.NLSFInterpCoef_Q2 < 1 << 2 ) { + NLSF_interpolation_flag = 1; + } else { + NLSF_interpolation_flag = 0; + } + + /* Decode excitation */ + rand_seed = psDec->indices.Seed; + for( i = 0; i < psDec->frame_length; i++ ) { + rand_seed = silk_RAND( rand_seed ); + psDec->exc_Q14[ i ] = silk_LSHIFT( (opus_int32)pulses[ i ], 14 ); + if( psDec->exc_Q14[ i ] > 0 ) { + psDec->exc_Q14[ i ] -= QUANT_LEVEL_ADJUST_Q10 << 4; + } else + if( psDec->exc_Q14[ i ] < 0 ) { + psDec->exc_Q14[ i ] += QUANT_LEVEL_ADJUST_Q10 << 4; + } + psDec->exc_Q14[ i ] += offset_Q10 << 4; + if( rand_seed < 0 ) { + psDec->exc_Q14[ i ] = -psDec->exc_Q14[ i ]; + } + + rand_seed = silk_ADD32_ovflw( rand_seed, pulses[ i ] ); + } + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + pexc_Q14 = psDec->exc_Q14; + pxq = xq; + sLTP_buf_idx = psDec->ltp_mem_length; + /* Loop over subframes */ + for( k = 0; k < psDec->nb_subfr; k++ ) { + pres_Q14 = res_Q14; + A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ]; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + B_Q14 = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ]; + signalType = psDec->indices.signalType; + + Gain_Q10 = silk_RSHIFT( psDecCtrl->Gains_Q16[ k ], 6 ); + inv_gain_Q31 = silk_INVERSE32_varQ( psDecCtrl->Gains_Q16[ k ], 47 ); + + /* Calculate gain adjustment factor */ + if( psDecCtrl->Gains_Q16[ k ] != psDec->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( psDec->prev_gain_Q16, psDecCtrl->Gains_Q16[ k ], 16 ); + + /* Scale short term state */ + for( i = 0; i < MAX_LPC_ORDER; i++ ) { + sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, sLPC_Q14[ i ] ); + } + } else { + gain_adj_Q16 = 1 << 16; + } + + /* Save inv_gain */ + silk_assert( inv_gain_Q31 != 0 ); + psDec->prev_gain_Q16 = psDecCtrl->Gains_Q16[ k ]; + + /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */ + if( psDec->lossCnt && psDec->prevSignalType == TYPE_VOICED && + psDec->indices.signalType != TYPE_VOICED && k < MAX_NB_SUBFR/2 ) { + + silk_memset( B_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + B_Q14[ LTP_ORDER/2 ] = SILK_FIX_CONST( 0.25, 14 ); + + signalType = TYPE_VOICED; + psDecCtrl->pitchL[ k ] = psDec->lagPrev; + } + + if( signalType == TYPE_VOICED ) { + /* Voiced */ + lag = psDecCtrl->pitchL[ k ]; + + /* Re-whitening */ + if( k == 0 || ( k == 2 && NLSF_interpolation_flag ) ) { + /* Rewhiten with new A coefs */ + start_idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + silk_assert( start_idx > 0 ); + + if( k == 2 ) { + silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) ); + } + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &psDec->outBuf[ start_idx + k * psDec->subfr_length ], + A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order ); + + /* After rewhitening the LTP state is unscaled */ + if( k == 0 ) { + /* Do LTP downscaling to reduce inter-packet dependency */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, psDecCtrl->LTP_scale_Q14 ), 2 ); + } + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWB( inv_gain_Q31, sLTP[ psDec->ltp_mem_length - i - 1 ] ); + } + } else { + /* Update LTP state when Gain changes */ + if( gain_adj_Q16 != 1 << 16 ) { + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ sLTP_buf_idx - i - 1 ] ); + } + } + } + } + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q15[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + pres_Q14[ i ] = silk_ADD_LSHIFT32( pexc_Q14[ i ], LTP_pred_Q13, 1 ); + + /* Update states */ + sLTP_Q15[ sLTP_buf_idx ] = silk_LSHIFT( pres_Q14[ i ], 1 ); + sLTP_buf_idx++; + } + } else { + pres_Q14 = pexc_Q14; + } + + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Short-term prediction */ + silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] ); + if( psDec->LPC_order == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12_tmp[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12_tmp[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12_tmp[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12_tmp[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12_tmp[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12_tmp[ 15 ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( pres_Q14[ i ], LPC_pred_Q10, 4 ); + + /* Scale with gain */ + pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) ); + } + + /* DEBUG_STORE_DATA( dec.pcm, pxq, psDec->subfr_length * sizeof( opus_int16 ) ) */ + + /* Update LPC filter state */ + silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + pexc_Q14 += psDec->subfr_length; + pxq += psDec->subfr_length; + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, sLPC_Q14, MAX_LPC_ORDER * sizeof( opus_int32 ) ); +} diff --git a/media/libopus/silk/decode_frame.c b/media/libopus/silk/decode_frame.c new file mode 100644 index 000000000000..91adc384e1cc --- /dev/null +++ b/media/libopus/silk/decode_frame.c @@ -0,0 +1,125 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "PLC.h" + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_decoder_control sDecCtrl; + opus_int L, mv_len, ret = 0; + opus_int pulses[ MAX_FRAME_LENGTH ]; + + L = psDec->frame_length; + sDecCtrl.LTP_scale_Q14 = 0; + + /* Safety checks */ + silk_assert( L > 0 && L <= MAX_FRAME_LENGTH ); + + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) ) + { + /*********************************************/ + /* Decode quantization indices of side info */ + /*********************************************/ + silk_decode_indices( psDec, psRangeDec, psDec->nFramesDecoded, lostFlag, condCoding ); + + /*********************************************/ + /* Decode quantization indices of excitation */ + /*********************************************/ + silk_decode_pulses( psRangeDec, pulses, psDec->indices.signalType, + psDec->indices.quantOffsetType, psDec->frame_length ); + + /********************************************/ + /* Decode parameters and pulse signal */ + /********************************************/ + silk_decode_parameters( psDec, &sDecCtrl, condCoding ); + + /* Update length. Sampling frequency may have changed */ + L = psDec->frame_length; + + /********************************************************/ + /* Run inverse NSQ */ + /********************************************************/ + silk_decode_core( psDec, &sDecCtrl, pOut, pulses ); + + /********************************************************/ + /* Update PLC state */ + /********************************************************/ + silk_PLC( psDec, &sDecCtrl, pOut, 0 ); + + psDec->lossCnt = 0; + psDec->prevSignalType = psDec->indices.signalType; + silk_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 ); + + /* A frame has been decoded without errors */ + psDec->first_frame_after_reset = 0; + } else { + /* Handle packet loss by extrapolation */ + silk_PLC( psDec, &sDecCtrl, pOut, 1 ); + } + + /*************************/ + /* Update output buffer. */ + /*************************/ + silk_assert( psDec->ltp_mem_length >= psDec->frame_length ); + mv_len = psDec->ltp_mem_length - psDec->frame_length; + silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) ); + silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) ); + + /****************************************************************/ + /* Ensure smooth connection of extrapolated and good frames */ + /****************************************************************/ + silk_PLC_glue_frames( psDec, pOut, L ); + + /************************************************/ + /* Comfort noise generation / estimation */ + /************************************************/ + silk_CNG( psDec, &sDecCtrl, pOut, L ); + + /* Update some decoder state variables */ + psDec->lagPrev = sDecCtrl.pitchL[ psDec->nb_subfr - 1 ]; + + /* Set output frame length */ + *pN = L; + + return ret; +} diff --git a/media/libopus/silk/decode_indices.c b/media/libopus/silk/decode_indices.c new file mode 100644 index 000000000000..e344b1e767aa --- /dev/null +++ b/media/libopus/silk/decode_indices.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode side-information parameters from payload */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int decode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + + /*******************************************/ + /* Decode signal type and quantizer offset */ + /*******************************************/ + if( decode_LBRR || psDec->VAD_flags[ FrameIndex ] ) { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_VAD_iCDF, 8 ) + 2; + } else { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_no_VAD_iCDF, 8 ); + } + psDec->indices.signalType = (opus_int8)silk_RSHIFT( Ix, 1 ); + psDec->indices.quantOffsetType = (opus_int8)( Ix & 1 ); + + /****************/ + /* Decode gains */ + /****************/ + /* First subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* Conditional coding */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } else { + /* Independent coding, in two stages: MSB bits followed by 3 LSBs */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)silk_LSHIFT( ec_dec_icdf( psRangeDec, silk_gain_iCDF[ psDec->indices.signalType ], 8 ), 3 ); + psDec->indices.GainsIndices[ 0 ] += (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform8_iCDF, 8 ); + } + + /* Remaining subframes */ + for( i = 1; i < psDec->nb_subfr; i++ ) { + psDec->indices.GainsIndices[ i ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } + + /**********************/ + /* Decode LSF Indices */ + /**********************/ + psDec->indices.NLSFIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->CB1_iCDF[ ( psDec->indices.signalType >> 1 ) * psDec->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psDec->psNLSF_CB, psDec->indices.NLSFIndices[ 0 ] ); + silk_assert( psDec->psNLSF_CB->order == psDec->LPC_order ); + for( i = 0; i < psDec->psNLSF_CB->order; i++ ) { + Ix = ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + if( Ix == 0 ) { + Ix -= ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } else if( Ix == 2 * NLSF_QUANT_MAX_AMPLITUDE ) { + Ix += ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } + psDec->indices.NLSFIndices[ i+1 ] = (opus_int8)( Ix - NLSF_QUANT_MAX_AMPLITUDE ); + } + + /* Decode LSF interpolation factor */ + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->indices.NLSFInterpCoef_Q2 = (opus_int8)ec_dec_icdf( psRangeDec, silk_NLSF_interpolation_factor_iCDF, 8 ); + } else { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.signalType == TYPE_VOICED ) + { + /*********************/ + /* Decode pitch lags */ + /*********************/ + /* Get lag index */ + decode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psDec->ec_prevSignalType == TYPE_VOICED ) { + /* Decode Delta index */ + delta_lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_delta_iCDF, 8 ); + if( delta_lagIndex > 0 ) { + delta_lagIndex = delta_lagIndex - 9; + psDec->indices.lagIndex = (opus_int16)( psDec->ec_prevLagIndex + delta_lagIndex ); + decode_absolute_lagIndex = 0; + } + } + if( decode_absolute_lagIndex ) { + /* Absolute decoding */ + psDec->indices.lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_lag_iCDF, 8 ) * silk_RSHIFT( psDec->fs_kHz, 1 ); + psDec->indices.lagIndex += (opus_int16)ec_dec_icdf( psRangeDec, psDec->pitch_lag_low_bits_iCDF, 8 ); + } + psDec->ec_prevLagIndex = psDec->indices.lagIndex; + + /* Get countour index */ + psDec->indices.contourIndex = (opus_int8)ec_dec_icdf( psRangeDec, psDec->pitch_contour_iCDF, 8 ); + + /********************/ + /* Decode LTP gains */ + /********************/ + /* Decode PERIndex value */ + psDec->indices.PERIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_per_index_iCDF, 8 ); + + for( k = 0; k < psDec->nb_subfr; k++ ) { + psDec->indices.LTPIndex[ k ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_gain_iCDF_ptrs[ psDec->indices.PERIndex ], 8 ); + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + psDec->indices.LTP_scaleIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTPscale_iCDF, 8 ); + } else { + psDec->indices.LTP_scaleIndex = 0; + } + } + psDec->ec_prevSignalType = psDec->indices.signalType; + + /***************/ + /* Decode seed */ + /***************/ + psDec->indices.Seed = (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform4_iCDF, 8 ); +} diff --git a/media/libopus/silk/decode_parameters.c b/media/libopus/silk/decode_parameters.c new file mode 100644 index 000000000000..c972805527d7 --- /dev/null +++ b/media/libopus/silk/decode_parameters.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ]; + const opus_int8 *cbk_ptr_Q7; + + /* Dequant Gains */ + silk_gains_dequant( psDecCtrl->Gains_Q16, psDec->indices.GainsIndices, + &psDec->LastGainIndex, condCoding == CODE_CONDITIONALLY, psDec->nb_subfr ); + + /****************/ + /* Decode NLSFs */ + /****************/ + silk_NLSF_decode( pNLSF_Q15, psDec->indices.NLSFIndices, psDec->psNLSF_CB ); + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order ); + + /* If just reset, e.g., because internal Fs changed, do not allow interpolation */ + /* improves the case of packet loss in the first frame after a switch */ + if( psDec->first_frame_after_reset == 1 ) { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.NLSFInterpCoef_Q2 < 4 ) { + /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */ + /* the previous NLSF1, and the current NLSF1 */ + for( i = 0; i < psDec->LPC_order; i++ ) { + pNLSF0_Q15[ i ] = psDec->prevNLSF_Q15[ i ] + silk_RSHIFT( silk_MUL( psDec->indices.NLSFInterpCoef_Q2, + pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ), 2 ); + } + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order ); + } else { + /* Copy LPC coefficients for first half from second half */ + silk_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + } + + silk_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* After a packet loss do BWE of LPC coefs */ + if( psDec->lossCnt ) { + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + } + + if( psDec->indices.signalType == TYPE_VOICED ) { + /*********************/ + /* Decode pitch lags */ + /*********************/ + + /* Decode pitch values */ + silk_decode_pitch( psDec->indices.lagIndex, psDec->indices.contourIndex, psDecCtrl->pitchL, psDec->fs_kHz, psDec->nb_subfr ); + + /* Decode Codebook Index */ + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ psDec->indices.PERIndex ]; /* set pointer to start of codebook */ + + for( k = 0; k < psDec->nb_subfr; k++ ) { + Ix = psDec->indices.LTPIndex[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = silk_LSHIFT( cbk_ptr_Q7[ Ix * LTP_ORDER + i ], 7 ); + } + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + Ix = psDec->indices.LTP_scaleIndex; + psDecCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ Ix ]; + } else { + silk_memset( psDecCtrl->pitchL, 0, psDec->nb_subfr * sizeof( opus_int ) ); + silk_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * psDec->nb_subfr * sizeof( opus_int16 ) ); + psDec->indices.PERIndex = 0; + psDecCtrl->LTP_scale_Q14 = 0; + } +} diff --git a/media/libopus/silk/decode_pitch.c b/media/libopus/silk/decode_pitch.c new file mode 100644 index 000000000000..8fc6f0724781 --- /dev/null +++ b/media/libopus/silk/decode_pitch.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +) +{ + opus_int lag, k, min_lag, max_lag, cbk_size; + const opus_int8 *Lag_CB_ptr; + + if( Fs_kHz == 8 ) { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_EXT; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_10MS; + } + } else { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + } + + min_lag = silk_SMULBB( PE_MIN_LAG_MS, Fs_kHz ); + max_lag = silk_SMULBB( PE_MAX_LAG_MS, Fs_kHz ); + lag = min_lag + lagIndex; + + for( k = 0; k < nb_subfr; k++ ) { + pitch_lags[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, contourIndex, cbk_size ); + pitch_lags[ k ] = silk_LIMIT( pitch_lags[ k ], min_lag, max_lag ); + } +} diff --git a/media/libopus/silk/decode_pulses.c b/media/libopus/silk/decode_pulses.c new file mode 100644 index 000000000000..e398f19c6d1d --- /dev/null +++ b/media/libopus/silk/decode_pulses.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*********************************************/ +/* Decode quantization indices of excitation */ +/*********************************************/ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, j, k, iter, abs_q, nLS, RateLevelIndex; + opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ]; + opus_int *pulses_ptr; + const opus_uint8 *cdf_ptr; + + /*********************/ + /* Decode rate level */ + /*********************/ + RateLevelIndex = ec_dec_icdf( psRangeDec, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + } + + /***************************************************/ + /* Sum-Weighted-Pulses Decoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + nLshifts[ i ] = 0; + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, cdf_ptr, 8 ); + + /* LSB indication */ + while( sum_pulses[ i ] == MAX_PULSES + 1 ) { + nLshifts[ i ]++; + /* When we've already got 10 LSBs, we shift the table to not allow (MAX_PULSES + 1) */ + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, + silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1] + ( nLshifts[ i ] == 10 ), 8 ); + } + } + + /***************************************************/ + /* Shell decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_decoder( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRangeDec, sum_pulses[ i ] ); + } else { + silk_memset( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( opus_int ) ); + } + } + + /***************************************************/ + /* LSB Decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( nLshifts[ i ] > 0 ) { + nLS = nLshifts[ i ]; + pulses_ptr = &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ]; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = pulses_ptr[ k ]; + for( j = 0; j < nLS; j++ ) { + abs_q = silk_LSHIFT( abs_q, 1 ); + abs_q += ec_dec_icdf( psRangeDec, silk_lsb_iCDF, 8 ); + } + pulses_ptr[ k ] = abs_q; + } + /* Mark the number of pulses non-zero for sign decoding. */ + sum_pulses[ i ] |= nLS << 5; + } + } + + /****************************************/ + /* Decode and add signs to pulse signal */ + /****************************************/ + silk_decode_signs( psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); +} diff --git a/media/libopus/silk/decoder_set_fs.c b/media/libopus/silk/decoder_set_fs.c new file mode 100644 index 000000000000..c0bf352b97b5 --- /dev/null +++ b/media/libopus/silk/decoder_set_fs.c @@ -0,0 +1,108 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int fs_API_Hz /* I API Sampling frequency (Hz) */ +) +{ + opus_int frame_length, ret = 0; + + silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + silk_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 ); + + /* New (sub)frame length */ + psDec->subfr_length = silk_SMULBB( SUB_FRAME_LENGTH_MS, fs_kHz ); + frame_length = silk_SMULBB( psDec->nb_subfr, psDec->subfr_length ); + + /* Initialize resampler when switching internal or external sampling frequency */ + if( psDec->fs_kHz != fs_kHz || psDec->fs_API_hz != fs_API_Hz ) { + /* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */ + ret += silk_resampler_init( &psDec->resampler_state, silk_SMULBB( fs_kHz, 1000 ), fs_API_Hz, 0 ); + + psDec->fs_API_hz = fs_API_Hz; + } + + if( psDec->fs_kHz != fs_kHz || frame_length != psDec->frame_length ) { + if( fs_kHz == 8 ) { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psDec->fs_kHz != fs_kHz ) { + psDec->ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + if( fs_kHz == 8 || fs_kHz == 12 ) { + psDec->LPC_order = MIN_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psDec->LPC_order = MAX_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_WB; + } + if( fs_kHz == 16 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( fs_kHz == 12 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else if( fs_kHz == 8 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } else { + /* unsupported sampling rate */ + silk_assert( 0 ); + } + psDec->first_frame_after_reset = 1; + psDec->lagPrev = 100; + psDec->LastGainIndex = 10; + psDec->prevSignalType = TYPE_NO_VOICE_ACTIVITY; + silk_memset( psDec->outBuf, 0, sizeof(psDec->outBuf)); + silk_memset( psDec->sLPC_Q14_buf, 0, sizeof(psDec->sLPC_Q14_buf) ); + } + + psDec->fs_kHz = fs_kHz; + psDec->frame_length = frame_length; + } + + /* Check that settings are valid */ + silk_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH ); + + return ret; +} + diff --git a/media/libopus/silk/define.h b/media/libopus/silk/define.h new file mode 100644 index 000000000000..3dc359594dfb --- /dev/null +++ b/media/libopus/silk/define.h @@ -0,0 +1,240 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_DEFINE_H +#define SILK_DEFINE_H + +#include "errors.h" +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Max number of encoder channels (1/2) */ +#define ENCODER_NUM_CHANNELS 2 +/* Number of decoder channels (1/2) */ +#define DECODER_NUM_CHANNELS 2 + +#define MAX_FRAMES_PER_PACKET 3 + +/* Limits on bitrate */ +#define MIN_TARGET_RATE_BPS 5000 +#define MAX_TARGET_RATE_BPS 80000 +#define TARGET_RATE_TAB_SZ 8 + +/* LBRR thresholds */ +#define LBRR_NB_MIN_RATE_BPS 12000 +#define LBRR_MB_MIN_RATE_BPS 14000 +#define LBRR_WB_MIN_RATE_BPS 16000 + +/* DTX settings */ +#define NB_SPEECH_FRAMES_BEFORE_DTX 10 /* eq 200 ms */ +#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */ + +/* Maximum sampling frequency */ +#define MAX_FS_KHZ 16 +#define MAX_API_FS_KHZ 48 + +/* Signal types */ +#define TYPE_NO_VOICE_ACTIVITY 0 +#define TYPE_UNVOICED 1 +#define TYPE_VOICED 2 + +/* Conditional coding types */ +#define CODE_INDEPENDENTLY 0 +#define CODE_INDEPENDENTLY_NO_LTP_SCALING 1 +#define CODE_CONDITIONALLY 2 + +/* Settings for stereo processing */ +#define STEREO_QUANT_TAB_SIZE 16 +#define STEREO_QUANT_SUB_STEPS 5 +#define STEREO_INTERP_LEN_MS 8 /* must be even */ +#define STEREO_RATIO_SMOOTH_COEF 0.01 /* smoothing coef for signal norms and stereo width */ + +/* Range of pitch lag estimates */ +#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ + +/* Maximum number of subframes */ +#define MAX_NB_SUBFR 4 + +/* Number of samples per frame */ +#define LTP_MEM_LENGTH_MS 20 +#define SUB_FRAME_LENGTH_MS 5 +#define MAX_SUB_FRAME_LENGTH ( SUB_FRAME_LENGTH_MS * MAX_FS_KHZ ) +#define MAX_FRAME_LENGTH_MS ( SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR ) +#define MAX_FRAME_LENGTH ( MAX_FRAME_LENGTH_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for pitch analysis */ +#define LA_PITCH_MS 2 +#define LA_PITCH_MAX ( LA_PITCH_MS * MAX_FS_KHZ ) + +/* Order of LPC used in find pitch */ +#define MAX_FIND_PITCH_LPC_ORDER 16 + +/* Length of LPC window used in find pitch */ +#define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MS_2_SF ( 10 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for noise shape analysis */ +#define LA_SHAPE_MS 5 +#define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ ) + +/* Maximum length of LPC window used in noise shape analysis */ +#define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ ) + +/* dB level of lowest gain quantization level */ +#define MIN_QGAIN_DB 2 +/* dB level of highest gain quantization level */ +#define MAX_QGAIN_DB 88 +/* Number of gain quantization levels */ +#define N_LEVELS_QGAIN 64 +/* Max increase in gain quantization index */ +#define MAX_DELTA_GAIN_QUANT 36 +/* Max decrease in gain quantization index */ +#define MIN_DELTA_GAIN_QUANT -4 + +/* Quantization offsets (multiples of 4) */ +#define OFFSET_VL_Q10 32 +#define OFFSET_VH_Q10 100 +#define OFFSET_UVL_Q10 100 +#define OFFSET_UVH_Q10 240 + +#define QUANT_LEVEL_ADJUST_Q10 80 + +/* Maximum numbers of iterations used to stabilize an LPC vector */ +#define MAX_LPC_STABILIZE_ITERATIONS 16 +#define MAX_PREDICTION_POWER_GAIN 1e4f +#define MAX_PREDICTION_POWER_GAIN_AFTER_RESET 1e2f + +#define MAX_LPC_ORDER 16 +#define MIN_LPC_ORDER 10 + +/* Find Pred Coef defines */ +#define LTP_ORDER 5 + +/* LTP quantization settings */ +#define NB_LTP_CBKS 3 + +/* Flag to use harmonic noise shaping */ +#define USE_HARM_SHAPING 1 + +/* Max LPC order of noise shaping filters */ +#define MAX_SHAPE_LPC_ORDER 16 + +#define HARM_SHAPE_FIR_TAPS 3 + +/* Maximum number of delayed decision states */ +#define MAX_DEL_DEC_STATES 4 + +#define LTP_BUF_LENGTH 512 +#define LTP_MASK ( LTP_BUF_LENGTH - 1 ) + +#define DECISION_DELAY 32 +#define DECISION_DELAY_MASK ( DECISION_DELAY - 1 ) + +/* Number of subframes for excitation entropy coding */ +#define SHELL_CODEC_FRAME_LENGTH 16 +#define LOG2_SHELL_CODEC_FRAME_LENGTH 4 +#define MAX_NB_SHELL_BLOCKS ( MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH ) + +/* Number of rate levels, for entropy coding of excitation */ +#define N_RATE_LEVELS 10 + +/* Maximum sum of pulses per shell coding frame */ +#define MAX_PULSES 16 + +#define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */ + +#if( MAX_LPC_ORDER > DECISION_DELAY ) +# define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER +#else +# define NSQ_LPC_BUF_LENGTH DECISION_DELAY +#endif + +/***********************/ +/* High pass filtering */ +/***********************/ +#define HIGH_PASS_INPUT 1 + +/***************************/ +/* Voice activity detector */ +/***************************/ +#define VAD_N_BANDS 4 + +#define VAD_INTERNAL_SUBFRAMES_LOG2 2 +#define VAD_INTERNAL_SUBFRAMES ( 1 << VAD_INTERNAL_SUBFRAMES_LOG2 ) + +#define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 1024 /* Must be < 4096 */ +#define VAD_NOISE_LEVELS_BIAS 50 + +/* Sigmoid settings */ +#define VAD_NEGATIVE_OFFSET_Q5 128 /* sigmoid is 0 at -128 */ +#define VAD_SNR_FACTOR_Q16 45000 + +/* smoothing for SNR measurement */ +#define VAD_SNR_SMOOTH_COEF_Q18 4096 + +/* Size of the piecewise linear cosine approximation table for the LSFs */ +#define LSF_COS_TAB_SZ_FIX 128 + +/******************/ +/* NLSF quantizer */ +/******************/ +#define NLSF_W_Q 2 +#define NLSF_VQ_MAX_VECTORS 32 +#define NLSF_VQ_MAX_SURVIVORS 32 +#define NLSF_QUANT_MAX_AMPLITUDE 4 +#define NLSF_QUANT_MAX_AMPLITUDE_EXT 10 +#define NLSF_QUANT_LEVEL_ADJ 0.1 +#define NLSF_QUANT_DEL_DEC_STATES_LOG2 2 +#define NLSF_QUANT_DEL_DEC_STATES ( 1 << NLSF_QUANT_DEL_DEC_STATES_LOG2 ) + +/* Transition filtering for mode switching */ +#define TRANSITION_TIME_MS 5120 /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/ +#define TRANSITION_NB 3 /* Hardcoded in tables */ +#define TRANSITION_NA 2 /* Hardcoded in tables */ +#define TRANSITION_INT_NUM 5 /* Hardcoded in tables */ +#define TRANSITION_FRAMES ( TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS ) +#define TRANSITION_INT_STEPS ( TRANSITION_FRAMES / ( TRANSITION_INT_NUM - 1 ) ) + +/* BWE factors to apply after packet loss */ +#define BWE_AFTER_LOSS_Q16 63570 + +/* Defines for CN generation */ +#define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */ +#define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */ +#define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/media/libopus/silk/enc_API.c b/media/libopus/silk/enc_API.c new file mode 100644 index 000000000000..4eb80f9e3a91 --- /dev/null +++ b/media/libopus/silk/enc_API.c @@ -0,0 +1,530 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "define.h" +#include "API.h" +#include "control.h" +#include "typedef.h" +#include "structs.h" +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *encSizeBytes = sizeof( silk_encoder ); + + return ret; +} + +/*************************/ +/* Init or Reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + silk_encoder *psEnc; + opus_int n, ret = SILK_NO_ERROR; + + psEnc = (silk_encoder *)encState; + + /* Reset encoder */ + silk_memset( psEnc, 0, sizeof( silk_encoder ) ); + for( n = 0; n < ENCODER_NUM_CHANNELS; n++ ) { + if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ] ) ) { + silk_assert( 0 ); + } + } + + psEnc->nChannelsAPI = 1; + psEnc->nChannelsInternal = 1; + + /* Read control structure */ + if( ret += silk_QueryEncoder( encState, encStatus ) ) { + silk_assert( 0 ); + } + + return ret; +} + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + opus_int ret = SILK_NO_ERROR; + silk_encoder_state_Fxx *state_Fxx; + silk_encoder *psEnc = (silk_encoder *)encState; + + state_Fxx = psEnc->state_Fxx; + + encStatus->nChannelsAPI = psEnc->nChannelsAPI; + encStatus->nChannelsInternal = psEnc->nChannelsInternal; + encStatus->API_sampleRate = state_Fxx[ 0 ].sCmn.API_fs_Hz; + encStatus->maxInternalSampleRate = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz; + encStatus->minInternalSampleRate = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz; + encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz; + encStatus->payloadSize_ms = state_Fxx[ 0 ].sCmn.PacketSize_ms; + encStatus->bitRate = state_Fxx[ 0 ].sCmn.TargetRate_bps; + encStatus->packetLossPercentage = state_Fxx[ 0 ].sCmn.PacketLoss_perc; + encStatus->complexity = state_Fxx[ 0 ].sCmn.Complexity; + encStatus->useInBandFEC = state_Fxx[ 0 ].sCmn.useInBandFEC; + encStatus->useDTX = state_Fxx[ 0 ].sCmn.useDTX; + encStatus->useCBR = state_Fxx[ 0 ].sCmn.useCBR; + encStatus->internalSampleRate = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encStatus->allowBandwidthSwitch = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch; + encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0; + + return ret; +} + + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */ +) +{ + opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0; + opus_int nSamplesToBuffer, nBlocksOf10ms, nSamplesFromInput = 0; + opus_int speech_act_thr_for_switch_Q8; + opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum; + silk_encoder *psEnc = ( silk_encoder * )encState; + opus_int16 buf[ MAX_FRAME_LENGTH_MS * MAX_API_FS_KHZ ]; + opus_int transition, curr_block, tot_blocks; + + psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0; + + /* Check values in encoder control structure */ + if( ( ret = check_control_input( encControl ) != 0 ) ) { + silk_assert( 0 ); + return ret; + } + + encControl->switchReady = 0; + + if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) { + /* Mono -> Stereo transition: init state of second channel and stereo state */ + ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ] ); + silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) ); + silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) ); + psEnc->sStereo.mid_side_amp_Q0[ 0 ] = 0; + psEnc->sStereo.mid_side_amp_Q0[ 1 ] = 1; + psEnc->sStereo.mid_side_amp_Q0[ 2 ] = 0; + psEnc->sStereo.mid_side_amp_Q0[ 3 ] = 1; + psEnc->sStereo.width_prev_Q14 = 0; + psEnc->sStereo.smth_width_Q14 = SILK_FIX_CONST( 1, 14 ); + if( psEnc->nChannelsAPI == 2 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) ); + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State, &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State, sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) ); + } + } + + transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal); + + psEnc->nChannelsAPI = encControl->nChannelsAPI; + psEnc->nChannelsInternal = encControl->nChannelsInternal; + + nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate ); + tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1; + curr_block = 0; + if( prefillFlag ) { + /* Only accept input length of 10 ms */ + if( nBlocksOf10ms != 1 ) { + ret = SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + silk_assert( 0 ); + return ret; + } + /* Reset Encoder */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + if( (ret = silk_init_encoder( &psEnc->state_Fxx[ n ] ) ) != 0 ) { + silk_assert( 0 ); + } + } + tmp_payloadSize_ms = encControl->payloadSize_ms; + encControl->payloadSize_ms = 10; + tmp_complexity = encControl->complexity; + encControl->complexity = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1; + } + } else { + /* Only accept input lengths that are a multiple of 10 ms */ + if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) { + ret = SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + silk_assert( 0 ); + return ret; + } + /* Make sure no more than one packet can be produced */ + if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) { + ret = SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + silk_assert( 0 ); + return ret; + } + } + + TargetRate_bps = silk_RSHIFT32( encControl->bitRate, encControl->nChannelsInternal - 1 ); + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + /* Force the side channel to the same rate as the mid */ + opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0; + if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, TargetRate_bps, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) { + silk_assert( 0 ); + return ret; + } + if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) { + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0; + } + } + psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX; + } + silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + + /* Input buffering/resampling and encoding */ + while( 1 ) { + nSamplesToBuffer = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz ); + nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 ); + /* Resample and write to buffer */ + if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) { + opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded; + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n ]; + } + /* Making sure to start both resamplers from the same state when switching from mono to stereo */ + if( psEnc->nPrevChannelsInternal == 1 && id==0 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state)); + } + + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + + nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n + 1 ]; + } + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + + psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer; + } else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) { + /* Combine left and right channels before resampling */ + for( n = 0; n < nSamplesFromInput; n++ ) { + sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ]; + buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + } + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + /* On the first mono frame, average the results for the two resampler states */ + if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) { + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) { + psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] = + silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] + + psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1); + } + } + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } else { + silk_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 ); + silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16)); + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } + + samplesIn += nSamplesFromInput * encControl->nChannelsAPI; + nSamplesIn -= nSamplesFromInput; + + /* Default */ + psEnc->allowBandwidthSwitch = 0; + + /* Silk encoder */ + if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) { + /* Enough data in input buffer, so encode */ + silk_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length ); + + /* Deal with LBRR data */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) { + /* Create space at start of payload for VAD and FEC flags */ + opus_uint8 iCDF[ 2 ] = { 0, 0 }; + iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + ec_enc_icdf( psRangeEnc, 0, iCDF, 8 ); + + /* Encode any LBRR data from previous packet */ + /* Encode LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + LBRR_symbol = 0; + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i ); + } + psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0; + if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) { + ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 ); + } + } + + /* Code LBRR indices and excitation signals */ + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) { + opus_int condCoding; + + if( encControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] ); + /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */ + if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding ); + silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType, + psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length ); + } + } + } + + /* Reset LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) ); + } + } + + silk_HP_variable_cutoff( psEnc->state_Fxx ); + + /* Total target bits for packet */ + nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + /* Subtract half of the bits already used */ + if( !prefillFlag ) { + nBits -= ec_tell( psRangeEnc ) >> 1; + } + /* Divide by number of uncoded frames left in packet */ + nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket - psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ); + /* Convert to bits/second */ + if( encControl->payloadSize_ms == 10 ) { + TargetRate_bps = silk_SMULBB( nBits, 100 ); + } else { + TargetRate_bps = silk_SMULBB( nBits, 50 ); + } + /* Subtract fraction of bits in excess of target in previous packets */ + TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS ); + /* Never exceed input bitrate */ + TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 ); + + /* Convert Left/Right to Mid/Side */ + if( encControl->nChannelsInternal == 2 ) { + silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ], + psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], + MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono, + psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + /* Reset side channel encoder memory for first frame with side coding */ + if( psEnc->prev_decode_only_middle == 1 ) { + silk_memset( &psEnc->state_Fxx[ 1 ].sShape, 0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sPrefilt, 0, sizeof( psEnc->state_Fxx[ 1 ].sPrefilt ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) ); + silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) ); + psEnc->state_Fxx[ 1 ].sCmn.prevLag = 100; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev = 100; + psEnc->state_Fxx[ 1 ].sShape.LastGainIndex = 10; + psEnc->state_Fxx[ 1 ].sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1; + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ] ); + } else { + psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0; + } + if( !prefillFlag ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + } + } + } else { + /* Buffering */ + silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) ); + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ] ); + + /* Encode */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + opus_int maxBits, useCBR; + + /* Handling rate constraints */ + maxBits = encControl->maxBits; + if( tot_blocks == 2 && curr_block == 0 ) { + maxBits = maxBits * 3 / 5; + } else if( tot_blocks == 3 ) { + if( curr_block == 0 ) { + maxBits = maxBits * 2 / 5; + } else if( curr_block == 1 ) { + maxBits = maxBits * 3 / 4; + } + } + useCBR = encControl->useCBR && curr_block == tot_blocks - 1; + + if( encControl->nChannelsInternal == 1 ) { + channelRate_bps = TargetRate_bps; + } else { + channelRate_bps = MStargetRates_bps[ n ]; + if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) { + useCBR = 0; + /* Give mid up to 1/2 of the max bits for that frame */ + maxBits -= encControl->maxBits / ( tot_blocks * 2 ); + } + } + + if( channelRate_bps > 0 ) { + opus_int condCoding; + + silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps ); + + /* Use independent coding if no previous frame available */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( n > 0 && psEnc->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) { + silk_assert( 0 ); + } + } + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0; + psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++; + } + psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ]; + + /* Insert VAD and FEC flags at beginning of bitstream */ + if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) { + flags = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ]; + } + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag; + } + if( !prefillFlag ) { + ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + } + + /* Return zero bytes if all channels DTXed */ + if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) { + *nBytesOut = 0; + } + + psEnc->nBitsExceeded += *nBytesOut * 8; + psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + psEnc->nBitsExceeded = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 ); + + /* Update flag indicating if bandwidth switching is allowed */ + speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ), + SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms ); + if( psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8 < speech_act_thr_for_switch_Q8 ) { + psEnc->allowBandwidthSwitch = 1; + psEnc->timeSinceSwitchAllowed_ms = 0; + } else { + psEnc->allowBandwidthSwitch = 0; + psEnc->timeSinceSwitchAllowed_ms += encControl->payloadSize_ms; + } + } + + if( nSamplesIn == 0 ) { + break; + } + } else { + break; + } + curr_block++; + } + + psEnc->nPrevChannelsInternal = encControl->nChannelsInternal; + + encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch; + encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0; + encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14; + if( prefillFlag ) { + encControl->payloadSize_ms = tmp_payloadSize_ms; + encControl->complexity = tmp_complexity; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0; + } + } + + return ret; +} + diff --git a/media/libopus/silk/encode_indices.c b/media/libopus/silk/encode_indices.c new file mode 100644 index 000000000000..f969a9b63987 --- /dev/null +++ b/media/libopus/silk/encode_indices.c @@ -0,0 +1,181 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Encode side-information parameters to payload */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, typeOffset; + opus_int encode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + const SideInfoIndices *psIndices; + + if( encode_LBRR ) { + psIndices = &psEncC->indices_LBRR[ FrameIndex ]; + } else { + psIndices = &psEncC->indices; + } + + /*******************************************/ + /* Encode signal type and quantizer offset */ + /*******************************************/ + typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType; + silk_assert( typeOffset >= 0 && typeOffset < 6 ); + silk_assert( encode_LBRR == 0 || typeOffset >= 2 ); + if( encode_LBRR || typeOffset >= 2 ) { + ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 ); + } + + /****************/ + /* Encode gains */ + /****************/ + /* first subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* conditional coding */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 ); + } else { + /* independent coding, in two stages: MSB bits followed by 3 LSBs */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN ); + ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 ); + } + + /* remaining subframes */ + for( i = 1; i < psEncC->nb_subfr; i++ ) { + silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 ); + } + + /****************/ + /* Encode NLSFs */ + /****************/ + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] ); + silk_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder ); + for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) { + if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + } + } + + /* Encode NLSF interpolation factor */ + if( psEncC->nb_subfr == MAX_NB_SUBFR ) { + silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 ); + } + + if( psIndices->signalType == TYPE_VOICED ) + { + /*********************/ + /* Encode pitch lags */ + /*********************/ + /* lag index */ + encode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) { + /* Delta Encoding */ + delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex; + if( delta_lagIndex < -8 || delta_lagIndex > 11 ) { + delta_lagIndex = 0; + } else { + delta_lagIndex = delta_lagIndex + 9; + encode_absolute_lagIndex = 0; /* Only use delta */ + } + silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 ); + ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 ); + } + if( encode_absolute_lagIndex ) { + /* Absolute encoding */ + opus_int32 pitch_high_bits, pitch_low_bits; + pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 ); + silk_assert( pitch_high_bits < 32 ); + ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 ); + } + psEncC->ec_prevLagIndex = psIndices->lagIndex; + + /* Countour index */ + silk_assert( psIndices->contourIndex >= 0 ); + silk_assert( ( psIndices->contourIndex < 34 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 4 ) || + ( psIndices->contourIndex < 11 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 4 ) || + ( psIndices->contourIndex < 12 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 2 ) || + ( psIndices->contourIndex < 3 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 2 ) ); + ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 ); + + /********************/ + /* Encode LTP gains */ + /********************/ + /* PERIndex value */ + silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 ); + + /* Codebook Indices */ + for( k = 0; k < psEncC->nb_subfr; k++ ) { + silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) ); + ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 ); + } + + /**********************/ + /* Encode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 ); + } + silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 ); + } + + psEncC->ec_prevSignalType = psIndices->signalType; + + /***************/ + /* Encode seed */ + /***************/ + silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 ); + ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 ); +} diff --git a/media/libopus/silk/encode_pulses.c b/media/libopus/silk/encode_pulses.c new file mode 100644 index 000000000000..32eb4cf82696 --- /dev/null +++ b/media/libopus/silk/encode_pulses.c @@ -0,0 +1,199 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*********************************************/ +/* Encode quantization indices of excitation */ +/*********************************************/ + +static inline opus_int combine_and_check( /* return ok */ + opus_int *pulses_comb, /* O */ + const opus_int *pulses_in, /* I */ + opus_int max_pulses, /* I max value for sum of pulses */ + opus_int len /* I number of output values */ +) +{ + opus_int k, sum; + + for( k = 0; k < len; k++ ) { + sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ]; + if( sum > max_pulses ) { + return 1; + } + pulses_comb[ k ] = sum; + } + + return 0; +} + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0; + opus_int32 abs_q, minSumBits_Q5, sumBits_Q5; + opus_int abs_pulses[ MAX_FRAME_LENGTH ]; + opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ]; + opus_int nRshifts[ MAX_NB_SHELL_BLOCKS ]; + opus_int pulses_comb[ 8 ]; + opus_int *abs_pulses_ptr; + const opus_int8 *pulses_ptr; + const opus_uint8 *cdf_ptr; + const opus_uint8 *nBits_ptr; + + silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/ + + /****************************/ + /* Prepare for shell coding */ + /****************************/ + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8)); + } + + /* Take the absolute value of the pulses */ + for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) { + abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] ); + abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] ); + abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] ); + abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ i + 3 ] ); + } + + /* Calc sum pulses per shell code frame */ + abs_pulses_ptr = abs_pulses; + for( i = 0; i < iter; i++ ) { + nRshifts[ i ] = 0; + + while( 1 ) { + /* 1+1 -> 2 */ + scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, silk_max_pulses_table[ 0 ], 8 ); + /* 2+2 -> 4 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 ); + /* 4+4 -> 8 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 ); + /* 8+8 -> 16 */ + scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 ); + + if( scale_down ) { + /* We need to downscale the quantization signal */ + nRshifts[ i ]++; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_pulses_ptr[ k ] = silk_RSHIFT( abs_pulses_ptr[ k ], 1 ); + } + } else { + /* Jump out of while(1) loop and go to next shell coding frame */ + break; + } + } + abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH; + } + + /**************/ + /* Rate level */ + /**************/ + /* find rate level that leads to fewest bits for coding of pulses per block info */ + minSumBits_Q5 = silk_int32_MAX; + for( k = 0; k < N_RATE_LEVELS - 1; k++ ) { + nBits_ptr = silk_pulses_per_block_BITS_Q5[ k ]; + sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + sumBits_Q5 += nBits_ptr[ MAX_PULSES + 1 ]; + } else { + sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ]; + } + } + if( sumBits_Q5 < minSumBits_Q5 ) { + minSumBits_Q5 = sumBits_Q5; + RateLevelIndex = k; + } + } + ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /***************************************************/ + /* Sum-Weighted-Pulses Encoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] == 0 ) { + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 ); + } else { + ec_enc_icdf( psRangeEnc, MAX_PULSES + 1, cdf_ptr, 8 ); + for( k = 0; k < nRshifts[ i ] - 1; k++ ) { + ec_enc_icdf( psRangeEnc, MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + } + + /******************/ + /* Shell Encoding */ + /******************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] ); + } + } + + /****************/ + /* LSB Encoding */ + /****************/ + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ]; + nLS = nRshifts[ i ] - 1; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] ); + for( j = nLS; j > 0; j-- ) { + bit = silk_RSHIFT( abs_q, j ) & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + bit = abs_q & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + } + } + + /****************/ + /* Encode signs */ + /****************/ + silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); +} diff --git a/media/libopus/silk/errors.h b/media/libopus/silk/errors.h new file mode 100644 index 000000000000..b936cf5af0d4 --- /dev/null +++ b/media/libopus/silk/errors.h @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_ERRORS_H +#define SILK_ERRORS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************/ +/* Error messages */ +/******************/ +#define SILK_NO_ERROR 0 + +/**************************/ +/* Encoder error messages */ +/**************************/ + +/* Input length is not a multiple of 10 ms, or length is longer than the packet length */ +#define SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES -101 + +/* Sampling frequency not 8000, 12000 or 16000 Hertz */ +#define SILK_ENC_FS_NOT_SUPPORTED -102 + +/* Packet size not 10, 20, 40, or 60 ms */ +#define SILK_ENC_PACKET_SIZE_NOT_SUPPORTED -103 + +/* Allocated payload buffer too short */ +#define SILK_ENC_PAYLOAD_BUF_TOO_SHORT -104 + +/* Loss rate not between 0 and 100 percent */ +#define SILK_ENC_INVALID_LOSS_RATE -105 + +/* Complexity setting not valid, use 0...10 */ +#define SILK_ENC_INVALID_COMPLEXITY_SETTING -106 + +/* Inband FEC setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_INBAND_FEC_SETTING -107 + +/* DTX setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_DTX_SETTING -108 + +/* CBR setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_CBR_SETTING -109 + +/* Internal encoder error */ +#define SILK_ENC_INTERNAL_ERROR -110 + +/* Internal encoder error */ +#define SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR -111 + +/**************************/ +/* Decoder error messages */ +/**************************/ + +/* Output sampling frequency lower than internal decoded sampling frequency */ +#define SILK_DEC_INVALID_SAMPLING_FREQUENCY -200 + +/* Payload size exceeded the maximum allowed 1024 bytes */ +#define SILK_DEC_PAYLOAD_TOO_LARGE -201 + +/* Payload has bit errors */ +#define SILK_DEC_PAYLOAD_ERROR -202 + +/* Payload has bit errors */ +#define SILK_DEC_INVALID_FRAME_SIZE -203 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/media/libopus/silk/fixed/LTP_analysis_filter_FIX.c b/media/libopus/silk/fixed/LTP_analysis_filter_FIX.c new file mode 100644 index 000000000000..33257f840bf1 --- /dev/null +++ b/media/libopus/silk/fixed/LTP_analysis_filter_FIX.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceeding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceeding samples starting at &x[0] for each subframe */ +) +{ + const opus_int16 *x_ptr, *x_lag_ptr; + opus_int16 Btmp_Q14[ LTP_ORDER ]; + opus_int16 *LTP_res_ptr; + opus_int k, i, j; + opus_int32 LTP_est; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < nb_subfr; k++ ) { + + x_lag_ptr = x_ptr - pitchL[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + Btmp_Q14[ i ] = LTPCoef_Q14[ k * LTP_ORDER + i ]; + } + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + + /* Long-term prediction */ + LTP_est = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] ); + for( j = 1; j < LTP_ORDER; j++ ) { + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ LTP_ORDER / 2 - j ], Btmp_Q14[ j ] ); + } + LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/ + + /* Subtract long-term prediction */ + LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est ); + + /* Scale residual */ + LTP_res_ptr[ i ] = silk_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] ); + + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} + diff --git a/media/libopus/silk/fixed/LTP_scale_ctrl_FIX.c b/media/libopus/silk/fixed/LTP_scale_ctrl_FIX.c new file mode 100644 index 000000000000..0aace53a3880 --- /dev/null +++ b/media/libopus/silk/fixed/LTP_scale_ctrl_FIX.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( + silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ]; +} diff --git a/media/libopus/silk/fixed/apply_sine_window_FIX.c b/media/libopus/silk/fixed/apply_sine_window_FIX.c new file mode 100644 index 000000000000..4d4f096e1301 --- /dev/null +++ b/media/libopus/silk/fixed/apply_sine_window_FIX.c @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* Every other sample is linearly interpolated, for speed. */ +/* Window length must be between 16 and 120 (incl) and a multiple of 4. */ + +/* Matlab code for table: + for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end +*/ +static opus_int16 freq_table_Q16[ 27 ] = { + 12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202, + 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422, + 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702, +}; + +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k, f_Q16, c_Q16; + opus_int32 S0_Q16, S1_Q16; + + silk_assert( win_type == 1 || win_type == 2 ); + + /* Length must be in a range from 16 to 120 and a multiple of 4 */ + silk_assert( length >= 16 && length <= 120 ); + silk_assert( ( length & 3 ) == 0 ); + + /* Frequency */ + k = ( length >> 2 ) - 4; + silk_assert( k >= 0 && k <= 26 ); + f_Q16 = (opus_int)freq_table_Q16[ k ]; + + /* Factor used for cosine approximation */ + c_Q16 = silk_SMULWB( f_Q16, -f_Q16 ); + silk_assert( c_Q16 >= -32768 ); + + /* initialize state */ + if( win_type == 1 ) { + /* start from 0 */ + S0_Q16 = 0; + /* approximation of sin(f) */ + S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 ); + } else { + /* start from 1 */ + S0_Q16 = ( 1 << 16 ); + /* approximation of cos(f) */ + S1_Q16 = ( 1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_RSHIFT( length, 4 ); + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] ); + px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] ); + S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1; + S0_Q16 = silk_min( S0_Q16, ( 1 << 16 ) ); + + px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] ); + px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] ); + S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16; + S1_Q16 = silk_min( S1_Q16, ( 1 << 16 ) ); + } +} diff --git a/media/libopus/silk/fixed/autocorr_FIX.c b/media/libopus/silk/fixed/autocorr_FIX.c new file mode 100644 index 000000000000..dd6c77922ff8 --- /dev/null +++ b/media/libopus/silk/fixed/autocorr_FIX.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount /* I Number of correlation taps to compute */ +) +{ + opus_int i, lz, nRightShifts, corrCount; + opus_int64 corr64; + + corrCount = silk_min_int( inputDataSize, correlationCount ); + + /* compute energy (zero-lag correlation) */ + corr64 = silk_inner_prod16_aligned_64( inputData, inputData, inputDataSize ); + + /* deal with all-zero input data */ + corr64 += 1; + + /* number of leading zeros */ + lz = silk_CLZ64( corr64 ); + + /* scaling: number of right shifts applied to correlations */ + nRightShifts = 35 - lz; + *scale = nRightShifts; + + if( nRightShifts <= 0 ) { + results[ 0 ] = silk_LSHIFT( (opus_int32)silk_CHECK_FIT32( corr64 ), -nRightShifts ); + + /* compute remaining correlations based on int32 inner product */ + for( i = 1; i < corrCount; i++ ) { + results[ i ] = silk_LSHIFT( silk_inner_prod_aligned( inputData, inputData + i, inputDataSize - i ), -nRightShifts ); + } + } else { + results[ 0 ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr64, nRightShifts ) ); + + /* compute remaining correlations based on int64 inner product */ + for( i = 1; i < corrCount; i++ ) { + results[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_inner_prod16_aligned_64( inputData, inputData + i, inputDataSize - i ), nRightShifts ) ); + } + } +} diff --git a/media/libopus/silk/fixed/burg_modified_FIX.c b/media/libopus/silk/fixed/burg_modified_FIX.c new file mode 100644 index 000000000000..fc82d36853f9 --- /dev/null +++ b/media/libopus/silk/fixed/burg_modified_FIX.c @@ -0,0 +1,269 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "define.h" +#include "tuning_parameters.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */ + +#define QA 25 +#define N_BITS_HEAD_ROOM 2 +#define MIN_RSHIFTS -16 +#define MAX_RSHIFTS (32 - QA) + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceeding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D /* I Order */ +) +{ + opus_int k, n, s, lz, rshifts, rshifts_extra, reached_max_gain; + opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const opus_int16 *x_ptr; + opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; + + silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length ); + if( rshifts > MAX_RSHIFTS ) { + C0 = silk_LSHIFT32( C0, rshifts - MAX_RSHIFTS ); + silk_assert( C0 > 0 ); + rshifts = MAX_RSHIFTS; + } else { + lz = silk_CLZ32( C0 ) - 1; + rshifts_extra = N_BITS_HEAD_ROOM - lz; + if( rshifts_extra > 0 ) { + rshifts_extra = silk_min( rshifts_extra, MAX_RSHIFTS - rshifts ); + C0 = silk_RSHIFT32( C0, rshifts_extra ); + } else { + rshifts_extra = silk_max( rshifts_extra, MIN_RSHIFTS - rshifts ); + C0 = silk_LSHIFT32( C0, -rshifts_extra ); + } + rshifts += rshifts_extra; + } + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64( + silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n ), rshifts ); + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_LSHIFT32( + silk_inner_prod_aligned( x_ptr, x_ptr + n, subfr_length - n ), -rshifts ); + } + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + + invGain_Q30 = 1 << 30; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + if( rshifts > -2 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp_QA = Af_QA[ k ]; + tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */ + tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */ + } + tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */ + tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */ + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */ + tmp1 = silk_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */ + tmp2 = silk_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */ + } + tmp1 = -tmp1; /* Q17 */ + tmp2 = -tmp2; /* Q17 */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1, + silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2, + silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */ + } + } + } + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */ + tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */ + num = 0; /* Q( -rshifts ) */ + nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */ + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1; + lz = silk_min( 32 - QA, lz ); + Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */ + + tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ), + Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */ + } + CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */ + CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */ + num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */ + num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */ + + /* Calculate the next order reflection (parcor) coefficient */ + if( silk_abs( num ) < nrg ) { + rc_Q31 = silk_DIV32_varQ( num, nrg, 31 ); + } else { + rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN; + } + + /* Update inverse prediction gain */ + tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 ); + if( tmp1 <= minInvGain_Q30 ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + tmp2 = ( 1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */ + rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */ + /* Newton-Raphson iteration */ + rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */ + rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */ + if( num < 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc_Q31 = -rc_Q31; + } + invGain_Q30 = minInvGain_Q30; + reached_max_gain = 1; + } else { + invGain_Q30 = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af_QA[ k ]; /* QA */ + tmp2 = Af_QA[ n - k - 1 ]; /* QA */ + Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */ + Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */ + } + Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */ + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af_QA[ k ] = 0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; /* Q( -rshifts ) */ + tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */ + CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + } + } + + if( reached_max_gain ) { + for( k = 0; k < D; k++ ) { + /* Scale coefficients */ + A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); + } + /* Subtract energy of preceeding samples from C0 */ + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D ), rshifts ); + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D ), -rshifts ); + } + } + /* Approximate residual energy */ + *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 ); + *res_nrg_Q = -rshifts; + } else { + /* Return residual energy */ + nrg = CAf[ 0 ]; /* Q( -rshifts ) */ + tmp1 = 1 << 16; /* Q16 */ + for( k = 0; k < D; k++ ) { + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */ + nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */ + tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */ + A_Q16[ k ] = -Atmp1; + } + *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( FIND_LPC_COND_FAC, C0 ), -tmp1 ); /* Q( -rshifts ) */ + *res_nrg_Q = -rshifts; + } +} diff --git a/media/libopus/silk/fixed/corrMatrix_FIX.c b/media/libopus/silk/fixed/corrMatrix_FIX.c new file mode 100644 index 000000000000..c0d3109a4f24 --- /dev/null +++ b/media/libopus/silk/fixed/corrMatrix_FIX.c @@ -0,0 +1,156 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/********************************************************************** + * Correlation Matrix Computations for LS estimate. + **********************************************************************/ + +#include "main_FIX.h" + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts /* I Right shifts of correlations */ +) +{ + opus_int lag, i; + const opus_int16 *ptr1, *ptr2; + opus_int32 inner_prod; + + ptr1 = &x[ order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + ptr2 = t; + /* Calculate X'*t */ + if( rshifts > 0 ) { + /* Right shifting used */ + for( lag = 0; lag < order; lag++ ) { + inner_prod = 0; + for( i = 0; i < L; i++ ) { + inner_prod += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts ); + } + Xt[ lag ] = inner_prod; /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } else { + silk_assert( rshifts == 0 ); + for( lag = 0; lag < order; lag++ ) { + Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L ); /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + const opus_int head_room, /* I Desired headroom */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int *rshifts /* I/O Right shifts of correlations */ +) +{ + opus_int i, j, lag, rshifts_local, head_room_rshifts; + opus_int32 energy; + const opus_int16 *ptr1, *ptr2; + + /* Calculate energy to find shift used to fit in 32 bits */ + silk_sum_sqr_shift( &energy, &rshifts_local, x, L + order - 1 ); + /* Add shifts to get the desired head room */ + head_room_rshifts = silk_max( head_room - silk_CLZ32( energy ), 0 ); + + energy = silk_RSHIFT32( energy, head_room_rshifts ); + rshifts_local += head_room_rshifts; + + /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */ + /* Remove contribution of first order - 1 samples */ + for( i = 0; i < order - 1; i++ ) { + energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), rshifts_local ); + } + if( rshifts_local < *rshifts ) { + /* Adjust energy */ + energy = silk_RSHIFT32( energy, *rshifts - rshifts_local ); + rshifts_local = *rshifts; + } + + /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */ + /* Fill out the diagonal of the correlation matrix */ + matrix_ptr( XX, 0, 0, order ) = energy; + ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */ + for( j = 1; j < order; j++ ) { + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), rshifts_local ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), rshifts_local ) ); + matrix_ptr( XX, j, j, order ) = energy; + } + + ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */ + /* Calculate the remaining elements of the correlation matrix */ + if( rshifts_local > 0 ) { + /* Right shifting used */ + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = 0; + for( i = 0; i < L; i++ ) { + energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts_local ); + } + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + for( j = 1; j < ( order - lag ); j++ ) { + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), rshifts_local ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), rshifts_local ) ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--; /* Update pointer to first sample of next column (lag) in X */ + } + } else { + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = silk_inner_prod_aligned( ptr1, ptr2, L ); + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( order - lag ); j++ ) { + energy = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) ); + energy = silk_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--;/* Update pointer to first sample of next column (lag) in X */ + } + } + *rshifts = rshifts_local; +} + diff --git a/media/libopus/silk/fixed/encode_frame_FIX.c b/media/libopus/silk/fixed/encode_frame_FIX.c new file mode 100644 index 000000000000..601a078220f5 --- /dev/null +++ b/media/libopus/silk/fixed/encode_frame_FIX.c @@ -0,0 +1,372 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static inline void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int32 xfw_Q3[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ +) +{ + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1 ); + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter < NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FIX sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + opus_int16 *x_frame, *res_pitch_frame; + opus_int32 xfw_Q3[ MAX_FRAME_LENGTH ]; + opus_int16 res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_uint8 ec_buf_copy[ 1275 ]; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /*************************************************************/ + /* pointers aligned with start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /* start of frame to encode */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /* start of pitch LPC residual frame */ + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) ); + + if( !psEnc->sCmn.prefillFlag ) { + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding ); + + /*****************************************/ + /* Prefiltering for noise shaper */ + /*****************************************/ + silk_prefilter_FIX( psEnc, &sEncCtrl, xfw_Q3, x_frame ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FIX( psEnc, &sEncCtrl, xfw_Q3, condCoding ); + + /* Loop over quantizer and entropy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 ); + } else { + silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 ); + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + silk_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 ); + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + silk_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) ); + if( nBits > maxBits ) { + gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) ); + } + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) ); + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + return ret; + } + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static inline void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int32 xfw_Q3[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int32 TempGains_Q16[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + /* Overwrite unquantized gains with quantized gains */ + silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 ); + } else { + silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 ); + } + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + } +} diff --git a/media/libopus/silk/fixed/find_LPC_FIX.c b/media/libopus/silk/fixed/find_LPC_FIX.c new file mode 100644 index 000000000000..ba52fa2b2ad7 --- /dev/null +++ b/media/libopus/silk/fixed/find_LPC_FIX.c @@ -0,0 +1,145 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Finds LPC vector from correlations, and converts to NLSF */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + opus_int32 a_Q16[ MAX_LPC_ORDER ]; + opus_int isInterpLower, shift; + opus_int32 res_nrg0, res_nrg1; + opus_int rshift0, rshift1; + + /* Used only for LSF interpolation */ + opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; + opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; + opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + opus_int16 LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ]; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: no interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + /* Optimal solution for last 10 ms */ + silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder ); + + /* subtract residual energy here, as that's easier than adding it to the */ + /* residual energy of the first 10 ms in each iteration of the search below */ + shift = res_tmp_nrg_Q - res_nrg_Q; + if( shift >= 0 ) { + if( shift < 32 ) { + res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift ); + } + } else { + silk_assert( shift > -32 ); + res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; + res_nrg_Q = res_tmp_nrg_Q; + } + + /* Convert to NLSFs */ + silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder ); + + /* Calculate residual energy with NLSF interpolation */ + silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder ); + + silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ); + silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ); + + /* Add subframe energies from first half frame */ + shift = rshift0 - rshift1; + if( shift >= 0 ) { + res_nrg1 = silk_RSHIFT( res_nrg1, shift ); + res_nrg_interp_Q = -rshift0; + } else { + res_nrg0 = silk_RSHIFT( res_nrg0, -shift ); + res_nrg_interp_Q = -rshift1; + } + res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 ); + + /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */ + shift = res_nrg_interp_Q - res_nrg_Q; + if( shift >= 0 ) { + if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + if( -shift < 32 ) { + if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + isInterpLower = silk_FALSE; + } + } + + /* Determine whether current interpolated NLSFs are best so far */ + if( isInterpLower == silk_TRUE ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + res_nrg_Q = res_nrg_interp_Q; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder ); + } + + silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); +} diff --git a/media/libopus/silk/fixed/find_LTP_FIX.c b/media/libopus/silk/fixed/find_LTP_FIX.c new file mode 100644 index 000000000000..078d84cb0723 --- /dev/null +++ b/media/libopus/silk/fixed/find_LTP_FIX.c @@ -0,0 +1,244 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Head room for correlations */ +#define LTP_CORRS_HEAD_ROOM 2 + +void silk_fit_LTP( + opus_int32 LTP_coefs_Q16[ LTP_ORDER ], + opus_int16 LTP_coefs_Q14[ LTP_ORDER ] +); + +void silk_find_LTP_FIX( + opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + opus_int *LTPredCodGain_Q7, /* O LTP coding gain */ + const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */ + const opus_int subfr_length, /* I subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset, /* I number of samples in LTP memory */ + opus_int corr_rshifts[ MAX_NB_SUBFR ] /* O right shifts applied to correlations */ +) +{ + opus_int i, k, lshift; + const opus_int16 *r_ptr, *lag_ptr; + opus_int16 *b_Q14_ptr; + + opus_int32 regu; + opus_int32 *WLTP_ptr; + opus_int32 b_Q16[ LTP_ORDER ], delta_b_Q14[ LTP_ORDER ], d_Q14[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], g_Q26; + opus_int32 w[ MAX_NB_SUBFR ], WLTP_max, max_abs_d_Q14, max_w_bits; + + opus_int32 temp32, denom32; + opus_int extra_shifts; + opus_int rr_shifts, maxRshifts, maxRshifts_wxtra, LZs; + opus_int32 LPC_res_nrg, LPC_LTP_res_nrg, div_Q16; + opus_int32 Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ]; + opus_int32 wd, m_Q12; + + b_Q14_ptr = b_Q14; + WLTP_ptr = WLTP; + r_ptr = &r_lpc[ mem_offset ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + + silk_sum_sqr_shift( &rr[ k ], &rr_shifts, r_ptr, subfr_length ); /* rr[ k ] in Q( -rr_shifts ) */ + + /* Assure headroom */ + LZs = silk_CLZ32( rr[k] ); + if( LZs < LTP_CORRS_HEAD_ROOM ) { + rr[ k ] = silk_RSHIFT_ROUND( rr[ k ], LTP_CORRS_HEAD_ROOM - LZs ); + rr_shifts += ( LTP_CORRS_HEAD_ROOM - LZs ); + } + corr_rshifts[ k ] = rr_shifts; + silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, LTP_CORRS_HEAD_ROOM, WLTP_ptr, &corr_rshifts[ k ] ); /* WLTP_fix_ptr in Q( -corr_rshifts[ k ] ) */ + + /* The correlation vector always has lower max abs value than rr and/or RR so head room is assured */ + silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr, corr_rshifts[ k ] ); /* Rr_fix_ptr in Q( -corr_rshifts[ k ] ) */ + if( corr_rshifts[ k ] > rr_shifts ) { + rr[ k ] = silk_RSHIFT( rr[ k ], corr_rshifts[ k ] - rr_shifts ); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */ + } + silk_assert( rr[ k ] >= 0 ); + + regu = 1; + regu = silk_SMLAWB( regu, rr[ k ], SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); + regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); + regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); + silk_regularize_correlations_FIX( WLTP_ptr, &rr[k], regu, LTP_ORDER ); + + silk_solve_LDL_FIX( WLTP_ptr, LTP_ORDER, Rr, b_Q16 ); /* WLTP_fix_ptr and Rr_fix_ptr both in Q(-corr_rshifts[k]) */ + + /* Limit and store in Q14 */ + silk_fit_LTP( b_Q16, b_Q14_ptr ); + + /* Calculate residual energy */ + nrg[ k ] = silk_residual_energy16_covar_FIX( b_Q14_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER, 14 ); /* nrg_fix in Q( -corr_rshifts[ k ] ) */ + + /* temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); */ + extra_shifts = silk_min_int( corr_rshifts[ k ], LTP_CORRS_HEAD_ROOM ); + denom32 = silk_LSHIFT_SAT32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 + extra_shifts ) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */ + silk_RSHIFT( silk_SMULWB( subfr_length, 655 ), corr_rshifts[ k ] - extra_shifts ); /* Q( -corr_rshifts[ k ] + extra_shifts ) */ + denom32 = silk_max( denom32, 1 ); + silk_assert( ((opus_int64)Wght_Q15[ k ] << 16 ) < silk_int32_MAX ); /* Wght always < 0.5 in Q0 */ + temp32 = silk_DIV32( silk_LSHIFT( (opus_int32)Wght_Q15[ k ], 16 ), denom32 ); /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */ + temp32 = silk_RSHIFT( temp32, 31 + corr_rshifts[ k ] - extra_shifts - 26 ); /* Q26 */ + + /* Limit temp such that the below scaling never wraps around */ + WLTP_max = 0; + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + WLTP_max = silk_max( WLTP_ptr[ i ], WLTP_max ); + } + lshift = silk_CLZ32( WLTP_max ) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor_fix */ + silk_assert( 26 - 18 + lshift >= 0 ); + if( 26 - 18 + lshift < 31 ) { + temp32 = silk_min_32( temp32, silk_LSHIFT( (opus_int32)1, 26 - 18 + lshift ) ); + } + + silk_scale_vector32_Q26_lshift_18( WLTP_ptr, temp32, LTP_ORDER * LTP_ORDER ); /* WLTP_ptr in Q( 18 - corr_rshifts[ k ] ) */ + + w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER/2, LTP_ORDER/2, LTP_ORDER ); /* w in Q( 18 - corr_rshifts[ k ] ) */ + silk_assert( w[k] >= 0 ); + + r_ptr += subfr_length; + b_Q14_ptr += LTP_ORDER; + WLTP_ptr += LTP_ORDER * LTP_ORDER; + } + + maxRshifts = 0; + for( k = 0; k < nb_subfr; k++ ) { + maxRshifts = silk_max_int( corr_rshifts[ k ], maxRshifts ); + } + + /* Compute LTP coding gain */ + if( LTPredCodGain_Q7 != NULL ) { + LPC_LTP_res_nrg = 0; + LPC_res_nrg = 0; + silk_assert( LTP_CORRS_HEAD_ROOM >= 2 ); /* Check that no overflow will happen when adding */ + for( k = 0; k < nb_subfr; k++ ) { + LPC_res_nrg = silk_ADD32( LPC_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( rr[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ + LPC_LTP_res_nrg = silk_ADD32( LPC_LTP_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ + } + LPC_LTP_res_nrg = silk_max( LPC_LTP_res_nrg, 1 ); /* avoid division by zero */ + + div_Q16 = silk_DIV32_varQ( LPC_res_nrg, LPC_LTP_res_nrg, 16 ); + *LTPredCodGain_Q7 = ( opus_int )silk_SMULBB( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) ); + + silk_assert( *LTPredCodGain_Q7 == ( opus_int )silk_SAT16( silk_MUL( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) ) ) ); + } + + /* smoothing */ + /* d = sum( B, 1 ); */ + b_Q14_ptr = b_Q14; + for( k = 0; k < nb_subfr; k++ ) { + d_Q14[ k ] = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + d_Q14[ k ] += b_Q14_ptr[ i ]; + } + b_Q14_ptr += LTP_ORDER; + } + + /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */ + + /* Find maximum absolute value of d_Q14 and the bits used by w in Q0 */ + max_abs_d_Q14 = 0; + max_w_bits = 0; + for( k = 0; k < nb_subfr; k++ ) { + max_abs_d_Q14 = silk_max_32( max_abs_d_Q14, silk_abs( d_Q14[ k ] ) ); + /* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */ + /* Find bits needed in Q( 18 - maxRshifts ) */ + max_w_bits = silk_max_32( max_w_bits, 32 - silk_CLZ32( w[ k ] ) + corr_rshifts[ k ] - maxRshifts ); + } + + /* max_abs_d_Q14 = (5 << 15); worst case, i.e. LTP_ORDER * -silk_int16_MIN */ + silk_assert( max_abs_d_Q14 <= ( 5 << 15 ) ); + + /* How many bits is needed for w*d' in Q( 18 - maxRshifts ) in the worst case, of all d_Q14's being equal to max_abs_d_Q14 */ + extra_shifts = max_w_bits + 32 - silk_CLZ32( max_abs_d_Q14 ) - 14; + + /* Subtract what we got available; bits in output var plus maxRshifts */ + extra_shifts -= ( 32 - 1 - 2 + maxRshifts ); /* Keep sign bit free as well as 2 bits for accumulation */ + extra_shifts = silk_max_int( extra_shifts, 0 ); + + maxRshifts_wxtra = maxRshifts + extra_shifts; + + temp32 = silk_RSHIFT( 262, maxRshifts + extra_shifts ) + 1; /* 1e-3f in Q( 18 - (maxRshifts + extra_shifts) ) */ + wd = 0; + for( k = 0; k < nb_subfr; k++ ) { + /* w has at least 2 bits of headroom so no overflow should happen */ + temp32 = silk_ADD32( temp32, silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ) ); /* Q( 18 - maxRshifts_wxtra ) */ + wd = silk_ADD32( wd, silk_LSHIFT( silk_SMULWW( silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ), d_Q14[ k ] ), 2 ) ); /* Q( 18 - maxRshifts_wxtra ) */ + } + m_Q12 = silk_DIV32_varQ( wd, temp32, 12 ); + + b_Q14_ptr = b_Q14; + for( k = 0; k < nb_subfr; k++ ) { + /* w_fix[ k ] from Q( 18 - corr_rshifts[ k ] ) to Q( 16 ) */ + if( 2 - corr_rshifts[k] > 0 ) { + temp32 = silk_RSHIFT( w[ k ], 2 - corr_rshifts[ k ] ); + } else { + temp32 = silk_LSHIFT_SAT32( w[ k ], corr_rshifts[ k ] - 2 ); + } + + g_Q26 = silk_MUL( + silk_DIV32( + SILK_FIX_CONST( LTP_SMOOTHING, 26 ), + silk_RSHIFT( SILK_FIX_CONST( LTP_SMOOTHING, 26 ), 10 ) + temp32 ), /* Q10 */ + silk_LSHIFT_SAT32( silk_SUB_SAT32( (opus_int32)m_Q12, silk_RSHIFT( d_Q14[ k ], 2 ) ), 4 ) ); /* Q16 */ + + temp32 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + delta_b_Q14[ i ] = silk_max_16( b_Q14_ptr[ i ], 1638 ); /* 1638_Q14 = 0.1_Q0 */ + temp32 += delta_b_Q14[ i ]; /* Q14 */ + } + temp32 = silk_DIV32( g_Q26, temp32 ); /* Q14 -> Q12 */ + for( i = 0; i < LTP_ORDER; i++ ) { + b_Q14_ptr[ i ] = silk_LIMIT_32( (opus_int32)b_Q14_ptr[ i ] + silk_SMULWB( silk_LSHIFT_SAT32( temp32, 4 ), delta_b_Q14[ i ] ), -16000, 28000 ); + } + b_Q14_ptr += LTP_ORDER; + } +} + +void silk_fit_LTP( + opus_int32 LTP_coefs_Q16[ LTP_ORDER ], + opus_int16 LTP_coefs_Q14[ LTP_ORDER ] +) +{ + opus_int i; + + for( i = 0; i < LTP_ORDER; i++ ) { + LTP_coefs_Q14[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( LTP_coefs_Q16[ i ], 2 ) ); + } +} diff --git a/media/libopus/silk/fixed/find_pitch_lags_FIX.c b/media/libopus/silk/fixed/find_pitch_lags_FIX.c new file mode 100644 index 000000000000..a830cdf6ebe3 --- /dev/null +++ b/media/libopus/silk/fixed/find_pitch_lags_FIX.c @@ -0,0 +1,137 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[] /* I Speech signal */ +) +{ + opus_int buf_len, i, scale; + opus_int32 thrhld_Q15, res_nrg; + const opus_int16 *x_buf, *x_buf_ptr; + opus_int16 Wsig[ FIND_PITCH_LPC_WIN_MAX ], *Wsig_ptr; + opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + opus_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ]; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safty check */ + silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.ltp_mem_length; + + /*************************************/ + /* Estimate LPC AR coefficients */ + /*************************************/ + + /* Calculate windowed signal */ + + /* First LA_LTP samples */ + x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle un - windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_buf_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); + + /* Add white noise, as fraction of energy */ + auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1; + + /* Calculate the reflection coefficients using schur */ + res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Convert From 32 bit Q24 to 16 bit Q12 coefs */ + for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) { + A_Q12[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) ); + } + + /* Do BWE */ + silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWITH_EXPANSION, 16 ) ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter( res, x_buf, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld_Q15 = SILK_FIX_CONST( 0.6, 15 ); + thrhld_Q15 = silk_SMLABB( thrhld_Q15, SILK_FIX_CONST( -0.004, 15 ), psEnc->sCmn.pitchEstimationLPCOrder ); + thrhld_Q15 = silk_SMLABB( thrhld_Q15, SILK_FIX_CONST( -0.1, 7 ), psEnc->sCmn.speech_activity_Q8 ); + thrhld_Q15 = silk_SMLABB( thrhld_Q15, SILK_FIX_CONST( -0.15, 15 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) ); + thrhld_Q15 = silk_SMLAWB( thrhld_Q15, SILK_FIX_CONST( -0.1, 16 ), psEnc->sCmn.input_tilt_Q15 ); + thrhld_Q15 = silk_SAT16( thrhld_Q15 ); + + /*****************************************/ + /* Call pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex, + &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16, + (opus_int16)thrhld_Q15, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr ) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr_Q15 = 0; + } +} diff --git a/media/libopus/silk/fixed/find_pred_coefs_FIX.c b/media/libopus/silk/fixed/find_pred_coefs_FIX.c new file mode 100644 index 000000000000..2053905c3571 --- /dev/null +++ b/media/libopus/silk/fixed/find_pred_coefs_FIX.c @@ -0,0 +1,136 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i; + opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ], Wght_Q15[ MAX_NB_SUBFR ]; + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; + const opus_int16 *x_ptr; + opus_int16 *x_pre_ptr, LPC_in_pre[ MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ]; + opus_int32 tmp, min_gain_Q16, minInvGain_Q30; + opus_int LTP_corrs_rshift[ MAX_NB_SUBFR ]; + + /* weighting for weighted least squares */ + min_gain_Q16 = silk_int32_MAX >> 6; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] ); + } + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + /* Divide to Q16 */ + silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 ); + /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */ + invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 ); + + /* Ensure Wght_Q15 a minimum value 1 */ + invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 363 ); + + /* Square the inverted gains */ + silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) ); + tmp = silk_SMULWB( invGains_Q16[ i ], invGains_Q16[ i ] ); + Wght_Q15[ i ] = silk_RSHIFT( tmp, 1 ); + + /* Invert the inverted and normalized gains */ + local_gains[ i ] = silk_DIV32( ( 1 << 16 ), invGains_Q16[ i ] ); + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /**********/ + /* VOICED */ + /**********/ + silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + /* LTP analysis */ + silk_find_LTP_FIX( psEncCtrl->LTPCoef_Q14, WLTP, &psEncCtrl->LTPredCodGain_Q7, + res_pitch, psEncCtrl->pitchL, Wght_Q15, psEnc->sCmn.subfr_length, + psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length, LTP_corrs_rshift ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14, + psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + + silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) ); + psEncCtrl->LTPredCodGain_Q7 = 0; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 ); + } else { + minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */ + minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30, + silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ), + silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 ); + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 ); + + /* Quantize LSFs */ + silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); +} diff --git a/media/libopus/silk/fixed/k2a_FIX.c b/media/libopus/silk/fixed/k2a_FIX.c new file mode 100644 index 000000000000..9ccdc4147344 --- /dev/null +++ b/media/libopus/silk/fixed/k2a_FIX.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 Atmp[ SILK_MAX_ORDER_LPC ]; + + for( k = 0; k < order; k++ ) { + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A_Q24[ n ]; + } + for( n = 0; n < k; n++ ) { + A_Q24[ n ] = silk_SMLAWB( A_Q24[ n ], silk_LSHIFT( Atmp[ k - n - 1 ], 1 ), rc_Q15[ k ] ); + } + A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 ); + } +} diff --git a/media/libopus/silk/fixed/k2a_Q16_FIX.c b/media/libopus/silk/fixed/k2a_Q16_FIX.c new file mode 100644 index 000000000000..3f39d5fc8d77 --- /dev/null +++ b/media/libopus/silk/fixed/k2a_Q16_FIX.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 Atmp[ SILK_MAX_ORDER_LPC ]; + + for( k = 0; k < order; k++ ) { + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A_Q24[ n ]; + } + for( n = 0; n < k; n++ ) { + A_Q24[ n ] = silk_SMLAWW( A_Q24[ n ], Atmp[ k - n - 1 ], rc_Q16[ k ] ); + } + A_Q24[ k ] = -silk_LSHIFT( rc_Q16[ k ], 8 ); + } +} diff --git a/media/libopus/silk/fixed/main_FIX.h b/media/libopus/silk/fixed/main_FIX.h new file mode 100644 index 000000000000..9f178975a66d --- /dev/null +++ b/media/libopus/silk/fixed/main_FIX.h @@ -0,0 +1,254 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MAIN_FIX_H +#define SILK_MAIN_FIX_H + +#include "SigProc_FIX.h" +#include "structs_FIX.h" +#include "control.h" +#include "main.h" +#include "PLC.h" +#include "debug.h" +#include "entenc.h" + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +extern "C" +{ +#endif +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX +#define silk_encode_frame_Fxx silk_encode_frame_FIX + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc /* I/O Pointer to Silk FIX encoder state */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/****************/ +/* Prefiltering */ +/****************/ +void silk_prefilter_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */ + opus_int32 xw_Q10[], /* O Weighted signal */ + const opus_int16 x[] /* I Speech signal */ +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x /* I Input signal [ frame_length + la_shape ] */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FIX( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[] /* I Speech signal */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +); + +/* LTP analysis */ +void silk_find_LTP_FIX( + opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + opus_int *LTPredCodGain_Q7, /* O LTP coding gain */ + const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */ + const opus_int subfr_length, /* I subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset, /* I number of samples in LTP memory */ + opus_int corr_rshifts[ MAX_NB_SUBFR ] /* O right shifts applied to correlations */ +); + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceeding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceeding samples starting at &x[0] for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceeding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order /* I LPC order */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +); + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + const opus_int head_room, /* I Desired headroom */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int *rshifts /* I/O Right shifts of correlations */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts /* I Right shifts of correlations */ +); + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FIX( + opus_int32 *XX, /* I/O Correlation matrices */ + opus_int32 *xx, /* I/O Correlation values */ + opus_int32 noise, /* I Noise to add */ + opus_int D /* I Dimension of XX */ +); + +/* Solves Ax = b, assuming A is symmetric */ +void silk_solve_LDL_FIX( + opus_int32 *A, /* I Pointer to symetric square matrix A */ + opus_int M, /* I Size of matrix */ + const opus_int32 *b, /* I Pointer to b vector */ + opus_int32 *x_Q16 /* O Pointer to x solution vector */ +); + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* FORCE_CPP_BUILD */ +#endif /* SILK_MAIN_FIX_H */ diff --git a/media/libopus/silk/fixed/noise_shape_analysis_FIX.c b/media/libopus/silk/fixed/noise_shape_analysis_FIX.c new file mode 100644 index 000000000000..94c5bb263385 --- /dev/null +++ b/media/libopus/silk/fixed/noise_shape_analysis_FIX.c @@ -0,0 +1,437 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */ +/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */ +static inline opus_int32 warped_gain( /* gain in Q16*/ + const opus_int32 *coefs_Q24, + opus_int lambda_Q16, + opus_int order +) { + opus_int i; + opus_int32 gain_Q24; + + lambda_Q16 = -lambda_Q16; + gain_Q24 = coefs_Q24[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 ); + } + gain_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 ); + return silk_INVERSE32_varQ( gain_Q24, 40 ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +static inline void limit_warped_coefs( + opus_int32 *coefs_syn_Q24, + opus_int32 *coefs_ana_Q24, + opus_int lambda_Q16, + opus_int32 limit_Q24, + opus_int order +) { + opus_int i, iter, ind = 0; + opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16; + opus_int32 nom_Q16, den_Q24; + + /* Convert to monic coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); + gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); + gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs_Q24 = -1; + for( i = 0; i < order; i++ ) { + tmp = silk_max( silk_abs_int32( coefs_syn_Q24[ i ] ), silk_abs_int32( coefs_ana_Q24[ i ] ) ); + if( tmp > maxabs_Q24 ) { + maxabs_Q24 = tmp; + ind = i; + } + } + if( maxabs_Q24 <= limit_Q24 ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + gain_syn_Q16 = silk_INVERSE32_varQ( gain_syn_Q16, 32 ); + gain_ana_Q16 = silk_INVERSE32_varQ( gain_ana_Q16, 32 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + + /* Apply bandwidth expansion */ + chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ( + silk_SMULWB( maxabs_Q24 - limit_Q24, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ), + silk_MUL( maxabs_Q24, ind + 1 ), 22 ); + silk_bwexpander_32( coefs_syn_Q24, order, chirp_Q16 ); + silk_bwexpander_32( coefs_ana_Q24, order, chirp_Q16 ); + + /* Convert to monic warped coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); + gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); + gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + } + silk_assert( 0 ); +} + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x /* I Input signal [ frame_length + la_shape ] */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0; + opus_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32; + opus_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + opus_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ]; + opus_int16 x_windowed[ SHAPE_LPC_WIN_MAX ]; + const opus_int16 *x_ptr, *pitch_res_ptr; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7; + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ] + + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 - + SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + if( psEnc->sCmn.useCBR == 0 ) { + b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8; + b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/ + silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/ + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 ); + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ), + SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initally set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + psEncCtrl->sparseness_Q8 = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) { + silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/ + + log_energy_Q7 = silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + psEncCtrl->sparseness_Q8 = silk_RSHIFT( silk_sigm_Q15( silk_SMULWB( energy_variation_Q7 - + SILK_FIX_CONST( 5.0, 7 ), SILK_FIX_CONST( 0.1, 16 ) ) ), 7 ); + + /* Set quantization offset depending on sparseness measure */ + if( psEncCtrl->sparseness_Q8 > SILK_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SILK_FIX_CONST( 0.5, 8 ) ); + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp1_Q16 = BWExp2_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + delta_Q16 = silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - silk_SMULBB( 3, psEncCtrl->coding_quality_Q14 ), + SILK_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) ); + BWExp1_Q16 = silk_SUB32( BWExp1_Q16, delta_Q16 ); + BWExp2_Q16 = silk_ADD32( BWExp2_Q16, delta_Q16 ); + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1_Q16 = silk_DIV32_16( silk_LSHIFT( BWExp1_Q16, 14 ), silk_RSHIFT( BWExp2_Q16, 2 ) ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) ); + shift += flat_part; + silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Calculate regular auto correlation */ + silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ), + SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; /* range: -12...30*/ + silk_assert( Qnrg >= -12 ); + silk_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; /* range: -6...15*/ + + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( tmp32, 16 - Qnrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + if( psEncCtrl->Gains_Q16[ k ] < 0 ) { + psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX; + } + } + + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 ); + + /* Compute noise shaping filter coefficients */ + silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) ); + + /* Bandwidth expansion for analysis filter shaping */ + silk_assert( BWExp1_Q16 <= SILK_FIX_CONST( 1.0, 16 ) ); + silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 ); + + /* Ratio of prediction gains, in energy domain */ + pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder ); + nrg = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder ); + + /*psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/ + pre_nrg_Q30 = silk_LSHIFT32( silk_SMULWB( pre_nrg_Q30, SILK_FIX_CONST( 0.7, 15 ) ), 1 ); + psEncCtrl->GainsPre_Q14[ k ] = ( opus_int ) SILK_FIX_CONST( 0.3, 14 ) + silk_DIV32_varQ( pre_nrg_Q30, nrg, 14 ); + + /* Convert to monic warped prediction coefficients and limit absolute values */ + limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); + + /* Convert from Q24 to Q13 and store in int16 */ + for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { + psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) ); + psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) ); + silk_assert( gain_mult_Q16 > 0 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + } + + gain_mult_Q16 = SILK_FIX_CONST( 1.0, 16 ) + silk_RSHIFT_ROUND( silk_MLA( SILK_FIX_CONST( INPUT_TILT, 26 ), + psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->GainsPre_Q14[ k ] = silk_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] ); + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ), + SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) ); + strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + } + silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/ + Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) - + silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ), + silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) ); + } else { + b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/ + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - + silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost_Q16 = silk_SMULWB( silk_SMULWB( SILK_FIX_CONST( 1.0, 17 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ), + psEnc->LTPCorr_Q15 ), SILK_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) ); + + /* More harmonic boost for noisy input signals */ + HarmBoost_Q16 = silk_SMLAWB( HarmBoost_Q16, + SILK_FIX_CONST( 1.0, 16 ) - silk_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SILK_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) ); + + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ), + SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ), + silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < MAX_NB_SUBFR; k++ ) { + psShapeSt->HarmBoost_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt->HarmBoost_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->HarmShapeGain_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmBoost_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16, 2 ); + psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } +} diff --git a/media/libopus/silk/fixed/pitch_analysis_core_FIX.c b/media/libopus/silk/fixed/pitch_analysis_core_FIX.c new file mode 100644 index 000000000000..7471eb5a2c92 --- /dev/null +++ b/media/libopus/silk/fixed/pitch_analysis_core_FIX.c @@ -0,0 +1,745 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" +#include "debug.h" + +#define SCRATCH_SIZE 22 + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +void silk_P_Ana_calc_corr_st3( + opus_int32 cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ],/* (O) 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +void silk_P_Ana_calc_energy_st3( + opus_int32 energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ],/* (O) 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +opus_int32 silk_P_Ana_find_scaling( + const opus_int16 *frame, + const opus_int frame_length, + const opus_int sum_sqr_len +); + +/*************************************************************/ +/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */ +/*************************************************************/ +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q15, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr /* I number of 5 ms subframes */ +) +{ + opus_int16 frame_8kHz[ PE_MAX_FRAME_LENGTH_ST_2 ]; + opus_int16 frame_4kHz[ PE_MAX_FRAME_LENGTH_ST_1 ]; + opus_int32 filt_state[ 6 ]; + opus_int32 scratch_mem[ 3 * PE_MAX_FRAME_LENGTH ]; + opus_int16 *input_frame_ptr; + opus_int i, k, d, j; + opus_int16 C[ PE_MAX_NB_SUBFR ][ ( PE_MAX_LAG >> 1 ) + 5 ]; + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 cross_corr, normalizer, energy, shift, energy_basis, energy_target; + opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp; + opus_int16 d_comp[ ( PE_MAX_LAG >> 1 ) + 5 ]; + opus_int32 sum, threshold, temp32, lag_counter; + opus_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new; + opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new; + opus_int32 energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + opus_int32 crosscorr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + opus_int frame_length, frame_length_8kHz, frame_length_4kHz, max_sum_sq_length; + opus_int sf_length, sf_length_8kHz, sf_length_4kHz; + opus_int min_lag, min_lag_8kHz, min_lag_4kHz; + opus_int max_lag, max_lag_8kHz, max_lag_4kHz; + opus_int32 contour_bias_Q20, diff, lz, lshift; + opus_int nb_cbk_search, cbk_size; + opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q15, corr_thres_Q15; + const opus_int8 *Lag_CB_ptr; + /* Check for valid sampling frequency */ + silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) ); + silk_assert( search_thres2_Q15 >= 0 && search_thres2_Q15 <= (1<<15) ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + sf_length_4kHz = PE_SUBFR_LENGTH_MS * 4; + sf_length_8kHz = PE_SUBFR_LENGTH_MS * 8; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + min_lag_4kHz = PE_MIN_LAG_MS * 4; + min_lag_8kHz = PE_MIN_LAG_MS * 8; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + max_lag_4kHz = PE_MAX_LAG_MS * 4; + max_lag_8kHz = PE_MAX_LAG_MS * 8 - 1; + + silk_memset( C, 0, sizeof( opus_int16 ) * nb_subfr * ( ( PE_MAX_LAG >> 1 ) + 5) ); + + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8kHz, frame, frame_length ); + } else if( Fs_kHz == 12 ) { + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8kHz, frame, frame_length ); + } else { + silk_assert( Fs_kHz == 8 ); + silk_memcpy( frame_8kHz, frame, frame_length_8kHz * sizeof(opus_int16) ); + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */ + silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] ); + } + + /******************************************************************************* + ** Scale 4 kHz signal down to prevent correlations measures from overflowing + ** find scaling as max scaling for each 8kHz(?) subframe + *******************************************************************************/ + + /* Inner product is calculated with different lengths, so scale for the worst case */ + max_sum_sq_length = silk_max_32( sf_length_8kHz, silk_LSHIFT( sf_length_4kHz, 2 ) ); + shift = silk_P_Ana_find_scaling( frame_4kHz, frame_length_4kHz, max_sum_sq_length ); + if( shift > 0 ) { + for( i = 0; i < frame_length_4kHz; i++ ) { + frame_4kHz[ i ] = silk_RSHIFT( frame_4kHz[ i ], shift ); + } + } + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + silk_assert( target_ptr >= frame_4kHz ); + silk_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - min_lag_4kHz; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + /* Calculate first vector products before loop */ + cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + normalizer = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length_8kHz ); + normalizer = silk_ADD_SAT32( normalizer, silk_SMULBB( sf_length_8kHz, 4000 ) ); + + temp32 = silk_DIV32( cross_corr, silk_SQRT_APPROX( normalizer ) + 1 ); + C[ k ][ min_lag_4kHz ] = (opus_int16)silk_SAT16( temp32 ); /* Q0 */ + + /* From now on normalizer is computed recursively */ + for( d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++ ) { + basis_ptr--; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer += + silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) - + silk_SMULBB( basis_ptr[ sf_length_8kHz ], basis_ptr[ sf_length_8kHz ] ); + + temp32 = silk_DIV32( cross_corr, silk_SQRT_APPROX( normalizer ) + 1 ); + C[ k ][ d ] = (opus_int16)silk_SAT16( temp32 ); /* Q0 */ + } + /* Update target pointer */ + target_ptr += sf_length_8kHz; + } + + /* Combine two subframes into single correlation measure and apply short-lag bias */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + sum = (opus_int32)C[ 0 ][ i ] + (opus_int32)C[ 1 ][ i ]; /* Q0 */ + silk_assert( silk_RSHIFT( sum, 1 ) == silk_SAT16( silk_RSHIFT( sum, 1 ) ) ); + sum = silk_RSHIFT( sum, 1 ); /* Q-1 */ + silk_assert( silk_LSHIFT( (opus_int32)-i, 4 ) == silk_SAT16( silk_LSHIFT( (opus_int32)-i, 4 ) ) ); + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q-1 */ + silk_assert( sum == silk_SAT16( sum ) ); + C[ 0 ][ i ] = (opus_int16)sum; /* Q-1 */ + } + } else { + /* Only short-lag bias */ + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + sum = (opus_int32)C[ 0 ][ i ]; + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q-1 */ + C[ 0 ][ i ] = (opus_int16)sum; /* Q-1 */ + } + } + + /* Sort */ + length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 ); + silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_insertion_sort_decreasing_int16( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch ); + + /* Escape if correlation is very low already here */ + target_ptr = &frame_4kHz[ silk_SMULBB( sf_length_4kHz, nb_subfr ) ]; + energy = silk_inner_prod_aligned( target_ptr, target_ptr, silk_LSHIFT( sf_length_4kHz, 2 ) ); + energy = silk_ADD_SAT32( energy, 1000 ); /* Q0 */ + Cmax = (opus_int)C[ 0 ][ min_lag_4kHz ]; /* Q-1 */ + threshold = silk_SMULBB( Cmax, Cmax ); /* Q-2 */ + + /* Compare in Q-2 domain */ + if( silk_RSHIFT( energy, 4 + 2 ) > threshold ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + threshold = silk_SMULWB( search_thres1_Q16, Cmax ); + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) { + d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 ); + } else { + length_d_srch = i; + break; + } + } + silk_assert( length_d_srch > 0 ); + + for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) { + d_comp[ i ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] ] = 1; + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ]; + } + + length_d_srch = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) { + if( d_comp[ i + 1 ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ]; + } + + length_d_comp = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) { + if( d_comp[ i ] > 0 ) { + d_comp[ length_d_comp ] = i - 2; + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + + /****************************************************************************** + ** Scale signal down to avoid correlations measures from overflowing + *******************************************************************************/ + /* find scaling as max scaling for each subframe */ + shift = silk_P_Ana_find_scaling( frame_8kHz, frame_length_8kHz, sf_length_8kHz ); + if( shift > 0 ) { + for( i = 0; i < frame_length_8kHz; i++ ) { + frame_8kHz[ i ] = silk_RSHIFT( frame_8kHz[ i ], shift ); + } + } + + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, PE_MAX_NB_SUBFR * ( ( PE_MAX_LAG >> 1 ) + 5 ) * sizeof( opus_int16 ) ); + + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + for( k = 0; k < nb_subfr; k++ ) { + + /* Check that we are within range of the array */ + silk_assert( target_ptr >= frame_8kHz ); + silk_assert( target_ptr + sf_length_8kHz <= frame_8kHz + frame_length_8kHz ); + + energy_target = silk_inner_prod_aligned( target_ptr, target_ptr, sf_length_8kHz ); + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_8kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_8kHz + frame_length_8kHz ); + + cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length_8kHz ); + if( cross_corr > 0 ) { + energy = silk_max( energy_target, energy_basis ); /* Find max to make sure first division < 1.0 */ + lz = silk_CLZ32( cross_corr ); + lshift = silk_LIMIT_32( lz - 1, 0, 15 ); + temp32 = silk_DIV32( silk_LSHIFT( cross_corr, lshift ), silk_RSHIFT( energy, 15 - lshift ) + 1 ); /* Q15 */ + silk_assert( temp32 == silk_SAT16( temp32 ) ); + temp32 = silk_SMULWB( cross_corr, temp32 ); /* Q(-1), cc * ( cc / max(b, t) ) */ + temp32 = silk_ADD_SAT32( temp32, temp32 ); /* Q(0) */ + lz = silk_CLZ32( temp32 ); + lshift = silk_LIMIT_32( lz - 1, 0, 15 ); + energy = silk_min( energy_target, energy_basis ); + C[ k ][ d ] = silk_DIV32( silk_LSHIFT( temp32, lshift ), silk_RSHIFT( energy, 15 - lshift ) + 1 ); /* Q15*/ + } else { + C[ k ][ d ] = 0; + } + } + target_ptr += sf_length_8kHz; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = silk_int32_MIN; + CCmax_b = silk_int32_MIN; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 ); + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag ); + } else { + prevLag_log2_Q7 = 0; + } + silk_assert( search_thres2_Q15 == silk_SAT16( search_thres2_Q15 ) ); + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + corr_thres_Q15 = silk_RSHIFT( silk_SMULBB( search_thres2_Q15, search_thres2_Q15 ), 13 ); + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + corr_thres_Q15 = silk_RSHIFT( silk_SMULBB( search_thres2_Q15, search_thres2_Q15 ), 14 ); + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbk_search; j++ ) { + CC[ j ] = 0; + for( i = 0; i < nb_subfr; i++ ) { + /* Try all codebooks */ + CC[ j ] = CC[ j ] + (opus_int32)C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )]; + } + } + /* Find best codebook */ + CCmax_new = silk_int32_MIN; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2_Q7 = silk_lin2log( (opus_int32)d ); /* Q7 */ + silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) ); + silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 15 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 15 ) ) ); + CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 15 ), lag_log2_Q7 ), 7 ); /* Q15 */ + + /* Bias towards previous lag */ + silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 15 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 15 ) ) ); + if( prevLag > 0 ) { + delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7; + silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) ); + delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 ); + prev_lag_bias_Q15 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 15 ), *LTPCorr_Q15 ), 15 ); /* Q15 */ + prev_lag_bias_Q15 = silk_DIV32( silk_MUL( prev_lag_bias_Q15, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + ( 1 << 6 ) ); + CCmax_new_b -= prev_lag_bias_Q15; /* Q15 */ + } + + if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > corr_thres_Q15 && /* Correlation needs to be high enough to be voiced */ + silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= min_lag_8kHz /* Lag must be in range */ + ) { + CCmax_b = CCmax_new_b; + CCmax = CCmax_new; + lag = d; + CBimax = CBimax_new; + } + } + + if( lag == -1 ) { + /* No suitable candidate found */ + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + if( Fs_kHz > 8 ) { + /***************************************************************************/ + /* Scale input signal down to avoid correlations measures from overflowing */ + /***************************************************************************/ + /* find scaling as max scaling for each subframe */ + shift = silk_P_Ana_find_scaling( frame, frame_length, sf_length ); + if( shift > 0 ) { + /* Move signal to scratch mem because the input signal should be unchanged */ + /* Reuse the 32 bit scratch mem vector, use a 16 bit pointer from now */ + input_frame_ptr = (opus_int16*)scratch_mem; + for( i = 0; i < frame_length; i++ ) { + input_frame_ptr[ i ] = silk_RSHIFT( frame[ i ], shift ); + } + } else { + input_frame_ptr = (opus_int16*)frame; + } + + /* Search in original signal */ + + CBimax_old = CBimax; + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 ); + } else if( Fs_kHz == 16 ) { + lag = silk_LSHIFT( lag, 1 ); + } else { + lag = silk_SMULBB( lag, 3 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + silk_assert( silk_LSHIFT( CCmax, 13 ) >= 0 ); + *LTPCorr_Q15 = (opus_int)silk_SQRT_APPROX( silk_LSHIFT( CCmax, 13 ) ); /* Output normalized correlation */ + + CCmax = silk_int32_MIN; + /* pitch lags according to second stage */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ]; + } + /* Calculate the correlations and energies needed in stage 3 */ + silk_P_Ana_calc_corr_st3( crosscorr_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity ); + silk_P_Ana_calc_energy_st3( energies_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias_Q20 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 20 ), lag ); + + /* Set up codebook parameters acording to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + for( d = start_lag; d <= end_lag; d++ ) { + for( j = 0; j < nb_cbk_search; j++ ) { + cross_corr = 0; + energy = 0; + for( k = 0; k < nb_subfr; k++ ) { + silk_assert( PE_MAX_NB_SUBFR == 4 ); + energy += silk_RSHIFT( energies_st3[ k ][ j ][ lag_counter ], 2 ); /* use mean, to avoid overflow */ + silk_assert( energy >= 0 ); + cross_corr += silk_RSHIFT( crosscorr_st3[ k ][ j ][ lag_counter ], 2 ); /* use mean, to avoid overflow */ + } + if( cross_corr > 0 ) { + /* Divide cross_corr / energy and get result in Q15 */ + lz = silk_CLZ32( cross_corr ); + /* Divide with result in Q13, cross_corr could be larger than energy */ + lshift = silk_LIMIT_32( lz - 1, 0, 13 ); + CCmax_new = silk_DIV32( silk_LSHIFT( cross_corr, lshift ), silk_RSHIFT( energy, 13 - lshift ) + 1 ); + CCmax_new = silk_SAT16( CCmax_new ); + CCmax_new = silk_SMULWB( cross_corr, CCmax_new ); + /* Saturate */ + if( CCmax_new > silk_RSHIFT( silk_int32_MAX, 3 ) ) { + CCmax_new = silk_int32_MAX; + } else { + CCmax_new = silk_LSHIFT( CCmax_new, 3 ); + } + /* Reduce depending on flatness of contour */ + diff = silk_int16_MAX - silk_RSHIFT( silk_MUL( contour_bias_Q20, j ), 5 ); /* Q20 -> Q15 */ + silk_assert( diff == silk_SAT16( diff ) ); + CCmax_new = silk_LSHIFT( silk_SMULWB( CCmax_new, diff ), 1 ); + } else { + CCmax_new = 0; + } + + if( CCmax_new > CCmax && + ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag + ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags and correlation */ + CCmax = silk_max( CCmax, 0 ); + *LTPCorr_Q15 = (opus_int)silk_SQRT_APPROX( silk_LSHIFT( CCmax, 13 ) ); /* Output normalized correlation */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag - min_lag_8kHz ); + *contourIndex = (opus_int8)CBimax; + } + silk_assert( *lagIndex >= 0 ); + /* return as voiced */ + return 0; +} + +/*************************************************************************/ +/* Calculates the correlations used in stage 3 search. In order to cover */ +/* the whole lag codebook for all the searched offset lags (lag +- 2), */ +/*************************************************************************/ +void silk_P_Ana_calc_corr_st3( + opus_int32 cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ],/* (O) 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) +{ + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 cross_corr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + opus_int32 scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + for( j = lag_low; j <= lag_high; j++ ) { + basis_ptr = target_ptr - ( start_lag + j ); + cross_corr = silk_inner_prod_aligned( (opus_int16*)target_ptr, (opus_int16*)basis_ptr, sf_length ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = cross_corr; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } +} + +/********************************************************************/ +/* Calculate the energies for first two subframes. The energies are */ +/* calculated recursively. */ +/********************************************************************/ +void silk_P_Ana_calc_energy_st3( + opus_int32 energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ],/* (O) 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) +{ + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + opus_int32 scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length ); + silk_assert( energy >= 0 ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] ); + silk_assert( energy >= 0 ); + + /* add part that comes into window */ + energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) ); + silk_assert( energy >= 0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + silk_assert( energies_st3[ k ][ i ][ j ] >= 0 ); + } + } + target_ptr += sf_length; + } +} + +opus_int32 silk_P_Ana_find_scaling( + const opus_int16 *frame, + const opus_int frame_length, + const opus_int sum_sqr_len +) +{ + opus_int32 nbits, x_max; + + x_max = silk_int16_array_maxabs( frame, frame_length ); + + if( x_max < silk_int16_MAX ) { + /* Number of bits needed for the sum of the squares */ + nbits = 32 - silk_CLZ32( silk_SMULBB( x_max, x_max ) ); + } else { + /* Here we don't know if x_max should have been silk_int16_MAX + 1, so we expect the worst case */ + nbits = 30; + } + nbits += 17 - silk_CLZ16( sum_sqr_len ); + + /* Without a guarantee of saturation, we need to keep the 31st bit free */ + if( nbits < 31 ) { + return 0; + } else { + return( nbits - 30 ); + } +} diff --git a/media/libopus/silk/fixed/prefilter_FIX.c b/media/libopus/silk/fixed/prefilter_FIX.c new file mode 100644 index 000000000000..31b0cb571714 --- /dev/null +++ b/media/libopus/silk/fixed/prefilter_FIX.c @@ -0,0 +1,204 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Prefilter for finding Quantizer input signal */ +static inline void silk_prefilt_FIX( + silk_prefilter_state_FIX *P, /* I/O state */ + opus_int32 st_res_Q12[], /* I short term residual signal */ + opus_int32 xw_Q3[], /* O prefiltered signal */ + opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + opus_int Tilt_Q14, /* I Tilt shaping coeficient */ + opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */ + opus_int lag, /* I Lag for harmonic shaping */ + opus_int length /* I Length of signals */ +); + +void silk_warped_LPC_analysis_filter_FIX( + opus_int32 state[], /* I/O State [order + 1] */ + opus_int32 res_Q2[], /* O Residual signal [length] */ + const opus_int16 coef_Q13[], /* I Coefficients [order] */ + const opus_int16 input[], /* I Input signal [length] */ + const opus_int16 lambda_Q16, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order /* I Filter order (even) */ +) +{ + opus_int n, i; + opus_int32 acc_Q11, tmp1, tmp2; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); + state[ 0 ] = silk_LSHIFT( input[ n ], 14 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); + state[ 1 ] = tmp2; + acc_Q11 = silk_RSHIFT( order, 1 ); + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); + state[ i ] = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); + state[ i + 1 ] = tmp2; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); + } + state[ order ] = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 ); + } +} + +void silk_prefilter_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */ + opus_int32 xw_Q3[], /* O Weighted signal */ + const opus_int16 x[] /* I Speech signal */ +) +{ + silk_prefilter_state_FIX *P = &psEnc->sPrefilt; + opus_int j, k, lag; + opus_int32 tmp_32; + const opus_int16 *AR1_shp_Q13; + const opus_int16 *px; + opus_int32 *pxw_Q3; + opus_int HarmShapeGain_Q12, Tilt_Q14; + opus_int32 HarmShapeFIRPacked_Q12, LF_shp_Q14; + opus_int32 x_filt_Q12[ MAX_SUB_FRAME_LENGTH ]; + opus_int32 st_res_Q2[ MAX_SUB_FRAME_LENGTH + MAX_LPC_ORDER ]; + opus_int16 B_Q10[ 2 ]; + + /* Set up pointers */ + px = x; + pxw_Q3 = xw_Q3; + lag = P->lagPrev; + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Update Variables that change per sub frame */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + lag = psEncCtrl->pitchL[ k ]; + } + + /* Noise shape parameters */ + HarmShapeGain_Q12 = silk_SMULWB( psEncCtrl->HarmShapeGain_Q14[ k ], 16384 - psEncCtrl->HarmBoost_Q14[ k ] ); + silk_assert( HarmShapeGain_Q12 >= 0 ); + HarmShapeFIRPacked_Q12 = silk_RSHIFT( HarmShapeGain_Q12, 2 ); + HarmShapeFIRPacked_Q12 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q12, 1 ), 16 ); + Tilt_Q14 = psEncCtrl->Tilt_Q14[ k ]; + LF_shp_Q14 = psEncCtrl->LF_shp_Q14[ k ]; + AR1_shp_Q13 = &psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Short term FIR filtering*/ + silk_warped_LPC_analysis_filter_FIX( P->sAR_shp, st_res_Q2, AR1_shp_Q13, px, + psEnc->sCmn.warping_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder ); + + /* Reduce (mainly) low frequencies during harmonic emphasis */ + B_Q10[ 0 ] = silk_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 4 ); + tmp_32 = silk_SMLABB( SILK_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 ); /* Q26 */ + tmp_32 = silk_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ); /* Q26 */ + tmp_32 = silk_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] ); /* Q24 */ + tmp_32 = silk_RSHIFT_ROUND( tmp_32, 14 ); /* Q10 */ + B_Q10[ 1 ]= silk_SAT16( tmp_32 ); + x_filt_Q12[ 0 ] = silk_SMLABB( silk_SMULBB( st_res_Q2[ 0 ], B_Q10[ 0 ] ), P->sHarmHP_Q2, B_Q10[ 1 ] ); + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + x_filt_Q12[ j ] = silk_SMLABB( silk_SMULBB( st_res_Q2[ j ], B_Q10[ 0 ] ), st_res_Q2[ j - 1 ], B_Q10[ 1 ] ); + } + P->sHarmHP_Q2 = st_res_Q2[ psEnc->sCmn.subfr_length - 1 ]; + + silk_prefilt_FIX( P, x_filt_Q12, pxw_Q3, HarmShapeFIRPacked_Q12, Tilt_Q14, LF_shp_Q14, lag, psEnc->sCmn.subfr_length ); + + px += psEnc->sCmn.subfr_length; + pxw_Q3 += psEnc->sCmn.subfr_length; + } + + P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ]; +} + +/* Prefilter for finding Quantizer input signal */ +static inline void silk_prefilt_FIX( + silk_prefilter_state_FIX *P, /* I/O state */ + opus_int32 st_res_Q12[], /* I short term residual signal */ + opus_int32 xw_Q3[], /* O prefiltered signal */ + opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + opus_int Tilt_Q14, /* I Tilt shaping coeficient */ + opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */ + opus_int lag, /* I Lag for harmonic shaping */ + opus_int length /* I Length of signals */ +) +{ + opus_int i, idx, LTP_shp_buf_idx; + opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10; + opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12; + opus_int16 *LTP_shp_buf; + + /* To speed up use temp variables instead of using the struct */ + LTP_shp_buf = P->sLTP_shp; + LTP_shp_buf_idx = P->sLTP_shp_buf_idx; + sLF_AR_shp_Q12 = P->sLF_AR_shp_Q12; + sLF_MA_shp_Q12 = P->sLF_MA_shp_Q12; + + for( i = 0; i < length; i++ ) { + if( lag > 0 ) { + /* unrolled loop */ + silk_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP_Q12 = silk_SMULBB( LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = silk_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = silk_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + } else { + n_LTP_Q12 = 0; + } + + n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 ); + n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 ); + + sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) ); + sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) ); + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) ); + + xw_Q3[i] = silk_RSHIFT_ROUND( silk_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 9 ); + } + + /* Copy temp variable back to state */ + P->sLF_AR_shp_Q12 = sLF_AR_shp_Q12; + P->sLF_MA_shp_Q12 = sLF_MA_shp_Q12; + P->sLTP_shp_buf_idx = LTP_shp_buf_idx; +} diff --git a/media/libopus/silk/fixed/process_gains_FIX.c b/media/libopus/silk/fixed/process_gains_FIX.c new file mode 100644 index 000000000000..740be0bc1e76 --- /dev/null +++ b/media/libopus/silk/fixed/process_gains_FIX.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */ + s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 ); + } + } + + /* Limit the quantized signal */ + /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */ + InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin( + silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + ResNrg = psEncCtrl->ResNrg[ k ]; + ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 ); + if( psEncCtrl->ResNrgQ[ k ] > 0 ) { + ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] ); + } else { + if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) { + ResNrgPart = silk_int32_MAX; + } else { + ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] ); + } + } + gain = psEncCtrl->Gains_Q16[ k ]; + gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) ); + if( gain_squared < silk_int16_MAX ) { + /* recalculate with higher precision */ + gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain ); + silk_assert( gain_squared > 0 ); + gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */ + gain = silk_min( gain, silk_int32_MAX >> 8 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */ + } else { + gain = silk_SQRT_APPROX( gain_squared ); /* Q0 */ + gain = silk_min( gain, silk_int32_MAX >> 16 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 ); /* Q16 */ + } + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ]; + psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 ) + + silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->sCmn.speech_activity_Q8 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 ); + + silk_assert( psEncCtrl->Lambda_Q10 > 0 ); + silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) ); +} diff --git a/media/libopus/silk/fixed/regularize_correlations_FIX.c b/media/libopus/silk/fixed/regularize_correlations_FIX.c new file mode 100644 index 000000000000..f0dac4a4174a --- /dev/null +++ b/media/libopus/silk/fixed/regularize_correlations_FIX.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FIX( + opus_int32 *XX, /* I/O Correlation matrices */ + opus_int32 *xx, /* I/O Correlation values */ + opus_int32 noise, /* I Noise to add */ + opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise ); + } + xx[ 0 ] += noise; +} diff --git a/media/libopus/silk/fixed/residual_energy16_FIX.c b/media/libopus/silk/fixed/residual_energy16_FIX.c new file mode 100644 index 000000000000..044469f0f74a --- /dev/null +++ b/media/libopus/silk/fixed/residual_energy16_FIX.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +) +{ + opus_int i, j, lshifts, Qxtra; + opus_int32 c_max, w_max, tmp, tmp2, nrg; + opus_int cn[ MAX_MATRIX_SIZE ]; + const opus_int32 *pRow; + + /* Safety checks */ + silk_assert( D >= 0 ); + silk_assert( D <= 16 ); + silk_assert( cQ > 0 ); + silk_assert( cQ < 16 ); + + lshifts = 16 - cQ; + Qxtra = lshifts; + + c_max = 0; + for( i = 0; i < D; i++ ) { + c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) ); + } + Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 ); + + w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] ); + Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 ); + Qxtra = silk_max_int( Qxtra, 0 ); + for( i = 0; i < D; i++ ) { + cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra ); + silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */ + } + lshifts -= Qxtra; + + /* Compute wxx - 2 * wXx * c */ + tmp = 0; + for( i = 0; i < D; i++ ) { + tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] ); + } + nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */ + + /* Add c' * wXX * c, assuming wXX is symmetric */ + tmp2 = 0; + for( i = 0; i < D; i++ ) { + tmp = 0; + pRow = &wXX[ i * D ]; + for( j = i + 1; j < D; j++ ) { + tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] ); + } + tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] ); + tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] ); + } + nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */ + + /* Keep one bit free always, because we add them for LSF interpolation */ + if( nrg < 1 ) { + nrg = 1; + } else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) { + nrg = silk_int32_MAX >> 1; + } else { + nrg = silk_LSHIFT( nrg, lshifts + 1 ); /* Q0 */ + } + return nrg; + +} diff --git a/media/libopus/silk/fixed/residual_energy_FIX.c b/media/libopus/silk/fixed/residual_energy_FIX.c new file mode 100644 index 000000000000..38948810a7c6 --- /dev/null +++ b/media/libopus/silk/fixed/residual_energy_FIX.c @@ -0,0 +1,91 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceeding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int offset, i, j, rshift, lz1, lz2; + opus_int16 *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + const opus_int16 *x_ptr; + opus_int32 tmp32; + + x_ptr = x; + offset = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + for( i = 0; i < nb_subfr >> 1; i++ ) { + /* Calculate half frame LPC residual signal including preceeding samples */ + silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_NB_SUBFR >> 1 ) * offset, LPC_order ); + + /* Point to first subframe of the just calculated LPC residual signal */ + LPC_res_ptr = LPC_res + LPC_order; + for( j = 0; j < ( MAX_NB_SUBFR >> 1 ); j++ ) { + /* Measure subframe energy */ + silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length ); + + /* Set Q values for the measured energy */ + nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift; + + /* Move to next subframe */ + LPC_res_ptr += offset; + } + /* Move to next frame half */ + x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset; + } + + /* Apply the squared subframe gains */ + for( i = 0; i < nb_subfr; i++ ) { + /* Fully upscale gains and energies */ + lz1 = silk_CLZ32( nrgs[ i ] ) - 1; + lz2 = silk_CLZ32( gains[ i ] ) - 1; + + tmp32 = silk_LSHIFT32( gains[ i ], lz2 ); + + /* Find squared gains */ + tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/ + + /* Scale energies */ + nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/ + nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32; + } +} diff --git a/media/libopus/silk/fixed/schur64_FIX.c b/media/libopus/silk/fixed/schur64_FIX.c new file mode 100644 index 000000000000..bab71155197f --- /dev/null +++ b/media/libopus/silk/fixed/schur64_FIX.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + opus_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31; + + silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 ); + + /* Check for invalid input */ + if( c[ 0 ] <= 0 ) { + silk_memset( rc_Q16, 0, order * sizeof( opus_int32 ) ); + return 0; + } + + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } + + for( k = 0; k < order; k++ ) { + /* Get reflection coefficient: divide two Q30 values and get result in Q31 */ + rc_tmp_Q31 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 ); + + /* Save the output */ + rc_Q16[ k ] = silk_RSHIFT_ROUND( rc_tmp_Q31, 15 ); + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1_Q30 = C[ n + k + 1 ][ 0 ]; + Ctmp2_Q30 = C[ n ][ 1 ]; + + /* Multiply and add the highest int32 */ + C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 ); + C[ n ][ 1 ] = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 ); + } + } + + return( C[ 0 ][ 1 ] ); +} diff --git a/media/libopus/silk/fixed/schur_FIX.c b/media/libopus/silk/fixed/schur_FIX.c new file mode 100644 index 000000000000..f037f3f74461 --- /dev/null +++ b/media/libopus/silk/fixed/schur_FIX.c @@ -0,0 +1,92 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +) +{ + opus_int k, n, lz; + opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + opus_int32 Ctmp1, Ctmp2, rc_tmp_Q15; + + silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 ); + + /* Get number of leading zeros */ + lz = silk_CLZ32( c[ 0 ] ); + + /* Copy correlations and adjust level to Q30 */ + if( lz < 2 ) { + /* lz must be 1, so shift one to the right */ + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = silk_RSHIFT( c[ k ], 1 ); + } + } else if( lz > 2 ) { + /* Shift to the left */ + lz -= 2; + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz ); + } + } else { + /* No need to shift */ + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } + } + + for( k = 0; k < order; k++ ) { + + /* Get reflection coefficient */ + rc_tmp_Q15 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) ); + + /* Clip (shouldn't happen for properly conditioned inputs) */ + rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 ); + + /* Store */ + rc_Q15[ k ] = (opus_int16)rc_tmp_Q15; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 ); + C[ n ][ 1 ] = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 ); + } + } + + /* return residual energy */ + return C[ 0 ][ 1 ]; +} diff --git a/media/libopus/silk/fixed/solve_LS_FIX.c b/media/libopus/silk/fixed/solve_LS_FIX.c new file mode 100644 index 000000000000..f6b5da0107b6 --- /dev/null +++ b/media/libopus/silk/fixed/solve_LS_FIX.c @@ -0,0 +1,245 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/*****************************/ +/* Internal function headers */ +/*****************************/ + +typedef struct { + opus_int32 Q36_part; + opus_int32 Q48_part; +} inv_D_t; + +/* Factorize square matrix A into LDL form */ +static inline void silk_LDL_factorize_FIX( + opus_int32 *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + opus_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */ + inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */ +); + +/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */ +static inline void silk_LS_SolveFirst_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +); + +/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */ +static inline void silk_LS_SolveLast_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + const opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +); + +static inline void silk_LS_divide_Q16_FIX( + opus_int32 T[], /* I/O Numenator vector */ + inv_D_t *inv_D, /* I 1 / D vector */ + opus_int M /* I dimension */ +); + +/* Solves Ax = b, assuming A is symmetric */ +void silk_solve_LDL_FIX( + opus_int32 *A, /* I Pointer to symetric square matrix A */ + opus_int M, /* I Size of matrix */ + const opus_int32 *b, /* I Pointer to b vector */ + opus_int32 *x_Q16 /* O Pointer to x solution vector */ +) +{ + opus_int32 L_Q16[ MAX_MATRIX_SIZE * MAX_MATRIX_SIZE ]; + opus_int32 Y[ MAX_MATRIX_SIZE ]; + inv_D_t inv_D[ MAX_MATRIX_SIZE ]; + + silk_assert( M <= MAX_MATRIX_SIZE ); + + /*************************************************** + Factorize A by LDL such that A = L*D*L', + where L is lower triangular with ones on diagonal + ****************************************************/ + silk_LDL_factorize_FIX( A, M, L_Q16, inv_D ); + + /**************************************************** + * substitute D*L'*x = Y. ie: + L*D*L'*x = b => L*Y = b <=> Y = inv(L)*b + ******************************************************/ + silk_LS_SolveFirst_FIX( L_Q16, M, b, Y ); + + /**************************************************** + D*L'*x = Y <=> L'*x = inv(D)*Y, because D is + diagonal just multiply with 1/d_i + ****************************************************/ + silk_LS_divide_Q16_FIX( Y, inv_D, M ); + + /**************************************************** + x = inv(L') * inv(D) * Y + *****************************************************/ + silk_LS_SolveLast_FIX( L_Q16, M, Y, x_Q16 ); +} + +static inline void silk_LDL_factorize_FIX( + opus_int32 *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + opus_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */ + inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */ +) +{ + opus_int i, j, k, status, loop_count; + const opus_int32 *ptr1, *ptr2; + opus_int32 diag_min_value, tmp_32, err; + opus_int32 v_Q0[ MAX_MATRIX_SIZE ], D_Q0[ MAX_MATRIX_SIZE ]; + opus_int32 one_div_diag_Q36, one_div_diag_Q40, one_div_diag_Q48; + + silk_assert( M <= MAX_MATRIX_SIZE ); + + status = 1; + diag_min_value = silk_max_32( silk_SMMUL( silk_ADD_SAT32( A[ 0 ], A[ silk_SMULBB( M, M ) - 1 ] ), SILK_FIX_CONST( FIND_LTP_COND_FAC, 31 ) ), 1 << 9 ); + for( loop_count = 0; loop_count < M && status == 1; loop_count++ ) { + status = 0; + for( j = 0; j < M; j++ ) { + ptr1 = matrix_adr( L_Q16, j, 0, M ); + tmp_32 = 0; + for( i = 0; i < j; i++ ) { + v_Q0[ i ] = silk_SMULWW( D_Q0[ i ], ptr1[ i ] ); /* Q0 */ + tmp_32 = silk_SMLAWW( tmp_32, v_Q0[ i ], ptr1[ i ] ); /* Q0 */ + } + tmp_32 = silk_SUB32( matrix_ptr( A, j, j, M ), tmp_32 ); + + if( tmp_32 < diag_min_value ) { + tmp_32 = silk_SUB32( silk_SMULBB( loop_count + 1, diag_min_value ), tmp_32 ); + /* Matrix not positive semi-definite, or ill conditioned */ + for( i = 0; i < M; i++ ) { + matrix_ptr( A, i, i, M ) = silk_ADD32( matrix_ptr( A, i, i, M ), tmp_32 ); + } + status = 1; + break; + } + D_Q0[ j ] = tmp_32; /* always < max(Correlation) */ + + /* two-step division */ + one_div_diag_Q36 = silk_INVERSE32_varQ( tmp_32, 36 ); /* Q36 */ + one_div_diag_Q40 = silk_LSHIFT( one_div_diag_Q36, 4 ); /* Q40 */ + err = silk_SUB32( 1 << 24, silk_SMULWW( tmp_32, one_div_diag_Q40 ) ); /* Q24 */ + one_div_diag_Q48 = silk_SMULWW( err, one_div_diag_Q40 ); /* Q48 */ + + /* Save 1/Ds */ + inv_D[ j ].Q36_part = one_div_diag_Q36; + inv_D[ j ].Q48_part = one_div_diag_Q48; + + matrix_ptr( L_Q16, j, j, M ) = 65536; /* 1.0 in Q16 */ + ptr1 = matrix_adr( A, j, 0, M ); + ptr2 = matrix_adr( L_Q16, j + 1, 0, M ); + for( i = j + 1; i < M; i++ ) { + tmp_32 = 0; + for( k = 0; k < j; k++ ) { + tmp_32 = silk_SMLAWW( tmp_32, v_Q0[ k ], ptr2[ k ] ); /* Q0 */ + } + tmp_32 = silk_SUB32( ptr1[ i ], tmp_32 ); /* always < max(Correlation) */ + + /* tmp_32 / D_Q0[j] : Divide to Q16 */ + matrix_ptr( L_Q16, i, j, M ) = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ), + silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) ); + + /* go to next column */ + ptr2 += M; + } + } + } + + silk_assert( status == 0 ); +} + +static inline void silk_LS_divide_Q16_FIX( + opus_int32 T[], /* I/O Numenator vector */ + inv_D_t *inv_D, /* I 1 / D vector */ + opus_int M /* I dimension */ +) +{ + opus_int i; + opus_int32 tmp_32; + opus_int32 one_div_diag_Q36, one_div_diag_Q48; + + for( i = 0; i < M; i++ ) { + one_div_diag_Q36 = inv_D[ i ].Q36_part; + one_div_diag_Q48 = inv_D[ i ].Q48_part; + + tmp_32 = T[ i ]; + T[ i ] = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ), silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) ); + } +} + +/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */ +static inline void silk_LS_SolveFirst_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +) +{ + opus_int i, j; + const opus_int32 *ptr32; + opus_int32 tmp_32; + + for( i = 0; i < M; i++ ) { + ptr32 = matrix_adr( L_Q16, i, 0, M ); + tmp_32 = 0; + for( j = 0; j < i; j++ ) { + tmp_32 = silk_SMLAWW( tmp_32, ptr32[ j ], x_Q16[ j ] ); + } + x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 ); + } +} + +/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */ +static inline void silk_LS_SolveLast_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + const opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +) +{ + opus_int i, j; + const opus_int32 *ptr32; + opus_int32 tmp_32; + + for( i = M - 1; i >= 0; i-- ) { + ptr32 = matrix_adr( L_Q16, 0, i, M ); + tmp_32 = 0; + for( j = M - 1; j > i; j-- ) { + tmp_32 = silk_SMLAWW( tmp_32, ptr32[ silk_SMULBB( j, M ) ], x_Q16[ j ] ); + } + x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 ); + } +} diff --git a/media/libopus/silk/fixed/structs_FIX.h b/media/libopus/silk/fixed/structs_FIX.h new file mode 100644 index 000000000000..8ba14fa16d2e --- /dev/null +++ b/media/libopus/silk/fixed/structs_FIX.h @@ -0,0 +1,133 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_STRUCTS_FIX_H +#define SILK_STRUCTS_FIX_H + +#include "typedef.h" +#include "main.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + opus_int32 HarmBoost_smth_Q16; + opus_int32 HarmShapeGain_smth_Q16; + opus_int32 Tilt_smth_Q16; +} silk_shape_state_FIX; + +/********************************/ +/* Prefilter state */ +/********************************/ +typedef struct { + opus_int16 sLTP_shp[ LTP_BUF_LENGTH ]; + opus_int32 sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int sLTP_shp_buf_idx; + opus_int32 sLF_AR_shp_Q12; + opus_int32 sLF_MA_shp_Q12; + opus_int32 sHarmHP_Q2; + opus_int32 rand_seed; + opus_int lagPrev; +} silk_prefilter_state_FIX; + +/********************************/ +/* Encoder state FIX */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with floating-point code */ + silk_shape_state_FIX sShape; /* Shape state */ + silk_prefilter_state_FIX sPrefilt; /* Prefilter State */ + + /* Buffer for find pitch and noise shape analysis */ + silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + opus_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator */ +} silk_encoder_state_FIX; + +/************************/ +/* Encoder control FIX */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + /* Testing */ + silk_DWORD_ALIGN opus_int16 AR1_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_DWORD_ALIGN opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int GainsPre_Q14[ MAX_NB_SUBFR ]; + opus_int HarmBoost_Q14[ MAX_NB_SUBFR ]; + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + opus_int Lambda_Q10; + opus_int input_quality_Q14; + opus_int coding_quality_Q14; + + /* measures */ + opus_int sparseness_Q8; + opus_int32 predGain_Q16; + opus_int LTPredCodGain_Q7; + opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + opus_int ResNrgQ[ MAX_NB_SUBFR ]; /* Q domain for the residual energy > 0 */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FIX; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FIX state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/media/libopus/silk/fixed/vector_ops_FIX.c b/media/libopus/silk/fixed/vector_ops_FIX.c new file mode 100644 index 000000000000..6cf41d6c20d8 --- /dev/null +++ b/media/libopus/silk/fixed/vector_ops_FIX.c @@ -0,0 +1,127 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +) +{ + opus_int i; + opus_int32 tmp32; + + for( i = 0; i < dataSize; i++ ) { + tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] ); + data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 ); + } +} + +/* Multiply a vector by a constant */ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +) +{ + opus_int i; + + for( i = 0; i < dataSize; i++ ) { + data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) ); /* OUTPUT: Q18 */ + } +} + +/* sum = for(i=0;i6, memory access can be reduced by half. */ +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} + +opus_int64 silk_inner_prod16_aligned_64( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int64 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} + +/* Function that returns the maximum absolut value of the input vector */ +opus_int16 silk_int16_array_maxabs( /* O Maximum absolute value, max: 2^15-1 */ + const opus_int16 *vec, /* I Input vector [len] */ + const opus_int32 len /* I Length of input vector */ +) +{ + opus_int32 max = 0, i, lvl = 0, ind; + if( len == 0 ) return 0; + + ind = len - 1; + max = silk_SMULBB( vec[ ind ], vec[ ind ] ); + for( i = len - 2; i >= 0; i-- ) { + lvl = silk_SMULBB( vec[ i ], vec[ i ] ); + if( lvl > max ) { + max = lvl; + ind = i; + } + } + + /* Do not return 32768, as it will not fit in an int16 so may lead to problems later on */ + if( max >= 1073676289 ) { /* (2^15-1)^2 = 1073676289 */ + return( silk_int16_MAX ); + } else { + if( vec[ ind ] < 0 ) { + return( -vec[ ind ] ); + } else { + return( vec[ ind ] ); + } + } +} diff --git a/media/libopus/silk/fixed/warped_autocorrelation_FIX.c b/media/libopus/silk/fixed/warped_autocorrelation_FIX.c new file mode 100644 index 000000000000..92912e5f992d --- /dev/null +++ b/media/libopus/silk/fixed/warped_autocorrelation_FIX.c @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +#define QC 10 +#define QS 14 + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FIX( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i, lsh; + opus_int32 tmp1_QS, tmp2_QS; + opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + + lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) ); + } + } + silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ +} diff --git a/media/libopus/silk/float/LPC_analysis_filter_FLP.c b/media/libopus/silk/float/LPC_analysis_filter_FLP.c new file mode 100644 index 000000000000..11980300c91e --- /dev/null +++ b/media/libopus/silk/float/LPC_analysis_filter_FLP.c @@ -0,0 +1,249 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" + +/************************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are set to zero */ +/************************************************/ + +/* 16th order LPC analysis filter, does not write first 16 samples */ +static inline void silk_LPC_analysis_filter16_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 16; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ] + + s_ptr[ -10 ] * PredCoef[ 10 ] + + s_ptr[ -11 ] * PredCoef[ 11 ] + + s_ptr[ -12 ] * PredCoef[ 12 ] + + s_ptr[ -13 ] * PredCoef[ 13 ] + + s_ptr[ -14 ] * PredCoef[ 14 ] + + s_ptr[ -15 ] * PredCoef[ 15 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 12th order LPC analysis filter, does not write first 12 samples */ +static inline void silk_LPC_analysis_filter12_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 12; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ] + + s_ptr[ -10 ] * PredCoef[ 10 ] + + s_ptr[ -11 ] * PredCoef[ 11 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 10th order LPC analysis filter, does not write first 10 samples */ +static inline void silk_LPC_analysis_filter10_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 10; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 8th order LPC analysis filter, does not write first 8 samples */ +static inline void silk_LPC_analysis_filter8_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 8; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 6th order LPC analysis filter, does not write first 6 samples */ +static inline void silk_LPC_analysis_filter6_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 6; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/************************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are set to zero */ +/************************************************/ +void silk_LPC_analysis_filter_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length, /* I Length of input signal */ + const opus_int Order /* I LPC order */ +) +{ + silk_assert( Order <= length ); + + switch( Order ) { + case 6: + silk_LPC_analysis_filter6_FLP( r_LPC, PredCoef, s, length ); + break; + + case 8: + silk_LPC_analysis_filter8_FLP( r_LPC, PredCoef, s, length ); + break; + + case 10: + silk_LPC_analysis_filter10_FLP( r_LPC, PredCoef, s, length ); + break; + + case 12: + silk_LPC_analysis_filter12_FLP( r_LPC, PredCoef, s, length ); + break; + + case 16: + silk_LPC_analysis_filter16_FLP( r_LPC, PredCoef, s, length ); + break; + + default: + silk_assert( 0 ); + break; + } + + /* Set first Order output samples to zero */ + silk_memset( r_LPC, 0, Order * sizeof( silk_float ) ); +} + diff --git a/media/libopus/silk/float/LPC_inv_pred_gain_FLP.c b/media/libopus/silk/float/LPC_inv_pred_gain_FLP.c new file mode 100644 index 000000000000..59ed7d4cacde --- /dev/null +++ b/media/libopus/silk/float/LPC_inv_pred_gain_FLP.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "SigProc_FLP.h" + +#define RC_THRESHOLD 0.9999f + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on silk_a2k_FLP() */ +silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */ + const silk_float *A, /* I prediction coefficients [order] */ + opus_int32 order /* I prediction order */ +) +{ + opus_int k, n; + double invGain, rc, rc_mult1, rc_mult2; + silk_float Atmp[ 2 ][ SILK_MAX_ORDER_LPC ]; + silk_float *Aold, *Anew; + + Anew = Atmp[ order & 1 ]; + silk_memcpy( Anew, A, order * sizeof(silk_float) ); + + invGain = 1.0; + for( k = order - 1; k > 0; k-- ) { + rc = -Anew[ k ]; + if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) { + return 0.0f; + } + rc_mult1 = 1.0f - rc * rc; + rc_mult2 = 1.0f / rc_mult1; + invGain *= rc_mult1; + /* swap pointers */ + Aold = Anew; + Anew = Atmp[ k & 1 ]; + for( n = 0; n < k; n++ ) { + Anew[ n ] = (silk_float)( ( Aold[ n ] - Aold[ k - n - 1 ] * rc ) * rc_mult2 ); + } + } + rc = -Anew[ 0 ]; + if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) { + return 0.0f; + } + rc_mult1 = 1.0f - rc * rc; + invGain *= rc_mult1; + return (silk_float)invGain; +} diff --git a/media/libopus/silk/float/LTP_analysis_filter_FLP.c b/media/libopus/silk/float/LTP_analysis_filter_FLP.c new file mode 100644 index 000000000000..7d2db93b4933 --- /dev/null +++ b/media/libopus/silk/float/LTP_analysis_filter_FLP.c @@ -0,0 +1,75 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +void silk_LTP_analysis_filter_FLP( + silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */ + const silk_float *x, /* I Input signal, with preceeding samples */ + const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int pre_length /* I Preceeding samples for each subframe */ +) +{ + const silk_float *x_ptr, *x_lag_ptr; + silk_float Btmp[ LTP_ORDER ]; + silk_float *LTP_res_ptr; + silk_float inv_gain; + opus_int k, i, j; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < nb_subfr; k++ ) { + x_lag_ptr = x_ptr - pitchL[ k ]; + inv_gain = invGains[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + Btmp[ i ] = B[ k * LTP_ORDER + i ]; + } + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + /* Subtract long-term prediction */ + for( j = 0; j < LTP_ORDER; j++ ) { + LTP_res_ptr[ i ] -= Btmp[ j ] * x_lag_ptr[ LTP_ORDER / 2 - j ]; + } + LTP_res_ptr[ i ] *= inv_gain; + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} diff --git a/media/libopus/silk/float/LTP_scale_ctrl_FLP.c b/media/libopus/silk/float/LTP_scale_ctrl_FLP.c new file mode 100644 index 000000000000..2354ebe98ef2 --- /dev/null +++ b/media/libopus/silk/float/LTP_scale_ctrl_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +void silk_LTP_scale_ctrl_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( round_loss * psEncCtrl->LTPredCodGain * 0.1f, 0.0f, 2.0f ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + + psEncCtrl->LTP_scale = (silk_float)silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ] / 16384.0f; +} diff --git a/media/libopus/silk/float/SigProc_FLP.h b/media/libopus/silk/float/SigProc_FLP.h new file mode 100644 index 000000000000..8b5a1facdc84 --- /dev/null +++ b/media/libopus/silk/float/SigProc_FLP.h @@ -0,0 +1,206 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FLP_H +#define SILK_SIGPROC_FLP_H + +#include "SigProc_FIX.h" +#include "float_cast.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/* Chirp (bw expand) LP AR filter */ +void silk_bwexpander_FLP( + silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I length of ar */ + const silk_float chirp /* I chirp factor (typically in range (0..1) ) */ +); + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on silk_FLP_a2k() */ +silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */ + const silk_float *A, /* I prediction coefficients [order] */ + opus_int32 order /* I prediction order */ +); + +silk_float silk_schur_FLP( /* O returns residual energy */ + silk_float refl_coef[], /* O reflection coefficients (length order) */ + const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ + opus_int order /* I order */ +); + +void silk_k2a_FLP( + silk_float *A, /* O prediction coefficients [order] */ + const silk_float *rc, /* I reflection coefficients [order] */ + opus_int32 order /* I prediction order */ +); + +/* Solve the normal equations using the Levinson-Durbin recursion */ +silk_float silk_levinsondurbin_FLP( /* O prediction error energy */ + silk_float A[], /* O prediction coefficients [order] */ + const silk_float corr[], /* I input auto-correlations [order + 1] */ + const opus_int order /* I prediction order */ +); + +/* compute autocorrelation */ +void silk_autocorrelation_FLP( + silk_float *results, /* O result (length correlationCount) */ + const silk_float *inputData, /* I input data to correlate */ + opus_int inputDataSize, /* I length of input */ + opus_int correlationCount /* I number of correlation taps to compute */ +); + +opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */ + const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr /* I Number of 5 ms subframes */ +); + +void silk_insertion_sort_decreasing_FLP( + silk_float *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +/* Compute reflection coefficients from input signal */ +silk_float silk_burg_modified_FLP( /* O returns residual energy */ + silk_float A[], /* O prediction coefficients (length order) */ + const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const silk_float minInvGain, /* I minimum inverse prediction gain */ + const opus_int subfr_length, /* I input signal subframe length (incl. D preceeding samples) */ + const opus_int nb_subfr, /* I number of subframes stacked in x */ + const opus_int D /* I order */ +); + +/* multiply a vector by a constant */ +void silk_scale_vector_FLP( + silk_float *data1, + silk_float gain, + opus_int dataSize +); + +/* copy and multiply a vector by a constant */ +void silk_scale_copy_vector_FLP( + silk_float *data_out, + const silk_float *data_in, + silk_float gain, + opus_int dataSize +); + +/* inner product of two silk_float arrays, with result as double */ +double silk_inner_product_FLP( + const silk_float *data1, + const silk_float *data2, + opus_int dataSize +); + +/* sum of squares of a silk_float array, with result as double */ +double silk_energy_FLP( + const silk_float *data, + opus_int dataSize +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +#define PI (3.1415926536f) + +#define silk_min_float( a, b ) (((a) < (b)) ? (a) : (b)) +#define silk_max_float( a, b ) (((a) > (b)) ? (a) : (b)) +#define silk_abs_float( a ) ((silk_float)fabs(a)) + +#define silk_LIMIT_float( a, limit1, limit2 ) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + +/* sigmoid function */ +static inline silk_float silk_sigmoid( silk_float x ) +{ + return (silk_float)(1.0 / (1.0 + exp(-x))); +} + +/* floating-point to integer conversion (rounding) */ +static inline opus_int32 silk_float2int( silk_float x ) +{ + return (opus_int32)float2int( x ); +} + +/* floating-point to integer conversion (rounding) */ +static inline void silk_float2short_array( + opus_int16 *out, + const silk_float *in, + opus_int32 length +) +{ + opus_int32 k; + for( k = length - 1; k >= 0; k-- ) { + out[k] = silk_SAT16( (opus_int32)float2int( in[k] ) ); + } +} + +/* integer to floating-point conversion */ +static inline void silk_short2float_array( + silk_float *out, + const opus_int16 *in, + opus_int32 length +) +{ + opus_int32 k; + for( k = length - 1; k >= 0; k-- ) { + out[k] = (silk_float)in[k]; + } +} + +/* using log2() helps the fixed-point conversion */ +static inline silk_float silk_log2( double x ) +{ + return ( silk_float )( 3.32192809488736 * log10( x ) ); +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FLP_H */ diff --git a/media/libopus/silk/float/apply_sine_window_FLP.c b/media/libopus/silk/float/apply_sine_window_FLP.c new file mode 100644 index 000000000000..d334e9d9aa55 --- /dev/null +++ b/media/libopus/silk/float/apply_sine_window_FLP.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Apply sine window to signal vector */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void silk_apply_sine_window_FLP( + silk_float px_win[], /* O Pointer to windowed signal */ + const silk_float px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k; + silk_float freq, c, S0, S1; + + silk_assert( win_type == 1 || win_type == 2 ); + + /* Length must be multiple of 4 */ + silk_assert( ( length & 3 ) == 0 ); + + freq = PI / ( length + 1 ); + + /* Approximation of 2 * cos(f) */ + c = 2.0f - freq * freq; + + /* Initialize state */ + if( win_type < 2 ) { + /* Start from 0 */ + S0 = 0.0f; + /* Approximation of sin(f) */ + S1 = freq; + } else { + /* Start from 1 */ + S0 = 1.0f; + /* Approximation of cos(f) */ + S1 = 0.5f * c; + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k + 0 ] = px[ k + 0 ] * 0.5f * ( S0 + S1 ); + px_win[ k + 1 ] = px[ k + 1 ] * S1; + S0 = c * S1 - S0; + px_win[ k + 2 ] = px[ k + 2 ] * 0.5f * ( S1 + S0 ); + px_win[ k + 3 ] = px[ k + 3 ] * S0; + S1 = c * S0 - S1; + } +} diff --git a/media/libopus/silk/float/autocorrelation_FLP.c b/media/libopus/silk/float/autocorrelation_FLP.c new file mode 100644 index 000000000000..8d38811548fb --- /dev/null +++ b/media/libopus/silk/float/autocorrelation_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "typedef.h" +#include "SigProc_FLP.h" + +/* compute autocorrelation */ +void silk_autocorrelation_FLP( + silk_float *results, /* O result (length correlationCount) */ + const silk_float *inputData, /* I input data to correlate */ + opus_int inputDataSize, /* I length of input */ + opus_int correlationCount /* I number of correlation taps to compute */ +) +{ + opus_int i; + + if( correlationCount > inputDataSize ) { + correlationCount = inputDataSize; + } + + for( i = 0; i < correlationCount; i++ ) { + results[ i ] = (silk_float)silk_inner_product_FLP( inputData, inputData + i, inputDataSize - i ); + } +} diff --git a/media/libopus/silk/float/burg_modified_FLP.c b/media/libopus/silk/float/burg_modified_FLP.c new file mode 100644 index 000000000000..2f6edfaee630 --- /dev/null +++ b/media/libopus/silk/float/burg_modified_FLP.c @@ -0,0 +1,186 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" +#include "tuning_parameters.h" +#include "define.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/ + +/* Compute reflection coefficients from input signal */ +silk_float silk_burg_modified_FLP( /* O returns residual energy */ + silk_float A[], /* O prediction coefficients (length order) */ + const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const silk_float minInvGain, /* I minimum inverse prediction gain */ + const opus_int subfr_length, /* I input signal subframe length (incl. D preceeding samples) */ + const opus_int nb_subfr, /* I number of subframes stacked in x */ + const opus_int D /* I order */ +) +{ + opus_int k, n, s, reached_max_gain; + double C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2; + const silk_float *x_ptr; + double C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ]; + double CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ]; + double Af[ SILK_MAX_ORDER_LPC ]; + + silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + C0 = silk_energy_FLP( x, nb_subfr * subfr_length ); + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) ); + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n ); + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f; + invGain = 1.0f; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + tmp1 = x_ptr[ n ]; + tmp2 = x_ptr[ subfr_length - n - 1 ]; + for( k = 0; k < n; k++ ) { + C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ]; + C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ]; + Atmp = Af[ k ]; + tmp1 += x_ptr[ n - k - 1 ] * Atmp; + tmp2 += x_ptr[ subfr_length - n + k ] * Atmp; + } + for( k = 0; k <= n; k++ ) { + CAf[ k ] -= tmp1 * x_ptr[ n - k ]; + CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ]; + } + } + tmp1 = C_first_row[ n ]; + tmp2 = C_last_row[ n ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + tmp1 += C_last_row[ n - k - 1 ] * Atmp; + tmp2 += C_first_row[ n - k - 1 ] * Atmp; + } + CAf[ n + 1 ] = tmp1; + CAb[ n + 1 ] = tmp2; + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + num = CAb[ n + 1 ]; + nrg_b = CAb[ 0 ]; + nrg_f = CAf[ 0 ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + num += CAb[ n - k ] * Atmp; + nrg_b += CAb[ k + 1 ] * Atmp; + nrg_f += CAf[ k + 1 ] * Atmp; + } + silk_assert( nrg_f > 0.0 ); + silk_assert( nrg_b > 0.0 ); + + /* Calculate the next order reflection (parcor) coefficient */ + rc = -2.0 * num / ( nrg_f + nrg_b ); + silk_assert( rc > -1.0 && rc < 1.0 ); + + /* Update inverse prediction gain */ + tmp1 = invGain * ( 1.0 - rc * rc ); + if( tmp1 <= minInvGain ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + rc = sqrt( 1.0 - minInvGain / invGain ); + if( num > 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc = -rc; + } + invGain = minInvGain; + reached_max_gain = 1; + } else { + invGain = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af[ k ]; + tmp2 = Af[ n - k - 1 ]; + Af[ k ] = tmp1 + rc * tmp2; + Af[ n - k - 1 ] = tmp2 + rc * tmp1; + } + Af[ n ] = rc; + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af[ k ] = 0.0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; + CAf[ k ] += rc * CAb[ n - k + 1 ]; + CAb[ n - k + 1 ] += rc * tmp1; + } + } + + if( reached_max_gain ) { + /* Convert to silk_float */ + for( k = 0; k < D; k++ ) { + A[ k ] = (silk_float)( -Af[ k ] ); + } + /* Subtract energy of preceeding samples from C0 */ + for( s = 0; s < nb_subfr; s++ ) { + C0 -= silk_energy_FLP( x + s * subfr_length, D ); + } + /* Approximate residual energy */ + nrg_f = C0 * invGain; + } else { + /* Compute residual energy and store coefficients as silk_float */ + nrg_f = CAf[ 0 ]; + tmp1 = 1.0; + for( k = 0; k < D; k++ ) { + Atmp = Af[ k ]; + nrg_f += CAf[ k + 1 ] * Atmp; + tmp1 += Atmp * Atmp; + A[ k ] = (silk_float)(-Atmp); + } + nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1; + } + + /* Return residual energy */ + return (silk_float)nrg_f; +} diff --git a/media/libopus/silk/float/bwexpander_FLP.c b/media/libopus/silk/float/bwexpander_FLP.c new file mode 100644 index 000000000000..1642b4b95953 --- /dev/null +++ b/media/libopus/silk/float/bwexpander_FLP.c @@ -0,0 +1,49 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* Chirp (bw expand) LP AR filter */ +void silk_bwexpander_FLP( + silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I length of ar */ + const silk_float chirp /* I chirp factor (typically in range (0..1) ) */ +) +{ + opus_int i; + silk_float cfac = chirp; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] *= cfac; + cfac *= chirp; + } + ar[ d - 1 ] *= cfac; +} diff --git a/media/libopus/silk/float/corrMatrix_FLP.c b/media/libopus/silk/float/corrMatrix_FLP.c new file mode 100644 index 000000000000..9de00d32be1f --- /dev/null +++ b/media/libopus/silk/float/corrMatrix_FLP.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/********************************************************************** + * Correlation matrix computations for LS estimate. + **********************************************************************/ + +#include "main_FLP.h" + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FLP( + const silk_float *x, /* I x vector [L+order-1] used to create X */ + const silk_float *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vecors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *Xt /* O X'*t correlation vector [order] */ +) +{ + opus_int lag; + const silk_float *ptr1; + + ptr1 = &x[ Order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + for( lag = 0; lag < Order; lag++ ) { + /* Calculate X[:,lag]'*t */ + Xt[ lag ] = (silk_float)silk_inner_product_FLP( ptr1, t, L ); + ptr1--; /* Next column of X */ + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FLP( + const silk_float *x, /* I x vector [ L+order-1 ] used to create X */ + const opus_int L, /* I Length of vectors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *XX /* O X'*X correlation matrix [order x order] */ +) +{ + opus_int j, lag; + double energy; + const silk_float *ptr1, *ptr2; + + ptr1 = &x[ Order - 1 ]; /* First sample of column 0 of X */ + energy = silk_energy_FLP( ptr1, L ); /* X[:,0]'*X[:,0] */ + matrix_ptr( XX, 0, 0, Order ) = ( silk_float )energy; + for( j = 1; j < Order; j++ ) { + /* Calculate X[:,j]'*X[:,j] */ + energy += ptr1[ -j ] * ptr1[ -j ] - ptr1[ L - j ] * ptr1[ L - j ]; + matrix_ptr( XX, j, j, Order ) = ( silk_float )energy; + } + + ptr2 = &x[ Order - 2 ]; /* First sample of column 1 of X */ + for( lag = 1; lag < Order; lag++ ) { + /* Calculate X[:,0]'*X[:,lag] */ + energy = silk_inner_product_FLP( ptr1, ptr2, L ); + matrix_ptr( XX, lag, 0, Order ) = ( silk_float )energy; + matrix_ptr( XX, 0, lag, Order ) = ( silk_float )energy; + /* Calculate X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( Order - lag ); j++ ) { + energy += ptr1[ -j ] * ptr2[ -j ] - ptr1[ L - j ] * ptr2[ L - j ]; + matrix_ptr( XX, lag + j, j, Order ) = ( silk_float )energy; + matrix_ptr( XX, j, lag + j, Order ) = ( silk_float )energy; + } + ptr2--; /* Next column of X */ + } +} diff --git a/media/libopus/silk/float/encode_frame_FLP.c b/media/libopus/silk/float/encode_frame_FLP.c new file mode 100644 index 000000000000..facb410496eb --- /dev/null +++ b/media/libopus/silk/float/encode_frame_FLP.c @@ -0,0 +1,372 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static inline void silk_LBRR_encode_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float xfw[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FLP( + silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ +) +{ + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1 ); + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter < NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int32 *pnBytesOut, /* O Number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FLP sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + silk_float *x_frame, *res_pitch_frame; + silk_float xfw[ MAX_FRAME_LENGTH ]; + silk_float res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; + opus_uint8 ec_buf_copy[ 1275 ]; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /**************************************************************/ + /* pointers aligned with start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /* start of frame to encode */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /* start of pitch LPC residual frame */ + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */ + for( i = 0; i < 8; i++ ) { + x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + i * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( i & 2 ) ) * 1e-6f; + } + + if( !psEnc->sCmn.prefillFlag ) { + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding ); + + /*****************************************/ + /* Prefiltering for noise shaper */ + /*****************************************/ + silk_prefilter_FLP( psEnc, &sEncCtrl, xfw, x_frame ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FLP( psEnc, &sEncCtrl, xfw, condCoding ); + + /* Loop over quantizer and entroy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, xfw ); + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + silk_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda *= 1.5f; + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + silk_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) ); + if( nBits > maxBits ) { + gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) ); + } + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f; + } + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) ); + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + return ret; + } + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static inline void silk_LBRR_encode_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float xfw[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int k; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_float TempGains[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains, psEncCtrl->Gains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + silk_gains_dequant( Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] = Gains_Q16[ k ] * ( 1.0f / 65536.0f ); + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, psIndices_LBRR, &sNSQ_LBRR, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], xfw ); + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains, TempGains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) ); + } +} diff --git a/media/libopus/silk/float/energy_FLP.c b/media/libopus/silk/float/energy_FLP.c new file mode 100644 index 000000000000..19f902ce41e3 --- /dev/null +++ b/media/libopus/silk/float/energy_FLP.c @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* sum of squares of a silk_float array, with result as double */ +double silk_energy_FLP( + const silk_float *data, + opus_int dataSize +) +{ + opus_int i, dataSize4; + double result; + + /* 4x unrolled loop */ + result = 0.0; + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + result += data[ i + 0 ] * (double)data[ i + 0 ] + + data[ i + 1 ] * (double)data[ i + 1 ] + + data[ i + 2 ] * (double)data[ i + 2 ] + + data[ i + 3 ] * (double)data[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data[ i ] * (double)data[ i ]; + } + + silk_assert( result >= 0.0 ); + return result; +} diff --git a/media/libopus/silk/float/find_LPC_FLP.c b/media/libopus/silk/float/find_LPC_FLP.c new file mode 100644 index 000000000000..940a8c0ac885 --- /dev/null +++ b/media/libopus/silk/float/find_LPC_FLP.c @@ -0,0 +1,104 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "define.h" +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* LPC analysis */ +void silk_find_LPC_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const silk_float x[], /* I Input signal */ + const silk_float minInvGain /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + silk_float a[ MAX_LPC_ORDER ]; + + /* Used only for NLSF interpolation */ + silk_float res_nrg, res_nrg_2nd, res_nrg_interp; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + silk_float a_tmp[ MAX_LPC_ORDER ]; + silk_float LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ]; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: No interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + res_nrg = silk_burg_modified_FLP( a, x, minInvGain, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + /* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than */ + /* adding it to the residual energy of the first 10 ms in each iteration of the search below */ + res_nrg -= silk_burg_modified_FLP( a_tmp, x + ( MAX_NB_SUBFR / 2 ) * subfr_length, minInvGain, subfr_length, MAX_NB_SUBFR / 2, psEncC->predictLPCOrder ); + + /* Convert to NLSFs */ + silk_A2NLSF_FLP( NLSF_Q15, a_tmp, psEncC->predictLPCOrder ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + res_nrg_2nd = silk_float_MAX; + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, psEncC->predictLPCOrder ); + + /* Calculate residual energy with LSF interpolation */ + silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, psEncC->predictLPCOrder ); + res_nrg_interp = (silk_float)( + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ) + + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ) ); + + /* Determine whether current interpolated NLSFs are best so far */ + if( res_nrg_interp < res_nrg ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } else if( res_nrg_interp > res_nrg_2nd ) { + /* No reason to continue iterating - residual energies will continue to climb */ + break; + } + res_nrg_2nd = res_nrg_interp; + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF_FLP( NLSF_Q15, a, psEncC->predictLPCOrder ); + } + + silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || + ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); +} diff --git a/media/libopus/silk/float/find_LTP_FLP.c b/media/libopus/silk/float/find_LTP_FLP.c new file mode 100644 index 000000000000..4caf4d242da3 --- /dev/null +++ b/media/libopus/silk/float/find_LTP_FLP.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +void silk_find_LTP_FLP( + silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float *LTPredCodGain, /* O LTP coding gain */ + const silk_float r_lpc[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset /* I Number of samples in LTP memory */ +) +{ + opus_int i, k; + silk_float *b_ptr, temp, *WLTP_ptr; + silk_float LPC_res_nrg, LPC_LTP_res_nrg; + silk_float d[ MAX_NB_SUBFR ], m, g, delta_b[ LTP_ORDER ]; + silk_float w[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], regu; + silk_float Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ]; + const silk_float *r_ptr, *lag_ptr; + + b_ptr = b; + WLTP_ptr = WLTP; + r_ptr = &r_lpc[ mem_offset ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + + silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, WLTP_ptr ); + silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr ); + + rr[ k ] = ( silk_float )silk_energy_FLP( r_ptr, subfr_length ); + regu = 1.0f + rr[ k ] + + matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ) + + matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ); + regu *= LTP_DAMPING / 3; + silk_regularize_correlations_FLP( WLTP_ptr, &rr[ k ], regu, LTP_ORDER ); + silk_solve_LDL_FLP( WLTP_ptr, LTP_ORDER, Rr, b_ptr ); + + /* Calculate residual energy */ + nrg[ k ] = silk_residual_energy_covar_FLP( b_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER ); + + temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); + silk_scale_vector_FLP( WLTP_ptr, temp, LTP_ORDER * LTP_ORDER ); + w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER / 2, LTP_ORDER / 2, LTP_ORDER ); + + r_ptr += subfr_length; + b_ptr += LTP_ORDER; + WLTP_ptr += LTP_ORDER * LTP_ORDER; + } + + /* Compute LTP coding gain */ + if( LTPredCodGain != NULL ) { + LPC_LTP_res_nrg = 1e-6f; + LPC_res_nrg = 0.0f; + for( k = 0; k < nb_subfr; k++ ) { + LPC_res_nrg += rr[ k ] * Wght[ k ]; + LPC_LTP_res_nrg += nrg[ k ] * Wght[ k ]; + } + + silk_assert( LPC_LTP_res_nrg > 0 ); + *LTPredCodGain = 3.0f * silk_log2( LPC_res_nrg / LPC_LTP_res_nrg ); + } + + /* Smoothing */ + /* d = sum( B, 1 ); */ + b_ptr = b; + for( k = 0; k < nb_subfr; k++ ) { + d[ k ] = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + d[ k ] += b_ptr[ i ]; + } + b_ptr += LTP_ORDER; + } + /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */ + temp = 1e-3f; + for( k = 0; k < nb_subfr; k++ ) { + temp += w[ k ]; + } + m = 0; + for( k = 0; k < nb_subfr; k++ ) { + m += d[ k ] * w[ k ]; + } + m = m / temp; + + b_ptr = b; + for( k = 0; k < nb_subfr; k++ ) { + g = LTP_SMOOTHING / ( LTP_SMOOTHING + w[ k ] ) * ( m - d[ k ] ); + temp = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + delta_b[ i ] = silk_max_float( b_ptr[ i ], 0.1f ); + temp += delta_b[ i ]; + } + temp = g / temp; + for( i = 0; i < LTP_ORDER; i++ ) { + b_ptr[ i ] = b_ptr[ i ] + delta_b[ i ] * temp; + } + b_ptr += LTP_ORDER; + } +} diff --git a/media/libopus/silk/float/find_pitch_lags_FLP.c b/media/libopus/silk/float/find_pitch_lags_FLP.c new file mode 100644 index 000000000000..c037138f5065 --- /dev/null +++ b/media/libopus/silk/float/find_pitch_lags_FLP.c @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" +#include "tuning_parameters.h" + +void silk_find_pitch_lags_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + silk_float res[], /* O Residual */ + const silk_float x[] /* I Speech signal */ +) +{ + opus_int buf_len; + silk_float thrhld, res_nrg; + const silk_float *x_buf_ptr, *x_buf; + silk_float auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + silk_float A[ MAX_FIND_PITCH_LPC_ORDER ]; + silk_float refl_coef[ MAX_FIND_PITCH_LPC_ORDER ]; + silk_float Wsig[ FIND_PITCH_LPC_WIN_MAX ]; + silk_float *Wsig_ptr; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safty check */ + silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.ltp_mem_length; + + /******************************************/ + /* Estimate LPC AR coeficients */ + /******************************************/ + + /* Calculate windowed signal */ + + /* First LA_LTP samples */ + x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle non-windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_buf_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ) ) * sizeof( silk_float ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorrelation_FLP( auto_corr, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); + + /* Add white noise, as a fraction of the energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * FIND_PITCH_WHITE_NOISE_FRACTION + 1; + + /* Calculate the reflection coefficients using Schur */ + res_nrg = silk_schur_FLP( refl_coef, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain = auto_corr[ 0 ] / silk_max_float( res_nrg, 1.0f ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_FLP( A, refl_coef, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Bandwidth expansion */ + silk_bwexpander_FLP( A, psEnc->sCmn.pitchEstimationLPCOrder, FIND_PITCH_BANDWITH_EXPANSION ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter_FLP( res, A, x_buf, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld = 0.6f; + thrhld -= 0.004f * psEnc->sCmn.pitchEstimationLPCOrder; + thrhld -= 0.1f * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + thrhld -= 0.15f * (psEnc->sCmn.prevSignalType >> 1); + thrhld -= 0.1f * psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ); + + /*****************************************/ + /* Call Pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core_FLP( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, + &psEnc->sCmn.indices.contourIndex, &psEnc->LTPCorr, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16 / 65536.0f, + thrhld, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr ) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr = 0; + } +} diff --git a/media/libopus/silk/float/find_pred_coefs_FLP.c b/media/libopus/silk/float/find_pred_coefs_FLP.c new file mode 100644 index 000000000000..d30eeef81862 --- /dev/null +++ b/media/libopus/silk/float/find_pred_coefs_FLP.c @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float res_pitch[], /* I Residual from pitch analysis */ + const silk_float x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i; + silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + silk_float invGains[ MAX_NB_SUBFR ], Wght[ MAX_NB_SUBFR ]; + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; + const silk_float *x_ptr; + silk_float *x_pre_ptr, LPC_in_pre[ MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ]; + silk_float minInvGain; + + /* Weighting for weighted least squares */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_assert( psEncCtrl->Gains[ i ] > 0.0f ); + invGains[ i ] = 1.0f / psEncCtrl->Gains[ i ]; + Wght[ i ] = invGains[ i ] * invGains[ i ]; + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /**********/ + /* VOICED */ + /**********/ + silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + /* LTP analysis */ + silk_find_LTP_FLP( psEncCtrl->LTPCoef, WLTP, &psEncCtrl->LTPredCodGain, res_pitch, + psEncCtrl->pitchL, Wght, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains_FLP( psEncCtrl->LTPCoef, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr ); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FLP( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FLP( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef, + psEncCtrl->pitchL, invGains, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_scale_copy_vector_FLP( x_pre_ptr, x_ptr, invGains[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + silk_memset( psEncCtrl->LTPCoef, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( silk_float ) ); + psEncCtrl->LTPredCodGain = 0.0f; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain = 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET; + } else { + minInvGain = (silk_float)pow( 2, psEncCtrl->LTPredCodGain / 3 ) / MAX_PREDICTION_POWER_GAIN; + minInvGain /= 0.25f + 0.75f * psEncCtrl->coding_quality; + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FLP( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain ); + + /* Quantize LSFs */ + silk_process_NLSFs_FLP( &psEnc->sCmn, psEncCtrl->PredCoef, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FLP( psEncCtrl->ResNrg, LPC_in_pre, psEncCtrl->PredCoef, psEncCtrl->Gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); +} + diff --git a/media/libopus/silk/float/inner_product_FLP.c b/media/libopus/silk/float/inner_product_FLP.c new file mode 100644 index 000000000000..0e4ebb21d8d2 --- /dev/null +++ b/media/libopus/silk/float/inner_product_FLP.c @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* inner product of two silk_float arrays, with result as double */ +double silk_inner_product_FLP( + const silk_float *data1, + const silk_float *data2, + opus_int dataSize +) +{ + opus_int i, dataSize4; + double result; + + /* 4x unrolled loop */ + result = 0.0; + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + result += data1[ i + 0 ] * (double)data2[ i + 0 ] + + data1[ i + 1 ] * (double)data2[ i + 1 ] + + data1[ i + 2 ] * (double)data2[ i + 2 ] + + data1[ i + 3 ] * (double)data2[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data1[ i ] * (double)data2[ i ]; + } + + return result; +} diff --git a/media/libopus/silk/float/k2a_FLP.c b/media/libopus/silk/float/k2a_FLP.c new file mode 100644 index 000000000000..8702bc796950 --- /dev/null +++ b/media/libopus/silk/float/k2a_FLP.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_FLP( + silk_float *A, /* O prediction coefficients [order] */ + const silk_float *rc, /* I reflection coefficients [order] */ + opus_int32 order /* I prediction order */ +) +{ + opus_int k, n; + silk_float Atmp[ SILK_MAX_ORDER_LPC ]; + + for( k = 0; k < order; k++ ) { + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A[ n ]; + } + for( n = 0; n < k; n++ ) { + A[ n ] += Atmp[ k - n - 1 ] * rc[ k ]; + } + A[ k ] = -rc[ k ]; + } +} diff --git a/media/libopus/silk/float/levinsondurbin_FLP.c b/media/libopus/silk/float/levinsondurbin_FLP.c new file mode 100644 index 000000000000..a6bb59aa8b0c --- /dev/null +++ b/media/libopus/silk/float/levinsondurbin_FLP.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* Solve the normal equations using the Levinson-Durbin recursion */ +silk_float silk_levinsondurbin_FLP( /* O prediction error energy */ + silk_float A[], /* O prediction coefficients [order] */ + const silk_float corr[], /* I input auto-correlations [order + 1] */ + const opus_int order /* I prediction order */ +) +{ + opus_int i, mHalf, m; + silk_float min_nrg, nrg, t, km, Atmp1, Atmp2; + + min_nrg = 1e-12f * corr[ 0 ] + 1e-9f; + nrg = corr[ 0 ]; + nrg = silk_max_float(min_nrg, nrg); + A[ 0 ] = corr[ 1 ] / nrg; + nrg -= A[ 0 ] * corr[ 1 ]; + nrg = silk_max_float(min_nrg, nrg); + + for( m = 1; m < order; m++ ) + { + t = corr[ m + 1 ]; + for( i = 0; i < m; i++ ) { + t -= A[ i ] * corr[ m - i ]; + } + + /* reflection coefficient */ + km = t / nrg; + + /* residual energy */ + nrg -= km * t; + nrg = silk_max_float(min_nrg, nrg); + + mHalf = m >> 1; + for( i = 0; i < mHalf; i++ ) { + Atmp1 = A[ i ]; + Atmp2 = A[ m - i - 1 ]; + A[ m - i - 1 ] -= km * Atmp1; + A[ i ] -= km * Atmp2; + } + if( m & 1 ) { + A[ mHalf ] -= km * A[ mHalf ]; + } + A[ m ] = km; + } + + /* return the residual energy */ + return nrg; +} + diff --git a/media/libopus/silk/float/main_FLP.h b/media/libopus/silk/float/main_FLP.h new file mode 100644 index 000000000000..5107921bbe6a --- /dev/null +++ b/media/libopus/silk/float/main_FLP.h @@ -0,0 +1,309 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MAIN_FLP_H +#define SILK_MAIN_FLP_H + +#include "SigProc_FLP.h" +#include "SigProc_FIX.h" +#include "structs_FLP.h" +#include "main.h" +#include "define.h" +#include "debug.h" +#include "entenc.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FLP +#define silk_encode_frame_Fxx silk_encode_frame_FLP + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FLP( + silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int32 *pnBytesOut, /* O Number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/****************/ +/* Prefiltering */ +/****************/ +void silk_prefilter_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + const silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */ + silk_float xw[], /* O Weighted signal */ + const silk_float x[] /* I Speech signal */ +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float *pitch_res, /* I LPC residual from pitch analysis */ + const silk_float *x /* I Input signal [frame_length + la_shape] */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FLP( + silk_float *corr, /* O Result [order + 1] */ + const silk_float *input, /* I Input data to correlate */ + const silk_float warping, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + silk_float res[], /* O Residual */ + const silk_float x[] /* I Speech signal */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float res_pitch[], /* I Residual from pitch analysis */ + const silk_float x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const silk_float x[], /* I Input signal */ + const silk_float minInvGain /* I Prediction gain from LTP (dB) */ +); + +/* LTP analysis */ +void silk_find_LTP_FLP( + silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float *LTPredCodGain, /* O LTP coding gain */ + const silk_float r_lpc[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset /* I Number of samples in LTP memory */ +); + +void silk_LTP_analysis_filter_FLP( + silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */ + const silk_float *x, /* I Input signal, with preceeding samples */ + const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int pre_length /* I Preceeding samples for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceeding samples */ +void silk_residual_energy_FLP( + silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + const silk_float x[], /* I Input signal */ + silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const silk_float gains[], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int LPC_order /* I LPC order */ +); + +/* 16th order LPC analysis filter */ +void silk_LPC_analysis_filter_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length, /* I Length of input signal */ + const opus_int Order /* I LPC order */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains_FLP( + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (Un-)quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */ + opus_int8 *periodicity_index, /* O Periodicity index */ + const silk_float W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Error weights */ + const opus_int mu_Q10, /* I Mu value (R/D tradeoff) */ + const opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const silk_float *c, /* I Filter coefficients */ + silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const silk_float *wXx, /* I Weighted correlation vector */ + const silk_float wxx, /* I Weighted correlation value */ + const opus_int D /* I Dimension */ +); + +/* Processing of gains */ +void silk_process_gains_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FLP( + const silk_float *x, /* I x vector [ L+order-1 ] used to create X */ + const opus_int L, /* I Length of vectors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *XX /* O X'*X correlation matrix [order x order] */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FLP( + const silk_float *x, /* I x vector [L+order-1] used to create X */ + const silk_float *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vecors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *Xt /* O X'*t correlation vector [order] */ +); + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FLP( + silk_float *XX, /* I/O Correlation matrices */ + silk_float *xx, /* I/O Correlation values */ + const silk_float noise, /* I Noise energy to add */ + const opus_int D /* I Dimension of XX */ +); + +/* Function to solve linear equation Ax = b, where A is an MxM symmetric matrix */ +void silk_solve_LDL_FLP( + silk_float *A, /* I/O Symmetric square matrix, out: reg. */ + const opus_int M, /* I Size of matrix */ + const silk_float *b, /* I Pointer to b vector */ + silk_float *x /* O Pointer to x solution vector */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void silk_apply_sine_window_FLP( + silk_float px_win[], /* O Pointer to windowed signal */ + const silk_float px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Wrapper functions. Call flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void silk_A2NLSF_FLP( + opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */ + const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +); + +/* Convert NLSF parameters to AR prediction filter coefficients */ +void silk_NLSF2A_FLP( + silk_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +); + +/* Limit, stabilize, and quantize NLSFs */ +void silk_process_NLSFs_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +/* Floating-point Silk NSQ wrapper */ +void silk_NSQ_wrapper_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SideInfoIndices *psIndices, /* I/O Quantization indices */ + silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const silk_float x[] /* I Prefiltered input signal */ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/media/libopus/silk/float/noise_shape_analysis_FLP.c b/media/libopus/silk/float/noise_shape_analysis_FLP.c new file mode 100644 index 000000000000..d1f1a69cc571 --- /dev/null +++ b/media/libopus/silk/float/noise_shape_analysis_FLP.c @@ -0,0 +1,363 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */ +/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */ +static inline silk_float warped_gain( + const silk_float *coefs, + silk_float lambda, + opus_int order +) { + opus_int i; + silk_float gain; + + lambda = -lambda; + gain = coefs[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain = lambda * gain + coefs[ i ]; + } + return (silk_float)( 1.0f / ( 1.0f - lambda * gain ) ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +static inline void warped_true2monic_coefs( + silk_float *coefs_syn, + silk_float *coefs_ana, + silk_float lambda, + silk_float limit, + opus_int order +) { + opus_int i, iter, ind = 0; + silk_float tmp, maxabs, chirp, gain_syn, gain_ana; + + /* Convert to monic coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ]; + } + gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] ); + gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; + } + + /* Limit */ + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs = -1.0f; + for( i = 0; i < order; i++ ) { + tmp = silk_max( silk_abs_float( coefs_syn[ i ] ), silk_abs_float( coefs_ana[ i ] ) ); + if( tmp > maxabs ) { + maxabs = tmp; + ind = i; + } + } + if( maxabs <= limit ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs_syn[ i - 1 ] += lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] += lambda * coefs_ana[ i ]; + } + gain_syn = 1.0f / gain_syn; + gain_ana = 1.0f / gain_ana; + for( i = 0; i < order; i++ ) { + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; + } + + /* Apply bandwidth expansion */ + chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) ); + silk_bwexpander_FLP( coefs_syn, order, chirp ); + silk_bwexpander_FLP( coefs_ana, order, chirp ); + + /* Convert to monic warped coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ]; + } + gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] ); + gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; + } + } + silk_assert( 0 ); +} + +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float *pitch_res, /* I LPC residual from pitch analysis */ + const silk_float *x /* I Input signal [frame_length + la_shape] */ +) +{ + silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + opus_int k, nSamples; + silk_float SNR_adj_dB, HarmBoost, HarmShapeGain, Tilt; + silk_float nrg, pre_nrg, log_energy, log_energy_prev, energy_variation; + silk_float delta, BWExp1, BWExp2, gain_mult, gain_add, strength, b, warping; + silk_float x_windowed[ SHAPE_LPC_WIN_MAX ]; + silk_float auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + const silk_float *x_ptr, *pitch_res_ptr; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB = psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ); + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality = 0.5f * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] + psEnc->sCmn.input_quality_bands_Q15[ 1 ] ) * ( 1.0f / 32768.0f ); + + /* Coding quality level, between 0.0 and 1.0 */ + psEncCtrl->coding_quality = silk_sigmoid( 0.25f * ( SNR_adj_dB - 20.0f ) ); + + if( psEnc->sCmn.useCBR == 0 ) { + /* Reduce coding SNR during low speech activity */ + b = 1.0f - psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + SNR_adj_dB -= BG_SNR_DECR_dB * psEncCtrl->coding_quality * ( 0.5f + 0.5f * psEncCtrl->input_quality ) * b * b; + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB += HARM_SNR_INCR_dB * psEnc->LTPCorr; + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB += ( -0.4f * psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) + 6.0f ) * ( 1.0f - psEncCtrl->input_quality ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initally set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + psEncCtrl->sparseness = 0.0f; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = 2 * psEnc->sCmn.fs_kHz; + energy_variation = 0.0f; + log_energy_prev = 0.0f; + pitch_res_ptr = pitch_res; + for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) { + nrg = ( silk_float )nSamples + ( silk_float )silk_energy_FLP( pitch_res_ptr, nSamples ); + log_energy = silk_log2( nrg ); + if( k > 0 ) { + energy_variation += silk_abs_float( log_energy - log_energy_prev ); + } + log_energy_prev = log_energy; + pitch_res_ptr += nSamples; + } + psEncCtrl->sparseness = silk_sigmoid( 0.4f * ( energy_variation - 5.0f ) ); + + /* Set quantization offset depending on sparseness measure */ + if( psEncCtrl->sparseness > SPARSENESS_THRESHOLD_QNT_OFFSET ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB += SPARSE_SNR_INCR_dB * ( psEncCtrl->sparseness - 0.5f ); + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength = FIND_PITCH_WHITE_NOISE_FRACTION * psEncCtrl->predGain; /* between 0.0 and 1.0 */ + BWExp1 = BWExp2 = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength ); + delta = LOW_RATE_BANDWIDTH_EXPANSION_DELTA * ( 1.0f - 0.75f * psEncCtrl->coding_quality ); + BWExp1 -= delta; + BWExp2 += delta; + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1 /= BWExp2; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping = (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f + 0.01f * psEncCtrl->coding_quality; + } else { + warping = 0.0f; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = ( psEnc->sCmn.shapeWinLength - flat_part ) / 2; + + silk_apply_sine_window_FLP( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(silk_float) ); + shift += flat_part; + silk_apply_sine_window_FLP( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FLP( auto_corr, x_windowed, warping, + psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Calculate regular auto correlation */ + silk_autocorrelation_FLP( auto_corr, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION; + + /* Convert correlations to prediction coefficients, and compute residual energy */ + nrg = silk_levinsondurbin_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], auto_corr, psEnc->sCmn.shapingLPCOrder ); + psEncCtrl->Gains[ k ] = ( silk_float )sqrt( nrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], warping, psEnc->sCmn.shapingLPCOrder ); + } + + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp2 ); + + /* Compute noise shaping filter coefficients */ + silk_memcpy( + &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], + &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], + psEnc->sCmn.shapingLPCOrder * sizeof( silk_float ) ); + + /* Bandwidth expansion for analysis filter shaping */ + silk_bwexpander_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp1 ); + + /* Ratio of prediction gains, in energy domain */ + pre_nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder ); + nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder ); + psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ); + + /* Convert to monic warped prediction coefficients and limit absolute values */ + warped_true2monic_coefs( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], + warping, 3.999f, psEnc->sCmn.shapingLPCOrder ); + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity */ + gain_mult = (silk_float)pow( 2.0f, -0.16f * SNR_adj_dB ); + gain_add = (silk_float)pow( 2.0f, 0.16f * MIN_QGAIN_DB ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] *= gain_mult; + psEncCtrl->Gains[ k ] += gain_add; + } + + gain_mult = 1.0f + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT; + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->GainsPre[ k ] *= gain_mult; + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength = LOW_FREQ_SHAPING * ( 1.0f + LOW_QUALITY_LOW_FREQ_SHAPING_DECR * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] * ( 1.0f / 32768.0f ) - 1.0f ) ); + strength *= psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b = 0.2f / psEnc->sCmn.fs_kHz + 3.0f / psEncCtrl->pitchL[ k ]; + psEncCtrl->LF_MA_shp[ k ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ k ] = 1.0f - b - b * strength; + } + Tilt = - HP_NOISE_COEF - + (1 - HP_NOISE_COEF) * HARM_HP_NOISE_COEF * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + } else { + b = 1.3f / psEnc->sCmn.fs_kHz; + psEncCtrl->LF_MA_shp[ 0 ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ 0 ] = 1.0f - b - b * strength * 0.6f; + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_MA_shp[ k ] = psEncCtrl->LF_MA_shp[ 0 ]; + psEncCtrl->LF_AR_shp[ k ] = psEncCtrl->LF_AR_shp[ 0 ]; + } + Tilt = -HP_NOISE_COEF; + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost = LOW_RATE_HARMONIC_BOOST * ( 1.0f - psEncCtrl->coding_quality ) * psEnc->LTPCorr; + + /* More harmonic boost for noisy input signals */ + HarmBoost += LOW_INPUT_QUALITY_HARMONIC_BOOST * ( 1.0f - psEncCtrl->input_quality ); + + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Harmonic noise shaping */ + HarmShapeGain = HARMONIC_SHAPING; + + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain += HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING * + ( 1.0f - ( 1.0f - psEncCtrl->coding_quality ) * psEncCtrl->input_quality ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain *= ( silk_float )sqrt( psEnc->LTPCorr ); + } else { + HarmShapeGain = 0.0f; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psShapeSt->HarmBoost_smth += SUBFR_SMTH_COEF * ( HarmBoost - psShapeSt->HarmBoost_smth ); + psEncCtrl->HarmBoost[ k ] = psShapeSt->HarmBoost_smth; + psShapeSt->HarmShapeGain_smth += SUBFR_SMTH_COEF * ( HarmShapeGain - psShapeSt->HarmShapeGain_smth ); + psEncCtrl->HarmShapeGain[ k ] = psShapeSt->HarmShapeGain_smth; + psShapeSt->Tilt_smth += SUBFR_SMTH_COEF * ( Tilt - psShapeSt->Tilt_smth ); + psEncCtrl->Tilt[ k ] = psShapeSt->Tilt_smth; + } +} diff --git a/media/libopus/silk/float/pitch_analysis_core_FLP.c b/media/libopus/silk/float/pitch_analysis_core_FLP.c new file mode 100644 index 000000000000..5546d09bb3b9 --- /dev/null +++ b/media/libopus/silk/float/pitch_analysis_core_FLP.c @@ -0,0 +1,630 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/***************************************************************************** +* Pitch analyser function +******************************************************************************/ +#include "SigProc_FLP.h" +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" + +#define SCRATCH_SIZE 22 +#define eps 1.192092896e-07f + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +static void silk_P_Ana_calc_energy_st3( + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +/************************************************************/ +/* CORE PITCH ANALYSIS FUNCTION */ +/************************************************************/ +opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */ + const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr /* I Number of 5 ms subframes */ +) +{ + opus_int i, k, d, j; + silk_float frame_8kHz[ PE_MAX_FRAME_LENGTH_MS * 8 ]; + silk_float frame_4kHz[ PE_MAX_FRAME_LENGTH_MS * 4 ]; + opus_int16 frame_8_FIX[ PE_MAX_FRAME_LENGTH_MS * 8 ]; + opus_int16 frame_4_FIX[ PE_MAX_FRAME_LENGTH_MS * 4 ]; + opus_int32 filt_state[ 6 ]; + silk_float threshold, contour_bias; + silk_float C[ PE_MAX_NB_SUBFR][ (PE_MAX_LAG >> 1) + 5 ]; + silk_float CC[ PE_NB_CBKS_STAGE2_EXT ]; + const silk_float *target_ptr, *basis_ptr; + double cross_corr, normalizer, energy, energy_tmp; + opus_int d_srch[ PE_D_SRCH_LENGTH ]; + opus_int16 d_comp[ (PE_MAX_LAG >> 1) + 5 ]; + opus_int length_d_srch, length_d_comp; + silk_float Cmax, CCmax, CCmax_b, CCmax_new_b, CCmax_new; + opus_int CBimax, CBimax_new, lag, start_lag, end_lag, lag_new; + opus_int cbk_size; + silk_float lag_log2, prevLag_log2, delta_lag_log2_sqr; + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + opus_int lag_counter; + opus_int frame_length, frame_length_8kHz, frame_length_4kHz; + opus_int sf_length, sf_length_8kHz, sf_length_4kHz; + opus_int min_lag, min_lag_8kHz, min_lag_4kHz; + opus_int max_lag, max_lag_8kHz, max_lag_4kHz; + opus_int nb_cbk_search; + const opus_int8 *Lag_CB_ptr; + + /* Check for valid sampling frequency */ + silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1 >= 0.0f && search_thres1 <= 1.0f ); + silk_assert( search_thres2 >= 0.0f && search_thres2 <= 1.0f ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + sf_length_4kHz = PE_SUBFR_LENGTH_MS * 4; + sf_length_8kHz = PE_SUBFR_LENGTH_MS * 8; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + min_lag_4kHz = PE_MIN_LAG_MS * 4; + min_lag_8kHz = PE_MIN_LAG_MS * 8; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + max_lag_4kHz = PE_MAX_LAG_MS * 4; + max_lag_8kHz = PE_MAX_LAG_MS * 8 - 1; + + silk_memset(C, 0, sizeof(silk_float) * nb_subfr * ((PE_MAX_LAG >> 1) + 5)); + + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + /* Resample to 16 -> 8 khz */ + opus_int16 frame_16_FIX[ 16 * PE_MAX_FRAME_LENGTH_MS ]; + silk_float2short_array( frame_16_FIX, frame, frame_length ); + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8_FIX, frame_16_FIX, frame_length ); + silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz ); + } else if( Fs_kHz == 12 ) { + /* Resample to 12 -> 8 khz */ + opus_int16 frame_12_FIX[ 12 * PE_MAX_FRAME_LENGTH_MS ]; + silk_float2short_array( frame_12_FIX, frame, frame_length ); + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8_FIX, frame_12_FIX, frame_length ); + silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz ); + } else { + silk_assert( Fs_kHz == 8 ); + silk_float2short_array( frame_8_FIX, frame, frame_length_8kHz ); + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_4_FIX, frame_8_FIX, frame_length_8kHz ); + silk_short2float_array( frame_4kHz, frame_4_FIX, frame_length_4kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] += frame_4kHz[ i - 1 ]; + } + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + silk_assert( target_ptr >= frame_4kHz ); + silk_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - min_lag_4kHz; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + /* Calculate first vector products before loop */ + cross_corr = silk_inner_product_FLP( target_ptr, basis_ptr, sf_length_8kHz ); + normalizer = silk_energy_FLP( basis_ptr, sf_length_8kHz ) + sf_length_8kHz * 4000.0f; + + C[ 0 ][ min_lag_4kHz ] += (silk_float)(cross_corr / sqrt(normalizer)); + + /* From now on normalizer is computed recursively */ + for(d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++) { + basis_ptr--; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + cross_corr = silk_inner_product_FLP(target_ptr, basis_ptr, sf_length_8kHz); + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer += + basis_ptr[ 0 ] * (double)basis_ptr[ 0 ] - + basis_ptr[ sf_length_8kHz ] * (double)basis_ptr[ sf_length_8kHz ]; + C[ 0 ][ d ] += (silk_float)(cross_corr / sqrt( normalizer )); + } + /* Update target pointer */ + target_ptr += sf_length_8kHz; + } + + /* Apply short-lag bias */ + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + C[ 0 ][ i ] -= C[ 0 ][ i ] * i / 4096.0f; + } + + /* Sort */ + length_d_srch = 4 + 2 * complexity; + silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_insertion_sort_decreasing_FLP( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch ); + + /* Escape if correlation is very low already here */ + Cmax = C[ 0 ][ min_lag_4kHz ]; + target_ptr = &frame_4kHz[ silk_SMULBB( sf_length_4kHz, nb_subfr ) ]; + energy = 1000.0f; + for( i = 0; i < silk_LSHIFT( sf_length_4kHz, 2 ); i++ ) { + energy += target_ptr[i] * (double)target_ptr[i]; + } + threshold = Cmax * Cmax; + if( energy / 16.0f > threshold ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + threshold = search_thres1 * Cmax; + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) { + d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 ); + } else { + length_d_srch = i; + break; + } + } + silk_assert( length_d_srch > 0 ); + + for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) { + d_comp[ i ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] ] = 1; + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ]; + } + + length_d_srch = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) { + if( d_comp[ i + 1 ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ]; + } + + length_d_comp = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) { + if( d_comp[ i ] > 0 ) { + d_comp[ length_d_comp ] = (opus_int16)( i - 2 ); + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, PE_MAX_NB_SUBFR*((PE_MAX_LAG >> 1) + 5) * sizeof(silk_float)); + + if( Fs_kHz == 8 ) { + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * 8 ]; + } else { + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + } + for( k = 0; k < nb_subfr; k++ ) { + energy_tmp = silk_energy_FLP( target_ptr, sf_length_8kHz ); + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + cross_corr = silk_inner_product_FLP( basis_ptr, target_ptr, sf_length_8kHz ); + energy = silk_energy_FLP( basis_ptr, sf_length_8kHz ); + if( cross_corr > 0.0f ) { + C[ k ][ d ] = (silk_float)(cross_corr * cross_corr / (energy * energy_tmp + eps)); + } else { + C[ k ][ d ] = 0.0f; + } + } + target_ptr += sf_length_8kHz; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = 0.0f; /* This value doesn't matter */ + CCmax_b = -1000.0f; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = silk_LSHIFT( prevLag, 1 ) / 3; + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2 = silk_log2((silk_float)prevLag); + } else { + prevLag_log2 = 0; + } + + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbk_search; j++ ) { + CC[j] = 0.0f; + for( i = 0; i < nb_subfr; i++ ) { + /* Try all codebooks */ + CC[ j ] += C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )]; + } + } + /* Find best codebook */ + CCmax_new = -1000.0f; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + CCmax_new = silk_max_float(CCmax_new, 0.0f); /* To avoid taking square root of negative number later */ + CCmax_new_b = CCmax_new; + + /* Bias towards shorter lags */ + lag_log2 = silk_log2((silk_float)d); + CCmax_new_b -= PE_SHORTLAG_BIAS * nb_subfr * lag_log2; + + /* Bias towards previous lag */ + if( prevLag > 0 ) { + delta_lag_log2_sqr = lag_log2 - prevLag_log2; + delta_lag_log2_sqr *= delta_lag_log2_sqr; + CCmax_new_b -= PE_PREVLAG_BIAS * nb_subfr * (*LTPCorr) * delta_lag_log2_sqr / (delta_lag_log2_sqr + 0.5f); + } + + if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > nb_subfr * search_thres2 * search_thres2 && /* Correlation needs to be high enough to be voiced */ + silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= min_lag_8kHz /* Lag must be in range */ + ) { + CCmax_b = CCmax_new_b; + CCmax = CCmax_new; + lag = d; + CBimax = CBimax_new; + } + } + + if( lag == -1 ) { + /* No suitable candidate found */ + silk_memset( pitch_out, 0, PE_MAX_NB_SUBFR * sizeof(opus_int) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + if( Fs_kHz > 8 ) { + /* Search in original signal */ + + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT_ROUND( silk_SMULBB( lag, 3 ), 1 ); + } else { /* Fs_kHz == 16 */ + lag = silk_LSHIFT( lag, 1 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + silk_assert( CCmax >= 0.0f ); + *LTPCorr = (silk_float)sqrt( CCmax / nb_subfr ); /* Output normalized correlation */ + + CCmax = -1000.0f; + + /* Calculate the correlations and energies needed in stage 3 */ + silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity ); + silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias = PE_FLATCONTOUR_BIAS / lag; + + /* Set up cbk parameters acording to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + + for( d = start_lag; d <= end_lag; d++ ) { + for( j = 0; j < nb_cbk_search; j++ ) { + cross_corr = 0.0; + energy = eps; + for( k = 0; k < nb_subfr; k++ ) { + energy += energies_st3[ k ][ j ][ lag_counter ]; + cross_corr += cross_corr_st3[ k ][ j ][ lag_counter ]; + } + if( cross_corr > 0.0 ) { + CCmax_new = (silk_float)(cross_corr * cross_corr / energy); + /* Reduce depending on flatness of contour */ + CCmax_new *= 1.0f - contour_bias * j; + } else { + CCmax_new = 0.0f; + } + + if( CCmax_new > CCmax && + ( d + (opus_int)silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag + ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag ); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags and correlation */ + silk_assert( CCmax >= 0.0f ); + *LTPCorr = (silk_float)sqrt( CCmax / nb_subfr ); /* Output normalized correlation */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag - min_lag_8kHz ); + *contourIndex = (opus_int8)CBimax; + } + silk_assert( *lagIndex >= 0 ); + /* return as voiced */ + return 0; +} + +static void silk_P_Ana_calc_corr_st3( + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) + /*********************************************************************** + Calculates the correlations used in stage 3 search. In order to cover + the whole lag codebook for all the searched offset lags (lag +- 2), + the following correlations are needed in each sub frame: + + sf1: lag range [-8,...,7] total 16 correlations + sf2: lag range [-4,...,4] total 9 correlations + sf3: lag range [-3,....4] total 8 correltions + sf4: lag range [-6,....8] total 15 correlations + + In total 48 correlations. The direct implementation computed in worst case + 4*12*5 = 240 correlations, but more likely around 120. + **********************************************************************/ +{ + const silk_float *target_ptr, *basis_ptr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + silk_float scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + for( j = lag_low; j <= lag_high; j++ ) { + basis_ptr = target_ptr - ( start_lag + j ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = (silk_float)silk_inner_product_FLP( target_ptr, basis_ptr, sf_length ); + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } +} + +static void silk_P_Ana_calc_energy_st3( + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) +/**************************************************************** +Calculate the energies for first two subframes. The energies are +calculated recursively. +****************************************************************/ +{ + const silk_float *target_ptr, *basis_ptr; + double energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + silk_float scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_energy_FLP( basis_ptr, sf_length ) + 1e-3; + silk_assert( energy >= 0.0 ); + scratch_mem[lag_counter] = (silk_float)energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= basis_ptr[sf_length - i] * (double)basis_ptr[sf_length - i]; + silk_assert( energy >= 0.0 ); + + /* add part that comes into window */ + energy += basis_ptr[ -i ] * (double)basis_ptr[ -i ]; + silk_assert( energy >= 0.0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[lag_counter] = (silk_float)energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + silk_assert( energies_st3[ k ][ i ][ j ] >= 0.0f ); + } + } + target_ptr += sf_length; + } +} diff --git a/media/libopus/silk/float/prefilter_FLP.c b/media/libopus/silk/float/prefilter_FLP.c new file mode 100644 index 000000000000..79ebf65f08c1 --- /dev/null +++ b/media/libopus/silk/float/prefilter_FLP.c @@ -0,0 +1,206 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* +* Prefilter for finding Quantizer input signal +*/ +static inline void silk_prefilt_FLP( + silk_prefilter_state_FLP *P, /* I/O state */ + silk_float st_res[], /* I */ + silk_float xw[], /* O */ + silk_float *HarmShapeFIR, /* I */ + silk_float Tilt, /* I */ + silk_float LF_MA_shp, /* I */ + silk_float LF_AR_shp, /* I */ + opus_int lag, /* I */ + opus_int length /* I */ +); + +void silk_warped_LPC_analysis_filter_FLP( + silk_float state[], /* I/O State [order + 1] */ + silk_float res[], /* O Residual signal [length] */ + const silk_float coef[], /* I Coefficients [order] */ + const silk_float input[], /* I Input signal [length] */ + const silk_float lambda, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order /* I Filter order (even) */ +) +{ + opus_int n, i; + silk_float acc, tmp1, tmp2; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = state[ 0 ] + lambda * state[ 1 ]; + state[ 0 ] = input[ n ]; + /* Output of allpass section */ + tmp1 = state[ 1 ] + lambda * ( state[ 2 ] - tmp2 ); + state[ 1 ] = tmp2; + acc = coef[ 0 ] * tmp2; + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = state[ i ] + lambda * ( state[ i + 1 ] - tmp1 ); + state[ i ] = tmp1; + acc += coef[ i - 1 ] * tmp1; + /* Output of allpass section */ + tmp1 = state[ i + 1 ] + lambda * ( state[ i + 2 ] - tmp2 ); + state[ i + 1 ] = tmp2; + acc += coef[ i ] * tmp2; + } + state[ order ] = tmp1; + acc += coef[ order - 1 ] * tmp1; + res[ n ] = input[ n ] - acc; + } +} + +/* +* silk_prefilter. Main prefilter function +*/ +void silk_prefilter_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + const silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */ + silk_float xw[], /* O Weighted signal */ + const silk_float x[] /* I Speech signal */ +) +{ + silk_prefilter_state_FLP *P = &psEnc->sPrefilt; + opus_int j, k, lag; + silk_float HarmShapeGain, Tilt, LF_MA_shp, LF_AR_shp; + silk_float B[ 2 ]; + const silk_float *AR1_shp; + const silk_float *px; + silk_float *pxw; + silk_float HarmShapeFIR[ 3 ]; + silk_float st_res[ MAX_SUB_FRAME_LENGTH + MAX_LPC_ORDER ]; + + /* Set up pointers */ + px = x; + pxw = xw; + lag = P->lagPrev; + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Update Variables that change per sub frame */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + lag = psEncCtrl->pitchL[ k ]; + } + + /* Noise shape parameters */ + HarmShapeGain = psEncCtrl->HarmShapeGain[ k ] * ( 1.0f - psEncCtrl->HarmBoost[ k ] ); + HarmShapeFIR[ 0 ] = 0.25f * HarmShapeGain; + HarmShapeFIR[ 1 ] = 32767.0f / 65536.0f * HarmShapeGain; + HarmShapeFIR[ 2 ] = 0.25f * HarmShapeGain; + Tilt = psEncCtrl->Tilt[ k ]; + LF_MA_shp = psEncCtrl->LF_MA_shp[ k ]; + LF_AR_shp = psEncCtrl->LF_AR_shp[ k ]; + AR1_shp = &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Short term FIR filtering */ + silk_warped_LPC_analysis_filter_FLP( P->sAR_shp, st_res, AR1_shp, px, + (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder ); + + /* Reduce (mainly) low frequencies during harmonic emphasis */ + B[ 0 ] = psEncCtrl->GainsPre[ k ]; + B[ 1 ] = -psEncCtrl->GainsPre[ k ] * + ( psEncCtrl->HarmBoost[ k ] * HarmShapeGain + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT ); + pxw[ 0 ] = B[ 0 ] * st_res[ 0 ] + B[ 1 ] * P->sHarmHP; + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + pxw[ j ] = B[ 0 ] * st_res[ j ] + B[ 1 ] * st_res[ j - 1 ]; + } + P->sHarmHP = st_res[ psEnc->sCmn.subfr_length - 1 ]; + + silk_prefilt_FLP( P, pxw, pxw, HarmShapeFIR, Tilt, LF_MA_shp, LF_AR_shp, lag, psEnc->sCmn.subfr_length ); + + px += psEnc->sCmn.subfr_length; + pxw += psEnc->sCmn.subfr_length; + } + P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ]; +} + +/* +* Prefilter for finding Quantizer input signal +*/ +static inline void silk_prefilt_FLP( + silk_prefilter_state_FLP *P, /* I/O state */ + silk_float st_res[], /* I */ + silk_float xw[], /* O */ + silk_float *HarmShapeFIR, /* I */ + silk_float Tilt, /* I */ + silk_float LF_MA_shp, /* I */ + silk_float LF_AR_shp, /* I */ + opus_int lag, /* I */ + opus_int length /* I */ +) +{ + opus_int i; + opus_int idx, LTP_shp_buf_idx; + silk_float n_Tilt, n_LF, n_LTP; + silk_float sLF_AR_shp, sLF_MA_shp; + silk_float *LTP_shp_buf; + + /* To speed up use temp variables instead of using the struct */ + LTP_shp_buf = P->sLTP_shp; + LTP_shp_buf_idx = P->sLTP_shp_buf_idx; + sLF_AR_shp = P->sLF_AR_shp; + sLF_MA_shp = P->sLF_MA_shp; + + for( i = 0; i < length; i++ ) { + if( lag > 0 ) { + silk_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP = LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ] * HarmShapeFIR[ 0 ]; + n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ] * HarmShapeFIR[ 1 ]; + n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ] * HarmShapeFIR[ 2 ]; + } else { + n_LTP = 0; + } + + n_Tilt = sLF_AR_shp * Tilt; + n_LF = sLF_AR_shp * LF_AR_shp + sLF_MA_shp * LF_MA_shp; + + sLF_AR_shp = st_res[ i ] - n_Tilt; + sLF_MA_shp = sLF_AR_shp - n_LF; + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = sLF_MA_shp; + + xw[ i ] = sLF_MA_shp - n_LTP; + } + /* Copy temp variable back to state */ + P->sLF_AR_shp = sLF_AR_shp; + P->sLF_MA_shp = sLF_MA_shp; + P->sLTP_shp_buf_idx = LTP_shp_buf_idx; +} diff --git a/media/libopus/silk/float/process_gains_FLP.c b/media/libopus/silk/float/process_gains_FLP.c new file mode 100644 index 000000000000..edac122e3bee --- /dev/null +++ b/media/libopus/silk/float/process_gains_FLP.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; + silk_float s, InvMaxSqrVal, gain, quant_offset; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + s = 1.0f - 0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] *= s; + } + } + + /* Limit the quantized signal */ + InvMaxSqrVal = ( silk_float )( pow( 2.0f, 0.33f * ( 21.0f - psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) ) ) / psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + gain = psEncCtrl->Gains[ k ]; + gain = ( silk_float )sqrt( gain * gain + psEncCtrl->ResNrg[ k ] * InvMaxSqrVal ); + psEncCtrl->Gains[ k ] = silk_min_float( gain, 32767.0f ); + } + + /* Prepare gains for noise shaping quantization */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + pGains_Q16[ k ] = (opus_int32)( psEncCtrl->Gains[ k ] * 65536.0f ); + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, pGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] = pGains_Q16[ k ] / 65536.0f; + } + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain + psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ) > 1.0f ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ] / 1024.0f; + psEncCtrl->Lambda = LAMBDA_OFFSET + + LAMBDA_DELAYED_DECISIONS * psEnc->sCmn.nStatesDelayedDecision + + LAMBDA_SPEECH_ACT * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ) + + LAMBDA_INPUT_QUALITY * psEncCtrl->input_quality + + LAMBDA_CODING_QUALITY * psEncCtrl->coding_quality + + LAMBDA_QUANT_OFFSET * quant_offset; + + silk_assert( psEncCtrl->Lambda > 0.0f ); + silk_assert( psEncCtrl->Lambda < 2.0f ); +} diff --git a/media/libopus/silk/float/regularize_correlations_FLP.c b/media/libopus/silk/float/regularize_correlations_FLP.c new file mode 100644 index 000000000000..7944780929b0 --- /dev/null +++ b/media/libopus/silk/float/regularize_correlations_FLP.c @@ -0,0 +1,48 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FLP( + silk_float *XX, /* I/O Correlation matrices */ + silk_float *xx, /* I/O Correlation values */ + const silk_float noise, /* I Noise energy to add */ + const opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) += noise; + } + xx[ 0 ] += noise; +} diff --git a/media/libopus/silk/float/residual_energy_FLP.c b/media/libopus/silk/float/residual_energy_FLP.c new file mode 100644 index 000000000000..03604bd16306 --- /dev/null +++ b/media/libopus/silk/float/residual_energy_FLP.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +#define MAX_ITERATIONS_RESIDUAL_NRG 10 +#define REGULARIZATION_FACTOR 1e-8f + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const silk_float *c, /* I Filter coefficients */ + silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const silk_float *wXx, /* I Weighted correlation vector */ + const silk_float wxx, /* I Weighted correlation value */ + const opus_int D /* I Dimension */ +) +{ + opus_int i, j, k; + silk_float tmp, nrg = 0.0f, regularization; + + /* Safety checks */ + silk_assert( D >= 0 ); + + regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] ); + for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) { + nrg = wxx; + + tmp = 0.0f; + for( i = 0; i < D; i++ ) { + tmp += wXx[ i ] * c[ i ]; + } + nrg -= 2.0f * tmp; + + /* compute c' * wXX * c, assuming wXX is symmetric */ + for( i = 0; i < D; i++ ) { + tmp = 0.0f; + for( j = i + 1; j < D; j++ ) { + tmp += matrix_c_ptr( wXX, i, j, D ) * c[ j ]; + } + nrg += c[ i ] * ( 2.0f * tmp + matrix_c_ptr( wXX, i, i, D ) * c[ i ] ); + } + if( nrg > 0 ) { + break; + } else { + /* Add white noise */ + for( i = 0; i < D; i++ ) { + matrix_c_ptr( wXX, i, i, D ) += regularization; + } + /* Increase noise for next run */ + regularization *= 2.0f; + } + } + if( k == MAX_ITERATIONS_RESIDUAL_NRG ) { + silk_assert( nrg == 0 ); + nrg = 1.0f; + } + + return nrg; +} + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceeding samples */ +void silk_residual_energy_FLP( + silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + const silk_float x[], /* I Input signal */ + silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const silk_float gains[], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int shift; + silk_float *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + + LPC_res_ptr = LPC_res + LPC_order; + shift = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + silk_LPC_analysis_filter_FLP( LPC_res, a[ 0 ], x + 0 * shift, 2 * shift, LPC_order ); + nrgs[ 0 ] = ( silk_float )( gains[ 0 ] * gains[ 0 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 1 ] = ( silk_float )( gains[ 1 ] * gains[ 1 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + + if( nb_subfr == MAX_NB_SUBFR ) { + silk_LPC_analysis_filter_FLP( LPC_res, a[ 1 ], x + 2 * shift, 2 * shift, LPC_order ); + nrgs[ 2 ] = ( silk_float )( gains[ 2 ] * gains[ 2 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 3 ] = ( silk_float )( gains[ 3 ] * gains[ 3 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + } +} diff --git a/media/libopus/silk/float/scale_copy_vector_FLP.c b/media/libopus/silk/float/scale_copy_vector_FLP.c new file mode 100644 index 000000000000..efc922fc810e --- /dev/null +++ b/media/libopus/silk/float/scale_copy_vector_FLP.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* copy and multiply a vector by a constant */ +void silk_scale_copy_vector_FLP( + silk_float *data_out, + const silk_float *data_in, + silk_float gain, + opus_int dataSize +) +{ + opus_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data_out[ i + 0 ] = gain * data_in[ i + 0 ]; + data_out[ i + 1 ] = gain * data_in[ i + 1 ]; + data_out[ i + 2 ] = gain * data_in[ i + 2 ]; + data_out[ i + 3 ] = gain * data_in[ i + 3 ]; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data_out[ i ] = gain * data_in[ i ]; + } +} diff --git a/media/libopus/silk/float/scale_vector_FLP.c b/media/libopus/silk/float/scale_vector_FLP.c new file mode 100644 index 000000000000..09feeacf316f --- /dev/null +++ b/media/libopus/silk/float/scale_vector_FLP.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* multiply a vector by a constant */ +void silk_scale_vector_FLP( + silk_float *data1, + silk_float gain, + opus_int dataSize +) +{ + opus_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data1[ i + 0 ] *= gain; + data1[ i + 1 ] *= gain; + data1[ i + 2 ] *= gain; + data1[ i + 3 ] *= gain; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data1[ i ] *= gain; + } +} diff --git a/media/libopus/silk/float/schur_FLP.c b/media/libopus/silk/float/schur_FLP.c new file mode 100644 index 000000000000..205f8d4d3596 --- /dev/null +++ b/media/libopus/silk/float/schur_FLP.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +silk_float silk_schur_FLP( /* O returns residual energy */ + silk_float refl_coef[], /* O reflection coefficients (length order) */ + const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ + opus_int order /* I order */ +) +{ + opus_int k, n; + silk_float C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + silk_float Ctmp1, Ctmp2, rc_tmp; + + silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 ); + + /* Copy correlations */ + for( k = 0; k < order+1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = auto_corr[ k ]; + } + + for( k = 0; k < order; k++ ) { + /* Get reflection coefficient */ + rc_tmp = -C[ k + 1 ][ 0 ] / silk_max_float( C[ 0 ][ 1 ], 1e-9f ); + + /* Save the output */ + refl_coef[ k ] = rc_tmp; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = Ctmp1 + Ctmp2 * rc_tmp; + C[ n ][ 1 ] = Ctmp2 + Ctmp1 * rc_tmp; + } + } + + /* Return residual energy */ + return C[ 0 ][ 1 ]; +} + diff --git a/media/libopus/silk/float/solve_LS_FLP.c b/media/libopus/silk/float/solve_LS_FLP.c new file mode 100644 index 000000000000..dd3775a938fb --- /dev/null +++ b/media/libopus/silk/float/solve_LS_FLP.c @@ -0,0 +1,207 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/********************************************************************** + * LDL Factorisation. Finds the upper triangular matrix L and the diagonal + * Matrix D (only the diagonal elements returned in a vector)such that + * the symmetric matric A is given by A = L*D*L'. + **********************************************************************/ +static inline void silk_LDL_FLP( + silk_float *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + silk_float *L, /* I/O Pointer to Square Upper triangular Matrix */ + silk_float *Dinv /* I/O Pointer to vector holding the inverse diagonal elements of D */ +); + +/********************************************************************** + * Function to solve linear equation Ax = b, when A is a MxM lower + * triangular matrix, with ones on the diagonal. + **********************************************************************/ +static inline void silk_SolveWithLowerTriangularWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +); + +/********************************************************************** + * Function to solve linear equation (A^T)x = b, when A is a MxM lower + * triangular, with ones on the diagonal. (ie then A^T is upper triangular) + **********************************************************************/ +static inline void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +); + +/********************************************************************** + * Function to solve linear equation Ax = b, when A is a MxM + * symmetric square matrix - using LDL factorisation + **********************************************************************/ +void silk_solve_LDL_FLP( + silk_float *A, /* I/O Symmetric square matrix, out: reg. */ + const opus_int M, /* I Size of matrix */ + const silk_float *b, /* I Pointer to b vector */ + silk_float *x /* O Pointer to x solution vector */ +) +{ + opus_int i; + silk_float L[ MAX_MATRIX_SIZE ][ MAX_MATRIX_SIZE ]; + silk_float T[ MAX_MATRIX_SIZE ]; + silk_float Dinv[ MAX_MATRIX_SIZE ]; /* inverse diagonal elements of D*/ + + silk_assert( M <= MAX_MATRIX_SIZE ); + + /*************************************************** + Factorize A by LDL such that A = L*D*(L^T), + where L is lower triangular with ones on diagonal + ****************************************************/ + silk_LDL_FLP( A, M, &L[ 0 ][ 0 ], Dinv ); + + /**************************************************** + * substitute D*(L^T) = T. ie: + L*D*(L^T)*x = b => L*T = b <=> T = inv(L)*b + ******************************************************/ + silk_SolveWithLowerTriangularWdiagOnes_FLP( &L[ 0 ][ 0 ], M, b, T ); + + /**************************************************** + D*(L^T)*x = T <=> (L^T)*x = inv(D)*T, because D is + diagonal just multiply with 1/d_i + ****************************************************/ + for( i = 0; i < M; i++ ) { + T[ i ] = T[ i ] * Dinv[ i ]; + } + /**************************************************** + x = inv(L') * inv(D) * T + *****************************************************/ + silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( &L[ 0 ][ 0 ], M, T, x ); +} + +static inline void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +) +{ + opus_int i, j; + silk_float temp; + const silk_float *ptr1; + + for( i = M - 1; i >= 0; i-- ) { + ptr1 = matrix_adr( L, 0, i, M ); + temp = 0; + for( j = M - 1; j > i ; j-- ) { + temp += ptr1[ j * M ] * x[ j ]; + } + temp = b[ i ] - temp; + x[ i ] = temp; + } +} + +static inline void silk_SolveWithLowerTriangularWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +) +{ + opus_int i, j; + silk_float temp; + const silk_float *ptr1; + + for( i = 0; i < M; i++ ) { + ptr1 = matrix_adr( L, i, 0, M ); + temp = 0; + for( j = 0; j < i; j++ ) { + temp += ptr1[ j ] * x[ j ]; + } + temp = b[ i ] - temp; + x[ i ] = temp; + } +} + +static inline void silk_LDL_FLP( + silk_float *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + silk_float *L, /* I/O Pointer to Square Upper triangular Matrix */ + silk_float *Dinv /* I/O Pointer to vector holding the inverse diagonal elements of D */ +) +{ + opus_int i, j, k, loop_count, err = 1; + silk_float *ptr1, *ptr2; + double temp, diag_min_value; + silk_float v[ MAX_MATRIX_SIZE ], D[ MAX_MATRIX_SIZE ]; /* temp arrays*/ + + silk_assert( M <= MAX_MATRIX_SIZE ); + + diag_min_value = FIND_LTP_COND_FAC * 0.5f * ( A[ 0 ] + A[ M * M - 1 ] ); + for( loop_count = 0; loop_count < M && err == 1; loop_count++ ) { + err = 0; + for( j = 0; j < M; j++ ) { + ptr1 = matrix_adr( L, j, 0, M ); + temp = matrix_ptr( A, j, j, M ); /* element in row j column j*/ + for( i = 0; i < j; i++ ) { + v[ i ] = ptr1[ i ] * D[ i ]; + temp -= ptr1[ i ] * v[ i ]; + } + if( temp < diag_min_value ) { + /* Badly conditioned matrix: add white noise and run again */ + temp = ( loop_count + 1 ) * diag_min_value - temp; + for( i = 0; i < M; i++ ) { + matrix_ptr( A, i, i, M ) += ( silk_float )temp; + } + err = 1; + break; + } + D[ j ] = ( silk_float )temp; + Dinv[ j ] = ( silk_float )( 1.0f / temp ); + matrix_ptr( L, j, j, M ) = 1.0f; + + ptr1 = matrix_adr( A, j, 0, M ); + ptr2 = matrix_adr( L, j + 1, 0, M); + for( i = j + 1; i < M; i++ ) { + temp = 0.0; + for( k = 0; k < j; k++ ) { + temp += ptr2[ k ] * v[ k ]; + } + matrix_ptr( L, i, j, M ) = ( silk_float )( ( ptr1[ i ] - temp ) * Dinv[ j ] ); + ptr2 += M; /* go to next column*/ + } + } + } + silk_assert( err == 0 ); +} + diff --git a/media/libopus/silk/float/sort_FLP.c b/media/libopus/silk/float/sort_FLP.c new file mode 100644 index 000000000000..2b0a1d1abe35 --- /dev/null +++ b/media/libopus/silk/float/sort_FLP.c @@ -0,0 +1,83 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ + +#include "typedef.h" +#include "SigProc_FLP.h" + +void silk_insertion_sort_decreasing_FLP( + silk_float *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + silk_float value; + opus_int i, j; + + /* Safety checks */ + silk_assert( K > 0 ); + silk_assert( L > 0 ); + silk_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} diff --git a/media/libopus/silk/float/structs_FLP.h b/media/libopus/silk/float/structs_FLP.h new file mode 100644 index 000000000000..b879fd17c34e --- /dev/null +++ b/media/libopus/silk/float/structs_FLP.h @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_STRUCTS_FLP_H +#define SILK_STRUCTS_FLP_H + +#include "typedef.h" +#include "main.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + silk_float HarmBoost_smth; + silk_float HarmShapeGain_smth; + silk_float Tilt_smth; +} silk_shape_state_FLP; + +/********************************/ +/* Prefilter state */ +/********************************/ +typedef struct { + silk_float sLTP_shp[ LTP_BUF_LENGTH ]; + silk_float sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int sLTP_shp_buf_idx; + silk_float sLF_AR_shp; + silk_float sLF_MA_shp; + silk_float sHarmHP; + opus_int32 rand_seed; + opus_int lagPrev; +} silk_prefilter_state_FLP; + +/********************************/ +/* Encoder state FLP */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with fixed-point code */ + silk_shape_state_FLP sShape; /* Noise shaping state */ + silk_prefilter_state_FLP sPrefilt; /* Prefilter State */ + + /* Buffer for find pitch and noise shape analysis */ + silk_float x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + silk_float LTPCorr; /* Normalized correlation from pitch lag estimator */ +} silk_encoder_state_FLP; + +/************************/ +/* Encoder control FLP */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + silk_float Gains[ MAX_NB_SUBFR ]; + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ]; /* holds interpolated and final coefficients */ + silk_float LTPCoef[LTP_ORDER * MAX_NB_SUBFR]; + silk_float LTP_scale; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + silk_float AR1[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_float AR2[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_float LF_MA_shp[ MAX_NB_SUBFR ]; + silk_float LF_AR_shp[ MAX_NB_SUBFR ]; + silk_float GainsPre[ MAX_NB_SUBFR ]; + silk_float HarmBoost[ MAX_NB_SUBFR ]; + silk_float Tilt[ MAX_NB_SUBFR ]; + silk_float HarmShapeGain[ MAX_NB_SUBFR ]; + silk_float Lambda; + silk_float input_quality; + silk_float coding_quality; + + /* Measures */ + silk_float sparseness; + silk_float predGain; + silk_float LTPredCodGain; + silk_float ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FLP; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FLP state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/media/libopus/silk/float/warped_autocorrelation_FLP.c b/media/libopus/silk/float/warped_autocorrelation_FLP.c new file mode 100644 index 000000000000..4bbfabeaa399 --- /dev/null +++ b/media/libopus/silk/float/warped_autocorrelation_FLP.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FLP( + silk_float *corr, /* O Result [order + 1] */ + const silk_float *input, /* I Input data to correlate */ + const silk_float warping, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i; + double tmp1, tmp2; + double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1 = input[ n ]; + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = state[ i ] + warping * ( state[ i + 1 ] - tmp1 ); + state[ i ] = tmp1; + C[ i ] += state[ 0 ] * tmp1; + /* Output of allpass section */ + tmp1 = state[ i + 1 ] + warping * ( state[ i + 2 ] - tmp2 ); + state[ i + 1 ] = tmp2; + C[ i + 1 ] += state[ 0 ] * tmp2; + } + state[ order ] = tmp1; + C[ order ] += state[ 0 ] * tmp1; + } + + /* Copy correlations in silk_float output format */ + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = ( silk_float )C[ i ]; + } +} diff --git a/media/libopus/silk/float/wrappers_FLP.c b/media/libopus/silk/float/wrappers_FLP.c new file mode 100644 index 000000000000..5e705b1df2e8 --- /dev/null +++ b/media/libopus/silk/float/wrappers_FLP.c @@ -0,0 +1,200 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Wrappers. Calls flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void silk_A2NLSF_FLP( + opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */ + const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int i; + opus_int32 a_fix_Q16[ MAX_LPC_ORDER ]; + + for( i = 0; i < LPC_order; i++ ) { + a_fix_Q16[ i ] = silk_float2int( pAR[ i ] * 65536.0f ); + } + + silk_A2NLSF( NLSF_Q15, a_fix_Q16, LPC_order ); +} + +/* Convert LSF parameters to AR prediction filter coefficients */ +void silk_NLSF2A_FLP( + silk_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int i; + opus_int16 a_fix_Q12[ MAX_LPC_ORDER ]; + + silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order ); + + for( i = 0; i < LPC_order; i++ ) { + pAR[ i ] = ( silk_float )a_fix_Q12[ i ] * ( 1.0f / 4096.0f ); + } +} + +/******************************************/ +/* Floating-point NLSF processing wrapper */ +/******************************************/ +void silk_process_NLSFs_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, j; + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + + silk_process_NLSFs( psEncC, PredCoef_Q12, NLSF_Q15, prev_NLSF_Q15); + + for( j = 0; j < 2; j++ ) { + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + PredCoef[ j ][ i ] = ( silk_float )PredCoef_Q12[ j ][ i ] * ( 1.0f / 4096.0f ); + } + } +} + +/****************************************/ +/* Floating-point Silk NSQ wrapper */ +/****************************************/ +void silk_NSQ_wrapper_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SideInfoIndices *psIndices, /* I/O Quantization indices */ + silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const silk_float x[] /* I Prefiltered input signal */ +) +{ + opus_int i, j; + opus_int32 x_Q3[ MAX_FRAME_LENGTH ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + + /* Noise shaping parameters */ + opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int Lambda_Q10; + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + + /* Convert control struct to fix control struct */ + /* Noise shape parameters */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + for( j = 0; j < psEnc->sCmn.shapingLPCOrder; j++ ) { + AR2_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = silk_float2int( psEncCtrl->AR2[ i * MAX_SHAPE_LPC_ORDER + j ] * 8192.0f ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + LF_shp_Q14[ i ] = silk_LSHIFT32( silk_float2int( psEncCtrl->LF_AR_shp[ i ] * 16384.0f ), 16 ) | + (opus_uint16)silk_float2int( psEncCtrl->LF_MA_shp[ i ] * 16384.0f ); + Tilt_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->Tilt[ i ] * 16384.0f ); + HarmShapeGain_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->HarmShapeGain[ i ] * 16384.0f ); + } + Lambda_Q10 = ( opus_int )silk_float2int( psEncCtrl->Lambda * 1024.0f ); + + /* prediction and coding parameters */ + for( i = 0; i < psEnc->sCmn.nb_subfr * LTP_ORDER; i++ ) { + LTPCoef_Q14[ i ] = (opus_int16)silk_float2int( psEncCtrl->LTPCoef[ i ] * 16384.0f ); + } + + for( j = 0; j < 2; j++ ) { + for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) { + PredCoef_Q12[ j ][ i ] = (opus_int16)silk_float2int( psEncCtrl->PredCoef[ j ][ i ] * 4096.0f ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + Gains_Q16[ i ] = silk_float2int( psEncCtrl->Gains[ i ] * 65536.0f ); + silk_assert( Gains_Q16[ i ] > 0 ); + } + + if( psIndices->signalType == TYPE_VOICED ) { + LTP_scale_Q14 = silk_LTPScales_table_Q14[ psIndices->LTP_scaleIndex ]; + } else { + LTP_scale_Q14 = 0; + } + + /* Convert input to fix */ + for( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + x_Q3[ i ] = silk_float2int( 8.0 * x[ i ] ); + } + + /* Call NSQ */ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14 ); + } else { + silk_NSQ( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14 ); + } +} + +/***********************************************/ +/* Floating-point Silk LTP quantiation wrapper */ +/***********************************************/ +void silk_quant_LTP_gains_FLP( + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (Un-)quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */ + opus_int8 *periodicity_index, /* O Periodicity index */ + const silk_float W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Error weights */ + const opus_int mu_Q10, /* I Mu value (R/D tradeoff) */ + const opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int i; + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ]; + opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ]; + + for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) { + B_Q14[ i ] = (opus_int16)silk_float2int( B[ i ] * 16384.0f ); + } + for( i = 0; i < nb_subfr * LTP_ORDER * LTP_ORDER; i++ ) { + W_Q18[ i ] = (opus_int32)silk_float2int( W[ i ] * 262144.0f ); + } + + silk_quant_LTP_gains( B_Q14, cbk_index, periodicity_index, W_Q18, mu_Q10, lowComplexity, nb_subfr ); + + for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) { + B[ i ] = (silk_float)B_Q14[ i ] * ( 1.0f / 16384.0f ); + } +} diff --git a/media/libopus/silk/gain_quant.c b/media/libopus/silk/gain_quant.c new file mode 100644 index 000000000000..a8fc7d22d959 --- /dev/null +++ b/media/libopus/silk/gain_quant.c @@ -0,0 +1,141 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +#define OFFSET ( ( MIN_QGAIN_DB * 128 ) / 6 + 16 * 128 ) +#define SCALE_Q16 ( ( 65536 * ( N_LEVELS_QGAIN - 1 ) ) / ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) +#define INV_SCALE_Q16 ( ( 65536 * ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) / ( N_LEVELS_QGAIN - 1 ) ) + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + /* Convert to log scale, scale, floor() */ + ind[ k ] = silk_SMULWB( SCALE_Q16, silk_lin2log( gain_Q16[ k ] ) - OFFSET ); + + /* Round towards previous quantized gain (hysteresis) */ + if( ind[ k ] < *prev_ind ) { + ind[ k ]++; + } + ind[ k ] = silk_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 ); + + /* Compute delta indices and limit */ + if( k == 0 && conditional == 0 ) { + /* Full index */ + ind[ k ] = silk_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 ); + *prev_ind = ind[ k ]; + } else { + /* Delta index */ + ind[ k ] = ind[ k ] - *prev_ind; + + /* Double the quantization step size for large gain increases, so that the max gain level can be reached */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind[ k ] > double_step_size_threshold ) { + ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 ); + } + + ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT ); + + /* Accumulate deltas */ + if( ind[ k ] > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold; + } else { + *prev_ind += ind[ k ]; + } + + /* Shift to make non-negative */ + ind[ k ] -= MIN_DELTA_GAIN_QUANT; + } + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, ind_tmp, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + if( k == 0 && conditional == 0 ) { + /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */ + *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 ); + } else { + /* Delta index */ + ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT; + + /* Accumulate deltas */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind_tmp > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold; + } else { + *prev_ind += ind_tmp; + } + } + *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 ); + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k; + opus_int32 gainsID; + + gainsID = 0; + for( k = 0; k < nb_subfr; k++ ) { + gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 ); + } + + return gainsID; +} diff --git a/media/libopus/silk/init_decoder.c b/media/libopus/silk/init_decoder.c new file mode 100644 index 000000000000..fe50a81745b1 --- /dev/null +++ b/media/libopus/silk/init_decoder.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/************************/ +/* Init Decoder State */ +/************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +) +{ + /* Clear the entire encoder state, except anything copied */ + silk_memset( psDec, 0, sizeof( silk_decoder_state ) ); + + /* Used to deactivate LSF interpolation */ + psDec->first_frame_after_reset = 1; + psDec->prev_gain_Q16 = 65536; + + /* Reset CNG state */ + silk_CNG_Reset( psDec ); + + /* Reset PLC state */ + silk_PLC_Reset( psDec ); + + return(0); +} + diff --git a/media/libopus/silk/init_encoder.c b/media/libopus/silk/init_encoder.c new file mode 100644 index 000000000000..1441a9664571 --- /dev/null +++ b/media/libopus/silk/init_encoder.c @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" + +/*********************************/ +/* Initialize Silk Encoder state */ +/*********************************/ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc /* I/O Pointer to Silk FIX encoder state */ +) +{ + opus_int ret = 0; + + /* Clear the entire encoder state */ + silk_memset( psEnc, 0, sizeof( silk_encoder_state_Fxx ) ); + + psEnc->sCmn.variable_HP_smth1_Q15 = silk_LSHIFT( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ), 8 ); + psEnc->sCmn.variable_HP_smth2_Q15 = psEnc->sCmn.variable_HP_smth1_Q15; + + /* Used to deactivate LSF interpolation, pitch prediction */ + psEnc->sCmn.first_frame_after_reset = 1; + + /* Initialize Silk VAD */ + ret += silk_VAD_Init( &psEnc->sCmn.sVAD ); + + return ret; +} diff --git a/media/libopus/silk/inner_prod_aligned.c b/media/libopus/silk/inner_prod_aligned.c new file mode 100644 index 000000000000..22e4b2bc51a2 --- /dev/null +++ b/media/libopus/silk/inner_prod_aligned.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_ADD_RSHIFT32( sum, silk_SMULBB( inVec1[ i ], inVec2[ i ] ), scale ); + } + return sum; +} diff --git a/media/libopus/silk/interpolate.c b/media/libopus/silk/interpolate.c new file mode 100644 index 000000000000..216f7c70245d --- /dev/null +++ b/media/libopus/silk/interpolate.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +) +{ + opus_int i; + + silk_assert( ifact_Q2 >= 0 ); + silk_assert( ifact_Q2 <= 4 ); + + for( i = 0; i < d; i++ ) { + xi[ i ] = (opus_int16)silk_ADD_RSHIFT( x0[ i ], silk_SMULBB( x1[ i ] - x0[ i ], ifact_Q2 ), 2 ); + } +} diff --git a/media/libopus/silk/lin2log.c b/media/libopus/silk/lin2log.c new file mode 100644 index 000000000000..0772e470bd35 --- /dev/null +++ b/media/libopus/silk/lin2log.c @@ -0,0 +1,46 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +/* Approximation of 128 * log2() (very close inverse of silk_log2lin()) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +) +{ + opus_int32 lz, frac_Q7; + + silk_CLZ_FRAC( inLin, &lz, &frac_Q7 ); + + /* Piece-wise parabolic approximation */ + return silk_LSHIFT( 31 - lz, 7 ) + silk_SMLAWB( frac_Q7, silk_MUL( frac_Q7, 128 - frac_Q7 ), 179 ); +} + diff --git a/media/libopus/silk/log2lin.c b/media/libopus/silk/log2lin.c new file mode 100644 index 000000000000..0a3d90be8f99 --- /dev/null +++ b/media/libopus/silk/log2lin.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Approximation of 2^() (very close inverse of silk_lin2log()) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +) +{ + opus_int32 out, frac_Q7; + + if( inLog_Q7 < 0 ) { + return 0; + } + + out = silk_LSHIFT( 1, silk_RSHIFT( inLog_Q7, 7 ) ); + frac_Q7 = inLog_Q7 & 0x7F; + if( inLog_Q7 < 2048 ) { + /* Piece-wise parabolic approximation */ + out = silk_ADD_RSHIFT( out, silk_MUL( out, silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 ); + } else { + /* Piece-wise parabolic approximation */ + out = silk_MLA( out, silk_RSHIFT( out, 7 ), silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ); + } + return out; +} diff --git a/media/libopus/silk/macros.h b/media/libopus/silk/macros.h new file mode 100644 index 000000000000..e6121e8b3635 --- /dev/null +++ b/media/libopus/silk/macros.h @@ -0,0 +1,136 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MACROS_H +#define SILK_MACROS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* This is an inline header file for general platform. */ + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#define silk_SMULWB(a32, b32) ((((a32) >> 16) * (opus_int32)((opus_int16)(b32))) + ((((a32) & 0x0000FFFF) * (opus_int32)((opus_int16)(b32))) >> 16)) + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#define silk_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))) + +/* (a32 * (b32 >> 16)) >> 16 */ +#define silk_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16)) + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#define silk_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16)) + +/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */ +#define silk_SMULBB(a32, b32) ((opus_int32)((opus_int16)(a32)) * (opus_int32)((opus_int16)(b32))) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */ +#define silk_SMLABB(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */ +#define silk_SMULBT(a32, b32) ((opus_int32)((opus_int16)(a32)) * ((b32) >> 16)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */ +#define silk_SMLABT(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * ((c32) >> 16)) + +/* a64 + (b32 * c32) */ +#define silk_SMLAL(a64, b32, c32) (silk_ADD64((a64), ((opus_int64)(b32) * (opus_int64)(c32)))) + +/* (a32 * b32) >> 16 */ +#define silk_SMULWW(a32, b32) silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)) + +/* a32 + ((b32 * c32) >> 16) */ +#define silk_SMLAWW(a32, b32, c32) silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)) + +/* add/subtract with output saturated */ +#define silk_ADD_SAT32(a, b) ((((a) + (b)) & 0x80000000) == 0 ? \ + ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) ) + +#define silk_SUB_SAT32(a, b) ((((a)-(b)) & 0x80000000) == 0 ? \ + (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) : \ + ((((a)^0x80000000) & (b) & 0x80000000) ? silk_int32_MAX : (a)-(b)) ) + +static inline opus_int32 silk_CLZ16(opus_int16 in16) +{ + opus_int32 out32 = 0; + if( in16 == 0 ) { + return 16; + } + /* test nibbles */ + if( in16 & 0xFF00 ) { + if( in16 & 0xF000 ) { + in16 >>= 12; + } else { + out32 += 4; + in16 >>= 8; + } + } else { + if( in16 & 0xFFF0 ) { + out32 += 8; + in16 >>= 4; + } else { + out32 += 12; + } + } + /* test bits and return */ + if( in16 & 0xC ) { + if( in16 & 0x8 ) + return out32 + 0; + else + return out32 + 1; + } else { + if( in16 & 0xE ) + return out32 + 2; + else + return out32 + 3; + } +} + +static inline opus_int32 silk_CLZ32(opus_int32 in32) +{ + /* test highest 16 bits and convert to opus_int16 */ + if( in32 & 0xFFFF0000 ) { + return silk_CLZ16((opus_int16)(in32 >> 16)); + } else { + return silk_CLZ16((opus_int16)in32) + 16; + } +} + +/* Row based */ +#define matrix_ptr(Matrix_base_adr, row, column, N) *(Matrix_base_adr + ((row)*(N)+(column))) +#define matrix_adr(Matrix_base_adr, row, column, N) (Matrix_base_adr + ((row)*(N)+(column))) + +/* Column based */ +#ifndef matrix_c_ptr +# define matrix_c_ptr(Matrix_base_adr, row, column, M) *(Matrix_base_adr + ((row)+(M)*(column))) +#endif +#define matrix_c_adr(Matrix_base_adr, row, column, M) (Matrix_base_adr + ((row)+(M)*(column))) + +#endif /* SILK_MACROS_H */ + diff --git a/media/libopus/silk/main.h b/media/libopus/silk/main.h new file mode 100644 index 000000000000..dd34c8a452eb --- /dev/null +++ b/media/libopus/silk/main.h @@ -0,0 +1,434 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MAIN_H +#define SILK_MAIN_H + +#include "SigProc_FIX.h" +#include "define.h" +#include "structs.h" +#include "tables.h" +#include "PLC.h" +#include "control.h" +#include "debug.h" +#include "entenc.h" +#include "entdec.h" + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +); + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +); + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +); + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +); + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +); + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +); + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +); + +/***************/ +/* Shell coder */ +/***************/ + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +); + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +); + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +); + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */ + opus_int mu_Q9, /* I Mu value (R/D tradeoff) */ + opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Entropy constrained matrix-weighted VQ, for a single input data vector */ +void silk_VQ_WMat_EC( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + opus_int L /* I number of vectors in codebook */ +); + +/************************************/ +/* Noise shaping quantization (NSQ) */ +/************************************/ +void silk_NSQ( + const silk_encoder_state *psEncC, /* I/O Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +/* Noise shaping using delayed decision */ +void silk_NSQ_del_dec( + const silk_encoder_state *psEncC, /* I/O Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +/************/ +/* Silk VAD */ +/************/ +/* Initialize the Silk VAD */ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/* Get speech activity level in Q8 */ +opus_int silk_VAD_GetSA_Q8( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +); + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting transition_frame_no = 1; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* NLSF Quantizer */ +/******************/ +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +); + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q26[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +); + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +); + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +); + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +); + +/****************************************************/ +/* Decoder Functions */ +/****************************************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +); + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int fs_API_Hz /* I API Sampling frequency (Hz) */ +); + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Decode indices from bitstream */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int pulses[ MAX_FRAME_LENGTH ] /* I Pulse signal */ +); + +/* Decode quantization indices of excitation (Shell coding) */ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* CNG */ +/******************/ + +/* Reset CNG */ +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +); + +/* Encoding of various parameters */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +#endif diff --git a/media/libopus/silk/pitch_est_defines.h b/media/libopus/silk/pitch_est_defines.h new file mode 100644 index 000000000000..32d2042ae92b --- /dev/null +++ b/media/libopus/silk/pitch_est_defines.h @@ -0,0 +1,92 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_PE_DEFINES_H +#define SILK_PE_DEFINES_H + +#include "SigProc_FIX.h" + +/********************************************************/ +/* Definitions for pitch estimator */ +/********************************************************/ + +#define PE_MAX_FS_KHZ 16 /* Maximum sampling frequency used */ + +#define PE_MAX_NB_SUBFR 4 +#define PE_SUBFR_LENGTH_MS 5 /* 5 ms */ + +#define PE_LTP_MEM_LENGTH_MS ( 4 * PE_SUBFR_LENGTH_MS ) + +#define PE_MAX_FRAME_LENGTH_MS ( PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS ) +#define PE_MAX_FRAME_LENGTH ( PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ ) +#define PE_MAX_FRAME_LENGTH_ST_1 ( PE_MAX_FRAME_LENGTH >> 2 ) +#define PE_MAX_FRAME_LENGTH_ST_2 ( PE_MAX_FRAME_LENGTH >> 1 ) +#define PE_MAX_SF_FRAME_LENGTH ( PE_SUB_FRAME * PE_MAX_FS_KHZ ) + +#define PE_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ +#define PE_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PE_MAX_LAG ( PE_MAX_LAG_MS * PE_MAX_FS_KHZ ) +#define PE_MIN_LAG ( PE_MIN_LAG_MS * PE_MAX_FS_KHZ ) + +#define PE_D_SRCH_LENGTH 24 + +#define PE_NB_STAGE3_LAGS 5 + +#define PE_NB_CBKS_STAGE2 3 +#define PE_NB_CBKS_STAGE2_EXT 11 + +#define PE_CB_mn2 1 +#define PE_CB_mx2 2 + +#define PE_NB_CBKS_STAGE3_MAX 34 +#define PE_NB_CBKS_STAGE3_MID 24 +#define PE_NB_CBKS_STAGE3_MIN 16 + +#define PE_NB_CBKS_STAGE3_10MS 12 +#define PE_NB_CBKS_STAGE2_10MS 3 + +#define PE_SHORTLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_PREVLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_FLATCONTOUR_BIAS 0.05f + +#define SILK_PE_MIN_COMPLEX 0 +#define SILK_PE_MID_COMPLEX 1 +#define SILK_PE_MAX_COMPLEX 2 + +/* Tables for 20 ms frames */ +extern const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ]; +extern const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ]; +extern const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ]; +extern const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ]; + +/* Tables for 10 ms frames */ +extern const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ 3 ]; +extern const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 12 ]; +extern const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ]; + +#endif + diff --git a/media/libopus/silk/pitch_est_tables.c b/media/libopus/silk/pitch_est_tables.c new file mode 100644 index 000000000000..aafa30dbc1e7 --- /dev/null +++ b/media/libopus/silk/pitch_est_tables.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "typedef.h" +#include "pitch_est_defines.h" + +const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ PE_NB_CBKS_STAGE2_10MS ] = +{ + {0, 1, 0}, + {0, 0, 1} +}; + +const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ PE_NB_CBKS_STAGE3_10MS ] = +{ + { 0, 0, 1,-1, 1,-1, 2,-2, 2,-2, 3,-3}, + { 0, 1, 0, 1,-1, 2,-1, 2,-2, 3,-2, 3} +}; + +const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ] = +{ + {-3, 7}, + {-2, 7} +}; + +const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ] = +{ + {0, 2,-1,-1,-1, 0, 0, 1, 1, 0, 1}, + {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0}, + {0,-1, 2, 1, 0, 1, 1, 0, 0,-1,-1} +}; + +const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ] = +{ + {0, 0, 1,-1, 0, 1,-1, 0,-1, 1,-2, 2,-2,-2, 2,-3, 2, 3,-3,-4, 3,-4, 4, 4,-5, 5,-6,-5, 6,-7, 6, 5, 8,-9}, + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 0, 1,-1,-1, 1,-1, 2, 1,-1, 2,-2,-2, 2,-2, 2, 2, 3,-3}, + {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,-1, 1, 0, 0, 2, 1,-1, 2,-1,-1, 2,-1, 2, 2,-1, 3,-2,-2,-2, 3}, + {0, 1, 0, 0, 1, 0, 1,-1, 2,-1, 2,-1, 2, 3,-2, 3,-2,-2, 4, 4,-3, 5,-3,-4, 6,-4, 6, 5,-5, 8,-6,-5,-7, 9} +}; + +const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ] = +{ + /* Lags to search for low number of stage3 cbks */ + { + {-5,8}, + {-1,6}, + {-1,6}, + {-4,10} + }, + /* Lags to search for middle number of stage3 cbks */ + { + {-6,10}, + {-2,6}, + {-1,6}, + {-5,10} + }, + /* Lags to search for max number of stage3 cbks */ + { + {-9,12}, + {-3,7}, + {-2,7}, + {-7,13} + } +}; + +const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ] = +{ + PE_NB_CBKS_STAGE3_MIN, + PE_NB_CBKS_STAGE3_MID, + PE_NB_CBKS_STAGE3_MAX +}; diff --git a/media/libopus/silk/process_NLSFs.c b/media/libopus/silk/process_NLSFs.c new file mode 100644 index 000000000000..c49f884f1bbf --- /dev/null +++ b/media/libopus/silk/process_NLSFs.c @@ -0,0 +1,105 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, doInterpolate; + opus_int NLSF_mu_Q20; + opus_int32 i_sqr_Q15; + opus_int16 pNLSF0_temp_Q15[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW_QW[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW0_temp_QW[ MAX_LPC_ORDER ]; + + silk_assert( psEncC->speech_activity_Q8 >= 0 ); + silk_assert( psEncC->speech_activity_Q8 <= SILK_FIX_CONST( 1.0, 8 ) ); + silk_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) ); + + /***********************/ + /* Calculate mu values */ + /***********************/ + /* NLSF_mu = 0.003 - 0.0015 * psEnc->speech_activity; */ + NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 ); + if( psEncC->nb_subfr == 2 ) { + /* Multiply by 1.5 for 10 ms packets */ + NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 ); + } + + silk_assert( NLSF_mu_Q20 > 0 ); + silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) ); + + /* Calculate NLSF weights */ + silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights for interpolated NLSFs */ + doInterpolate = ( psEncC->useInterpolatedNLSFs == 1 ) && ( psEncC->indices.NLSFInterpCoef_Q2 < 4 ); + if( doInterpolate ) { + /* Calculate the interpolated NLSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Calculate first half NLSF weights for the interpolated NLSFs */ + silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights with contribution from first half */ + i_sqr_Q15 = silk_LSHIFT( silk_SMULBB( psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2 ), 11 ); + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + pNLSFW_QW[ i ] = silk_SMLAWB( silk_RSHIFT( pNLSFW_QW[ i ], 1 ), pNLSFW0_temp_QW[ i ], i_sqr_Q15 ); + silk_assert( pNLSFW_QW[ i ] >= 1 ); + } + } + + silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW, + NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType ); + + /* Convert quantized NLSFs back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder ); + + if( doInterpolate ) { + /* Calculate the interpolated, quantized LSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Convert back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder ); + + } else { + /* Copy LPC coefficients for first half from second half */ + silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) ); + } +} diff --git a/media/libopus/silk/quant_LTP_gains.c b/media/libopus/silk/quant_LTP_gains.c new file mode 100644 index 000000000000..d98798e3851d --- /dev/null +++ b/media/libopus/silk/quant_LTP_gains.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */ + opus_int mu_Q9, /* I Mu value (R/D tradeoff) */ + opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int j, k, cbk_size; + opus_int8 temp_idx[ MAX_NB_SUBFR ]; + const opus_uint8 *cl_ptr_Q5; + const opus_int8 *cbk_ptr_Q7; + const opus_int16 *b_Q14_ptr; + const opus_int32 *W_Q18_ptr; + opus_int32 rate_dist_Q14_subfr, rate_dist_Q14, min_rate_dist_Q14; + + /***************************************************/ + /* iterate over different codebooks with different */ + /* rates/distortions, and choose best */ + /***************************************************/ + min_rate_dist_Q14 = silk_int32_MAX; + for( k = 0; k < 3; k++ ) { + cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[ k ]; + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ k ]; + cbk_size = silk_LTP_vq_sizes[ k ]; + + /* Set up pointer to first subframe */ + W_Q18_ptr = W_Q18; + b_Q14_ptr = B_Q14; + + rate_dist_Q14 = 0; + for( j = 0; j < nb_subfr; j++ ) { + silk_VQ_WMat_EC( + &temp_idx[ j ], /* O index of best codebook vector */ + &rate_dist_Q14_subfr, /* O best weighted quantization error + mu * rate */ + b_Q14_ptr, /* I input vector to be quantized */ + W_Q18_ptr, /* I weighting matrix */ + cbk_ptr_Q7, /* I codebook */ + cl_ptr_Q5, /* I code length for each codebook vector */ + mu_Q9, /* I tradeoff between weighted error and rate */ + cbk_size /* I number of vectors in codebook */ + ); + + rate_dist_Q14 = silk_ADD_POS_SAT32( rate_dist_Q14, rate_dist_Q14_subfr ); + + b_Q14_ptr += LTP_ORDER; + W_Q18_ptr += LTP_ORDER * LTP_ORDER; + } + + /* Avoid never finding a codebook */ + rate_dist_Q14 = silk_min( silk_int32_MAX - 1, rate_dist_Q14 ); + + if( rate_dist_Q14 < min_rate_dist_Q14 ) { + min_rate_dist_Q14 = rate_dist_Q14; + *periodicity_index = (opus_int8)k; + silk_memcpy( cbk_index, temp_idx, nb_subfr * sizeof( opus_int8 ) ); + } + + /* Break early in low-complexity mode if rate distortion is below threshold */ + if( lowComplexity && ( rate_dist_Q14 < silk_LTP_gain_middle_avg_RD_Q14 ) ) { + break; + } + } + + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ]; + for( j = 0; j < nb_subfr; j++ ) { + for( k = 0; k < LTP_ORDER; k++ ) { + B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT( cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7 ); + } + } +} + diff --git a/media/libopus/silk/resampler.c b/media/libopus/silk/resampler.c new file mode 100644 index 000000000000..9055c813930b --- /dev/null +++ b/media/libopus/silk/resampler.c @@ -0,0 +1,215 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * Matrix of resampling methods used: + * Fs_out (kHz) + * 8 12 16 24 48 + * + * 8 C UF U UF UF + * 12 AF C UF U UF + * Fs_in (kHz) 16 D AF C UF UF + * 24 AF D AF C U + * 48 AF AF AF D C + * + * C -> Copy (no resampling) + * D -> Allpass-based 2x downsampling + * U -> Allpass-based 2x upsampling + * UF -> Allpass-based 2x upsampling followed by FIR interpolation + * AF -> AR2 filter followed by FIR interpolation + */ + +#include "resampler_private.h" + +/* Tables with delay compensation values to equalize total delay for different modes */ +static const opus_int8 delay_matrix_enc[ 5 ][ 3 ] = { +/* in \ out 8 12 16 */ +/* 8 */ { 6, 0, 3 }, +/* 12 */ { 0, 7, 3 }, +/* 16 */ { 0, 1, 10 }, +/* 24 */ { 0, 2, 6 }, +/* 48 */ { 18, 10, 12 } +}; + +static const opus_int8 delay_matrix_dec[ 3 ][ 5 ] = { +/* in \ out 8 12 16 24 48 */ +/* 8 */ { 4, 0, 2, 0, 0 }, +/* 12 */ { 0, 9, 4, 7, 4 }, +/* 16 */ { 0, 3, 12, 7, 7 } +}; + +/* Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4] */ +#define rateID(R) ( ( ( ((R)>>12) - ((R)>16000) ) >> ((R)>24000) ) - 1 ) + +#define USE_silk_resampler_copy (0) +#define USE_silk_resampler_private_up2_HQ_wrapper (1) +#define USE_silk_resampler_private_IIR_FIR (2) +#define USE_silk_resampler_private_down_FIR (3) + +/* Initialize/reset the resampler state for a given pair of input/output sampling rates */ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +) +{ + opus_int up2x; + + /* Clear state */ + silk_memset( S, 0, sizeof( silk_resampler_state_struct ) ); + + /* Input checking */ + if( forEnc ) { + if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000 ) || + ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 ) ) { + silk_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_enc[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } else { + if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 ) || + ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000 ) ) { + silk_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_dec[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } + + S->Fs_in_kHz = silk_DIV32_16( Fs_Hz_in, 1000 ); + S->Fs_out_kHz = silk_DIV32_16( Fs_Hz_out, 1000 ); + + /* Number of samples processed per batch */ + S->batchSize = S->Fs_in_kHz * RESAMPLER_MAX_BATCH_SIZE_MS; + + /* Find resampler with the right sampling ratio */ + up2x = 0; + if( Fs_Hz_out > Fs_Hz_in ) { + /* Upsample */ + if( Fs_Hz_out == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 1 */ + /* Special case: directly use 2x upsampler */ + S->resampler_function = USE_silk_resampler_private_up2_HQ_wrapper; + } else { + /* Default resampler */ + S->resampler_function = USE_silk_resampler_private_IIR_FIR; + up2x = 1; + } + } else if ( Fs_Hz_out < Fs_Hz_in ) { + /* Downsample */ + S->resampler_function = USE_silk_resampler_private_down_FIR; + if( silk_MUL( Fs_Hz_out, 4 ) == silk_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 4 */ + S->FIR_Fracs = 3; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_3_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 3 */ + S->FIR_Fracs = 2; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_2_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 2 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR1; + S->Coefs = silk_Resampler_1_2_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 3 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 4 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 6 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_6_COEFS; + } else { + /* None available */ + silk_assert( 0 ); + return -1; + } + } else { + /* Input and output sampling rates are equal: copy */ + S->resampler_function = USE_silk_resampler_copy; + } + + /* Ratio of input/output samples */ + S->invRatio_Q16 = silk_LSHIFT32( silk_DIV32( silk_LSHIFT32( Fs_Hz_in, 14 + up2x ), Fs_Hz_out ), 2 ); + /* Make sure the ratio is rounded up */ + while( silk_SMULWW( S->invRatio_Q16, Fs_Hz_out ) < silk_LSHIFT32( Fs_Hz_in, up2x ) ) { + S->invRatio_Q16++; + } + + return 0; +} + +/* Resampler: convert from one sampling rate to another */ +/* Input and output sampling rate are at most 48000 Hz */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int nSamples; + + /* Need at least 1 ms of input data */ + silk_assert( inLen >= S->Fs_in_kHz ); + /* Delay can't exceed the 1 ms of buffering */ + silk_assert( S->inputDelay <= S->Fs_in_kHz ); + + nSamples = S->Fs_in_kHz - S->inputDelay; + + /* Copy to delay buffer */ + silk_memcpy( &S->delayBuf[ S->inputDelay ], in, nSamples * sizeof( opus_int16 ) ); + + switch( S->resampler_function ) { + case USE_silk_resampler_private_up2_HQ_wrapper: + silk_resampler_private_up2_HQ_wrapper( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_up2_HQ_wrapper( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_IIR_FIR: + silk_resampler_private_IIR_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_IIR_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_down_FIR: + silk_resampler_private_down_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_down_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + default: + silk_memcpy( out, S->delayBuf, S->Fs_in_kHz * sizeof( opus_int16 ) ); + silk_memcpy( &out[ S->Fs_out_kHz ], &in[ nSamples ], ( inLen - S->Fs_in_kHz ) * sizeof( opus_int16 ) ); + } + + /* Copy to delay buffer */ + silk_memcpy( S->delayBuf, &in[ inLen - S->inputDelay ], S->inputDelay * sizeof( opus_int16 ) ); + + return 0; +} diff --git a/media/libopus/silk/resampler_down2.c b/media/libopus/silk/resampler_down2.c new file mode 100644 index 000000000000..3f6a8f9d616f --- /dev/null +++ b/media/libopus/silk/resampler_down2.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_rom.h" + +/* Downsample by a factor 2 */ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ len ] */ + const opus_int16 *in, /* I Input signal [ floor(len/2) ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 k, len2 = silk_RSHIFT32( inLen, 1 ); + opus_int32 in32, out32, Y, X; + + silk_assert( silk_resampler_down2_0 > 0 ); + silk_assert( silk_resampler_down2_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_down2_1 ); + out32 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_down2_0 ); + out32 = silk_ADD32( out32, S[ 1 ] ); + out32 = silk_ADD32( out32, X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add, convert back to int16 and store to output */ + out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32, 11 ) ); + } +} + diff --git a/media/libopus/silk/resampler_down2_3.c b/media/libopus/silk/resampler_down2_3.c new file mode 100644 index 000000000000..9f4f22fc3144 --- /dev/null +++ b/media/libopus/silk/resampler_down2_3.c @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +#define ORDER_FIR 4 + +/* Downsample by a factor 2/3, low quality */ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 nSamplesIn, counter, res_Q6; + opus_int32 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR ]; + opus_int32 *buf_ptr; + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + while( 1 ) { + nSamplesIn = silk_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, + silk_Resampler_2_3_COEFS_LQ, nSamplesIn ); + + /* Interpolate filtered signal */ + buf_ptr = buf; + counter = nSamplesIn; + while( counter > 2 ) { + /* Inner product */ + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + res_Q6 = silk_SMULWB( buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + buf_ptr += 3; + counter -= 3; + } + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); +} diff --git a/media/libopus/silk/resampler_private.h b/media/libopus/silk/resampler_private.h new file mode 100644 index 000000000000..96fe83ed5d01 --- /dev/null +++ b/media/libopus/silk/resampler_private.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_RESAMPLER_PRIVATE_H +#define SILK_RESAMPLER_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "SigProc_FIX.h" +#include "resampler_structs.h" +#include "resampler_rom.h" + +/* Number of input samples to process in the inner loop */ +#define RESAMPLER_MAX_BATCH_SIZE_MS 10 +#define RESAMPLER_MAX_FS_KHZ 48 +#define RESAMPLER_MAX_BATCH_SIZE_IN ( RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ ) + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Second order AR filter */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +); + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_PRIVATE_H */ diff --git a/media/libopus/silk/resampler_private_AR2.c b/media/libopus/silk/resampler_private_AR2.c new file mode 100644 index 000000000000..5add355305db --- /dev/null +++ b/media/libopus/silk/resampler_private_AR2.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Second order AR filter with single delay elements */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +) +{ + opus_int32 k; + opus_int32 out32; + + for( k = 0; k < len; k++ ) { + out32 = silk_ADD_LSHIFT32( S[ 0 ], (opus_int32)in[ k ], 8 ); + out_Q8[ k ] = out32; + out32 = silk_LSHIFT( out32, 2 ); + S[ 0 ] = silk_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] ); + S[ 1 ] = silk_SMULWB( out32, A_Q14[ 1 ] ); + } +} + diff --git a/media/libopus/silk/resampler_private_IIR_FIR.c b/media/libopus/silk/resampler_private_IIR_FIR.c new file mode 100644 index 000000000000..f17fb5cae3a0 --- /dev/null +++ b/media/libopus/silk/resampler_private_IIR_FIR.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +static inline opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL( + opus_int16 *out, + opus_int16 *buf, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q15; + opus_int16 *buf_ptr; + opus_int32 table_index; + + /* Interpolate upsampled signal and store in output array */ + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + table_index = silk_SMULWB( index_Q16 & 0xFFFF, 12 ); + buf_ptr = &buf[ index_Q16 >> 16 ]; + + res_Q15 = silk_SMULBB( buf_ptr[ 0 ], silk_resampler_frac_FIR_12[ table_index ][ 0 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 1 ], silk_resampler_frac_FIR_12[ table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 2 ], silk_resampler_frac_FIR_12[ table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 3 ], silk_resampler_frac_FIR_12[ table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 4 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 5 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 6 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 7 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 0 ] ); + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) ); + } + return out; +} +/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + opus_int16 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_12 ]; + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Upsample 2x */ + silk_resampler_private_up2_HQ( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 ); /* + 1 because 2x upsampling */ + out = silk_resampler_private_IIR_FIR_INTERPOL( out, buf, max_index_Q16, index_increment_Q16 ); + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); +} + diff --git a/media/libopus/silk/resampler_private_down_FIR.c b/media/libopus/silk/resampler_private_down_FIR.c new file mode 100644 index 000000000000..d1ee15a36e08 --- /dev/null +++ b/media/libopus/silk/resampler_private_down_FIR.c @@ -0,0 +1,189 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +static inline opus_int16 *silk_resampler_private_down_FIR_INTERPOL( + opus_int16 *out, + opus_int32 *buf, + const opus_int16 *FIR_Coefs, + opus_int FIR_Order, + opus_int FIR_Fracs, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q6; + opus_int32 *buf_ptr; + opus_int32 interpol_ind; + const opus_int16 *interpol_ptr; + + switch( FIR_Order ) { + case RESAMPLER_DOWN_ORDER_FIR0: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Fractional part gives interpolation coefficients */ + interpol_ind = silk_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs ); + + /* Inner product */ + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind ]; + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 8 ] ); + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * ( FIR_Fracs - 1 - interpol_ind ) ]; + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 17 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 16 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 15 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 14 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 13 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 12 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 8 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR1: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 23 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 22 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 21 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 20 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 19 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 18 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 17 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 16 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 15 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 14 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 13 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 12 ] ), FIR_Coefs[ 11 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR2: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 35 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 34 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 33 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 32 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 31 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 30 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 29 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 28 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 27 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 26 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 25 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 24 ] ), FIR_Coefs[ 11 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 12 ], buf_ptr[ 23 ] ), FIR_Coefs[ 12 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 13 ], buf_ptr[ 22 ] ), FIR_Coefs[ 13 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 14 ], buf_ptr[ 21 ] ), FIR_Coefs[ 14 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 15 ], buf_ptr[ 20 ] ), FIR_Coefs[ 15 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 16 ], buf_ptr[ 19 ] ), FIR_Coefs[ 16 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 17 ], buf_ptr[ 18 ] ), FIR_Coefs[ 17 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + default: + silk_assert( 0 ); + } + return out; +} + +/* Resample with a 2nd order AR filter followed by FIR interpolation */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + opus_int32 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + SILK_RESAMPLER_MAX_FIR_ORDER ]; + const opus_int16 *FIR_Coefs; + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR, S->FIR_Order * sizeof( opus_int32 ) ); + + FIR_Coefs = &S->Coefs[ 2 ]; + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( S->sIIR, &buf[ S->FIR_Order ], in, S->Coefs, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 ); + + /* Interpolate filtered signal */ + out = silk_resampler_private_down_FIR_INTERPOL( out, buf, FIR_Coefs, S->FIR_Order, + S->FIR_Fracs, max_index_Q16, index_increment_Q16 ); + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 1 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); +} diff --git a/media/libopus/silk/resampler_private_up2_HQ.c b/media/libopus/silk/resampler_private_up2_HQ.c new file mode 100644 index 000000000000..09dc9c7d918e --- /dev/null +++ b/media/libopus/silk/resampler_private_up2_HQ.c @@ -0,0 +1,113 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Upsample by a factor 2, high quality */ +/* Uses 2nd order allpass filters for the 2x upsampling, followed by a */ +/* notch filter just above Nyquist. */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + opus_int32 k; + opus_int32 in32, out32_1, out32_2, Y, X; + + silk_assert( silk_resampler_up2_hq_0[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 2 ] < 0 ); + silk_assert( silk_resampler_up2_hq_1[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 2 ] < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ k ], 10 ); + + /* First all-pass section for even output sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 0 ] ); + out32_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for even output sample */ + Y = silk_SUB32( out32_1, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 1 ] ); + out32_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for even output sample */ + Y = silk_SUB32( out32_2, S[ 2 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_0[ 2 ] ); + out32_1 = silk_ADD32( S[ 2 ], X ); + S[ 2 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + + /* First all-pass section for odd output sample */ + Y = silk_SUB32( in32, S[ 3 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 0 ] ); + out32_1 = silk_ADD32( S[ 3 ], X ); + S[ 3 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for odd output sample */ + Y = silk_SUB32( out32_1, S[ 4 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 1 ] ); + out32_2 = silk_ADD32( S[ 4 ], X ); + S[ 4 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for odd output sample */ + Y = silk_SUB32( out32_2, S[ 5 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_1[ 2 ] ); + out32_1 = silk_ADD32( S[ 5 ], X ); + S[ 5 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + } +} + +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + silk_resampler_private_up2_HQ( S->sIIR, out, in, len ); +} diff --git a/media/libopus/silk/resampler_rom.c b/media/libopus/silk/resampler_rom.c new file mode 100644 index 000000000000..9c4750c31593 --- /dev/null +++ b/media/libopus/silk/resampler_rom.c @@ -0,0 +1,104 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Filter coefficients for IIR/FIR polyphase resampling * + * Total size: 179 Words (358 Bytes) */ + +#include "resampler_private.h" + +/* Tables for 2x downsampler */ +const opus_int16 silk_resampler_down2_0 = 9872; +const opus_int16 silk_resampler_down2_1 = 39809 - 65536; + +/* Tables for 2x upsampler, high quality */ +const opus_int16 silk_resampler_up2_hq_0[ 3 ] = { 1746, 14986, 39083 - 65536 }; +const opus_int16 silk_resampler_up2_hq_1[ 3 ] = { 6854, 25769, 55542 - 65536 }; + +/* Matlab code for the notch filter coefficients: */ +/* B = [1, 0.147, 1]; A = [1, 0.107, 0.89]; G = 0.93; freqz(G * B, A, 2^14, 16e3); axis([0, 8000, -10, 1]) */ +/* fprintf('\t%6d, %6d, %6d, %6d\n', round(B(2)*2^16), round(-A(2)*2^16), round((1-A(3))*2^16), round(G*2^15)) */ +const opus_int16 silk_resampler_up2_hq_notch[ 4 ] = { 9634, -7012, 7209, 30474 }; + +/* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -20694, -13867, + -49, 64, 17, -157, 353, -496, 163, 11047, 22205, + -39, 6, 91, -170, 186, 23, -896, 6336, 19928, + -19, -36, 102, -89, -24, 328, -951, 2568, 15909, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -14457, -14019, + 64, 128, -122, 36, 310, -768, 584, 9267, 17733, + 12, 128, 18, -142, 288, -117, -865, 4123, 14459, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ] = { + 616, -14323, + -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 16102, -15162, + -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 22500, -15099, + 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 27540, -15257, + 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = { + -2797, -6507, + 4697, 10739, + 1567, 8276, +}; + +/* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ] = { + { 189, -600, 617, 30567 }, + { 117, -159, -1070, 29704 }, + { 52, 221, -2392, 28276 }, + { -4, 529, -3350, 26341 }, + { -48, 758, -3956, 23973 }, + { -80, 905, -4235, 21254 }, + { -99, 972, -4222, 18278 }, + { -107, 967, -3957, 15143 }, + { -103, 896, -3487, 11950 }, + { -91, 773, -2865, 8798 }, + { -71, 611, -2143, 5784 }, + { -46, 425, -1375, 2996 }, +}; diff --git a/media/libopus/silk/resampler_rom.h b/media/libopus/silk/resampler_rom.h new file mode 100644 index 000000000000..c1ff59e0fda1 --- /dev/null +++ b/media/libopus/silk/resampler_rom.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_FIX_RESAMPLER_ROM_H +#define SILK_FIX_RESAMPLER_ROM_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "typedef.h" +#include "resampler_structs.h" + +#define RESAMPLER_DOWN_ORDER_FIR0 18 +#define RESAMPLER_DOWN_ORDER_FIR1 24 +#define RESAMPLER_DOWN_ORDER_FIR2 36 +#define RESAMPLER_ORDER_FIR_12 8 + +/* Tables for 2x downsampler */ +extern const opus_int16 silk_resampler_down2_0; +extern const opus_int16 silk_resampler_down2_1; + +/* Tables for 2x upsampler, high quality */ +extern const opus_int16 silk_resampler_up2_hq_0[ 3 ]; +extern const opus_int16 silk_resampler_up2_hq_1[ 3 ]; + +/* Tables with IIR and FIR coefficients for fractional downsamplers */ +extern const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ]; +extern const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ]; + +/* Table with interplation fractions of 1/24, 3/24, ..., 23/24 */ +extern const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ]; + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_RESAMPLER_ROM_H */ diff --git a/media/libopus/silk/resampler_structs.h b/media/libopus/silk/resampler_structs.h new file mode 100644 index 000000000000..e5289efdbb2e --- /dev/null +++ b/media/libopus/silk/resampler_structs.h @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_RESAMPLER_STRUCTS_H +#define SILK_RESAMPLER_STRUCTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SILK_RESAMPLER_MAX_FIR_ORDER 36 +#define SILK_RESAMPLER_MAX_IIR_ORDER 6 + +typedef struct _silk_resampler_state_struct{ + opus_int32 sIIR[ SILK_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */ + opus_int32 sFIR[ SILK_RESAMPLER_MAX_FIR_ORDER ]; + opus_int16 delayBuf[ 48 ]; + opus_int resampler_function; + opus_int batchSize; + opus_int32 invRatio_Q16; + opus_int FIR_Order; + opus_int FIR_Fracs; + opus_int Fs_in_kHz; + opus_int Fs_out_kHz; + opus_int inputDelay; + const opus_int16 *Coefs; +} silk_resampler_state_struct; + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_STRUCTS_H */ + diff --git a/media/libopus/silk/shell_coder.c b/media/libopus/silk/shell_coder.c new file mode 100644 index 000000000000..9ec343c0f8ec --- /dev/null +++ b/media/libopus/silk/shell_coder.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* shell coder; pulse-subframe length is hardcoded */ + +static inline void combine_pulses( + opus_int *out, /* O combined pulses vector [len] */ + const opus_int *in, /* I input vector [2 * len] */ + const opus_int len /* I number of OUTPUT samples */ +) +{ + opus_int k; + for( k = 0; k < len; k++ ) { + out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ]; + } +} + +static inline void encode_split( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int p_child1, /* I pulse amplitude of first child subframe */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + ec_enc_icdf( psRangeEnc, p_child1, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + } +} + +static inline void decode_split( + opus_int *p_child1, /* O pulse amplitude of first child subframe */ + opus_int *p_child2, /* O pulse amplitude of second child subframe */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + p_child1[ 0 ] = ec_dec_icdf( psRangeDec, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + p_child2[ 0 ] = p - p_child1[ 0 ]; + } else { + p_child1[ 0 ] = 0; + p_child2[ 0 ] = 0; + } +} + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +) +{ + opus_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + /* tree representation per pulse-subframe */ + combine_pulses( pulses1, pulses0, 8 ); + combine_pulses( pulses2, pulses1, 4 ); + combine_pulses( pulses3, pulses2, 2 ); + combine_pulses( pulses4, pulses3, 1 ); + + encode_split( psRangeEnc, pulses3[ 0 ], pulses4[ 0 ], silk_shell_code_table3 ); + + encode_split( psRangeEnc, pulses2[ 0 ], pulses3[ 0 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 0 ], pulses2[ 0 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 0 ], pulses1[ 0 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 2 ], pulses1[ 1 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 2 ], pulses2[ 1 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 4 ], pulses1[ 2 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 6 ], pulses1[ 3 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses2[ 2 ], pulses3[ 1 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 4 ], pulses2[ 2 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 8 ], pulses1[ 4 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 10 ], pulses1[ 5 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 6 ], pulses2[ 3 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 12 ], pulses1[ 6 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 14 ], pulses1[ 7 ], silk_shell_code_table0 ); +} + + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +) +{ + opus_int pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + decode_split( &pulses3[ 0 ], &pulses3[ 1 ], psRangeDec, pulses4, silk_shell_code_table3 ); + + decode_split( &pulses2[ 0 ], &pulses2[ 1 ], psRangeDec, pulses3[ 0 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 0 ], &pulses1[ 1 ], psRangeDec, pulses2[ 0 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 0 ], &pulses0[ 1 ], psRangeDec, pulses1[ 0 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 2 ], &pulses0[ 3 ], psRangeDec, pulses1[ 1 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 2 ], &pulses1[ 3 ], psRangeDec, pulses2[ 1 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 4 ], &pulses0[ 5 ], psRangeDec, pulses1[ 2 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 6 ], &pulses0[ 7 ], psRangeDec, pulses1[ 3 ], silk_shell_code_table0 ); + + decode_split( &pulses2[ 2 ], &pulses2[ 3 ], psRangeDec, pulses3[ 1 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 4 ], &pulses1[ 5 ], psRangeDec, pulses2[ 2 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 8 ], &pulses0[ 9 ], psRangeDec, pulses1[ 4 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 10 ], &pulses0[ 11 ], psRangeDec, pulses1[ 5 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 6 ], &pulses1[ 7 ], psRangeDec, pulses2[ 3 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 12 ], &pulses0[ 13 ], psRangeDec, pulses1[ 6 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 14 ], &pulses0[ 15 ], psRangeDec, pulses1[ 7 ], silk_shell_code_table0 ); +} diff --git a/media/libopus/silk/sigm_Q15.c b/media/libopus/silk/sigm_Q15.c new file mode 100644 index 000000000000..8d6b84b07098 --- /dev/null +++ b/media/libopus/silk/sigm_Q15.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Approximate sigmoid function */ + +#include "SigProc_FIX.h" + +/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */ +static const opus_int32 sigm_LUT_slope_Q10[ 6 ] = { + 237, 153, 73, 30, 12, 7 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */ +static const opus_int32 sigm_LUT_pos_Q15[ 6 ] = { + 16384, 23955, 28861, 31213, 32178, 32548 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */ +static const opus_int32 sigm_LUT_neg_Q15[ 6 ] = { + 16384, 8812, 3906, 1554, 589, 219 +}; + +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +) +{ + opus_int ind; + + if( in_Q5 < 0 ) { + /* Negative input */ + in_Q5 = -in_Q5; + if( in_Q5 >= 6 * 32 ) { + return 0; /* Clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_neg_Q15[ ind ] - silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } else { + /* Positive input */ + if( in_Q5 >= 6 * 32 ) { + return 32767; /* clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_pos_Q15[ ind ] + silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } +} + diff --git a/media/libopus/silk/sort.c b/media/libopus/silk/sort.c new file mode 100644 index 000000000000..e5034f8c185f --- /dev/null +++ b/media/libopus/silk/sort.c @@ -0,0 +1,154 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ +/* */ +/* Shell short: http://en.wikipedia.org/wiki/Shell_sort */ + +#include "SigProc_FIX.h" + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int32 value; + opus_int i, j; + + /* Safety checks */ + silk_assert( K > 0 ); + silk_assert( L > 0 ); + silk_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value < a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} + +#ifdef FIXED_POINT +/* This function is only used by the fixed-point build */ +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int i, j; + opus_int value; + + /* Safety checks */ + silk_assert( K > 0 ); + silk_assert( L > 0 ); + silk_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} +#endif + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +) +{ + opus_int value; + opus_int i, j; + + /* Safety checks */ + silk_assert( L > 0 ); + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < L; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + } + a[ j + 1 ] = value; /* Write value */ + } +} diff --git a/media/libopus/silk/stereo_LR_to_MS.c b/media/libopus/silk/stereo_LR_to_MS.c new file mode 100644 index 000000000000..bc2039419117 --- /dev/null +++ b/media/libopus/silk/stereo_LR_to_MS.c @@ -0,0 +1,219 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13; + opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24; + opus_int16 side[ MAX_FRAME_LENGTH + 2 ]; + opus_int16 LP_mid[ MAX_FRAME_LENGTH ], HP_mid[ MAX_FRAME_LENGTH ]; + opus_int16 LP_side[ MAX_FRAME_LENGTH ], HP_side[ MAX_FRAME_LENGTH ]; + opus_int16 *mid = &x1[ -2 ]; + + /* Convert to basic mid/side signals */ + for( n = 0; n < frame_length + 2; n++ ) { + sum = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ]; + diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ]; + mid[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) ); + } + + /* Buffering */ + silk_memcpy( mid, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &mid[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* LP and HP filter mid signal */ + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 ); + LP_mid[ n ] = sum; + HP_mid[ n ] = mid[ n + 1 ] - sum; + } + + /* LP and HP filter side signal */ + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( side[ n ] + side[ n + 2 ], side[ n + 1 ], 1 ), 2 ); + LP_side[ n ] = sum; + HP_side[ n ] = side[ n + 1 ] - sum; + } + + /* Find energies and predictors */ + is10msFrame = frame_length == 10 * fs_kHz; + smooth_coef_Q16 = is10msFrame ? + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) : + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF, 16 ); + smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 ); + + pred_Q13[ 0 ] = silk_stereo_find_predictor( &LP_ratio_Q14, LP_mid, LP_side, &state->mid_side_amp_Q0[ 0 ], frame_length, smooth_coef_Q16 ); + pred_Q13[ 1 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 ); + /* Ratio of the norms of residual and mid signals */ + frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 ); + frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) ); + + /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */ + total_rate_bps -= is10msFrame ? 1200 : 600; /* Subtract approximate bitrate for coding stereo parameters */ + if( total_rate_bps < 1 ) { + total_rate_bps = 1; + } + min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 900 ); + silk_assert( min_mid_rate_bps < 32767 ); + /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */ + frac_3_Q16 = silk_MUL( 3, frac_Q16 ); + mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 ); + /* If Mid bitrate below minimum, reduce stereo width */ + if( mid_side_rates_bps[ 0 ] < min_mid_rate_bps ) { + mid_side_rates_bps[ 0 ] = min_mid_rate_bps; + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + /* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */ + width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps, + silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 ); + width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) ); + } else { + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } + + /* Smoother */ + state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 ); + + /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */ + *mid_only_flag = 0; + if( toMono ) { + /* Last frame before stereo->mono transition; collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + silk_stereo_quant_pred( pred_Q13, ix ); + } else if( state->width_prev_Q14 == 0 && + ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) ) + { + /* Code as panned-mono; previous frame already had zero width */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + mid_side_rates_bps[ 0 ] = total_rate_bps; + mid_side_rates_bps[ 1 ] = 0; + *mid_only_flag = 1; + } else if( state->width_prev_Q14 != 0 && + ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) ) + { + /* Transition to zero-width stereo */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) { + /* Full-width stereo coding */ + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } else { + /* Reduced-width stereo coding; scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = state->smth_width_Q14; + } + + /* Make sure to keep on encoding until the tapered output has been transmitted */ + if( *mid_only_flag == 1 ) { + state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz; + if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) { + *mid_only_flag = 0; + } else { + /* Limit to avoid wrapping around */ + state->silent_side_len = 10000; + } + } else { + state->silent_side_len = 0; + } + + if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) { + mid_side_rates_bps[ 1 ] = 1; + mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]); + } + + /* Interpolate predictors and subtract prediction from side channel */ + pred0_Q13 = -state->pred_prev_Q13[ 0 ]; + pred1_Q13 = -state->pred_prev_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( state->width_prev_Q14, 10 ); + denom_Q16 = silk_DIV32_16( 1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + deltaw_Q24 = silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + w_Q24 += deltaw_Q24; + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + + pred0_Q13 = -pred_Q13[ 0 ]; + pred1_Q13 = -pred_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( width_Q14, 10 ); + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ]; + state->width_prev_Q14 = (opus_int16)width_Q14; +} diff --git a/media/libopus/silk/stereo_MS_to_LR.c b/media/libopus/silk/stereo_MS_to_LR.c new file mode 100644 index 000000000000..a9f105b53b0c --- /dev/null +++ b/media/libopus/silk/stereo_MS_to_LR.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, pred0_Q13, pred1_Q13; + + /* Buffering */ + silk_memcpy( x1, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( x2, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &x1[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &x2[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* Interpolate predictors and add prediction to side channel */ + pred0_Q13 = state->pred_prev_Q13[ 0 ]; + pred1_Q13 = state->pred_prev_Q13[ 1 ]; + denom_Q16 = silk_DIV32_16( 1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + pred0_Q13 = pred_Q13[ 0 ]; + pred1_Q13 = pred_Q13[ 1 ]; + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = pred_Q13[ 1 ]; + + /* Convert to left/right signals */ + for( n = 0; n < frame_length; n++ ) { + sum = x1[ n + 1 ] + (opus_int32)x2[ n + 1 ]; + diff = x1[ n + 1 ] - (opus_int32)x2[ n + 1 ]; + x1[ n + 1 ] = (opus_int16)silk_SAT16( sum ); + x2[ n + 1 ] = (opus_int16)silk_SAT16( diff ); + } +} diff --git a/media/libopus/silk/stereo_decode_pred.c b/media/libopus/silk/stereo_decode_pred.c new file mode 100644 index 000000000000..a7c2e41bdfb6 --- /dev/null +++ b/media/libopus/silk/stereo_decode_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +) +{ + opus_int n, ix[ 2 ][ 3 ]; + opus_int32 low_Q13, step_Q13; + + /* Entropy decoding */ + n = ec_dec_icdf( psRangeDec, silk_stereo_pred_joint_iCDF, 8 ); + ix[ 0 ][ 2 ] = silk_DIV32_16( n, 5 ); + ix[ 1 ][ 2 ] = n - 5 * ix[ 0 ][ 2 ]; + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] = ec_dec_icdf( psRangeDec, silk_uniform3_iCDF, 8 ); + ix[ n ][ 1 ] = ec_dec_icdf( psRangeDec, silk_uniform5_iCDF, 8 ); + } + + /* Dequantize */ + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] += 3 * ix[ n ][ 2 ]; + low_Q13 = silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + pred_Q13[ n ] = silk_SMLABB( low_Q13, step_Q13, 2 * ix[ n ][ 1 ] + 1 ); + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +) +{ + /* Decode flag that only mid channel is coded */ + *decode_only_mid = ec_dec_icdf( psRangeDec, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/media/libopus/silk/stereo_encode_pred.c b/media/libopus/silk/stereo_encode_pred.c new file mode 100644 index 000000000000..0b78a2e57d01 --- /dev/null +++ b/media/libopus/silk/stereo_encode_pred.c @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +) +{ + opus_int n; + + /* Entropy coding */ + n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ]; + silk_assert( n < 25 ); + ec_enc_icdf( psRangeEnc, n, silk_stereo_pred_joint_iCDF, 8 ); + for( n = 0; n < 2; n++ ) { + silk_assert( ix[ n ][ 0 ] < 3 ); + silk_assert( ix[ n ][ 1 ] < STEREO_QUANT_SUB_STEPS ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 0 ], silk_uniform3_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 1 ], silk_uniform5_iCDF, 8 ); + } +} + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +) +{ + /* Encode flag that only mid channel is coded */ + ec_enc_icdf( psRangeEnc, mid_only_flag, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/media/libopus/silk/stereo_find_predictor.c b/media/libopus/silk/stereo_find_predictor.c new file mode 100644 index 000000000000..9460bf7b81b9 --- /dev/null +++ b/media/libopus/silk/stereo_find_predictor.c @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +) +{ + opus_int scale, scale1, scale2; + opus_int32 nrgx, nrgy, corr, pred_Q13, pred2_Q10; + + /* Find predictor */ + silk_sum_sqr_shift( &nrgx, &scale1, x, length ); + silk_sum_sqr_shift( &nrgy, &scale2, y, length ); + scale = silk_max_int( scale1, scale2 ); + scale = scale + ( scale & 1 ); /* make even */ + nrgy = silk_RSHIFT32( nrgy, scale - scale2 ); + nrgx = silk_RSHIFT32( nrgx, scale - scale1 ); + nrgx = silk_max_int( nrgx, 1 ); + corr = silk_inner_prod_aligned_scale( x, y, scale, length ); + pred_Q13 = silk_DIV32_varQ( corr, nrgx, 13 ); + pred_Q13 = silk_LIMIT( pred_Q13, -(1 << 14), 1 << 14 ); + pred2_Q10 = silk_SMULWB( pred_Q13, pred_Q13 ); + + /* Faster update for signals with large prediction parameters */ + smooth_coef_Q16 = (opus_int)silk_max_int( smooth_coef_Q16, silk_abs( pred2_Q10 ) ); + + /* Smoothed mid and residual norms */ + silk_assert( smooth_coef_Q16 < 32768 ); + scale = silk_RSHIFT( scale, 1 ); + mid_res_amp_Q0[ 0 ] = silk_SMLAWB( mid_res_amp_Q0[ 0 ], silk_LSHIFT( silk_SQRT_APPROX( nrgx ), scale ) - mid_res_amp_Q0[ 0 ], + smooth_coef_Q16 ); + /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */ + nrgy = silk_SUB_LSHIFT32( nrgy, silk_SMULWB( corr, pred_Q13 ), 3 + 1 ); + nrgy = silk_ADD_LSHIFT32( nrgy, silk_SMULWB( nrgx, pred2_Q10 ), 6 ); + mid_res_amp_Q0[ 1 ] = silk_SMLAWB( mid_res_amp_Q0[ 1 ], silk_LSHIFT( silk_SQRT_APPROX( nrgy ), scale ) - mid_res_amp_Q0[ 1 ], + smooth_coef_Q16 ); + + /* Ratio of smoothed residual and mid norms */ + *ratio_Q14 = silk_DIV32_varQ( mid_res_amp_Q0[ 1 ], silk_max( mid_res_amp_Q0[ 0 ], 1 ), 14 ); + *ratio_Q14 = silk_LIMIT( *ratio_Q14, 0, 32767 ); + + return pred_Q13; +} diff --git a/media/libopus/silk/stereo_quant_pred.c b/media/libopus/silk/stereo_quant_pred.c new file mode 100644 index 000000000000..faacf04d6a89 --- /dev/null +++ b/media/libopus/silk/stereo_quant_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +) +{ + opus_int i, j, n; + opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0; + + /* Quantize */ + for( n = 0; n < 2; n++ ) { + /* Brute-force search over quantization levels */ + err_min_Q13 = silk_int32_MAX; + for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) { + low_Q13 = silk_stereo_pred_quant_Q13[ i ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) { + lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 ); + err_Q13 = silk_abs( pred_Q13[ n ] - lvl_Q13 ); + if( err_Q13 < err_min_Q13 ) { + err_min_Q13 = err_Q13; + quant_pred_Q13 = lvl_Q13; + ix[ n ][ 0 ] = i; + ix[ n ][ 1 ] = j; + } else { + /* Error increasing, so we're past the optimum */ + goto done; + } + } + } + done: + ix[ n ][ 2 ] = silk_DIV32_16( ix[ n ][ 0 ], 3 ); + ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3; + pred_Q13[ n ] = quant_pred_Q13; + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} diff --git a/media/libopus/silk/structs.h b/media/libopus/silk/structs.h new file mode 100644 index 000000000000..6bada59b91a9 --- /dev/null +++ b/media/libopus/silk/structs.h @@ -0,0 +1,324 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_STRUCTS_H +#define SILK_STRUCTS_H + +#include "typedef.h" +#include "SigProc_FIX.h" +#include "define.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************/ +/* Noise shaping quantization state */ +/************************************/ +typedef struct { + opus_int16 xq[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */ + opus_int32 sLTP_shp_Q14[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 sLF_AR_shp_Q14; + opus_int lagPrev; + opus_int sLTP_buf_idx; + opus_int sLTP_shp_buf_idx; + opus_int32 rand_seed; + opus_int32 prev_gain_Q16; + opus_int rewhite_flag; +} silk_nsq_state; + +/********************************/ +/* VAD state */ +/********************************/ +typedef struct { + opus_int32 AnaState[ 2 ]; /* Analysis filterbank state: 0-8 kHz */ + opus_int32 AnaState1[ 2 ]; /* Analysis filterbank state: 0-4 kHz */ + opus_int32 AnaState2[ 2 ]; /* Analysis filterbank state: 0-2 kHz */ + opus_int32 XnrgSubfr[ VAD_N_BANDS ]; /* Subframe energies */ + opus_int32 NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band */ + opus_int16 HPstate; /* State of differentiator in the lowest band */ + opus_int32 NL[ VAD_N_BANDS ]; /* Noise energy level in each band */ + opus_int32 inv_NL[ VAD_N_BANDS ]; /* Inverse noise energy level in each band */ + opus_int32 NoiseLevelBias[ VAD_N_BANDS ]; /* Noise level estimator bias/offset */ + opus_int32 counter; /* Frame counter used in the initial phase */ +} silk_VAD_state; + +/* Variable cut-off low-pass filter state */ +typedef struct { + opus_int32 In_LP_State[ 2 ]; /* Low pass filter state */ + opus_int32 transition_frame_no; /* Counter which is mapped to a cut-off frequency */ + opus_int mode; /* Operating mode, <0: switch down, >0: switch up; 0: do nothing */ +} silk_LP_state; + +/* Structure containing NLSF codebook */ +typedef struct { + const opus_int16 nVectors; + const opus_int16 order; + const opus_int16 quantStepSize_Q16; + const opus_int16 invQuantStepSize_Q6; + const opus_uint8 *CB1_NLSF_Q8; + const opus_uint8 *CB1_iCDF; + const opus_uint8 *pred_Q8; + const opus_uint8 *ec_sel; + const opus_uint8 *ec_iCDF; + const opus_uint8 *ec_Rates_Q5; + const opus_int16 *deltaMin_Q15; +} silk_NLSF_CB_struct; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; + opus_int32 mid_side_amp_Q0[ 4 ]; + opus_int16 smth_width_Q14; + opus_int16 width_prev_Q14; + opus_int16 silent_side_len; + opus_int8 predIx[ MAX_FRAMES_PER_PACKET ][ 2 ][ 3 ]; + opus_int8 mid_only_flags[ MAX_FRAMES_PER_PACKET ]; +} stereo_enc_state; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; +} stereo_dec_state; + +typedef struct { + opus_int8 GainsIndices[ MAX_NB_SUBFR ]; + opus_int8 LTPIndex[ MAX_NB_SUBFR ]; + opus_int8 NLSFIndices[ MAX_LPC_ORDER + 1 ]; + opus_int16 lagIndex; + opus_int8 contourIndex; + opus_int8 signalType; + opus_int8 quantOffsetType; + opus_int8 NLSFInterpCoef_Q2; + opus_int8 PERIndex; + opus_int8 LTP_scaleIndex; + opus_int8 Seed; +} SideInfoIndices; + +/********************************/ +/* Encoder state */ +/********************************/ +typedef struct { + opus_int32 In_HP_State[ 2 ]; /* High pass filter state */ + opus_int32 variable_HP_smth1_Q15; /* State of first smoother */ + opus_int32 variable_HP_smth2_Q15; /* State of second smoother */ + silk_LP_state sLP; /* Low pass filter state */ + silk_VAD_state sVAD; /* Voice activity detector state */ + silk_nsq_state sNSQ; /* Noise Shape Quantizer State */ + opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */ + opus_int speech_activity_Q8; /* Speech activity */ + opus_int allow_bandwidth_switch; /* Flag indicating that switching of internal bandwidth is allowed */ + opus_int8 LBRRprevLastGainIndex; + opus_int8 prevSignalType; + opus_int prevLag; + opus_int pitch_LPC_win_length; + opus_int max_pitch_lag; /* Highest possible pitch lag (samples) */ + opus_int32 API_fs_Hz; /* API sampling frequency (Hz) */ + opus_int32 prev_API_fs_Hz; /* Previous API sampling frequency (Hz) */ + opus_int maxInternal_fs_Hz; /* Maximum internal sampling frequency (Hz) */ + opus_int minInternal_fs_Hz; /* Minimum internal sampling frequency (Hz) */ + opus_int desiredInternal_fs_Hz; /* Soft request for internal sampling frequency (Hz) */ + opus_int fs_kHz; /* Internal sampling frequency (kHz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int la_pitch; /* Look-ahead for pitch analysis (samples) */ + opus_int la_shape; /* Look-ahead for noise shape analysis (samples) */ + opus_int shapeWinLength; /* Window length for noise shape analysis (samples) */ + opus_int32 TargetRate_bps; /* Target bitrate (bps) */ + opus_int PacketSize_ms; /* Number of milliseconds to put in each packet */ + opus_int PacketLoss_perc; /* Packet loss rate measured by farend */ + opus_int32 frameCounter; + opus_int Complexity; /* Complexity setting */ + opus_int nStatesDelayedDecision; /* Number of states in delayed decision quantization */ + opus_int useInterpolatedNLSFs; /* Flag for using NLSF interpolation */ + opus_int shapingLPCOrder; /* Filter order for noise shaping filters */ + opus_int predictLPCOrder; /* Filter order for prediction filters */ + opus_int pitchEstimationComplexity; /* Complexity level for pitch estimator */ + opus_int pitchEstimationLPCOrder; /* Whitening filter order for pitch estimator */ + opus_int32 pitchEstimationThreshold_Q16; /* Threshold for pitch estimator */ + opus_int LTPQuantLowComplexity; /* Flag for low complexity LTP quantization */ + opus_int mu_LTP_Q9; /* Rate-distortion tradeoff in LTP quantization */ + opus_int NLSF_MSVQ_Survivors; /* Number of survivors in NLSF MSVQ */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation, pitch prediction */ + opus_int controlled_since_last_payload; /* Flag for ensuring codec_control only runs once per packet */ + opus_int warping_Q16; /* Warping parameter for warped noise shaping */ + opus_int useCBR; /* Flag to enable constant bitrate */ + opus_int prefillFlag; /* Flag to indicate that only buffers are prefilled, no coding */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + opus_int input_quality_bands_Q15[ VAD_N_BANDS ]; + opus_int input_tilt_Q15; + opus_int SNR_dB_Q7; /* Quality setting */ + + opus_int8 VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int8 LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + SideInfoIndices indices; + opus_int8 pulses[ MAX_FRAME_LENGTH ]; + + /* Input/output buffering */ + opus_int16 inputBuf[ MAX_FRAME_LENGTH + 2 ]; /* Buffer containing input signal */ + opus_int inputBufIx; + opus_int nFramesPerPacket; + opus_int nFramesEncoded; /* Number of frames analyzed in current packet */ + + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int channelNb; + + /* Parameters For LTP scaling Control */ + opus_int frames_since_onset; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + silk_resampler_state_struct resampler_state; + + /* DTX */ + opus_int useDTX; /* Flag to enable DTX */ + opus_int inDTX; /* Flag to signal DTX period */ + opus_int noSpeechCounter; /* Counts concecutive nonactive frames, used by DTX */ + + /* Inband Low Bitrate Redundancy (LBRR) data */ + opus_int useInBandFEC; /* Saves the API setting for query */ + opus_int LBRR_enabled; /* Depends on useInBandFRC, bitrate and packet loss rate */ + opus_int LBRR_GainIncreases; /* Gains increment for coding LBRR frames */ + SideInfoIndices indices_LBRR[ MAX_FRAMES_PER_PACKET ]; + opus_int8 pulses_LBRR[ MAX_FRAMES_PER_PACKET ][ MAX_FRAME_LENGTH ]; +} silk_encoder_state; + + +/* Struct for Packet Loss Concealment */ +typedef struct { + opus_int32 pitchL_Q8; /* Pitch lag to use for voiced concealment */ + opus_int16 LTPCoef_Q14[ LTP_ORDER ]; /* LTP coeficients to use for voiced concealment */ + opus_int16 prevLPC_Q12[ MAX_LPC_ORDER ]; + opus_int last_frame_lost; /* Was previous frame lost */ + opus_int32 rand_seed; /* Seed for unvoiced signal generation */ + opus_int16 randScale_Q14; /* Scaling of unvoiced random signal */ + opus_int32 conc_energy; + opus_int conc_energy_shift; + opus_int16 prevLTP_scale_Q14; + opus_int32 prevGain_Q16[ 2 ]; + opus_int fs_kHz; + opus_int nb_subfr; + opus_int subfr_length; +} silk_PLC_struct; + +/* Struct for CNG */ +typedef struct { + opus_int32 CNG_exc_buf_Q14[ MAX_FRAME_LENGTH ]; + opus_int16 CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ]; + opus_int32 CNG_synth_state[ MAX_LPC_ORDER ]; + opus_int32 CNG_smth_Gain_Q16; + opus_int32 rand_seed; + opus_int fs_kHz; +} silk_CNG_struct; + +/********************************/ +/* Decoder state */ +/********************************/ +typedef struct { + opus_int32 prev_gain_Q16; + opus_int32 exc_Q14[ MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14_buf[ MAX_LPC_ORDER ]; + opus_int16 outBuf[ MAX_FRAME_LENGTH + 2 * MAX_SUB_FRAME_LENGTH ]; /* Buffer for output signal */ + opus_int lagPrev; /* Previous Lag */ + opus_int8 LastGainIndex; /* Previous gain index */ + opus_int fs_kHz; /* Sampling frequency in kHz */ + opus_int32 fs_API_hz; /* API sample frequency (Hz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int LPC_order; /* LPC order */ + opus_int16 prevNLSF_Q15[ MAX_LPC_ORDER ]; /* Used to interpolate LSFs */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + + /* For buffering payload in case of more frames per packet */ + opus_int nFramesDecoded; + opus_int nFramesPerPacket; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + opus_int VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + silk_resampler_state_struct resampler_state; + + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + + /* Quantization indices */ + SideInfoIndices indices; + + /* CNG state */ + silk_CNG_struct sCNG; + + /* Stuff used for PLC */ + opus_int lossCnt; + opus_int prevSignalType; + + silk_PLC_struct sPLC; + +} silk_decoder_state; + +/************************/ +/* Decoder control */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int pitchL[ MAX_NB_SUBFR ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + /* Holds interpolated and final coefficients, 4-byte aligned */ + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; +} silk_decoder_control; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/media/libopus/silk/sum_sqr_shift.c b/media/libopus/silk/sum_sqr_shift.c new file mode 100644 index 000000000000..246d5f4a27fb --- /dev/null +++ b/media/libopus/silk/sum_sqr_shift.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +) +{ + opus_int i, shft; + opus_int32 nrg_tmp, nrg; + + nrg = 0; + shft = 0; + len--; + for( i = 0; i < len; i += 2 ) { + nrg = silk_SMLABB_ovflw( nrg, x[ i ], x[ i ] ); + nrg = silk_SMLABB_ovflw( nrg, x[ i + 1 ], x[ i + 1 ] ); + if( nrg < 0 ) { + /* Scale down */ + nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 ); + shft = 2; + break; + } + } + for( ; i < len; i += 2 ) { + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, (opus_uint32)nrg_tmp, shft ); + if( nrg < 0 ) { + /* Scale down */ + nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 ); + shft += 2; + } + } + if( i == len ) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + + /* Make sure to have at least one extra leading zero (two leading zeros in total) */ + if( nrg & 0xC0000000 ) { + nrg = silk_RSHIFT_uint( (opus_uint32)nrg, 2 ); + shft += 2; + } + + /* Output arguments */ + *shift = shft; + *energy = nrg; +} + diff --git a/media/libopus/silk/table_LSF_cos.c b/media/libopus/silk/table_LSF_cos.c new file mode 100644 index 000000000000..7c9c747dbd2d --- /dev/null +++ b/media/libopus/silk/table_LSF_cos.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +/* Cosine approximation table for LSF conversion */ +/* Q12 values (even) */ +const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ] = { + 8192, 8190, 8182, 8170, + 8152, 8130, 8104, 8072, + 8034, 7994, 7946, 7896, + 7840, 7778, 7714, 7644, + 7568, 7490, 7406, 7318, + 7226, 7128, 7026, 6922, + 6812, 6698, 6580, 6458, + 6332, 6204, 6070, 5934, + 5792, 5648, 5502, 5352, + 5198, 5040, 4880, 4718, + 4552, 4382, 4212, 4038, + 3862, 3684, 3502, 3320, + 3136, 2948, 2760, 2570, + 2378, 2186, 1990, 1794, + 1598, 1400, 1202, 1002, + 802, 602, 402, 202, + 0, -202, -402, -602, + -802, -1002, -1202, -1400, + -1598, -1794, -1990, -2186, + -2378, -2570, -2760, -2948, + -3136, -3320, -3502, -3684, + -3862, -4038, -4212, -4382, + -4552, -4718, -4880, -5040, + -5198, -5352, -5502, -5648, + -5792, -5934, -6070, -6204, + -6332, -6458, -6580, -6698, + -6812, -6922, -7026, -7128, + -7226, -7318, -7406, -7490, + -7568, -7644, -7714, -7778, + -7840, -7896, -7946, -7994, + -8034, -8072, -8104, -8130, + -8152, -8170, -8182, -8190, + -8192 +}; diff --git a/media/libopus/silk/tables.h b/media/libopus/silk/tables.h new file mode 100644 index 000000000000..813fadd14065 --- /dev/null +++ b/media/libopus/silk/tables.h @@ -0,0 +1,120 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_TABLES_H +#define SILK_TABLES_H + +#include "define.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Entropy coding tables (with size in bytes indicated) */ +extern const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ]; /* 24 */ +extern const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ]; /* 41 */ + +extern const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ];/* 32 */ +extern const opus_uint8 silk_pitch_delta_iCDF[ 21 ]; /* 21 */ +extern const opus_uint8 silk_pitch_contour_iCDF[ 34 ]; /* 34 */ +extern const opus_uint8 silk_pitch_contour_NB_iCDF[ 11 ]; /* 11 */ +extern const opus_uint8 silk_pitch_contour_10_ms_iCDF[ 12 ]; /* 12 */ +extern const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[ 3 ]; /* 3 */ + +extern const opus_uint8 silk_pulses_per_block_iCDF[ N_RATE_LEVELS ][ MAX_PULSES + 2 ]; /* 180 */ +extern const opus_uint8 silk_pulses_per_block_BITS_Q5[ N_RATE_LEVELS - 1 ][ MAX_PULSES + 2 ]; /* 162 */ + +extern const opus_uint8 silk_rate_levels_iCDF[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ +extern const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ + +extern const opus_uint8 silk_max_pulses_table[ 4 ]; /* 4 */ + +extern const opus_uint8 silk_shell_code_table0[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table1[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table2[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table3[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table_offsets[ MAX_PULSES + 1 ]; /* 17 */ + +extern const opus_uint8 silk_lsb_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 silk_sign_iCDF[ 42 ]; /* 42 */ + +extern const opus_uint8 silk_uniform3_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 silk_uniform4_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_uniform5_iCDF[ 5 ]; /* 5 */ +extern const opus_uint8 silk_uniform6_iCDF[ 6 ]; /* 6 */ +extern const opus_uint8 silk_uniform8_iCDF[ 8 ]; /* 8 */ + +extern const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ]; /* 7 */ + +extern const opus_uint8 silk_LTP_per_index_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_int16 silk_LTP_gain_middle_avg_RD_Q14; +extern const opus_int8 * const silk_LTP_vq_ptrs_Q7[ NB_LTP_CBKS ]; /* 168 */ +extern const opus_int8 silk_LTP_vq_sizes[ NB_LTP_CBKS ]; /* 3 */ + +extern const opus_uint8 silk_LTPscale_iCDF[ 3 ]; /* 4 */ +extern const opus_int16 silk_LTPScales_table_Q14[ 3 ]; /* 6 */ + +extern const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ]; /* 2 */ + +extern const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ]; /* 32 */ +extern const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ]; /* 25 */ +extern const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ]; /* 10 */ + +extern const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ]; /* 5 */ + +extern const silk_NLSF_CB_struct silk_NLSF_CB_WB; /* 1040 */ +extern const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB; /* 728 */ + +/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */ +extern const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ]; /* 32 */ +extern const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ]; /* 32 */ +extern const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ]; /* 32 */ +extern const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ]; /* 32 */ + +/* Quantization offsets */ +extern const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; /* 8 */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +extern const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ]; /* 60 */ +extern const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ]; /* 60 */ + +/* Rom table with cosine values */ +extern const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ]; /* 258 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/media/libopus/silk/tables_LTP.c b/media/libopus/silk/tables_LTP.c new file mode 100644 index 000000000000..bc9c4e45b9e8 --- /dev/null +++ b/media/libopus/silk/tables_LTP.c @@ -0,0 +1,272 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_LTP_per_index_iCDF[3] = { + 179, 99, 0 +}; + +const opus_uint8 silk_LTP_gain_iCDF_0[8] = { + 71, 56, 43, 30, 21, 12, 6, 0 +}; + +const opus_uint8 silk_LTP_gain_iCDF_1[16] = { + 199, 165, 144, 124, 109, 96, 84, 71, + 61, 51, 42, 32, 23, 15, 8, 0 +}; + +const opus_uint8 silk_LTP_gain_iCDF_2[32] = { + 241, 225, 211, 199, 187, 175, 164, 153, + 142, 132, 123, 114, 105, 96, 88, 80, + 72, 64, 57, 50, 44, 38, 33, 29, + 24, 20, 16, 12, 9, 5, 2, 0 +}; + +const opus_int16 silk_LTP_gain_middle_avg_RD_Q14 = 12304; + +const opus_uint8 silk_LTP_gain_BITS_Q5_0[8] = { + 15, 131, 138, 138, 155, 155, 173, 173 +}; + +const opus_uint8 silk_LTP_gain_BITS_Q5_1[16] = { + 69, 93, 115, 118, 131, 138, 141, 138, + 150, 150, 155, 150, 155, 160, 166, 160 +}; + +const opus_uint8 silk_LTP_gain_BITS_Q5_2[32] = { + 131, 128, 134, 141, 141, 141, 145, 145, + 145, 150, 155, 155, 155, 155, 160, 160, + 160, 160, 166, 166, 173, 173, 182, 192, + 182, 192, 192, 192, 205, 192, 205, 224 +}; + +const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_iCDF_0, + silk_LTP_gain_iCDF_1, + silk_LTP_gain_iCDF_2 +}; + +const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_BITS_Q5_0, + silk_LTP_gain_BITS_Q5_1, + silk_LTP_gain_BITS_Q5_2 +}; + +const opus_int8 silk_LTP_gain_vq_0[8][5] = +{ +{ + 4, 6, 24, 7, 5 +}, +{ + 0, 0, 2, 0, 0 +}, +{ + 12, 28, 41, 13, -4 +}, +{ + -9, 15, 42, 25, 14 +}, +{ + 1, -2, 62, 41, -9 +}, +{ + -10, 37, 65, -4, 3 +}, +{ + -6, 4, 66, 7, -8 +}, +{ + 16, 14, 38, -3, 33 +} +}; + +const opus_int8 silk_LTP_gain_vq_1[16][5] = +{ +{ + 13, 22, 39, 23, 12 +}, +{ + -1, 36, 64, 27, -6 +}, +{ + -7, 10, 55, 43, 17 +}, +{ + 1, 1, 8, 1, 1 +}, +{ + 6, -11, 74, 53, -9 +}, +{ + -12, 55, 76, -12, 8 +}, +{ + -3, 3, 93, 27, -4 +}, +{ + 26, 39, 59, 3, -8 +}, +{ + 2, 0, 77, 11, 9 +}, +{ + -8, 22, 44, -6, 7 +}, +{ + 40, 9, 26, 3, 9 +}, +{ + -7, 20, 101, -7, 4 +}, +{ + 3, -8, 42, 26, 0 +}, +{ + -15, 33, 68, 2, 23 +}, +{ + -2, 55, 46, -2, 15 +}, +{ + 3, -1, 21, 16, 41 +} +}; + +const opus_int8 silk_LTP_gain_vq_2[32][5] = +{ +{ + -6, 27, 61, 39, 5 +}, +{ + -11, 42, 88, 4, 1 +}, +{ + -2, 60, 65, 6, -4 +}, +{ + -1, -5, 73, 56, 1 +}, +{ + -9, 19, 94, 29, -9 +}, +{ + 0, 12, 99, 6, 4 +}, +{ + 8, -19, 102, 46, -13 +}, +{ + 3, 2, 13, 3, 2 +}, +{ + 9, -21, 84, 72, -18 +}, +{ + -11, 46, 104, -22, 8 +}, +{ + 18, 38, 48, 23, 0 +}, +{ + -16, 70, 83, -21, 11 +}, +{ + 5, -11, 117, 22, -8 +}, +{ + -6, 23, 117, -12, 3 +}, +{ + 3, -8, 95, 28, 4 +}, +{ + -10, 15, 77, 60, -15 +}, +{ + -1, 4, 124, 2, -4 +}, +{ + 3, 38, 84, 24, -25 +}, +{ + 2, 13, 42, 13, 31 +}, +{ + 21, -4, 56, 46, -1 +}, +{ + -1, 35, 79, -13, 19 +}, +{ + -7, 65, 88, -9, -14 +}, +{ + 20, 4, 81, 49, -29 +}, +{ + 20, 0, 75, 3, -17 +}, +{ + 5, -9, 44, 92, -8 +}, +{ + 1, -3, 22, 69, 31 +}, +{ + -6, 95, 41, -12, 5 +}, +{ + 39, 67, 16, -4, 1 +}, +{ + 0, -6, 120, 55, -36 +}, +{ + -13, 44, 122, 4, -24 +}, +{ + 81, 5, 11, 3, 7 +}, +{ + 2, 0, 9, 10, 88 +} +}; + +const opus_int8 * const silk_LTP_vq_ptrs_Q7[NB_LTP_CBKS] = { + (opus_int8 *)&silk_LTP_gain_vq_0[0][0], + (opus_int8 *)&silk_LTP_gain_vq_1[0][0], + (opus_int8 *)&silk_LTP_gain_vq_2[0][0] +}; + +const opus_int8 silk_LTP_vq_sizes[NB_LTP_CBKS] = { + 8, 16, 32 +}; diff --git a/media/libopus/silk/tables_NLSF_CB_NB_MB.c b/media/libopus/silk/tables_NLSF_CB_NB_MB.c new file mode 100644 index 000000000000..8890a613eb13 --- /dev/null +++ b/media/libopus/silk/tables_NLSF_CB_NB_MB.c @@ -0,0 +1,159 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_NLSF_CB1_NB_MB_Q8[ 320 ] = { + 12, 35, 60, 83, 108, 132, 157, 180, + 206, 228, 15, 32, 55, 77, 101, 125, + 151, 175, 201, 225, 19, 42, 66, 89, + 114, 137, 162, 184, 209, 230, 12, 25, + 50, 72, 97, 120, 147, 172, 200, 223, + 26, 44, 69, 90, 114, 135, 159, 180, + 205, 225, 13, 22, 53, 80, 106, 130, + 156, 180, 205, 228, 15, 25, 44, 64, + 90, 115, 142, 168, 196, 222, 19, 24, + 62, 82, 100, 120, 145, 168, 190, 214, + 22, 31, 50, 79, 103, 120, 151, 170, + 203, 227, 21, 29, 45, 65, 106, 124, + 150, 171, 196, 224, 30, 49, 75, 97, + 121, 142, 165, 186, 209, 229, 19, 25, + 52, 70, 93, 116, 143, 166, 192, 219, + 26, 34, 62, 75, 97, 118, 145, 167, + 194, 217, 25, 33, 56, 70, 91, 113, + 143, 165, 196, 223, 21, 34, 51, 72, + 97, 117, 145, 171, 196, 222, 20, 29, + 50, 67, 90, 117, 144, 168, 197, 221, + 22, 31, 48, 66, 95, 117, 146, 168, + 196, 222, 24, 33, 51, 77, 116, 134, + 158, 180, 200, 224, 21, 28, 70, 87, + 106, 124, 149, 170, 194, 217, 26, 33, + 53, 64, 83, 117, 152, 173, 204, 225, + 27, 34, 65, 95, 108, 129, 155, 174, + 210, 225, 20, 26, 72, 99, 113, 131, + 154, 176, 200, 219, 34, 43, 61, 78, + 93, 114, 155, 177, 205, 229, 23, 29, + 54, 97, 124, 138, 163, 179, 209, 229, + 30, 38, 56, 89, 118, 129, 158, 178, + 200, 231, 21, 29, 49, 63, 85, 111, + 142, 163, 193, 222, 27, 48, 77, 103, + 133, 158, 179, 196, 215, 232, 29, 47, + 74, 99, 124, 151, 176, 198, 220, 237, + 33, 42, 61, 76, 93, 121, 155, 174, + 207, 225, 29, 53, 87, 112, 136, 154, + 170, 188, 208, 227, 24, 30, 52, 84, + 131, 150, 166, 186, 203, 229, 37, 48, + 64, 84, 104, 118, 156, 177, 201, 230 +}; + +const opus_uint8 silk_NLSF_CB1_iCDF_NB_MB[ 64 ] = { + 212, 178, 148, 129, 108, 96, 85, 82, + 79, 77, 61, 59, 57, 56, 51, 49, + 48, 45, 42, 41, 40, 38, 36, 34, + 31, 30, 21, 12, 10, 3, 1, 0, + 255, 245, 244, 236, 233, 225, 217, 203, + 190, 176, 175, 161, 149, 136, 125, 114, + 102, 91, 81, 71, 60, 52, 43, 35, + 28, 20, 19, 18, 12, 11, 5, 0 +}; + +const opus_uint8 silk_NLSF_CB2_SELECT_NB_MB[ 160 ] = { + 16, 0, 0, 0, 0, 99, 66, 36, + 36, 34, 36, 34, 34, 34, 34, 83, + 69, 36, 52, 34, 116, 102, 70, 68, + 68, 176, 102, 68, 68, 34, 65, 85, + 68, 84, 36, 116, 141, 152, 139, 170, + 132, 187, 184, 216, 137, 132, 249, 168, + 185, 139, 104, 102, 100, 68, 68, 178, + 218, 185, 185, 170, 244, 216, 187, 187, + 170, 244, 187, 187, 219, 138, 103, 155, + 184, 185, 137, 116, 183, 155, 152, 136, + 132, 217, 184, 184, 170, 164, 217, 171, + 155, 139, 244, 169, 184, 185, 170, 164, + 216, 223, 218, 138, 214, 143, 188, 218, + 168, 244, 141, 136, 155, 170, 168, 138, + 220, 219, 139, 164, 219, 202, 216, 137, + 168, 186, 246, 185, 139, 116, 185, 219, + 185, 138, 100, 100, 134, 100, 102, 34, + 68, 68, 100, 68, 168, 203, 221, 218, + 168, 167, 154, 136, 104, 70, 164, 246, + 171, 137, 139, 137, 155, 218, 219, 139 +}; + +const opus_uint8 silk_NLSF_CB2_iCDF_NB_MB[ 72 ] = { + 255, 254, 253, 238, 14, 3, 2, 1, + 0, 255, 254, 252, 218, 35, 3, 2, + 1, 0, 255, 254, 250, 208, 59, 4, + 2, 1, 0, 255, 254, 246, 194, 71, + 10, 2, 1, 0, 255, 252, 236, 183, + 82, 8, 2, 1, 0, 255, 252, 235, + 180, 90, 17, 2, 1, 0, 255, 248, + 224, 171, 97, 30, 4, 1, 0, 255, + 254, 236, 173, 95, 37, 7, 1, 0 +}; + +const opus_uint8 silk_NLSF_CB2_BITS_NB_MB_Q5[ 72 ] = { + 255, 255, 255, 131, 6, 145, 255, 255, + 255, 255, 255, 236, 93, 15, 96, 255, + 255, 255, 255, 255, 194, 83, 25, 71, + 221, 255, 255, 255, 255, 162, 73, 34, + 66, 162, 255, 255, 255, 210, 126, 73, + 43, 57, 173, 255, 255, 255, 201, 125, + 71, 48, 58, 130, 255, 255, 255, 166, + 110, 73, 57, 62, 104, 210, 255, 255, + 251, 123, 65, 55, 68, 100, 171, 255 +}; + +const opus_uint8 silk_NLSF_PRED_NB_MB_Q8[ 18 ] = { + 179, 138, 140, 148, 151, 149, 153, 151, + 163, 116, 67, 82, 59, 92, 72, 100, + 89, 92 +}; + +const opus_int16 silk_NLSF_DELTA_MIN_NB_MB_Q15[ 11 ] = { + 250, 3, 6, 3, 3, 3, 4, 3, + 3, 3, 461 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB = +{ + 32, + 10, + SILK_FIX_CONST( 0.18, 16 ), + SILK_FIX_CONST( 1.0 / 0.18, 6 ), + silk_NLSF_CB1_NB_MB_Q8, + silk_NLSF_CB1_iCDF_NB_MB, + silk_NLSF_PRED_NB_MB_Q8, + silk_NLSF_CB2_SELECT_NB_MB, + silk_NLSF_CB2_iCDF_NB_MB, + silk_NLSF_CB2_BITS_NB_MB_Q5, + silk_NLSF_DELTA_MIN_NB_MB_Q15, +}; diff --git a/media/libopus/silk/tables_NLSF_CB_WB.c b/media/libopus/silk/tables_NLSF_CB_WB.c new file mode 100644 index 000000000000..d980bca85a62 --- /dev/null +++ b/media/libopus/silk/tables_NLSF_CB_WB.c @@ -0,0 +1,198 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_NLSF_CB1_WB_Q8[ 512 ] = { + 7, 23, 38, 54, 69, 85, 100, 116, + 131, 147, 162, 178, 193, 208, 223, 239, + 13, 25, 41, 55, 69, 83, 98, 112, + 127, 142, 157, 171, 187, 203, 220, 236, + 15, 21, 34, 51, 61, 78, 92, 106, + 126, 136, 152, 167, 185, 205, 225, 240, + 10, 21, 36, 50, 63, 79, 95, 110, + 126, 141, 157, 173, 189, 205, 221, 237, + 17, 20, 37, 51, 59, 78, 89, 107, + 123, 134, 150, 164, 184, 205, 224, 240, + 10, 15, 32, 51, 67, 81, 96, 112, + 129, 142, 158, 173, 189, 204, 220, 236, + 8, 21, 37, 51, 65, 79, 98, 113, + 126, 138, 155, 168, 179, 192, 209, 218, + 12, 15, 34, 55, 63, 78, 87, 108, + 118, 131, 148, 167, 185, 203, 219, 236, + 16, 19, 32, 36, 56, 79, 91, 108, + 118, 136, 154, 171, 186, 204, 220, 237, + 11, 28, 43, 58, 74, 89, 105, 120, + 135, 150, 165, 180, 196, 211, 226, 241, + 6, 16, 33, 46, 60, 75, 92, 107, + 123, 137, 156, 169, 185, 199, 214, 225, + 11, 19, 30, 44, 57, 74, 89, 105, + 121, 135, 152, 169, 186, 202, 218, 234, + 12, 19, 29, 46, 57, 71, 88, 100, + 120, 132, 148, 165, 182, 199, 216, 233, + 17, 23, 35, 46, 56, 77, 92, 106, + 123, 134, 152, 167, 185, 204, 222, 237, + 14, 17, 45, 53, 63, 75, 89, 107, + 115, 132, 151, 171, 188, 206, 221, 240, + 9, 16, 29, 40, 56, 71, 88, 103, + 119, 137, 154, 171, 189, 205, 222, 237, + 16, 19, 36, 48, 57, 76, 87, 105, + 118, 132, 150, 167, 185, 202, 218, 236, + 12, 17, 29, 54, 71, 81, 94, 104, + 126, 136, 149, 164, 182, 201, 221, 237, + 15, 28, 47, 62, 79, 97, 115, 129, + 142, 155, 168, 180, 194, 208, 223, 238, + 8, 14, 30, 45, 62, 78, 94, 111, + 127, 143, 159, 175, 192, 207, 223, 239, + 17, 30, 49, 62, 79, 92, 107, 119, + 132, 145, 160, 174, 190, 204, 220, 235, + 14, 19, 36, 45, 61, 76, 91, 108, + 121, 138, 154, 172, 189, 205, 222, 238, + 12, 18, 31, 45, 60, 76, 91, 107, + 123, 138, 154, 171, 187, 204, 221, 236, + 13, 17, 31, 43, 53, 70, 83, 103, + 114, 131, 149, 167, 185, 203, 220, 237, + 17, 22, 35, 42, 58, 78, 93, 110, + 125, 139, 155, 170, 188, 206, 224, 240, + 8, 15, 34, 50, 67, 83, 99, 115, + 131, 146, 162, 178, 193, 209, 224, 239, + 13, 16, 41, 66, 73, 86, 95, 111, + 128, 137, 150, 163, 183, 206, 225, 241, + 17, 25, 37, 52, 63, 75, 92, 102, + 119, 132, 144, 160, 175, 191, 212, 231, + 19, 31, 49, 65, 83, 100, 117, 133, + 147, 161, 174, 187, 200, 213, 227, 242, + 18, 31, 52, 68, 88, 103, 117, 126, + 138, 149, 163, 177, 192, 207, 223, 239, + 16, 29, 47, 61, 76, 90, 106, 119, + 133, 147, 161, 176, 193, 209, 224, 240, + 15, 21, 35, 50, 61, 73, 86, 97, + 110, 119, 129, 141, 175, 198, 218, 237 +}; + +const opus_uint8 silk_NLSF_CB1_iCDF_WB[ 64 ] = { + 225, 204, 201, 184, 183, 175, 158, 154, + 153, 135, 119, 115, 113, 110, 109, 99, + 98, 95, 79, 68, 52, 50, 48, 45, + 43, 32, 31, 27, 18, 10, 3, 0, + 255, 251, 235, 230, 212, 201, 196, 182, + 167, 166, 163, 151, 138, 124, 110, 104, + 90, 78, 76, 70, 69, 57, 45, 34, + 24, 21, 11, 6, 5, 4, 3, 0 +}; + +const opus_uint8 silk_NLSF_CB2_SELECT_WB[ 256 ] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 100, 102, 102, 68, 68, 36, 34, 96, + 164, 107, 158, 185, 180, 185, 139, 102, + 64, 66, 36, 34, 34, 0, 1, 32, + 208, 139, 141, 191, 152, 185, 155, 104, + 96, 171, 104, 166, 102, 102, 102, 132, + 1, 0, 0, 0, 0, 16, 16, 0, + 80, 109, 78, 107, 185, 139, 103, 101, + 208, 212, 141, 139, 173, 153, 123, 103, + 36, 0, 0, 0, 0, 0, 0, 1, + 48, 0, 0, 0, 0, 0, 0, 32, + 68, 135, 123, 119, 119, 103, 69, 98, + 68, 103, 120, 118, 118, 102, 71, 98, + 134, 136, 157, 184, 182, 153, 139, 134, + 208, 168, 248, 75, 189, 143, 121, 107, + 32, 49, 34, 34, 34, 0, 17, 2, + 210, 235, 139, 123, 185, 137, 105, 134, + 98, 135, 104, 182, 100, 183, 171, 134, + 100, 70, 68, 70, 66, 66, 34, 131, + 64, 166, 102, 68, 36, 2, 1, 0, + 134, 166, 102, 68, 34, 34, 66, 132, + 212, 246, 158, 139, 107, 107, 87, 102, + 100, 219, 125, 122, 137, 118, 103, 132, + 114, 135, 137, 105, 171, 106, 50, 34, + 164, 214, 141, 143, 185, 151, 121, 103, + 192, 34, 0, 0, 0, 0, 0, 1, + 208, 109, 74, 187, 134, 249, 159, 137, + 102, 110, 154, 118, 87, 101, 119, 101, + 0, 2, 0, 36, 36, 66, 68, 35, + 96, 164, 102, 100, 36, 0, 2, 33, + 167, 138, 174, 102, 100, 84, 2, 2, + 100, 107, 120, 119, 36, 197, 24, 0 +}; + +const opus_uint8 silk_NLSF_CB2_iCDF_WB[ 72 ] = { + 255, 254, 253, 244, 12, 3, 2, 1, + 0, 255, 254, 252, 224, 38, 3, 2, + 1, 0, 255, 254, 251, 209, 57, 4, + 2, 1, 0, 255, 254, 244, 195, 69, + 4, 2, 1, 0, 255, 251, 232, 184, + 84, 7, 2, 1, 0, 255, 254, 240, + 186, 86, 14, 2, 1, 0, 255, 254, + 239, 178, 91, 30, 5, 1, 0, 255, + 248, 227, 177, 100, 19, 2, 1, 0 +}; + +const opus_uint8 silk_NLSF_CB2_BITS_WB_Q5[ 72 ] = { + 255, 255, 255, 156, 4, 154, 255, 255, + 255, 255, 255, 227, 102, 15, 92, 255, + 255, 255, 255, 255, 213, 83, 24, 72, + 236, 255, 255, 255, 255, 150, 76, 33, + 63, 214, 255, 255, 255, 190, 121, 77, + 43, 55, 185, 255, 255, 255, 245, 137, + 71, 43, 59, 139, 255, 255, 255, 255, + 131, 66, 50, 66, 107, 194, 255, 255, + 166, 116, 76, 55, 53, 125, 255, 255 +}; + +const opus_uint8 silk_NLSF_PRED_WB_Q8[ 30 ] = { + 175, 148, 160, 176, 178, 173, 174, 164, + 177, 174, 196, 182, 198, 192, 182, 68, + 62, 66, 60, 72, 117, 85, 90, 118, + 136, 151, 142, 160, 142, 155 +}; + +const opus_int16 silk_NLSF_DELTA_MIN_WB_Q15[ 17 ] = { + 100, 3, 40, 3, 3, 3, 5, 14, + 14, 10, 11, 3, 8, 9, 7, 3, + 347 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_WB = +{ + 32, + 16, + SILK_FIX_CONST( 0.15, 16 ), + SILK_FIX_CONST( 1.0 / 0.15, 6 ), + silk_NLSF_CB1_WB_Q8, + silk_NLSF_CB1_iCDF_WB, + silk_NLSF_PRED_WB_Q8, + silk_NLSF_CB2_SELECT_WB, + silk_NLSF_CB2_iCDF_WB, + silk_NLSF_CB2_BITS_WB_Q5, + silk_NLSF_DELTA_MIN_WB_Q15, +}; + diff --git a/media/libopus/silk/tables_gain.c b/media/libopus/silk/tables_gain.c new file mode 100644 index 000000000000..e0fb9838c1f6 --- /dev/null +++ b/media/libopus/silk/tables_gain.c @@ -0,0 +1,63 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ] = +{ +{ + 224, 112, 44, 15, 3, 2, 1, 0 +}, +{ + 254, 237, 192, 132, 70, 23, 4, 0 +}, +{ + 255, 252, 226, 155, 61, 11, 2, 0 +} +}; + +const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ] = { + 250, 245, 234, 203, 71, 50, 42, 38, + 35, 33, 31, 29, 28, 27, 26, 25, + 24, 23, 22, 21, 20, 19, 18, 17, + 16, 15, 14, 13, 12, 11, 10, 9, + 8, 7, 6, 5, 4, 3, 2, 1, + 0 +}; + +#ifdef __cplusplus +} +#endif diff --git a/media/libopus/silk/tables_other.c b/media/libopus/silk/tables_other.c new file mode 100644 index 000000000000..9a3313924cef --- /dev/null +++ b/media/libopus/silk/tables_other.c @@ -0,0 +1,138 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "structs.h" +#include "define.h" +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */ +const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ] = { + 0, 8000, 9400, 11500, 13500, 17500, 25000, MAX_TARGET_RATE_BPS +}; +const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ] = { + 0, 9000, 12000, 14500, 18500, 24500, 35500, MAX_TARGET_RATE_BPS +}; +const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ] = { + 0, 10500, 14000, 17000, 21500, 28500, 42000, MAX_TARGET_RATE_BPS +}; +const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ] = { + 18, 29, 38, 40, 46, 52, 62, 84 +}; + +/* Tables for stereo predictor coding */ +const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ] = { + -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, + 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732 +}; +const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ] = { + 249, 247, 246, 245, 244, + 234, 210, 202, 201, 200, + 197, 174, 82, 59, 56, + 55, 54, 46, 22, 12, + 11, 10, 9, 7, 0 +}; +const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ] = { 64, 0 }; + +/* Tables for LBRR flags */ +const opus_uint8 silk_LBRR_flags_2_iCDF[ 3 ] = { 203, 150, 0 }; +const opus_uint8 silk_LBRR_flags_3_iCDF[ 7 ] = { 215, 195, 166, 125, 110, 82, 0 }; +const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ] = { + silk_LBRR_flags_2_iCDF, + silk_LBRR_flags_3_iCDF +}; + +/* Table for LSB coding */ +const opus_uint8 silk_lsb_iCDF[ 2 ] = { 120, 0 }; + +/* Tables for LTPScale */ +const opus_uint8 silk_LTPscale_iCDF[ 3 ] = { 128, 64, 0 }; + +/* Tables for signal type and offset coding */ +const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ] = { + 232, 158, 10, 0 +}; +const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ] = { + 230, 0 +}; + +/* Tables for NLSF interpolation factor */ +const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ] = { 243, 221, 192, 181, 0 }; + +/* Quantization offsets */ +const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = { + { OFFSET_UVL_Q10, OFFSET_UVH_Q10 }, { OFFSET_VL_Q10, OFFSET_VH_Q10 } +}; + +/* Table for LTPScale */ +const opus_int16 silk_LTPScales_table_Q14[ 3 ] = { 15565, 12288, 8192 }; + +/* Uniform entropy tables */ +const opus_uint8 silk_uniform3_iCDF[ 3 ] = { 171, 85, 0 }; +const opus_uint8 silk_uniform4_iCDF[ 4 ] = { 192, 128, 64, 0 }; +const opus_uint8 silk_uniform5_iCDF[ 5 ] = { 205, 154, 102, 51, 0 }; +const opus_uint8 silk_uniform6_iCDF[ 6 ] = { 213, 171, 128, 85, 43, 0 }; +const opus_uint8 silk_uniform8_iCDF[ 8 ] = { 224, 192, 160, 128, 96, 64, 32, 0 }; + +const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ] = { 100, 40, 16, 7, 3, 1, 0 }; + +/* Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ] = +{ +{ 250767114, 501534038, 250767114 }, +{ 209867381, 419732057, 209867381 }, +{ 170987846, 341967853, 170987846 }, +{ 131531482, 263046905, 131531482 }, +{ 89306658, 178584282, 89306658 } +}; + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] = +{ +{ 506393414, 239854379 }, +{ 411067935, 169683996 }, +{ 306733530, 116694253 }, +{ 185807084, 77959395 }, +{ 35497197, 57401098 } +}; + +#ifdef __cplusplus +} +#endif + diff --git a/media/libopus/silk/tables_pitch_lag.c b/media/libopus/silk/tables_pitch_lag.c new file mode 100644 index 000000000000..e0d87f2df29c --- /dev/null +++ b/media/libopus/silk/tables_pitch_lag.c @@ -0,0 +1,69 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ] = { + 253, 250, 244, 233, 212, 182, 150, 131, + 120, 110, 98, 85, 72, 60, 49, 40, + 32, 25, 19, 15, 13, 11, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0 +}; + +const opus_uint8 silk_pitch_delta_iCDF[21] = { + 210, 208, 206, 203, 199, 193, 183, 168, + 142, 104, 74, 52, 37, 27, 20, 14, + 10, 6, 4, 2, 0 +}; + +const opus_uint8 silk_pitch_contour_iCDF[34] = { + 223, 201, 183, 167, 152, 138, 124, 111, + 98, 88, 79, 70, 62, 56, 50, 44, + 39, 35, 31, 27, 24, 21, 18, 16, + 14, 12, 10, 8, 6, 4, 3, 2, + 1, 0 +}; + +const opus_uint8 silk_pitch_contour_NB_iCDF[11] = { + 188, 176, 155, 138, 119, 97, 67, 43, + 26, 10, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_iCDF[12] = { + 165, 119, 80, 61, 47, 35, 27, 20, + 14, 9, 4, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[3] = { + 113, 63, 0 +}; + + diff --git a/media/libopus/silk/tables_pulses_per_block.c b/media/libopus/silk/tables_pulses_per_block.c new file mode 100644 index 000000000000..9859e32640b6 --- /dev/null +++ b/media/libopus/silk/tables_pulses_per_block.c @@ -0,0 +1,264 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_max_pulses_table[ 4 ] = { + 8, 10, 12, 16 +}; + +const opus_uint8 silk_pulses_per_block_iCDF[ 10 ][ 18 ] = { +{ + 125, 51, 26, 18, 15, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 198, 105, 45, 22, 15, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 213, 162, 116, 83, 59, 43, 32, 24, + 18, 15, 12, 9, 7, 6, 5, 3, + 2, 0 +}, +{ + 239, 187, 116, 59, 28, 16, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 250, 229, 188, 135, 86, 51, 30, 19, + 13, 10, 8, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 249, 235, 213, 185, 156, 128, 103, 83, + 66, 53, 42, 33, 26, 21, 17, 13, + 10, 0 +}, +{ + 254, 249, 235, 206, 164, 118, 77, 46, + 27, 16, 10, 7, 5, 4, 3, 2, + 1, 0 +}, +{ + 255, 253, 249, 239, 220, 191, 156, 119, + 85, 57, 37, 23, 15, 10, 6, 4, + 2, 0 +}, +{ + 255, 253, 251, 246, 237, 223, 203, 179, + 152, 124, 98, 75, 55, 40, 29, 21, + 15, 0 +}, +{ + 255, 254, 253, 247, 220, 162, 106, 67, + 42, 28, 18, 12, 9, 6, 4, 3, + 2, 0 +} +}; + +const opus_uint8 silk_pulses_per_block_BITS_Q5[ 9 ][ 18 ] = { +{ + 31, 57, 107, 160, 205, 205, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 69, 47, 67, 111, 166, 205, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 82, 74, 79, 95, 109, 128, 145, 160, + 173, 205, 205, 205, 224, 255, 255, 224, + 255, 224 +}, +{ + 125, 74, 59, 69, 97, 141, 182, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 173, 115, 85, 73, 76, 92, 115, 145, + 173, 205, 224, 224, 255, 255, 255, 255, + 255, 255 +}, +{ + 166, 134, 113, 102, 101, 102, 107, 118, + 125, 138, 145, 155, 166, 182, 192, 192, + 205, 150 +}, +{ + 224, 182, 134, 101, 83, 79, 85, 97, + 120, 145, 173, 205, 224, 255, 255, 255, + 255, 255 +}, +{ + 255, 224, 192, 150, 120, 101, 92, 89, + 93, 102, 118, 134, 160, 182, 192, 224, + 224, 224 +}, +{ + 255, 224, 224, 182, 155, 134, 118, 109, + 104, 102, 106, 111, 118, 131, 145, 160, + 173, 131 +} +}; + +const opus_uint8 silk_rate_levels_iCDF[ 2 ][ 9 ] = +{ +{ + 241, 190, 178, 132, 87, 74, 41, 14, + 0 +}, +{ + 223, 193, 157, 140, 106, 57, 39, 18, + 0 +} +}; + +const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ 9 ] = +{ +{ + 131, 74, 141, 79, 80, 138, 95, 104, + 134 +}, +{ + 95, 99, 91, 125, 93, 76, 123, 115, + 123 +} +}; + +const opus_uint8 silk_shell_code_table0[ 152 ] = { + 128, 0, 214, 42, 0, 235, 128, 21, + 0, 244, 184, 72, 11, 0, 248, 214, + 128, 42, 7, 0, 248, 225, 170, 80, + 25, 5, 0, 251, 236, 198, 126, 54, + 18, 3, 0, 250, 238, 211, 159, 82, + 35, 15, 5, 0, 250, 231, 203, 168, + 128, 88, 53, 25, 6, 0, 252, 238, + 216, 185, 148, 108, 71, 40, 18, 4, + 0, 253, 243, 225, 199, 166, 128, 90, + 57, 31, 13, 3, 0, 254, 246, 233, + 212, 183, 147, 109, 73, 44, 23, 10, + 2, 0, 255, 250, 240, 223, 198, 166, + 128, 90, 58, 33, 16, 6, 1, 0, + 255, 251, 244, 231, 210, 181, 146, 110, + 75, 46, 25, 12, 5, 1, 0, 255, + 253, 248, 238, 221, 196, 164, 128, 92, + 60, 35, 18, 8, 3, 1, 0, 255, + 253, 249, 242, 229, 208, 180, 146, 110, + 76, 48, 27, 14, 7, 3, 1, 0 +}; + +const opus_uint8 silk_shell_code_table1[ 152 ] = { + 129, 0, 207, 50, 0, 236, 129, 20, + 0, 245, 185, 72, 10, 0, 249, 213, + 129, 42, 6, 0, 250, 226, 169, 87, + 27, 4, 0, 251, 233, 194, 130, 62, + 20, 4, 0, 250, 236, 207, 160, 99, + 47, 17, 3, 0, 255, 240, 217, 182, + 131, 81, 41, 11, 1, 0, 255, 254, + 233, 201, 159, 107, 61, 20, 2, 1, + 0, 255, 249, 233, 206, 170, 128, 86, + 50, 23, 7, 1, 0, 255, 250, 238, + 217, 186, 148, 108, 70, 39, 18, 6, + 1, 0, 255, 252, 243, 226, 200, 166, + 128, 90, 56, 30, 13, 4, 1, 0, + 255, 252, 245, 231, 209, 180, 146, 110, + 76, 47, 25, 11, 4, 1, 0, 255, + 253, 248, 237, 219, 194, 163, 128, 93, + 62, 37, 19, 8, 3, 1, 0, 255, + 254, 250, 241, 226, 205, 177, 145, 111, + 79, 51, 30, 15, 6, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table2[ 152 ] = { + 129, 0, 203, 54, 0, 234, 129, 23, + 0, 245, 184, 73, 10, 0, 250, 215, + 129, 41, 5, 0, 252, 232, 173, 86, + 24, 3, 0, 253, 240, 200, 129, 56, + 15, 2, 0, 253, 244, 217, 164, 94, + 38, 10, 1, 0, 253, 245, 226, 189, + 132, 71, 27, 7, 1, 0, 253, 246, + 231, 203, 159, 105, 56, 23, 6, 1, + 0, 255, 248, 235, 213, 179, 133, 85, + 47, 19, 5, 1, 0, 255, 254, 243, + 221, 194, 159, 117, 70, 37, 12, 2, + 1, 0, 255, 254, 248, 234, 208, 171, + 128, 85, 48, 22, 8, 2, 1, 0, + 255, 254, 250, 240, 220, 189, 149, 107, + 67, 36, 16, 6, 2, 1, 0, 255, + 254, 251, 243, 227, 201, 166, 128, 90, + 55, 29, 13, 5, 2, 1, 0, 255, + 254, 252, 246, 234, 213, 183, 147, 109, + 73, 43, 22, 10, 4, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table3[ 152 ] = { + 130, 0, 200, 58, 0, 231, 130, 26, + 0, 244, 184, 76, 12, 0, 249, 214, + 130, 43, 6, 0, 252, 232, 173, 87, + 24, 3, 0, 253, 241, 203, 131, 56, + 14, 2, 0, 254, 246, 221, 167, 94, + 35, 8, 1, 0, 254, 249, 232, 193, + 130, 65, 23, 5, 1, 0, 255, 251, + 239, 211, 162, 99, 45, 15, 4, 1, + 0, 255, 251, 243, 223, 186, 131, 74, + 33, 11, 3, 1, 0, 255, 252, 245, + 230, 202, 158, 105, 57, 24, 8, 2, + 1, 0, 255, 253, 247, 235, 214, 179, + 132, 84, 44, 19, 7, 2, 1, 0, + 255, 254, 250, 240, 223, 196, 159, 112, + 69, 36, 15, 6, 2, 1, 0, 255, + 254, 253, 245, 231, 209, 176, 136, 93, + 55, 27, 11, 3, 2, 1, 0, 255, + 254, 253, 252, 239, 221, 194, 158, 117, + 76, 42, 18, 4, 3, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table_offsets[ 17 ] = { + 0, 0, 2, 5, 9, 14, 20, 27, + 35, 44, 54, 65, 77, 90, 104, 119, + 135 +}; + +const opus_uint8 silk_sign_iCDF[ 42 ] = { + 254, 49, 67, 77, 82, 93, 99, + 198, 11, 18, 24, 31, 36, 45, + 255, 46, 66, 78, 87, 94, 104, + 208, 14, 21, 32, 42, 51, 66, + 255, 94, 104, 109, 112, 115, 118, + 248, 53, 69, 80, 88, 95, 102 +}; diff --git a/media/libopus/silk/tuning_parameters.h b/media/libopus/silk/tuning_parameters.h new file mode 100644 index 000000000000..ff0d0b68d17f --- /dev/null +++ b/media/libopus/silk/tuning_parameters.h @@ -0,0 +1,168 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_TUNING_PARAMETERS_H +#define SILK_TUNING_PARAMETERS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decay time for bitreservoir */ +#define BITRESERVOIR_DECAY_TIME_MS 500 + +/*******************/ +/* Pitch estimator */ +/*******************/ + +/* Level of noise floor for whitening filter LPC analysis in pitch analysis */ +#define FIND_PITCH_WHITE_NOISE_FRACTION 1e-3f + +/* Bandwidth expansion for whitening filter in pitch analysis */ +#define FIND_PITCH_BANDWITH_EXPANSION 0.99f + +/*********************/ +/* Linear prediction */ +/*********************/ + +/* LPC analysis defines: regularization and bandwidth expansion */ +#define FIND_LPC_COND_FAC 1e-5f + +/* LTP analysis defines */ +#define FIND_LTP_COND_FAC 1e-5f +#define LTP_DAMPING 0.05f +#define LTP_SMOOTHING 0.1f + +/* LTP quantization settings */ +#define MU_LTP_QUANT_NB 0.03f +#define MU_LTP_QUANT_MB 0.025f +#define MU_LTP_QUANT_WB 0.02f + +/***********************/ +/* High pass filtering */ +/***********************/ + +/* Smoothing parameters for low end of pitch frequency range estimation */ +#define VARIABLE_HP_SMTH_COEF1 0.1f +#define VARIABLE_HP_SMTH_COEF2 0.015f +#define VARIABLE_HP_MAX_DELTA_FREQ 0.4f + +/* Min and max cut-off frequency values (-3 dB points) */ +#define VARIABLE_HP_MIN_CUTOFF_HZ 60 +#define VARIABLE_HP_MAX_CUTOFF_HZ 100 + +/***********/ +/* Various */ +/***********/ + +/* VAD threshold */ +#define SPEECH_ACTIVITY_DTX_THRES 0.05f + +/* Speech Activity LBRR enable threshold */ +#define LBRR_SPEECH_ACTIVITY_THRES 0.3f + +/*************************/ +/* Perceptual parameters */ +/*************************/ + +/* reduction in coding SNR during low speech activity */ +#define BG_SNR_DECR_dB 2.0f + +/* factor for reducing quantization noise during voiced speech */ +#define HARM_SNR_INCR_dB 2.0f + +/* factor for reducing quantization noise for unvoiced sparse signals */ +#define SPARSE_SNR_INCR_dB 2.0f + +/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */ +#define SPARSENESS_THRESHOLD_QNT_OFFSET 0.75f + +/* warping control */ +#define WARPING_MULTIPLIER 0.015f + +/* fraction added to first autocorrelation value */ +#define SHAPE_WHITE_NOISE_FRACTION 5e-5f + +/* noise shaping filter chirp factor */ +#define BANDWIDTH_EXPANSION 0.95f + +/* difference between chirp factors for analysis and synthesis noise shaping filters at low bitrates */ +#define LOW_RATE_BANDWIDTH_EXPANSION_DELTA 0.01f + +/* extra harmonic boosting (signal shaping) at low bitrates */ +#define LOW_RATE_HARMONIC_BOOST 0.1f + +/* extra harmonic boosting (signal shaping) for noisy input signals */ +#define LOW_INPUT_QUALITY_HARMONIC_BOOST 0.1f + +/* harmonic noise shaping */ +#define HARMONIC_SHAPING 0.3f + +/* extra harmonic noise shaping for high bitrates or noisy input */ +#define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING 0.2f + +/* parameter for shaping noise towards higher frequencies */ +#define HP_NOISE_COEF 0.25f + +/* parameter for shaping noise even more towards higher frequencies during voiced speech */ +#define HARM_HP_NOISE_COEF 0.35f + +/* parameter for applying a high-pass tilt to the input signal */ +#define INPUT_TILT 0.05f + +/* parameter for extra high-pass tilt to the input signal at high rates */ +#define HIGH_RATE_INPUT_TILT 0.1f + +/* parameter for reducing noise at the very low frequencies */ +#define LOW_FREQ_SHAPING 4.0f + +/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */ +#define LOW_QUALITY_LOW_FREQ_SHAPING_DECR 0.5f + +/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */ +#define SUBFR_SMTH_COEF 0.4f + +/* parameters defining the R/D tradeoff in the residual quantizer */ +#define LAMBDA_OFFSET 1.2f +#define LAMBDA_SPEECH_ACT -0.2f +#define LAMBDA_DELAYED_DECISIONS -0.05f +#define LAMBDA_INPUT_QUALITY -0.1f +#define LAMBDA_CODING_QUALITY -0.2f +#define LAMBDA_QUANT_OFFSET 0.8f + +/* Compensation in bitrate calculations for 10 ms modes */ +#define REDUCE_BITRATE_10_MS_BPS 2200 + +/* Maximum time before allowing a bandwidth transition */ +#define MAX_BANDWIDTH_SWITCH_DELAY_MS 5000 + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_TUNING_PARAMETERS_H */ diff --git a/media/libopus/silk/typedef.h b/media/libopus/silk/typedef.h new file mode 100644 index 000000000000..e259d75832fd --- /dev/null +++ b/media/libopus/silk/typedef.h @@ -0,0 +1,102 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_TYPEDEF_H +#define SILK_TYPEDEF_H + +#include "opus_types.h" + +#ifndef silk_USE_DOUBLE_PRECISION_FLOATS +#define silk_USE_DOUBLE_PRECISION_FLOATS 0 +#endif + +#include +#if defined( __GNUC__ ) +#include +#endif + +#define silk_int_ptr_size intptr_t + +#if silk_USE_DOUBLE_PRECISION_FLOATS +# define silk_float double +# define silk_float_MAX DBL_MAX +#else +# define silk_float float +# define silk_float_MAX FLT_MAX +#endif + +#ifdef _WIN32 +# define silk_STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y) +#else +# define silk_STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y) +#endif + +#define silk_int64_MAX ((opus_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */ +#define silk_int64_MIN ((opus_int64)0x8000000000000000LL) /* -2^63 */ +#define silk_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647 */ +#define silk_int32_MIN ((opus_int32)0x80000000) /* -2^31 = -2147483648 */ +#define silk_int16_MAX 0x7FFF /* 2^15 - 1 = 32767 */ +#define silk_int16_MIN ((opus_int16)0x8000) /* -2^15 = -32768 */ +#define silk_int8_MAX 0x7F /* 2^7 - 1 = 127 */ +#define silk_int8_MIN ((opus_int8)0x80) /* -2^7 = -128 */ + +#define silk_uint32_MAX 0xFFFFFFFF /* 2^32 - 1 = 4294967295 */ +#define silk_uint32_MIN 0x00000000 +#define silk_uint16_MAX 0xFFFF /* 2^16 - 1 = 65535 */ +#define silk_uint16_MIN 0x0000 +#define silk_uint8_MAX 0xFF /* 2^8 - 1 = 255 */ +#define silk_uint8_MIN 0x00 + +#define silk_TRUE 1 +#define silk_FALSE 0 + +/* assertions */ +#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS)) +# ifndef silk_assert +# include /* ASSERTE() */ +# define silk_assert(COND) _ASSERTE(COND) +# endif +#else +# ifdef ENABLE_ASSERTIONS +# include +# include +#define silk_fatal(str) _silk_fatal(str, __FILE__, __LINE__); +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +static inline void _silk_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +# define silk_assert(COND) {if (!(COND)) {silk_fatal("assertion failed: " #COND);}} +# else +# define silk_assert(COND) +# endif +#endif + +#endif /* SILK_TYPEDEF_H */ diff --git a/media/libopus/silk_sources.mk b/media/libopus/silk_sources.mk new file mode 100644 index 000000000000..0de367b43bbf --- /dev/null +++ b/media/libopus/silk_sources.mk @@ -0,0 +1,138 @@ +SILK_SOURCES = \ +silk/CNG.c \ +silk/code_signs.c \ +silk/init_decoder.c \ +silk/decode_core.c \ +silk/decode_frame.c \ +silk/decode_parameters.c \ +silk/decode_indices.c \ +silk/decode_pulses.c \ +silk/decoder_set_fs.c \ +silk/dec_API.c \ +silk/enc_API.c \ +silk/encode_indices.c \ +silk/encode_pulses.c \ +silk/gain_quant.c \ +silk/interpolate.c \ +silk/LP_variable_cutoff.c \ +silk/NLSF_decode.c \ +silk/NSQ.c \ +silk/NSQ_del_dec.c \ +silk/PLC.c \ +silk/shell_coder.c \ +silk/tables_gain.c \ +silk/tables_LTP.c \ +silk/tables_NLSF_CB_NB_MB.c \ +silk/tables_NLSF_CB_WB.c \ +silk/tables_other.c \ +silk/tables_pitch_lag.c \ +silk/tables_pulses_per_block.c \ +silk/VAD.c \ +silk/control_audio_bandwidth.c \ +silk/quant_LTP_gains.c \ +silk/VQ_WMat_EC.c \ +silk/HP_variable_cutoff.c \ +silk/NLSF_encode.c \ +silk/NLSF_VQ.c \ +silk/NLSF_unpack.c \ +silk/NLSF_del_dec_quant.c \ +silk/process_NLSFs.c \ +silk/stereo_LR_to_MS.c \ +silk/stereo_MS_to_LR.c \ +silk/check_control_input.c \ +silk/control_SNR.c \ +silk/init_encoder.c \ +silk/control_codec.c \ +silk/A2NLSF.c \ +silk/ana_filt_bank_1.c \ +silk/biquad_alt.c \ +silk/bwexpander_32.c \ +silk/bwexpander.c \ +silk/debug.c \ +silk/decode_pitch.c \ +silk/inner_prod_aligned.c \ +silk/lin2log.c \ +silk/log2lin.c \ +silk/LPC_analysis_filter.c \ +silk/LPC_inv_pred_gain.c \ +silk/table_LSF_cos.c \ +silk/NLSF2A.c \ +silk/NLSF_stabilize.c \ +silk/NLSF_VQ_weights_laroia.c \ +silk/pitch_est_tables.c \ +silk/resampler.c \ +silk/resampler_down2_3.c \ +silk/resampler_down2.c \ +silk/resampler_private_AR2.c \ +silk/resampler_private_down_FIR.c \ +silk/resampler_private_IIR_FIR.c \ +silk/resampler_private_up2_HQ.c \ +silk/resampler_rom.c \ +silk/sigm_Q15.c \ +silk/sort.c \ +silk/sum_sqr_shift.c \ +silk/stereo_decode_pred.c \ +silk/stereo_encode_pred.c \ +silk/stereo_find_predictor.c \ +silk/stereo_quant_pred.c + + +SILK_SOURCES_FIXED = \ +silk/fixed/LTP_analysis_filter_FIX.c \ +silk/fixed/LTP_scale_ctrl_FIX.c \ +silk/fixed/corrMatrix_FIX.c \ +silk/fixed/encode_frame_FIX.c \ +silk/fixed/find_LPC_FIX.c \ +silk/fixed/find_LTP_FIX.c \ +silk/fixed/find_pitch_lags_FIX.c \ +silk/fixed/find_pred_coefs_FIX.c \ +silk/fixed/noise_shape_analysis_FIX.c \ +silk/fixed/prefilter_FIX.c \ +silk/fixed/process_gains_FIX.c \ +silk/fixed/regularize_correlations_FIX.c \ +silk/fixed/residual_energy16_FIX.c \ +silk/fixed/residual_energy_FIX.c \ +silk/fixed/solve_LS_FIX.c \ +silk/fixed/warped_autocorrelation_FIX.c \ +silk/fixed/apply_sine_window_FIX.c \ +silk/fixed/autocorr_FIX.c \ +silk/fixed/burg_modified_FIX.c \ +silk/fixed/k2a_FIX.c \ +silk/fixed/k2a_Q16_FIX.c \ +silk/fixed/pitch_analysis_core_FIX.c \ +silk/fixed/vector_ops_FIX.c \ +silk/fixed/schur64_FIX.c \ +silk/fixed/schur_FIX.c + +SILK_SOURCES_FLOAT = \ +silk/float/apply_sine_window_FLP.c \ +silk/float/corrMatrix_FLP.c \ +silk/float/encode_frame_FLP.c \ +silk/float/find_LPC_FLP.c \ +silk/float/find_LTP_FLP.c \ +silk/float/find_pitch_lags_FLP.c \ +silk/float/find_pred_coefs_FLP.c \ +silk/float/LPC_analysis_filter_FLP.c \ +silk/float/LTP_analysis_filter_FLP.c \ +silk/float/LTP_scale_ctrl_FLP.c \ +silk/float/noise_shape_analysis_FLP.c \ +silk/float/prefilter_FLP.c \ +silk/float/process_gains_FLP.c \ +silk/float/regularize_correlations_FLP.c \ +silk/float/residual_energy_FLP.c \ +silk/float/solve_LS_FLP.c \ +silk/float/warped_autocorrelation_FLP.c \ +silk/float/wrappers_FLP.c \ +silk/float/autocorrelation_FLP.c \ +silk/float/burg_modified_FLP.c \ +silk/float/bwexpander_FLP.c \ +silk/float/energy_FLP.c \ +silk/float/inner_product_FLP.c \ +silk/float/k2a_FLP.c \ +silk/float/levinsondurbin_FLP.c \ +silk/float/LPC_inv_pred_gain_FLP.c \ +silk/float/pitch_analysis_core_FLP.c \ +silk/float/scale_copy_vector_FLP.c \ +silk/float/scale_vector_FLP.c \ +silk/float/schur_FLP.c \ +silk/float/sort_FLP.c diff --git a/media/libopus/src/opus.c b/media/libopus/src/opus.c new file mode 100644 index 000000000000..0d68dad0a436 --- /dev/null +++ b/media/libopus/src/opus.c @@ -0,0 +1,47 @@ +/* Copyright (c) 2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus.h" +#include "opus_private.h" + +int encode_size(int size, unsigned char *data) +{ + if (size < 252) + { + data[0] = size; + return 1; + } else { + data[0] = 252+(size&0x3); + data[1] = (size-(int)data[0])>>2; + return 2; + } +} + diff --git a/media/libopus/src/opus_decoder.c b/media/libopus/src/opus_decoder.c new file mode 100644 index 000000000000..889b5a4f3790 --- /dev/null +++ b/media/libopus/src/opus_decoder.c @@ -0,0 +1,936 @@ +/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "celt.h" +#include "opus.h" +#include "entdec.h" +#include "modes.h" +#include "API.h" +#include "stack_alloc.h" +#include "float_cast.h" +#include "opus_private.h" +#include "os_support.h" +#include "structs.h" +#include "define.h" + +struct OpusDecoder { + int celt_dec_offset; + int silk_dec_offset; + int channels; + opus_int32 Fs; /** Sampling rate (at the API level) */ + silk_DecControlStruct DecControl; + + /* Everything beyond this point gets cleared on a reset */ +#define OPUS_DECODER_RESET_START stream_channels + int stream_channels; + + int bandwidth; + int mode; + int prev_mode; + int frame_size; + int prev_redundancy; + + opus_uint32 rangeFinal; +}; + +#ifdef FIXED_POINT +static inline opus_int16 SAT16(opus_int32 x) { + return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x; +}; +#endif + + +int opus_decoder_get_size(int channels) +{ + int silkDecSizeBytes, celtDecSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Decoder_Size( &silkDecSizeBytes ); + if(ret) + return 0; + silkDecSizeBytes = align(silkDecSizeBytes); + celtDecSizeBytes = celt_decoder_get_size(channels); + return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes; +} + +int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) +{ + void *silk_dec; + CELTDecoder *celt_dec; + int ret, silkDecSizeBytes; + + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_decoder_get_size(channels)); + /* Initialize SILK encoder */ + ret = silk_Get_Decoder_Size(&silkDecSizeBytes); + if (ret) + return OPUS_INTERNAL_ERROR; + + silkDecSizeBytes = align(silkDecSizeBytes); + st->silk_dec_offset = align(sizeof(OpusDecoder)); + st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes; + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + st->DecControl.API_sampleRate = st->Fs; + st->DecControl.nChannelsAPI = st->channels; + + /* Reset decoder */ + ret = silk_InitDecoder( silk_dec ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* Initialize CELT decoder */ + ret = celt_decoder_init(celt_dec, Fs, channels); + if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0)); + + st->prev_mode = 0; + st->frame_size = Fs/400; + return OPUS_OK; +} + +OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error) +{ + int ret; + OpusDecoder *st; + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels)); + if (st == NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_decoder_init(st, Fs, channels); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, + opus_val16 *out, int overlap, int channels, + const opus_val16 *window, opus_int32 Fs) +{ + int i, c; + int inc = 48000/Fs; + for (c=0;csilk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + F20 = st->Fs/50; + F10 = F20>>1; + F5 = F10>>1; + F2_5 = F5>>1; + if (frame_size < F2_5) + return OPUS_BUFFER_TOO_SMALL; + /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */ + if (len<=1) + { + data = NULL; + /* In that case, don't conceal more than what the ToC says */ + frame_size = IMIN(frame_size, st->frame_size); + } + if (data != NULL) + { + audiosize = st->frame_size; + mode = st->mode; + ec_dec_init(&dec,(unsigned char*)data,len); + } else { + audiosize = frame_size; + + if (st->prev_mode == 0) + { + /* If we haven't got any packet yet, all we can do is return zeros */ + for (i=0;ichannels;i++) + pcm[i] = 0; + RESTORE_STACK; + return audiosize; + } else { + mode = st->prev_mode; + } + } + + /* For CELT/hybrid PLC of more than 20 ms, do multiple calls */ + if (data==NULL && frame_size > F20 && mode != MODE_SILK_ONLY) + { + int nb_samples = 0; + do { + int ret = opus_decode_frame(st, NULL, 0, pcm, F20, 0); + if (ret != F20) + return OPUS_INTERNAL_ERROR; + pcm += F20*st->channels; + nb_samples += F20; + } while (nb_samples < frame_size); + RESTORE_STACK; + return frame_size; + } + ALLOC(pcm_transition, F5*st->channels, opus_val16); + + if (data!=NULL && st->prev_mode > 0 && ( + (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy) + || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ) + ) + { + transition = 1; + if (mode == MODE_CELT_ONLY) + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + } + if (audiosize > frame_size) + { + /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ + RESTORE_STACK; + return OPUS_BAD_ARG; + } else { + frame_size = audiosize; + } + + ALLOC(pcm_silk, IMAX(F10, frame_size)*st->channels, opus_int16); + ALLOC(redundant_audio, F5*st->channels, opus_val16); + + /* SILK processing */ + if (mode != MODE_CELT_ONLY) + { + int lost_flag, decoded_samples; + opus_int16 *pcm_ptr = pcm_silk; + + if (st->prev_mode==MODE_CELT_ONLY) + silk_InitDecoder( silk_dec ); + + /* The SILK PLC cannot support produce frames of less than 10 ms */ + st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs); + + if (data != NULL) + { + st->DecControl.nChannelsInternal = st->stream_channels; + if( mode == MODE_SILK_ONLY ) { + if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { + st->DecControl.internalSampleRate = 8000; + } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { + st->DecControl.internalSampleRate = 12000; + } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { + st->DecControl.internalSampleRate = 16000; + } else { + st->DecControl.internalSampleRate = 16000; + silk_assert( 0 ); + } + } else { + /* Hybrid mode */ + st->DecControl.internalSampleRate = 16000; + } + } + + lost_flag = data == NULL ? 1 : 2 * decode_fec; + decoded_samples = 0; + do { + /* Call SILK decoder */ + int first_frame = decoded_samples == 0; + silk_ret = silk_Decode( silk_dec, &st->DecControl, + lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size ); + if( silk_ret ) { + if (lost_flag) { + /* PLC failure should not be fatal */ + silk_frame_size = frame_size; + for (i=0;ichannels;i++) + pcm_ptr[i] = 0; + } else { + RESTORE_STACK; + return OPUS_INVALID_PACKET; + } + } + pcm_ptr += silk_frame_size * st->channels; + decoded_samples += silk_frame_size; + } while( decoded_samples < frame_size ); + } + + start_band = 0; + if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL + && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len) + { + /* Check if we have a redundant 0-8 kHz band */ + if (mode == MODE_HYBRID) + redundancy = ec_dec_bit_logp(&dec, 12); + else + redundancy = 1; + if (redundancy) + { + celt_to_silk = ec_dec_bit_logp(&dec, 1); + /* redundancy_bytes will be at least two, in the non-hybrid + case due to the ec_tell() check above */ + redundancy_bytes = mode==MODE_HYBRID ? + (opus_int32)ec_dec_uint(&dec, 256)+2 : + len-((ec_tell(&dec)+7)>>3); + len -= redundancy_bytes; + /* This is a sanity check. It should never happen for a valid + packet, so the exact behaviour is not normative. */ + if (len*8 < ec_tell(&dec)) + { + len = 0; + redundancy_bytes = 0; + redundancy = 0; + } + /* Shrink decoder because of raw bits */ + dec.storage -= redundancy_bytes; + } + } + if (mode != MODE_CELT_ONLY) + start_band = 17; + + { + int endband=21; + + switch(st->bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + endband = 13; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: + endband = 17; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + endband = 19; + break; + case OPUS_BANDWIDTH_FULLBAND: + endband = 21; + break; + } + celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband)); + celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels)); + } + + if (redundancy) + transition = 0; + + if (transition && mode != MODE_CELT_ONLY) + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + + /* 5 ms redundant frame for CELT->SILK*/ + if (redundancy && celt_to_silk) + { + celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, + redundant_audio, F5, NULL); + celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); + } + + /* MUST be after PLC */ + celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band)); + + if (mode != MODE_SILK_ONLY) + { + int celt_frame_size = IMIN(F20, frame_size); + /* Make sure to discard any previous CELT state */ + if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy) + celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); + /* Decode CELT */ + celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, + len, pcm, celt_frame_size, &dec); + } else { + unsigned char silence[2] = {0xFF, 0xFF}; + for (i=0;ichannels;i++) + pcm[i] = 0; + /* For hybrid -> SILK transitions, we let the CELT MDCT + do a fade-out by decoding a silence frame */ + if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) + { + celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); + celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL); + } + } + + if (mode != MODE_CELT_ONLY) + { +#ifdef FIXED_POINT + for (i=0;ichannels;i++) + pcm[i] = SAT16(pcm[i] + pcm_silk[i]); +#else + for (i=0;ichannels;i++) + pcm[i] = pcm[i] + (opus_val16)((1./32768.)*pcm_silk[i]); +#endif + } + + { + const CELTMode *celt_mode; + celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode)); + window = celt_mode->window; + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); + celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); + + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL); + celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); + smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, + pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); + } + if (redundancy && celt_to_silk) + { + for (c=0;cchannels;c++) + { + for (i=0;ichannels*i+c] = redundant_audio[st->channels*i+c]; + } + smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs); + } + if (transition) + { + if (audiosize >= F5) + { + for (i=0;ichannels*F2_5;i++) + pcm[i] = pcm_transition[i]; + smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, + st->channels, window, st->Fs); + } else { + /* Not enough time to do a clean transition, but we do it anyway + This will not preserve amplitude perfectly and may introduce + a bit of temporal aliasing, but it shouldn't be too bad and + that's pretty much the best we can do. In any case, generating this + transition it pretty silly in the first place */ + smooth_fade(pcm_transition, pcm, + pcm, F2_5, + st->channels, window, st->Fs); + } + } + + if (len <= 1) + st->rangeFinal = 0; + else + st->rangeFinal = dec.rng ^ redundant_rng; + + st->prev_mode = mode; + st->prev_redundancy = redundancy && !celt_to_silk; + RESTORE_STACK; + return celt_ret < 0 ? celt_ret : audiosize; + +} + +static int parse_size(const unsigned char *data, int len, short *size) +{ + if (len<1) + { + *size = -1; + return -1; + } else if (data[0]<252) + { + *size = data[0]; + return 1; + } else if (len<2) + { + *size = -1; + return -1; + } else { + *size = 4*data[1] + data[0]; + return 2; + } +} + +static int opus_packet_parse_impl(const unsigned char *data, int len, + int self_delimited, unsigned char *out_toc, + const unsigned char *frames[48], short size[48], int *payload_offset) +{ + int i, bytes; + int count; + int cbr; + unsigned char ch, toc; + int framesize; + int last_size; + const unsigned char *data0 = data; + + if (size==NULL) + return OPUS_BAD_ARG; + + framesize = opus_packet_get_samples_per_frame(data, 48000); + + cbr = 0; + toc = *data++; + len--; + last_size = len; + switch (toc&0x3) + { + /* One frame */ + case 0: + count=1; + break; + /* Two CBR frames */ + case 1: + count=2; + cbr = 1; + if (!self_delimited) + { + if (len&0x1) + return OPUS_INVALID_PACKET; + size[0] = last_size = len/2; + } + break; + /* Two VBR frames */ + case 2: + count = 2; + bytes = parse_size(data, len, size); + len -= bytes; + if (size[0]<0 || size[0] > len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size = len-size[0]; + break; + /* Multiple CBR/VBR frames (from 0 to 120 ms) */ + case 3: + if (len<1) + return OPUS_INVALID_PACKET; + /* Number of frames encoded in bits 0 to 5 */ + ch = *data++; + count = ch&0x3F; + if (count <= 0 || framesize*count > 5760) + return OPUS_INVALID_PACKET; + len--; + /* Padding flag is bit 6 */ + if (ch&0x40) + { + int padding=0; + int p; + do { + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; + padding += p==255 ? 254: p; + } while (p==255); + len -= padding; + } + if (len<0) + return OPUS_INVALID_PACKET; + /* VBR flag is bit 7 */ + cbr = !(ch&0x80); + if (!cbr) + { + /* VBR case */ + last_size = len; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size -= bytes+size[i]; + } + if (last_size<0) + return OPUS_INVALID_PACKET; + } else if (!self_delimited) + { + /* CBR case */ + last_size = len/count; + if (last_size*count!=len) + return OPUS_INVALID_PACKET; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + /* For CBR packets, apply the size to all the frames. */ + if (cbr) + { + if (size[count-1]*count > len) + return OPUS_INVALID_PACKET; + for (i=0;i last_size) + return OPUS_INVALID_PACKET; + } else + { + /* Because it's not encoded explicitly, it's possible the size of the + last packet (or all the packets, for the CBR case) is larger than + 1275. Reject them here.*/ + if (last_size > 1275) + return OPUS_INVALID_PACKET; + size[count-1] = last_size; + } + + if (frames) + { + for (i=0;i1) + return OPUS_BAD_ARG; + if (len==0 || data==NULL) + return opus_decode_frame(st, NULL, 0, pcm, frame_size, 0); + else if (len<0) + return OPUS_BAD_ARG; + + tot_offset = 0; + st->mode = opus_packet_get_mode(data); + st->bandwidth = opus_packet_get_bandwidth(data); + st->frame_size = opus_packet_get_samples_per_frame(data, st->Fs); + st->stream_channels = opus_packet_get_nb_channels(data); + + count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset); + if (count < 0) + return count; + + data += offset; + tot_offset += offset; + + if (count*st->frame_size > frame_size) + return OPUS_BUFFER_TOO_SMALL; + nb_samples=0; + for (i=0;ichannels; + nb_samples += ret; + } + if (packet_offset != NULL) + *packet_offset = tot_offset; + return nb_samples; +} + +#ifdef FIXED_POINT + +int opus_decode(OpusDecoder *st, const unsigned char *data, + int len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL); +} + +#ifndef DISABLE_FLOAT_API +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + int len, float *pcm, int frame_size, int decode_fec) +{ + VARDECL(opus_int16, out); + int ret, i; + ALLOC_STACK; + + ALLOC(out, frame_size*st->channels, opus_int16); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = (1.f/32768.f)*(out[i]); + } + RESTORE_STACK; + return ret; +} +#endif + + +#else +int opus_decode(OpusDecoder *st, const unsigned char *data, + int len, opus_int16 *pcm, int frame_size, int decode_fec) +{ + VARDECL(float, out); + int ret, i; + ALLOC_STACK; + + if(frame_size<0)return OPUS_BAD_ARG; + + ALLOC(out, frame_size*st->channels, float); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = FLOAT2INT16(out[i]); + } + RESTORE_STACK; + return ret; +} + +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + int len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL); +} + +#endif + +int opus_decoder_ctl(OpusDecoder *st, int request, ...) +{ + int ret = OPUS_OK; + va_list ap; + void *silk_dec; + CELTDecoder *celt_dec; + + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + + + va_start(ap, request); + + switch (request) + { + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->bandwidth; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + *value = st->rangeFinal; + } + break; + case OPUS_RESET_STATE: + { + OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START, + sizeof(OpusDecoder)- + ((char*)&st->OPUS_DECODER_RESET_START - (char*)st)); + + celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); + silk_InitDecoder( silk_dec ); + st->stream_channels = st->channels; + st->frame_size = st->Fs/400; + } + break; + case OPUS_GET_PITCH_REQUEST: + { + int *value = va_arg(ap, opus_int32*); + if (value==NULL) + { + ret = OPUS_BAD_ARG; + break; + } + if (st->prev_mode == MODE_CELT_ONLY) + celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value)); + else + *value = st->DecControl.prevPitchLag; + } + break; + default: + /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + + va_end(ap); + return ret; +} + +void opus_decoder_destroy(OpusDecoder *st) +{ + opus_free(st); +} + + +int opus_packet_get_bandwidth(const unsigned char *data) +{ + int bandwidth; + if (data[0]&0x80) + { + bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3); + if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if ((data[0]&0x60) == 0x60) + { + bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND : + OPUS_BANDWIDTH_SUPERWIDEBAND; + } else { + bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3); + } + return bandwidth; +} + +int opus_packet_get_samples_per_frame(const unsigned char *data, + opus_int32 Fs) +{ + int audiosize; + if (data[0]&0x80) + { + audiosize = ((data[0]>>3)&0x3); + audiosize = (Fs<>3)&0x3); + if (audiosize == 3) + audiosize = Fs*60/1000; + else + audiosize = (Fs<Fs); + /* Can't have more than 120 ms */ + if (samples*25 > dec->Fs*3) + return OPUS_INVALID_PACKET; + else + return samples; +} diff --git a/media/libopus/src/opus_encoder.c b/media/libopus/src/opus_encoder.c new file mode 100644 index 000000000000..805bffb0c644 --- /dev/null +++ b/media/libopus/src/opus_encoder.c @@ -0,0 +1,1543 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "celt.h" +#include "entenc.h" +#include "modes.h" +#include "API.h" +#include "stack_alloc.h" +#include "float_cast.h" +#include "opus.h" +#include "arch.h" +#include "opus_private.h" +#include "os_support.h" + +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "fixed/structs_FIX.h" +#else +#include "float/structs_FLP.h" +#endif + +#define MAX_ENCODER_BUFFER 480 + +struct OpusEncoder { + int celt_enc_offset; + int silk_enc_offset; + silk_EncControlStruct silk_mode; + int application; + int channels; + int delay_compensation; + int force_channels; + int signal_type; + int user_bandwidth; + int max_bandwidth; + int user_forced_mode; + int voice_ratio; + opus_int32 Fs; + int use_vbr; + int vbr_constraint; + opus_int32 bitrate_bps; + opus_int32 user_bitrate_bps; + int encoder_buffer; + +#define OPUS_ENCODER_RESET_START stream_channels + int stream_channels; + opus_int16 hybrid_stereo_width_Q14; + opus_int32 variable_HP_smth2_Q15; + opus_val32 hp_mem[4]; + int mode; + int prev_mode; + int prev_channels; + int prev_framesize; + int bandwidth; + int silk_bw_switch; + /* Sampling rate (at the API level) */ + int first; + opus_val16 delay_buffer[MAX_ENCODER_BUFFER*2]; + + opus_uint32 rangeFinal; +}; + +/* Transition tables for the voice and music. First column is the + middle (memoriless) threshold. The second column is the hysteresis + (difference with the middle) */ +static const opus_int32 mono_voice_bandwidth_thresholds[8] = { + 11000, 1000, /* NB<->MB */ + 14000, 1000, /* MB<->WB */ + 21000, 2000, /* WB<->SWB */ + 29000, 2000, /* SWB<->FB */ +}; +static const opus_int32 mono_music_bandwidth_thresholds[8] = { + 14000, 1000, /* MB not allowed */ + 18000, 2000, /* MB<->WB */ + 24000, 2000, /* WB<->SWB */ + 33000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_voice_bandwidth_thresholds[8] = { + 11000, 1000, /* NB<->MB */ + 14000, 1000, /* MB<->WB */ + 21000, 2000, /* WB<->SWB */ + 32000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_music_bandwidth_thresholds[8] = { + 14000, 1000, /* MB not allowed */ + 18000, 2000, /* MB<->WB */ + 24000, 2000, /* WB<->SWB */ + 48000, 2000, /* SWB<->FB */ +}; +/* Threshold bit-rates for switching between mono and stereo */ +static const opus_int32 stereo_voice_threshold = 26000; +static const opus_int32 stereo_music_threshold = 36000; + +/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */ +static const opus_int32 mode_thresholds[2][2] = { + /* voice */ /* music */ + { 48000, 24000}, /* mono */ + { 48000, 24000}, /* stereo */ +}; + +int opus_encoder_get_size(int channels) +{ + int silkEncSizeBytes, celtEncSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return 0; + silkEncSizeBytes = align(silkEncSizeBytes); + celtEncSizeBytes = celt_encoder_get_size(channels); + return align(sizeof(OpusEncoder))+silkEncSizeBytes+celtEncSizeBytes; +} + +int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application) +{ + void *silk_enc; + CELTEncoder *celt_enc; + int err; + int ret, silkEncSizeBytes; + + if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)|| + (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO + && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_encoder_get_size(channels)); + /* Create SILK encoder */ + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return OPUS_BAD_ARG; + silkEncSizeBytes = align(silkEncSizeBytes); + st->silk_enc_offset = align(sizeof(OpusEncoder)); + st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes; + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + + ret = silk_InitEncoder( silk_enc, &st->silk_mode ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* default SILK parameters */ + st->silk_mode.nChannelsAPI = channels; + st->silk_mode.nChannelsInternal = channels; + st->silk_mode.API_sampleRate = st->Fs; + st->silk_mode.maxInternalSampleRate = 16000; + st->silk_mode.minInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = 16000; + st->silk_mode.payloadSize_ms = 20; + st->silk_mode.bitRate = 25000; + st->silk_mode.packetLossPercentage = 0; + st->silk_mode.complexity = 10; + st->silk_mode.useInBandFEC = 0; + st->silk_mode.useDTX = 0; + st->silk_mode.useCBR = 0; + + /* Create CELT encoder */ + /* Initialize CELT encoder */ + err = celt_encoder_init(celt_enc, Fs, channels); + if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(10)); + + st->use_vbr = 1; + /* Makes constrained VBR the default (safer for real-time use) */ + st->vbr_constraint = 1; + st->user_bitrate_bps = OPUS_AUTO; + st->bitrate_bps = 3000+Fs*channels; + st->application = application; + st->signal_type = OPUS_AUTO; + st->user_bandwidth = OPUS_AUTO; + st->max_bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->force_channels = OPUS_AUTO; + st->user_forced_mode = OPUS_AUTO; + st->voice_ratio = -1; + st->encoder_buffer = st->Fs/100; + + /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead + + 1.5 ms for SILK resamplers and stereo prediction) */ + st->delay_compensation = st->Fs/250; + + st->hybrid_stereo_width_Q14 = 1 << 14; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + + return OPUS_OK; +} + +static int pad_frame(unsigned char *data, int len, int new_len) +{ + if (len == new_len) + return 0; + if (len > new_len) + return 1; + + if ((data[0]&0x3)==0) + { + int i; + int padding, nb_255s; + + padding = new_len - len; + if (padding >= 2) + { + nb_255s = (padding-2)/255; + + for (i=len-1;i>=1;i--) + data[i+nb_255s+2] = data[i]; + data[0] |= 0x3; + data[1] = 0x41; + for (i=0;i=1;i--) + data[i+1] = data[i]; + data[0] |= 0x3; + data[1] = 1; + } + return 0; + } else { + return 1; + } +} + +static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels) +{ + int period; + unsigned char toc; + period = 0; + while (framerate < 400) + { + framerate <<= 1; + period++; + } + if (mode == MODE_SILK_ONLY) + { + toc = (bandwidth-OPUS_BANDWIDTH_NARROWBAND)<<5; + toc |= (period-2)<<3; + } else if (mode == MODE_CELT_ONLY) + { + int tmp = bandwidth-OPUS_BANDWIDTH_MEDIUMBAND; + if (tmp < 0) + tmp = 0; + toc = 0x80; + toc |= tmp << 5; + toc |= period<<3; + } else /* Hybrid */ + { + toc = 0x60; + toc |= (bandwidth-OPUS_BANDWIDTH_SUPERWIDEBAND)<<4; + toc |= (period-2)<<3; + } + toc |= (channels==2)<<2; + return toc; +} + +#ifndef FIXED_POINT +void silk_biquad_float( + const opus_val16 *in, /* I: Input signal */ + const opus_int32 *B_Q28, /* I: MA coefficients [3] */ + const opus_int32 *A_Q28, /* I: AR coefficients [2] */ + opus_val32 *S, /* I/O: State vector [2] */ + opus_val16 *out, /* O: Output signal */ + const opus_int32 len, /* I: Signal length (must be even) */ + int stride +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_val32 vout; + opus_val32 inval; + opus_val32 A[2], B[3]; + + A[0] = (opus_val32)(A_Q28[0] * (1./((opus_int32)1<<28))); + A[1] = (opus_val32)(A_Q28[1] * (1./((opus_int32)1<<28))); + B[0] = (opus_val32)(B_Q28[0] * (1./((opus_int32)1<<28))); + B[1] = (opus_val32)(B_Q28[1] * (1./((opus_int32)1<<28))); + B[2] = (opus_val32)(B_Q28[2] * (1./((opus_int32)1<<28))); + + /* Negate A_Q28 values and split in two parts */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k*stride ]; + vout = S[ 0 ] + B[0]*inval; + + S[ 0 ] = S[1] - vout*A[0] + B[1]*inval; + + S[ 1 ] = - vout*A[1] + B[2]*inval; + + /* Scale back to Q0 and saturate */ + out[ k*stride ] = vout; + } +} +#endif + +static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs) +{ + opus_int32 B_Q28[ 3 ], A_Q28[ 2 ]; + opus_int32 Fc_Q19, r_Q28, r_Q22; + + silk_assert( cutoff_Hz <= silk_int32_MAX / SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ) ); + Fc_Q19 = silk_DIV32_16( silk_SMULBB( SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ), cutoff_Hz ), Fs/1000 ); + silk_assert( Fc_Q19 > 0 && Fc_Q19 < 32768 ); + + r_Q28 = SILK_FIX_CONST( 1.0, 28 ) - silk_MUL( SILK_FIX_CONST( 0.92, 9 ), Fc_Q19 ); + + /* b = r * [ 1; -2; 1 ]; */ + /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */ + B_Q28[ 0 ] = r_Q28; + B_Q28[ 1 ] = silk_LSHIFT( -r_Q28, 1 ); + B_Q28[ 2 ] = r_Q28; + + /* -r * ( 2 - Fc * Fc ); */ + r_Q22 = silk_RSHIFT( r_Q28, 6 ); + A_Q28[ 0 ] = silk_SMULWW( r_Q22, silk_SMULWW( Fc_Q19, Fc_Q19 ) - SILK_FIX_CONST( 2.0, 22 ) ); + A_Q28[ 1 ] = silk_SMULWW( r_Q22, r_Q22 ); + +#ifdef FIXED_POINT + silk_biquad_alt( in, B_Q28, A_Q28, hp_mem, out, len, channels ); + if( channels == 2 ) { + silk_biquad_alt( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels ); + } +#else + silk_biquad_float( in, B_Q28, A_Q28, hp_mem, out, len, channels ); + if( channels == 2 ) { + silk_biquad_float( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels ); + } +#endif +} + +static void stereo_fade(const opus_val16 *in, opus_val16 *out, opus_val16 g1, opus_val16 g2, + int overlap, int frame_size, int channels, const opus_val16 *window, opus_int32 Fs) +{ + int i; + int inc = 48000/Fs; + g1 = Q15ONE-g1; + g2 = Q15ONE-g2; + for (i=0;iFs/400; + if (st->user_bitrate_bps==OPUS_AUTO) + return 60*st->Fs/frame_size + st->Fs*st->channels; + else if (st->user_bitrate_bps==OPUS_BITRATE_MAX) + return max_data_bytes*8*st->Fs/frame_size; + else + return st->user_bitrate_bps; +} + +#ifdef FIXED_POINT +#define opus_encode_native opus_encode +int opus_encode(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, int max_data_bytes) +#else +#define opus_encode_native opus_encode_float +int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, int max_data_bytes) +#endif +{ + void *silk_enc; + CELTEncoder *celt_enc; + int i; + int ret=0; + int nBytes; + ec_enc enc; + int bytes_target; + int prefill=0; + int start_band = 0; + int redundancy = 0; + int redundancy_bytes = 0; + int celt_to_silk = 0; + VARDECL(opus_val16, pcm_buf); + int nb_compr_bytes; + int to_celt = 0; + opus_uint32 redundant_rng = 0; + int cutoff_Hz, hp_freq_smth1; + int voice_est; + opus_int32 equiv_rate; + int delay_compensation; + int frame_rate; + opus_int32 max_rate; + int curr_bandwidth; + VARDECL(opus_val16, tmp_prefill); + + ALLOC_STACK; + + max_data_bytes = IMIN(1276, max_data_bytes); + + st->rangeFinal = 0; + if (400*frame_size != st->Fs && 200*frame_size != st->Fs && 100*frame_size != st->Fs && + 50*frame_size != st->Fs && 25*frame_size != st->Fs && 50*frame_size != 3*st->Fs) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + if (max_data_bytes<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + + st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes); + + frame_rate = st->Fs/frame_size; + if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8 + || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400))) + { + int tocmode = st->mode; + if (tocmode==0) + tocmode = MODE_SILK_ONLY; + if (frame_rate>100) + tocmode = MODE_CELT_ONLY; + if (frame_rate < 50) + tocmode = MODE_SILK_ONLY; + data[0] = gen_toc(tocmode, frame_rate, + st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth, + st->stream_channels); + RESTORE_STACK; + return 1; + } + if (!st->use_vbr) + { + int cbrBytes; + cbrBytes = IMIN( (st->bitrate_bps + 4*frame_rate)/(8*frame_rate) , max_data_bytes); + st->bitrate_bps = cbrBytes * (8*frame_rate); + max_data_bytes = cbrBytes; + } + max_rate = frame_rate*max_data_bytes*8; + + /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */ + equiv_rate = st->bitrate_bps - 60*(st->Fs/frame_size - 50); + + if (st->signal_type == OPUS_SIGNAL_VOICE) + voice_est = 127; + else if (st->signal_type == OPUS_SIGNAL_MUSIC) + voice_est = 0; + else if (st->voice_ratio >= 0) + voice_est = st->voice_ratio*327>>8; + else if (st->application == OPUS_APPLICATION_VOIP) + voice_est = 115; + else + voice_est = 48; + + if (st->force_channels!=OPUS_AUTO && st->channels == 2) + { + st->stream_channels = st->force_channels; + } else { +#ifdef FUZZING + /* Random mono/stereo decision */ + if (st->channels == 2 && (rand()&0x1F)==0) + st->stream_channels = 3-st->stream_channels; +#else + /* Rate-dependent mono-stereo decision */ + if (st->channels == 2) + { + opus_int32 stereo_threshold; + stereo_threshold = stereo_music_threshold + ((voice_est*voice_est*(stereo_voice_threshold-stereo_music_threshold))>>14); + if (st->stream_channels == 2) + stereo_threshold -= 4000; + else + stereo_threshold += 4000; + st->stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1; + } else { + st->stream_channels = st->channels; + } +#endif + } + + /* Mode selection depending on application and signal type */ + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + { + st->mode = MODE_CELT_ONLY; + } else if (st->user_forced_mode == OPUS_AUTO) + { +#ifdef FUZZING + /* Random mode switching */ + if ((rand()&0xF)==0) + { + if ((rand()&0x1)==0) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } else { + if (st->prev_mode==MODE_CELT_ONLY) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } +#else + int chan; + opus_int32 mode_voice, mode_music; + opus_int32 threshold; + + chan = (st->channels==2) && st->force_channels!=1; + mode_voice = mode_thresholds[chan][0]; + mode_music = mode_thresholds[chan][1]; + threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14); + + /* Hysteresis */ + if (st->prev_mode == MODE_CELT_ONLY) + threshold -= 4000; + else if (st->prev_mode>0) + threshold += 4000; + + st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY; + + /* When FEC is enabled and there's enough packet loss, use SILK */ + if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4) + st->mode = MODE_SILK_ONLY; + /* When encoding voice and DTX is enabled, set the encoder to SILK mode (at least for now) */ + if (st->silk_mode.useDTX && voice_est > 100) + st->mode = MODE_SILK_ONLY; +#endif + } else { + st->mode = st->user_forced_mode; + } + + /* Override the chosen mode to make sure we meet the requested frame size */ + if (st->mode != MODE_CELT_ONLY && frame_size < st->Fs/100) + st->mode = MODE_CELT_ONLY; + + if (st->stream_channels == 1 && st->prev_channels ==2 && st->silk_mode.toMono==0 + && st->mode != MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY) + { + /* Delay stereo->mono transition by two frames so that SILK can do a smooth downmix */ + st->silk_mode.toMono = 1; + st->stream_channels = 2; + } else { + st->silk_mode.toMono = 0; + } + + if (st->prev_mode > 0 && + ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) || + (st->mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY))) + { + redundancy = 1; + celt_to_silk = (st->mode != MODE_CELT_ONLY); + if (!celt_to_silk) + { + /* Switch to SILK/hybrid if frame size is 10 ms or more*/ + if (frame_size >= st->Fs/100) + { + st->mode = st->prev_mode; + to_celt = 1; + } else { + redundancy=0; + } + } + } + if (st->silk_bw_switch) + { + redundancy = 1; + celt_to_silk = 1; + st->silk_bw_switch = 0; + } + + if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) + { + silk_EncControlStruct dummy; + silk_InitEncoder( silk_enc, &dummy); + prefill=1; + } + + /* Automatic (rate-dependent) bandwidth selection */ + if (st->mode == MODE_CELT_ONLY || st->first || st->silk_mode.allowBandwidthSwitch) + { + const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds; + opus_int32 bandwidth_thresholds[8]; + int bandwidth = OPUS_BANDWIDTH_FULLBAND; + opus_int32 equiv_rate2; + + equiv_rate2 = equiv_rate; + if (st->mode != MODE_CELT_ONLY) + { + /* Adjust the threshold +/- 10% depending on complexity */ + equiv_rate2 = equiv_rate2 * (45+st->silk_mode.complexity)/50; + /* CBR is less efficient by ~1 kb/s */ + if (!st->use_vbr) + equiv_rate2 -= 1000; + } + if (st->channels==2 && st->force_channels!=1) + { + voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds; + music_bandwidth_thresholds = stereo_music_bandwidth_thresholds; + } else { + voice_bandwidth_thresholds = mono_voice_bandwidth_thresholds; + music_bandwidth_thresholds = mono_music_bandwidth_thresholds; + } + /* Interpolate bandwidth thresholds depending on voice estimation */ + for (i=0;i<8;i++) + { + bandwidth_thresholds[i] = music_bandwidth_thresholds[i] + + ((voice_est*voice_est*(voice_bandwidth_thresholds[i]-music_bandwidth_thresholds[i]))>>14); + } + do { + int threshold, hysteresis; + threshold = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)]; + hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1]; + if (!st->first) + { + if (st->bandwidth >= bandwidth) + threshold -= hysteresis; + else + threshold += hysteresis; + } + if (equiv_rate2 >= threshold) + break; + } while (--bandwidth>OPUS_BANDWIDTH_NARROWBAND); + st->bandwidth = bandwidth; + /* Prevents any transition to SWB/FB until the SILK layer has fully + switched to WB mode and turned the variable LP filter off */ + if (!st->first && st->mode != MODE_CELT_ONLY && !st->silk_mode.inWBmodeWithoutVariableLP && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + + if (st->bandwidth>st->max_bandwidth) + st->bandwidth = st->max_bandwidth; + + if (st->user_bandwidth != OPUS_AUTO) + st->bandwidth = st->user_bandwidth; + + /* This prevents us from using hybrid at unsafe CBR/max rates */ + if (st->mode != MODE_CELT_ONLY && max_rate < 15000) + { + st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND); + } + + /* Prevents Opus from wasting bits on frequencies that are above + the Nyquist rate of the input signal */ + if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + if (st->Fs <= 16000 && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + if (st->Fs <= 12000 && st->bandwidth > OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND) + st->bandwidth = OPUS_BANDWIDTH_NARROWBAND; + + /* If max_data_bytes represents less than 8 kb/s, switch to CELT-only mode */ + if (max_data_bytes < (frame_rate > 50 ? 12000 : 8000)*frame_size / (st->Fs * 8)) + st->mode = MODE_CELT_ONLY; + + /* CELT mode doesn't support mediumband, use wideband instead */ + if (st->mode == MODE_CELT_ONLY && st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + + /* Can't support higher than wideband for >20 ms frames */ + if (frame_size > st->Fs/50 && (st->mode == MODE_CELT_ONLY || st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)) + { + VARDECL(unsigned char, tmp_data); + int nb_frames; + int bak_mode, bak_bandwidth, bak_channels, bak_to_mono; + OpusRepacketizer rp; + int bytes_per_frame; + + + nb_frames = frame_size > st->Fs/25 ? 3 : 2; + bytes_per_frame = max_data_bytes/nb_frames-3; + + ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char); + + opus_repacketizer_init(&rp); + + bak_mode = st->user_forced_mode; + bak_bandwidth = st->user_bandwidth; + bak_channels = st->force_channels; + + st->user_forced_mode = st->mode; + st->user_bandwidth = st->bandwidth; + st->force_channels = st->stream_channels; + bak_to_mono = st->silk_mode.toMono; + + if (bak_to_mono) + st->force_channels = 1; + else + st->prev_channels = st->stream_channels; + for (i=0;isilk_mode.toMono = 0; + /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */ + if (to_celt && i==nb_frames-1) + st->user_forced_mode = MODE_CELT_ONLY; + tmp_len = opus_encode_native(st, pcm+i*(st->channels*st->Fs/50), st->Fs/50, tmp_data+i*bytes_per_frame, bytes_per_frame); + if (tmp_len<0) + return OPUS_INTERNAL_ERROR; + ret = opus_repacketizer_cat(&rp, tmp_data+i*bytes_per_frame, tmp_len); + if (ret<0) + return OPUS_INTERNAL_ERROR; + } + ret = opus_repacketizer_out(&rp, data, max_data_bytes); + if (ret<0) + return OPUS_INTERNAL_ERROR; + + st->user_forced_mode = bak_mode; + st->user_bandwidth = bak_bandwidth; + st->force_channels = bak_channels; + st->silk_mode.toMono = bak_to_mono; + RESTORE_STACK; + return ret; + } + + curr_bandwidth = st->bandwidth; + + /* Chooses the appropriate mode for speech + *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */ + if (st->mode == MODE_SILK_ONLY && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_HYBRID; + if (st->mode == MODE_HYBRID && curr_bandwidth <= OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_SILK_ONLY; + + /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */ + bytes_target = IMIN(max_data_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1; + + data += 1; + + ec_enc_init(&enc, data, max_data_bytes-1); + + ALLOC(pcm_buf, (delay_compensation+frame_size)*st->channels, opus_val16); + for (i=0;ichannels;i++) + pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-delay_compensation)*st->channels+i]; + + if (st->mode == MODE_CELT_ONLY) + hp_freq_smth1 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + else + hp_freq_smth1 = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.variable_HP_smth1_Q15; + + st->variable_HP_smth2_Q15 = silk_SMLAWB( st->variable_HP_smth2_Q15, + hp_freq_smth1 - st->variable_HP_smth2_Q15, SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) ); + + /* convert from log scale to Hertz */ + cutoff_Hz = silk_log2lin( silk_RSHIFT( st->variable_HP_smth2_Q15, 8 ) ); + + if (st->application == OPUS_APPLICATION_VOIP) + { + hp_cutoff(pcm, cutoff_Hz, &pcm_buf[delay_compensation*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); + } else { + for (i=0;ichannels;i++) + pcm_buf[delay_compensation*st->channels + i] = pcm[i]; + } + + /* SILK processing */ + if (st->mode != MODE_CELT_ONLY) + { +#ifdef FIXED_POINT + const opus_int16 *pcm_silk; +#else + VARDECL(opus_int16, pcm_silk); + ALLOC(pcm_silk, st->channels*frame_size, opus_int16); +#endif + st->silk_mode.bitRate = 8*bytes_target*frame_rate; + if( st->mode == MODE_HYBRID ) { + st->silk_mode.bitRate /= st->stream_channels; + if( curr_bandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND ) { + if( st->Fs == 100 * frame_size ) { + /* 24 kHz, 10 ms */ + st->silk_mode.bitRate = ( ( st->silk_mode.bitRate + 2000 + st->use_vbr * 1000 ) * 2 ) / 3; + } else { + /* 24 kHz, 20 ms */ + st->silk_mode.bitRate = ( ( st->silk_mode.bitRate + 1000 + st->use_vbr * 1000 ) * 2 ) / 3; + } + } else { + if( st->Fs == 100 * frame_size ) { + /* 48 kHz, 10 ms */ + st->silk_mode.bitRate = ( st->silk_mode.bitRate + 8000 + st->use_vbr * 3000 ) / 2; + } else { + /* 48 kHz, 20 ms */ + st->silk_mode.bitRate = ( st->silk_mode.bitRate + 9000 + st->use_vbr * 1000 ) / 2; + } + } + st->silk_mode.bitRate *= st->stream_channels; + /* don't let SILK use more than 80% */ + if( st->silk_mode.bitRate > ( st->bitrate_bps - 8*st->Fs/frame_size ) * 4/5 ) { + st->silk_mode.bitRate = ( st->bitrate_bps - 8*st->Fs/frame_size ) * 4/5; + } + } + + st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs; + st->silk_mode.nChannelsAPI = st->channels; + st->silk_mode.nChannelsInternal = st->stream_channels; + if (curr_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.desiredInternalSampleRate = 8000; + } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.desiredInternalSampleRate = 12000; + } else { + silk_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND ); + st->silk_mode.desiredInternalSampleRate = 16000; + } + if( st->mode == MODE_HYBRID ) { + /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */ + st->silk_mode.minInternalSampleRate = 16000; + } else { + st->silk_mode.minInternalSampleRate = 8000; + } + + if (st->mode == MODE_SILK_ONLY) + { + opus_int32 effective_max_rate = max_rate; + st->silk_mode.maxInternalSampleRate = 16000; + if (frame_rate > 50) + effective_max_rate = effective_max_rate*2/3; + if (effective_max_rate < 13000) + { + st->silk_mode.maxInternalSampleRate = 12000; + st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate); + } + if (effective_max_rate < 9600) + { + st->silk_mode.maxInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate); + } + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + + st->silk_mode.useCBR = !st->use_vbr; + + /* Call SILK encoder for the low band */ + nBytes = IMIN(1275, max_data_bytes-1); + + st->silk_mode.maxBits = nBytes*8; + /* Only allow up to 90% of the bits for hybrid mode*/ + if (st->mode == MODE_HYBRID) + st->silk_mode.maxBits = (opus_int32)st->silk_mode.maxBits*9/10; + if (st->silk_mode.useCBR) + { + st->silk_mode.maxBits = (st->silk_mode.bitRate * frame_size / (st->Fs * 8))*8; + /* Reduce the initial target to make it easier to reach the CBR rate */ + st->silk_mode.bitRate = IMAX(1, st->silk_mode.bitRate-2000); + } + if (redundancy) + st->silk_mode.maxBits -= st->silk_mode.maxBits/(1 + frame_size/(st->Fs/200)); + + if (prefill) + { + int zero=0; +#ifdef FIXED_POINT + pcm_silk = st->delay_buffer; +#else + for (i=0;iencoder_buffer*st->channels;i++) + pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]); +#endif + silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1 ); + } + +#ifdef FIXED_POINT + pcm_silk = pcm_buf+delay_compensation*st->channels; +#else + for (i=0;ichannels;i++) + pcm_silk[i] = FLOAT2INT16(pcm_buf[delay_compensation*st->channels + i]); +#endif + ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 ); + if( ret ) { + /*fprintf (stderr, "SILK encode error: %d\n", ret);*/ + /* Handle error */ + return OPUS_INTERNAL_ERROR; + } + if (nBytes==0) + { + st->rangeFinal = 0; + data[-1] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + RESTORE_STACK; + return 1; + } + /* Extract SILK internal bandwidth for signaling in first byte */ + if( st->mode == MODE_SILK_ONLY ) { + if( st->silk_mode.internalSampleRate == 8000 ) { + curr_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if( st->silk_mode.internalSampleRate == 12000 ) { + curr_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + } else if( st->silk_mode.internalSampleRate == 16000 ) { + curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + } else { + silk_assert( st->silk_mode.internalSampleRate == 16000 ); + } + + st->silk_mode.opusCanSwitch = st->silk_mode.switchReady; + if (st->silk_mode.opusCanSwitch) + { + redundancy = 1; + celt_to_silk = 0; + st->silk_bw_switch = 1; + } + } + + /* CELT processing */ + { + int endband=21; + + switch(curr_bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + endband = 13; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: + endband = 17; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + endband = 19; + break; + case OPUS_BANDWIDTH_FULLBAND: + endband = 21; + break; + } + celt_encoder_ctl(celt_enc, CELT_SET_END_BAND(endband)); + celt_encoder_ctl(celt_enc, CELT_SET_CHANNELS(st->stream_channels)); + } + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + if (st->mode != MODE_SILK_ONLY) + { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + /* Allow prediction unless we decide to disable it later */ + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(2)); + + if (st->mode == MODE_HYBRID) + { + int len; + + len = (ec_tell(&enc)+7)>>3; + if (redundancy) + len += st->mode == MODE_HYBRID ? 3 : 1; + if( st->use_vbr ) { + nb_compr_bytes = len + bytes_target - (st->silk_mode.bitRate * frame_size) / (8 * st->Fs); + } else { + /* check if SILK used up too much */ + nb_compr_bytes = len > bytes_target ? len : bytes_target; + } + } else { + if (st->use_vbr) + { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps)); + nb_compr_bytes = max_data_bytes-1; + } else { + nb_compr_bytes = bytes_target; + } + } + + } else { + nb_compr_bytes = 0; + } + + ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16); + if (st->mode != MODE_SILK_ONLY && st->mode != st->prev_mode && st->prev_mode > 0) + { + for (i=0;ichannels*st->Fs/400;i++) + tmp_prefill[i] = st->delay_buffer[(st->encoder_buffer-st->delay_compensation-st->Fs/400)*st->channels + i]; + } + + for (i=0;ichannels*(st->encoder_buffer-(frame_size+delay_compensation));i++) + st->delay_buffer[i] = st->delay_buffer[i+st->channels*frame_size]; + for (;iencoder_buffer*st->channels;i++) + st->delay_buffer[i] = pcm_buf[(frame_size+delay_compensation-st->encoder_buffer)*st->channels+i]; + + + if (st->mode != MODE_HYBRID || st->stream_channels==1) + st->silk_mode.stereoWidth_Q14 = 1<<14; + if( st->channels == 2 ) { + /* Apply stereo width reduction (at low bitrates) */ + if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) { + opus_val16 g1, g2; + const CELTMode *celt_mode; + + celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode)); + g1 = st->hybrid_stereo_width_Q14; + g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14); +#ifdef FIXED_POINT + g1 = g1==16384 ? Q15ONE : SHL16(g1,1); + g2 = g2==16384 ? Q15ONE : SHL16(g2,1); +#else + g1 *= (1./16384); + g2 *= (1./16384); +#endif + stereo_fade(pcm_buf, pcm_buf, g1, g2, celt_mode->overlap, + frame_size, st->channels, celt_mode->window, st->Fs); + st->hybrid_stereo_width_Q14 = st->silk_mode.stereoWidth_Q14; + } + } + + if ( st->mode != MODE_CELT_ONLY && ec_tell(&enc)+17+20*(st->mode == MODE_HYBRID) <= 8*(max_data_bytes-1)) + { + /* For SILK mode, the redundancy is inferred from the length */ + if (st->mode == MODE_HYBRID && (redundancy || ec_tell(&enc)+37 <= 8*nb_compr_bytes)) + ec_enc_bit_logp(&enc, redundancy, 12); + if (redundancy) + { + int max_redundancy; + ec_enc_bit_logp(&enc, celt_to_silk, 1); + if (st->mode == MODE_HYBRID) + max_redundancy = (max_data_bytes-1)-nb_compr_bytes-1; + else + max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+7)>>3); + /* Target the same bit-rate for redundancy as for the rest, + up to a max of 257 bytes */ + redundancy_bytes = IMIN(max_redundancy, st->bitrate_bps/1600); + redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes)); + if (st->mode == MODE_HYBRID) + ec_enc_uint(&enc, redundancy_bytes-2, 256); + } + } else { + redundancy = 0; + } + + if (!redundancy) + st->silk_bw_switch = 0; + + if (st->mode != MODE_CELT_ONLY)start_band=17; + + if (st->mode == MODE_SILK_ONLY) + { + ret = (ec_tell(&enc)+7)>>3; + ec_enc_done(&enc); + nb_compr_bytes = ret; + } else { + nb_compr_bytes = IMIN((max_data_bytes-1)-redundancy_bytes, nb_compr_bytes); + ec_enc_shrink(&enc, nb_compr_bytes); + } + + + /* 5 ms redundant frame for CELT->SILK */ + if (redundancy && celt_to_silk) + { + int err; + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + return OPUS_INTERNAL_ERROR; + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + } + + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(start_band)); + + if (st->mode != MODE_SILK_ONLY) + { + if (st->mode != st->prev_mode && st->prev_mode > 0) + { + unsigned char dummy[2]; + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + + /* Prefilling */ + celt_encode_with_ec(celt_enc, tmp_prefill, st->Fs/400, dummy, 2, NULL); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + } + /* If false, we already busted the budget and we'll end up with a "PLC packet" */ + if (ec_tell(&enc) <= 8*nb_compr_bytes) + { + ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc); + if (ret < 0) + return OPUS_INTERNAL_ERROR; + } + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + int err; + unsigned char dummy[2]; + int N2, N4; + N2 = st->Fs/200; + N4 = st->Fs/400; + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + + /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */ + celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL); + + err = celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + return OPUS_INTERNAL_ERROR; + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + } + + + + /* Signalling the mode in the first byte */ + data--; + data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + + st->rangeFinal = enc.rng ^ redundant_rng; + + if (to_celt) + st->prev_mode = MODE_CELT_ONLY; + else + st->prev_mode = st->mode; + st->prev_channels = st->stream_channels; + st->prev_framesize = frame_size; + + st->first = 0; + + /* In the unlikely case that the SILK encoder busted its target, tell + the decoder to call the PLC */ + if (ec_tell(&enc) > (max_data_bytes-1)*8) + { + data[1] = 0; + ret = 1; + st->rangeFinal = 0; + } else if (st->mode==MODE_SILK_ONLY&&!redundancy) + { + /*When in LPC only mode it's perfectly + reasonable to strip off trailing zero bytes as + the required range decoder behavior is to + fill these in. This can't be done when the MDCT + modes are used because the decoder needs to know + the actual length for allocation purposes.*/ + while(ret>2&&data[ret]==0)ret--; + } + /* Count ToC and redundancy */ + ret += 1+redundancy_bytes; + if (!st->use_vbr && ret >= 3) + { + if (pad_frame(data, ret, max_data_bytes)) + return OPUS_INTERNAL_ERROR; + ret = max_data_bytes; + } + RESTORE_STACK; + return ret; +} + +#ifdef FIXED_POINT + +#ifndef DISABLE_FLOAT_API +int opus_encode_float(OpusEncoder *st, const float *pcm, int frame_size, + unsigned char *data, int max_data_bytes) +{ + int i, ret; + VARDECL(opus_int16, in); + ALLOC_STACK; + + if(frame_size<0)return OPUS_BAD_ARG; + + ALLOC(in, frame_size*st->channels, opus_int16); + + for (i=0;ichannels;i++) + in[i] = FLOAT2INT16(pcm[i]); + ret = opus_encode(st, in, frame_size, data, max_data_bytes); + RESTORE_STACK; + return ret; +} +#endif + +#else +int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size, + unsigned char *data, int max_data_bytes) +{ + int i, ret; + VARDECL(float, in); + ALLOC_STACK; + + ALLOC(in, frame_size*st->channels, float); + + for (i=0;ichannels;i++) + in[i] = (1.0f/32768)*pcm[i]; + ret = opus_encode_float(st, in, frame_size, data, max_data_bytes); + RESTORE_STACK; + return ret; +} +#endif + + +int opus_encoder_ctl(OpusEncoder *st, int request, ...) +{ + int ret; + CELTEncoder *celt_enc; + va_list ap; + + ret = OPUS_OK; + va_start(ap, request); + + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + switch (request) + { + case OPUS_SET_APPLICATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ( (value != OPUS_APPLICATION_VOIP && value != OPUS_APPLICATION_AUDIO + && value != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + || (!st->first && st->application != value)) + { + ret = OPUS_BAD_ARG; + break; + } + st->application = value; + } + break; + case OPUS_GET_APPLICATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->application; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX) + { + if (value <= 0) + goto bad_arg; + else if (value <= 500) + value = 500; + else if (value > (opus_int32)300000*st->channels) + value = (opus_int32)300000*st->channels; + } + st->user_bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = user_bitrate_to_bitrate(st, st->prev_framesize, 1276); + } + break; + case OPUS_SET_FORCE_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if((value<1 || value>st->channels) && value != OPUS_AUTO) + return OPUS_BAD_ARG; + st->force_channels = value; + } + break; + case OPUS_GET_FORCE_CHANNELS_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->force_channels; + } + break; + case OPUS_SET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) + return OPUS_BAD_ARG; + st->max_bandwidth = value; + if (st->max_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->max_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->max_bandwidth; + } + break; + case OPUS_SET_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO) + return OPUS_BAD_ARG; + st->user_bandwidth = value; + if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->user_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->bandwidth; + } + break; + case OPUS_SET_DTX_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + return OPUS_BAD_ARG; + st->silk_mode.useDTX = value; + } + break; + case OPUS_GET_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->silk_mode.useDTX; + } + break; + case OPUS_SET_COMPLEXITY_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>10) + return OPUS_BAD_ARG; + st->silk_mode.complexity = value; + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(value)); + } + break; + case OPUS_GET_COMPLEXITY_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->silk_mode.complexity; + } + break; + case OPUS_SET_INBAND_FEC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + return OPUS_BAD_ARG; + st->silk_mode.useInBandFEC = value; + } + break; + case OPUS_GET_INBAND_FEC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->silk_mode.useInBandFEC; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < 0 || value > 100) + return OPUS_BAD_ARG; + st->silk_mode.packetLossPercentage = value; + celt_encoder_ctl(celt_enc, OPUS_SET_PACKET_LOSS_PERC(value)); + } + break; + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->silk_mode.packetLossPercentage; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + return OPUS_BAD_ARG; + st->use_vbr = value; + st->silk_mode.useCBR = 1-value; + } + break; + case OPUS_GET_VBR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->use_vbr; + } + break; + case OPUS_SET_VOICE_RATIO_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value>100 || value<-1) + goto bad_arg; + st->voice_ratio = value; + } + break; + case OPUS_GET_VOICE_RATIO_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->voice_ratio; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + return OPUS_BAD_ARG; + st->vbr_constraint = value; + } + break; + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->vbr_constraint; + } + break; + case OPUS_SET_SIGNAL_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value!=OPUS_AUTO && value!=OPUS_SIGNAL_VOICE && value!=OPUS_SIGNAL_MUSIC) + return OPUS_BAD_ARG; + st->signal_type = value; + } + break; + case OPUS_GET_SIGNAL_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->signal_type; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->Fs/400; + if (st->application != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + *value += st->delay_compensation; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + *value = st->rangeFinal; + } + break; + case OPUS_RESET_STATE: + { + void *silk_enc; + silk_EncControlStruct dummy; + silk_enc = (char*)st+st->silk_enc_offset; + + OPUS_CLEAR((char*)&st->OPUS_ENCODER_RESET_START, + sizeof(OpusEncoder)- + ((char*)&st->OPUS_ENCODER_RESET_START - (char*)st)); + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + silk_InitEncoder( silk_enc, &dummy ); + st->stream_channels = st->channels; + st->hybrid_stereo_width_Q14 = 1 << 14; + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + } + break; + case OPUS_SET_FORCE_MODE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < MODE_SILK_ONLY || value > MODE_CELT_ONLY) && value != OPUS_AUTO) + goto bad_arg; + st->user_forced_mode = value; + } + break; + default: + /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + va_end(ap); + return ret; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + +void opus_encoder_destroy(OpusEncoder *st) +{ + opus_free(st); +} diff --git a/media/libopus/src/opus_multistream.c b/media/libopus/src/opus_multistream.c new file mode 100644 index 000000000000..a2a48b9a4d53 --- /dev/null +++ b/media/libopus/src/opus_multistream.c @@ -0,0 +1,853 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" + +typedef struct ChannelLayout { + int nb_channels; + int nb_streams; + int nb_coupled_streams; + unsigned char mapping[256]; +} ChannelLayout; + +struct OpusMSEncoder { + ChannelLayout layout; + int bitrate; + /* Encoder states go here */ +}; + +struct OpusMSDecoder { + ChannelLayout layout; + /* Decoder states go here */ +}; + + +#ifdef FIXED_POINT +#define opus_encode_native opus_encode +#else +#define opus_encode_native opus_encode_float +#endif + +static int validate_layout(const ChannelLayout *layout) +{ + int i, max_channel; + + max_channel = layout->nb_streams+layout->nb_coupled_streams; + if (max_channel>255) + return 0; + for (i=0;inb_channels;i++) + { + if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255) + return 0; + } + return 1; +} + + +static int get_left_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2) + return i; + } + return -1; +} + +static int get_right_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2+1) + return i; + } + return -1; +} + +static int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id+layout->nb_coupled_streams) + return i; + } + return -1; +} + +static int validate_encoder_layout(const ChannelLayout *layout) +{ + int s; + for (s=0;snb_streams;s++) + { + if (s < layout->nb_coupled_streams) + { + if (get_left_channel(layout, s, -1)==-1) + return 0; + if (get_right_channel(layout, s, -1)==-1) + return 0; + } else { + if (get_mono_channel(layout, s, -1)==-1) + return 0; + } + } + return 1; +} + +opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams) +{ + int coupled_size; + int mono_size; + + if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + return align(sizeof(OpusMSEncoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + + + +int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *mapping, + int application +) +{ + int coupled_size; + int mono_size; + int i; + char *ptr; + + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout)) + return OPUS_BAD_ARG; + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application); + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application); + ptr += align(mono_size); + } + return OPUS_OK; +} + +OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *mapping, + int application, + int *error +) +{ + int ret; + OpusMSEncoder *st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + + +#ifdef FIXED_POINT +int opus_multistream_encode( +#else +int opus_multistream_encode_float( +#endif + OpusMSEncoder *st, + const opus_val16 *pcm, + int frame_size, + unsigned char *data, + int max_data_bytes +) +{ + int coupled_size; + int mono_size; + int s, i; + char *ptr; + int tot_size; + VARDECL(opus_val16, buf); + /* Max size in case the encoder decides to return three frames */ + unsigned char tmp_data[3*1275+7]; + OpusRepacketizer rp; + ALLOC_STACK; + + ALLOC(buf, 2*frame_size, opus_val16); + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + if (max_data_bytes < 2*st->layout.nb_streams-1) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + /* Counting ToC */ + tot_size = 0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + int len; + int curr_max; + + opus_repacketizer_init(&rp); + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + { + int left, right; + left = get_left_channel(&st->layout, s, -1); + right = get_right_channel(&st->layout, s, -1); + for (i=0;ilayout.nb_channels*i+left]; + buf[2*i+1] = pcm[st->layout.nb_channels*i+right]; + } + ptr += align(coupled_size); + } else { + int chan = get_mono_channel(&st->layout, s, -1); + for (i=0;ilayout.nb_channels*i+chan]; + ptr += align(mono_size); + } + /* number of bytes left (+Toc) */ + curr_max = max_data_bytes - tot_size; + /* Reserve one byte for the last stream and 2 for the others */ + curr_max -= 2*(st->layout.nb_streams-s)-1; + len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max); + if (len<0) + { + RESTORE_STACK; + return len; + } + /* We need to use the repacketizer to add the self-delimiting lengths + while taking into account the fact that the encoder can now return + more than one frame at a time (e.g. 60 ms CELT-only) */ + opus_repacketizer_cat(&rp, tmp_data, len); + len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), data, max_data_bytes-tot_size, s != st->layout.nb_streams-1); + data += len; + tot_size += len; + } + RESTORE_STACK; + return tot_size; + +} + +#ifdef FIXED_POINT + +#ifndef DISABLE_FLOAT_API +int opus_multistream_encode_float( + OpusMSEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + int max_data_bytes +) +{ + int i, ret; + VARDECL(opus_int16, in); + ALLOC_STACK; + + ALLOC(in, frame_size*st->layout.nb_channels, opus_int16); + + for (i=0;ilayout.nb_channels;i++) + in[i] = FLOAT2INT16(pcm[i]); + ret = opus_multistream_encode(st, in, frame_size, data, max_data_bytes); + RESTORE_STACK; + return ret; +} +#endif + +#else + +int opus_multistream_encode( + OpusMSEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + int max_data_bytes +) +{ + int i, ret; + VARDECL(float, in); + ALLOC_STACK; + + ALLOC(in, frame_size*st->layout.nb_channels, float); + + for (i=0;ilayout.nb_channels;i++) + in[i] = (1./32768)*pcm[i]; + ret = opus_multistream_encode_float(st, in, frame_size, data, max_data_bytes); + RESTORE_STACK; + return ret; +} + +#endif + +int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) +{ + va_list ap; + int coupled_size, mono_size; + char *ptr; + int ret = OPUS_OK; + + va_start(ap, request); + + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + switch (request) + { + case OPUS_SET_BITRATE_REQUEST: + { + int chan, s; + opus_int32 value = va_arg(ap, opus_int32); + chan = st->layout.nb_streams + st->layout.nb_coupled_streams; + value /= chan; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + opus_encoder_ctl(enc, request, value * (s < st->layout.nb_coupled_streams ? 2 : 1)); + } + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + int s; + opus_int32 *value = va_arg(ap, opus_int32*); + *value = 0; + for (s=0;slayout.nb_streams;s++) + { + opus_int32 rate; + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + opus_encoder_ctl(enc, request, &rate); + *value += rate; + } + } + break; + case OPUS_GET_VBR_REQUEST: + case OPUS_GET_APPLICATION_REQUEST: + case OPUS_GET_BANDWIDTH_REQUEST: + case OPUS_GET_COMPLEXITY_REQUEST: + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + case OPUS_GET_DTX_REQUEST: + case OPUS_GET_VOICE_RATIO_REQUEST: + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + case OPUS_GET_SIGNAL_REQUEST: + case OPUS_GET_LOOKAHEAD_REQUEST: + case OPUS_GET_INBAND_FEC_REQUEST: + { + OpusEncoder *enc; + /* For int32* GET params, just query the first stream */ + opus_int32 *value = va_arg(ap, opus_int32*); + enc = (OpusEncoder*)ptr; + ret = opus_encoder_ctl(enc, request, value); + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + int s; + opus_uint32 *value = va_arg(ap, opus_uint32*); + opus_uint32 tmp; + *value=0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_SET_COMPLEXITY_REQUEST: + case OPUS_SET_VBR_REQUEST: + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + case OPUS_SET_BANDWIDTH_REQUEST: + case OPUS_SET_SIGNAL_REQUEST: + case OPUS_SET_APPLICATION_REQUEST: + case OPUS_SET_INBAND_FEC_REQUEST: + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + case OPUS_SET_DTX_REQUEST: + case OPUS_SET_FORCE_MODE_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusEncoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + ret = OPUS_BAD_ARG; + value = va_arg(ap, OpusEncoder**); + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusEncoder*)ptr; + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + + va_end(ap); + return ret; +} + +void opus_multistream_encoder_destroy(OpusMSEncoder *st) +{ + opus_free(st); +} + + +/* DECODER */ + +opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams) +{ + int coupled_size; + int mono_size; + + if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + return align(sizeof(OpusMSDecoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + +int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *mapping +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout)) + return OPUS_BAD_ARG; + + ptr = (char*)st + align(sizeof(OpusMSDecoder)); + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2); + if(ret!=OPUS_OK)return ret; + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + return OPUS_OK; +} + + +OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *mapping, + int *error +) +{ + int ret; + OpusMSDecoder *st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; + + +} + +static int opus_multistream_decode_native( + OpusMSDecoder *st, + const unsigned char *data, + int len, + opus_val16 *pcm, + int frame_size, + int decode_fec +) +{ + int coupled_size; + int mono_size; + int s, i, c; + char *ptr; + int do_plc=0; + VARDECL(opus_val16, buf); + ALLOC_STACK; + + ALLOC(buf, 2*frame_size, opus_val16); + ptr = (char*)st + align(sizeof(OpusMSDecoder)); + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + + if (len==0) + do_plc = 1; + if (len < 0) + return OPUS_BAD_ARG; + if (!do_plc && len < 2*st->layout.nb_streams-1) + return OPUS_INVALID_PACKET; + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + int packet_offset, ret; + + dec = (OpusDecoder*)ptr; + ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); + + if (!do_plc && len<=0) + { + RESTORE_STACK; + return OPUS_INVALID_PACKET; + } + packet_offset = 0; + ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset); + data += packet_offset; + len -= packet_offset; + if (ret > frame_size) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + if (s>0 && ret != frame_size) + { + RESTORE_STACK; + return OPUS_INVALID_PACKET; + } + if (ret <= 0) + { + RESTORE_STACK; + return ret; + } + frame_size = ret; + if (s < st->layout.nb_coupled_streams) + { + int chan, prev; + prev = -1; + /* Copy "left" audio to the channel(s) where it belongs */ + while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) + { + for (i=0;ilayout.nb_channels*i+chan] = buf[2*i]; + prev = chan; + } + prev = -1; + /* Copy "right" audio to the channel(s) where it belongs */ + while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) + { + for (i=0;ilayout.nb_channels*i+chan] = buf[2*i+1]; + prev = chan; + } + } else { + int chan, prev; + prev = -1; + /* Copy audio to the channel(s) where it belongs */ + while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) + { + for (i=0;ilayout.nb_channels*i+chan] = buf[i]; + prev = chan; + } + } + } + /* Handle muted channels */ + for (c=0;clayout.nb_channels;c++) + { + if (st->layout.mapping[c] == 255) + { + for (i=0;ilayout.nb_channels*i+c] = 0; + } + } + RESTORE_STACK; + return frame_size; +} + +#ifdef FIXED_POINT +int opus_multistream_decode( + OpusMSDecoder *st, + const unsigned char *data, + int len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) +{ + return opus_multistream_decode_native(st, data, len, pcm, frame_size, decode_fec); +} + +#ifndef DISABLE_FLOAT_API +int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data, + int len, float *pcm, int frame_size, int decode_fec) +{ + VARDECL(opus_int16, out); + int ret, i; + ALLOC_STACK; + + ALLOC(out, frame_size*st->layout.nb_channels, opus_int16); + + ret = opus_multistream_decode_native(st, data, len, out, frame_size, decode_fec); + if (ret > 0) + { + for (i=0;ilayout.nb_channels;i++) + pcm[i] = (1./32768.)*(out[i]); + } + RESTORE_STACK; + return ret; +} +#endif + +#else + +int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data, + int len, opus_int16 *pcm, int frame_size, int decode_fec) +{ + VARDECL(float, out); + int ret, i; + ALLOC_STACK; + + ALLOC(out, frame_size*st->layout.nb_channels, float); + + ret = opus_multistream_decode_native(st, data, len, out, frame_size, decode_fec); + if (ret > 0) + { + for (i=0;ilayout.nb_channels;i++) + pcm[i] = FLOAT2INT16(out[i]); + } + RESTORE_STACK; + return ret; +} + +int opus_multistream_decode_float( + OpusMSDecoder *st, + const unsigned char *data, + int len, + float *pcm, + int frame_size, + int decode_fec +) +{ + return opus_multistream_decode_native(st, data, len, pcm, frame_size, decode_fec); +} +#endif + +int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) +{ + va_list ap; + int coupled_size, mono_size; + char *ptr; + int ret = OPUS_OK; + + va_start(ap, request); + + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + ptr = (char*)st + align(sizeof(OpusMSDecoder)); + switch (request) + { + case OPUS_GET_BANDWIDTH_REQUEST: + { + OpusDecoder *dec; + /* For int32* GET params, just query the first stream */ + opus_int32 *value = va_arg(ap, opus_int32*); + dec = (OpusDecoder*)ptr; + ret = opus_decoder_ctl(dec, request, value); + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + int s; + opus_uint32 *value = va_arg(ap, opus_uint32*); + opus_uint32 tmp; + *value = 0; + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_RESET_STATE: + { + int s; + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, OPUS_RESET_STATE); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusDecoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + ret = OPUS_BAD_ARG; + value = va_arg(ap, OpusDecoder**); + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusDecoder*)ptr; + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + + va_end(ap); + return ret; +} + + +void opus_multistream_decoder_destroy(OpusMSDecoder *st) +{ + opus_free(st); +} diff --git a/media/libopus/src/opus_private.h b/media/libopus/src/opus_private.h new file mode 100644 index 000000000000..c79e4b39f609 --- /dev/null +++ b/media/libopus/src/opus_private.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef OPUS_PRIVATE_H +#define OPUS_PRIVATE_H + +#include "arch.h" +#include "opus.h" + +struct OpusRepacketizer { + unsigned char toc; + int nb_frames; + const unsigned char *frames[48]; + short len[48]; + int framesize; +}; + + +#define MODE_SILK_ONLY 1000 +#define MODE_HYBRID 1001 +#define MODE_CELT_ONLY 1002 + +#define OPUS_SET_VOICE_RATIO_REQUEST 11018 +#define OPUS_GET_VOICE_RATIO_REQUEST 11019 + +/** Configures the encoder's expected percentage of voice + * opposed to music or other signals. + * + * @note This interface is currently more aspiration than actuality. It's + * ultimately expected to bias an automatic signal classifier, but it currently + * just shifts the static bitrate to mode mapping around a little bit. + * + * @param[in] x int: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_SET_VOICE_RATIO(x) OPUS_SET_VOICE_RATIO_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured voice ratio value, @see OPUS_SET_VOICE_RATIO + * + * @param[out] x int*: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_GET_VOICE_RATIO(x) OPUS_GET_VOICE_RATIO_REQUEST, __opus_check_int_ptr(x) + + +#define OPUS_SET_FORCE_MODE_REQUEST 11002 +#define OPUS_SET_FORCE_MODE(x) OPUS_SET_FORCE_MODE_REQUEST, __opus_check_int(x) + + +int encode_size(int size, unsigned char *data); + +int opus_decode_native(OpusDecoder *st, const unsigned char *data, int len, + opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, int *packet_offset); + +/* Make sure everything's aligned to 4 bytes (this may need to be increased + on really weird architectures) */ +static inline int align(int i) +{ + return (i+3)&-4; +} + +int opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, unsigned char *data, int maxlen, int self_delimited); + +#endif /* OPUS_PRIVATE_H */ diff --git a/media/libopus/src/repacketizer.c b/media/libopus/src/repacketizer.c new file mode 100644 index 000000000000..dd923a218450 --- /dev/null +++ b/media/libopus/src/repacketizer.c @@ -0,0 +1,208 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus.h" +#include "opus_private.h" +#include "os_support.h" + + +int opus_repacketizer_get_size(void) +{ + return sizeof(OpusRepacketizer); +} + +OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) +{ + rp->nb_frames = 0; + return rp; +} + +OpusRepacketizer *opus_repacketizer_create(void) +{ + OpusRepacketizer *rp; + rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size()); + if(rp==NULL)return NULL; + return opus_repacketizer_init(rp); +} + +void opus_repacketizer_destroy(OpusRepacketizer *rp) +{ + opus_free(rp); +} + +int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, int len) +{ + unsigned char tmp_toc; + int curr_nb_frames,ret; + /* Set of check ToC */ + if (len<1) return OPUS_INVALID_PACKET; + if (rp->nb_frames == 0) + { + rp->toc = data[0]; + rp->framesize = opus_packet_get_samples_per_frame(data, 8000); + } else if ((rp->toc&0xFC) != (data[0]&0xFC)) + { + /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/ + return OPUS_INVALID_PACKET; + } + curr_nb_frames = opus_packet_get_nb_frames(data, len); + if(curr_nb_frames<1) return OPUS_INVALID_PACKET; + + /* Check the 120 ms maximum packet size */ + if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960) + { + return OPUS_INVALID_PACKET; + } + + ret=opus_packet_parse(data, len, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL); + if(ret<1)return ret; + + rp->nb_frames += curr_nb_frames; + return OPUS_OK; +} + +int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) +{ + return rp->nb_frames; +} + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen, int self_delimited) +{ + int i, count; + opus_int32 tot_size; + short *len; + const unsigned char **frames; + + if (begin<0 || begin>=end || end>rp->nb_frames) + { + /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/ + return OPUS_BAD_ARG; + } + count = end-begin; + + len = rp->len+begin; + frames = rp->frames+begin; + if (self_delimited) + tot_size = 1 + (len[count-1]>=252); + else + tot_size = 0; + + switch (count) + { + case 1: + { + /* Code 0 */ + tot_size += len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *data++ = rp->toc&0xFC; + } + break; + case 2: + { + if (len[1] == len[0]) + { + /* Code 1 */ + tot_size += 2*len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *data++ = (rp->toc&0xFC) | 0x1; + } else { + /* Code 2 */ + tot_size += len[0]+len[1]+2+(len[0]>=252); + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *data++ = (rp->toc&0xFC) | 0x2; + data += encode_size(len[0], data); + } + } + break; + default: + { + /* Code 3 */ + int vbr; + + vbr = 0; + for (i=1;i=252) + len[i]; + tot_size += len[count-1]; + + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *data++ = (rp->toc&0xFC) | 0x3; + *data++ = count | 0x80; + for (i=0;i maxlen) + return OPUS_BUFFER_TOO_SMALL; + *data++ = (rp->toc&0xFC) | 0x3; + *data++ = count; + } + } + break; + } + if (self_delimited) { + int sdlen = encode_size(len[count-1], data); + data += sdlen; + } + /* Copy the actual data */ + for (i=0;inb_frames, data, maxlen, 0); +} + + diff --git a/media/libopus/update.sh b/media/libopus/update.sh new file mode 100755 index 000000000000..76e66591bcc4 --- /dev/null +++ b/media/libopus/update.sh @@ -0,0 +1,59 @@ +#!/bin/sh +# +# Usage: ./update.sh +# +# Copies the needed files from a directory containing the original +# libopus source, and applies any local patches we're carrying. + +TARGET='.' + +STATIC_FILES="COPYING" +MK_FILES="opus_sources.mk celt_sources.mk silk_sources.mk \ + opus_headers.txt celt_headers.txt silk_headers.txt" + +# Make sure we have a source directory +if test -z $1 || ! test -r $1/include/opus.h; then + echo "Update the current directory from a source checkout" + echo "usage: $0 ../opus" + exit 1 +fi + +# "parse" the makefile fragments to get the list of source files +# requires GNU sed extensions +SRC_FILES=$(sed -e ':a;N;$!ba;s/\\\n//g;s/[A-Z_]* = //g' \ + $(for file in ${MK_FILES}; do echo "$1/${file}"; done)) + +# pre-release versions of the code don't list opus_custom.h +# in celt_headers.mk, so we must include it manually +HDR_FILES="include/opus_custom.h" + +# make sure the necessary subdirectories exist +for file in ${SRC_FILES}; do + echo "testing ${file}" + base=${file##*/} + dir="${file%"${base}"}" + if test ! -d "${TARGET}/${dir}"; then + cmd="mkdir -p ${TARGET}/${dir}" + echo ${cmd} + ${cmd} + fi +done + +# copy files into the target directory +for file in ${STATIC_FILES} ${MK_FILES} ${SRC_FILES} ${HDR_FILES}; do + cmd="cp $1/${file} ${TARGET}/${file}" + echo ${cmd} + ${cmd} +done + +# query git for the revision we're copying from +if test -d $1/.git; then + version=$(cd $1 && git describe --tags) +else + version="UNKNOWN" +fi +echo "copied from revision ${version}" +# update README revision +sed -e "s/^The git tag\/revision used was .*/The git tag\/revision used was ${version}./" \ + ${TARGET}/README_MOZILLA > ${TARGET}/README_MOZILLA+ && \ + mv ${TARGET}/README_MOZILLA+ ${TARGET}/README_MOZILLA From 4e5d9404d3d05822efc03f207926326abeb8bcce Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Mon, 30 Apr 2012 16:20:22 -0700 Subject: [PATCH 051/159] Bug 674225 - Add libopus to the mozilla build system. - r=ted This builds the opus reference library in media/libopus. We support both fixed and floating point builds, switched by MOZ_OPUS_FIXED. Currently this isn't defined by anything but should probably offer a configure option, and default to true on arm. Thanks to Tim Terriberry for additional review. --- config/autoconf.mk.in | 1 + configure.in | 14 +++++++ layout/media/Makefile.in | 6 +++ layout/media/symbols.def.in | 8 ++++ media/libopus/Makefile.in | 76 ++++++++++++++++++++++++++++++++++++ toolkit/toolkit-makefiles.sh | 6 +++ toolkit/toolkit-tiers.mk | 6 +++ 7 files changed, 117 insertions(+) create mode 100644 media/libopus/Makefile.in diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index a979255820b0..821ea8a22889 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -170,6 +170,7 @@ MOZ_MEDIA = @MOZ_MEDIA@ MOZ_VORBIS = @MOZ_VORBIS@ MOZ_TREMOR = @MOZ_TREMOR@ MOZ_NO_THEORA_ASM = @MOZ_NO_THEORA_ASM@ +MOZ_OPUS = @MOZ_OPUS@ MOZ_WEBM = @MOZ_WEBM@ MOZ_GSTREAMER = @MOZ_GSTREAMER@ MOZ_VP8_ERROR_CONCEALMENT = @MOZ_VP8_ERROR_CONCEALMENT@ diff --git a/configure.in b/configure.in index bee2ab1a112b..04424af366c1 100644 --- a/configure.in +++ b/configure.in @@ -4562,6 +4562,7 @@ MOZ_VORBIS= MOZ_TREMOR= MOZ_WAVE=1 MOZ_MEDIA= +MOZ_OPUS=1 MOZ_WEBM=1 MOZ_VP8_ERROR_CONCEALMENT= MOZ_VP8_ENCODER= @@ -5624,6 +5625,14 @@ if test -n "$MOZ_OGG"; then fi fi +dnl ======================================================== +dnl = Disable Opus audio codec support +dnl ======================================================== +MOZ_ARG_DISABLE_BOOL(opus, +[ --disable-opus Disable support for Opus audio], + MOZ_OPUS=, + MOZ_OPUS=1) + dnl ======================================================== dnl = Disable VP8 decoder support dnl ======================================================== @@ -5822,6 +5831,10 @@ if test -n "$MOZ_TREMOR"; then AC_DEFINE(MOZ_TREMOR) fi +if test -n "$MOZ_OPUS"; then + AC_DEFINE(MOZ_OPUS) +fi + dnl ======================================================== dnl = Check alsa availability on Linux if using sydneyaudio dnl ======================================================== @@ -8709,6 +8722,7 @@ AC_SUBST(MOZ_CUBEB) AC_SUBST(MOZ_WAVE) AC_SUBST(MOZ_VORBIS) AC_SUBST(MOZ_TREMOR) +AC_SUBST(MOZ_OPUS) AC_SUBST(MOZ_WEBM) AC_SUBST(MOZ_VP8_ERROR_CONCEALMENT) AC_SUBST(MOZ_VP8_ENCODER) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index aa5bf594ab16..1e5d3fed59d1 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -71,6 +71,12 @@ SHARED_LIBRARY_LIBS += \ $(NULL) endif +ifdef MOZ_OPUS +SHARED_LIBRARY_LIBS += \ + $(DEPTH)/media/libopus/$(LIB_PREFIX)opus.$(LIB_SUFFIX) \ + $(NULL) +endif + ifdef MOZ_WEBM SHARED_LIBRARY_LIBS += \ $(DEPTH)/media/libnestegg/src/$(LIB_PREFIX)nestegg.$(LIB_SUFFIX) \ diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index d070ff1443cf..c60527decdfe 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -97,6 +97,14 @@ th_packet_isheader th_packet_iskeyframe th_setup_free #endif +#ifdef MOZ_OPUS +opus_decoder_create +opus_decoder_destroy +opus_decoder_ctl +opus_decoder_get_nb_samples +opus_decode +opus_decode_float +#endif ShInitialize ShFinalize ShGetObjectCode diff --git a/media/libopus/Makefile.in b/media/libopus/Makefile.in new file mode 100644 index 000000000000..ad93e7e71ccf --- /dev/null +++ b/media/libopus/Makefile.in @@ -0,0 +1,76 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = opus +LIBRARY_NAME = opus +FORCE_STATIC_LIB= 1 + +DEFINES += \ + -DOPUS_BUILD \ + -DOPUS_VERSION='"draft-11-mozilla"' \ + -DUSE_ALLOCA \ + -Drestrict= \ + $(NULL) + +ifneq ($(filter $(OS_ARCH),Linux Darwin),) + DEFINES += -DHAVE_LRINTF +endif +ifeq ($(OS_ARCH), WINNT) + DEFINES += -Dinline=__inline +endif +ifeq ($(OS_ARCH),AIX) +DEFINES += -Dalloca=__alloca +endif + +EXPORTS_NAMESPACES = opus + +EXPORTS_opus = \ + include/opus.h \ + include/opus_defines.h \ + include/opus_types.h \ + include/opus_multistream.h \ + $(NULL) + +LOCAL_INCLUDES += \ + -I$(srcdir)/include \ + -I$(srcdir)/celt \ + -I$(srcdir)/silk \ + -I$(srcdir)/src \ + $(NULL) + +VPATH += \ + $(srcdir)/celt \ + $(srcdir)/silk \ + $(srcdir)/src \ + $(NULL) + +include $(srcdir)/celt_sources.mk +include $(srcdir)/silk_sources.mk +include $(srcdir)/opus_sources.mk + +CSRCS = \ + $(notdir $(CELT_SOURCES)) \ + $(notdir $(SILK_SOURCES)) \ + $(notdir $(OPUS_SOURCES)) \ + $(NULL) + +ifdef MOZ_OPUS_FIXED +DEFINES += -DFIXED_POINT=1 -DDISABLE_FLOAT_API +LOCAL_INCLUDES += -I$(srcdir)/silk/fixed +VPATH += $(srcdir)/silk/fixed +CSRCS += $(notdir $(SILK_SOURCES_FIXED)) +else +LOCAL_INCLUDES += -I$(srcdir)/silk/float +VPATH += $(srcdir)/silk/float +CSRCS += $(notdir $(SILK_SOURCES_FLOAT)) +endif + +include $(topsrcdir)/config/rules.mk diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index 1fc3125a9b2c..53ec983243e2 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -1575,6 +1575,12 @@ if [ "$MOZ_TREMOR" ]; then " fi +if [ "$MOZ_OPUS" ]; then + add_makefiles " + media/libopus/Makefile + " +fi + if [ "$MOZ_OGG" ]; then add_makefiles " content/media/ogg/Makefile diff --git a/toolkit/toolkit-tiers.mk b/toolkit/toolkit-tiers.mk index 9f89574d608c..d5b1fbcc0256 100644 --- a/toolkit/toolkit-tiers.mk +++ b/toolkit/toolkit-tiers.mk @@ -133,6 +133,12 @@ tier_platform_dirs += \ $(NULL) endif +ifdef MOZ_OPUS +tier_platform_dirs += \ + media/libopus \ + $(NULL) +endif + ifdef MOZ_WEBM tier_platform_dirs += media/libnestegg ifndef MOZ_NATIVE_LIBVPX From e8e0f22c6e0bd7f5ab66a34c5bd67cf576fd30a5 Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Mon, 30 Apr 2012 16:52:27 -0700 Subject: [PATCH 052/159] Bug 747581. r=khuey. --- dom/indexedDB/IDBFactory.cpp | 42 -------------- dom/indexedDB/IDBFactory.h | 7 --- dom/indexedDB/IndexedDatabaseManager.cpp | 70 +++++++++++++++++++----- dom/indexedDB/IndexedDatabaseManager.h | 13 +++++ dom/indexedDB/OpenDatabaseHelper.cpp | 7 ++- dom/indexedDB/test/unit/head_idb.js | 17 ++---- dom/ipc/ContentParent.cpp | 15 ++--- 7 files changed, 87 insertions(+), 84 deletions(-) diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp index f1436d6a7a2f..2f48e5861f0b 100644 --- a/dom/indexedDB/IDBFactory.cpp +++ b/dom/indexedDB/IDBFactory.cpp @@ -46,12 +46,10 @@ #include "mozilla/storage.h" #include "mozilla/dom/ContentChild.h" -#include "nsAppDirectoryServiceDefs.h" #include "nsComponentManagerUtils.h" #include "nsIScriptSecurityManager.h" #include "nsCharSeparatedTokenizer.h" #include "nsContentUtils.h" -#include "nsDirectoryServiceUtils.h" #include "nsDOMClassInfoID.h" #include "nsIPrincipal.h" #include "nsHashKeys.h" @@ -180,46 +178,6 @@ IDBFactory::NoteUsedByProcessType(GeckoProcessType aProcessType) } } -// static -nsresult -IDBFactory::GetDirectory(nsIFile** aDirectory) -{ - nsresult rv; - if (XRE_GetProcessType() == GeckoProcessType_Default) { - rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aDirectory); - NS_ENSURE_SUCCESS(rv, rv); - rv = (*aDirectory)->Append(NS_LITERAL_STRING("indexedDB")); - NS_ENSURE_SUCCESS(rv, rv); - } else { - nsCOMPtr localDirectory = - do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); - rv = localDirectory->InitWithPath( - ContentChild::GetSingleton()->GetIndexedDBPath()); - NS_ENSURE_SUCCESS(rv, rv); - localDirectory.forget((nsILocalFile**)aDirectory); - } - return NS_OK; -} - -// static -nsresult -IDBFactory::GetDirectoryForOrigin(const nsACString& aASCIIOrigin, - nsIFile** aDirectory) -{ - nsCOMPtr directory; - nsresult rv = GetDirectory(getter_AddRefs(directory)); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin); - originSanitized.ReplaceChar(":/", '+'); - - rv = directory->Append(originSanitized); - NS_ENSURE_SUCCESS(rv, rv); - - directory.forget(aDirectory); - return NS_OK; -} - inline bool IgnoreWhitespace(PRUnichar c) diff --git a/dom/indexedDB/IDBFactory.h b/dom/indexedDB/IDBFactory.h index 6144330692e7..b945a5af77a5 100644 --- a/dom/indexedDB/IDBFactory.h +++ b/dom/indexedDB/IDBFactory.h @@ -81,13 +81,6 @@ public: static void NoteUsedByProcessType(GeckoProcessType aProcessType); - static nsresult - GetDirectory(nsIFile** aDirectory); - - static nsresult - GetDirectoryForOrigin(const nsACString& aASCIIOrigin, - nsIFile** aDirectory); - static nsresult LoadDatabaseInformation(mozIStorageConnection* aConnection, nsIAtom* aDatabaseId, diff --git a/dom/indexedDB/IndexedDatabaseManager.cpp b/dom/indexedDB/IndexedDatabaseManager.cpp index cb9034f720e3..3739963ded91 100644 --- a/dom/indexedDB/IndexedDatabaseManager.cpp +++ b/dom/indexedDB/IndexedDatabaseManager.cpp @@ -37,11 +37,14 @@ * * ***** END LICENSE BLOCK ***** */ +#include "base/basictypes.h" + #include "IndexedDatabaseManager.h" #include "DatabaseInfo.h" #include "nsIDOMScriptObjectFactory.h" #include "nsIFile.h" +#include "nsILocalFile.h" #include "nsIObserverService.h" #include "nsIScriptObjectPrincipal.h" #include "nsIScriptSecurityManager.h" @@ -53,7 +56,10 @@ #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "mozilla/storage.h" +#include "mozilla/dom/ContentChild.h" +#include "nsAppDirectoryServiceDefs.h" #include "nsContentUtils.h" +#include "nsDirectoryServiceUtils.h" #include "nsThreadUtils.h" #include "nsXPCOM.h" #include "nsXPCOMPrivate.h" @@ -239,6 +245,18 @@ IndexedDatabaseManager::GetOrCreate() return nsnull; } + nsCOMPtr dbBaseDirectory; + nsresult rv = + NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + getter_AddRefs(dbBaseDirectory)); + NS_ENSURE_SUCCESS(rv, nsnull); + + rv = dbBaseDirectory->Append(NS_LITERAL_STRING("indexedDB")); + NS_ENSURE_SUCCESS(rv, nsnull); + + rv = dbBaseDirectory->GetPath(instance->mDatabaseBasePath); + NS_ENSURE_SUCCESS(rv, nsnull); + // Make a timer here to avoid potential failures later. We don't actually // initialize the timer until shutdown. instance->mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID); @@ -248,8 +266,7 @@ IndexedDatabaseManager::GetOrCreate() NS_ENSURE_TRUE(obs, nsnull); // We need this callback to know when to shut down all our threads. - nsresult rv = obs->AddObserver(instance, NS_XPCOM_SHUTDOWN_OBSERVER_ID, - false); + rv = obs->AddObserver(instance, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); NS_ENSURE_SUCCESS(rv, nsnull); // Make a lazy thread for any IO we need (like clearing or enumerating the @@ -284,6 +301,32 @@ IndexedDatabaseManager::FactoryCreate() return GetOrCreate().get(); } +nsresult +IndexedDatabaseManager::GetDirectoryForOrigin(const nsACString& aASCIIOrigin, + nsIFile** aDirectory) const +{ + nsresult rv; + nsCOMPtr directory = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + const nsString& path = XRE_GetProcessType() == GeckoProcessType_Default ? + GetBaseDirectory() : + ContentChild::GetSingleton()->GetIndexedDBPath(); + + rv = directory->InitWithPath(path); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin); + originSanitized.ReplaceChar(":/", '+'); + + rv = directory->Append(originSanitized); + NS_ENSURE_SUCCESS(rv, rv); + + directory.forget(reinterpret_cast(aDirectory)); + return NS_OK; +} + bool IndexedDatabaseManager::RegisterDatabase(IDBDatabase* aDatabase) { @@ -631,8 +674,7 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin, #endif nsCOMPtr directory; - nsresult rv = IDBFactory::GetDirectoryForOrigin(aOrigin, - getter_AddRefs(directory)); + nsresult rv = GetDirectoryForOrigin(aOrigin, getter_AddRefs(directory)); NS_ENSURE_SUCCESS(rv, rv); bool exists; @@ -1282,6 +1324,9 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(IndexedDatabaseManager::OriginClearRunnable, NS_IMETHODIMP IndexedDatabaseManager::OriginClearRunnable::Run() { + IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); + NS_ASSERTION(mgr, "This should never fail!"); + if (NS_IsMainThread()) { // On the first time on the main thread we dispatch to the IO thread. if (mFirstCallback) { @@ -1303,9 +1348,6 @@ IndexedDatabaseManager::OriginClearRunnable::Run() NS_ASSERTION(!mThread, "Should have been cleared already!"); - IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); - NS_ASSERTION(mgr, "This should never fail!"); - mgr->InvalidateFileManagersForOrigin(mOrigin); // Tell the IndexedDatabaseManager that we're done. @@ -1318,8 +1360,7 @@ IndexedDatabaseManager::OriginClearRunnable::Run() // Remove the directory that contains all our databases. nsCOMPtr directory; - nsresult rv = IDBFactory::GetDirectoryForOrigin(mOrigin, - getter_AddRefs(directory)); + nsresult rv = mgr->GetDirectoryForOrigin(mOrigin, getter_AddRefs(directory)); if (NS_SUCCEEDED(rv)) { bool exists; rv = directory->Exists(&exists); @@ -1377,6 +1418,9 @@ IncrementUsage(PRUint64* aUsage, PRUint64 aDelta) nsresult IndexedDatabaseManager::AsyncUsageRunnable::RunInternal() { + IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); + NS_ASSERTION(mgr, "This should never fail!"); + if (NS_IsMainThread()) { // Call the callback unless we were canceled. if (!mCanceled) { @@ -1390,10 +1434,7 @@ IndexedDatabaseManager::AsyncUsageRunnable::RunInternal() mCallback = nsnull; // And tell the IndexedDatabaseManager that we're done. - IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); - if (mgr) { - mgr->OnUsageCheckComplete(this); - } + mgr->OnUsageCheckComplete(this); return NS_OK; } @@ -1404,8 +1445,7 @@ IndexedDatabaseManager::AsyncUsageRunnable::RunInternal() // Get the directory that contains all the database files we care about. nsCOMPtr directory; - nsresult rv = IDBFactory::GetDirectoryForOrigin(mOrigin, - getter_AddRefs(directory)); + nsresult rv = mgr->GetDirectoryForOrigin(mOrigin, getter_AddRefs(directory)); NS_ENSURE_SUCCESS(rv, rv); bool exists; diff --git a/dom/indexedDB/IndexedDatabaseManager.h b/dom/indexedDB/IndexedDatabaseManager.h index 703066bef59c..3771ec461bdc 100644 --- a/dom/indexedDB/IndexedDatabaseManager.h +++ b/dom/indexedDB/IndexedDatabaseManager.h @@ -60,6 +60,7 @@ #define INDEXEDDB_MANAGER_CONTRACTID "@mozilla.org/dom/indexeddb/manager;1" class mozIStorageQuotaCallback; +class nsIFile; class nsITimer; BEGIN_INDEXEDDB_NAMESPACE @@ -193,6 +194,16 @@ public: nsresult AsyncDeleteFile(FileManager* aFileManager, PRInt64 aFileId); + const nsString& + GetBaseDirectory() const + { + return mDatabaseBasePath; + } + + nsresult + GetDirectoryForOrigin(const nsACString& aASCIIOrigin, + nsIFile** aDirectory) const; + static mozilla::Mutex& FileMutex() { IndexedDatabaseManager* mgr = Get(); @@ -388,6 +399,8 @@ private: // It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt // and FileInfo.mSliceRefCnt mozilla::Mutex mFileMutex; + + nsString mDatabaseBasePath; }; class AutoEnterWindow diff --git a/dom/indexedDB/OpenDatabaseHelper.cpp b/dom/indexedDB/OpenDatabaseHelper.cpp index 0ebbd9b26a57..712b679305af 100644 --- a/dom/indexedDB/OpenDatabaseHelper.cpp +++ b/dom/indexedDB/OpenDatabaseHelper.cpp @@ -2337,9 +2337,12 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { NS_ASSERTION(!aConnection, "How did we get a connection here?"); + IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); + NS_ASSERTION(mgr, "This should never fail!"); + nsCOMPtr directory; - nsresult rv = IDBFactory::GetDirectoryForOrigin(mASCIIOrigin, - getter_AddRefs(directory)); + nsresult rv = mgr->GetDirectoryForOrigin(mASCIIOrigin, + getter_AddRefs(directory)); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ASSERTION(directory, "What?"); diff --git a/dom/indexedDB/test/unit/head_idb.js b/dom/indexedDB/test/unit/head_idb.js index 67ca40e8cb68..ba0bd042e10c 100644 --- a/dom/indexedDB/test/unit/head_idb.js +++ b/dom/indexedDB/test/unit/head_idb.js @@ -3,17 +3,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -const Ci = Components.interfaces; -const nsIIndexedDatabaseManager = - Ci.nsIIndexedDatabaseManager; -var idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"] - .getService(nsIIndexedDatabaseManager); -idbManager.initWindowless(this); -// in xpcshell profile are not default -do_get_profile(); -// oddly, if ProfD is requested from some worker thread first instead of the main thread it is crashing... so: -var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties); -var file = dirSvc.get("ProfD", Ci.nsIFile); +const { 'classes': Cc, 'interfaces': Ci } = Components; const DOMException = Ci.nsIDOMDOMException; const IDBCursor = Ci.nsIIDBCursor; @@ -26,7 +16,12 @@ const IDBIndex = Ci.nsIIDBIndex const IDBObjectStore = Ci.nsIIDBObjectStore const IDBRequest = Ci.nsIIDBRequest +// XPCShell does not get a profile by default. +do_get_profile(); +var idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"]. + getService(Ci.nsIIndexedDatabaseManager); +idbManager.initWindowless(this); function is(a, b, msg) { if(a != b) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 13b198ec5882..d0cd91ab8054 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -69,6 +69,7 @@ #include "nsAppDirectoryServiceDefs.h" #include "nsAppRunner.h" #include "IDBFactory.h" +#include "IndexedDatabaseManager.h" #if defined(MOZ_SYDNEYAUDIO) #include "AudioParent.h" #endif @@ -528,18 +529,18 @@ ContentParent::RecvReadPermissions(InfallibleTArray* aPermissio bool ContentParent::RecvGetIndexedDBDirectory(nsString* aDirectory) { - indexedDB::IDBFactory::NoteUsedByProcessType(GeckoProcessType_Content); + using namespace indexedDB; - nsCOMPtr dbDirectory; - nsresult rv = indexedDB::IDBFactory::GetDirectory(getter_AddRefs(dbDirectory)); + IDBFactory::NoteUsedByProcessType(GeckoProcessType_Content); - if (NS_FAILED(rv)) { - NS_ERROR("Failed to get IndexedDB directory"); + nsRefPtr mgr = + IndexedDatabaseManager::GetOrCreate(); + if (!mgr) { + NS_ERROR("This should not fail!"); return true; } - dbDirectory->GetPath(*aDirectory); - + *aDirectory = mgr->GetBaseDirectory(); return true; } From 5932dbcb76c79628565319b949d32242b548e751 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Mon, 30 Apr 2012 17:10:30 -0700 Subject: [PATCH 053/159] Get rooting analysis to pass jit-tests in the interpreter, bug 745742. r=billm --- js/src/builtin/MapObject.cpp | 18 +- js/src/builtin/MapObject.h | 5 + js/src/frontend/BytecodeEmitter.cpp | 33 ++-- js/src/frontend/Parser.cpp | 57 ++++--- js/src/frontend/TokenStream.cpp | 4 +- js/src/frontend/TokenStream.h | 4 +- js/src/gc/Root.h | 46 +++++- js/src/jsapi.cpp | 99 ++++++----- js/src/jsapi.h | 6 +- js/src/jsarray.cpp | 133 +++++++-------- js/src/jsarray.h | 2 +- js/src/jsatom.cpp | 2 + js/src/jsatominlines.h | 2 + js/src/jsclass.h | 19 +++ js/src/jsclone.cpp | 6 +- js/src/jscntxt.h | 31 +++- js/src/jscntxtinlines.h | 3 +- js/src/jscompartment.cpp | 42 ++--- js/src/jscompartment.h | 5 +- js/src/jsdate.cpp | 8 +- js/src/jsdbgapi.cpp | 21 ++- js/src/jsexn.cpp | 12 +- js/src/jsexn.h | 2 +- js/src/jsfriendapi.cpp | 7 +- js/src/jsfun.cpp | 42 ++--- js/src/jsfun.h | 4 +- js/src/jsfuninlines.h | 2 +- js/src/jsgc.cpp | 63 ++++++- js/src/jsgc.h | 9 - js/src/jsgcinlines.h | 2 +- js/src/jsinfer.cpp | 2 +- js/src/jsinterp.cpp | 120 ++++++++------ js/src/jsinterpinlines.h | 24 +-- js/src/jsiter.cpp | 55 ++++--- js/src/jsiter.h | 8 +- js/src/jsnum.cpp | 7 + js/src/jsobj.cpp | 133 +++++++++------ js/src/jsobj.h | 10 +- js/src/jsobjinlines.h | 44 +++-- js/src/json.cpp | 33 ++-- js/src/jsonparser.h | 4 + js/src/jsopcode.cpp | 22 ++- js/src/jsproxy.cpp | 246 ++++++++++++++++------------ js/src/jspubtd.h | 1 + js/src/jsreflect.cpp | 2 + js/src/jsscope.cpp | 27 +-- js/src/jsscope.h | 15 ++ js/src/jsscript.cpp | 36 ++-- js/src/jsscript.h | 2 +- js/src/jsstr.cpp | 40 +++-- js/src/jstypedarray.cpp | 182 ++++++++++++-------- js/src/jswatchpoint.cpp | 23 +-- js/src/jswatchpoint.h | 6 +- js/src/jsweakmap.cpp | 9 +- js/src/jswrapper.cpp | 24 ++- js/src/jsxml.cpp | 15 +- js/src/methodjit/MonoIC.cpp | 2 +- js/src/methodjit/PolyIC.cpp | 12 +- js/src/methodjit/StubCalls.cpp | 3 +- js/src/perf/jsperf.cpp | 2 +- js/src/shell/js.cpp | 33 ++-- js/src/shell/jsheaptools.cpp | 14 +- js/src/vm/ArgumentsObject.cpp | 28 ++-- js/src/vm/Debugger.cpp | 127 +++++++------- js/src/vm/Debugger.h | 12 +- js/src/vm/GlobalObject.cpp | 64 ++++---- js/src/vm/GlobalObject.h | 8 +- js/src/vm/ObjectImpl.h | 8 + js/src/vm/RegExpObject.cpp | 4 +- js/src/vm/RegExpStatics.h | 18 +- js/src/vm/ScopeObject.cpp | 31 ++-- js/src/vm/ScopeObject.h | 2 +- js/src/vm/Stack-inl.h | 7 +- js/src/vm/String-inl.h | 2 + js/src/vm/StringObject-inl.h | 2 +- 75 files changed, 1290 insertions(+), 868 deletions(-) diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 97f366e3a901..ee1930d30d14 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -56,16 +56,16 @@ using namespace js; static JSObject * -InitClass(JSContext *cx, GlobalObject *global, Class *clasp, JSProtoKey key, Native construct, +InitClass(JSContext *cx, Handle global, Class *clasp, JSProtoKey key, Native construct, JSFunctionSpec *methods) { - JSObject *proto = global->createBlankPrototype(cx, clasp); + RootedVarObject proto(cx, global->createBlankPrototype(cx, clasp)); if (!proto) return NULL; proto->setPrivate(NULL); JSAtom *atom = cx->runtime->atomState.classAtoms[key]; - JSFunction *ctor = global->createConstructor(cx, construct, atom, 1); + RootedVarFunction ctor(cx, global->createConstructor(cx, construct, atom, 1)); if (!ctor || !LinkConstructorAndPrototype(cx, ctor, proto) || !DefinePropertiesAndBrand(cx, proto, NULL, methods) || @@ -179,7 +179,8 @@ JSFunctionSpec MapObject::methods[] = { JSObject * MapObject::initClass(JSContext *cx, JSObject *obj) { - return InitClass(cx, &obj->asGlobal(), &class_, JSProto_Map, construct, methods); + return InitClass(cx, RootedVar(cx, &obj->asGlobal()), + &class_, JSProto_Map, construct, methods); } void @@ -224,6 +225,8 @@ class AddToMap { if (!hkey.setValue(cx, key)) return false; + HashableValue::StackRoot hkeyRoot(cx, &hkey); + Value val; if (!pairobj->getElement(cx, 1, &val)) return false; @@ -239,7 +242,7 @@ class AddToMap { JSBool MapObject::construct(JSContext *cx, unsigned argc, Value *vp) { - JSObject *obj = NewBuiltinClassInstance(cx, &class_); + RootedVarObject obj(cx, NewBuiltinClassInstance(cx, &class_)); if (!obj) return false; @@ -381,7 +384,8 @@ JSFunctionSpec SetObject::methods[] = { JSObject * SetObject::initClass(JSContext *cx, JSObject *obj) { - return InitClass(cx, &obj->asGlobal(), &class_, JSProto_Set, construct, methods); + return InitClass(cx, RootedVar(cx, &obj->asGlobal()), + &class_, JSProto_Set, construct, methods); } void @@ -428,7 +432,7 @@ class AddToSet { JSBool SetObject::construct(JSContext *cx, unsigned argc, Value *vp) { - JSObject *obj = NewBuiltinClassInstance(cx, &class_); + RootedVarObject obj(cx, NewBuiltinClassInstance(cx, &class_)); if (!obj) return false; diff --git a/js/src/builtin/MapObject.h b/js/src/builtin/MapObject.h index cbda9aa657fa..c62ea699c3b4 100644 --- a/js/src/builtin/MapObject.h +++ b/js/src/builtin/MapObject.h @@ -73,6 +73,11 @@ class HashableValue { bool setValue(JSContext *cx, const Value &v); HashNumber hash() const; bool equals(const HashableValue &other) const; + + struct StackRoot { + StackRoot(JSContext *cx, HashableValue *pv) : valueRoot(cx, (Value*) &pv->value) {} + RootValue valueRoot; + }; }; typedef HashMap ValueMap; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index eb556c59bf3e..f53835944595 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1150,24 +1150,24 @@ EmitEnterBlock(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op) if (!EmitObjectOp(cx, pn->pn_objbox, op, bce)) return false; - StaticBlockObject &blockObj = pn->pn_objbox->object->asStaticBlock(); + RootedVar blockObj(cx, &pn->pn_objbox->object->asStaticBlock()); int depth = bce->stackDepth - - (blockObj.slotCount() + ((op == JSOP_ENTERLET1) ? 1 : 0)); + (blockObj->slotCount() + ((op == JSOP_ENTERLET1) ? 1 : 0)); JS_ASSERT(depth >= 0); - blockObj.setStackDepth(depth); + blockObj->setStackDepth(depth); int depthPlusFixed = AdjustBlockSlot(cx, bce, depth); if (depthPlusFixed < 0) return false; - for (unsigned i = 0; i < blockObj.slotCount(); i++) { - Definition *dn = blockObj.maybeDefinitionParseNode(i); + for (unsigned i = 0; i < blockObj->slotCount(); i++) { + Definition *dn = blockObj->maybeDefinitionParseNode(i); /* Beware the empty destructuring dummy. */ if (!dn) { - JS_ASSERT(i + 1 <= blockObj.slotCount()); + JS_ASSERT(i + 1 <= blockObj->slotCount()); continue; } @@ -1183,7 +1183,7 @@ EmitEnterBlock(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op) #endif bool aliased = bce->bindingsAccessedDynamically() || bce->shouldNoteClosedName(dn); - blockObj.setAliased(i, aliased); + blockObj->setAliased(i, aliased); } /* @@ -1193,10 +1193,10 @@ EmitEnterBlock(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op) */ if ((bce->flags & TCF_FUN_EXTENSIBLE_SCOPE) || bce->bindings.extensibleParents()) { - Shape *newShape = Shape::setExtensibleParents(cx, blockObj.lastProperty()); + Shape *newShape = Shape::setExtensibleParents(cx, blockObj->lastProperty()); if (!newShape) return false; - blockObj.setLastPropertyInfallible(newShape); + blockObj->setLastPropertyInfallible(newShape); } return true; @@ -3938,7 +3938,7 @@ ParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp) case PNK_RB: { JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST)); - JSObject *obj = NewDenseAllocatedArray(cx, pn_count); + RootedVarObject obj(cx, NewDenseAllocatedArray(cx, pn_count)); if (!obj) return false; @@ -4488,7 +4488,7 @@ EmitLet(JSContext *cx, BytecodeEmitter *bce, ParseNode *pnLet) JS_ASSERT(varList->isArity(PN_LIST)); ParseNode *letBody = pnLet->pn_right; JS_ASSERT(letBody->isLet() && letBody->isKind(PNK_LEXICALSCOPE)); - StaticBlockObject &blockObj = letBody->pn_objbox->object->asStaticBlock(); + RootedVar blockObj(cx, &letBody->pn_objbox->object->asStaticBlock()); ptrdiff_t letHeadOffset = bce->offset(); int letHeadDepth = bce->stackDepth; @@ -4499,7 +4499,7 @@ EmitLet(JSContext *cx, BytecodeEmitter *bce, ParseNode *pnLet) /* Push storage for hoisted let decls (e.g. 'let (x) { let y }'). */ uint32_t alreadyPushed = unsigned(bce->stackDepth - letHeadDepth); - uint32_t blockObjCount = blockObj.slotCount(); + uint32_t blockObjCount = blockObj->slotCount(); for (uint32_t i = alreadyPushed; i < blockObjCount; ++i) { /* Tell the decompiler not to print the decl in the let head. */ if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0) @@ -4509,7 +4509,7 @@ EmitLet(JSContext *cx, BytecodeEmitter *bce, ParseNode *pnLet) } StmtInfo stmtInfo(cx); - PushBlockScope(bce, &stmtInfo, blockObj, bce->offset()); + PushBlockScope(bce, &stmtInfo, *blockObj, bce->offset()); if (!letNotes.update(cx, bce, bce->offset())) return false; @@ -4532,7 +4532,7 @@ EmitLet(JSContext *cx, BytecodeEmitter *bce, ParseNode *pnLet) } JS_ASSERT(leaveOp == JSOP_LEAVEBLOCK || leaveOp == JSOP_LEAVEBLOCKEXPR); - EMIT_UINT16_IMM_OP(leaveOp, blockObj.slotCount()); + EMIT_UINT16_IMM_OP(leaveOp, blockObj->slotCount()); ptrdiff_t bodyEnd = bce->offset(); JS_ASSERT(bodyEnd > bodyBegin); @@ -4637,6 +4637,7 @@ EmitLexicalScope(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) StmtInfo stmtInfo(cx); ObjectBox *objbox = pn->pn_objbox; StaticBlockObject &blockObj = objbox->object->asStaticBlock(); + size_t slots = blockObj.slotCount(); PushBlockScope(bce, &stmtInfo, blockObj, bce->offset()); /* @@ -4675,7 +4676,7 @@ EmitLexicalScope(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) return false; } - EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObj.slotCount()); + EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, slots); return PopStatementBCE(cx, bce); } @@ -4710,7 +4711,7 @@ EmitForIn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE); JS_ASSERT_IF(letDecl, pn1->isLet()); - StaticBlockObject *blockObj = letDecl ? &pn1->pn_objbox->object->asStaticBlock() : NULL; + RootedVar blockObj(cx, letDecl ? &pn1->pn_objbox->object->asStaticBlock() : NULL); uint32_t blockObjCount = blockObj ? blockObj->slotCount() : 0; if (letDecl) { diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 4a48bf8dfc82..a4d531ddf1ab 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -948,19 +948,20 @@ static JSBool BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc); struct BindData { - BindData() : fresh(true) {} + BindData(JSContext *cx) : let(cx), fresh(true) {} ParseNode *pn; /* name node for definition processing and error source coordinates */ JSOp op; /* prolog bytecode or nop */ Binder binder; /* binder, discriminates u */ - union { - struct { - VarContext varContext; - StaticBlockObject *blockObj; - unsigned overflow; - } let; - }; + + struct LetData { + LetData(JSContext *cx) : blockObj(cx) {} + VarContext varContext; + RootedVar blockObj; + unsigned overflow; + } let; + bool fresh; void initLet(VarContext varContext, StaticBlockObject &blockObj, unsigned overflow) { @@ -1040,10 +1041,10 @@ Parser::newFunction(TreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind) RootedVarObject parent(context); parent = tc->inFunction() ? NULL : tc->scopeChain(); - JSFunction *fun = - js_NewFunction(context, NULL, NULL, 0, - JSFUN_INTERPRETED | (kind == Expression ? JSFUN_LAMBDA : 0), - parent, atom); + RootedVarFunction fun(context); + fun = js_NewFunction(context, NULL, NULL, 0, + JSFUN_INTERPRETED | (kind == Expression ? JSFUN_LAMBDA : 0), + parent, atom); if (fun && !tc->compileAndGo()) { if (!fun->clearParent(context)) return NULL; @@ -1268,7 +1269,7 @@ LeaveFunction(ParseNode *fn, TreeContext *funtc, PropertyName *funName = NULL, } static bool -DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name); +DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, Handle name); /* * FIXME? this Parser method was factored from Parser::functionDef with minimal @@ -1308,7 +1309,7 @@ Parser::functionArguments(TreeContext &funtc, FunctionBox *funbox, ParseNode **l * anonymous positional parameter, so here we must tweak our * binder and its data. */ - BindData data; + BindData data(context); data.pn = NULL; data.op = JSOP_DEFVAR; data.binder = BindDestructuringArg; @@ -2083,7 +2084,7 @@ OuterLet(TreeContext *tc, StmtInfo *stmt, JSAtom *atom) * stack frame slots. */ static bool -DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name) +DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, Handle name) { GlobalScope *globalScope = bce->globalScope; HandleObject globalObj = globalScope->globalObj; @@ -2091,7 +2092,6 @@ DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name) if (!bce->compileAndGo() || !globalObj || bce->compilingForEval()) return true; - JS_ASSERT(!IsPoisonedPtr(name)); AtomIndexAddPtr p = globalScope->names.lookupForAdd(name); if (!p) { JSContext *cx = bce->parser->context; @@ -2129,8 +2129,6 @@ DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name) if (!globalScope->defs.append(def)) return false; - JS_ASSERT(!IsPoisonedPtr(name)); - jsatomid index = globalScope->names.count(); if (!globalScope->names.add(p, name, index)) return false; @@ -2212,7 +2210,8 @@ BindTopLevelVar(JSContext *cx, BindData *data, ParseNode *pn, TreeContext *tc) * is present, try to bake in either an already available slot or a * predicted slot that will be defined after compiling is completed. */ - return DefineGlobal(pn, tc->asBytecodeEmitter(), pn->pn_atom->asPropertyName()); + return DefineGlobal(pn, tc->asBytecodeEmitter(), + RootedVarPropertyName(cx, pn->pn_atom->asPropertyName())); } static bool @@ -2596,7 +2595,7 @@ CheckDestructuring(JSContext *cx, BindData *data, ParseNode *left, TreeContext * } RootedVar blockObj(cx); - blockObj = data && data->binder == BindLet ? data->let.blockObj : NULL; + blockObj = data && data->binder == BindLet ? data->let.blockObj.reference() : NULL; uint32_t blockCountBefore = blockObj ? blockObj->slotCount() : 0; if (left->isKind(PNK_RB)) { @@ -2895,7 +2894,7 @@ Parser::letBlock(LetContext letContext) if (!pnlet) return NULL; - StaticBlockObject *blockObj = StaticBlockObject::create(context); + RootedVar blockObj(context, StaticBlockObject::create(context)); if (!blockObj) return NULL; @@ -3185,7 +3184,7 @@ Parser::forStatement() bool forDecl = false; /* Non-null when forDecl is true for a 'for (let ...)' statement. */ - StaticBlockObject *blockObj = NULL; + RootedVar blockObj(context); /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */ ParseNode *pn1; @@ -3578,7 +3577,7 @@ Parser::tryStatement() do { ParseNode *pnblock; - BindData data; + BindData data(context); /* Check for another catch after unconditional catch. */ if (lastCatch && !lastCatch->pn_kid2) { @@ -4320,7 +4319,7 @@ Parser::variables(ParseNodeKind kind, StaticBlockObject *blockObj, VarContext va * var, whereas let is block scoped. ES-Harmony wants block-scoped const so * this code will change soon. */ - BindData data; + BindData data(context); if (blockObj) data.initLet(varContext, *blockObj, JSMSG_TOO_MANY_LOCALS); else @@ -5314,7 +5313,7 @@ Parser::comprehensionTail(ParseNode *kid, unsigned blockid, bool isGenexp, unsigned adjust; ParseNode *pn, *pn2, *pn3, **pnp; StmtInfo stmtInfo(context); - BindData data; + BindData data(context); TokenKind tt; JS_ASSERT(tokenStream.currentToken().type == TOK_FOR); @@ -5387,7 +5386,7 @@ Parser::comprehensionTail(ParseNode *kid, unsigned blockid, bool isGenexp, GenexpGuard guard(tc); - PropertyName *name = NULL; + RootedVarPropertyName name(context); tt = tokenStream.getToken(); switch (tt) { #if JS_HAS_DESTRUCTURING @@ -6389,7 +6388,7 @@ Parser::xmlElementOrList(JSBool allowList) ParseNode *pn, *pn2, *list; TokenKind tt; - JSAtom *startAtom, *endAtom; + RootedVarAtom startAtom(context), endAtom(context); JS_CHECK_RECURSION(context, return NULL); @@ -6407,7 +6406,7 @@ Parser::xmlElementOrList(JSBool allowList) /* * XMLElement. Append the tag and its contents, if any, to pn. */ - pn2 = xmlTagContent(PNK_XMLSTAGO, &startAtom); + pn2 = xmlTagContent(PNK_XMLSTAGO, startAtom.address()); if (!pn2) return NULL; tokenStream.matchToken(TOK_XMLSPACE); @@ -6466,7 +6465,7 @@ Parser::xmlElementOrList(JSBool allowList) } /* Parse end tag; check mismatch at compile-time if we can. */ - pn2 = xmlTagContent(PNK_XMLETAGO, &endAtom); + pn2 = xmlTagContent(PNK_XMLETAGO, endAtom.address()); if (!pn2) return NULL; if (pn2->isKind(PNK_XMLETAGO)) { diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 902edb35532c..d689761dd5fa 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -155,7 +155,9 @@ js::IsIdentifier(JSLinearString *str) /* Initialize members that aren't initialized in |init|. */ TokenStream::TokenStream(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin) : tokens(), tokensRoot(cx, &tokens), - cursor(), lookahead(), flags(), userbufRoot(cx, &userbuf), listenerTSData(), tokenbuf(cx), + cursor(), lookahead(), flags(), + linebaseRoot(cx, &linebase), prevLinebaseRoot(cx, &prevLinebase), userbufRoot(cx, &userbuf), + listenerTSData(), tokenbuf(cx), cx(cx), originPrincipals(JSScript::normalizeOriginPrincipals(prin, originPrin)) { if (originPrincipals) diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 53f8d7a26f4f..cdff3afc5bd3 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -819,8 +819,10 @@ class TokenStream unsigned flags; /* flags -- see above */ const jschar *linebase; /* start of current line; points into userbuf */ const jschar *prevLinebase; /* start of previous line; NULL if on the first line */ + JS::SkipRoot linebaseRoot; + JS::SkipRoot prevLinebaseRoot; TokenBuf userbuf; /* user input buffer */ - JS::SkipRoot userbufRoot; /* prevent overwriting of char pointers within userbuf */ + JS::SkipRoot userbufRoot; const char *filename; /* input filename or null */ jschar *sourceMap; /* source map's filename or null */ void *listenerTSData;/* listener data for this TokenStream */ diff --git a/js/src/gc/Root.h b/js/src/gc/Root.h index 4babe71a9083..b9d3b4825157 100644 --- a/js/src/gc/Root.h +++ b/js/src/gc/Root.h @@ -137,6 +137,7 @@ class Handle template inline Handle(const RootedVar &root); const T *address() { return ptr; } + T value() { return *ptr; } operator T () { return value(); } T operator ->() { return value(); } @@ -145,7 +146,6 @@ class Handle Handle() {} const T *ptr; - T value() { return *ptr; } template void testAssign() { @@ -196,9 +196,9 @@ class Root this->stack = reinterpret_cast**>(&cx->thingGCRooters[kind]); this->prev = *stack; *stack = this; -#endif JS_ASSERT(!RootMethods::poisoned(*ptr)); +#endif this->ptr = ptr; @@ -257,18 +257,30 @@ class SkipRoot const uint8_t *start; const uint8_t *end; - public: template - SkipRoot(JSContext *cx_, const T *ptr - JS_GUARD_OBJECT_NOTIFIER_PARAM) + void init(ContextFriendFields *cx, const T *ptr, size_t count) { - ContextFriendFields *cx = ContextFriendFields::get(cx_); - this->stack = &cx->skipGCRooters; this->prev = *stack; *stack = this; this->start = (const uint8_t *) ptr; - this->end = this->start + sizeof(T); + this->end = this->start + (sizeof(T) * count); + } + + public: + template + SkipRoot(JSContext *cx, const T *ptr + JS_GUARD_OBJECT_NOTIFIER_PARAM) + { + init(ContextFriendFields::get(cx), ptr, 1); + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + template + SkipRoot(JSContext *cx, const T *ptr, size_t count + JS_GUARD_OBJECT_NOTIFIER_PARAM) + { + init(ContextFriendFields::get(cx), ptr, count); JS_GUARD_OBJECT_NOTIFIER_INIT; } @@ -294,6 +306,13 @@ class SkipRoot JS_GUARD_OBJECT_NOTIFIER_INIT; } + template + SkipRoot(JSContext *cx, const T *ptr, size_t count + JS_GUARD_OBJECT_NOTIFIER_PARAM) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + #endif /* DEBUG && JSGC_ROOT_ANALYSIS */ JS_DECL_USE_GUARD_OBJECT_NOTIFIER @@ -363,6 +382,17 @@ typedef RootedVar RootedVarString; typedef RootedVar RootedVarId; typedef RootedVar RootedVarValue; +/* + * Hook for dynamic root analysis. Checks the native stack and poisons + * references to GC things which have not been rooted. + */ +#if defined(JSGC_ROOT_ANALYSIS) && defined(DEBUG) && !defined(JS_THREADSAFE) +void CheckStackRoots(JSContext *cx); +inline void MaybeCheckStackRoots(JSContext *cx) { CheckStackRoots(cx); } +#else +inline void MaybeCheckStackRoots(JSContext *cx) {} +#endif + } /* namespace JS */ #endif /* __cplusplus */ diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 0fc2e967f323..3aec067cb368 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -544,8 +544,7 @@ JS_ValueToNumber(JSContext *cx, jsval v, double *dp) CHECK_REQUEST(cx); assertSameCompartment(cx, v); - AutoValueRooter tvr(cx, v); - return ToNumber(cx, tvr.value(), dp); + return ToNumber(cx, v, dp); } JS_PUBLIC_API(JSBool) @@ -573,8 +572,8 @@ JS_ValueToECMAInt32(JSContext *cx, jsval v, int32_t *ip) CHECK_REQUEST(cx); assertSameCompartment(cx, v); - AutoValueRooter tvr(cx, v); - return ToInt32(cx, tvr.value(), ip); + RootedVarValue value(cx, v); + return ToInt32(cx, value, ip); } JS_PUBLIC_API(JSBool) @@ -584,8 +583,7 @@ JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32_t *ip) CHECK_REQUEST(cx); assertSameCompartment(cx, v); - AutoValueRooter tvr(cx, v); - return ToUint32(cx, tvr.value(), (uint32_t *)ip); + return ToUint32(cx, v, (uint32_t *)ip); } JS_PUBLIC_API(JSBool) @@ -595,8 +593,7 @@ JS_ValueToInt32(JSContext *cx, jsval v, int32_t *ip) CHECK_REQUEST(cx); assertSameCompartment(cx, v); - AutoValueRooter tvr(cx, v); - return NonstandardToInt32(cx, tvr.value(), (int32_t *)ip); + return NonstandardToInt32(cx, v, (int32_t *)ip); } JS_PUBLIC_API(JSBool) @@ -606,8 +603,7 @@ JS_ValueToUint16(JSContext *cx, jsval v, uint16_t *ip) CHECK_REQUEST(cx); assertSameCompartment(cx, v); - AutoValueRooter tvr(cx, v); - return ValueToUint16(cx, tvr.value(), (uint16_t *)ip); + return ValueToUint16(cx, v, (uint16_t *)ip); } JS_PUBLIC_API(JSBool) @@ -746,6 +742,7 @@ JSRuntime::JSRuntime() gcInterFrameGC(0), gcSliceBudget(SliceBudget::Unlimited), gcIncrementalEnabled(true), + gcExactScanningEnabled(true), gcPoke(false), gcRunning(false), #ifdef JS_GC_ZEAL @@ -1723,7 +1720,7 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj) assertSameCompartment(cx, obj); - return obj->global().initStandardClasses(cx); + return GlobalObject::initStandardClasses(cx, RootedVar(cx, &obj->global())); } #define CLASP(name) (&name##Class) @@ -1975,16 +1972,18 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved) } JS_PUBLIC_API(JSBool) -JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj) +JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj_) { JSRuntime *rt; unsigned i; AssertNoGC(cx); CHECK_REQUEST(cx); - assertSameCompartment(cx, obj); + assertSameCompartment(cx, obj_); rt = cx->runtime; + RootedVarObject obj(cx, obj_); + /* * Check whether we need to bind 'undefined' and define it if so. * Since ES5 15.1.1.3 undefined can't be deleted. @@ -3174,7 +3173,7 @@ JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto) AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, proto); - return SetProto(cx, obj, proto, JS_FALSE); + return SetProto(cx, RootedVarObject(cx, obj), RootedVarObject(cx, proto), JS_FALSE); } JS_PUBLIC_API(JSObject *) @@ -3192,7 +3191,7 @@ JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent) JS_ASSERT(!obj->isScope()); JS_ASSERT(parent || !obj->getParent()); assertSameCompartment(cx, obj, parent); - return obj->setParent(cx, parent); + return JSObject::setParent(cx, RootedVarObject(cx, obj), RootedVarObject(cx, parent)); } JS_PUBLIC_API(JSObject *) @@ -3409,12 +3408,12 @@ JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *paren JSProtoKey protoKey = GetClassProtoKey(clasp); /* Protect constructor in case a crazy getter for .prototype uproots it. */ - AutoValueRooter tvr(cx); - if (!js_FindClassObject(cx, parent, protoKey, tvr.addr(), clasp)) + RootedVarValue value(cx); + if (!js_FindClassObject(cx, parent, protoKey, value.address(), clasp)) return NULL; Value rval; - if (!InvokeConstructor(cx, tvr.value(), argc, argv, &rval)) + if (!InvokeConstructor(cx, value, argc, argv, &rval)) return NULL; /* @@ -3624,7 +3623,7 @@ JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, siz } static JSBool -DefinePropertyById(JSContext *cx, HandleObject obj, jsid id, const Value &value, +DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs, unsigned flags, int tinyid) { @@ -3644,8 +3643,6 @@ DefinePropertyById(JSContext *cx, HandleObject obj, jsid id, const Value &value, * JS Function objects. */ if (attrs & JSPROP_NATIVE_ACCESSORS) { - RootId idRoot(cx, &id); - JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); attrs &= ~JSPROP_NATIVE_ACCESSORS; if (getter) { @@ -3656,6 +3653,7 @@ DefinePropertyById(JSContext *cx, HandleObject obj, jsid id, const Value &value, attrs |= JSPROP_GETTER; } if (setter) { + RootObject getRoot(cx, (JSObject **) &getter); JSObject *setobj = JS_NewFunction(cx, (Native) setter, 1, 0, &obj->global(), NULL); if (!setobj) return false; @@ -3684,22 +3682,26 @@ DefinePropertyById(JSContext *cx, HandleObject obj, jsid id, const Value &value, } JS_PUBLIC_API(JSBool) -JS_DefinePropertyById(JSContext *cx, JSObject *obj_, jsid id, jsval value, +JS_DefinePropertyById(JSContext *cx, JSObject *obj_, jsid id_, jsval value_, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) { RootedVarObject obj(cx, obj_); + RootedVarId id(cx, id_); + RootedVarValue value(cx, value_); return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0); } JS_PUBLIC_API(JSBool) -JS_DefineElement(JSContext *cx, JSObject *obj_, uint32_t index, jsval value, +JS_DefineElement(JSContext *cx, JSObject *obj_, uint32_t index, jsval value_, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) { RootedVarObject obj(cx, obj_); + RootedVarValue value(cx, value_); + RootGetterSetter gsRoot(cx, attrs, &getter, &setter); AssertNoGC(cx); CHECK_REQUEST(cx); - jsid id; - if (!IndexToId(cx, index, &id)) + RootedVarId id(cx); + if (!IndexToId(cx, index, id.address())) return false; return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0); } @@ -3709,18 +3711,16 @@ DefineProperty(JSContext *cx, JSObject *obj_, const char *name, const Value &val PropertyOp getter, StrictPropertyOp setter, unsigned attrs, unsigned flags, int tinyid) { - jsid id; - JSAtom *atom; - RootedVarObject obj(cx, obj_); RootedVarValue value(cx, value_); + RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + RootedVarId id(cx); if (attrs & JSPROP_INDEX) { id = INT_TO_JSID(intptr_t(name)); - atom = NULL; attrs &= ~JSPROP_INDEX; } else { - atom = js_Atomize(cx, name, strlen(name)); + JSAtom *atom = js_Atomize(cx, name, strlen(name)); if (!atom) return JS_FALSE; id = ATOM_TO_JSID(atom); @@ -3745,13 +3745,17 @@ JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8 static JSBool DefineUCProperty(JSContext *cx, JSObject *obj_, const jschar *name, size_t namelen, - const Value &value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs, + const Value &value_, PropertyOp getter, StrictPropertyOp setter, unsigned attrs, unsigned flags, int tinyid) { - RootObject obj(cx, &obj_); + RootedVarObject obj(cx, obj_); + RootedVarValue value(cx, value_); + RootGetterSetter gsRoot(cx, attrs, &getter, &setter); JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); - return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs, - flags, tinyid); + if (!atom) + return false; + RootedVarId id(cx, ATOM_TO_JSID(atom)); + return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid); } JS_PUBLIC_API(JSBool) @@ -4049,22 +4053,25 @@ JS_GetElementIfPresent(JSContext *cx, JSObject *obj, uint32_t index, JSObject *o } JS_PUBLIC_API(JSBool) -JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp) +JS_GetProperty(JSContext *cx, JSObject *obj_, const char *name, jsval *vp) { + RootedVarObject obj(cx, obj_); JSAtom *atom = js_Atomize(cx, name, strlen(name)); return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp); } JS_PUBLIC_API(JSBool) -JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def, jsval *vp) +JS_GetPropertyDefault(JSContext *cx, JSObject *obj_, const char *name, jsval def, jsval *vp) { + RootedVarObject obj(cx, obj_); JSAtom *atom = js_Atomize(cx, name, strlen(name)); return atom && JS_GetPropertyByIdDefault(cx, obj, ATOM_TO_JSID(atom), def, vp); } JS_PUBLIC_API(JSBool) -JS_GetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp) +JS_GetUCProperty(JSContext *cx, JSObject *obj_, const jschar *name, size_t namelen, jsval *vp) { + RootedVarObject obj(cx, obj_); JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp); } @@ -4100,18 +4107,22 @@ JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) } JS_PUBLIC_API(JSBool) -JS_SetElement(JSContext *cx, JSObject *obj, uint32_t index, jsval *vp) +JS_SetElement(JSContext *cx, JSObject *obj_, uint32_t index, jsval *vp) { AssertNoGC(cx); CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, *vp); + assertSameCompartment(cx, obj_, *vp); + RootedVarObject obj(cx, obj_); + RootValue vpRoot(cx, vp); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); return obj->setElement(cx, index, vp, false); } JS_PUBLIC_API(JSBool) -JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp) +JS_SetProperty(JSContext *cx, JSObject *obj_, const char *name, jsval *vp) { + RootedVarObject obj(cx, obj_); + RootValue vpRoot(cx, vp); JSAtom *atom = js_Atomize(cx, name, strlen(name)); return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp); } @@ -4383,7 +4394,7 @@ JS_NewElementIterator(JSContext *cx, JSObject *obj) AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - return ElementIteratorObject::create(cx, obj); + return ElementIteratorObject::create(cx, RootedVarObject(cx, obj)); } JS_PUBLIC_API(JSObject *) @@ -4615,9 +4626,9 @@ JS_IsNativeFunction(JSObject *funobj, JSNative call) JS_PUBLIC_API(JSObject*) JS_BindCallable(JSContext *cx, JSObject *callable, JSObject *newThis) { - RootedVarObject target(cx); - target = callable; - return js_fun_bind(cx, target, ObjectValue(*newThis), NULL, 0); + RootedVarObject target(cx, callable); + RootedVarValue thisArg(cx, ObjectValue(*newThis)); + return js_fun_bind(cx, target, thisArg, NULL, 0); } JSBool diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 1872ce536792..266b3a63574f 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1070,7 +1070,7 @@ class AutoArrayRooter : private AutoGCRooter { public: AutoArrayRooter(JSContext *cx, size_t len, Value *vec JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, len), array(vec) + : AutoGCRooter(cx, len), array(vec), skip(cx, array, len) { JS_GUARD_OBJECT_NOTIFIER_INIT; JS_ASSERT(tag >= 0); @@ -1092,6 +1092,8 @@ class AutoArrayRooter : private AutoGCRooter { private: JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + SkipRoot skip; }; /* The auto-root for enumeration object and its state. */ @@ -2381,8 +2383,10 @@ JS_ALWAYS_INLINE bool ToNumber(JSContext *cx, const Value &v, double *out) { AssertArgumentsAreSane(cx, v); + if (v.isNumber()) { *out = v.toNumber(); + MaybeCheckStackRoots(cx); return true; } return js::ToNumberSlow(cx, v, out); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 120671ee6dc0..ac0f9a69f1b8 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -166,17 +166,17 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, uint32_t *lengthp) } } - AutoValueRooter tvr(cx); - if (!obj->getProperty(cx, cx->runtime->atomState.lengthAtom, tvr.addr())) + RootedVarValue value(cx); + if (!obj->getProperty(cx, cx->runtime->atomState.lengthAtom, value.address())) return false; - if (tvr.value().isInt32()) { - *lengthp = uint32_t(tvr.value().toInt32()); /* uint32_t cast does ToUint32_t */ + if (value.reference().isInt32()) { + *lengthp = uint32_t(value.reference().toInt32()); /* uint32_t cast does ToUint32_t */ return true; } - return ToUint32(cx, tvr.value(), (uint32_t *)lengthp); + return ToUint32(cx, value, (uint32_t *)lengthp); } namespace js { @@ -366,12 +366,13 @@ JSObject::arrayGetOwnDataElement(JSContext *cx, size_t i, Value *vp) * properly rooted and can be used as GC-protected storage for temporaries. */ static inline JSBool -DoGetElement(JSContext *cx, JSObject *obj, double index, JSBool *hole, Value *vp) +DoGetElement(JSContext *cx, JSObject *obj_, double index, JSBool *hole, Value *vp) { - AutoIdRooter idr(cx); + RootedVarObject obj(cx, obj_); + RootedVarId id(cx); *hole = JS_FALSE; - if (!IndexToId(cx, obj, index, hole, idr.addr())) + if (!IndexToId(cx, obj, index, hole, id.address())) return JS_FALSE; if (*hole) { vp->setUndefined(); @@ -380,13 +381,13 @@ DoGetElement(JSContext *cx, JSObject *obj, double index, JSBool *hole, Value *vp JSObject *obj2; JSProperty *prop; - if (!obj->lookupGeneric(cx, idr.id(), &obj2, &prop)) + if (!obj->lookupGeneric(cx, id, &obj2, &prop)) return JS_FALSE; if (!prop) { vp->setUndefined(); *hole = JS_TRUE; } else { - if (!obj->getGeneric(cx, idr.id(), vp)) + if (!obj->getGeneric(cx, id, vp)) return JS_FALSE; *hole = JS_FALSE; } @@ -443,7 +444,7 @@ GetElement(JSContext *cx, JSObject *obj, IndexType index, JSBool *hole, Value *v namespace js { static bool -GetElementsSlow(JSContext *cx, JSObject *aobj, uint32_t length, Value *vp) +GetElementsSlow(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp) { for (uint32_t i = 0; i < length; i++) { if (!aobj->getElement(cx, i, &vp[i])) @@ -454,7 +455,7 @@ GetElementsSlow(JSContext *cx, JSObject *aobj, uint32_t length, Value *vp) } bool -GetElements(JSContext *cx, JSObject *aobj, uint32_t length, Value *vp) +GetElements(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp) { if (aobj->isDenseArray() && length <= aobj->getDenseArrayInitializedLength() && !js_PrototypeHasIndexedProperties(cx, aobj)) { @@ -517,8 +518,8 @@ SetArrayElement(JSContext *cx, HandleObject obj, double index, const Value &v) return JS_FALSE; JS_ASSERT(!JSID_IS_VOID(idr.id())); - Value tmp = v; - return obj->setGeneric(cx, idr.id(), &tmp, true); + RootedVarValue tmp(cx, v); + return obj->setGeneric(cx, idr.id(), tmp.address(), true); } /* @@ -1075,18 +1076,12 @@ namespace js { /* non-static for direct definition of array elements within the engine */ JSBool -array_defineElement(JSContext *cx, JSObject *obj_, uint32_t index, const Value *value, +array_defineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { - RootedVarObject obj(cx, obj_); - if (!obj->isDenseArray()) return js_DefineElement(cx, obj, index, value, getter, setter, attrs); - jsid id; - if (!IndexToId(cx, index, &id)) - return false; - do { /* * UINT32_MAX is not an array index and must not affect the length @@ -1109,7 +1104,11 @@ array_defineElement(JSContext *cx, JSObject *obj_, uint32_t index, const Value * return true; } while (false); - if (!JSObject::makeDenseArraySlow(cx, obj)) + RootObject objRoot(cx, &obj); + RootValue valueRoot(cx, value); + RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + + if (!JSObject::makeDenseArraySlow(cx, objRoot)) return false; return js_DefineElement(cx, obj, index, value, getter, setter, attrs); } @@ -1211,7 +1210,7 @@ array_deleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, J obj->setDenseArrayElement(index, MagicValue(JS_ARRAY_HOLE)); } - if (!js_SuppressDeletedElement(cx, obj, index)) + if (!js_SuppressDeletedElement(cx, RootedVarObject(cx, obj), index)) return false; rval->setBoolean(true); @@ -1468,7 +1467,7 @@ class ArraySharpDetector sharp(false) {} - bool init(JSObject *obj) { + bool init(HandleObject obj) { success = js_EnterSharpObject(cx, obj, NULL, &alreadySeen, &sharp); if (!success) return false; @@ -1492,7 +1491,7 @@ array_toSource(JSContext *cx, unsigned argc, Value *vp) JS_CHECK_RECURSION(cx, return false); CallArgs args = CallArgsFromVp(argc, vp); - JSObject *obj = ToObject(cx, &args.thisv()); + RootedVarObject obj(cx, ToObject(cx, &args.thisv())); if (!obj) return false; if (!obj->isArray()) @@ -1608,17 +1607,15 @@ class AutoArrayCycleDetector }; static JSBool -array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, - JSString *sepstr, CallArgs &args) +array_toString_sub(JSContext *cx, HandleObject obj, JSBool locale, + HandleString sepstr, CallArgs &args) { static const jschar comma = ','; const jschar *sep; size_t seplen; if (sepstr) { + sep = NULL; seplen = sepstr->length(); - sep = sepstr->getChars(cx); - if (!sep) - return false; } else { sep = , seplen = 1; @@ -1697,7 +1694,8 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, } if (index + 1 != length) { - if (!sb.append(sep, seplen)) + const jschar *sepchars = sep ? sep : sepstr->getChars(cx); + if (!sepchars || !sb.append(sepchars, seplen)) return false; } } @@ -1753,7 +1751,7 @@ array_toLocaleString(JSContext *cx, unsigned argc, Value *vp) JS_CHECK_RECURSION(cx, return false); CallArgs args = CallArgsFromVp(argc, vp); - JSObject *obj = ToObject(cx, &args.thisv()); + RootedVarObject obj(cx, ToObject(cx, &args.thisv())); if (!obj) return false; @@ -1761,7 +1759,7 @@ array_toLocaleString(JSContext *cx, unsigned argc, Value *vp) * Passing comma here as the separator. Need a way to get a * locale-specific version. */ - return array_toString_sub(cx, obj, JS_TRUE, NULL, args); + return array_toString_sub(cx, obj, JS_TRUE, RootedVarString(cx), args); } static inline bool @@ -1844,13 +1842,13 @@ InitArrayElements(JSContext *cx, HandleObject obj, uint32_t start, uint32_t coun return false; JS_ASSERT(start == MAX_ARRAY_INDEX + 1); - AutoValueRooter tvr(cx); - AutoIdRooter idr(cx); + RootedVarValue value(cx); + RootedVarId id(cx); Value idval = DoubleValue(MAX_ARRAY_INDEX + 1); do { - *tvr.addr() = *vector++; - if (!js_ValueToStringId(cx, idval, idr.addr()) || - !obj->setGeneric(cx, idr.id(), tvr.addr(), true)) { + value = *vector++; + if (!js_ValueToStringId(cx, idval, id.address()) || + !obj->setGeneric(cx, id, value.address(), true)) { return false; } idval.getDoubleRef() += 1; @@ -1900,7 +1898,7 @@ array_join(JSContext *cx, unsigned argc, Value *vp) JS_CHECK_RECURSION(cx, return false); CallArgs args = CallArgsFromVp(argc, vp); - JSString *str; + RootedVarString str(cx); if (args.hasDefined(0)) { str = ToString(cx, args[0]); if (!str) @@ -1909,7 +1907,7 @@ array_join(JSContext *cx, unsigned argc, Value *vp) } else { str = NULL; } - JSObject *obj = ToObject(cx, &args.thisv()); + RootedVarObject obj(cx, ToObject(cx, &args.thisv())); if (!obj) return false; return array_toString_sub(cx, obj, JS_FALSE, str, args); @@ -2223,6 +2221,8 @@ js::array_sort(JSContext *cx, unsigned argc, Value *vp) fval.setNull(); } + RootValue fvalRoot(cx, &fval); + RootedVarObject obj(cx, ToObject(cx, &args.thisv())); if (!obj) return false; @@ -2487,8 +2487,8 @@ array_pop_slowly(JSContext *cx, HandleObject obj, CallArgs &args) index--; JSBool hole; - Value elt; - if (!GetElement(cx, obj, index, &hole, &elt)) + RootedVarValue elt(cx); + if (!GetElement(cx, obj, index, &hole, elt.address())) return false; if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) @@ -2510,8 +2510,8 @@ array_pop_dense(JSContext *cx, HandleObject obj, CallArgs &args) index--; JSBool hole; - Value elt; - if (!GetElement(cx, obj, index, &hole, &elt)) + RootedVarValue elt(cx); + if (!GetElement(cx, obj, index, &hole, elt.address())) return JS_FALSE; if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) @@ -2590,11 +2590,11 @@ js::array_shift(JSContext *cx, unsigned argc, Value *vp) return JS_FALSE; /* Slide down the array above the first element. */ - AutoValueRooter tvr(cx); + RootedVarValue value(cx); for (uint32_t i = 0; i < length; i++) { if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, i + 1, &hole, tvr.addr()) || - !SetOrDeleteArrayElement(cx, obj, i, hole, tvr.value())) { + !GetElement(cx, obj, i + 1, &hole, value.address()) || + !SetOrDeleteArrayElement(cx, obj, i, hole, value)) { return JS_FALSE; } } @@ -2644,13 +2644,13 @@ array_unshift(JSContext *cx, unsigned argc, Value *vp) if (!optimized) { double last = length; double upperIndex = last + args.length(); - AutoValueRooter tvr(cx); + RootedVarValue value(cx); do { --last, --upperIndex; JSBool hole; if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, last, &hole, tvr.addr()) || - !SetOrDeleteArrayElement(cx, obj, upperIndex, hole, tvr.value())) { + !GetElement(cx, obj, last, &hole, value.address()) || + !SetOrDeleteArrayElement(cx, obj, upperIndex, hole, value)) { return JS_FALSE; } } while (last != 0); @@ -2771,7 +2771,7 @@ array_splice(JSContext *cx, unsigned argc, Value *vp) JS_ASSERT(len - actualStart >= actualDeleteCount); /* Steps 2, 8-9. */ - JSObject *arr; + RootedVarObject arr(cx); if (CanOptimizeForDenseStorage(obj, actualStart, actualDeleteCount, cx)) { arr = NewDenseCopiedArray(cx, actualDeleteCount, obj->getDenseArrayElements() + actualStart); @@ -2989,15 +2989,15 @@ js::array_concat(JSContext *cx, unsigned argc, Value *vp) return false; const Value &v = p[i]; if (v.isObject()) { - JSObject &obj = v.toObject(); - if (ObjectClassIs(obj, ESClass_Array, cx)) { + RootedVarObject obj(cx, &v.toObject()); + if (ObjectClassIs(*obj, ESClass_Array, cx)) { uint32_t alength; - if (!js_GetLengthProperty(cx, &obj, &alength)) + if (!js_GetLengthProperty(cx, obj, &alength)) return false; for (uint32_t slot = 0; slot < alength; slot++) { JSBool hole; Value tmp; - if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetElement(cx, &obj, slot, &hole, &tmp)) + if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetElement(cx, obj, slot, &hole, &tmp)) return false; /* @@ -3028,7 +3028,7 @@ array_slice(JSContext *cx, unsigned argc, Value *vp) CallArgs args = CallArgsFromVp(argc, vp); - JSObject *obj = ToObject(cx, &args.thisv()); + RootedVarObject obj(cx, ToObject(cx, &args.thisv())); if (!obj) return false; @@ -3084,13 +3084,13 @@ array_slice(JSContext *cx, unsigned argc, Value *vp) return JS_FALSE; TryReuseArrayType(obj, nobj); - AutoValueRooter tvr(cx); + RootedVarValue value(cx); for (slot = begin; slot < end; slot++) { if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, slot, &hole, tvr.addr())) { + !GetElement(cx, obj, slot, &hole, value.address())) { return JS_FALSE; } - if (!hole && !SetArrayElement(cx, nobj, slot - begin, tvr.value())) + if (!hole && !SetArrayElement(cx, nobj, slot - begin, value)) return JS_FALSE; } @@ -3234,7 +3234,7 @@ static inline bool array_readonlyCommon(JSContext *cx, CallArgs &args) { /* Step 1. */ - JSObject *obj = ToObject(cx, &args.thisv()); + RootedVarObject obj(cx, ToObject(cx, &args.thisv())); if (!obj) return false; @@ -3248,7 +3248,7 @@ array_readonlyCommon(JSContext *cx, CallArgs &args) js_ReportMissingArg(cx, args.calleev(), 0); return false; } - JSObject *callable = js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK); + RootedVarObject callable(cx, js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK)); if (!callable) return false; @@ -3326,7 +3326,7 @@ array_map(JSContext *cx, unsigned argc, Value *vp) CallArgs args = CallArgsFromVp(argc, vp); /* Step 1. */ - JSObject *obj = ToObject(cx, &args.thisv()); + RootedVarObject obj(cx, ToObject(cx, &args.thisv())); if (!obj) return false; @@ -3340,7 +3340,7 @@ array_map(JSContext *cx, unsigned argc, Value *vp) js_ReportMissingArg(cx, args.calleev(), 0); return false; } - JSObject *callable = js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK); + RootedVarObject callable(cx, js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK)); if (!callable) return false; @@ -3402,7 +3402,7 @@ array_filter(JSContext *cx, unsigned argc, Value *vp) CallArgs args = CallArgsFromVp(argc, vp); /* Step 1. */ - JSObject *obj = ToObject(cx, &args.thisv()); + RootedVarObject obj(cx, ToObject(cx, &args.thisv())); if (!obj) return false; @@ -3416,7 +3416,7 @@ array_filter(JSContext *cx, unsigned argc, Value *vp) js_ReportMissingArg(cx, args.calleev(), 0); return false; } - JSObject *callable = js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK); + RootedVarObject callable(cx, js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK)); if (!callable) return false; @@ -3880,6 +3880,9 @@ mjit::stubs::NewDenseUnallocatedArray(VMFrame &f, uint32_t length) JSObject * NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *vp, JSObject *proto /* = NULL */) { + // XXX vp may be an internal pointer to an object's dense array elements. + SkipRoot skip(cx, &vp); + JSObject* obj = NewArray(cx, length, proto); if (!obj) return NULL; diff --git a/js/src/jsarray.h b/js/src/jsarray.h index a3dc5a203ac6..092ee3ab5d08 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -136,7 +136,7 @@ array_deleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, J * js_GetLengthProperty on aobj. */ extern bool -GetElements(JSContext *cx, JSObject *aobj, uint32_t length, js::Value *vp); +GetElements(JSContext *cx, HandleObject aobj, uint32_t length, js::Value *vp); /* Natives exposed for optimization by the interpreter and JITs. */ diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index f716d7ae6183..2e54a3f4d84c 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -340,6 +340,8 @@ AtomizeInline(JSContext *cx, const jschar **pchars, size_t length, JSFixedString *key; + SkipRoot skip(cx, &chars); + if (ocb == TakeCharOwnership) { key = js_NewString(cx, const_cast(chars), length); if (!key) diff --git a/js/src/jsatominlines.h b/js/src/jsatominlines.h index a63ba028b921..904f4ee61576 100644 --- a/js/src/jsatominlines.h +++ b/js/src/jsatominlines.h @@ -178,6 +178,8 @@ BackfillIndexInCharBuffer(uint32_t index, mozilla::RangedPtr end) inline bool IndexToId(JSContext *cx, uint32_t index, jsid *idp) { + MaybeCheckStackRoots(cx); + if (index <= JSID_INT_MAX) { *idp = INT_TO_JSID(index); return true; diff --git a/js/src/jsclass.h b/js/src/jsclass.h index a9cf05da9b49..2f9e4e3b15c7 100644 --- a/js/src/jsclass.h +++ b/js/src/jsclass.h @@ -413,6 +413,25 @@ IsObjectWithClass(const Value &v, ESClassValue classValue, JSContext *cx); } /* namespace js */ +namespace JS { + +inline bool +IsPoisonedSpecialId(js::SpecialId iden) +{ + if (iden.isObject()) + return IsPoisonedPtr(iden.toObject()); + return false; +} + +template <> struct RootMethods +{ + static js::SpecialId initial() { return js::SpecialId(); } + static ThingRootKind kind() { return THING_ROOT_ID; } + static bool poisoned(js::SpecialId id) { return IsPoisonedSpecialId(id); } +}; + +} /* namespace JS */ + #endif /* __cplusplus */ #endif /* jsclass_h__ */ diff --git a/js/src/jsclone.cpp b/js/src/jsclone.cpp index 3bd33dd43e44..5092127567b1 100644 --- a/js/src/jsclone.cpp +++ b/js/src/jsclone.cpp @@ -961,10 +961,10 @@ JSStructuredCloneReader::read(Value *vp) return false; while (objs.length() != 0) { - JSObject *obj = &objs.back().toObject(); + RootedVarObject obj(context(), &objs.back().toObject()); - jsid id; - if (!readId(&id)) + RootedVarId id(context()); + if (!readId(id.address())) return false; if (JSID_IS_VOID(id)) { diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index f4aef744eaa5..e9facd49bb1f 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -128,7 +128,8 @@ GetGSNCache(JSContext *cx); struct PendingProxyOperation { PendingProxyOperation *next; - JSObject *object; + RootedVarObject object; + PendingProxyOperation(JSContext *cx, JSObject *object) : next(NULL), object(cx, object) {} }; typedef Vector ScriptAndCountsVector; @@ -141,14 +142,26 @@ struct ConservativeGCData */ uintptr_t *nativeStackTop; +#if defined(JSGC_ROOT_ANALYSIS) && (JS_STACK_GROWTH_DIRECTION < 0) + /* + * Record old contents of the native stack from the last time there was a + * scan, to reduce the overhead involved in repeatedly rescanning the + * native stack during root analysis. oldStackData stores words in reverse + * order starting at oldStackEnd. + */ + uintptr_t *oldStackMin, *oldStackEnd; + uintptr_t *oldStackData; + size_t oldStackCapacity; // in sizeof(uintptr_t) +#endif + union { jmp_buf jmpbuf; uintptr_t words[JS_HOWMANY(sizeof(jmp_buf), sizeof(uintptr_t))]; } registerSnapshot; - ConservativeGCData() - : nativeStackTop(NULL) - {} + ConservativeGCData() { + PodZero(this); + } ~ConservativeGCData() { #ifdef JS_THREADSAFE @@ -399,6 +412,13 @@ struct JSRuntime : js::RuntimeFriendFields */ bool gcIncrementalEnabled; + /* + * Whether exact stack scanning is enabled for this runtime. This is + * currently only used for dynamic root analysis. Exact scanning starts out + * enabled, and is disabled if e4x has been used. + */ + bool gcExactScanningEnabled; + /* * We save all conservative scanned roots in this vector so that * conservative scanning can be "replayed" deterministically. In DEBUG mode, @@ -1653,11 +1673,12 @@ class AutoValueArray : public AutoGCRooter { js::Value *start_; unsigned length_; + SkipRoot skip; public: AutoValueArray(JSContext *cx, js::Value *start, unsigned length JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, VALARRAY), start_(start), length_(length) + : AutoGCRooter(cx, VALARRAY), start_(start), length_(length), skip(cx, start, length) { JS_GUARD_OBJECT_NOTIFIER_INIT; } diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 5584b9489ebb..3dc642767495 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -362,7 +362,7 @@ CallJSPropertyOp(JSContext *cx, PropertyOp op, JSObject *receiver, jsid id, Valu assertSameCompartment(cx, receiver, id, *vp); JSBool ok = op(cx, receiver, id, vp); if (ok) - assertSameCompartment(cx, receiver, *vp); + assertSameCompartment(cx, *vp); return ok; } @@ -490,6 +490,7 @@ JSContext::ensureGeneratorStackSpace() inline void JSContext::setPendingException(js::Value v) { + JS_ASSERT(!IsPoisonedValue(v)); this->throwing = true; this->exception = v; js::assertSameCompartment(this, v); diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 0c58d910e6b0..08896fcfa14b 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -210,7 +210,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp) * we parent all wrappers to the global object in their home compartment. * This loses us some transparency, and is generally very cheesy. */ - JSObject *global; + RootedVarObject global(cx); if (cx->hasfp()) { global = &cx->fp()->global(); } else { @@ -271,11 +271,11 @@ JSCompartment::wrap(JSContext *cx, Value *vp) if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(*vp)) { *vp = p->value; if (vp->isObject()) { - JSObject *obj = &vp->toObject(); + RootedVarObject obj(cx, &vp->toObject()); JS_ASSERT(obj->isCrossCompartmentWrapper()); if (global->getClass() != &dummy_class && obj->getParent() != global) { do { - if (!obj->setParent(cx, global)) + if (!JSObject::setParent(cx, obj, global)) return false; obj = obj->getProto(); } while (obj && obj->isCrossCompartmentWrapper()); @@ -285,7 +285,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp) } if (vp->isString()) { - Value orig = *vp; + RootedVarValue orig(cx, *vp); JSString *str = vp->toString(); const jschar *chars = str->getChars(cx); if (!chars) @@ -297,7 +297,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp) return crossCompartmentWrappers.put(orig, *vp); } - JSObject *obj = &vp->toObject(); + RootedVarObject obj(cx, &vp->toObject()); /* * Recurse to wrap the prototype. Long prototype chains will run out of @@ -309,8 +309,8 @@ JSCompartment::wrap(JSContext *cx, Value *vp) * here (since Object.prototype->parent->proto leads to Object.prototype * itself). */ - JSObject *proto = obj->getProto(); - if (!wrap(cx, &proto)) + RootedVarObject proto(cx, obj->getProto()); + if (!wrap(cx, proto.address())) return false; /* @@ -318,7 +318,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp) * the wrap hook to reason over what wrappers are currently applied * to the object. */ - JSObject *wrapper = cx->runtime->wrapObjectCallback(cx, obj, proto, global, flags); + RootedVarObject wrapper(cx, cx->runtime->wrapObjectCallback(cx, obj, proto, global, flags)); if (!wrapper) return false; @@ -330,7 +330,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp) if (!crossCompartmentWrappers.put(GetProxyPrivate(wrapper), *vp)) return false; - if (!wrapper->setParent(cx, global)) + if (!JSObject::setParent(cx, wrapper, global)) return false; return true; } @@ -338,20 +338,20 @@ JSCompartment::wrap(JSContext *cx, Value *vp) bool JSCompartment::wrap(JSContext *cx, JSString **strp) { - AutoValueRooter tvr(cx, StringValue(*strp)); - if (!wrap(cx, tvr.addr())) + RootedVarValue value(cx, StringValue(*strp)); + if (!wrap(cx, value.address())) return false; - *strp = tvr.value().toString(); + *strp = value.reference().toString(); return true; } bool JSCompartment::wrap(JSContext *cx, HeapPtrString *strp) { - AutoValueRooter tvr(cx, StringValue(*strp)); - if (!wrap(cx, tvr.addr())) + RootedVarValue value(cx, StringValue(*strp)); + if (!wrap(cx, value.address())) return false; - *strp = tvr.value().toString(); + *strp = value.reference().toString(); return true; } @@ -360,10 +360,10 @@ JSCompartment::wrap(JSContext *cx, JSObject **objp) { if (!*objp) return true; - AutoValueRooter tvr(cx, ObjectValue(**objp)); - if (!wrap(cx, tvr.addr())) + RootedVarValue value(cx, ObjectValue(**objp)); + if (!wrap(cx, value.address())) return false; - *objp = &tvr.value().toObject(); + *objp = &value.reference().toObject(); return true; } @@ -372,10 +372,10 @@ JSCompartment::wrapId(JSContext *cx, jsid *idp) { if (JSID_IS_INT(*idp)) return true; - AutoValueRooter tvr(cx, IdToValue(*idp)); - if (!wrap(cx, tvr.addr())) + RootedVarValue value(cx, IdToValue(*idp)); + if (!wrap(cx, value.address())) return false; - return ValueToId(cx, tvr.value(), idp); + return ValueToId(cx, value.reference(), idp); } bool diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index ed2b89067bbb..13fc6a5a5705 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -170,6 +170,7 @@ struct WrapperHasher typedef Value Lookup; static HashNumber hash(Value key) { + JS_ASSERT(!IsPoisonedValue(key)); uint64_t bits = JSVAL_TO_IMPL(key).asBits; return uint32_t(bits) ^ uint32_t(bits >> 32); } @@ -582,10 +583,10 @@ class AutoCompartment class ErrorCopier { AutoCompartment ∾ - JSObject *scope; + RootedVarObject scope; public: - ErrorCopier(AutoCompartment &ac, JSObject *scope) : ac(ac), scope(scope) { + ErrorCopier(AutoCompartment &ac, JSObject *scope) : ac(ac), scope(ac.context, scope) { JS_ASSERT(scope->compartment() == ac.origin); } ~ErrorCopier(); diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 678c3bb2d148..eb899ed01f8d 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -1734,7 +1734,7 @@ date_setTime(JSContext *cx, unsigned argc, Value *vp) CallArgs args = CallArgsFromVp(argc, vp); bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_setTime, &DateClass, &ok); + RootedVarObject obj(cx, NonGenericMethodGuard(cx, args, date_setTime, &DateClass, &ok)); if (!obj) return ok; @@ -1756,7 +1756,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi CallArgs args = CallArgsFromVp(argc, vp); bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok); + RootedVarObject obj(cx, NonGenericMethodGuard(cx, args, native, &DateClass, &ok)); if (!obj) return ok; @@ -1900,7 +1900,7 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi CallArgs args = CallArgsFromVp(argc, vp); bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok); + RootedVarObject obj(cx, NonGenericMethodGuard(cx, args, native, &DateClass, &ok)); if (!obj) return ok; @@ -2018,7 +2018,7 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp) CallArgs args = CallArgsFromVp(argc, vp); bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_setYear, &DateClass, &ok); + RootedVarObject obj(cx, NonGenericMethodGuard(cx, args, date_setYear, &DateClass, &ok)); if (!obj) return ok; diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index c11e243c1e8c..88f4c73197c8 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -259,33 +259,34 @@ JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *hoop, void **closurep) /************************************************************************/ JS_PUBLIC_API(JSBool) -JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id, - JSWatchPointHandler handler, JSObject *closure) +JS_SetWatchPoint(JSContext *cx, JSObject *obj_, jsid id, + JSWatchPointHandler handler, JSObject *closure_) { - assertSameCompartment(cx, obj); + assertSameCompartment(cx, obj_); id = js_CheckForStringIndex(id); + RootedVarObject obj(cx, obj_), closure(cx, closure_); + JSObject *origobj; Value v; unsigned attrs; - jsid propid; origobj = obj; - OBJ_TO_INNER_OBJECT(cx, obj); + OBJ_TO_INNER_OBJECT(cx, obj.reference()); if (!obj) return false; - AutoValueRooter idroot(cx); + RootedVarId propid(cx); + if (JSID_IS_INT(id)) { propid = id; } else if (JSID_IS_OBJECT(id)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH_PROP); return false; } else { - if (!js_ValueToStringId(cx, IdToValue(id), &propid)) + if (!js_ValueToStringId(cx, IdToValue(id), propid.address())) return false; propid = js_CheckForStringIndex(propid); - idroot.set(IdToValue(propid)); } /* @@ -738,7 +739,9 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fpArg, if (!CheckDebugMode(cx)) return false; - Env *env = JS_GetFrameScopeChain(cx, fpArg); + SkipRoot skip(cx, &chars); + + RootedVar env(cx, JS_GetFrameScopeChain(cx, fpArg)); if (!env) return false; diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 6eb6314d159c..7b9cb371bf51 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -1091,7 +1091,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, } static bool -IsDuckTypedErrorObject(JSContext *cx, JSObject *exnObject, const char **filename_strp) +IsDuckTypedErrorObject(JSContext *cx, HandleObject exnObject, const char **filename_strp) { JSBool found; if (!JS_HasProperty(cx, exnObject, js_message_str, &found) || !found) @@ -1115,10 +1115,9 @@ IsDuckTypedErrorObject(JSContext *cx, JSObject *exnObject, const char **filename JSBool js_ReportUncaughtException(JSContext *cx) { - JSObject *exnObject; jsval roots[6]; JSErrorReport *reportp, report; - JSString *str; + RootedVarString str(cx); if (!JS_IsExceptionPending(cx)) return true; @@ -1136,6 +1135,7 @@ js_ReportUncaughtException(JSContext *cx) * need to root other intermediates, so allocate an operand stack segment * to protect all of these values. */ + RootedVarObject exnObject(cx); if (JSVAL_IS_PRIMITIVE(exn)) { exnObject = NULL; } else { @@ -1157,14 +1157,14 @@ js_ReportUncaughtException(JSContext *cx) (exnObject->isError() || IsDuckTypedErrorObject(cx, exnObject, &filename_str))) { - JSString *name = NULL; + RootedVarString name(cx); if (JS_GetProperty(cx, exnObject, js_name_str, &roots[2]) && JSVAL_IS_STRING(roots[2])) { name = JSVAL_TO_STRING(roots[2]); } - JSString *msg = NULL; + RootedVarString msg(cx); if (JS_GetProperty(cx, exnObject, js_message_str, &roots[3]) && JSVAL_IS_STRING(roots[3])) { @@ -1234,7 +1234,7 @@ js_ReportUncaughtException(JSContext *cx) } extern JSObject * -js_CopyErrorObject(JSContext *cx, JSObject *errobj, JSObject *scope) +js_CopyErrorObject(JSContext *cx, HandleObject errobj, HandleObject scope) { assertSameCompartment(cx, scope); JSExnPrivate *priv = GetExnPrivate(errobj); diff --git a/js/src/jsexn.h b/js/src/jsexn.h index 930c0329e17d..70d69be6eabb 100644 --- a/js/src/jsexn.h +++ b/js/src/jsexn.h @@ -99,7 +99,7 @@ js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale, * (errobj->getPrivate() must not be NULL). */ extern JSObject * -js_CopyErrorObject(JSContext *cx, JSObject *errobj, JSObject *scope); +js_CopyErrorObject(JSContext *cx, js::HandleObject errobj, js::HandleObject scope); static JS_INLINE JSProtoKey GetExceptionProtoKey(int exn) diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index eae2d322b3ad..98a361b8cb23 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -187,7 +187,7 @@ JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape) } static bool -DefineHelpProperty(JSContext *cx, JSObject *obj, const char *prop, const char *value) +DefineHelpProperty(JSContext *cx, HandleObject obj, const char *prop, const char *value) { JSAtom *atom = js_Atomize(cx, value, strlen(value)); if (!atom) @@ -212,8 +212,9 @@ JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj, const JSFunctionSpecWit if (!atom) return false; - JSFunction *fun = js_DefineFunction(cx, objRoot, - ATOM_TO_JSID(atom), fs->call, fs->nargs, fs->flags); + RootedVarFunction fun(cx); + fun = js_DefineFunction(cx, objRoot, + ATOM_TO_JSID(atom), fs->call, fs->nargs, fs->flags); if (!fun) return false; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index fc9485d1789c..d5734c973c50 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -646,7 +646,7 @@ JSBool js_fun_apply(JSContext *cx, unsigned argc, Value *vp) { /* Step 1. */ - Value fval = vp[1]; + RootedVarValue fval(cx, vp[1]); if (!js_IsCallable(fval)) { ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &FunctionClass); return false; @@ -688,7 +688,7 @@ js_fun_apply(JSContext *cx, unsigned argc, Value *vp) * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in * original version of ES5). */ - JSObject *aobj = &vp[3].toObject(); + RootedVarObject aobj(cx, &vp[3].toObject()); uint32_t length; if (!js_GetLengthProperty(cx, aobj, &length)) return false; @@ -732,29 +732,31 @@ static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1; static const uint32_t BOUND_FUNCTION_RESERVED_SLOTS = 2; inline bool -JSFunction::initBoundFunction(JSContext *cx, const Value &thisArg, +JSFunction::initBoundFunction(JSContext *cx, HandleValue thisArg, const Value *args, unsigned argslen) { JS_ASSERT(isFunction()); + RootedVarFunction self(cx, this); + /* * Convert to a dictionary to set the BOUND_FUNCTION flag and increase * the slot span to cover the arguments and additional slots for the 'this' * value and arguments count. */ - if (!toDictionaryMode(cx)) + if (!self->toDictionaryMode(cx)) return false; - if (!setFlag(cx, BaseShape::BOUND_FUNCTION)) + if (!self->setFlag(cx, BaseShape::BOUND_FUNCTION)) return false; - if (!setSlotSpan(cx, BOUND_FUNCTION_RESERVED_SLOTS + argslen)) + if (!self->setSlotSpan(cx, BOUND_FUNCTION_RESERVED_SLOTS + argslen)) return false; - setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg); - setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen)); + self->setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg); + self->setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen)); - initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen); + self->initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen); return true; } @@ -895,7 +897,7 @@ fun_bind(JSContext *cx, unsigned argc, Value *vp) } /* Steps 7-9. */ - Value thisArg = args.length() >= 1 ? args[0] : UndefinedValue(); + RootedVarValue thisArg(cx, args.length() >= 1 ? args[0] : UndefinedValue()); JSObject *boundFunction = js_fun_bind(cx, target, thisArg, boundArgs, argslen); if (!boundFunction) @@ -907,7 +909,7 @@ fun_bind(JSContext *cx, unsigned argc, Value *vp) } JSObject* -js_fun_bind(JSContext *cx, HandleObject target, Value thisArg, +js_fun_bind(JSContext *cx, HandleObject target, HandleValue thisArg, Value *boundArgs, unsigned argslen) { /* Steps 15-16. */ @@ -921,14 +923,14 @@ js_fun_bind(JSContext *cx, HandleObject target, Value thisArg, /* Step 4-6, 10-11. */ JSAtom *name = target->isFunction() ? target->toFunction()->atom.get() : NULL; - JSObject *funobj = - js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length, - JSFUN_CONSTRUCTOR, target, name); + RootedVarObject funobj(cx); + funobj = js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length, + JSFUN_CONSTRUCTOR, target, name); if (!funobj) return NULL; /* NB: Bound functions abuse |parent| to store their target. */ - if (!funobj->setParent(cx, target)) + if (!JSObject::setParent(cx, funobj, target)) return NULL; if (!funobj->toFunction()->initBoundFunction(cx, thisArg, boundArgs, argslen)) @@ -983,6 +985,7 @@ Function(JSContext *cx, unsigned argc, Value *vp) } Bindings bindings(cx); + Bindings::StackRoot bindingsRoot(cx, &bindings); const char *filename; unsigned lineno; @@ -1112,6 +1115,8 @@ Function(JSContext *cx, unsigned argc, Value *vp) const jschar *chars; size_t length; + SkipRoot skip(cx, &chars); + if (args.length()) { JSString *str = ToString(cx, args[args.length() - 1]); if (!str) @@ -1130,8 +1135,8 @@ Function(JSContext *cx, unsigned argc, Value *vp) * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42, * and so would a call to f from another top-level's script or function. */ - JSFunction *fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED, - global, cx->runtime->atomState.anonymousAtom); + RootedVarFunction fun(cx, js_NewFunction(cx, NULL, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED, + global, cx->runtime->atomState.anonymousAtom)); if (!fun) return false; @@ -1229,7 +1234,7 @@ js_CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent, JSObject *cloneobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind); if (!cloneobj) return NULL; - JSFunction *clone = static_cast(cloneobj); + RootedVarFunction clone(cx, static_cast(cloneobj)); clone->nargs = fun->nargs; clone->flags = fun->flags & ~JSFUN_EXTENDED; @@ -1354,7 +1359,6 @@ void js_ReportIsNotFunction(JSContext *cx, const Value *vp, unsigned flags) { const char *name = NULL, *source = NULL; - AutoValueRooter tvr(cx); unsigned error = (flags & JSV2F_CONSTRUCT) ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION; /* diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 599b13c473b3..0c98e6d77688 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -188,7 +188,7 @@ struct JSFunction : public JSObject /* Bound function accessors. */ - inline bool initBoundFunction(JSContext *cx, const js::Value &thisArg, + inline bool initBoundFunction(JSContext *cx, js::HandleValue thisArg, const js::Value *args, unsigned argslen); inline JSObject *getBoundFunctionTarget() const; @@ -323,7 +323,7 @@ extern JSBool js_fun_call(JSContext *cx, unsigned argc, js::Value *vp); extern JSObject* -js_fun_bind(JSContext *cx, js::HandleObject target, js::Value thisArg, +js_fun_bind(JSContext *cx, js::HandleObject target, js::HandleValue thisArg, js::Value *boundArgs, unsigned argslen); #endif /* jsfun_h___ */ diff --git a/js/src/jsfuninlines.h b/js/src/jsfuninlines.h index 8ba8e1225558..a383ea998bef 100644 --- a/js/src/jsfuninlines.h +++ b/js/src/jsfuninlines.h @@ -238,7 +238,7 @@ CloneFunctionObjectIfNotSingleton(JSContext *cx, HandleFunction fun, HandleObjec * with its type in existence. */ if (fun->hasSingletonType()) { - if (!fun->setParent(cx, SkipScopeParent(parent))) + if (!JSObject::setParent(cx, fun, RootedVarObject(cx, SkipScopeParent(parent)))) return NULL; fun->setEnvironment(parent); return fun; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 873419c3ec51..b00f7584f211 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3942,6 +3942,9 @@ SetDeterministicGC(JSContext *cx, bool enabled) #endif } +} /* namespace gc */ +} /* namespace js */ + #if defined(DEBUG) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) static void @@ -3955,7 +3958,6 @@ CheckStackRoot(JSTracer *trc, uintptr_t *w) ConservativeGCTest test = MarkIfGCThingWord(trc, *w); if (test == CGCT_VALID) { - JSContext *iter = NULL; bool matched = false; JSRuntime *rt = trc->runtime; for (ContextIter cx(rt); !cx.done(); cx.next()) { @@ -3994,20 +3996,27 @@ CheckStackRootsRange(JSTracer *trc, uintptr_t *begin, uintptr_t *end) CheckStackRoot(trc, i); } +static void +EmptyMarkCallback(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) +{} + void -CheckStackRoots(JSContext *cx) +JS::CheckStackRoots(JSContext *cx) { - AutoCopyFreeListToArenas copy(cx->runtime); + JSRuntime *rt = cx->runtime; + + if (!rt->gcExactScanningEnabled) + return; + + AutoCopyFreeListToArenas copy(rt); JSTracer checker; - JS_TracerInit(&checker, cx, EmptyMarkCallback); + JS_TracerInit(&checker, rt, EmptyMarkCallback); - ThreadData *td = JS_THREAD_DATA(cx); + ConservativeGCData *cgcd = &rt->conservativeGC; + cgcd->recordStackTop(); - ConservativeGCThreadData *ctd = &td->conservativeGC; - ctd->recordStackTop(); - - JS_ASSERT(ctd->hasStackToScan()); + JS_ASSERT(cgcd->hasStackToScan()); uintptr_t *stackMin, *stackEnd; #if JS_STACK_GROWTH_DIRECTION > 0 stackMin = rt->nativeStackBase; @@ -4015,6 +4024,39 @@ CheckStackRoots(JSContext *cx) #else stackMin = cgcd->nativeStackTop + 1; stackEnd = reinterpret_cast(rt->nativeStackBase); + + uintptr_t *&oldStackMin = cgcd->oldStackMin, *&oldStackEnd = cgcd->oldStackEnd; + uintptr_t *&oldStackData = cgcd->oldStackData; + uintptr_t &oldStackCapacity = cgcd->oldStackCapacity; + + /* + * Adjust the stack to remove regions which have not changed since the + * stack was last scanned, and update the last scanned state. + */ + if (stackEnd != oldStackEnd) { + rt->free_(oldStackData); + oldStackCapacity = rt->nativeStackQuota / sizeof(uintptr_t); + oldStackData = (uintptr_t *) rt->malloc_(oldStackCapacity * sizeof(uintptr_t)); + if (!oldStackData) { + oldStackCapacity = 0; + } else { + uintptr_t *existing = stackEnd - 1, *copy = oldStackData; + while (existing >= stackMin && size_t(copy - oldStackData) < oldStackCapacity) + *copy++ = *existing--; + oldStackEnd = stackEnd; + oldStackMin = existing + 1; + } + } else { + uintptr_t *existing = stackEnd - 1, *copy = oldStackData; + while (existing >= stackMin && existing >= oldStackMin && *existing == *copy) { + copy++; + existing--; + } + stackEnd = existing + 1; + while (existing >= stackMin && size_t(copy - oldStackData) < oldStackCapacity) + *copy++ = *existing--; + oldStackMin = existing + 1; + } #endif JS_ASSERT(stackMin <= stackEnd); @@ -4025,6 +4067,9 @@ CheckStackRoots(JSContext *cx) #endif /* DEBUG && JSGC_ROOT_ANALYSIS && !JS_THREADSAFE */ +namespace js { +namespace gc { + #ifdef JS_GC_ZEAL /* diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 43e072eb517a..da52099737bc 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -1972,15 +1972,6 @@ RunDebugGC(JSContext *cx); void SetDeterministicGC(JSContext *cx, bool enabled); -#if defined(JSGC_ROOT_ANALYSIS) && defined(DEBUG) && !defined(JS_THREADSAFE) -/* Overwrites stack references to GC things which have not been rooted. */ -void CheckStackRoots(JSContext *cx); - -inline void MaybeCheckStackRoots(JSContext *cx) { CheckStackRoots(cx); } -#else -inline void MaybeCheckStackRoots(JSContext *cx) {} -#endif - const int ZealPokeValue = 1; const int ZealAllocValue = 2; const int ZealFrameGCValue = 3; diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index 6ecb73e8160c..d21fbe4dd0c1 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -447,7 +447,7 @@ NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize) js::gc::RunDebugGC(cx); #endif - js::gc::MaybeCheckStackRoots(cx); + MaybeCheckStackRoots(cx); JSCompartment *comp = cx->compartment; void *t = comp->arenas.allocateFromFreeList(kind, thingSize); diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index ffc32e52a822..63104d0aa981 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -5709,7 +5709,7 @@ JSObject::getNewType(JSContext *cx, JSFunction *fun) TypeObject * JSCompartment::getLazyType(JSContext *cx, JSObject *proto) { - gc::MaybeCheckStackRoots(cx); + MaybeCheckStackRoots(cx); TypeObjectSet &table = cx->compartment->lazyTypeObjects; diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 5bcb575b9f75..c5cc7679dd7f 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -153,6 +153,8 @@ js::GetScopeChain(JSContext *cx, StackFrame *fp) return fp->scopeChain(); } + Root sharedBlockRoot(cx, &sharedBlock); + /* * We have one or more lexical scopes to reflect into fp->scopeChain, so * make sure there's a call object at the current head of the scope chain, @@ -160,7 +162,7 @@ js::GetScopeChain(JSContext *cx, StackFrame *fp) * * Also, identify the innermost compiler-allocated block we needn't clone. */ - JSObject *limitBlock, *limitClone; + RootedVarObject limitBlock(cx), limitClone(cx); if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj()) { JS_ASSERT_IF(fp->scopeChain()->isClonedBlock(), fp->scopeChain()->getPrivate() != fp); if (!CallObject::createForFunction(cx, fp)) @@ -212,7 +214,7 @@ js::GetScopeChain(JSContext *cx, StackFrame *fp) * create() leaves the clone's enclosingScope unset. We set it below. */ RootedVar innermostNewChild(cx); - innermostNewChild = ClonedBlockObject::create(cx, *sharedBlock, fp); + innermostNewChild = ClonedBlockObject::create(cx, sharedBlockRoot, fp); if (!innermostNewChild) return NULL; @@ -230,7 +232,7 @@ js::GetScopeChain(JSContext *cx, StackFrame *fp) break; /* As in the call above, we don't know the real parent yet. */ - RootedVar clone(cx, ClonedBlockObject::create(cx, *sharedBlock, fp)); + RootedVar clone(cx, ClonedBlockObject::create(cx, sharedBlockRoot, fp)); if (!clone) return NULL; @@ -329,6 +331,7 @@ js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call) if (thisv.isNullOrUndefined()) { JSObject *thisp = call.callee().global().thisObject(cx); + JS_ASSERT(!IsPoisonedPtr(thisp)); if (!thisp) return false; call.thisv().setObject(*thisp); @@ -368,21 +371,23 @@ Class js_NoSuchMethodClass = { * parameters. */ bool -js::OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval, Value *vp) +js::OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval_, Value *vp) { + RootedVarValue idval(cx, idval_); + jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); - AutoValueRooter tvr(cx); - if (!js_GetMethod(cx, obj, id, 0, tvr.addr())) + RootedVarValue value(cx); + if (!js_GetMethod(cx, obj, id, 0, value.address())) return false; TypeScript::MonitorUnknown(cx, cx->fp()->script(), cx->regs().pc); - if (tvr.value().isPrimitive()) { - *vp = tvr.value(); + if (value.reference().isPrimitive()) { + *vp = value; } else { #if JS_HAS_XML_SUPPORT /* Extract the function name from function::name qname. */ - if (idval.isObject()) { - JSObject *obj = &idval.toObject(); + if (idval.reference().isObject()) { + JSObject *obj = &idval.reference().toObject(); if (js_GetLocalNameFromFunctionQName(obj, &id, cx)) idval = IdToValue(id); } @@ -392,7 +397,7 @@ js::OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval, Value *vp) if (!obj) return false; - obj->setSlot(JSSLOT_FOUND_FUNCTION, tvr.value()); + obj->setSlot(JSSLOT_FOUND_FUNCTION, value); obj->setSlot(JSSLOT_SAVED_ID, idval); vp->setObject(*obj); } @@ -450,9 +455,9 @@ js::RunScript(JSContext *cx, JSScript *script, StackFrame *fp) struct CheckStackBalance { JSContext *cx; StackFrame *fp; - JSObject *enumerators; + RootedVarObject enumerators; CheckStackBalance(JSContext *cx) - : cx(cx), fp(cx->fp()), enumerators(cx->enumerators) + : cx(cx), fp(cx->fp()), enumerators(cx, cx->enumerators) {} ~CheckStackBalance() { JS_ASSERT(fp == cx->fp()); @@ -513,7 +518,7 @@ js::InvokeKernel(JSContext *cx, CallArgs args, MaybeConstruct construct) } /* Invoke native functions. */ - JSFunction *fun = callee.toFunction(); + RootedVarFunction fun(cx, callee.toFunction()); JS_ASSERT_IF(construct, !fun->isNativeConstructor()); if (fun->isNative()) return CallJSNative(cx, fun->native(), args); @@ -784,17 +789,17 @@ js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *resu return true; } - Value lvalue = lval; - Value rvalue = rval; + RootedVarValue lvalue(cx, lval); + RootedVarValue rvalue(cx, rval); - if (!ToPrimitive(cx, &lvalue)) + if (!ToPrimitive(cx, lvalue.address())) return false; - if (!ToPrimitive(cx, &rvalue)) + if (!ToPrimitive(cx, rvalue.address())) return false; - if (lvalue.isString() && rvalue.isString()) { - JSString *l = lvalue.toString(); - JSString *r = rvalue.toString(); + if (lvalue.reference().isString() && rvalue.reference().isString()) { + JSString *l = lvalue.reference().toString(); + JSString *r = rvalue.reference().toString(); return EqualStrings(cx, l, r, result); } @@ -2050,7 +2055,8 @@ BEGIN_CASE(JSOP_IN) js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL); goto error; } - JSObject *obj = &rref.toObject(); + RootedVarObject &obj = rootObject0; + obj = &rref.toObject(); jsid id; FETCH_ELEMENT_ID(obj, -2, id); JSObject *obj2; @@ -2206,10 +2212,13 @@ BEGIN_CASE(JSOP_BINDNAME) if (obj->isGlobal()) break; - PropertyName *name; + RootedVarPropertyName &name = rootName0; LOAD_NAME(0, name); - obj = FindIdentifierBase(cx, regs.fp()->scopeChain(), name); + RootedVarObject &scopeChain = rootObject0; + scopeChain = regs.fp()->scopeChain(); + + obj = FindIdentifierBase(cx, scopeChain, name); if (!obj) goto error; } while (0); @@ -2410,8 +2419,9 @@ END_CASE(JSOP_ADD) BEGIN_CASE(JSOP_SUB) { - Value lval = regs.sp[-2]; - Value rval = regs.sp[-1]; + RootedVarValue &lval = rootValue0, &rval = rootValue1; + lval = regs.sp[-2]; + rval = regs.sp[-1]; if (!SubOperation(cx, lval, rval, ®s.sp[-2])) goto error; regs.sp--; @@ -2420,8 +2430,9 @@ END_CASE(JSOP_SUB) BEGIN_CASE(JSOP_MUL) { - Value lval = regs.sp[-2]; - Value rval = regs.sp[-1]; + RootedVarValue &lval = rootValue0, &rval = rootValue1; + lval = regs.sp[-2]; + rval = regs.sp[-1]; if (!MulOperation(cx, lval, rval, ®s.sp[-2])) goto error; regs.sp--; @@ -2430,8 +2441,9 @@ END_CASE(JSOP_MUL) BEGIN_CASE(JSOP_DIV) { - Value lval = regs.sp[-2]; - Value rval = regs.sp[-1]; + RootedVarValue &lval = rootValue0, &rval = rootValue1; + lval = regs.sp[-2]; + rval = regs.sp[-1]; if (!DivOperation(cx, lval, rval, ®s.sp[-2])) goto error; regs.sp--; @@ -2440,8 +2452,9 @@ END_CASE(JSOP_DIV) BEGIN_CASE(JSOP_MOD) { - Value lval = regs.sp[-2]; - Value rval = regs.sp[-1]; + RootedVarValue &lval = rootValue0, &rval = rootValue1; + lval = regs.sp[-2]; + rval = regs.sp[-1]; if (!ModOperation(cx, lval, rval, ®s.sp[-2])) goto error; regs.sp--; @@ -2524,14 +2537,14 @@ END_CASE(JSOP_DELNAME) BEGIN_CASE(JSOP_DELPROP) { - PropertyName *name; + RootedVarPropertyName &name = rootName0; LOAD_NAME(0, name); JSObject *obj; FETCH_OBJECT(cx, -1, obj); - Value rval; - if (!obj->deleteProperty(cx, name, &rval, script->strictModeCode)) + RootedVarValue &rval = rootValue0; + if (!obj->deleteProperty(cx, name, rval.address(), script->strictModeCode)) goto error; regs.sp[-1] = rval; @@ -2690,7 +2703,7 @@ END_CASE(JSOP_GETELEM) BEGIN_CASE(JSOP_SETELEM) { - JSObject *obj; + RootedVarObject &obj = rootObject0; FETCH_OBJECT(cx, -3, obj); jsid id; FETCH_ELEMENT_ID(obj, -2, id); @@ -2704,13 +2717,15 @@ END_CASE(JSOP_SETELEM) BEGIN_CASE(JSOP_ENUMELEM) { + RootedVarObject &obj = rootObject0; + RootedVarValue &rval = rootValue0; + /* Funky: the value to set is under the [obj, id] pair. */ - JSObject *obj; FETCH_OBJECT(cx, -2, obj); jsid id; FETCH_ELEMENT_ID(obj, -1, id); - Value rval = regs.sp[-3]; - if (!obj->setGeneric(cx, id, &rval, script->strictModeCode)) + rval = regs.sp[-3]; + if (!obj->setGeneric(cx, id, rval.address(), script->strictModeCode)) goto error; regs.sp -= 3; } @@ -3159,7 +3174,6 @@ BEGIN_CASE(JSOP_DEFFUN) */ RootedVarFunction &fun = rootFunction0; fun = script->getFunction(GET_UINT32_INDEX(regs.pc)); - JSObject *obj = fun; RootedVarObject &obj2 = rootObject0; if (fun->isNullClosure()) { @@ -3184,11 +3198,10 @@ BEGIN_CASE(JSOP_DEFFUN) * windows, and user-defined JS functions precompiled and then shared among * requests in server-side JS. */ - if (obj->toFunction()->environment() != obj2) { - obj = CloneFunctionObjectIfNotSingleton(cx, fun, obj2); - if (!obj) + if (fun->environment() != obj2) { + fun = CloneFunctionObjectIfNotSingleton(cx, fun, obj2); + if (!fun) goto error; - JS_ASSERT_IF(script->hasGlobal(), obj->getProto() == fun->getProto()); } /* @@ -3204,16 +3217,19 @@ BEGIN_CASE(JSOP_DEFFUN) * current scope chain even for the case of function expression statements * and functions defined by eval inside let or with blocks. */ - JSObject *parent = ®s.fp()->varObj(); + RootedVarObject &parent = rootObject0; + parent = ®s.fp()->varObj(); /* ES5 10.5 (NB: with subsequent errata). */ - PropertyName *name = fun->atom->asPropertyName(); + RootedVarPropertyName &name = rootName0; + name = fun->atom->asPropertyName(); JSProperty *prop = NULL; JSObject *pobj; if (!parent->lookupProperty(cx, name, &pobj, &prop)) goto error; - Value rval = ObjectValue(*obj); + RootedVarValue &rval = rootValue0; + rval = ObjectValue(*fun); do { /* Steps 5d, 5f. */ @@ -3257,7 +3273,7 @@ BEGIN_CASE(JSOP_DEFFUN) */ /* Step 5f. */ - if (!parent->setProperty(cx, name, &rval, script->strictModeCode)) + if (!parent->setProperty(cx, name, rval.address(), script->strictModeCode)) goto error; } while (false); } @@ -3487,10 +3503,12 @@ BEGIN_CASE(JSOP_INITELEM) JS_ASSERT(regs.sp - regs.fp()->base() >= 3); const Value &rref = regs.sp[-1]; + RootedVarObject &obj = rootObject0; + /* Find the object being initialized at top of stack. */ const Value &lref = regs.sp[-3]; JS_ASSERT(lref.isObject()); - JSObject *obj = &lref.toObject(); + obj = &lref.toObject(); /* Fetch id now that we have obj. */ jsid id; @@ -3637,6 +3655,8 @@ BEGIN_CASE(JSOP_ANYNAME) { JS_ASSERT(!script->strictModeCode); + cx->runtime->gcExactScanningEnabled = false; + jsid id; if (!js_GetAnyName(cx, &id)) goto error; @@ -3854,6 +3874,8 @@ BEGIN_CASE(JSOP_TOXML) { JS_ASSERT(!script->strictModeCode); + cx->runtime->gcExactScanningEnabled = false; + Value rval = regs.sp[-1]; JSObject *obj = js_ValueToXMLObject(cx, rval); if (!obj) diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index df11c76ade1c..356f28e5e76c 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -256,8 +256,7 @@ GetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, Value *vp } RootObject objRoot(cx, &obj); - - jsid id = ATOM_TO_JSID(name); + RootedVarId id(cx, ATOM_TO_JSID(name)); if (obj->getOps()->getProperty) { if (!GetPropertyGenericMaybeCallXML(cx, op, objRoot, id, vp)) @@ -610,48 +609,48 @@ AddOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res) } static JS_ALWAYS_INLINE bool -SubOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res) +SubOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, Value *res) { double d1, d2; if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2)) return false; double d = d1 - d2; - if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble())) + if (!res->setNumber(d) && !(lhs.value().isDouble() || rhs.value().isDouble())) types::TypeScript::MonitorOverflow(cx); return true; } static JS_ALWAYS_INLINE bool -MulOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res) +MulOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, Value *res) { double d1, d2; if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2)) return false; double d = d1 * d2; - if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble())) + if (!res->setNumber(d) && !(lhs.value().isDouble() || rhs.value().isDouble())) types::TypeScript::MonitorOverflow(cx); return true; } static JS_ALWAYS_INLINE bool -DivOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res) +DivOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, Value *res) { double d1, d2; if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2)) return false; res->setNumber(NumberDiv(d1, d2)); - if (d2 == 0 || (res->isDouble() && !(lhs.isDouble() || rhs.isDouble()))) + if (d2 == 0 || (res->isDouble() && !(lhs.value().isDouble() || rhs.value().isDouble()))) types::TypeScript::MonitorOverflow(cx); return true; } static JS_ALWAYS_INLINE bool -ModOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res) +ModOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, Value *res) { int32_t l, r; - if (lhs.isInt32() && rhs.isInt32() && - (l = lhs.toInt32()) >= 0 && (r = rhs.toInt32()) > 0) { + if (lhs.value().isInt32() && rhs.value().isInt32() && + (l = lhs.value().toInt32()) >= 0 && (r = rhs.value().toInt32()) > 0) { int32_t mod = l % r; res->setInt32(mod); return true; @@ -838,6 +837,7 @@ SetObjectElementOperation(JSContext *cx, JSObject *obj, jsid id, const Value &va if (lval.isInt32() && rval.isInt32()) { \ *res = lval.toInt32() OP rval.toInt32(); \ } else { \ + RootValue lvalRoot(cx, &lval), rvalRoot(cx, &rval); \ if (!ToPrimitive(cx, JSTYPE_NUMBER, &lval)) \ return false; \ if (!ToPrimitive(cx, JSTYPE_NUMBER, &rval)) \ @@ -886,7 +886,7 @@ GuardFunApplySpeculation(JSContext *cx, FrameRegs ®s) if (regs.sp[-1].isMagic(JS_OPTIMIZED_ARGUMENTS)) { CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp); if (!IsNativeFunction(args.calleev(), js_fun_apply)) { - if (!regs.fp()->script()->applySpeculationFailed(cx)) + if (!JSScript::applySpeculationFailed(cx, regs.fp()->script())) return false; args[1] = ObjectValue(regs.fp()->argsObj()); } diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 8aea91e89deb..5bfc60e91c74 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -953,7 +953,7 @@ js::CloseIterator(JSContext *cx, JSObject *obj) bool js::UnwindIteratorForException(JSContext *cx, JSObject *obj) { - Value v = cx->getPendingException(); + RootedVarValue v(cx, cx->getPendingException()); cx->clearPendingException(); if (!CloseIterator(cx, obj)) return false; @@ -992,7 +992,7 @@ js::UnwindIteratorForUncatchableException(JSContext *cx, JSObject *obj) */ template static bool -SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, StringPredicate predicate) +SuppressDeletedPropertyHelper(JSContext *cx, HandleObject obj, StringPredicate predicate) { JSObject *iterobj = cx->enumerators; while (iterobj) { @@ -1072,25 +1072,25 @@ SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, StringPredicate pred } class SingleStringPredicate { - JSFlatString *str; + Handle str; public: - SingleStringPredicate(JSFlatString *str) : str(str) {} + SingleStringPredicate(JSContext *cx, Handle str) : str(str) {} bool operator()(JSFlatString *str) { return EqualStrings(str, this->str); } bool matchesAtMostOne() { return true; } }; bool -js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id) +js_SuppressDeletedProperty(JSContext *cx, HandleObject obj, jsid id) { - JSFlatString *str = IdToString(cx, id); + RootedVar str(cx, IdToString(cx, id)); if (!str) return false; - return SuppressDeletedPropertyHelper(cx, obj, SingleStringPredicate(str)); + return SuppressDeletedPropertyHelper(cx, obj, SingleStringPredicate(cx, str)); } bool -js_SuppressDeletedElement(JSContext *cx, JSObject *obj, uint32_t index) +js_SuppressDeletedElement(JSContext *cx, HandleObject obj, uint32_t index) { jsid id; if (!IndexToId(cx, index, &id)) @@ -1113,7 +1113,7 @@ class IndexRangePredicate { }; bool -js_SuppressDeletedElements(JSContext *cx, JSObject *obj, uint32_t begin, uint32_t end) +js_SuppressDeletedElements(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end) { return SuppressDeletedPropertyHelper(cx, obj, IndexRangePredicate(begin, end)); } @@ -1121,7 +1121,7 @@ js_SuppressDeletedElements(JSContext *cx, JSObject *obj, uint32_t begin, uint32_ const uint32_t CLOSED_INDEX = UINT32_MAX; JSObject * -ElementIteratorObject::create(JSContext *cx, JSObject *obj) +ElementIteratorObject::create(JSContext *cx, HandleObject obj) { JS_ASSERT(obj); JSObject *iterobj = NewObjectWithGivenProto(cx, &ElementIteratorClass, NULL, obj); @@ -1153,14 +1153,16 @@ ElementIteratorObject::setIndex(uint32_t index) bool ElementIteratorObject::iteratorNext(JSContext *cx, Value *vp) { + RootedVar self(cx, this); + uint32_t i, length; RootedVarObject obj(cx, getTargetObject()); if (!js_GetLengthProperty(cx, obj, &length)) goto error; - i = getIndex(); + i = self->getIndex(); if (i >= length) { - setIndex(CLOSED_INDEX); + self->setIndex(CLOSED_INDEX); vp->setMagic(JS_NO_ITER_VALUE); return true; } @@ -1170,11 +1172,11 @@ ElementIteratorObject::iteratorNext(JSContext *cx, Value *vp) goto error; /* On success, bump the index. */ - setIndex(i + 1); + self->setIndex(i + 1); return true; error: - setIndex(CLOSED_INDEX); + self->setIndex(CLOSED_INDEX); return false; } @@ -1440,7 +1442,7 @@ js_NewGenerator(JSContext *cx) JS_ASSERT(stackfp->base() == cx->regs().sp); JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs()); - GlobalObject *global = &stackfp->global(); + RootedVar global(cx, &stackfp->global()); JSObject *proto = global->getOrCreateGeneratorPrototype(cx); if (!proto) return NULL; @@ -1728,9 +1730,9 @@ static JSFunctionSpec generator_methods[] = { #endif /* JS_HAS_GENERATORS */ static bool -InitIteratorClass(JSContext *cx, GlobalObject *global) +InitIteratorClass(JSContext *cx, Handle global) { - JSObject *iteratorProto = global->createBlankPrototype(cx, &IteratorClass); + RootedVarObject iteratorProto(cx, global->createBlankPrototype(cx, &IteratorClass)); if (!iteratorProto) return false; @@ -1742,7 +1744,8 @@ InitIteratorClass(JSContext *cx, GlobalObject *global) iteratorProto->setNativeIterator(ni); - JSFunction *ctor = global->createConstructor(cx, Iterator, CLASS_ATOM(cx, Iterator), 2); + RootedVarFunction ctor(cx); + ctor = global->createConstructor(cx, Iterator, CLASS_ATOM(cx, Iterator), 2); if (!ctor) return false; @@ -1755,22 +1758,22 @@ InitIteratorClass(JSContext *cx, GlobalObject *global) return DefineConstructorAndPrototype(cx, global, JSProto_Iterator, ctor, iteratorProto); } -bool -GlobalObject::initGeneratorClass(JSContext *cx) +/* static */ bool +GlobalObject::initGeneratorClass(JSContext *cx, Handle global) { #if JS_HAS_GENERATORS - JSObject *proto = createBlankPrototype(cx, &GeneratorClass); + RootedVarObject proto(cx, global->createBlankPrototype(cx, &GeneratorClass)); if (!proto || !DefinePropertiesAndBrand(cx, proto, NULL, generator_methods)) return false; - setReservedSlot(GENERATOR_PROTO, ObjectValue(*proto)); + global->setReservedSlot(GENERATOR_PROTO, ObjectValue(*proto)); #endif return true; } static JSObject * -InitStopIterationClass(JSContext *cx, GlobalObject *global) +InitStopIterationClass(JSContext *cx, Handle global) { - JSObject *proto = global->createBlankPrototype(cx, &StopIterationClass); + RootedVarObject proto(cx, global->createBlankPrototype(cx, &StopIterationClass)); if (!proto || !proto->freeze(cx)) return NULL; @@ -1788,7 +1791,7 @@ js_InitIteratorClasses(JSContext *cx, JSObject *obj) { JS_ASSERT(obj->isNative()); - GlobalObject *global = &obj->asGlobal(); + RootedVar global(cx, &obj->asGlobal()); /* * Bail if Iterator has already been initialized. We test for Iterator @@ -1802,7 +1805,7 @@ js_InitIteratorClasses(JSContext *cx, JSObject *obj) if (iter) return iter; - if (!InitIteratorClass(cx, global) || !global->initGeneratorClass(cx)) + if (!InitIteratorClass(cx, global) || !GlobalObject::initGeneratorClass(cx, global)) return NULL; return InitStopIterationClass(cx, global); } diff --git a/js/src/jsiter.h b/js/src/jsiter.h index e18963faa525..c745ec214a50 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -109,7 +109,7 @@ class ElementIteratorObject : public JSObject { NumSlots }; - static JSObject *create(JSContext *cx, JSObject *target); + static JSObject *create(JSContext *cx, HandleObject target); inline uint32_t getIndex() const; inline void setIndex(uint32_t index); @@ -202,13 +202,13 @@ UnwindIteratorForUncatchableException(JSContext *cx, JSObject *obj); } extern bool -js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id); +js_SuppressDeletedProperty(JSContext *cx, js::HandleObject obj, jsid id); extern bool -js_SuppressDeletedElement(JSContext *cx, JSObject *obj, uint32_t index); +js_SuppressDeletedElement(JSContext *cx, js::HandleObject obj, uint32_t index); extern bool -js_SuppressDeletedElements(JSContext *cx, JSObject *obj, uint32_t begin, uint32_t end); +js_SuppressDeletedElements(JSContext *cx, js::HandleObject obj, uint32_t begin, uint32_t end); /* * IteratorMore() indicates whether another value is available. It might diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index a9ceba1a8d67..c0944d956082 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -1228,6 +1228,13 @@ NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb) JS_PUBLIC_API(bool) ToNumberSlow(JSContext *cx, Value v, double *out) { +#ifdef DEBUG + { + SkipRoot skip(cx, &v); + MaybeCheckStackRoots(cx); + } +#endif + JS_ASSERT(!v.isNumber()); goto skip_int_double; for (;;) { diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index ec0ae6cf379e..31b14080949e 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -158,8 +158,10 @@ obj_getProto(JSContext *cx, JSObject *obj, jsid id, Value *vp) size_t sSetProtoCalled = 0; static JSBool -obj_setProto(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +obj_setProto(JSContext *cx, JSObject *obj_, jsid id, JSBool strict, Value *vp) { + RootedVarObject obj(cx, obj_); + if (!cx->runningWithTrustedPrincipals()) ++sSetProtoCalled; @@ -172,7 +174,7 @@ obj_setProto(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) if (!vp->isObjectOrNull()) return true; - JSObject *pobj = vp->toObjectOrNull(); + RootedVarObject pobj(cx, vp->toObjectOrNull()); unsigned attrs; id = ATOM_TO_JSID(cx->runtime->atomState.protoAtom); if (!CheckAccess(cx, obj, id, JSAccessMode(JSACC_PROTO|JSACC_WRITE), vp, &attrs)) @@ -188,7 +190,7 @@ obj_setProto(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) #endif /* !JS_HAS_OBJ_PROTO_PROP */ static bool -MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap, JSSharpInfo *value) +MarkSharpObjects(JSContext *cx, HandleObject obj, JSIdArray **idap, JSSharpInfo *value) { JS_CHECK_RECURSION(cx, return NULL); @@ -199,7 +201,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap, JSSharpInfo *va JSSharpInfo sharpid; JSSharpTable::Ptr p = map->table.lookup(obj); if (!p) { - if (!map->table.put(obj, sharpid)) + if (!map->table.put(obj.value(), sharpid)) return false; ida = JS_Enumerate(cx, obj); @@ -217,33 +219,35 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap, JSSharpInfo *va if (!prop) continue; bool hasGetter, hasSetter; - AutoValueRooter v(cx); - AutoValueRooter setter(cx); + Value value = UndefinedValue(), setter = UndefinedValue(); + RootValue valueRoot(cx, &value), setterRoot(cx, &setter); if (obj2->isNative()) { const Shape *shape = (Shape *) prop; hasGetter = shape->hasGetterValue(); hasSetter = shape->hasSetterValue(); if (hasGetter) - v.set(shape->getterValue()); + value = shape->getterValue(); if (hasSetter) - setter.set(shape->setterValue()); + setter = shape->setterValue(); } else { hasGetter = hasSetter = false; } if (hasSetter) { /* Mark the getter, then set val to setter. */ - if (hasGetter && v.value().isObject()) { - ok = MarkSharpObjects(cx, &v.value().toObject(), NULL, NULL); + if (hasGetter && value.isObject()) { + ok = MarkSharpObjects(cx, RootedVarObject(cx, &value.toObject()), NULL, NULL); if (!ok) break; } - v.set(setter.value()); + value = setter; } else if (!hasGetter) { - ok = obj->getGeneric(cx, id, v.addr()); + ok = obj->getGeneric(cx, id, &value); if (!ok) break; } - if (v.value().isObject() && !MarkSharpObjects(cx, &v.value().toObject(), NULL, NULL)) { + if (value.isObject() && + !MarkSharpObjects(cx, RootedVarObject(cx, &value.toObject()), NULL, NULL)) + { ok = false; break; } @@ -267,7 +271,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap, JSSharpInfo *va } bool -js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, bool *alreadySeen, bool *isSharp) +js_EnterSharpObject(JSContext *cx, HandleObject obj, JSIdArray **idap, bool *alreadySeen, bool *isSharp) { if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; @@ -320,7 +324,7 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, bool *alread */ p = map->table.lookup(obj); if (!p) { - if (!map->table.put(obj, sharpid)) + if (!map->table.put(obj.value(), sharpid)) goto bad; goto out; } @@ -424,7 +428,7 @@ obj_toSource(JSContext *cx, unsigned argc, Value *vp) /* If outermost, we need parentheses to be an expression, not a block. */ bool outermost = (cx->sharpObjectMap.depth == 0); - JSObject *obj = ToObject(cx, &vp[1]); + RootedVarObject obj(cx, ToObject(cx, &vp[1])); if (!obj) return false; @@ -938,7 +942,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c * may not exist in the current frame if it doesn't see 'eval'.) */ unsigned staticLevel; - Value thisv; + RootedVarValue thisv(cx); if (evalType == DIRECT_EVAL) { staticLevel = caller->script()->staticLevel + 1; @@ -966,12 +970,14 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c thisv = ObjectValue(*thisobj); } - JSLinearString *linearStr = str->ensureLinear(cx); + RootedVar linearStr(cx, str->ensureLinear(cx)); if (!linearStr) return false; const jschar *chars = linearStr->chars(); size_t length = linearStr->length(); + SkipRoot skip(cx, &chars); + /* * If the eval string starts with '(' or '[' and ends with ')' or ']', it may be JSON. * Try the JSON parser first because it's much faster. If the eval string @@ -1187,12 +1193,12 @@ obj_watch(JSContext *cx, unsigned argc, Value *vp) return false; } - JSObject *callable = js_ValueToCallableObject(cx, &vp[3], 0); + RootedVarObject callable(cx, js_ValueToCallableObject(cx, &vp[3], 0)); if (!callable) return false; - jsid propid; - if (!ValueToId(cx, vp[2], &propid)) + RootedVarId propid(cx); + if (!ValueToId(cx, vp[2], propid.address())) return false; RootedVarObject obj(cx, ToObject(cx, &vp[1])); @@ -1388,11 +1394,11 @@ DefineAccessor(JSContext *cx, unsigned argc, Value *vp) return false; } - jsid id; - if (!ValueToId(cx, args[0], &id)) + RootedVarId id(cx); + if (!ValueToId(cx, args[0], id.address())) return false; - JSObject *descObj = NewBuiltinClassInstance(cx, &ObjectClass); + RootedVarObject descObj(cx, NewBuiltinClassInstance(cx, &ObjectClass)); if (!descObj) return false; @@ -1410,12 +1416,10 @@ DefineAccessor(JSContext *cx, unsigned argc, Value *vp) if (!descObj->defineProperty(cx, acc, args[1])) return false; + RootedVarObject thisObj(cx, &args.thisv().toObject()); + JSBool dummy; - if (!js_DefineOwnProperty(cx, - RootedVarObject(cx, &args.thisv().toObject()), - RootedVarId(cx, id), - ObjectValue(*descObj), &dummy)) - { + if (!js_DefineOwnProperty(cx, thisObj, id, ObjectValue(*descObj), &dummy)) { return false; } args.rval().setUndefined(); @@ -1519,6 +1523,8 @@ NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, Value /* We have our own property, so start creating the descriptor. */ PropDesc d; + PropDesc::StackRoot dRoot(cx, &d); + d.initFromPropertyDescriptor(*desc); if (!d.makeObject(cx)) return false; @@ -1563,7 +1569,7 @@ PropDesc::makeObject(JSContext *cx) { MOZ_ASSERT(!isUndefined()); - JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass); + RootedVarObject obj(cx, NewBuiltinClassInstance(cx, &ObjectClass)); if (!obj) return false; @@ -3078,28 +3084,39 @@ js_InferFlags(JSContext *cx, unsigned defaultFlags) JSBool JSObject::nonNativeSetProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict) { + JSObject *self = this; if (JS_UNLIKELY(watched())) { id = js_CheckForStringIndex(id); + + RootObject selfRoot(cx, &self); + RootId idRoot(cx, &id); + WatchpointMap *wpmap = cx->compartment->watchpointMap; - if (wpmap && !wpmap->triggerWatchpoint(cx, this, id, vp)) + if (wpmap && !wpmap->triggerWatchpoint(cx, selfRoot, idRoot, vp)) return false; } - return getOps()->setGeneric(cx, this, id, vp, strict); + return self->getOps()->setGeneric(cx, self, id, vp, strict); } JSBool JSObject::nonNativeSetElement(JSContext *cx, uint32_t index, js::Value *vp, JSBool strict) { + JSObject *self = this; if (JS_UNLIKELY(watched())) { + RootObject selfRoot(cx, &self); + jsid id; if (!IndexToId(cx, index, &id)) return false; JS_ASSERT(id == js_CheckForStringIndex(id)); + + RootId idRoot(cx, &id); + WatchpointMap *wpmap = cx->compartment->watchpointMap; - if (wpmap && !wpmap->triggerWatchpoint(cx, this, id, vp)) + if (wpmap && !wpmap->triggerWatchpoint(cx, selfRoot, idRoot, vp)) return false; } - return getOps()->setElement(cx, this, index, vp, strict); + return self->getOps()->setElement(cx, self, index, vp, strict); } bool @@ -3114,14 +3131,16 @@ JSObject::deleteByValue(JSContext *cx, const Value &property, Value *rval, bool if (ValueIsSpecial(this, &propval, &sid, cx)) return deleteSpecial(cx, sid, rval, strict); + RootedVarObject self(cx, this); + JSAtom *name; if (!js_ValueToAtom(cx, propval, &name)) return false; if (name->isIndex(&index)) - return deleteElement(cx, index, rval, false); + return self->deleteElement(cx, index, rval, false); - return deleteProperty(cx, name->asPropertyName(), rval, false); + return self->deleteProperty(cx, name->asPropertyName(), rval, false); } JS_FRIEND_API(bool) @@ -3674,8 +3693,7 @@ DefineConstructorAndPrototype(JSContext *cx, HandleObject obj, JSProtoKey key, H cached = true; } - AutoValueRooter tvr2(cx, ObjectValue(*fun)); - if (!DefineStandardSlot(cx, obj, key, atom, tvr2.value(), 0, named)) + if (!DefineStandardSlot(cx, obj, key, atom, ObjectValue(*fun), 0, named)) goto bad; /* @@ -4100,7 +4118,7 @@ static JSObjectOp lazy_prototype_init[JSProto_LIMIT] = { namespace js { bool -SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles) +SetProto(JSContext *cx, HandleObject obj, HandleObject proto, bool checkForCycles) { JS_ASSERT_IF(!checkForCycles, obj != proto); JS_ASSERT(obj->isExtensible()); @@ -4129,7 +4147,7 @@ SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles) * * :XXX: bug 707717 make this code less brittle. */ - JSObject *oldproto = obj; + RootedVarObject oldproto(cx, obj); while (oldproto && oldproto->isNative()) { if (oldproto->hasSingletonType()) { if (!oldproto->generateOwnShape(cx)) @@ -4399,10 +4417,12 @@ js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id) } Shape * -js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, +js_AddNativeProperty(JSContext *cx, HandleObject obj, jsid id_, PropertyOp getter, StrictPropertyOp setter, uint32_t slot, unsigned attrs, unsigned flags, int shortid) { + RootedVarId id(cx, id_); + /* Convert string indices to integers if appropriate. */ id = js_CheckForStringIndex(id); @@ -4426,14 +4446,23 @@ js_DefineProperty(JSContext *cx, JSObject *obj_, jsid id, const Value *value, } JSBool -js_DefineElement(JSContext *cx, JSObject *obj_, uint32_t index, const Value *value, +js_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { - RootObject obj(cx, &obj_); + if (index <= JSID_INT_MAX) { + return !!DefineNativeProperty(cx, RootedVarObject(cx, obj), INT_TO_JSID(index), *value, + getter, setter, attrs, 0, 0); + } + + RootObject objRoot(cx, &obj); + RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + RootValue valueRoot(cx, value); + jsid id; if (!IndexToId(cx, index, &id)) return false; - return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0); + + return !!DefineNativeProperty(cx, objRoot, id, *value, getter, setter, attrs, 0, 0); } /* @@ -4470,6 +4499,7 @@ DefineNativeProperty(JSContext *cx, HandleObject obj, jsid id, const Value &valu JS_ASSERT(!(attrs & JSPROP_NATIVE_ACCESSORS)); RootId idRoot(cx, &id); + RootGetterSetter gsRoot(cx, attrs, &getter, &setter); /* Make a local copy of value so addProperty can mutate its inout parameter. */ RootedVarValue value(cx); @@ -4851,7 +4881,7 @@ js::FindProperty(JSContext *cx, HandlePropertyName name, HandleObject scopeChain } JSObject * -js::FindIdentifierBase(JSContext *cx, JSObject *scopeChain, PropertyName *name) +js::FindIdentifierBase(JSContext *cx, HandleObject scopeChain, HandlePropertyName name) { /* * This function should not be called for a global object or from the @@ -4859,7 +4889,7 @@ js::FindIdentifierBase(JSContext *cx, JSObject *scopeChain, PropertyName *name) */ JS_ASSERT(scopeChain->enclosingScope() != NULL); - JSObject *obj = scopeChain; + RootedVarObject obj(cx, scopeChain); /* * Loop over cacheable objects on the scope chain until we find a @@ -5237,7 +5267,7 @@ js_SetPropertyHelper(JSContext *cx, HandleObject obj, jsid id, unsigned defineHo if (JS_UNLIKELY(obj->watched())) { /* Fire watchpoints, if any. */ WatchpointMap *wpmap = cx->compartment->watchpointMap; - if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp)) + if (wpmap && !wpmap->triggerWatchpoint(cx, obj, idRoot, vp)) return false; } @@ -5477,7 +5507,7 @@ js_SetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned * } JSBool -js_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +js_DeleteGeneric(JSContext *cx, JSObject *obj_, jsid id_, Value *rval, JSBool strict) { JSObject *proto; JSProperty *prop; @@ -5485,6 +5515,9 @@ js_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool stri rval->setBoolean(true); + RootedVarObject obj(cx, obj_); + RootedVarId id(cx, id_); + /* Convert string indices to integers if appropriate. */ id = js_CheckForStringIndex(id); @@ -5526,8 +5559,10 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, } JSBool -js_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict) +js_DeleteElement(JSContext *cx, JSObject *obj_, uint32_t index, Value *rval, JSBool strict) { + RootedVarObject obj(cx, obj_); + jsid id; if (!IndexToId(cx, index, &id)) return false; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 2d2fbb7fbbe6..a876c93fb447 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -521,7 +521,7 @@ struct JSObject : public js::ObjectImpl /* Access the parent link of an object. */ inline JSObject *getParent() const; - bool setParent(JSContext *cx, JSObject *newParent); + static bool setParent(JSContext *cx, js::HandleObject obj, js::HandleObject newParent); /* * Get the enclosing scope of an object. When called on non-scope object, @@ -1039,7 +1039,7 @@ class ValueArray { /* For manipulating JSContext::sharpObjectMap. */ extern bool -js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, bool *alreadySeen, bool *isSharp); +js_EnterSharpObject(JSContext *cx, js::HandleObject obj, JSIdArray **idap, bool *alreadySeen, bool *isSharp); extern void js_LeaveSharpObject(JSContext *cx, JSIdArray **idap); @@ -1213,7 +1213,7 @@ js_CheckForStringIndex(jsid id); * and setter, slot, attributes, and other members. */ extern js::Shape * -js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, +js_AddNativeProperty(JSContext *cx, js::HandleObject obj, jsid id, JSPropertyOp getter, JSStrictPropertyOp setter, uint32_t slot, unsigned attrs, unsigned flags, int shortid); @@ -1308,7 +1308,7 @@ FindProperty(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, JSObject **objp, JSObject **pobjp, JSProperty **propp); extern JSObject * -FindIdentifierBase(JSContext *cx, JSObject *scopeChain, PropertyName *name); +FindIdentifierBase(JSContext *cx, HandleObject scopeChain, HandlePropertyName name); } @@ -1464,7 +1464,7 @@ js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, namespace js { extern bool -SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles); +SetProto(JSContext *cx, HandleObject obj, HandleObject proto, bool checkForCycles); extern JSString * obj_toStringHelper(JSContext *cx, JSObject *obj); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 0486d450a5fd..3bc38d0e8dd5 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -227,13 +227,15 @@ JSObject::deleteProperty(JSContext *cx, js::PropertyName *name, js::Value *rval, inline bool JSObject::deleteElement(JSContext *cx, uint32_t index, js::Value *rval, bool strict) { + js::RootedVarObject self(cx, this); + jsid id; if (!js::IndexToId(cx, index, &id)) return false; - js::types::AddTypePropertyId(cx, this, id, js::types::Type::UndefinedType()); - js::types::MarkTypePropertyConfigured(cx, this, id); - js::DeleteElementOp op = getOps()->deleteElement; - return (op ? op : js_DeleteElement)(cx, this, index, rval, strict); + js::types::AddTypePropertyId(cx, self, id, js::types::Type::UndefinedType()); + js::types::MarkTypePropertyConfigured(cx, self, id); + js::DeleteElementOp op = self->getOps()->deleteElement; + return (op ? op : js_DeleteElement)(cx, self, index, rval, strict); } inline bool @@ -1084,16 +1086,19 @@ JSObject::lookupSpecial(JSContext *cx, js::SpecialId sid, JSObject **objp, JSPro } inline JSBool -JSObject::getElement(JSContext *cx, JSObject *receiver, uint32_t index, js::Value *vp) +JSObject::getElement(JSContext *cx, JSObject *receiver_, uint32_t index, js::Value *vp) { js::ElementIdOp op = getOps()->getElement; if (op) - return op(cx, this, receiver, index, vp); + return op(cx, this, receiver_, index, vp); + + js::RootedVarObject self(cx, this); + js::RootedVarObject receiver(cx, receiver_); jsid id; if (!js::IndexToId(cx, index, &id)) return false; - return getGeneric(cx, receiver, id, vp); + return self->getGeneric(cx, receiver, id, vp); } inline JSBool @@ -1103,14 +1108,17 @@ JSObject::getElement(JSContext *cx, uint32_t index, js::Value *vp) } inline JSBool -JSObject::getElementIfPresent(JSContext *cx, JSObject *receiver, uint32_t index, js::Value *vp, +JSObject::getElementIfPresent(JSContext *cx, JSObject *receiver_, uint32_t index, js::Value *vp, bool *present) { + js::RootedVarObject self(cx, this), receiver(cx, receiver_); + js::ElementIfPresentOp op = getOps()->getElementIfPresent; if (op) return op(cx, this, receiver, index, vp, present); - /* For now, do the index-to-id conversion just once, then use + /* + * For now, do the index-to-id conversion just once, then use * lookupGeneric/getGeneric. Once lookupElement and getElement stop both * doing index-to-id conversions, we can use those here. */ @@ -1120,7 +1128,7 @@ JSObject::getElementIfPresent(JSContext *cx, JSObject *receiver, uint32_t index, JSObject *obj2; JSProperty *prop; - if (!lookupGeneric(cx, id, &obj2, &prop)) + if (!self->lookupGeneric(cx, id, &obj2, &prop)) return false; if (!prop) { @@ -1130,7 +1138,7 @@ JSObject::getElementIfPresent(JSContext *cx, JSObject *receiver, uint32_t index, } *present = true; - return getGeneric(cx, receiver, id, vp); + return self->getGeneric(cx, receiver, id, vp); } inline JSBool @@ -1269,7 +1277,7 @@ class AutoPropDescArrayRooter : private AutoGCRooter { public: AutoPropDescArrayRooter(JSContext *cx) - : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx) + : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx), skip(cx, &descriptors) { } PropDesc *append() { @@ -1291,12 +1299,15 @@ class AutoPropDescArrayRooter : private AutoGCRooter private: PropDescArray descriptors; + SkipRoot skip; }; class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescriptor { public: - AutoPropertyDescriptorRooter(JSContext *cx) : AutoGCRooter(cx, DESCRIPTOR) { + AutoPropertyDescriptorRooter(JSContext *cx) + : AutoGCRooter(cx, DESCRIPTOR), skip(cx, this) + { obj = NULL; attrs = 0; getter = (PropertyOp) NULL; @@ -1305,7 +1316,7 @@ class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescri } AutoPropertyDescriptorRooter(JSContext *cx, PropertyDescriptor *desc) - : AutoGCRooter(cx, DESCRIPTOR) + : AutoGCRooter(cx, DESCRIPTOR), skip(cx, this) { obj = desc->obj; attrs = desc->attrs; @@ -1315,6 +1326,9 @@ class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescri } friend void AutoGCRooter::trace(JSTracer *trc); + + private: + SkipRoot skip; }; inline bool @@ -1636,7 +1650,7 @@ DefineConstructorAndPrototype(JSContext *cx, GlobalObject *global, JS_ASSERT(proto); jsid id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[key]); - JS_ASSERT(!global->nativeLookup(cx, id)); + JS_ASSERT(!global->nativeLookupNoAllocation(cx, id)); /* Set these first in case AddTypePropertyId looks for this class. */ global->setSlot(key, ObjectValue(*ctor)); diff --git a/js/src/json.cpp b/js/src/json.cpp index 74a797ca015f..e0e49268af72 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -213,10 +213,10 @@ class StringifyContext { public: StringifyContext(JSContext *cx, StringBuffer &sb, const StringBuffer &gap, - JSObject *replacer, const AutoIdVector &propertyList) + HandleObject replacer, const AutoIdVector &propertyList) : sb(sb), gap(gap), - replacer(replacer), + replacer(cx, replacer), propertyList(propertyList), depth(0), objectStack(cx) @@ -232,7 +232,7 @@ class StringifyContext StringBuffer &sb; const StringBuffer ⪆ - JSObject * const replacer; + RootedVarObject replacer; const AutoIdVector &propertyList; uint32_t depth; HashSet objectStack; @@ -258,8 +258,8 @@ WriteIndent(JSContext *cx, StringifyContext *scx, uint32_t limit) class CycleDetector { public: - CycleDetector(StringifyContext *scx, JSObject *obj) - : objectStack(scx->objectStack), obj(obj) { + CycleDetector(JSContext *cx, StringifyContext *scx, JSObject *obj) + : objectStack(scx->objectStack), obj(cx, obj) { } bool init(JSContext *cx) { @@ -277,7 +277,7 @@ class CycleDetector private: HashSet &objectStack; - JSObject *const obj; + RootedVarObject obj; }; template @@ -396,7 +396,7 @@ IsFilteredValue(const Value &v) /* ES5 15.12.3 JO. */ static JSBool -JO(JSContext *cx, JSObject *obj, StringifyContext *scx) +JO(JSContext *cx, HandleObject obj, StringifyContext *scx) { /* * This method implements the JO algorithm in ES5 15.12.3, but: @@ -409,7 +409,7 @@ JO(JSContext *cx, JSObject *obj, StringifyContext *scx) */ /* Steps 1-2, 11. */ - CycleDetector detect(scx, obj); + CycleDetector detect(cx, scx, obj); if (!detect.init(cx)) return JS_FALSE; @@ -481,7 +481,7 @@ JO(JSContext *cx, JSObject *obj, StringifyContext *scx) /* ES5 15.12.3 JA. */ static JSBool -JA(JSContext *cx, JSObject *obj, StringifyContext *scx) +JA(JSContext *cx, HandleObject obj, StringifyContext *scx) { /* * This method implements the JA algorithm in ES5 15.12.3, but: @@ -494,7 +494,7 @@ JA(JSContext *cx, JSObject *obj, StringifyContext *scx) */ /* Steps 1-2, 11. */ - CycleDetector detect(scx, obj); + CycleDetector detect(cx, scx, obj); if (!detect.init(cx)) return JS_FALSE; @@ -599,7 +599,7 @@ Str(JSContext *cx, const Value &v, StringifyContext *scx) /* Step 10. */ JS_ASSERT(v.isObject()); - JSObject *obj = &v.toObject(); + RootedVarObject obj(cx, &v.toObject()); scx->depth++; JSBool ok; @@ -614,8 +614,11 @@ Str(JSContext *cx, const Value &v, StringifyContext *scx) /* ES5 15.12.3. */ JSBool -js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, Value space, StringBuffer &sb) +js_Stringify(JSContext *cx, Value *vp, JSObject *replacer_, Value space, StringBuffer &sb) { + RootedVarObject replacer(cx, replacer_); + RootValue spaceRoot(cx, &space); + /* Step 4. */ AutoIdVector propertyList(cx); if (replacer) { @@ -928,9 +931,11 @@ static JSFunctionSpec json_static_methods[] = { }; JSObject * -js_InitJSONClass(JSContext *cx, JSObject *obj) +js_InitJSONClass(JSContext *cx, JSObject *obj_) { - JSObject *JSON = NewObjectWithClassProto(cx, &JSONClass, NULL, obj); + RootedVarObject obj(cx, obj_); + + RootedVarObject JSON(cx, NewObjectWithClassProto(cx, &JSONClass, NULL, obj)); if (!JSON || !JSON->setSingletonType(cx)) return NULL; diff --git a/js/src/jsonparser.h b/js/src/jsonparser.h index 21b4bdf278cc..381fc6314169 100644 --- a/js/src/jsonparser.h +++ b/js/src/jsonparser.h @@ -66,6 +66,9 @@ class JSONParser mozilla::RangedPtr current; const mozilla::RangedPtr end; + /* For current/end as cursors into a string. */ + js::SkipRoot root; + js::Value v; const ParsingMode parsingMode; @@ -95,6 +98,7 @@ class JSONParser : cx(cx), current(data, length), end(data + length, data, length), + root(cx, this), parsingMode(parsingMode), errorHandling(errorHandling) #ifdef DEBUG diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 7e6b1ff4e364..8c0a0bb981f6 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -354,8 +354,10 @@ js_DumpPCCounts(JSContext *cx, JSScript *script, js::Sprinter *sp) * If counts != NULL, include a counter of the number of times each op was executed. */ JS_FRIEND_API(JSBool) -js_DisassembleAtPC(JSContext *cx, JSScript *script, JSBool lines, jsbytecode *pc, Sprinter *sp) +js_DisassembleAtPC(JSContext *cx, JSScript *script_, JSBool lines, jsbytecode *pc, Sprinter *sp) { + RootedVar script(cx, script_); + jsbytecode *next, *end; unsigned len; @@ -451,11 +453,13 @@ ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes) return false; Shape::Range r = obj->lastProperty()->all(); + Shape::Range::Root root(cx, &r); + while (!r.empty()) { - const Shape &shape = r.front(); - JSAtom *atom = JSID_IS_INT(shape.propid()) + RootedVar shape(cx, &r.front()); + JSAtom *atom = JSID_IS_INT(shape->propid()) ? cx->runtime->atomState.emptyAtom - : JSID_TO_ATOM(shape.propid()); + : JSID_TO_ATOM(shape->propid()); JSAutoByteString bytes; if (!js_AtomToPrintableString(cx, atom, &bytes)) @@ -463,7 +467,7 @@ ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes) r.popFront(); source = JS_sprintf_append(source, "%s: %d%s", - bytes.ptr(), shape.shortid(), + bytes.ptr(), shape->shortid(), !r.empty() ? ", " : ""); if (!source) return false; @@ -5507,7 +5511,9 @@ js_DecompileFunctionBody(JSPrinter *jp) JSBool js_DecompileFunction(JSPrinter *jp) { - JSFunction *fun = jp->fun; + JSContext *cx = jp->sprinter.context; + + RootedVarFunction fun(cx, jp->fun); JS_ASSERT(fun); JS_ASSERT(!jp->script); @@ -5537,7 +5543,7 @@ js_DecompileFunction(JSPrinter *jp) } else { JSScript *script = fun->script(); #if JS_HAS_DESTRUCTURING - SprintStack ss(jp->sprinter.context); + SprintStack ss(cx); #endif /* Print the parameters. */ @@ -5567,7 +5573,7 @@ js_DecompileFunction(JSPrinter *jp) pc += js_CodeSpec[*pc].length; LOCAL_ASSERT(*pc == JSOP_DUP); if (!ss.printer) { - ok = InitSprintStack(jp->sprinter.context, &ss, jp, StackDepth(script)); + ok = InitSprintStack(cx, &ss, jp, StackDepth(script)); if (!ok) break; } diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 7da342b665b1..8f04cafa4af1 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -154,8 +154,11 @@ ProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, V } bool -ProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver, uint32_t index, Value *vp, bool *present) +ProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy_, JSObject *receiver_, uint32_t index, Value *vp, bool *present) { + RootedVarObject proxy(cx, proxy_); + RootedVarObject receiver(cx, receiver_); + jsid id; if (!IndexToId(cx, index, &id)) return false; @@ -333,10 +336,10 @@ bool ProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc, Value *vp) { JS_ASSERT(OperationInProgress(cx, proxy)); - AutoValueRooter rval(cx); - JSBool ok = Invoke(cx, vp[1], GetCall(proxy), argc, JS_ARGV(cx, vp), rval.addr()); + RootedVarValue rval(cx); + JSBool ok = Invoke(cx, vp[1], GetCall(proxy), argc, JS_ARGV(cx, vp), rval.address()); if (ok) - JS_SET_RVAL(cx, vp, rval.value()); + JS_SET_RVAL(cx, vp, rval); return ok; } @@ -430,13 +433,13 @@ GetDerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp) } static bool -Trap(JSContext *cx, JSObject *handler, Value fval, unsigned argc, Value* argv, Value *rval) +Trap(JSContext *cx, HandleObject handler, HandleValue fval, unsigned argc, Value* argv, Value *rval) { return Invoke(cx, ObjectValue(*handler), fval, argc, argv, rval); } static bool -Trap1(JSContext *cx, JSObject *handler, Value fval, jsid id, Value *rval) +Trap1(JSContext *cx, HandleObject handler, HandleValue fval, jsid id, Value *rval) { JSString *str = ToString(cx, IdToValue(id)); if (!str) @@ -446,7 +449,7 @@ Trap1(JSContext *cx, JSObject *handler, Value fval, jsid id, Value *rval) } static bool -Trap2(JSContext *cx, JSObject *handler, Value fval, jsid id, Value v, Value *rval) +Trap2(JSContext *cx, HandleObject handler, HandleValue fval, jsid id, Value v, Value *rval) { JSString *str = ToString(cx, IdToValue(id)); if (!str) @@ -578,157 +581,169 @@ GetProxyHandlerObject(JSContext *cx, JSObject *proxy) } bool -ScriptedProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, +ScriptedProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set, PropertyDescriptor *desc) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); - AutoValueRooter tvr(cx); - return GetFundamentalTrap(cx, handler, ATOM(getPropertyDescriptor), tvr.addr()) && - Trap1(cx, handler, tvr.value(), id, tvr.addr()) && - ((tvr.value().isUndefined() && IndicatePropertyNotFound(cx, desc)) || - (ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), tvr.value()) && - ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc))); + RootedVarId id(cx, id_); + RootedVarObject proxy(cx, proxy_); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); + RootedVarValue fval(cx), value(cx); + return GetFundamentalTrap(cx, handler, ATOM(getPropertyDescriptor), fval.address()) && + Trap1(cx, handler, fval, id, value.address()) && + ((value.reference().isUndefined() && IndicatePropertyNotFound(cx, desc)) || + (ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), value) && + ParsePropertyDescriptorObject(cx, proxy, id, value, desc))); } bool -ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, +ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set, PropertyDescriptor *desc) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); - AutoValueRooter tvr(cx); - return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyDescriptor), tvr.addr()) && - Trap1(cx, handler, tvr.value(), id, tvr.addr()) && - ((tvr.value().isUndefined() && IndicatePropertyNotFound(cx, desc)) || - (ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), tvr.value()) && - ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc))); + RootedVarId id(cx, id_); + RootedVarObject proxy(cx, proxy_); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); + RootedVarValue fval(cx), value(cx); + return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyDescriptor), fval.address()) && + Trap1(cx, handler, fval, id, value.address()) && + ((value.reference().isUndefined() && IndicatePropertyNotFound(cx, desc)) || + (ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), value) && + ParsePropertyDescriptorObject(cx, proxy, id, value, desc))); } bool -ScriptedProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id, +ScriptedProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id_, PropertyDescriptor *desc) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); - AutoValueRooter tvr(cx); - AutoValueRooter fval(cx); - return GetFundamentalTrap(cx, handler, ATOM(defineProperty), fval.addr()) && - NewPropertyDescriptorObject(cx, desc, tvr.addr()) && - Trap2(cx, handler, fval.value(), id, tvr.value(), tvr.addr()); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); + RootedVarValue fval(cx), value(cx); + RootedVarId id(cx, id_); + return GetFundamentalTrap(cx, handler, ATOM(defineProperty), fval.address()) && + NewPropertyDescriptorObject(cx, desc, value.address()) && + Trap2(cx, handler, fval, id, value, value.address()); } bool ScriptedProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); - AutoValueRooter tvr(cx); - return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyNames), tvr.addr()) && - Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) && - ArrayToIdVector(cx, tvr.value(), props); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); + RootedVarValue fval(cx), value(cx); + return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyNames), fval.address()) && + Trap(cx, handler, fval, 0, NULL, value.address()) && + ArrayToIdVector(cx, value, props); } bool ScriptedProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); - AutoValueRooter tvr(cx); - return GetFundamentalTrap(cx, handler, ATOM(delete), tvr.addr()) && - Trap1(cx, handler, tvr.value(), id, tvr.addr()) && - ValueToBool(cx, tvr.value(), bp); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); + RootedVarValue fval(cx), value(cx); + return GetFundamentalTrap(cx, handler, ATOM(delete), fval.address()) && + Trap1(cx, handler, fval, id, value.address()) && + ValueToBool(cx, value, bp); } bool ScriptedProxyHandler::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); - AutoValueRooter tvr(cx); - return GetFundamentalTrap(cx, handler, ATOM(enumerate), tvr.addr()) && - Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) && - ArrayToIdVector(cx, tvr.value(), props); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); + RootedVarValue fval(cx), value(cx); + return GetFundamentalTrap(cx, handler, ATOM(enumerate), fval.address()) && + Trap(cx, handler, fval, 0, NULL, value.address()) && + ArrayToIdVector(cx, value, props); } bool -ScriptedProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp) +ScriptedProxyHandler::has(JSContext *cx, JSObject *proxy_, jsid id, bool *bp) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); - AutoValueRooter tvr(cx); - if (!GetDerivedTrap(cx, handler, ATOM(has), tvr.addr())) + RootedVarObject proxy(cx, proxy_); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); + RootedVarValue fval(cx), value(cx); + if (!GetDerivedTrap(cx, handler, ATOM(has), fval.address())) return false; - if (!js_IsCallable(tvr.value())) + if (!js_IsCallable(fval)) return ProxyHandler::has(cx, proxy, id, bp); - return Trap1(cx, handler, tvr.value(), id, tvr.addr()) && - ValueToBool(cx, tvr.value(), bp); + return Trap1(cx, handler, fval, id, value.address()) && + ValueToBool(cx, value, bp); } bool -ScriptedProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp) +ScriptedProxyHandler::hasOwn(JSContext *cx, JSObject *proxy_, jsid id, bool *bp) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); - AutoValueRooter tvr(cx); - if (!GetDerivedTrap(cx, handler, ATOM(hasOwn), tvr.addr())) + RootedVarObject proxy(cx, proxy_); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); + RootedVarValue fval(cx), value(cx); + if (!GetDerivedTrap(cx, handler, ATOM(hasOwn), fval.address())) return false; - if (!js_IsCallable(tvr.value())) + if (!js_IsCallable(fval)) return ProxyHandler::hasOwn(cx, proxy, id, bp); - return Trap1(cx, handler, tvr.value(), id, tvr.addr()) && - ValueToBool(cx, tvr.value(), bp); + return Trap1(cx, handler, fval, id, value.address()) && + ValueToBool(cx, value, bp); } bool -ScriptedProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp) +ScriptedProxyHandler::get(JSContext *cx, JSObject *proxy_, JSObject *receiver, jsid id_, Value *vp) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); + RootedVarId id(cx, id_); + RootedVarObject proxy(cx, proxy_); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); JSString *str = ToString(cx, IdToValue(id)); if (!str) return false; - AutoValueRooter tvr(cx, StringValue(str)); - Value argv[] = { ObjectOrNullValue(receiver), tvr.value() }; - AutoValueRooter fval(cx); - if (!GetDerivedTrap(cx, handler, ATOM(get), fval.addr())) + RootedVarValue value(cx, StringValue(str)); + Value argv[] = { ObjectOrNullValue(receiver), value }; + RootedVarValue fval(cx); + if (!GetDerivedTrap(cx, handler, ATOM(get), fval.address())) return false; - if (!js_IsCallable(fval.value())) + if (!js_IsCallable(fval)) return ProxyHandler::get(cx, proxy, receiver, id, vp); - return Trap(cx, handler, fval.value(), 2, argv, vp); + return Trap(cx, handler, fval, 2, argv, vp); } bool -ScriptedProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, +ScriptedProxyHandler::set(JSContext *cx, JSObject *proxy_, JSObject *receiver, jsid id_, bool strict, Value *vp) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); + RootedVarId id(cx, id_); + RootedVarObject proxy(cx, proxy_); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); JSString *str = ToString(cx, IdToValue(id)); if (!str) return false; - AutoValueRooter tvr(cx, StringValue(str)); - Value argv[] = { ObjectOrNullValue(receiver), tvr.value(), *vp }; - AutoValueRooter fval(cx); - if (!GetDerivedTrap(cx, handler, ATOM(set), fval.addr())) + RootedVarValue value(cx, StringValue(str)); + Value argv[] = { ObjectOrNullValue(receiver), value, *vp }; + RootedVarValue fval(cx); + if (!GetDerivedTrap(cx, handler, ATOM(set), fval.address())) return false; - if (!js_IsCallable(fval.value())) + if (!js_IsCallable(fval)) return ProxyHandler::set(cx, proxy, receiver, id, strict, vp); - return Trap(cx, handler, fval.value(), 3, argv, tvr.addr()); + return Trap(cx, handler, fval, 3, argv, value.address()); } bool -ScriptedProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props) +ScriptedProxyHandler::keys(JSContext *cx, JSObject *proxy_, AutoIdVector &props) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); - AutoValueRooter tvr(cx); - if (!GetDerivedTrap(cx, handler, ATOM(keys), tvr.addr())) + RootedVarObject proxy(cx, proxy_); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); + RootedVarValue value(cx); + if (!GetDerivedTrap(cx, handler, ATOM(keys), value.address())) return false; - if (!js_IsCallable(tvr.value())) + if (!js_IsCallable(value)) return ProxyHandler::keys(cx, proxy, props); - return Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) && - ArrayToIdVector(cx, tvr.value(), props); + return Trap(cx, handler, value, 0, NULL, value.address()) && + ArrayToIdVector(cx, value, props); } bool -ScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp) +ScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp) { - JSObject *handler = GetProxyHandlerObject(cx, proxy); - AutoValueRooter tvr(cx); - if (!GetDerivedTrap(cx, handler, ATOM(iterate), tvr.addr())) + RootedVarObject proxy(cx, proxy_); + RootedVarObject handler(cx, GetProxyHandlerObject(cx, proxy)); + RootedVarValue value(cx); + if (!GetDerivedTrap(cx, handler, ATOM(iterate), value.address())) return false; - if (!js_IsCallable(tvr.value())) + if (!js_IsCallable(value)) return ProxyHandler::iterate(cx, proxy, flags, vp); - return Trap(cx, handler, tvr.value(), 0, NULL, vp) && + return Trap(cx, handler, value, 0, NULL, vp) && ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(iterate), *vp); } @@ -738,9 +753,10 @@ class AutoPendingProxyOperation { JSRuntime *rt; PendingProxyOperation op; public: - AutoPendingProxyOperation(JSContext *cx, JSObject *proxy) : rt(cx->runtime) { + AutoPendingProxyOperation(JSContext *cx, JSObject *proxy) + : rt(cx->runtime), op(cx, proxy) + { op.next = rt->pendingProxyOperation; - op.object = proxy; rt->pendingProxyOperation = &op; } @@ -982,9 +998,11 @@ proxy_innerObject(JSContext *cx, JSObject *obj) } static JSBool -proxy_LookupGeneric(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, +proxy_LookupGeneric(JSContext *cx, JSObject *obj_, jsid id, JSObject **objp, JSProperty **propp) { + RootedVarObject obj(cx, obj_); + id = js_CheckForStringIndex(id); bool found; @@ -1009,9 +1027,11 @@ proxy_LookupProperty(JSContext *cx, JSObject *obj, PropertyName *name, JSObject } static JSBool -proxy_LookupElement(JSContext *cx, JSObject *obj, uint32_t index, JSObject **objp, +proxy_LookupElement(JSContext *cx, JSObject *obj_, uint32_t index, JSObject **objp, JSProperty **propp) { + RootedVarObject obj(cx, obj_); + jsid id; if (!IndexToId(cx, index, &id)) return false; @@ -1048,9 +1068,11 @@ proxy_DefineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Val } static JSBool -proxy_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *value, +proxy_DefineElement(JSContext *cx, JSObject *obj_, uint32_t index, const Value *value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { + RootedVarObject obj(cx, obj_); + jsid id; if (!IndexToId(cx, index, &id)) return false; @@ -1079,8 +1101,11 @@ proxy_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName } static JSBool -proxy_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp) +proxy_GetElement(JSContext *cx, JSObject *obj_, JSObject *receiver_, uint32_t index, Value *vp) { + RootedVarObject obj(cx, obj_); + RootedVarObject receiver(cx, receiver_); + jsid id; if (!IndexToId(cx, index, &id)) return false; @@ -1115,8 +1140,10 @@ proxy_SetProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, J } static JSBool -proxy_SetElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict) +proxy_SetElement(JSContext *cx, JSObject *obj_, uint32_t index, Value *vp, JSBool strict) { + RootedVarObject obj(cx, obj_); + jsid id; if (!IndexToId(cx, index, &id)) return false; @@ -1148,8 +1175,10 @@ proxy_GetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, un } static JSBool -proxy_GetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp) +proxy_GetElementAttributes(JSContext *cx, JSObject *obj_, uint32_t index, unsigned *attrsp) { + RootedVarObject obj(cx, obj_); + jsid id; if (!IndexToId(cx, index, &id)) return false; @@ -1182,8 +1211,10 @@ proxy_SetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, un } static JSBool -proxy_SetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp) +proxy_SetElementAttributes(JSContext *cx, JSObject *obj_, uint32_t index, unsigned *attrsp) { + RootedVarObject obj(cx, obj_); + jsid id; if (!IndexToId(cx, index, &id)) return false; @@ -1197,10 +1228,12 @@ proxy_SetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned } static JSBool -proxy_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +proxy_DeleteGeneric(JSContext *cx, JSObject *obj_, jsid id, Value *rval, JSBool strict) { JS_ASSERT(id == js_CheckForStringIndex(id)); + RootedVarObject obj(cx, obj_); + // TODO: throwing away strict bool deleted; if (!Proxy::delete_(cx, obj, id, &deleted) || !js_SuppressDeletedProperty(cx, obj, id)) @@ -1216,8 +1249,10 @@ proxy_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rv } static JSBool -proxy_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict) +proxy_DeleteElement(JSContext *cx, JSObject *obj_, uint32_t index, Value *rval, JSBool strict) { + RootedVarObject obj(cx, obj_); + jsid id; if (!IndexToId(cx, index, &id)) return false; @@ -1466,9 +1501,12 @@ JS_FRIEND_DATA(Class) js::FunctionProxyClass = { }; JS_FRIEND_API(JSObject *) -js::NewProxyObject(JSContext *cx, ProxyHandler *handler, const Value &priv, JSObject *proto, - JSObject *parent, JSObject *call, JSObject *construct) +js::NewProxyObject(JSContext *cx, ProxyHandler *handler, const Value &priv_, JSObject *proto_, + JSObject *parent_, JSObject *call_, JSObject *construct_) { + RootedVarValue priv(cx, priv_); + RootedVarObject proto(cx, proto_), parent(cx, parent_), call(cx, call_), construct(cx, construct_); + JS_ASSERT_IF(proto, cx->compartment == proto->compartment()); JS_ASSERT_IF(parent, cx->compartment == parent->compartment()); bool fun = call || construct; @@ -1607,9 +1645,11 @@ Class js::ProxyClass = { }; JS_FRIEND_API(JSObject *) -js_InitProxyClass(JSContext *cx, JSObject *obj) +js_InitProxyClass(JSContext *cx, JSObject *obj_) { - JSObject *module = NewObjectWithClassProto(cx, &ProxyClass, NULL, obj); + RootedVarObject obj(cx, obj_); + + RootedVarObject module(cx, NewObjectWithClassProto(cx, &ProxyClass, NULL, obj)); if (!module || !module->setSingletonType(cx)) return NULL; diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 47fad22a74c1..c4571818468f 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -261,6 +261,7 @@ enum ThingRootKind THING_ROOT_TYPE_OBJECT, THING_ROOT_STRING, THING_ROOT_SCRIPT, + THING_ROOT_XML, THING_ROOT_ID, THING_ROOT_VALUE, THING_ROOT_LIMIT diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index a14933cd8dc6..4b3e424d296c 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -3102,6 +3102,8 @@ ASTSerializer::functionBody(ParseNode *pn, TokenPos *pos, Value *dst) static JSBool reflect_parse(JSContext *cx, uint32_t argc, jsval *vp) { + cx->runtime->gcExactScanningEnabled = false; + if (argc < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, "Reflect.parse", "0", "s"); diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index d9ec9a499382..1f2badb92f53 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -542,6 +542,8 @@ JSObject::addPropertyInternal(JSContext *cx, jsid id, RootId idRoot(cx, &id); RootedVarObject self(cx, this); + RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + PropertyTable *table = NULL; if (!inDictionaryMode()) { bool stableSlot = @@ -650,6 +652,7 @@ JSObject::putProperty(JSContext *cx, jsid id, NormalizeGetterAndSetter(cx, this, id, attrs, flags, getter, setter); RootedVarObject self(cx, this); + RootGetterSetter gsRoot(cx, attrs, &getter, &setter); /* Search for id in order to claim its entry if table has been allocated. */ Shape **spp; @@ -861,21 +864,21 @@ JSObject::removeProperty(JSContext *cx, jsid id) * return deleted DictionaryShapes! See bug 595365. Do this before changing * the object or table, so the remaining removal is infallible. */ - Shape *spare = NULL; + RootedVarShape spare(cx); if (self->inDictionaryMode()) { spare = js_NewGCShape(cx); if (!spare) return false; new (spare) Shape(shape->base()->unowned(), 0); - if (shape == lastProperty()) { + if (shape == self->lastProperty()) { /* * Get an up to date unowned base shape for the new last property * when removing the dictionary's last property. Information in * base shapes for non-last properties may be out of sync with the * object's state. */ - Shape *previous = lastProperty()->parent; - StackBaseShape base(lastProperty()->base()); + RootedVarShape previous(cx, self->lastProperty()->parent); + StackBaseShape base(self->lastProperty()->base()); base.updateGetterSetter(previous->attrs, previous->getter(), previous->setter()); BaseShape *nbase = BaseShape::getUnowned(cx, base); if (!nbase) @@ -1041,31 +1044,31 @@ JSObject::shadowingShapeChange(JSContext *cx, const Shape &shape) bool JSObject::clearParent(JSContext *cx) { - return setParent(cx, NULL); + return setParent(cx, RootedVarObject(cx, this), RootedVarObject(cx)); } -bool -JSObject::setParent(JSContext *cx, JSObject *parent) +/* static */ bool +JSObject::setParent(JSContext *cx, HandleObject obj, HandleObject parent) { if (parent && !parent->setDelegate(cx)) return false; - if (inDictionaryMode()) { - StackBaseShape base(lastProperty()); + if (obj->inDictionaryMode()) { + StackBaseShape base(obj->lastProperty()); base.parent = parent; UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base); if (!nbase) return false; - lastProperty()->base()->adoptUnowned(nbase); + obj->lastProperty()->base()->adoptUnowned(nbase); return true; } - Shape *newShape = Shape::setObjectParent(cx, parent, getProto(), shape_); + Shape *newShape = Shape::setObjectParent(cx, parent, obj->getProto(), obj->shape_); if (!newShape) return false; - shape_ = newShape; + obj->shape_ = newShape; return true; } diff --git a/js/src/jsscope.h b/js/src/jsscope.h index 66211f19143a..2ce4e2d288e3 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -897,6 +897,21 @@ struct Shape : public js::gc::Cell } }; +class RootGetterSetter +{ + mozilla::Maybe getterRoot; + mozilla::Maybe setterRoot; + + public: + RootGetterSetter(JSContext *cx, uint8_t attrs, PropertyOp *pgetter, StrictPropertyOp *psetter) + { + if (attrs & JSPROP_GETTER) + getterRoot.construct(cx, (JSObject **) pgetter); + if (attrs & JSPROP_SETTER) + setterRoot.construct(cx, (JSObject **) psetter); + } +}; + struct EmptyShape : public js::Shape { EmptyShape(UnownedBaseShape *base, uint32_t nfixed); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index d3cd66df9c9b..01f84261d947 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -145,7 +145,7 @@ Bindings::add(JSContext *cx, HandleAtom name, BindingKind kind) slot += nargs + nvars; } - jsid id; + RootedVarId id(cx); if (!name) { JS_ASSERT(kind == ARGUMENT); /* destructuring */ id = INT_TO_JSID(nargs); @@ -444,6 +444,8 @@ js::XDRScript(XDRState *xdr, JSScript **scriptp, JSScript *parentScript) JS_ASSERT(nvars != Bindings::BINDING_COUNT_LIMIT); Bindings bindings(cx); + Bindings::StackRoot bindingsRoot(cx, &bindings); + uint32_t nameCount = nargs + nvars; if (nameCount > 0) { LifoAllocScope las(&cx->tempLifoAlloc()); @@ -1282,7 +1284,7 @@ JSScript * JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce) { uint32_t mainLength, prologLength, nfixed; - JSScript *script; + RootedVar script(cx); const char *filename; JSFunction *fun; @@ -2046,11 +2048,13 @@ JSScript::setNeedsArgsObj(bool needsArgsObj) needsArgsObj_ = needsArgsObj; } -bool -JSScript::applySpeculationFailed(JSContext *cx) +/* static */ bool +JSScript::applySpeculationFailed(JSContext *cx, JSScript *script_) { - JS_ASSERT(analyzedArgsUsage()); - JS_ASSERT(argumentsHasLocalBinding()); + RootedVar script(cx, script_); + + JS_ASSERT(script->analyzedArgsUsage()); + JS_ASSERT(script->argumentsHasLocalBinding()); /* * It is possible that the apply speculation has already failed, everything @@ -2058,12 +2062,12 @@ JSScript::applySpeculationFailed(JSContext *cx) * stack that has just now flowed into an apply. In this case, there is * nothing to do; GuardFunApplySpeculation will patch in the real argsobj. */ - if (needsArgsObj()) + if (script->needsArgsObj()) return true; - needsArgsObj_ = true; + script->needsArgsObj_ = true; - const unsigned slot = argumentsLocalSlot(); + const unsigned slot = script->argumentsLocalSlot(); /* * By design, the apply-arguments optimization is only made when there @@ -2079,7 +2083,7 @@ JSScript::applySpeculationFailed(JSContext *cx) */ for (AllFramesIter i(cx->stack.space()); !i.done(); ++i) { StackFrame *fp = i.fp(); - if (fp->isFunctionFrame() && fp->script() == this) { + if (fp->isFunctionFrame() && fp->script() == script) { if (!fp->hasArgsObj()) { ArgumentsObject *obj = ArgumentsObject::create(cx, fp); if (!obj) { @@ -2088,7 +2092,7 @@ JSScript::applySpeculationFailed(JSContext *cx) * and !fp->hasArgsObj. It is, however, safe to leave frames * where fp->hasArgsObj and !fp->script->needsArgsObj. */ - needsArgsObj_ = false; + script->needsArgsObj_ = false; return false; } @@ -2100,15 +2104,15 @@ JSScript::applySpeculationFailed(JSContext *cx) } #ifdef JS_METHODJIT - if (hasJITCode()) { - mjit::Recompiler::clearStackReferences(cx->runtime->defaultFreeOp(), this); - mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), this); + if (script->hasJITCode()) { + mjit::Recompiler::clearStackReferences(cx->runtime->defaultFreeOp(), script); + mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), script); } #endif - if (hasAnalysis() && analysis()->ranInference()) { + if (script->hasAnalysis() && script->analysis()->ranInference()) { types::AutoEnterTypeInference enter(cx); - types::TypeScript::MonitorUnknown(cx, this, argumentsBytecode()); + types::TypeScript::MonitorUnknown(cx, script, script->argumentsBytecode()); } return true; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 7645395d002f..5499bf298bdc 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -604,7 +604,7 @@ struct JSScript : public js::gc::Cell bool analyzedArgsUsage() const { return !needsArgsAnalysis_; } bool needsArgsObj() const { JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; } void setNeedsArgsObj(bool needsArgsObj); - bool applySpeculationFailed(JSContext *cx); + static bool applySpeculationFailed(JSContext *cx, JSScript *script); /* Hash table chaining for JSCompartment::evalCache. */ JSScript *&evalHashLink() { return *globalObject.unsafeGetUnioned(); } diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 202b972c04d9..de8d7c735bf5 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -402,9 +402,10 @@ JSSubString js_EmptySubString = {0, js_empty_ucstr}; static const unsigned STRING_ELEMENT_ATTRS = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT; static JSBool -str_enumerate(JSContext *cx, JSObject *obj) +str_enumerate(JSContext *cx, JSObject *obj_) { - JSString *str = obj->asString().unbox(); + RootedVarObject obj(cx, obj_); + RootedVarString str(cx, obj->asString().unbox()); for (size_t i = 0, length = str->length(); i < length; i++) { JSString *str1 = js_NewDependentString(cx, str, i, 1); if (!str1) @@ -420,12 +421,14 @@ str_enumerate(JSContext *cx, JSObject *obj) } static JSBool -str_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, +str_resolve(JSContext *cx, JSObject *obj_, jsid id, unsigned flags, JSObject **objp) { if (!JSID_IS_INT(id)) return JS_TRUE; + RootedVarObject obj(cx, obj_); + JSString *str = obj->asString().unbox(); int32_t slot = JSID_TO_INT(id); @@ -1338,7 +1341,7 @@ str_trimRight(JSContext *cx, unsigned argc, Value *vp) /* Result of a successfully performed flat match. */ class FlatMatch { - JSAtom *patstr; + RootedVarAtom patstr; const jschar *pat; size_t patlen; int32_t match_; @@ -1346,7 +1349,7 @@ class FlatMatch friend class StringRegExpGuard; public: - FlatMatch() : patstr(NULL) {} /* Old GCC wants this initialization. */ + FlatMatch(JSContext *cx) : patstr(cx) {} JSLinearString *pattern() const { return patstr; } size_t patternLength() const { return patlen; } @@ -1424,7 +1427,7 @@ class StringRegExpGuard } public: - StringRegExpGuard() {} + StringRegExpGuard(JSContext *cx) : fm(cx) {} /* init must succeed in order to call tryFlatMatch or normalizeRegExp. */ bool init(JSContext *cx, CallArgs args, bool convertVoid = false) @@ -1590,7 +1593,7 @@ DoMatch(JSContext *cx, RegExpStatics *res, JSString *str, RegExpShared &re, } static bool -BuildFlatMatchArray(JSContext *cx, JSString *textstr, const FlatMatch &fm, CallArgs *args) +BuildFlatMatchArray(JSContext *cx, HandleString textstr, const FlatMatch &fm, CallArgs *args) { if (fm.match() < 0) { args->rval() = NullValue(); @@ -1598,7 +1601,7 @@ BuildFlatMatchArray(JSContext *cx, JSString *textstr, const FlatMatch &fm, CallA } /* For this non-global match, produce a RegExp.exec-style array. */ - JSObject *obj = NewSlowEmptyArray(cx); + RootedVarObject obj(cx, NewSlowEmptyArray(cx)); if (!obj) return false; @@ -1639,11 +1642,11 @@ JSBool js::str_match(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - JSString *str = ThisToStringForStringProto(cx, args); + RootedVarString str(cx, ThisToStringForStringProto(cx, args)); if (!str) return false; - StringRegExpGuard g; + StringRegExpGuard g(cx); if (!g.init(cx, args, true)) return false; @@ -1675,11 +1678,11 @@ JSBool js::str_search(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - JSString *str = ThisToStringForStringProto(cx, args); + RootedVarString str(cx, ThisToStringForStringProto(cx, args)); if (!str) return false; - StringRegExpGuard g; + StringRegExpGuard g(cx); if (!g.init(cx, args, true)) return false; if (const FlatMatch *fm = g.tryFlatMatch(cx, str, 1, args.length())) { @@ -1717,7 +1720,8 @@ js::str_search(JSContext *cx, unsigned argc, Value *vp) struct ReplaceData { ReplaceData(JSContext *cx) - : str(cx), lambda(cx), elembase(cx), repstr(cx), sb(cx) + : str(cx), g(cx), lambda(cx), elembase(cx), repstr(cx), + dollarRoot(cx, &dollar), dollarEndRoot(cx, &dollarEnd), sb(cx) {} RootedVarString str; /* 'this' parameter object as a string */ @@ -1727,6 +1731,8 @@ struct ReplaceData RootedVar repstr; /* replacement string */ const jschar *dollar; /* null or pointer to first $ in repstr */ const jschar *dollarEnd; /* limit pointer for js_strchr_limit */ + SkipRoot dollarRoot; /* XXX prevent dollar from being relocated */ + SkipRoot dollarEndRoot; /* ditto */ int leftIndex; /* left context index in str->chars */ JSSubString dollarStr; /* for "$$" InterpretDollar result */ bool calledBack; /* record whether callback has been called */ @@ -1844,7 +1850,7 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t } if (JSObject *lambda = rdata.lambda) { - PreserveRegExpStatics staticsGuard(res); + PreserveRegExpStatics staticsGuard(cx, res); if (!staticsGuard.init(cx)) return false; @@ -1988,7 +1994,7 @@ BuildFlatReplacement(JSContext *cx, HandleString textstr, HandleString repstr, return false; size_t pos = 0; while (!r.empty()) { - JSString *str = r.front(); + RootedVarString str(cx, r.front()); size_t len = str->length(); size_t strEnd = pos + len; if (pos < matchEnd && strEnd > match) { @@ -2061,7 +2067,7 @@ static inline bool BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *repstr, const jschar *firstDollar, const FlatMatch &fm, CallArgs *args) { - JSLinearString *textstr = textstrArg->ensureLinear(cx); + RootedVar textstr(cx, textstrArg->ensureLinear(cx)); if (!textstr) return NULL; @@ -2589,7 +2595,7 @@ js::str_split(JSContext *cx, unsigned argc, Value *vp) CallArgs args = CallArgsFromVp(argc, vp); /* Steps 1-2. */ - JSString *str = ThisToStringForStringProto(cx, args); + RootedVarString str(cx, ThisToStringForStringProto(cx, args)); if (!str) return false; diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index a1639f3048b1..fb26c163beb4 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -270,7 +270,7 @@ ArrayBufferObject::allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents } static JSObject * -DelegateObject(JSContext *cx, JSObject *obj) +DelegateObject(JSContext *cx, HandleObject obj) { if (!obj->getPrivate()) { JSObject *delegate = NewObjectWithGivenProto(cx, &ObjectClass, obj->getProto(), NULL); @@ -283,7 +283,9 @@ DelegateObject(JSContext *cx, JSObject *obj) JSObject * ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, uint8_t *contents) { - JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBufferObject::protoClass); + SkipRoot skip(cx, &contents); + + RootedVarObject obj(cx, NewBuiltinClassInstance(cx, &ArrayBufferObject::protoClass)); if (!obj) return NULL; #ifdef JS_THREADSAFE @@ -343,16 +345,19 @@ ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj) static JSProperty * const PROPERTY_FOUND = reinterpret_cast(1); JSBool -ArrayBufferObject::obj_lookupGeneric(JSContext *cx, JSObject *obj, jsid id, +ArrayBufferObject::obj_lookupGeneric(JSContext *cx, JSObject *obj_, jsid id_, JSObject **objp, JSProperty **propp) { + RootedVarObject obj(cx, obj_); + RootedVarId id(cx, id_); + if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) { *propp = PROPERTY_FOUND; *objp = getArrayBuffer(obj); return true; } - JSObject *delegate = DelegateObject(cx, obj); + RootedVarObject delegate(cx, DelegateObject(cx, obj)); if (!delegate) return false; @@ -390,10 +395,12 @@ ArrayBufferObject::obj_lookupProperty(JSContext *cx, JSObject *obj, PropertyName } JSBool -ArrayBufferObject::obj_lookupElement(JSContext *cx, JSObject *obj, uint32_t index, +ArrayBufferObject::obj_lookupElement(JSContext *cx, JSObject *obj_, uint32_t index, JSObject **objp, JSProperty **propp) { - JSObject *delegate = DelegateObject(cx, obj); + RootedVarObject obj(cx, obj_); + + RootedVarObject delegate(cx, DelegateObject(cx, obj)); if (!delegate) return false; @@ -428,12 +435,16 @@ ArrayBufferObject::obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid } JSBool -ArrayBufferObject::obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v, +ArrayBufferObject::obj_defineGeneric(JSContext *cx, JSObject *obj_, jsid id_, const Value *v, PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { - if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) + if (JSID_IS_ATOM(id_, cx->runtime->atomState.byteLengthAtom)) return true; + RootedVarObject obj(cx, obj_); + RootedVarId id(cx, id_); + RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + JSObject *delegate = DelegateObject(cx, obj); if (!delegate) return false; @@ -449,9 +460,12 @@ ArrayBufferObject::obj_defineProperty(JSContext *cx, JSObject *obj, } JSBool -ArrayBufferObject::obj_defineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *v, +ArrayBufferObject::obj_defineElement(JSContext *cx, JSObject *obj_, uint32_t index, const Value *v, PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { + RootedVarObject obj(cx, obj_); + RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + JSObject *delegate = DelegateObject(cx, obj); if (!delegate) return false; @@ -466,8 +480,11 @@ ArrayBufferObject::obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid } JSBool -ArrayBufferObject::obj_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp) +ArrayBufferObject::obj_getGeneric(JSContext *cx, JSObject *obj_, JSObject *receiver_, jsid id_, Value *vp) { + RootedVarObject obj(cx, obj_), receiver(cx, receiver_); + RootedVarId id(cx, id_); + obj = getArrayBuffer(obj); JS_ASSERT(obj); if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) { @@ -478,13 +495,16 @@ ArrayBufferObject::obj_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiv RootedVarObject delegate(cx, DelegateObject(cx, obj)); if (!delegate) return false; - return js_GetProperty(cx, delegate, RootedVarObject(cx, receiver), id, vp); + return js_GetProperty(cx, delegate, receiver, id, vp); } JSBool -ArrayBufferObject::obj_getProperty(JSContext *cx, JSObject *obj, - JSObject *receiver, PropertyName *name, Value *vp) +ArrayBufferObject::obj_getProperty(JSContext *cx, JSObject *obj_, + JSObject *receiver_, PropertyName *name_, Value *vp) { + RootedVarObject obj(cx, obj_), receiver(cx, receiver_); + RootedVarPropertyName name(cx, name_); + obj = getArrayBuffer(obj); if (name == cx->runtime->atomState.byteLengthAtom) { vp->setInt32(obj->asArrayBuffer().byteLength()); @@ -494,24 +514,28 @@ ArrayBufferObject::obj_getProperty(JSContext *cx, JSObject *obj, RootedVarObject delegate(cx, DelegateObject(cx, obj)); if (!delegate) return false; - return js_GetProperty(cx, delegate, RootedVarObject(cx, receiver), ATOM_TO_JSID(name), vp); + return js_GetProperty(cx, delegate, receiver, ATOM_TO_JSID(name), vp); } JSBool ArrayBufferObject::obj_getElement(JSContext *cx, JSObject *obj, - JSObject *receiver, uint32_t index, Value *vp) + JSObject *receiver_, uint32_t index, Value *vp) { - RootedVarObject delegate(cx, DelegateObject(cx, getArrayBuffer(obj))); + RootedVarObject receiver(cx, receiver_); + + RootedVarObject delegate(cx, DelegateObject(cx, RootedVarObject(cx, getArrayBuffer(obj)))); if (!delegate) return false; - return js_GetElement(cx, delegate, RootedVarObject(cx, receiver), index, vp); + return js_GetElement(cx, delegate, receiver, index, vp); } JSBool -ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver, +ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver_, uint32_t index, Value *vp, bool *present) { - JSObject *delegate = DelegateObject(cx, getArrayBuffer(obj)); + RootedVarObject receiver(cx, receiver_); + + JSObject *delegate = DelegateObject(cx, RootedVarObject(cx, getArrayBuffer(obj))); if (!delegate) return false; return delegate->getElementIfPresent(cx, receiver, index, vp, present); @@ -525,8 +549,11 @@ ArrayBufferObject::obj_getSpecial(JSContext *cx, JSObject *obj, } JSBool -ArrayBufferObject::obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) +ArrayBufferObject::obj_setGeneric(JSContext *cx, JSObject *obj_, jsid id_, Value *vp, JSBool strict) { + RootedVarObject obj(cx, obj_); + RootedVarId id(cx, id_); + if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) return true; @@ -554,7 +581,7 @@ ArrayBufferObject::obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value * // since obj_getProperty will fetch it as a plain // property from the delegate. - JSObject *oldDelegateProto = delegate->getProto(); + RootedVarObject oldDelegateProto(cx, delegate->getProto()); if (!js_SetPropertyHelper(cx, delegate, id, 0, vp, strict)) return false; @@ -566,7 +593,7 @@ ArrayBufferObject::obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value * obj->reportNotExtensible(cx); return false; } - if (!SetProto(cx, obj, vp->toObjectOrNull(), true)) { + if (!SetProto(cx, obj, RootedVarObject(cx, vp->toObjectOrNull()), true)) { // this can be caused for example by setting x.__proto__ = x // restore delegate prototype chain SetProto(cx, delegate, oldDelegateProto, true); @@ -587,9 +614,11 @@ ArrayBufferObject::obj_setProperty(JSContext *cx, JSObject *obj, } JSBool -ArrayBufferObject::obj_setElement(JSContext *cx, JSObject *obj, +ArrayBufferObject::obj_setElement(JSContext *cx, JSObject *obj_, uint32_t index, Value *vp, JSBool strict) { + RootedVarObject obj(cx, obj_); + RootedVarObject delegate(cx, DelegateObject(cx, obj)); if (!delegate) return false; @@ -605,9 +634,12 @@ ArrayBufferObject::obj_setSpecial(JSContext *cx, JSObject *obj, } JSBool -ArrayBufferObject::obj_getGenericAttributes(JSContext *cx, JSObject *obj, - jsid id, unsigned *attrsp) +ArrayBufferObject::obj_getGenericAttributes(JSContext *cx, JSObject *obj_, + jsid id_, unsigned *attrsp) { + RootedVarObject obj(cx, obj_); + RootedVarId id(cx, id_); + if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) { *attrsp = JSPROP_PERMANENT | JSPROP_READONLY; return true; @@ -627,9 +659,11 @@ ArrayBufferObject::obj_getPropertyAttributes(JSContext *cx, JSObject *obj, } JSBool -ArrayBufferObject::obj_getElementAttributes(JSContext *cx, JSObject *obj, +ArrayBufferObject::obj_getElementAttributes(JSContext *cx, JSObject *obj_, uint32_t index, unsigned *attrsp) { + RootedVarObject obj(cx, obj_); + JSObject *delegate = DelegateObject(cx, obj); if (!delegate) return false; @@ -644,9 +678,12 @@ ArrayBufferObject::obj_getSpecialAttributes(JSContext *cx, JSObject *obj, } JSBool -ArrayBufferObject::obj_setGenericAttributes(JSContext *cx, JSObject *obj, - jsid id, unsigned *attrsp) +ArrayBufferObject::obj_setGenericAttributes(JSContext *cx, JSObject *obj_, + jsid id_, unsigned *attrsp) { + RootedVarObject obj(cx, obj_); + RootedVarId id(cx, id_); + if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS); @@ -667,9 +704,11 @@ ArrayBufferObject::obj_setPropertyAttributes(JSContext *cx, JSObject *obj, } JSBool -ArrayBufferObject::obj_setElementAttributes(JSContext *cx, JSObject *obj, +ArrayBufferObject::obj_setElementAttributes(JSContext *cx, JSObject *obj_, uint32_t index, unsigned *attrsp) { + RootedVarObject obj(cx, obj_); + JSObject *delegate = DelegateObject(cx, obj); if (!delegate) return false; @@ -684,9 +723,12 @@ ArrayBufferObject::obj_setSpecialAttributes(JSContext *cx, JSObject *obj, } JSBool -ArrayBufferObject::obj_deleteProperty(JSContext *cx, JSObject *obj, - PropertyName *name, Value *rval, JSBool strict) +ArrayBufferObject::obj_deleteProperty(JSContext *cx, JSObject *obj_, + PropertyName *name_, Value *rval, JSBool strict) { + RootedVarObject obj(cx, obj_); + RootedVarPropertyName name(cx, name_); + if (name == cx->runtime->atomState.byteLengthAtom) { rval->setBoolean(false); return true; @@ -699,9 +741,11 @@ ArrayBufferObject::obj_deleteProperty(JSContext *cx, JSObject *obj, } JSBool -ArrayBufferObject::obj_deleteElement(JSContext *cx, JSObject *obj, +ArrayBufferObject::obj_deleteElement(JSContext *cx, JSObject *obj_, uint32_t index, Value *rval, JSBool strict) { + RootedVarObject obj(cx, obj_); + JSObject *delegate = DelegateObject(cx, obj); if (!delegate) return false; @@ -709,9 +753,12 @@ ArrayBufferObject::obj_deleteElement(JSContext *cx, JSObject *obj, } JSBool -ArrayBufferObject::obj_deleteSpecial(JSContext *cx, JSObject *obj, - SpecialId sid, Value *rval, JSBool strict) +ArrayBufferObject::obj_deleteSpecial(JSContext *cx, JSObject *obj_, + SpecialId sid_, Value *rval, JSBool strict) { + RootedVarObject obj(cx, obj_); + RootedVar sid(cx, sid_); + JSObject *delegate = DelegateObject(cx, obj); if (!delegate) return false; @@ -1149,7 +1196,7 @@ class TypedArrayTemplate } static bool - setElementTail(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp, JSBool strict) + setElementTail(JSContext *cx, HandleObject tarray, uint32_t index, Value *vp, JSBool strict) { JS_ASSERT(tarray); JS_ASSERT(index < getLength(tarray)); @@ -1205,7 +1252,7 @@ class TypedArrayTemplate static JSBool obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) { - JSObject *tarray = getTypedArray(obj); + RootedVarObject tarray(cx, getTypedArray(obj)); JS_ASSERT(tarray); if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { @@ -1237,7 +1284,7 @@ class TypedArrayTemplate static JSBool obj_setElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict) { - JSObject *tarray = getTypedArray(obj); + RootedVarObject tarray(cx, getTypedArray(obj)); JS_ASSERT(tarray); if (index >= getLength(tarray)) { @@ -1382,9 +1429,9 @@ class TypedArrayTemplate } static JSObject * - createTypedArray(JSContext *cx, JSObject *bufobj, uint32_t byteOffset, uint32_t len) + createTypedArray(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len) { - JSObject *obj = NewBuiltinClassInstance(cx, protoClass()); + RootedVarObject obj(cx, NewBuiltinClassInstance(cx, protoClass())); if (!obj) return NULL; #ifdef JS_THREADSAFE @@ -1466,7 +1513,7 @@ class TypedArrayTemplate /* () or (number) */ uint32_t len = 0; if (argc == 0 || ValueIsLength(cx, argv[0], &len)) { - JSObject *bufobj = createBufferWithSizeAndCount(cx, len); + RootedVarObject bufobj(cx, createBufferWithSizeAndCount(cx, len)); if (!bufobj) return NULL; @@ -1480,7 +1527,7 @@ class TypedArrayTemplate return NULL; } - JSObject *dataObj = &argv[0].toObject(); + RootedVarObject dataObj(cx, &argv[0].toObject()); /* (typedArray) */ if (dataObj->isTypedArray()) { @@ -1488,7 +1535,7 @@ class TypedArrayTemplate JS_ASSERT(otherTypedArray); uint32_t len = getLength(otherTypedArray); - JSObject *bufobj = createBufferWithSizeAndCount(cx, len); + RootedVarObject bufobj(cx, createBufferWithSizeAndCount(cx, len)); if (!bufobj) return NULL; @@ -1572,11 +1619,11 @@ class TypedArrayTemplate CallArgs args = CallArgsFromVp(argc, vp); bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_set, fastClass(), &ok); + RootedVarObject obj(cx, NonGenericMethodGuard(cx, args, fun_set, fastClass(), &ok)); if (!obj) return ok; - JSObject *tarray = getTypedArray(obj); + RootedVarObject tarray(cx, getTypedArray(obj)); if (!tarray) return true; @@ -1604,7 +1651,7 @@ class TypedArrayTemplate return false; } - JSObject *arg0 = args[0].toObjectOrNull(); + RootedVarObject arg0(cx, args[0].toObjectOrNull()); if (arg0->isTypedArray()) { JSObject *src = TypedArray::getTypedArray(arg0); if (!src || @@ -1639,7 +1686,7 @@ class TypedArrayTemplate public: static JSObject * - createTypedArrayWithBuffer(JSContext *cx, JSObject *bufobj, + createTypedArrayWithBuffer(JSContext *cx, HandleObject bufobj, int32_t byteOffsetInt, int32_t lengthInt) { uint32_t boffset = (byteOffsetInt == -1) ? 0 : uint32_t(byteOffsetInt); @@ -1678,17 +1725,17 @@ class TypedArrayTemplate } static JSObject * - createTypedArrayFromArray(JSContext *cx, JSObject *other) + createTypedArrayFromArray(JSContext *cx, HandleObject other) { uint32_t len; if (!js_GetLengthProperty(cx, other, &len)) return NULL; - JSObject *bufobj = createBufferWithSizeAndCount(cx, len); + RootedVarObject bufobj(cx, createBufferWithSizeAndCount(cx, len)); if (!bufobj) return NULL; - JSObject *obj = createTypedArray(cx, bufobj, 0, len); + RootedVarObject obj(cx, createTypedArray(cx, bufobj, 0, len)); if (!obj || !copyFromArray(cx, obj, other, len)) return NULL; return obj; @@ -1698,7 +1745,7 @@ class TypedArrayTemplate * Note: the offset and length arguments are ignored if an array is passed in. */ static JSObject * - createTypedArrayWithOffsetLength(JSContext *cx, JSObject *other, + createTypedArrayWithOffsetLength(JSContext *cx, HandleObject other, int32_t byteOffsetInt, int32_t lengthInt) { JS_ASSERT(!other->isTypedArray()); @@ -1737,7 +1784,7 @@ class TypedArrayTemplate JS_ASSERT(begin <= getLength(tarray)); JS_ASSERT(end <= getLength(tarray)); - JSObject *bufobj = getBuffer(tarray); + RootedVarObject bufobj(cx, getBuffer(tarray)); JS_ASSERT(bufobj); JS_ASSERT(begin <= end); @@ -1789,7 +1836,7 @@ class TypedArrayTemplate static bool copyFromArray(JSContext *cx, JSObject *thisTypedArrayObj, - JSObject *ar, uint32_t len, uint32_t offset = 0) + HandleObject ar, uint32_t len, uint32_t offset = 0) { thisTypedArrayObj = getTypedArray(thisTypedArrayObj); JS_ASSERT(thisTypedArrayObj); @@ -1797,6 +1844,7 @@ class TypedArrayTemplate JS_ASSERT(offset <= getLength(thisTypedArrayObj)); JS_ASSERT(len <= getLength(thisTypedArrayObj) - offset); NativeType *dest = static_cast(getDataOffset(thisTypedArrayObj)) + offset; + SkipRoot skip(cx, &dest); if (ar->isDenseArray() && ar->getDenseArrayInitializedLength() >= len) { JS_ASSERT(ar->getArrayLength() == len); @@ -2248,7 +2296,7 @@ template static inline JSObject * NewArray(JSContext *cx, uint32_t nelements) { - JSObject *buffer = TypedArrayTemplate::createBufferWithSizeAndCount(cx, nelements); + RootedVarObject buffer(cx, TypedArrayTemplate::createBufferWithSizeAndCount(cx, nelements)); if (!buffer) return NULL; return TypedArrayTemplate::createTypedArray(cx, buffer, 0, nelements); @@ -2256,7 +2304,7 @@ NewArray(JSContext *cx, uint32_t nelements) template static inline JSObject * -NewArrayWithBuffer(JSContext *cx, JSObject *arrayBuffer, int32_t byteoffset, int32_t intLength) +NewArrayWithBuffer(JSContext *cx, HandleObject arrayBuffer, int32_t byteoffset, int32_t intLength) { if (!arrayBuffer->isArrayBuffer()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS); @@ -2275,13 +2323,13 @@ NewArrayWithBuffer(JSContext *cx, JSObject *arrayBuffer, int32_t byteoffset, int } \ JS_FRIEND_API(JSObject *) JS_New ## Name ## ArrayFromArray(JSContext *cx, JSObject *other) \ { \ - return TypedArrayTemplate::createTypedArrayFromArray(cx, other); \ + return TypedArrayTemplate::createTypedArrayFromArray(cx, RootedVarObject(cx, other)); \ } \ JS_FRIEND_API(JSObject *) JS_New ## Name ## ArrayWithBuffer(JSContext *cx, \ JSObject *arrayBuffer, uint32_t byteoffset, int32_t length) \ { \ MOZ_ASSERT(byteoffset <= INT32_MAX); \ - return NewArrayWithBuffer(cx, arrayBuffer, byteoffset, length); \ + return NewArrayWithBuffer(cx, RootedVarObject(cx, arrayBuffer), byteoffset, length); \ } \ JS_FRIEND_API(JSBool) JS_Is ## Name ## Array(JSObject *obj, JSContext *cx) \ { \ @@ -2381,15 +2429,15 @@ IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double) template static inline JSObject * -InitTypedArrayClass(JSContext *cx, GlobalObject *global) +InitTypedArrayClass(JSContext *cx, Handle global) { - JSObject *proto = global->createBlankPrototype(cx, ArrayType::protoClass()); + RootedVarObject proto(cx, global->createBlankPrototype(cx, ArrayType::protoClass())); if (!proto) return NULL; - JSFunction *ctor = - global->createConstructor(cx, ArrayType::class_constructor, - cx->runtime->atomState.classAtoms[ArrayType::key], 3); + RootedVarFunction ctor(cx); + ctor = global->createConstructor(cx, ArrayType::class_constructor, + cx->runtime->atomState.classAtoms[ArrayType::key], 3); if (!ctor) return NULL; @@ -2452,15 +2500,15 @@ Class TypedArray::protoClasses[TYPE_MAX] = { }; static JSObject * -InitArrayBufferClass(JSContext *cx, GlobalObject *global) +InitArrayBufferClass(JSContext *cx, Handle global) { - JSObject *arrayBufferProto = global->createBlankPrototype(cx, &ArrayBufferObject::protoClass); + RootedVarObject arrayBufferProto(cx, global->createBlankPrototype(cx, &ArrayBufferObject::protoClass)); if (!arrayBufferProto) return NULL; - JSFunction *ctor = - global->createConstructor(cx, ArrayBufferObject::class_constructor, - CLASS_ATOM(cx, ArrayBuffer), 1); + RootedVarFunction ctor(cx); + ctor = global->createConstructor(cx, ArrayBufferObject::class_constructor, + CLASS_ATOM(cx, ArrayBuffer), 1); if (!ctor) return NULL; @@ -2481,7 +2529,7 @@ js_InitTypedArrayClasses(JSContext *cx, JSObject *obj) { JS_ASSERT(obj->isNative()); - GlobalObject *global = &obj->asGlobal(); + RootedVar global(cx, &obj->asGlobal()); /* Idempotency required: we initialize several things, possibly lazily. */ JSObject *stop; diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index d0f592ce69cf..07fff3279e6f 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -56,18 +56,19 @@ class AutoEntryHolder { Map ↦ Map::Ptr p; uint32_t gen; - WatchKey key; + RootedVarObject obj; + RootedVarId id; public: - AutoEntryHolder(Map &map, Map::Ptr p) - : map(map), p(p), gen(map.generation()), key(p->key) { + AutoEntryHolder(JSContext *cx, Map &map, Map::Ptr p) + : map(map), p(p), gen(map.generation()), obj(cx, p->key.object), id(cx, p->key.id) { JS_ASSERT(!p->value.held); p->value.held = true; } ~AutoEntryHolder() { if (gen != map.generation()) - p = map.lookup(key); + p = map.lookup(WatchKey(obj, id)); if (p) p->value.held = false; } @@ -80,10 +81,10 @@ WatchpointMap::init() } bool -WatchpointMap::watch(JSContext *cx, JSObject *obj, jsid id, - JSWatchPointHandler handler, JSObject *closure) +WatchpointMap::watch(JSContext *cx, HandleObject obj, HandleId id, + JSWatchPointHandler handler, HandleObject closure) { - JS_ASSERT(id == js_CheckForStringIndex(id)); + JS_ASSERT(id.value() == js_CheckForStringIndex(id)); JS_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id)); if (!obj->setWatched(cx)) @@ -131,18 +132,18 @@ WatchpointMap::clear() } bool -WatchpointMap::triggerWatchpoint(JSContext *cx, JSObject *obj, jsid id, Value *vp) +WatchpointMap::triggerWatchpoint(JSContext *cx, HandleObject obj, HandleId id, Value *vp) { - JS_ASSERT(id == js_CheckForStringIndex(id)); + JS_ASSERT(id.value() == js_CheckForStringIndex(id)); Map::Ptr p = map.lookup(WatchKey(obj, id)); if (!p || p->value.held) return true; - AutoEntryHolder holder(map, p); + AutoEntryHolder holder(cx, map, p); /* Copy the entry, since GC would invalidate p. */ JSWatchPointHandler handler = p->value.handler; - JSObject *closure = p->value.closure; + RootedVarObject closure(cx, p->value.closure); /* Determine the property's old value. */ Value old; diff --git a/js/src/jswatchpoint.h b/js/src/jswatchpoint.h index 7e4f7402ae99..b08732a6ba44 100644 --- a/js/src/jswatchpoint.h +++ b/js/src/jswatchpoint.h @@ -79,14 +79,14 @@ class WatchpointMap { typedef HashMap, SystemAllocPolicy> Map; bool init(); - bool watch(JSContext *cx, JSObject *obj, jsid id, - JSWatchPointHandler handler, JSObject *closure); + bool watch(JSContext *cx, HandleObject obj, HandleId id, + JSWatchPointHandler handler, HandleObject closure); void unwatch(JSObject *obj, jsid id, JSWatchPointHandler *handlerp, JSObject **closurep); void unwatchObject(JSObject *obj); void clear(); - bool triggerWatchpoint(JSContext *cx, JSObject *obj, jsid id, Value *vp); + bool triggerWatchpoint(JSContext *cx, HandleObject obj, HandleId id, Value *vp); static bool markAllIteratively(JSTracer *trc); bool markIteratively(JSTracer *trc); diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index a0396b16ace2..2d5e0b7f4fb6 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -392,14 +392,15 @@ js_InitWeakMapClass(JSContext *cx, JSObject *obj) { JS_ASSERT(obj->isNative()); - GlobalObject *global = &obj->asGlobal(); + RootedVar global(cx, &obj->asGlobal()); - JSObject *weakMapProto = global->createBlankPrototype(cx, &WeakMapClass); + RootedVarObject weakMapProto(cx, global->createBlankPrototype(cx, &WeakMapClass)); if (!weakMapProto) return NULL; - JSFunction *ctor = global->createConstructor(cx, WeakMap_construct, - CLASS_ATOM(cx, WeakMap), 0); + RootedVarFunction ctor(cx); + ctor = global->createConstructor(cx, WeakMap_construct, + CLASS_ATOM(cx, WeakMap), 0); if (!ctor) return NULL; diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index ea19ca8f6872..eb3de60fad7c 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -521,7 +521,7 @@ ErrorCopier::~ErrorCopier() if (exc.isObject() && exc.toObject().isError() && exc.toObject().getPrivate()) { cx->clearPendingException(); ac.leave(); - JSObject *copyobj = js_CopyErrorObject(cx, &exc.toObject(), scope); + JSObject *copyobj = js_CopyErrorObject(cx, RootedVarObject(cx, &exc.toObject()), scope); if (copyobj) cx->setPendingException(ObjectValue(*copyobj)); } @@ -636,15 +636,17 @@ CrossCompartmentWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receive } bool -CrossCompartmentWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, +CrossCompartmentWrapper::set(JSContext *cx, JSObject *wrapper_, JSObject *receiver_, jsid id_, bool strict, Value *vp) { - AutoValueRooter tvr(cx, *vp); + RootedVarObject wrapper(cx, wrapper_), receiver(cx, receiver_); + RootedVarId id(cx, id_); + RootedVarValue value(cx, *vp); PIERCE(cx, wrapper, SET, - call.destination->wrap(cx, &receiver) && - call.destination->wrapId(cx, &id) && - call.destination->wrap(cx, tvr.addr()), - Wrapper::set(cx, wrapper, receiver, id, strict, tvr.addr()), + call.destination->wrap(cx, receiver.address()) && + call.destination->wrapId(cx, id.address()) && + call.destination->wrap(cx, value.address()), + Wrapper::set(cx, wrapper, receiver, id, strict, value.address()), NOTHING); } @@ -737,8 +739,10 @@ CrossCompartmentWrapper::iterate(JSContext *cx, JSObject *wrapper, unsigned flag } bool -CrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper, unsigned argc, Value *vp) +CrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper_, unsigned argc, Value *vp) { + RootedVarObject wrapper(cx, wrapper_); + AutoCompartment call(cx, wrappedObject(wrapper)); if (!call.enter()) return false; @@ -759,9 +763,11 @@ CrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper, unsigned argc, V } bool -CrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper, unsigned argc, Value *argv, +CrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper_, unsigned argc, Value *argv, Value *rval) { + RootedVarObject wrapper(cx, wrapper_); + AutoCompartment call(cx, wrappedObject(wrapper)); if (!call.enter()) return false; diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index b3343fa1bf97..d949ea5d5f85 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -4772,7 +4772,7 @@ xml_lookupGeneric(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, JSProp *propp = NULL; } else { const Shape *shape = - js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, + js_AddNativeProperty(cx, RootedVarObject(cx, obj), id, GetProperty, PutProperty, SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, 0, 0); if (!shape) @@ -4807,7 +4807,7 @@ xml_lookupElement(JSContext *cx, JSObject *obj, uint32_t index, JSObject **objp, return false; const Shape *shape = - js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, + js_AddNativeProperty(cx, RootedVarObject(cx, obj), id, GetProperty, PutProperty, SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, 0, 0); if (!shape) @@ -7259,6 +7259,8 @@ uint32_t xml_serial; JSXML * js_NewXML(JSContext *cx, JSXMLClass xml_class) { + cx->runtime->gcExactScanningEnabled = false; + JSXML *xml = js_NewGCXML(cx); if (!xml) return NULL; @@ -7391,8 +7393,9 @@ js_GetXMLObject(JSContext *cx, JSXML *xml) JSObject * js_InitNamespaceClass(JSContext *cx, JSObject *obj) { - JS_ASSERT(obj->isNative()); + cx->runtime->gcExactScanningEnabled = false; + JS_ASSERT(obj->isNative()); GlobalObject *global = &obj->asGlobal(); JSObject *namespaceProto = global->createBlankPrototype(cx, &NamespaceClass); @@ -7423,8 +7426,9 @@ js_InitNamespaceClass(JSContext *cx, JSObject *obj) JSObject * js_InitQNameClass(JSContext *cx, JSObject *obj) { - JS_ASSERT(obj->isNative()); + cx->runtime->gcExactScanningEnabled = false; + JS_ASSERT(obj->isNative()); GlobalObject *global = &obj->asGlobal(); JSObject *qnameProto = global->createBlankPrototype(cx, &QNameClass); @@ -7455,8 +7459,9 @@ js_InitQNameClass(JSContext *cx, JSObject *obj) JSObject * js_InitXMLClass(JSContext *cx, JSObject *obj) { - JS_ASSERT(obj->isNative()); + cx->runtime->gcExactScanningEnabled = false; + JS_ASSERT(obj->isNative()); GlobalObject *global = &obj->asGlobal(); JSObject *xmlProto = global->createBlankPrototype(cx, &XMLClass); diff --git a/js/src/methodjit/MonoIC.cpp b/js/src/methodjit/MonoIC.cpp index 728e285eeef7..07f22ac38ad2 100644 --- a/js/src/methodjit/MonoIC.cpp +++ b/js/src/methodjit/MonoIC.cpp @@ -1118,7 +1118,7 @@ ic::SplatApplyArgs(VMFrame &f) } /* Steps 4-5. */ - JSObject *aobj = &args[1].toObject(); + RootedVarObject aobj(cx, &args[1].toObject()); uint32_t length; if (!js_GetLengthProperty(cx, aobj, &length)) THROWV(false); diff --git a/js/src/methodjit/PolyIC.cpp b/js/src/methodjit/PolyIC.cpp index bbcaa31a6b1d..b3332411af69 100644 --- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -1302,8 +1302,8 @@ class ScopeNameCompiler : public PICStubCompiler private: typedef Vector JumpList; - JSObject *scopeChain; - PropertyName *name; + RootedVarObject scopeChain; + RootedVarPropertyName name; GetPropHelper getprop; ScopeNameCompiler *thisFromCtor() { return this; } @@ -1360,7 +1360,7 @@ class ScopeNameCompiler : public PICStubCompiler ScopeNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic, PropertyName *name, VoidStubPIC stub) : PICStubCompiler("name", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)), - scopeChain(scopeChain), name(name), + scopeChain(f.cx, scopeChain), name(f.cx, name), getprop(f.cx, NULL, name, *thisFromCtor(), f) { } @@ -1643,14 +1643,14 @@ class ScopeNameCompiler : public PICStubCompiler class BindNameCompiler : public PICStubCompiler { - JSObject *scopeChain; - PropertyName *name; + RootedVarObject scopeChain; + RootedVarPropertyName name; public: BindNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic, PropertyName *name, VoidStubPIC stub) : PICStubCompiler("bind", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)), - scopeChain(scopeChain), name(name) + scopeChain(f.cx, scopeChain), name(f.cx, name) { } static void reset(Repatcher &repatcher, ic::PICInfo &pic) diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index 3ff2c8a8a9bd..4da7bddceea3 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -87,7 +87,8 @@ using namespace JSC; void JS_FASTCALL stubs::BindName(VMFrame &f, PropertyName *name) { - JSObject *obj = FindIdentifierBase(f.cx, f.fp()->scopeChain(), name); + JSObject *obj = FindIdentifierBase(f.cx, f.fp()->scopeChain(), + RootedVarPropertyName(f.cx, name)); if (!obj) THROW(); f.regs.sp[0].setObject(*obj); diff --git a/js/src/perf/jsperf.cpp b/js/src/perf/jsperf.cpp index 48a97c081d72..d35c48599e0f 100644 --- a/js/src/perf/jsperf.cpp +++ b/js/src/perf/jsperf.cpp @@ -201,7 +201,7 @@ pm_construct(JSContext* cx, unsigned argc, jsval* vp) if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "u", &mask)) return JS_FALSE; - JSObject *obj = JS_NewObjectForConstructor(cx, &pm_class, vp); + js::RootedVarObject obj(cx, JS_NewObjectForConstructor(cx, &pm_class, vp)); if (!obj) return JS_FALSE; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index a1ca01fb311d..992609d1d4ac 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -739,7 +739,7 @@ Options(JSContext *cx, unsigned argc, jsval *vp) static JSBool Load(JSContext *cx, unsigned argc, jsval *vp) { - JSObject *thisobj = JS_THIS_OBJECT(cx, vp); + RootedVarObject thisobj(cx, JS_THIS_OBJECT(cx, vp)); if (!thisobj) return JS_FALSE; @@ -1698,6 +1698,8 @@ DisassembleScript(JSContext *cx, JSScript *script, JSFunction *fun, bool lines, Sprint(sp, "\n"); } + Root scriptRoot(cx, &script); + if (!js_Disassemble(cx, script, lines, sp)) return false; SrcNotes(cx, script, sp); @@ -2126,15 +2128,15 @@ DumpObject(JSContext *cx, unsigned argc, jsval *vp) JSBool DumpStack(JSContext *cx, unsigned argc, Value *vp) { - JSObject *arr = JS_NewArrayObject(cx, 0, NULL); + RootedVarObject arr(cx, JS_NewArrayObject(cx, 0, NULL)); if (!arr) return false; - JSString *evalStr = JS_NewStringCopyZ(cx, "eval-code"); + RootedVarString evalStr(cx, JS_NewStringCopyZ(cx, "eval-code")); if (!evalStr) return false; - JSString *globalStr = JS_NewStringCopyZ(cx, "global-code"); + RootedVarString globalStr(cx, JS_NewStringCopyZ(cx, "global-code")); if (!globalStr) return false; @@ -2525,8 +2527,10 @@ typedef struct ComplexObject { } ComplexObject; static JSBool -sandbox_enumerate(JSContext *cx, JSObject *obj) +sandbox_enumerate(JSContext *cx, JSObject *obj_) { + RootedVarObject obj(cx, obj_); + jsval v; JSBool b; @@ -2538,9 +2542,12 @@ sandbox_enumerate(JSContext *cx, JSObject *obj) } static JSBool -sandbox_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, +sandbox_resolve(JSContext *cx, JSObject *obj_, jsid id_, unsigned flags, JSObject **objp) { + RootedVarObject obj(cx, obj_); + RootedVarId id(cx, id_); + jsval v; JSBool b, resolved; @@ -2572,7 +2579,7 @@ static JSClass sandbox_class = { static JSObject * NewSandbox(JSContext *cx, bool lazy) { - JSObject *obj = JS_NewCompartmentAndGlobalObject(cx, &sandbox_class, NULL); + RootedVarObject obj(cx, JS_NewCompartmentAndGlobalObject(cx, &sandbox_class, NULL)); if (!obj) return NULL; @@ -2584,12 +2591,12 @@ NewSandbox(JSContext *cx, bool lazy) if (!lazy && !JS_InitStandardClasses(cx, obj)) return NULL; - AutoValueRooter root(cx, BooleanValue(lazy)); - if (!JS_SetProperty(cx, obj, "lazy", root.jsval_addr())) + RootedVarValue value(cx, BooleanValue(lazy)); + if (!JS_SetProperty(cx, obj, "lazy", value.address())) return NULL; } - if (!cx->compartment->wrap(cx, &obj)) + if (!cx->compartment->wrap(cx, obj.address())) return NULL; return obj; } @@ -2607,6 +2614,8 @@ EvalInContext(JSContext *cx, unsigned argc, jsval *vp) if (!src) return false; + SkipRoot skip(cx, &src); + bool lazy = false; if (srclen == 4) { if (src[0] == 'l' && src[1] == 'a' && src[2] == 'z' && src[3] == 'y') { @@ -3410,7 +3419,7 @@ Serialize(JSContext *cx, unsigned argc, jsval *vp) JSBool Deserialize(JSContext *cx, unsigned argc, jsval *vp) { - jsval v = argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID; + RootedVar v(cx, argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID); JSObject *obj; if (JSVAL_IS_PRIMITIVE(v) || !(obj = JSVAL_TO_OBJECT(v))->isTypedArray()) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "deserialize"); @@ -3427,7 +3436,7 @@ Deserialize(JSContext *cx, unsigned argc, jsval *vp) } if (!JS_ReadStructuredClone(cx, (uint64_t *) TypedArray::getDataOffset(array), TypedArray::getByteLength(array), - JS_STRUCTURED_CLONE_VERSION, &v, NULL, NULL)) { + JS_STRUCTURED_CLONE_VERSION, v.address(), NULL, NULL)) { return false; } JS_SET_RVAL(cx, vp, v); diff --git a/js/src/shell/jsheaptools.cpp b/js/src/shell/jsheaptools.cpp index b93288ab696c..686ebbe0055e 100644 --- a/js/src/shell/jsheaptools.cpp +++ b/js/src/shell/jsheaptools.cpp @@ -352,10 +352,10 @@ HeapReverser::getEdgeDescription() class ReferenceFinder { public: ReferenceFinder(JSContext *cx, const HeapReverser &reverser) - : context(cx), reverser(reverser) { } + : context(cx), reverser(reverser), result(cx) { } /* Produce an object describing all references to |target|. */ - JSObject *findReferences(JSObject *target); + JSObject *findReferences(HandleObject target); private: /* The context in which to do allocation and error-handling. */ @@ -365,7 +365,7 @@ class ReferenceFinder { const HeapReverser &reverser; /* The results object we're currently building. */ - JSObject *result; + RootedVarObject result; /* A list of edges we've traversed to get to a certain point. */ class Path { @@ -513,6 +513,8 @@ ReferenceFinder::addReferrer(jsval referrer, Path *path) return false; AutoReleasePtr releasePathName(context, pathName); + Root referrerRoot(context, &referrer); + /* Find the property of the results object named |pathName|. */ jsval v; if (!JS_GetProperty(context, result, pathName, &v)) @@ -528,7 +530,7 @@ ReferenceFinder::addReferrer(jsval referrer, Path *path) /* The property's value had better be an array. */ JS_ASSERT(JSVAL_IS_OBJECT(v) && !JSVAL_IS_NULL(v)); - JSObject *array = JSVAL_TO_OBJECT(v); + RootedVarObject array(context, JSVAL_TO_OBJECT(v)); JS_ASSERT(JS_IsArrayObject(context, array)); /* Append our referrer to this array. */ @@ -538,7 +540,7 @@ ReferenceFinder::addReferrer(jsval referrer, Path *path) } JSObject * -ReferenceFinder::findReferences(JSObject *target) +ReferenceFinder::findReferences(HandleObject target) { result = JS_NewObject(context, NULL, NULL, NULL); if (!result) @@ -573,7 +575,7 @@ FindReferences(JSContext *cx, unsigned argc, jsval *vp) /* Given the reversed map, find the referents of target. */ ReferenceFinder finder(cx, reverser); - JSObject *references = finder.findReferences(JSVAL_TO_OBJECT(target)); + JSObject *references = finder.findReferences(RootedVarObject(cx, JSVAL_TO_OBJECT(target))); if (!references) return false; diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index b16240c2a018..826e9eb6bf42 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -265,8 +265,8 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) * of setting it in case the user has changed the prototype to an object * that has a setter for this id. */ - AutoValueRooter tvr(cx); - return js_DeleteGeneric(cx, &argsobj, id, tvr.addr(), false) && + RootedVarValue value(cx); + return js_DeleteGeneric(cx, &argsobj, id, value.address(), false) && js_DefineProperty(cx, &argsobj, id, vp, NULL, NULL, JSPROP_ENUMERATE); } @@ -353,13 +353,13 @@ NormalArgumentsObject::optimizedGetElem(JSContext *cx, StackFrame *fp, const Val static JSBool args_enumerate(JSContext *cx, JSObject *obj) { - NormalArgumentsObject &argsobj = obj->asNormalArguments(); + RootedVar argsobj(cx, &obj->asNormalArguments()); /* * Trigger reflection in args_resolve using a series of js_LookupProperty * calls. */ - int argc = int(argsobj.initialLength()); + int argc = int(argsobj->initialLength()); for (int i = -2; i != argc; i++) { jsid id = (i == -2) ? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) @@ -369,7 +369,7 @@ args_enumerate(JSContext *cx, JSObject *obj) JSObject *pobj; JSProperty *prop; - if (!js_LookupProperty(cx, &argsobj, id, &pobj, &prop)) + if (!js_LookupProperty(cx, argsobj, id, &pobj, &prop)) return false; } return true; @@ -424,8 +424,8 @@ StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) * args_delProperty to clear the corresponding reserved slot so the GC can * collect its value. */ - AutoValueRooter tvr(cx); - return js_DeleteGeneric(cx, argsobj, id, tvr.addr(), strict) && + RootedVarValue value(cx); + return js_DeleteGeneric(cx, argsobj, id, value.address(), strict) && js_SetPropertyHelper(cx, argsobj, id, 0, vp, strict); } @@ -434,7 +434,7 @@ strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSObje { *objp = NULL; - StrictArgumentsObject &argsobj = obj->asStrictArguments(); + RootedVar argsobj(cx, &obj->asStrictArguments()); unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE; PropertyOp getter = StrictArgGetter; @@ -442,12 +442,12 @@ strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSObje if (JSID_IS_INT(id)) { uint32_t arg = uint32_t(JSID_TO_INT(id)); - if (arg >= argsobj.initialLength() || argsobj.isElementDeleted(arg)) + if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg)) return true; attrs |= JSPROP_ENUMERATE; } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { - if (argsobj.hasOverriddenLength()) + if (argsobj->hasOverriddenLength()) return true; } else { if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) && @@ -456,15 +456,15 @@ strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSObje } attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED; - getter = CastAsPropertyOp(argsobj.global().getThrowTypeError()); - setter = CastAsStrictPropertyOp(argsobj.global().getThrowTypeError()); + getter = CastAsPropertyOp(argsobj->global().getThrowTypeError()); + setter = CastAsStrictPropertyOp(argsobj->global().getThrowTypeError()); } Value undef = UndefinedValue(); - if (!js_DefineProperty(cx, &argsobj, id, &undef, getter, setter, attrs)) + if (!js_DefineProperty(cx, argsobj, id, &undef, getter, setter, attrs)) return false; - *objp = &argsobj; + *objp = argsobj; return true; } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 10a60e46ce98..6949eebe4aa2 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -525,7 +525,7 @@ Debugger::slowPathOnEnterFrame(JSContext *cx, Value *vp) { /* Build the list of recipients. */ AutoValueVector triggered(cx); - GlobalObject *global = &cx->fp()->global(); + RootedVar global(cx, &cx->fp()->global()); if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) { for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) { Debugger *dbg = *p; @@ -557,12 +557,12 @@ bool Debugger::slowPathOnLeaveFrame(JSContext *cx, bool frameOk) { StackFrame *fp = cx->fp(); - GlobalObject *global = &fp->global(); + RootedVar global(cx, &fp->global()); /* Save the frame's completion value. */ JSTrapStatus status; - Value value; - Debugger::resultToCompletion(cx, frameOk, fp->returnValue(), &status, &value); + RootedVarValue value(cx); + Debugger::resultToCompletion(cx, frameOk, fp->returnValue(), &status, value.address()); /* Build a list of the recipients. */ AutoObjectVector frames(cx); @@ -575,12 +575,12 @@ Debugger::slowPathOnLeaveFrame(JSContext *cx, bool frameOk) /* For each Debugger.Frame, fire its onPop handler, if any. */ for (JSObject **p = frames.begin(); p != frames.end(); p++) { - JSObject *frameobj = *p; + RootedVarObject frameobj(cx, *p); Debugger *dbg = Debugger::fromChildJSObject(frameobj); if (dbg->enabled && !frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER).isUndefined()) { - const Value &handler = frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER); + RootedVarValue handler(cx, frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER)); AutoCompartment ac(cx, dbg->object); @@ -669,7 +669,7 @@ Debugger::slowPathOnLeaveFrame(JSContext *cx, bool frameOk) } bool -Debugger::wrapEnvironment(JSContext *cx, Env *env, Value *rval) +Debugger::wrapEnvironment(JSContext *cx, Handle env, Value *rval) { if (!env) { rval->setNull(); @@ -688,7 +688,7 @@ Debugger::wrapEnvironment(JSContext *cx, Env *env, Value *rval) return false; envobj->setPrivate(env); envobj->setReservedSlot(JSSLOT_DEBUGENV_OWNER, ObjectValue(*object)); - if (!environments.relookupOrAdd(p, env, envobj)) { + if (!environments.relookupOrAdd(p, env.value(), envobj)) { js_ReportOutOfMemory(cx); return false; } @@ -703,7 +703,7 @@ Debugger::wrapDebuggeeValue(JSContext *cx, Value *vp) assertSameCompartment(cx, object.get()); if (vp->isObject()) { - JSObject *obj = &vp->toObject(); + RootedVarObject obj(cx, &vp->toObject()); ObjectWeakMap::AddPtr p = objects.lookupForAdd(obj); if (p) { @@ -808,7 +808,8 @@ Debugger::newCompletionValue(JSContext *cx, JSTrapStatus status, Value value, Va */ assertSameCompartment(cx, object.get()); - jsid key; + RootedVarId key(cx); + RootValue valueRoot(cx, &value); switch (status) { case JSTRAP_RETURN: @@ -919,7 +920,7 @@ CallMethodIfPresent(JSContext *cx, HandleObject obj, const char *name, int argc, JSTrapStatus Debugger::fireDebuggerStatement(JSContext *cx, Value *vp) { - JSObject *hook = getHook(OnDebuggerStatement); + RootedVarObject hook(cx, getHook(OnDebuggerStatement)); JS_ASSERT(hook); JS_ASSERT(hook->isCallable()); @@ -941,12 +942,12 @@ Debugger::fireDebuggerStatement(JSContext *cx, Value *vp) JSTrapStatus Debugger::fireExceptionUnwind(JSContext *cx, Value *vp) { - JSObject *hook = getHook(OnExceptionUnwind); + RootedVarObject hook(cx, getHook(OnExceptionUnwind)); JS_ASSERT(hook); JS_ASSERT(hook->isCallable()); StackFrame *fp = cx->fp(); - Value exc = cx->getPendingException(); + RootedVarValue exc(cx, cx->getPendingException()); cx->clearPendingException(); AutoCompartment ac(cx, object); @@ -954,6 +955,8 @@ Debugger::fireExceptionUnwind(JSContext *cx, Value *vp) return JSTRAP_ERROR; Value argv[2]; + AutoValueArray avr(cx, argv, 2); + argv[1] = exc; if (!getScriptFrame(cx, fp, &argv[0]) || !wrapDebuggeeValue(cx, &argv[1])) return handleUncaughtException(ac, vp, false); @@ -969,7 +972,7 @@ Debugger::fireExceptionUnwind(JSContext *cx, Value *vp) JSTrapStatus Debugger::fireEnterFrame(JSContext *cx, Value *vp) { - JSObject *hook = getHook(OnEnterFrame); + RootedVarObject hook(cx, getHook(OnEnterFrame)); JS_ASSERT(hook); JS_ASSERT(hook->isCallable()); @@ -988,9 +991,9 @@ Debugger::fireEnterFrame(JSContext *cx, Value *vp) } void -Debugger::fireNewScript(JSContext *cx, JSScript *script) +Debugger::fireNewScript(JSContext *cx, Handle script) { - JSObject *hook = getHook(OnNewScript); + RootedVarObject hook(cx, getHook(OnNewScript)); JS_ASSERT(hook); JS_ASSERT(hook->isCallable()); @@ -1025,7 +1028,7 @@ Debugger::dispatchHook(JSContext *cx, Value *vp, Hook which) * different compartments--every compartment *except* this one. */ AutoValueVector triggered(cx); - GlobalObject *global = &cx->fp()->global(); + RootedVar global(cx, &cx->fp()->global()); if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) { for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) { Debugger *dbg = *p; @@ -1071,8 +1074,11 @@ AddNewScriptRecipients(GlobalObject::DebuggerVector *src, AutoValueVector *dest) } void -Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal) +Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script_, GlobalObject *compileAndGoGlobal_) { + RootedVar script(cx, script_); + RootedVar compileAndGoGlobal(cx, compileAndGoGlobal_); + JS_ASSERT(script->compileAndGo == !!compileAndGoGlobal); /* @@ -1112,8 +1118,8 @@ JSTrapStatus Debugger::onTrap(JSContext *cx, Value *vp) { StackFrame *fp = cx->fp(); - JSScript *script = fp->script(); - GlobalObject *scriptGlobal = &fp->global(); + RootedVar script(cx, fp->script()); + RootedVar scriptGlobal(cx, &fp->global()); jsbytecode *pc = cx->regs().pc; BreakpointSite *site = script->getBreakpointSite(pc); JSOp op = JSOp(*pc); @@ -1174,7 +1180,7 @@ Debugger::onSingleStep(JSContext *cx, Value *vp) * onStep handlers mess with that (other than by returning a resumption * value). */ - Value exception = UndefinedValue(); + RootedVarValue exception(cx, UndefinedValue()); bool exceptionPending = cx->isExceptionPending(); if (exceptionPending) { exception = cx->getPendingException(); @@ -1705,10 +1711,10 @@ Debugger::addDebuggee(JSContext *cx, unsigned argc, Value *vp) { REQUIRE_ARGC("Debugger.addDebuggee", 1); THIS_DEBUGGER(cx, argc, vp, "addDebuggee", args, dbg); - JSObject *referent = dbg->unwrapDebuggeeArgument(cx, args[0]); + RootedVarObject referent(cx, dbg->unwrapDebuggeeArgument(cx, args[0])); if (!referent) return false; - GlobalObject *global = &referent->global(); + RootedVar global(cx, &referent->global()); if (!dbg->addDebuggeeGlobal(cx, global)) return false; @@ -1750,7 +1756,7 @@ JSBool Debugger::getDebuggees(JSContext *cx, unsigned argc, Value *vp) { THIS_DEBUGGER(cx, argc, vp, "getDebuggees", args, dbg); - JSObject *arrobj = NewDenseAllocatedArray(cx, dbg->debuggees.count(), NULL); + RootedVarObject arrobj(cx, NewDenseAllocatedArray(cx, dbg->debuggees.count(), NULL)); if (!arrobj) return false; arrobj->ensureDenseArrayInitializedLength(cx, 0, dbg->debuggees.count()); @@ -1812,7 +1818,7 @@ Debugger::construct(JSContext *cx, unsigned argc, Value *vp) Value v; if (!args.callee().getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &v)) return false; - JSObject *proto = &v.toObject(); + RootedVarObject proto(cx, &v.toObject()); JS_ASSERT(proto->getClass() == &Debugger::jsclass); /* @@ -1820,13 +1826,13 @@ Debugger::construct(JSContext *cx, unsigned argc, Value *vp) * Debugger.{Frame,Object,Script}.prototype in reserved slots. The rest of * the reserved slots are for hooks; they default to undefined. */ - JSObject *obj = NewObjectWithGivenProto(cx, &Debugger::jsclass, proto, NULL); + RootedVarObject obj(cx, NewObjectWithGivenProto(cx, &Debugger::jsclass, proto, NULL)); if (!obj) return false; for (unsigned slot = JSSLOT_DEBUG_PROTO_START; slot < JSSLOT_DEBUG_PROTO_STOP; slot++) obj->setReservedSlot(slot, proto->getReservedSlot(slot)); - Debugger *dbg = cx->new_(cx, obj); + Debugger *dbg = cx->new_(cx, obj.reference()); if (!dbg) return false; obj->setPrivate(dbg); @@ -1837,7 +1843,7 @@ Debugger::construct(JSContext *cx, unsigned argc, Value *vp) /* Add the initial debuggees, if any. */ for (unsigned i = 0; i < argc; i++) { - GlobalObject *debuggee = &GetProxyPrivate(&args[i].toObject()).toObject().global(); + RootedVar debuggee(cx, &GetProxyPrivate(&args[i].toObject()).toObject().global()); if (!dbg->addDebuggeeGlobal(cx, debuggee)) return false; } @@ -1847,7 +1853,7 @@ Debugger::construct(JSContext *cx, unsigned argc, Value *vp) } bool -Debugger::addDebuggeeGlobal(JSContext *cx, GlobalObject *global) +Debugger::addDebuggeeGlobal(JSContext *cx, Handle global) { if (debuggees.has(global)) return true; @@ -1897,7 +1903,7 @@ Debugger::addDebuggeeGlobal(JSContext *cx, GlobalObject *global) AutoCompartment ac(cx, global); if (!ac.enter()) return false; - GlobalObject::DebuggerVector *v = global->getOrCreateDebuggers(cx); + GlobalObject::DebuggerVector *v = GlobalObject::getOrCreateDebuggers(cx, global); if (!v || !v->append(this)) { js_ReportOutOfMemory(cx); } else { @@ -2322,14 +2328,14 @@ Debugger::findScripts(JSContext *cx, unsigned argc, Value *vp) if (!query.findScripts(&scripts)) return false; - JSObject *result = NewDenseAllocatedArray(cx, scripts.length(), NULL); + RootedVarObject result(cx, NewDenseAllocatedArray(cx, scripts.length(), NULL)); if (!result) return false; result->ensureDenseArrayInitializedLength(cx, 0, scripts.length()); for (size_t i = 0; i < scripts.length(); i++) { - JSObject *scriptObject = dbg->wrapScript(cx, scripts[i]); + JSObject *scriptObject = dbg->wrapScript(cx, RootedVar(cx, scripts[i])); if (!scriptObject) return false; result->setDenseArrayElement(i, ObjectValue(*scriptObject)); @@ -2404,7 +2410,7 @@ Class DebuggerScript_class = { }; JSObject * -Debugger::newDebuggerScript(JSContext *cx, JSScript *script) +Debugger::newDebuggerScript(JSContext *cx, Handle script) { assertSameCompartment(cx, object.get()); @@ -2420,7 +2426,7 @@ Debugger::newDebuggerScript(JSContext *cx, JSScript *script) } JSObject * -Debugger::wrapScript(JSContext *cx, JSScript *script) +Debugger::wrapScript(JSContext *cx, Handle script) { assertSameCompartment(cx, object.get()); JS_ASSERT(cx->compartment != script->compartment()); @@ -2429,7 +2435,7 @@ Debugger::wrapScript(JSContext *cx, JSScript *script) JSObject *scriptobj = newDebuggerScript(cx, script); /* The allocation may have caused a GC, which can remove table entries. */ - if (!scriptobj || !scripts.relookupOrAdd(p, script, scriptobj)) + if (!scriptobj || !scripts.relookupOrAdd(p, script.value(), scriptobj)) return NULL; } @@ -2473,10 +2479,10 @@ DebuggerScript_checkThis(JSContext *cx, const CallArgs &args, const char *fnname #define THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, fnname, args, obj, script) \ CallArgs args = CallArgsFromVp(argc, vp); \ - JSObject *obj = DebuggerScript_checkThis(cx, args, fnname); \ + RootedVarObject obj(cx, DebuggerScript_checkThis(cx, args, fnname)); \ if (!obj) \ return false; \ - JSScript *script = GetScriptReferent(obj) + RootedVar script(cx, GetScriptReferent(obj)) static JSBool DebuggerScript_getUrl(JSContext *cx, unsigned argc, Value *vp) @@ -2536,7 +2542,7 @@ DebuggerScript_getChildScripts(JSContext *cx, unsigned argc, Value *vp) JSObject *obj = objects->vector[i]; if (obj->isFunction()) { JSFunction *fun = static_cast(obj); - JSObject *s = dbg->wrapScript(cx, fun->script()); + JSObject *s = dbg->wrapScript(cx, RootedVar(cx, fun->script())); if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s))) return false; } @@ -2833,7 +2839,7 @@ DebuggerScript_setBreakpoint(JSContext *cx, unsigned argc, Value *vp) THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "setBreakpoint", args, obj, script); Debugger *dbg = Debugger::fromChildJSObject(obj); - GlobalObject *scriptGlobal = script->getGlobalObjectOrNull(); + RootedVar scriptGlobal(cx, script->getGlobalObjectOrNull()); if (!dbg->observesGlobal(ScriptGlobal(cx, script, scriptGlobal))) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_DEBUGGING); return false; @@ -3008,7 +3014,7 @@ StackContains(JSContext *cx, StackFrame *fp) #define THIS_FRAME(cx, argc, vp, fnname, args, thisobj, fp) \ CallArgs args = CallArgsFromVp(argc, vp); \ - JSObject *thisobj = CheckThisFrame(cx, args, fnname, true); \ + RootedVarObject thisobj(cx, CheckThisFrame(cx, args, fnname, true)); \ if (!thisobj) \ return false; \ StackFrame *fp = (StackFrame *) thisobj->getPrivate(); \ @@ -3049,7 +3055,7 @@ DebuggerFrame_getEnvironment(JSContext *cx, unsigned argc, Value *vp) { THIS_FRAME_OWNER(cx, argc, vp, "get environment", args, thisobj, fp, dbg); - Env *env; + RootedVar env(cx); { AutoCompartment ac(cx, fp->scopeChain()); if (!ac.enter()) @@ -3204,12 +3210,12 @@ DebuggerFrame_getArguments(JSContext *cx, unsigned argc, Value *vp) } for (int32_t i = 0; i < fargc; i++) { - JSFunction *getobj = - js_NewFunction(cx, NULL, DebuggerArguments_getArg, 0, 0, global, NULL, - JSFunction::ExtendedFinalizeKind); + RootedVarFunction getobj(cx); + getobj = js_NewFunction(cx, NULL, DebuggerArguments_getArg, 0, 0, global, NULL, + JSFunction::ExtendedFinalizeKind); if (!getobj || !DefineNativeProperty(cx, argsobj, INT_TO_JSID(i), UndefinedValue(), - JS_DATA_TO_FUNC_PTR(PropertyOp, getobj), NULL, + JS_DATA_TO_FUNC_PTR(PropertyOp, getobj.reference()), NULL, JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_GETTER, 0, 0)) { return false; @@ -3234,7 +3240,7 @@ DebuggerFrame_getScript(JSContext *cx, unsigned argc, Value *vp) if (fp->isFunctionFrame() && !fp->isEvalFrame()) { JSFunction *callee = fp->callee().toFunction(); if (callee->isInterpreted()) { - scriptObject = debug->wrapScript(cx, callee->script()); + scriptObject = debug->wrapScript(cx, RootedVar(cx, callee->script())); if (!scriptObject) return false; } @@ -3244,7 +3250,7 @@ DebuggerFrame_getScript(JSContext *cx, unsigned argc, Value *vp) * frames. */ JSScript *script = fp->script(); - scriptObject = debug->wrapScript(cx, script); + scriptObject = debug->wrapScript(cx, RootedVar(cx, script)); if (!scriptObject) return false; } @@ -3362,11 +3368,14 @@ DebuggerFrame_setOnPop(JSContext *cx, unsigned argc, Value *vp) namespace js { JSBool -EvaluateInEnv(JSContext *cx, Env *env, StackFrame *fp, const jschar *chars, +EvaluateInEnv(JSContext *cx, Handle env, StackFrame *fp, const jschar *chars, unsigned length, const char *filename, unsigned lineno, Value *rval) { assertSameCompartment(cx, env, fp); + JS_ASSERT(!IsPoisonedPtr(chars)); + SkipRoot skip(cx, &chars); + if (fp) { /* Execute assumes an already-computed 'this" value. */ if (!ComputeThis(cx, fp)) @@ -3413,7 +3422,7 @@ DebuggerFrameEval(JSContext *cx, unsigned argc, Value *vp, EvalBindingsMode mode "Debugger.Frame.eval", "string", InformalValueTypeName(args[0])); return false; } - JSLinearString *linearStr = args[0].toString()->ensureLinear(cx); + RootedVar linearStr(cx, args[0].toString()->ensureLinear(cx)); if (!linearStr) return false; @@ -3657,7 +3666,7 @@ DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp) return true; } - const JSFunction *fun = obj->toFunction(); + RootedVarFunction fun(cx, obj->toFunction()); JSObject *result = NewDenseAllocatedArray(cx, fun->nargs, NULL); if (!result) return false; @@ -3701,7 +3710,7 @@ DebuggerObject_getScript(JSContext *cx, unsigned argc, Value *vp) return true; } - JSObject *scriptObject = dbg->wrapScript(cx, fun->script()); + JSObject *scriptObject = dbg->wrapScript(cx, RootedVar(cx, fun->script())); if (!scriptObject) return false; @@ -3720,7 +3729,7 @@ DebuggerObject_getEnvironment(JSContext *cx, unsigned argc, Value *vp) return true; } - Env *env = obj->toFunction()->environment(); + RootedVar env(cx, obj->toFunction()->environment()); return dbg->wrapEnvironment(cx, env, &args.rval()); } @@ -4048,7 +4057,7 @@ ApplyOrCall(JSContext *cx, unsigned argc, Value *vp, ApplyOrCallMode mode) js_apply_str); return false; } - JSObject *argsobj = &args[1].toObject(); + RootedVarObject argsobj(cx, &args[1].toObject()); if (!js_GetLengthProperty(cx, argsobj, &callArgc)) return false; callArgc = unsigned(JS_MIN(callArgc, StackSpace::ARGS_LENGTH_MAX)); @@ -4215,7 +4224,7 @@ DebuggerEnv_checkThis(JSContext *cx, const CallArgs &args, const char *fnname) JSObject *envobj = DebuggerEnv_checkThis(cx, args, fnname); \ if (!envobj) \ return false; \ - Env *env = static_cast(envobj->getPrivate()); \ + RootedVar env(cx, static_cast(envobj->getPrivate())); \ JS_ASSERT(env) #define THIS_DEBUGENV_OWNER(cx, argc, vp, fnname, args, envobj, env, dbg) \ @@ -4254,7 +4263,7 @@ DebuggerEnv_getParent(JSContext *cx, unsigned argc, Value *vp) THIS_DEBUGENV_OWNER(cx, argc, vp, "get parent", args, envobj, env, dbg); /* Don't bother switching compartments just to get env's parent. */ - Env *parent = env->enclosingScope(); + RootedVar parent(cx, env->enclosingScope()); return dbg->wrapEnvironment(cx, parent, &args.rval()); } @@ -4380,13 +4389,13 @@ DebuggerEnv_setVariable(JSContext *cx, unsigned argc, Value *vp) if (!ValueToIdentifier(cx, args[0], &id)) return false; - Value v = args[1]; - if (!dbg->unwrapDebuggeeValue(cx, &v)) + RootedVarValue v(cx, args[1]); + if (!dbg->unwrapDebuggeeValue(cx, v.address())) return false; { AutoCompartment ac(cx, env); - if (!ac.enter() || !cx->compartment->wrapId(cx, &id) || !cx->compartment->wrap(cx, &v)) + if (!ac.enter() || !cx->compartment->wrapId(cx, &id) || !cx->compartment->wrap(cx, v.address())) return false; /* This can trigger setters. */ @@ -4402,7 +4411,7 @@ DebuggerEnv_setVariable(JSContext *cx, unsigned argc, Value *vp) } /* Just set the property. */ - if (!env->setGeneric(cx, id, &v, true)) + if (!env->setGeneric(cx, id, v.address(), true)) return false; } diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 41e1521b97c4..e5a73a002019 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -122,7 +122,7 @@ class Debugger { class FrameRange; class ScriptQuery; - bool addDebuggeeGlobal(JSContext *cx, GlobalObject *obj); + bool addDebuggeeGlobal(JSContext *cx, Handle obj); void removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global, GlobalObjectSet::Enum *compartmentEnum, GlobalObjectSet::Enum *debugEnum); @@ -224,13 +224,13 @@ class Debugger { * Allocate and initialize a Debugger.Script instance whose referent is * |script|. */ - JSObject *newDebuggerScript(JSContext *cx, JSScript *script); + JSObject *newDebuggerScript(JSContext *cx, Handle script); /* * Receive a "new script" event from the engine. A new script was compiled * or deserialized. */ - void fireNewScript(JSContext *cx, JSScript *script); + void fireNewScript(JSContext *cx, Handle script); static inline Debugger *fromLinks(JSCList *links); inline Breakpoint *firstBreakpoint() const; @@ -289,7 +289,7 @@ class Debugger { * create a Debugger.Environment object for the given Env. On success, * store the Environment object in *vp and return true. */ - bool wrapEnvironment(JSContext *cx, Env *env, Value *vp); + bool wrapEnvironment(JSContext *cx, Handle env, Value *vp); /* * Like cx->compartment->wrap(cx, vp), but for the debugger compartment. @@ -370,7 +370,7 @@ class Debugger { * needed. The context |cx| must be in the debugger compartment; |script| * must be a script in a debuggee compartment. */ - JSObject *wrapScript(JSContext *cx, JSScript *script); + JSObject *wrapScript(JSContext *cx, Handle script); private: Debugger(const Debugger &) MOZ_DELETE; @@ -562,7 +562,7 @@ Debugger::onNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndG } extern JSBool -EvaluateInEnv(JSContext *cx, Env *env, StackFrame *fp, const jschar *chars, +EvaluateInEnv(JSContext *cx, Handle env, StackFrame *fp, const jschar *chars, unsigned length, const char *filename, unsigned lineno, Value *rval); } diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 4febaf531575..b02d31c2f78d 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -289,42 +289,42 @@ GlobalObject::create(JSContext *cx, Class *clasp) return obj; } -bool -GlobalObject::initStandardClasses(JSContext *cx) +/* static */ bool +GlobalObject::initStandardClasses(JSContext *cx, Handle global) { JSAtomState &state = cx->runtime->atomState; /* Define a top-level property 'undefined' with the undefined value. */ - if (!defineProperty(cx, state.typeAtoms[JSTYPE_VOID], UndefinedValue(), - JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) + if (!global->defineProperty(cx, state.typeAtoms[JSTYPE_VOID], UndefinedValue(), + JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) { return false; } - if (!initFunctionAndObjectClasses(cx)) + if (!global->initFunctionAndObjectClasses(cx)) return false; /* Initialize the rest of the standard objects and functions. */ - return js_InitArrayClass(cx, this) && - js_InitBooleanClass(cx, this) && - js_InitExceptionClasses(cx, this) && - js_InitMathClass(cx, this) && - js_InitNumberClass(cx, this) && - js_InitJSONClass(cx, this) && - js_InitRegExpClass(cx, this) && - js_InitStringClass(cx, this) && - js_InitTypedArrayClasses(cx, this) && + return js_InitArrayClass(cx, global) && + js_InitBooleanClass(cx, global) && + js_InitExceptionClasses(cx, global) && + js_InitMathClass(cx, global) && + js_InitNumberClass(cx, global) && + js_InitJSONClass(cx, global) && + js_InitRegExpClass(cx, global) && + js_InitStringClass(cx, global) && + js_InitTypedArrayClasses(cx, global) && #if JS_HAS_XML_SUPPORT - js_InitXMLClasses(cx, this) && + js_InitXMLClasses(cx, global) && #endif #if JS_HAS_GENERATORS - js_InitIteratorClasses(cx, this) && + js_InitIteratorClasses(cx, global) && #endif - js_InitDateClass(cx, this) && - js_InitWeakMapClass(cx, this) && - js_InitProxyClass(cx, this) && - js_InitMapClass(cx, this) && - js_InitSetClass(cx, this); + js_InitDateClass(cx, global) && + js_InitWeakMapClass(cx, global) && + js_InitProxyClass(cx, global) && + js_InitMapClass(cx, global) && + js_InitSetClass(cx, global); } void @@ -475,39 +475,39 @@ GlobalObject::getDebuggers() return (DebuggerVector *) debuggers.toObject().getPrivate(); } -GlobalObject::DebuggerVector * -GlobalObject::getOrCreateDebuggers(JSContext *cx) +/* static */ GlobalObject::DebuggerVector * +GlobalObject::getOrCreateDebuggers(JSContext *cx, Handle global) { - assertSameCompartment(cx, this); - DebuggerVector *debuggers = getDebuggers(); + assertSameCompartment(cx, global); + DebuggerVector *debuggers = global->getDebuggers(); if (debuggers) return debuggers; - JSObject *obj = NewObjectWithGivenProto(cx, &GlobalDebuggees_class, NULL, this); + JSObject *obj = NewObjectWithGivenProto(cx, &GlobalDebuggees_class, NULL, global); if (!obj) return NULL; debuggers = cx->new_(); if (!debuggers) return NULL; obj->setPrivate(debuggers); - setReservedSlot(DEBUGGERS, ObjectValue(*obj)); + global->setReservedSlot(DEBUGGERS, ObjectValue(*obj)); return debuggers; } -bool -GlobalObject::addDebugger(JSContext *cx, Debugger *dbg) +/* static */ bool +GlobalObject::addDebugger(JSContext *cx, Handle global, Debugger *dbg) { - DebuggerVector *debuggers = getOrCreateDebuggers(cx); + DebuggerVector *debuggers = getOrCreateDebuggers(cx, global); if (!debuggers) return false; #ifdef DEBUG for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) JS_ASSERT(*p != dbg); #endif - if (debuggers->empty() && !compartment()->addDebuggee(cx, this)) + if (debuggers->empty() && !global->compartment()->addDebuggee(cx, global)) return false; if (!debuggers->append(dbg)) { - compartment()->removeDebuggee(cx->runtime->defaultFreeOp(), this); + global->compartment()->removeDebuggee(cx->runtime->defaultFreeOp(), global); return false; } return true; diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 1e3217f29598..bd53e9831b6a 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -344,8 +344,8 @@ class GlobalObject : public JSObject { bool getFunctionNamespace(JSContext *cx, Value *vp); - bool initGeneratorClass(JSContext *cx); - bool initStandardClasses(JSContext *cx); + static bool initGeneratorClass(JSContext *cx, Handle global); + static bool initStandardClasses(JSContext *cx, Handle global); typedef js::Vector DebuggerVector; @@ -359,9 +359,9 @@ class GlobalObject : public JSObject { * The same, but create the empty vector if one does not already * exist. Returns NULL only on OOM. */ - DebuggerVector *getOrCreateDebuggers(JSContext *cx); + static DebuggerVector *getOrCreateDebuggers(JSContext *cx, Handle global); - bool addDebugger(JSContext *cx, Debugger *dbg); + static bool addDebugger(JSContext *cx, Handle global, Debugger *dbg); }; /* diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index 02e868d57559..a174920bd6bb 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -226,6 +226,14 @@ struct PropDesc { bool wrapInto(JSContext *cx, JSObject *obj, const jsid &id, jsid *wrappedId, PropDesc *wrappedDesc) const; + + struct StackRoot { + StackRoot(JSContext *cx, PropDesc *pd) + : pdRoot(cx, &pd->pd_), valueRoot(cx, &pd->value_), + getRoot(cx, &pd->get_), setRoot(cx, &pd->set_) + {} + RootValue pdRoot, valueRoot, getRoot, setRoot; + }; }; class DenseElementsHeader; diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 08086a33872f..a3836c8affef 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -394,11 +394,13 @@ RegExpObject::createNoStatics(JSContext *cx, HandleAtom source, RegExpFlag flags bool RegExpObject::createShared(JSContext *cx, RegExpGuard *g) { + RootedVar self(cx, this); + JS_ASSERT(!maybeShared()); if (!cx->compartment->regExps.get(cx, getSource(), getFlags(), g)) return false; - setShared(cx, **g); + self->setShared(cx, **g); return true; } diff --git a/js/src/vm/RegExpStatics.h b/js/src/vm/RegExpStatics.h index 70cfd9a1d2ec..f4c20f1884d4 100644 --- a/js/src/vm/RegExpStatics.h +++ b/js/src/vm/RegExpStatics.h @@ -241,17 +241,31 @@ class RegExpStatics void getLastParen(JSSubString *out) const; void getLeftContext(JSSubString *out) const; void getRightContext(JSSubString *out) const; + + class StackRoot + { + Root matchPairsInputRoot; + RootString pendingInputRoot; + + public: + StackRoot(JSContext *cx, RegExpStatics *buffer) + : matchPairsInputRoot(cx, (JSLinearString**) &buffer->matchPairsInput), + pendingInputRoot(cx, (JSString**) &buffer->pendingInput) + {} + }; }; class PreserveRegExpStatics { RegExpStatics * const original; RegExpStatics buffer; + RegExpStatics::StackRoot bufferRoot; public: - explicit PreserveRegExpStatics(RegExpStatics *original) + explicit PreserveRegExpStatics(JSContext *cx, RegExpStatics *original) : original(original), - buffer(RegExpStatics::InitBuffer()) + buffer(RegExpStatics::InitBuffer()), + bufferRoot(cx, &buffer) {} bool init(JSContext *cx) { diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 88ba7643896c..a9f3b452a52f 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -176,10 +176,9 @@ CallObject::create(JSContext *cx, JSScript *script, HandleObject enclosing, Hand * whose call objects do not have a consistent global variable and need * to be updated dynamically. */ - JSObject &global = enclosing->global(); - if (&global != obj->getParent()) { + if (&enclosing->global() != obj->getParent()) { JS_ASSERT(obj->getParent() == NULL); - if (!obj->setParent(cx, &global)) + if (!JSObject::setParent(cx, obj, RootedVarObject(cx, &enclosing->global()))) return NULL; } @@ -226,7 +225,8 @@ CallObject::createForFunction(JSContext *cx, StackFrame *fp) * For a named function expression Call's parent points to an environment * object holding function's name. */ - if (JSAtom *lambdaName = CallObjectLambdaName(fp->fun())) { + RootedVarAtom lambdaName(cx, CallObjectLambdaName(fp->fun())); + if (lambdaName) { scopeChain = DeclEnvObject::create(cx, fp); if (!scopeChain) return NULL; @@ -423,7 +423,7 @@ DeclEnvObject::create(JSContext *cx, StackFrame *fp) if (!emptyDeclEnvShape) return NULL; - JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyDeclEnvShape, type, NULL); + RootedVarObject obj(cx, JSObject::create(cx, FINALIZE_KIND, emptyDeclEnvShape, type, NULL)); if (!obj) return NULL; @@ -449,7 +449,7 @@ WithObject::create(JSContext *cx, StackFrame *fp, HandleObject proto, HandleObje if (!emptyWithShape) return NULL; - JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyWithShape, type, NULL); + RootedVarObject obj(cx, JSObject::create(cx, FINALIZE_KIND, emptyWithShape, type, NULL)); if (!obj) return NULL; @@ -694,36 +694,35 @@ Class js::WithClass = { }; ClonedBlockObject * -ClonedBlockObject::create(JSContext *cx, StaticBlockObject &block, StackFrame *fp) +ClonedBlockObject::create(JSContext *cx, Handle block, StackFrame *fp) { RootedVarTypeObject type(cx); - type = block.getNewType(cx); + type = block->getNewType(cx); if (!type) return NULL; HeapSlot *slots; - if (!PreallocateObjectDynamicSlots(cx, block.lastProperty(), &slots)) + if (!PreallocateObjectDynamicSlots(cx, block->lastProperty(), &slots)) return NULL; RootedVarShape shape(cx); - shape = block.lastProperty(); + shape = block->lastProperty(); - JSObject *obj = JSObject::create(cx, FINALIZE_KIND, shape, type, slots); + RootedVarObject obj(cx, JSObject::create(cx, FINALIZE_KIND, shape, type, slots)); if (!obj) return NULL; /* Set the parent if necessary, as for call objects. */ - JSObject &global = fp->global(); - if (&global != obj->getParent()) { + if (&fp->global() != obj->getParent()) { JS_ASSERT(obj->getParent() == NULL); - if (!obj->setParent(cx, &global)) + if (!JSObject::setParent(cx, obj, RootedVarObject(cx, &fp->global()))) return NULL; } JS_ASSERT(!obj->inDictionaryMode()); - JS_ASSERT(obj->slotSpan() >= block.slotCount() + RESERVED_SLOTS); + JS_ASSERT(obj->slotSpan() >= block->slotCount() + RESERVED_SLOTS); - obj->setReservedSlot(DEPTH_SLOT, PrivateUint32Value(block.stackDepth())); + obj->setReservedSlot(DEPTH_SLOT, PrivateUint32Value(block->stackDepth())); obj->setPrivate(js_FloatingFrameIfGenerator(cx, fp)); if (obj->lastProperty()->extensibleParents() && !obj->generateOwnShape(cx)) diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 97da34d06019..6f7d94ac1976 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -277,7 +277,7 @@ class StaticBlockObject : public BlockObject class ClonedBlockObject : public BlockObject { public: - static ClonedBlockObject *create(JSContext *cx, StaticBlockObject &block, StackFrame *fp); + static ClonedBlockObject *create(JSContext *cx, Handle block, StackFrame *fp); /* The static block from which this block was cloned. */ StaticBlockObject &staticBlock() const; diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index c27da8c9b98e..d0ad0dc3c4fe 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -358,10 +358,7 @@ StackFrame::functionPrologue(JSContext *cx) JS_ASSERT(isNonEvalFunctionFrame()); JS_ASSERT(!isGeneratorFrame()); - JSFunction *fun = this->fun(); - JSScript *script = fun->script(); - - if (fun->isHeavyweight()) { + if (fun()->isHeavyweight()) { if (!CallObject::createForFunction(cx, this)) return false; } else { @@ -369,7 +366,7 @@ StackFrame::functionPrologue(JSContext *cx) scopeChain(); } - if (script->nesting()) { + if (script()->nesting()) { JS_ASSERT(maintainNestingState()); types::NestingPrologue(cx, this); } diff --git a/js/src/vm/String-inl.h b/js/src/vm/String-inl.h index 2ad6435738d0..8fda6e505106 100644 --- a/js/src/vm/String-inl.h +++ b/js/src/vm/String-inl.h @@ -450,6 +450,8 @@ namespace js { static JS_ALWAYS_INLINE JSFixedString * NewShortString(JSContext *cx, const jschar *chars, size_t length) { + SkipRoot skip(cx, &chars); + /* * Don't bother trying to find a static atom; measurement shows that not * many get here (for one, Atomize is catching them). diff --git a/js/src/vm/StringObject-inl.h b/js/src/vm/StringObject-inl.h index 4ca08c61d525..02a414e5d07c 100644 --- a/js/src/vm/StringObject-inl.h +++ b/js/src/vm/StringObject-inl.h @@ -71,7 +71,7 @@ StringObject::init(JSContext *cx, HandleString str) } } - JS_ASSERT(nativeLookupNoAllocation(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot() + JS_ASSERT(self->nativeLookupNoAllocation(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot() == LENGTH_SLOT); self->setStringThis(str); From dfdca5c41605c34e14674c29316890c87c6f571b Mon Sep 17 00:00:00 2001 From: Oleg Romashin Date: Mon, 30 Apr 2012 17:03:08 -0700 Subject: [PATCH 054/159] Bug 748694 - Switch Maemo WebGL to FBO. r=jgilbert,bgirard --- gfx/gl/GLContextProviderEGL.cpp | 58 +++++---------------------------- 1 file changed, 8 insertions(+), 50 deletions(-) diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index aff41ae17887..2894faca3201 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -181,7 +181,7 @@ CreateBasicEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig); #endif static EGLConfig -CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig = nsnull, EGLenum aDepth = 0); +CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig = nsnull); #endif static EGLint gContextAttribs[] = { @@ -744,45 +744,6 @@ GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize) return true; } -#ifdef MOZ_X11 - if (gUseBackingSurface && mThebesSurface) { - if (aNewSize == mThebesSurface->GetSize()) { - return true; - } - - EGLNativePixmapType pixmap = 0; - nsRefPtr xsurface = - gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()), - gfxXlibSurface::FindRenderFormat(DefaultXDisplay(), - gfxASurface::ImageFormatRGB24), - aNewSize); - // Make sure that pixmap created and ready for GL rendering - XSync(DefaultXDisplay(), False); - - if (xsurface->CairoStatus() != 0) { - return false; - } - pixmap = (EGLNativePixmapType)xsurface->XDrawable(); - if (!pixmap) { - return false; - } - - EGLSurface surface; - EGLConfig config = 0; - int depth = gfxUtils::ImageFormatToDepth(gfxPlatform::GetPlatform()->GetOffscreenFormat()); - surface = CreateEGLSurfaceForXSurface(xsurface, &config, depth); - if (!config) { - return false; - } - if (!ResizeOffscreenFBOs(aNewSize, true)) - return false; - - mThebesSurface = xsurface; - - return true; - } -#endif - #if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) if (ResizeOffscreenPixmapSurface(aNewSize)) { if (ResizeOffscreenFBOs(aNewSize, true)) @@ -1788,7 +1749,7 @@ TRY_ATTRIBS_AGAIN: #ifdef MOZ_X11 EGLSurface -CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig, EGLenum aDepth) +CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig) { gfxXlibSurface* xsurface = static_cast(aSurface); bool opaque = @@ -1827,7 +1788,7 @@ CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig, EGLenum a static EGLint pixmap_config[] = { LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PIXMAP_BIT, LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_DEPTH_SIZE, aDepth, + LOCAL_EGL_DEPTH_SIZE, 0, LOCAL_EGL_BIND_TO_TEXTURE_RGB, LOCAL_EGL_TRUE, LOCAL_EGL_NONE }; @@ -1835,7 +1796,7 @@ CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig, EGLenum a static EGLint pixmap_lock_config[] = { LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PIXMAP_BIT | LOCAL_EGL_LOCK_SURFACE_BIT_KHR, LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_DEPTH_SIZE, aDepth, + LOCAL_EGL_DEPTH_SIZE, 0, LOCAL_EGL_BIND_TO_TEXTURE_RGB, LOCAL_EGL_TRUE, LOCAL_EGL_NONE }; @@ -1888,7 +1849,7 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize, gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()), gfxXlibSurface::FindRenderFormat(DefaultXDisplay(), gfxASurface::ImageFormatRGB24), - gUseBackingSurface ? aSize : gfxIntSize(16, 16)); + aSize); // XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error XSync(DefaultXDisplay(), False); @@ -1907,8 +1868,7 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize, EGLConfig config = 0; #ifdef MOZ_X11 - int depth = gfxUtils::ImageFormatToDepth(gfxPlatform::GetPlatform()->GetOffscreenFormat()); - surface = CreateEGLSurfaceForXSurface(thebesSurface, &config, gUseBackingSurface ? depth : 0); + surface = CreateEGLSurfaceForXSurface(thebesSurface, &config); #endif if (!config) { return nsnull; @@ -1925,8 +1885,6 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize, glContext->HoldSurface(thebesSurface); - glContext->mCanBindToTexture = true; - return glContext.forget(); } @@ -1974,13 +1932,13 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize, return glContext.forget(); #elif defined(MOZ_X11) nsRefPtr glContext = - GLContextEGL::CreateEGLPixmapOffscreenContext(aSize, aFormat, true); + GLContextEGL::CreateEGLPixmapOffscreenContext(gfxIntSize(16, 16), aFormat, true); if (!glContext) { return nsnull; } - if (!(aFlags & GLContext::ContextFlagsGlobal) && !gUseBackingSurface && !glContext->ResizeOffscreenFBOs(glContext->OffscreenActualSize(), true)) { + if (!(aFlags & GLContext::ContextFlagsGlobal) && !glContext->ResizeOffscreenFBO(aSize, true)) { // we weren't able to create the initial // offscreen FBO, so this is dead return nsnull; From bd6ff7ba6b8b9760a872e307af510d4b0dc15e76 Mon Sep 17 00:00:00 2001 From: Oleg Romashin Date: Mon, 30 Apr 2012 17:03:26 -0700 Subject: [PATCH 055/159] Bug 750276 - Make CompositorParent transforms not android-only. r=ajuma --- gfx/layers/ipc/CompositorParent.cpp | 63 +++++++++++++++++++++-------- gfx/layers/ipc/CompositorParent.h | 7 +++- 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index a873e1e69f3f..5ee470177a36 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -60,6 +60,8 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, MessageLoop* aMsgLoop, Pl : mWidget(aWidget) , mCurrentCompositeTask(NULL) , mPaused(false) + , mXScale(1.0) + , mYScale(1.0) , mIsFirstPaint(false) , mLayersUpdated(false) , mCompositorLoop(aMsgLoop) @@ -244,9 +246,7 @@ CompositorParent::Composite() return; } -#ifdef MOZ_WIDGET_ANDROID TransformShadowTree(); -#endif Layer* aLayer = mLayerManager->GetRoot(); mozilla::layers::RenderTraceLayers(aLayer, "0000"); @@ -261,7 +261,6 @@ CompositorParent::Composite() #endif } -#ifdef MOZ_WIDGET_ANDROID // Do a breadth-first search to find the first layer in the tree that is // scrollable. Layer* @@ -292,7 +291,6 @@ CompositorParent::GetPrimaryScrollableLayer() return root; } -#endif // Go down shadow layer tree, setting properties to match their non-shadow // counterparts. @@ -314,7 +312,6 @@ SetShadowProperties(Layer* aLayer) void CompositorParent::TransformShadowTree() { -#ifdef MOZ_WIDGET_ANDROID Layer* layer = GetPrimaryScrollableLayer(); ShadowLayer* shadow = layer->AsShadowLayer(); ContainerLayer* container = layer->AsContainerLayer(); @@ -329,19 +326,19 @@ CompositorParent::TransformShadowTree() if (mIsFirstPaint && metrics) { nsIntPoint scrollOffset = metrics->mViewportScrollOffset; mContentSize = metrics->mContentSize; - mozilla::AndroidBridge::Bridge()->SetFirstPaintViewport(scrollOffset.x, scrollOffset.y, - 1/rootScaleX, - mContentSize.width, - mContentSize.height, - metrics->mCSSContentSize.width, - metrics->mCSSContentSize.height); + SetFirstPaintViewport(scrollOffset.x, scrollOffset.y, + 1/rootScaleX, + mContentSize.width, + mContentSize.height, + metrics->mCSSContentSize.width, + metrics->mCSSContentSize.height); mIsFirstPaint = false; } else if (metrics && (metrics->mContentSize != mContentSize)) { mContentSize = metrics->mContentSize; - mozilla::AndroidBridge::Bridge()->SetPageSize(1/rootScaleX, mContentSize.width, - mContentSize.height, - metrics->mCSSContentSize.width, - metrics->mCSSContentSize.height); + SetPageSize(1/rootScaleX, mContentSize.width, + mContentSize.height, + metrics->mCSSContentSize.width, + metrics->mCSSContentSize.height); } // We synchronise the viewport information with Java after sending the above @@ -353,8 +350,8 @@ CompositorParent::TransformShadowTree() displayPort.x += scrollOffset.x; displayPort.y += scrollOffset.y; - mozilla::AndroidBridge::Bridge()->SyncViewportInfo(displayPort, 1/rootScaleX, mLayersUpdated, - mScrollOffset, mXScale, mYScale); + SyncViewportInfo(displayPort, 1/rootScaleX, mLayersUpdated, + mScrollOffset, mXScale, mYScale); mLayersUpdated = false; } @@ -381,6 +378,38 @@ CompositorParent::TransformShadowTree() ViewTransform treeTransform(nsIntPoint(0,0), mXScale, mYScale); shadow->SetShadowTransform(gfx3DMatrix(treeTransform) * currentTransform); } +} + +void +CompositorParent::SetFirstPaintViewport(float aOffsetX, float aOffsetY, float aZoom, + float aPageWidth, float aPageHeight, + float aCssPageWidth, float aCssPageHeight) +{ +#ifdef MOZ_WIDGET_ANDROID + mozilla::AndroidBridge::Bridge()->SetFirstPaintViewport(aOffsetX, aOffsetY, + aZoom, aPageWidth, aPageHeight, + aCssPageWidth, aCssPageHeight); +#endif +} + +void +CompositorParent::SetPageSize(float aZoom, float aPageWidth, float aPageHeight, + float aCssPageWidth, float aCssPageHeight) +{ +#ifdef MOZ_WIDGET_ANDROID + mozilla::AndroidBridge::Bridge()->SetPageSize(aZoom, aPageWidth, aPageHeight, + aCssPageWidth, aCssPageHeight); +#endif +} + +void +CompositorParent::SyncViewportInfo(const nsIntRect& aDisplayPort, + float aDisplayResolution, bool aLayersUpdated, + nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY) +{ +#ifdef MOZ_WIDGET_ANDROID + mozilla::AndroidBridge::Bridge()->SyncViewportInfo(aDisplayPort, aDisplayResolution, aLayersUpdated, + aScrollOffset, aScaleX, aScaleY); #endif } diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index 1e5dcc64e504..0e1cccb337de 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -114,6 +114,11 @@ protected: virtual void ScheduleTask(CancelableTask*, int); virtual void Composite(); virtual void ScheduleComposition(); + virtual void SetFirstPaintViewport(float aOffsetX, float aOffsetY, float aZoom, float aPageWidth, float aPageHeight, + float aCssPageWidth, float aCssPageHeight); + virtual void SetPageSize(float aZoom, float aPageWidth, float aPageHeight, float aCssPageWidth, float aCssPageHeight); + virtual void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated, + nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY); private: void PauseComposition(); @@ -126,13 +131,11 @@ private: inline PlatformThreadId CompositorThreadID(); // Platform specific functions -#ifdef MOZ_WIDGET_ANDROID /** * Does a breadth-first search to find the first layer in the tree with a * displayport set. */ Layer* GetPrimaryScrollableLayer(); -#endif nsRefPtr mLayerManager; nsIWidget* mWidget; From 0c9bd026a9bdc59add953bb0f129c87fd8a63848 Mon Sep 17 00:00:00 2001 From: Paul ADENOT Date: Mon, 30 Apr 2012 20:29:24 -0400 Subject: [PATCH 056/159] Bug 462959 - Implement nsIDOMHTMLMediaElement::GetPlayed(). r=cpearce, kinetik --- .../html/content/public/nsHTMLMediaElement.h | 7 +++ .../html/content/src/nsHTMLMediaElement.cpp | 55 ++++++++++++++++++- content/html/content/src/nsTimeRanges.cpp | 47 ++++++++++++++-- content/html/content/src/nsTimeRanges.h | 21 ++++++- .../html/nsIDOMHTMLMediaElement.idl | 1 + 5 files changed, 120 insertions(+), 11 deletions(-) diff --git a/content/html/content/public/nsHTMLMediaElement.h b/content/html/content/public/nsHTMLMediaElement.h index 8f66992dc444..e376f79aa1df 100644 --- a/content/html/content/public/nsHTMLMediaElement.h +++ b/content/html/content/public/nsHTMLMediaElement.h @@ -53,6 +53,7 @@ #include "mozilla/CORSMode.h" #include "nsDOMMediaStream.h" #include "mozilla/Mutex.h" +#include "nsTimeRanges.h" // Define to output information on decoding and painting framerate /* #define DEBUG_FRAME_RATE 1 */ @@ -762,6 +763,12 @@ protected: // An audio stream for writing audio directly from JS. nsRefPtr mAudioStream; + // Range of time played. + nsTimeRanges mPlayed; + + // Stores the time at the start of the current 'played' range. + double mCurrentPlayRangeStart; + // True if MozAudioAvailable events can be safely dispatched, based on // a media and element same-origin check. bool mAllowAudioData; diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp index 4bfdd990c761..ba6ff990e9e4 100644 --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -1238,6 +1238,16 @@ NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(double aCurrentTime) return NS_ERROR_DOM_INVALID_STATE_ERR; } + if (mCurrentPlayRangeStart != -1.0) { + double rangeEndTime = 0; + GetCurrentTime(&rangeEndTime); + LOG(PR_LOG_DEBUG, ("%p Adding \'played\' a range : [%f, %f]", this, mCurrentPlayRangeStart, rangeEndTime)); + // Multiple seek without playing, or seek while playing. + if (mCurrentPlayRangeStart != rangeEndTime) { + mPlayed.Add(mCurrentPlayRangeStart, rangeEndTime); + } + } + if (!mDecoder) { LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) failed: no decoder", this, aCurrentTime)); return NS_ERROR_DOM_INVALID_STATE_ERR; @@ -1254,7 +1264,7 @@ NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(double aCurrentTime) return NS_ERROR_FAILURE; } - // Clamp the time to [0, duration] as required by the spec + // Clamp the time to [0, duration] as required by the spec. double clampedTime = NS_MAX(0.0, aCurrentTime); double duration = mDecoder->GetDuration(); if (duration >= 0) { @@ -1266,8 +1276,10 @@ NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(double aCurrentTime) // event if it changes the playback position as a result of the seek. LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) starting seek", this, aCurrentTime)); nsresult rv = mDecoder->Seek(clampedTime); + // Start a new range at position we seeked to. + mCurrentPlayRangeStart = clampedTime; - // We changed whether we're seeking so we need to AddRemoveSelfReference + // We changed whether we're seeking so we need to AddRemoveSelfReference. AddRemoveSelfReference(); return rv; @@ -1306,6 +1318,35 @@ NS_IMETHODIMP nsHTMLMediaElement::GetPaused(bool *aPaused) return NS_OK; } +/* readonly attribute nsIDOMHTMLTimeRanges played; */ +NS_IMETHODIMP nsHTMLMediaElement::GetPlayed(nsIDOMTimeRanges** aPlayed) +{ + nsTimeRanges* ranges = new nsTimeRanges(); + NS_ADDREF(*aPlayed = ranges); + + PRUint32 timeRangeCount = 0; + mPlayed.GetLength(&timeRangeCount); + for (PRUint32 i = 0; i < timeRangeCount; i++) { + double begin; + double end; + mPlayed.Start(i, &begin); + mPlayed.End(i, &end); + ranges->Add(begin, end); + } + + if (mCurrentPlayRangeStart != -1.0) { + double now = 0.0; + GetCurrentTime(&now); + if (mCurrentPlayRangeStart != now) { + ranges->Add(mCurrentPlayRangeStart, now); + } + } + + ranges->Normalize(); + + return NS_OK; +} + /* void pause (); */ NS_IMETHODIMP nsHTMLMediaElement::Pause() { @@ -1596,6 +1637,7 @@ nsHTMLMediaElement::nsHTMLMediaElement(already_AddRefed aNodeInfo) mLastCurrentTime(0.0), mFragmentStart(-1.0), mFragmentEnd(-1.0), + mCurrentPlayRangeStart(-1.0), mAllowAudioData(false), mBegun(false), mLoadedFirstFrame(false), @@ -1715,6 +1757,10 @@ NS_IMETHODIMP nsHTMLMediaElement::Play() } } + if (mCurrentPlayRangeStart == -1.0) { + GetCurrentTime(&mCurrentPlayRangeStart); + } + // TODO: If the playback has ended, then the user agent must set // seek to the effective start. // TODO: The playback rate must be set to the default playback rate. @@ -2837,6 +2883,9 @@ void nsHTMLMediaElement::NotifyAutoplayDataReady() if (mDecoder) { SetPlayedOrSeeked(true); + if (mCurrentPlayRangeStart == -1.0) { + GetCurrentTime(&mCurrentPlayRangeStart); + } mDecoder->Play(); } else if (mStream) { SetPlayedOrSeeked(true); @@ -3099,7 +3148,7 @@ void nsHTMLMediaElement::NotifyAddedSource() } // A load was paused in the resource selection algorithm, waiting for - // a new source child to be added, resume the resource selction algorithm. + // a new source child to be added, resume the resource selection algorithm. if (mLoadWaitStatus == WAITING_FOR_SOURCE) { QueueLoadFromSourceTask(); } diff --git a/content/html/content/src/nsTimeRanges.cpp b/content/html/content/src/nsTimeRanges.cpp index 70c3e1889f16..5ef66c2c0e6f 100644 --- a/content/html/content/src/nsTimeRanges.cpp +++ b/content/html/content/src/nsTimeRanges.cpp @@ -51,22 +51,26 @@ NS_INTERFACE_MAP_BEGIN(nsTimeRanges) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TimeRanges) NS_INTERFACE_MAP_END -nsTimeRanges::nsTimeRanges() { +nsTimeRanges::nsTimeRanges() +{ MOZ_COUNT_CTOR(nsTimeRanges); } -nsTimeRanges::~nsTimeRanges() { +nsTimeRanges::~nsTimeRanges() +{ MOZ_COUNT_DTOR(nsTimeRanges); } NS_IMETHODIMP -nsTimeRanges::GetLength(PRUint32* aLength) { +nsTimeRanges::GetLength(PRUint32* aLength) +{ *aLength = mRanges.Length(); return NS_OK; } NS_IMETHODIMP -nsTimeRanges::Start(PRUint32 aIndex, double* aTime) { +nsTimeRanges::Start(PRUint32 aIndex, double* aTime) +{ if (aIndex >= mRanges.Length()) return NS_ERROR_DOM_INDEX_SIZE_ERR; *aTime = mRanges[aIndex].mStart; @@ -74,7 +78,8 @@ nsTimeRanges::Start(PRUint32 aIndex, double* aTime) { } NS_IMETHODIMP -nsTimeRanges::End(PRUint32 aIndex, double* aTime) { +nsTimeRanges::End(PRUint32 aIndex, double* aTime) +{ if (aIndex >= mRanges.Length()) return NS_ERROR_DOM_INDEX_SIZE_ERR; *aTime = mRanges[aIndex].mEnd; @@ -82,6 +87,36 @@ nsTimeRanges::End(PRUint32 aIndex, double* aTime) { } void -nsTimeRanges::Add(double aStart, double aEnd) { +nsTimeRanges::Add(double aStart, double aEnd) +{ + if (aStart > aEnd) { + NS_WARNING("Can't add a range if the end is older that the start."); + return; + } mRanges.AppendElement(TimeRange(aStart,aEnd)); } + +void +nsTimeRanges::Normalize() +{ + if (mRanges.Length() >= 2) { + nsAutoTArray normalized; + + mRanges.Sort(CompareTimeRanges()); + + // This merges the intervals. + TimeRange current(mRanges[0]); + for (PRUint32 i = 1; i < mRanges.Length(); i++) { + if (current.mEnd >= mRanges[i].mStart) { + current.mEnd = mRanges[i].mEnd; + } else { + normalized.AppendElement(current); + current = mRanges[i]; + } + } + + normalized.AppendElement(current); + + mRanges = normalized; + } +} diff --git a/content/html/content/src/nsTimeRanges.h b/content/html/content/src/nsTimeRanges.h index 8359b2378deb..ba0174dcec65 100644 --- a/content/html/content/src/nsTimeRanges.h +++ b/content/html/content/src/nsTimeRanges.h @@ -45,7 +45,8 @@ // Implements media TimeRanges: // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#timeranges -class nsTimeRanges MOZ_FINAL : public nsIDOMTimeRanges { +class nsTimeRanges MOZ_FINAL : public nsIDOMTimeRanges +{ public: NS_DECL_ISUPPORTS NS_DECL_NSIDOMTIMERANGES @@ -55,9 +56,14 @@ public: void Add(double aStart, double aEnd); + // See http://www.whatwg.org/html/#normalized-timeranges-object + void Normalize(); + private: - struct TimeRange { + // Comparator which orders TimeRanges by start time. Used by Normalize(). + struct TimeRange + { TimeRange(double aStart, double aEnd) : mStart(aStart), mEnd(aEnd) {} @@ -65,6 +71,17 @@ private: double mEnd; }; + struct CompareTimeRanges + { + bool Equals(const TimeRange& aTr1, const TimeRange& aTr2) const { + return aTr1.mStart == aTr2.mStart && aTr1.mEnd == aTr2.mEnd; + } + + bool LessThan(const TimeRange& aTr1, const TimeRange& aTr2) const { + return aTr1.mStart < aTr2.mStart; + } + }; + nsAutoTArray mRanges; }; diff --git a/dom/interfaces/html/nsIDOMHTMLMediaElement.idl b/dom/interfaces/html/nsIDOMHTMLMediaElement.idl index 979c88a1dfec..571a605c7500 100644 --- a/dom/interfaces/html/nsIDOMHTMLMediaElement.idl +++ b/dom/interfaces/html/nsIDOMHTMLMediaElement.idl @@ -93,6 +93,7 @@ interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement readonly attribute double initialTime; readonly attribute double duration; readonly attribute boolean paused; + readonly attribute nsIDOMTimeRanges played; readonly attribute nsIDOMTimeRanges seekable; readonly attribute boolean ended; readonly attribute boolean mozAutoplayEnabled; From 47bc5ed443135ad2a5068ec174fc1cb2ff19254b Mon Sep 17 00:00:00 2001 From: Paul ADENOT Date: Mon, 30 Apr 2012 20:29:29 -0400 Subject: [PATCH 057/159] Bug 462960 - Add tests for the played member. r=cpearce --- content/media/test/Makefile.in | 1 + content/media/test/manifest.js | 8 + content/media/test/test_played.html | 221 ++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 content/media/test/test_played.html diff --git a/content/media/test/Makefile.in b/content/media/test/Makefile.in index c583074de478..3545bc01d5f0 100644 --- a/content/media/test/Makefile.in +++ b/content/media/test/Makefile.in @@ -134,6 +134,7 @@ _TEST_FILES = \ test_paused_after_ended.html \ test_play_events.html \ test_play_events_2.html \ + test_played.html \ test_playback.html \ test_playback_errors.html \ test_seekable1.html \ diff --git a/content/media/test/manifest.js b/content/media/test/manifest.js index 0a3e6e2df4c7..bf0c882e93b1 100644 --- a/content/media/test/manifest.js +++ b/content/media/test/manifest.js @@ -23,6 +23,14 @@ var gProgressTests = [ { name:"bogus.duh", type:"bogus/duh" } ]; +// Used by test_played.html +var gPlayedTests = [ + { name:"big.wav", type:"audio/x-wav", duration:9.0 }, + { name:"sound.ogg", type:"audio/ogg", duration:4.0 }, + { name:"seek.ogv", type:"video/ogg", duration:3.966 }, + { name:"seek.webm", type:"video/webm", duration:3.966 }, +]; + // Used by test_mozLoadFrom. Need one test file per decoder backend, plus // anything for testing clone-specific bugs. var cloneKey = Math.floor(Math.random()*100000000); diff --git a/content/media/test/test_played.html b/content/media/test/test_played.html new file mode 100644 index 000000000000..07fa43a7918c --- /dev/null +++ b/content/media/test/test_played.html @@ -0,0 +1,221 @@ + + + +Test played member for media elements + + + + + + +
    +
    +
    + + From 124c70c9fc3ddc9e44f139d3658ab23ddba29608 Mon Sep 17 00:00:00 2001 From: Raymond Lee Date: Mon, 30 Apr 2012 01:53:08 +0800 Subject: [PATCH 058/159] Bug 666538 - Use Telemetry to collect Panorama usage/perf data. r=ttaubert --- browser/base/content/browser-tabview.js | 4 ++ browser/components/tabview/tabview.js | 1 + browser/components/tabview/telemetry.js | 63 +++++++++++++++++++ browser/components/tabview/ui.js | 3 + .../telemetry/TelemetryHistograms.h | 8 +++ 5 files changed, 79 insertions(+) create mode 100644 browser/components/tabview/telemetry.js diff --git a/browser/base/content/browser-tabview.js b/browser/base/content/browser-tabview.js index 4a741a60fd80..851c45c8d0de 100644 --- a/browser/base/content/browser-tabview.js +++ b/browser/base/content/browser-tabview.js @@ -214,6 +214,8 @@ let TabView = { this._isFrameLoading = true; + TelemetryStopwatch.start("PANORAMA_INITIALIZATION_TIME_MS"); + // ___ find the deck this._deck = document.getElementById("tab-view-deck"); @@ -229,6 +231,8 @@ let TabView = { window.addEventListener("tabviewframeinitialized", function onInit() { window.removeEventListener("tabviewframeinitialized", onInit, false); + TelemetryStopwatch.finish("PANORAMA_INITIALIZATION_TIME_MS"); + self._isFrameLoading = false; self._window = self._iframe.contentWindow; self._setBrowserKeyHandlers(); diff --git a/browser/components/tabview/tabview.js b/browser/components/tabview/tabview.js index ef5c3a2ce277..79acae12becc 100644 --- a/browser/components/tabview/tabview.js +++ b/browser/components/tabview/tabview.js @@ -73,4 +73,5 @@ let AllTabs = { #include drag.js #include trench.js #include search.js +#include telemetry.js #include ui.js diff --git a/browser/components/tabview/telemetry.js b/browser/components/tabview/telemetry.js new file mode 100644 index 000000000000..42f98bad8392 --- /dev/null +++ b/browser/components/tabview/telemetry.js @@ -0,0 +1,63 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Collects telemetry data for Tabview. + */ +let Telemetry = { + TOPIC_GATHER_TELEMETRY: "gather-telemetry", + + /** + * Initializes the object. + */ + init: function Telemetry_init() { + Services.obs.addObserver(this, this.TOPIC_GATHER_TELEMETRY, false); + }, + + /** + * Uninitializes the object. + */ + uninit: function Telemetry_uninit() { + Services.obs.removeObserver(this, this.TOPIC_GATHER_TELEMETRY); + }, + + /** + * Adds telemetry values to gather usage statistics. + */ + _collect: function Telemetry_collect() { + let stackedGroupsCount = 0; + let childCounts = []; + + GroupItems.groupItems.forEach(function (groupItem) { + if (!groupItem.isEmpty()) { + childCounts.push(groupItem.getChildren().length); + + if (groupItem.isStacked()) + stackedGroupsCount++; + } + }); + + function addTelemetryValue(aId, aValue) { + Services.telemetry.getHistogramById("PANORAMA_" + aId).add(aValue); + } + function median(aChildCounts) { + aChildCounts.sort(function(x, y) { return x - y; }); + let middle = Math.floor(aChildCounts.length / 2); + return aChildCounts[middle]; + } + + addTelemetryValue("GROUPS_COUNT", GroupItems.groupItems.length); + addTelemetryValue("STACKED_GROUPS_COUNT", stackedGroupsCount); + addTelemetryValue("MEDIAN_TABS_IN_GROUPS_COUNT", median(childCounts)); + }, + + /** + * Observes for gather telemetry topic. + */ + observe: function Telemetry_observe(aSubject, aTopic, aData) { + if (!gPrivateBrowsing.privateBrowsingEnabled) + this._collect(); + } +} + diff --git a/browser/components/tabview/ui.js b/browser/components/tabview/ui.js index ebaff2dc3816..d8eafe64979a 100644 --- a/browser/components/tabview/ui.js +++ b/browser/components/tabview/ui.js @@ -171,6 +171,8 @@ let UI = { // ___ search Search.init(); + Telemetry.init(); + // ___ currentTab this._currentTab = gBrowser.selectedTab; @@ -312,6 +314,7 @@ let UI = { GroupItems.uninit(); FavIcons.uninit(); Storage.uninit(); + Telemetry.uninit(); this._removeTabActionHandlers(); this._currentTab = null; diff --git a/toolkit/components/telemetry/TelemetryHistograms.h b/toolkit/components/telemetry/TelemetryHistograms.h index bda9faab4493..005cf6f6adb9 100644 --- a/toolkit/components/telemetry/TelemetryHistograms.h +++ b/toolkit/components/telemetry/TelemetryHistograms.h @@ -451,6 +451,14 @@ HISTOGRAM(NEWTAB_PAGE_ENABLED, 0, 1, 2, BOOLEAN, "New tab page is enabled.") HISTOGRAM(NEWTAB_PAGE_PINNED_SITES_COUNT, 1, 9, 10, EXPONENTIAL, "Number of pinned sites on the new tab page.") HISTOGRAM(NEWTAB_PAGE_BLOCKED_SITES_COUNT, 1, 100, 10, EXPONENTIAL, "Number of sites blocked from the new tab page.") +/** + * Panorama telemetry. + */ +HISTOGRAM(PANORAMA_INITIALIZATION_TIME_MS, 1, 10000, 15, EXPONENTIAL, "Time it takes to initialize Panorama (ms)") +HISTOGRAM(PANORAMA_GROUPS_COUNT, 1, 25, 15, EXPONENTIAL, "Number of groups in Panorama") +HISTOGRAM(PANORAMA_STACKED_GROUPS_COUNT, 1, 25, 15, EXPONENTIAL, "Number of stacked groups in Panorama") +HISTOGRAM(PANORAMA_MEDIAN_TABS_IN_GROUPS_COUNT, 1, 100, 15, EXPONENTIAL, "Median of tabs in groups in Panorama") + /** * Native Fennec Telemetry */ From 99fdbe540a2ea93e1caf88badc02eb94813326ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=83=C2=A7ois=20Wang?= Date: Mon, 26 Mar 2012 17:49:44 +0200 Subject: [PATCH 059/159] Bug 736010 - Make downloaded fonts usable in nsMathMLChar. r=karlt --- layout/mathml/nsMathMLChar.cpp | 96 +++++++++++++++++----------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 7fe1d6de4372..db32c11e2d95 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -1041,7 +1041,7 @@ insert: } // Update the font and rendering context if there is a family change -static void +static bool SetFontFamily(nsStyleContext* aStyleContext, nsRenderingContext& aRenderingContext, nsFont& aFont, @@ -1052,14 +1052,24 @@ SetFontFamily(nsStyleContext* aStyleContext, const nsAString& family = aGlyphCode.font ? aGlyphTable->FontNameFor(aGlyphCode) : aDefaultFamily; if (! family.Equals(aFont.name)) { - aFont.name = family; + nsFont font = aFont; + font.name = family; nsRefPtr fm; - aRenderingContext.DeviceContext()->GetMetricsFor(aFont, + aRenderingContext.DeviceContext()->GetMetricsFor(font, aStyleContext->GetStyleFont()->mLanguage, aStyleContext->PresContext()->GetUserFontSet(), *getter_AddRefs(fm)); - aRenderingContext.SetFont(fm); + // Set the font if it is an unicode table + // or if the same family name has been found + if (aGlyphTable == &gGlyphTableList->mUnicodeTable || + fm->GetThebesFontGroup()->GetFontAt(0)->GetFontEntry()-> + FamilyName() == family) { + aFont.name = family; + aRenderingContext.SetFont(fm); + } else + return false; // We did not set the font } + return true; } class nsMathMLChar::StretchEnumContext { @@ -1089,9 +1099,6 @@ public: EnumCallback(const nsString& aFamily, bool aGeneric, void *aData); private: - static bool - ResolverCallback (const nsAString& aFamily, void *aData); - bool TryVariants(nsGlyphTable* aGlyphTable, const nsAString& aFamily); bool TryParts(nsGlyphTable* aGlyphTable, const nsAString& aFamily); @@ -1150,7 +1157,12 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, nsGlyphCode ch; while ((ch = aGlyphTable->BigOf(mPresContext, mChar, size)).Exists()) { - SetFontFamily(sc, mRenderingContext, font, aGlyphTable, ch, aFamily); + if(!SetFontFamily(sc, mRenderingContext, font, aGlyphTable, ch, aFamily)) { + // if largeopOnly is set, break now + if (largeopOnly) break; + ++size; + continue; + } NS_ASSERTION(maxWidth || ch.code[0] != mChar->mGlyph.code[0] || ch.code[1] != mChar->mGlyph.code[1] || @@ -1274,8 +1286,10 @@ nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable, sizedata[i] = mTargetSize; } else { - SetFontFamily(mChar->mStyleContext, mRenderingContext, - font, aGlyphTable, ch, aFamily); + if (!SetFontFamily(mChar->mStyleContext, mRenderingContext, + font, aGlyphTable, ch, aFamily)) + return false; + nsBoundingMetrics bm = mRenderingContext.GetBoundingMetrics(ch.code, ch.Length()); @@ -1370,38 +1384,6 @@ nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable, return IsSizeOK(mPresContext, computedSize, mTargetSize, mStretchHint); } -// This is only called for glyph table corresponding to a family that exists. -// See if the table has a glyph that matches the container -bool -nsMathMLChar::StretchEnumContext::ResolverCallback (const nsAString& aFamily, - void *aData) -{ - StretchEnumContext* context = static_cast(aData); - nsGlyphTable* glyphTable = context->mGlyphTable; - - // Only try this table once. - context->mTablesTried.AppendElement(glyphTable); - - // If the unicode table is being used, then search all font families. If a - // special table is being used then the font in this family should have the - // specified glyphs. - const nsAString& family = glyphTable == &gGlyphTableList->mUnicodeTable ? - context->mFamilies : aFamily; - - if(context->mTryVariants) { - bool isOK = context->TryVariants(glyphTable, family); - if (isOK) - return false; // no need to continue - } - - if(context->mTryParts) { - bool isOK = context->TryParts(glyphTable, family); - if (isOK) - return false; // no need to continue - } - return true; -} - // This is called for each family, whether it exists or not bool nsMathMLChar::StretchEnumContext::EnumCallback(const nsString& aFamily, @@ -1417,16 +1399,32 @@ nsMathMLChar::StretchEnumContext::EnumCallback(const nsString& aFamily, if (context->mTablesTried.Contains(glyphTable)) return true; // already tried this one + // Check font family if it is not a generic one + // We test with the kNullGlyph + nsStyleContext *sc = context->mChar->mStyleContext; + nsFont font = sc->GetStyleFont()->mFont; + if (!aGeneric && !SetFontFamily(sc, context->mRenderingContext, + font, NULL, kNullGlyph, aFamily)) + return true; // Could not set the family + context->mGlyphTable = glyphTable; - if (aGeneric) - return ResolverCallback(aFamily, aData); + // Now see if the table has a glyph that matches the container - bool aborted; - gfxPlatform *pf = gfxPlatform::GetPlatform(); - nsresult rv = - pf->ResolveFontName(aFamily, ResolverCallback, aData, aborted); - return NS_SUCCEEDED(rv) && !aborted; // true means continue + // Only try this table once. + context->mTablesTried.AppendElement(glyphTable); + + // If the unicode table is being used, then search all font families. If a + // special table is being used then the font in this family should have the + // specified glyphs. + const nsAString& family = glyphTable == &gGlyphTableList->mUnicodeTable ? + context->mFamilies : aFamily; + + if((context->mTryVariants && context->TryVariants(glyphTable, family)) || + (context->mTryParts && context->TryParts(glyphTable, family))) + return false; // no need to continue + + return true; // true means continue } nsresult From 30e87cca70e97446ad18e756128bee189aa59f97 Mon Sep 17 00:00:00 2001 From: Ekanan Ketunuti Date: Fri, 23 Mar 2012 20:04:02 +0700 Subject: [PATCH 060/159] Bug 738605 - Don't use an XML comment inside a CDATA block in menulist.xml. r=neil --- toolkit/content/widgets/menulist.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/content/widgets/menulist.xml b/toolkit/content/widgets/menulist.xml index 3314d2157ce7..e868dc37da40 100644 --- a/toolkit/content/widgets/menulist.xml +++ b/toolkit/content/widgets/menulist.xml @@ -386,7 +386,7 @@ + // Droppable is currently used for the Firefox bookmarks dialog only return (this.getAttribute("droppable") == "false") ? Components.interfaces.nsIAccessibleProvider.XULTextBox : Components.interfaces.nsIAccessibleProvider.XULCombobox; From 3fda15b8e0e4f6fc7762fd490c44285ec33b7257 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Apr 2012 23:51:10 -0700 Subject: [PATCH 061/159] Bug 739512: Patch 10: add JSScripts::hasConsts() et al. r=dvander. --- js/src/frontend/BytecodeCompiler.cpp | 8 +++----- js/src/jsdbgapi.cpp | 6 +++--- js/src/jsinterp.cpp | 2 +- js/src/jsobj.cpp | 2 +- js/src/jsopcode.cpp | 2 +- js/src/jsscript.cpp | 16 ++++++++-------- js/src/jsscript.h | 26 +++++++++++++++++--------- js/src/methodjit/InvokeHelpers.cpp | 2 +- js/src/shell/js.cpp | 4 ++-- js/src/vm/Debugger.cpp | 2 +- js/src/vm/ScopeObject.cpp | 2 +- 11 files changed, 39 insertions(+), 33 deletions(-) diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 87bee0118831..4f4c70d1945c 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -112,7 +112,7 @@ DefineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript* script) JSScript *outer = worklist.back(); worklist.popBack(); - if (JSScript::isValidOffset(outer->objectsOffset)) { + if (outer->hasObjects()) { JSObjectArray *arr = outer->objects(); /* @@ -132,16 +132,14 @@ DefineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript* script) outer->isOuterFunction = true; inner->isInnerFunction = true; } - if (!JSScript::isValidOffset(inner->globalsOffset) && - !JSScript::isValidOffset(inner->objectsOffset)) { + if (!inner->hasGlobals() && !inner->hasObjects()) continue; - } if (!worklist.append(inner)) return false; } } - if (!JSScript::isValidOffset(outer->globalsOffset)) + if (!outer->hasGlobals()) continue; GlobalSlotArray *globalUses = outer->globals(); diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 88f4c73197c8..2b2d217d4b1a 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1017,7 +1017,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script) continue; nbytes += (sn - notes + 1) * sizeof *sn; - if (JSScript::isValidOffset(script->objectsOffset)) { + if (script->hasObjects()) { objarray = script->objects(); size_t i = objarray->length; nbytes += sizeof *objarray + i * sizeof objarray->vector[0]; @@ -1026,7 +1026,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script) } while (i != 0); } - if (JSScript::isValidOffset(script->regexpsOffset)) { + if (script->hasRegexps()) { objarray = script->regexps(); size_t i = objarray->length; nbytes += sizeof *objarray + i * sizeof objarray->vector[0]; @@ -1035,7 +1035,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script) } while (i != 0); } - if (JSScript::isValidOffset(script->trynotesOffset)) { + if (script->hasTrynotes()) { nbytes += sizeof(JSTryNoteArray) + script->trynotes()->length * sizeof(JSTryNote); } diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index c5cc7679dd7f..9621d9fa1bc2 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -1017,7 +1017,7 @@ TryNoteIter::TryNoteIter(const FrameRegs ®s) script(regs.fp()->script()), pcOffset(regs.pc - script->main()) { - if (JSScript::isValidOffset(script->trynotesOffset)) { + if (script->hasTrynotes()) { tn = script->trynotes()->vector; tnEnd = tn + script->trynotes()->length; } else { diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 31b14080949e..84c0a149994d 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -817,7 +817,7 @@ EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, unsigned */ JS_ASSERT(script->objects()->length >= 1); if (script->objects()->length == 1 && - !JSScript::isValidOffset(script->regexpsOffset)) { + !script->hasRegexps()) { JS_ASSERT(staticLevel == script->staticLevel); *scriptp = script->evalHashLink(); script->evalHashLink() = NULL; diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 8c0a0bb981f6..a9c0a0931e8f 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1822,7 +1822,7 @@ GetLocal(SprintStack *ss, int i) * not in a block. In either case, return GetStr(ss, i). */ JSScript *script = ss->printer->script; - if (!JSScript::isValidOffset(script->objectsOffset)) + if (!script->hasObjects()) return GetStr(ss, i); // In case of a let variable, the stack points to a JSOP_ENTERBLOCK opcode. diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 01f84261d947..bcef2ee2091a 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -428,7 +428,7 @@ js::XDRScript(XDRState *xdr, JSScript **scriptp, JSScript *parentScript) JS_ASSERT_IF(parentScript, parentScript->compartment() == script->compartment()); /* Should not XDR scripts optimized for a single global object. */ - JS_ASSERT(!JSScript::isValidOffset(script->globalsOffset)); + JS_ASSERT(!script->hasGlobals()); nargs = script->bindings.numArgs(); nvars = script->bindings.numVars(); @@ -535,13 +535,13 @@ js::XDRScript(XDRState *xdr, JSScript **scriptp, JSScript *parentScript) notes = script->notes(); nsrcnotes = script->numNotes(); - if (JSScript::isValidOffset(script->constsOffset)) + if (script->hasConsts()) nconsts = script->consts()->length; - if (JSScript::isValidOffset(script->objectsOffset)) + if (script->hasObjects()) nobjects = script->objects()->length; - if (JSScript::isValidOffset(script->regexpsOffset)) + if (script->hasRegexps()) nregexps = script->regexps()->length; - if (JSScript::isValidOffset(script->trynotesOffset)) + if (script->hasTrynotes()) ntrynotes = script->trynotes()->length; /* no globals when encoding; see assertion above */ nClosedArgs = script->numClosedArgs(); @@ -1993,17 +1993,17 @@ JSScript::markChildren(JSTracer *trc) MarkString(trc, &atoms[i], "atom"); } - if (JSScript::isValidOffset(objectsOffset)) { + if (hasObjects()) { JSObjectArray *objarray = objects(); MarkObjectRange(trc, objarray->length, objarray->vector, "objects"); } - if (JSScript::isValidOffset(regexpsOffset)) { + if (hasRegexps()) { JSObjectArray *objarray = regexps(); MarkObjectRange(trc, objarray->length, objarray->vector, "objects"); } - if (JSScript::isValidOffset(constsOffset)) { + if (hasConsts()) { JSConstArray *constarray = consts(); MarkValueRange(trc, constarray->length, constarray->vector, "consts"); } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 5499bf298bdc..65b39c5f72a4 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -736,47 +736,55 @@ struct JSScript : public js::gc::Cell static const uint8_t INVALID_OFFSET = 0xFF; static bool isValidOffset(uint8_t offset) { return offset != INVALID_OFFSET; } + bool hasConsts() { return isValidOffset(constsOffset); } + bool hasObjects() { return isValidOffset(objectsOffset); } + bool hasRegexps() { return isValidOffset(regexpsOffset); } + bool hasTrynotes() { return isValidOffset(trynotesOffset); } + bool hasGlobals() { return isValidOffset(globalsOffset); } + bool hasClosedArgs() { return isValidOffset(closedArgsOffset); } + bool hasClosedVars() { return isValidOffset(closedVarsOffset); } + JSConstArray *consts() { - JS_ASSERT(isValidOffset(constsOffset)); + JS_ASSERT(hasConsts()); return reinterpret_cast(data + constsOffset); } JSObjectArray *objects() { - JS_ASSERT(isValidOffset(objectsOffset)); + JS_ASSERT(hasObjects()); return reinterpret_cast(data + objectsOffset); } JSObjectArray *regexps() { - JS_ASSERT(isValidOffset(regexpsOffset)); + JS_ASSERT(hasRegexps()); return reinterpret_cast(data + regexpsOffset); } JSTryNoteArray *trynotes() { - JS_ASSERT(isValidOffset(trynotesOffset)); + JS_ASSERT(hasTrynotes()); return reinterpret_cast(data + trynotesOffset); } js::GlobalSlotArray *globals() { - JS_ASSERT(isValidOffset(globalsOffset)); + JS_ASSERT(hasGlobals()); return reinterpret_cast(data + globalsOffset); } js::ClosedSlotArray *closedArgs() { - JS_ASSERT(isValidOffset(closedArgsOffset)); + JS_ASSERT(hasClosedArgs()); return reinterpret_cast(data + closedArgsOffset); } js::ClosedSlotArray *closedVars() { - JS_ASSERT(isValidOffset(closedVarsOffset)); + JS_ASSERT(hasClosedVars()); return reinterpret_cast(data + closedVarsOffset); } uint32_t numClosedArgs() { - return isValidOffset(closedArgsOffset) ? closedArgs()->length : 0; + return hasClosedArgs() ? closedArgs()->length : 0; } uint32_t numClosedVars() { - return isValidOffset(closedVarsOffset) ? closedVars()->length : 0; + return hasClosedVars() ? closedVars()->length : 0; } js::HeapPtrAtom &getAtom(size_t index) const { diff --git a/js/src/methodjit/InvokeHelpers.cpp b/js/src/methodjit/InvokeHelpers.cpp index e6e2be9ca6c4..27120caabf99 100644 --- a/js/src/methodjit/InvokeHelpers.cpp +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -78,7 +78,7 @@ FindExceptionHandler(JSContext *cx) StackFrame *fp = cx->fp(); JSScript *script = fp->script(); - if (!JSScript::isValidOffset(script->trynotesOffset)) + if (!script->hasTrynotes()) return NULL; error: diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 992609d1d4ac..339bf7361962 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1661,7 +1661,7 @@ TryNotes(JSContext *cx, JSScript *script, Sprinter *sp) { JSTryNote *tn, *tnlimit; - if (!JSScript::isValidOffset(script->trynotesOffset)) + if (!script->hasTrynotes()) return JS_TRUE; tn = script->trynotes()->vector; @@ -1705,7 +1705,7 @@ DisassembleScript(JSContext *cx, JSScript *script, JSFunction *fun, bool lines, SrcNotes(cx, script, sp); TryNotes(cx, script, sp); - if (recursive && JSScript::isValidOffset(script->objectsOffset)) { + if (recursive && script->hasObjects()) { JSObjectArray *objects = script->objects(); for (unsigned i = 0; i != objects->length; ++i) { JSObject *obj = objects->vector[i]; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 6949eebe4aa2..71fc2acc5d82 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -2531,7 +2531,7 @@ DebuggerScript_getChildScripts(JSContext *cx, unsigned argc, Value *vp) JSObject *result = NewDenseEmptyArray(cx); if (!result) return false; - if (JSScript::isValidOffset(script->objectsOffset)) { + if (script->hasObjects()) { /* * script->savedCallerFun indicates that this is a direct eval script * and the calling function is stored as script->objects()->vector[0]. diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index a9f3b452a52f..d9a0f8e0965e 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -906,7 +906,7 @@ js::XDRStaticBlockObject(XDRState *xdr, JSScript *script, StaticBlockObjec uint32_t depthAndCount = 0; if (mode == XDR_ENCODE) { obj = *objp; - parentId = JSScript::isValidOffset(script->objectsOffset) + parentId = script->hasObjects() ? FindObjectIndex(script->objects(), obj->enclosingBlock()) : NO_PARENT_INDEX; uint32_t depth = obj->stackDepth(); From 40c48e65182d42fa71cfcd5ac9b0987a5aa417b5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Apr 2012 23:51:12 -0700 Subject: [PATCH 062/159] Bug 739512: Patch 4: move JS{Const,Object,TryNote}Array into the |js| namespace. r=sfink. --- js/src/frontend/BytecodeCompiler.cpp | 2 +- js/src/frontend/BytecodeEmitter.cpp | 6 ++-- js/src/frontend/BytecodeEmitter.h | 6 ++-- js/src/jsdbgapi.cpp | 8 ++--- js/src/jsopcode.cpp | 2 +- js/src/jsscript.cpp | 48 ++++++++++++++-------------- js/src/jsscript.h | 46 +++++++++++++------------- js/src/jsscriptinlines.h | 2 +- js/src/shell/js.cpp | 2 +- js/src/vm/Debugger.cpp | 2 +- js/src/vm/ScopeObject.cpp | 2 +- 11 files changed, 62 insertions(+), 64 deletions(-) diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 4f4c70d1945c..804238522932 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -113,7 +113,7 @@ DefineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript* script) worklist.popBack(); if (outer->hasObjects()) { - JSObjectArray *arr = outer->objects(); + ObjectArray *arr = outer->objects(); /* * If this is an eval script, don't treat the saved caller function diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index f53835944595..038a07865d1a 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -6982,7 +6982,7 @@ NewTryNote(JSContext *cx, BytecodeEmitter *bce, JSTryNoteKind kind, unsigned sta } void -frontend::FinishTakingTryNotes(BytecodeEmitter *bce, JSTryNoteArray *array) +frontend::FinishTakingTryNotes(BytecodeEmitter *bce, TryNoteArray *array) { TryNode *tryNode; JSTryNote *tn; @@ -7048,7 +7048,7 @@ CGObjectList::index(ObjectBox *objbox) } void -CGObjectList::finish(JSObjectArray *array) +CGObjectList::finish(ObjectArray *array) { JS_ASSERT(length <= INDEX_LIMIT); JS_ASSERT(length == array->length); @@ -7064,7 +7064,7 @@ CGObjectList::finish(JSObjectArray *array) } void -GCConstList::finish(JSConstArray *array) +GCConstList::finish(ConstArray *array) { JS_ASSERT(array->length == list.length()); Value *src = list.begin(), *srcend = list.end(); diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 97ddf91dcfb5..36842af8b920 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -537,7 +537,7 @@ struct CGObjectList { CGObjectList() : length(0), lastbox(NULL) {} unsigned index(ObjectBox *objbox); - void finish(JSObjectArray *array); + void finish(ObjectArray *array); }; class GCConstList { @@ -546,7 +546,7 @@ class GCConstList { GCConstList(JSContext *cx) : list(cx) {} bool append(Value v) { return list.append(v); } size_t length() const { return list.length(); } - void finish(JSConstArray *array); + void finish(ConstArray *array); }; struct GlobalScope { @@ -1004,7 +1004,7 @@ JSBool FinishTakingSrcNotes(JSContext *cx, BytecodeEmitter *bce, jssrcnote *notes); void -FinishTakingTryNotes(BytecodeEmitter *bce, JSTryNoteArray *array); +FinishTakingTryNotes(BytecodeEmitter *bce, TryNoteArray *array); } /* namespace frontend */ diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 2b2d217d4b1a..07fb17e4938d 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1000,7 +1000,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script) { size_t nbytes, pbytes; jssrcnote *sn, *notes; - JSObjectArray *objarray; + ObjectArray *objarray; JSPrincipals *principals; nbytes = sizeof *script; @@ -1035,10 +1035,8 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script) } while (i != 0); } - if (script->hasTrynotes()) { - nbytes += sizeof(JSTryNoteArray) + - script->trynotes()->length * sizeof(JSTryNote); - } + if (script->hasTrynotes()) + nbytes += sizeof(TryNoteArray) + script->trynotes()->length * sizeof(JSTryNote); principals = script->principals; if (principals) { diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index a9c0a0931e8f..55b144fbcc79 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -526,7 +526,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, // with an offset. This simplifies code coverage analysis // based on this disassembled output. if (op == JSOP_TRY) { - JSTryNoteArray *trynotes = script->trynotes(); + TryNoteArray *trynotes = script->trynotes(); uint32_t i; for(i = 0; i < trynotes->length; i++) { JSTryNote note = trynotes->vector[i]; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index bcef2ee2091a..52282892b002 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1031,10 +1031,10 @@ js::FreeScriptFilenames(JSCompartment *comp) * * Array type Array elements Offset Accessor * ---------- -------------- ------ -------- - * JSConstArray Consts constsOffset consts() - * JSObjectArray Objects objectsOffset objects() - * JSObjectArray Regexps regexpsOffset regexps() - * JSTryNoteArray Try notes tryNotesOffset trynotes() + * ConstArray Consts constsOffset consts() + * ObjectArray Objects objectsOffset objects() + * ObjectArray Regexps regexpsOffset regexps() + * TryNoteArray Try notes tryNotesOffset trynotes() * GlobalSlotArray Globals globalsOffset globals() * ClosedSlotArray ClosedArgs closedArgsOffset closedArgs() * ClosedSlotArray ClosedVars closedVarsOffset closedVars() @@ -1087,9 +1087,9 @@ js::FreeScriptFilenames(JSCompartment *comp) * jsval-aligned. (There is an assumption that |data| itself is jsval-aligned; * we check this below). */ -JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(JSConstArray)); -JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(JSObjectArray)); /* there are two of these */ -JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(JSTryNoteArray)); +JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ConstArray)); +JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ObjectArray)); /* there are two of these */ +JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(TryNoteArray)); JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(GlobalSlotArray)); JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ClosedSlotArray)); /* there are two of these */ @@ -1111,12 +1111,12 @@ JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(jsbytecode, jssrcnote)); * closedVars array -- the last optional array -- still fits in 1 byte and does * not coincide with INVALID_OFFSET. */ -JS_STATIC_ASSERT(sizeof(JSConstArray) + - sizeof(JSObjectArray) + - sizeof(JSObjectArray) + - sizeof(JSTryNoteArray) + - sizeof(js::GlobalSlotArray) + - sizeof(js::ClosedSlotArray) +JS_STATIC_ASSERT(sizeof(ConstArray) + + sizeof(ObjectArray) + + sizeof(ObjectArray) + + sizeof(TryNoteArray) + + sizeof(GlobalSlotArray) + + sizeof(ClosedSlotArray) < JSScript::INVALID_OFFSET); JS_STATIC_ASSERT(JSScript::INVALID_OFFSET <= 255); @@ -1129,14 +1129,14 @@ JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t size_t size = 0; if (nconsts != 0) - size += sizeof(JSConstArray) + nconsts * sizeof(Value); + size += sizeof(ConstArray) + nconsts * sizeof(Value); size += sizeof(JSAtom *) * natoms; if (nobjects != 0) - size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *); + size += sizeof(ObjectArray) + nobjects * sizeof(JSObject *); if (nregexps != 0) - size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *); + size += sizeof(ObjectArray) + nregexps * sizeof(JSObject *); if (ntrynotes != 0) - size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote); + size += sizeof(TryNoteArray) + ntrynotes * sizeof(JSTryNote); if (nglobals != 0) size += sizeof(GlobalSlotArray) + nglobals * sizeof(GlobalSlotArray::Entry); if (nClosedArgs != 0) @@ -1171,25 +1171,25 @@ JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t uint8_t *cursor = data; if (nconsts != 0) { script->constsOffset = uint8_t(cursor - data); - cursor += sizeof(JSConstArray); + cursor += sizeof(ConstArray); } else { script->constsOffset = JSScript::INVALID_OFFSET; } if (nobjects != 0) { script->objectsOffset = uint8_t(cursor - data); - cursor += sizeof(JSObjectArray); + cursor += sizeof(ObjectArray); } else { script->objectsOffset = JSScript::INVALID_OFFSET; } if (nregexps != 0) { script->regexpsOffset = uint8_t(cursor - data); - cursor += sizeof(JSObjectArray); + cursor += sizeof(ObjectArray); } else { script->regexpsOffset = JSScript::INVALID_OFFSET; } if (ntrynotes != 0) { script->trynotesOffset = uint8_t(cursor - data); - cursor += sizeof(JSTryNoteArray); + cursor += sizeof(TryNoteArray); } else { script->trynotesOffset = JSScript::INVALID_OFFSET; } @@ -1994,17 +1994,17 @@ JSScript::markChildren(JSTracer *trc) } if (hasObjects()) { - JSObjectArray *objarray = objects(); + ObjectArray *objarray = objects(); MarkObjectRange(trc, objarray->length, objarray->vector, "objects"); } if (hasRegexps()) { - JSObjectArray *objarray = regexps(); + ObjectArray *objarray = regexps(); MarkObjectRange(trc, objarray->length, objarray->vector, "objects"); } if (hasConsts()) { - JSConstArray *constarray = consts(); + ConstArray *constarray = consts(); MarkValueRange(trc, constarray->length, constarray->vector, "consts"); } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 65b39c5f72a4..a390d381740a 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -75,22 +75,22 @@ struct JSTryNote { uint32_t length; /* length of the try statement or for-in loop */ }; -typedef struct JSTryNoteArray { - JSTryNote *vector; /* array of indexed try notes */ - uint32_t length; /* count of indexed try notes */ -} JSTryNoteArray; +namespace js { -typedef struct JSObjectArray { - js::HeapPtrObject *vector; /* array of indexed objects */ - uint32_t length; /* count of indexed objects */ -} JSObjectArray; - -typedef struct JSConstArray { +struct ConstArray { js::HeapValue *vector; /* array of indexed constant values */ uint32_t length; -} JSConstArray; +}; -namespace js { +struct ObjectArray { + js::HeapPtrObject *vector; /* array of indexed objects */ + uint32_t length; /* count of indexed objects */ +}; + +struct TryNoteArray { + JSTryNote *vector; /* array of indexed try notes */ + uint32_t length; /* count of indexed try notes */ +}; struct GlobalSlotArray { struct Entry { @@ -273,7 +273,7 @@ class Bindings } /* namespace js */ #define JS_OBJECT_ARRAY_SIZE(length) \ - (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length)) + (offsetof(ObjectArray, vector) + sizeof(JSObject *) * (length)) #ifdef JS_METHODJIT namespace JSC { @@ -744,24 +744,24 @@ struct JSScript : public js::gc::Cell bool hasClosedArgs() { return isValidOffset(closedArgsOffset); } bool hasClosedVars() { return isValidOffset(closedVarsOffset); } - JSConstArray *consts() { + js::ConstArray *consts() { JS_ASSERT(hasConsts()); - return reinterpret_cast(data + constsOffset); + return reinterpret_cast(data + constsOffset); } - JSObjectArray *objects() { + js::ObjectArray *objects() { JS_ASSERT(hasObjects()); - return reinterpret_cast(data + objectsOffset); + return reinterpret_cast(data + objectsOffset); } - JSObjectArray *regexps() { + js::ObjectArray *regexps() { JS_ASSERT(hasRegexps()); - return reinterpret_cast(data + regexpsOffset); + return reinterpret_cast(data + regexpsOffset); } - JSTryNoteArray *trynotes() { + js::TryNoteArray *trynotes() { JS_ASSERT(hasTrynotes()); - return reinterpret_cast(data + trynotesOffset); + return reinterpret_cast(data + trynotesOffset); } js::GlobalSlotArray *globals() { @@ -797,7 +797,7 @@ struct JSScript : public js::gc::Cell } JSObject *getObject(size_t index) { - JSObjectArray *arr = objects(); + js::ObjectArray *arr = objects(); JS_ASSERT(index < arr->length); return arr->vector[index]; } @@ -812,7 +812,7 @@ struct JSScript : public js::gc::Cell inline JSObject *getRegExp(size_t index); const js::Value &getConst(size_t index) { - JSConstArray *arr = consts(); + js::ConstArray *arr = consts(); JS_ASSERT(index < arr->length); return arr->vector[index]; } diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index 473d00c588f3..fd6d8c2e3da5 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -170,7 +170,7 @@ JSScript::getCallerFunction() inline JSObject * JSScript::getRegExp(size_t index) { - JSObjectArray *arr = regexps(); + js::ObjectArray *arr = regexps(); JS_ASSERT(uint32_t(index) < arr->length); JSObject *obj = arr->vector[index]; JS_ASSERT(obj->isRegExp()); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 339bf7361962..512af33e0555 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1706,7 +1706,7 @@ DisassembleScript(JSContext *cx, JSScript *script, JSFunction *fun, bool lines, TryNotes(cx, script, sp); if (recursive && script->hasObjects()) { - JSObjectArray *objects = script->objects(); + ObjectArray *objects = script->objects(); for (unsigned i = 0; i != objects->length; ++i) { JSObject *obj = objects->vector[i]; if (obj->isFunction()) { diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 71fc2acc5d82..1926df7ca10d 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -2537,7 +2537,7 @@ DebuggerScript_getChildScripts(JSContext *cx, unsigned argc, Value *vp) * and the calling function is stored as script->objects()->vector[0]. * It is not really a child script of this script, so skip it. */ - JSObjectArray *objects = script->objects(); + ObjectArray *objects = script->objects(); for (uint32_t i = script->savedCallerFun ? 1 : 0; i < objects->length; i++) { JSObject *obj = objects->vector[i]; if (obj->isFunction()) { diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index d9a0f8e0965e..a363f6dde97b 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -878,7 +878,7 @@ Class js::BlockClass = { #define NO_PARENT_INDEX UINT32_MAX static uint32_t -FindObjectIndex(JSObjectArray *array, JSObject *obj) +FindObjectIndex(ObjectArray *array, JSObject *obj) { size_t i; From 9ded30d62ebbb62cfe35cc01cae4a931529ea2a3 Mon Sep 17 00:00:00 2001 From: Gene Lian Date: Thu, 26 Apr 2012 16:46:52 +0800 Subject: [PATCH 063/159] Bug 743064: Shutdown FramebufferWatcher thread gracefully by using it as a pthread. r=cjones a=b2g-only --- widget/gonk/nsWindow.cpp | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/widget/gonk/nsWindow.cpp b/widget/gonk/nsWindow.cpp index 585b6b09ee98..076f063941e6 100644 --- a/widget/gonk/nsWindow.cpp +++ b/widget/gonk/nsWindow.cpp @@ -79,7 +79,7 @@ static android::FramebufferNativeWindow *gNativeWindow = nsnull; static bool sFramebufferOpen; static bool sUsingOMTC; static nsRefPtr sOMTCSurface; -static nsCOMPtr sFramebufferWatchThread; +static pthread_t sFramebufferWatchThread; namespace { @@ -112,17 +112,15 @@ private: static const char* kSleepFile = "/sys/power/wait_for_fb_sleep"; static const char* kWakeFile = "/sys/power/wait_for_fb_wake"; -class FramebufferWatcher : public nsRunnable { -public: - FramebufferWatcher() - : mScreenOnEvent(new ScreenOnOffEvent(true)) - , mScreenOffEvent(new ScreenOnOffEvent(false)) - {} +static void *frameBufferWatcher(void *) { - NS_IMETHOD Run() { - int len = 0; - char buf; + int len = 0; + char buf; + nsRefPtr mScreenOnEvent = new ScreenOnOffEvent(true); + nsRefPtr mScreenOffEvent = new ScreenOnOffEvent(false); + + while (true) { // Cannot use epoll here because kSleepFile and kWakeFile are // always ready to read and blocking. { @@ -142,17 +140,10 @@ public: NS_WARN_IF_FALSE(len >= 0, "WAIT_FOR_FB_WAKE failed"); NS_DispatchToMainThread(mScreenOnEvent); } - - // Dispatch to ourself. - NS_DispatchToCurrentThread(this); - - return NS_OK; } - -private: - nsRefPtr mScreenOnEvent; - nsRefPtr mScreenOffEvent; -}; + + return NULL; +} } // anonymous namespace @@ -162,8 +153,11 @@ nsWindow::nsWindow() // workaround Bug 725143 hal::SetScreenEnabled(true); - // Watching screen on/off state - NS_NewThread(getter_AddRefs(sFramebufferWatchThread), new FramebufferWatcher()); + // Watching screen on/off state by using a pthread + // which implicitly calls exit() when the main thread ends + if (pthread_create(&sFramebufferWatchThread, NULL, frameBufferWatcher, NULL)) { + NS_RUNTIMEABORT("Failed to create framebufferWatcherThread, aborting..."); + } sUsingOMTC = Preferences::GetBool("layers.offmainthreadcomposition.enabled", false); From 125ed8223fc35cf89320d26eb490c962ce5f7986 Mon Sep 17 00:00:00 2001 From: Yoshi Huang Date: Mon, 30 Apr 2012 13:11:59 +0800 Subject: [PATCH 064/159] Bug 750161 - B2G RIL: typo in cardstatechange event. r=philikon --- dom/system/gonk/RadioInterfaceLayer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index 5659614b2d84..b5c963ba0678 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -305,7 +305,7 @@ RadioInterfaceLayer.prototype = { break; case "cardstatechange": this.radioState.cardState = message.cardState; - ppmm.sendAsyncMessage("RIL:CardStateChange", message); + ppmm.sendAsyncMessage("RIL:CardStateChanged", message); break; case "sms-received": this.handleSmsReceived(message); From 4454d0d3c87925e32374537ea252fd9ee77d65c5 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 30 Apr 2012 15:02:11 -0700 Subject: [PATCH 065/159] Bug 749231: Set the devtools.debugger.log pref in head_dbg.js, so we always get packet logs. r=past --- toolkit/devtools/debugger/tests/unit/head_dbg.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/toolkit/devtools/debugger/tests/unit/head_dbg.js b/toolkit/devtools/debugger/tests/unit/head_dbg.js index 57374f6e952a..6ff2ff35720a 100644 --- a/toolkit/devtools/debugger/tests/unit/head_dbg.js +++ b/toolkit/devtools/debugger/tests/unit/head_dbg.js @@ -7,9 +7,14 @@ const Ci = Components.interfaces; const Cu = Components.utils; const Cr = Components.results; +Cu.import("resource://gre/modules/Services.jsm"); + +// Always log packets when running tests. runxpcshelltests.py will throw +// the output away anyway, unless you give it the --verbose flag. +Services.prefs.setBoolPref("devtools.debugger.log", true); + Cu.import("resource:///modules/devtools/dbg-server.jsm"); Cu.import("resource:///modules/devtools/dbg-client.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); function check_except(func) From 25fd20a3a50175e18443fb74e08b88832ed7f718 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Tue, 1 May 2012 13:45:32 +0200 Subject: [PATCH 066/159] Bug 744388 - [Page Thumbnails] implement a custom storage, don't use the file cache; r=dietrich --- browser/components/nsBrowserGlue.js | 6 + browser/components/thumbnails/PageThumbs.jsm | 195 +++++++++++------- .../thumbnails/PageThumbsProtocol.js | 8 + .../components/thumbnails/test/Makefile.in | 1 + .../test/browser_thumbnails_redirect.js | 33 +-- .../test/browser_thumbnails_storage.js | 89 ++++++++ browser/components/thumbnails/test/head.js | 2 +- 7 files changed, 227 insertions(+), 107 deletions(-) create mode 100644 browser/components/thumbnails/test/browser_thumbnails_storage.js diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index e6b325212317..c1e0ac38a167 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -68,6 +68,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils", XPCOMUtils.defineLazyModuleGetter(this, "webappsUI", "resource:///modules/webappsUI.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", + "resource:///modules/PageThumbs.jsm"); + const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser"; const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; @@ -358,6 +361,8 @@ BrowserGlue.prototype = { // Initialize webapps UI webappsUI.init(); + PageThumbs.init(); + Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); }, @@ -379,6 +384,7 @@ BrowserGlue.prototype = { _onProfileShutdown: function BG__onProfileShutdown() { this._shutdownPlaces(); this._sanitizer.onShutdown(); + PageThumbs.uninit(); }, // All initial windows have opened. diff --git a/browser/components/thumbnails/PageThumbs.jsm b/browser/components/thumbnails/PageThumbs.jsm index 4cefd4befdc4..92b364fb3b91 100644 --- a/browser/components/thumbnails/PageThumbs.jsm +++ b/browser/components/thumbnails/PageThumbs.jsm @@ -4,7 +4,7 @@ "use strict"; -let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsCache"]; +let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsStorage", "PageThumbsCache"]; const Cu = Components.utils; const Cc = Components.classes; @@ -12,6 +12,11 @@ const Ci = Components.interfaces; const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; +/** + * Name of the directory in the profile that contains the thumbnails. + */ +const THUMBNAIL_DIRECTORY = "thumbnails"; + /** * The default background color for page thumbnails. */ @@ -25,12 +30,28 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", + "resource://gre/modules/PlacesUtils.jsm"); + +XPCOMUtils.defineLazyGetter(this, "gCryptoHash", function () { + return Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash); +}); + +XPCOMUtils.defineLazyGetter(this, "gUnicodeConverter", function () { + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = 'utf8'; + return converter; +}); + /** * Singleton providing functionality for capturing web page thumbnails and for * accessing them if already cached. */ let PageThumbs = { - /** * The calculated width and height of the thumbnails. */ @@ -52,6 +73,14 @@ let PageThumbs = { */ get contentType() "image/png", + init: function PageThumbs_init() { + PlacesUtils.history.addObserver(PageThumbsHistoryObserver, false); + }, + + uninit: function PageThumbs_uninit() { + PlacesUtils.history.removeObserver(PageThumbsHistoryObserver); + }, + /** * Gets the thumbnail image's url for a given web page's url. * @param aUrl The web page's url that is depicted in the thumbnail. @@ -124,32 +153,14 @@ let PageThumbs = { // Sync and therefore also redirect sources appear on the newtab // page. We also want thumbnails for those. if (url != originalURL) - PageThumbsCache._copy(url, originalURL); + PageThumbsStorage.copy(url, originalURL); } if (aCallback) aCallback(aSuccessful); } - // Get a writeable cache entry. - PageThumbsCache.getWriteEntry(url, function (aEntry) { - if (!aEntry) { - finish(false); - return; - } - - let outputStream = aEntry.openOutputStream(0); - - // Write the image data to the cache entry. - NetUtil.asyncCopy(aInputStream, outputStream, function (aResult) { - let success = Components.isSuccessCode(aResult); - if (success) - aEntry.markValid(); - - aEntry.close(); - finish(success); - }); - }); + PageThumbsStorage.write(url, aInputStream, finish); }); }, @@ -208,6 +219,88 @@ let PageThumbs = { } }; +let PageThumbsStorage = { + getFileForURL: function Storage_getFileForURL(aURL) { + let hash = this._calculateMD5Hash(aURL); + let parts = [THUMBNAIL_DIRECTORY, hash[0], hash[1], hash.slice(2) + ".png"]; + return FileUtils.getFile("ProfD", parts); + }, + + write: function Storage_write(aURL, aDataStream, aCallback) { + let file = this.getFileForURL(aURL); + let fos = FileUtils.openSafeFileOutputStream(file); + + NetUtil.asyncCopy(aDataStream, fos, function (aResult) { + FileUtils.closeSafeFileOutputStream(fos); + aCallback(Components.isSuccessCode(aResult)); + }); + }, + + copy: function Storage_copy(aSourceURL, aTargetURL) { + let sourceFile = this.getFileForURL(aSourceURL); + let targetFile = this.getFileForURL(aTargetURL); + + try { + sourceFile.copyTo(targetFile.parent, targetFile.leafName); + } catch (e) { + /* We might not be permitted to write to the file. */ + } + }, + + remove: function Storage_remove(aURL) { + try { + this.getFileForURL(aURL).remove(false); + } catch (e) { + /* The file might not exist or we're not permitted to remove it. */ + } + }, + + wipe: function Storage_wipe() { + try { + FileUtils.getDir("ProfD", [THUMBNAIL_DIRECTORY]).remove(true); + } catch (e) { + /* The file might not exist or we're not permitted to remove it. */ + } + }, + + _calculateMD5Hash: function Storage_calculateMD5Hash(aValue) { + let hash = gCryptoHash; + let value = gUnicodeConverter.convertToByteArray(aValue); + + hash.init(hash.MD5); + hash.update(value, value.length); + return this._convertToHexString(hash.finish(false)); + }, + + _convertToHexString: function Storage_convertToHexString(aData) { + let hex = ""; + for (let i = 0; i < aData.length; i++) + hex += ("0" + aData.charCodeAt(i).toString(16)).slice(-2); + return hex; + }, + +}; + +let PageThumbsHistoryObserver = { + onDeleteURI: function Thumbnails_onDeleteURI(aURI, aGUID) { + PageThumbsStorage.remove(aURI.spec); + }, + + onClearHistory: function Thumbnails_onClearHistory() { + PageThumbsStorage.wipe(); + }, + + onTitleChanged: function () {}, + onBeginUpdateBatch: function () {}, + onEndUpdateBatch: function () {}, + onVisit: function () {}, + onBeforeDeleteURI: function () {}, + onPageChanged: function () {}, + onDeleteVisits: function () {}, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]) +}; + /** * A singleton handling the storage of page thumbnails. */ @@ -222,64 +315,6 @@ let PageThumbsCache = { this._openCacheEntry(aKey, Ci.nsICache.ACCESS_READ, aCallback); }, - /** - * Calls the given callback with a cache entry opened for writing. - * @param aKey The key identifying the desired cache entry. - * @param aCallback The callback that is called when the cache entry is ready. - */ - getWriteEntry: function Cache_getWriteEntry(aKey, aCallback) { - // Try to open the desired cache entry. - this._openCacheEntry(aKey, Ci.nsICache.ACCESS_WRITE, aCallback); - }, - - /** - * Copies an existing cache entry's data to a new cache entry. - * @param aSourceKey The key that contains the data to copy. - * @param aTargetKey The key that will be the copy of aSourceKey's data. - */ - _copy: function Cache_copy(aSourceKey, aTargetKey) { - let sourceEntry, targetEntry, waitingCount = 2; - - function finish() { - if (sourceEntry) - sourceEntry.close(); - - if (targetEntry) - targetEntry.close(); - } - - function copyDataWhenReady() { - if (--waitingCount > 0) - return; - - if (!sourceEntry || !targetEntry) { - finish(); - return; - } - - let inputStream = sourceEntry.openInputStream(0); - let outputStream = targetEntry.openOutputStream(0); - - // Copy the image data to a new entry. - NetUtil.asyncCopy(inputStream, outputStream, function (aResult) { - if (Components.isSuccessCode(aResult)) - targetEntry.markValid(); - - finish(); - }); - } - - this.getReadEntry(aSourceKey, function (aSourceEntry) { - sourceEntry = aSourceEntry; - copyDataWhenReady(); - }); - - this.getWriteEntry(aTargetKey, function (aTargetEntry) { - targetEntry = aTargetEntry; - copyDataWhenReady(); - }); - }, - /** * Opens the cache entry identified by the given key. * @param aKey The key identifying the desired cache entry. diff --git a/browser/components/thumbnails/PageThumbsProtocol.js b/browser/components/thumbnails/PageThumbsProtocol.js index 4cf06067b73a..d72e82798579 100644 --- a/browser/components/thumbnails/PageThumbsProtocol.js +++ b/browser/components/thumbnails/PageThumbsProtocol.js @@ -72,6 +72,14 @@ Protocol.prototype = { * @return The newly created channel. */ newChannel: function Proto_newChannel(aURI) { + let {url} = parseURI(aURI); + let file = PageThumbsStorage.getFileForURL(url); + + if (file.exists()) { + let fileuri = Services.io.newFileURI(file); + return Services.io.newChannelFromURI(fileuri); + } + return new Channel(aURI); }, diff --git a/browser/components/thumbnails/test/Makefile.in b/browser/components/thumbnails/test/Makefile.in index ac00a023a678..c7af21dc9a55 100644 --- a/browser/components/thumbnails/test/Makefile.in +++ b/browser/components/thumbnails/test/Makefile.in @@ -14,6 +14,7 @@ include $(topsrcdir)/config/rules.mk _BROWSER_FILES = \ browser_thumbnails_capture.js \ browser_thumbnails_redirect.js \ + browser_thumbnails_storage.js \ browser_thumbnails_bug726727.js \ head.js \ background_red.html \ diff --git a/browser/components/thumbnails/test/browser_thumbnails_redirect.js b/browser/components/thumbnails/test/browser_thumbnails_redirect.js index 54803e1e348a..7bc420c1ed62 100644 --- a/browser/components/thumbnails/test/browser_thumbnails_redirect.js +++ b/browser/components/thumbnails/test/browser_thumbnails_redirect.js @@ -4,9 +4,6 @@ const URL = "http://mochi.test:8888/browser/browser/components/thumbnails/" + "test/background_red_redirect.sjs"; -let cacheService = Cc["@mozilla.org/network/cache-service;1"] - .getService(Ci.nsICacheService); - /** * These tests ensure that we save and provide thumbnails for redirecting sites. */ @@ -19,33 +16,17 @@ function runTests() { yield addTab(URL); yield captureAndCheckColor(255, 0, 0, "we have a red thumbnail"); - // Wait until the referrer's thumbnail's cache entry has been written. - yield whenCacheEntryExists(URL); + // Wait until the referrer's thumbnail's file has been written. + yield whenFileExists(URL); yield checkThumbnailColor(URL, 255, 0, 0, "referrer has a red thumbnail"); } -function whenCacheEntryExists(aKey) { +function whenFileExists(aURL) { let callback = next; - checkCacheEntryExists(aKey, function (aExists) { - if (!aExists) - callback = function () whenCacheEntryExists(aKey); + let file = PageThumbsStorage.getFileForURL(aURL); + if (!file.exists()) + callback = function () whenFileExists(aURL); - executeSoon(callback); - }); -} - -function checkCacheEntryExists(aKey, aCallback) { - PageThumbsCache.getReadEntry(aKey, function (aEntry) { - let inputStream = aEntry && aEntry.openInputStream(0); - let exists = inputStream && inputStream.available(); - - if (inputStream) - inputStream.close(); - - if (aEntry) - aEntry.close(); - - aCallback(exists); - }); + executeSoon(callback); } diff --git a/browser/components/thumbnails/test/browser_thumbnails_storage.js b/browser/components/thumbnails/test/browser_thumbnails_storage.js new file mode 100644 index 000000000000..db91a980173e --- /dev/null +++ b/browser/components/thumbnails/test/browser_thumbnails_storage.js @@ -0,0 +1,89 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const URL = "http://mochi.test:8888/"; +const URL_COPY = URL + "#copy"; + +XPCOMUtils.defineLazyGetter(this, "Sanitizer", function () { + let tmp = {}; + Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader) + .loadSubScript("chrome://browser/content/sanitize.js", tmp); + return tmp.Sanitizer; +}); + +/** + * These tests ensure that the thumbnail storage is working as intended. + * Newly captured thumbnails should be saved as files and they should as well + * be removed when the user sanitizes their history. + */ +function runTests() { + clearHistory(); + + // create a thumbnail + yield addTab(URL); + yield whenFileExists(); + gBrowser.removeTab(gBrowser.selectedTab); + + // clear all browser history + yield clearHistory(); + + // create a thumbnail + yield addTab(URL); + yield whenFileExists(); + gBrowser.removeTab(gBrowser.selectedTab); + + // make sure copy() updates an existing file + PageThumbsStorage.copy(URL, URL_COPY); + let copy = PageThumbsStorage.getFileForURL(URL_COPY); + let mtime = copy.lastModifiedTime -= 60; + + PageThumbsStorage.copy(URL, URL_COPY); + isnot(PageThumbsStorage.getFileForURL(URL_COPY).lastModifiedTime, mtime, + "thumbnail file was updated"); + + // clear last 10 mins of history + yield clearHistory(true); + ok(!copy.exists(), "copy of thumbnail has been removed"); +} + +function clearHistory(aUseRange) { + let s = new Sanitizer(); + s.prefDomain = "privacy.cpd."; + + let prefs = gPrefService.getBranch(s.prefDomain); + prefs.setBoolPref("history", true); + prefs.setBoolPref("downloads", false); + prefs.setBoolPref("cache", false); + prefs.setBoolPref("cookies", false); + prefs.setBoolPref("formdata", false); + prefs.setBoolPref("offlineApps", false); + prefs.setBoolPref("passwords", false); + prefs.setBoolPref("sessions", false); + prefs.setBoolPref("siteSettings", false); + + if (aUseRange) { + let usec = Date.now() * 1000; + s.range = [usec - 10 * 60 * 1000 * 1000, usec]; + } + + s.sanitize(); + s.range = null; + + executeSoon(function () { + if (PageThumbsStorage.getFileForURL(URL).exists()) + clearHistory(aFile, aUseRange); + else + next(); + }); +} + +function whenFileExists() { + let callback = whenFileExists; + + let file = PageThumbsStorage.getFileForURL(URL); + if (file.exists() && file.fileSize) + callback = next; + + executeSoon(callback); +} diff --git a/browser/components/thumbnails/test/head.js b/browser/components/thumbnails/test/head.js index 6bfd76e7d300..6a4ee10335db 100644 --- a/browser/components/thumbnails/test/head.js +++ b/browser/components/thumbnails/test/head.js @@ -4,7 +4,7 @@ let tmp = {}; Cu.import("resource:///modules/PageThumbs.jsm", tmp); let PageThumbs = tmp.PageThumbs; -let PageThumbsCache = tmp.PageThumbsCache; +let PageThumbsStorage = tmp.PageThumbsStorage; registerCleanupFunction(function () { while (gBrowser.tabs.length > 1) From b96da93606b5807345b83b6c4d413600fab806fc Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Tue, 1 May 2012 16:34:57 +0100 Subject: [PATCH 067/159] Backout 080fc3a7cdfe (bug 744388) for xpcshell failures --- browser/components/nsBrowserGlue.js | 6 - browser/components/thumbnails/PageThumbs.jsm | 197 +++++++----------- .../thumbnails/PageThumbsProtocol.js | 8 - .../components/thumbnails/test/Makefile.in | 1 - .../test/browser_thumbnails_redirect.js | 33 ++- .../test/browser_thumbnails_storage.js | 89 -------- browser/components/thumbnails/test/head.js | 2 +- 7 files changed, 108 insertions(+), 228 deletions(-) delete mode 100644 browser/components/thumbnails/test/browser_thumbnails_storage.js diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index c1e0ac38a167..e6b325212317 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -68,9 +68,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils", XPCOMUtils.defineLazyModuleGetter(this, "webappsUI", "resource:///modules/webappsUI.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", - "resource:///modules/PageThumbs.jsm"); - const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser"; const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; @@ -361,8 +358,6 @@ BrowserGlue.prototype = { // Initialize webapps UI webappsUI.init(); - PageThumbs.init(); - Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); }, @@ -384,7 +379,6 @@ BrowserGlue.prototype = { _onProfileShutdown: function BG__onProfileShutdown() { this._shutdownPlaces(); this._sanitizer.onShutdown(); - PageThumbs.uninit(); }, // All initial windows have opened. diff --git a/browser/components/thumbnails/PageThumbs.jsm b/browser/components/thumbnails/PageThumbs.jsm index 92b364fb3b91..3330718d4e1a 100644 --- a/browser/components/thumbnails/PageThumbs.jsm +++ b/browser/components/thumbnails/PageThumbs.jsm @@ -4,7 +4,7 @@ "use strict"; -let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsStorage", "PageThumbsCache"]; +let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsCache"]; const Cu = Components.utils; const Cc = Components.classes; @@ -12,11 +12,6 @@ const Ci = Components.interfaces; const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; -/** - * Name of the directory in the profile that contains the thumbnails. - */ -const THUMBNAIL_DIRECTORY = "thumbnails"; - /** * The default background color for page thumbnails. */ @@ -30,28 +25,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", - "resource://gre/modules/FileUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", - "resource://gre/modules/PlacesUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "gCryptoHash", function () { - return Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash); -}); - -XPCOMUtils.defineLazyGetter(this, "gUnicodeConverter", function () { - let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] - .createInstance(Ci.nsIScriptableUnicodeConverter); - converter.charset = 'utf8'; - return converter; -}); - /** * Singleton providing functionality for capturing web page thumbnails and for * accessing them if already cached. */ let PageThumbs = { + /** * The calculated width and height of the thumbnails. */ @@ -73,14 +52,6 @@ let PageThumbs = { */ get contentType() "image/png", - init: function PageThumbs_init() { - PlacesUtils.history.addObserver(PageThumbsHistoryObserver, false); - }, - - uninit: function PageThumbs_uninit() { - PlacesUtils.history.removeObserver(PageThumbsHistoryObserver); - }, - /** * Gets the thumbnail image's url for a given web page's url. * @param aUrl The web page's url that is depicted in the thumbnail. @@ -153,14 +124,32 @@ let PageThumbs = { // Sync and therefore also redirect sources appear on the newtab // page. We also want thumbnails for those. if (url != originalURL) - PageThumbsStorage.copy(url, originalURL); + PageThumbsCache._copy(url, originalURL); } if (aCallback) aCallback(aSuccessful); } - PageThumbsStorage.write(url, aInputStream, finish); + // Get a writeable cache entry. + PageThumbsCache.getWriteEntry(url, function (aEntry) { + if (!aEntry) { + finish(false); + return; + } + + let outputStream = aEntry.openOutputStream(0); + + // Write the image data to the cache entry. + NetUtil.asyncCopy(aInputStream, outputStream, function (aResult) { + let success = Components.isSuccessCode(aResult); + if (success) + aEntry.markValid(); + + aEntry.close(); + finish(success); + }); + }); }); }, @@ -208,7 +197,7 @@ let PageThumbs = { */ _getThumbnailSize: function PageThumbs_getThumbnailSize() { if (!this._thumbnailWidth || !this._thumbnailHeight) { - let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"] + let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"] .getService(Ci.nsIScreenManager); let left = {}, top = {}, width = {}, height = {}; screenManager.primaryScreen.GetRect(left, top, width, height); @@ -219,88 +208,6 @@ let PageThumbs = { } }; -let PageThumbsStorage = { - getFileForURL: function Storage_getFileForURL(aURL) { - let hash = this._calculateMD5Hash(aURL); - let parts = [THUMBNAIL_DIRECTORY, hash[0], hash[1], hash.slice(2) + ".png"]; - return FileUtils.getFile("ProfD", parts); - }, - - write: function Storage_write(aURL, aDataStream, aCallback) { - let file = this.getFileForURL(aURL); - let fos = FileUtils.openSafeFileOutputStream(file); - - NetUtil.asyncCopy(aDataStream, fos, function (aResult) { - FileUtils.closeSafeFileOutputStream(fos); - aCallback(Components.isSuccessCode(aResult)); - }); - }, - - copy: function Storage_copy(aSourceURL, aTargetURL) { - let sourceFile = this.getFileForURL(aSourceURL); - let targetFile = this.getFileForURL(aTargetURL); - - try { - sourceFile.copyTo(targetFile.parent, targetFile.leafName); - } catch (e) { - /* We might not be permitted to write to the file. */ - } - }, - - remove: function Storage_remove(aURL) { - try { - this.getFileForURL(aURL).remove(false); - } catch (e) { - /* The file might not exist or we're not permitted to remove it. */ - } - }, - - wipe: function Storage_wipe() { - try { - FileUtils.getDir("ProfD", [THUMBNAIL_DIRECTORY]).remove(true); - } catch (e) { - /* The file might not exist or we're not permitted to remove it. */ - } - }, - - _calculateMD5Hash: function Storage_calculateMD5Hash(aValue) { - let hash = gCryptoHash; - let value = gUnicodeConverter.convertToByteArray(aValue); - - hash.init(hash.MD5); - hash.update(value, value.length); - return this._convertToHexString(hash.finish(false)); - }, - - _convertToHexString: function Storage_convertToHexString(aData) { - let hex = ""; - for (let i = 0; i < aData.length; i++) - hex += ("0" + aData.charCodeAt(i).toString(16)).slice(-2); - return hex; - }, - -}; - -let PageThumbsHistoryObserver = { - onDeleteURI: function Thumbnails_onDeleteURI(aURI, aGUID) { - PageThumbsStorage.remove(aURI.spec); - }, - - onClearHistory: function Thumbnails_onClearHistory() { - PageThumbsStorage.wipe(); - }, - - onTitleChanged: function () {}, - onBeginUpdateBatch: function () {}, - onEndUpdateBatch: function () {}, - onVisit: function () {}, - onBeforeDeleteURI: function () {}, - onPageChanged: function () {}, - onDeleteVisits: function () {}, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]) -}; - /** * A singleton handling the storage of page thumbnails. */ @@ -315,6 +222,64 @@ let PageThumbsCache = { this._openCacheEntry(aKey, Ci.nsICache.ACCESS_READ, aCallback); }, + /** + * Calls the given callback with a cache entry opened for writing. + * @param aKey The key identifying the desired cache entry. + * @param aCallback The callback that is called when the cache entry is ready. + */ + getWriteEntry: function Cache_getWriteEntry(aKey, aCallback) { + // Try to open the desired cache entry. + this._openCacheEntry(aKey, Ci.nsICache.ACCESS_WRITE, aCallback); + }, + + /** + * Copies an existing cache entry's data to a new cache entry. + * @param aSourceKey The key that contains the data to copy. + * @param aTargetKey The key that will be the copy of aSourceKey's data. + */ + _copy: function Cache_copy(aSourceKey, aTargetKey) { + let sourceEntry, targetEntry, waitingCount = 2; + + function finish() { + if (sourceEntry) + sourceEntry.close(); + + if (targetEntry) + targetEntry.close(); + } + + function copyDataWhenReady() { + if (--waitingCount > 0) + return; + + if (!sourceEntry || !targetEntry) { + finish(); + return; + } + + let inputStream = sourceEntry.openInputStream(0); + let outputStream = targetEntry.openOutputStream(0); + + // Copy the image data to a new entry. + NetUtil.asyncCopy(inputStream, outputStream, function (aResult) { + if (Components.isSuccessCode(aResult)) + targetEntry.markValid(); + + finish(); + }); + } + + this.getReadEntry(aSourceKey, function (aSourceEntry) { + sourceEntry = aSourceEntry; + copyDataWhenReady(); + }); + + this.getWriteEntry(aTargetKey, function (aTargetEntry) { + targetEntry = aTargetEntry; + copyDataWhenReady(); + }); + }, + /** * Opens the cache entry identified by the given key. * @param aKey The key identifying the desired cache entry. diff --git a/browser/components/thumbnails/PageThumbsProtocol.js b/browser/components/thumbnails/PageThumbsProtocol.js index d72e82798579..4cf06067b73a 100644 --- a/browser/components/thumbnails/PageThumbsProtocol.js +++ b/browser/components/thumbnails/PageThumbsProtocol.js @@ -72,14 +72,6 @@ Protocol.prototype = { * @return The newly created channel. */ newChannel: function Proto_newChannel(aURI) { - let {url} = parseURI(aURI); - let file = PageThumbsStorage.getFileForURL(url); - - if (file.exists()) { - let fileuri = Services.io.newFileURI(file); - return Services.io.newChannelFromURI(fileuri); - } - return new Channel(aURI); }, diff --git a/browser/components/thumbnails/test/Makefile.in b/browser/components/thumbnails/test/Makefile.in index c7af21dc9a55..ac00a023a678 100644 --- a/browser/components/thumbnails/test/Makefile.in +++ b/browser/components/thumbnails/test/Makefile.in @@ -14,7 +14,6 @@ include $(topsrcdir)/config/rules.mk _BROWSER_FILES = \ browser_thumbnails_capture.js \ browser_thumbnails_redirect.js \ - browser_thumbnails_storage.js \ browser_thumbnails_bug726727.js \ head.js \ background_red.html \ diff --git a/browser/components/thumbnails/test/browser_thumbnails_redirect.js b/browser/components/thumbnails/test/browser_thumbnails_redirect.js index 7bc420c1ed62..54803e1e348a 100644 --- a/browser/components/thumbnails/test/browser_thumbnails_redirect.js +++ b/browser/components/thumbnails/test/browser_thumbnails_redirect.js @@ -4,6 +4,9 @@ const URL = "http://mochi.test:8888/browser/browser/components/thumbnails/" + "test/background_red_redirect.sjs"; +let cacheService = Cc["@mozilla.org/network/cache-service;1"] + .getService(Ci.nsICacheService); + /** * These tests ensure that we save and provide thumbnails for redirecting sites. */ @@ -16,17 +19,33 @@ function runTests() { yield addTab(URL); yield captureAndCheckColor(255, 0, 0, "we have a red thumbnail"); - // Wait until the referrer's thumbnail's file has been written. - yield whenFileExists(URL); + // Wait until the referrer's thumbnail's cache entry has been written. + yield whenCacheEntryExists(URL); yield checkThumbnailColor(URL, 255, 0, 0, "referrer has a red thumbnail"); } -function whenFileExists(aURL) { +function whenCacheEntryExists(aKey) { let callback = next; - let file = PageThumbsStorage.getFileForURL(aURL); - if (!file.exists()) - callback = function () whenFileExists(aURL); + checkCacheEntryExists(aKey, function (aExists) { + if (!aExists) + callback = function () whenCacheEntryExists(aKey); - executeSoon(callback); + executeSoon(callback); + }); +} + +function checkCacheEntryExists(aKey, aCallback) { + PageThumbsCache.getReadEntry(aKey, function (aEntry) { + let inputStream = aEntry && aEntry.openInputStream(0); + let exists = inputStream && inputStream.available(); + + if (inputStream) + inputStream.close(); + + if (aEntry) + aEntry.close(); + + aCallback(exists); + }); } diff --git a/browser/components/thumbnails/test/browser_thumbnails_storage.js b/browser/components/thumbnails/test/browser_thumbnails_storage.js deleted file mode 100644 index db91a980173e..000000000000 --- a/browser/components/thumbnails/test/browser_thumbnails_storage.js +++ /dev/null @@ -1,89 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -const URL = "http://mochi.test:8888/"; -const URL_COPY = URL + "#copy"; - -XPCOMUtils.defineLazyGetter(this, "Sanitizer", function () { - let tmp = {}; - Cc["@mozilla.org/moz/jssubscript-loader;1"] - .getService(Ci.mozIJSSubScriptLoader) - .loadSubScript("chrome://browser/content/sanitize.js", tmp); - return tmp.Sanitizer; -}); - -/** - * These tests ensure that the thumbnail storage is working as intended. - * Newly captured thumbnails should be saved as files and they should as well - * be removed when the user sanitizes their history. - */ -function runTests() { - clearHistory(); - - // create a thumbnail - yield addTab(URL); - yield whenFileExists(); - gBrowser.removeTab(gBrowser.selectedTab); - - // clear all browser history - yield clearHistory(); - - // create a thumbnail - yield addTab(URL); - yield whenFileExists(); - gBrowser.removeTab(gBrowser.selectedTab); - - // make sure copy() updates an existing file - PageThumbsStorage.copy(URL, URL_COPY); - let copy = PageThumbsStorage.getFileForURL(URL_COPY); - let mtime = copy.lastModifiedTime -= 60; - - PageThumbsStorage.copy(URL, URL_COPY); - isnot(PageThumbsStorage.getFileForURL(URL_COPY).lastModifiedTime, mtime, - "thumbnail file was updated"); - - // clear last 10 mins of history - yield clearHistory(true); - ok(!copy.exists(), "copy of thumbnail has been removed"); -} - -function clearHistory(aUseRange) { - let s = new Sanitizer(); - s.prefDomain = "privacy.cpd."; - - let prefs = gPrefService.getBranch(s.prefDomain); - prefs.setBoolPref("history", true); - prefs.setBoolPref("downloads", false); - prefs.setBoolPref("cache", false); - prefs.setBoolPref("cookies", false); - prefs.setBoolPref("formdata", false); - prefs.setBoolPref("offlineApps", false); - prefs.setBoolPref("passwords", false); - prefs.setBoolPref("sessions", false); - prefs.setBoolPref("siteSettings", false); - - if (aUseRange) { - let usec = Date.now() * 1000; - s.range = [usec - 10 * 60 * 1000 * 1000, usec]; - } - - s.sanitize(); - s.range = null; - - executeSoon(function () { - if (PageThumbsStorage.getFileForURL(URL).exists()) - clearHistory(aFile, aUseRange); - else - next(); - }); -} - -function whenFileExists() { - let callback = whenFileExists; - - let file = PageThumbsStorage.getFileForURL(URL); - if (file.exists() && file.fileSize) - callback = next; - - executeSoon(callback); -} diff --git a/browser/components/thumbnails/test/head.js b/browser/components/thumbnails/test/head.js index 6a4ee10335db..6bfd76e7d300 100644 --- a/browser/components/thumbnails/test/head.js +++ b/browser/components/thumbnails/test/head.js @@ -4,7 +4,7 @@ let tmp = {}; Cu.import("resource:///modules/PageThumbs.jsm", tmp); let PageThumbs = tmp.PageThumbs; -let PageThumbsStorage = tmp.PageThumbsStorage; +let PageThumbsCache = tmp.PageThumbsCache; registerCleanupFunction(function () { while (gBrowser.tabs.length > 1) From 95a2642bca9a9e61f14a360089eee3951abc3937 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Tue, 1 May 2012 13:45:32 +0200 Subject: [PATCH 068/159] Bug 744388 - [Page Thumbnails] implement a custom storage, don't use the file cache; r=dietrich --- browser/components/nsBrowserGlue.js | 6 + browser/components/thumbnails/PageThumbs.jsm | 201 +++++++++++------- .../thumbnails/PageThumbsProtocol.js | 8 + .../components/thumbnails/test/Makefile.in | 1 + .../test/browser_thumbnails_redirect.js | 33 +-- .../test/browser_thumbnails_storage.js | 89 ++++++++ browser/components/thumbnails/test/head.js | 2 +- 7 files changed, 234 insertions(+), 106 deletions(-) create mode 100644 browser/components/thumbnails/test/browser_thumbnails_storage.js diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index e6b325212317..c1e0ac38a167 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -68,6 +68,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils", XPCOMUtils.defineLazyModuleGetter(this, "webappsUI", "resource:///modules/webappsUI.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", + "resource:///modules/PageThumbs.jsm"); + const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser"; const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; @@ -358,6 +361,8 @@ BrowserGlue.prototype = { // Initialize webapps UI webappsUI.init(); + PageThumbs.init(); + Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); }, @@ -379,6 +384,7 @@ BrowserGlue.prototype = { _onProfileShutdown: function BG__onProfileShutdown() { this._shutdownPlaces(); this._sanitizer.onShutdown(); + PageThumbs.uninit(); }, // All initial windows have opened. diff --git a/browser/components/thumbnails/PageThumbs.jsm b/browser/components/thumbnails/PageThumbs.jsm index 3330718d4e1a..64dc943ff6d3 100644 --- a/browser/components/thumbnails/PageThumbs.jsm +++ b/browser/components/thumbnails/PageThumbs.jsm @@ -4,7 +4,7 @@ "use strict"; -let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsCache"]; +let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsStorage", "PageThumbsCache"]; const Cu = Components.utils; const Cc = Components.classes; @@ -12,6 +12,11 @@ const Ci = Components.interfaces; const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; +/** + * Name of the directory in the profile that contains the thumbnails. + */ +const THUMBNAIL_DIRECTORY = "thumbnails"; + /** * The default background color for page thumbnails. */ @@ -25,11 +30,29 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", + "resource://gre/modules/PlacesUtils.jsm"); + +XPCOMUtils.defineLazyGetter(this, "gCryptoHash", function () { + return Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash); +}); + +XPCOMUtils.defineLazyGetter(this, "gUnicodeConverter", function () { + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = 'utf8'; + return converter; +}); + /** * Singleton providing functionality for capturing web page thumbnails and for * accessing them if already cached. */ let PageThumbs = { + _initialized: false, /** * The calculated width and height of the thumbnails. @@ -52,6 +75,20 @@ let PageThumbs = { */ get contentType() "image/png", + init: function PageThumbs_init() { + if (!this._initialized) { + this._initialized = true; + PlacesUtils.history.addObserver(PageThumbsHistoryObserver, false); + } + }, + + uninit: function PageThumbs_uninit() { + if (this._initialized) { + this._initialized = false; + PlacesUtils.history.removeObserver(PageThumbsHistoryObserver); + } + }, + /** * Gets the thumbnail image's url for a given web page's url. * @param aUrl The web page's url that is depicted in the thumbnail. @@ -124,32 +161,14 @@ let PageThumbs = { // Sync and therefore also redirect sources appear on the newtab // page. We also want thumbnails for those. if (url != originalURL) - PageThumbsCache._copy(url, originalURL); + PageThumbsStorage.copy(url, originalURL); } if (aCallback) aCallback(aSuccessful); } - // Get a writeable cache entry. - PageThumbsCache.getWriteEntry(url, function (aEntry) { - if (!aEntry) { - finish(false); - return; - } - - let outputStream = aEntry.openOutputStream(0); - - // Write the image data to the cache entry. - NetUtil.asyncCopy(aInputStream, outputStream, function (aResult) { - let success = Components.isSuccessCode(aResult); - if (success) - aEntry.markValid(); - - aEntry.close(); - finish(success); - }); - }); + PageThumbsStorage.write(url, aInputStream, finish); }); }, @@ -208,6 +227,88 @@ let PageThumbs = { } }; +let PageThumbsStorage = { + getFileForURL: function Storage_getFileForURL(aURL) { + let hash = this._calculateMD5Hash(aURL); + let parts = [THUMBNAIL_DIRECTORY, hash[0], hash[1], hash.slice(2) + ".png"]; + return FileUtils.getFile("ProfD", parts); + }, + + write: function Storage_write(aURL, aDataStream, aCallback) { + let file = this.getFileForURL(aURL); + let fos = FileUtils.openSafeFileOutputStream(file); + + NetUtil.asyncCopy(aDataStream, fos, function (aResult) { + FileUtils.closeSafeFileOutputStream(fos); + aCallback(Components.isSuccessCode(aResult)); + }); + }, + + copy: function Storage_copy(aSourceURL, aTargetURL) { + let sourceFile = this.getFileForURL(aSourceURL); + let targetFile = this.getFileForURL(aTargetURL); + + try { + sourceFile.copyTo(targetFile.parent, targetFile.leafName); + } catch (e) { + /* We might not be permitted to write to the file. */ + } + }, + + remove: function Storage_remove(aURL) { + try { + this.getFileForURL(aURL).remove(false); + } catch (e) { + /* The file might not exist or we're not permitted to remove it. */ + } + }, + + wipe: function Storage_wipe() { + try { + FileUtils.getDir("ProfD", [THUMBNAIL_DIRECTORY]).remove(true); + } catch (e) { + /* The file might not exist or we're not permitted to remove it. */ + } + }, + + _calculateMD5Hash: function Storage_calculateMD5Hash(aValue) { + let hash = gCryptoHash; + let value = gUnicodeConverter.convertToByteArray(aValue); + + hash.init(hash.MD5); + hash.update(value, value.length); + return this._convertToHexString(hash.finish(false)); + }, + + _convertToHexString: function Storage_convertToHexString(aData) { + let hex = ""; + for (let i = 0; i < aData.length; i++) + hex += ("0" + aData.charCodeAt(i).toString(16)).slice(-2); + return hex; + }, + +}; + +let PageThumbsHistoryObserver = { + onDeleteURI: function Thumbnails_onDeleteURI(aURI, aGUID) { + PageThumbsStorage.remove(aURI.spec); + }, + + onClearHistory: function Thumbnails_onClearHistory() { + PageThumbsStorage.wipe(); + }, + + onTitleChanged: function () {}, + onBeginUpdateBatch: function () {}, + onEndUpdateBatch: function () {}, + onVisit: function () {}, + onBeforeDeleteURI: function () {}, + onPageChanged: function () {}, + onDeleteVisits: function () {}, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]) +}; + /** * A singleton handling the storage of page thumbnails. */ @@ -222,64 +323,6 @@ let PageThumbsCache = { this._openCacheEntry(aKey, Ci.nsICache.ACCESS_READ, aCallback); }, - /** - * Calls the given callback with a cache entry opened for writing. - * @param aKey The key identifying the desired cache entry. - * @param aCallback The callback that is called when the cache entry is ready. - */ - getWriteEntry: function Cache_getWriteEntry(aKey, aCallback) { - // Try to open the desired cache entry. - this._openCacheEntry(aKey, Ci.nsICache.ACCESS_WRITE, aCallback); - }, - - /** - * Copies an existing cache entry's data to a new cache entry. - * @param aSourceKey The key that contains the data to copy. - * @param aTargetKey The key that will be the copy of aSourceKey's data. - */ - _copy: function Cache_copy(aSourceKey, aTargetKey) { - let sourceEntry, targetEntry, waitingCount = 2; - - function finish() { - if (sourceEntry) - sourceEntry.close(); - - if (targetEntry) - targetEntry.close(); - } - - function copyDataWhenReady() { - if (--waitingCount > 0) - return; - - if (!sourceEntry || !targetEntry) { - finish(); - return; - } - - let inputStream = sourceEntry.openInputStream(0); - let outputStream = targetEntry.openOutputStream(0); - - // Copy the image data to a new entry. - NetUtil.asyncCopy(inputStream, outputStream, function (aResult) { - if (Components.isSuccessCode(aResult)) - targetEntry.markValid(); - - finish(); - }); - } - - this.getReadEntry(aSourceKey, function (aSourceEntry) { - sourceEntry = aSourceEntry; - copyDataWhenReady(); - }); - - this.getWriteEntry(aTargetKey, function (aTargetEntry) { - targetEntry = aTargetEntry; - copyDataWhenReady(); - }); - }, - /** * Opens the cache entry identified by the given key. * @param aKey The key identifying the desired cache entry. diff --git a/browser/components/thumbnails/PageThumbsProtocol.js b/browser/components/thumbnails/PageThumbsProtocol.js index 4cf06067b73a..d72e82798579 100644 --- a/browser/components/thumbnails/PageThumbsProtocol.js +++ b/browser/components/thumbnails/PageThumbsProtocol.js @@ -72,6 +72,14 @@ Protocol.prototype = { * @return The newly created channel. */ newChannel: function Proto_newChannel(aURI) { + let {url} = parseURI(aURI); + let file = PageThumbsStorage.getFileForURL(url); + + if (file.exists()) { + let fileuri = Services.io.newFileURI(file); + return Services.io.newChannelFromURI(fileuri); + } + return new Channel(aURI); }, diff --git a/browser/components/thumbnails/test/Makefile.in b/browser/components/thumbnails/test/Makefile.in index ac00a023a678..c7af21dc9a55 100644 --- a/browser/components/thumbnails/test/Makefile.in +++ b/browser/components/thumbnails/test/Makefile.in @@ -14,6 +14,7 @@ include $(topsrcdir)/config/rules.mk _BROWSER_FILES = \ browser_thumbnails_capture.js \ browser_thumbnails_redirect.js \ + browser_thumbnails_storage.js \ browser_thumbnails_bug726727.js \ head.js \ background_red.html \ diff --git a/browser/components/thumbnails/test/browser_thumbnails_redirect.js b/browser/components/thumbnails/test/browser_thumbnails_redirect.js index 54803e1e348a..7bc420c1ed62 100644 --- a/browser/components/thumbnails/test/browser_thumbnails_redirect.js +++ b/browser/components/thumbnails/test/browser_thumbnails_redirect.js @@ -4,9 +4,6 @@ const URL = "http://mochi.test:8888/browser/browser/components/thumbnails/" + "test/background_red_redirect.sjs"; -let cacheService = Cc["@mozilla.org/network/cache-service;1"] - .getService(Ci.nsICacheService); - /** * These tests ensure that we save and provide thumbnails for redirecting sites. */ @@ -19,33 +16,17 @@ function runTests() { yield addTab(URL); yield captureAndCheckColor(255, 0, 0, "we have a red thumbnail"); - // Wait until the referrer's thumbnail's cache entry has been written. - yield whenCacheEntryExists(URL); + // Wait until the referrer's thumbnail's file has been written. + yield whenFileExists(URL); yield checkThumbnailColor(URL, 255, 0, 0, "referrer has a red thumbnail"); } -function whenCacheEntryExists(aKey) { +function whenFileExists(aURL) { let callback = next; - checkCacheEntryExists(aKey, function (aExists) { - if (!aExists) - callback = function () whenCacheEntryExists(aKey); + let file = PageThumbsStorage.getFileForURL(aURL); + if (!file.exists()) + callback = function () whenFileExists(aURL); - executeSoon(callback); - }); -} - -function checkCacheEntryExists(aKey, aCallback) { - PageThumbsCache.getReadEntry(aKey, function (aEntry) { - let inputStream = aEntry && aEntry.openInputStream(0); - let exists = inputStream && inputStream.available(); - - if (inputStream) - inputStream.close(); - - if (aEntry) - aEntry.close(); - - aCallback(exists); - }); + executeSoon(callback); } diff --git a/browser/components/thumbnails/test/browser_thumbnails_storage.js b/browser/components/thumbnails/test/browser_thumbnails_storage.js new file mode 100644 index 000000000000..db91a980173e --- /dev/null +++ b/browser/components/thumbnails/test/browser_thumbnails_storage.js @@ -0,0 +1,89 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const URL = "http://mochi.test:8888/"; +const URL_COPY = URL + "#copy"; + +XPCOMUtils.defineLazyGetter(this, "Sanitizer", function () { + let tmp = {}; + Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader) + .loadSubScript("chrome://browser/content/sanitize.js", tmp); + return tmp.Sanitizer; +}); + +/** + * These tests ensure that the thumbnail storage is working as intended. + * Newly captured thumbnails should be saved as files and they should as well + * be removed when the user sanitizes their history. + */ +function runTests() { + clearHistory(); + + // create a thumbnail + yield addTab(URL); + yield whenFileExists(); + gBrowser.removeTab(gBrowser.selectedTab); + + // clear all browser history + yield clearHistory(); + + // create a thumbnail + yield addTab(URL); + yield whenFileExists(); + gBrowser.removeTab(gBrowser.selectedTab); + + // make sure copy() updates an existing file + PageThumbsStorage.copy(URL, URL_COPY); + let copy = PageThumbsStorage.getFileForURL(URL_COPY); + let mtime = copy.lastModifiedTime -= 60; + + PageThumbsStorage.copy(URL, URL_COPY); + isnot(PageThumbsStorage.getFileForURL(URL_COPY).lastModifiedTime, mtime, + "thumbnail file was updated"); + + // clear last 10 mins of history + yield clearHistory(true); + ok(!copy.exists(), "copy of thumbnail has been removed"); +} + +function clearHistory(aUseRange) { + let s = new Sanitizer(); + s.prefDomain = "privacy.cpd."; + + let prefs = gPrefService.getBranch(s.prefDomain); + prefs.setBoolPref("history", true); + prefs.setBoolPref("downloads", false); + prefs.setBoolPref("cache", false); + prefs.setBoolPref("cookies", false); + prefs.setBoolPref("formdata", false); + prefs.setBoolPref("offlineApps", false); + prefs.setBoolPref("passwords", false); + prefs.setBoolPref("sessions", false); + prefs.setBoolPref("siteSettings", false); + + if (aUseRange) { + let usec = Date.now() * 1000; + s.range = [usec - 10 * 60 * 1000 * 1000, usec]; + } + + s.sanitize(); + s.range = null; + + executeSoon(function () { + if (PageThumbsStorage.getFileForURL(URL).exists()) + clearHistory(aFile, aUseRange); + else + next(); + }); +} + +function whenFileExists() { + let callback = whenFileExists; + + let file = PageThumbsStorage.getFileForURL(URL); + if (file.exists() && file.fileSize) + callback = next; + + executeSoon(callback); +} diff --git a/browser/components/thumbnails/test/head.js b/browser/components/thumbnails/test/head.js index 6bfd76e7d300..6a4ee10335db 100644 --- a/browser/components/thumbnails/test/head.js +++ b/browser/components/thumbnails/test/head.js @@ -4,7 +4,7 @@ let tmp = {}; Cu.import("resource:///modules/PageThumbs.jsm", tmp); let PageThumbs = tmp.PageThumbs; -let PageThumbsCache = tmp.PageThumbsCache; +let PageThumbsStorage = tmp.PageThumbsStorage; registerCleanupFunction(function () { while (gBrowser.tabs.length > 1) From c3b7194898fe035d798050ad2631252b0d4f63ef Mon Sep 17 00:00:00 2001 From: Jonathan Griffin Date: Tue, 1 May 2012 12:25:34 -0700 Subject: [PATCH 069/159] Bug 750843 - Update marionette for ICS emulator, a=testonly, npotb --- testing/marionette/client/marionette/emulator.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/testing/marionette/client/marionette/emulator.py b/testing/marionette/client/marionette/emulator.py index fff221e8825a..7df2a98aad2c 100644 --- a/testing/marionette/client/marionette/emulator.py +++ b/testing/marionette/client/marionette/emulator.py @@ -36,24 +36,24 @@ class Emulator(object): raise Exception('Must define B2G_HOME or pass the homedir parameter') self.adb = os.path.join(self.homedir, - 'glue/gonk/out/host/linux-x86/bin/adb') + 'glue/gonk-ics/out/host/linux-x86/bin/adb') if not os.access(self.adb, os.F_OK): self.adb = os.path.join(self.homedir, 'bin/adb') self.binary = os.path.join(self.homedir, - 'glue/gonk/out/host/linux-x86/bin/emulator') + 'glue/gonk-ics/out/host/linux-x86/bin/emulator') if not os.access(self.binary, os.F_OK): self.binary = os.path.join(self.homedir, 'bin/emulator') self._check_file(self.binary) self.kernelImg = os.path.join(self.homedir, - 'boot/kernel-android-qemu/arch/arm/boot/zImage') + 'glue/gonk-ics/prebuilts/qemu-kernel/arm/kernel-qemu-armv7') if not os.access(self.kernelImg, os.F_OK): - self.kernelImg = os.path.join(self.homedir, 'zImage') + self.kernelImg = os.path.join(self.homedir, 'kernel-qemu-armv7') self._check_file(self.kernelImg) self.sysDir = os.path.join(self.homedir, - 'glue/gonk/out/target/product/generic/') + 'glue/gonk-ics/out/target/product/generic/') if not os.access(self.sysDir, os.F_OK): self.sysDir = os.path.join(self.homedir, 'generic/') self._check_file(self.sysDir) From 2a47586403f89a51e7f7bda53d13ca3c68f4dc43 Mon Sep 17 00:00:00 2001 From: Malini Das Date: Tue, 1 May 2012 12:37:34 -0700 Subject: [PATCH 070/159] Bug 750553 - Rename getAttributeValue to getElementAttribute, r=jgriffin, a=testonly, npotb --- testing/marionette/atoms/atoms.js | 4 ++-- testing/marionette/client/marionette/marionette.py | 2 +- testing/marionette/marionette-actors.js | 8 ++++---- testing/marionette/marionette-listener.js | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/testing/marionette/atoms/atoms.js b/testing/marionette/atoms/atoms.js index f09d9c04cf94..406851dfc08b 100644 --- a/testing/marionette/atoms/atoms.js +++ b/testing/marionette/atoms/atoms.js @@ -150,8 +150,8 @@ function Z(a,b,c){a.va=i;return Rb(a,b,a.A,pd(a,b),c,h)}function pd(a,b){if(!(b (b=zb(a),b=new C(b.width/2,b.height/2));c=c||new od;c.move(a,b);c.z!==k&&g(new y(13,"Cannot press more then one button or an already pressed button."));c.z=0;c.ha=c.m();!qb()&&(P(c.m(),"OPTION")||P(c.m(),"SELECT"))?a=i:(a=E(c.m()).activeElement,a=(b=Z(c,lc))&&a!=E(c.m()).activeElement?l:b);if(a&&(a=c.ba||c.l,b=E(a).activeElement,a!=b)){if(b&&u(b.blur))try{b.blur()}catch(B){g(B)}u(a.focus)&&a.focus()}c.z===k&&g(new y(13,"Cannot release a button when no button is pressed."));Z(c,nc);if(0==c.z&&c.m()== c.ha){b=c.A;d=pd(c,ic);if(Ob(c.l,i)&&Hb(c.l)){a=k;if(Yb)for(e=c.l;e;e=e.parentNode)if(P(e,"A")){a=e;break}else{a:{if(P(e,"INPUT")&&(f=e.type.toLowerCase(),"submit"==f||"image"==f)){f=i;break a}if(P(e,"BUTTON")&&(f=e.type.toLowerCase(),"submit"==f)){f=i;break a}f=l}if(f)break}if(e=Bb(c.l)){e=c.l;Bb(e)||g(new y(15,"Element is not selectable"));f="selected";m=e.type&&e.type.toLowerCase();if("checkbox"==m||"radio"==m)f="checked";e=!!Eb(e,f)}if(c.ba&&(f=c.ba,!e||f.multiple))c.l.selected=!e,Ub(f,hc);Rb(c, ic,b,d)&&a&&ac(a)&&(b=a.href,d=G(E(a)),a.target?d.open(b,a.target):d.location.href=b)}c.Z&&Z(c,kc);c.Z=!c.Z}else 2==c.z&&Z(c,jc);c.z=k;c.ha=k}var ud=["_"],$=q;!(ud[0]in $)&&$.execScript&&$.execScript("var "+ud[0]);for(var wd;ud.length&&(wd=ud.shift());)!ud.length&&r(td)?$[wd]=td:$=$[wd]?$[wd]:$[wd]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);} -//getAttributeValue -var getAttributeValue = function(){return function(){var f=null,g=!1,h=this; +//getElementAttribute +var getElementAttribute = function(){return function(){var f=null,g=!1,h=this; function i(a){var c=typeof a;if("object"==c)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return c;var b=Object.prototype.toString.call(a);if("[object Window]"==b)return"object";if("[object Array]"==b||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==b||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if("function"== c&&"undefined"==typeof a.call)return"object";return c}function j(a,c){function b(){}b.prototype=c.prototype;a.f=c.prototype;a.prototype=new b};function k(a,c){for(var b=1;b Date: Tue, 1 May 2012 12:50:17 -0700 Subject: [PATCH 071/159] Bug 750302 - DeviceManager files should have new-style license boilerplate, r=jmaher, a=android-only --- build/mobile/devicemanager.py | 41 +++----------------------------- build/mobile/devicemanagerADB.py | 4 ++++ build/mobile/devicemanagerSUT.py | 41 +++----------------------------- build/mobile/droid.py | 41 +++----------------------------- 4 files changed, 13 insertions(+), 114 deletions(-) diff --git a/build/mobile/devicemanager.py b/build/mobile/devicemanager.py index 4a6ef7378526..f735b984c55c 100755 --- a/build/mobile/devicemanager.py +++ b/build/mobile/devicemanager.py @@ -1,41 +1,6 @@ -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is Test Automation Framework. -# -# The Initial Developer of the Original Code is Joel Maher. -# -# Portions created by the Initial Developer are Copyright (C) 2009 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Joel Maher (Original Developer) -# Clint Talbert -# Mark Cote -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. import time import hashlib diff --git a/build/mobile/devicemanagerADB.py b/build/mobile/devicemanagerADB.py index 37d803ec28f9..d93846f8557d 100644 --- a/build/mobile/devicemanagerADB.py +++ b/build/mobile/devicemanagerADB.py @@ -1,3 +1,7 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + import subprocess from devicemanager import DeviceManager, DMError, _pop_last_line import re diff --git a/build/mobile/devicemanagerSUT.py b/build/mobile/devicemanagerSUT.py index d2a26a113b43..c1f3c9f5eb38 100644 --- a/build/mobile/devicemanagerSUT.py +++ b/build/mobile/devicemanagerSUT.py @@ -1,41 +1,6 @@ -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is Test Automation Framework. -# -# The Initial Developer of the Original Code is Joel Maher. -# -# Portions created by the Initial Developer are Copyright (C) 2009 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Joel Maher (Original Developer) -# Clint Talbert -# Mark Cote -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. import socket import SocketServer diff --git a/build/mobile/droid.py b/build/mobile/droid.py index ebf07d973378..8b4ba054a3e7 100644 --- a/build/mobile/droid.py +++ b/build/mobile/droid.py @@ -1,41 +1,6 @@ -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is Test Automation Framework. -# -# The Initial Developer of the Original Code is -# Mozilla foundation -# -# Portions created by the Initial Developer are Copyright (C) 2009 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Joel Maher (Original Developer) -# William Lachance -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. from devicemanagerADB import DeviceManagerADB from devicemanagerSUT import DeviceManagerSUT From 16fa213e3d99771d437a3ffa23cf777b3e9f695f Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Tue, 1 May 2012 13:59:07 -0700 Subject: [PATCH 072/159] Bug 747023 - Install software notification doorhanger popup can appear from page in background tab. r=mfinkle a=android-only --- mobile/android/chrome/content/browser.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 1a8900b58bf2..d6a854d9aaf6 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -3378,6 +3378,11 @@ var XPInstallObserver = { break; case "addon-install-blocked": let installInfo = aSubject.QueryInterface(Ci.amIWebInstallInfo); + let win = installInfo.originatingWindow; + let tab = BrowserApp.getTabForWindow(win.top); + if (!tab) + return; + let host = installInfo.originatingURI.host; let brandShortName = Strings.brand.GetStringFromName("brandShortName"); @@ -3417,7 +3422,7 @@ var XPInstallObserver = { } }]; } - NativeWindow.doorhanger.show(message, aTopic, buttons); + NativeWindow.doorhanger.show(message, aTopic, buttons, tab.id); break; } }, From 87300281b7b902973fead0e6f5da469e8d121253 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Tue, 1 May 2012 14:56:08 -0700 Subject: [PATCH 073/159] Bug 742267 - Restore AwesomeBar's cursor position when gaining input focus. r=blassey a=android-only --- mobile/android/base/AwesomeBar.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mobile/android/base/AwesomeBar.java b/mobile/android/base/AwesomeBar.java index 19b07ea4dc18..23c4a202ff3b 100644 --- a/mobile/android/base/AwesomeBar.java +++ b/mobile/android/base/AwesomeBar.java @@ -40,7 +40,6 @@ package org.mozilla.gecko; import android.app.Activity; -import android.app.ActionBar; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; @@ -51,7 +50,6 @@ import android.content.res.Configuration; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.os.Build; import android.os.Bundle; import android.text.Editable; import android.text.Spanned; @@ -73,7 +71,6 @@ import android.widget.Button; import android.widget.EditText; import android.widget.ExpandableListView; import android.widget.ImageButton; -import android.widget.RelativeLayout; import android.widget.ListView; import android.widget.TabWidget; import android.widget.Toast; @@ -398,15 +395,21 @@ public class AwesomeBar extends GeckoActivity implements GeckoEventListener { selEnd = mText.getSelectionEnd(); } - // Return focus to the edit box, and dispatch the event to it - mText.requestFocusFromTouch(); - if (selStart >= 0) { // Restore the selection, which gets lost due to the focus switch mText.setSelection(selStart, selEnd); } + // Manually dispatch the key event to the AwesomeBar before restoring (default) input + // focus. dispatchKeyEvent() will update AwesomeBar's cursor position. mText.dispatchKeyEvent(event); + int newCursorPos = mText.getSelectionEnd(); + + // requestFocusFromTouch() will select all AwesomeBar text, so we must restore cursor + // position so subsequent typing does not overwrite all text. + mText.requestFocusFromTouch(); + mText.setSelection(newCursorPos); + return true; } } From 694b255813ab102a45aaf638f8145d7f58867f19 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 1 May 2012 15:19:32 -0700 Subject: [PATCH 074/159] Bug 749215: Install the debug server jsms as symlinks, when appropriate. r=rcampbell --- toolkit/devtools/debugger/Makefile.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toolkit/devtools/debugger/Makefile.in b/toolkit/devtools/debugger/Makefile.in index 43508985e69e..871e93d4a89f 100644 --- a/toolkit/devtools/debugger/Makefile.in +++ b/toolkit/devtools/debugger/Makefile.in @@ -72,5 +72,5 @@ endif include $(topsrcdir)/config/rules.mk libs:: - $(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools - $(NSINSTALL) $(srcdir)/server/*.jsm $(FINAL_TARGET)/modules/devtools + $(INSTALL) $(IFLAGS1) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools + $(INSTALL) $(IFLAGS1) $(srcdir)/server/*.jsm $(FINAL_TARGET)/modules/devtools From 94f1f2174d4f5fcc1c60abc2df83beca4bc548a4 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 1 May 2012 15:29:48 -0700 Subject: [PATCH 075/159] Bug 749258: Have toolkit/devtools/debugger xpcshell tests register a listener for Components.utils.reportError, so tests fail when they throw an exception. r=past --- toolkit/devtools/debugger/dbg-client.jsm | 8 ++-- .../devtools/debugger/server/dbg-server.js | 18 +++++++- .../devtools/debugger/tests/unit/head_dbg.js | 46 +++++++++++++++++++ 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/toolkit/devtools/debugger/dbg-client.jsm b/toolkit/devtools/debugger/dbg-client.jsm index 36156207e2db..c81b1699afb7 100644 --- a/toolkit/devtools/debugger/dbg-client.jsm +++ b/toolkit/devtools/debugger/dbg-client.jsm @@ -375,10 +375,10 @@ DebuggerClient.prototype = { */ request: function DC_request(aRequest, aOnResponse) { if (!this._connected) { - throw "Have not yet received a hello packet from the server."; + throw Error("Have not yet received a hello packet from the server."); } if (!aRequest.to) { - throw "Request packet has no destination."; + throw Error("Request packet has no destination."); } this._pendingRequests.push({ to: aRequest.to, @@ -449,7 +449,7 @@ DebuggerClient.prototype = { onResponse(aPacket); } } catch(ex) { - dumpn("Error handling response: " + ex + " - " + ex.stack); + dumpn("Error handling response: " + ex + " - stack:\n" + ex.stack); Cu.reportError(ex); } @@ -536,7 +536,7 @@ ThreadClient.prototype = { _assertPaused: function TC_assertPaused(aCommand) { if (!this.paused) { - throw aCommand + " command sent while not paused."; + throw Error(aCommand + " command sent while not paused."); } }, diff --git a/toolkit/devtools/debugger/server/dbg-server.js b/toolkit/devtools/debugger/server/dbg-server.js index 49591d44f2ef..6afaaa367711 100644 --- a/toolkit/devtools/debugger/server/dbg-server.js +++ b/toolkit/devtools/debugger/server/dbg-server.js @@ -63,6 +63,17 @@ function dbg_assert(cond, e) { } } +/* Turn the error e into a string, without fail. */ +function safeErrorString(aError) { + try { + var s = aError.toString(); + if (typeof s === "string") + return s; + } catch (ee) { } + + return ""; +} + loadSubScript.call(this, "chrome://global/content/devtools/dbg-transport.js"); // XPCOM constructors @@ -445,11 +456,14 @@ DebuggerServerConnection.prototype = { } catch(e) { Cu.reportError(e); ret = { error: "unknownError", - message: "An unknown error has occurred while processing request." }; + message: ("error occurred while processing '" + aPacket.type + + "' request: " + safeErrorString(e)) }; } } else { ret = { error: "unrecognizedPacketType", - message: 'Actor "' + actor.actorID + '" does not recognize the packet type "' + aPacket.type + '"' }; + message: ('Actor "' + actor.actorID + + '" does not recognize the packet type "' + + aPacket.type + '"') }; } if (!ret) { diff --git a/toolkit/devtools/debugger/tests/unit/head_dbg.js b/toolkit/devtools/debugger/tests/unit/head_dbg.js index 6ff2ff35720a..eb96facf6acf 100644 --- a/toolkit/devtools/debugger/tests/unit/head_dbg.js +++ b/toolkit/devtools/debugger/tests/unit/head_dbg.js @@ -16,6 +16,52 @@ Services.prefs.setBoolPref("devtools.debugger.log", true); Cu.import("resource:///modules/devtools/dbg-server.jsm"); Cu.import("resource:///modules/devtools/dbg-client.jsm"); +// Convert an nsIScriptError 'aFlags' value into an appropriate string. +function scriptErrorFlagsToKind(aFlags) { + var kind; + if (aFlags & Ci.nsIScriptError.warningFlag) + kind = "warning"; + if (aFlags & Ci.nsIScriptError.exceptionFlag) + kind = "exception"; + else + kind = "error"; + + if (aFlags & Ci.nsIScriptError.strictFlag) + kind = "strict " + kind; + + return kind; +} + +// Register a console listener, so console messages don't just disappear +// into the ether. +let errorCount = 0; +let listener = { + observe: function (aMessage) { + errorCount++; + try { + // If we've been given an nsIScriptError, then we can print out + // something nicely formatted, for tools like Emacs to pick up. + var scriptError = aMessage.QueryInterface(Ci.nsIScriptError); + dump(aMessage.sourceName + ":" + aMessage.lineNumber + ": " + + scriptErrorFlagsToKind(aMessage.flags) + ": " + + aMessage.errorMessage + "\n"); + var string = aMessage.errorMessage; + } catch (x) { + // Be a little paranoid with message, as the whole goal here is to lose + // no information. + try { + var string = "" + aMessage.message; + } catch (x) { + var string = ""; + } + } + + do_throw("head_dbg.js got console message: " + string + "\n"); + } +}; + +let consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService); +consoleService.registerListener(listener); function check_except(func) { From 62c505068c57f7ac09d3b40d8daab1d6d92b507a Mon Sep 17 00:00:00 2001 From: Panos Astithas Date: Tue, 1 May 2012 15:31:00 -0700 Subject: [PATCH 076/159] Bug 749258: Fix debugger server tests exposed as broken when we start listening for errors. r=dcamp --- toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js | 6 ++---- .../devtools/debugger/tests/unit/test_threadlifetime-05.js | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js b/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js index ab5df24536b5..2aecc881b111 100644 --- a/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js +++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js @@ -27,8 +27,8 @@ function run_test() function test_breakpoint_running() { - let path = getFilePath('test_breakpoint-01.js'); - let location = { url: path, line: gDebuggee.line0 + 3}; + let path = getFilePath('test_breakpoint-02.js'); + let location = { url: path, line: gDebuggee.line0 + 2}; gDebuggee.eval("var line0 = Error().lineNumber;\n" + "var a = 1;\n" + // line0 + 1 @@ -37,8 +37,6 @@ function test_breakpoint_running() // Setting the breakpoint later should interrupt the debuggee. gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) { do_check_eq(aPacket.type, "paused"); - do_check_eq(aPacket.frame.where.url, path); - do_check_eq(aPacket.frame.where.line, location); do_check_eq(aPacket.why.type, "interrupted"); }); diff --git a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js index e0796fe830c2..a6b056e9b527 100644 --- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js +++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js @@ -70,10 +70,10 @@ function release_grips(aFrameArgs, aThreadGrips) arg_grips(aFrameArgs, function (aNewGrips) { for (let i = 0; i < aNewGrips.length; i++) { do_check_neq(aThreadGrips[i].actor, aNewGrips[i].actor); - gThreadClient.resume(function () { - finishClient(gClient); - }); } + gThreadClient.resume(function () { + finishClient(gClient); + }); }); }); }); From e9da94f67150e45ffd08e18c4eb6899b157ec3f4 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 1 May 2012 16:54:45 -0700 Subject: [PATCH 077/159] Bug 750368: Help 'make xpcshell-tests' find 'mozinfo' Python module. r=ted --- config/rules.mk | 6 +++--- js/src/config/rules.mk | 6 +++--- testing/testsuite-targets.mk | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config/rules.mk b/config/rules.mk index c52223500a74..61f5496d1498 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -112,7 +112,7 @@ testxpcsrcdir = $(topsrcdir)/testing/xpcshell # See also testsuite-targets.mk 'xpcshell-tests' target for global execution. xpcshell-tests: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ @@ -142,7 +142,7 @@ xpcshell-tests-remote: # attach a debugger and then start the test. check-interactive: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ @@ -155,7 +155,7 @@ check-interactive: # Execute a single test, specified in $(SOLO_FILE) check-one: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk index c52223500a74..61f5496d1498 100644 --- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -112,7 +112,7 @@ testxpcsrcdir = $(topsrcdir)/testing/xpcshell # See also testsuite-targets.mk 'xpcshell-tests' target for global execution. xpcshell-tests: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ @@ -142,7 +142,7 @@ xpcshell-tests-remote: # attach a debugger and then start the test. check-interactive: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ @@ -155,7 +155,7 @@ check-interactive: # Execute a single test, specified in $(SOLO_FILE) check-one: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 9a869a8e4367..194ed384ce01 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -239,7 +239,7 @@ GARBAGE += $(addsuffix .log,$(MOCHITESTS) reftest crashtest jstestbrowser) # Usage: |make [TEST_PATH=...] [EXTRA_TEST_ARGS=...] xpcshell-tests|. xpcshell-tests: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(topsrcdir)/testing/xpcshell/runxpcshelltests.py \ --manifest=$(DEPTH)/_tests/xpcshell/xpcshell.ini \ --build-info-json=$(DEPTH)/mozinfo.json \ From eb98c92b84794728923de5bd64f33d2dd7cd2037 Mon Sep 17 00:00:00 2001 From: Mark Finkle Date: Tue, 1 May 2012 20:20:46 -0400 Subject: [PATCH 078/159] Bug 750243 - Make sure target.currentURI is not null before saving an image r=wesj a=android-only --- mobile/android/chrome/content/browser.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index d6a854d9aaf6..8b2f987cdc90 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1140,8 +1140,6 @@ var NativeWindow = { _contextId: 0, // id to assign to new context menu items if they are added init: function() { - this.imageContext = this.SelectorContext("img"); - Services.obs.addObserver(this, "Gesture:LongPress", false); // TODO: These should eventually move into more appropriate classes @@ -1186,18 +1184,17 @@ var NativeWindow = { }); this.add(Strings.browser.GetStringFromName("contextmenu.saveImage"), - this.imageContext, + this.imageSaveableContext, function(aTarget) { let imageCache = Cc["@mozilla.org/image/cache;1"].getService(Ci.imgICache); let props = imageCache.findEntryProperties(aTarget.currentURI, aTarget.ownerDocument.characterSet); - var contentDisposition = ""; - var type = ""; + let contentDisposition = ""; + let type = ""; try { String(props.get("content-disposition", Ci.nsISupportsCString)); String(props.get("type", Ci.nsISupportsCString)); } catch(ex) { } - var browser = BrowserApp.getBrowserForDocument(aTarget.ownerDocument); - ContentAreaUtils.internalSave(aTarget.currentURI.spec, null, null, contentDisposition, type, false, "SaveImageTitle", null, browser.documentURI, true, null); + ContentAreaUtils.internalSave(aTarget.currentURI.spec, null, null, contentDisposition, type, false, "SaveImageTitle", null, aTarget.ownerDocument.documentURIObject, true, null); }); }, @@ -1285,6 +1282,16 @@ var NativeWindow = { } }, + imageSaveableContext: { + matches: function imageSaveableContextMatches(aElement) { + if (aElement instanceof Ci.nsIImageLoadingContent && aElement.currentURI) { + // The image must be loaded to allow saving + let request = aElement.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST); + return (request && (request.imageStatus & request.STATUS_SIZE_AVAILABLE)); + } + } + }, + _sendToContent: function(aX, aY) { // initially we look for nearby clickable elements. If we don't find one we fall back to using whatever this click was on let rootElement = ElementTouchHelper.elementFromPoint(BrowserApp.selectedBrowser.contentWindow, aX, aY); From fd55dbdfcd68b237be9245d2507dc3c15248ed7c Mon Sep 17 00:00:00 2001 From: Serge Gautherie Date: Wed, 2 May 2012 15:39:24 +0200 Subject: [PATCH 079/159] Bug 747668. (Ev1) XPFE autocomplete.xml: Move code into searchParam. r=neil. DONTBUILD (a=npotb). --- .../autocomplete/resources/content/autocomplete.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/xpfe/components/autocomplete/resources/content/autocomplete.xml b/xpfe/components/autocomplete/resources/content/autocomplete.xml index 6cebcfb05cf7..873458d5bc4d 100644 --- a/xpfe/components/autocomplete/resources/content/autocomplete.xml +++ b/xpfe/components/autocomplete/resources/content/autocomplete.xml @@ -139,6 +139,10 @@ onset="this.setAttribute('timeout', val); return val;" onget="return parseInt(this.getAttribute('timeout')) || 0;"/> + + Date: Tue, 1 May 2012 22:17:31 -0400 Subject: [PATCH 080/159] Bug 735970 - Add xpcshell tests for version downgrades. r=rstrong, a=test-only. --- .../update/test/unit/data/old_version_mar.mar | Bin 0 -> 421 bytes .../unit/data/wrong_product_channel_mar.mar | Bin 0 -> 421 bytes .../update/test/unit/head_update.js.in | 5 +- .../unit/test_0113_versionDowngradeCheck.js | 65 ++++++++++++++++++ .../unit/test_0114_productChannelCheck.js | 65 ++++++++++++++++++ .../test/unit/xpcshell_updater_windows.ini | 2 + 6 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 toolkit/mozapps/update/test/unit/data/old_version_mar.mar create mode 100644 toolkit/mozapps/update/test/unit/data/wrong_product_channel_mar.mar create mode 100644 toolkit/mozapps/update/test/unit/test_0113_versionDowngradeCheck.js create mode 100644 toolkit/mozapps/update/test/unit/test_0114_productChannelCheck.js diff --git a/toolkit/mozapps/update/test/unit/data/old_version_mar.mar b/toolkit/mozapps/update/test/unit/data/old_version_mar.mar new file mode 100644 index 0000000000000000000000000000000000000000..31550698a0fc1c8b2896717f4efd13681e29dc28 GIT binary patch literal 421 zcmeZu3^HV3VC-N31IDF5iV=bt8DuWLUL~||wWh1^mxFAx7hf}pOtDMeD&I0M`^CHU z-*_U-uB@3dvD_%s;swvEfuZ()#iD8!TZx3bG9toV1CH|@4Rkl_GGi; z#kVK2dH>OyF0uD=!Vk^=vEGZWYr*-#l&3{@vn1jz@)l z9et>(xWI5nZQk!%2kqXTR(~n3AJ-$=lGM zocNHv5yBIdF*($Z+S$}6>>-<~ye@ zd~g1Hao#J3_u^)(79Rq7t~{Pow_fDR>myy>Pqn`&zvNGHW=wQ@Tv3s7aK)j{TQ0db zV`B;m6wWrpd{5rU`(W>zDOXLycqdw_obx@p>sHM2dwb-??7s7_Ep~tBYVCca?D5p5 ziN!3*%01axPd*F3PEKB}@M+(_XDk;gzX;!MogIEsDE7_F!yj1IZ*Ew!LpM%vHtSpa z%(@fmI?iE-i}G2I9FEvBYuV*C`!zQ!^7r|l@scWnhD8R5PD;wpOR0=c&PdG5OU+@> a0*X-^NFv3 (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +/* Test version downgrade MAR security check */ + +const TEST_ID = "0113"; + +// We don't actually care if the MAR has any data, we only care about the +// application return code and update.status result. +const TEST_FILES = []; + +const VERSION_DOWNGRADE_ERROR = "23"; + +function run_test() { + // Setup an old version MAR file + do_register_cleanup(cleanupUpdaterTest); + setupUpdaterTest(MAR_OLD_VERSION_FILE); + + // Apply the MAR + let exitValue = runUpdate(); + logTestInfo("testing updater binary process exitValue for failure when " + + "applying a version downgrade MAR"); + // Make sure the updater executed successfully + do_check_eq(exitValue, 0); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + + //Make sure we get a version downgrade error + let updateStatus = readStatusFile(updatesDir); + do_check_eq(updateStatus.split(": ")[1], VERSION_DOWNGRADE_ERROR); +} diff --git a/toolkit/mozapps/update/test/unit/test_0114_productChannelCheck.js b/toolkit/mozapps/update/test/unit/test_0114_productChannelCheck.js new file mode 100644 index 000000000000..3d5f71748528 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0114_productChannelCheck.js @@ -0,0 +1,65 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2012 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian R. Bondy (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +/* Test product/channel MAR security check */ + +const TEST_ID = "0114"; + +// We don't actually care if the MAR has any data, we only care about the +// application return code and update.status result. +const TEST_FILES = []; + +const MAR_CHANNEL_MISMATCH_ERROR = "22"; + +function run_test() { + // Setup a wrong channel MAR file + do_register_cleanup(cleanupUpdaterTest); + setupUpdaterTest(MAR_WRONG_CHANNEL_FILE); + + // Apply the MAR + let exitValue = runUpdate(); + logTestInfo("testing updater binary process exitValue for failure when " + + "applying a wrong product and channel MAR file"); + // Make sure the updater executed successfully + do_check_eq(exitValue, 0); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + + //Make sure we get a version downgrade error + let updateStatus = readStatusFile(updatesDir); + do_check_eq(updateStatus.split(": ")[1], MAR_CHANNEL_MISMATCH_ERROR); +} diff --git a/toolkit/mozapps/update/test/unit/xpcshell_updater_windows.ini b/toolkit/mozapps/update/test/unit/xpcshell_updater_windows.ini index cdda5ec9b4d2..8aaa26607b5a 100644 --- a/toolkit/mozapps/update/test/unit/xpcshell_updater_windows.ini +++ b/toolkit/mozapps/update/test/unit/xpcshell_updater_windows.ini @@ -1,3 +1,5 @@ +[test_0113_versionDowngradeCheck.js] +[test_0114_productChannelCheck.js] [test_0150_appBinReplaced_xp_win_complete.js] [test_0151_appBinPatched_xp_win_partial.js] [test_0160_appInUse_xp_win_complete.js] From 258b1d36486da3a0ba6032e7785d1021e13364ac Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Tue, 1 May 2012 23:23:45 -0400 Subject: [PATCH 081/159] Sync webidl-parser to m-c to pick up Bug 742141. r=me a=me --- dom/bindings/parser/WebIDL.py | 12 ++++++------ dom/bindings/parser/tests/test_attr.py | 16 +++++++++++++++- dom/bindings/parser/tests/test_method.py | 7 ++++++- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 932263d16414..a0e4e85afadd 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -1659,7 +1659,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): class Tokenizer(object): tokens = [ "INTEGER", - "FLOAT", + "FLOATLITERAL", "IDENTIFIER", "STRING", "WHITESPACE", @@ -1679,7 +1679,7 @@ class Tokenizer(object): filename=self._filename)) return t - def t_FLOAT(self, t): + def t_FLOATLITERAL(self, t): r'-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)' assert False return t @@ -1741,7 +1741,7 @@ class Tokenizer(object): "boolean": "BOOLEAN", "byte": "BYTE", "double": "DOUBLE", - "float": "FLOAT_", + "float": "FLOAT", "long": "LONG", "object": "OBJECT", "octet": "OCTET", @@ -2043,7 +2043,7 @@ class Parser(Tokenizer): def p_ConstValueFloat(self, p): """ - ConstValue : FLOAT + ConstValue : FLOATLITERAL """ assert False pass @@ -2464,7 +2464,7 @@ class Parser(Tokenizer): def p_Other(self, p): """ Other : INTEGER - | FLOAT + | FLOATLITERAL | IDENTIFIER | STRING | OTHER @@ -2489,7 +2489,7 @@ class Parser(Tokenizer): | DOUBLE | EXCEPTION | FALSE - | FLOAT_ + | FLOAT | GETTER | IMPLEMENTS | INHERIT diff --git a/dom/bindings/parser/tests/test_attr.py b/dom/bindings/parser/tests/test_attr.py index fb93d3186227..7056f9a413c9 100644 --- a/dom/bindings/parser/tests/test_attr.py +++ b/dom/bindings/parser/tests/test_attr.py @@ -21,7 +21,9 @@ def WebIDLTest(parser, harness): ("::TestAttr%s::rstr", "rstr", "String%s", True), ("::TestAttr%s::obj", "obj", "Object%s", False), ("::TestAttr%s::robj", "robj", "Object%s", True), - ("::TestAttr%s::object", "object", "Object%s", False)] + ("::TestAttr%s::object", "object", "Object%s", False), + ("::TestAttr%s::f", "f", "Float%s", False), + ("::TestAttr%s::rf", "rf", "Float%s", True)] parser.parse(""" interface TestAttr { @@ -46,6 +48,8 @@ def WebIDLTest(parser, harness): attribute object obj; readonly attribute object robj; attribute object _object; + attribute float f; + readonly attribute float rf; }; interface TestAttrNullable { @@ -70,6 +74,8 @@ def WebIDLTest(parser, harness): attribute object? obj; readonly attribute object? robj; attribute object? _object; + attribute float? f; + readonly attribute float? rf; }; interface TestAttrArray { @@ -94,6 +100,8 @@ def WebIDLTest(parser, harness): attribute object[] obj; readonly attribute object[] robj; attribute object[] _object; + attribute float[] f; + readonly attribute float[] rf; }; interface TestAttrNullableArray { @@ -118,6 +126,8 @@ def WebIDLTest(parser, harness): attribute object[]? obj; readonly attribute object[]? robj; attribute object[]? _object; + attribute float[]? f; + readonly attribute float[]? rf; }; interface TestAttrArrayOfNullableTypes { @@ -142,6 +152,8 @@ def WebIDLTest(parser, harness): attribute object?[] obj; readonly attribute object?[] robj; attribute object?[] _object; + attribute float?[] f; + readonly attribute float?[] rf; }; interface TestAttrNullableArrayOfNullableTypes { @@ -166,6 +178,8 @@ def WebIDLTest(parser, harness): attribute object?[]? obj; readonly attribute object?[]? robj; attribute object?[]? _object; + attribute float?[]? f; + readonly attribute float?[]? rf; }; """) diff --git a/dom/bindings/parser/tests/test_method.py b/dom/bindings/parser/tests/test_method.py index 4d3fbefc6501..98aca556f385 100644 --- a/dom/bindings/parser/tests/test_method.py +++ b/dom/bindings/parser/tests/test_method.py @@ -15,6 +15,7 @@ def WebIDLTest(parser, harness): object getObject(); void setObject(object arg1); void setAny(any arg1); + float doFloats(float arg1); }; """) @@ -27,7 +28,7 @@ def WebIDLTest(parser, harness): "Should be an IDLInterface") harness.check(iface.identifier.QName(), "::TestMethods", "Interface has the right QName") harness.check(iface.identifier.name, "TestMethods", "Interface has the right name") - harness.check(len(iface.members), 12, "Expect 12 members") + harness.check(len(iface.members), 13, "Expect 13 members") methods = iface.members @@ -112,3 +113,7 @@ def WebIDLTest(parser, harness): "setAny", [("Void", [("::TestMethods::setAny::arg1", "arg1", "Any", False, False)])]) + checkMethod(methods[12], "::TestMethods::doFloats", + "doFloats", + [("Float", + [("::TestMethods::doFloats::arg1", "arg1", "Float", False, False)])]) From 918e705c984d42b5abc02264a4c3acd3273630c1 Mon Sep 17 00:00:00 2001 From: Marco Zehe Date: Wed, 2 May 2012 06:56:40 +0200 Subject: [PATCH 082/159] Proper fix for disabling tests for bug 746970, copy and paste error, a=test-only --- accessible/tests/mochitest/events/test_focus_general.xul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accessible/tests/mochitest/events/test_focus_general.xul b/accessible/tests/mochitest/events/test_focus_general.xul index d069ef688fcd..b5c18e8c5954 100644 --- a/accessible/tests/mochitest/events/test_focus_general.xul +++ b/accessible/tests/mochitest/events/test_focus_general.xul @@ -73,7 +73,7 @@ // show popup again for the next test gQueue.push(new synthClick("popupbutton", new nofocusChecker())); -if (MAC) { +if (!MAC) { // click menubutton of the 'menubutton' button while popup of button open. gQueue.push(new synthClick("mbb", new focusChecker("mbb"), { where: "right" })); // close popup, focus stays on menubutton, fire focus event From 914731b237838da94d4f652fe774fcd22f4df23b Mon Sep 17 00:00:00 2001 From: Myk Melez Date: Wed, 2 May 2012 00:09:10 -0700 Subject: [PATCH 083/159] bug 750568 - whitelist twitter and google identity providers in webapp runtime; r=myk, a=js-only --- webapprt/ContentPolicy.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/webapprt/ContentPolicy.js b/webapprt/ContentPolicy.js index 392ddeefd1ca..37c70468d90e 100644 --- a/webapprt/ContentPolicy.js +++ b/webapprt/ContentPolicy.js @@ -14,6 +14,9 @@ const allowedOrigins = [ WebappRT.config.app.origin, "https://browserid.org", "https://www.facebook.com", + "https://accounts.google.com", + "https://www.google.com", + "https://api.twitter.com", ]; function ContentPolicy() {} From 26930790affbefa87329612ad6d622ef0042ccf7 Mon Sep 17 00:00:00 2001 From: Serge Gautherie Date: Wed, 2 May 2012 12:24:40 +0200 Subject: [PATCH 084/159] Bug 635825. (Av1) Re-enable test_notifications.html, test_privbrowsing.html and test_prompt.html on SeaMonkey. rs=Callek (a=test-only). --- toolkit/components/passwordmgr/test/Makefile.in | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/toolkit/components/passwordmgr/test/Makefile.in b/toolkit/components/passwordmgr/test/Makefile.in index 06eef1902ec9..25a8b8d4716e 100644 --- a/toolkit/components/passwordmgr/test/Makefile.in +++ b/toolkit/components/passwordmgr/test/Makefile.in @@ -82,6 +82,8 @@ MOCHI_TESTS = \ test_maxforms_1.html \ test_maxforms_2.html \ test_maxforms_3.html \ + test_notifications.html \ + test_privbrowsing.html \ test_prompt_async.html \ test_xhr.html \ test_xml_load.html \ @@ -112,23 +114,11 @@ MOCHI_CONTENT = \ subtst_prompt_async.html \ $(NULL) -# Don't run these tests in suite -ifndef MOZ_SUITE -MOCHI_TESTS += \ - test_privbrowsing.html \ - test_notifications.html \ - $(NULL) ifneq ($(OS_TARGET),Linux) MOCHI_TESTS += \ test_prompt.html \ $(NULL) endif -endif -ifdef MOZ_SUITE -$(warning test_prompt.html is disabled until doorhanger notfications work. Bug 598360) -$(warning test_notifications.html is disabled until doorhanger notfications work. Bug 598360) -$(warning test_privbrowsing.html is disabled due to doorhangers, Bug 598360, and no privatebrowsing support) -endif # This test doesn't pass because we can't ensure a cross-platform # event that occurs between DOMContentLoaded and Pageload From 252238df66650bea3e27560860a541abbd461f60 Mon Sep 17 00:00:00 2001 From: Serge Gautherie Date: Wed, 2 May 2012 14:14:18 +0200 Subject: [PATCH 085/159] Bug 741070. (Cv1a-FF) Sessionstore tests: Improve and merge 'provideWindow()' and 'whenWindowLoaded()' into 'head.js', Add an 'info()' call, Nits. r=paul (a=test-only). --- .../sessionstore/test/browser_394759_basic.js | 30 ---------------- .../test/browser_394759_behavior.js | 35 ++----------------- .../test/browser_595601-restore_hidden.js | 14 ++------ .../sessionstore/test/browser_701377.js | 14 ++------ browser/components/sessionstore/test/head.js | 31 ++++++++++++++++ 5 files changed, 40 insertions(+), 84 deletions(-) diff --git a/browser/components/sessionstore/test/browser_394759_basic.js b/browser/components/sessionstore/test/browser_394759_basic.js index 7540698585ff..fc162586d75a 100644 --- a/browser/components/sessionstore/test/browser_394759_basic.js +++ b/browser/components/sessionstore/test/browser_394759_basic.js @@ -35,36 +35,6 @@ * * ***** END LICENSE BLOCK ***** */ -function provideWindow(aCallback, aURL, aFeatures) { - function callback() { - executeSoon(function () { - aCallback(win); - }); - } - - let win = openDialog(getBrowserURL(), "", aFeatures || "chrome,all,dialog=no", aURL); - - whenWindowLoaded(win, function () { - if (!aURL) { - callback(); - return; - } - win.gBrowser.selectedBrowser.addEventListener("load", function() { - win.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); - callback(); - }, true); - }); -} - -function whenWindowLoaded(aWin, aCallback) { - aWin.addEventListener("load", function () { - aWin.removeEventListener("load", arguments.callee, false); - executeSoon(function () { - aCallback(aWin); - }); - }, false); -} - function test() { waitForExplicitFinish(); diff --git a/browser/components/sessionstore/test/browser_394759_behavior.js b/browser/components/sessionstore/test/browser_394759_behavior.js index a2d8f8a84a97..cfecaa5051a4 100644 --- a/browser/components/sessionstore/test/browser_394759_behavior.js +++ b/browser/components/sessionstore/test/browser_394759_behavior.js @@ -35,43 +35,13 @@ * * ***** END LICENSE BLOCK ***** */ -function provideWindow(aCallback, aURL, aFeatures) { - function callback() { - executeSoon(function () { - aCallback(win); - }); - } - - let win = openDialog(getBrowserURL(), "", aFeatures || "chrome,all,dialog=no", aURL); - - whenWindowLoaded(win, function () { - if (!aURL) { - callback(); - return; - } - win.gBrowser.selectedBrowser.addEventListener("load", function() { - win.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); - callback(); - }, true); - }); -} - -function whenWindowLoaded(aWin, aCallback) { - aWin.addEventListener("load", function () { - aWin.removeEventListener("load", arguments.callee, false); - executeSoon(function () { - aCallback(aWin); - }); - }, false); -} - function test() { // This test takes quite some time, and timeouts frequently, so we require // more time to run. // See Bug 518970. requestLongerTimeout(2); - waitForExplicitFinish(); + waitForExplicitFinish(); // helper function that does the actual testing function openWindowRec(windowsToOpen, expectedResults, recCallback) { @@ -94,13 +64,14 @@ function test() { executeSoon(recCallback); return; } + // hack to force window to be considered a popup (toolbar=no didn't work) let winData = windowsToOpen.shift(); let settings = "chrome,dialog=no," + (winData.isPopup ? "all=no" : "all"); let url = "http://example.com/?window=" + windowsToOpen.length; - provideWindow(function (win) { + provideWindow(function onTestURLLoaded(win) { win.close(); openWindowRec(windowsToOpen, expectedResults, recCallback); }, url, settings); diff --git a/browser/components/sessionstore/test/browser_595601-restore_hidden.js b/browser/components/sessionstore/test/browser_595601-restore_hidden.js index 3971a51d2a29..b53d92308a73 100644 --- a/browser/components/sessionstore/test/browser_595601-restore_hidden.js +++ b/browser/components/sessionstore/test/browser_595601-restore_hidden.js @@ -93,14 +93,6 @@ let TabsProgressListener = { } } -// ---------- -function whenWindowLoaded(win, callback) { - win.addEventListener("load", function onLoad() { - win.removeEventListener("load", onLoad, false); - executeSoon(callback); - }, false); -} - // ---------- function newWindowWithState(state, callback) { let opts = "chrome,all,dialog=no,height=800,width=800"; @@ -108,10 +100,10 @@ function newWindowWithState(state, callback) { registerCleanupFunction(function () win.close()); - whenWindowLoaded(win, function () { - TabsProgressListener.init(win); + whenWindowLoaded(win, function onWindowLoaded(aWin) { + TabsProgressListener.init(aWin); TabsProgressListener.setCallback(callback); - ss.setWindowState(win, JSON.stringify(state), true); + ss.setWindowState(aWin, JSON.stringify(state), true); }); } diff --git a/browser/components/sessionstore/test/browser_701377.js b/browser/components/sessionstore/test/browser_701377.js index e0c363dada4b..e526b7eb7451 100644 --- a/browser/components/sessionstore/test/browser_701377.js +++ b/browser/components/sessionstore/test/browser_701377.js @@ -27,14 +27,6 @@ function test() { }); } -// ---------- -function whenWindowLoaded(aWindow, aCallback) { - aWindow.addEventListener("load", function onLoad() { - aWindow.removeEventListener("load", onLoad, false); - executeSoon(aCallback); - }, false); -} - // ---------- function newWindowWithState(aState, aCallback) { let opts = "chrome,all,dialog=no,height=800,width=800"; @@ -42,8 +34,8 @@ function newWindowWithState(aState, aCallback) { registerCleanupFunction(function () win.close()); - whenWindowLoaded(win, function () { - ss.setWindowState(win, JSON.stringify(aState), true); - executeSoon(function () aCallback(win)); + whenWindowLoaded(win, function onWindowLoaded(aWin) { + ss.setWindowState(aWin, JSON.stringify(aState), true); + executeSoon(function () aCallback(aWin)); }); } diff --git a/browser/components/sessionstore/test/head.js b/browser/components/sessionstore/test/head.js index a5f451d52c1a..45715bbc10d7 100644 --- a/browser/components/sessionstore/test/head.js +++ b/browser/components/sessionstore/test/head.js @@ -49,6 +49,28 @@ registerCleanupFunction(function () { // session restore tests to be run standalone without triggering errors. Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler).defaultArgs; +function provideWindow(aCallback, aURL, aFeatures) { + function callbackSoon(aWindow) { + executeSoon(function executeCallbackSoon() { + aCallback(aWindow); + }); + } + + let win = openDialog(getBrowserURL(), "", aFeatures || "chrome,all,dialog=no", aURL); + whenWindowLoaded(win, function onWindowLoaded(aWin) { + if (!aURL) { + info("Loaded a blank window."); + callbackSoon(aWin); + return; + } + + aWin.gBrowser.selectedBrowser.addEventListener("load", function selectedBrowserLoadListener() { + aWin.gBrowser.selectedBrowser.removeEventListener("load", selectedBrowserLoadListener, true); + callbackSoon(aWin); + }, true); + }); +} + // This assumes that tests will at least have some state/entries function waitForBrowserState(aState, aSetStateCallback) { let windows = [window]; @@ -198,6 +220,15 @@ function whenBrowserLoaded(aBrowser, aCallback) { }, true); } +function whenWindowLoaded(aWindow, aCallback) { + aWindow.addEventListener("load", function windowLoadListener() { + aWindow.removeEventListener("load", windowLoadListener, false); + executeSoon(function executeWhenWindowLoaded() { + aCallback(aWindow); + }); + }, false); +} + var gUniqueCounter = 0; function r() { return Date.now() + "-" + (++gUniqueCounter); From b16cdefef5dea7cec6d0bce23c1cbbe935057862 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Wed, 2 May 2012 10:51:09 -0400 Subject: [PATCH 086/159] Bug 750722 - Fix missing null check. r=mfinkle a=android-only --- mobile/android/chrome/content/browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 8b2f987cdc90..e12dad1c3f55 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2567,7 +2567,7 @@ var BrowserEventHandler = { this._scrollableElement = this._findScrollableElement(this._scrollableElement, false); let doc = BrowserApp.selectedBrowser.contentDocument; - if (this._scrollableElement == doc.body || this._scrollableElement == doc.documentElement) { + if (this._scrollableElement == null || this._scrollableElement == doc.body || this._scrollableElement == doc.documentElement) { sendMessageToJava({ gecko: { type: "Panning:CancelOverride" } }); return; } From 531aa26939aeef42d003576b4ed82e546f41906d Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Wed, 2 May 2012 09:07:58 -0700 Subject: [PATCH 087/159] Bug 695204 - Display site security. r=mfinkle a=android-only --- mobile/android/base/BrowserToolbar.java | 17 +- mobile/android/base/GeckoApp.java | 30 ++- mobile/android/base/Makefile.in | 8 + mobile/android/base/SiteIdentityPopup.java | 142 ++++++++++++++ mobile/android/base/Tab.java | 20 +- .../base/locales/en-US/android_strings.dtd | 15 ++ .../resources/drawable-hdpi/larry_blue.png | Bin 0 -> 5189 bytes .../resources/drawable-hdpi/larry_green.png | Bin 0 -> 5193 bytes .../drawable-xhdpi-v11/larry_blue.png | Bin 0 -> 7443 bytes .../drawable-xhdpi-v11/larry_green.png | Bin 0 -> 7439 bytes .../base/resources/drawable/larry_blue.png | Bin 0 -> 3115 bytes .../base/resources/drawable/larry_green.png | Bin 0 -> 3164 bytes .../resources/layout/site_identity_popup.xml | 82 ++++++++ .../android/base/resources/values/colors.xml | 2 + mobile/android/base/strings.xml.in | 4 + mobile/android/chrome/content/browser.js | 180 ++++++++++++++++-- .../locales/en-US/chrome/browser.properties | 2 - 17 files changed, 473 insertions(+), 29 deletions(-) create mode 100644 mobile/android/base/SiteIdentityPopup.java create mode 100644 mobile/android/base/resources/drawable-hdpi/larry_blue.png create mode 100644 mobile/android/base/resources/drawable-hdpi/larry_green.png create mode 100644 mobile/android/base/resources/drawable-xhdpi-v11/larry_blue.png create mode 100644 mobile/android/base/resources/drawable-xhdpi-v11/larry_green.png create mode 100644 mobile/android/base/resources/drawable/larry_blue.png create mode 100644 mobile/android/base/resources/drawable/larry_green.png create mode 100644 mobile/android/base/resources/layout/site_identity_popup.xml diff --git a/mobile/android/base/BrowserToolbar.java b/mobile/android/base/BrowserToolbar.java index 6e5c7833df5d..ab5d0b4b4c17 100644 --- a/mobile/android/base/BrowserToolbar.java +++ b/mobile/android/base/BrowserToolbar.java @@ -60,6 +60,7 @@ import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.RelativeLayout.LayoutParams; import android.widget.TextView; import android.widget.TextSwitcher; import android.widget.ViewSwitcher.ViewFactory; @@ -172,6 +173,18 @@ public class BrowserToolbar { mFavicon = (ImageButton) mLayout.findViewById(R.id.favicon); mSiteSecurity = (ImageButton) mLayout.findViewById(R.id.site_security); + mSiteSecurity.setOnClickListener(new Button.OnClickListener() { + public void onClick(View view) { + int[] lockLocation = new int[2]; + view.getLocationOnScreen(lockLocation); + LayoutParams lockLayoutParams = (LayoutParams) view.getLayoutParams(); + + // Calculate the left margin for the arrow based on the position of the lock icon. + int leftMargin = lockLocation[0] - lockLayoutParams.rightMargin; + GeckoApp.mSiteIdentityPopup.show(leftMargin); + } + }); + mProgressSpinner = (AnimationDrawable) resources.getDrawable(R.drawable.progress_spinner); mStop = (ImageButton) mLayout.findViewById(R.id.stop); @@ -322,9 +335,9 @@ public class BrowserToolbar { public void setSecurityMode(String mode) { mTitleCanExpand = false; - if (mode.equals("identified")) { + if (mode.equals(SiteIdentityPopup.IDENTIFIED)) { mSiteSecurity.setImageLevel(1); - } else if (mode.equals("verified")) { + } else if (mode.equals(SiteIdentityPopup.VERIFIED)) { mSiteSecurity.setImageLevel(2); } else { mSiteSecurity.setImageLevel(0); diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 851654ba4b53..f6cb97744b70 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -138,6 +138,7 @@ abstract public class GeckoApp public static BrowserToolbar mBrowserToolbar; public static DoorHangerPopup mDoorHangerPopup; + public static SiteIdentityPopup mSiteIdentityPopup; public static FormAssistPopup mFormAssistPopup; public Favicons mFavicons; @@ -665,7 +666,7 @@ abstract public class GeckoApp tab.setContentType(contentType); tab.updateFavicon(null); tab.updateFaviconURL(null); - tab.updateSecurityMode("unknown"); + tab.updateIdentityData(null); tab.removeTransientDoorHangers(); tab.setHasTouchListeners(false); tab.setCheckerboardColor(Color.WHITE); @@ -677,7 +678,7 @@ abstract public class GeckoApp if (Tabs.getInstance().isSelectedTab(tab)) { mBrowserToolbar.setTitle(uri); mBrowserToolbar.setFavicon(null); - mBrowserToolbar.setSecurityMode("unknown"); + mBrowserToolbar.setSecurityMode(tab.getSecurityMode()); mDoorHangerPopup.updatePopup(); mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:"))); @@ -688,17 +689,17 @@ abstract public class GeckoApp }); } - void handleSecurityChange(final int tabId, final String mode) { + void handleSecurityChange(final int tabId, final JSONObject identityData) { final Tab tab = Tabs.getInstance().getTab(tabId); if (tab == null) return; - tab.updateSecurityMode(mode); + tab.updateIdentityData(identityData); mMainHandler.post(new Runnable() { public void run() { if (Tabs.getInstance().isSelectedTab(tab)) - mBrowserToolbar.setSecurityMode(mode); + mBrowserToolbar.setSecurityMode(tab.getSecurityMode()); } }); } @@ -871,9 +872,9 @@ abstract public class GeckoApp handleLocationChange(tabId, uri, documentURI, contentType, sameDocument); } else if (event.equals("Content:SecurityChange")) { final int tabId = message.getInt("tabID"); - final String mode = message.getString("mode"); - Log.i(LOGTAG, "Security Mode - " + mode); - handleSecurityChange(tabId, mode); + final JSONObject identity = message.getJSONObject("identity"); + Log.i(LOGTAG, "Security Mode - " + identity.getString("mode")); + handleSecurityChange(tabId, identity); } else if (event.equals("Content:StateChange")) { final int tabId = message.getInt("tabID"); final String uri = message.getString("uri"); @@ -1204,7 +1205,7 @@ abstract public class GeckoApp return; tab.setState("about:home".equals(uri) ? Tab.STATE_SUCCESS : Tab.STATE_LOADING); - tab.updateSecurityMode("unknown"); + tab.updateIdentityData(null); if (Tabs.getInstance().isSelectedTab(tab)) getLayerController().getView().getRenderer().resetCheckerboard(); mMainHandler.post(new Runnable() { @@ -1665,6 +1666,7 @@ abstract public class GeckoApp mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container); mDoorHangerPopup = new DoorHangerPopup(this); + mSiteIdentityPopup = new SiteIdentityPopup(this); mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup); Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - UI almost up"); @@ -1955,6 +1957,9 @@ abstract public class GeckoApp // Undo whatever we did in onPause. super.onResume(); + if (mSiteIdentityPopup != null) + mSiteIdentityPopup.dismiss(); + int newOrientation = getResources().getConfiguration().orientation; if (mOrientation != newOrientation) { @@ -2081,6 +2086,8 @@ abstract public class GeckoApp mOrientation = newConfig.orientation; if (mFormAssistPopup != null) mFormAssistPopup.hide(); + if (mSiteIdentityPopup != null) + mSiteIdentityPopup.dismiss(); refreshActionBar(); } } @@ -2551,6 +2558,11 @@ abstract public class GeckoApp return; } + if (mSiteIdentityPopup.isShowing()) { + mSiteIdentityPopup.dismiss(); + return; + } + if (mDOMFullScreen) { GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FullScreen:Exit", null)); return; diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index dd764a517e79..24b32ddd1be1 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -110,6 +110,7 @@ FENNEC_JAVA_FILES = \ sqlite/SQLiteBridgeException.java \ RemoteTabs.java \ SetupScreen.java \ + SiteIdentityPopup.java \ SurfaceBits.java \ Tab.java \ Tabs.java \ @@ -272,6 +273,7 @@ RES_LAYOUT = \ res/layout/notification_progress_text.xml \ res/layout/site_setting_title.xml \ res/layout/setup_screen.xml \ + res/layout/site_identity_popup.xml \ res/layout/remote_tabs.xml \ res/layout/remote_tabs_child.xml \ res/layout/remote_tabs_group.xml \ @@ -366,6 +368,8 @@ RES_DRAWABLE_BASE = \ res/drawable/doorhanger_bg.9.png \ res/drawable/doorhanger_shadow_bg.9.png \ res/drawable/doorhanger_popup_bg.9.png \ + res/drawable/larry_blue.png \ + res/drawable/larry_green.png \ res/drawable/site_security_identified.png \ res/drawable/site_security_verified.png \ res/drawable/urlbar_stop.png \ @@ -423,6 +427,8 @@ RES_DRAWABLE_HDPI = \ res/drawable-hdpi/doorhanger_bg.9.png \ res/drawable-hdpi/doorhanger_shadow_bg.9.png \ res/drawable-hdpi/doorhanger_popup_bg.9.png \ + res/drawable-hdpi/larry_blue.png \ + res/drawable-hdpi/larry_green.png \ res/drawable-hdpi/site_security_identified.png \ res/drawable-hdpi/site_security_verified.png \ res/drawable-hdpi/urlbar_stop.png \ @@ -492,6 +498,8 @@ RES_DRAWABLE_XHDPI_V11 = \ res/drawable-xhdpi-v11/doorhanger_shadow_bg.9.png \ res/drawable-xhdpi-v11/doorhanger_popup_bg.9.png \ res/drawable-xhdpi-v11/urlbar_stop.png \ + res/drawable-xhdpi-v11/larry_blue.png \ + res/drawable-xhdpi-v11/larry_green.png \ res/drawable-xhdpi-v11/site_security_identified.png \ res/drawable-xhdpi-v11/site_security_verified.png \ res/drawable-xhdpi-v11/tabs_button_tail.9.png \ diff --git a/mobile/android/base/SiteIdentityPopup.java b/mobile/android/base/SiteIdentityPopup.java new file mode 100644 index 000000000000..5255f263977c --- /dev/null +++ b/mobile/android/base/SiteIdentityPopup.java @@ -0,0 +1,142 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.BitmapDrawable; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.PopupWindow; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.RelativeLayout.LayoutParams; +import android.widget.ImageView; +import android.widget.TextView; + +import org.json.JSONObject; +import org.json.JSONException; + +public class SiteIdentityPopup extends PopupWindow { + private static final String LOGTAG = "GeckoSiteIdentityPopup"; + + public static final String UNKNOWN = "unknown"; + public static final String VERIFIED = "verified"; + public static final String IDENTIFIED = "identified"; + + private Context mContext; + private Resources mResources; + private boolean mInflated; + + private TextView mHost; + private TextView mOwner; + private TextView mSupplemental; + private TextView mVerifier; + private TextView mEncrypted; + + private ImageView mLarry; + private ImageView mArrow; + + public SiteIdentityPopup(Context aContext) { + super(aContext); + mContext = aContext; + mResources = aContext.getResources(); + mInflated = false; + } + + private void init() { + setBackgroundDrawable(new BitmapDrawable()); + setOutsideTouchable(true); + setWindowLayoutMode(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); + + LayoutInflater inflater = LayoutInflater.from(mContext); + RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.site_identity_popup, null); + setContentView(layout); + + mHost = (TextView) layout.findViewById(R.id.host); + mOwner = (TextView) layout.findViewById(R.id.owner); + mSupplemental = (TextView) layout.findViewById(R.id.supplemental); + mVerifier = (TextView) layout.findViewById(R.id.verifier); + mEncrypted = (TextView) layout.findViewById(R.id.encrypted); + + mLarry = (ImageView) layout.findViewById(R.id.larry); + mArrow = (ImageView) layout.findViewById(R.id.arrow); + + mInflated = true; + } + + public void show(int leftMargin) { + JSONObject identityData = Tabs.getInstance().getSelectedTab().getIdentityData(); + if (identityData == null) { + Log.e(LOGTAG, "Tab has no identity data"); + return; + } + + String mode; + try { + mode = identityData.getString("mode"); + } catch (JSONException e) { + Log.e(LOGTAG, "Exception trying to get identity mode: " + e); + return; + } + + if (!mode.equals(VERIFIED) && !mode.equals(IDENTIFIED)) { + Log.e(LOGTAG, "Can't show site identity popup in non-identified state"); + return; + } + + if (!mInflated) + init(); + + try { + String host = identityData.getString("host"); + mHost.setText(host); + + String owner = identityData.getString("owner"); + mOwner.setText(owner); + + String verifier = identityData.getString("verifier"); + mVerifier.setText(verifier); + + String encrypted = identityData.getString("encrypted"); + mEncrypted.setText(encrypted); + } catch (JSONException e) { + Log.e(LOGTAG, "Exception trying to get identity data: " + e); + return; + } + + try { + String supplemental = identityData.getString("supplemental"); + mSupplemental.setText(supplemental); + mSupplemental.setVisibility(View.VISIBLE); + } catch (JSONException e) { + mSupplemental.setVisibility(View.INVISIBLE); + } + + if (mode.equals(VERIFIED)) { + // Use a blue theme for SSL + mLarry.setImageResource(R.drawable.larry_blue); + mHost.setTextColor(mResources.getColor(R.color.identity_verified)); + mOwner.setTextColor(mResources.getColor(R.color.identity_verified)); + mSupplemental.setTextColor(mResources.getColor(R.color.identity_verified)); + } else { + // Use a green theme for EV + mLarry.setImageResource(R.drawable.larry_green); + mHost.setTextColor(mResources.getColor(R.color.identity_identified)); + mOwner.setTextColor(mResources.getColor(R.color.identity_identified)); + mSupplemental.setTextColor(mResources.getColor(R.color.identity_identified)); + } + + // Position the mArrow according to lock position + LayoutParams layoutParams = (LayoutParams) mArrow.getLayoutParams(); + LayoutParams newLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + newLayoutParams.setMargins(leftMargin, layoutParams.topMargin, 0, 0); + mArrow.setLayoutParams(newLayoutParams); + + // This will place the popup at the correct vertical position + showAsDropDown(GeckoApp.mBrowserToolbar.mSiteSecurity); + } +} diff --git a/mobile/android/base/Tab.java b/mobile/android/base/Tab.java index 58bd868f6c21..861c01ba2f23 100644 --- a/mobile/android/base/Tab.java +++ b/mobile/android/base/Tab.java @@ -77,7 +77,7 @@ public final class Tab { private String mTitle; private Drawable mFavicon; private String mFaviconUrl; - private String mSecurityMode; + private JSONObject mIdentityData; private Drawable mThumbnail; private List mHistory; private int mHistoryIndex; @@ -119,7 +119,7 @@ public final class Tab { mTitle = title; mFavicon = null; mFaviconUrl = null; - mSecurityMode = "unknown"; + mIdentityData = null; mThumbnail = null; mHistory = new ArrayList(); mHistoryIndex = -1; @@ -270,7 +270,16 @@ public final class Tab { } public String getSecurityMode() { - return mSecurityMode; + try { + return mIdentityData.getString("mode"); + } catch (Exception e) { + // If mIdentityData is null, or we get a JSONException + return SiteIdentityPopup.UNKNOWN; + } + } + + public JSONObject getIdentityData() { + return mIdentityData; } public boolean isBookmark() { @@ -368,8 +377,9 @@ public final class Tab { Log.i(LOGTAG, "Updated favicon URL for tab with id: " + mId); } - public void updateSecurityMode(String mode) { - mSecurityMode = mode; + + public void updateIdentityData(JSONObject identityData) { + mIdentityData = identityData; } private void updateBookmark() { diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd index 7205aab9ba52..4975c917193e 100644 --- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -126,3 +126,18 @@ + + + + + diff --git a/mobile/android/base/resources/drawable-hdpi/larry_blue.png b/mobile/android/base/resources/drawable-hdpi/larry_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..4007364d42574e6db465b730f0dde1b9a51513e5 GIT binary patch literal 5189 zcmV-L6uRq)P)0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU_=Sf6CRCwC$TnThl<+V;?5;RbV0VIKd zAqh$D6z+XskT67zkc1?J$WStp04^#Lsi*;mB9n*+3wsA{!Vp3d85Nn7()RiAy*`IN zA6Bgk0kO1L8EOGTWWAzmo%ip1{++wefBzGPoLIu@U2CsSPv!tsY&w}!y76RAW&O#V@=Yqi{%L$aZsUGRa19=VbIa<~{jfc0 z!`E5tdAHpvjEk@=I`TqJqoS1UV)VMARKB4o(|0RM`7ZSvsPuLJHXJYGzo(INU>mRX zUGtivRJ`H8CjV7MVb6=YRT%dZMx!iCkAL}ZHHrdccB|im*Q(n#kNO)Zm2X=;D&c;5 z9qh+#ypP?>_PKnFOTJYY7skjG-gDqH_FuMKu@T0kIJL}@5ikY5fid(q-h-YC_h!$s z-%55ag3*XRS@T~5W;r+$kZ~wY7PnuLOfK~}ND(rHN+x9>{cRNEx)n1!Fy~E0nR`Gb zy8Xz0MXBPytH^#z)3;yPkv?xnG`m-DJH`Rm_G0wVpz8Pk1k6cxs*(nb0m(7B{OXCS z2aHH|%GFh-zD6=GF~uoY0lHsQ6_f~|v6~eocjLwX;ZoC{Pbi~7;k^>7lUB7{0p@^& z0fUf2ggy0Qn|F@Z(z14aY#ln&W<<48BBTc^yS_ev)}14wD`^LLreBYrIqZz zGfnuur})h~N6$WFdhQSB;F^2aD@t6&<~#^33{ctOQRy=q^;8Ze2PYPon@aY<`3|rA zT0(b8gfXen{ zl-GB{@&f}(*MHi#X#J<~4b-p1zumXkza2x)LF!);xG#RzYj3lAn+=mVs+L1*Rpu2j z+xO7g;~pOObQ1_dh}b^k7B0bAkDavoNw%-60b_yywI8D~jLH~Q7)UVb(S|Ti6le5O zqw5qUj|GesJ1-v@x9n|;#Q1mX_t45}ybiWGQ;qoCp1=C=jATmdled09*eBYP`pN%s{;=tH~ z*Ajz8U!?6;RX2TuqDhoG0_Fk@JWMD? z{x~+Phd4B+HeQ4OLp?8^$1?}xY#iJeAC7}FlVB5$4`93!$YvX}gIK%B^T&U^UkE+FpADIKsr5Zq)fnyf~c`A)mVhv*)Is!UV z7PmZrL!u)&|T%hjQ11b}_DNO#YJc-WiY9L=7w5;|sEfPCb~o@c6eVO%``x z5Db%sW3qb#b5s0p_zmY9s;V@Vq7o>IJnm0e_{9mh78r-#xKH~ScL$_@j50`&T^j$$ z-v1SIPtkl}zUttq8RoWBGO17)#yC;bVRn$2m_XYEkDI($WgIZeAmOoG4i?k94*Y-1B;vmRQ zjLN85OTD}Zdr@%Hx9tkFiNMhQ)3^Q?yI-0CK!nOTnl&KvX#6B&T+(8{#NoaUkU04C z07ns5+3mu6s@ezs8a{r z0TPEu$pA*>iF1E_ES1D$vT@TQ4W?X{WhX9#^^AX--2;G%aH9rhr@^L(lE8iu6odd6 z@Ve~PpX{30(EK+*QDFZa1BMnDfC9@t;k+_6GbV4*Aw^w<-IPw z6CY>yiZgm}lA6R_e1gguEewn7SHrT5eH_-`7cpQ+J=?#C5qQs091sofh{3>(%VYAM ze@B!muqQa94zFJVK|NiO+oa;viRspcFp}<%6jqp1PA@NpI|P95!@+7aOwKd z#u3VAC@VZ_zzV2bnO#~8i$Xa*gm{V1t0o%ZH7gsw&MK-omOFFX-&a1o_3SF7iYC6j z*5n#s#N8z9V|p&Wqb0+51B?G{a0~5P8u~EhJ7MaDc>t z04C2Dj?v?=J)R$XXq#Fyf!{-zmc%dks4gh5;U=PZOY;XaSW^zr?0r8p!{m&fzo*aj zNNz9}ckn_p?s{PEufPe2NP{mnT6)8b3&~#o-=n8)|DhTF=!gy6JG->zp|!Bg3(`1g z==Bjd)GIoR6V8+ST!C@n8LN+bU?L#If^k4h3U!L2EiIorDt#z-@b%igfzXc7-IiZ( zTKvVu6sNye!|J(V#)V`q`j7jjZ2SHa6ir~DVrP;Jd6s4ZE^Yc{^=R)wCmSX|tmnXI zg#h@rw5Q*m0+R=5GmRYJcP^9Eto0W@yb*^N$~{+Rc+}m?lAikAS2R{in7!v$oVnL5 z&1rMDI>tAuOiNv>_0}TlAWuz5(p)NlsS7!gRatu7+SXJ)SQQR{o^ZWx`76ps{KDSmu@)W?vZdWRPC$!Onl`% z25Y}0ycU=eLell+3x5s_;iduDcQG&4|Mbjt@!ZC$Hrljh`npTfCErf4h z*i_l@d-m*n-W`By7m?}x=J5UXTB#TN@E{|yE;;sVUVN9UX2FJYuY-XG9fvjuxZyCy z^@+^LmTzl57MD4zfX8c(@!->P9VkPWv96PiV5m_oT7gJX$&x|ecuYir@i>)KR9*b@ ziO>2H`wE`xqSSv~BBIHgb9qez)OXvOq9ShQMV8~Mkin1Hk6U8D3{L%Y2Daw?s z-(SjE^6zsv2-x>Jg3Hi*pMQ5&0kb9d)M{-BA{t^=B4TM&$}H|c&{9TV*TQ=R+O?6- zsdf#di9Q#fX>w_89SBg6P6ucAVK4vrT@YKn7B9GXom=sf0PM0%=kBi2ivhInWHGXV)_81EpHLAAa)=&Q#f-yL*V||1PJk z3vBrm!-C;lb&FXwf5hCzYr(Z5#?*XsICC?xC9XhdUX(bhemH@m^ALeeth@RE)pEIA z%c}k6a8`o=PPn!86_Jr`RmDt+E6!iQs<^1Cq7+~?e{$ocqq!?T7}Z9k9bijD=vxLz z(n-U3%`8Y2WtQ2ct^X!Jr*GH59NkkB2%RN61G_e_rGTB1^yKe8a(K0Wgf`zeh#f+A zKZZ%sR2Glrz4BRw1WNMR5@?M_tWGu=X1BKNXjyWsSzXoVJ{VJ3|11?*TJ-{P2U`K%L`8KPyXUhdxeZrZ zz}bi%Po{=2IkA;nj{(MpzY)C^8>01!NWhRtdtnVv8C&hzpz-Qh(1zQ+ZQn~QZo?S# z7zYnY?=iSw9rWFztq}h#2C8NOdIE`>z`Ru1mT!Nb@wm_Kbl}MGYH(G8tX9* zTSv#-5jV`uP>+jZ`a)F%22Irj9so8B)Us^*< z{}9f+jIf?@ixaC3oM`2`J8*XKPhd9@N@H5BDuJM)b_t}7bx$}Ki^V-h%y^ZzJq${G z?BH$;ibbhHdn@*kfL-g-JE59`n%MLhGVF;r#)725q|$n;9x!0{YWHKg^jcabK=QgX z8p3FH?Bq4?n{}#Rh}Bu#@?)Zb$Ko;0BqAO>9U9Mp(3k;_9^8#KPE6t*-oVB|*zP{K z(92QaR=buwdD-3L>%TjLjfr~B2CMvNHmnkp(3Xu8nFq};Ng(=n4lCaUszh78G%H>7 z80*${5y_l`=@$WELv-AngS%-}O%~YF?fyD;EvM$pp=@Gf#R+zhZcf=T3OuA;|3#gK$#wnRO}BBoH<6|7yIC>Af zr-euN7^Ek?sBhPDnpB`7l>h@WG=+9L$p8bYRX5TW7R>9BgBi{0J#Nt>sA?1;dl7}@*W`$B0tB$YU^l?!{6`%RJCwfkIW4uQ1M#%Y_U?XD}@?~GA| zU2;x)8xgS*HkMVwUQB%E59ds-KwE~AMtj!UfO#~Gi?31{M#nS&|JZ#Cnd;GrRT# z_xKvSHi2V(v@Kt}9``3ZFk{E)Z^iT*%221Gyqd^9*sHT;$O}<)$Q)|?L32e3AA34-M;3`Fr zRvSkbe!x9p6(KwRplH_~aGyB@K!eRKFYd^C{E&gjL{YU{D`VX2-l$i-)=C((Ld=Uy zE87hS2P}t#_NpGX+$PSnLDzs9`xr+Xw_)J%kNxH-I3;dhTkYDY6{=lxc(rPUQr`-g zy5zw#&4;OqS|k8#PzSBy58+jyB;NE=%suB+M)z?^yOyF(G^AW+0;hvr3-6sck24-I zzmT+fs$I(Qdj5o;i+Uj9ti-#WZnriv&C-Urbe ztFXZCrf1xsxxabCwCpeEWOi+M_5KH;%y{1>E!Zf_FJ&GU)z7MvP0%of7RfsUn^7u2!<6@YRqjcML-*esI%B&cC}*7&GHH3VU6gC0hJ!j=qX048LcsZJn$+F zS!aMKiJd{>+R9L3I5=Q8h#rXl*{nIwq3YQtpSSxG}b#DorrN!$@AZ95`$O_ za;eP`i!8E$Hr1maAj|rP^;S@J2F7V}Rcv3C_0fr`meu1=;BA7v!i>S9b1&NZV9`O4 zI|bv!24-2Ih4#qF&a(?>FvaIY2}CELSC{A%jH3l<@wGl!w4sF@`sxf(g+-*Ktpc=O zOYDtQ^8e|os)4#)fe;beDX|GhhRe08zDs{uDSf|`m2@z5h5*HsakC95?9}d9pZY@WY=j*)GTb)SvO(sY~hHkY$v|`!Rl!nGQ$2gvs>O#MXUC- zGn2k!s?&rcw7~|uo^0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU_>q$gGRCwC$TzgbkRrUumol!Ga*@))o zjAmIn+Vu59ew& zO(XAn;C^9T@4d&DC!T7Fb=O?qMkw8V{+kapbncr!y3dm1>>OL4{d&7{4%X}#zL)L8 zvrk`3c9Zu#a=$R{Awm;BbuGJIRBv?`U$whk^`Y*Pt6>tsF}z=V)h4Z7S3;z<^GYx| zZ;|%l-lBRNy4J32Ga~PL>V9F|gM^;;9rEyo{0o*l5>p5xfI-Dq9ST!CF#{80JTO$+ zM)x|&HhI_B`$^CBCiL>#D}Mh4W)3jTi9VbWmOvMGo=GH=R?KL4o>`3Rd-__6`{K=y zDD8IF-OQG@FWk(Mw(D;0LF+y43pX;|wS-_Bt}DNs{(0gDLB8Z!-koR%+&h5Kybt~~ z|7*+$HuU6SXcbDHND8$>)}}DqEXF+nFVGGJhhYy(*OF~mv)-(1iFdo|qR&&Q>CDoD z(8$5R>>rU=yZR1h0M8iKUe*p?A2O!Fb(n!>GHxt;A$#zV@}>WsHUHTPzraz){R5va z0P+ibiqNQnR|B79`^RU`f3EzaV?p1+JtrF1y4R-!27+s0!jOGw#+$!601RLZll7fV z8n(P~z-?z8EZ=L>4QtaGhpD1@v%BbG%=b$}{o~2`nS`bbXa=DLfIa7ILgt zC))!<_EAEC%j^@J_E`VRVR2J0+hhHtHQUC=*)~rO?mk=WM-Sv5pof|Gw|7c_o6~58ITfW-LG3pC7(Fr#$w< zV`T|hjE0)@-wDW9Lm`T%VFlG0mr1Vk8DI@1M1iMH2dG!6pdJ?3#0IZK_pOq>F|*tk?LM@kGN~ zH%P*#h3{p8^it--*EC5)0mWU(JY^k0$~IFtbf}fLYIo zVnZz&5#ruoysU-X`x{^u8&aKQT%VxO7Z%T6FgDA7*3)^Cv;EprMf+Uu{u{@c+K|f1 zgdztkBQyy)*^6R!&Ah;*p1nsl zURK>uX2wEhl1&(4z%`~bPPIlh9pb>#zM`cPZvPW*%`q~$I zL*PKF#HwMWY9uU5oQfrJPr~4 zo`RsiV4n@^G`TY^I$g|MD&~{II{#wm{|z1S$TA9Fb)Ip&k`?t9b}-?bI#gdqI&Pxb zi~}e8iMb1Z`=J`igb588Fw2Qt4-rlmxpi74dEN^q013A1N979Tm5?Y+H=Z$8*gV`wHJC+SmIJUoN`S*i<`EVq81^^X3&1%?K ztZP@BVM{7q9+C$TRG3cR`%$x<^X@{;uH+)I(-AWnWX{%XuK4n^7 zMZ(PTOFL6f)NM~YQMWBkUK>+M-Bx;CI^C9!7hg=3)}{0rrFCi2`J&o{G}ndbErMa| z{Yjo>K+*ZsX|A)WFWgO*4sPgAXdI!iP1^$-m}`Oqe-?I8KkjZB=bfCf#JA!~`e)~_ ze|W3*#x7DAv%_6|Jxv37pKeXjYy(8Dfy3!}*ydq#2BpI}NIU_)mz5LriI=|Mrgzzu zl(V%rGNeTNx$C=bm0nCsOWnO>U`Hg^n~FPFq2;d!J?~$b3mH|1+3x^yWnDd^eAIlvEmaB#(2AeoR7P=Nu9l%Rr=v%(9JwRdCi zdQi*dKX7orglz}r{S~_;aT#-5l)3Ge=D3{;ep^YhWm4XPFpa4Io=LJ*57nU{e7S=j zn9vvEzfk9 zt~K+oFxH`%ruKT~t-Q*(U8Bbifvmk{)%uCmL{I!<=aIL*9ya39Wz?r?@A6Rb|88zM zMN*BxG%euh(8Zc^l17`D!MOx>trKBxa_FTEyVj*lKS$m@i&h7)Vb{Ch{DzC5`%08( z$jU`WR+36wN5Zw0#WeXY9-7YD%|~m9axQD!D8-`iaVHwrOA5K7KCOA~{1@j?f6Ypr z&(R$~8G0S9h&WJ5#2+VNL|H1CS)s~WGlT{DOp8`)8A}8EB{bG$Qq%LZ6X6+EEs5ls za7|pxBh4qt_a8kSauX^RgziA9;gx&3v>{BYMmlqC+Yh@Atq!Fi;NT88 zmpw8+U%s;HT0E6ByG9qO87P~=1b#U3u_zDiW4DPNm-Sjdp$Qo)PhQ=08w7+|Y~H!YRvl%NQ%m{_;-uy_HaEPuH0nT8R<3Fmg0JwF1f=OEaJqF zQF7<$oSN0&vxZ?bm}SmY$UHr| zP?F*!l{Ic?v)EaQf1OKji5SC119lg%6w2p9+<&fGbsGw>MSAU2bF9=Bk?W!bK5e?{ z1tZ2i{`~l1>i{NdPh~gLH!$>|^5+Z*dkSk3u-@}tNOVa>W5R7P=W62Erc{E9q%U&o z^kz~Zc*%*Zr?_<0s-QPmrvbe@<%ujBGAep4Xw@XrmiXJCqmA+^s^r>qo#OIPr4BC{ zKi+S|?qlcQzr*KOi|TC#mMvI12E7PYs{G2MjzK!p4SrPS3#kr{#dVlS-rjjq|K-TT~zA9rx%SF$4W=1j(T>` zE*4&?COXs*&}57Ny;0c`=RS3H%ir>UKz!D${I>sL zaOn1T9-a?z=t7DuGM)S2{=$$X+4YFfR4jQ?L;UbS$72^DOq*bso@Gu{|;h?YH!Ow690>rw)Et4`1H9|ZJy)%&-hN}Yn5 ztmx4vIdf3}6huNyEOKSAg%&Z3sT62;TO|`9dHo3ej!^LG^^Bfyq$seW*WM2c7*_mM)VENMW|Y;}XUnWyo<$u| z?Wr~Kro}H$g6L13^Gr@|?W#L`sg=k{RDx=x)3j2e)^Naaf!pBA7>B)i6$7+rN+94F zMtUu;dTlwVjuPrn>-|ABs8?%GY`QXk_Wq6(={!i|vp~owf!<^PMDargXU`>r!TDCa zae?!>#0Uvs9*J={9_3X69%?%dy(QFZhg|j~34Nh4G1jx~sV(7AlDjDjdw}Y_34|h& zcF$|&l{3zY;o1(yK;9=}&gJwsNAuy3#5mA#_+v%k8S~eS^co<*px2yjSYab*N@UUR zrYy{x<|CgYv~n>?2D4v<7!%Y2Wt&FKMb!bo(1?_2qHxFy4^_D%EIRjvN$`08;X1wc zUf9%OC6_jTTSmYNzQ#|)7!~Zacr0t{Y|SvsguOLx^6>pfDwh7og`7s-KsG89<7A}Q@@qCodJP~kZ8Tuj884>W_zuzmqa82~?a71%kW5%I`-ck$ z!$$rPG|m9N_TnWDTQgp-C1%fRHqvXA09z5ghVS=eopJIB7gK8CEm|V~v1+z65$r!??uVvvV03iT|?zg6M+iwQy?jHF~X*RH-w3jsHuit*C=H zcA^4uvr1nznXtKwo>MYmBD4Ztye4^ykzUhD9AD!G`(IuNxic}~iCwgC=I7X7J8?Pg zTe(`w#)Wkjjemx*Hy-s7{bq{QjF-uORO3w8UdTmgA#C|WqISG?g+lE^+emsSI*yMX zmfBx(lJiqU{u&_HqQXe58$E?pe5@+tbB-=4wiac=pcEp^fA*+c@_XYY_zlt#=l9i% zlZGFpOdHt_)YzAg9N;69_snSmqeS(qqSrnpaVYlJJfS)YI!uulb>ag)>Tw8j8eU!W z55Eu10zFBKUKUWx`3|AURMOg$)FC=arGP`n3=uGE78ms;oOMeO`Jj>~|pOJF=L-;2UQ4)uTyhKTD z#u)6&iGK3q-_hL}_aJp^cuNeZ^ecqc652*+y9ty5(`jhJGOjKKhhARy=v+*_sF4^= zKfny~i{3f2R0M2liX2TsNA9P^*C@ZC0cYv(|A}z|#%Yic9n@t1N#c0MZQHvfmqAhd z@0xtMMR#Xh&-}9+(qOtqn0`&3f=!)vjo+51VUwq3!`JfDw#nD;rc<`bYj_8gtg%`W zK5F2h_wLTPM|K{0`yfB{g{b_@=^_3!!qi0J7oI9oUv_3`cS5=wgj{oSJ(VLkQNGm( zJ`!PZB8kFvF`|Fi@Nn(+i~}H(M}K)Vna|}iCa9s7Lo)+}exg#FKK#UK=@g6`& zUeCqV<1Wn%Ha0=Qja^ugsn7p9IEGn;h1V|8|NUKr0C$1J*_5;$t_INlz@dJqrYg>rjlL^?N1cQV?KIldyP_4AE>~d}S4$j9Hmv5TP#W-;%-imc$9C(nV!jd?_j~ ziOlmiDnvBG^Z37V?xmTkiE)^hD;l1n@(NGMWX1%x=3N?o3UEIW894$;kOJ;o#PFIVkxD`!lt4?|ACq2U!`>N*I_+D7UyYRiyJ7$?S{cTq* zeQD3W>1FQpwVfr?roZi~h0n`&7lJ>kdwTt}-2L+ZV0CSOXOKIK00000NkvXXu0mjf Dm*^cD literal 0 HcmV?d00001 diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/larry_blue.png b/mobile/android/base/resources/drawable-xhdpi-v11/larry_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..3fa00fe743d78c53590bf856e37dbcd18199dc1e GIT binary patch literal 7443 zcmV+u9qi(XP))maqmx zC!JpDNC4UQ)j&|z5KKf6M06aLMP+^w2%sQ>y%->b9Z^;toN+ue#~D2{;{48!`>zf} zac}?yQ3UiKoOAkrx9i>RTen|T2S_(eNS*UecXd}+SH1i0_T8l{mg=#k^m@7?bNu?F zL+;vicv#Vf!^7@aue}zF0iVIRlf1{{=)P)9-l+W!Ug4blJVo+5`kOK9jt&vmRNGRs zMYg&(J@ERtfty01f}NqzT`y^4((X{GaF_NTUhmwi4g4NI$L}VI*P=b4Q1PDV@9D9) zkKa$;s||kaZQDa3aZOEX$P(S^iQ&zd@$&C(UL6W`d@dA%R~YVK^gRp@*?0J(@9{VI zy-U721F`4wmTCh(hxa+9(R0Fa;(BZ~WQlGdPTGkvIb;6kr(jZH(z1PG!o+)GJcbJLT(+=yBowUF5wyX68%h_TRDT z_`F_oUv2?bSAwp)mKbfsDDLpshsRJxpC#ea5Kxs9gMY*s1>9VCpd;|355ofo;)D_ zqd@|%|9Ua{wk>$>b!vfuvEY>AE~hkBH<{@ddY^C}ItOTkAQu9$5=|g4T_tEb!oKyP zH;%QNwDzNRlgd7X(Q2X?1=@Q$S{Igm*tSsa7q0o(`pAKkVIqt3bt?;nGK$MbCXkCj zgtio;z&3aPVLpl6^bT8W0X=c3=%bb!C63X6^CX-=HiMPaYrVMO`**!Aj+rLLos}GL z>_X4-ug~Jj6|4Jx>Axgut0P8sy=EO|XU_ZJc>6gAPG-+LaI(WA+UreowO1JU9e+

    51fPr2k$fFK0Vg4;L|Tb3MG_4*}hmm0ag>}rqM5kLSr_3^IlHD!aj1P zro|bp#po|C{2!>K+l*N;OMG@+f~~r1#mEt3iWqZ~I0~d+mRJ!7M1sN1$c{lx>5tw1 z^O>>1Pm0Cysg*cqrgPE3&yj;#-@a^))D;QE=p>QAva=>}z=EuwZ~{?F2HvAA2O{MP zP8zT=6dErqv!ZP$clCOBM_L^7*=k>Sr~>7Dk_Z$wy+@QD>2lZRBSTeSCm20DT zgE64W0apZ25m-$YSn72W=MF_3D$6j0BB764gu);3d?+;Gg`bX&TyAPUTeB7%sz8D# zi9ogb&i`ZIseAwZ1Aw3~CQ9%W!BGTEDcD)GC;A@2Py|#dc!~o)$KSyDlL3}`DIVo! z4jVThfSZO2^SMym{m!yx{^5d~S>$Ph{G=Ta)6h%N^ z23-X%L8v?74o1y&{N7ut!{Tg-7jgbr?-}>0Q-|Mm7u{PB~1^Ivx|k!Q6F z4#FEv0ta0?bnU7C=`WmUr(ZwexWI5iap5@wYRlEFK)@Yr9;l9n^CZO&f|W#J4p8o9 za0g!Cuq`0+em>K0!JB=E$g?^Z9jbtHB*93i*ZNimi zqSzgkDm+vH-zUvc<@gm|xJOPj#h~!mPOCNer~jJM2PJ?R;UJu#1QIB<|FZXIkJ_$r zwAo_f;)^aaydTiFXnE4(IOp*5C51pa1hu6XjjIL;gvY}0NHnf(l>b zN>p`Bi?M-UNW{SESQxe9n&($Jfl|^&mZW=q=ZMn_IFjrr&Ifk9;i`N#e0Ms)wjDjmeM+#G11z4#JyHGJzU2 z^p3vED8icU(~By4&nm*vEFMoV)(5i9{>y=cJF3orUh$)aL#-9KF_nlzj)P-cjEWKn ztT>#EBp?Yq%G%w!@E_kGlE6)CD$d;se~;=cD%LQ>P3NiAsHLS6piLZsTm;HcS!i6$ z(eDu|@#@X#h?(t3zK8?;l->G{4X;pc;fu-$NwE3U#sCskXSP3m;s^0xd15q5iVpGw z^{a;}Np~<-6xe)vD~@vz9^W##92C|=*QD8}*jAkT7hD5M15Z#bnz=5eh=IyriWonm zpWZ8jb*Tv@5XIa)#5CnGd(=~KoLwOXxDJBjfryuZK;VmYZe6hE_ZTvvI#sm@X;u$) z%F#*Z7-hy|9~~9{F-D9V6MZvYx~izRjhLJYNx<)&B)-o@9Qq<@$tMtqIY{}M(C(rA zhk0gBWvw{3K~hY|RcFs%pV_+vL}{YACrlu`2x)R-0|<@pFwl zBi4&^4wj-VB`E~L3!|y9-qKi|q~a(fB!t9At~>GN}`eH)e8`?f2^7}q;K6&g%DkZpk z0sC3Y&-`q?@3&uw1y(M8J5}CC<75&CHjit`k*`%g4|nj;ibLX1htE!|9^|}sGkhh?JX2aP)y?i0r> z5o5X-edRq|b2;v#ech%VW?AolwSs4ua?_KpG=$ozxNDZb?A;qWPyB78+`@fzZfN7P zXgO-&C)BrG8C!}p!GTZ^rtdGtSTQDxagQ8u%@f5KB00)y}XB>dgmYRt;F z?fxhi(OMen7f|Jj5DE+U{r(8tlguo$b^L&){{&p6KUzK0H2BytXU$_aio*+uwQF;X)JZ zv|iD+Q){N|Jhy+^izmv8Hy^wA)`hP%uL`M>BJ~mkp{BOXd*YAaJH(6CCkPZx8M0)* zy=dFFJMaFrRul$lUV}Dkg<_DTNDIdxyQnYu416)8!nEG&qvwG4{SA)AA~h^rgX6-G z*ou>frJJEWB761u6J>oLshY||_+tnuk8R}6+XNyH z3zm$qt11?8sd=kDDK6gq^O;+>YJOI{f-6;kkpiW7-LyymMK&IfISAavpb|qQtNiQw ztbUJ+Ys^$|P_3L_?i~z70pinhK()wFvA7DipZ#>u(yFOEOqEv6z`9M+OR{GD`73&3 z+}L;-6)Ujc#%L<9N1`1V{-D+-k9ZozdyL>L3Isb8b*dCeX)$=tZs{BG z%E6TEaV6;k*PS~KT;~qzb0JWN_Z8eYV#5!AhhwXPlWIxtxii2eZ6}q#rz(f6LLHPk z;K>71Agvh06>_Z#iAL@~&Qj$e;BPRW+93(eqr*s0SJ2#gZBw-A9dV7fiJ{Ub*A82K z{7)bT-K@s~&GXI`ueWX!9JZojn{<9JYO6hE+t-69Z$8pR`U7A(+r=nu+~tnFSx;-2 z7Opny(r|RK?x!bxZXXlVCUCa!E{|DU$oYcI>WXFYYQSGs7Du&;)>-1|g zghHG4Ypu*;=DvUbFm2~|I|e-ZvPWLr$m?$E8nplFy>H;=t&5MJYnU_USxLZ)b?#EK z$Cjk$m4AN-i~uhSt8;OR+@PwurWs27J1TaJl0Yf%7%( zId!YJ#_kGKKCE{}Zq)RSOD5x^C^hP_5UvmrbDa6Bk6)Lrjk(j{`rL-RSi_AV{=g$HG zxV+}<3W@4aRW@$x*-yLAEN@i>R!FTbvtAiEa%(gRUPS=9P*e&WlMHENC0EeAs=%6euxznN*3fGSDca}%>4mC17LA6msi3MR9=gOaclIFUxzvG_w&I;&f&}p@C z_YEpLK?H#)8ZYXChAsI^?@QpE6#F<$?|>r++(TCxZ>qu5sN#t{E+SPE=8`L%!dH=d zUKwBSfYbp|MeBvoc%li9X0Cudzv0%@yX>DIcUz~AD$x{ziSsofSGmxwOQkzhC7gCe?JdtcpqZnU&^z^euROAE*w$!%2Iq3h!FIno3XPvx;w0aPOGWs~ zv$K?0mq}k9)JuiW3kYLDOued7?{u4^>7BkCjCDb_PcLp&qRkVG>Ki~k$Oz)s0 z-HBOjMtTUHQ=`RJnF>A78@XviAAK=ire#iPER>>3FzK>Z6L}MbUh4j!t}98{-wB(g zW$HRo)oSO)gLE2;GUtDGm^z$T`A3VfXk`XgVeqCM5j1{$;0*{^O2;w9$dSfHp%bV6 z*i-;6eN5@(&1y>{1 z)v~Y8idJTGWbRxYBfSHX0V@n?0T}FKUkMspva{kailWmbeoG}wC~Hej>MK%Z7eE?T zwomO>s6-!KJ@lfm5feZmVP{lf$xyLLol_6_UIA8Gt@E{J8D^j=x29Z*GMYx-+e&4= zoKo)$Dbw^0+zSYa4^3#~8omuyuc}7Is3SX?$Tpu|XJH8ow*;w-<}H@PMaV@;r%^{BRcbPF3%UXh zzh1Q2=9udpG-v=bi};3qz4K}0-%w*j6{@HD)pC(l;;5H~)nRE^x<*3*y(L2l5^orp z!Za3R;xtAGq>7O8@_GK5yApZ_0*4478->7mIi-s=W8$ugs==-063X~>X;|q~^=Vi} zlM$H&g;$LsYE{Em4)??fl0^t)^XXS96`h`7EJg)XFi-oA+rcHumVFH1f&GQdbZU4DA zs*K(Ng9h~ul@|Da)Jdgr9~FvW^Qj+IP}R+tB57C+TzQ+_%Z{I;;Hg{D#hr=5;T;>X4&@|Hl95IuOwX$FgN$1JhmToU@m*#7 z9a`U{%7x%?5$!prGFEs3OHP72*JB#iEn+;FUR3^`GZ5P?OSOXODyLaFI$vhFsq!}D zAUYu)1sIww9v#p)=k}mXAB)jD)-fgN!^@-ojw=}J-?@V7=&OJmIU95i*rv-Y3#&OseniT1%2b?g&TpwmLxsFOINAa}#(!m6-m@fJZtZNPB?hm|qH0!ZK#9ynGKS zM3DzpUQa;AWiI!_7OmVJ5=&f{kTM);p04XCFJP!fUUR*ZxBm1&tdvvbFz|Sk%G9P@ z;2;kyq`n?S{EdLpE8!`UDY6EpsU%j06oHK`m)3nGOdyI0!p+CiJA?g)w?LE^^p2{( zwkxPctW|L)B$O&Oz!}gJ2t(w&1$K3Q%%@Jog*!e@-SdG(YfNG2?||OvSsv>5N-NkKD1 zc@Ce$AN$Y_J9#Jv?mGjqj|N2oS6c$19|Y$7_12zG%8*DsBfZmCKDtJgr>#mb!6bM} z1e;IYD~}f_=aibKPg6sr+H+9zL54-W5xoQcPVQ>s1Vf%%KpkHy##9f&MQDpAce;YH zX=C&p^#7_afl4Y4b(p#DZ-50_)J45vy#x7qU=*mhgooL&w#XgSw*kFbkx9yPDLjg- zQu_D-r@;ett1E#r#B)<$mFD|RMtTSQo$h6NXIAwnIEP7OO5{oo z3sqMFHJ84Q)kyDjTy^@OSJ7S3&7SGatuH&NFQsO5wm}ZLDoV;9Yr{kTuB*Vzt|xVl zia06aNi5yl-}l-}t?$_MPMYHB$!+Cp%Yx|Bl=(4u96V(ip2CdBgrCSfF?tNVZ!>Yt z|GJlHT^yAqE&ka44HuI7Tiv$W(iw*4uSJ&1KSlXc#zP(EeRR}A!rC|-CY2l2S;SQa zW&%7gElHzm*8IPJp?Z=erv75wh{v3+Mgm=S$C(-v@!HGO5GaWR@|GG~b;w1@eu7uc zCJ6+!zBEUWgRD8Mvp*seH3Ui$fqE>{9*4lI?PxVej^gnP)z-`&wc*qnXn#44wZ?>& zmb{H6w!FkPm*MuAJM^tId2391?A^Qc`}i5Q-YnRB;@!dPwZ|bi1F;VwF{-z%&ID@i ze(LxK*vb;3qu2ryT35n8eva)iu?;4^LV7Q6t%=9?DARrueu%F;Z!g&%6ZYXh0HMI& zbuH5dCZF(7h0Ui&xUU8@I|CbVI9MSuFL87S)esDd9HVw-*y_v~h=vVl0}YQs3Yn@L z1q;|*iiR4Nt05kwnkZV_%xifZq{XJHH<7BxPd4jqO0#{aae!e8-Y|on(-}zKqo%JI zza!q@PYvS_?p5{DvHOj?Yq^8^A^}bWnh~Tr526fL1%YUVf!(jJm8FRwoa1<}9oqbe zbE1)0ROMc)S_$w)Q*8+ZRo?NE+iB+%Rr6R?$lF`04uN|J$I!SD@9kh#KZO5JAJACs zImqU#yokf(L7JS%OD|RCFf}-gp2W-}vMxn87FC97wI&eFi&h25=&JRW8kfc3MCxi} zOU;X&&2q1EN@E+Ot2#j1uO=NtEBZKbRQgEOB+4x9inldWH9%L1Q&qJCEx4|>1hOyC z>mYYf{oHX{T|tvU_==86B=M_jg>p(`CmyTkR13l#R96{Rdq2pwK<@{cH65g@8y!!| zA?V{^nWM|ZU@+=0qlcTx>-9j%-Er?yn@ciVBpO! zXwu_Vql2&pl9u)Wo9I z9l;|t@B9xQP}QDR9SH=Pq)`0T+>*S^okR>+Xmu?$Tg_Ip)oe9e&2|~L{|8gT)KvY> RQ@a2F002ovPDHLkV1i3_M$-TQ literal 0 HcmV?d00001 diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/larry_green.png b/mobile/android/base/resources/drawable-xhdpi-v11/larry_green.png new file mode 100644 index 0000000000000000000000000000000000000000..fc037ba197571c069aeed34ea19708d3ca36e04c GIT binary patch literal 7439 zcmV+q9q{6bP)BwsMx*D<-(->B%p})llkeHxx9rI@uEF-v zzKkc>Gd1=!Y}R&h&Re}-*nVPsxcrNp@F!;$g!i9WXzj7>J3ZGpw(pBv2u#;O@8?>fy$p5H1-tJJZ_}w6!*CGaVvUq)pmYCS^JQ4~T444M8NNkR^2ikYL zV*$(-m?^Nw4yTsdqghv%bBpe8$yXYDDgoVRyR)gsas?kzQr zW53(lFO+^`w(=8;%C}X_9zT2e(Cb0#iqdm8V(li@1}y)e|JN${;yh-vHJP2^OrnIP zY|OmIr(}82CeSSnFznB#+t;+tdW%(l?=bafXR(J1x4>rr(d?4{>D#R(FQ0}M*Mp>UZD|{A#)I|1+ zN(1{{vs0lE(H94HIpjQdIW;kmDYuMo0sq0FIoW&RLPVD66 z_Di(3i&(p>+09psS+=?VH+dUg_&W>|Xp7!|k++wvW7au-9qi#6^ZGu%8Kl z{{M;hNgUf@G&}bDC~I|>vi9$+4Ph-khV3P8mqm|2lrShTfwuzTiYv#4OHWPRN+ zhxdwJ8^ErQufaWUUl|(s1>SSm==Ni|tca?QjuQzqyH+u5Fd&;mT?VPFaFk0$$J4?) zPD}`wSLcL_59Pc+W6{8-5!B~aD+>lyn;KL~tO#VN-doEv9{G6hj3-S8r|sl)I!$Nt z&$2@_OZtuT9`w3cI7?eo{T_uV`k_$ugyTh(qriy{r?J^Z$+UxfO1F{hu|RDu+RoC}I(5@c1w{p-tSYy1$=c+5C6;Fp2s>xk=*Oc?pi2uX zrW^!g83vH}yaBBzn<_@KYe!{E$=-4NZPe9lRITxkO$EWL_2}X#E3O=4cn!)<&iY}= zx{)0S%QIvUzQoY9Hqj)|C7X7=x*8OjBKABwg2){YosQuGc>o5v&rP<0R09~!$HY*j zov(6>sE*-i0@u&S73n9r1Jfi>XkaxGJc=?Xe$`gr7?6uFqg8{*B!ujVwr7`ZVkBAD zAd44$bv6NIuS84;6e$jZ-dpPC5#1yH@Th4|^yIV1nn6({P@|mX0~2;uO*;!R(Qr2r zcBLCwG$ureLeEn-56UB%kU=8bVn!f4vglLFBI6p#n58^CWkRP^?lEZfR;Yh9vWF-r z32}pbZJTecNc{%?!(`Du!jkM+pkvqQy_SiJo^4gA0+lDYCs7h&;fwP-yu7M73msju z@FX4sQ%T?ij|PEQYsOk{)-qTFZE`Mei@+x+zYDT6BpTIHRdNgEusLA;f<`EFkf;;L z^7u;bdUU5#)ztp%cTDwRqb*h@7^+cF65{y%T0mr#cM!JDQx-g3B!{Reds1-(s;#NQ z;q<)7L6Tyl#i^78mAZ`r6h{<&X`)Uu7T1r+pf<7cB*1oU-;s|^(YDNNPNpbN-CB1Byh2;|dUX_;NO(swYQ zKgl6y<@Z2skP(lo)Tz9uy3_uX2oi| z_Lde`4cStW@{_GEnwix8VEo4+nh3{^L2;u8#K0v=-eX zet}Std|Emd2WmF{KE_%cvN?c!^_jQ!xica`d=7<34Z#XH4060?%R%qY_dj&wbYP{? zo;?DA)Zjgz1M{q#O~j?sYE8lL>TQ*2oIq`3O&|-WaKp`4j9pbQ=${VZPc%}McR}{U zA;Ew+Z92DH&hGtqtlp`$Jaa_sm)F%#hXeypa#H#eK#0rJru6Dvcx2p{aJ;a)KNtgP`syZHUyJ^ zyy$an)5~(1ukN$=b|wBVjU3B^4%(*uiT{_m^x4yFfW66nJCwi2m9ZoaY!9s6KJ0HQ z*xYkNyFZZ8 z^=Rhn&z^zio6_kh17m*HrN`Y{*fld)OJuDhe}~`I#e3Y!1nKC^rO#B$Jes<7WRzt{ z@LQSki)m|zI{n9;A9wC?*OqIp|HA^0iBSVPp^4|$vBhx}90&zr`p&F9&)Oi?M(_sD z{4#4#a3|+m7d> z^HMHzevO3r&2GS>0VUa;3DVijm-d}5m?b+&aVFKFI(@-xFzx@yT3gn}PMq7LlB(Uh zcnY$^D7tjw)`ceAS$Hse{H|kj3oucPCY_l{WqHtCjKlmK>d4{%*<0S6sByOG-Y?Sz3N#arySc^OhGKoSn3AP11F>!Byh8 zT!J9f(EiDP-VU~dj1^POC=yYvHNvde7`VIS(^(r1oLOX~(3hQ@Ze(59NoEtR&&8nP zvjj8xT~0E?L^a&gw&Qb1KpSV63aaZNX|1?2-85Qv4?V*b4OQ00Me7RFrtdzLY2exc zbp&YCPZ$z)TSfNr*~^C1O6DQ_F@%(#f2?DRRlxGZ>@%Oh;$UXgvd=Ak-L|m<_MV#m zLm7Kf=rmoXwVTgS49f=`-fNkK+lgsj5{&c<_=OJ-CjZp>(VHi+XS`i8gBoQneyJM} z1u_n)Zx8Im-KVm`+mB{fy|FR5Rx%IcxmJ_Ftmx@;-tPTZF_B5s_G(cE#jh_;4**zy z=ZQ&1t`ha3$#EN%yC$Rwxal0e^s^B+;`X2FcP|ckIG@`_a^_&%&_L(r#Yd)o12ayQ zatQ|gb~Z~34o~=e7=tU<#!PC&t>=fqU6MAv>tS8ibS)7me&rV55P%f}-c6NdjjX`?xB4(L*HeB#-X zs&N*|Q`8t!1YipdyxAUjyS{;VE>$@*EKH!3qEGP&u!n4NZqzncu(pfd4*6%4o|-Pi z(R6Yf*d55r?!8;z^Gjw?eqlJXZ`ZR>>Vu2te-0>{S&JfMeU)Ak2B|g{dBOhKOUk zm?b~W-FG_I&^+*kAe94}kr%{3@|$){@pHKZLe9(mRRCD*aGtUGCY#FAx4?fF8z6We zabgC9`Z%_~&nKkN2T5cYF%-HoFQWI_#&P3+QfL_*@BZAqZ?k7?qwvbd4GSbR-}c$$ zZzyX+?jkE9lvtqntk^oZgqt?*e1Fx})G?r8pc*NAvJ2Rafp3D~-c~U)pSwt!^AXjO z6X#sDlK8hiOi2fA4W_;QpQ(<|GAx&}rbv*gnuZu;#Ug#?lb^6>d`c4oGUUz<%Rts84qgl)Q zC6rW7K8vcf2@KS0Ve}k6n+$jn5v9qNtfaF^Bv3#A*GqC|pvO!Umf813Yl7YxCdUbA zS*wa2o6j;jytN|bN3O2x?VZ>22hV}d0aiu<=#(wk)8EVsG82nu|M2GfquQUx%rP?K z3Jy&^1%so2bT+bxkWl<6$q~20G)q(tR2Tx)F%@!@9)tUVBGmN8%e8VRYe`?j-ho*! zX7Bk01e8u=g#PCFMfbXO(lzULjyMLa4Gl92n3u8G^yUyX-NRVkrX7?0=NOPPSxaLi55;$BS}@%xvoImvJ5Pf3f@hn`=C1 zb>ZNXG?b0ANQIN5U<-HV^(BTo}h@ zRxMeZa&Haf5|caq6NQ!L@^hel5^YmD?lNc|)U9M)=Uru#X^j;#Yi_oKD?O zRGD$Iv_M#feaQnq5`k`IHP<##e-r&PnbqkMxIiw!bccc$t3OKX>0%EVYAM(|aD7N2 z7gU2mCI~C-@()&`uAZDBcW%Se`0lQr8UC;=V+xNkIpj`$Y1$U5F;b-j>oQQG zE_(`~6R*DR_sam?Ny8yQD+4YdWMWW!Ikitj)@l9+!@Moi$sJT^Ot}+quwq9E&Kf#% zBM}JX#zQX+f8;%rw|j+IgP-l%0Le<;PUQz!)1c)QRAlC7<_(}#N#fu9U_|<^lNo|{ z+R4LHm9hwpP%gatulRVt8M$(mY}?4QQdLt9|JOUA^G*m@a>Fq$k|C|)D6SPA9SBx` zjS2$Bah%svU3=cWVe^3zKL?35jzU+JFQXIY#zR%IdU1>p+mB|QSh#xReL$SqZw$7Q zeq~RxY{APJeKSWFjZ*CYp zvheUUgFO@+weLZFUZQ)&>lk&C@V=9#xTvzVMa`6E1&X;q8_GtUWu?r;XB&pJMC)$Rar_c|9P}YfUvhv_&YiSxhT22S?k4R!cZu?ow5JCv<3%rO?oT zC9Rzxdok!>c4jd8gsgGTFUWBPb_c~M9%OA~zvMsfq$5(c&S^1lnbqlvVbE%ZRCudc zC6=6o&kARykR+z!@5pZC*-l4w@`Mf`cb?=iFQwc8R=tflY$FMO8kLp%>0Fcq9SjTn zLwz1@f9pFe#QU?HimtPXbl`fGyIuAOQ2tHttuY$S6csg$_+L6&j6)Trfc#2C-Q9Llq98pFQVUXTbr( z0z;7o(9kdxUHV=}UZ~C+p?f(OXC-k_rIIXezeC-pMkv~O+}_d39q_ZEy+dUuW!H8t zRUqQp4x-P{R{d+coEe2-t$wd`_`h^@rE#>18d<7q#VqOzgMG^Q&bvHj2DL6x%2E=j zE5#lhUS*QjytRFPq1^FHWkUVR7?OMGGrc&d?NTx*m%3ed!(~}ZH}(6rCT@GZQjsiV zkK>ExzSA2zu`iD_HgxroEZ zlyawl**h4xETmXG$;s;O&hcuM71;}qoWm1^T0fYz2Eu#Lv;A5J0rjGDxm)~SQi)MX zKsf=Q+jME66W-bxL=9tVJJB}S-!2FMOpV<6-TLim@9g?K!;m{_U!6}YD}z$hSDm4# zsNNETlA0HD;7G5>I<;82GBn^jT^SW8WZ386!FPEZ#H51y8}?3rqH4Q{{mkja8p7r|NS!s7fE zdQ{aZuu506Tdo|X!BNLenDzXFJFBLjEwRu{J_ixsbv zQ7D%nt1fB8tL^vdJPQsP!S)Q5T2r~>aWhn@4-7gD*e(N9=JDrJAzm*lJUsa%U@Nec zGxcgvzoH7^L`!O--;a9F-IiRVm<3OaR`3!s^;qa)BRDvN3WHYGj@l%&tf|})2t+Fj z(;12T2y*9={GDUhpfMUrd7;m(Dtaixi*m9;nAXn2RU}(%5x{UU^}N zx7f8^YbbZLo&>pmYStS)UFFW}8%89Wfy37#Dg<%}gxYOxK1x;D8I`u@se?7}8gl~^ zW@*!KH#*Sz@El8vwYH>A7wO?nIr(Q$l)UwaPNx>j$oidr-{hBIJQ!9Z8J zGcNmCQ|?raQ+T-jN;}TRy6I;ct)eB)6rV%eqc{vt9W7FbEDyB2cHkN3Snf2BneGn2 zlKajBGTcfI*dgenUDuX1k~@XR{K^hinF&;$%Eoq0V8^mUl_HBgb-apX9M6Hdh7+p= zXMtCG&ae6iuPkhbl3^c7?yTPtSOaO4Xz$1=DsJ#yS!qxuR0jp{qTjNA?2>OjN4;)O zJzeJ0U~#llCeH8vna39UA^tRr|6rc|N7bUT6Cto0D^o#HehbeiI12 z*=X;0%z8R4)N-fygWHc!I*ZvGswI|OMg`ag0h>?VIX(z z`_qjxc}PSBKfbKs@Whh<2ct{Z=vWzb*U)4FIl)*)I_dISRUpZb1^D;X{~7fBkU!~? zdM$gWl;8^FD#mgcTV3cc;83wGjZL8_P$SjO>+z_yRrZq+Vw4 zBrFaF!C9r3TBl;{G)AgCfwP5u~gIs;T&DGBa#Reto zUx(=vvmnHTFP#k1;k<(qQFSXE*H;2v$8DWfI=QoP-|&;N^Hf};!B5zaU%6^A&4ZP} zA1Y%sQl&~c*jJxr&?Q{vsE8BCR$^&0WBD_i$7VgbpRSxtS4~zOV=FK76_>jR=kYu2 zab;$@Dl=Pw`8ZT@tjQ7t@=|Q|l|YePO<)W|@z?&Iny;dKK5Z0aTc{Q{M7cx*meBx> z{FXL!Gl4&_X^h&VD}#eh>*Gc$5WoL|ok4Y`_RDKUxPe7N7w`eAhn3mhdb zcUxsG^Q^sD7Sk+qX_nH=Gd^S4%QChvB_%ekvYW>5^7y$t>z-DLOkQqtTSeBPqN5Xk z#G>x9QA$G&at21dHB=e=_%kSi0g1~(*-Pd*0LLgTdx_;S@meT-Nsq%G%4_0x_&x4R z6s0w3gKNy{ileP+DHM33@+QP`CF44C^{^1bNw>-&vWuT$@>Kb+6do3I)Q{I> zdf_tUiDIg$pG>tduPR?j^h%2>Gs`8ZYZAPpX*oKaT>T}Gv6!xyI~tT0u9YkP>Pobz z(qZHzH638yZI(LKZLh;KUe8&aUzv44>-)$ZC$GLGdZNW8Jt-U*Ws$u2p!*C;axH07 zlVVE0@fqaTW7N3dw`;fg9O*DJdz8T=a_~(zd*tjpni3Kt81xPh}|&xHW}6^aU4 z_DZUt{>nMC82NN|eyU^10Bsc!uEMKU$rLltMGwb?5N>FmI;rETw9Kv*0SlP}t&4!t zp$Hy|)WOg8bzOw>cprK_Me)%42KaeI1O=pP?EkXwjsG`k-cztNz&-VmKv#Lpydzjr zbKq~dK~{Uy`bZ!^l0x#=b)MKEccRf?pk3@~*c!Hmtzm1}8n!y#{vTJ=U)5Dq#e)C< N002ovPDHLkV1lqOb0h!& literal 0 HcmV?d00001 diff --git a/mobile/android/base/resources/drawable/larry_blue.png b/mobile/android/base/resources/drawable/larry_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..d31b1ef9384995cbac057442d3a99033ad1c55d9 GIT binary patch literal 3115 zcmV+`4Ak?9P)aipyg{|kVe9sR~9MeKd_ zovNJU#vkH1Ng2n5m+{AP9lr-rkmHDh{P8#qzgLzU?vu7ctoiW3g%uCtSJ!o@(`$$v z?oemecBtW;U0X%ZGwUD3!}Aul>qsPe^t3nXSjQMBb_}3!$E8{WPzH0Sulw_I7n7sIY=XlbIz|{@& z$$R#e%s!ETA!EkoD@wlYR-xIzv&1?Npx_wKlr1x)WQ|2vaa?>I$IU6Z^~GzxvJ7%h zO(cQtSNX3#dKE_1FRlD7az4aTav-82vYtpOk$qN5p0zfl#G?hE;s~g;6F)pv7kspw z+#f|`B$3eIyo;A$7JZiPd6%3Ix3GOsJ*Qb)o8Ml(|3>}teXWg4N?RKjm$Wvf>}hRW zwzstrt}%go_&Bblt%|Cy<$z#zu(8SrusHdV?jK?Hj#o@<6+1bcrDnu z-EUoU6MVpJkwt*)T_$Hs+~@tefb5SuN3CcH+ScAB{05sfrs~+K!b~b`0R)|7Y9Iv1 zgwS>okOF+b%d!~)S|3d$ibx!=q-4jJ_l00EKq0New-lP^|0eH7SOo}sW&AN1DRw?4 zZgX*PUQ@F*Do11xjTqorNkCTJd1w#pLPph2s_pHUm<@rNj@|hCn>N`HGy=ddI6PzS z@tcc-)-^T5v4wzy+vp*llGRGhv;V+Mu(oApv;xE>I-`)h>ti(_h0Zvp!i`P@QkcKF zSeD<^EYsQy2&g}byn8`N0vHstTLA5ws{4ezGt1gLBaFsl}f{3?;VV3a>;f5t; z#(?nbK|Dv^nL@2_!Pu z+K-I$PA)wwBO@jx1{^*3r0l!yIyvhkd43I%AUfg$Yy{;_2PKQhuZWaTf#Yl<(}{T6 z0tPlWB8x`I66+gPy19ZEz&C6r!s?8AWdj2JW$ z=iuV^o6vXva9@mVycWH;mHHKP37*}wP3PUy>pQo;dAj@hhD$#_fiybzq9Ls|Cy=7U z9#Zyf68j~Qm`}0g#&l{!_6a3_nVNm-`L#FBJZnv@{bwHSyGbYL1Q{lg4Zi6$H?bE7 z6|{ia>=ctiSl< z6PWVX&piJ|o?faM=0CCAC-=%dzx2u$^2`J?%;q?+^5MsG^gI|GpFszi6J;|6_hcwg zWem%}g%*9=?JzoU3u#vhZO0V-`4{nIpdu@b2P5V%@sWEU{FOZ8iaRqncJJL?kc&(| z%y$Ut2T)&#EBX9)ly%h9&cqCL@a&RXMTtjx2b-AwaTq0Z+$`;8*PWC}KtPi~#Z@^q zQ3-V~x}i@>!9YMJAm!7GU?Y~BeDLW*0D?a>wVF@3RvvwPFL+j_)Wq!AM{hhE2YL;o zg>59f%-H+mbLQ6oFplV9rhHduKc#6u*z`zsbys_QgR#vCOJC$UIqp=bP?wpCfWCs> zW}N!rX+qJ}83K=OCs|hLzfk|I6S7;D$0&5BZH3v9aE6!!ymReq((Xzc9Sn=z-_Zaw z&(zpd+rsohI&S;zuf-mO4@Vy287mc7UoTLfcdG9gPQ)qy(5gQR;8DN`~`bS?SpWy9=)d++G z;5K*D8PaaPxj|y8=bmD0H;IRNyTJud7RX}4VS^_GWKU@?#=$jUCvj$9u|{wP2_p;= zS|8odHA^H%4z->aO0yi4l&0I}K1M_7seUpgI;i8IIiVk%A8j(mM zxt@vJKNU;%!cdxy?Eq(2GpsK0q>H_Em8$oN{` zZhA`68q;bjtVz78h{A$ZwS%*7X?VfC$8w!G5M{aXsJX}W*v(98mxlCS;BR`0E(;4= zX!I^>H)5fZknWlKT2d7PyK*KnmB=RF*H8WpdwRSwz$g{j%@`C>D23_?&yUUj@D5Gj zVBm($+-LANLNM%DI4d&Bl-8_H*wOkmsLvYD#2p_qYL^M>4}HU#M24ekurUX> zkawtR4}EDj)xG^wPl;Mgb5!K$BNsLDb|dC&WxC$8gHsI_om&eC+tpkmzZ?_0;RC<)sxN#}_TCum z;$KKp=8@*AvM|!_3yUt3Yjc?0#8-8-gD;D!Fs5=bLV)*G<(7p$mTvZRX+=t-?=)&N zD%wFiQ-DD2f_b}H#_T4p%s5UH=1md-n@P33eGrQ{Yz2g8Yb32jI8!yVGgnbEX*V^< zf9XsIt$3E?y52?oz5=pli%=Z+{(B?4dDCDwY+XtwQbomtfYS>`3K)EU0t)lX)K_4; zVaqExg21-H*bw$O=`)pffQt4fpwZOkz-|VSrOYWI8(Pl!tg8FWGqtMCdu3IdS6WpY z9K+s=?g`Hj0}wQ#i5g8xWiOFjJwND`ED`nM3m^n@{~{2s&u9fSCwFo=abI0VAi zut59P{>RXl&4U&YvwlKJu=a1QzHAQkUpJ4RP@sK>{{k|=6}jxamo5MR002ovPDHLk FV1m`M{F(p& literal 0 HcmV?d00001 diff --git a/mobile/android/base/resources/drawable/larry_green.png b/mobile/android/base/resources/drawable/larry_green.png new file mode 100644 index 0000000000000000000000000000000000000000..ad6f84c26ab96b7116e45e29fd54c10d67e737e2 GIT binary patch literal 3164 zcmV-i45RajP)Orp4~1E^{FrynJ#Xpi>bh0;-uk}pb-#Z9KlD02$ZrnHzyFs% zaE&h$xyD!LxQDNjxh8aOe3gW*&tpsB&kd-J=9$Lo(DzYazx!WsXw-Czv5vQE-QErtHKti zw(MG^`nupj+-hjAW4|WIzFg-#`w|R_44MqI;HkIBIr@3QQ#o(s8S2MUABR4y?u_Lg z{BVZ5|KbE!)e+5=v;~P~uDHdID{DW@Rd=emqUNYV2qzu-HG;m8tq(ur&@2p8tp*Qlxg}sW)S;1)+G7hGv zWdx^R%m_%olo7~Z3l@Z*)6as_ujU7&;Lz3GAvz(2YXx_&EfAH=<6L2bDiyDWsVc=O z143Z0|FQr*O6h>a8}3f^FHUjQ&ttio=W!yd>WC7Z!KyozTvcZ@YOmtTo*jXZGu7K6 z$RiTdkcfHc9*P4LiGt>^dem-eY>HzBgr^=38HJy8nP1Ts(^cMngzum9P3I6@DCmi$ zih_mS4#CWmAIhVO#J$!4LC5Y;K-nbQtqW5 zJpG%rbB2^{^$O9IMN>kB4RNQ};;`tXjd%5MsQ+rmSr*$pzKmS$XmQD=jpvdFdHy<;s9%#-KYSh*R z*#sS7mNrrlO1B5jCxxi2l4MOU+4UNIXECxt22cvfsmb7!`5e=P;NxrBF68Y{S3bB7 zI<}_We70#ac4jKFf%^W)%zX!!-^pw^@Qw{Rf{5Y%z@Zg&_Kve|qV{gcrr{ayXP{H# z@TBZQb{N@FY;e6B*-~WV4RHpJF~~N4wPIS@&C311k}4#?dd*Jmu+=gNwF5r%sR7|8 z6@Dgo&@+(D#Wn*!GwH>I@iPXU*pD4QEcST1(~s;b!L_TxIt1@4JrO*kxN|$k6*j6u zYTC}$HM~fCOH=J8o`#?2DY%Amr>N<+hMK1!+Ma+wawK>5#8=}@YTe8M(NEPEQ?#)HcCP<6OMUXmiCK_ET? ze&i!UE(&$hMwz@R3-}s@p1ZHzl;THG&ngkN1Y8JOLvgdRs3)>X!r(JxJ6AcF-^pm$ z_l~g4_f$6IjKjo|$ISBkciTa~gWsLe<8 zUww(?I=qm{EpjaoX($?@U&@=?`gl_AH^bUUjub+sjTuzhU-@qAxe+V-O zbewncQGDmRO;)qIS)KmMgst|lG9~RnqLt8428GsYknp0Z194Jzcx5@J{gBhc@*f`V zsCX96Pc-QdCXD7xsNEcTP%~IbiCjbYKxb7Q@xP?r_Fcy8*hX$XtELn^3VkiCtTYu6 zgHMGhR|w%FgFAWU+n1={Z5SO4xmo6W8KMQoK{k3)dFk=8^kUW@b9TO@@f95^AYp-1 zK*#@7c0@syN|UU*;IfL2Fn-ykoJq~u_Ld%e9u;!*3c~%3%Dr7?lSV=%oe9n)-P*qo z!XCnk2#`dWWQ}#`V^qQ70b5DYU~&yHT-g!B6*Z~8_YHNPbiMG9vJ&kRByZ?J@;nCh zH_d#^Z7GgJ+R#K2QLY>5B!s zer6L`G%KyXNW6&RiXKKiuYRuN^NbcG={;uio`v6|e&w_i;;N?!HP4V`qP!_=4(ljI z6A01K9eAZDn{}u^E_=(zO&A^#ll;wdQi0TYK+|*70Ugs~@G9di?DYCS0{{i|!Ioqi zVZ-^v6(>>N+%7+O8H5>ulX*!BlkB||MTc@c9N7Y72fp)MR8C4H9UfAh(gFyaFBk54 zg8?icWh?r-?B)skjoG9T>byCJ^MJ`WXR+XW5 zcUBw7YV>?J`*SlD2AYF4^j=gr}GXFhL0Iur9Ug?gi=x0RlXLU&+w?HJQx z$1WAP{>&~jDVt=q2v&1;oez1l0_P>qwMfXZuxGd2x&Whhb>2WVE#|A5k4QL?QiJH+ z)JaS5%H)AP8Vad{YSmC(T-?w7|H(uCpeE7U6ZuOIV z&639`MTCTsDA85sGQ#>bgpb<}&qbv|2+Fl`iOCydRwARr?NY(+H)fMZ_~Ow10P+UP zKY4{iP`PICG+a_p0;T-DIn?c$buZV&o5L&tbDXTaQXdlX2YW~ zWghlEMafmMBo95aW%H)+sa!Nznv0Rp%9AK6#3@4@B6&3eLwZ2pTXD|J#{-l?;+AA~ zRp%WcZ@wjYbGzJMz2DGIsI_lO&?ozyl%9vdsbz2U0AsuwV{qXZ+yno&Bspd_d89gT z5^uWiD@QA%dG)E0ompA9ySIKcis`LG`W*AJAIknA&YMjON?Jm@2nJ*aPg8YqLGaOX zjO1BgI%Mvrv^_`X4ZL2Vi5>|jI!A;JRIc^%K$}PP{R)l7IR|-Tj9z6fj!AaNIHMk0G!9dvgrPxgWv*OC`G|M)c2=9CW7tr6RhR&1+g)+34_KCw}(`Y6=I zjuu%oYL7ze|3Xmd`qCjw(cmaPL+b=A?Pnz9biS3ZUs!LO`kfH$K-|7YDiH7 z^0ydPRied~-tZwq4~x)~>q`U(V}op^7Sy5Pj+}2Jw1YD|^N9qAWT%EnJQSkf5%jO` z{}_66m|_8O*KcTR^!>M1Z;nCuziy_#p?yf+jQksm&OcdFrRd230000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/base/resources/values/colors.xml b/mobile/android/base/resources/values/colors.xml index a66706089e22..5c2538dac4eb 100644 --- a/mobile/android/base/resources/values/colors.xml +++ b/mobile/android/base/resources/values/colors.xml @@ -6,5 +6,7 @@ #ffffff #ACC4D5 #ffffff + #77BAFF + #B7D46A diff --git a/mobile/android/base/strings.xml.in b/mobile/android/base/strings.xml.in index 1c6ae935bab8..6f708b0579fa 100644 --- a/mobile/android/base/strings.xml.in +++ b/mobile/android/base/strings.xml.in @@ -148,4 +148,8 @@ @bookmarks_aboutHome@ about:home + + + &identity_connected_to; + &identity_run_by; diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index e12dad1c3f55..79f191b0cb92 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2213,6 +2213,8 @@ Tab.prototype = { if (contentWin != contentWin.top) return; + this._hostChanged = true; + let browser = BrowserApp.getBrowserForWindow(contentWin); let uri = browser.currentURI.spec; let documentURI = ""; @@ -2249,26 +2251,29 @@ Tab.prototype = { } }, + // Properties used to cache security state used to update the UI + _state: null, + _hostChanged: false, // onLocationChange will flip this bit + onSecurityChange: function(aWebProgress, aRequest, aState) { - let mode = "unknown"; - if (aState & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) - mode = "identified"; - else if (aState & Ci.nsIWebProgressListener.STATE_SECURE_HIGH) - mode = "verified"; - else if (aState & Ci.nsIWebProgressListener.STATE_IS_BROKEN) - mode = "mixed"; - else - mode = "unknown"; + // Don't need to do anything if the data we use to update the UI hasn't changed + if (this._state == aState && !this._hostChanged) + return; + + this._state = aState; + this._hostChanged = false; + + let identity = IdentityHandler.checkIdentity(aState, this.browser); let message = { gecko: { type: "Content:SecurityChange", tabID: this.id, - mode: mode + identity: identity } }; - sendMessageToJava(message); + sendMessageToJava(message); }, onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) { @@ -4605,6 +4610,159 @@ var CharacterEncoding = { } }; +var IdentityHandler = { + // Mode strings used to control CSS display + IDENTITY_MODE_IDENTIFIED : "identified", // High-quality identity information + IDENTITY_MODE_DOMAIN_VERIFIED : "verified", // Minimal SSL CA-signed domain verification + IDENTITY_MODE_UNKNOWN : "unknown", // No trusted identity information + + // Cache the most recent SSLStatus and Location seen in getIdentityStrings + _lastStatus : null, + _lastLocation : null, + + /** + * Helper to parse out the important parts of _lastStatus (of the SSL cert in + * particular) for use in constructing identity UI strings + */ + getIdentityData : function() { + let result = {}; + let status = this._lastStatus.QueryInterface(Components.interfaces.nsISSLStatus); + let cert = status.serverCert; + + // Human readable name of Subject + result.subjectOrg = cert.organization; + + // SubjectName fields, broken up for individual access + if (cert.subjectName) { + result.subjectNameFields = {}; + cert.subjectName.split(",").forEach(function(v) { + let field = v.split("="); + this[field[0]] = field[1]; + }, result.subjectNameFields); + + // Call out city, state, and country specifically + result.city = result.subjectNameFields.L; + result.state = result.subjectNameFields.ST; + result.country = result.subjectNameFields.C; + } + + // Human readable name of Certificate Authority + result.caOrg = cert.issuerOrganization || cert.issuerCommonName; + result.cert = cert; + + return result; + }, + + getIdentityMode: function getIdentityMode(aState) { + if (aState & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) + return this.IDENTITY_MODE_IDENTIFIED; + + if (aState & Ci.nsIWebProgressListener.STATE_SECURE_HIGH) + return this.IDENTITY_MODE_DOMAIN_VERIFIED; + + return this.IDENTITY_MODE_UNKNOWN; + }, + + /** + * Determine the identity of the page being displayed by examining its SSL cert + * (if available). Return the data needed to update the UI. + */ + checkIdentity: function checkIdentity(aState, aBrowser) { + this._lastStatus = aBrowser.securityUI + .QueryInterface(Components.interfaces.nsISSLStatusProvider) + .SSLStatus; + + // Don't pass in the actual location object, since it can cause us to + // hold on to the window object too long. Just pass in the fields we + // care about. (bug 424829) + let locationObj = {}; + try { + let location = aBrowser.contentWindow.location; + locationObj.host = location.host; + locationObj.hostname = location.hostname; + locationObj.port = location.port; + } catch (ex) { + // Can sometimes throw if the URL being visited has no host/hostname, + // e.g. about:blank. The _state for these pages means we won't need these + // properties anyways, though. + } + this._lastLocation = locationObj; + + let mode = this.getIdentityMode(aState); + let result = { mode: mode }; + + // We can't to do anything else for pages without identity data + if (mode == this.IDENTITY_MODE_UNKNOWN) + return result; + + // Ideally we'd just make this a Java string + result.encrypted = Strings.browser.GetStringFromName("identity.encrypted2"); + result.host = this.getEffectiveHost(); + + let iData = this.getIdentityData(); + result.verifier = Strings.browser.formatStringFromName("identity.identified.verifier", [iData.caOrg], 1); + + // If the cert is identified, then we can populate the results with credentials + if (mode == this.IDENTITY_MODE_IDENTIFIED) { + result.owner = iData.subjectOrg; + + // Build an appropriate supplemental block out of whatever location data we have + let supplemental = ""; + if (iData.city) + supplemental += iData.city + "\n"; + if (iData.state && iData.country) + supplemental += Strings.browser.formatStringFromName("identity.identified.state_and_country", [iData.state, iData.country], 2); + else if (iData.state) // State only + supplemental += iData.state; + else if (iData.country) // Country only + supplemental += iData.country; + result.supplemental = supplemental; + + return result; + } + + // Otherwise, we don't know the cert owner + result.owner = Strings.browser.GetStringFromName("identity.ownerUnknown2"); + + // Cache the override service the first time we need to check it + if (!this._overrideService) + this._overrideService = Cc["@mozilla.org/security/certoverride;1"].getService(Ci.nsICertOverrideService); + + // Check whether this site is a security exception. XPConnect does the right + // thing here in terms of converting _lastLocation.port from string to int, but + // the overrideService doesn't like undefined ports, so make sure we have + // something in the default case (bug 432241). + // .hostname can return an empty string in some exceptional cases - + // hasMatchingOverride does not handle that, so avoid calling it. + // Updating the tooltip value in those cases isn't critical. + // FIXME: Fixing bug 646690 would probably makes this check unnecessary + if (this._lastLocation.hostname && + this._overrideService.hasMatchingOverride(this._lastLocation.hostname, + (this._lastLocation.port || 443), + iData.cert, {}, {})) + result.verifier = Strings.browser.GetStringFromName("identity.identified.verified_by_you"); + + return result; + }, + + /** + * Return the eTLD+1 version of the current hostname + */ + getEffectiveHost: function getEffectiveHost() { + if (!this._IDNService) + this._IDNService = Cc["@mozilla.org/network/idn-service;1"] + .getService(Ci.nsIIDNService); + try { + let baseDomain = Services.eTLD.getBaseDomainFromHost(this._lastLocation.hostname); + return this._IDNService.convertToDisplayIDN(baseDomain, {}); + } catch (e) { + // If something goes wrong (e.g. hostname is an IP address) just fail back + // to the full domain. + return this._lastLocation.hostname; + } + } +}; + function OverscrollController(aTab) { this.tab = aTab; } diff --git a/mobile/android/locales/en-US/chrome/browser.properties b/mobile/android/locales/en-US/chrome/browser.properties index 150cde853dd4..5d9cee0d34cf 100644 --- a/mobile/android/locales/en-US/chrome/browser.properties +++ b/mobile/android/locales/en-US/chrome/browser.properties @@ -75,8 +75,6 @@ identity.identified.verified_by_you=You have added a security exception for this identity.identified.state_and_country=%S, %S identity.identified.title_with_country=%S (%S) identity.encrypted2=Encrypted -identity.unencrypted2=Not encrypted -identity.unknown.tooltip=This website does not supply identity information. identity.ownerUnknown2=(unknown) # Geolocation UI From d2f36d38b35c0353aacfdd711e875d3e7657b3c3 Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Wed, 2 May 2012 09:07:58 -0700 Subject: [PATCH 088/159] Bug 736272 - Add extra awesomeness weight to bookmarks. r=lucasr a=android-only --- mobile/android/base/db/LocalBrowserDB.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mobile/android/base/db/LocalBrowserDB.java b/mobile/android/base/db/LocalBrowserDB.java index 1ecb26b1862d..2667645929e2 100644 --- a/mobile/android/base/db/LocalBrowserDB.java +++ b/mobile/android/base/db/LocalBrowserDB.java @@ -167,8 +167,10 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface { // approximation using the Cauchy distribution: multiplier = 15^2 / (age^2 + 15^2). // Using 15 as our scale parameter, we get a constant 15^2 = 225. Following this math, // frecencyScore = numVisits * max(1, 100 * 225 / (age*age + 225)). (See bug 704977) + // We also give bookmarks an extra bonus boost by adding 100 points to their frecency score. final String age = "(" + Combined.DATE_LAST_VISITED + " - " + System.currentTimeMillis() + ") / 86400000"; - final String sortOrder = Combined.VISITS + " * MAX(1, 100 * 225 / (" + age + "*" + age + " + 225)) DESC"; + final String sortOrder = "(CASE WHEN " + Combined.BOOKMARK_ID + " > -1 THEN 100 ELSE 0 END) + " + + Combined.VISITS + " * MAX(1, 100 * 225 / (" + age + "*" + age + " + 225)) DESC"; Cursor c = cr.query(combinedUriWithLimit(limit), projection, From a0e9f3a75eb3535778c2d6cd284f992b84b0fa8f Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Wed, 2 May 2012 09:07:58 -0700 Subject: [PATCH 089/159] Bug 749853 - about:* pages (and other unwanted URIs) should not be stored in history. r=mfinkle a=android-only --- mobile/android/base/GlobalHistory.java | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/mobile/android/base/GlobalHistory.java b/mobile/android/base/GlobalHistory.java index 2e3b362913a3..c22d25915812 100644 --- a/mobile/android/base/GlobalHistory.java +++ b/mobile/android/base/GlobalHistory.java @@ -45,6 +45,7 @@ import java.lang.ref.SoftReference; import android.content.ContentResolver; import android.database.Cursor; +import android.net.Uri; import android.os.Handler; import android.util.Log; @@ -115,12 +116,49 @@ class GlobalHistory { GeckoAppShell.notifyUriVisited(uri); } + // Logic ported from nsNavHistory::CanAddURI. + // http://mxr.mozilla.org/mozilla-central/source/toolkit/components/places/nsNavHistory.cpp#1272 + private boolean canAddURI(String uri) { + if (uri == null || uri.length() == 0) + return false; + + // First, heck the most common cases (HTTP, HTTPS) to avoid most of the work. + if (uri.startsWith("http:") || uri.startsWith("https:")) + return true; + + String scheme = Uri.parse(uri).getScheme(); + if (scheme == null) + return false; + + // Now check for all bad things. + if (scheme.equals("about") || + scheme.equals("imap") || + scheme.equals("news") || + scheme.equals("mailbox") || + scheme.equals("moz-anno") || + scheme.equals("view-source") || + scheme.equals("chrome") || + scheme.equals("resource") || + scheme.equals("data") || + scheme.equals("wyciwyg") || + scheme.equals("javascript")) + return false; + + return true; + } + public void add(String uri) { + if (!canAddURI(uri)) + return; + BrowserDB.updateVisitedHistory(GeckoApp.mAppContext.getContentResolver(), uri); addToGeckoOnly(uri); } public void update(String uri, String title) { + if (!canAddURI(uri)) + return; + ContentResolver resolver = GeckoApp.mAppContext.getContentResolver(); BrowserDB.updateHistoryTitle(resolver, uri, title); } From f9c57d8f36391c8b93fea12876708a10464930ba Mon Sep 17 00:00:00 2001 From: Malini Das Date: Wed, 2 May 2012 10:21:05 -0400 Subject: [PATCH 090/159] Bug 746031 - Support nested iframes correctly in Marionette, r=jgriffin, a=npotb, --- .../tests/unit/test_switch_frame.py | 52 ++++++++ .../marionette/client/marionette/www/test.xul | 2 + .../client/marionette/www/test2.xul | 15 +++ .../marionette/www/test_inner_iframe.html | 9 ++ .../marionette/www/test_nested_iframe.html | 9 ++ .../marionette/www/test_nested_iframe.xul | 6 + testing/marionette/marionette-actors.js | 108 ++++++++++++----- testing/marionette/marionette-listener.js | 112 ++++++++---------- 8 files changed, 221 insertions(+), 92 deletions(-) create mode 100644 testing/marionette/client/marionette/www/test2.xul create mode 100644 testing/marionette/client/marionette/www/test_inner_iframe.html create mode 100644 testing/marionette/client/marionette/www/test_nested_iframe.html create mode 100644 testing/marionette/client/marionette/www/test_nested_iframe.xul diff --git a/testing/marionette/client/marionette/tests/unit/test_switch_frame.py b/testing/marionette/client/marionette/tests/unit/test_switch_frame.py index c2e6133f9ac8..644b7ce12181 100644 --- a/testing/marionette/client/marionette/tests/unit/test_switch_frame.py +++ b/testing/marionette/client/marionette/tests/unit/test_switch_frame.py @@ -46,3 +46,55 @@ class TestSwitchFrame(MarionetteTestCase): self.assertEqual("Marionette IFrame Test", self.marionette.execute_script("return window.document.title;")) self.marionette.switch_to_frame("test_iframe") self.assertTrue("test.html" in self.marionette.get_url()) + + def test_switch_nested(self): + self.assertTrue(self.marionette.execute_script("window.location.href = 'about:blank'; return true;")) + self.assertEqual("about:blank", self.marionette.execute_script("return window.location.href;")) + test_html = self.marionette.absolute_url("test_nested_iframe.html") + self.marionette.navigate(test_html) + self.assertNotEqual("about:blank", self.marionette.execute_script("return window.location.href;")) + self.assertEqual("Marionette IFrame Test", self.marionette.execute_script("return window.document.title;")) + self.marionette.switch_to_frame("test_iframe") + self.assertTrue("test_inner_iframe.html" in self.marionette.get_url()) + self.marionette.switch_to_frame("inner_frame") + self.assertTrue("test.html" in self.marionette.get_url()) + self.marionette.switch_to_frame() # go back to main frame + self.assertTrue("test_nested_iframe.html" in self.marionette.get_url()) + #test that we're using the right window object server-side + self.assertTrue("test_nested_iframe.html" in self.marionette.execute_script("return window.location.href;")) + +class TestSwitchFrameChrome(MarionetteTestCase): + def setUp(self): + MarionetteTestCase.setUp(self) + self.marionette.set_context("chrome") + self.win = self.marionette.get_window() + #need to get the file:// path for xul + unit = os.path.abspath(os.path.join(os.path.realpath(__file__), os.path.pardir)) + tests = os.path.abspath(os.path.join(unit, os.path.pardir)) + mpath = os.path.abspath(os.path.join(tests, os.path.pardir)) + xul = "file://" + os.path.join(mpath, "www", "test.xul") + self.marionette.execute_script("window.open('" + xul +"', '_blank', 'chrome,centerscreen');") + + def tearDown(self): + self.marionette.execute_script("window.close();") + self.marionette.switch_to_window(self.win) + MarionetteTestCase.tearDown(self) + + def test_switch_simple(self): + self.assertTrue("test.xul" in self.marionette.get_url()) + self.marionette.switch_to_frame(0) + self.assertTrue("test2.xul" in self.marionette.get_url()) + self.marionette.switch_to_frame() + self.assertTrue("test.xul" in self.marionette.get_url()) + self.marionette.switch_to_frame("iframe") + self.assertTrue("test2.xul" in self.marionette.get_url()) + self.marionette.switch_to_frame() + self.assertTrue("test.xul" in self.marionette.get_url()) + self.marionette.switch_to_frame("iframename") + self.assertTrue("test2.xul" in self.marionette.get_url()) + self.marionette.switch_to_frame() + self.assertTrue("test.xul" in self.marionette.get_url()) + + #I can't seem to access a xul iframe within a xul iframe + def test_switch_nested(self): + pass diff --git a/testing/marionette/client/marionette/www/test.xul b/testing/marionette/client/marionette/www/test.xul index 5b8aef24382e..bdc991cc7d6d 100644 --- a/testing/marionette/client/marionette/www/test.xul +++ b/testing/marionette/client/marionette/www/test.xul @@ -12,4 +12,6 @@ + + + diff --git a/testing/marionette/client/marionette/www/test_nested_iframe.html b/testing/marionette/client/marionette/www/test_nested_iframe.html new file mode 100644 index 000000000000..81eb596d26ea --- /dev/null +++ b/testing/marionette/client/marionette/www/test_nested_iframe.html @@ -0,0 +1,9 @@ + + + +Marionette IFrame Test + + + + + diff --git a/testing/marionette/client/marionette/www/test_nested_iframe.xul b/testing/marionette/client/marionette/www/test_nested_iframe.xul new file mode 100644 index 000000000000..ee5d0c87afae --- /dev/null +++ b/testing/marionette/client/marionette/www/test_nested_iframe.xul @@ -0,0 +1,6 @@ + + + + + + diff --git a/layout/reftests/bugs/748803-1.html b/layout/reftests/bugs/748803-1.html new file mode 100644 index 000000000000..c20235dfc5cf --- /dev/null +++ b/layout/reftests/bugs/748803-1.html @@ -0,0 +1,8 @@ + + + + +

    + + + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 5fef0f15d8c0..9838b72f12d2 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1700,3 +1700,4 @@ fuzzy-if(d2d,1,19) fuzzy-if(cocoaWidget,1,170) == 718521.html 718521-ref.html needs-focus == 731726-1.html 731726-1-ref.html == 735481-1.html 735481-1-ref.html == 745934-1.html 745934-1-ref.html +== 748803-1.html 748803-1-ref.html From 4dfa35563b8ec9ce4655f15b666c28bfe4f6e979 Mon Sep 17 00:00:00 2001 From: Christian Holler Date: Mon, 30 Apr 2012 22:01:29 -0400 Subject: [PATCH 111/159] Bug 749588 - Remove set_limits in jit_test.py, r=dmandelin --HG-- extra : rebase_source : 98b9b32f10030f3605d88b904d749ac30b98c824 --- js/src/jit-test/jit_test.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/js/src/jit-test/jit_test.py b/js/src/jit-test/jit_test.py index 1501bed53118..b0b5a5ed6e72 100755 --- a/js/src/jit-test/jit_test.py +++ b/js/src/jit-test/jit_test.py @@ -142,15 +142,6 @@ def get_test_cmd(path, jitflags, lib_dir, shell_args): return ([ JS ] + list(set(jitflags)) + shell_args + [ '-e', expr, '-f', os.path.join(lib_dir, 'prolog.js'), '-f', path ]) -def set_limits(): - # resource module not supported on all platforms - try: - import resource - GB = 2**30 - resource.setrlimit(resource.RLIMIT_AS, (1*GB, 1*GB)) - except: - return - def tmppath(token): fd, path = tempfile.mkstemp(prefix=token) os.close(fd) @@ -164,11 +155,9 @@ def read_and_unlink(path): return d def th_run_cmd(cmdline, options, l): - # close_fds and preexec_fn are not supported on Windows and will - # cause a ValueError. + # close_fds is not supported on Windows and will cause a ValueError. if sys.platform != 'win32': options["close_fds"] = True - options["preexec_fn"] = set_limits p = Popen(cmdline, stdin=PIPE, stdout=PIPE, stderr=PIPE, **options) l[0] = p From 2b71769566cd626923046a7aba3ba3bcec9ee29a Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Mon, 30 Apr 2012 19:05:59 -0700 Subject: [PATCH 112/159] Bug 708136 - Don't teardown GL objects if teardown's makecurrent fails - r=bjacob --- gfx/gl/GLContext.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 79b6d756964c..a39b5ccd53a2 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -1748,13 +1748,16 @@ GLContext::MarkDestroyed() if (IsDestroyed()) return; - MakeCurrent(); - DeleteOffscreenFBOs(); + if (MakeCurrent()) { + DeleteOffscreenFBOs(); - fDeleteProgram(mBlitProgram); - mBlitProgram = 0; - fDeleteFramebuffers(1, &mBlitFramebuffer); - mBlitFramebuffer = 0; + fDeleteProgram(mBlitProgram); + mBlitProgram = 0; + fDeleteFramebuffers(1, &mBlitFramebuffer); + mBlitFramebuffer = 0; + } else { + NS_WARNING("MakeCurrent() failed during MarkDestroyed! Skipping GL object teardown."); + } mSymbols.Zero(); } From ce67c5e409e45e3d7e5688f2da0f3db6402ca0db Mon Sep 17 00:00:00 2001 From: Edward Lee Date: Mon, 30 Apr 2012 19:24:24 -0700 Subject: [PATCH 113/159] Bug 749047 - Cannot save downloaded files from within the desktop web runtime [r=myk] Default downloads to the Downloads directory set by the platform just like Firefox. --- webapprt/prefs.js | 1 + 1 file changed, 1 insertion(+) diff --git a/webapprt/prefs.js b/webapprt/prefs.js index 94c364297494..bcd34ebf95b3 100644 --- a/webapprt/prefs.js +++ b/webapprt/prefs.js @@ -3,4 +3,5 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ pref("browser.chromeURL", "chrome://webapprt/content/webapp.xul"); +pref("browser.download.folderList", 1); pref("general.useragent.compatMode.firefox", true); From 50f82f949447890f9ca437f871a0d83aeb46838d Mon Sep 17 00:00:00 2001 From: aceman Date: Mon, 30 Apr 2012 22:45:02 -0400 Subject: [PATCH 114/159] Bug 750501 - Fix build failure in nsDOMClassInfo.cpp due to missing nsIDOMMediaStream.h when MOZ_MEDIA is disabled. r=bz --- dom/base/nsDOMClassInfo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index a7ddf188f88c..60c418950a96 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -309,7 +309,9 @@ #include "nsIDOMHTMLSourceElement.h" #include "nsIDOMHTMLVideoElement.h" #include "nsIDOMHTMLAudioElement.h" +#if defined (MOZ_MEDIA) #include "nsIDOMMediaStream.h" +#endif #include "nsIDOMProgressEvent.h" #include "nsIDOMCSS2Properties.h" #include "nsIDOMCSSCharsetRule.h" From aac13b73c56ad80113b616feee6ee63cb126e4db Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Tue, 1 May 2012 12:04:30 +0900 Subject: [PATCH 115/159] Bug 625664 - accelerometer support using Windows 7 Sensor API. r=dougt --- hal/Makefile.in | 2 +- hal/windows/WindowsSensor.cpp | 182 ++++++++++++++++++++++++++++++++++ toolkit/library/Makefile.in | 2 +- 3 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 hal/windows/WindowsSensor.cpp diff --git a/hal/Makefile.in b/hal/Makefile.in index 73a16dda1971..eb3d6cb55520 100644 --- a/hal/Makefile.in +++ b/hal/Makefile.in @@ -100,7 +100,7 @@ else ifeq (WINNT,$(OS_TARGET)) CPPSRCS += \ WindowsHal.cpp \ WindowsBattery.cpp \ - FallbackSensor.cpp \ + WindowsSensor.cpp \ $(NULL) else ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) CPPSRCS += \ diff --git a/hal/windows/WindowsSensor.cpp b/hal/windows/WindowsSensor.cpp new file mode 100644 index 000000000000..e700e6cffb95 --- /dev/null +++ b/hal/windows/WindowsSensor.cpp @@ -0,0 +1,182 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Hal.h" + +#include +#include +#include + +#define MEAN_GRAVITY 9.80665 +#define DEFAULT_SENSOR_POLL 100 + +using namespace mozilla::hal; + +namespace mozilla { +namespace hal_impl { + +static nsRefPtr sAccelerometer; + +class SensorEvent : public ISensorEvents { +public: + SensorEvent() : mCount(0) { + } + + // IUnknown interface + + STDMETHODIMP_(ULONG) AddRef() { + return InterlockedIncrement(&mCount); + } + + STDMETHODIMP_(ULONG) Release() { + ULONG count = InterlockedDecrement(&mCount); + if (!count) { + delete this; + return 0; + } + return count; + } + + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) { + if (iid == IID_IUnknown) { + *ppv = static_cast(this); + } else if (iid == IID_ISensorEvents) { + *ppv = static_cast(this); + } else { + return E_NOINTERFACE; + } + AddRef(); + return S_OK; + } + + // ISensorEvents interface + + STDMETHODIMP OnEvent(ISensor *aSensor, REFGUID aId, IPortableDeviceValues *aData) { + return S_OK; + } + + STDMETHODIMP OnLeave(REFSENSOR_ID aId) { + return S_OK; + } + + STDMETHODIMP OnStateChanged(ISensor *aSensor, SensorState state) { + return S_OK; + } + + STDMETHODIMP OnDataUpdated(ISensor *aSensor, ISensorDataReport *aReport) { + PROPVARIANT v; + HRESULT hr; + InfallibleTArray values; + + // X-axis acceleration in g's + hr = aReport->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_X_G, &v); + if (FAILED(hr)) { + return hr; + } + values.AppendElement(float(-v.dblVal * MEAN_GRAVITY)); + + // Y-axis acceleration in g's + hr = aReport->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Y_G, &v); + if (FAILED(hr)) { + return hr; + } + values.AppendElement(float(-v.dblVal * MEAN_GRAVITY)); + + // Z-axis acceleration in g's + hr = aReport->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Z_G, &v); + if (FAILED(hr)) { + return hr; + } + values.AppendElement(float(-v.dblVal * MEAN_GRAVITY)); + + hal::SensorData sdata(hal::SENSOR_ACCELERATION, + PR_Now(), + values, + hal::SENSOR_ACCURACY_UNKNOWN); + hal::NotifySensorChange(sdata); + + return S_OK; + } + +private: + ULONG mCount; +}; + +void +EnableSensorNotifications(SensorType aSensor) +{ + if (aSensor != SENSOR_ACCELERATION) { + return; + } + + if (sAccelerometer) { + return; + } + + nsRefPtr manager; + if (FAILED(CoCreateInstance(CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, + IID_ISensorManager, getter_AddRefs(manager)))) { + return; + } + + // accelerometer event + + nsRefPtr collection; + if (FAILED(manager->GetSensorsByType(SENSOR_TYPE_ACCELEROMETER_3D, + getter_AddRefs(collection)))) { + return; + } + + ULONG count = 0; + collection->GetCount(&count); + if (!count) { + return; + } + + nsRefPtr sensor; + collection->GetAt(0, getter_AddRefs(sensor)); + if (!sensor) { + return; + } + + // Set report interval to 100ms if possible. + // Default value depends on drivers. + nsRefPtr values; + if (SUCCEEDED(CoCreateInstance(CLSID_PortableDeviceValues, NULL, + CLSCTX_INPROC_SERVER, + IID_IPortableDeviceValues, + getter_AddRefs(values)))) { + if (SUCCEEDED(values->SetUnsignedIntegerValue( + SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, + DEFAULT_SENSOR_POLL))) { + nsRefPtr returns; + sensor->SetProperties(values, getter_AddRefs(returns)); + } + } + + nsRefPtr event = new SensorEvent(); + nsRefPtr sensorEvents; + if (FAILED(event->QueryInterface(IID_ISensorEvents, + getter_AddRefs(sensorEvents)))) { + return; + } + + if (FAILED(sensor->SetEventSink(sensorEvents))) { + return; + } + + sAccelerometer = sensor; +} + +void +DisableSensorNotifications(SensorType aSensor) +{ + if (aSensor == SENSOR_ACCELERATION && sAccelerometer) { + sAccelerometer->SetEventSink(NULL); + sAccelerometer = nsnull; + } +} + +} // hal_impl +} // mozilla diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index b1e62b625275..89b0b7dbd2d5 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -522,7 +522,7 @@ endif endif ifeq ($(OS_ARCH),WINNT) -OS_LIBS += $(call EXPAND_LIBNAME,shell32 ole32 version winspool comdlg32 imm32 msimg32 shlwapi psapi ws2_32 dbghelp rasapi32 rasdlg iphlpapi uxtheme setupapi secur32) +OS_LIBS += $(call EXPAND_LIBNAME,shell32 ole32 version winspool comdlg32 imm32 msimg32 shlwapi psapi ws2_32 dbghelp rasapi32 rasdlg iphlpapi uxtheme setupapi secur32 sensorsapi portabledeviceguids) ifdef MOZ_CRASHREPORTER OS_LIBS += $(call EXPAND_LIBNAME,wininet) endif From 67f459e31b0995633be7b86624af1dc1e4100728 Mon Sep 17 00:00:00 2001 From: Mark Capella Date: Tue, 1 May 2012 12:08:31 +0900 Subject: [PATCH 116/159] Bug 740747 - dexpcom nsAccessible::GetName, r=surkov, tbsaunde --- .../src/atk/ApplicationAccessibleWrap.cpp | 7 ++- .../src/atk/ApplicationAccessibleWrap.h | 3 +- accessible/src/atk/nsAccessibleWrap.cpp | 32 +++++------ accessible/src/base/FocusManager.h | 2 +- accessible/src/base/nsAccessible.cpp | 56 ++++++++++--------- accessible/src/base/nsAccessible.h | 21 +++++++ accessible/src/base/nsDocAccessible.cpp | 18 +++--- accessible/src/base/nsDocAccessible.h | 2 +- accessible/src/base/nsRootAccessible.cpp | 21 +++---- accessible/src/base/nsRootAccessible.h | 4 +- accessible/src/base/nsTextEquivUtils.cpp | 11 ++-- .../src/generic/ApplicationAccessible.cpp | 12 ++-- .../src/generic/ApplicationAccessible.h | 2 +- .../src/html/nsHTMLSelectAccessible.cpp | 2 +- accessible/src/html/nsHTMLTextAccessible.cpp | 15 ++--- accessible/src/html/nsHTMLTextAccessible.h | 8 +-- accessible/src/mac/mozAccessible.mm | 2 +- accessible/src/msaa/nsAccessibleWrap.cpp | 4 +- .../src/msaa/nsXULMenuAccessibleWrap.cpp | 18 +++--- accessible/src/msaa/nsXULMenuAccessibleWrap.h | 2 +- accessible/src/xul/nsXULAlertAccessible.cpp | 6 +- accessible/src/xul/nsXULAlertAccessible.h | 4 +- accessible/src/xul/nsXULTreeAccessible.cpp | 13 ++--- accessible/src/xul/nsXULTreeAccessible.h | 3 +- .../src/xul/nsXULTreeGridAccessible.cpp | 19 +++---- accessible/src/xul/nsXULTreeGridAccessible.h | 4 +- 26 files changed, 145 insertions(+), 146 deletions(-) diff --git a/accessible/src/atk/ApplicationAccessibleWrap.cpp b/accessible/src/atk/ApplicationAccessibleWrap.cpp index ed9e2718ae85..9b970972c32e 100644 --- a/accessible/src/atk/ApplicationAccessibleWrap.cpp +++ b/accessible/src/atk/ApplicationAccessibleWrap.cpp @@ -690,14 +690,15 @@ ApplicationAccessibleWrap::Unload() // } } -NS_IMETHODIMP -ApplicationAccessibleWrap::GetName(nsAString& aName) +ENameValueFlag +ApplicationAccessibleWrap::Name(nsString& aName) { // ATK doesn't provide a way to obtain an application name (for example, // Firefox or Thunderbird) like IA2 does. Thus let's return an application // name as accessible name that was used to get a branding name (for example, // Minefield aka nightly Firefox or Daily aka nightly Thunderbird). - return GetAppName(aName); + GetAppName(aName); + return eNameOK; } NS_IMETHODIMP diff --git a/accessible/src/atk/ApplicationAccessibleWrap.h b/accessible/src/atk/ApplicationAccessibleWrap.h index 920b3e89535f..527659b952db 100644 --- a/accessible/src/atk/ApplicationAccessibleWrap.h +++ b/accessible/src/atk/ApplicationAccessibleWrap.h @@ -57,8 +57,7 @@ public: virtual bool Init(); // nsAccessible - NS_IMETHOD GetName(nsAString &aName); - + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual bool AppendChild(nsAccessible* aChild); virtual bool RemoveChild(nsAccessible* aChild); diff --git a/accessible/src/atk/nsAccessibleWrap.cpp b/accessible/src/atk/nsAccessibleWrap.cpp index b968b4b25434..5b388224baab 100644 --- a/accessible/src/atk/nsAccessibleWrap.cpp +++ b/accessible/src/atk/nsAccessibleWrap.cpp @@ -678,25 +678,21 @@ finalizeCB(GObject *aObj) G_OBJECT_CLASS (parent_class)->finalize(aObj); } -const gchar * -getNameCB(AtkObject *aAtkObj) +const gchar* +getNameCB(AtkObject* aAtkObj) { - nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj); - if (!accWrap) { - return nsnull; - } + nsAccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + if (!accWrap) + return nsnull; - /* nsIAccessible is responsible for the non-NULL name */ - nsAutoString uniName; - nsresult rv = accWrap->GetName(uniName); - NS_ENSURE_SUCCESS(rv, nsnull); + nsAutoString uniName; + accWrap->Name(uniName); - NS_ConvertUTF8toUTF16 objName(aAtkObj->name); - if (!uniName.Equals(objName)) { - atk_object_set_name(aAtkObj, - NS_ConvertUTF16toUTF8(uniName).get()); - } - return aAtkObj->name; + NS_ConvertUTF8toUTF16 objName(aAtkObj->name); + if (!uniName.Equals(objName)) + atk_object_set_name(aAtkObj, NS_ConvertUTF16toUTF8(uniName).get()); + + return aAtkObj->name; } const gchar * @@ -1043,8 +1039,8 @@ nsAccessibleWrap::FirePlatformEvent(AccEvent* aEvent) case nsIAccessibleEvent::EVENT_NAME_CHANGE: { - nsString newName; - accessible->GetName(newName); + nsAutoString newName; + accessible->Name(newName); NS_ConvertUTF16toUTF8 utf8Name(newName); if (!atkObj->name || !utf8Name.Equals(atkObj->name)) atk_object_set_name(atkObj, utf8Name.get()); diff --git a/accessible/src/base/FocusManager.h b/accessible/src/base/FocusManager.h index 10caf0c9ac69..97b6628e2b51 100644 --- a/accessible/src/base/FocusManager.h +++ b/accessible/src/base/FocusManager.h @@ -211,7 +211,7 @@ private: nsAutoString role; \ GetAccService()->GetStringRole(aAccessible->Role(), role); \ nsAutoString name; \ - aAccessible->GetName(name); \ + aAccessible->Name(name); \ printf(" role: %s, name: %s; ", NS_ConvertUTF16toUTF8(role).get(), \ NS_ConvertUTF16toUTF8(name).get()); \ A11YDEBUG_FOCUS_LOG_DOMNODE(aAccessible->GetNode()) \ diff --git a/accessible/src/base/nsAccessible.cpp b/accessible/src/base/nsAccessible.cpp index ee59d117f599..0cd14c0e8e91 100644 --- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -209,9 +209,8 @@ nsAccessible::nsAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : NS_ConvertUTF16toUTF8(content->NodeInfo()->QualifiedName()).get(), (void *)content.get()); nsAutoString buf; - if (NS_SUCCEEDED(GetName(buf))) { - printf(" Name:[%s]", NS_ConvertUTF16toUTF8(buf).get()); - } + Name(buf); + printf(" Name:[%s]", NS_ConvertUTF16toUTF8(buf).get()); } printf("\n"); } @@ -278,45 +277,52 @@ nsAccessible::GetName(nsAString& aName) if (IsDefunct()) return NS_ERROR_FAILURE; + nsAutoString name; + Name(name); + aName.Assign(name); + + return NS_OK; +} + +ENameValueFlag +nsAccessible::Name(nsString& aName) +{ + aName.Truncate(); + GetARIAName(aName); if (!aName.IsEmpty()) - return NS_OK; + return eNameOK; nsCOMPtr xblAccessible(do_QueryInterface(mContent)); if (xblAccessible) { xblAccessible->GetAccessibleName(aName); if (!aName.IsEmpty()) - return NS_OK; + return eNameOK; } nsresult rv = GetNameInternal(aName); - NS_ENSURE_SUCCESS(rv, rv); - if (!aName.IsEmpty()) - return NS_OK; + return eNameOK; // In the end get the name from tooltip. - nsIAtom *tooltipAttr = nsnull; - - if (mContent->IsHTML()) - tooltipAttr = nsGkAtoms::title; - else if (mContent->IsXUL()) - tooltipAttr = nsGkAtoms::tooltiptext; - else - return NS_OK; - - // XXX: if CompressWhiteSpace worked on nsAString we could avoid a copy. - nsAutoString name; - if (mContent->GetAttr(kNameSpaceID_None, tooltipAttr, name)) { - name.CompressWhitespace(); - aName = name; - return NS_OK_NAME_FROM_TOOLTIP; + if (mContent->IsHTML()) { + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) { + aName.CompressWhitespace(); + return eNameFromTooltip; + } + } else if (mContent->IsXUL()) { + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aName)) { + aName.CompressWhitespace(); + return eNameFromTooltip; + } + } else { + return eNameOK; } if (rv != NS_OK_EMPTY_NAME) aName.SetIsVoid(true); - return NS_OK; + return eNameOK; } NS_IMETHODIMP @@ -364,7 +370,7 @@ nsAccessible::Description(nsString& aDescription) nsGkAtoms::title; if (mContent->GetAttr(kNameSpaceID_None, descAtom, aDescription)) { nsAutoString name; - GetName(name); + Name(name); if (name.IsEmpty() || aDescription == name) // Don't use tooltip for a description if this object // has no name or the tooltip is the same as the name diff --git a/accessible/src/base/nsAccessible.h b/accessible/src/base/nsAccessible.h index b951ad44b7d6..adbeb4ae8d26 100644 --- a/accessible/src/base/nsAccessible.h +++ b/accessible/src/base/nsAccessible.h @@ -65,9 +65,25 @@ class nsHTMLImageMapAccessible; class nsHTMLLIAccessible; struct nsRoleMapEntry; class Relation; + namespace mozilla { namespace a11y { class TableAccessible; + +/** + * Name type flags. + */ +enum ENameValueFlag { + /** + * Name either + * a) present (not empty): !name.IsEmpty() + * b) no name (was missed): name.IsVoid() + * c) was left empty by the author on demand: name.IsEmpty() && !name.IsVoid() + */ + eNameOK, + eNameFromTooltip // Tooltip was used as a name +}; + } } class nsTextAccessible; @@ -140,6 +156,11 @@ public: */ virtual void Value(nsString& aValue); + /** + * Get the name of this accessible. + */ + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); + /** * Return DOM node associated with this accessible. */ diff --git a/accessible/src/base/nsDocAccessible.cpp b/accessible/src/base/nsDocAccessible.cpp index 4d0bdf687068..2abe39fb1831 100644 --- a/accessible/src/base/nsDocAccessible.cpp +++ b/accessible/src/base/nsDocAccessible.cpp @@ -213,26 +213,26 @@ NS_IMPL_RELEASE_INHERITED(nsDocAccessible, nsHyperTextAccessible) //////////////////////////////////////////////////////////////////////////////// // nsIAccessible -NS_IMETHODIMP -nsDocAccessible::GetName(nsAString& aName) +ENameValueFlag +nsDocAccessible::Name(nsString& aName) { - nsresult rv = NS_OK; aName.Truncate(); + if (mParent) { - rv = mParent->GetName(aName); // Allow owning iframe to override the name + mParent->Name(aName); // Allow owning iframe to override the name } if (aName.IsEmpty()) { // Allow name via aria-labelledby or title attribute - rv = nsAccessible::GetName(aName); + nsAccessible::Name(aName); } if (aName.IsEmpty()) { - rv = GetTitle(aName); // Try title element + GetTitle(aName); // Try title element } if (aName.IsEmpty()) { // Last resort: use URL - rv = GetURL(aName); + GetURL(aName); } - - return rv; + + return eNameOK; } // nsAccessible public method diff --git a/accessible/src/base/nsDocAccessible.h b/accessible/src/base/nsDocAccessible.h index 7a9fb2132fd8..43c2d3aa21a8 100644 --- a/accessible/src/base/nsDocAccessible.h +++ b/accessible/src/base/nsDocAccessible.h @@ -92,7 +92,6 @@ public: virtual ~nsDocAccessible(); // nsIAccessible - NS_IMETHOD GetName(nsAString& aName); NS_IMETHOD GetAttributes(nsIPersistentProperties **aAttributes); NS_IMETHOD TakeFocus(void); @@ -111,6 +110,7 @@ public: virtual nsIDocument* GetDocumentNode() const { return mDocument; } // nsAccessible + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual void Description(nsString& aDescription); virtual nsAccessible* FocusedChild(); virtual mozilla::a11y::role NativeRole(); diff --git a/accessible/src/base/nsRootAccessible.cpp b/accessible/src/base/nsRootAccessible.cpp index 9dc740230002..64db988e4371 100644 --- a/accessible/src/base/nsRootAccessible.cpp +++ b/accessible/src/base/nsRootAccessible.cpp @@ -110,27 +110,22 @@ nsRootAccessible::~nsRootAccessible() } //////////////////////////////////////////////////////////////////////////////// -// nsIAccessible +// nsAccessible -/* readonly attribute AString name; */ -NS_IMETHODIMP -nsRootAccessible::GetName(nsAString& aName) +ENameValueFlag +nsRootAccessible::Name(nsString& aName) { aName.Truncate(); - if (!mDocument) { - return NS_ERROR_FAILURE; - } - if (mRoleMapEntry) { - nsAccessible::GetName(aName); - if (!aName.IsEmpty()) { - return NS_OK; - } + nsAccessible::Name(aName); + if (!aName.IsEmpty()) + return eNameOK; } nsCOMPtr document = do_QueryInterface(mDocument); - return document->GetTitle(aName); + document->GetTitle(aName); + return eNameOK; } role diff --git a/accessible/src/base/nsRootAccessible.h b/accessible/src/base/nsRootAccessible.h index d27090411424..e81aa4f5e73a 100644 --- a/accessible/src/base/nsRootAccessible.h +++ b/accessible/src/base/nsRootAccessible.h @@ -62,9 +62,6 @@ public: nsIPresShell* aPresShell); virtual ~nsRootAccessible(); - // nsIAccessible - NS_IMETHOD GetName(nsAString& aName); - // nsIDOMEventListener NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); @@ -72,6 +69,7 @@ public: virtual void Shutdown(); // nsAccessible + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual Relation RelationByType(PRUint32 aType); virtual mozilla::a11y::role NativeRole(); virtual PRUint64 NativeState(); diff --git a/accessible/src/base/nsTextEquivUtils.cpp b/accessible/src/base/nsTextEquivUtils.cpp index b4fb7ea66b3d..156ee78619ca 100644 --- a/accessible/src/base/nsTextEquivUtils.cpp +++ b/accessible/src/base/nsTextEquivUtils.cpp @@ -48,6 +48,8 @@ #include "nsArrayUtils.h" +using namespace mozilla::a11y; + #define NS_OK_NO_NAME_CLAUSE_HANDLED \ NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x24) @@ -227,19 +229,16 @@ nsTextEquivUtils::AppendFromAccessible(nsAccessible *aAccessible, return rv; } - nsAutoString text; - nsresult rv = aAccessible->GetName(text); - NS_ENSURE_SUCCESS(rv, rv); - bool isEmptyTextEquiv = true; // If the name is from tooltip then append it to result string in the end // (see h. step of name computation guide). - if (rv != NS_OK_NAME_FROM_TOOLTIP) + nsAutoString text; + if (aAccessible->Name(text) != eNameFromTooltip) isEmptyTextEquiv = !AppendString(aString, text); // Implementation of f. step. - rv = AppendFromValue(aAccessible, aString); + nsresult rv = AppendFromValue(aAccessible, aString); NS_ENSURE_SUCCESS(rv, rv); if (rv != NS_OK_NO_NAME_CLAUSE_HANDLED) diff --git a/accessible/src/generic/ApplicationAccessible.cpp b/accessible/src/generic/ApplicationAccessible.cpp index 73a8a0a812a1..c1b5bf3b8d16 100644 --- a/accessible/src/generic/ApplicationAccessible.cpp +++ b/accessible/src/generic/ApplicationAccessible.cpp @@ -96,8 +96,8 @@ ApplicationAccessible::GetPreviousSibling(nsIAccessible** aPreviousSibling) return NS_OK; } -NS_IMETHODIMP -ApplicationAccessible::GetName(nsAString& aName) +ENameValueFlag +ApplicationAccessible::Name(nsString& aName) { aName.Truncate(); @@ -105,12 +105,14 @@ ApplicationAccessible::GetName(nsAString& aName) mozilla::services::GetStringBundleService(); NS_ASSERTION(bundleService, "String bundle service must be present!"); - NS_ENSURE_STATE(bundleService); + if (!bundleService) + return eNameOK; nsCOMPtr bundle; nsresult rv = bundleService->CreateBundle("chrome://branding/locale/brand.properties", getter_AddRefs(bundle)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_FAILED(rv)) + return eNameOK; nsXPIDLString appName; rv = bundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(), @@ -121,7 +123,7 @@ ApplicationAccessible::GetName(nsAString& aName) } aName.Assign(appName); - return NS_OK; + return eNameOK; } void diff --git a/accessible/src/generic/ApplicationAccessible.h b/accessible/src/generic/ApplicationAccessible.h index a0d32d7b876d..66a470611b45 100644 --- a/accessible/src/generic/ApplicationAccessible.h +++ b/accessible/src/generic/ApplicationAccessible.h @@ -79,7 +79,6 @@ public: NS_IMETHOD GetParent(nsIAccessible **aParent); NS_IMETHOD GetNextSibling(nsIAccessible **aNextSibling); NS_IMETHOD GetPreviousSibling(nsIAccessible **aPreviousSibling); - NS_IMETHOD GetName(nsAString &aName); NS_IMETHOD GetAttributes(nsIPersistentProperties **aAttributes); NS_IMETHOD GroupPosition(PRInt32 *aGroupLevel, PRInt32 *aSimilarItemsInGroup, PRInt32 *aPositionInGroup); @@ -101,6 +100,7 @@ public: virtual bool IsPrimaryForNode() const; // nsAccessible + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual void ApplyARIAState(PRUint64* aState); virtual void Description(nsString& aDescription); virtual void Value(nsString& aValue); diff --git a/accessible/src/html/nsHTMLSelectAccessible.cpp b/accessible/src/html/nsHTMLSelectAccessible.cpp index 87893fd3057c..f6d382a0a485 100644 --- a/accessible/src/html/nsHTMLSelectAccessible.cpp +++ b/accessible/src/html/nsHTMLSelectAccessible.cpp @@ -594,7 +594,7 @@ nsHTMLComboboxAccessible::Value(nsString& aValue) // Use accessible name of selected option. nsAccessible* option = SelectedOption(); if (option) - option->GetName(aValue); + option->Name(aValue); } PRUint8 diff --git a/accessible/src/html/nsHTMLTextAccessible.cpp b/accessible/src/html/nsHTMLTextAccessible.cpp index 7f0cbe8de85d..f1271facd67b 100644 --- a/accessible/src/html/nsHTMLTextAccessible.cpp +++ b/accessible/src/html/nsHTMLTextAccessible.cpp @@ -68,12 +68,12 @@ nsHTMLTextAccessible:: NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLTextAccessible, nsTextAccessible) -NS_IMETHODIMP -nsHTMLTextAccessible::GetName(nsAString& aName) +ENameValueFlag +nsHTMLTextAccessible::Name(nsString& aName) { // Text node, ARIA can't be used. aName = mText; - return NS_OK; + return eNameOK; } role @@ -348,14 +348,11 @@ nsHTMLListBulletAccessible::IsPrimaryForNode() const //////////////////////////////////////////////////////////////////////////////// // nsHTMLListBulletAccessible: nsAccessible -NS_IMETHODIMP -nsHTMLListBulletAccessible::GetName(nsAString &aName) +ENameValueFlag +nsHTMLListBulletAccessible::Name(nsString &aName) { aName.Truncate(); - if (IsDefunct()) - return NS_ERROR_FAILURE; - // Native anonymous content, ARIA can't be used. Get list bullet text. nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame()); NS_ASSERTION(blockFrame, "No frame for list item!"); @@ -366,7 +363,7 @@ nsHTMLListBulletAccessible::GetName(nsAString &aName) aName.Append(' '); } - return NS_OK; + return eNameOK; } role diff --git a/accessible/src/html/nsHTMLTextAccessible.h b/accessible/src/html/nsHTMLTextAccessible.h index c2a9c86d1158..2bd2325637ec 100644 --- a/accessible/src/html/nsHTMLTextAccessible.h +++ b/accessible/src/html/nsHTMLTextAccessible.h @@ -55,10 +55,8 @@ public: // nsISupports NS_DECL_ISUPPORTS_INHERITED - // nsIAccessible - NS_IMETHOD GetName(nsAString& aName); - // nsAccessible + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes); virtual mozilla::a11y::role NativeRole(); virtual PRUint64 NativeState(); @@ -129,13 +127,11 @@ class nsHTMLListBulletAccessible : public nsLeafAccessible public: nsHTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc); - // nsIAccessible - NS_IMETHOD GetName(nsAString& aName); - // nsAccessNode virtual bool IsPrimaryForNode() const; // nsAccessible + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual mozilla::a11y::role NativeRole(); virtual PRUint64 NativeState(); virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0, diff --git a/accessible/src/mac/mozAccessible.mm b/accessible/src/mac/mozAccessible.mm index 1085f425ee36..d6d081ba2012 100644 --- a/accessible/src/mac/mozAccessible.mm +++ b/accessible/src/mac/mozAccessible.mm @@ -514,7 +514,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible) NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; nsAutoString title; - mGeckoAccessible->GetName (title); + mGeckoAccessible->Name(title); return title.IsEmpty() ? nil : [NSString stringWithCharacters:title.BeginReading() length:title.Length()]; NS_OBJC_END_TRY_ABORT_BLOCK_NIL; diff --git a/accessible/src/msaa/nsAccessibleWrap.cpp b/accessible/src/msaa/nsAccessibleWrap.cpp index 4831ecdefe19..aad14f62bc77 100644 --- a/accessible/src/msaa/nsAccessibleWrap.cpp +++ b/accessible/src/msaa/nsAccessibleWrap.cpp @@ -285,9 +285,7 @@ __try { return CO_E_OBJNOTCONNECTED; nsAutoString name; - nsresult rv = xpAccessible->GetName(name); - if (NS_FAILED(rv)) - return GetHRESULT(rv); + xpAccessible->Name(name); // The name was not provided, e.g. no alt attribute for an image. A screen // reader may choose to invent its own accessible name, e.g. from an image src diff --git a/accessible/src/msaa/nsXULMenuAccessibleWrap.cpp b/accessible/src/msaa/nsXULMenuAccessibleWrap.cpp index a0e6f81ce4c1..4424a2a1195e 100644 --- a/accessible/src/msaa/nsXULMenuAccessibleWrap.cpp +++ b/accessible/src/msaa/nsXULMenuAccessibleWrap.cpp @@ -38,6 +38,8 @@ #include "nsXULMenuAccessibleWrap.h" #include "nsINameSpaceManager.h" +using namespace mozilla::a11y; + //////////////////////////////////////////////////////////////////////////////// // nsXULMenuAccessibleWrap //////////////////////////////////////////////////////////////////////////////// @@ -48,21 +50,19 @@ nsXULMenuitemAccessibleWrap:: { } -NS_IMETHODIMP -nsXULMenuitemAccessibleWrap::GetName(nsAString& aName) +ENameValueFlag +nsXULMenuitemAccessibleWrap::Name(nsString& aName) { // XXX This should be done in get_accName() so that nsIAccessible::GetName()] // provides the same results on all platforms - nsresult rv = nsXULMenuitemAccessible::GetName(aName); - if (NS_FAILED(rv)) { - return rv; - } + nsXULMenuitemAccessible::Name(aName); + if (aName.IsEmpty()) + return eNameOK; nsAutoString accel; mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, accel); - if (!accel.IsEmpty()) { + if (!accel.IsEmpty()) aName += NS_LITERAL_STRING("\t") + accel; - } - return NS_OK; + return eNameOK; } diff --git a/accessible/src/msaa/nsXULMenuAccessibleWrap.h b/accessible/src/msaa/nsXULMenuAccessibleWrap.h index fdd122f43c4f..6adada7c7e8a 100644 --- a/accessible/src/msaa/nsXULMenuAccessibleWrap.h +++ b/accessible/src/msaa/nsXULMenuAccessibleWrap.h @@ -47,7 +47,7 @@ public: virtual ~nsXULMenuitemAccessibleWrap() {} // nsIAccessible - NS_IMETHOD GetName(nsAString& aName); + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); }; #endif diff --git a/accessible/src/xul/nsXULAlertAccessible.cpp b/accessible/src/xul/nsXULAlertAccessible.cpp index 530cf520f640..57a91390ac72 100644 --- a/accessible/src/xul/nsXULAlertAccessible.cpp +++ b/accessible/src/xul/nsXULAlertAccessible.cpp @@ -66,13 +66,13 @@ nsXULAlertAccessible::NativeState() return nsAccessible::NativeState() | states::ALERT; } -NS_IMETHODIMP -nsXULAlertAccessible::GetName(nsAString& aName) +ENameValueFlag +nsXULAlertAccessible::Name(nsString& aName) { // Screen readers need to read contents of alert, not the accessible name. // If we have both some screen readers will read the alert twice. aName.Truncate(); - return NS_OK; + return eNameOK; } //////////////////////////////////////////////////////////////////////////////// diff --git a/accessible/src/xul/nsXULAlertAccessible.h b/accessible/src/xul/nsXULAlertAccessible.h index e3eaf6e43cfe..2d701adeadb6 100644 --- a/accessible/src/xul/nsXULAlertAccessible.h +++ b/accessible/src/xul/nsXULAlertAccessible.h @@ -51,10 +51,8 @@ public: NS_DECL_ISUPPORTS_INHERITED - // nsIAccessible - NS_IMETHOD GetName(nsAString& aName); - // nsAccessible + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual mozilla::a11y::role NativeRole(); virtual PRUint64 NativeState(); diff --git a/accessible/src/xul/nsXULTreeAccessible.cpp b/accessible/src/xul/nsXULTreeAccessible.cpp index 67715840da8c..e5ab37135bdd 100644 --- a/accessible/src/xul/nsXULTreeAccessible.cpp +++ b/accessible/src/xul/nsXULTreeAccessible.cpp @@ -1176,16 +1176,13 @@ NS_IMPL_RELEASE_INHERITED(nsXULTreeItemAccessible, nsXULTreeItemAccessibleBase) //////////////////////////////////////////////////////////////////////////////// // nsXULTreeItemAccessible: nsIAccessible implementation -NS_IMETHODIMP -nsXULTreeItemAccessible::GetName(nsAString& aName) +ENameValueFlag +nsXULTreeItemAccessible::Name(nsString& aName) { aName.Truncate(); - if (IsDefunct()) - return NS_ERROR_FAILURE; - GetCellName(mColumn, aName); - return NS_OK; + return eNameOK; } //////////////////////////////////////////////////////////////////////////////// @@ -1197,7 +1194,7 @@ nsXULTreeItemAccessible::Init() if (!nsXULTreeItemAccessibleBase::Init()) return false; - GetName(mCachedName); + Name(mCachedName); return true; } @@ -1235,7 +1232,7 @@ nsXULTreeItemAccessible::RowInvalidated(PRInt32 aStartColIdx, PRInt32 aEndColIdx) { nsAutoString name; - GetName(name); + Name(name); if (name != mCachedName) { nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this); diff --git a/accessible/src/xul/nsXULTreeAccessible.h b/accessible/src/xul/nsXULTreeAccessible.h index a1bba9c42caa..44abae0a62ee 100644 --- a/accessible/src/xul/nsXULTreeAccessible.h +++ b/accessible/src/xul/nsXULTreeAccessible.h @@ -267,13 +267,12 @@ public: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeItemAccessible, nsXULTreeItemAccessibleBase) - NS_IMETHOD GetName(nsAString& aName); - // nsAccessNode virtual bool Init(); virtual void Shutdown(); // nsAccessible + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual mozilla::a11y::role NativeRole(); // nsXULTreeItemAccessibleBase diff --git a/accessible/src/xul/nsXULTreeGridAccessible.cpp b/accessible/src/xul/nsXULTreeGridAccessible.cpp index c7f47ac009e0..b2d61c84b160 100644 --- a/accessible/src/xul/nsXULTreeGridAccessible.cpp +++ b/accessible/src/xul/nsXULTreeGridAccessible.cpp @@ -657,14 +657,11 @@ nsXULTreeGridRowAccessible::NativeRole() return roles::ROW; } -NS_IMETHODIMP -nsXULTreeGridRowAccessible::GetName(nsAString& aName) +ENameValueFlag +nsXULTreeGridRowAccessible::Name(nsString& aName) { aName.Truncate(); - if (IsDefunct()) - return NS_ERROR_FAILURE; - // XXX: the row name sholdn't be a concatenation of cell names (bug 664384). nsCOMPtr column = nsCoreUtils::GetFirstSensibleColumn(mTree); while (column) { @@ -678,7 +675,7 @@ nsXULTreeGridRowAccessible::GetName(nsAString& aName) column = nsCoreUtils::GetNextSensibleColumn(column); } - return NS_OK; + return eNameOK; } nsAccessible* @@ -844,13 +841,13 @@ nsXULTreeGridCellAccessible::FocusedChild() return nsnull; } -NS_IMETHODIMP -nsXULTreeGridCellAccessible::GetName(nsAString& aName) +ENameValueFlag +nsXULTreeGridCellAccessible::Name(nsString& aName) { aName.Truncate(); - if (IsDefunct() || !mTreeView) - return NS_ERROR_FAILURE; + if (!mTreeView) + return eNameOK; mTreeView->GetCellText(mRow, mColumn, aName); @@ -862,7 +859,7 @@ nsXULTreeGridCellAccessible::GetName(nsAString& aName) if (aName.IsEmpty()) mTreeView->GetCellValue(mRow, mColumn, aName); - return NS_OK; + return eNameOK; } NS_IMETHODIMP diff --git a/accessible/src/xul/nsXULTreeGridAccessible.h b/accessible/src/xul/nsXULTreeGridAccessible.h index 234c4c5c86a4..b30d9b479cd3 100644 --- a/accessible/src/xul/nsXULTreeGridAccessible.h +++ b/accessible/src/xul/nsXULTreeGridAccessible.h @@ -103,7 +103,7 @@ public: // nsAccessible virtual mozilla::a11y::role NativeRole(); - NS_IMETHOD GetName(nsAString& aName); + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual nsAccessible* ChildAtPoint(PRInt32 aX, PRInt32 aY, EWhichChildAtPoint aWhichChild); @@ -155,7 +155,6 @@ public: // nsIAccessible - NS_IMETHOD GetName(nsAString& aName); NS_IMETHOD GetBounds(PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight); @@ -170,6 +169,7 @@ public: virtual bool IsPrimaryForNode() const; // nsAccessible + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual nsAccessible* FocusedChild(); virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes); virtual PRInt32 IndexInParent() const; From 878c1e1e239ca0d69958543aaa3a7560555d0a2f Mon Sep 17 00:00:00 2001 From: Richard Newman Date: Mon, 30 Apr 2012 21:08:33 -0700 Subject: [PATCH 117/159] Bug 749727 - Ensure that each Fennec channel runs its password content provider in a different process. r=blassey, a=blocking-fennec --- mobile/android/base/AndroidManifest.xml.in | 8 +++++++- mobile/android/base/Makefile.in | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mobile/android/base/AndroidManifest.xml.in b/mobile/android/base/AndroidManifest.xml.in index 033c16eccb97..c3bd47df5415 100644 --- a/mobile/android/base/AndroidManifest.xml.in +++ b/mobile/android/base/AndroidManifest.xml.in @@ -185,10 +185,16 @@ android:authorities="@ANDROID_PACKAGE_NAME@.db.browser" android:permission="@ANDROID_PACKAGE_NAME@.permissions.BROWSER_PROVIDER"/> + + android:process="@MANGLED_ANDROID_PACKAGE_NAME@.PasswordsProvider"/> Date: Tue, 1 May 2012 01:43:59 -0500 Subject: [PATCH 118/159] Bug 749816. When setting the display port for an element We only need to discard layer contents when we are hiding a document with a widget. r=roc --- dom/base/nsDOMWindowUtils.cpp | 7 +++++-- layout/base/crashtests/749816-1.html | 15 +++++++++++++++ layout/base/crashtests/crashtests.list | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 layout/base/crashtests/749816-1.html diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index a755b5151b1f..b05d4a39d640 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -359,8 +359,11 @@ nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx, usingDisplayport ? rootDisplayport : rootFrame->GetVisualOverflowRect(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS); - // Send empty paint transaction in order to release retained layers - if (displayport.IsEmpty()) { + // If we are hiding something that is a display root then send empty paint + // transaction in order to release retained layers because it won't get + // any more paint requests when it is hidden. + if (displayport.IsEmpty() && + rootFrame == nsLayoutUtils::GetDisplayRootFrame(rootFrame)) { nsCOMPtr widget = GetWidget(); if (widget) { bool isRetainingManager; diff --git a/layout/base/crashtests/749816-1.html b/layout/base/crashtests/749816-1.html new file mode 100644 index 000000000000..125553886e6b --- /dev/null +++ b/layout/base/crashtests/749816-1.html @@ -0,0 +1,15 @@ + + +crash in epoll_wait after changing display: table-column style to display:none on body + + + + +This page should not crash Fennec + + \ No newline at end of file diff --git a/layout/base/crashtests/crashtests.list b/layout/base/crashtests/crashtests.list index dc9a818a7067..91203db2ec5d 100644 --- a/layout/base/crashtests/crashtests.list +++ b/layout/base/crashtests/crashtests.list @@ -355,3 +355,4 @@ load 727601.html asserts(0-2) pref(dom.disable_open_during_load,false) load 735943.html # the assertion is bug 735966 asserts(0-2) load 736389-1.xhtml # sometimes the above assertions are delayed and is reported on this test instead load 736924-1.html +load 749816-1.html From 5c5c30a688ce3b9fa475b73b3c08da2bb90338bb Mon Sep 17 00:00:00 2001 From: Gervase Markham Date: Tue, 1 May 2012 09:31:37 +0100 Subject: [PATCH 119/159] Bug 750294 - update about:license to give link to Hg rev and build instructions. r=luis. --- toolkit/content/license.html | 38 +++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/toolkit/content/license.html b/toolkit/content/license.html index d27835b79a83..8f6f5444e884 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -1,4 +1,4 @@ - +h @@ -28,26 +28,29 @@ #ifdef APP_LICENSE_BLOCK #includesubst @APP_LICENSE_BLOCK@ #endif - +

    All of the source code to this product is - available - under licenses which are both + available under licenses which are both free and open source. - Most of it is available under the Mozilla Public License 2.0 (MPL). +#ifdef SOURCE_REPO +#ifdef SOURCE_CHANGESET + The specific source code for this product is identified by the URL + @SOURCE_REPO@/rev/@SOURCE_CHANGESET@, + and you can read + instructions + on how to download and build it for yourself. +#endif +#endif

    - - -

    The remainder of the software which is not under the MPL is available - under one of - a variety of other licenses. Those that require reproduction +

    More specifically, most of the source code is available under the + Mozilla Public License 2.0 (MPL). + The MPL has a + FAQ to help + you understand it. The remainder of the software which is not + under the MPL is available under one of a variety of other + permissive licenses. Those that require reproduction of the license text in the distribution are given below. (Note: your copy of this product may not contain code covered by one or more of the licenses listed here, depending on the exact product @@ -55,6 +58,9 @@

      +
    • Mozilla Public License 2.0 +

      +
    • Android Open Source License
    • ANGLE License
    • Apache License 2.0
    • From c7871fe089a783397fbdb9e608caaab47d2af155 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Tue, 1 May 2012 09:34:52 +0300 Subject: [PATCH 120/159] Bug 748303 part 1 - Clean up various nsHTMLEditRules methods; r=ehsan --- editor/libeditor/html/nsHTMLEditRules.cpp | 277 ++++++++++------------ 1 file changed, 130 insertions(+), 147 deletions(-) diff --git a/editor/libeditor/html/nsHTMLEditRules.cpp b/editor/libeditor/html/nsHTMLEditRules.cpp index 0b342272127b..284014bb3ecb 100644 --- a/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/editor/libeditor/html/nsHTMLEditRules.cpp @@ -1505,10 +1505,13 @@ nsHTMLEditRules::WillLoadHTML(nsISelection *aSelection, bool *aCancel) } nsresult -nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, bool *aCancel, bool *aHandled) +nsHTMLEditRules::WillInsertBreak(nsISelection* aSelection, + bool* aCancel, bool* aHandled) { - if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } - // initialize out param + if (!aSelection || !aCancel || !aHandled) { + return NS_ERROR_NULL_POINTER; + } + // initialize out params *aCancel = false; *aHandled = false; @@ -1516,73 +1519,70 @@ nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, bool *aCancel, bool * bool bCollapsed; nsresult res = aSelection->GetIsCollapsed(&bCollapsed); NS_ENSURE_SUCCESS(res, res); - if (!bCollapsed) - { + if (!bCollapsed) { res = mHTMLEditor->DeleteSelection(nsIEditor::eNone); NS_ENSURE_SUCCESS(res, res); } - + res = WillInsert(aSelection, aCancel); NS_ENSURE_SUCCESS(res, res); - + // initialize out param // we want to ignore result of WillInsert() *aCancel = false; // split any mailcites in the way. // should we abort this if we encounter table cell boundaries? - if (IsMailEditor()) - { + if (IsMailEditor()) { res = SplitMailCites(aSelection, IsPlaintextEditor(), aHandled); NS_ENSURE_SUCCESS(res, res); - if (*aHandled) return NS_OK; + if (*aHandled) { + return NS_OK; + } } // smart splitting rules nsCOMPtr node; PRInt32 offset; - res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset); + res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(node), + &offset); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); // do nothing if the node is read-only - if (!mHTMLEditor->IsModifiableNode(node)) - { + if (!mHTMLEditor->IsModifiableNode(node)) { *aCancel = true; return NS_OK; } // identify the block nsCOMPtr blockParent; - if (IsBlockNode(node)) + if (IsBlockNode(node)) { blockParent = node; - else + } else { blockParent = mHTMLEditor->GetBlockNodeParent(node); + } NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE); - // if the active editing host is an inline element, - // or if the active editing host is the block parent itself, - // just append a br. + // if the active editing host is an inline element, or if the active editing + // host is the block parent itself, just append a br. nsCOMPtr hostContent = mHTMLEditor->GetActiveEditingHost(); nsCOMPtr hostNode = do_QueryInterface(hostContent); - if (!nsEditorUtils::IsDescendantOf(blockParent, hostNode)) - { + if (!nsEditorUtils::IsDescendantOf(blockParent, hostNode)) { res = StandardBreakImpl(node, offset, aSelection); NS_ENSURE_SUCCESS(res, res); *aHandled = true; return NS_OK; } - // if block is empty, populate with br. - // (for example, imagine a div that contains the word "text". the user selects - // "text" and types return. "text" is deleted leaving an empty block. we want - // to put in one br to make block have a line. then code further below will put - // in a second br.) + // if block is empty, populate with br. (for example, imagine a div that + // contains the word "text". the user selects "text" and types return. + // "text" is deleted leaving an empty block. we want to put in one br to + // make block have a line. then code further below will put in a second br.) bool isEmpty; - res = IsEmptyBlock(blockParent, &isEmpty); - if (isEmpty) - { + IsEmptyBlock(blockParent, &isEmpty); + if (isEmpty) { PRUint32 blockLen; res = mHTMLEditor->GetLengthOfDOMNode(blockParent, blockLen); NS_ENSURE_SUCCESS(res, res); @@ -1590,42 +1590,36 @@ nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, bool *aCancel, bool * res = mHTMLEditor->CreateBR(blockParent, blockLen, address_of(brNode)); NS_ENSURE_SUCCESS(res, res); } - + nsCOMPtr listItem = IsInListItem(blockParent); - if (listItem && listItem != hostNode) - { - res = ReturnInListItem(aSelection, listItem, node, offset); + if (listItem && listItem != hostNode) { + ReturnInListItem(aSelection, listItem, node, offset); *aHandled = true; return NS_OK; - } - - // headers: close (or split) header - else if (nsHTMLEditUtils::IsHeader(blockParent)) - { - res = ReturnInHeader(aSelection, blockParent, node, offset); + } else if (nsHTMLEditUtils::IsHeader(blockParent)) { + // headers: close (or split) header + ReturnInHeader(aSelection, blockParent, node, offset); *aHandled = true; return NS_OK; - } - - // paragraphs: special rules to look for
      s - else if (nsHTMLEditUtils::IsParagraph(blockParent)) - { - res = ReturnInParagraph(aSelection, blockParent, node, offset, aCancel, aHandled); + } else if (nsHTMLEditUtils::IsParagraph(blockParent)) { + // paragraphs: special rules to look for
      s + res = ReturnInParagraph(aSelection, blockParent, node, offset, + aCancel, aHandled); NS_ENSURE_SUCCESS(res, res); // fall through, we may not have handled it in ReturnInParagraph() } - + // if not already handled then do the standard thing - if (!(*aHandled)) - { - res = StandardBreakImpl(node, offset, aSelection); + if (!(*aHandled)) { *aHandled = true; + return StandardBreakImpl(node, offset, aSelection); } - return res; + return NS_OK; } nsresult -nsHTMLEditRules::StandardBreakImpl(nsIDOMNode *aNode, PRInt32 aOffset, nsISelection *aSelection) +nsHTMLEditRules::StandardBreakImpl(nsIDOMNode* aNode, PRInt32 aOffset, + nsISelection* aSelection) { nsCOMPtr brNode; bool bAfterBlock = false; @@ -1633,89 +1627,89 @@ nsHTMLEditRules::StandardBreakImpl(nsIDOMNode *aNode, PRInt32 aOffset, nsISelect nsresult res = NS_OK; nsCOMPtr node(aNode); nsCOMPtr selPriv(do_QueryInterface(aSelection)); - - if (IsPlaintextEditor()) - { + + if (IsPlaintextEditor()) { res = mHTMLEditor->CreateBR(node, aOffset, address_of(brNode)); - } - else - { + } else { nsWSRunObject wsObj(mHTMLEditor, node, aOffset); nsCOMPtr visNode, linkNode; - PRInt32 visOffset=0, newOffset; + PRInt32 visOffset = 0, newOffset; PRInt16 wsType; - res = wsObj.PriorVisibleNode(node, aOffset, address_of(visNode), &visOffset, &wsType); + res = wsObj.PriorVisibleNode(node, aOffset, address_of(visNode), + &visOffset, &wsType); NS_ENSURE_SUCCESS(res, res); - if (wsType & nsWSRunObject::eBlock) + if (wsType & nsWSRunObject::eBlock) { bAfterBlock = true; - res = wsObj.NextVisibleNode(node, aOffset, address_of(visNode), &visOffset, &wsType); + } + res = wsObj.NextVisibleNode(node, aOffset, address_of(visNode), + &visOffset, &wsType); NS_ENSURE_SUCCESS(res, res); - if (wsType & nsWSRunObject::eBlock) + if (wsType & nsWSRunObject::eBlock) { bBeforeBlock = true; - if (mHTMLEditor->IsInLink(node, address_of(linkNode))) - { + } + if (mHTMLEditor->IsInLink(node, address_of(linkNode))) { // split the link nsCOMPtr linkParent; res = linkNode->GetParentNode(getter_AddRefs(linkParent)); NS_ENSURE_SUCCESS(res, res); - res = mHTMLEditor->SplitNodeDeep(linkNode, node, aOffset, &newOffset, true); + res = mHTMLEditor->SplitNodeDeep(linkNode, node, aOffset, + &newOffset, true); NS_ENSURE_SUCCESS(res, res); // reset {node,aOffset} to the point where link was split node = linkParent; aOffset = newOffset; } - res = wsObj.InsertBreak(address_of(node), &aOffset, address_of(brNode), nsIEditor::eNone); + res = wsObj.InsertBreak(address_of(node), &aOffset, + address_of(brNode), nsIEditor::eNone); } NS_ENSURE_SUCCESS(res, res); res = nsEditor::GetNodeLocation(brNode, address_of(node), &aOffset); NS_ENSURE_SUCCESS(res, res); - if (bAfterBlock && bBeforeBlock) - { - // we just placed a br between block boundaries. - // This is the one case where we want the selection to be before - // the br we just placed, as the br will be on a new line, - // rather than at end of prior line. + if (bAfterBlock && bBeforeBlock) { + // we just placed a br between block boundaries. This is the one case + // where we want the selection to be before the br we just placed, as the + // br will be on a new line, rather than at end of prior line. selPriv->SetInterlinePosition(true); res = aSelection->Collapse(node, aOffset); - } - else - { - nsWSRunObject wsObj(mHTMLEditor, node, aOffset+1); - nsCOMPtr secondBR; - PRInt32 visOffset=0; - PRInt16 wsType; - res = wsObj.NextVisibleNode(node, aOffset+1, address_of(secondBR), &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); - if (wsType==nsWSRunObject::eBreak) - { - // the next thing after the break we inserted is another break. Move the 2nd - // break to be the first breaks sibling. This will prevent them from being - // in different inline nodes, which would break SetInterlinePosition(). It will - // also assure that if the user clicks away and then clicks back on their new - // blank line, they will still get the style from the line above. - nsCOMPtr brParent; - PRInt32 brOffset; - res = nsEditor::GetNodeLocation(secondBR, address_of(brParent), &brOffset); - NS_ENSURE_SUCCESS(res, res); - if ((brParent != node) || (brOffset != (aOffset+1))) - { - res = mHTMLEditor->MoveNode(secondBR, node, aOffset+1); - NS_ENSURE_SUCCESS(res, res); - } - } - // SetInterlinePosition(true) means we want the caret to stick to the content on the "right". - // We want the caret to stick to whatever is past the break. This is - // because the break is on the same line we were on, but the next content - // will be on the following line. - - // An exception to this is if the break has a next sibling that is a block node. - // Then we stick to the left to avoid an uber caret. + } else { + nsWSRunObject wsObj(mHTMLEditor, node, aOffset+1); + nsCOMPtr secondBR; + PRInt32 visOffset = 0; + PRInt16 wsType; + res = wsObj.NextVisibleNode(node, aOffset+1, address_of(secondBR), + &visOffset, &wsType); + NS_ENSURE_SUCCESS(res, res); + if (wsType == nsWSRunObject::eBreak) { + // the next thing after the break we inserted is another break. Move + // the 2nd break to be the first breaks sibling. This will prevent them + // from being in different inline nodes, which would break + // SetInterlinePosition(). It will also assure that if the user clicks + // away and then clicks back on their new blank line, they will still + // get the style from the line above. + nsCOMPtr brParent; + PRInt32 brOffset; + res = nsEditor::GetNodeLocation(secondBR, address_of(brParent), + &brOffset); + NS_ENSURE_SUCCESS(res, res); + if (brParent != node || brOffset != aOffset + 1) { + res = mHTMLEditor->MoveNode(secondBR, node, aOffset+1); + NS_ENSURE_SUCCESS(res, res); + } + } + // SetInterlinePosition(true) means we want the caret to stick to the + // content on the "right". We want the caret to stick to whatever is past + // the break. This is because the break is on the same line we were on, + // but the next content will be on the following line. + + // An exception to this is if the break has a next sibling that is a block + // node. Then we stick to the left to avoid an uber caret. nsCOMPtr siblingNode; brNode->GetNextSibling(getter_AddRefs(siblingNode)); - if (siblingNode && IsBlockNode(siblingNode)) + if (siblingNode && IsBlockNode(siblingNode)) { selPriv->SetInterlinePosition(false); - else + } else { selPriv->SetInterlinePosition(true); + } res = aSelection->Collapse(node, aOffset+1); } return res; @@ -6600,17 +6594,18 @@ nsHTMLEditRules::ReturnInHeader(nsISelection *aSelection, /////////////////////////////////////////////////////////////////////////// // ReturnInParagraph: do the right thing for returns pressed in paragraphs -// -nsresult -nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, - nsIDOMNode *aPara, - nsIDOMNode *aNode, +// +nsresult +nsHTMLEditRules::ReturnInParagraph(nsISelection* aSelection, + nsIDOMNode* aPara, + nsIDOMNode* aNode, PRInt32 aOffset, - bool *aCancel, - bool *aHandled) + bool* aCancel, + bool* aHandled) { - if (!aSelection || !aPara || !aNode || !aCancel || !aHandled) - { return NS_ERROR_NULL_POINTER; } + if (!aSelection || !aPara || !aNode || !aCancel || !aHandled) { + return NS_ERROR_NULL_POINTER; + } *aCancel = false; *aHandled = false; @@ -6619,7 +6614,7 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, nsresult res = nsEditor::GetNodeLocation(aNode, address_of(parent), &offset); NS_ENSURE_SUCCESS(res, res); - bool doesCRCreateNewP; + bool doesCRCreateNewP; res = mHTMLEditor->GetReturnInParagraphCreatesNewParagraph(&doesCRCreateNewP); NS_ENSURE_SUCCESS(res, res); @@ -6629,41 +6624,31 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, if (aNode == aPara && doesCRCreateNewP) { // we are at the edges of the block, newBRneeded not needed! sibling = aNode; - } - else if (mHTMLEditor->IsTextNode(aNode)) - { + } else if (mHTMLEditor->IsTextNode(aNode)) { nsCOMPtr textNode = do_QueryInterface(aNode); PRUint32 strLength; res = textNode->GetLength(&strLength); NS_ENSURE_SUCCESS(res, res); - + // at beginning of text node? - if (!aOffset) - { + if (!aOffset) { // is there a BR prior to it? mHTMLEditor->GetPriorHTMLSibling(aNode, address_of(sibling)); - if (!sibling || - !mHTMLEditor->IsVisBreak(sibling) || nsTextEditUtils::HasMozAttr(sibling)) - { + if (!sibling || !mHTMLEditor->IsVisBreak(sibling) || + nsTextEditUtils::HasMozAttr(sibling)) { newBRneeded = true; } - } - else if (aOffset == (PRInt32)strLength) - { + } else if (aOffset == (PRInt32)strLength) { // we're at the end of text node... // is there a BR after to it? res = mHTMLEditor->GetNextHTMLSibling(aNode, address_of(sibling)); - if (!sibling || - !mHTMLEditor->IsVisBreak(sibling) || nsTextEditUtils::HasMozAttr(sibling)) - { + if (!sibling || !mHTMLEditor->IsVisBreak(sibling) || + nsTextEditUtils::HasMozAttr(sibling)) { newBRneeded = true; offset++; } - } - else - { - if (doesCRCreateNewP) - { + } else { + if (doesCRCreateNewP) { nsCOMPtr tmp; res = mEditor->SplitNode(aNode, aOffset, getter_AddRefs(tmp)); NS_ENSURE_SUCCESS(res, res); @@ -6673,29 +6658,27 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, newBRneeded = true; offset++; } - } - else - { - // not in a text node. + } else { + // not in a text node. // is there a BR prior to it? nsCOMPtr nearNode, selNode = aNode; res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode)); NS_ENSURE_SUCCESS(res, res); - if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode)) - { + if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || + nsTextEditUtils::HasMozAttr(nearNode)) { // is there a BR after it? res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode)); NS_ENSURE_SUCCESS(res, res); - if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode)) - { + if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || + nsTextEditUtils::HasMozAttr(nearNode)) { newBRneeded = true; } } - if (!newBRneeded) + if (!newBRneeded) { sibling = nearNode; + } } - if (newBRneeded) - { + if (newBRneeded) { // if CR does not create a new P, default to BR creation NS_ENSURE_TRUE(doesCRCreateNewP, NS_OK); From e249870181279397058b689086cf22ed498cd587 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Tue, 1 May 2012 09:34:52 +0300 Subject: [PATCH 121/159] Bug 748303 part 2 - Handle non-text/elements correctly when calling (Tag)CanContain(Tag); r=ehsan --- editor/libeditor/base/nsEditor.cpp | 11 +++++++++++ editor/libeditor/base/nsEditor.h | 1 + editor/libeditor/html/nsHTMLEditor.cpp | 6 +----- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 86a18a1cb828..36e7b677729a 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -3528,6 +3528,17 @@ nsEditor::IsBlockNode(nsINode *aNode) return false; } +bool +nsEditor::CanContain(nsIDOMNode* aParent, nsIDOMNode* aChild) +{ + nsCOMPtr parentElement = do_QueryInterface(aParent); + NS_ENSURE_TRUE(parentElement, false); + + nsAutoString parentStringTag; + parentElement->GetTagName(parentStringTag); + return TagCanContain(parentStringTag, aChild); +} + bool nsEditor::CanContainTag(nsIDOMNode* aParent, const nsAString &aChildTag) { diff --git a/editor/libeditor/base/nsEditor.h b/editor/libeditor/base/nsEditor.h index e6448c18e20c..63a4b287ee4a 100644 --- a/editor/libeditor/base/nsEditor.h +++ b/editor/libeditor/base/nsEditor.h @@ -534,6 +534,7 @@ public: /** returns true if aParent can contain a child of type aTag */ + bool CanContain(nsIDOMNode* aParent, nsIDOMNode* aChild); bool CanContainTag(nsIDOMNode* aParent, const nsAString &aTag); bool TagCanContain(const nsAString &aParentTag, nsIDOMNode* aChild); virtual bool TagCanContainTag(const nsAString &aParentTag, const nsAString &aChildTag); diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index 61b91b877c2c..339e35e6c906 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -1846,17 +1846,13 @@ nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode, NS_ENSURE_TRUE(ioOffset, NS_ERROR_NULL_POINTER); nsresult res = NS_OK; - nsAutoString tagName; - aNode->GetNodeName(tagName); - ToLowerCase(tagName); nsCOMPtr parent = *ioParent; nsCOMPtr topChild = *ioParent; nsCOMPtr tmp; PRInt32 offsetOfInsert = *ioOffset; // Search up the parent chain to find a suitable container - while (!CanContainTag(parent, tagName)) - { + while (!CanContain(parent, aNode)) { // If the current parent is a root (body or table element) // then go no further - we can't insert if (nsTextEditUtils::IsBody(parent) || nsHTMLEditUtils::IsTableElement(parent)) From cc7333f44f5315df709a1feabb8716336033ad64 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Tue, 1 May 2012 09:34:52 +0300 Subject: [PATCH 122/159] Bug 748303 part 3 - Convert (Tag)CanContain(Tag) to nsIAtom*; r=ehsan --- editor/libeditor/base/nsEditor.cpp | 38 ++++++++------------- editor/libeditor/base/nsEditor.h | 6 ++-- editor/libeditor/html/nsHTMLEditRules.cpp | 34 +++++++++--------- editor/libeditor/html/nsHTMLEditor.cpp | 28 +++++++-------- editor/libeditor/html/nsHTMLEditor.h | 2 +- editor/libeditor/html/nsHTMLEditorStyle.cpp | 32 +++++++++-------- editor/libeditor/text/nsPlaintextEditor.cpp | 3 +- editor/libeditor/text/nsTextEditRules.cpp | 4 ++- 8 files changed, 71 insertions(+), 76 deletions(-) diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 36e7b677729a..46debdde49aa 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -3531,45 +3531,35 @@ nsEditor::IsBlockNode(nsINode *aNode) bool nsEditor::CanContain(nsIDOMNode* aParent, nsIDOMNode* aChild) { - nsCOMPtr parentElement = do_QueryInterface(aParent); + nsCOMPtr parentElement = do_QueryInterface(aParent); NS_ENSURE_TRUE(parentElement, false); - nsAutoString parentStringTag; - parentElement->GetTagName(parentStringTag); - return TagCanContain(parentStringTag, aChild); + return TagCanContain(parentElement->Tag(), aChild); } bool -nsEditor::CanContainTag(nsIDOMNode* aParent, const nsAString &aChildTag) +nsEditor::CanContainTag(nsIDOMNode* aParent, nsIAtom* aChildTag) { - nsCOMPtr parentElement = do_QueryInterface(aParent); + nsCOMPtr parentElement = do_QueryInterface(aParent); NS_ENSURE_TRUE(parentElement, false); - - nsAutoString parentStringTag; - parentElement->GetTagName(parentStringTag); - return TagCanContainTag(parentStringTag, aChildTag); + + return TagCanContainTag(parentElement->Tag(), aChildTag); } bool -nsEditor::TagCanContain(const nsAString &aParentTag, nsIDOMNode* aChild) +nsEditor::TagCanContain(nsIAtom* aParentTag, nsIDOMNode* aChild) { - nsAutoString childStringTag; - - if (IsTextNode(aChild)) - { - childStringTag.AssignLiteral("#text"); + if (IsTextNode(aChild)) { + return TagCanContainTag(aParentTag, nsGkAtoms::textTagName); } - else - { - nsCOMPtr childElement = do_QueryInterface(aChild); - NS_ENSURE_TRUE(childElement, false); - childElement->GetTagName(childStringTag); - } - return TagCanContainTag(aParentTag, childStringTag); + + nsCOMPtr element = do_QueryInterface(aChild); + NS_ENSURE_TRUE(element, false); + return TagCanContainTag(aParentTag, element->Tag()); } bool -nsEditor::TagCanContainTag(const nsAString &aParentTag, const nsAString &aChildTag) +nsEditor::TagCanContainTag(nsIAtom* aParentTag, nsIAtom* aChildTag) { return true; } diff --git a/editor/libeditor/base/nsEditor.h b/editor/libeditor/base/nsEditor.h index 63a4b287ee4a..c74348b4908d 100644 --- a/editor/libeditor/base/nsEditor.h +++ b/editor/libeditor/base/nsEditor.h @@ -535,9 +535,9 @@ public: /** returns true if aParent can contain a child of type aTag */ bool CanContain(nsIDOMNode* aParent, nsIDOMNode* aChild); - bool CanContainTag(nsIDOMNode* aParent, const nsAString &aTag); - bool TagCanContain(const nsAString &aParentTag, nsIDOMNode* aChild); - virtual bool TagCanContainTag(const nsAString &aParentTag, const nsAString &aChildTag); + bool CanContainTag(nsIDOMNode* aParent, nsIAtom* aTag); + bool TagCanContain(nsIAtom* aParentTag, nsIDOMNode* aChild); + virtual bool TagCanContainTag(nsIAtom* aParentTag, nsIAtom* aChildTag); /** returns true if aNode is our root node */ bool IsRootNode(nsIDOMNode *inNode); diff --git a/editor/libeditor/html/nsHTMLEditRules.cpp b/editor/libeditor/html/nsHTMLEditRules.cpp index 284014bb3ecb..e161d18f95ce 100644 --- a/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/editor/libeditor/html/nsHTMLEditRules.cpp @@ -1328,8 +1328,9 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, // dont put text in places that can't have it if (!mHTMLEditor->IsTextNode(selNode) && - !mHTMLEditor->CanContainTag(selNode, NS_LITERAL_STRING("#text"))) + !mHTMLEditor->CanContainTag(selNode, nsGkAtoms::textTagName)) { return NS_ERROR_FAILURE; + } // we need to get the doc nsCOMPtr doc = mHTMLEditor->GetDOMDocument(); @@ -2525,8 +2526,7 @@ nsHTMLEditRules::InsertBRIfNeeded(nsISelection *aSelection) { // if we are tucked between block boundaries then insert a br // first check that we are allowed to - if (mHTMLEditor->CanContainTag(node, NS_LITERAL_STRING("br"))) - { + if (mHTMLEditor->CanContainTag(node, nsGkAtoms::br)) { nsCOMPtr brNode; res = mHTMLEditor->CreateBR(node, offset, address_of(brNode), nsIEditor::ePrevious); } @@ -2818,14 +2818,9 @@ nsHTMLEditRules::MoveNodeSmart(nsIDOMNode *aSource, nsIDOMNode *aDest, PRInt32 * { NS_ENSURE_TRUE(aSource && aDest && aOffset, NS_ERROR_NULL_POINTER); - nsAutoString tag; nsresult res; - res = mHTMLEditor->GetTagString(aSource, tag); - NS_ENSURE_SUCCESS(res, res); - ToLowerCase(tag); // check if this node can go into the destination node - if (mHTMLEditor->CanContainTag(aDest, tag)) - { + if (mHTMLEditor->CanContain(aDest, aSource)) { // if it can, move it there res = mHTMLEditor->MoveNode(aSource, aDest, *aOffset); NS_ENSURE_SUCCESS(res, res); @@ -3027,7 +3022,8 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection, NS_ENSURE_SUCCESS(res, res); // make sure we can put a list here - if (!mHTMLEditor->CanContainTag(parent, *aListType)) { + nsCOMPtr listTypeAtom = do_GetAtom(*aListType); + if (!mHTMLEditor->CanContainTag(parent, listTypeAtom)) { *aCancel = true; return NS_OK; } @@ -3701,10 +3697,11 @@ nsHTMLEditRules::WillCSSIndent(nsISelection *aSelection, bool *aCancel, bool * a if (!curQuote) { // First, check that our element can contain a div. - NS_NAMED_LITERAL_STRING(divquoteType, "div"); - if (!mEditor->CanContainTag(curParent, divquoteType)) + if (!mEditor->CanContainTag(curParent, nsGkAtoms::div)) { return NS_OK; // cancelled + } + NS_NAMED_LITERAL_STRING(divquoteType, "div"); res = SplitAsNeeded(&divquoteType, address_of(curParent), &offset); NS_ENSURE_SUCCESS(res, res); res = mHTMLEditor->CreateNode(divquoteType, curParent, offset, getter_AddRefs(curQuote)); @@ -3932,8 +3929,9 @@ nsHTMLEditRules::WillHTMLIndent(nsISelection *aSelection, bool *aCancel, bool * if (!curQuote) { // First, check that our element can contain a blockquote. - if (!mEditor->CanContainTag(curParent, quoteType)) + if (!mEditor->CanContainTag(curParent, nsGkAtoms::blockquote)) { return NS_OK; // cancelled + } res = SplitAsNeeded("eType, address_of(curParent), &offset); NS_ENSURE_SUCCESS(res, res); @@ -4776,8 +4774,9 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection, { // First, check that our element can contain a div. NS_NAMED_LITERAL_STRING(divType, "div"); - if (!mEditor->CanContainTag(curParent, divType)) + if (!mEditor->CanContainTag(curParent, nsGkAtoms::div)) { return NS_OK; // cancelled + } res = SplitAsNeeded(&divType, address_of(curParent), &offset); NS_ENSURE_SUCCESS(res, res); @@ -7291,6 +7290,7 @@ nsHTMLEditRules::SplitAsNeeded(const nsAString *aTag, NS_ENSURE_TRUE(*inOutParent, NS_ERROR_NULL_POINTER); nsCOMPtr tagParent, temp, splitNode, parent = *inOutParent; nsresult res = NS_OK; + nsCOMPtr tagAtom = do_GetAtom(*aTag); // check that we have a place that can legally contain the tag while (!tagParent) @@ -7305,8 +7305,7 @@ nsHTMLEditRules::SplitAsNeeded(const nsAString *aTag, break; } } - if (mHTMLEditor->CanContainTag(parent, *aTag)) - { + if (mHTMLEditor->CanContainTag(parent, tagAtom)) { tagParent = parent; break; } @@ -7736,8 +7735,7 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection res = mHTMLEditor->IsEmptyNode(theblock, &bIsEmptyNode, false, false); NS_ENSURE_SUCCESS(res, res); // check if br can go into the destination node - if (bIsEmptyNode && mHTMLEditor->CanContainTag(selNode, NS_LITERAL_STRING("br"))) - { + if (bIsEmptyNode && mHTMLEditor->CanContainTag(selNode, nsGkAtoms::br)) { nsCOMPtr rootNode = do_QueryInterface(mHTMLEditor->GetRoot()); NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE); if (selNode == rootNode) diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index 339e35e6c906..78d37f46ae71 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -2250,8 +2250,8 @@ nsHTMLEditor::MakeOrChangeList(const nsAString& aListType, bool entireList, cons nsCOMPtr topChild = node; nsCOMPtr tmp; - while ( !CanContainTag(parent, aListType)) - { + nsCOMPtr listAtom = do_GetAtom(aListType); + while (!CanContainTag(parent, listAtom)) { parent->GetParentNode(getter_AddRefs(tmp)); NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE); topChild = parent; @@ -2394,8 +2394,8 @@ nsHTMLEditor::InsertBasicBlock(const nsAString& aBlockType) nsCOMPtr topChild = node; nsCOMPtr tmp; - while ( !CanContainTag(parent, aBlockType)) - { + nsCOMPtr blockAtom = do_GetAtom(aBlockType); + while (!CanContainTag(parent, blockAtom)) { parent->GetParentNode(getter_AddRefs(tmp)); NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE); topChild = parent; @@ -2475,9 +2475,7 @@ nsHTMLEditor::Indent(const nsAString& aIndent) nsCOMPtr parent = node; nsCOMPtr topChild = node; nsCOMPtr tmp; - NS_NAMED_LITERAL_STRING(bq, "blockquote"); - while ( !CanContainTag(parent, bq)) - { + while (!CanContainTag(parent, nsGkAtoms::blockquote)) { parent->GetParentNode(getter_AddRefs(tmp)); NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE); topChild = parent; @@ -2493,7 +2491,8 @@ nsHTMLEditor::Indent(const nsAString& aIndent) // make a blockquote nsCOMPtr newBQ; - res = CreateNode(bq, parent, offset, getter_AddRefs(newBQ)); + res = CreateNode(NS_LITERAL_STRING("blockquote"), parent, offset, + getter_AddRefs(newBQ)); NS_ENSURE_SUCCESS(res, res); // put a space in it so layout will draw the list item res = selection->Collapse(newBQ,0); @@ -3778,20 +3777,21 @@ nsHTMLEditor::EndOperation() } bool -nsHTMLEditor::TagCanContainTag(const nsAString& aParentTag, const nsAString& aChildTag) +nsHTMLEditor::TagCanContainTag(nsIAtom* aParentTag, nsIAtom* aChildTag) { + MOZ_ASSERT(aParentTag && aChildTag); + nsIParserService* parserService = nsContentUtils::GetParserService(); PRInt32 childTagEnum; // XXX Should this handle #cdata-section too? - if (aChildTag.EqualsLiteral("#text")) { + if (aChildTag == nsGkAtoms::textTagName) { childTagEnum = eHTMLTag_text; - } - else { - childTagEnum = parserService->HTMLStringTagToId(aChildTag); + } else { + childTagEnum = parserService->HTMLAtomTagToId(aChildTag); } - PRInt32 parentTagEnum = parserService->HTMLStringTagToId(aParentTag); + PRInt32 parentTagEnum = parserService->HTMLAtomTagToId(aParentTag); NS_ASSERTION(parentTagEnum < NS_HTML_TAG_MAX, "Fix the caller, this type of node can never contain children."); diff --git a/editor/libeditor/html/nsHTMLEditor.h b/editor/libeditor/html/nsHTMLEditor.h index f01ede53a5df..a1f549af7c96 100644 --- a/editor/libeditor/html/nsHTMLEditor.h +++ b/editor/libeditor/html/nsHTMLEditor.h @@ -324,7 +324,7 @@ public: NS_IMETHOD EndOperation(); /** returns true if aParentTag can contain a child of type aChildTag */ - virtual bool TagCanContainTag(const nsAString& aParentTag, const nsAString& aChildTag); + virtual bool TagCanContainTag(nsIAtom* aParentTag, nsIAtom* aChildTag); /** returns true if aNode is a container */ virtual bool IsContainer(nsINode* aNode); diff --git a/editor/libeditor/html/nsHTMLEditorStyle.cpp b/editor/libeditor/html/nsHTMLEditorStyle.cpp index 6eccc3f9154f..0bf855f54877 100644 --- a/editor/libeditor/html/nsHTMLEditorStyle.cpp +++ b/editor/libeditor/html/nsHTMLEditorStyle.cpp @@ -278,9 +278,9 @@ nsHTMLEditor::SetInlinePropertyOnTextNode( nsIDOMCharacterData *aTextNode, nsresult res = aTextNode->GetParentNode(getter_AddRefs(parent)); NS_ENSURE_SUCCESS(res, res); - nsAutoString tagString; - aProperty->ToString(tagString); - if (!CanContainTag(parent, tagString)) return NS_OK; + if (!CanContainTag(parent, aProperty)) { + return NS_OK; + } // don't need to do anything if no characters actually selected if (aStartOffset == aEndOffset) return NS_OK; @@ -370,7 +370,7 @@ nsHTMLEditor::SetInlinePropertyOnNodeImpl(nsIDOMNode *aNode, // If this is an element that can't be contained in a span, we have to // recurse to its children. - if (!TagCanContain(NS_LITERAL_STRING("span"), aNode)) { + if (!TagCanContain(nsGkAtoms::span, aNode)) { nsCOMPtr childNodes; res = aNode->GetChildNodes(getter_AddRefs(childNodes)); NS_ENSURE_SUCCESS(res, res); @@ -1454,9 +1454,9 @@ nsHTMLEditor::RelativeFontChange( PRInt32 aSizeChange) NS_ENSURE_SUCCESS(res, res); selectedNode = parent; } - nsAutoString tag; - atom->ToString(tag); - if (!CanContainTag(selectedNode, tag)) return NS_OK; + if (!CanContainTag(selectedNode, atom)) { + return NS_OK; + } // manipulating text attributes on a collapsed selection only sets state for the next text insertion return mTypeInState->SetProp(atom, EmptyString(), EmptyString()); @@ -1599,7 +1599,9 @@ nsHTMLEditor::RelativeFontChangeOnTextNode( PRInt32 aSizeChange, nsCOMPtr parent; res = aTextNode->GetParentNode(getter_AddRefs(parent)); NS_ENSURE_SUCCESS(res, res); - if (!CanContainTag(parent, NS_LITERAL_STRING("big"))) return NS_OK; + if (!CanContainTag(parent, nsGkAtoms::big)) { + return NS_OK; + } nsCOMPtr tmp, node = do_QueryInterface(aTextNode); @@ -1730,9 +1732,12 @@ nsHTMLEditor::RelativeFontChangeOnNode( PRInt32 aSizeChange, nsresult res = NS_OK; nsCOMPtr tmp; - nsAutoString tag; - if (aSizeChange == 1) tag.AssignLiteral("big"); - else tag.AssignLiteral("small"); + nsIAtom* atom; + if (aSizeChange == 1) { + atom = nsGkAtoms::big; + } else { + atom = nsGkAtoms::small; + } // is it the opposite of what we want? if ( ((aSizeChange == 1) && nsHTMLEditUtils::IsSmall(aNode)) || @@ -1746,8 +1751,7 @@ nsHTMLEditor::RelativeFontChangeOnNode( PRInt32 aSizeChange, return res; } // can it be put inside a "big" or "small"? - if (TagCanContain(tag, aNode)) - { + if (TagCanContain(atom, aNode)) { // first populate any nested font tags that have the size attr set res = RelativeFontChangeHelper(aSizeChange, aNode); NS_ENSURE_SUCCESS(res, res); @@ -1771,7 +1775,7 @@ nsHTMLEditor::RelativeFontChangeOnNode( PRInt32 aSizeChange, return res; } // else insert it above aNode - res = InsertContainerAbove(aNode, address_of(tmp), tag); + res = InsertContainerAbove(aNode, address_of(tmp), nsAtomString(atom)); return res; } // none of the above? then cycle through the children. diff --git a/editor/libeditor/text/nsPlaintextEditor.cpp b/editor/libeditor/text/nsPlaintextEditor.cpp index 818398c0bedf..9701746a8370 100644 --- a/editor/libeditor/text/nsPlaintextEditor.cpp +++ b/editor/libeditor/text/nsPlaintextEditor.cpp @@ -884,8 +884,9 @@ NS_IMETHODIMP nsPlaintextEditor::InsertLineBreak() NS_ENSURE_SUCCESS(res, res); // don't put text in places that can't have it - if (!IsTextNode(selNode) && !CanContainTag(selNode, NS_LITERAL_STRING("#text"))) + if (!IsTextNode(selNode) && !CanContainTag(selNode, nsGkAtoms::textTagName)) { return NS_ERROR_FAILURE; + } // we need to get the doc nsCOMPtr doc = GetDOMDocument(); diff --git a/editor/libeditor/text/nsTextEditRules.cpp b/editor/libeditor/text/nsTextEditRules.cpp index 91e5542257bd..ef326b6da662 100644 --- a/editor/libeditor/text/nsTextEditRules.cpp +++ b/editor/libeditor/text/nsTextEditRules.cpp @@ -707,8 +707,10 @@ nsTextEditRules::WillInsertText(PRInt32 aAction, NS_ENSURE_SUCCESS(res, res); // don't put text in places that can't have it - if (!mEditor->IsTextNode(selNode) && !mEditor->CanContainTag(selNode, NS_LITERAL_STRING("#text"))) + if (!mEditor->IsTextNode(selNode) && + !mEditor->CanContainTag(selNode, nsGkAtoms::textTagName)) { return NS_ERROR_FAILURE; + } // we need to get the doc nsCOMPtr doc = mEditor->GetDOMDocument(); From 4caeecec31b334008c77c08369d994bf1e869129 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 1 May 2012 11:06:23 +0100 Subject: [PATCH 123/159] bug 749658 - test for unwanted tab-strip overflow. r=roc --- browser/components/tabview/test/Makefile.in | 1 + .../tabview/test/browser_tabview_bug749658.js | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 browser/components/tabview/test/browser_tabview_bug749658.js diff --git a/browser/components/tabview/test/Makefile.in b/browser/components/tabview/test/Makefile.in index 25ee5a1c375e..66cea9aabd34 100644 --- a/browser/components/tabview/test/Makefile.in +++ b/browser/components/tabview/test/Makefile.in @@ -173,6 +173,7 @@ _BROWSER_FILES = \ browser_tabview_bug716880.js \ browser_tabview_bug728887.js \ browser_tabview_bug733115.js \ + browser_tabview_bug749658.js \ browser_tabview_click_group.js \ browser_tabview_dragdrop.js \ browser_tabview_exit_button.js \ diff --git a/browser/components/tabview/test/browser_tabview_bug749658.js b/browser/components/tabview/test/browser_tabview_bug749658.js new file mode 100644 index 000000000000..a0716aa5355c --- /dev/null +++ b/browser/components/tabview/test/browser_tabview_bug749658.js @@ -0,0 +1,26 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +let win; + +function test() { + waitForExplicitFinish(); + + newWindowWithTabView(function(newWin) { + win = newWin; + + registerCleanupFunction(function() { + win.close(); + }); + + is(win.gBrowser.tabContainer.getAttribute("overflow"), "", + "The tabstrip should not be overflowing"); + + finish(); + }, function(newWin) { + /* add a tab with a ridiculously long title to trigger bug 749658 */ + var longTitle = "this is a very long title for the new tab "; + longTitle = longTitle + longTitle + longTitle + longTitle + longTitle; + longTitle = longTitle + longTitle + longTitle + longTitle + longTitle; + newWin.gBrowser.addTab("data:text/html," + longTitle); + }); +} From 3899208e5a9109cb3e55f2fdb18d90cee84e47bc Mon Sep 17 00:00:00 2001 From: Jonathan Kew <jkew@mozilla.com> Date: Tue, 1 May 2012 11:06:47 +0100 Subject: [PATCH 124/159] bug 749658 - reftest for unwanted scroll-overflow due to cropped textbox label. r=roc --- layout/reftests/xul/reftest.list | 1 + layout/reftests/xul/textbox-overflow-1-ref.xul | 10 ++++++++++ layout/reftests/xul/textbox-overflow-1.xul | 10 ++++++++++ 3 files changed, 21 insertions(+) create mode 100644 layout/reftests/xul/textbox-overflow-1-ref.xul create mode 100644 layout/reftests/xul/textbox-overflow-1.xul diff --git a/layout/reftests/xul/reftest.list b/layout/reftests/xul/reftest.list index b648b76e854d..d7a8ce253c5c 100644 --- a/layout/reftests/xul/reftest.list +++ b/layout/reftests/xul/reftest.list @@ -1,3 +1,4 @@ == menuitem-key.xul menuitem-key-ref.xul == menulist-shrinkwrap-1.xul menulist-shrinkwrap-1-ref.xul fails-if(Android) fails-if(winWidget) == menulist-shrinkwrap-2.xul menulist-shrinkwrap-2-ref.xul +== textbox-overflow-1.xul textbox-overflow-1-ref.xul # for bug 749658 diff --git a/layout/reftests/xul/textbox-overflow-1-ref.xul b/layout/reftests/xul/textbox-overflow-1-ref.xul new file mode 100644 index 000000000000..d6d3a53761fb --- /dev/null +++ b/layout/reftests/xul/textbox-overflow-1-ref.xul @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- bug 749658 - The cropped label should *not* cause a scroll bar to appear. + If it does, the scrollbars in the testcase and reference will differ + because the total scroll-overflow extent will be different. --> +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="left"> + <hbox width="150px" style="overflow: scroll"> + <label value="A very long label for a small item" + width="120px" crop="right"/> + </hbox> +</window> diff --git a/layout/reftests/xul/textbox-overflow-1.xul b/layout/reftests/xul/textbox-overflow-1.xul new file mode 100644 index 000000000000..431d29ba8621 --- /dev/null +++ b/layout/reftests/xul/textbox-overflow-1.xul @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- bug 749658 - The cropped label should *not* cause a scroll bar to appear. + If it does, the scrollbars in the testcase and reference will differ + because the total scroll-overflow extent will be different. --> +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" align="left"> + <hbox width="150px" style="overflow: scroll"> + <label value="A very long label for a small item that should not trigger a scroll bar" + width="120px" crop="right"/> + </hbox> +</window> From 6e994932ac947427d48cdb6918bd9da1449b271f Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Tue, 1 May 2012 10:58:11 -0400 Subject: [PATCH 125/159] Bug 750728 - Disable Graphite for now to see if it helps with PGO Windows builds; r=ted CLOSED TREE --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 04424af366c1..21e0f9ea2bae 100644 --- a/configure.in +++ b/configure.in @@ -4610,7 +4610,7 @@ BUILD_CTYPES=1 MOZ_USE_NATIVE_POPUP_WINDOWS= MOZ_ANDROID_HISTORY= MOZ_WEBSMS_BACKEND= -MOZ_GRAPHITE=1 +MOZ_GRAPHITE= ACCESSIBILITY=1 case "$target_os" in From 027db3afd85d06bdfda4abb65b9ddd74258a8d4e Mon Sep 17 00:00:00 2001 From: Ed Morley <emorley@mozilla.com> Date: Tue, 1 May 2012 17:09:44 +0100 Subject: [PATCH 126/159] Bug 750717 - Output linker max virtual size using 'TinderboxPrint' so it appears in the TBPL summary; r=ted CLOSED TREE --- build/link.py | 158 +++++++++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/build/link.py b/build/link.py index 740b641ad98e..ac5e91b11787 100644 --- a/build/link.py +++ b/build/link.py @@ -1,79 +1,79 @@ -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is cl.py: a python wrapper for cl to automatically generate -# dependency information. -# -# The Initial Developer of the Original Code is -# Mozilla Foundation. -# Portions created by the Initial Developer are Copyright (C) 2010 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Ted Mielczarek <ted@mielczarek.org> -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** - -from __future__ import with_statement -import os, platform, subprocess, sys, threading, time -from win32 import procmem - -def measure_vsize_threadfunc(proc, output_file): - """ - Measure the virtual memory usage of |proc| at regular intervals - until it exits, then print the maximum value and write it to - |output_file|. - """ - maxvsize = 0 - while proc.returncode is None: - maxvsize, vsize = procmem.get_vmsize(proc._handle) - time.sleep(0.5) - print "linker max virtual size: %d" % maxvsize - with open(output_file, "w") as f: - f.write("%d\n" % maxvsize) - -def measure_link_vsize(output_file, args): - """ - Execute |args|, and measure the maximum virtual memory usage of the process, - printing it to stdout when finished. - """ - proc = subprocess.Popen(args) - t = threading.Thread(target=measure_vsize_threadfunc, - args=(proc, output_file)) - t.start() - # Wait for the linker to finish. - exitcode = proc.wait() - # ...and then wait for the background thread to finish. - t.join() - return exitcode - -if __name__ == "__main__": - if platform.system() != "Windows": - print >>sys.stderr, "link.py is only for use on Windows!" - sys.exit(1) - if len(sys.argv) < 3: - print >>sys.stderr, "Usage: link.py <output filename> <commandline>" - sys.exit(1) - sys.exit(measure_link_vsize(sys.argv[1], sys.argv[2:])) +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is cl.py: a python wrapper for cl to automatically generate +# dependency information. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2010 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Ted Mielczarek <ted@mielczarek.org> +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +from __future__ import with_statement +import os, platform, subprocess, sys, threading, time +from win32 import procmem + +def measure_vsize_threadfunc(proc, output_file): + """ + Measure the virtual memory usage of |proc| at regular intervals + until it exits, then print the maximum value and write it to + |output_file|. + """ + maxvsize = 0 + while proc.returncode is None: + maxvsize, vsize = procmem.get_vmsize(proc._handle) + time.sleep(0.5) + print "TinderboxPrint: linker max vsize: %d" % maxvsize + with open(output_file, "w") as f: + f.write("%d\n" % maxvsize) + +def measure_link_vsize(output_file, args): + """ + Execute |args|, and measure the maximum virtual memory usage of the process, + printing it to stdout when finished. + """ + proc = subprocess.Popen(args) + t = threading.Thread(target=measure_vsize_threadfunc, + args=(proc, output_file)) + t.start() + # Wait for the linker to finish. + exitcode = proc.wait() + # ...and then wait for the background thread to finish. + t.join() + return exitcode + +if __name__ == "__main__": + if platform.system() != "Windows": + print >>sys.stderr, "link.py is only for use on Windows!" + sys.exit(1) + if len(sys.argv) < 3: + print >>sys.stderr, "Usage: link.py <output filename> <commandline>" + sys.exit(1) + sys.exit(measure_link_vsize(sys.argv[1], sys.argv[2:])) From c425367f588e02161403d5ab6f1fa5cbe3624033 Mon Sep 17 00:00:00 2001 From: Sriram Ramasubramanian <sriram@mozilla.com> Date: Tue, 1 May 2012 10:50:27 -0700 Subject: [PATCH 127/159] Bug 747419: Optimize TabsTray rows inflation using ViewHolder pattern [r=lucasr, a=android-only] --HG-- extra : rebase_source : b93eb7463623d5b916590fd9a0367f2ccb6dea36 --- mobile/android/base/TabsTray.java | 90 +++++++++++++++++++------------ 1 file changed, 57 insertions(+), 33 deletions(-) diff --git a/mobile/android/base/TabsTray.java b/mobile/android/base/TabsTray.java index ef0de8bc5944..96663ae796ab 100644 --- a/mobile/android/base/TabsTray.java +++ b/mobile/android/base/TabsTray.java @@ -66,7 +66,8 @@ public class TabsTray extends GeckoActivity implements Tabs.OnTabsChangedListene mList.setRecyclerListener(new RecyclerListener() { @Override public void onMovedToScrapHeap(View view) { - ((ImageView) view.findViewById(R.id.thumbnail)).setImageDrawable(null); + TabRow row = (TabRow) view.getTag(); + row.thumbnail.setImageDrawable(null); } }); @@ -166,7 +167,11 @@ public class TabsTray extends GeckoActivity implements Tabs.OnTabsChangedListene mListContainer.requestLayout(); } else { View view = mList.getChildAt(position - mList.getFirstVisiblePosition()); - mTabsAdapter.assignValues(view, tab); + if (view == null) + return; + + TabRow row = (TabRow) view.getTag(); + mTabsAdapter.assignValues(row, tab); } } @@ -213,8 +218,30 @@ public class TabsTray extends GeckoActivity implements Tabs.OnTabsChangedListene } } + // ViewHolder for a row in the list + private class TabRow { + int id; + TextView title; + ImageView thumbnail; + ImageView selectedIndicator; + ImageButton close; + + public TabRow(View view) { + title = (TextView) view.findViewById(R.id.title); + thumbnail = (ImageView) view.findViewById(R.id.thumbnail); + selectedIndicator = (ImageView) view.findViewById(R.id.selected_indicator); + close = (ImageButton) view.findViewById(R.id.close); + } + } + // Adapter to bind tabs into a list private class TabsAdapter extends BaseAdapter { + private Context mContext; + private ArrayList<Tab> mTabs; + private LayoutInflater mInflater; + private View.OnClickListener mOnInfoClickListener; + private Button.OnClickListener mOnCloseClickListener; + public TabsAdapter(Context context, ArrayList<Tab> tabs) { mContext = context; mInflater = LayoutInflater.from(mContext); @@ -229,7 +256,7 @@ public class TabsTray extends GeckoActivity implements Tabs.OnTabsChangedListene mOnInfoClickListener = new View.OnClickListener() { public void onClick(View v) { - Tabs.getInstance().selectTab(Integer.parseInt((String) v.getTag())); + Tabs.getInstance().selectTab(((TabRow) v.getTag()).id); finishActivity(); } }; @@ -272,45 +299,48 @@ public class TabsTray extends GeckoActivity implements Tabs.OnTabsChangedListene mTabs.remove(tab); } - public void assignValues(View view, Tab tab) { - if (view == null || tab == null) + public void assignValues(TabRow row, Tab tab) { + if (row == null || tab == null) return; - ImageView thumbnail = (ImageView) view.findViewById(R.id.thumbnail); + row.id = tab.getId(); Drawable thumbnailImage = tab.getThumbnail(); if (thumbnailImage != null) - thumbnail.setImageDrawable(thumbnailImage); + row.thumbnail.setImageDrawable(thumbnailImage); else if (TextUtils.equals(tab.getURL(), ABOUT_HOME)) - thumbnail.setImageResource(R.drawable.abouthome_thumbnail); + row.thumbnail.setImageResource(R.drawable.abouthome_thumbnail); else - thumbnail.setImageResource(R.drawable.tab_thumbnail_default); + row.thumbnail.setImageResource(R.drawable.tab_thumbnail_default); if (Tabs.getInstance().isSelectedTab(tab)) - ((ImageView) view.findViewById(R.id.selected_indicator)).setVisibility(View.VISIBLE); + row.selectedIndicator.setVisibility(View.VISIBLE); + else + row.selectedIndicator.setVisibility(View.GONE); - TextView title = (TextView) view.findViewById(R.id.title); - title.setText(tab.getDisplayTitle()); + row.title.setText(tab.getDisplayTitle()); + + row.close.setTag(String.valueOf(row.id)); + row.close.setVisibility(mTabs.size() > 1 ? View.VISIBLE : View.GONE); } public View getView(int position, View convertView, ViewGroup parent) { - convertView = mInflater.inflate(R.layout.tabs_row, null); + TabRow row; + + if (convertView == null) { + convertView = mInflater.inflate(R.layout.tabs_row, null); + convertView.setOnClickListener(mOnInfoClickListener); + + row = new TabRow(convertView); + row.close.setOnClickListener(mOnCloseClickListener); + + convertView.setTag(row); + } else { + row = (TabRow) convertView.getTag(); + } Tab tab = mTabs.get(position); - - RelativeLayout info = (RelativeLayout) convertView.findViewById(R.id.info); - info.setTag(String.valueOf(tab.getId())); - info.setOnClickListener(mOnInfoClickListener); - - assignValues(convertView, tab); - - ImageButton close = (ImageButton) convertView.findViewById(R.id.close); - if (mTabs.size() > 1) { - close.setTag(String.valueOf(tab.getId())); - close.setOnClickListener(mOnCloseClickListener); - } else { - close.setVisibility(View.GONE); - } + assignValues(row, tab); return convertView; } @@ -322,11 +352,5 @@ public class TabsTray extends GeckoActivity implements Tabs.OnTabsChangedListene @Override public void notifyDataSetInvalidated() { } - - private Context mContext; - private ArrayList<Tab> mTabs; - private LayoutInflater mInflater; - private View.OnClickListener mOnInfoClickListener; - private Button.OnClickListener mOnCloseClickListener; } } From 809d68efea037ad535c7ff5e6416b39dd901f006 Mon Sep 17 00:00:00 2001 From: Jonathan Kew <jkew@mozilla.com> Date: Tue, 1 May 2012 20:00:35 +0100 Subject: [PATCH 128/159] bug 750728 - move graphite from libxul to libgkmedias on windows, to help with PGO problems. r=khuey a=ehsan to land on a CLOSED TREE --- configure.in | 2 +- gfx/graphite2/src/Makefile.in | 16 +++++++++++++--- layout/media/Makefile.in | 4 ++++ toolkit/library/Makefile.in | 4 ---- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/configure.in b/configure.in index 21e0f9ea2bae..04424af366c1 100644 --- a/configure.in +++ b/configure.in @@ -4610,7 +4610,7 @@ BUILD_CTYPES=1 MOZ_USE_NATIVE_POPUP_WINDOWS= MOZ_ANDROID_HISTORY= MOZ_WEBSMS_BACKEND= -MOZ_GRAPHITE= +MOZ_GRAPHITE=1 ACCESSIBILITY=1 case "$target_os" in diff --git a/gfx/graphite2/src/Makefile.in b/gfx/graphite2/src/Makefile.in index bb6b12ec9086..fba914e5e18a 100644 --- a/gfx/graphite2/src/Makefile.in +++ b/gfx/graphite2/src/Makefile.in @@ -56,7 +56,13 @@ include $(srcdir)/files.mk MODULE = graphite2 LIBRARY_NAME = mozgraphite2 + +# on Windows, we're going to link graphite with gkmedias instead of libxul +ifeq (WINNT,$(OS_TARGET)) +VISIBILITY_FLAGS = +else LIBXUL_LIBRARY = 1 +endif # MSVC doesn't like the paths in _SOURCES, so strip off the prefix # and leave bare filenames @@ -68,6 +74,13 @@ EXPORTS_graphite2 = $(_PUBLIC_HEADERS) FORCE_STATIC_LIB = 1 FORCE_USE_PIC = 1 +ifeq (WINNT,$(OS_TARGET)) +DEFINES += -DGRAPHITE2_EXPORTING +else +# tell graphite2 not to export symbols, we'll be linking it directly with thebes +DEFINES += -DGRAPHITE2_STATIC +endif + include $(topsrcdir)/config/rules.mk DEFINES += -DPACKAGE_VERSION="\"moz\"" @@ -76,9 +89,6 @@ DEFINES += -DPACKAGE_BUGREPORT="\"http://bugzilla.mozilla.org/\"" # disable features we don't need in the graphite2 code, to reduce code size DEFINES += -DGRAPHITE2_NFILEFACE -DGRAPHITE2_NTRACING -DGRAPHITE2_NSEGCACHE -# tell graphite2 not to export symbols, we'll be linking it directly with thebes -DEFINES += -DGRAPHITE2_STATIC - # provide a custom header that overrides malloc() and friends, # to ensure safe OOM handling DEFINES += -DGRAPHITE2_CUSTOM_HEADER="\"MozGrMalloc.h\"" diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index 1e5d3fed59d1..190b6b2c4ac7 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -51,6 +51,10 @@ endif SHARED_LIBRARY_LIBS = $(MOZ_OTS_LIBS) +ifdef MOZ_GRAPHITE +SHARED_LIBRARY_LIBS += $(MOZ_GRAPHITE_LIBS) +endif + ifdef MOZ_VORBIS SHARED_LIBRARY_LIBS += \ $(DEPTH)/media/libvorbis/lib/$(LIB_PREFIX)vorbis.$(LIB_SUFFIX) \ diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index 89b0b7dbd2d5..a627e1fde096 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -344,10 +344,6 @@ EXTRA_DSO_LDOPTS += \ $(SQLITE_LIBS) \ $(NULL) -ifdef MOZ_GRAPHITE -EXTRA_DSO_LDOPTS += $(MOZ_GRAPHITE_LIBS) -endif - ifdef MOZ_NATIVE_ZLIB EXTRA_DSO_LDOPTS += $(ZLIB_LIBS) else From b48fb8b460c4c5f589f65c2afcae49313a7b3a7f Mon Sep 17 00:00:00 2001 From: Josh Aas <joshmoz@gmail.com> Date: Tue, 1 May 2012 16:47:35 -0400 Subject: [PATCH 129/159] Bug 748343: Remove support for "java" and "packages" objects from the DOM. r=jst sr=smaug a=ehsan CLOSED TREE --- dom/base/nsDOMClassInfo.cpp | 35 +-- dom/base/nsGlobalWindow.cpp | 271 --------------------- dom/base/nsGlobalWindow.h | 11 - dom/base/nsPIDOMWindow.h | 11 +- dom/plugins/base/nsNPAPIPluginInstance.cpp | 57 ----- dom/plugins/base/nsNPAPIPluginInstance.h | 1 - dom/plugins/base/nsPluginHost.cpp | 51 +--- dom/plugins/base/nsPluginHost.h | 1 - dom/plugins/base/nsPluginTags.cpp | 8 +- dom/plugins/base/nsPluginTags.h | 1 - 10 files changed, 19 insertions(+), 428 deletions(-) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 60c418950a96..466d561297d7 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1779,8 +1779,6 @@ jsid nsDOMClassInfo::sAddEventListener_id= JSID_VOID; jsid nsDOMClassInfo::sBaseURIObject_id = JSID_VOID; jsid nsDOMClassInfo::sNodePrincipal_id = JSID_VOID; jsid nsDOMClassInfo::sDocumentURIObject_id=JSID_VOID; -jsid nsDOMClassInfo::sJava_id = JSID_VOID; -jsid nsDOMClassInfo::sPackages_id = JSID_VOID; jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID; jsid nsDOMClassInfo::sURL_id = JSID_VOID; jsid nsDOMClassInfo::sKeyPath_id = JSID_VOID; @@ -2051,8 +2049,6 @@ nsDOMClassInfo::DefineStaticJSVals(JSContext *cx) SET_JSID_TO_STRING(sBaseURIObject_id, cx, "baseURIObject"); SET_JSID_TO_STRING(sNodePrincipal_id, cx, "nodePrincipal"); SET_JSID_TO_STRING(sDocumentURIObject_id,cx,"documentURIObject"); - SET_JSID_TO_STRING(sJava_id, cx, "java"); - SET_JSID_TO_STRING(sPackages_id, cx, "Packages"); SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject"); SET_JSID_TO_STRING(sURL_id, cx, "URL"); SET_JSID_TO_STRING(sKeyPath_id, cx, "keyPath"); @@ -5155,8 +5151,6 @@ nsDOMClassInfo::ShutDown() sBaseURIObject_id = JSID_VOID; sNodePrincipal_id = JSID_VOID; sDocumentURIObject_id=JSID_VOID; - sJava_id = JSID_VOID; - sPackages_id = JSID_VOID; sWrappedJSObject_id = JSID_VOID; sKeyPath_id = JSID_VOID; sAutoIncrement_id = JSID_VOID; @@ -7294,34 +7288,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_OK; } - if (id == sJava_id || id == sPackages_id) { - static bool isResolvingJavaProperties; - - if (!isResolvingJavaProperties) { - isResolvingJavaProperties = true; - - // Tell the window to initialize the Java properties. The - // window needs to do this as we need to do this only once, - // and detecting that reliably from here is hard. - - win->InitJavaProperties(); - - JSBool hasProp; - bool ok = ::JS_HasPropertyById(cx, obj, id, &hasProp); - - isResolvingJavaProperties = false; - - if (!ok) { - return NS_ERROR_FAILURE; - } - - if (hasProp) { - *objp = obj; - - return NS_OK; - } - } - } else if (id == sDialogArguments_id && win->IsModalContentWindow()) { + if (id == sDialogArguments_id && win->IsModalContentWindow()) { nsCOMPtr<nsIArray> args; ((nsGlobalModalWindow *)win)->GetDialogArguments(getter_AddRefs(args)); diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 33e31ca833e9..9cf5873154e5 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -452,195 +452,6 @@ static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID; #endif static const char sPopStatePrefStr[] = "browser.history.allowPopState"; -class nsDummyJavaPluginOwner : public nsIPluginInstanceOwner -{ -public: - nsDummyJavaPluginOwner(nsIDocument *aDocument) - : mDocument(aDocument) - { - } - - void Destroy(); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_NSIPLUGININSTANCEOWNER - - NS_IMETHOD GetURL(const char *aURL, const char *aTarget, - nsIInputStream *aPostStream, - void *aHeadersData, PRUint32 aHeadersDataLen); - NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg); - NPError ShowNativeContextMenu(NPMenu* menu, void* event); - NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, - double *destX, double *destY, NPCoordinateSpace destSpace); - void SendIdleEvent(); - - NPError InitAsyncSurface(NPSize *size, NPImageFormat format, - void *initData, NPAsyncSurface *surface) - { return NPERR_GENERIC_ERROR; } - - NPError FinalizeAsyncSurface(NPAsyncSurface *surface) { return NPERR_GENERIC_ERROR; } - void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) { return; } - - NS_DECL_CYCLE_COLLECTION_CLASS(nsDummyJavaPluginOwner) - -private: - nsRefPtr<nsNPAPIPluginInstance> mInstance; - nsCOMPtr<nsIDocument> mDocument; -}; - -NS_IMPL_CYCLE_COLLECTION_2(nsDummyJavaPluginOwner, mDocument, mInstance) - -// QueryInterface implementation for nsDummyJavaPluginOwner -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDummyJavaPluginOwner) - NS_INTERFACE_MAP_ENTRY(nsISupports) - NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDummyJavaPluginOwner) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDummyJavaPluginOwner) - - -void -nsDummyJavaPluginOwner::Destroy() -{ - // If we have a plugin instance, stop it and destroy it now. - if (mInstance) { - mInstance->Stop(); - mInstance->InvalidateOwner(); - mInstance = nsnull; - } - - mDocument = nsnull; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::SetInstance(nsNPAPIPluginInstance *aInstance) -{ - // If we're going to null out mInstance after use, be sure to call - // mInstance->InvalidateOwner() here, since it now won't be called - // from nsDummyJavaPluginOwner::Destroy(). - if (mInstance && !aInstance) - mInstance->InvalidateOwner(); - - mInstance = aInstance; - - return NS_OK; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::GetInstance(nsNPAPIPluginInstance **aInstance) -{ - *aInstance = mInstance; - NS_IF_ADDREF(*aInstance); - - return NS_OK; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::GetWindow(NPWindow *&aWindow) -{ - aWindow = nsnull; - - return NS_OK; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::CallSetWindow() -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::GetMode(PRInt32 *aMode) -{ - // This is wrong, but there's no better alternative. - *aMode = NP_EMBED; - - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::CreateWidget(void) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::GetURL(const char *aURL, const char *aTarget, - nsIInputStream *aPostStream, - void *aHeadersData, PRUint32 aHeadersDataLen) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::ShowStatus(const char *aStatusMsg) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::ShowStatus(const PRUnichar *aStatusMsg) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NPError -nsDummyJavaPluginOwner::ShowNativeContextMenu(NPMenu* menu, void* event) -{ - return NPERR_GENERIC_ERROR; -} - -NPBool -nsDummyJavaPluginOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, - double *destX, double *destY, NPCoordinateSpace destSpace) -{ - return false; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::GetDocument(nsIDocument **aDocument) -{ - NS_IF_ADDREF(*aDocument = mDocument); - - return NS_OK; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::InvalidateRect(NPRect *invalidRect) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::InvalidateRegion(NPRegion invalidRegion) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::RedrawPlugin() -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::GetNetscapeWindow(void *value) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDummyJavaPluginOwner::SetEventModel(PRInt32 eventModel) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -void -nsDummyJavaPluginOwner::SendIdleEvent() -{ -} - /** * An object implementing the window.URL property. */ @@ -858,7 +669,6 @@ NewOuterWindowProxy(JSContext *cx, JSObject *parent) nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) : nsPIDOMWindow(aOuterWindow), mIsFrozen(false), - mDidInitJavaProperties(false), mFullScreen(false), mIsClosed(false), mInClose(false), @@ -1366,17 +1176,6 @@ nsGlobalWindow::FreeInnerObjects() js::DontNukeForGlobalObject); } - if (mDummyJavaPluginOwner) { - // Tear down the dummy java plugin. - - // XXXjst: On a general note, should windows with java stuff in - // them ever even make it into the fast-back cache? - - mDummyJavaPluginOwner->Destroy(); - mDummyJavaPluginOwner = nsnull; - mDidInitJavaProperties = false; - } - CleanupCachedXBLHandlers(this); #ifdef DEBUG @@ -1500,9 +1299,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGlobalWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFrameElement) - // Traverse mDummyJavaPluginOwner - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDummyJavaPluginOwner) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFocusedNode) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPendingStorageEvents) @@ -1538,13 +1334,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFrameElement) - // Unlink mDummyJavaPluginOwner - if (tmp->mDummyJavaPluginOwner) { - tmp->mDummyJavaPluginOwner->Destroy(); - NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDummyJavaPluginOwner) - tmp->mDidInitJavaProperties = false; - } - NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFocusedNode) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPendingStorageEvents) @@ -2297,16 +2086,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, // XXXmarkh - tell other languages about this? ::JS_DeleteProperty(cx, currentInner->mJSObject, "document"); - - if (mDummyJavaPluginOwner) { - // Since we're reusing the inner window, tear down the - // dummy Java plugin we created for the old document in - // this window. - mDummyJavaPluginOwner->Destroy(); - mDummyJavaPluginOwner = nsnull; - - mDidInitJavaProperties = false; - } } } else { rv = newInnerWindow->InnerSetNewDocument(aDocument); @@ -6925,56 +6704,6 @@ nsGlobalWindow::NotifyDOMWindowThawed(nsGlobalWindow* aWindow) { } } -void -nsGlobalWindow::InitJavaProperties() -{ - nsIScriptContext *scx = GetContextInternal(); - - if (mDidInitJavaProperties || IsOuterWindow() || !scx || !mJSObject) { - return; - } - - // Set mDidInitJavaProperties to true here even if initialization - // can fail. If it fails, we won't try again... - mDidInitJavaProperties = true; - - mDummyJavaPluginOwner = new nsDummyJavaPluginOwner(mDoc); - if (!mDummyJavaPluginOwner) { - return; - } - - nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); - nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get()); - if (!pluginHost) { - return; - } - pluginHost->InstantiateDummyJavaPlugin(mDummyJavaPluginOwner); - - // It's possible for us (or the Java plugin, rather) to process - // events during the above call, which can lead to this window being - // torn down or what not, so re-check that the dummy plugin is still - // around. - if (!mDummyJavaPluginOwner) { - return; - } - - nsRefPtr<nsNPAPIPluginInstance> dummyPlugin; - mDummyJavaPluginOwner->GetInstance(getter_AddRefs(dummyPlugin)); - - if (dummyPlugin) { - // A dummy plugin was instantiated. This means we have a Java - // plugin that supports NPRuntime. For such a plugin, the plugin - // instantiation code defines the Java properties for us, so we're - // done here. - - return; - } - - // No NPRuntime enabled Java plugin found, null out the owner we - // would have used in that case as it's no longer needed. - mDummyJavaPluginOwner = nsnull; -} - JSObject* nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey) { diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index fcc0cad79794..d2d272fe8d97 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -130,7 +130,6 @@ class nsIDocShellLoadInfo; class WindowStateHolder; class nsGlobalWindowObserver; class nsGlobalWindow; -class nsDummyJavaPluginOwner; class PostMessageEvent; class nsRunnable; class nsDOMEventTargetHelper; @@ -493,8 +492,6 @@ public: NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsGlobalWindow, nsIScriptGlobalObject) - void InitJavaProperties(); - virtual NS_HIDDEN_(JSObject*) GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey); @@ -825,10 +822,6 @@ protected: // where we don't want to force creation of a new inner window since // we're in the middle of doing just that. bool mIsFrozen : 1; - - // True if the Java properties have been initialized on this - // window. Only used on inner windows. - bool mDidInitJavaProperties : 1; // These members are only used on outer window objects. Make sure // you never set any of these on an inner object! @@ -929,10 +922,6 @@ protected: nsRefPtr<nsLocation> mLocation; nsRefPtr<nsHistory> mHistory; - // Holder of the dummy java plugin, used to expose window.java and - // window.packages. - nsRefPtr<nsDummyJavaPluginOwner> mDummyJavaPluginOwner; - // These member variables are used on both inner and the outer windows. nsCOMPtr<nsIPrincipal> mDocumentPrincipal; nsCOMPtr<nsIDocument> mDoc; // For fast access to principals diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index e7faf252e00b..87310565c335 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -80,8 +80,8 @@ class nsIArray; class nsPIWindowRoot; #define NS_PIDOMWINDOW_IID \ -{ 0x9aef58e9, 0x5225, 0x4e58, \ - { 0x9a, 0xfb, 0xe6, 0x63, 0x97, 0x1d, 0x86, 0x88 } } +{ 0x7a6238d4, 0x7cbc, 0x43b2, \ + { 0x86, 0x68, 0x92, 0xeb, 0x9e, 0xb0, 0x49, 0xaf } } class nsPIDOMWindow : public nsIDOMWindowInternal { @@ -486,12 +486,7 @@ public: void SetHasMouseEnterLeaveEventListeners() { mMayHaveMouseEnterLeaveEventListener = true; - } - - /** - * Initialize window.java and window.Packages. - */ - virtual void InitJavaProperties() = 0; + } virtual JSObject* GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey) = 0; virtual void CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey, diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 6400042c72de..18a4417af727 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -835,63 +835,6 @@ nsNPAPIPluginInstance::GetJSObject(JSContext *cx, JSObject** outObject) return NS_OK; } -nsresult -nsNPAPIPluginInstance::DefineJavaProperties() -{ - NPObject *plugin_obj = nsnull; - - // The dummy Java plugin's scriptable object is what we want to - // expose as window.Packages. And Window.Packages.java will be - // exposed as window.java. - - // Get the scriptable plugin object. - nsresult rv = GetValueFromPlugin(NPPVpluginScriptableNPObject, &plugin_obj); - - if (NS_FAILED(rv) || !plugin_obj) { - return NS_ERROR_FAILURE; - } - - // Get the NPObject wrapper for window. - NPObject *window_obj = _getwindowobject(&mNPP); - - if (!window_obj) { - _releaseobject(plugin_obj); - - return NS_ERROR_FAILURE; - } - - NPIdentifier java_id = _getstringidentifier("java"); - NPIdentifier packages_id = _getstringidentifier("Packages"); - - NPObject *java_obj = nsnull; - NPVariant v; - OBJECT_TO_NPVARIANT(plugin_obj, v); - - // Define the properties. - - bool ok = _setproperty(&mNPP, window_obj, packages_id, &v); - if (ok) { - ok = _getproperty(&mNPP, plugin_obj, java_id, &v); - - if (ok && NPVARIANT_IS_OBJECT(v)) { - // Set java_obj so that we properly release it at the end of - // this function. - java_obj = NPVARIANT_TO_OBJECT(v); - - ok = _setproperty(&mNPP, window_obj, java_id, &v); - } - } - - _releaseobject(window_obj); - _releaseobject(plugin_obj); - _releaseobject(java_obj); - - if (!ok) - return NS_ERROR_FAILURE; - - return NS_OK; -} - nsresult nsNPAPIPluginInstance::SetCached(bool aCache) { diff --git a/dom/plugins/base/nsNPAPIPluginInstance.h b/dom/plugins/base/nsNPAPIPluginInstance.h index 1bf381b0808a..31164803b1f1 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.h +++ b/dom/plugins/base/nsNPAPIPluginInstance.h @@ -108,7 +108,6 @@ public: nsresult GetDrawingModel(PRInt32* aModel); nsresult IsRemoteDrawingCoreAnimation(bool* aDrawing); nsresult GetJSObject(JSContext *cx, JSObject** outObject); - nsresult DefineJavaProperties(); bool ShouldCache(); nsresult IsWindowless(bool* isWindowless); nsresult AsyncSetWindow(NPWindow* window); diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 2a0573168cbe..a81e8b54d0fc 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -2553,7 +2553,7 @@ nsPluginHost::WritePluginInfo() (tag->mName.get()), PLUGIN_REGISTRY_FIELD_DELIMITER, PLUGIN_REGISTRY_END_OF_LINE_MARKER, - tag->mMimeTypes.Length() + (tag->mIsNPRuntimeEnabledJavaPlugin ? 1 : 0)); + tag->mMimeTypes.Length() + 1); // Add in each mimetype this plugin supports for (PRUint32 i = 0; i < tag->mMimeTypes.Length(); i++) { @@ -2568,17 +2568,17 @@ nsPluginHost::WritePluginInfo() PLUGIN_REGISTRY_END_OF_LINE_MARKER); } - if (tag->mIsNPRuntimeEnabledJavaPlugin) { - PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n", - tag->mMimeTypes.Length(), PLUGIN_REGISTRY_FIELD_DELIMITER, - "application/x-java-vm-npruntime", - PLUGIN_REGISTRY_FIELD_DELIMITER, - "", - PLUGIN_REGISTRY_FIELD_DELIMITER, - "", - PLUGIN_REGISTRY_FIELD_DELIMITER, - PLUGIN_REGISTRY_END_OF_LINE_MARKER); - } + // This used to depend on whether or not we had an npruntime-enabled + // Java plugin but we don't care any more, we just assume we do. + PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n", + tag->mMimeTypes.Length(), PLUGIN_REGISTRY_FIELD_DELIMITER, + "application/x-java-vm-npruntime", + PLUGIN_REGISTRY_FIELD_DELIMITER, + "", + PLUGIN_REGISTRY_FIELD_DELIMITER, + "", + PLUGIN_REGISTRY_FIELD_DELIMITER, + PLUGIN_REGISTRY_END_OF_LINE_MARKER); } } @@ -3666,33 +3666,6 @@ nsPluginHost::NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow) return PLUG_NewPluginNativeWindow(aPluginNativeWindow); } -nsresult -nsPluginHost::InstantiateDummyJavaPlugin(nsIPluginInstanceOwner *aOwner) -{ - // Pass false as the second arg, we want the answer to be the - // same here whether the Java plugin is enabled or not. - nsPluginTag *plugin = FindPluginForType("application/x-java-vm", false); - - if (!plugin || !plugin->mIsNPRuntimeEnabledJavaPlugin) { - // No NPRuntime enabled Java plugin found, no point in - // instantiating a dummy plugin then. - - return NS_OK; - } - - nsresult rv = SetUpPluginInstance("application/x-java-vm", nsnull, aOwner); - NS_ENSURE_SUCCESS(rv, rv); - - nsRefPtr<nsNPAPIPluginInstance> instance; - aOwner->GetInstance(getter_AddRefs(instance)); - if (!instance) - return NS_OK; - - instance->DefineJavaProperties(); - - return NS_OK; -} - nsresult nsPluginHost::GetPluginName(nsNPAPIPluginInstance *aPluginInstance, const char** aPluginName) diff --git a/dom/plugins/base/nsPluginHost.h b/dom/plugins/base/nsPluginHost.h index 2b0838027f0d..1c848a291eb1 100644 --- a/dom/plugins/base/nsPluginHost.h +++ b/dom/plugins/base/nsPluginHost.h @@ -148,7 +148,6 @@ public: char **outPostData, PRUint32 *outPostDataLen); nsresult CreateTempFileToPost(const char *aPostDataURL, nsIFile **aTmpFile); nsresult NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow); - nsresult InstantiateDummyJavaPlugin(nsIPluginInstanceOwner *aOwner); void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, bool isVisible); void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame); diff --git a/dom/plugins/base/nsPluginTags.cpp b/dom/plugins/base/nsPluginTags.cpp index f8d8050be09e..3b7e060fb9bb 100644 --- a/dom/plugins/base/nsPluginTags.cpp +++ b/dom/plugins/base/nsPluginTags.cpp @@ -81,7 +81,6 @@ mMimeDescriptions(aPluginTag->mMimeDescriptions), mExtensions(aPluginTag->mExtensions), mLibrary(nsnull), mIsJavaPlugin(aPluginTag->mIsJavaPlugin), -mIsNPRuntimeEnabledJavaPlugin(aPluginTag->mIsNPRuntimeEnabledJavaPlugin), mIsFlashPlugin(aPluginTag->mIsFlashPlugin), mFileName(aPluginTag->mFileName), mFullPath(aPluginTag->mFullPath), @@ -97,7 +96,6 @@ mName(aPluginInfo->fName), mDescription(aPluginInfo->fDescription), mLibrary(nsnull), mIsJavaPlugin(false), -mIsNPRuntimeEnabledJavaPlugin(false), mIsFlashPlugin(false), mFileName(aPluginInfo->fFileName), mFullPath(aPluginInfo->fFullPath), @@ -128,7 +126,6 @@ mName(aName), mDescription(aDescription), mLibrary(nsnull), mIsJavaPlugin(false), -mIsNPRuntimeEnabledJavaPlugin(false), mIsFlashPlugin(false), mFileName(aFileName), mFullPath(aFullPath), @@ -163,13 +160,14 @@ void nsPluginTag::InitMime(const char* const* aMimeTypes, } // If we already marked this as a Java plugin, a later MIME type will tell - // us if it is npruntime-enabled. + // us if it is npruntime-enabled. We don't actually care any more because we + // don't support Java access via the "java" and "packages" DOM objects, so + // we don't save the value, but we skip the MIME type. if (mIsJavaPlugin) { if (strcmp(aMimeTypes[i], "application/x-java-vm-npruntime") == 0) { // This "magic MIME type" should not be exposed, but is just a signal // to the browser that this is new-style java. // Don't add it or its associated information to our arrays. - mIsNPRuntimeEnabledJavaPlugin = true; continue; } } diff --git a/dom/plugins/base/nsPluginTags.h b/dom/plugins/base/nsPluginTags.h index b166d21ff7f8..81f1bb23f23a 100644 --- a/dom/plugins/base/nsPluginTags.h +++ b/dom/plugins/base/nsPluginTags.h @@ -110,7 +110,6 @@ public: PRLibrary *mLibrary; nsRefPtr<nsNPAPIPlugin> mPlugin; bool mIsJavaPlugin; - bool mIsNPRuntimeEnabledJavaPlugin; bool mIsFlashPlugin; nsCString mFileName; // UTF-8 nsCString mFullPath; // UTF-8 From 69253597474a3cefec258c151e20ff25fa55eaed Mon Sep 17 00:00:00 2001 From: Luke Wagner <luke@mozilla.com> Date: Tue, 1 May 2012 14:01:06 -0700 Subject: [PATCH 130/159] Bug 749617 - rm XDRState::codeString (r=njn,a=not-libxul) --HG-- extra : rebase_source : de4e8eba904cd44a7b3d99edd85d841a359b83d5 --- js/src/frontend/BytecodeEmitter.h | 2 +- js/src/jsatom.cpp | 16 ++++++++----- js/src/jsscript.cpp | 14 ++++++------ js/src/vm/Xdr.cpp | 38 ------------------------------- js/src/vm/Xdr.h | 1 - 5 files changed, 18 insertions(+), 53 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 97ddf91dcfb5..fd4b4bda8f3b 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -544,7 +544,7 @@ class GCConstList { Vector<Value> list; public: GCConstList(JSContext *cx) : list(cx) {} - bool append(Value v) { return list.append(v); } + bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); } size_t length() const { return list.length(); } void finish(JSConstArray *array); }; diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index f716d7ae6183..eb2561963270 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -665,14 +665,18 @@ bool js::XDRAtom(XDRState<mode> *xdr, JSAtom **atomp) { if (mode == XDR_ENCODE) { - JSString *str = *atomp; - return xdr->codeString(&str); + uint32_t nchars = (*atomp)->length(); + if (!xdr->codeUint32(&nchars)) + return false; + + jschar *chars = const_cast<jschar *>((*atomp)->getChars(xdr->cx())); + if (!chars) + return false; + + return xdr->codeChars(chars, nchars); } - /* - * Inline XDRState::codeString when decoding to avoid JSString allocation - * for already existing atoms. See bug 321985. - */ + /* Avoid JSString allocation for already existing atoms. See bug 321985. */ uint32_t nchars; if (!xdr->codeUint32(&nchars)) return false; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index d3cd66df9c9b..959d5ea9457d 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -308,7 +308,7 @@ XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp) enum ConstTag { SCRIPT_INT = 0, SCRIPT_DOUBLE = 1, - SCRIPT_STRING = 2, + SCRIPT_ATOM = 2, SCRIPT_TRUE = 3, SCRIPT_FALSE = 4, SCRIPT_NULL = 5, @@ -322,7 +322,7 @@ XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp) } else if (vp->isDouble()) { tag = SCRIPT_DOUBLE; } else if (vp->isString()) { - tag = SCRIPT_STRING; + tag = SCRIPT_ATOM; } else if (vp->isTrue()) { tag = SCRIPT_TRUE; } else if (vp->isFalse()) { @@ -359,14 +359,14 @@ XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp) vp->init(DoubleValue(d)); break; } - case SCRIPT_STRING: { - JSString *str; + case SCRIPT_ATOM: { + JSAtom *atom; if (mode == XDR_ENCODE) - str = vp->toString(); - if (!xdr->codeString(&str)) + atom = &vp->toString()->asAtom(); + if (!XDRAtom(xdr, &atom)) return false; if (mode == XDR_DECODE) - vp->init(StringValue(str)); + vp->init(StringValue(atom)); break; } case SCRIPT_TRUE: diff --git a/js/src/vm/Xdr.cpp b/js/src/vm/Xdr.cpp index 9e75bc1f73a7..7a4407d4ea38 100644 --- a/js/src/vm/Xdr.cpp +++ b/js/src/vm/Xdr.cpp @@ -129,44 +129,6 @@ XDRState<mode>::codeChars(jschar *chars, size_t nchars) return true; } -/* - * Convert between a JS (Unicode) string and the XDR representation. - */ -template<XDRMode mode> -bool -XDRState<mode>::codeString(JSString **strp) -{ - uint32_t nchars; - jschar *chars; - - if (mode == XDR_ENCODE) - nchars = (*strp)->length(); - if (!codeUint32(&nchars)) - return false; - - if (mode == XDR_DECODE) - chars = (jschar *) cx()->malloc_((nchars + 1) * sizeof(jschar)); - else - chars = const_cast<jschar *>((*strp)->getChars(cx())); - if (!chars) - return false; - - if (!codeChars(chars, nchars)) - goto bad; - if (mode == XDR_DECODE) { - chars[nchars] = 0; - *strp = JS_NewUCString(cx(), chars, nchars); - if (!*strp) - goto bad; - } - return true; - -bad: - if (mode == XDR_DECODE) - Foreground::free_(chars); - return false; -} - template<XDRMode mode> static bool VersionCheck(XDRState<mode> *xdr) diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 78f3a6be44fc..1cf9edec0da5 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -287,7 +287,6 @@ class XDRState { } bool codeChars(jschar *chars, size_t nchars); - bool codeString(JSString **strp); bool codeFunction(JSObject **objp); bool codeScript(JSScript **scriptp); From 22f2cf9466c9ae4517c3dd48a73bff8d069271a5 Mon Sep 17 00:00:00 2001 From: Luke Wagner <luke@mozilla.com> Date: Tue, 1 May 2012 15:45:01 -0700 Subject: [PATCH 131/159] Bug 749617 - improve getLocalNamesArray (r=waldo,a=not-libxul) --HG-- extra : rebase_source : 184c3644798da9bca23da017f6f9a53e28711930 --- js/src/frontend/BytecodeCompiler.cpp | 4 ++-- js/src/jsdbgapi.cpp | 9 +++++---- js/src/jsfun.h | 3 --- js/src/jsopcode.cpp | 12 ++++++------ js/src/jsscript.cpp | 22 ++++++++++++---------- js/src/jsscript.h | 9 ++++++++- js/src/vm/Debugger.cpp | 4 ++-- 7 files changed, 35 insertions(+), 28 deletions(-) diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 87bee0118831..ec9052815ed6 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -377,12 +377,12 @@ frontend::CompileFunctionBody(JSContext *cx, JSFunction *fun, * NB: do not use AutoLocalNameArray because it will release space * allocated from cx->tempLifoAlloc by DefineArg. */ - Vector<JSAtom *> names(cx); + BindingNames names(cx); if (!funbce.bindings.getLocalNameArray(cx, &names)) { fn = NULL; } else { for (unsigned i = 0; i < nargs; i++) { - if (!DefineArg(fn, names[i], i, &funbce)) { + if (!DefineArg(fn, names[i].maybeAtom, i, &funbce)) { fn = NULL; break; } diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index c11e243c1e8c..a0caf1f0d72a 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -435,7 +435,7 @@ JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun) extern JS_PUBLIC_API(uintptr_t *) JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp) { - Vector<JSAtom *> localNames(cx); + BindingNames localNames(cx); if (!fun->script()->bindings.getLocalNameArray(cx, &localNames)) return NULL; @@ -448,15 +448,16 @@ JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp) return NULL; } - JS_ASSERT(sizeof(*names) == sizeof(*localNames.begin())); - js_memcpy(names, localNames.begin(), localNames.length() * sizeof(*names)); + for (size_t i = 0; i < localNames.length(); i++) + names[i] = reinterpret_cast<uintptr_t>(localNames[i].maybeAtom); + return names; } extern JS_PUBLIC_API(JSAtom *) JS_LocalNameToAtom(uintptr_t w) { - return JS_LOCAL_NAME_TO_ATOM(w); + return reinterpret_cast<JSAtom *>(w); } extern JS_PUBLIC_API(JSString *) diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 599b13c473b3..d4ff16a27ddd 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -121,9 +121,6 @@ struct JSFunction : public JSObject /* uint16_t representation bounds number of call object dynamic slots. */ enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) }; -#define JS_LOCAL_NAME_TO_ATOM(nameWord) ((JSAtom *) ((nameWord) & ~uintptr_t(1))) -#define JS_LOCAL_NAME_IS_CONST(nameWord) ((((nameWord) & uintptr_t(1))) != 0) - /* * For an interpreted function, accessors for the initial scope object of * activations (stack frames) of the function. diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 7e6b1ff4e364..023ebc761787 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1087,7 +1087,7 @@ struct JSPrinter jsbytecode *dvgfence; /* DecompileExpression fencepost */ jsbytecode **pcstack; /* DecompileExpression modeled stack */ JSFunction *fun; /* interpreted function */ - Vector<JSAtom *> *localNames; /* argument and variable names */ + BindingNames *localNames; /* argument and variable names */ Vector<DecompiledOpcode> *decompiledOpcodes; /* optional state for decompiled ops */ DecompiledOpcode &decompiled(jsbytecode *pc) { @@ -1118,7 +1118,7 @@ js_NewPrinter(JSContext *cx, const char *name, JSFunction *fun, jp->localNames = NULL; jp->decompiledOpcodes = NULL; if (fun && fun->isInterpreted() && fun->script()->bindings.count() > 0) { - jp->localNames = cx->new_<Vector<JSAtom *> >(cx); + jp->localNames = cx->new_<BindingNames>(cx); if (!jp->localNames || !fun->script()->bindings.getLocalNameArray(cx, jp->localNames)) { js_DestroyPrinter(jp); return NULL; @@ -1767,7 +1767,7 @@ GetArgOrVarAtom(JSPrinter *jp, unsigned slot) { LOCAL_ASSERT_RV(jp->fun, NULL); LOCAL_ASSERT_RV(slot < jp->fun->script()->bindings.count(), NULL); - JSAtom *name = (*jp->localNames)[slot]; + JSAtom *name = (*jp->localNames)[slot].maybeAtom; #if !JS_HAS_DESTRUCTURING LOCAL_ASSERT_RV(name, NULL); #endif @@ -4663,8 +4663,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb) #if JS_HAS_GENERATOR_EXPRS sn = js_GetSrcNote(jp->script, pc); if (sn && SN_TYPE(sn) == SRC_GENEXP) { - Vector<JSAtom *> *innerLocalNames; - Vector<JSAtom *> *outerLocalNames; + BindingNames *innerLocalNames; + BindingNames *outerLocalNames; JSScript *inner, *outer; Vector<DecompiledOpcode> *decompiledOpcodes; SprintStack ss2(cx); @@ -4680,7 +4680,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb) */ LifoAllocScope las(&cx->tempLifoAlloc()); if (fun->script()->bindings.count() > 0) { - innerLocalNames = cx->new_<Vector<JSAtom *> >(cx); + innerLocalNames = cx->new_<BindingNames>(cx); if (!innerLocalNames || !fun->script()->bindings.getLocalNameArray(cx, innerLocalNames)) { diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 959d5ea9457d..f42228983924 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -214,12 +214,12 @@ Bindings::callObjectShape(JSContext *cx) const } bool -Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp) +Bindings::getLocalNameArray(JSContext *cx, BindingNames *namesp) { JS_ASSERT(lastBinding); JS_ASSERT(count() > 0); - Vector<JSAtom *> &names = *namesp; + BindingNames &names = *namesp; JS_ASSERT(names.empty()); unsigned n = count(); @@ -229,7 +229,7 @@ Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp) #ifdef DEBUG JSAtom * const POISON = reinterpret_cast<JSAtom *>(0xdeadbeef); for (unsigned i = 0; i < n; i++) - names[i] = POISON; + names[i].maybeAtom = POISON; #endif for (Shape::Range r = lastBinding->all(); !r.empty(); r.popFront()) { @@ -238,23 +238,25 @@ Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp) if (shape.getter() == CallObject::getArgOp) { JS_ASSERT(index < nargs); + names[index].kind = ARGUMENT; } else { JS_ASSERT(index < nvars); index += nargs; + names[index].kind = shape.writable() ? VARIABLE : CONSTANT; } if (JSID_IS_ATOM(shape.propid())) { - names[index] = JSID_TO_ATOM(shape.propid()); + names[index].maybeAtom = JSID_TO_ATOM(shape.propid()); } else { JS_ASSERT(JSID_IS_INT(shape.propid())); JS_ASSERT(shape.getter() == CallObject::getArgOp); - names[index] = NULL; + names[index].maybeAtom = NULL; } } #ifdef DEBUG for (unsigned i = 0; i < n; i++) - JS_ASSERT(names[i] != POISON); + JS_ASSERT(names[i].maybeAtom != POISON); #endif return true; @@ -463,13 +465,13 @@ js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript) return false; } - Vector<JSAtom *> names(cx); + BindingNames names(cx); if (mode == XDR_ENCODE) { if (!script->bindings.getLocalNameArray(cx, &names)) return false; PodZero(bitmap, bitmapLength); for (unsigned i = 0; i < nameCount; i++) { - if (i < nargs && names[i]) + if (i < nargs && names[i].maybeAtom) bitmap[i >> JS_BITS_PER_UINT32_LOG2] |= JS_BIT(i & (JS_BITS_PER_UINT32 - 1)); } } @@ -487,14 +489,14 @@ js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript) if (!bindings.addDestructuring(cx, &dummy)) return false; } else { - JS_ASSERT(!names[i]); + JS_ASSERT(!names[i].maybeAtom); } continue; } RootedVarAtom name(cx); if (mode == XDR_ENCODE) - name = names[i]; + name = names[i].maybeAtom; if (!XDRAtom(xdr, name.address())) return false; if (mode == XDR_DECODE) { diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 7645395d002f..0f088c8aba70 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -110,6 +110,13 @@ struct Shape; enum BindingKind { NONE, ARGUMENT, VARIABLE, CONSTANT }; +struct BindingName { + JSAtom *maybeAtom; + BindingKind kind; +}; + +typedef Vector<BindingName, 32> BindingNames; + /* * Formal parameters and local variables are stored in a shape tree * path encapsulated within this class. This class represents bindings for @@ -238,7 +245,7 @@ class Bindings * The name at an element will be null when the element is for an argument * corresponding to a destructuring pattern. */ - bool getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp); + bool getLocalNameArray(JSContext *cx, BindingNames *namesp); /* * Protect stored bindings from mutation. Subsequent attempts to add diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 10a60e46ce98..10b53085425a 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -3667,12 +3667,12 @@ DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp) JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs()); if (fun->nargs > 0) { - Vector<JSAtom *> names(cx); + BindingNames names(cx); if (!fun->script()->bindings.getLocalNameArray(cx, &names)) return false; for (size_t i = 0; i < fun->nargs; i++) { - JSAtom *name = names[i]; + JSAtom *name = names[i].maybeAtom; result->setDenseArrayElement(i, name ? StringValue(name) : UndefinedValue()); } } From eb29bf64ef55f4e8429e77f3fcb215781ff017eb Mon Sep 17 00:00:00 2001 From: Luke Wagner <luke@mozilla.com> Date: Tue, 1 May 2012 20:39:05 -0700 Subject: [PATCH 132/159] Bug 749617 - Optimize js::CloneScript (r=njn,a=not-libxul) --HG-- extra : rebase_source : a18f454312960f048b0ef15a3b3b7d48f9ba49f8 --- .../jit-test/tests/basic/testScriptCloning.js | 24 ++ js/src/jsfun.cpp | 30 +++ js/src/jsfun.h | 3 + js/src/jsscript.cpp | 231 ++++++++++++++++-- js/src/jsscript.h | 2 + js/src/vm/RegExpObject.cpp | 18 ++ js/src/vm/RegExpObject.h | 3 + js/src/vm/ScopeObject.cpp | 77 ++++-- js/src/vm/ScopeObject.h | 4 + js/src/vm/Xdr.h | 2 +- 10 files changed, 351 insertions(+), 43 deletions(-) create mode 100644 js/src/jit-test/tests/basic/testScriptCloning.js diff --git a/js/src/jit-test/tests/basic/testScriptCloning.js b/js/src/jit-test/tests/basic/testScriptCloning.js new file mode 100644 index 000000000000..ca77ea9380fe --- /dev/null +++ b/js/src/jit-test/tests/basic/testScriptCloning.js @@ -0,0 +1,24 @@ +var g = newGlobal('new-compartment'); + +g.f = new Function('return function(x) { return x }'); +assertEq(g.eval("clone(f)()(9)"), 9); + +g.f = new Function('return function(x) { let(y = x+1) { return y } }'); +assertEq(g.eval("clone(f)()(9)"), 10); + +g.f = new Function('return function(x) { let(y = x, z = 1) { return y+z } }'); +assertEq(g.eval("clone(f)()(9)"), 10); + +g.f = new Function('return function(x) { return x.search(/ponies/) }'); +assertEq(g.eval("clone(f)()('123ponies')"), 3); + +g.f = new Function('return function(x,y) { return x.search(/a/) + y.search(/b/) }'); +assertEq(g.eval("clone(f)()('12a','foo')"), 1); + +g.f = new Function('return [function(x) x+2, function(y) let(z=y+1) z]'); +assertEq(g.eval("let ([f,g] = clone(f)()) f(g(4))"), 7); + +g.f = new Function('return function(x) { switch(x) { case "a": return "b"; case null: return "c" } }'); +assertEq(g.eval("clone(f)()('a')"), "b"); +assertEq(g.eval("clone(f)()(null)"), "c"); +assertEq(g.eval("clone(f)()(3)"), undefined); diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index fc9485d1789c..189025b6babe 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -374,6 +374,7 @@ template<XDRMode mode> bool js::XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript) { + /* NB: Keep this in sync with CloneInterpretedFunction. */ JSFunction *fun; JSAtom *atom; uint32_t firstword; /* flag telling whether fun->atom is non-null, @@ -442,6 +443,35 @@ js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *xdr, JSObject **objp, JSScript template bool js::XDRInterpretedFunction(XDRState<XDR_DECODE> *xdr, JSObject **objp, JSScript *parentScript); +JSObject * +js::CloneInterpretedFunction(JSContext *cx, JSFunction *srcFun) +{ + /* NB: Keep this in sync with XDRInterpretedFunction. */ + + RootedVarObject parent(cx, NULL); + JSFunction *clone = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, parent, NULL); + if (!clone) + return NULL; + if (!clone->clearParent(cx)) + return NULL; + if (!clone->clearType(cx)) + return NULL; + + JSScript *clonedScript = CloneScript(cx, srcFun->script()); + if (!clonedScript) + return NULL; + + clone->nargs = srcFun->nargs; + clone->flags = srcFun->flags; + clone->atom.init(srcFun->atom); + clone->initScript(clonedScript); + if (!clonedScript->typeSetFunction(cx, clone)) + return NULL; + + js_CallNewScriptHook(cx, clone->script(), clone); + return clone; +} + /* * [[HasInstance]] internal method for Function objects: fetch the .prototype * property of its 'this' parameter, and walks the prototype chain of v (only diff --git a/js/src/jsfun.h b/js/src/jsfun.h index d4ff16a27ddd..d5c7c49af9f0 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -311,6 +311,9 @@ template<XDRMode mode> bool XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript); +extern JSObject * +CloneInterpretedFunction(JSContext *cx, JSFunction *fun); + } /* namespace js */ extern JSBool diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index f42228983924..d7cf53080a20 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -76,6 +76,8 @@ #include "jsobjinlines.h" #include "jsscriptinlines.h" +#include "vm/RegExpObject-inl.h" + using namespace js; using namespace js::gc; using namespace js::frontend; @@ -217,7 +219,8 @@ bool Bindings::getLocalNameArray(JSContext *cx, BindingNames *namesp) { JS_ASSERT(lastBinding); - JS_ASSERT(count() > 0); + if (count() == 0) + return true; BindingNames &names = *namesp; JS_ASSERT(names.empty()); @@ -395,6 +398,8 @@ template<XDRMode mode> bool js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript) { + /* NB: Keep this in sync with CloneScript. */ + enum ScriptBits { NoScriptRval, SavedCallerFun, @@ -1120,11 +1125,10 @@ JS_STATIC_ASSERT(sizeof(JSConstArray) + < JSScript::INVALID_OFFSET); JS_STATIC_ASSERT(JSScript::INVALID_OFFSET <= 255); -JSScript * -JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms, - uint32_t nobjects, uint32_t nregexps, - uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals, - uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets, JSVersion version) +static inline size_t +ScriptDataSize(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms, + uint32_t nobjects, uint32_t nregexps, uint32_t ntrynotes, uint32_t nconsts, + uint32_t nglobals, uint16_t nClosedArgs, uint16_t nClosedVars) { size_t size = 0; @@ -1146,16 +1150,33 @@ JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t size += length * sizeof(jsbytecode); size += nsrcnotes * sizeof(jssrcnote); + return size; +} - /* - * We assume that calloc aligns on sizeof(Value) if the size we ask to - * allocate divides sizeof(Value). - */ - JS_STATIC_ASSERT(sizeof(Value) == sizeof(double)); +static inline uint8_t * +AllocScriptData(JSContext *cx, size_t size) +{ uint8_t *data = static_cast<uint8_t *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value)))); if (!data) return NULL; + JS_ASSERT(size_t(data) % sizeof(Value) == 0); + return data; +} + +JSScript * +JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms, + uint32_t nobjects, uint32_t nregexps, + uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals, + uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets, JSVersion version) +{ + size_t size = ScriptDataSize(cx, length, nsrcnotes, natoms, nobjects, nregexps, + ntrynotes, nconsts, nglobals, nClosedArgs, nClosedVars); + + uint8_t *data = AllocScriptData(cx, size); + if (!data) + return NULL; + JSScript *script = js_NewGCScript(cx); if (!script) { Foreground::free_(data); @@ -1449,6 +1470,10 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce) Debugger::onNewScript(cx, script, compileAndGoGlobal); } + /* + * initScriptCounts updates scriptCountsMap if necessary. The other script + * maps in JSCompartment are populated lazily. + */ if (cx->hasRunOption(JSOPTION_PCCOUNT)) (void) script->initScriptCounts(cx); @@ -1738,28 +1763,186 @@ CurrentScriptFileLineOriginSlow(JSContext *cx, const char **file, unsigned *line } /* namespace js */ -JSScript * -js::CloneScript(JSContext *cx, JSScript *script) +template <class T> +static inline T * +Rebase(JSScript *dst, JSScript *src, T *srcp) { - JS_ASSERT(cx->compartment != script->compartment()); + size_t off = reinterpret_cast<uint8_t *>(srcp) - src->data; + return reinterpret_cast<T *>(dst->data + off); +} - /* Serialize script. */ - XDREncoder encoder(cx); +JSScript * +js::CloneScript(JSContext *cx, JSScript *src) +{ + /* NB: Keep this in sync with XDRScript. */ - if (!XDRScript(&encoder, &script, NULL)) + uint32_t nconsts = JSScript::isValidOffset(src->constsOffset) ? src->consts()->length : 0; + uint32_t nobjects = JSScript::isValidOffset(src->objectsOffset) ? src->objects()->length : 0; + uint32_t nregexps = JSScript::isValidOffset(src->regexpsOffset) ? src->regexps()->length : 0; + uint32_t ntrynotes = JSScript::isValidOffset(src->trynotesOffset) ? src->trynotes()->length : 0; + uint32_t nClosedArgs = src->numClosedArgs(); + uint32_t nClosedVars = src->numClosedVars(); + JS_ASSERT(!JSScript::isValidOffset(src->globalsOffset)); + uint32_t nglobals = 0; + + /* Script data */ + + size_t size = ScriptDataSize(cx, src->length, src->numNotes(), src->natoms, + nobjects, nregexps, ntrynotes, nconsts, nglobals, + nClosedArgs, nClosedVars); + + uint8_t *data = AllocScriptData(cx, size); + if (!data) return NULL; - uint32_t nbytes; - const void *p = encoder.getData(&nbytes); + /* Bindings */ - /* De-serialize script. */ - XDRDecoder decoder(cx, p, nbytes, cx->compartment->principals, script->originPrincipals); + Bindings bindings(cx); + BindingNames names(cx); + if (!src->bindings.getLocalNameArray(cx, &names)) + return false; - JSScript *newScript; - if (!XDRScript(&decoder, &newScript, NULL)) + for (unsigned i = 0; i < names.length(); ++i) { + if (JSAtom *atom = names[i].maybeAtom) { + if (!bindings.add(cx, RootedVarAtom(cx, atom), names[i].kind)) + return false; + } else { + uint16_t _; + if (!bindings.addDestructuring(cx, &_)) + return false; + } + } + + if (!bindings.ensureShape(cx)) + return false; + bindings.makeImmutable(); + + /* Objects */ + + AutoObjectVector objects(cx); + if (nobjects != 0) { + HeapPtrObject *vector = src->objects()->vector; + for (unsigned i = 0; i < nobjects; i++) { + JSObject *clone = vector[i]->isStaticBlock() + ? CloneStaticBlockObject(cx, vector[i]->asStaticBlock(), objects, src) + : CloneInterpretedFunction(cx, vector[i]->toFunction()); + if (!clone || !objects.append(clone)) + return false; + } + } + + /* RegExps */ + + AutoObjectVector regexps(cx); + for (unsigned i = 0; i < nregexps; i++) { + HeapPtrObject *vector = src->regexps()->vector; + for (unsigned i = 0; i < nregexps; i++) { + JSObject *clone = CloneScriptRegExpObject(cx, vector[i]->asRegExp()); + if (!clone || !regexps.append(clone)) + return false; + } + } + + /* Now that all fallible allocation is complete, create the GC thing. */ + + JSScript *dst = js_NewGCScript(cx); + if (!dst) { + Foreground::free_(data); return NULL; + } - return newScript; + PodZero(dst); + + new (&dst->bindings) Bindings(cx); + dst->bindings.transfer(cx, &bindings); + + /* This assignment must occur before all the Rebase calls. */ + dst->data = data; + memcpy(data, src->data, size); + + dst->code = Rebase<jsbytecode>(dst, src, src->code); + + /* Script filenames are runtime-wide. */ + dst->filename = src->filename; + + /* Atoms are runtime-wide. */ + if (src->natoms != 0) + dst->atoms = Rebase<HeapPtrAtom>(dst, src, src->atoms); + + dst->principals = cx->compartment->principals; + if (dst->principals) + JS_HoldPrincipals(dst->principals); + + /* Establish invariant: principals implies originPrincipals. */ + dst->originPrincipals = src->originPrincipals; + if (!dst->originPrincipals) + dst->originPrincipals = dst->principals; + if (dst->originPrincipals) + JS_HoldPrincipals(dst->originPrincipals); + + dst->length = src->length; + dst->lineno = src->lineno; + dst->mainOffset = src->mainOffset; + dst->natoms = src->natoms; + dst->setVersion(src->getVersion()); + dst->nfixed = src->nfixed; + dst->nTypeSets = src->nTypeSets; + dst->nslots = src->nslots; + dst->staticLevel = src->staticLevel; + if (src->argumentsHasLocalBinding()) { + dst->setArgumentsHasLocalBinding(src->argumentsLocalSlot()); + if (src->analyzedArgsUsage()) + dst->setNeedsArgsObj(src->needsArgsObj()); + } + dst->constsOffset = src->constsOffset; + dst->objectsOffset = src->objectsOffset; + dst->regexpsOffset = src->regexpsOffset; + dst->trynotesOffset = src->trynotesOffset; + dst->globalsOffset = src->globalsOffset; + dst->closedArgsOffset = src->closedArgsOffset; + dst->closedVarsOffset = src->closedVarsOffset; + dst->noScriptRval = src->noScriptRval; + dst->savedCallerFun = src->savedCallerFun; + dst->strictModeCode = src->strictModeCode; + dst->compileAndGo = src->compileAndGo; + dst->bindingsAccessedDynamically = src->bindingsAccessedDynamically; + dst->hasSingletons = src->hasSingletons; + dst->isGenerator = src->isGenerator; + + /* + * initScriptCounts updates scriptCountsMap if necessary. The other script + * maps in JSCompartment are populated lazily. + */ + if (cx->hasRunOption(JSOPTION_PCCOUNT)) + (void) dst->initScriptCounts(cx); + + if (nconsts != 0) { + HeapValue *vector = Rebase<HeapValue>(dst, src, src->consts()->vector); + dst->consts()->vector = vector; + for (unsigned i = 0; i < nconsts; ++i) + JS_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom()); + } + if (nobjects != 0) { + HeapPtrObject *vector = Rebase<HeapPtr<JSObject> >(dst, src, src->objects()->vector); + dst->objects()->vector = vector; + for (unsigned i = 0; i < nobjects; ++i) + vector[i].init(objects[i]); + } + if (nregexps != 0) { + HeapPtrObject *vector = Rebase<HeapPtr<JSObject> >(dst, src, src->regexps()->vector); + dst->regexps()->vector = vector; + for (unsigned i = 0; i < nregexps; ++i) + vector[i].init(regexps[i]); + } + if (ntrynotes != 0) + dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector); + if (nClosedArgs != 0) + dst->closedArgs()->vector = Rebase<uint32_t>(dst, src, src->closedArgs()->vector); + if (nClosedVars != 0) + dst->closedVars()->vector = Rebase<uint32_t>(dst, src, src->closedVars()->vector); + JS_ASSERT(nglobals == 0); + + return dst; } DebugScript * diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 0f088c8aba70..a7534519c59d 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -592,6 +592,8 @@ struct JSScript : public js::gc::Cell JSVersion version); static JSScript *NewScriptFromEmitter(JSContext *cx, js::BytecodeEmitter *bce); + void setVersion(JSVersion v) { version = v; } + /* See TCF_ARGUMENTS_HAS_LOCAL_BINDING comment. */ bool argumentsHasLocalBinding() const { return argsHasLocalBinding_; } jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; } diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 08086a33872f..b142d9cfd28b 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -760,6 +760,8 @@ template<XDRMode mode> bool js::XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp) { + /* NB: Keep this in sync with CloneScriptRegExpObject. */ + RootedVarAtom source(xdr->cx()); uint32_t flagsword = 0; @@ -791,3 +793,19 @@ js::XDRScriptRegExpObject(XDRState<XDR_ENCODE> *xdr, HeapPtrObject *objp); template bool js::XDRScriptRegExpObject(XDRState<XDR_DECODE> *xdr, HeapPtrObject *objp); + +JSObject * +js::CloneScriptRegExpObject(JSContext *cx, RegExpObject &reobj) +{ + /* NB: Keep this in sync with XDRScriptRegExpObject. */ + + RootedVarAtom source(cx, reobj.getSource()); + RegExpObject *clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), NULL); + if (!clone) + return NULL; + if (!clone->clearParent(cx)) + return false; + if (!clone->clearType(cx)) + return false; + return clone; +} diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index 0691626eeb6a..b27a70980830 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -474,6 +474,9 @@ template<XDRMode mode> bool XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp); +extern JSObject * +CloneScriptRegExpObject(JSContext *cx, RegExpObject &re); + } /* namespace js */ #endif diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 88ba7643896c..ae015dcef311 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -878,18 +878,23 @@ Class js::BlockClass = { #define NO_PARENT_INDEX UINT32_MAX +/* + * If there's a parent id, then get the parent out of our script's object + * array. We know that we clone block objects in outer-to-inner order, which + * means that getting the parent now will work. + */ static uint32_t -FindObjectIndex(JSObjectArray *array, JSObject *obj) +FindObjectIndex(JSScript *script, StaticBlockObject *maybeBlock) { - size_t i; + if (!maybeBlock || !JSScript::isValidOffset(script->objectsOffset)) + return NO_PARENT_INDEX; - if (array) { - i = array->length; - do { - - if (array->vector[--i] == obj) - return i; - } while (i != 0); + JSObjectArray *objects = script->objects(); + HeapPtrObject *vector = objects->vector; + unsigned length = objects->length; + for (unsigned i = 0; i < length; ++i) { + if (vector[i] == maybeBlock) + return i; } return NO_PARENT_INDEX; @@ -899,6 +904,8 @@ template<XDRMode mode> bool js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp) { + /* NB: Keep this in sync with CloneStaticBlockObject. */ + JSContext *cx = xdr->cx(); StaticBlockObject *obj = NULL; @@ -907,9 +914,7 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObjec uint32_t depthAndCount = 0; if (mode == XDR_ENCODE) { obj = *objp; - parentId = JSScript::isValidOffset(script->objectsOffset) - ? FindObjectIndex(script->objects(), obj->enclosingBlock()) - : NO_PARENT_INDEX; + parentId = FindObjectIndex(script, obj->enclosingBlock()); uint32_t depth = obj->stackDepth(); JS_ASSERT(depth <= UINT16_MAX); count = obj->slotCount(); @@ -927,11 +932,6 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObjec return false; *objp = obj; - /* - * If there's a parent id, then get the parent out of our script's - * object array. We know that we XDR block object in outer-to-inner - * order, which means that getting the parent now will work. - */ obj->setEnclosingBlock(parentId == NO_PARENT_INDEX ? NULL : &script->getObject(parentId)->asStaticBlock()); @@ -976,7 +976,8 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObjec } } else { AutoShapeVector shapes(cx); - shapes.growBy(count); + if (!shapes.growBy(count)) + return false; for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) { const Shape *shape = &r.front(); @@ -1016,3 +1017,43 @@ js::XDRStaticBlockObject(XDRState<XDR_ENCODE> *xdr, JSScript *script, StaticBloc template bool js::XDRStaticBlockObject(XDRState<XDR_DECODE> *xdr, JSScript *script, StaticBlockObject **objp); + +JSObject * +js::CloneStaticBlockObject(JSContext *cx, StaticBlockObject &srcBlock, + const AutoObjectVector &objects, JSScript *src) +{ + /* NB: Keep this in sync with XDRStaticBlockObject. */ + + StaticBlockObject *clone = StaticBlockObject::create(cx); + if (!clone) + return false; + + uint32_t parentId = FindObjectIndex(src, srcBlock.enclosingBlock()); + clone->setEnclosingBlock(parentId == NO_PARENT_INDEX + ? NULL + : &objects[parentId]->asStaticBlock()); + + clone->setStackDepth(srcBlock.stackDepth()); + + /* Shape::Range is reverse order, so build a list in forward order. */ + AutoShapeVector shapes(cx); + if (!shapes.growBy(srcBlock.slotCount())) + return false; + for (Shape::Range r = srcBlock.lastProperty()->all(); !r.empty(); r.popFront()) + shapes[r.front().shortid()] = &r.front(); + + for (const Shape **p = shapes.begin(); p != shapes.end(); ++p) { + jsid id = (*p)->propid(); + unsigned i = (*p)->shortid(); + + bool redeclared; + if (!clone->addVar(cx, id, i, &redeclared)) { + JS_ASSERT(!redeclared); + return false; + } + + clone->setAliased(i, srcBlock.isAliased(i)); + } + + return clone; +} diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 97da34d06019..d397ffb2d182 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -299,6 +299,10 @@ template<XDRMode mode> bool XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp); +extern JSObject * +CloneStaticBlockObject(JSContext *cx, StaticBlockObject &srcBlock, + const AutoObjectVector &objects, JSScript *src); + } /* namespace js */ #endif /* ScopeObject_h___ */ diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 1cf9edec0da5..f442a1fca0fb 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -57,7 +57,7 @@ namespace js { * and saved versions. If deserialization fails, the data should be * invalidated if possible. */ -static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 114); +static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 115); class XDRBuffer { public: From 407c4aad13f4b5891af1049c1a279844af419236 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Wed, 2 May 2012 09:28:29 -0400 Subject: [PATCH 133/159] Bug 750747 - Rip out libpng from libxul; r=khuey --- layout/media/Makefile.in | 6 +++++ layout/media/symbols.def.in | 52 +++++++++++++++++++++++++++++++++++++ media/libpng/Makefile.in | 4 +-- toolkit/library/Makefile.in | 5 +++- 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index 190b6b2c4ac7..9dcf0f6911aa 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -102,6 +102,12 @@ SHARED_LIBRARY_LIBS += \ $(NULL) endif +ifndef MOZ_NATIVE_PNG +SHARED_LIBRARY_LIBS += \ + $(DEPTH)/media/libpng/$(LIB_PREFIX)mozpng.$(LIB_SUFFIX) \ + $(NULL) +endif + SHARED_LIBRARY_LIBS += \ $(DEPTH)/gfx/angle/$(LIB_PREFIX)angle.$(LIB_SUFFIX) \ $(NULL) diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index c60527decdfe..74c553477ba1 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -115,3 +115,55 @@ ShGetInfo ShConstructCompiler ShGetActiveAttrib ShGetActiveUniform +#ifndef MOZ_NATIVE_PNG +MOZ_APNG_get_first_frame_is_hidden +MOZ_APNG_get_next_frame_blend_op +MOZ_APNG_get_next_frame_delay_den +MOZ_APNG_get_next_frame_delay_num +MOZ_APNG_get_next_frame_dispose_op +MOZ_APNG_set_prog_frame_fn +MOZ_APNG_get_next_frame_height +MOZ_APNG_get_next_frame_width +MOZ_APNG_get_next_frame_x_offset +MOZ_APNG_get_next_frame_y_offset +MOZ_APNG_set_acTL +MOZ_APNG_set_first_frame_is_hidden +MOZ_APNG_set_num_plays +MOZ_APNG_write_frame_head +MOZ_APNG_write_frame_tail +MOZ_PNG_cr_info_str +MOZ_PNG_cr_read_str +MOZ_PNG_cr_write_str +MOZ_PNG_dest_read_str +MOZ_PNG_dest_write_str +MOZ_PNG_free_data +MOZ_PNG_get_channels +MOZ_PNG_get_cHRM +MOZ_PNG_get_gAMA +MOZ_PNG_get_IHDR +MOZ_PNG_get_iCCP +MOZ_PNG_get_io_ptr +MOZ_PNG_get_progressive_ptr +MOZ_PNG_get_sRGB +MOZ_PNG_get_tRNS +MOZ_PNG_get_valid +MOZ_PNG_longjmp +MOZ_PNG_process_data +MOZ_PNG_progressive_combine_row +MOZ_PNG_read_update_info +MOZ_PNG_set_cHRM +MOZ_PNG_set_crc_action +MOZ_PNG_set_gAMA +MOZ_PNG_set_gamma +MOZ_PNG_set_gray_to_rgb +MOZ_PNG_set_expand +MOZ_PNG_set_IHDR +MOZ_PNG_set_interlace_handling +MOZ_PNG_set_longjmp_fn +MOZ_PNG_set_progressive_read_fn +MOZ_PNG_set_scale_16 +MOZ_PNG_set_write_fn +MOZ_PNG_write_end +MOZ_PNG_write_info +MOZ_PNG_write_row +#endif diff --git a/media/libpng/Makefile.in b/media/libpng/Makefile.in index 9058a73f27b9..3001e6df505e 100644 --- a/media/libpng/Makefile.in +++ b/media/libpng/Makefile.in @@ -44,10 +44,10 @@ include $(DEPTH)/config/autoconf.mk MODULE = png LIBRARY_NAME = mozpng +FORCE_STATIC_LIB= 1 ifeq ($(OS_ARCH),WINNT) -LIBRARY_NAME = png +VISIBILITY_FLAGS= endif -LIBXUL_LIBRARY = 1 CSRCS = \ diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index a627e1fde096..c5584520a54a 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -334,7 +334,6 @@ endif EXTRA_DSO_LDOPTS += \ $(LIBS_DIR) \ $(JPEG_LIBS) \ - $(PNG_LIBS) \ $(QCMS_LIBS) \ $(MOZ_JS_LIBS) \ $(NSS_LIBS) \ @@ -344,6 +343,10 @@ EXTRA_DSO_LDOPTS += \ $(SQLITE_LIBS) \ $(NULL) +ifdef MOZ_NATIVE_PNG +EXTRA_DSO_LDOPTS += $(PNG_LIBS) +endif + ifdef MOZ_NATIVE_ZLIB EXTRA_DSO_LDOPTS += $(ZLIB_LIBS) else From 1a47114977d9acc3d100d7f352a196afd741c303 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Wed, 2 May 2012 09:28:52 -0400 Subject: [PATCH 134/159] Bug 750867 - Rip out libjpeg from libxul; r=khuey Landing on a CLOSED TREE --- layout/media/Makefile.in | 6 ++++++ layout/media/symbols.def.in | 24 ++++++++++++++++++++++++ media/libjpeg/Makefile.in | 4 +--- toolkit/library/Makefile.in | 5 ++++- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index 9dcf0f6911aa..c3eff7004a31 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -108,6 +108,12 @@ SHARED_LIBRARY_LIBS += \ $(NULL) endif +ifndef MOZ_NATIVE_JPEG +SHARED_LIBRARY_LIBS += \ + $(DEPTH)/media/libjpeg/$(LIB_PREFIX)mozjpeg.$(LIB_SUFFIX) \ + $(NULL) +endif + SHARED_LIBRARY_LIBS += \ $(DEPTH)/gfx/angle/$(LIB_PREFIX)angle.$(LIB_SUFFIX) \ $(NULL) diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index 74c553477ba1..de30819a9b9b 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -167,3 +167,27 @@ MOZ_PNG_write_end MOZ_PNG_write_info MOZ_PNG_write_row #endif +#ifndef MOZ_NATIVE_JPEG +jpeg_calc_output_dimensions +jpeg_consume_input +jpeg_CreateCompress +jpeg_CreateDecompress +jpeg_destroy_compress +jpeg_destroy_decompress +jpeg_finish_compress +jpeg_finish_decompress +jpeg_finish_output +jpeg_has_multiple_scans +jpeg_input_complete +jpeg_read_header +jpeg_read_scanlines +jpeg_resync_to_restart +jpeg_save_markers +jpeg_set_defaults +jpeg_set_quality +jpeg_start_compress +jpeg_start_decompress +jpeg_start_output +jpeg_std_error +jpeg_write_scanlines +#endif diff --git a/media/libjpeg/Makefile.in b/media/libjpeg/Makefile.in index f7507755bb70..f4ebc2c55845 100644 --- a/media/libjpeg/Makefile.in +++ b/media/libjpeg/Makefile.in @@ -48,11 +48,9 @@ MODULE = jpeg LIBRARY_NAME = mozjpeg ifeq ($(OS_ARCH),WINNT) -LIBRARY_NAME = jpeg32$(VERSION_NUMBER) +VISIBILITY_FLAGS = endif -GRE_MODULE = 1 - CSRCS = \ jcomapi.c \ jdapimin.c \ diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index c5584520a54a..0a5073edddbf 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -333,7 +333,6 @@ endif EXTRA_DSO_LDOPTS += \ $(LIBS_DIR) \ - $(JPEG_LIBS) \ $(QCMS_LIBS) \ $(MOZ_JS_LIBS) \ $(NSS_LIBS) \ @@ -343,6 +342,10 @@ EXTRA_DSO_LDOPTS += \ $(SQLITE_LIBS) \ $(NULL) +ifdef MOZ_NATIVE_JPEG +EXTRA_DSO_LDOPTS += $(JPEG_LIBS) +endif + ifdef MOZ_NATIVE_PNG EXTRA_DSO_LDOPTS += $(PNG_LIBS) endif From c40417ceb509b14c0a3fa2972a4d15f576685ae3 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Wed, 2 May 2012 10:04:33 -0400 Subject: [PATCH 135/159] Backout changeset e58855b90cf6 (bug 750747) because of build bustage of a CLOSED TREE --- layout/media/Makefile.in | 6 ----- layout/media/symbols.def.in | 52 ------------------------------------- media/libpng/Makefile.in | 4 +-- toolkit/library/Makefile.in | 5 +--- 4 files changed, 3 insertions(+), 64 deletions(-) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index c3eff7004a31..81fa2bcb91f2 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -102,12 +102,6 @@ SHARED_LIBRARY_LIBS += \ $(NULL) endif -ifndef MOZ_NATIVE_PNG -SHARED_LIBRARY_LIBS += \ - $(DEPTH)/media/libpng/$(LIB_PREFIX)mozpng.$(LIB_SUFFIX) \ - $(NULL) -endif - ifndef MOZ_NATIVE_JPEG SHARED_LIBRARY_LIBS += \ $(DEPTH)/media/libjpeg/$(LIB_PREFIX)mozjpeg.$(LIB_SUFFIX) \ diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index de30819a9b9b..02b2c15b01de 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -115,58 +115,6 @@ ShGetInfo ShConstructCompiler ShGetActiveAttrib ShGetActiveUniform -#ifndef MOZ_NATIVE_PNG -MOZ_APNG_get_first_frame_is_hidden -MOZ_APNG_get_next_frame_blend_op -MOZ_APNG_get_next_frame_delay_den -MOZ_APNG_get_next_frame_delay_num -MOZ_APNG_get_next_frame_dispose_op -MOZ_APNG_set_prog_frame_fn -MOZ_APNG_get_next_frame_height -MOZ_APNG_get_next_frame_width -MOZ_APNG_get_next_frame_x_offset -MOZ_APNG_get_next_frame_y_offset -MOZ_APNG_set_acTL -MOZ_APNG_set_first_frame_is_hidden -MOZ_APNG_set_num_plays -MOZ_APNG_write_frame_head -MOZ_APNG_write_frame_tail -MOZ_PNG_cr_info_str -MOZ_PNG_cr_read_str -MOZ_PNG_cr_write_str -MOZ_PNG_dest_read_str -MOZ_PNG_dest_write_str -MOZ_PNG_free_data -MOZ_PNG_get_channels -MOZ_PNG_get_cHRM -MOZ_PNG_get_gAMA -MOZ_PNG_get_IHDR -MOZ_PNG_get_iCCP -MOZ_PNG_get_io_ptr -MOZ_PNG_get_progressive_ptr -MOZ_PNG_get_sRGB -MOZ_PNG_get_tRNS -MOZ_PNG_get_valid -MOZ_PNG_longjmp -MOZ_PNG_process_data -MOZ_PNG_progressive_combine_row -MOZ_PNG_read_update_info -MOZ_PNG_set_cHRM -MOZ_PNG_set_crc_action -MOZ_PNG_set_gAMA -MOZ_PNG_set_gamma -MOZ_PNG_set_gray_to_rgb -MOZ_PNG_set_expand -MOZ_PNG_set_IHDR -MOZ_PNG_set_interlace_handling -MOZ_PNG_set_longjmp_fn -MOZ_PNG_set_progressive_read_fn -MOZ_PNG_set_scale_16 -MOZ_PNG_set_write_fn -MOZ_PNG_write_end -MOZ_PNG_write_info -MOZ_PNG_write_row -#endif #ifndef MOZ_NATIVE_JPEG jpeg_calc_output_dimensions jpeg_consume_input diff --git a/media/libpng/Makefile.in b/media/libpng/Makefile.in index 3001e6df505e..9058a73f27b9 100644 --- a/media/libpng/Makefile.in +++ b/media/libpng/Makefile.in @@ -44,10 +44,10 @@ include $(DEPTH)/config/autoconf.mk MODULE = png LIBRARY_NAME = mozpng -FORCE_STATIC_LIB= 1 ifeq ($(OS_ARCH),WINNT) -VISIBILITY_FLAGS= +LIBRARY_NAME = png endif +LIBXUL_LIBRARY = 1 CSRCS = \ diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index 0a5073edddbf..e6f5aae423ef 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -333,6 +333,7 @@ endif EXTRA_DSO_LDOPTS += \ $(LIBS_DIR) \ + $(PNG_LIBS) \ $(QCMS_LIBS) \ $(MOZ_JS_LIBS) \ $(NSS_LIBS) \ @@ -346,10 +347,6 @@ ifdef MOZ_NATIVE_JPEG EXTRA_DSO_LDOPTS += $(JPEG_LIBS) endif -ifdef MOZ_NATIVE_PNG -EXTRA_DSO_LDOPTS += $(PNG_LIBS) -endif - ifdef MOZ_NATIVE_ZLIB EXTRA_DSO_LDOPTS += $(ZLIB_LIBS) else From bc1fb7a14e0acac0c456fab4bb45812ae27e06fb Mon Sep 17 00:00:00 2001 From: Ted Mielczarek <ted.mielczarek@gmail.com> Date: Wed, 2 May 2012 07:15:07 -0400 Subject: [PATCH 136/159] bug 740242 - add some diagnostics to get more info about Python exceptions during Mochitest. r=jmaher, a=test-only --- build/automation.py.in | 2 +- testing/mochitest/runtests.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/automation.py.in b/build/automation.py.in index c291ac5ff0eb..78ccc5d451e8 100644 --- a/build/automation.py.in +++ b/build/automation.py.in @@ -792,13 +792,13 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t (line, didTimeout) = self.readWithTimeout(logsource, timeout) while line != "" and not didTimeout: + self.log.info(line.rstrip().decode("UTF-8", "ignore")) if logger: logger.log(line) if "TEST-START" in line and "|" in line: self.lastTestSeen = line.split("|")[1].strip() if stackFixerFunction: line = stackFixerFunction(line) - self.log.info(line.rstrip().decode("UTF-8", "ignore")) if not debuggerInfo and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line: if self.haveDumpedScreen: self.log.info("Not taking screenshot here: see the one that was previously logged") diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index 2b324bf77f99..4e464bf6e910 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -700,7 +700,7 @@ class Mochitest(object): self.automation.log.info("INFO | runtests.py | Received keyboard interrupt.\n"); status = -1 except: - self.automation.log.info("INFO | runtests.py | Received unexpected exception while running application '%s'\n" % (sys.exc_info()[1])) + self.automation.log.exception("INFO | runtests.py | Received unexpected exception while running application\n") status = 1 if options.vmwareRecording: From 67f5e36a7d2b10d0aa196f81a8771fb2845fad49 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek <ted.mielczarek@gmail.com> Date: Wed, 2 May 2012 07:15:07 -0400 Subject: [PATCH 137/159] bug 748797 - support MOZ_LINKER_EXTRACT=1 as a configure option to turn on linker extraction all the time. r=glandium,blassey, a=android-only CLOSED TREE --- config/autoconf.mk.in | 2 ++ configure.in | 1 + mobile/android/base/App.java.in | 7 +++++++ mobile/android/base/GeckoApp.java | 4 ++++ mobile/android/base/GeckoAppShell.java | 27 +++++++++++++++----------- mobile/android/base/Makefile.in | 4 ++++ 6 files changed, 34 insertions(+), 11 deletions(-) diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index 821ea8a22889..d61d56312c47 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -715,6 +715,8 @@ MOZ_SYSTEM_PLY = @MOZ_SYSTEM_PLY@ MOZ_PACKAGE_JSSHELL = @MOZ_PACKAGE_JSSHELL@ +MOZ_LINKER_EXTRACT = @MOZ_LINKER_EXTRACT@ + # We only want to do the pymake sanity on Windows, other os's can cope ifeq ($(HOST_OS_ARCH),WINNT) # Ensure invariants between GNU Make and pymake diff --git a/configure.in b/configure.in index 04424af366c1..773b86512e26 100644 --- a/configure.in +++ b/configure.in @@ -8490,6 +8490,7 @@ AC_SUBST(MOZ_OS2_TOOLS) AC_SUBST(MOZ_POST_DSO_LIB_COMMAND) AC_SUBST(MOZ_POST_PROGRAM_COMMAND) +AC_SUBST(MOZ_LINKER_EXTRACT) dnl ======================================================== dnl = Mac bundle name prefix diff --git a/mobile/android/base/App.java.in b/mobile/android/base/App.java.in index 3a96303f5455..4c324d30e569 100644 --- a/mobile/android/base/App.java.in +++ b/mobile/android/base/App.java.in @@ -79,5 +79,12 @@ public class App extends GeckoApp { #endif return super.onOptionsItemSelected(item); } + +#ifdef MOZ_LINKER_EXTRACT + @Override + public boolean linkerExtract() { + return true; + } +#endif }; diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index dc5b7d3ae4dd..8d1a992d1eb7 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -2831,4 +2831,8 @@ abstract public class GeckoApp } }); } + + public boolean linkerExtract() { + return false; + } } \ No newline at end of file diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 6c506fc74783..cecc8f902f59 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -310,21 +310,26 @@ public class GeckoAppShell File cacheFile = getCacheDir(context); putenv("GRE_HOME=" + getGREDir(context).getPath()); - File[] files = cacheFile.listFiles(); - if (files != null) { - Iterator<File> cacheFiles = Arrays.asList(files).iterator(); - while (cacheFiles.hasNext()) { - File libFile = cacheFiles.next(); - if (libFile.getName().endsWith(".so")) - libFile.delete(); - } - } // setup the libs cache String linkerCache = System.getenv("MOZ_LINKER_CACHE"); - if (System.getenv("MOZ_LINKER_CACHE") == null) { - GeckoAppShell.putenv("MOZ_LINKER_CACHE=" + cacheFile.getPath()); + if (linkerCache == null) { + linkerCache = cacheFile.getPath(); + GeckoAppShell.putenv("MOZ_LINKER_CACHE=" + linkerCache); } + + if (GeckoApp.mAppContext != null && + GeckoApp.mAppContext.linkerExtract()) { + GeckoAppShell.putenv("MOZ_LINKER_EXTRACT=1"); + // Ensure that the cache dir is world-writable + File cacheDir = new File(linkerCache); + if (cacheDir.isDirectory()) { + cacheDir.setWritable(true, false); + cacheDir.setExecutable(true, false); + cacheDir.setReadable(true, false); + } + } + sLibsSetup = true; } diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index a454755046ae..df0bc30310e1 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -212,6 +212,10 @@ DEFINES += \ -DUA_BUILDID=$(UA_BUILDID) \ $(NULL) +ifdef MOZ_LINKER_EXTRACT +DEFINES += -DMOZ_LINKER_EXTRACT=1 +endif + GARBAGE += \ AndroidManifest.xml \ classes.dex \ From d834ad844c41e0f7ef1053a2797d4c820ca7f5a8 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Wed, 2 May 2012 11:02:15 -0400 Subject: [PATCH 138/159] Bug 750747 - Rip out libpng from libxul; r=khuey Landing on a CLOSED TREE --- layout/media/Makefile.in | 6 +++++ layout/media/symbols.def.in | 52 +++++++++++++++++++++++++++++++++++++ media/libpng/Makefile.in | 4 +-- toolkit/library/Makefile.in | 5 +++- 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index 81fa2bcb91f2..c3eff7004a31 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -102,6 +102,12 @@ SHARED_LIBRARY_LIBS += \ $(NULL) endif +ifndef MOZ_NATIVE_PNG +SHARED_LIBRARY_LIBS += \ + $(DEPTH)/media/libpng/$(LIB_PREFIX)mozpng.$(LIB_SUFFIX) \ + $(NULL) +endif + ifndef MOZ_NATIVE_JPEG SHARED_LIBRARY_LIBS += \ $(DEPTH)/media/libjpeg/$(LIB_PREFIX)mozjpeg.$(LIB_SUFFIX) \ diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index 02b2c15b01de..de30819a9b9b 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -115,6 +115,58 @@ ShGetInfo ShConstructCompiler ShGetActiveAttrib ShGetActiveUniform +#ifndef MOZ_NATIVE_PNG +MOZ_APNG_get_first_frame_is_hidden +MOZ_APNG_get_next_frame_blend_op +MOZ_APNG_get_next_frame_delay_den +MOZ_APNG_get_next_frame_delay_num +MOZ_APNG_get_next_frame_dispose_op +MOZ_APNG_set_prog_frame_fn +MOZ_APNG_get_next_frame_height +MOZ_APNG_get_next_frame_width +MOZ_APNG_get_next_frame_x_offset +MOZ_APNG_get_next_frame_y_offset +MOZ_APNG_set_acTL +MOZ_APNG_set_first_frame_is_hidden +MOZ_APNG_set_num_plays +MOZ_APNG_write_frame_head +MOZ_APNG_write_frame_tail +MOZ_PNG_cr_info_str +MOZ_PNG_cr_read_str +MOZ_PNG_cr_write_str +MOZ_PNG_dest_read_str +MOZ_PNG_dest_write_str +MOZ_PNG_free_data +MOZ_PNG_get_channels +MOZ_PNG_get_cHRM +MOZ_PNG_get_gAMA +MOZ_PNG_get_IHDR +MOZ_PNG_get_iCCP +MOZ_PNG_get_io_ptr +MOZ_PNG_get_progressive_ptr +MOZ_PNG_get_sRGB +MOZ_PNG_get_tRNS +MOZ_PNG_get_valid +MOZ_PNG_longjmp +MOZ_PNG_process_data +MOZ_PNG_progressive_combine_row +MOZ_PNG_read_update_info +MOZ_PNG_set_cHRM +MOZ_PNG_set_crc_action +MOZ_PNG_set_gAMA +MOZ_PNG_set_gamma +MOZ_PNG_set_gray_to_rgb +MOZ_PNG_set_expand +MOZ_PNG_set_IHDR +MOZ_PNG_set_interlace_handling +MOZ_PNG_set_longjmp_fn +MOZ_PNG_set_progressive_read_fn +MOZ_PNG_set_scale_16 +MOZ_PNG_set_write_fn +MOZ_PNG_write_end +MOZ_PNG_write_info +MOZ_PNG_write_row +#endif #ifndef MOZ_NATIVE_JPEG jpeg_calc_output_dimensions jpeg_consume_input diff --git a/media/libpng/Makefile.in b/media/libpng/Makefile.in index 9058a73f27b9..3001e6df505e 100644 --- a/media/libpng/Makefile.in +++ b/media/libpng/Makefile.in @@ -44,10 +44,10 @@ include $(DEPTH)/config/autoconf.mk MODULE = png LIBRARY_NAME = mozpng +FORCE_STATIC_LIB= 1 ifeq ($(OS_ARCH),WINNT) -LIBRARY_NAME = png +VISIBILITY_FLAGS= endif -LIBXUL_LIBRARY = 1 CSRCS = \ diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index e6f5aae423ef..0a5073edddbf 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -333,7 +333,6 @@ endif EXTRA_DSO_LDOPTS += \ $(LIBS_DIR) \ - $(PNG_LIBS) \ $(QCMS_LIBS) \ $(MOZ_JS_LIBS) \ $(NSS_LIBS) \ @@ -347,6 +346,10 @@ ifdef MOZ_NATIVE_JPEG EXTRA_DSO_LDOPTS += $(JPEG_LIBS) endif +ifdef MOZ_NATIVE_PNG +EXTRA_DSO_LDOPTS += $(PNG_LIBS) +endif + ifdef MOZ_NATIVE_ZLIB EXTRA_DSO_LDOPTS += $(ZLIB_LIBS) else From 43cc1f598f6440690cff3e6096a78f887a78f7d1 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Wed, 2 May 2012 14:05:46 -0400 Subject: [PATCH 139/159] Bug 751186 - Rip out qcms from libxul; r=khuey Landed on a CLOSED TREE --- layout/media/Makefile.in | 2 +- layout/media/symbols.def.in | 14 ++++++++++++++ toolkit/library/Makefile.in | 1 - 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index c3eff7004a31..e0d4fec2b3ff 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -49,7 +49,7 @@ ifeq (WINNT,$(OS_TARGET)) FORCE_SHARED_LIB = 1 endif -SHARED_LIBRARY_LIBS = $(MOZ_OTS_LIBS) +SHARED_LIBRARY_LIBS = $(MOZ_OTS_LIBS) $(QCMS_LIBS) ifdef MOZ_GRAPHITE SHARED_LIBRARY_LIBS += $(MOZ_GRAPHITE_LIBS) diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index de30819a9b9b..dcbedcc2c829 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -191,3 +191,17 @@ jpeg_start_output jpeg_std_error jpeg_write_scanlines #endif +qcms_enable_iccv4 +qcms_profile_create_rgb_with_gamma +qcms_profile_from_memory +qcms_profile_from_path +qcms_profile_from_unicode_path +qcms_profile_get_color_space +qcms_profile_get_rendering_intent +qcms_profile_is_bogus +qcms_profile_precache_output_transform +qcms_profile_release +qcms_profile_sRGB +qcms_transform_create +qcms_transform_data +qcms_transform_release diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index 0a5073edddbf..ba4df6e434b1 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -333,7 +333,6 @@ endif EXTRA_DSO_LDOPTS += \ $(LIBS_DIR) \ - $(QCMS_LIBS) \ $(MOZ_JS_LIBS) \ $(NSS_LIBS) \ $(MOZ_CAIRO_LIBS) \ From 147de6e8d8129bec835625730e7f8ade453ec156 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Wed, 2 May 2012 14:10:53 -0400 Subject: [PATCH 140/159] Bug 751201 - Rip out expat from libxul Landed on a CLOSED TREE --- layout/media/Makefile.in | 1 + layout/media/symbols.def.in | 35 +++++++++++++++++++++++++++++++ parser/htmlparser/src/Makefile.in | 1 - 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index e0d4fec2b3ff..5c46e55c9ee6 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -116,6 +116,7 @@ endif SHARED_LIBRARY_LIBS += \ $(DEPTH)/gfx/angle/$(LIB_PREFIX)angle.$(LIB_SUFFIX) \ + $(DEPTH)/parser/expat/lib/$(LIB_PREFIX)mozexpat_s.$(LIB_SUFFIX) \ $(NULL) ifeq (WINNT,$(OS_TARGET)) diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index dcbedcc2c829..cebac56e91a8 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -205,3 +205,38 @@ qcms_profile_sRGB qcms_transform_create qcms_transform_data qcms_transform_release +MOZ_XMLCheckQName +MOZ_XMLIsLetter +MOZ_XMLIsNCNameChar +MOZ_XMLTranslateEntity +MOZ_XML_ExternalEntityParserCreate +MOZ_XML_GetBase +MOZ_XML_GetCurrentByteIndex +MOZ_XML_GetCurrentColumnNumber +MOZ_XML_GetCurrentLineNumber +MOZ_XML_GetErrorCode +MOZ_XML_GetIdAttributeIndex +MOZ_XML_GetMismatchedTag +MOZ_XML_GetSpecifiedAttributeCount +MOZ_XML_Parse +MOZ_XML_ParserCreate_MM +MOZ_XML_ParserFree +MOZ_XML_ResumeParser +MOZ_XML_SetBase +MOZ_XML_SetCdataSectionHandler +MOZ_XML_SetCharacterDataHandler +MOZ_XML_SetCommentHandler +MOZ_XML_SetDefaultHandlerExpand +MOZ_XML_SetDoctypeDeclHandler +MOZ_XML_SetElementHandler +MOZ_XML_SetExternalEntityRefHandler +MOZ_XML_SetExternalEntityRefHandlerArg +MOZ_XML_SetNamespaceDeclHandler +MOZ_XML_SetNotationDeclHandler +MOZ_XML_SetParamEntityParsing +MOZ_XML_SetProcessingInstructionHandler +MOZ_XML_SetReturnNSTriplet +MOZ_XML_SetUnparsedEntityDeclHandler +MOZ_XML_SetUserData +MOZ_XML_SetXmlDeclHandler +MOZ_XML_StopParser diff --git a/parser/htmlparser/src/Makefile.in b/parser/htmlparser/src/Makefile.in index 4afe32346e6f..56c4d8954a4c 100644 --- a/parser/htmlparser/src/Makefile.in +++ b/parser/htmlparser/src/Makefile.in @@ -52,7 +52,6 @@ LIBXUL_LIBRARY = 1 SHARED_LIBRARY_LIBS = \ - $(DEPTH)/parser/expat/lib/$(LIB_PREFIX)mozexpat_s.$(LIB_SUFFIX) \ $(DEPTH)/parser/xml/src/$(LIB_PREFIX)saxp.$(LIB_SUFFIX) \ $(NULL) From d0be68448b25302827ed4671e020290a3c2c4bc1 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Wed, 2 May 2012 16:28:13 -0400 Subject: [PATCH 141/159] Bug 751273 - Part 1: Remove the debugging code in Cairo which we don't use any more; r=jrmuizel Landing on a CLOSED TREE --- gfx/cairo/cairo/src/cairo-spline.c | 23 ------------ widget/xpwidgets/GfxInfoBase.cpp | 60 ------------------------------ 2 files changed, 83 deletions(-) diff --git a/gfx/cairo/cairo/src/cairo-spline.c b/gfx/cairo/cairo/src/cairo-spline.c index e75ff5ee3260..ca2e2dc64c1a 100644 --- a/gfx/cairo/cairo/src/cairo-spline.c +++ b/gfx/cairo/cairo/src/cairo-spline.c @@ -183,26 +183,13 @@ _cairo_spline_error_squared (const cairo_spline_knots_t *knots) return cerr; } -void StoreSpline(int ax, int ay, int bx, int by, int cx, double cy, int dx, int dy); -void CrashSpline(double tolerance, int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy); - static cairo_status_t _cairo_spline_decompose_into (cairo_spline_knots_t *s1, double tolerance_squared, cairo_spline_t *result) { - static int depth; cairo_spline_knots_t s2; cairo_status_t status; - depth++; - if (depth == 200) { - CrashSpline(tolerance_squared, s1->a.x, s1->a.y, - s1->b.x, s1->b.y, - s1->c.x, s1->c.y, - s1->d.x, s1->d.y); - } - if (_cairo_spline_error_squared (s1) < tolerance_squared) { - depth--; return _cairo_spline_add_point (result, &s1->a); } @@ -210,12 +197,10 @@ _cairo_spline_decompose_into (cairo_spline_knots_t *s1, double tolerance_squared status = _cairo_spline_decompose_into (s1, tolerance_squared, result); if (unlikely (status)) { - depth--; return status; } status = _cairo_spline_decompose_into (&s2, tolerance_squared, result); - depth--; return status; } @@ -225,14 +210,6 @@ _cairo_spline_decompose (cairo_spline_t *spline, double tolerance) cairo_spline_knots_t s1; cairo_status_t status; - StoreSpline(spline->knots.a.x, - spline->knots.a.y, - spline->knots.b.x, - spline->knots.b.y, - spline->knots.c.x, - spline->knots.c.y, - spline->knots.d.x, - spline->knots.d.y); s1 = spline->knots; spline->last_point = s1.a; status = _cairo_spline_decompose_into (&s1, tolerance * tolerance, spline); diff --git a/widget/xpwidgets/GfxInfoBase.cpp b/widget/xpwidgets/GfxInfoBase.cpp index da66767bca5e..21317ce36688 100644 --- a/widget/xpwidgets/GfxInfoBase.cpp +++ b/widget/xpwidgets/GfxInfoBase.cpp @@ -114,66 +114,6 @@ void InitGfxDriverInfoShutdownObserver() observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); } -extern "C" { - void StoreSpline(int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy); - void CrashSpline(double tolerance, int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy); -} - -static int crash_ax; -static int crash_ay; -static int crash_bx; -static int crash_by; -static int crash_cx; -static int crash_cy; -static int crash_dx; -static int crash_dy; - -void -StoreSpline(int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy) { - crash_ax = ax; - crash_ay = ay; - crash_bx = bx; - crash_by = by; - crash_cx = cx; - crash_cy = cy; - crash_dx = dx; - crash_dy = dy; -} - -void -CrashSpline(double tolerance, int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy) { -#if defined(MOZ_CRASHREPORTER) - static bool annotated; - - if (!annotated) { - nsCAutoString note; - - note.AppendPrintf("curve "); - note.AppendPrintf("%x ", crash_ax); - note.AppendPrintf("%x, ", crash_ay); - note.AppendPrintf("%x ", crash_bx); - note.AppendPrintf("%x, ", crash_by); - note.AppendPrintf("%x ", crash_cx); - note.AppendPrintf("%x, ", crash_cy); - note.AppendPrintf("%x ", crash_dx); - note.AppendPrintf("%x\n", crash_dy); - note.AppendPrintf("crv-crash(%f): ", tolerance); - note.AppendPrintf("%x ", ax); - note.AppendPrintf("%x, ", ay); - note.AppendPrintf("%x ", bx); - note.AppendPrintf("%x, ", by); - note.AppendPrintf("%x ", cx); - note.AppendPrintf("%x, ", cy); - note.AppendPrintf("%x ", dx); - note.AppendPrintf("%x\n", dy); - - CrashReporter::AppendAppNotesToCrashReport(note); - annotated = true; - } -#endif -} - - using namespace mozilla::widget; using namespace mozilla; From 28ecf2b61bf5b77ae677228f82e0dd2a81eb9e1e Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Wed, 2 May 2012 16:32:16 -0400 Subject: [PATCH 142/159] Bug 751273 - Part 2: Rip out cairo and pixman from libxul; r=ted Landing on a CLOSED TREE --- layout/media/Makefile.in | 4 +- layout/media/symbols.def.in | 203 ++++++++++++++++++++++++++++++++++++ toolkit/library/Makefile.in | 3 +- 3 files changed, 207 insertions(+), 3 deletions(-) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index 5c46e55c9ee6..9ffd3cba353f 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -49,7 +49,7 @@ ifeq (WINNT,$(OS_TARGET)) FORCE_SHARED_LIB = 1 endif -SHARED_LIBRARY_LIBS = $(MOZ_OTS_LIBS) $(QCMS_LIBS) +SHARED_LIBRARY_LIBS = $(MOZ_OTS_LIBS) $(QCMS_LIBS) $(MOZ_CAIRO_LIBS) ifdef MOZ_GRAPHITE SHARED_LIBRARY_LIBS += $(MOZ_GRAPHITE_LIBS) @@ -138,6 +138,8 @@ ifeq (WINNT,$(OS_TARGET)) symbols.def: symbols.def.in $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(ACDEFINES) $< > $@ +OS_LIBS += $(call EXPAND_LIBNAME, msimg32) + ifdef MOZ_CUBEB OS_LIBS += $(call EXPAND_LIBNAME, winmm) endif diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index cebac56e91a8..1c17855cca5c 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -240,3 +240,206 @@ MOZ_XML_SetUnparsedEntityDeclHandler MOZ_XML_SetUserData MOZ_XML_SetXmlDeclHandler MOZ_XML_StopParser +_moz_cairo_append_path +_moz_cairo_arc +_moz_cairo_arc_negative +_moz_cairo_clip +_moz_cairo_clip_extents +_moz_cairo_clip_preserve +_moz_cairo_close_path +_moz_cairo_copy_clip_rectangle_list +_moz_cairo_copy_path +_moz_cairo_copy_path_flat +_moz_cairo_create +_moz_cairo_curve_to +_moz_cairo_debug_reset_static_data +_moz_cairo_destroy +_moz_cairo_device_to_user +_moz_cairo_device_to_user_distance +_moz_cairo_fill +_moz_cairo_fill_extents +_moz_cairo_fill_preserve +_moz_cairo_font_face_destroy +_moz_cairo_font_options_create +_moz_cairo_font_options_destroy +_moz_cairo_font_options_get_hint_metrics +_moz_cairo_font_options_set_antialias +_moz_cairo_format_stride_for_width +_moz_cairo_get_antialias +_moz_cairo_get_current_point +_moz_cairo_get_dash +_moz_cairo_get_dash_count +_moz_cairo_get_fill_rule +_moz_cairo_get_group_target +_moz_cairo_get_line_cap +_moz_cairo_get_line_join +_moz_cairo_get_line_width +_moz_cairo_get_matrix +_moz_cairo_get_miter_limit +_moz_cairo_get_operator +_moz_cairo_get_scaled_font +_moz_cairo_get_source +_moz_cairo_get_target +_moz_cairo_glyph_extents +_moz_cairo_glyph_path +_moz_cairo_identity_matrix +_moz_cairo_image_surface_create +_moz_cairo_image_surface_create_for_data +_moz_cairo_image_surface_get_data +_moz_cairo_image_surface_get_format +_moz_cairo_image_surface_get_height +_moz_cairo_image_surface_get_stride +_moz_cairo_image_surface_get_width +_moz_cairo_in_fill +_moz_cairo_in_stroke +_moz_cairo_line_to +_moz_cairo_mask +_moz_cairo_mask_surface +_moz_cairo_matrix_init +_moz_cairo_matrix_init_identity +_moz_cairo_matrix_init_scale +_moz_cairo_matrix_invert +_moz_cairo_matrix_multiply +_moz_cairo_matrix_rotate +_moz_cairo_matrix_scale +_moz_cairo_matrix_transform_distance +_moz_cairo_matrix_transform_point +_moz_cairo_matrix_translate +_moz_cairo_move_to +_moz_cairo_new_path +_moz_cairo_new_sub_path +_moz_cairo_paint +_moz_cairo_paint_with_alpha +_moz_cairo_path_destroy +_moz_cairo_path_extents +_moz_cairo_pattern_add_color_stop_rgba +_moz_cairo_pattern_create_for_surface +_moz_cairo_pattern_create_linear +_moz_cairo_pattern_create_radial +_moz_cairo_pattern_create_rgba +_moz_cairo_pattern_destroy +_moz_cairo_pattern_get_color_stop_count +_moz_cairo_pattern_get_color_stop_rgba +_moz_cairo_pattern_get_extend +_moz_cairo_pattern_get_filter +_moz_cairo_pattern_get_linear_points +_moz_cairo_pattern_get_matrix +_moz_cairo_pattern_get_radial_circles +_moz_cairo_pattern_get_rgba +_moz_cairo_pattern_get_surface +_moz_cairo_pattern_get_type +_moz_cairo_pattern_reference +_moz_cairo_pattern_set_extend +_moz_cairo_pattern_set_filter +_moz_cairo_pattern_set_matrix +_moz_cairo_pattern_status +_moz_cairo_pdf_surface_create_for_stream +_moz_cairo_pop_group +_moz_cairo_pop_group_to_source +_moz_cairo_push_group_with_content +_moz_cairo_rectangle +_moz_cairo_rectangle_list_destroy +_moz_cairo_reference +_moz_cairo_reset_clip +_moz_cairo_restore +_moz_cairo_rotate +_moz_cairo_save +_moz_cairo_scale +_moz_cairo_scaled_font_create +_moz_cairo_scaled_font_destroy +_moz_cairo_scaled_font_get_font_matrix +_moz_cairo_scaled_font_get_font_options +_moz_cairo_scaled_font_get_type +_moz_cairo_scaled_font_reference +_moz_cairo_scaled_font_status +_moz_cairo_set_antialias +_moz_cairo_set_dash +_moz_cairo_set_fill_rule +_moz_cairo_set_font_face +_moz_cairo_set_font_size +_moz_cairo_set_line_cap +_moz_cairo_set_line_join +_moz_cairo_set_line_width +_moz_cairo_set_matrix +_moz_cairo_set_miter_limit +_moz_cairo_set_operator +_moz_cairo_set_scaled_font +_moz_cairo_set_source +_moz_cairo_set_source_rgba +_moz_cairo_set_source_surface +_moz_cairo_show_glyphs +_moz_cairo_status +_moz_cairo_stroke +_moz_cairo_stroke_extents +_moz_cairo_stroke_preserve +_moz_cairo_surface_create_similar +_moz_cairo_surface_destroy +_moz_cairo_surface_finish +_moz_cairo_surface_flush +_moz_cairo_surface_get_content +_moz_cairo_surface_get_device_offset +_moz_cairo_surface_get_reference_count +_moz_cairo_surface_get_subpixel_antialiasing +_moz_cairo_surface_get_type +_moz_cairo_surface_get_user_data +_moz_cairo_surface_mark_dirty +_moz_cairo_surface_mark_dirty_rectangle +_moz_cairo_surface_reference +_moz_cairo_surface_set_device_offset +_moz_cairo_surface_set_fallback_resolution +_moz_cairo_surface_set_subpixel_antialiasing +_moz_cairo_surface_set_user_data +_moz_cairo_surface_show_page +_moz_cairo_surface_status +_moz_cairo_tee_surface_add +_moz_cairo_tee_surface_create +_moz_cairo_tee_surface_index +_moz_cairo_transform +_moz_cairo_translate +_moz_cairo_user_to_device +_moz_cairo_user_to_device_distance +_moz_cairo_win32_font_face_create_for_logfontw_hfont +_moz_cairo_win32_printing_surface_create +_moz_cairo_win32_scaled_font_select_font +_moz_cairo_win32_surface_create +_moz_cairo_win32_surface_create_with_ddb +_moz_cairo_win32_surface_create_with_dib +_moz_cairo_win32_surface_get_dc +_moz_cairo_win32_surface_get_image +_moz_pixman_image_composite32 +_moz_pixman_image_create_bits +_moz_pixman_image_set_transform +_moz_pixman_image_unref +_moz_pixman_transform_from_pixman_f_transform +_moz_pixman_transform_invert +cairo_d2d_create_device +cairo_d2d_create_device_from_d3d10device +cairo_d2d_device_get_device +cairo_d2d_get_dc +cairo_d2d_get_image_surface_cache_usage +cairo_d2d_get_surface_vram_usage +cairo_d2d_present_backbuffer +cairo_d2d_release_dc +cairo_d2d_scroll +cairo_d2d_surface_create +cairo_d2d_surface_create_for_handle +cairo_d2d_surface_create_for_hwnd +cairo_d2d_surface_create_for_texture +cairo_d2d_surface_get_height +cairo_d2d_surface_get_texture +cairo_d2d_surface_get_width +cairo_dwrite_font_face_create_for_dwrite_fontface +cairo_dwrite_get_cleartype_rendering_mode +cairo_dwrite_scaled_font_allow_manual_show_glyphs +cairo_dwrite_scaled_font_get_force_GDI_classic +cairo_dwrite_scaled_font_set_force_GDI_classic +cairo_dwrite_set_cleartype_params +cairo_null_surface_create +cairo_release_device +cairo_surface_attach_snapshot +cairo_win32_get_dc_with_clip +cairo_win32_get_system_text_quality +cairo_win32_surface_create_with_alpha +cairo_win32_surface_get_height +cairo_win32_surface_get_width +cairo_win32_surface_set_can_convert_to_dib diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index ba4df6e434b1..d0f39251cc48 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -335,7 +335,6 @@ EXTRA_DSO_LDOPTS += \ $(LIBS_DIR) \ $(MOZ_JS_LIBS) \ $(NSS_LIBS) \ - $(MOZ_CAIRO_LIBS) \ $(MOZ_HARFBUZZ_LIBS) \ $(MOZ_APP_EXTRA_LIBS) \ $(SQLITE_LIBS) \ @@ -523,7 +522,7 @@ endif endif ifeq ($(OS_ARCH),WINNT) -OS_LIBS += $(call EXPAND_LIBNAME,shell32 ole32 version winspool comdlg32 imm32 msimg32 shlwapi psapi ws2_32 dbghelp rasapi32 rasdlg iphlpapi uxtheme setupapi secur32 sensorsapi portabledeviceguids) +OS_LIBS += $(call EXPAND_LIBNAME,shell32 ole32 version winspool comdlg32 imm32 msimg32 shlwapi psapi ws2_32 dbghelp rasapi32 rasdlg iphlpapi uxtheme setupapi secur32 sensorsapi portabledeviceguids windowscodecs) ifdef MOZ_CRASHREPORTER OS_LIBS += $(call EXPAND_LIBNAME,wininet) endif From 5d044656b75d8b5315d8427904d9e6c9aba052b2 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Wed, 2 May 2012 16:46:25 -0400 Subject: [PATCH 143/159] Backed out changeset 27c51f14c3ed (bug 751273) because of build bustage on Linux on a CLOSED TREE --- layout/media/Makefile.in | 4 +- layout/media/symbols.def.in | 203 ------------------------------------ toolkit/library/Makefile.in | 3 +- 3 files changed, 3 insertions(+), 207 deletions(-) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index 9ffd3cba353f..5c46e55c9ee6 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -49,7 +49,7 @@ ifeq (WINNT,$(OS_TARGET)) FORCE_SHARED_LIB = 1 endif -SHARED_LIBRARY_LIBS = $(MOZ_OTS_LIBS) $(QCMS_LIBS) $(MOZ_CAIRO_LIBS) +SHARED_LIBRARY_LIBS = $(MOZ_OTS_LIBS) $(QCMS_LIBS) ifdef MOZ_GRAPHITE SHARED_LIBRARY_LIBS += $(MOZ_GRAPHITE_LIBS) @@ -138,8 +138,6 @@ ifeq (WINNT,$(OS_TARGET)) symbols.def: symbols.def.in $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(ACDEFINES) $< > $@ -OS_LIBS += $(call EXPAND_LIBNAME, msimg32) - ifdef MOZ_CUBEB OS_LIBS += $(call EXPAND_LIBNAME, winmm) endif diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index 1c17855cca5c..cebac56e91a8 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -240,206 +240,3 @@ MOZ_XML_SetUnparsedEntityDeclHandler MOZ_XML_SetUserData MOZ_XML_SetXmlDeclHandler MOZ_XML_StopParser -_moz_cairo_append_path -_moz_cairo_arc -_moz_cairo_arc_negative -_moz_cairo_clip -_moz_cairo_clip_extents -_moz_cairo_clip_preserve -_moz_cairo_close_path -_moz_cairo_copy_clip_rectangle_list -_moz_cairo_copy_path -_moz_cairo_copy_path_flat -_moz_cairo_create -_moz_cairo_curve_to -_moz_cairo_debug_reset_static_data -_moz_cairo_destroy -_moz_cairo_device_to_user -_moz_cairo_device_to_user_distance -_moz_cairo_fill -_moz_cairo_fill_extents -_moz_cairo_fill_preserve -_moz_cairo_font_face_destroy -_moz_cairo_font_options_create -_moz_cairo_font_options_destroy -_moz_cairo_font_options_get_hint_metrics -_moz_cairo_font_options_set_antialias -_moz_cairo_format_stride_for_width -_moz_cairo_get_antialias -_moz_cairo_get_current_point -_moz_cairo_get_dash -_moz_cairo_get_dash_count -_moz_cairo_get_fill_rule -_moz_cairo_get_group_target -_moz_cairo_get_line_cap -_moz_cairo_get_line_join -_moz_cairo_get_line_width -_moz_cairo_get_matrix -_moz_cairo_get_miter_limit -_moz_cairo_get_operator -_moz_cairo_get_scaled_font -_moz_cairo_get_source -_moz_cairo_get_target -_moz_cairo_glyph_extents -_moz_cairo_glyph_path -_moz_cairo_identity_matrix -_moz_cairo_image_surface_create -_moz_cairo_image_surface_create_for_data -_moz_cairo_image_surface_get_data -_moz_cairo_image_surface_get_format -_moz_cairo_image_surface_get_height -_moz_cairo_image_surface_get_stride -_moz_cairo_image_surface_get_width -_moz_cairo_in_fill -_moz_cairo_in_stroke -_moz_cairo_line_to -_moz_cairo_mask -_moz_cairo_mask_surface -_moz_cairo_matrix_init -_moz_cairo_matrix_init_identity -_moz_cairo_matrix_init_scale -_moz_cairo_matrix_invert -_moz_cairo_matrix_multiply -_moz_cairo_matrix_rotate -_moz_cairo_matrix_scale -_moz_cairo_matrix_transform_distance -_moz_cairo_matrix_transform_point -_moz_cairo_matrix_translate -_moz_cairo_move_to -_moz_cairo_new_path -_moz_cairo_new_sub_path -_moz_cairo_paint -_moz_cairo_paint_with_alpha -_moz_cairo_path_destroy -_moz_cairo_path_extents -_moz_cairo_pattern_add_color_stop_rgba -_moz_cairo_pattern_create_for_surface -_moz_cairo_pattern_create_linear -_moz_cairo_pattern_create_radial -_moz_cairo_pattern_create_rgba -_moz_cairo_pattern_destroy -_moz_cairo_pattern_get_color_stop_count -_moz_cairo_pattern_get_color_stop_rgba -_moz_cairo_pattern_get_extend -_moz_cairo_pattern_get_filter -_moz_cairo_pattern_get_linear_points -_moz_cairo_pattern_get_matrix -_moz_cairo_pattern_get_radial_circles -_moz_cairo_pattern_get_rgba -_moz_cairo_pattern_get_surface -_moz_cairo_pattern_get_type -_moz_cairo_pattern_reference -_moz_cairo_pattern_set_extend -_moz_cairo_pattern_set_filter -_moz_cairo_pattern_set_matrix -_moz_cairo_pattern_status -_moz_cairo_pdf_surface_create_for_stream -_moz_cairo_pop_group -_moz_cairo_pop_group_to_source -_moz_cairo_push_group_with_content -_moz_cairo_rectangle -_moz_cairo_rectangle_list_destroy -_moz_cairo_reference -_moz_cairo_reset_clip -_moz_cairo_restore -_moz_cairo_rotate -_moz_cairo_save -_moz_cairo_scale -_moz_cairo_scaled_font_create -_moz_cairo_scaled_font_destroy -_moz_cairo_scaled_font_get_font_matrix -_moz_cairo_scaled_font_get_font_options -_moz_cairo_scaled_font_get_type -_moz_cairo_scaled_font_reference -_moz_cairo_scaled_font_status -_moz_cairo_set_antialias -_moz_cairo_set_dash -_moz_cairo_set_fill_rule -_moz_cairo_set_font_face -_moz_cairo_set_font_size -_moz_cairo_set_line_cap -_moz_cairo_set_line_join -_moz_cairo_set_line_width -_moz_cairo_set_matrix -_moz_cairo_set_miter_limit -_moz_cairo_set_operator -_moz_cairo_set_scaled_font -_moz_cairo_set_source -_moz_cairo_set_source_rgba -_moz_cairo_set_source_surface -_moz_cairo_show_glyphs -_moz_cairo_status -_moz_cairo_stroke -_moz_cairo_stroke_extents -_moz_cairo_stroke_preserve -_moz_cairo_surface_create_similar -_moz_cairo_surface_destroy -_moz_cairo_surface_finish -_moz_cairo_surface_flush -_moz_cairo_surface_get_content -_moz_cairo_surface_get_device_offset -_moz_cairo_surface_get_reference_count -_moz_cairo_surface_get_subpixel_antialiasing -_moz_cairo_surface_get_type -_moz_cairo_surface_get_user_data -_moz_cairo_surface_mark_dirty -_moz_cairo_surface_mark_dirty_rectangle -_moz_cairo_surface_reference -_moz_cairo_surface_set_device_offset -_moz_cairo_surface_set_fallback_resolution -_moz_cairo_surface_set_subpixel_antialiasing -_moz_cairo_surface_set_user_data -_moz_cairo_surface_show_page -_moz_cairo_surface_status -_moz_cairo_tee_surface_add -_moz_cairo_tee_surface_create -_moz_cairo_tee_surface_index -_moz_cairo_transform -_moz_cairo_translate -_moz_cairo_user_to_device -_moz_cairo_user_to_device_distance -_moz_cairo_win32_font_face_create_for_logfontw_hfont -_moz_cairo_win32_printing_surface_create -_moz_cairo_win32_scaled_font_select_font -_moz_cairo_win32_surface_create -_moz_cairo_win32_surface_create_with_ddb -_moz_cairo_win32_surface_create_with_dib -_moz_cairo_win32_surface_get_dc -_moz_cairo_win32_surface_get_image -_moz_pixman_image_composite32 -_moz_pixman_image_create_bits -_moz_pixman_image_set_transform -_moz_pixman_image_unref -_moz_pixman_transform_from_pixman_f_transform -_moz_pixman_transform_invert -cairo_d2d_create_device -cairo_d2d_create_device_from_d3d10device -cairo_d2d_device_get_device -cairo_d2d_get_dc -cairo_d2d_get_image_surface_cache_usage -cairo_d2d_get_surface_vram_usage -cairo_d2d_present_backbuffer -cairo_d2d_release_dc -cairo_d2d_scroll -cairo_d2d_surface_create -cairo_d2d_surface_create_for_handle -cairo_d2d_surface_create_for_hwnd -cairo_d2d_surface_create_for_texture -cairo_d2d_surface_get_height -cairo_d2d_surface_get_texture -cairo_d2d_surface_get_width -cairo_dwrite_font_face_create_for_dwrite_fontface -cairo_dwrite_get_cleartype_rendering_mode -cairo_dwrite_scaled_font_allow_manual_show_glyphs -cairo_dwrite_scaled_font_get_force_GDI_classic -cairo_dwrite_scaled_font_set_force_GDI_classic -cairo_dwrite_set_cleartype_params -cairo_null_surface_create -cairo_release_device -cairo_surface_attach_snapshot -cairo_win32_get_dc_with_clip -cairo_win32_get_system_text_quality -cairo_win32_surface_create_with_alpha -cairo_win32_surface_get_height -cairo_win32_surface_get_width -cairo_win32_surface_set_can_convert_to_dib diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index d0f39251cc48..ba4df6e434b1 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -335,6 +335,7 @@ EXTRA_DSO_LDOPTS += \ $(LIBS_DIR) \ $(MOZ_JS_LIBS) \ $(NSS_LIBS) \ + $(MOZ_CAIRO_LIBS) \ $(MOZ_HARFBUZZ_LIBS) \ $(MOZ_APP_EXTRA_LIBS) \ $(SQLITE_LIBS) \ @@ -522,7 +523,7 @@ endif endif ifeq ($(OS_ARCH),WINNT) -OS_LIBS += $(call EXPAND_LIBNAME,shell32 ole32 version winspool comdlg32 imm32 msimg32 shlwapi psapi ws2_32 dbghelp rasapi32 rasdlg iphlpapi uxtheme setupapi secur32 sensorsapi portabledeviceguids windowscodecs) +OS_LIBS += $(call EXPAND_LIBNAME,shell32 ole32 version winspool comdlg32 imm32 msimg32 shlwapi psapi ws2_32 dbghelp rasapi32 rasdlg iphlpapi uxtheme setupapi secur32 sensorsapi portabledeviceguids) ifdef MOZ_CRASHREPORTER OS_LIBS += $(call EXPAND_LIBNAME,wininet) endif From 26ec731b76da2351e2b47495e45615b3e70d20de Mon Sep 17 00:00:00 2001 From: Bobby Holley <bobbyholley@gmail.com> Date: Wed, 2 May 2012 23:57:34 +0200 Subject: [PATCH 144/159] Bug 750859 - remove unused (or seldom-used) PrivilegeManager functions. r=bz --- caps/src/nsSecurityManagerFactory.cpp | 177 -------------------------- content/base/test/test_bug466080.html | 4 +- content/base/test/test_bug482935.html | 4 +- 3 files changed, 2 insertions(+), 183 deletions(-) diff --git a/caps/src/nsSecurityManagerFactory.cpp b/caps/src/nsSecurityManagerFactory.cpp index b3ba0ecb9c2b..bf83cbc7703c 100644 --- a/caps/src/nsSecurityManagerFactory.cpp +++ b/caps/src/nsSecurityManagerFactory.cpp @@ -95,63 +95,6 @@ getBytesArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, unsigned argc, j return str && bytes->encode(cx, str); } -static void -getUTF8StringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, - unsigned argc, jsval *argv, nsCString& aRetval) -{ - aRetval.Truncate(); - - if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) { - JS_ReportError(cx, "String argument expected"); - return; - } - - /* - * We don't want to use JS_ValueToString because we want to be able - * to have an object to represent a target in subsequent versions. - */ - JSString *str = JSVAL_TO_STRING(argv[argNum]); - if (!str) - return; - - const PRUnichar *data = JS_GetStringCharsZ(cx, str); - if (!data) - return; - - CopyUTF16toUTF8(data, aRetval); -} - -static JSBool -netscape_security_isPrivilegeEnabled(JSContext *cx, unsigned argc, jsval *vp) -{ - JSObject *obj = JS_THIS_OBJECT(cx, vp); - if (!obj) - return JS_FALSE; - - bool result = false; - if (JSString *str = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp))) { - JSAutoByteString cap(cx, str); - if (!cap) - return JS_FALSE; - - nsresult rv; - nsCOMPtr<nsIScriptSecurityManager> securityManager = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - if (NS_SUCCEEDED(rv)) { - // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); - - rv = securityManager->IsCapabilityEnabled(cap.ptr(), &result); - if (NS_FAILED(rv)) - result = JS_FALSE; - } - } else { - return JS_FALSE; - } - JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(result)); - return JS_TRUE; -} - - static JSBool netscape_security_enablePrivilege(JSContext *cx, unsigned argc, jsval *vp) { @@ -195,128 +138,8 @@ netscape_security_enablePrivilege(JSContext *cx, unsigned argc, jsval *vp) return JS_TRUE; } -static JSBool -netscape_security_disablePrivilege(JSContext *cx, unsigned argc, jsval *vp) -{ - JSObject *obj = JS_THIS_OBJECT(cx, vp); - if (!obj) - return JS_FALSE; - - JSAutoByteString cap; - if (!getBytesArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), &cap)) - return JS_FALSE; - - nsresult rv; - nsCOMPtr<nsIScriptSecurityManager> securityManager = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - if (NS_FAILED(rv)) - return JS_FALSE; - - // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); - - rv = securityManager->DisableCapability(cap.ptr()); - if (NS_FAILED(rv)) - return JS_FALSE; - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; -} - -static JSBool -netscape_security_revertPrivilege(JSContext *cx, unsigned argc, jsval *vp) -{ - JSObject *obj = JS_THIS_OBJECT(cx, vp); - if (!obj) - return JS_FALSE; - - JSAutoByteString cap; - if (!getBytesArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), &cap)) - return JS_FALSE; - - nsresult rv; - nsCOMPtr<nsIScriptSecurityManager> securityManager = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - if (NS_FAILED(rv)) - return JS_FALSE; - - // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); - - rv = securityManager->RevertCapability(cap.ptr()); - if (NS_FAILED(rv)) - return JS_FALSE; - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; -} - -static JSBool -netscape_security_setCanEnablePrivilege(JSContext *cx, unsigned argc, jsval *vp) -{ - JSObject *obj = JS_THIS_OBJECT(cx, vp); - if (!obj) - return JS_FALSE; - - if (argc < 2) return JS_FALSE; - nsCAutoString principalFingerprint; - getUTF8StringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), principalFingerprint); - JSAutoByteString cap; - getBytesArgument(cx, obj, 1, argc, JS_ARGV(cx, vp), &cap); - if (principalFingerprint.IsEmpty() || !cap) - return JS_FALSE; - - nsresult rv; - nsCOMPtr<nsIScriptSecurityManager> securityManager = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - if (NS_FAILED(rv)) - return JS_FALSE; - - // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); - - rv = securityManager->SetCanEnableCapability(principalFingerprint, - cap.ptr(), - nsIPrincipal::ENABLE_GRANTED); - if (NS_FAILED(rv)) - return JS_FALSE; - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; -} - -static JSBool -netscape_security_invalidate(JSContext *cx, unsigned argc, jsval *vp) -{ - JSObject *obj = JS_THIS_OBJECT(cx, vp); - if (!obj) - return JS_FALSE; - - nsCAutoString principalFingerprint; - getUTF8StringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), principalFingerprint); - if (principalFingerprint.IsEmpty()) - return JS_FALSE; - - nsresult rv; - nsCOMPtr<nsIScriptSecurityManager> securityManager = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - if (NS_FAILED(rv)) - return JS_FALSE; - - // NS_ASSERTION(cx == GetCurrentContext(), "unexpected context"); - - rv = securityManager->SetCanEnableCapability(principalFingerprint, - nsPrincipal::sInvalid, - nsIPrincipal::ENABLE_GRANTED); - if (NS_FAILED(rv)) - return JS_FALSE; - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; -} - static JSFunctionSpec PrivilegeManager_static_methods[] = { - { "isPrivilegeEnabled", netscape_security_isPrivilegeEnabled, 1,0}, { "enablePrivilege", netscape_security_enablePrivilege, 1,0}, - { "disablePrivilege", netscape_security_disablePrivilege, 1,0}, - { "revertPrivilege", netscape_security_revertPrivilege, 1,0}, - //-- System Cert Functions - { "setCanEnablePrivilege", netscape_security_setCanEnablePrivilege, - 2,0}, - { "invalidate", netscape_security_invalidate, 1,0}, {nsnull,nsnull,0,0} }; diff --git a/content/base/test/test_bug466080.html b/content/base/test/test_bug466080.html index 17a76819bb7c..b613d63fa203 100644 --- a/content/base/test/test_bug466080.html +++ b/content/base/test/test_bug466080.html @@ -96,9 +96,7 @@ function onWindowLoad() { xhr.withCredentials = test.withCredentials; - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - xhr.setRequestHeader("Connection", "Keep-Alive", false); - netscape.security.PrivilegeManager.disablePrivilege("UniversalXPConnect"); + SpecialPowers.wrap(xhr).setRequestHeader("Connection", "Keep-Alive", false); try { xhr.send(); diff --git a/content/base/test/test_bug482935.html b/content/base/test/test_bug482935.html index 20efcacef7c5..35e732ddf4dd 100644 --- a/content/base/test/test_bug482935.html +++ b/content/base/test/test_bug482935.html @@ -11,11 +11,9 @@ var url = "bug482935.sjs"; function clearCache() { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - Components.classes["@mozilla.org/network/cache-service;1"]. + SpecialPowers.wrap(Components).classes["@mozilla.org/network/cache-service;1"]. getService(Components.interfaces.nsICacheService). evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE); - netscape.security.PrivilegeManager.disablePrivilege("UniversalXPConnect"); } // Tests that the response is cached if the request is cancelled From c532e2d4c37d3948e159257af21b727fec09321d Mon Sep 17 00:00:00 2001 From: Bobby Holley <bobbyholley@gmail.com> Date: Wed, 2 May 2012 23:57:34 +0200 Subject: [PATCH 145/159] Bug 750859 - Kill the CAPS confirm dialog. r=bz This will break addons using enablePrivilege, but that's going away too. We've been warning for many releases now, so it's time to bite the bullet. --- caps/include/nsScriptSecurityManager.h | 4 - caps/src/nsScriptSecurityManager.cpp | 115 +------------------------ 2 files changed, 3 insertions(+), 116 deletions(-) diff --git a/caps/include/nsScriptSecurityManager.h b/caps/include/nsScriptSecurityManager.h index 6228642f98ea..acbeceb16f13 100644 --- a/caps/include/nsScriptSecurityManager.h +++ b/caps/include/nsScriptSecurityManager.h @@ -523,10 +523,6 @@ private: JSStackFrame** frameResult, nsresult* rv); - static bool - CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal, - const char* aCapability, bool *checkValue); - static void FormatCapabilityString(nsAString& aCapability); diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index 82f25bcc4fc0..f83cc3b0b13f 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -2726,125 +2726,16 @@ nsScriptSecurityManager::FormatCapabilityString(nsAString& aCapability) aCapability = newcaps; } -bool -nsScriptSecurityManager::CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal, - const char* aCapability, bool *checkValue) -{ - nsresult rv; - *checkValue = false; - - //-- Get a prompter for the current window. - nsCOMPtr<nsIPrompt> prompter; - if (cx) - { - nsIScriptContext *scriptContext = GetScriptContext(cx); - if (scriptContext) - { - nsCOMPtr<nsIDOMWindow> domWin = - do_QueryInterface(scriptContext->GetGlobalObject()); - if (domWin) - domWin->GetPrompter(getter_AddRefs(prompter)); - } - } - - if (!prompter) - { - //-- Couldn't get prompter from the current window, so get the prompt service. - nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); - if (wwatch) - wwatch->GetNewPrompter(0, getter_AddRefs(prompter)); - if (!prompter) - return false; - } - - //-- Localize the dialog text - nsXPIDLString check; - rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("CheckMessage").get(), - getter_Copies(check)); - if (NS_FAILED(rv)) - return false; - - nsXPIDLString title; - rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Titleline").get(), - getter_Copies(title)); - if (NS_FAILED(rv)) - return false; - - nsXPIDLString yesStr; - rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Yes").get(), - getter_Copies(yesStr)); - if (NS_FAILED(rv)) - return false; - - nsXPIDLString noStr; - rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("No").get(), - getter_Copies(noStr)); - if (NS_FAILED(rv)) - return false; - - nsCAutoString val; - bool hasCert; - aPrincipal->GetHasCertificate(&hasCert); - if (hasCert) - rv = aPrincipal->GetPrettyName(val); - else - rv = GetPrincipalDomainOrigin(aPrincipal, val); - - if (NS_FAILED(rv)) - return false; - - NS_ConvertUTF8toUTF16 location(val); - NS_ConvertASCIItoUTF16 capability(aCapability); - FormatCapabilityString(capability); - const PRUnichar *formatStrings[] = { location.get(), capability.get() }; - - nsXPIDLString message; - rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityQuery").get(), - formatStrings, - ArrayLength(formatStrings), - getter_Copies(message)); - if (NS_FAILED(rv)) - return false; - - PRInt32 buttonPressed = 1; // If the user exits by clicking the close box, assume No (button 1) - rv = prompter->ConfirmEx(title.get(), message.get(), - (nsIPrompt::BUTTON_DELAY_ENABLE) + - (nsIPrompt::BUTTON_POS_1_DEFAULT) + - (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) + - (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1), - yesStr.get(), noStr.get(), nsnull, check.get(), checkValue, &buttonPressed); - - if (NS_FAILED(rv)) - *checkValue = false; - return (buttonPressed == 0); -} - NS_IMETHODIMP nsScriptSecurityManager::RequestCapability(nsIPrincipal* aPrincipal, const char *capability, PRInt16* canEnable) { if (NS_FAILED(aPrincipal->CanEnableCapability(capability, canEnable))) return NS_ERROR_FAILURE; + // The confirm dialog is no longer supported. All of this stuff is going away + // real soon now anyhow. if (*canEnable == nsIPrincipal::ENABLE_WITH_USER_PERMISSION) - { - // Prompt user for permission to enable capability. - JSContext* cx = GetCurrentJSContext(); - // The actual value is irrelevant but we shouldn't be handing out - // malformed JSBools to XPConnect. - bool remember = false; - if (CheckConfirmDialog(cx, aPrincipal, capability, &remember)) - *canEnable = nsIPrincipal::ENABLE_GRANTED; - else - *canEnable = nsIPrincipal::ENABLE_DENIED; - if (remember) - { - //-- Save principal to prefs and to mPrincipals - if (NS_FAILED(aPrincipal->SetCanEnableCapability(capability, *canEnable))) - return NS_ERROR_FAILURE; - if (NS_FAILED(SavePrincipal(aPrincipal))) - return NS_ERROR_FAILURE; - } - } + *canEnable = nsIPrincipal::ENABLE_DENIED; return NS_OK; } From e6e34db54d441987ee3e5de70a82d4e6cb8c3dcd Mon Sep 17 00:00:00 2001 From: Bobby Holley <bobbyholley@gmail.com> Date: Wed, 2 May 2012 23:57:34 +0200 Subject: [PATCH 146/159] Bug 750859 - Remove (most of) SetCanEnableCapability. r=bz --- caps/idl/nsIPrincipal.idl | 4 +- caps/idl/nsIScriptSecurityManager.idl | 8 +- caps/include/nsPrincipal.h | 3 + caps/include/nsScriptSecurityManager.h | 3 - caps/src/nsNullPrincipal.cpp | 8 -- caps/src/nsPrincipal.cpp | 2 +- caps/src/nsScriptSecurityManager.cpp | 123 ------------------------- caps/src/nsSystemPrincipal.cpp | 8 -- ipc/testshell/XPCShellEnvironment.cpp | 8 -- js/xpconnect/shell/xpcshell.cpp | 9 -- 10 files changed, 6 insertions(+), 170 deletions(-) diff --git a/caps/idl/nsIPrincipal.idl b/caps/idl/nsIPrincipal.idl index cfc2bac4dfaa..646a7139f128 100644 --- a/caps/idl/nsIPrincipal.idl +++ b/caps/idl/nsIPrincipal.idl @@ -52,7 +52,7 @@ interface nsIContentSecurityPolicy; [ptr] native JSContext(JSContext); [ptr] native JSPrincipals(JSPrincipals); -[scriptable, uuid(f8c4c89a-d726-421b-8415-3e34b241175b)] +[scriptable, uuid(fb783979-b3f8-4e0d-980f-f0f83b0f505d)] interface nsIPrincipal : nsISerializable { /** @@ -115,8 +115,6 @@ interface nsIPrincipal : nsISerializable // XXXbz again, what if this lives in our hashtable and someone // messes with it? Is that OK? [noscript] short canEnableCapability(in string capability); - [noscript] void setCanEnableCapability(in string capability, - in short canEnable); [noscript] boolean isCapabilityEnabled(in string capability, in voidPtr annotation); [noscript] void enableCapability(in string capability, diff --git a/caps/idl/nsIScriptSecurityManager.idl b/caps/idl/nsIScriptSecurityManager.idl index b35e797ce7ee..4af2d6f39242 100644 --- a/caps/idl/nsIScriptSecurityManager.idl +++ b/caps/idl/nsIScriptSecurityManager.idl @@ -41,7 +41,7 @@ interface nsIURI; interface nsIChannel; -[scriptable, uuid(50eda256-4dd2-4c7c-baed-96983910af9f)] +[scriptable, uuid(d6cf287a-476a-43ba-aa03-70af4a01044e)] interface nsIScriptSecurityManager : nsIXPCSecurityManager { ///////////////// Security Checks ////////////////// @@ -245,12 +245,6 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager * Allow 'certificateID' to enable 'capability.' Can only be performed * by code signed by the system certificate. */ - // XXXbz Capabilities can't have non-ascii chars? - // XXXbz ideally we'd pass a subjectName here too, and the nsISupports - // cert we're enabling for... - void setCanEnableCapability(in AUTF8String certificateFingerprint, - in string capability, - in short canEnable); /////////////////////// /** diff --git a/caps/include/nsPrincipal.h b/caps/include/nsPrincipal.h index 1542dc6ba7de..6742a22ff082 100644 --- a/caps/include/nsPrincipal.h +++ b/caps/include/nsPrincipal.h @@ -107,6 +107,9 @@ public: #endif protected: + // Formerly an IDL method. Now just a protected helper. + nsresult SetCanEnableCapability(const char *capability, PRInt16 canEnable); + nsTArray< nsAutoPtr<nsHashtable> > mAnnotations; nsHashtable* mCapabilities; nsCString mPrefName; diff --git a/caps/include/nsScriptSecurityManager.h b/caps/include/nsScriptSecurityManager.h index acbeceb16f13..05603beae5eb 100644 --- a/caps/include/nsScriptSecurityManager.h +++ b/caps/include/nsScriptSecurityManager.h @@ -526,9 +526,6 @@ private: static void FormatCapabilityString(nsAString& aCapability); - nsresult - SavePrincipal(nsIPrincipal* aToSave); - /** * Check capability levels for an |aObj| that implements * nsISecurityCheckedComponent. diff --git a/caps/src/nsNullPrincipal.cpp b/caps/src/nsNullPrincipal.cpp index 8f69ade01b5f..77d5f204b409 100644 --- a/caps/src/nsNullPrincipal.cpp +++ b/caps/src/nsNullPrincipal.cpp @@ -220,14 +220,6 @@ nsNullPrincipal::CanEnableCapability(const char *aCapability, return NS_OK; } -NS_IMETHODIMP -nsNullPrincipal::SetCanEnableCapability(const char *aCapability, - PRInt16 aCanEnable) -{ - return NS_ERROR_NOT_AVAILABLE; -} - - NS_IMETHODIMP nsNullPrincipal::IsCapabilityEnabled(const char *aCapability, void *aAnnotation, diff --git a/caps/src/nsPrincipal.cpp b/caps/src/nsPrincipal.cpp index 0d84720d1127..f387c8122ffe 100644 --- a/caps/src/nsPrincipal.cpp +++ b/caps/src/nsPrincipal.cpp @@ -542,7 +542,7 @@ nsPrincipal::CanEnableCapability(const char *capability, PRInt16 *result) return NS_OK; } -NS_IMETHODIMP +nsresult nsPrincipal::SetCanEnableCapability(const char *capability, PRInt16 canEnable) { diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index f83cc3b0b13f..1381fac84c6e 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -2536,64 +2536,6 @@ nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj return result; } -nsresult -nsScriptSecurityManager::SavePrincipal(nsIPrincipal* aToSave) -{ - //-- Save to mPrincipals - mPrincipals.Put(aToSave, aToSave); - - //-- Save to prefs - nsXPIDLCString idPrefName; - nsXPIDLCString id; - nsXPIDLCString subjectName; - nsXPIDLCString grantedList; - nsXPIDLCString deniedList; - bool isTrusted; - nsresult rv = aToSave->GetPreferences(getter_Copies(idPrefName), - getter_Copies(id), - getter_Copies(subjectName), - getter_Copies(grantedList), - getter_Copies(deniedList), - &isTrusted); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - - nsCAutoString grantedPrefName; - nsCAutoString deniedPrefName; - nsCAutoString subjectNamePrefName; - rv = GetPrincipalPrefNames( idPrefName, - grantedPrefName, - deniedPrefName, - subjectNamePrefName ); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - - mIsWritingPrefs = true; - if (grantedList) { - Preferences::SetCString(grantedPrefName.get(), grantedList); - } else { - Preferences::ClearUser(grantedPrefName.get()); - } - - if (deniedList) { - Preferences::SetCString(deniedPrefName.get(), deniedList); - } else { - Preferences::ClearUser(deniedPrefName.get()); - } - - if (grantedList || deniedList) { - Preferences::SetCString(idPrefName, id); - Preferences::SetCString(subjectNamePrefName.get(), subjectName); - } else { - Preferences::ClearUser(idPrefName); - Preferences::ClearUser(subjectNamePrefName.get()); - } - - mIsWritingPrefs = false; - - nsIPrefService* prefService = Preferences::GetService(); - NS_ENSURE_TRUE(prefService, NS_ERROR_FAILURE); - return prefService->SavePrefFile(nsnull); -} - ///////////////// Capabilities API ///////////////////// NS_IMETHODIMP nsScriptSecurityManager::IsCapabilityEnabled(const char *capability, @@ -2864,71 +2806,6 @@ nsScriptSecurityManager::DisableCapability(const char *capability) return NS_OK; } -//////////////// Master Certificate Functions /////////////////////////////////////// -NS_IMETHODIMP -nsScriptSecurityManager::SetCanEnableCapability(const nsACString& certFingerprint, - const char* capability, - PRInt16 canEnable) -{ - NS_ENSURE_ARG(!certFingerprint.IsEmpty()); - - nsresult rv; - nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv); - if (NS_FAILED(rv)) - return rv; - - //-- Get the system certificate - if (!mSystemCertificate) - { - nsCOMPtr<nsIFile> systemCertFile; - nsCOMPtr<nsIProperties> directoryService = - do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); - if (!directoryService) return NS_ERROR_FAILURE; - rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile), - getter_AddRefs(systemCertFile)); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - systemCertFile->AppendNative(NS_LITERAL_CSTRING("systemSignature.jar")); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - nsCOMPtr<nsIZipReader> systemCertZip = do_CreateInstance(kZipReaderCID, &rv); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - rv = systemCertZip->Open(systemCertFile); - if (NS_SUCCEEDED(rv)) - { - rv = systemCertZip->GetCertificatePrincipal(EmptyCString(), - getter_AddRefs(mSystemCertificate)); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - } - } - - //-- Make sure the caller's principal is the system certificate - bool isEqual = false; - if (mSystemCertificate) - { - rv = mSystemCertificate->Equals(subjectPrincipal, &isEqual); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - } - if (!isEqual) - { - JSContext* cx = GetCurrentJSContext(); - if (!cx) return NS_ERROR_FAILURE; - static const char msg1[] = "Only code signed by the system certificate may call SetCanEnableCapability or Invalidate"; - static const char msg2[] = "Attempt to call SetCanEnableCapability or Invalidate when no system certificate has been established"; - SetPendingException(cx, mSystemCertificate ? msg1 : msg2); - return NS_ERROR_FAILURE; - } - - //-- Get the target principal - nsCOMPtr<nsIPrincipal> objectPrincipal; - rv = DoGetCertificatePrincipal(certFingerprint, EmptyCString(), - EmptyCString(), nsnull, - nsnull, false, - getter_AddRefs(objectPrincipal)); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - rv = objectPrincipal->SetCanEnableCapability(capability, canEnable); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - return SavePrincipal(objectPrincipal); -} - //////////////////////////////////////////////// // Methods implementing nsIXPCSecurityManager // //////////////////////////////////////////////// diff --git a/caps/src/nsSystemPrincipal.cpp b/caps/src/nsSystemPrincipal.cpp index 2b3f5b499bca..6840a5f18ccd 100644 --- a/caps/src/nsSystemPrincipal.cpp +++ b/caps/src/nsSystemPrincipal.cpp @@ -167,14 +167,6 @@ nsSystemPrincipal::CanEnableCapability(const char *capability, return NS_OK; } -NS_IMETHODIMP -nsSystemPrincipal::SetCanEnableCapability(const char *capability, - PRInt16 canEnable) -{ - return NS_ERROR_FAILURE; -} - - NS_IMETHODIMP nsSystemPrincipal::IsCapabilityEnabled(const char *capability, void *annotation, diff --git a/ipc/testshell/XPCShellEnvironment.cpp b/ipc/testshell/XPCShellEnvironment.cpp index a7062f717c87..ae9c1e0b84c7 100644 --- a/ipc/testshell/XPCShellEnvironment.cpp +++ b/ipc/testshell/XPCShellEnvironment.cpp @@ -872,14 +872,6 @@ FullTrustSecMan::DisableCapability(const char *capability) return NS_OK; } -NS_IMETHODIMP -FullTrustSecMan::SetCanEnableCapability(const nsACString & certificateFingerprint, - const char *capability, - PRInt16 canEnable) -{ - return NS_OK; -} - NS_IMETHODIMP FullTrustSecMan::GetObjectPrincipal(JSContext * cx, JSObject * obj, diff --git a/js/xpconnect/shell/xpcshell.cpp b/js/xpconnect/shell/xpcshell.cpp index 2b97f5fcb4de..2045c68443e0 100644 --- a/js/xpconnect/shell/xpcshell.cpp +++ b/js/xpconnect/shell/xpcshell.cpp @@ -1521,15 +1521,6 @@ FullTrustSecMan::DisableCapability(const char *capability) return NS_OK; } -/* void setCanEnableCapability (in AUTF8String certificateFingerprint, in string capability, in short canEnable); */ -NS_IMETHODIMP -FullTrustSecMan::SetCanEnableCapability(const nsACString & certificateFingerprint, - const char *capability, - PRInt16 canEnable) -{ - return NS_OK; -} - /* [noscript] nsIPrincipal getObjectPrincipal (in JSContextPtr cx, in JSObjectPtr obj); */ NS_IMETHODIMP FullTrustSecMan::GetObjectPrincipal(JSContext * cx, JSObject * obj, From 710c5cfdb0b8ec89333cd1d11a7321bbe96d6295 Mon Sep 17 00:00:00 2001 From: Bobby Holley <bobbyholley@gmail.com> Date: Wed, 2 May 2012 23:57:43 +0200 Subject: [PATCH 147/159] Bug 750859 - Remove {Disable,Revert}Capability. r=bz, PGO helper on CLOSED TREE --- caps/idl/nsIPrincipal.idl | 7 +----- caps/idl/nsIScriptSecurityManager.idl | 15 +----------- caps/src/nsNullPrincipal.cpp | 15 ------------ caps/src/nsPrincipal.cpp | 28 ---------------------- caps/src/nsScriptSecurityManager.cpp | 34 --------------------------- caps/src/nsSystemPrincipal.cpp | 16 ------------- ipc/testshell/XPCShellEnvironment.cpp | 12 ---------- js/xpconnect/shell/xpcshell.cpp | 14 ----------- 8 files changed, 2 insertions(+), 139 deletions(-) diff --git a/caps/idl/nsIPrincipal.idl b/caps/idl/nsIPrincipal.idl index 646a7139f128..273351fdb08b 100644 --- a/caps/idl/nsIPrincipal.idl +++ b/caps/idl/nsIPrincipal.idl @@ -52,7 +52,7 @@ interface nsIContentSecurityPolicy; [ptr] native JSContext(JSContext); [ptr] native JSPrincipals(JSPrincipals); -[scriptable, uuid(fb783979-b3f8-4e0d-980f-f0f83b0f505d)] +[scriptable, uuid(42ba6a38-d619-49ab-8248-3d247e959d5e)] interface nsIPrincipal : nsISerializable { /** @@ -119,11 +119,6 @@ interface nsIPrincipal : nsISerializable in voidPtr annotation); [noscript] void enableCapability(in string capability, inout voidPtr annotation); - [noscript] void revertCapability(in string capability, - inout voidPtr annotation); - [noscript] void disableCapability(in string capability, - inout voidPtr annotation); - /** * The codebase URI to which this principal pertains. This is * generally the document URI. diff --git a/caps/idl/nsIScriptSecurityManager.idl b/caps/idl/nsIScriptSecurityManager.idl index 4af2d6f39242..d6835733f6c5 100644 --- a/caps/idl/nsIScriptSecurityManager.idl +++ b/caps/idl/nsIScriptSecurityManager.idl @@ -41,7 +41,7 @@ interface nsIURI; interface nsIChannel; -[scriptable, uuid(d6cf287a-476a-43ba-aa03-70af4a01044e)] +[scriptable, uuid(3708aa92-e2d9-4fd1-9e46-edfa3eb5ebf5)] interface nsIScriptSecurityManager : nsIXPCSecurityManager { ///////////////// Security Checks ////////////////// @@ -227,19 +227,6 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager */ void enableCapability(in string capability); - /** - * Remove 'capability' from the innermost frame of the currently - * executing script. Any setting of 'capability' from enclosing - * frames thus comes into effect. - */ - void revertCapability(in string capability); - - /** - * Disable 'capability' in the innermost frame of the currently executing - * script. - */ - void disableCapability(in string capability); - //////////////// Master Certificate Functions //////////////////// /** * Allow 'certificateID' to enable 'capability.' Can only be performed diff --git a/caps/src/nsNullPrincipal.cpp b/caps/src/nsNullPrincipal.cpp index 77d5f204b409..4abed5161067 100644 --- a/caps/src/nsNullPrincipal.cpp +++ b/caps/src/nsNullPrincipal.cpp @@ -238,21 +238,6 @@ nsNullPrincipal::EnableCapability(const char *aCapability, void **aAnnotation) return NS_OK; } -NS_IMETHODIMP -nsNullPrincipal::RevertCapability(const char *aCapability, void **aAnnotation) -{ - *aAnnotation = nsnull; - return NS_OK; -} - -NS_IMETHODIMP -nsNullPrincipal::DisableCapability(const char *aCapability, void **aAnnotation) -{ - // Just a no-op. They're all disabled anyway. - *aAnnotation = nsnull; - return NS_OK; -} - NS_IMETHODIMP nsNullPrincipal::GetURI(nsIURI** aURI) { diff --git a/caps/src/nsPrincipal.cpp b/caps/src/nsPrincipal.cpp index f387c8122ffe..e71a7d167ab4 100644 --- a/caps/src/nsPrincipal.cpp +++ b/caps/src/nsPrincipal.cpp @@ -615,34 +615,6 @@ nsPrincipal::EnableCapability(const char *capability, void **annotation) return SetCapability(capability, annotation, AnnotationEnabled); } -NS_IMETHODIMP -nsPrincipal::DisableCapability(const char *capability, void **annotation) -{ - return SetCapability(capability, annotation, AnnotationDisabled); -} - -NS_IMETHODIMP -nsPrincipal::RevertCapability(const char *capability, void **annotation) -{ - if (*annotation) { - nsHashtable *ht = (nsHashtable *) *annotation; - const char *start = capability; - for(;;) { - const char *space = PL_strchr(start, ' '); - int len = space ? space - start : strlen(start); - nsCAutoString capString(start, len); - nsCStringKey key(capString); - ht->Remove(&key); - if (!space) { - return NS_OK; - } - - start = space + 1; - } - } - return NS_OK; -} - nsresult nsPrincipal::SetCapability(const char *capability, void **annotation, AnnotationValue value) diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index 1381fac84c6e..c138155c600d 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -2772,40 +2772,6 @@ nsScriptSecurityManager::EnableCapability(const char *capability) return NS_OK; } -NS_IMETHODIMP -nsScriptSecurityManager::RevertCapability(const char *capability) -{ - JSContext *cx = GetCurrentJSContext(); - JSStackFrame *fp; - nsresult rv; - nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv); - if (NS_FAILED(rv)) - return rv; - if (!principal) - return NS_ERROR_NOT_AVAILABLE; - void *annotation = JS_GetFrameAnnotation(cx, fp); - principal->RevertCapability(capability, &annotation); - JS_SetFrameAnnotation(cx, fp, annotation); - return NS_OK; -} - -NS_IMETHODIMP -nsScriptSecurityManager::DisableCapability(const char *capability) -{ - JSContext *cx = GetCurrentJSContext(); - JSStackFrame *fp; - nsresult rv; - nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv); - if (NS_FAILED(rv)) - return rv; - if (!principal) - return NS_ERROR_NOT_AVAILABLE; - void *annotation = JS_GetFrameAnnotation(cx, fp); - principal->DisableCapability(capability, &annotation); - JS_SetFrameAnnotation(cx, fp, annotation); - return NS_OK; -} - //////////////////////////////////////////////// // Methods implementing nsIXPCSecurityManager // //////////////////////////////////////////////// diff --git a/caps/src/nsSystemPrincipal.cpp b/caps/src/nsSystemPrincipal.cpp index 6840a5f18ccd..af28fd5978ed 100644 --- a/caps/src/nsSystemPrincipal.cpp +++ b/caps/src/nsSystemPrincipal.cpp @@ -183,22 +183,6 @@ nsSystemPrincipal::EnableCapability(const char *capability, void **annotation) return NS_OK; } -NS_IMETHODIMP -nsSystemPrincipal::RevertCapability(const char *capability, void **annotation) -{ - *annotation = nsnull; - return NS_OK; -} - -NS_IMETHODIMP -nsSystemPrincipal::DisableCapability(const char *capability, void **annotation) -{ - // Can't disable the capabilities of the system principal. - // XXX might be handy to be able to do so! - *annotation = nsnull; - return NS_ERROR_FAILURE; -} - NS_IMETHODIMP nsSystemPrincipal::GetURI(nsIURI** aURI) { diff --git a/ipc/testshell/XPCShellEnvironment.cpp b/ipc/testshell/XPCShellEnvironment.cpp index ae9c1e0b84c7..6c80f7bb3f84 100644 --- a/ipc/testshell/XPCShellEnvironment.cpp +++ b/ipc/testshell/XPCShellEnvironment.cpp @@ -860,18 +860,6 @@ FullTrustSecMan::EnableCapability(const char *capability) return NS_OK;; } -NS_IMETHODIMP -FullTrustSecMan::RevertCapability(const char *capability) -{ - return NS_OK; -} - -NS_IMETHODIMP -FullTrustSecMan::DisableCapability(const char *capability) -{ - return NS_OK; -} - NS_IMETHODIMP FullTrustSecMan::GetObjectPrincipal(JSContext * cx, JSObject * obj, diff --git a/js/xpconnect/shell/xpcshell.cpp b/js/xpconnect/shell/xpcshell.cpp index 2045c68443e0..a533fa4486c6 100644 --- a/js/xpconnect/shell/xpcshell.cpp +++ b/js/xpconnect/shell/xpcshell.cpp @@ -1507,20 +1507,6 @@ FullTrustSecMan::EnableCapability(const char *capability) return NS_OK;; } -/* void revertCapability (in string capability); */ -NS_IMETHODIMP -FullTrustSecMan::RevertCapability(const char *capability) -{ - return NS_OK; -} - -/* void disableCapability (in string capability); */ -NS_IMETHODIMP -FullTrustSecMan::DisableCapability(const char *capability) -{ - return NS_OK; -} - /* [noscript] nsIPrincipal getObjectPrincipal (in JSContextPtr cx, in JSObjectPtr obj); */ NS_IMETHODIMP FullTrustSecMan::GetObjectPrincipal(JSContext * cx, JSObject * obj, From 52cd3e016850666d329e1b13d4f2fd9be3852187 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Wed, 2 May 2012 16:32:16 -0400 Subject: [PATCH 148/159] Bug 751273 - Part 2: Rip out cairo and pixman from libxul; r=khuey Landing on a CLOSED TREE --HG-- extra : rebase_source : 92b945b90bb70a020609ad8ac0ffe633076bed10 --- config/autoconf.mk.in | 1 + configure.in | 8 +- layout/media/Makefile.in | 4 +- layout/media/symbols.def.in | 203 ++++++++++++++++++++++++++++++++++++ toolkit/library/Makefile.in | 4 +- 5 files changed, 215 insertions(+), 5 deletions(-) diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index d61d56312c47..0e949d0d25dd 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -277,6 +277,7 @@ MOZ_CAIRO_CFLAGS = @MOZ_CAIRO_CFLAGS@ MOZ_PREF_EXTENSIONS = @MOZ_PREF_EXTENSIONS@ MOZ_CAIRO_LIBS = @MOZ_CAIRO_LIBS@ +MOZ_CAIRO_OSLIBS = @MOZ_CAIRO_OSLIBS@ MOZ_ENABLE_GNOMEUI = @MOZ_ENABLE_GNOMEUI@ MOZ_GNOMEUI_CFLAGS = @MOZ_GNOMEUI_CFLAGS@ diff --git a/configure.in b/configure.in index 773b86512e26..e5563de13528 100644 --- a/configure.in +++ b/configure.in @@ -6327,6 +6327,7 @@ if test -n "$MOZ_TREE_FREETYPE"; then FT2_CFLAGS='-I$(topsrcdir)/modules/freetype2/include' CAIRO_FT_CFLAGS='-I$(topsrcdir)/modules/freetype2/include' FT2_LIBS='$(call EXPAND_LIBNAME_PATH,freetype,$(DEPTH)/modules/freetype2/.libs)' + CAIRO_FT_OSLIBS='' CAIRO_FT_LIBS='$(call EXPAND_LIBNAME_PATH,freetype,$(DEPTH)/modules/freetype2/.libs)' AC_DEFINE(HAVE_FT_BITMAP_SIZE_Y_PPEM) AC_DEFINE(HAVE_FT_GLYPHSLOT_EMBOLDEN) @@ -8123,7 +8124,8 @@ if test "$MOZ_TREE_CAIRO"; then FT_FONT_FEATURE="#define CAIRO_HAS_FT_FONT 1" MOZ_ENABLE_CAIRO_FT=1 CAIRO_FT_CFLAGS="-I${MZFTCFGFT2}/include" - CAIRO_FT_LIBS="-L${MZFTCFGFT2}/lib -lmozft -lmzfntcfg" + CAIRO_FT_OSLIBS="-L${MZFTCFGFT2}/lib -lmozft -lmzfntcfg" + CAIRO_FT_LIBS="" ;; esac if test "$USE_FC_FREETYPE"; then @@ -8157,6 +8159,7 @@ if test "$MOZ_TREE_CAIRO"; then AC_SUBST(TEE_SURFACE_FEATURE) MOZ_CAIRO_LIBS='$(call EXPAND_LIBNAME_PATH,mozcairo,$(DEPTH)/gfx/cairo/cairo/src)'" $CAIRO_FT_LIBS" + MOZ_CAIRO_OSLIBS='${CAIRO_FT_OSLIBS}' if test "$MOZ_TREE_PIXMAN"; then AC_DEFINE(MOZ_TREE_PIXMAN) @@ -8168,7 +8171,7 @@ if test "$MOZ_TREE_CAIRO"; then fi if test "$MOZ_X11"; then - MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS $XLDFLAGS -lXrender -lfreetype -lfontconfig" + MOZ_CAIRO_OSLIBS="$MOZ_CAIRO_OSLIBS $XLDFLAGS -lXrender -lfreetype -lfontconfig" fi CAIRO_FEATURES_H=gfx/cairo/cairo/src/cairo-features.h @@ -8189,6 +8192,7 @@ fi AC_SUBST(MOZ_TREE_CAIRO) AC_SUBST(MOZ_CAIRO_CFLAGS) AC_SUBST(MOZ_CAIRO_LIBS) +AC_SUBST(MOZ_CAIRO_OSLIBS) AC_SUBST(MOZ_TREE_PIXMAN) dnl ======================================================== diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index 5c46e55c9ee6..9ffd3cba353f 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -49,7 +49,7 @@ ifeq (WINNT,$(OS_TARGET)) FORCE_SHARED_LIB = 1 endif -SHARED_LIBRARY_LIBS = $(MOZ_OTS_LIBS) $(QCMS_LIBS) +SHARED_LIBRARY_LIBS = $(MOZ_OTS_LIBS) $(QCMS_LIBS) $(MOZ_CAIRO_LIBS) ifdef MOZ_GRAPHITE SHARED_LIBRARY_LIBS += $(MOZ_GRAPHITE_LIBS) @@ -138,6 +138,8 @@ ifeq (WINNT,$(OS_TARGET)) symbols.def: symbols.def.in $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(ACDEFINES) $< > $@ +OS_LIBS += $(call EXPAND_LIBNAME, msimg32) + ifdef MOZ_CUBEB OS_LIBS += $(call EXPAND_LIBNAME, winmm) endif diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index cebac56e91a8..1c17855cca5c 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -240,3 +240,206 @@ MOZ_XML_SetUnparsedEntityDeclHandler MOZ_XML_SetUserData MOZ_XML_SetXmlDeclHandler MOZ_XML_StopParser +_moz_cairo_append_path +_moz_cairo_arc +_moz_cairo_arc_negative +_moz_cairo_clip +_moz_cairo_clip_extents +_moz_cairo_clip_preserve +_moz_cairo_close_path +_moz_cairo_copy_clip_rectangle_list +_moz_cairo_copy_path +_moz_cairo_copy_path_flat +_moz_cairo_create +_moz_cairo_curve_to +_moz_cairo_debug_reset_static_data +_moz_cairo_destroy +_moz_cairo_device_to_user +_moz_cairo_device_to_user_distance +_moz_cairo_fill +_moz_cairo_fill_extents +_moz_cairo_fill_preserve +_moz_cairo_font_face_destroy +_moz_cairo_font_options_create +_moz_cairo_font_options_destroy +_moz_cairo_font_options_get_hint_metrics +_moz_cairo_font_options_set_antialias +_moz_cairo_format_stride_for_width +_moz_cairo_get_antialias +_moz_cairo_get_current_point +_moz_cairo_get_dash +_moz_cairo_get_dash_count +_moz_cairo_get_fill_rule +_moz_cairo_get_group_target +_moz_cairo_get_line_cap +_moz_cairo_get_line_join +_moz_cairo_get_line_width +_moz_cairo_get_matrix +_moz_cairo_get_miter_limit +_moz_cairo_get_operator +_moz_cairo_get_scaled_font +_moz_cairo_get_source +_moz_cairo_get_target +_moz_cairo_glyph_extents +_moz_cairo_glyph_path +_moz_cairo_identity_matrix +_moz_cairo_image_surface_create +_moz_cairo_image_surface_create_for_data +_moz_cairo_image_surface_get_data +_moz_cairo_image_surface_get_format +_moz_cairo_image_surface_get_height +_moz_cairo_image_surface_get_stride +_moz_cairo_image_surface_get_width +_moz_cairo_in_fill +_moz_cairo_in_stroke +_moz_cairo_line_to +_moz_cairo_mask +_moz_cairo_mask_surface +_moz_cairo_matrix_init +_moz_cairo_matrix_init_identity +_moz_cairo_matrix_init_scale +_moz_cairo_matrix_invert +_moz_cairo_matrix_multiply +_moz_cairo_matrix_rotate +_moz_cairo_matrix_scale +_moz_cairo_matrix_transform_distance +_moz_cairo_matrix_transform_point +_moz_cairo_matrix_translate +_moz_cairo_move_to +_moz_cairo_new_path +_moz_cairo_new_sub_path +_moz_cairo_paint +_moz_cairo_paint_with_alpha +_moz_cairo_path_destroy +_moz_cairo_path_extents +_moz_cairo_pattern_add_color_stop_rgba +_moz_cairo_pattern_create_for_surface +_moz_cairo_pattern_create_linear +_moz_cairo_pattern_create_radial +_moz_cairo_pattern_create_rgba +_moz_cairo_pattern_destroy +_moz_cairo_pattern_get_color_stop_count +_moz_cairo_pattern_get_color_stop_rgba +_moz_cairo_pattern_get_extend +_moz_cairo_pattern_get_filter +_moz_cairo_pattern_get_linear_points +_moz_cairo_pattern_get_matrix +_moz_cairo_pattern_get_radial_circles +_moz_cairo_pattern_get_rgba +_moz_cairo_pattern_get_surface +_moz_cairo_pattern_get_type +_moz_cairo_pattern_reference +_moz_cairo_pattern_set_extend +_moz_cairo_pattern_set_filter +_moz_cairo_pattern_set_matrix +_moz_cairo_pattern_status +_moz_cairo_pdf_surface_create_for_stream +_moz_cairo_pop_group +_moz_cairo_pop_group_to_source +_moz_cairo_push_group_with_content +_moz_cairo_rectangle +_moz_cairo_rectangle_list_destroy +_moz_cairo_reference +_moz_cairo_reset_clip +_moz_cairo_restore +_moz_cairo_rotate +_moz_cairo_save +_moz_cairo_scale +_moz_cairo_scaled_font_create +_moz_cairo_scaled_font_destroy +_moz_cairo_scaled_font_get_font_matrix +_moz_cairo_scaled_font_get_font_options +_moz_cairo_scaled_font_get_type +_moz_cairo_scaled_font_reference +_moz_cairo_scaled_font_status +_moz_cairo_set_antialias +_moz_cairo_set_dash +_moz_cairo_set_fill_rule +_moz_cairo_set_font_face +_moz_cairo_set_font_size +_moz_cairo_set_line_cap +_moz_cairo_set_line_join +_moz_cairo_set_line_width +_moz_cairo_set_matrix +_moz_cairo_set_miter_limit +_moz_cairo_set_operator +_moz_cairo_set_scaled_font +_moz_cairo_set_source +_moz_cairo_set_source_rgba +_moz_cairo_set_source_surface +_moz_cairo_show_glyphs +_moz_cairo_status +_moz_cairo_stroke +_moz_cairo_stroke_extents +_moz_cairo_stroke_preserve +_moz_cairo_surface_create_similar +_moz_cairo_surface_destroy +_moz_cairo_surface_finish +_moz_cairo_surface_flush +_moz_cairo_surface_get_content +_moz_cairo_surface_get_device_offset +_moz_cairo_surface_get_reference_count +_moz_cairo_surface_get_subpixel_antialiasing +_moz_cairo_surface_get_type +_moz_cairo_surface_get_user_data +_moz_cairo_surface_mark_dirty +_moz_cairo_surface_mark_dirty_rectangle +_moz_cairo_surface_reference +_moz_cairo_surface_set_device_offset +_moz_cairo_surface_set_fallback_resolution +_moz_cairo_surface_set_subpixel_antialiasing +_moz_cairo_surface_set_user_data +_moz_cairo_surface_show_page +_moz_cairo_surface_status +_moz_cairo_tee_surface_add +_moz_cairo_tee_surface_create +_moz_cairo_tee_surface_index +_moz_cairo_transform +_moz_cairo_translate +_moz_cairo_user_to_device +_moz_cairo_user_to_device_distance +_moz_cairo_win32_font_face_create_for_logfontw_hfont +_moz_cairo_win32_printing_surface_create +_moz_cairo_win32_scaled_font_select_font +_moz_cairo_win32_surface_create +_moz_cairo_win32_surface_create_with_ddb +_moz_cairo_win32_surface_create_with_dib +_moz_cairo_win32_surface_get_dc +_moz_cairo_win32_surface_get_image +_moz_pixman_image_composite32 +_moz_pixman_image_create_bits +_moz_pixman_image_set_transform +_moz_pixman_image_unref +_moz_pixman_transform_from_pixman_f_transform +_moz_pixman_transform_invert +cairo_d2d_create_device +cairo_d2d_create_device_from_d3d10device +cairo_d2d_device_get_device +cairo_d2d_get_dc +cairo_d2d_get_image_surface_cache_usage +cairo_d2d_get_surface_vram_usage +cairo_d2d_present_backbuffer +cairo_d2d_release_dc +cairo_d2d_scroll +cairo_d2d_surface_create +cairo_d2d_surface_create_for_handle +cairo_d2d_surface_create_for_hwnd +cairo_d2d_surface_create_for_texture +cairo_d2d_surface_get_height +cairo_d2d_surface_get_texture +cairo_d2d_surface_get_width +cairo_dwrite_font_face_create_for_dwrite_fontface +cairo_dwrite_get_cleartype_rendering_mode +cairo_dwrite_scaled_font_allow_manual_show_glyphs +cairo_dwrite_scaled_font_get_force_GDI_classic +cairo_dwrite_scaled_font_set_force_GDI_classic +cairo_dwrite_set_cleartype_params +cairo_null_surface_create +cairo_release_device +cairo_surface_attach_snapshot +cairo_win32_get_dc_with_clip +cairo_win32_get_system_text_quality +cairo_win32_surface_create_with_alpha +cairo_win32_surface_get_height +cairo_win32_surface_get_width +cairo_win32_surface_set_can_convert_to_dib diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index ba4df6e434b1..5e1ab0c07225 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -335,7 +335,7 @@ EXTRA_DSO_LDOPTS += \ $(LIBS_DIR) \ $(MOZ_JS_LIBS) \ $(NSS_LIBS) \ - $(MOZ_CAIRO_LIBS) \ + $(MOZ_CAIRO_OSLIBS) \ $(MOZ_HARFBUZZ_LIBS) \ $(MOZ_APP_EXTRA_LIBS) \ $(SQLITE_LIBS) \ @@ -523,7 +523,7 @@ endif endif ifeq ($(OS_ARCH),WINNT) -OS_LIBS += $(call EXPAND_LIBNAME,shell32 ole32 version winspool comdlg32 imm32 msimg32 shlwapi psapi ws2_32 dbghelp rasapi32 rasdlg iphlpapi uxtheme setupapi secur32 sensorsapi portabledeviceguids) +OS_LIBS += $(call EXPAND_LIBNAME,shell32 ole32 version winspool comdlg32 imm32 msimg32 shlwapi psapi ws2_32 dbghelp rasapi32 rasdlg iphlpapi uxtheme setupapi secur32 sensorsapi portabledeviceguids windowscodecs) ifdef MOZ_CRASHREPORTER OS_LIBS += $(call EXPAND_LIBNAME,wininet) endif From 66b90a8522d90109bf5d1b637400541503941560 Mon Sep 17 00:00:00 2001 From: Asaf Romano <aromano@mozilla.com> Date: Wed, 2 May 2012 15:06:07 -0700 Subject: [PATCH 149/159] Bug 750269 - Fix places transactions leak with cpg (r=mak,a=not-in-libxul) --- toolkit/components/places/PlacesUtils.jsm | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/toolkit/components/places/PlacesUtils.jsm b/toolkit/components/places/PlacesUtils.jsm index 52df1399aae5..eb81b2b4bc8d 100644 --- a/toolkit/components/places/PlacesUtils.jsm +++ b/toolkit/components/places/PlacesUtils.jsm @@ -2242,7 +2242,26 @@ XPCOMUtils.defineLazyGetter(PlacesUtils, "transactionManager", function() { this.transactionManager.RemoveListener(this); this.transactionManager.clear(); }); - return tm; + + // Bug 750269 + // The transaction manager keeps strong references to transactions, and by + // that, also to the global for each transaction. A transaction, however, + // could be either the transaction itself (for which the global is this + // module) or some js-proxy in another global, usually a window. The later + // would leak because the transaction lifetime (in the manager's stacks) + // is independent of the global from which doTransaction was called. + // To avoid such a leak, we hide the native doTransaction from callers, + // and let each doTransaction call go through this module. + // Doing so ensures that, as long as the transaction is any of the + // PlacesXXXTransaction objects declared in this module, the object + // referenced by the transaction manager has the module itself as global. + return Object.create(tm, { + "doTransaction": { + value: function(aTransaction) { + tm.doTransaction(aTransaction); + } + } + }); }); XPCOMUtils.defineLazyGetter(this, "bundle", function() { From 1ef0a14fe7878544598c82f5f4fb10201dfbe6b7 Mon Sep 17 00:00:00 2001 From: Bobby Holley <bobbyholley@gmail.com> Date: Wed, 2 May 2012 15:06:27 -0700 Subject: [PATCH 150/159] Bug 751086 - Disable toolkit/mozapps/plugins/tests/browser_bug435788.js for leaks (r=Mano,a=test-only) --- toolkit/mozapps/plugins/tests/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/mozapps/plugins/tests/Makefile.in b/toolkit/mozapps/plugins/tests/Makefile.in index 9c333f248693..9a7151169dfb 100644 --- a/toolkit/mozapps/plugins/tests/Makefile.in +++ b/toolkit/mozapps/plugins/tests/Makefile.in @@ -49,7 +49,7 @@ USE_STATIC_LIBS = 1 ifneq (mobile,$(MOZ_BUILD_APP)) _BROWSER_FILES = \ - browser_bug435788.js \ + $(warning browser_bug435788.js has been disabled due to leaks - see bug 751100) \ pfs_bug435788_1.rdf \ pfs_bug435788_2.rdf \ GoodExtension.xpi \ From 4b42d9ae2b29749423211097e8c870d6bb824942 Mon Sep 17 00:00:00 2001 From: Jose Antonio Olivera Ortega <josea.olivera@gmail.com> Date: Wed, 2 May 2012 16:32:46 -0700 Subject: [PATCH 151/159] Bug 714973 - Add emergency calls to RIL's state machine. r=philikon --- dom/system/gonk/RadioInterfaceLayer.js | 2 +- dom/system/gonk/ril_consts.js | 5 + dom/system/gonk/ril_worker.js | 121 +++++++++++++++++++------ 3 files changed, 100 insertions(+), 28 deletions(-) diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index b5c963ba0678..1515e9963b39 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -361,7 +361,7 @@ RadioInterfaceLayer.prototype = { voiceInfo); return; } - //TODO emergency calls + voiceInfo.emergencyCallsOnly = state.emergencyCallsOnly; voiceInfo.connected = (state.regState == RIL.NETWORK_CREG_STATE_REGISTERED_HOME) || (state.regState == RIL.NETWORK_CREG_STATE_REGISTERED_ROAMING); diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js index 63ae51252446..24d3891a94ab 100644 --- a/dom/system/gonk/ril_consts.js +++ b/dom/system/gonk/ril_consts.js @@ -145,6 +145,7 @@ const REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE = 104; const REQUEST_ISIM_AUTHENTICATION = 105; const REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU = 106; const REQUEST_STK_SEND_ENVELOPE_WITH_STATUS = 107; +const REQUEST_DIAL_EMERGENCY_CALL = 10016; // Akami/Maguro specific parcel types. const REQUEST_VOICE_RADIO_TECH = 105; @@ -339,6 +340,10 @@ const NETWORK_CREG_STATE_SEARCHING = 2; const NETWORK_CREG_STATE_DENIED = 3; const NETWORK_CREG_STATE_UNKNOWN = 4; const NETWORK_CREG_STATE_REGISTERED_ROAMING = 5; +const NETWORK_CREG_STATE_NOT_SEARCHING_EMERGENCY_CALLS = 10; +const NETWORK_CREG_STATE_SEARCHING_EMERGENCY_CALLS = 12; +const NETWORK_CREG_STATE_DENIED_EMERGENCY_CALLS = 13; +const NETWORK_CREG_STATE_UNKNOWN_EMERGENCY_CALLS = 14; const NETWORK_CREG_TECH_UNKNOWN = 0; const NETWORK_CREG_TECH_GPRS = 1; diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index 2d3e73509872..1647811bc64f 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -77,11 +77,15 @@ const PARCEL_SIZE_SIZE = UINT32_SIZE; const PDU_HEX_OCTET_SIZE = 4; +const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"]; + let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = false; let RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = false; // This flag defaults to true since on RIL v6 and later, we get the // version number via the UNSOLICITED_RIL_CONNECTED parcel. let RILQUIRKS_V5_LEGACY = true; +let RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = false; +let RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = false; /** * This object contains helpers buffering incoming data & deconstructing it @@ -688,34 +692,44 @@ let RIL = { return; } - // The Samsung Galaxy S2 I-9100 radio sends an extra Uint32 in the - // call state. - let model_id = libcutils.property_get("ril.model_id"); - if (DEBUG) debug("Detected RIL model " + model_id); - if (model_id == "I9100") { - if (DEBUG) { - debug("Detected I9100, enabling " + - "RILQUIRKS_CALLSTATE_EXTRA_UINT32, " + - "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP."); - } - RILQUIRKS_CALLSTATE_EXTRA_UINT32 = true; - RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true; - } - if (model_id == "I9023" || model_id == "I9020") { - if (DEBUG) { - debug("Detected I9020/I9023, enabling " + - "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP"); - } - RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true; - } let ril_impl = libcutils.property_get("gsm.version.ril-impl"); - if (ril_impl == "Qualcomm RIL 1.0") { - if (DEBUG) { - debug("Detected Qualcomm RIL 1.0, " + - "disabling RILQUIRKS_V5_LEGACY to false"); - } - RILQUIRKS_V5_LEGACY = false; + if (DEBUG) debug("Detected RIL implementation " + ril_impl); + switch (ril_impl) { + case "Samsung RIL(IPC) v2.0": + // The Samsung Galaxy S2 I-9100 radio sends an extra Uint32 in the + // call state. + let model_id = libcutils.property_get("ril.model_id"); + if (DEBUG) debug("Detected RIL model " + model_id); + if (model_id == "I9100") { + if (DEBUG) { + debug("Detected I9100, enabling " + + "RILQUIRKS_CALLSTATE_EXTRA_UINT32, " + + "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP, " + + "RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL."); + } + RILQUIRKS_CALLSTATE_EXTRA_UINT32 = true; + RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true; + RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = true; + } + if (model_id == "I9023" || model_id == "I9020") { + if (DEBUG) { + debug("Detected I9020/I9023, enabling " + + "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP"); + } + RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true; + } + break; + case "Qualcomm RIL 1.0": + if (DEBUG) { + debug("Detected Qualcomm RIL 1.0, " + + "disabling RILQUIRKS_V5_LEGACY and " + + "enabling RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE."); + } + RILQUIRKS_V5_LEGACY = false; + RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = true; + break; } + this.rilQuirksInitialized = true; }, @@ -1132,7 +1146,26 @@ let RIL = { * Integer doing something XXX TODO */ dial: function dial(options) { - let token = Buf.newParcel(REQUEST_DIAL); + let dial_request_type = REQUEST_DIAL; + if (this.voiceRegistrationState.emergencyCallsOnly) { + if (!this._isEmergencyNumber(options.number)) { + if (DEBUG) { + // TODO: Notify an error here so that the DOM will see an error event. + debug(options.number + " is not a valid emergency number."); + } + return; + } + if (RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL) { + dial_request_type = REQUEST_DIAL_EMERGENCY_CALL; + } + } else { + if (this._isEmergencyNumber(options.number) && + RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL) { + dial_request_type = REQUEST_DIAL_EMERGENCY_CALL; + } + } + + let token = Buf.newParcel(dial_request_type); Buf.writeString(options.number); Buf.writeUint32(options.clirMode || 0); Buf.writeUint32(options.uusInfo || 0); @@ -1429,6 +1462,29 @@ let RIL = { Buf.simpleRequest(REQUEST_LAST_CALL_FAIL_CAUSE); }, + /** + * Check a given number against the list of emergency numbers provided by the RIL. + * + * @param number + * The number to look up. + */ + _isEmergencyNumber: function _isEmergencyNumber(number) { + // Check read-write ecclist property first. + let numbers = libcutils.property_get("ril.ecclist"); + if (!numbers) { + // Then read-only ecclist property since others RIL only uses this. + numbers = libcutils.property_get("ro.ril.ecclist"); + } + + if (numbers) { + numbers = numbers.split(","); + } else { + // No ecclist system property, so use our own list. + numbers = DEFAULT_EMERGENCY_NUMBERS; + } + + return numbers.indexOf(number) != -1; + }, /** * Process ICC status. @@ -1613,12 +1669,23 @@ let RIL = { }, _processVoiceRegistrationState: function _processVoiceRegistrationState(state) { + this.initRILQuirks(); + let rs = this.voiceRegistrationState; let stateChanged = false; let regState = RIL.parseInt(state[0], NETWORK_CREG_STATE_UNKNOWN); if (rs.regState != regState) { rs.regState = regState; + if (RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE) { + rs.emergencyCallsOnly = + (regState != NETWORK_CREG_STATE_REGISTERED_HOME) && + (regState != NETWORK_CREG_STATE_REGISTERED_ROAMING); + } else { + rs.emergencyCallsOnly = + (regState >= NETWORK_CREG_STATE_NOT_SEARCHING_EMERGENCY_CALLS) && + (regState <= NETWORK_CREG_STATE_UNKNOWN_EMERGENCY_CALLS); + } stateChanged = true; if (regState == NETWORK_CREG_STATE_REGISTERED_HOME || regState == NETWORK_CREG_STATE_REGISTERED_ROAMING) { From 9a869553f84c10c29411286af772c89a7a7fcc77 Mon Sep 17 00:00:00 2001 From: Philipp von Weitershausen <philipp@weitershausen.de> Date: Wed, 2 May 2012 16:32:46 -0700 Subject: [PATCH 152/159] Bug 750592 - B2G RIL: only enable RILQUIRKS_CALLSTATE_EXTRA_UINT32 on SGS2 gingerbread. r=qDot --- dom/system/gonk/ril_worker.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index 1647811bc64f..daf8bcd89fbf 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -703,13 +703,15 @@ let RIL = { if (model_id == "I9100") { if (DEBUG) { debug("Detected I9100, enabling " + - "RILQUIRKS_CALLSTATE_EXTRA_UINT32, " + "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP, " + "RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL."); } - RILQUIRKS_CALLSTATE_EXTRA_UINT32 = true; RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true; RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = true; + if (RILQUIRKS_V5_LEGACY) { + if (DEBUG) debug("...and RILQUIRKS_CALLSTATE_EXTRA_UINT32"); + RILQUIRKS_CALLSTATE_EXTRA_UINT32 = true; + } } if (model_id == "I9023" || model_id == "I9020") { if (DEBUG) { From bab14518ab2c626c5679505e7ec638bd25d1f1bc Mon Sep 17 00:00:00 2001 From: Philipp von Weitershausen <philipp@weitershausen.de> Date: Wed, 2 May 2012 16:33:15 -0700 Subject: [PATCH 153/159] Bug 750589 - Update default MobileConnection permissions after Gaia refactoring (#1277). r=fabrice a=b2g-only --- b2g/app/b2g.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 38eb62a7e880..152938bc9a35 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -435,7 +435,7 @@ pref("dom.sms.enabled", true); pref("dom.sms.whitelist", "file://,http://homescreen.gaiamobile.org,http://sms.gaiamobile.org"); // Temporary permission hack for WebMobileConnection -pref("dom.mobileconnection.whitelist", "http://homescreen.gaiamobile.org"); +pref("dom.mobileconnection.whitelist", "http://system.gaiamobile.org,http://homescreen.gaiamobile.org,http://dialer.gaiamobile.org"); // Temporary permission hack for WebContacts pref("dom.mozContacts.enabled", true); From 928443e854dffb2c2a84d67b15469cf660b3a5cf Mon Sep 17 00:00:00 2001 From: Olli Pettay <Olli.Pettay@helsinki.fi> Date: Thu, 3 May 2012 13:59:51 +0300 Subject: [PATCH 154/159] Bug 751286 - eventPhase NONE constant, r=sicking --- content/events/src/nsDOMEvent.cpp | 5 +++-- content/events/test/test_eventctors.html | 2 ++ content/smil/test/test_smilTimeEvents.xhtml | 2 +- dom/interfaces/events/nsIDOMEvent.idl | 7 ++++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/content/events/src/nsDOMEvent.cpp b/content/events/src/nsDOMEvent.cpp index 5b5b7899e4bf..1c3066a9c92f 100644 --- a/content/events/src/nsDOMEvent.cpp +++ b/content/events/src/nsDOMEvent.cpp @@ -427,7 +427,8 @@ nsDOMEvent::GetEventPhase(PRUint16* aEventPhase) { // Note, remember to check that this works also // if or when Bug 235441 is fixed. - if (mEvent->currentTarget == mEvent->target || + if ((mEvent->currentTarget && + mEvent->currentTarget == mEvent->target) || ((mEvent->flags & NS_EVENT_FLAG_CAPTURE) && (mEvent->flags & NS_EVENT_FLAG_BUBBLE))) { *aEventPhase = nsIDOMEvent::AT_TARGET; @@ -436,7 +437,7 @@ nsDOMEvent::GetEventPhase(PRUint16* aEventPhase) } else if (mEvent->flags & NS_EVENT_FLAG_BUBBLE) { *aEventPhase = nsIDOMEvent::BUBBLING_PHASE; } else { - *aEventPhase = 0; + *aEventPhase = nsIDOMEvent::NONE; } return NS_OK; } diff --git a/content/events/test/test_eventctors.html b/content/events/test/test_eventctors.html index ee992edf674e..ecad322eb0b0 100644 --- a/content/events/test/test_eventctors.html +++ b/content/events/test/test_eventctors.html @@ -64,7 +64,9 @@ ok(e.type, "hello", "Wrong event type!"); ok(!e.isTrusted, "Event shouldn't be trusted!"); ok(!e.bubbles, "Event shouldn't bubble!"); ok(!e.cancelable, "Event shouldn't be cancelable!"); +is(e.eventPhase, Event.NONE, "Wrong event phase"); document.dispatchEvent(e); +is(e.eventPhase, Event.NONE, "Wrong event phase"); is(receivedEvent, e, "Wrong event!"); e = new Event("hello", { bubbles: true, cancelable: true }); diff --git a/content/smil/test/test_smilTimeEvents.xhtml b/content/smil/test/test_smilTimeEvents.xhtml index c7c9e7fc5f79..d8681ee92bd1 100644 --- a/content/smil/test/test_smilTimeEvents.xhtml +++ b/content/smil/test/test_smilTimeEvents.xhtml @@ -157,7 +157,7 @@ function testCreateEvent() is(evt.detail, 3, "Unexpected detail for user-generated event"); is(evt.target, null, "Unexpected event target"); is(evt.currentTarget, null, "Unexpected event current target"); - is(evt.eventPhase, evt.AT_TARGET); + is(evt.eventPhase, evt.NONE); is(evt.bubbles, false, "Event should not bubble"); is(evt.cancelable, false, "Event should not be cancelable"); is(evt.view, null, "Event view should be null"); diff --git a/dom/interfaces/events/nsIDOMEvent.idl b/dom/interfaces/events/nsIDOMEvent.idl index 3ef215b24388..b08b60f90357 100644 --- a/dom/interfaces/events/nsIDOMEvent.idl +++ b/dom/interfaces/events/nsIDOMEvent.idl @@ -46,13 +46,18 @@ interface nsIDOMEventTarget; * the Document Object Model. * * For more information on this interface please see - * http://www.w3.org/TR/DOM-Level-2-Events/ + * http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html and + * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html */ [scriptable, uuid(e85cff74-951f-45c1-be0c-89442ea2f500)] interface nsIDOMEvent : nsISupports { // PhaseType + /** + * The event isn't being dispatched. + */ + const unsigned short NONE = 0; /** * The current event phase is the capturing phase. */ From 9f46038aebed0c3e0726557a1dfc2bedd95fd359 Mon Sep 17 00:00:00 2001 From: Matt Brubeck <mbrubeck@mozilla.com> Date: Thu, 3 May 2012 09:15:38 -0700 Subject: [PATCH 155/159] Bug 750051 - Disable window.find in Fennec because it breaks and/or crashes [r=jst] --- dom/base/nsGlobalWindow.cpp | 3 ++ dom/tests/mochitest/bugs/Makefile.in | 1 + dom/tests/mochitest/bugs/test_bug750051.html | 38 ++++++++++++++++++++ mobile/android/app/mobile.js | 1 + 4 files changed, 43 insertions(+) create mode 100644 dom/tests/mochitest/bugs/test_bug750051.html diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 9cf5873154e5..ba70a62b3df2 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -7063,6 +7063,9 @@ nsGlobalWindow::Find(const nsAString& aStr, bool aCaseSensitive, bool aSearchInFrames, bool aShowDialog, bool *aDidFind) { + if (Preferences::GetBool("dom.disable_window_find", false)) + return NS_ERROR_NOT_AVAILABLE; + FORWARD_TO_OUTER(Find, (aStr, aCaseSensitive, aBackwards, aWrapAround, aWholeWord, aSearchInFrames, aShowDialog, aDidFind), NS_ERROR_NOT_INITIALIZED); diff --git a/dom/tests/mochitest/bugs/Makefile.in b/dom/tests/mochitest/bugs/Makefile.in index b2f1802e80ed..754857614d7e 100644 --- a/dom/tests/mochitest/bugs/Makefile.in +++ b/dom/tests/mochitest/bugs/Makefile.in @@ -160,6 +160,7 @@ _TEST_FILES = \ test_bug743615.html \ utils_bug743615.js \ worker_bug743615.js \ + test_bug750051.html \ $(NULL) libs:: $(_TEST_FILES) diff --git a/dom/tests/mochitest/bugs/test_bug750051.html b/dom/tests/mochitest/bugs/test_bug750051.html new file mode 100644 index 000000000000..181233a41369 --- /dev/null +++ b/dom/tests/mochitest/bugs/test_bug750051.html @@ -0,0 +1,38 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=750051 +--> +<head> + <title>Test for Bug 750051 + + + + +Mozilla Bug 750051 +

      + +
      +
      +
      + + diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index 519226ed47d0..f53bb28a106f 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -252,6 +252,7 @@ pref("privacy.popups.showBrowserMessage", true); pref("dom.disable_window_open_dialog_feature", true); pref("dom.disable_window_showModalDialog", true); pref("dom.disable_window_print", true); +pref("dom.disable_window_find", true); pref("keyword.enabled", true); pref("keyword.URL", "https://www.google.com/m?ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q="); From 303401cb6f66d875f662356d8e45cd855a67c02b Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Thu, 3 May 2012 18:25:07 +0200 Subject: [PATCH 156/159] Bug 745254, r=kaie --- .../content/test/browser_alltabslistener.js | 2 - .../boot/src/nsSecureBrowserUIImpl.cpp | 76 ++++++++++++++++++- .../manager/boot/src/nsSecureBrowserUIImpl.h | 1 + 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/browser/base/content/test/browser_alltabslistener.js b/browser/base/content/test/browser_alltabslistener.js index 4d7d11435169..07e4d117a839 100644 --- a/browser/base/content/test/browser_alltabslistener.js +++ b/browser/base/content/test/browser_alltabslistener.js @@ -131,7 +131,6 @@ function startTest2() { "onStateChange", "onLocationChange", "onSecurityChange", - "onSecurityChange", "onStateChange" ]; gFrontNotifications = gAllNotifications; @@ -156,7 +155,6 @@ function startTest4() { "onStateChange", "onLocationChange", "onSecurityChange", - "onSecurityChange", "onStateChange" ]; gFrontNotifications = []; diff --git a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp index cfdc89967191..a6ec844f7702 100644 --- a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp +++ b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp @@ -169,6 +169,7 @@ nsSecureBrowserUIImpl::nsSecureBrowserUIImpl() , mSubRequestsLowSecurity(0) , mSubRequestsBrokenSecurity(0) , mSubRequestsNoSecurity(0) + , mRestoreSubrequests(false) #ifdef DEBUG , mOnStateLocationChangeReentranceDetection(0) #endif @@ -573,6 +574,11 @@ nsSecureBrowserUIImpl::EvaluateAndUpdateSecurityState(nsIRequest* aRequest, nsIS mCurrentToplevelSecurityInfo = aRequest; else mCurrentToplevelSecurityInfo = info; + + // The subrequest counters are now in sync with + // mCurrentToplevelSecurityInfo, don't restore after top level + // document load finishes. + mRestoreSubrequests = false; } return UpdateSecurityState(aRequest, withNewLocation, @@ -1113,6 +1119,8 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress, prevContentSecurity->SetCountSubRequestsBrokenSecurity(saveSubBroken); prevContentSecurity->SetCountSubRequestsNoSecurity(saveSubNo); prevContentSecurity->Flush(); + PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI:%p: Saving subs in START to %p as %d,%d,%d,%d\n", + this, prevContentSecurity.get(), saveSubHigh, saveSubLow, saveSubBroken, saveSubNo)); } bool retrieveAssociatedState = false; @@ -1146,8 +1154,19 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress, newContentSecurity->GetCountSubRequestsLowSecurity(&newSubLow); newContentSecurity->GetCountSubRequestsBrokenSecurity(&newSubBroken); newContentSecurity->GetCountSubRequestsNoSecurity(&newSubNo); + PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI:%p: Restoring subs in START from %p to %d,%d,%d,%d\n", + this, newContentSecurity.get(), newSubHigh, newSubLow, newSubBroken, newSubNo)); } } + else + { + // If we don't get OnLocationChange for this top level load later, + // it didn't get rendered. But we reset the state to unknown and + // mSubRequests* to zeros. If we would have left these values after + // this top level load stoped, we would override the original top level + // load with all zeros and break mixed content state on back and forward. + mRestoreSubrequests = true; + } } { @@ -1214,20 +1233,75 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress, } } + bool sinkChanged = false; + bool inProgress; { ReentrantMonitorAutoEnter lock(mReentrantMonitor); if (allowSecurityStateChange) { + sinkChanged = (mToplevelEventSink != temp_ToplevelEventSink); mToplevelEventSink = temp_ToplevelEventSink; } --mDocumentRequestsInProgress; + inProgress = mDocumentRequestsInProgress > 0; } if (allowSecurityStateChange && requestHasTransferedData) { // Data has been transferred for the single toplevel // request. Evaluate the security state. - return EvaluateAndUpdateSecurityState(aRequest, securityInfo, false); + // Do this only when the sink has changed. We update and notify + // the state from OnLacationChange, this is actually redundant. + // But when the target sink changes between OnLocationChange and + // OnStateChange, we have to fire the notification here (again). + + if (sinkChanged) + return EvaluateAndUpdateSecurityState(aRequest, securityInfo, false); + } + + if (mRestoreSubrequests && !inProgress) + { + // We get here when there were no OnLocationChange between + // OnStateChange(START) and OnStateChange(STOP). Then the load has not + // been rendered but has been retargeted in some other way then by external + // app handler. Restore mSubRequests* members to what the current security + // state info holds (it was reset to all zero in OnStateChange(START) + // before). + nsCOMPtr currentContentSecurity; + { + ReentrantMonitorAutoEnter lock(mReentrantMonitor); + currentContentSecurity = do_QueryInterface(mCurrentToplevelSecurityInfo); + + // Drop this indication flag, the restore opration is just being + // done. + mRestoreSubrequests = false; + + // We can do this since the state didn't actually change. + mNewToplevelSecurityStateKnown = true; + } + + PRInt32 subHigh = 0; + PRInt32 subLow = 0; + PRInt32 subBroken = 0; + PRInt32 subNo = 0; + + if (currentContentSecurity) + { + currentContentSecurity->GetCountSubRequestsHighSecurity(&subHigh); + currentContentSecurity->GetCountSubRequestsLowSecurity(&subLow); + currentContentSecurity->GetCountSubRequestsBrokenSecurity(&subBroken); + currentContentSecurity->GetCountSubRequestsNoSecurity(&subNo); + PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI:%p: Restoring subs in STOP from %p to %d,%d,%d,%d\n", + this, currentContentSecurity.get(), subHigh, subLow, subBroken, subNo)); + } + + { + ReentrantMonitorAutoEnter lock(mReentrantMonitor); + mSubRequestsHighSecurity = subHigh; + mSubRequestsLowSecurity = subLow; + mSubRequestsBrokenSecurity = subBroken; + mSubRequestsNoSecurity = subNo; + } } return NS_OK; diff --git a/security/manager/boot/src/nsSecureBrowserUIImpl.h b/security/manager/boot/src/nsSecureBrowserUIImpl.h index 535ff290a7c1..fad715e2cc52 100644 --- a/security/manager/boot/src/nsSecureBrowserUIImpl.h +++ b/security/manager/boot/src/nsSecureBrowserUIImpl.h @@ -130,6 +130,7 @@ protected: PRInt32 mSubRequestsLowSecurity; PRInt32 mSubRequestsBrokenSecurity; PRInt32 mSubRequestsNoSecurity; + bool mRestoreSubrequests; #ifdef DEBUG /* related to mReentrantMonitor */ PRInt32 mOnStateLocationChangeReentranceDetection; From f4603a370beb8500f9eb4ca79620e9f7877fde26 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Thu, 3 May 2012 19:17:01 +0300 Subject: [PATCH 157/159] Bug 751561 - Call forgetSkippable at least twice before CC, r=mccr8 --HG-- extra : rebase_source : 7434eb9be0bbdfd7fe44e1aeced9698d6c0627e1 --- content/base/src/nsCCUncollectableMarker.cpp | 2 +- dom/base/nsJSEnvironment.cpp | 25 +++++++++++--------- dom/base/nsJSEnvironment.h | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/content/base/src/nsCCUncollectableMarker.cpp b/content/base/src/nsCCUncollectableMarker.cpp index 432fec70f88a..decbeaff20de 100644 --- a/content/base/src/nsCCUncollectableMarker.cpp +++ b/content/base/src/nsCCUncollectableMarker.cpp @@ -317,7 +317,7 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic, // JS cleanup can be slow. Do it only if there has been a GC. bool cleanupJS = - !nsJSContext::CleanupSinceLastGC() && + nsJSContext::CleanupsSinceLastGC() == 0 && !strcmp(aTopic, "cycle-collector-forget-skippable"); bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin"); diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index c27346195329..27625e5f8a7c 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -186,7 +186,7 @@ static PRUint32 sRemovedPurples = 0; static PRUint32 sForgetSkippableBeforeCC = 0; static PRUint32 sPreviousSuspectedCount = 0; -static bool sCleanupSinceLastGC = true; +static PRUint32 sCleanupsSinceLastGC = PR_UINT32_MAX; static bool sNeedsFullCC = false; nsScriptNameSpaceManager *gNameSpaceManager; @@ -2951,14 +2951,18 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, PRUint32 suspected = nsCycleCollector_suspectedCount(); - for (PRInt32 i = 0; i < aExtraForgetSkippableCalls; ++i) { - nsCycleCollector_forgetSkippable(); + // nsCycleCollector_forgetSkippable may mark some gray js to black. + if (sCleanupsSinceLastGC < 2 && aExtraForgetSkippableCalls >= 0) { + for (;sCleanupsSinceLastGC < 2; ++sCleanupsSinceLastGC) { + nsCycleCollector_forgetSkippable(); + } } - // nsCycleCollector_forgetSkippable may mark some gray js to black. - if (!sCleanupSinceLastGC && aExtraForgetSkippableCalls >= 0) { + for (PRInt32 i = 0; i < aExtraForgetSkippableCalls; ++i) { nsCycleCollector_forgetSkippable(); + ++sCleanupsSinceLastGC; } + nsCycleCollectorResults ccResults; nsCycleCollector_collect(&ccResults, aListener); sCCollectedWaitingForGC += ccResults.mFreedRefCounted + ccResults.mFreedGCed; @@ -3062,7 +3066,6 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, sTotalForgetSkippableTime = 0; sRemovedPurples = 0; sForgetSkippableBeforeCC = 0; - sCleanupSinceLastGC = true; sNeedsFullCC = false; } @@ -3098,7 +3101,7 @@ TimerFireForgetSkippable(PRUint32 aSuspected, bool aRemoveChildless) PRTime startTime = PR_Now(); nsCycleCollector_forgetSkippable(aRemoveChildless); sPreviousSuspectedCount = nsCycleCollector_suspectedCount(); - sCleanupSinceLastGC = true; + ++sCleanupsSinceLastGC; PRTime delta = PR_Now() - startTime; if (sMinForgetSkippableTime > delta) { sMinForgetSkippableTime = delta; @@ -3167,10 +3170,10 @@ CCTimerFired(nsITimer *aTimer, void *aClosure) } // static -bool -nsJSContext::CleanupSinceLastGC() +PRUint32 +nsJSContext::CleanupsSinceLastGC() { - return sCleanupSinceLastGC; + return sCleanupsSinceLastGC; } // static @@ -3389,7 +3392,7 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip nsJSContext::KillGCTimer(); sCCollectedWaitingForGC = 0; - sCleanupSinceLastGC = false; + sCleanupsSinceLastGC = 0; if (aDesc.isCompartment) { // If this is a compartment GC, restart it. We still want diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index aa2b3534683c..bf03a9a3215c 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -202,7 +202,7 @@ public: virtual void GC(js::gcreason::Reason aReason); - static bool CleanupSinceLastGC(); + static PRUint32 CleanupsSinceLastGC(); nsIScriptGlobalObject* GetCachedGlobalObject() { From 84e253b4d49199b777fc5a04052eaa874da91b2a Mon Sep 17 00:00:00 2001 From: Ali Juma Date: Thu, 3 May 2012 12:33:51 -0400 Subject: [PATCH 158/159] Bug 748048 - Part 1: Remove SetInvalidationDimensions and GetInvalidationDimensions. r=roc --- dom/base/nsDOMWindowUtils.cpp | 13 ------------- layout/generic/nsFrame.cpp | 4 ++++ view/public/nsIView.h | 15 ++------------- view/src/nsView.cpp | 13 ------------- view/src/nsView.h | 12 ------------ view/src/nsViewManager.cpp | 16 ++-------------- 6 files changed, 8 insertions(+), 65 deletions(-) diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index b05d4a39d640..bb8a80be8d84 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -331,19 +331,6 @@ nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx, // We are setting a root displayport for a document. // The pres shell needs a special flag set. presShell->SetIgnoreViewportScrolling(true); - - // The root document currently has a widget, but we might end up - // painting content inside the displayport but outside the widget - // bounds. This ensures the document's view honors invalidations - // within the displayport. - nsPresContext* presContext = GetPresContext(); - if (presContext && presContext->IsRoot()) { - nsIFrame* rootFrame = presShell->GetRootFrame(); - nsIView* view = rootFrame->GetView(); - if (view) { - view->SetInvalidationDimensions(&displayport); - } - } } } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 31b2cf82e9af..ecdc582a55ab 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4553,6 +4553,10 @@ void nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX, nscoord aY, PRUint32 aFlags) { + if (aDamageRect.IsEmpty()) { + return; + } + /* If we're a transformed frame, then we need to apply our transform to the * damage rectangle so that the redraw correctly redraws the transformed * region. We're moved over aX and aY from our origin, but since this aX diff --git a/view/public/nsIView.h b/view/public/nsIView.h index 6d4fe367d9d9..aa2beb642993 100644 --- a/view/public/nsIView.h +++ b/view/public/nsIView.h @@ -63,8 +63,8 @@ enum nsViewVisibility { }; #define NS_IVIEW_IID \ - { 0xda62efbf, 0x0711, 0x4b79, \ - { 0x87, 0x85, 0x9e, 0xec, 0xed, 0xf5, 0xb0, 0x32 } } + { 0x697948d2, 0x3f10, 0x407d, \ + { 0xb8, 0x94, 0x9f, 0x36, 0xd2, 0x11, 0xdb, 0xf1 } } // Public view flags @@ -167,17 +167,6 @@ public: nsRect r = mDimBounds; r.MoveBy(-mPosX, -mPosY); return r; } - /** - * Set the dimensions at which invalidations are clipped, which can - * be different than |GetDimensions()|. |aRect| is relative to - * |this|. It can be null, in which case invalidations return to - * being clipped to the view dimensions. - * - * The caller is responsible for invalidating the area that may lie - * outside the view dimensions but inside |aRect| after this call. - */ - void SetInvalidationDimensions(const nsRect* aRect); - /** * Get the offset between the coordinate systems of |this| and aOther. * Adding the return value to a point in the coordinate system of |this| diff --git a/view/src/nsView.cpp b/view/src/nsView.cpp index 652d64ecac18..2be25b1ba6f7 100644 --- a/view/src/nsView.cpp +++ b/view/src/nsView.cpp @@ -206,7 +206,6 @@ nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility) mViewManager = aViewManager; mDirtyRegion = nsnull; mDeletionObserver = nsnull; - mHaveInvalidationDimensions = false; mWidgetIsTopLevel = false; } @@ -355,11 +354,6 @@ void nsView::SetPosition(nscoord aX, nscoord aY) ResetWidgetBounds(true, false); } -void nsIView::SetInvalidationDimensions(const nsRect* aRect) -{ - return Impl()->SetInvalidationDimensions(aRect); -} - void nsView::ResetWidgetBounds(bool aRecurse, bool aForceSync) { if (mWindow) { @@ -498,13 +492,6 @@ void nsView::SetDimensions(const nsRect& aRect, bool aPaint, bool aResizeWidget) } } -void nsView::SetInvalidationDimensions(const nsRect* aRect) -{ - if ((mHaveInvalidationDimensions = !!aRect)) { - mInvalidationDimensions = *aRect; - } -} - void nsView::NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible) { if (!aEffectivelyVisible) diff --git a/view/src/nsView.h b/view/src/nsView.h index 4bcec9b2a94a..579ba9e561ef 100644 --- a/view/src/nsView.h +++ b/view/src/nsView.h @@ -76,7 +76,6 @@ public: */ virtual void SetDimensions(const nsRect &aRect, bool aPaint = true, bool aResizeWidget = true); - void SetInvalidationDimensions(const nsRect* aRect); /** * Called to indicate that the visibility of a view has been @@ -149,10 +148,6 @@ public: // Same as GetBounds but converts to parent appunits if they are different. nsRect GetBoundsInParentUnits() const; - nsRect GetInvalidationDimensions() const { - return mHaveInvalidationDimensions ? mInvalidationDimensions : GetDimensions(); - } - // These are defined exactly the same in nsIView, but for now they have to be redeclared // here because of stupid C++ method hiding rules @@ -205,13 +200,6 @@ protected: void DoResetWidgetBounds(bool aMoveOnly, bool aInvalidateChangedSize); nsRegion* mDirtyRegion; - // invalidations are clipped to mInvalidationDimensions, not - // GetDimensions(), when mHaveInvalidationDimensions is true. This - // is used to support persistent "displayport" rendering; see - // nsPresShell.cpp. The coordinates of mInvalidationDimensions are - // relative to |this|. - nsRect mInvalidationDimensions; - bool mHaveInvalidationDimensions; private: void InitializeWindow(bool aEnableDragDrop, bool aResetVisibility); diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index 0075e757f8c2..849632479076 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -479,13 +479,6 @@ nsViewManager::InvalidateWidgetArea(nsView *aWidgetView, widget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height); #endif - // If the bounds don't overlap at all, there's nothing to do - nsRegion intersection; - intersection.And(aWidgetView->GetInvalidationDimensions(), aDamagedRegion); - if (intersection.IsEmpty()) { - return; - } - // If the widget is hidden, it don't cover nothing if (widget) { bool visible; @@ -542,7 +535,7 @@ nsViewManager::InvalidateWidgetArea(nsView *aWidgetView, } nsRegion leftOver; - leftOver.Sub(intersection, children); + leftOver.Sub(aDamagedRegion, children); if (!leftOver.IsEmpty()) { const nsRect* r; @@ -1320,13 +1313,8 @@ nsIntRect nsViewManager::ViewToWidget(nsView *aView, const nsRect &aRect) const { NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager"); - // intersect aRect with bounds of aView, to prevent generating any illegal rectangles. - nsRect bounds = aView->GetInvalidationDimensions(); - nsRect rect; - rect.IntersectRect(aRect, bounds); - // account for the view's origin not lining up with the widget's - rect += aView->ViewToWidgetOffset(); + nsRect rect = aRect + aView->ViewToWidgetOffset(); // finally, convert to device coordinates. return rect.ToOutsidePixels(AppUnitsPerDevPixel()); From 6868660a49dd49367bff491af911a48f4a5248a6 Mon Sep 17 00:00:00 2001 From: Ali Juma Date: Thu, 3 May 2012 12:34:02 -0400 Subject: [PATCH 159/159] Bug 748048 - Part 2: Don't restrict invalidation to the widget's boundaries on Android. r=roc --- widget/android/nsWindow.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index db7e8a3cdbe5..0c5d735bcb06 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -1019,9 +1019,7 @@ nsWindow::DrawTo(gfxASurface *targetSurface, const nsIntRect &invalidRect) // If we have no covering child, then we need to render this. if (coveringChildIndex == -1) { nsPaintEvent event(true, NS_PAINT, this); - - nsIntRect tileRect(0, 0, gAndroidBounds.width, gAndroidBounds.height); - event.region = boundsRect.Intersect(invalidRect).Intersect(tileRect); + event.region = invalidRect; switch (GetLayerManager(nsnull)->GetBackendType()) { case LayerManager::LAYERS_BASIC: { @@ -1126,11 +1124,10 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) layers::renderTraceEventEnd("Get surface", "424545"); layers::renderTraceEventStart("Widget draw to", "434646"); - nsIntRect dirtyRect = ae->Rect().Intersect(nsIntRect(0, 0, gAndroidBounds.width, gAndroidBounds.height)); if (targetSurface->CairoStatus()) { ALOG("### Failed to create a valid surface from the bitmap"); } else { - DrawTo(targetSurface, dirtyRect); + DrawTo(targetSurface, ae->Rect()); } layers::renderTraceEventEnd("Widget draw to", "434646"); return;