diff --git a/autobuild.xml b/autobuild.xml
index e32857f6b7a4c993db404a12900fac1e526fffb2..ca7874423d1ff429f2dcfe90b03d4e05aa71648d 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1902,11 +1902,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>666ad5a7dd4bede7745cbe2846e2516b47510720824c57fa976bf8424b4f7745b8adbc209e65410ad0e03d3f78f8146d841fb81bbf23fc05358be11ffef60900</string>
+              <string>4261f3c8510252c4767c422f309d6f5c462f3069dbe5d943bc72444d6ba56b796ed1c4e3b65c2c6ff12e37379445a6b172226bc56e3557e2bd698bf8d86ec322</string>
               <key>hash_algorithm</key>
               <string>blake2b</string>
               <key>url</key>
-              <string>https://git.alchemyviewer.org/api/v4/projects/147/packages/generic/openjpeg/2.4.0.2371/openjpeg-2.4.0-darwin64-2371.tar.zst</string>
+              <string>https://git.alchemyviewer.org/api/v4/projects/105/packages/generic/openjpeg/1.5.1.2451/openjpeg-1.5.1-darwin64-2451.tar.zst</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -1916,11 +1916,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>331d224c638d9ee50c519d8714ad48b8e1c7802ee18ff7b64c77c1905d48cee1a4f0d0c1f23c546dc298464817e4fd39a61b066537ea0a1cbcc90f059ae1747f</string>
+              <string>bfadf99f079161d6f2cef1ce1c4d2623a1aa8f02ba87ff71697af048261d4ea3ca2cbe3e95d627abe985c10bd80edd16b18ef124c7af57246a4ad7887de985d9</string>
               <key>hash_algorithm</key>
               <string>blake2b</string>
               <key>url</key>
-              <string>https://git.alchemyviewer.org/api/v4/projects/147/packages/generic/openjpeg/2.4.0.2371/openjpeg-2.4.0-linux64-2371.tar.zst</string>
+              <string>https://git.alchemyviewer.org/api/v4/projects/105/packages/generic/openjpeg/1.5.1.2451/openjpeg-1.5.1-linux64-2451.tar.zst</string>
             </map>
             <key>name</key>
             <string>linux64</string>
@@ -1930,11 +1930,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>4bc3980bf4bf9b5d933fcca1949bd2890a5fb2e3a22675e524ea6989150a77211e30f3bc81999272f23387f3aefcd2d894dca7f5bea6f79fcb6b8aea6a02ebcb</string>
+              <string>d10bc74430b0ee657cb9c6bafec81860974547c1890c038e4223b6e50665cf352a0b8c7dd2db81b21c086a15c6a55ba545d087f88dedddf599fd743e515564c9</string>
               <key>hash_algorithm</key>
               <string>blake2b</string>
               <key>url</key>
-              <string>https://git.alchemyviewer.org/api/v4/projects/147/packages/generic/openjpeg/2.4.0.2371/openjpeg-2.4.0-windows64-2371.tar.zst</string>
+              <string>https://git.alchemyviewer.org/api/v4/projects/105/packages/generic/openjpeg/1.5.1.2451/openjpeg-1.5.1-windows64-2451.tar.zst</string>
             </map>
             <key>name</key>
             <string>windows64</string>
@@ -1945,9 +1945,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>license_file</key>
         <string>LICENSES/openjpeg.txt</string>
         <key>copyright</key>
-        <string>Copyright (c) 2002-2014, Universite catholique de Louvain, Belgium, Copyright (c) 2002-2012, Professor Benoit Macq, Copyright (c) 2003-2012, Antonin Descampe, Copyright (c) 2003-2009, Francois-Olivier Devaux, Copyright (c) 2005, Herve Drolon, FreeImage Team, Copyright (c) 2002-2003, Yannick Verschueren, Copyright (c) 2001-2003, David Janssens</string>
+        <string>Copyright (c) 2002-2012, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium, Copyright (c) 2002-2012, Professor Benoit Macq, Copyright (c) 2003-2012, Antonin Descampe, Copyright (c) 2003-2009, Francois-Olivier Devaux, Copyright (c) 2005, Herve Drolon, FreeImage Team, Copyright (c) 2002-2003, Yannick Verschueren, Copyright (c) 2001-2003, David Janssens</string>
         <key>version</key>
-        <string>2.4.0</string>
+        <string>1.5.1</string>
         <key>name</key>
         <string>openjpeg</string>
         <key>description</key>
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index ecb2eda9014623449ac480e5bdfc8059516ec683..8f8322d8c47de220aa150eb10c45768177d0f054 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -58,12 +58,12 @@ if(WINDOWS)
 
     set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}")
     set(debug_files
-        openjp2.dll
+        openjpeg.dll
         )
 
     set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
     set(release_files
-        openjp2.dll
+        openjpeg.dll
         )
 
     # ICU4C (same filenames for 32 and 64 bit builds)
diff --git a/indra/cmake/OpenJPEG.cmake b/indra/cmake/OpenJPEG.cmake
index 32739d5786de349b03e602cd7e38ec4ed77b01c5..5d4abf57afd8aa39c73230a993bb1464e8320c82 100644
--- a/indra/cmake/OpenJPEG.cmake
+++ b/indra/cmake/OpenJPEG.cmake
@@ -9,9 +9,9 @@ use_prebuilt_binary(openjpeg)
 
 if(WINDOWS)
   target_link_libraries(ll::openjpeg INTERFACE
-      debug ${ARCH_PREBUILT_DIRS_DEBUG}/openjp2.lib
-      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/openjp2.lib)
+      debug ${ARCH_PREBUILT_DIRS_DEBUG}/openjpeg.lib
+      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/openjpeg.lib)
 else ()
-  target_link_libraries(ll::openjpeg INTERFACE openjp2 )
+  target_link_libraries(ll::openjpeg INTERFACE openjpeg )
 endif ()
-target_include_directories( ll::openjpeg SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/openjpeg)
+target_include_directories( ll::openjpeg SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/openjpeg-1.5)
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp
index aafb2e228670f1081561ae316712fac1063e7a46..ce7035de4fb4a7e0cfa7c549e742ad25efac110a 100644
--- a/indra/llimagej2coj/llimagej2coj.cpp
+++ b/indra/llimagej2coj/llimagej2coj.cpp
@@ -1,25 +1,25 @@
-/** 
+/**
  * @file llimagej2coj.cpp
  * @brief This is an implementation of JPEG2000 encode/decode using OpenJPEG.
  *
  * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2010, Linden Research, Inc.
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
  * version 2.1 of the License only.
- * 
+ *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
@@ -27,134 +27,11 @@
 #include "linden_common.h"
 #include "llimagej2coj.h"
 
-// this is defined so that we get static linking.
+ // this is defined so that we get static linking.
 #include "openjpeg.h"
 
 #include "lltimer.h"
-
-struct LLJp2StreamReader 
-{
-	LLJp2StreamReader(LLImageJ2C* pImage) : m_pImage(pImage), m_Position(0) { }
-
-	static OPJ_SIZE_T readStream(void* pBufferOut, OPJ_SIZE_T szBufferOut, void* pUserData)
-	{
-		LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData);
-		if (!pBufferOut || !pStream || !pStream->m_pImage)
-			return (OPJ_SIZE_T)-1;
-
-		OPJ_SIZE_T szBufferRead = llmin(szBufferOut, pStream->m_pImage->getDataSize() - pStream->m_Position);
-		if (!szBufferRead)
-			return (OPJ_SIZE_T)-1;
-
-		memcpy(pBufferOut, pStream->m_pImage->getData() + pStream->m_Position, szBufferRead);
-		pStream->m_Position += szBufferRead;
-		return szBufferRead;
-	}
-
-	static OPJ_OFF_T skipStream(OPJ_OFF_T bufferOffset, void* pUserData)
-	{
-		LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData);
-		if (!pStream || !pStream->m_pImage)
-			return (OPJ_OFF_T)-1;
-
-		if (bufferOffset < 0)
-		{
-			// Skipping backward
-			if (pStream->m_Position == 0)
-				return (OPJ_OFF_T)-1;              // Already at the start of the stream
-			else if (pStream->m_Position + bufferOffset < 0)
-				bufferOffset = -(OPJ_OFF_T)pStream->m_Position; // Don't underflow
-		}
-		else
-		{
-			// Skipping forward
-			OPJ_SIZE_T szRemaining = pStream->m_pImage->getDataSize() - pStream->m_Position;
-			if (!szRemaining)
-				return (OPJ_OFF_T)-1;              // Already at the end of the stream
-			else if (bufferOffset > szRemaining)
-				bufferOffset = szRemaining;          // Don't overflow
-		}
-		pStream->m_Position += bufferOffset;
-
-		return bufferOffset;
-	}
-
-	static OPJ_BOOL seekStream(OPJ_OFF_T bufferOffset, void* pUserData)
-	{
-		LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData);
-		if (!pStream || !pStream->m_pImage)
-			return OPJ_FALSE;
-
-		if (bufferOffset < 0 || bufferOffset > pStream->m_pImage->getDataSize())
-			return OPJ_FALSE;
-
-		pStream->m_Position = bufferOffset;
-		return OPJ_TRUE;
-	}
-
-	LLImageJ2C* m_pImage = nullptr;
-	OPJ_SIZE_T  m_Position = 0;
-};
-
-struct LLJp2StreamWriter 
-{
-	LLJp2StreamWriter(LLImageJ2C* pImage) : m_pImage(pImage), m_Position(0) { }
-
-	static OPJ_SIZE_T writeStream(void* pBufferIn, OPJ_SIZE_T szBufferIn, void* pUserData)
-	{
-		LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData);
-		if (!pBufferIn || !pStream || !pStream->m_pImage)
-			return (OPJ_SIZE_T)-1;
-
-		if (pStream->m_Position + szBufferIn > pStream->m_pImage->getDataSize())
-			pStream->m_pImage->reallocateData(pStream->m_Position + szBufferIn);
-
-		memcpy(pStream->m_pImage->getData() + pStream->m_Position, pBufferIn, szBufferIn);
-		pStream->m_Position += szBufferIn;
-		return szBufferIn;
-	}
-
-	static OPJ_OFF_T skipStream(OPJ_OFF_T bufferOffset, void* pUserData)
-	{
-		LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData);
-		if (!pStream || !pStream->m_pImage)
-			return -1;
-
-		if (bufferOffset < 0)
-		{
-			// Skipping backward
-			if (pStream->m_Position == 0)
-				return -1;                           // Already at the start of the stream
-			else if (pStream->m_Position + bufferOffset < 0)
-				bufferOffset = -(OPJ_OFF_T)pStream->m_Position; // Don't underflow
-		}
-		else
-		{
-			// Skipping forward
-			if (pStream->m_Position + bufferOffset > pStream->m_pImage->getDataSize())
-				return -1;                           // Don't allow skipping past the end of the stream
-		}
-
-		pStream->m_Position += bufferOffset;
-		return bufferOffset;
-	}
-
-	static OPJ_BOOL seekStream(OPJ_OFF_T bufferOffset, void* pUserData)
-	{
-		LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData);
-		if (!pStream || !pStream->m_pImage)
-			return OPJ_FALSE;
-
-		if (bufferOffset < 0 || bufferOffset > pStream->m_pImage->getDataSize())
-			return OPJ_FALSE;
-
-		pStream->m_Position = bufferOffset;
-		return OPJ_TRUE;
-	}
-
-	LLImageJ2C* m_pImage = nullptr;
-	OPJ_OFF_T m_Position = 0;
-};
+//#include "llmemory.h"
 
 // Factory function: see declaration in llimagej2c.cpp
 LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
@@ -164,10 +41,11 @@ LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
 
 std::string LLImageJ2COJ::getEngineInfo() const
 {
-#ifdef OPJ_PACKAGE_VERSION
-	return std::string("OpenJPEG: " OPJ_PACKAGE_VERSION ", Runtime: ") + opj_version();
+#ifdef OPENJPEG_VERSION
+	return std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ")
+		+ opj_version();
 #else
-	return std::string("OpenJPEG Runtime: ") + opj_version();
+	return std::string("OpenJPEG runtime: ") + opj_version();
 #endif
 }
 
@@ -181,7 +59,7 @@ static std::string chomp(const char* msg)
 		size_t last = message.size() - 1;
 		if (message[last] == '\n')
 		{
-			message.resize( last );
+			message.resize(last);
 		}
 	}
 	return message;
@@ -192,21 +70,21 @@ sample error callback expecting a LLFILE* client object
 */
 void error_callback(const char* msg, void*)
 {
-	LL_WARNS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+	LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
 }
 /**
 sample warning callback expecting a LLFILE* client object
 */
 void warning_callback(const char* msg, void*)
 {
-	LL_WARNS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+	LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
 }
 /**
 sample debug callback expecting no client object
 */
 void info_callback(const char* msg, void*)
 {
-	LL_INFOS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+	LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
 }
 
 // Divide a by 2 to the power of b and round upwards
@@ -215,70 +93,47 @@ int ceildivpow2(int a, int b)
 	return (a + (1 << b) - 1) >> b;
 }
 
+
 LLImageJ2COJ::LLImageJ2COJ()
 	: LLImageJ2CImpl()
 {
 }
 
-bool LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
+
+bool LLImageJ2COJ::initDecode(LLImageJ2C& base, LLImageRaw& raw_image, int discard_level, int* region)
 {
 	// No specific implementation for this method in the OpenJpeg case
 	return false;
 }
 
-bool LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
+bool LLImageJ2COJ::initEncode(LLImageJ2C& base, LLImageRaw& raw_image, int blocks_size, int precincts_size, int levels)
 {
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 	// No specific implementation for this method in the OpenJpeg case
 	return false;
 }
 
-bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
+bool LLImageJ2COJ::decodeImpl(LLImageJ2C& base, LLImageRaw& raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
 {
+	//
+	// FIXME: Get the comment field out of the texture
+	//
+
 	LLTimer decode_timer;
 
-	/* Extract metadata */
-	/* ---------------- */
-	U8* c_data = base.getData();
-	size_t c_size =  base.getDataSize();
-	size_t position = 0;
-	
-	while (position < 1024 && position < (c_size - 7)) // the comment field should be in the first 1024 bytes.
-	{
-		if (c_data[position] == 0xff && c_data[position + 1] == 0x64)
-		{
-			U8 high_byte = c_data[position + 2];
-			U8 low_byte = c_data[position + 3];
-			S32 c_length = (high_byte * 256) + low_byte; // This size also counts the markers, 00 01 and itself
-			if (c_length > 200) // sanity check
-			{
-				// While comments can be very long, anything longer then 200 is suspect.
-				break;
-			}
-			
-			if (position + 2 + c_length > c_size)
-			{
-				// comment extends past end of data, corruption, or all data not retrived yet.
-				break;
-			}
-			
-			// if the comment block does not end at the end of data, check to see if the next
-			// block starts with 0xFF
-			if (position + 2 + c_length < c_size && c_data[position + 2 + c_length] != 0xff)
-			{
-				// invalied comment block
-				break;
-			}
-			
-			// extract the comment minus the markers, 00 01
-			raw_image.mComment.assign((char*)c_data + position + 6, c_length - 4);
-			break;
-		}
-		++position;
-	}
-	
 	opj_dparameters_t parameters;	/* decompression parameters */
-	opj_image_t *image = NULL;
+	opj_event_mgr_t event_mgr = { };		/* event manager */
+	opj_image_t* image = nullptr;
+
+	opj_dinfo_t* dinfo = nullptr;	/* handle to a decompressor */
+	opj_cio_t* cio = nullptr;
+
+
+#if SHOW_DEBUG
+	/* configure the event callbacks (not required) */
+	event_mgr.error_handler = error_callback;
+	event_mgr.warning_handler = warning_callback;
+	event_mgr.info_handler = info_callback;
+#endif
 
 	/* set decoding parameters to default values */
 	opj_set_default_decoder_parameters(&parameters);
@@ -291,63 +146,35 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
 	/* JPEG-2000 codestream */
 
 	/* get a decoder handle */
-	opj_codec_t* opj_decoder_p = opj_create_decompress(OPJ_CODEC_J2K);
-	if (!opj_decoder_p)
-	{
-#ifdef SHOW_DEBUG
-		LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to create decoder!" << LL_ENDL;
-#endif
-		base.decodeFailed();
-		return true; // done
-	}
+	dinfo = opj_create_decompress(CODEC_J2K);
 
-#if 0
 	/* catch events using our callbacks and give a local context */
-	opj_set_error_handler(opj_decoder_p, error_callback, nullptr);
-	opj_set_warning_handler(opj_decoder_p, warning_callback, nullptr);
-	opj_set_info_handler(opj_decoder_p, info_callback, nullptr);
-#endif
+	opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
 
 	/* setup the decoder decoding parameters using user parameters */
-	if (!opj_setup_decoder(opj_decoder_p, &parameters))
-	{
-#ifdef SHOW_DEBUG
-		LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL;
-#endif
-		opj_destroy_codec(opj_decoder_p);
-		base.decodeFailed();
-		return true; // done
-	}
-
-	//opj_decoder_set_strict_mode(opj_decoder_p, OPJ_FALSE);
+	opj_setup_decoder(dinfo, &parameters);
 
 	/* open a byte stream */
-	LLJp2StreamReader streamReader(&base);
-	opj_stream_t* opj_stream_p = opj_stream_default_create(OPJ_STREAM_READ);
-	opj_stream_set_read_function(opj_stream_p, LLJp2StreamReader::readStream);
-	opj_stream_set_skip_function(opj_stream_p, LLJp2StreamReader::skipStream);
-	opj_stream_set_seek_function(opj_stream_p, LLJp2StreamReader::seekStream);
-	opj_stream_set_user_data(opj_stream_p, &streamReader, nullptr);
-	opj_stream_set_user_data_length(opj_stream_p, base.getDataSize());
+	cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize());
 
 	/* decode the stream and fill the image structure */
-	bool success = opj_read_header(opj_stream_p, opj_decoder_p, &image) &&
-	                opj_decode(opj_decoder_p, opj_stream_p, image) &&
-					opj_end_decompress(opj_decoder_p, opj_stream_p);
+	image = opj_decode(dinfo, cio);
 
 	/* close the byte stream */
-	opj_stream_destroy(opj_stream_p);
+	opj_cio_close(cio);
 
 	/* free remaining structures */
-	opj_destroy_codec(opj_decoder_p);
-
+	if (dinfo)
+	{
+		opj_destroy_decompress(dinfo);
+	}
 
 	// The image decode failed if the return was NULL or the component
 	// count was zero.  The latter is just a sanity check before we
 	// dereference the array.
-	if (!success || !image || !image->numcomps)
+	if (!image || !image->numcomps)
 	{
-#ifdef SHOW_DEBUG
+#if SHOW_DEBUG
 		LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL;
 #endif
 		if (image)
@@ -358,15 +185,23 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
 		return true; // done
 	}
 
-	if(image->numcomps <= first_channel)
+	// sometimes we get bad data out of the cache - check to see if the decode succeeded
+	for (S32 i = 0; i < image->numcomps; i++)
 	{
-		LL_WARNS() << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << LL_ENDL;
-		if (image)
+		if (image->comps[i].factor != base.getRawDiscardLevel())
 		{
+			// if we didn't get the discard level we're expecting, fail
 			opj_image_destroy(image);
+			base.decodeFailed();
+			return true;
 		}
-		base.decodeFailed();
+	}
 
+	if (image->numcomps <= first_channel)
+	{
+		LL_WARNS() << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << LL_ENDL;
+		opj_image_destroy(image);
+		base.decodeFailed();
 		return true;
 	}
 
@@ -374,7 +209,7 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
 
 	S32 img_components = image->numcomps;
 	S32 channels = img_components - first_channel;
-	if( channels > max_channel_count )
+	if (channels > max_channel_count)
 		channels = max_channel_count;
 
 	// Component buffers are allocated in an image width by height buffer.
@@ -385,11 +220,11 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
 	// (Assuming all the components have the same width, height and
 	// factor.)
 	S32 comp_width = image->comps[0].w;
-	S32 f=image->comps[0].factor;
+	S32 f = image->comps[0].factor;
 	S32 width = ceildivpow2(image->x1 - image->x0, f);
 	S32 height = ceildivpow2(image->y1 - image->y0, f);
 	raw_image.resize(width, height, channels);
-	U8 *rawp = raw_image.getData();
+	U8* rawp = raw_image.getData();
 	if (!rawp)
 	{
 		opj_image_destroy(image);
@@ -401,7 +236,7 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
 	// first_channel is what channel to start copying from
 	// dest is what channel to copy to.  first_channel comes from the
 	// argument, dest always starts writing at channel zero.
-	for (S32 comp = first_channel, dest=0; comp < first_channel + channels;
+	for (S32 comp = first_channel, dest = 0; comp < first_channel + channels;
 		comp++, dest++)
 	{
 		if (image->comps[comp].data)
@@ -411,14 +246,14 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
 			{
 				for (S32 x = 0; x < width; x++)
 				{
-					rawp[offset] = image->comps[comp].data[y*comp_width + x];
+					rawp[offset] = image->comps[comp].data[y * comp_width + x];
 					offset += channels;
 				}
 			}
 		}
 		else // Some rare OpenJPEG versions have this bug.
 		{
-#ifdef SHOW_DEBUG
+#if SHOW_DEBUG
 			LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << LL_ENDL;
 #endif
 			opj_image_destroy(image);
@@ -434,10 +269,20 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
 }
 
 
-bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible)
+bool LLImageJ2COJ::encodeImpl(LLImageJ2C& base, const LLImageRaw& raw_image, const char* comment_text, F32 encode_time, bool reversible)
 {
 	const S32 MAX_COMPS = 5;
 	opj_cparameters_t parameters;	/* compression parameters */
+	opj_event_mgr_t event_mgr = { };		/* event manager */
+
+
+	/*
+	configure the event callbacks (not required)
+	setting of each callback is optional
+	*/
+	event_mgr.error_handler = error_callback;
+	event_mgr.warning_handler = warning_callback;
+	event_mgr.info_handler = info_callback;
 
 	/* set encoding parameters to default values */
 	opj_set_default_encoder_parameters(&parameters);
@@ -452,10 +297,10 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con
 	else
 	{
 		parameters.tcp_numlayers = 5;
-                parameters.tcp_rates[0] = 1920.0f;
-                parameters.tcp_rates[1] = 480.0f;
-                parameters.tcp_rates[2] = 120.0f;
-                parameters.tcp_rates[3] = 30.0f;
+		parameters.tcp_rates[0] = 1920.0f;
+		parameters.tcp_rates[1] = 480.0f;
+		parameters.tcp_rates[2] = 120.0f;
+		parameters.tcp_rates[3] = 30.0f;
 		parameters.tcp_rates[4] = 10.0f;
 		parameters.irreversible = 1;
 		if (raw_image.getComponents() >= 3)
@@ -466,26 +311,26 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con
 
 	if (!comment_text)
 	{
-		parameters.cp_comment = (char *) "";
+		parameters.cp_comment = (char*)"";
 	}
 	else
 	{
 		// Awful hacky cast, too lazy to copy right now.
-		parameters.cp_comment = (char *) comment_text;
+		parameters.cp_comment = (char*)comment_text;
 	}
 
 	//
 	// Fill in the source image from our raw image
 	//
-	OPJ_COLOR_SPACE color_space = OPJ_CLRSPC_SRGB;
+	OPJ_COLOR_SPACE color_space = CLRSPC_SRGB;
 	opj_image_cmptparm_t cmptparm[MAX_COMPS];
-	opj_image_t * image = NULL;
+	opj_image_t* image = nullptr;
 	S32 numcomps = raw_image.getComponents();
 	S32 width = raw_image.getWidth();
 	S32 height = raw_image.getHeight();
 
 	memset(&cmptparm[0], 0, MAX_COMPS * sizeof(opj_image_cmptparm_t));
-	for(S32 c = 0; c < numcomps; c++) {
+	for (S32 c = 0; c < numcomps; c++) {
 		cmptparm[c].prec = 8;
 		cmptparm[c].bpp = 8;
 		cmptparm[c].sgnd = 0;
@@ -502,12 +347,12 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con
 	image->y1 = height;
 
 	S32 i = 0;
-	const U8 *src_datap = raw_image.getData();
+	const U8* src_datap = raw_image.getData();
 	for (S32 y = height - 1; y >= 0; y--)
 	{
 		for (S32 x = 0; x < width; x++)
 		{
-			const U8 *pixel = src_datap + (y*width + x) * numcomps;
+			const U8* pixel = src_datap + (y * width + x) * numcomps;
 			for (S32 c = 0; c < numcomps; c++)
 			{
 				image->comps[c].data[i] = *pixel;
@@ -517,113 +362,104 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con
 		}
 	}
 
+
+
 	/* encode the destination image */
 	/* ---------------------------- */
 
+	int codestream_length;
+	opj_cio_t* cio = nullptr;
+
 	/* get a J2K compressor handle */
-	opj_codec_t* opj_encoder_p = opj_create_compress(OPJ_CODEC_J2K);
+	opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K);
 
-#ifdef SHOW_DEBUG
 	/* catch events using our callbacks and give a local context */
-	opj_set_error_handler(opj_encoder_p, error_callback, nullptr);
-	opj_set_warning_handler(opj_encoder_p, warning_callback, nullptr);
-	opj_set_info_handler(opj_encoder_p, info_callback, nullptr);
-#endif
+	opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);
 
 	/* setup the encoder parameters using the current image and using user parameters */
-	if (!opj_setup_encoder(opj_encoder_p, &parameters, image))
-	{
-		opj_destroy_codec(opj_encoder_p);
-		opj_image_destroy(image);
-		LL_DEBUGS("Texture") << "Failed to encode image." << LL_ENDL;
-		return false;
-	}
+	opj_setup_encoder(cinfo, &parameters, image);
 
 	/* open a byte stream for writing */
 	/* allocate memory for all tiles */
-	LLJp2StreamWriter streamWriter(&base);
-	opj_stream_t* opj_stream_p = opj_stream_default_create(OPJ_STREAM_WRITE);
-	opj_stream_set_write_function(opj_stream_p, LLJp2StreamWriter::writeStream);
-	opj_stream_set_skip_function(opj_stream_p, LLJp2StreamWriter::skipStream);
-	opj_stream_set_seek_function(opj_stream_p, LLJp2StreamWriter::seekStream);
-	opj_stream_set_user_data(opj_stream_p, &streamWriter, nullptr);
-	opj_stream_set_user_data_length(opj_stream_p, raw_image.getDataSize());
+	cio = opj_cio_open((opj_common_ptr)cinfo, nullptr, 0);
 
 	/* encode the image */
-	if (!opj_start_compress(opj_encoder_p, image, opj_stream_p) ||
-		!opj_encode(opj_encoder_p, opj_stream_p) ||
-		!opj_end_compress(opj_encoder_p, opj_stream_p))
+	bool bSuccess = opj_encode(cinfo, cio, image, nullptr);
+	if (!bSuccess)
 	{
-		opj_stream_destroy(opj_stream_p);
-		opj_destroy_codec(opj_encoder_p);
-		opj_image_destroy(image);
+		opj_cio_close(cio);
 		LL_DEBUGS("Texture") << "Failed to encode image." << LL_ENDL;
 		return false;
 	}
+	codestream_length = cio_tell(cio);
 
+	base.copyData(cio->buffer, codestream_length);
 	base.updateData(); // set width, height
 
 	/* close and free the byte stream */
-	opj_stream_destroy(opj_stream_p);
+	opj_cio_close(cio);
 
 	/* free remaining compression structures */
-	opj_destroy_codec(opj_encoder_p);
+	opj_destroy_compress(cinfo);
+
+
+	/* free user parameters structure */
+	if (parameters.cp_matrice) free(parameters.cp_matrice);
 
 	/* free image data */
 	opj_image_destroy(image);
-
 	return true;
 }
 
-inline S32 extractLong4( U8 const *aBuffer, int nOffset )
+inline S32 extractLong4(U8 const* aBuffer, int nOffset)
 {
-	S32 ret = aBuffer[ nOffset ] << 24;
-	ret += aBuffer[ nOffset + 1 ] << 16;
-	ret += aBuffer[ nOffset + 2 ] << 8;
-	ret += aBuffer[ nOffset + 3 ];
+	S32 ret = aBuffer[nOffset] << 24;
+	ret += aBuffer[nOffset + 1] << 16;
+	ret += aBuffer[nOffset + 2] << 8;
+	ret += aBuffer[nOffset + 3];
 	return ret;
 }
 
-inline S32 extractShort2( U8 const *aBuffer, int nOffset )
+inline S32 extractShort2(U8 const* aBuffer, int nOffset)
 {
-	S32 ret = aBuffer[ nOffset ] << 8;
-	ret += aBuffer[ nOffset + 1 ];
+	S32 ret = aBuffer[nOffset] << 8;
+	ret += aBuffer[nOffset + 1];
 
 	return ret;
 }
 
-inline bool isSOC( U8 const *aBuffer )
+inline bool isSOC(U8 const* aBuffer)
 {
-	return aBuffer[ 0 ] == 0xFF && aBuffer[ 1 ] == 0x4F;
+	return aBuffer[0] == 0xFF && aBuffer[1] == 0x4F;
 }
 
-inline bool isSIZ( U8 const *aBuffer )
+inline bool isSIZ(U8 const* aBuffer)
 {
-	return aBuffer[ 0 ] == 0xFF && aBuffer[ 1 ] == 0x51;
+	return aBuffer[0] == 0xFF && aBuffer[1] == 0x51;
 }
 
-bool getMetadataFast( LLImageJ2C &aImage, S32 &aW, S32 &aH, S32 &aComps )
+bool getMetadataFast(LLImageJ2C& aImage, S32& aW, S32& aH, S32& aComps)
 {
-	const int J2K_HDR_LEN( 42 );
-	const int J2K_HDR_X1( 8 );
-	const int J2K_HDR_Y1( 12 );
-	const int J2K_HDR_X0( 16 );
-	const int J2K_HDR_Y0( 20 );
-	const int J2K_HDR_NUMCOMPS( 40 );
-
-	if( aImage.getDataSize() < J2K_HDR_LEN )
+	const int J2K_HDR_LEN(42);
+	const int J2K_HDR_X1(8);
+	const int J2K_HDR_Y1(12);
+	const int J2K_HDR_X0(16);
+	const int J2K_HDR_Y0(20);
+	const int J2K_HDR_NUMCOMPS(40);
+
+	if (aImage.getDataSize() < J2K_HDR_LEN)
 		return false;
 
 	U8 const* pBuffer = aImage.getData();
 
-	if( !isSOC( pBuffer ) || !isSIZ( pBuffer+2 ) )
+	if (!isSOC(pBuffer) || !isSIZ(pBuffer + 2))
 		return false;
 
-	S32 x1 = extractLong4( pBuffer, J2K_HDR_X1 );
-	S32 y1 = extractLong4( pBuffer, J2K_HDR_Y1 );
-	S32 x0 = extractLong4( pBuffer, J2K_HDR_X0 );
-	S32 y0 = extractLong4( pBuffer, J2K_HDR_Y0 );
-	S32 numComps = extractShort2( pBuffer, J2K_HDR_NUMCOMPS );
+	S32 x1 = extractLong4(pBuffer, J2K_HDR_X1);
+	S32 y1 = extractLong4(pBuffer, J2K_HDR_Y1);
+	S32 x0 = extractLong4(pBuffer, J2K_HDR_X0);
+	S32 y0 = extractLong4(pBuffer, J2K_HDR_Y0);
+	S32 numComps = extractShort2(pBuffer, J2K_HDR_NUMCOMPS);
 
 	aComps = numComps;
 	aW = x1 - x0;
@@ -632,7 +468,7 @@ bool getMetadataFast( LLImageJ2C &aImage, S32 &aW, S32 &aH, S32 &aComps )
 	return true;
 }
 
-bool LLImageJ2COJ::getMetadata(LLImageJ2C &base)
+bool LLImageJ2COJ::getMetadata(LLImageJ2C& base)
 {
 	//
 	// FIXME: We get metadata by decoding the ENTIRE image.
@@ -645,7 +481,7 @@ bool LLImageJ2COJ::getMetadata(LLImageJ2C &base)
 	S32 height(0);
 	S32 img_components(0);
 
-	if ( getMetadataFast( base, width, height, img_components ) )
+	if (getMetadataFast(base, width, height, img_components))
 	{
 		base.setSize(width, height, img_components);
 		return true;
@@ -654,77 +490,63 @@ bool LLImageJ2COJ::getMetadata(LLImageJ2C &base)
 	// Do it the old and slow way, decode the image with openjpeg
 
 	opj_dparameters_t parameters;	/* decompression parameters */
-	opj_image_t *image = nullptr;
-	opj_codec_t *opj_decoder = nullptr;	/* handle to a decompressor */
+	opj_event_mgr_t event_mgr = { };		/* event manager */
+	opj_image_t* image = nullptr;
+
+	opj_dinfo_t* dinfo = nullptr;	/* handle to a decompressor */
+	opj_cio_t* cio = nullptr;
+
+
+	/* configure the event callbacks (not required) */
+	event_mgr.error_handler = error_callback;
+	event_mgr.warning_handler = warning_callback;
+	event_mgr.info_handler = info_callback;
 
 	/* set decoding parameters to default values */
 	opj_set_default_decoder_parameters(&parameters);
 
+	// Only decode what's required to get the size data.
+	parameters.cp_limit_decoding = LIMIT_TO_MAIN_HEADER;
+
+	//parameters.cp_reduce = mRawDiscardLevel;
+
 	/* decode the code-stream */
 	/* ---------------------- */
 
 	/* JPEG-2000 codestream */
 
 	/* get a decoder handle */
-	opj_decoder = opj_create_decompress(OPJ_CODEC_J2K);
-	if (opj_decoder)
-	{
-		LL_WARNS() << "ERROR -> getMetadata: failed to create decoder!" << LL_ENDL;
-		return false;
-	}
+	dinfo = opj_create_decompress(CODEC_J2K);
 
-#ifdef SHOW_DEBUG
 	/* catch events using our callbacks and give a local context */
-	opj_set_error_handler(opj_decoder, error_callback, nullptr);
-	opj_set_warning_handler(opj_decoder, warning_callback, nullptr);
-	opj_set_info_handler(opj_decoder, info_callback, nullptr);
-#endif
+	opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
 
 	/* setup the decoder decoding parameters using user parameters */
-	if (!opj_setup_decoder(opj_decoder, &parameters))
-	{
-		LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL;
-		opj_destroy_codec(opj_decoder);
-		return false;
-	}
+	opj_setup_decoder(dinfo, &parameters);
 
 	/* open a byte stream */
-	LLJp2StreamReader streamReader(&base);
-	opj_stream_t* decode_stream = opj_stream_default_create(OPJ_STREAM_READ);
-	opj_stream_set_read_function(decode_stream, LLJp2StreamReader::readStream);
-	opj_stream_set_skip_function(decode_stream, LLJp2StreamReader::skipStream);
-	opj_stream_set_seek_function(decode_stream, LLJp2StreamReader::seekStream);
-	opj_stream_set_user_data(decode_stream, &streamReader, nullptr);
-	opj_stream_set_user_data_length(decode_stream, base.getDataSize());
+	cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize());
 
 	/* decode the stream and fill the image structure */
-	if (!opj_read_header(decode_stream, opj_decoder, &image))
-	{
-		LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL;
-
-		opj_stream_destroy(decode_stream);
-		opj_destroy_codec(opj_decoder);
-
-		if (image)
-		{
-			opj_image_destroy(image);
-		}
-		return false;
-	}
+	image = opj_decode(dinfo, cio);
 
 	/* close the byte stream */
-	opj_stream_destroy(decode_stream);
+	opj_cio_close(cio);
 
 	/* free remaining structures */
-	opj_destroy_codec(opj_decoder);
+	if (dinfo)
+	{
+		opj_destroy_decompress(dinfo);
+	}
 
-	if(!image)
+	if (!image)
 	{
 		LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL;
 		return false;
 	}
 
 	// Copy image data into our raw image format (instead of the separate channel format
+
 	img_components = image->numcomps;
 	width = image->x1 - image->x0;
 	height = image->y1 - image->y0;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index f092c725ab9b8e91121b051cbbc83a06800c21e7..39c77de8a389733daeae6cd74760b0a845a39510 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1936,7 +1936,7 @@ if (WINDOWS)
       # The following commented dependencies are determined at variably at build time. Can't do this here.
       ${CMAKE_SOURCE_DIR}/../etc/message.xml
       ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg
-      ${SHARED_LIB_STAGING_DIR}/openjp2.dll
+      ${SHARED_LIB_STAGING_DIR}/openjpeg.dll
       #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/SLVoice.exe
       #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/libsndfile-1.dll
       #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/vivoxoal.dll
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index bd962b441cab3a22e3901f2615e0e329f1b14b70..df184fb16aad8d6d4959b24df4c2a64ccc070e19 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -457,7 +457,7 @@ def construct(self):
         with self.prefix(src=os.path.join(self.args['build'], os.pardir,
                                           'sharedlibs', self.args['buildtype'])):
             # For image support
-            self.path("openjp2.dll")
+            self.path("openjpeg.dll")
 
             # Get openal dll for audio engine, continue if missing
             if self.args['openal'] == 'ON' or self.args['openal'] == 'TRUE':
@@ -1241,7 +1241,7 @@ def construct(self):
 
         with self.prefix(src=relpkgdir, dst="lib"):
             self.path("libSDL2*.so*")
-            self.path("libopenjp2.*so*")
+            self.path("libopenjpeg.*so*")
             self.path("libjpeg.so*")
 
             if self.args['openal'] == 'ON' or self.args['openal'] == 'TRUE':
@@ -1279,7 +1279,7 @@ def construct(self):
 
         with self.prefix(src=relpkgdir, dst="lib"):
             self.path("libSDL2*.so*")
-            self.path("libopenjp2.*so*")
+            self.path("libopenjpeg.*so*")
             self.path("libjpeg.so*")
             self.path("libsdbus-c++.so*")