From cfc8f154e5a7a3231db5045d5eac129da1cb638e Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 21 Oct 2021 11:26:16 +0200 Subject: [PATCH] libs: Import upstream code from jxrlib 1.1. Signed-off-by: Alexandre Julliard --- configure | 24 + configure.ac | 2 + libs/jxr/LICENSE | 23 + libs/jxr/Makefile.in | 25 + libs/jxr/image/decode/JXRTranscode.c | 991 +++++++ libs/jxr/image/decode/decode.c | 200 ++ libs/jxr/image/decode/decode.h | 143 + libs/jxr/image/decode/postprocess.c | 288 ++ libs/jxr/image/decode/segdec.c | 1205 ++++++++ libs/jxr/image/decode/strInvTransform.c | 1888 ++++++++++++ libs/jxr/image/decode/strPredQuantDec.c | 539 ++++ libs/jxr/image/decode/strdec.c | 3628 +++++++++++++++++++++++ libs/jxr/image/encode/encode.c | 144 + libs/jxr/image/encode/encode.h | 113 + libs/jxr/image/encode/segenc.c | 1186 ++++++++ libs/jxr/image/encode/strFwdTransform.c | 1111 +++++++ libs/jxr/image/encode/strPredQuantEnc.c | 511 ++++ libs/jxr/image/encode/strenc.c | 2370 +++++++++++++++ libs/jxr/image/sys/adapthuff.c | 511 ++++ libs/jxr/image/sys/ansi.h | 61 + libs/jxr/image/sys/common.h | 131 + libs/jxr/image/sys/image.c | 183 ++ libs/jxr/image/sys/perfTimer.h | 115 + libs/jxr/image/sys/strPredQuant.c | 306 ++ libs/jxr/image/sys/strTransform.c | 85 + libs/jxr/image/sys/strTransform.h | 50 + libs/jxr/image/sys/strcodec.c | 1251 ++++++++ libs/jxr/image/sys/strcodec.h | 678 +++++ libs/jxr/image/sys/windowsmediaphoto.h | 515 ++++ libs/jxr/image/sys/xplatform_image.h | 84 + libs/jxr/image/x86/x86.h | 58 + libs/jxr/jxrgluelib/JXRGlue.c | 930 ++++++ libs/jxr/jxrgluelib/JXRGlue.h | 642 ++++ libs/jxr/jxrgluelib/JXRGlueJxr.c | 2280 ++++++++++++++ libs/jxr/jxrgluelib/JXRGluePFC.c | 2338 +++++++++++++++ libs/jxr/jxrgluelib/JXRMeta.c | 905 ++++++ libs/jxr/jxrgluelib/JXRMeta.h | 258 ++ 37 files changed, 25772 insertions(+) create mode 100644 libs/jxr/LICENSE create mode 100644 libs/jxr/Makefile.in create mode 100644 libs/jxr/image/decode/JXRTranscode.c create mode 100644 libs/jxr/image/decode/decode.c create mode 100644 libs/jxr/image/decode/decode.h create mode 100644 libs/jxr/image/decode/postprocess.c create mode 100644 libs/jxr/image/decode/segdec.c create mode 100644 libs/jxr/image/decode/strInvTransform.c create mode 100644 libs/jxr/image/decode/strPredQuantDec.c create mode 100644 libs/jxr/image/decode/strdec.c create mode 100644 libs/jxr/image/encode/encode.c create mode 100644 libs/jxr/image/encode/encode.h create mode 100644 libs/jxr/image/encode/segenc.c create mode 100644 libs/jxr/image/encode/strFwdTransform.c create mode 100644 libs/jxr/image/encode/strPredQuantEnc.c create mode 100644 libs/jxr/image/encode/strenc.c create mode 100644 libs/jxr/image/sys/adapthuff.c create mode 100644 libs/jxr/image/sys/ansi.h create mode 100644 libs/jxr/image/sys/common.h create mode 100644 libs/jxr/image/sys/image.c create mode 100644 libs/jxr/image/sys/perfTimer.h create mode 100644 libs/jxr/image/sys/strPredQuant.c create mode 100644 libs/jxr/image/sys/strTransform.c create mode 100644 libs/jxr/image/sys/strTransform.h create mode 100644 libs/jxr/image/sys/strcodec.c create mode 100644 libs/jxr/image/sys/strcodec.h create mode 100644 libs/jxr/image/sys/windowsmediaphoto.h create mode 100644 libs/jxr/image/sys/xplatform_image.h create mode 100644 libs/jxr/image/x86/x86.h create mode 100644 libs/jxr/jxrgluelib/JXRGlue.c create mode 100644 libs/jxr/jxrgluelib/JXRGlue.h create mode 100644 libs/jxr/jxrgluelib/JXRGlueJxr.c create mode 100644 libs/jxr/jxrgluelib/JXRGluePFC.c create mode 100644 libs/jxr/jxrgluelib/JXRMeta.c create mode 100644 libs/jxr/jxrgluelib/JXRMeta.h diff --git a/configure b/configure index efae283f9fa..1e18ad994a4 100755 --- a/configure +++ b/configure @@ -707,6 +707,8 @@ PNG_PE_LIBS PNG_PE_CFLAGS LCMS2_PE_LIBS LCMS2_PE_CFLAGS +JXR_PE_LIBS +JXR_PE_CFLAGS JPEG_PE_LIBS JPEG_PE_CFLAGS GSM_PE_LIBS @@ -1784,6 +1786,7 @@ enable_dxerr9 enable_dxguid enable_gsm enable_jpeg +enable_jxr enable_lcms2 enable_mfuuid enable_png @@ -1930,6 +1933,8 @@ GSM_PE_CFLAGS GSM_PE_LIBS JPEG_PE_CFLAGS JPEG_PE_LIBS +JXR_PE_CFLAGS +JXR_PE_LIBS LCMS2_PE_CFLAGS LCMS2_PE_LIBS PNG_PE_CFLAGS @@ -2717,6 +2722,9 @@ Some influential environment variables: C compiler flags for the PE jpeg, overriding the bundled version JPEG_PE_LIBS Linker flags for the PE jpeg, overriding the bundled version + JXR_PE_CFLAGS + C compiler flags for the PE jxr, overriding the bundled version + JXR_PE_LIBS Linker flags for the PE jxr, overriding the bundled version LCMS2_PE_CFLAGS C compiler flags for the PE lcms2, overriding the bundled version @@ -10718,6 +10726,19 @@ fi $as_echo "$as_me:${as_lineno-$LINENO}: jpeg cflags: $JPEG_PE_CFLAGS" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: jpeg libs: $JPEG_PE_LIBS" >&5 +if ${JXR_PE_CFLAGS:+false} :; then : + JXR_PE_CFLAGS="-I\$(top_srcdir)/libs/jxr/jxrgluelib -I\$(top_srcdir)/libs/jxr/image/sys" +else + enable_jxr=no +fi +if ${JXR_PE_LIBS:+false} :; then : + JXR_PE_LIBS=jxr +else + enable_jxr=no +fi +$as_echo "$as_me:${as_lineno-$LINENO}: jxr cflags: $JXR_PE_CFLAGS" >&5 +$as_echo "$as_me:${as_lineno-$LINENO}: jxr libs: $JXR_PE_LIBS" >&5 + if ${LCMS2_PE_CFLAGS:+false} :; then : LCMS2_PE_CFLAGS="-I\$(top_srcdir)/libs/lcms2/include" else @@ -18942,6 +18963,8 @@ GSM_PE_CFLAGS = $GSM_PE_CFLAGS GSM_PE_LIBS = $GSM_PE_LIBS JPEG_PE_CFLAGS = $JPEG_PE_CFLAGS JPEG_PE_LIBS = $JPEG_PE_LIBS +JXR_PE_CFLAGS = $JXR_PE_CFLAGS +JXR_PE_LIBS = $JXR_PE_LIBS LCMS2_PE_CFLAGS = $LCMS2_PE_CFLAGS LCMS2_PE_LIBS = $LCMS2_PE_LIBS PNG_PE_CFLAGS = $PNG_PE_CFLAGS @@ -20238,6 +20261,7 @@ wine_fn_config_makefile libs/dxerr9 enable_dxerr9 wine_fn_config_makefile libs/dxguid enable_dxguid wine_fn_config_makefile libs/gsm enable_gsm wine_fn_config_makefile libs/jpeg enable_jpeg +wine_fn_config_makefile libs/jxr enable_jxr wine_fn_config_makefile libs/lcms2 enable_lcms2 wine_fn_config_makefile libs/mfuuid enable_mfuuid wine_fn_config_makefile libs/png enable_png diff --git a/configure.ac b/configure.ac index 62af43220ce..06d727baa80 100644 --- a/configure.ac +++ b/configure.ac @@ -1056,6 +1056,7 @@ dnl **** External libraries **** WINE_EXTLIB_FLAGS(GSM, gsm, gsm, "-I\$(top_srcdir)/libs/gsm/inc") WINE_EXTLIB_FLAGS(JPEG, jpeg, jpeg, "-I\$(top_srcdir)/libs/jpeg") +WINE_EXTLIB_FLAGS(JXR, jxr, jxr, "-I\$(top_srcdir)/libs/jxr/jxrgluelib -I\$(top_srcdir)/libs/jxr/image/sys") WINE_EXTLIB_FLAGS(LCMS2, lcms2, lcms2, "-I\$(top_srcdir)/libs/lcms2/include") WINE_EXTLIB_FLAGS(PNG, png, "png \$(ZLIB_PE_LIBS)", "-I\$(top_srcdir)/libs/png") WINE_EXTLIB_FLAGS(TIFF, tiff, tiff, "-I\$(top_srcdir)/libs/tiff/libtiff") @@ -3705,6 +3706,7 @@ WINE_CONFIG_MAKEFILE(libs/dxerr9) WINE_CONFIG_MAKEFILE(libs/dxguid) WINE_CONFIG_MAKEFILE(libs/gsm) WINE_CONFIG_MAKEFILE(libs/jpeg) +WINE_CONFIG_MAKEFILE(libs/jxr) WINE_CONFIG_MAKEFILE(libs/lcms2) WINE_CONFIG_MAKEFILE(libs/mfuuid) WINE_CONFIG_MAKEFILE(libs/png) diff --git a/libs/jxr/LICENSE b/libs/jxr/LICENSE new file mode 100644 index 00000000000..77322d90c23 --- /dev/null +++ b/libs/jxr/LICENSE @@ -0,0 +1,23 @@ +Copyright © Microsoft Corp. +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 HOLDER 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/libs/jxr/Makefile.in b/libs/jxr/Makefile.in new file mode 100644 index 00000000000..5203dc970aa --- /dev/null +++ b/libs/jxr/Makefile.in @@ -0,0 +1,25 @@ +EXTLIB = libjxr.a +EXTRAINCL = -I$(srcdir)/jxrgluelib -I$(srcdir)/image/sys -DDISABLE_PERF_MEASUREMENT + +C_SRCS = \ + image/decode/JXRTranscode.c \ + image/decode/decode.c \ + image/decode/postprocess.c \ + image/decode/segdec.c \ + image/decode/strInvTransform.c \ + image/decode/strPredQuantDec.c \ + image/decode/strdec.c \ + image/encode/encode.c \ + image/encode/segenc.c \ + image/encode/strFwdTransform.c \ + image/encode/strPredQuantEnc.c \ + image/encode/strenc.c \ + image/sys/adapthuff.c \ + image/sys/image.c \ + image/sys/strPredQuant.c \ + image/sys/strTransform.c \ + image/sys/strcodec.c \ + jxrgluelib/JXRGlue.c \ + jxrgluelib/JXRGlueJxr.c \ + jxrgluelib/JXRGluePFC.c \ + jxrgluelib/JXRMeta.c diff --git a/libs/jxr/image/decode/JXRTranscode.c b/libs/jxr/image/decode/JXRTranscode.c new file mode 100644 index 00000000000..a0db30adcdb --- /dev/null +++ b/libs/jxr/image/decode/JXRTranscode.c @@ -0,0 +1,991 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "windowsmediaphoto.h" +#include "strcodec.h" +#include "decode.h" + +EXTERN_C Void freePredInfo(CWMImageStrCodec *); + +EXTERN_C Int ReadWMIHeader(CWMImageInfo *, CWMIStrCodecParam *, CCoreParameters *); +EXTERN_C Int StrIODecInit(CWMImageStrCodec *); +EXTERN_C Int StrDecInit(CWMImageStrCodec *); +EXTERN_C Int readPackets(CWMImageStrCodec *); +EXTERN_C Int DecodeMacroblockDC(CWMImageStrCodec *, CCodingContext *, Int, Int); +EXTERN_C Int DecodeMacroblockLowpass(CWMImageStrCodec *, CCodingContext *, Int, Int); +EXTERN_C Int DecodeMacroblockHighpass(CWMImageStrCodec *, CCodingContext *, Int, Int); +EXTERN_C Void predDCACDec(CWMImageStrCodec *); +EXTERN_C Void predACDec(CWMImageStrCodec *); +EXTERN_C Void StrIODecTerm(CWMImageStrCodec *); +EXTERN_C Void FreeCodingContextDec(CWMImageStrCodec *); + +EXTERN_C Int StrEncInit(CWMImageStrCodec *); +EXTERN_C Void StrIOEncTerm(CWMImageStrCodec *); +EXTERN_C Void FreeCodingContextEnc(CWMImageStrCodec *); +EXTERN_C Int encodeMB(CWMImageStrCodec *, Int, Int); +EXTERN_C Int writeIndexTableNull(CWMImageStrCodec *); +EXTERN_C Void writePacketHeader(BitIOInfo *, U8, U8); + +EXTERN_C Int WriteWMIHeader(CWMImageStrCodec *); +EXTERN_C Int ReadImagePlaneHeader(CWMImageInfo *, CWMIStrCodecParam *, CCoreParameters *, SimpleBitIO *); +EXTERN_C Int WriteImagePlaneHeader(CWMImageStrCodec *); +EXTERN_C Int writeIndexTable(CWMImageStrCodec *); +EXTERN_C Int copyTo(struct WMPStream *, struct WMPStream *, size_t); + +const static Bool bFlipV[O_MAX] = {FALSE, TRUE , FALSE, TRUE, TRUE , TRUE, FALSE, FALSE}; +const static Bool bFlipH[O_MAX] = {FALSE, FALSE, TRUE , TRUE, FALSE, TRUE, FALSE, TRUE}; + +typedef struct CTileQPInfo +{ + U8 dcMode; + U8 dcIndex[MAX_CHANNELS]; + + Bool bUseDC; + U8 lpNum; + Bool bUseDCAlpha; + U8 lpNumAlpha; + U8 lpMode[16]; + U8 lpIndex[16][MAX_CHANNELS]; + + Bool bUseLP; + U8 hpNum; + Bool bUseLPAlpha; + U8 hpNumAlpha; + U8 hpMode[16]; + U8 hpIndex[16][MAX_CHANNELS]; +} CTileQPInfo; + +Void transcodeQuantizer(BitIOInfo * pIO, U8 cIndex[MAX_CHANNELS], U8 cChMode, size_t cChannel) +{ + if(cChMode > 2) + cChMode = 2; + + if(cChannel > 1) + putBit16(pIO, cChMode, 2); // Channel mode + else + cChMode = 0; + + putBit16(pIO, cIndex[0], 8); // Y + + if(cChMode == 1) // MIXED + putBit16(pIO, cIndex[1], 8); // UV + else if(cChMode > 0){ // INDEPENDENT + size_t i; + + for(i = 1; i < cChannel; i ++) + putBit16(pIO, cIndex[i], 8); // UV + } +} + +Void transcodeQuantizers(BitIOInfo * pIO, U8 cIndex[16][MAX_CHANNELS], U8 cChMode[16], U32 cNum, size_t cChannel, Bool bCopy) +{ + putBit16(pIO, bCopy == TRUE ? 1 : 0, 1); + if(bCopy == FALSE){ + U32 i; + + putBit16(pIO, cNum - 1, 4); + + for(i = 0; i < cNum; i ++) + transcodeQuantizer(pIO, cIndex[i], cChMode[i], cChannel); + } +} + +Void transcodeQuantizersAlpha(BitIOInfo * pIO, U8 cIndex[16][MAX_CHANNELS], U32 cNum, size_t iChannel, Bool bCopy) +{ + putBit16(pIO, bCopy == TRUE ? 1 : 0, 1); + if(bCopy == FALSE){ + U32 i; + + putBit16(pIO, cNum - 1, 4); + + for(i = 0; i < cNum; i ++) + putBit16(pIO, cIndex[i][iChannel], 8); + } +} + +Void transcodeTileHeader(CWMImageStrCodec * pSC, CTileQPInfo * pTileQPInfo) +{ + if(pSC->m_bCtxLeft && pSC->m_bCtxTop && pSC->m_bSecondary == FALSE){ // write packet headers + CCodingContext * pContext = &pSC->m_pCodingContext[pSC->cTileColumn]; + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + U8 pID = (U8)((pSC->cTileRow * (pSC->WMISCP.cNumOfSliceMinus1V + 1) + pSC->cTileColumn) & 0x1F); + CWMImageStrCodec * pSCAlpha = (pSC->m_param.bAlphaChannel ? pSC->m_pNextSC : NULL); + const size_t iAlphaPos = pSC->m_param.cNumChannels; + + writePacketHeader(pContext->m_pIODC, pSC->WMISCP.bfBitstreamFormat == SPATIAL ? 0 : 1, pID); + if (pSC->m_param.bTrimFlexbitsFlag && pSC->WMISCP.bfBitstreamFormat == SPATIAL) + putBit16(pContext->m_pIODC, pContext->m_iTrimFlexBits, 4); + + if((pSC->m_param.uQPMode & 1) != 0) // not DC uniform + transcodeQuantizer(pContext->m_pIODC, pTileQPInfo->dcIndex, pTileQPInfo->dcMode, pSC->WMISCP.cChannel); + if(pSCAlpha != NULL && (pSCAlpha->m_param.uQPMode & 1) != 0) // not DC uniform + putBit16(pContext->m_pIODC, pTileQPInfo->dcIndex[iAlphaPos], 8); + + if(pSC->WMISCP.bfBitstreamFormat == SPATIAL) { + if(pSC->WMISCP.sbSubband != SB_DC_ONLY){ + if((pSC->m_param.uQPMode & 2) != 0) // not LP uniform + transcodeQuantizers(pContext->m_pIODC, pTileQPInfo->lpIndex, pTileQPInfo->lpMode, pTileQPInfo->lpNum, pSC->WMISCP.cChannel, pTileQPInfo->bUseDC); + if(pSCAlpha != NULL && (pSCAlpha->m_param.uQPMode & 2) != 0) // not LP uniform + transcodeQuantizersAlpha(pContext->m_pIODC, pTileQPInfo->lpIndex, pTileQPInfo->lpNumAlpha, iAlphaPos, pTileQPInfo->bUseDCAlpha); + if(pSC->WMISCP.sbSubband != SB_NO_HIGHPASS){ + if((pSC->m_param.uQPMode & 4) != 0) // not HP uniform + transcodeQuantizers(pContext->m_pIODC, pTileQPInfo->hpIndex, pTileQPInfo->hpMode, pTileQPInfo->hpNum, pSC->WMISCP.cChannel, pTileQPInfo->bUseLP); + if(pSCAlpha != NULL && (pSCAlpha->m_param.uQPMode & 4) != 0) // not HP uniform + transcodeQuantizersAlpha(pContext->m_pIODC, pTileQPInfo->hpIndex, pTileQPInfo->hpNumAlpha, iAlphaPos, pTileQPInfo->bUseLPAlpha); + } + } + } + else{ + if(pSC->WMISCP.sbSubband != SB_DC_ONLY){ + writePacketHeader(pContext->m_pIOLP, 2, pID); + if((pSC->m_param.uQPMode & 2) != 0) // not LP uniform + transcodeQuantizers(pContext->m_pIOLP, pTileQPInfo->lpIndex, pTileQPInfo->lpMode, pTileQPInfo->lpNum, pSC->WMISCP.cChannel, pTileQPInfo->bUseDC); + if(pSCAlpha != NULL && (pSCAlpha->m_param.uQPMode & 2) != 0) // not LP uniform + transcodeQuantizersAlpha(pContext->m_pIOLP, pTileQPInfo->lpIndex, pTileQPInfo->lpNumAlpha, iAlphaPos, pTileQPInfo->bUseDCAlpha); + + if(pSC->WMISCP.sbSubband != SB_NO_HIGHPASS){ + writePacketHeader(pContext->m_pIOAC, 3, pID); + if((pSC->m_param.uQPMode & 4) != 0) // not HP uniform + transcodeQuantizers(pContext->m_pIOAC, pTileQPInfo->hpIndex, pTileQPInfo->hpMode, pTileQPInfo->hpNum, pSC->WMISCP.cChannel, pTileQPInfo->bUseLP); + if(pSCAlpha != NULL && (pSCAlpha->m_param.uQPMode & 4) != 0) // not HP uniform + transcodeQuantizersAlpha(pContext->m_pIOAC, pTileQPInfo->hpIndex, pTileQPInfo->hpNumAlpha, iAlphaPos, pTileQPInfo->bUseLPAlpha); + + if(pSC->WMISCP.sbSubband != SB_NO_FLEXBITS){ + writePacketHeader(pContext->m_pIOFL, 4, pID); + if (pSC->m_param.bTrimFlexbitsFlag) + putBit16(pContext->m_pIOFL, pContext->m_iTrimFlexBits, 4); + } + } + } + } + pTile->cBitsLP = (pTileQPInfo->bUseDC ? 0 : dquantBits(pTileQPInfo->lpNum)); + pTile->cBitsHP = (pTileQPInfo->bUseLP ? 0 : dquantBits(pTileQPInfo->hpNum)); + if(pSCAlpha != NULL){ + pTile = pSCAlpha->pTile + pSC->cTileColumn; + pTile->cBitsLP = (pTileQPInfo->bUseDCAlpha ? 0 : dquantBits(pTileQPInfo->lpNumAlpha)); + pTile->cBitsHP = (pTileQPInfo->bUseLPAlpha ? 0 : dquantBits(pTileQPInfo->hpNumAlpha)); + } + } +} + +Void transformDCBlock(PixelI * pOrg, PixelI * pDst, ORIENTATION oOrientation) +{ + size_t i; + + if(bFlipV[oOrientation]) + for(i = 0; i < 16; i += 4) + pOrg[i + 1] = -pOrg[i + 1], pOrg[i + 3] = -pOrg[i + 3]; + + if(bFlipH[oOrientation]) + for(i = 0; i < 4; i ++) + pOrg[i + 4] = -pOrg[i + 4], pOrg[i + 12] = -pOrg[i + 12]; + + if(oOrientation < O_RCW) + memcpy(pDst, pOrg, 16 * sizeof(PixelI)); + else + for(i = 0; i < 16; i ++) + pDst[i] = pOrg[(i >> 2) + ((i & 3) << 2)]; +} + +Void transformDCBlock422(PixelI * pOrg, PixelI * pDst, ORIENTATION oOrientation) +{ + assert(oOrientation < O_RCW); + + if(bFlipV[oOrientation]) + pOrg[1] = -pOrg[1], pOrg[3] = -pOrg[3], pOrg[4] = -pOrg[4], pOrg[5] = -pOrg[5], pOrg[7] = -pOrg[7]; + + if(bFlipH[oOrientation]) + pOrg[2] = -pOrg[2], pOrg[3] = -pOrg[3], pOrg[6] = -pOrg[6], pOrg[7] = -pOrg[7]; + + if(bFlipV[oOrientation]) + pDst[0] = pOrg[0], pDst[1] = pOrg[5], pDst[2] = pOrg[6], pDst[3] = pOrg[7], pDst[4] = pOrg[4], pDst[5] = pOrg[1], pDst[6] = pOrg[2], pDst[7] = pOrg[3]; + else + memcpy(pDst, pOrg, 8 * sizeof(PixelI)); +} + +Void transformDCBlock420(PixelI * pOrg, PixelI * pDst, ORIENTATION oOrientation) +{ + if(bFlipV[oOrientation]) + pOrg[1] = -pOrg[1], pOrg[3] = -pOrg[3]; + + if(bFlipH[oOrientation]) + pOrg[2] = -pOrg[2], pOrg[3] = -pOrg[3]; + + pDst[0] = pOrg[0], pDst[3] = pOrg[3]; + if(oOrientation < O_RCW) + pDst[1] = pOrg[1], pDst[2] = pOrg[2]; + else + pDst[1] = pOrg[2], pDst[2] = pOrg[1]; +} + +Void transformACBlocks(PixelI * pOrg, PixelI * pDst, ORIENTATION oOrientation) +{ + PixelI * pO, * pD; + const Int * pT = dctIndex[0]; + size_t i, j, k; + + for(j = 0, pO = pOrg; j < 16; j ++, pO += 16){ + if(bFlipV[oOrientation]) + for(i = 0; i < 16; i += 4) + pO[pT[i + 1]] = -pO[pT[i + 1]], pO[pT[i + 3]] = -pO[pT[i + 3]]; + + if(bFlipH[oOrientation]) + for(i = 0; i < 4; i ++) + pO[pT[i + 4]] = -pO[pT[i + 4]], pO[pT[i + 12]] = -pO[pT[i + 12]]; + } + + for(j = 0; j < 4; j ++) + for(i = 0; i < 4; i ++){ + size_t ii = (bFlipV[oOrientation] ? 3 - i : i); + size_t jj = (bFlipH[oOrientation] ? 3 - j : j); + + if(oOrientation < O_RCW) + memcpy(pDst + (jj * 4 + ii) * 16, pOrg + (j * 4 + i) * 16, 16 * sizeof(PixelI)); + else{ + pO = pOrg + (j * 4 + i) * 16; + pD = pDst + (ii * 4 + jj) * 16; + for(k = 1; k < 16; k ++) + pD[pT[k]] = pO[pT[(k >> 2) + ((k & 3) << 2)]]; + } + } +} + +Void transformACBlocks422(PixelI * pOrg, PixelI * pDst, ORIENTATION oOrientation) +{ + PixelI * pO; + const Int * pT = dctIndex[0]; + size_t i, j; + + assert(oOrientation < O_RCW); + + for(j = 0, pO = pOrg; j < 8; j ++, pO += 16){ + if(bFlipV[oOrientation]) + for(i = 0; i < 16; i += 4) + pO[pT[i + 1]] = -pO[pT[i + 1]], pO[pT[i + 3]] = -pO[pT[i + 3]]; + + if(bFlipH[oOrientation]) + for(i = 0; i < 4; i ++) + pO[pT[i + 4]] = -pO[pT[i + 4]], pO[pT[i + 12]] = -pO[pT[i + 12]]; + } + + for(j = 0; j < 2; j ++) + for(i = 0; i < 4; i ++){ + size_t ii = (bFlipV[oOrientation] ? 3 - i : i); + size_t jj = (bFlipH[oOrientation] ? 1 - j : j); + + memcpy(pDst + (jj * 4 + ii) * 16, pOrg + (j * 4 + i) * 16, 16 * sizeof(PixelI)); + } +} + +Void transformACBlocks420(PixelI * pOrg, PixelI * pDst, ORIENTATION oOrientation) +{ + PixelI * pO, * pD; + const Int * pT = dctIndex[0]; + size_t i, j, k; + + for(j = 0, pO = pOrg; j < 4; j ++, pO += 16){ + if(bFlipV[oOrientation]) + for(i = 0; i < 16; i += 4) + pO[pT[i + 1]] = -pO[pT[i + 1]], pO[pT[i + 3]] = -pO[pT[i + 3]]; + + if(bFlipH[oOrientation]) + for(i = 0; i < 4; i ++) + pO[pT[i + 4]] = -pO[pT[i + 4]], pO[pT[i + 12]] = -pO[pT[i + 12]]; + } + + for(j = 0; j < 2; j ++) + for(i = 0; i < 2; i ++){ + size_t ii = (bFlipV[oOrientation] ? 1 - i : i); + size_t jj = (bFlipH[oOrientation] ? 1 - j : j); + + if(oOrientation < O_RCW) + memcpy(pDst + (jj * 2 + ii) * 16, pOrg + (j * 2 + i) * 16, 16 * sizeof(PixelI)); + else{ + pO = pOrg + (j * 2 + i) * 16; + pD = pDst + (ii * 2 + jj) * 16; + for(k = 1; k < 16; k ++) + pD[pT[k]] = pO[pT[(k >> 2) + ((k & 3) << 2)]]; + } + } +} + +Int getROI(CWMImageInfo * pII, CCoreParameters * pCore, CWMIStrCodecParam * pSCP, CWMTranscodingParam * pParam) +{ + const ORIENTATION oO = pParam->oOrientation; + size_t iLeft, iTop, cWidth, cHeight, i, j; + size_t mbLeft, mbRight, mbTop, mbBottom; + size_t * iTile = (size_t *)malloc(MAX_TILES * sizeof(size_t)); + + if(iTile == NULL) + return ICERR_ERROR; + + if(pParam->cLeftX + pParam->cWidth > pII->cWidth || pParam->cTopY + pParam->cHeight > pII->cHeight) // invalid region + return ICERR_ERROR; + + cWidth = pParam->cWidth, cHeight = pParam->cHeight; + iLeft = pParam->cLeftX + pCore->cExtraPixelsLeft, iTop = pParam->cTopY + pCore->cExtraPixelsTop; + if(pSCP->olOverlap != OL_NONE && pParam->bIgnoreOverlap == FALSE){ // include pixels borrowed + size_t cBlurred = (pSCP->olOverlap == OL_TWO ? 10 : 2); + + if(iLeft > cBlurred) + iLeft -= cBlurred, cWidth += cBlurred; + else + cWidth += iLeft, iLeft = 0; + if(iTop > cBlurred) + iTop -= cBlurred, cHeight += cBlurred; + else + cHeight += iTop, iTop = 0; + cWidth += cBlurred, cHeight += cBlurred; + if(iLeft + cWidth > pII->cWidth + pCore->cExtraPixelsLeft + pCore->cExtraPixelsRight) + cWidth = pII->cWidth + pCore->cExtraPixelsLeft + pCore->cExtraPixelsRight - iLeft; + if(iTop + cHeight > pII->cHeight + pCore->cExtraPixelsTop + pCore->cExtraPixelsBottom) + cHeight = pII->cHeight + pCore->cExtraPixelsTop + pCore->cExtraPixelsBottom - iTop; + } + + mbTop = (iTop >> 4), mbLeft = (iLeft >> 4); + mbBottom = (iTop + cHeight + 15) >> 4, mbRight = (iLeft + cWidth + 15) >> 4; + pCore->cExtraPixelsLeft += pParam->cLeftX - (mbLeft << 4); + pCore->cExtraPixelsRight = ((mbRight - mbLeft) << 4) - pParam->cWidth - pCore->cExtraPixelsLeft; + pCore->cExtraPixelsTop += pParam->cTopY - (mbTop << 4); + pCore->cExtraPixelsBottom = ((mbBottom - mbTop) << 4) - pParam->cHeight - pCore->cExtraPixelsTop; + + pII->cWidth = ((mbRight - mbLeft) << 4) - pCore->cExtraPixelsLeft - pCore->cExtraPixelsRight; + pII->cHeight = ((mbBottom - mbTop) << 4) - pCore->cExtraPixelsTop - pCore->cExtraPixelsBottom; + pParam->cLeftX = iLeft, pParam->cTopY = iTop; + pParam->cWidth = cWidth, pParam->cHeight = cHeight; + + // extra pixels in transformed space +#define SWAP(a, b) i = a, a = b, b = i + if(oO == O_FLIPH || oO == O_FLIPVH || oO == O_RCW_FLIPV || oO == O_RCW_FLIPVH) + SWAP(pCore->cExtraPixelsLeft, pCore->cExtraPixelsRight); + if(oO == O_FLIPV || oO == O_FLIPVH || oO == O_RCW || oO == O_RCW_FLIPV) + SWAP(pCore->cExtraPixelsTop, pCore->cExtraPixelsBottom); + if(oO >= O_RCW){ + SWAP(pCore->cExtraPixelsLeft, pCore->cExtraPixelsTop); + SWAP(pCore->cExtraPixelsRight, pCore->cExtraPixelsBottom); + } + + // adjust tiling + for(i = 0, j = 0, iTile[0] = 0; i <= (size_t)pSCP->cNumOfSliceMinus1V; i ++) + if((size_t)pSCP->uiTileX[i] >= mbLeft && (size_t)pSCP->uiTileX[i] < mbRight){ + if(j >= MAX_TILES) + j = MAX_TILES - 1; + iTile[j] = (size_t)pSCP->uiTileX[i] - mbLeft, j ++; + } + if(iTile[0] == 0) + for(i = 0, pSCP->cNumOfSliceMinus1V = (j == 0 ? 0 : (U32)(j - 1)); i < j; i ++) + pSCP->uiTileX[i] = (U32)iTile[i]; + else + for(i = 1, pSCP->uiTileX[0] = 0, pSCP->cNumOfSliceMinus1V = (U32)j; i <= j; i ++) + pSCP->uiTileX[i] = (U32)iTile[i - 1]; + if(oO == O_FLIPH || oO == O_FLIPVH || oO == O_RCW_FLIPV || oO == O_RCW_FLIPVH){ // reverse order + for(i = 0; i <= (size_t)pSCP->cNumOfSliceMinus1V; i ++) + iTile[i] = mbRight - mbLeft - (size_t)pSCP->uiTileX[i]; + for(i = 1, pSCP->uiTileX[0] = 0; i <= (size_t)pSCP->cNumOfSliceMinus1V; i ++) + pSCP->uiTileX[i] = (U32)(iTile[(size_t)pSCP->cNumOfSliceMinus1V - i + 1]); + } + for(i = 0, j = 0, iTile[0] = 0; i <= (size_t)pSCP->cNumOfSliceMinus1H; i ++) + if(pSCP->uiTileY[i] >= mbTop && pSCP->uiTileY[i] < mbBottom){ + if(j >= MAX_TILES) + j = MAX_TILES - 1; + iTile[j] = (size_t)pSCP->uiTileY[i] - mbTop, j ++; + } + if(iTile[0] == 0) + for(i = 0, pSCP->cNumOfSliceMinus1H = (j == 0 ? 0 : (U32)(j - 1)); i < j; i ++) + pSCP->uiTileY[i] = (U32)iTile[i]; + else + for(i = 1, pSCP->uiTileY[0] = 0, pSCP->cNumOfSliceMinus1H = (U32)j; i <= j; i ++) + pSCP->uiTileY[i] = (U32)iTile[i - 1]; + if(oO == O_FLIPV || oO == O_FLIPVH || oO == O_RCW || oO == O_RCW_FLIPV){ // reverse order + for(i = 0; i <= (size_t)pSCP->cNumOfSliceMinus1H; i ++) + iTile[i] = mbBottom - mbTop - (size_t)pSCP->uiTileY[i]; + for(i = 1, pSCP->uiTileY[0] = 0; i <= (size_t)pSCP->cNumOfSliceMinus1H; i ++) + pSCP->uiTileY[i] = (U32)(iTile[(size_t)pSCP->cNumOfSliceMinus1H - i + 1]); + } + if(oO >= O_RCW){ // switch X & Y + for(i = 0; i <= (size_t)pSCP->cNumOfSliceMinus1V; i ++) + iTile[i] = (size_t)pSCP->uiTileX[i]; + for(i = 0; i <= (size_t)pSCP->cNumOfSliceMinus1H; i ++) + pSCP->uiTileX[i] = pSCP->uiTileY[i]; + for(i = 0; i <= (size_t)pSCP->cNumOfSliceMinus1V; i ++) + pSCP->uiTileY[i] = (U32)iTile[i]; + i = (size_t)pSCP->cNumOfSliceMinus1H, pSCP->cNumOfSliceMinus1H = pSCP->cNumOfSliceMinus1V, pSCP->cNumOfSliceMinus1V = (U32)i; + } + + free(iTile); + + return ICERR_OK; +} + +Bool isTileBoundary(U32 * pTilePos, U32 cTiles, U32 cMBs, U32 iPos) +{ + U32 i; + + for(i = 0; i < cTiles; i ++) + if(iPos == pTilePos[i] * 16) + break; + + return ((i < cTiles || (iPos + 15) / 16 >= cMBs) ? TRUE : FALSE); +} + +Bool isTileExtraction(CWMImageStrCodec * pSC, CWMTranscodingParam * pParam) +{ + if(pParam->bIgnoreOverlap == FALSE && pSC->WMISCP.olOverlap == OL_NONE) + pParam->bIgnoreOverlap = TRUE; + + if(pParam->bIgnoreOverlap == TRUE && pParam->oOrientation == O_NONE && pParam->bfBitstreamFormat == pSC->WMISCP.bfBitstreamFormat){ + if(pParam->bfBitstreamFormat == SPATIAL && pParam->sbSubband != pSC->WMISCP.sbSubband) + return FALSE; + + return (isTileBoundary(pSC->WMISCP.uiTileX, pSC->WMISCP.cNumOfSliceMinus1V + 1, (U32)pSC->cmbWidth, (U32)(pParam->cLeftX + pSC->m_param.cExtraPixelsLeft)) && + isTileBoundary(pSC->WMISCP.uiTileY, pSC->WMISCP.cNumOfSliceMinus1H + 1, (U32)pSC->cmbHeight, (U32)(pParam->cTopY + pSC->m_param.cExtraPixelsTop)) && + isTileBoundary(pSC->WMISCP.uiTileX, pSC->WMISCP.cNumOfSliceMinus1V + 1, (U32)pSC->cmbWidth, (U32)(pParam->cLeftX + pParam->cWidth + pSC->m_param.cExtraPixelsLeft)) && + isTileBoundary(pSC->WMISCP.uiTileY, pSC->WMISCP.cNumOfSliceMinus1H + 1, (U32)pSC->cmbHeight, (U32)(pParam->cTopY + pParam->cHeight + pSC->m_param.cExtraPixelsTop))); + } + + return FALSE; +} + +Int WMPhotoTranscode(struct WMPStream * pStreamIn, struct WMPStream * pStreamOut, CWMTranscodingParam * pParam) +{ + PixelI * pMBBuf, MBBufAlpha[256]; // shared buffer, decoder <=> encoder bridge + PixelI * pFrameBuf = NULL, * pFrameBufAlpha = NULL; + CWMIMBInfo * pMBInfo = NULL, * pMBInfoAlpha = NULL; + CWMImageStrCodec * pSCDec, * pSCEnc, * pSC; + CWMDecoderParameters aDecoderParam = {0}; + U8 * pIOHeaderDec, * pIOHeaderEnc; + CCodingContext * pContext; + CTileQPInfo * pTileQPInfo = NULL; + ORIENTATION oO = pParam->oOrientation; + size_t iAlphaPos = 0; + size_t cUnit; + size_t i, j, mbLeft, mbRight, mbTop, mbBottom, mbWidth, mbHeight; + + if(pStreamIn == NULL || pStreamOut == NULL || pParam == NULL) + return ICERR_ERROR; + + // initialize decoder + if((pSCDec = (CWMImageStrCodec *)malloc(sizeof(CWMImageStrCodec))) == NULL) + return ICERR_ERROR; + memset(pSCDec, 0, sizeof(CWMImageStrCodec)); + + pSCDec->WMISCP.pWStream = pStreamIn; + if(ReadWMIHeader(&pSCDec->WMII, &pSCDec->WMISCP, &pSCDec->m_param) != ICERR_OK) + return ICERR_ERROR; + + if(pSCDec->WMISCP.cfColorFormat == YUV_422 && oO >= O_RCW) + pParam->oOrientation = oO = O_NONE; // Can not rotate 422 in compressed domain! + + pSCDec->cmbWidth = (pSCDec->WMII.cWidth + pSCDec->m_param.cExtraPixelsLeft + pSCDec->m_param.cExtraPixelsRight + 15) / 16; + pSCDec->cmbHeight = (pSCDec->WMII.cHeight + pSCDec->m_param.cExtraPixelsTop + pSCDec->m_param.cExtraPixelsBottom + 15) / 16; + pSCDec->m_param.cNumChannels = pSCDec->WMISCP.cChannel; + pSCDec->m_Dparam = &aDecoderParam; + pSCDec->m_Dparam->bSkipFlexbits = (pSCDec->WMISCP.sbSubband == SB_NO_FLEXBITS); + pSCDec->m_param.bTranscode = TRUE; + + pParam->bIgnoreOverlap = isTileExtraction(pSCDec, pParam); + + cUnit = (pSCDec->m_param.cfColorFormat == YUV_420 ? 384 : (pSCDec->m_param.cfColorFormat == YUV_422 ? 512 : 256 * pSCDec->m_param.cNumChannels)); + if(cUnit > 256 * MAX_CHANNELS) + return ICERR_ERROR; + pSCDec->p1MBbuffer[0] = pMBBuf = (PixelI *)malloc(cUnit * sizeof(PixelI)); + if(pMBBuf == NULL) + return ICERR_ERROR; + pSCDec->p1MBbuffer[1] = pSCDec->p1MBbuffer[0] + 256; + for(i = 2; i < pSCDec->m_param.cNumChannels; i ++) + pSCDec->p1MBbuffer[i] = pSCDec->p1MBbuffer[i - 1] + (pSCDec->m_param.cfColorFormat == YUV_420 ? 64 : (pSCDec->m_param.cfColorFormat == YUV_422 ? 128 : 256)); + + if(pSCDec->m_param.bAlphaChannel){ // alpha channel + SimpleBitIO SB = {0}; + + iAlphaPos = pSCDec->m_param.cNumChannels; + if((pSCDec->m_pNextSC = (CWMImageStrCodec *)malloc(sizeof(CWMImageStrCodec))) == NULL) + return ICERR_ERROR; + *pSCDec->m_pNextSC = *pSCDec; + pSCDec->m_pNextSC->p1MBbuffer[0] = MBBufAlpha; + pSCDec->m_pNextSC->WMISCP.cfColorFormat = pSCDec->m_pNextSC->WMII.cfColorFormat = pSCDec->m_pNextSC->m_param.cfColorFormat = Y_ONLY; + pSCDec->m_pNextSC->WMISCP.cChannel = pSCDec->m_pNextSC->m_param.cNumChannels = 1; + pSCDec->m_pNextSC->m_bSecondary = TRUE; + pSCDec->m_pNextSC->m_pNextSC = pSCDec; + + // read plane header of second image plane + if(attach_SB(&SB, pSCDec->WMISCP.pWStream) != ICERR_OK) + return ICERR_ERROR; + ReadImagePlaneHeader(&pSCDec->m_pNextSC->WMII, &pSCDec->m_pNextSC->WMISCP, &pSCDec->m_pNextSC->m_param, &SB); + detach_SB(&SB); + + if(StrDecInit(pSCDec->m_pNextSC) != ICERR_OK) + return ICERR_ERROR; + } + else + pParam->uAlphaMode = 0; + + pIOHeaderDec = (U8 *)malloc((PACKETLENGTH * 4 - 1) + PACKETLENGTH * 4 + sizeof(BitIOInfo)); + if(pIOHeaderDec == NULL) + return ICERR_ERROR; + memset(pIOHeaderDec, 0, (PACKETLENGTH * 4 - 1) + PACKETLENGTH * 4 + sizeof(BitIOInfo)); + pSCDec->pIOHeader = (BitIOInfo *)((U8 *)ALIGNUP(pIOHeaderDec, PACKETLENGTH * 4) + PACKETLENGTH * 2); + + if(StrIODecInit(pSCDec) != ICERR_OK) + return ICERR_ERROR; + + if(StrDecInit(pSCDec) != ICERR_OK) + return ICERR_ERROR; + + if(pSCDec->m_param.bAlphaChannel){ // alpha channel + if(StrDecInit(pSCDec->m_pNextSC) != ICERR_OK) + return ICERR_ERROR; + } + + // initialize encoder + if((pSCEnc = (CWMImageStrCodec *)malloc(sizeof(CWMImageStrCodec))) == NULL) + return ICERR_ERROR; + memset(pSCEnc, 0, sizeof(CWMImageStrCodec)); + + pSCEnc->WMII = pSCDec->WMII; + pSCEnc->WMISCP = pSCDec->WMISCP; + pSCEnc->m_param = pSCDec->m_param; + pSCEnc->WMISCP.pWStream = pStreamOut; + pSCEnc->WMISCP.bfBitstreamFormat = pParam->bfBitstreamFormat; +// pSCEnc->m_param.cfColorFormat = pSCEnc->WMISCP.cfColorFormat = pParam->cfColorFormat; + pSCEnc->m_param.cfColorFormat = pSCEnc->WMISCP.cfColorFormat; + pSCEnc->m_param.cNumChannels = (pSCEnc->WMISCP.cfColorFormat == Y_ONLY ? 1 : (pSCEnc->WMISCP.cfColorFormat == YUV_444 ? 3 : pSCEnc->WMISCP.cChannel)); + pSCEnc->m_param.bAlphaChannel = (pParam->uAlphaMode > 0); + pSCEnc->m_param.bTranscode = TRUE; + if(pParam->sbSubband >= SB_MAX) + pParam->sbSubband = SB_ALL; + if(pParam->sbSubband > pSCEnc->WMISCP.sbSubband) + pSCEnc->WMISCP.sbSubband = pParam->sbSubband; + pSCEnc->m_bSecondary = FALSE; + + pIOHeaderEnc = (U8 *)malloc((PACKETLENGTH * 4 - 1) + PACKETLENGTH * 4 + sizeof(BitIOInfo)); + if(pIOHeaderEnc == NULL) + return ICERR_ERROR; + memset(pIOHeaderEnc, 0, (PACKETLENGTH * 4 - 1) + PACKETLENGTH * 4 + sizeof(BitIOInfo)); + pSCEnc->pIOHeader = (BitIOInfo *)((U8 *)ALIGNUP(pIOHeaderEnc, PACKETLENGTH * 4) + PACKETLENGTH * 2); + + for(i = 0; i < pSCEnc->m_param.cNumChannels; i ++) + pSCEnc->pPlane[i] = pSCDec->p1MBbuffer[i]; + + for(i = 1; i < pSCDec->cNumBitIO * (pSCDec->WMISCP.cNumOfSliceMinus1H + 1); i ++){ + if(pSCDec->pIndexTable[i] == 0 && i + 1 != pSCDec->cNumBitIO * (pSCDec->WMISCP.cNumOfSliceMinus1H + 1)) // empty packet + pSCDec->pIndexTable[i] = pSCDec->pIndexTable[i + 1]; + if(pSCDec->pIndexTable[i] != 0 && pSCDec->pIndexTable[i] < pSCDec->pIndexTable[i - 1]) // out of order bitstream, can not do fast tile extraction! + pParam->bIgnoreOverlap = FALSE; + } + + if(getROI(&pSCEnc->WMII, &pSCEnc->m_param, &pSCEnc->WMISCP, pParam) != ICERR_OK) + return ICERR_ERROR; + + mbLeft = (pParam->cLeftX >> 4); + mbRight = ((pParam->cLeftX + pParam->cWidth + 15) >> 4); + mbTop = (pParam->cTopY >> 4); + mbBottom = ((pParam->cTopY + pParam->cHeight + 15) >> 4); + + if(pSCDec->WMISCP.uiTileX[pSCDec->WMISCP.cNumOfSliceMinus1V] >= mbLeft && pSCDec->WMISCP.uiTileX[pSCDec->WMISCP.cNumOfSliceMinus1V] <= mbRight && + pSCDec->WMISCP.uiTileY[pSCDec->WMISCP.cNumOfSliceMinus1H] >= mbTop && pSCDec->WMISCP.uiTileY[pSCDec->WMISCP.cNumOfSliceMinus1H] <= mbBottom) + pParam->bIgnoreOverlap = FALSE; + + pSCEnc->bTileExtraction = pParam->bIgnoreOverlap; + + mbWidth = pSCEnc->cmbWidth = mbRight - mbLeft; + mbHeight = pSCEnc->cmbHeight = mbBottom - mbTop; + if(oO >= O_RCW){ + SWAP(pSCEnc->WMII.cWidth, pSCEnc->WMII.cHeight); + SWAP(pSCEnc->cmbWidth, pSCEnc->cmbHeight); + } + + if(oO != O_NONE){ + pFrameBuf = (PixelI *)malloc(pSCEnc->cmbWidth * pSCEnc->cmbHeight * cUnit * sizeof(PixelI)); + if(pFrameBuf == NULL || (pSCEnc->cmbWidth * pSCEnc->cmbHeight * cUnit * sizeof(PixelI) < pSCEnc->cmbWidth * pSCEnc->cmbHeight * cUnit)) + return ICERR_ERROR; + pMBInfo = (CWMIMBInfo *)malloc(pSCEnc->cmbWidth * pSCEnc->cmbHeight * sizeof(CWMIMBInfo)); + if(pMBInfo == NULL || (pSCEnc->cmbWidth * pSCEnc->cmbHeight * sizeof(CWMIMBInfo) < pSCEnc->cmbWidth * pSCEnc->cmbHeight)) + return ICERR_ERROR; + if(pParam->uAlphaMode > 0){ // alpha channel + pFrameBufAlpha = (PixelI *)malloc(pSCEnc->cmbWidth * pSCEnc->cmbHeight * 256 * sizeof(PixelI)); + if(pFrameBufAlpha == NULL || (pSCEnc->cmbWidth * pSCEnc->cmbHeight * 256 * sizeof(PixelI) < pSCEnc->cmbWidth * pSCEnc->cmbHeight * 256)) + return ICERR_ERROR; + pMBInfoAlpha = (CWMIMBInfo *)malloc(pSCEnc->cmbWidth * pSCEnc->cmbHeight * sizeof(CWMIMBInfo)); + if(pMBInfoAlpha == NULL || (pSCEnc->cmbWidth * pSCEnc->cmbHeight * sizeof(CWMIMBInfo) < pSCEnc->cmbWidth * pSCEnc->cmbHeight)) + return ICERR_ERROR; + } + } + + if(oO < O_RCW && pSCEnc->WMII.oOrientation < O_RCW) + pSCEnc->WMII.oOrientation ^= oO; + else if(oO >= O_RCW && pSCEnc->WMII.oOrientation >= O_RCW){ + pSCEnc->WMII.oOrientation ^= oO; + pSCEnc->WMII.oOrientation = (pSCEnc->WMII.oOrientation & 1) * 2 + (pSCEnc->WMII.oOrientation >> 1); + } + else if(oO >= O_RCW && pSCEnc->WMII.oOrientation < O_RCW) + pSCEnc->WMII.oOrientation = oO ^ ((pSCEnc->WMII.oOrientation & 1) * 2 + (pSCEnc->WMII.oOrientation >> 1)); + else + pSCEnc->WMII.oOrientation ^= ((oO & 1) * 2 + (oO >> 1)); + +// pSCEnc->WMISCP.nExpBias += 128; + + if(pParam->bIgnoreOverlap == TRUE){ + attachISWrite(pSCEnc->pIOHeader, pSCEnc->WMISCP.pWStream); + pSCEnc->pTile = pSCDec->pTile; + if(pSCEnc->WMISCP.cNumOfSliceMinus1H + pSCEnc->WMISCP.cNumOfSliceMinus1V == 0 && pSCEnc->WMISCP.bfBitstreamFormat == SPATIAL) + pSCEnc->m_param.bIndexTable = FALSE; + WriteWMIHeader(pSCEnc); + } + else{ + pTileQPInfo = (CTileQPInfo *)malloc((oO == O_NONE ? 1 : (pSCEnc->WMISCP.cNumOfSliceMinus1H + 1) * (pSCEnc->WMISCP.cNumOfSliceMinus1V + 1)) * sizeof( CTileQPInfo)); + if(pTileQPInfo == NULL || ((oO == O_NONE ? 1 : (pSCEnc->WMISCP.cNumOfSliceMinus1H + 1) * (pSCEnc->WMISCP.cNumOfSliceMinus1V + 1)) * sizeof( CTileQPInfo) < (oO == O_NONE ? 1 : (pSCEnc->WMISCP.cNumOfSliceMinus1H + 1) * (pSCEnc->WMISCP.cNumOfSliceMinus1V + 1)))) + return ICERR_ERROR; + + if(StrEncInit(pSCEnc) != ICERR_OK) + return ICERR_ERROR; + } + + if(pParam->uAlphaMode > 0){ // alpha channel +// pSCEnc->WMISCP.nExpBias -= 128; + if((pSCEnc->m_pNextSC = (CWMImageStrCodec *)malloc(sizeof(CWMImageStrCodec))) == NULL) + return ICERR_ERROR; + *pSCEnc->m_pNextSC = *pSCEnc; + pSCEnc->m_pNextSC->pPlane[0] = pSCDec->m_pNextSC->p1MBbuffer[0]; + pSCEnc->m_pNextSC->WMISCP.cfColorFormat = pSCEnc->m_pNextSC->WMII.cfColorFormat = pSCEnc->m_pNextSC->m_param.cfColorFormat = Y_ONLY; + pSCEnc->m_pNextSC->WMISCP.cChannel = pSCEnc->m_pNextSC->m_param.cNumChannels = 1; + pSCEnc->m_pNextSC->m_bSecondary = TRUE; + pSCEnc->m_pNextSC->m_pNextSC = pSCEnc; + pSCEnc->m_pNextSC->m_param = pSCDec->m_pNextSC->m_param; + pSCEnc->m_param.bAlphaChannel = TRUE; + + if(pParam->bIgnoreOverlap == TRUE) + pSCEnc->m_pNextSC->pTile = pSCDec->m_pNextSC->pTile; + else if(StrEncInit(pSCEnc->m_pNextSC) != ICERR_OK) + return ICERR_ERROR; + + WriteImagePlaneHeader(pSCEnc->m_pNextSC); + } + + if(pParam->bIgnoreOverlap == TRUE){ + SUBBAND sbEnc = pSCEnc->WMISCP.sbSubband, sbDec = pSCDec->WMISCP.sbSubband; + size_t cfEnc = ((pSCEnc->WMISCP.bfBitstreamFormat == SPATIAL || sbEnc == SB_DC_ONLY) ? 1 : (sbEnc == SB_NO_HIGHPASS ? 2 : (sbEnc == SB_NO_FLEXBITS ? 3 : 4))); + size_t cfDec = ((pSCDec->WMISCP.bfBitstreamFormat == SPATIAL || sbDec == SB_DC_ONLY) ? 1 : (sbDec == SB_NO_HIGHPASS ? 2 : (sbDec == SB_NO_FLEXBITS ? 3 : 4))); + size_t k, l = 0; + + pSCEnc->pIndexTable = (size_t *)malloc(sizeof(size_t) * (pSCEnc->WMISCP.cNumOfSliceMinus1H + 1) * (pSCEnc->WMISCP.cNumOfSliceMinus1V + 1) * cfEnc); + + if(pSCEnc->pIndexTable == NULL || cfEnc > cfDec) + return ICERR_ERROR; + + pSCEnc->cNumBitIO = cfEnc * (pSCEnc->WMISCP.cNumOfSliceMinus1V + 1); + + for(j = 0; j <= pSCDec->WMISCP.cNumOfSliceMinus1H; j ++){ + for(i = 0; i <= pSCDec->WMISCP.cNumOfSliceMinus1V; i ++) + if(pSCDec->WMISCP.uiTileX[i] >= mbLeft && pSCDec->WMISCP.uiTileX[i] < mbRight && + pSCDec->WMISCP.uiTileY[j] >= mbTop && pSCDec->WMISCP.uiTileY[j] < mbBottom){ + for(k = 0; k < cfEnc; k ++, l ++) + pSCEnc->pIndexTable[l] = pSCDec->pIndexTable[(j * (pSCDec->WMISCP.cNumOfSliceMinus1V + 1) + i) * cfDec + k + 1] - pSCDec->pIndexTable[(j * (pSCDec->WMISCP.cNumOfSliceMinus1V + 1) + i) * cfDec + k]; + } + } + + if(pSCEnc->WMISCP.cNumOfSliceMinus1H + pSCEnc->WMISCP.cNumOfSliceMinus1V == 0 && pSCEnc->WMISCP.bfBitstreamFormat == SPATIAL){ + pSCEnc->m_param.bIndexTable = FALSE; + pSCEnc->cNumBitIO = 0; + writeIndexTableNull(pSCEnc); + } + else + writeIndexTable(pSCEnc); + + detachISWrite(pSCEnc, pSCEnc->pIOHeader); + + for(j = l = 0; j <= pSCDec->WMISCP.cNumOfSliceMinus1H; j ++){ + for(i = 0; i <= pSCDec->WMISCP.cNumOfSliceMinus1V; i ++) + if(pSCDec->WMISCP.uiTileX[i] >= mbLeft && pSCDec->WMISCP.uiTileX[i] < mbRight && + pSCDec->WMISCP.uiTileY[j] >= mbTop && pSCDec->WMISCP.uiTileY[j] < mbBottom){ + for(k = 0; k < cfEnc; k ++){ + pSCDec->WMISCP.pWStream->SetPos(pSCDec->WMISCP.pWStream, pSCDec->pIndexTable[(j * (pSCDec->WMISCP.cNumOfSliceMinus1V + 1) + i) * cfDec + k] + pSCDec->cHeaderSize); + copyTo(pSCDec->WMISCP.pWStream, pSCEnc->WMISCP.pWStream, pSCEnc->pIndexTable[l++]); + } + } + } + + free(pSCEnc->pIndexTable); + } + else + writeIndexTableNull(pSCEnc); + + for(pSCDec->cRow = 0; pSCDec->cRow < mbBottom && pParam->bIgnoreOverlap == FALSE; pSCDec->cRow ++){ + for(pSCDec->cColumn = 0; pSCDec->cColumn < pSCDec->cmbWidth; pSCDec->cColumn ++){ + Int cRow = (Int)pSCDec->cRow, cColumn = (Int)pSCDec->cColumn; + CWMITile * pTile; + + memset(pMBBuf, 0, sizeof(PixelI) * cUnit); + if(pSCDec->m_param.bAlphaChannel){ // alpha channel + memset(pSCDec->m_pNextSC->p1MBbuffer[0], 0, sizeof(PixelI) * 256); + pSCDec->m_pNextSC->cRow = pSCDec->cRow; + pSCDec->m_pNextSC->cColumn = pSCDec->cColumn; + } + + // decode + pSC = pSCDec; + for(i = (pSCDec->m_param.bAlphaChannel ? 2 : 1); i > 0; i --){ + getTilePos(pSCDec, cColumn, cRow); + if(i == 2){ + pSCDec->m_pNextSC->cTileColumn = pSCDec->cTileColumn; + pSCDec->m_pNextSC->cTileRow = pSCDec->cTileRow; + } + + if(readPackets(pSCDec) != ICERR_OK) + return ICERR_ERROR; + + pContext = &pSCDec->m_pCodingContext[pSCDec->cTileColumn]; + + if(DecodeMacroblockDC(pSCDec, pContext, cColumn, cRow) != ICERR_OK) + return ICERR_ERROR; + + if(pSCDec->cSB > 1) + if(DecodeMacroblockLowpass(pSCDec, pContext, cColumn, cRow) != ICERR_OK) + return ICERR_ERROR; + + predDCACDec(pSCDec); + + if(pSCDec->cSB > 2) + if(DecodeMacroblockHighpass(pSCDec, pContext, cColumn, cRow) != ICERR_OK) + return ICERR_ERROR; + + predACDec(pSCDec); + + updatePredInfo(pSCDec, &pSCDec->MBInfo, cColumn, pSCDec->WMISCP.cfColorFormat); + + pSCDec = pSCDec->m_pNextSC; + } + pSCDec = pSC; + + if(pSCDec->cRow >= mbTop && pSCDec->cColumn >= mbLeft && pSCDec->cColumn < mbRight){ + cRow = (Int)(pSCDec->cRow - mbTop); + if(bFlipV[oO]) + cRow = (Int)mbHeight - cRow - 1; + cColumn = (Int)(pSCDec->cColumn - mbLeft); + if(bFlipH[oO]) + cColumn = (Int)mbWidth - cColumn - 1; + + pSCEnc->m_bCtxLeft = pSCEnc->m_bCtxTop = FALSE; + for(i = 0; i <= pSCEnc->WMISCP.cNumOfSliceMinus1H; i ++) + if(pSCEnc->WMISCP.uiTileY[i] == (U32)(oO < O_RCW ? cRow : cColumn)){ + pSCEnc->cTileRow = i; + pSCEnc->m_bCtxTop = TRUE; + break; + } + for(i = 0; i <= pSCEnc->WMISCP.cNumOfSliceMinus1V; i ++) + if(pSCEnc->WMISCP.uiTileX[i] == (U32)(oO < O_RCW ? cColumn : cRow)){ + pSCEnc->cTileColumn = i; + pSCEnc->m_bCtxLeft = TRUE; + break; + } + + if(pSCEnc->m_bCtxLeft && pSCEnc->m_bCtxTop){ // a new tile, buffer tile DQuant info + CTileQPInfo * pTmp = pTileQPInfo; + + pTile = pSCDec->pTile + pSCDec->cTileColumn; + + if(oO != O_NONE) + pTmp += pSCEnc->cTileRow * (pSCEnc->WMISCP.cNumOfSliceMinus1V + 1) + pSCEnc->cTileColumn; + + pTmp->dcMode = pTile->cChModeDC; + for(i = 0; i < pSCEnc->WMISCP.cChannel; i ++) + pTmp->dcIndex[i] = pTile->pQuantizerDC[i][0].iIndex; + + if(pSCEnc->WMISCP.sbSubband != SB_DC_ONLY){ + pTmp->bUseDC = pTile->bUseDC; + pTmp->lpNum = pTile->cNumQPLP; + if(pTmp->bUseDC == FALSE) + for(j = 0; j < pTmp->lpNum; j ++){ + pTmp->lpMode[j] = pTile->cChModeLP[j]; + for(i = 0; i < pSCEnc->WMISCP.cChannel; i ++) + pTmp->lpIndex[j][i] = pTile->pQuantizerLP[i][j].iIndex; + } + + if(pSCEnc->WMISCP.sbSubband != SB_NO_HIGHPASS){ + pTmp->bUseLP = pTile->bUseLP; + pTmp->hpNum = pTile->cNumQPHP; + if(pTmp->bUseLP == FALSE) + for(j = 0; j < pTmp->hpNum; j ++){ + pTmp->hpMode[j] = pTile->cChModeHP[j]; + for(i = 0; i < pSCEnc->WMISCP.cChannel; i ++) + pTmp->hpIndex[j][i] = pTile->pQuantizerHP[i][j].iIndex; + } + } + } + + if(pParam->uAlphaMode > 0){ + pTile = pSCDec->m_pNextSC->pTile + pSCDec->cTileColumn; + + pTmp->dcIndex[iAlphaPos] = pTile->pQuantizerDC[0][0].iIndex; + + if(pSCEnc->WMISCP.sbSubband != SB_DC_ONLY){ + pTmp->bUseDCAlpha = pTile->bUseDC; + pTmp->lpNumAlpha = pTile->cNumQPLP; + if(pTmp->bUseDCAlpha == FALSE) + for(j = 0; j < pTmp->lpNumAlpha; j ++) + pTmp->lpIndex[j][iAlphaPos] = pTile->pQuantizerLP[0][j].iIndex; + if(pSCEnc->WMISCP.sbSubband != SB_NO_HIGHPASS){ + pTmp->bUseLPAlpha = pTile->bUseLP; + pTmp->hpNumAlpha = pTile->cNumQPHP; + if(pTmp->bUseLPAlpha == FALSE) + for(j = 0; j < pTmp->hpNumAlpha; j ++) + pTmp->hpIndex[j][iAlphaPos] = pTile->pQuantizerHP[0][j].iIndex; + } + } + } + } + + if(oO == O_NONE){ + // encode + pSCEnc->cColumn = pSCDec->cColumn - mbLeft + 1; + pSCEnc->cRow = pSCDec->cRow + 1 - mbTop; + pSCEnc->MBInfo = pSCDec->MBInfo; + + getTilePos(pSCEnc, cColumn, cRow); + + if(pSCEnc->m_bCtxLeft && pSCEnc->m_bCtxTop) + transcodeTileHeader(pSCEnc, pTileQPInfo); + + if(encodeMB(pSCEnc, cColumn, cRow) != ICERR_OK) + return ICERR_ERROR; + if(pParam->uAlphaMode > 0){ + pSCEnc->m_pNextSC->cColumn = pSCDec->cColumn - mbLeft + 1; + pSCEnc->m_pNextSC->cRow = pSCDec->cRow + 1 - mbTop; + getTilePos(pSCEnc->m_pNextSC, cColumn, cRow); + pSCEnc->m_pNextSC->MBInfo = pSCDec->m_pNextSC->MBInfo; + if(encodeMB(pSCEnc->m_pNextSC, cColumn, cRow) != ICERR_OK) + return ICERR_ERROR; + } + } + else{ + size_t cOff = (oO < O_RCW ? (size_t)cRow * mbWidth + (size_t)cColumn : (size_t)cRow + mbHeight * (size_t)cColumn); + + pMBInfo[cOff] = pSCDec->MBInfo; + + memcpy(&pFrameBuf[cOff * cUnit], pMBBuf, cUnit * sizeof(PixelI)); + + if(pParam->uAlphaMode > 0){ + pMBInfoAlpha[cOff] = pSCDec->m_pNextSC->MBInfo; + + memcpy(&pFrameBufAlpha[cOff * 256], MBBufAlpha, 256 * sizeof(PixelI)); + } + } + } + } + + advanceOneMBRow(pSCDec); + + if(oO == O_NONE) + advanceOneMBRow(pSCEnc); + } + + if(oO != O_NONE){ + for(pSCEnc->cRow = 1; pSCEnc->cRow <= pSCEnc->cmbHeight; pSCEnc->cRow ++){ + for(pSCEnc->cColumn = 1; pSCEnc->cColumn <= pSCEnc->cmbWidth; pSCEnc->cColumn ++){ + Int cRow, cColumn; + size_t cOff = (pSCEnc->cRow - 1) * pSCEnc->cmbWidth + pSCEnc->cColumn - 1; + + for(i = 0; i < ((pSCEnc->m_param.cfColorFormat == YUV_420 || pSCEnc->m_param.cfColorFormat == YUV_422) ? 1 : pSCEnc->m_param.cNumChannels); i ++){ + transformDCBlock(pMBInfo[cOff].iBlockDC[i], pSCEnc->MBInfo.iBlockDC[i], oO); + transformACBlocks(pFrameBuf + cOff * cUnit + i * 256, pMBBuf + 256 * i, oO); + } + if(pSCEnc->WMISCP.cfColorFormat == YUV_420) + for(i = 0; i < 2; i ++){ + transformDCBlock420(pMBInfo[cOff].iBlockDC[i + 1], pSCEnc->MBInfo.iBlockDC[i + 1], oO); + transformACBlocks420(pFrameBuf + cOff * cUnit + 256 + i * 64, pMBBuf + 256 + i * 64, oO); + } + else if(pSCEnc->WMISCP.cfColorFormat == YUV_422) + for(i = 0; i < 2; i ++){ + transformDCBlock422(pMBInfo[cOff].iBlockDC[i + 1], pSCEnc->MBInfo.iBlockDC[i + 1], oO); + transformACBlocks422(pFrameBuf + cOff * cUnit + 256 + i * 128, pMBBuf + 256 + i * 128, oO); + } + + pSCEnc->MBInfo.iQIndexLP = pMBInfo[cOff].iQIndexLP; + pSCEnc->MBInfo.iQIndexHP = pMBInfo[cOff].iQIndexHP; + + cRow = (Int)pSCEnc->cRow - 1; + cColumn = (Int)pSCEnc->cColumn - 1; + getTilePos(pSCEnc, cColumn, cRow); + + if(pSCEnc->m_bCtxLeft && pSCEnc->m_bCtxTop) + transcodeTileHeader(pSCEnc, pTileQPInfo + pSCEnc->cTileRow * (pSCEnc->WMISCP.cNumOfSliceMinus1V + 1) + pSCEnc->cTileColumn); + if(encodeMB(pSCEnc, cColumn, cRow) != ICERR_OK) + return ICERR_ERROR; + + if(pParam->uAlphaMode > 0){ + pSCEnc->m_pNextSC->cColumn = pSCEnc->cColumn; + pSCEnc->m_pNextSC->cRow = pSCEnc->cRow; + getTilePos(pSCEnc->m_pNextSC, cColumn, cRow); + pSCEnc->m_pNextSC->MBInfo = pSCDec->m_pNextSC->MBInfo; + + transformDCBlock(pMBInfoAlpha[cOff].iBlockDC[0], pSCEnc->m_pNextSC->MBInfo.iBlockDC[0], oO); + transformACBlocks(pFrameBufAlpha + cOff * 256, MBBufAlpha, oO); + + pSCEnc->m_pNextSC->MBInfo.iQIndexLP = pMBInfoAlpha[cOff].iQIndexLP; + pSCEnc->m_pNextSC->MBInfo.iQIndexHP = pMBInfoAlpha[cOff].iQIndexHP; + + if(encodeMB(pSCEnc->m_pNextSC, cColumn, cRow) != ICERR_OK) + return ICERR_ERROR; + } + } + + advanceOneMBRow(pSCEnc); + } + } + + free(pMBBuf); + if(oO != O_NONE){ + free(pFrameBuf); + free(pMBInfo); + if(pParam->uAlphaMode > 0){ // alpha channel + free(pFrameBufAlpha); + free(pMBInfoAlpha); + } + } + + freePredInfo(pSCDec); + freeTileInfo(pSCDec); + StrIODecTerm(pSCDec); + FreeCodingContextDec(pSCDec); + if(pSCDec->m_param.bAlphaChannel) + free(pSCDec->m_pNextSC); + free(pSCDec); + free(pIOHeaderDec); + + if(pParam->bIgnoreOverlap == FALSE){ + freePredInfo(pSCEnc); + freeTileInfo(pSCEnc); + StrIOEncTerm(pSCEnc); + free(pTileQPInfo); + FreeCodingContextEnc(pSCEnc); + } + free(pSCEnc); + free(pIOHeaderEnc); + + return ICERR_OK; +} diff --git a/libs/jxr/image/decode/decode.c b/libs/jxr/image/decode/decode.c new file mode 100644 index 00000000000..dcaea493e4e --- /dev/null +++ b/libs/jxr/image/decode/decode.c @@ -0,0 +1,200 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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. +// +//*@@@---@@@@****************************************************************** +/****************************************************************************** + +Module Name: + decode.c + +Abstract: + Defines the entry point for the console application. + +Author: + +Revision History: +*******************************************************************************/ +#include "strcodec.h" +#include "decode.h" + +#ifdef MEM_TRACE +#define TRACE_MALLOC 1 +#define TRACE_NEW 0 +#define TRACE_HEAP 0 +#include "memtrace.h" +#endif + +/****************************************************************** +Free Adaptive Huffman Table +******************************************************************/ +static Void CleanAH(CAdaptiveHuffman **ppAdHuff) +{ + CAdaptiveHuffman *pAdHuff; + + if (NULL != ppAdHuff) { + pAdHuff = *ppAdHuff; + if (NULL != pAdHuff) { + free(pAdHuff); + } + *ppAdHuff = NULL; + } +} + +static Void CleanAHDec(CCodingContext * pSC) +{ + Int kk; + + for (kk = 0; kk < NUMVLCTABLES; kk++) { + CleanAH(&(pSC->m_pAHexpt[kk])); + } + CleanAH(&(pSC->m_pAdaptHuffCBPCY)); + CleanAH(&(pSC->m_pAdaptHuffCBPCY1)); +} + +/************************************************************************* + Initialize an adaptive huffman table +*************************************************************************/ +static Int InitializeAH(CAdaptiveHuffman **ppAdHuff, Int iSym) +{ + Int iMemStatus = 0; + + CAdaptiveHuffman *pAdHuff = Allocate(iSym, DECODER); + if (pAdHuff == NULL) { + iMemStatus = -1; // out of memory + goto ErrorExit; + } + + //Adapt(pAdHuff, bFixedTables); + //InitHuffman(pAdHuff->m_pHuffman); + //if (ICERR_OK != initHuff(pAdHuff->m_pHuffman, 1, pAdHuff->m_pTable, NULL)) { + // goto ErrorExit; + //} + *ppAdHuff = pAdHuff; + return ICERR_OK; + +ErrorExit: + if (pAdHuff) { + free(pAdHuff); + } + *ppAdHuff = NULL; + if (-1 == iMemStatus) { + printf("Insufficient memory to init decoder.\n"); + } + return ICERR_ERROR; +} + + +/************************************************************************* + Context allocation +*************************************************************************/ +Int AllocateCodingContextDec(CWMImageStrCodec *pSC, Int iNumContexts) +{ + Int i, iCBPSize, k; + static const Int aAlphabet[] = {5,4,8,7,7, 12,6,6,12,6,6,7,7, 12,6,6,12,6,6,7,7}; + + if (iNumContexts > MAX_TILES || iNumContexts < 1) // only between 1 and MAX_TILES allowed + return ICERR_ERROR; + + if (pSC == NULL) + return ICERR_ERROR; + + pSC->m_pCodingContext = malloc (iNumContexts * sizeof (CCodingContext)); + if (pSC->m_pCodingContext == NULL) { + pSC->cNumCodingContext = 0; + return ICERR_ERROR; + } + memset (pSC->m_pCodingContext, 0, iNumContexts * sizeof (CCodingContext)); + + pSC->cNumCodingContext = iNumContexts; + iCBPSize = (pSC->m_param.cfColorFormat == Y_ONLY || pSC->m_param.cfColorFormat == NCOMPONENT + || pSC->m_param.cfColorFormat == CMYK) ? 5 : 9; + + /** allocate / initialize members **/ + for (i = 0; i < iNumContexts; i++) { + CCodingContext *pContext = &(pSC->m_pCodingContext[i]); + + /** allocate adaptive Huffman encoder **/ + if (InitializeAH(&pContext->m_pAdaptHuffCBPCY, iCBPSize) != ICERR_OK) { + return ICERR_ERROR; + } + if (InitializeAH(&pContext->m_pAdaptHuffCBPCY1, 5) != ICERR_OK) { + return ICERR_ERROR; + } + + for(k = 0; k < NUMVLCTABLES; k ++){ + if (InitializeAH(&pContext->m_pAHexpt[k], aAlphabet[k]) != ICERR_OK) { + return ICERR_ERROR; + } + } + + ResetCodingContextDec(pContext); + } + + return ICERR_OK; +} + +/************************************************************************* + Context reset on encoder +*************************************************************************/ +Void ResetCodingContextDec(CCodingContext *pContext) +{ + Int k; + /** set flags **/ + pContext->m_pAdaptHuffCBPCY->m_bInitialize = FALSE; + pContext->m_pAdaptHuffCBPCY1->m_bInitialize = FALSE; + for(k = 0; k < NUMVLCTABLES; k ++) + pContext->m_pAHexpt[k]->m_bInitialize = FALSE; + + // reset VLC tables + AdaptLowpassDec (pContext); + AdaptHighpassDec (pContext); + + // reset zigzag patterns, totals + InitZigzagScan(pContext); + // reset bit reduction and cbp models + ResetCodingContext(pContext); +} + +/************************************************************************* + Context deletion +*************************************************************************/ +Void FreeCodingContextDec(CWMImageStrCodec *pSC) +{ + Int iContexts = (Int)(pSC->cNumCodingContext), i, k; + + if (iContexts > 0 && pSC->m_pCodingContext) { + + for (i = 0; i < iContexts; i++) { + CCodingContext *pContext = &(pSC->m_pCodingContext[i]); + CleanAH (&pContext->m_pAdaptHuffCBPCY); + CleanAH (&pContext->m_pAdaptHuffCBPCY1); + for (k = 0; k < NUMVLCTABLES; k++) + CleanAH (&pContext->m_pAHexpt[k]); + } + free (pSC->m_pCodingContext); + } +} + diff --git a/libs/jxr/image/decode/decode.h b/libs/jxr/image/decode/decode.h new file mode 100644 index 00000000000..44c12e4c193 --- /dev/null +++ b/libs/jxr/image/decode/decode.h @@ -0,0 +1,143 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 WMI_DECODE_H +#define WMI_DECODE_H + +typedef struct CWMDecoderParameters { + /** ROI decode **/ + Bool bDecodeFullFrame; + Bool bDecodeFullWidth; + + /** thumbnail decode **/ + Bool bSkipFlexbits; + size_t cThumbnailScale; // 1: cThumbnailScale thumbnail, only supports cThumbnailScale = 2^m for now + Bool bDecodeHP; + Bool bDecodeLP; + + // Region of interest decoding + size_t cROILeftX; + size_t cROIRightX; + size_t cROITopY; + size_t cROIBottomY; + + // table lookups for rotation and flip + size_t * pOffsetX; + size_t * pOffsetY; +} CWMDecoderParameters; + +Void predCBPDec(CWMImageStrCodec *, CCodingContext *); +Void predDCACDec(CWMImageStrCodec *); +Void predACDec(CWMImageStrCodec *); + +Int dequantizeMacroblock(CWMImageStrCodec *); +Int invTransformMacroblock(CWMImageStrCodec * pSC); +Int invTransformMacroblock_alteredOperators_hard(CWMImageStrCodec * pSC); + +Int DecodeMacroblockDC(CWMImageStrCodec * pSC, CCodingContext *pContext, Int iMBX, Int iMBY); +Int DecodeMacroblockLowpass(CWMImageStrCodec * pSC, CCodingContext *pContext, Int iMBX, Int iMBY); +Int DecodeMacroblockHighpass(CWMImageStrCodec * pSC, CCodingContext *pContext, Int iMBX, Int iMBY); + +Int AdaptLowpassDec(struct CCodingContext *); +Int AdaptHighpassDec(struct CCodingContext *); + +Void ResetCodingContextDec(CCodingContext *pContext); +Void FreeCodingContextDec(struct CWMImageStrCodec *pSC); + +/*************************************************************************/ +// Inverse transform functions +// 2-point post filter for boundaries (only used in 420 UV DC subband) +Void strPost2(PixelI *, PixelI *); + +// 2x2 post filter (only used in 420 UV DC subband) +Void strPost2x2(PixelI *, PixelI *, PixelI *, PixelI *); + +/** 4-point post filter for boundaries **/ +Void strPost4(PixelI *, PixelI *, PixelI *, PixelI *); + +/** data allocation in working buffer (first stage) **/ + +/** Y, 444 U and V **/ +/** 0 1 2 3 **/ +/** 32 33 34 35 **/ +/** 64 65 66 67 **/ +/** 96 97 98 99 **/ + +/** 420 U and V **/ +/** 0 2 4 6 **/ +/** 64 66 68 70 **/ +/** 128 130 132 134 **/ +/** 192 194 196 198 **/ + +/** 4x4 inverse DCT for first stage **/ +Void strIDCT4x4FirstStage(PixelI *); +Void strIDCT4x4Stage1(PixelI*); +Void strIDCT4x4FirstStage420UV(PixelI *); + +/** 4x4 post filter for first stage **/ +Void strPost4x4FirstStage(PixelI *); +Void strPost4x4Stage1Split(PixelI*, PixelI*, Int, Int, Bool); +Void strPost4x4Stage1(PixelI*, Int, Int, Bool); +Void strPost4x4Stage1Split_alternate(PixelI*, PixelI*, Int); +Void strPost4x4Stage1_alternate(PixelI*, Int); +//Void strPost4x4Stage1Split_420(PixelI*, PixelI*); +//Void strPost4x4Stage1_420(PixelI*); + +Void strPost4x4FirstStage420UV(PixelI *); + +/** data allocation in working buffer (second stage)**/ + +/** Y, 444 U and V **/ +/** 0 4 8 12 **/ +/** 128 132 136 140 **/ +/** 256 260 264 268 **/ +/** 384 388 392 396 **/ + +/** 420 U and V **/ +/** 0 8 **/ +/** 256 264 **/ + +/** 4x4 invesr DCT for second stage **/ +//Void strIDCT4x4SecondStage(PixelI *); +Void strIDCT4x4Stage2(PixelI*); +Void strNormalizeDec(PixelI*, Bool); +Void strDCT2x2dnDec(PixelI *, PixelI *, PixelI *, PixelI *); + +/** 4x4 post filter for second stage **/ +Void strPost4x4SecondStage(PixelI *); +Void strPost4x4Stage2Split(PixelI*, PixelI*); +Void strPost4x4Stage2Split_alternate(PixelI*, PixelI*); + +/** Huffman decode related defines **/ +#define HUFFMAN_DECODE_ROOT_BITS_LOG 3 +#define HUFFMAN_DECODE_ROOT_BITS (5) + +Int getHuff(const short *pDecodeTable, BitIOInfo* pIO); + +#endif // WMI_DECODE_H + diff --git a/libs/jxr/image/decode/postprocess.c b/libs/jxr/image/decode/postprocess.c new file mode 100644 index 00000000000..e58bd6eeafd --- /dev/null +++ b/libs/jxr/image/decode/postprocess.c @@ -0,0 +1,288 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "windowsmediaphoto.h" +#include "strcodec.h" + +Void smoothMB(PixelI * p1, PixelI * p0, PixelI * q0, PixelI * q1) +{ + // p1 p0 | q0 q1 + PixelI delta = ((((*q0 - *p0) << 2) + (*p1 - *q1)) >> 3); + + *q0 -= delta; + *p0 += delta; +} + +Void smooth(PixelI * p2, PixelI * p1, PixelI * p0, PixelI * q0, PixelI * q1, PixelI * q2) +{ + // p2 p1 p0 | q0 q1 q2 + PixelI delta = ((((*q0 - *p0) << 2) + (*p1 - *q1)) >> 3); + + *q0 -= delta; + *p0 += delta; + + *p1 = (*p1 >> 1) + ((*p0 + *p2) >> 2); + *q1 = (*q1 >> 1) + ((*q0 + *q2) >> 2); +} + +Int initPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t mbWidth, size_t iNumChannels) +{ + size_t i, j, k, l; + Bool b32bit = sizeof(int) == 4; + + for(j = 0; j < iNumChannels; j ++){ + for(i = 0; i < 2; i ++){ + // 2 more are allocated to avoid boundary check + if(b32bit) // integer overlow/underflow check for 32-bit system + if((((mbWidth + 2) >> 16) * sizeof(struct tagPostProcInfo)) & 0xffff0000) + return ICERR_ERROR; + strPostProcInfo[j][i] = (struct tagPostProcInfo *)malloc((mbWidth + 2) * sizeof(struct tagPostProcInfo)); + assert(strPostProcInfo[j][i] != NULL); + if(strPostProcInfo[j][i] == NULL){ + return ICERR_ERROR; + } + strPostProcInfo[j][i] ++; + + // initialize out-of-bound MBs as bumpy (no post at all) to avoid boundary check + // left boundary + strPostProcInfo[j][i][-1].ucMBTexture = 3; + for(l = 0; l < 4; l ++){ + for(k = 0; k < 4; k ++){ + strPostProcInfo[j][i][-1].ucBlockTexture[l][k] = 3; + } + } + // right boundary + strPostProcInfo[j][i][mbWidth] = strPostProcInfo[j][i][-1]; + } + } + + return ICERR_OK; +} + +Void termPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t iNumChannels) +{ + size_t i, j; + + for(j = 0; j < iNumChannels; j ++){ + for(i = 0; i < 2; i ++){ + if(strPostProcInfo[j][i] != NULL){ + free(strPostProcInfo[j][i] - 1); + } + } + } +} + +Void slideOneMBRow(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t iNumChannels, size_t mbWidth, Bool top, Bool bottom) +{ + size_t i, j; + struct tagPostProcInfo * bar; + + for(i = 0; i < iNumChannels; i ++){ + // swap previous row and current row + bar = strPostProcInfo[i][0]; + strPostProcInfo[i][0] = strPostProcInfo[i][1]; + strPostProcInfo[i][1] = bar; + + if(top){ // if top row, previous row is out of boundary + for(j = 0; j < mbWidth; j ++){ + strPostProcInfo[i][0][j] = strPostProcInfo[i][0][-1]; // set as bumpy + } + } + + if(bottom){ // if bottom bottom row, set current row of MBs (out of boundary) as bumpy + for(j = 0; j < mbWidth; j ++){ + strPostProcInfo[i][1][j] = strPostProcInfo[i][1][-1]; // set as bumpy + } + } + } +} + +// get DC and texture infomation right before transform +Void updatePostProcInfo(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * pMB, size_t mbX, size_t cc) +{ + size_t i, j; + struct tagPostProcInfo * pMBInfo = strPostProcInfo[cc][1] + mbX; + + // DC of MB + pMBInfo->iMBDC = pMB[0]; + + // texture of MB + pMBInfo->ucMBTexture = 0; // smooth + for(i = 16; i < 256; i += 16){ + if(pMB[i] != 0){ + pMBInfo->ucMBTexture = 3; // bumpy + break; + } + } + + // DCs of blocks not available yet, will collect after demacroblocking + + // textures of blocks + for(j = 0; j < 4; j ++) + for(i = 0; i < 4; i ++){ + PixelI * p = pMB + i * 64 + j * 16; + size_t k; + + for(k = 1, pMBInfo->ucBlockTexture[j][i] = 0; k < 16; k ++){ + if(p[k] != 0){ + pMBInfo->ucBlockTexture[j][i] = 3; + break; + } + } + } +} + +// demacroblock critirion: two MBs have same texture other than bumpy and DCs differ less than 1 +#define DMB(a, b) (a->ucMBTexture + b->ucMBTexture == 0) && (abs(a->iMBDC - b->iMBDC) <= threshold) + +// demacroblock and get DCs of blocks +Void postProcMB(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p0, PixelI * p1, size_t mbX, size_t cc, Int threshold) +{ + /* 4 MBs involved, current MB is d, we have 4 2-pixel boundary segments */ + /* | */ + /* a | b */ + /* - - + + */ + /* c ! d */ + /* ! */ + struct tagPostProcInfo * pMBb = strPostProcInfo[cc][0] + mbX, * pMBa = pMBb - 1, * pMBd = strPostProcInfo[cc][1] + mbX, * pMBc = pMBd - 1; + + // demacroblock segment -- + if(DMB(pMBa, pMBc)){ + smoothMB(p0 - 256 + 10 * 16, p0 - 256 + 11 * 16, p1 - 256 + 8 * 16, p1 - 256 + 9 * 16); + smoothMB(p0 - 256 + 14 * 16, p0 - 256 + 15 * 16, p1 - 256 + 12 * 16, p1 - 256 + 13 * 16); + } + + // demacroblock segment ++ + if(DMB(pMBb, pMBd)){ + smoothMB(p0 + 2 * 16, p0 + 3 * 16, p1 + 0 * 16, p1 + 1 * 16); + smoothMB(p0 + 6 * 16, p0 + 7 * 16, p1 + 4 * 16, p1 + 5 * 16); + } + + // demacroblock segment | + if(DMB(pMBa, pMBb)){ + smoothMB(p0 - 256 + 10 * 16, p0 - 256 + 14 * 16, p0 + 2 * 16, p0 + 6 * 16); + smoothMB(p0 - 256 + 11 * 16, p0 - 256 + 15 * 16, p0 + 3 * 16, p0 + 7 * 16); + } + + // demacroblock segment ! + if(DMB(pMBc, pMBd)){ + smoothMB(p1 - 256 + 8 * 16, p1 - 256 + 12 * 16, p1 + 0 * 16, p1 + 4 * 16); + smoothMB(p1 - 256 + 9 * 16, p1 - 256 + 13 * 16, p1 + 1 * 16, p1 + 5 * 16); + } + + /* update DCs of blocks */ + // MB d + pMBd->iBlockDC[0][0] = p1[0 * 16]; + pMBd->iBlockDC[0][1] = p1[4 * 16]; + pMBd->iBlockDC[1][0] = p1[1 * 16]; + pMBd->iBlockDC[1][1] = p1[5 * 16]; + + // MB b + pMBb->iBlockDC[2][0] = p0[2 * 16]; + pMBb->iBlockDC[2][1] = p0[6 * 16]; + pMBb->iBlockDC[3][0] = p0[3 * 16]; + pMBb->iBlockDC[3][1] = p0[7 * 16]; + + // MB c + pMBc->iBlockDC[0][2] = p1[ 8 * 16 - 256]; + pMBc->iBlockDC[0][3] = p1[12 * 16 - 256]; + pMBc->iBlockDC[1][2] = p1[ 9 * 16 - 256]; + pMBc->iBlockDC[1][3] = p1[13 * 16 - 256]; + + // MB a + pMBa->iBlockDC[2][2] = p0[10 * 16 - 256]; + pMBa->iBlockDC[2][3] = p0[14 * 16 - 256]; + pMBa->iBlockDC[3][2] = p0[11 * 16 - 256]; + pMBa->iBlockDC[3][3] = p0[15 * 16 - 256]; +} + +/* deblock and destair blocks */ +/* 4 MBs involved, need to process 16 blocks of a */ +/* | */ +/* a | b */ +/* - - - - */ +/* c | d */ +/* | */ +Void postProcBlock(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p0, PixelI * p1, size_t mbX, size_t cc, Int threshold) +{ + size_t i, j, k; + Int dc[5][5]; + U8 texture[5][5]; + struct tagPostProcInfo * pMBb = strPostProcInfo[cc][0] + mbX, * pMBa = pMBb - 1, * pMBd = strPostProcInfo[cc][1] + mbX, * pMBc = pMBd - 1; + PixelI * pc, * pt; + + /* copy DC and Texture info, can be optimized out */ + for(j = 0; j < 4; j ++){ + // from MB a + for(i = 0; i < 4; i ++){ + dc[j][i] = pMBa->iBlockDC[j][i]; + texture[j][i] = pMBa->ucBlockTexture[j][i]; + } + + // 4 blocks from MB c + dc[4][j] = pMBc->iBlockDC[0][j]; + texture[4][j] = pMBc->ucBlockTexture[0][j]; + + // 4 blocks from MB b + dc[j][4] = pMBb->iBlockDC[j][0]; + texture[j][4] = pMBb->ucBlockTexture[j][0]; + } + // 1 block from MB d + dc[4][4] = pMBd->iBlockDC[0][0]; + texture[4][4] = pMBd->ucBlockTexture[0][0]; + + /* block boundaries */ + /* | */ + /* | */ + /* --- */ + + for(j = 0; j < 4; j ++){ + for(i = 0; i < 4; i ++){ + pc = p0 - 256 + i * 64 + j * 16; + + // deblock + if(texture[j][i] + texture[j + 1][i] < 3 && abs(dc[j][i] - dc[j + 1][i]) <= threshold){ + // smooth horizontal boundary ---- + pt = (j < 3 ? pc + 16 : p1 - 256 + i * 64); + for(k = 0; k < 4; k ++){ + smooth(pc + idxCC[1][k], pc + idxCC[2][k], pc + idxCC[3][k], pt + idxCC[0][k], pt + idxCC[1][k], pt + idxCC[2][k]); + } + } + + // two horizontally adjacent blocks have same texture and similiar DCs + if(texture[j][i] + texture[j][i + 1] < 3 && abs(dc[j][i] - dc[j][i + 1]) <= threshold){ + // smooth vertical boundary | + pt = pc + 64; + for(k = 0; k < 4; k ++){ + smooth(pc + idxCC[k][1], pc + idxCC[k][2], pc + idxCC[k][3], pt + idxCC[k][0], pt + idxCC[k][1], pt + idxCC[k][2]); + } + } + } + } +} + diff --git a/libs/jxr/image/decode/segdec.c b/libs/jxr/image/decode/segdec.c new file mode 100644 index 00000000000..96ca3c8463d --- /dev/null +++ b/libs/jxr/image/decode/segdec.c @@ -0,0 +1,1205 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strcodec.h" +#include "decode.h" + +#ifdef MEM_TRACE +#define TRACE_MALLOC 1 +#define TRACE_NEW 0 +#define TRACE_HEAP 0 +#include "memtrace.h" +#endif + +extern const int dctIndex[3][16]; +extern const int blkOffset[16]; +extern const int blkOffsetUV[4]; +static Int DecodeSignificantAbsLevel (struct CAdaptiveHuffman *pAHexpt, BitIOInfo* pIO); + +//#undef X86OPT_INLINE + +#ifdef X86OPT_INLINE +#define _FORCEINLINE __forceinline +#else // X86OPT_INLINE +#define _FORCEINLINE +#endif // X86OPT_INLINE + +//================================================================ +// Memory access functions +//================================================================ +static U32 _FORCEINLINE _load4(void* pv) +{ +#ifdef _BIG__ENDIAN_ + return (*(U32*)pv); +#else // _BIG__ENDIAN_ +#if defined(_M_IA64) || defined(_ARM_) + U32 v; + v = ((U16 *) pv)[0]; + v |= ((U32)((U16 *) pv)[1]) << 16; + return _byteswap_ulong(v); +#else // _M_IA64 + return _byteswap_ulong(*(U32*)pv); +#endif // _M_IA64 +#endif // _BIG__ENDIAN_ +} + +static _FORCEINLINE U32 _peekBit16(BitIOInfo* pIO, U32 cBits) +{ + PEEKBIT16(pIO, cBits); + // masking is not needed here because shift of unsigned int is implemented as a logical shift (SHR)! +} + +#define LOAD16 _load4 +static _FORCEINLINE U32 _flushBit16(BitIOInfo* pIO, U32 cBits) +{ + FLUSHBIT16(pIO, cBits); +} + +static _FORCEINLINE U32 _getBit16(BitIOInfo* pIO, U32 cBits) +{ + U32 uiRet = _peekBit16(pIO, cBits); + _flushBit16(pIO, cBits); + + return uiRet; +} + +#define SIGN_BIT(TypeOrValue) (((UInt) 1) << (8 * sizeof (TypeOrValue) - 1)) +/*********************************************************************************************************** + Huffman decode (input is a fully built Huffman table) +***********************************************************************************************************/ +Int getHuff(const short *pDecodeTable, BitIOInfo* pIO) +{ + Int iSymbol, iSymbolHuff; + iSymbol = pDecodeTable[peekBit16(pIO, HUFFMAN_DECODE_ROOT_BITS)]; + + flushBit16(pIO, iSymbol < 0 ? HUFFMAN_DECODE_ROOT_BITS : iSymbol & ((1 << HUFFMAN_DECODE_ROOT_BITS_LOG) - 1)); + iSymbolHuff = iSymbol >> HUFFMAN_DECODE_ROOT_BITS_LOG; + + if (iSymbolHuff < 0) { + iSymbolHuff = iSymbol; + while ((iSymbolHuff = pDecodeTable[iSymbolHuff + SIGN_BIT (pDecodeTable[0]) + getBit16(pIO, 1)]) < 0); + } + return (iSymbolHuff); +} + +#if 1 +static _FORCEINLINE U32 _getBool16(BitIOInfo* pIO) +{ + U32 uiRet = pIO->uiAccumulator >> 31;//_peekBit16(pIO, 1); + //_flushBit16(pIO, 1); + pIO->cBitsUsed++; + if (pIO->cBitsUsed < 16) { + pIO->uiAccumulator <<= 1; + } + else { + pIO->pbCurrent = MASKPTR(pIO->pbCurrent + ((pIO->cBitsUsed >> 3)/* & 2*/), pIO->iMask); + pIO->cBitsUsed &= 16 - 1; + pIO->uiAccumulator = LOAD16(pIO->pbCurrent) << pIO->cBitsUsed; + } + + return uiRet; +} + +static _FORCEINLINE I32 _getSign(BitIOInfo* pIO) +{ + I32 uiRet = (int) pIO->uiAccumulator >> 31;//_peekBit16(pIO, 1); + //_flushBit16(pIO, 1); + pIO->cBitsUsed++; + if (pIO->cBitsUsed < 16) { + pIO->uiAccumulator <<= 1; + } + else { + pIO->pbCurrent = MASKPTR(pIO->pbCurrent + ((pIO->cBitsUsed >> 3)/* & 2*/), pIO->iMask); + pIO->cBitsUsed &= 16 - 1; + pIO->uiAccumulator = LOAD16(pIO->pbCurrent) << pIO->cBitsUsed; + } + + return uiRet; +} +#else +#define _getBool16(x) _getBit16((x),1) +#define _getSign(x) (-_getBit16((x),1)) +#endif + +/** this function returns cBits if zero is read, or a signed value if first cBits are not all zero **/ +static _FORCEINLINE I32 _getBit16s(BitIOInfo* pIO, U32 cBits) +{ + I32 iRet = (I32)_peekBit16(pIO, cBits + 1); + iRet = ((iRet >> 1) ^ (-(iRet & 1))) + (iRet & 1); + _flushBit16(pIO, cBits + (iRet != 0)); + return iRet; +} + +/************************************************************************* + Huffman decoding with short tables +*************************************************************************/ +static _FORCEINLINE Int _getHuffShort(const short *pDecodeTable, BitIOInfo* pIO) +{ + Int iSymbol = pDecodeTable[_peekBit16(pIO, HUFFMAN_DECODE_ROOT_BITS)]; + assert(iSymbol >= 0); + // for some strange reason, inlining flushBit doesn't work well + flushBit16(pIO, iSymbol & ((1 << HUFFMAN_DECODE_ROOT_BITS_LOG) - 1)); + return (iSymbol >> HUFFMAN_DECODE_ROOT_BITS_LOG); +} +/************************************************************************* + Adapt + Huffman init +*************************************************************************/ +static Int AdaptDecFixed (CAdaptiveHuffman *pAH) +{ + AdaptDiscriminant (pAH); + return ICERR_OK; +} + +/************************************************************************* + DecodeCBP +*************************************************************************/ +static Void DecodeCBP(CWMImageStrCodec * pSC, CCodingContext *pContext) +{ + BitIOInfo* pIO = pContext->m_pIOAC; + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannel = (cf == NCOMPONENT || cf == CMYK) ? (Int) pSC->m_param.cNumChannels : 1; + Int iCBPCY, iCBPCU , iCBPCV; + Int k, iBlock, i; + Int iNumCBP; + Bool bIsChroma; + CAdaptiveHuffman *pAHCBP = pContext->m_pAdaptHuffCBPCY; + CAdaptiveHuffman *pAHCBP1 = pContext->m_pAdaptHuffCBPCY1; + CAdaptiveHuffman *pAHex1 = pContext->m_pAHexpt[1]; + + readIS_L1(pSC, pIO); + + for (i = 0; i < iChannel; i++) { + + iCBPCY = iCBPCU = iCBPCV = 0; + iNumCBP = _getHuffShort(pAHCBP1->m_hufDecTable, pIO); + pAHCBP1->m_iDiscriminant += pAHCBP1->m_pDelta[iNumCBP]; + + switch (iNumCBP) { + case 2: + iNumCBP = _getBit16(pIO, 2); + if (iNumCBP == 0) + iNumCBP = 3; + else if (iNumCBP == 1) + iNumCBP = 5; + else { + static const Int aTab[] = { 6, 9, 10, 12 }; + iNumCBP = aTab[iNumCBP * 2 + _getBool16 (pIO) - 4]; + } + break; + case 1: + iNumCBP = 1 << _getBit16(pIO, 2); + break; + case 3: + iNumCBP = 0xf ^ (1 << _getBit16(pIO, 2)); + break; + case 4: + iNumCBP = 0xf; + } + + for (iBlock = 0; iBlock < 4; iBlock++) { + if (iNumCBP & (1 << iBlock)) { + static const UInt gFLC0[] = { 0,2,1,2,2,0 }; + static const UInt gOff0[] = { 0,4,2,8,12,1 }; + static const UInt gOut0[] = { 0,15,3,12, 1,2,4,8, 5,6,9,10, 7,11,13,14 }; + Int iNumBlockCBP = getHuff(pAHCBP->m_hufDecTable, pIO); + unsigned int val = (unsigned int) iNumBlockCBP + 1, iCode1; + + pAHCBP->m_iDiscriminant += pAHCBP->m_pDelta[iNumBlockCBP]; + iNumBlockCBP = 0; + + if (val >= 6) { // chroma present + if (_getBool16 (pIO)) { + iNumBlockCBP = 0x10; + } + else if (_getBool16 (pIO)) { + iNumBlockCBP = 0x20; + } + else { + iNumBlockCBP = 0x30; + } + if (val == 9) { + if (_getBool16 (pIO)) { + // do nothing + } + else if (_getBool16 (pIO)) { + val = 10; + } + else { + val = 11; + } + } + val -= 6; + } + iCode1 = gOff0[val]; + if (gFLC0[val]) { + iCode1 += _getBit16(pIO, gFLC0[val]); + } + iNumBlockCBP += gOut0[iCode1]; + + switch (cf) { + case YUV_444: + iCBPCY |= ((iNumBlockCBP & 0xf) << (iBlock * 4)); + for (k = 0; k < 2; k++) { + bIsChroma = ((iNumBlockCBP>>(k+4)) & 0x01); + if (bIsChroma) { // U is present in block + Int iCode = _getHuffShort(pAHex1->m_hufDecTable, pIO); + switch (iCode) { + case 1: + iCode = _getBit16(pIO, 2); + if (iCode == 0) + iCode = 3; + else if (iCode == 1) + iCode = 5; + else { + static const Int aTab[] = { 6, 9, 10, 12 }; + iCode = aTab[iCode * 2 + _getBool16 (pIO) - 4]; + } + break; + case 0: + iCode = 1 << _getBit16(pIO, 2); + break; + case 2: + iCode = 0xf ^ (1 << _getBit16(pIO, 2)); + break; + case 3: + iCode = 0xf; + } + if (k == 0) + iCBPCU |= (iCode << (iBlock * 4)); + else + iCBPCV |= (iCode << (iBlock * 4)); + } + } + break; + + case YUV_420: + iCBPCY |= ((iNumBlockCBP & 0xf) << (iBlock * 4)); + iCBPCU |= ((iNumBlockCBP >> 4) & 0x1) << (iBlock); + iCBPCV |= ((iNumBlockCBP >> 5) & 0x1) << (iBlock); + break; + + case YUV_422: + iCBPCY |= ((iNumBlockCBP & 0xf) << (iBlock * 4)); + for (k = 0; k < 2; k ++) { + Int iCode = 5; + const Int iShift[4] = {0, 1, 4, 5}; + if((iNumBlockCBP >> (k + 4)) & 0x01) { + if(_getBool16(pIO)) { + iCode = 1; + } + else if(_getBool16(pIO)){ + iCode = 4; + } + iCode <<= iShift[iBlock]; + if(k == 0) iCBPCU |= iCode; + else iCBPCV |= iCode; + } + } + break; + + default: + iCBPCY |= (iNumBlockCBP << (iBlock * 4)); + } + } + } + + pSC->MBInfo.iDiffCBP[i] = iCBPCY; + if (cf == YUV_420 || cf == YUV_444 || cf == YUV_422) { + pSC->MBInfo.iDiffCBP[1] = iCBPCU; + pSC->MBInfo.iDiffCBP[2] = iCBPCV; + } + } +} + +/************************************************************************* + Experimental code -- decodeBlock + SR = <0 1 2> == + alphabet 12: + pAHexpt[0] == + alphabet 6: + pAHexpt[1] == + pAHexpt[2] == + alphabet 4: + pAHexpt[3] == (SR may be last or insignificant only) + alphabet f(run) (this can be extended to 6 contexts - SL and SR') + pAHexpt[4] == + alphabet f(lev) (this can be extended to 9 contexts) + pAHexpt[5-6] == first symbol + pAHexpt[7-8] == condition on SRn no use +*************************************************************************/ + +Int _FORCEINLINE DecodeSignificantRun (Int iMaxRun, struct CAdaptiveHuffman *pAHexpt, BitIOInfo* pIO) +{ + Int iIndex; + static const Int aRemap[] = {1,2,3,5,7, 1,2,3,5,7, /*1,2,3,4,6, */1,2,3,4,5 }; + Int iBin = gSignificantRunBin[iMaxRun]; + Int iRun = 0, iFLC = 0; + + if (iMaxRun < 5) { + if (iMaxRun == 1) { + return 1; + } + else if (_getBool16 (pIO)) { + return 1; + } + else if (iMaxRun == 2 || _getBool16 (pIO)) { + return 2; + } + else if (iMaxRun == 3 || _getBool16 (pIO)) { + return 3; + } + return 4; + } + iIndex = _getHuffShort (pAHexpt->m_hufDecTable, pIO); + iIndex += iBin * 5; + iRun = aRemap[iIndex]; + iFLC = gSignificantRunFixedLength[iIndex]; + if (iFLC) { + iRun += _getBit16 (pIO, iFLC); + } + return iRun; +} + +#ifndef X86OPT_INLINE +static Void DecodeFirstIndex (Int *pIndex, struct CAdaptiveHuffman *pAHexpt, + BitIOInfo* pIO) +#else +static __forceinline Void DecodeFirstIndex (Int *pIndex, struct CAdaptiveHuffman *pAHexpt, + BitIOInfo* pIO) +#endif +{ + Int iIndex; + iIndex = getHuff (pAHexpt->m_hufDecTable, pIO); + pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; + pAHexpt->m_iDiscriminant1 += pAHexpt->m_pDelta1[iIndex]; + *pIndex = iIndex; +} + +#ifndef X86OPT_INLINE +static Void DecodeIndex (Int *pIndex, Int iLoc, struct CAdaptiveHuffman *pAHexpt, + BitIOInfo* pIO) +#else +static __forceinline Void DecodeIndex (Int *pIndex, Int iLoc, + struct CAdaptiveHuffman *pAHexpt, BitIOInfo* pIO) +#endif +{ + Int iIndex; + if (iLoc < 15) { + iIndex = _getHuffShort (pAHexpt->m_hufDecTable, pIO); + pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; + pAHexpt->m_iDiscriminant1 += pAHexpt->m_pDelta1[iIndex]; + *pIndex = iIndex; + } + else if (iLoc == 15) { + if (_getBool16 (pIO) == 0) { + iIndex = 0; + } + else if (_getBool16 (pIO) == 0) { + iIndex = 2; + } + else { + iIndex = 1 + 2 * _getBool16 (pIO); + } + *pIndex = iIndex; + } + else { //if (iLoc == 16) { /* deterministic */ + Int iSL = _getBit16 (pIO, 1/* + 1*/); + *pIndex = iSL;// >> 1; + } +} + +static _FORCEINLINE Int DecodeBlock (Bool bChroma, Int *aLocalCoef, struct CAdaptiveHuffman **pAHexpt, + const Int iContextOffset, BitIOInfo* pIO, Int iLocation) +{ + Int iSR, iSRn, iIndex, iNumNonzero = 1, iCont, iSign; + struct CAdaptiveHuffman **pAH1 = pAHexpt + iContextOffset + bChroma * 3; + + /** first symbol **/ + DecodeFirstIndex (&iIndex, /*&iSign, */pAH1[0], pIO); + iSR = (iIndex & 1); + iSRn = iIndex >> 2; + + iCont = iSR & iSRn; + iSign = _getSign(pIO); + + if (iIndex & 2 /* iSL */) { + aLocalCoef[1] = (DecodeSignificantAbsLevel (pAHexpt[6 + iContextOffset + iCont], pIO) ^ iSign) - iSign; + } + else { + aLocalCoef[1] = (1 | iSign); // 0 -> 1; -1 -> -1 + } + aLocalCoef[0] = 0; + if (iSR == 0) { + aLocalCoef[0] = DecodeSignificantRun (15 - iLocation, pAHexpt[0], pIO); + } + iLocation += aLocalCoef[0] + 1; + + while (iSRn != 0) { + iSR = iSRn & 1; + aLocalCoef[iNumNonzero * 2] = 0; + if (iSR == 0) { + aLocalCoef[iNumNonzero * 2] = DecodeSignificantRun (15 - iLocation, pAHexpt[0], pIO); + } + iLocation += aLocalCoef[iNumNonzero * 2] + 1; + DecodeIndex (&iIndex, /*&iSign, */iLocation, pAH1[iCont + 1], pIO); + iSRn = iIndex >> 1; + + assert (iSRn >= 0 && iSRn < 3); + iCont &= iSRn; /** huge difference! **/ + iSign = _getSign(pIO); + + if (iIndex & 1 /* iSL */) { + aLocalCoef[iNumNonzero * 2 + 1] = + (DecodeSignificantAbsLevel (pAHexpt[6 + iContextOffset + iCont], pIO) ^ iSign) - iSign; + } + else { + aLocalCoef[iNumNonzero * 2 + 1] = (1 | iSign); // 0 -> 1; -1 -> -1 (was 1 + (iSign * 2)) + } + iNumNonzero++; + } + return iNumNonzero; +} + +/************************************************************************* + DecodeBlockHighpass : +*************************************************************************/ +static _FORCEINLINE Int DecodeBlockHighpass (const Bool bChroma, struct CAdaptiveHuffman **pAHexpt, + BitIOInfo* pIO, const Int iQP, Int *pCoef, CAdaptiveScan *pScan) +{ + const Int iContextOffset = CTDC + CONTEXTX; + UInt iLoc = 1; + Int iSR, iSRn, iIndex, iNumNonzero = 1, iCont, iSign, iLevel; + struct CAdaptiveHuffman **pAH1 = pAHexpt + iContextOffset + bChroma * 3; + const CAdaptiveScan *pConstScan = (const CAdaptiveScan *) pScan; + + /** first symbol **/ + DecodeFirstIndex (&iIndex, /*&iSign, */pAH1[0], pIO); + iSR = (iIndex & 1); + iSRn = iIndex >> 2; + + iCont = iSR & iSRn; + iSign = _getSign(pIO); + + iLevel = (iQP ^ iSign) - iSign; + if (iIndex & 2 /* iSL */) { + iLevel *= DecodeSignificantAbsLevel (pAHexpt[6 + iContextOffset + iCont], pIO);// ^ iSign) - iSign; + } + //else { + // iLevel = (1 | iSign); // 0 -> 1; -1 -> -1 + //} + if (iSR == 0) { + iLoc += DecodeSignificantRun (15 - iLoc, pAHexpt[0], pIO); + } + iLoc &= 0xf; + pCoef[pConstScan[iLoc].uScan] = (PixelI) iLevel;//(PixelI)(iQP * iLevel); + pScan[iLoc].uTotal++; + if (iLoc && pScan[iLoc].uTotal > pScan[iLoc - 1].uTotal) { + CAdaptiveScan cTemp = pScan[iLoc]; + pScan[iLoc] = pScan[iLoc - 1]; + pScan[iLoc - 1] = cTemp; + } + iLoc = (iLoc + 1) & 0xf; + //iLoc++; + + while (iSRn != 0) { + iSR = iSRn & 1; + if (iSR == 0) { + iLoc += DecodeSignificantRun (15 - iLoc, pAHexpt[0], pIO); + if (iLoc >= 16) + return 16; + } + DecodeIndex (&iIndex, /*&iSign, */iLoc + 1, pAH1[iCont + 1], pIO); + iSRn = iIndex >> 1; + + assert (iSRn >= 0 && iSRn < 3); + iCont &= iSRn; /** huge difference! **/ + iSign = _getSign(pIO); + + iLevel = (iQP ^ iSign) - iSign; + if (iIndex & 1 /* iSL */) { + iLevel *= DecodeSignificantAbsLevel (pAHexpt[6 + iContextOffset + iCont], pIO);// ^ iSign) - iSign; + //iLevel = (DecodeSignificantAbsLevel (pAHexpt[6 + iContextOffset + iCont], pIO) ^ iSign) - iSign; + } + //else { + // iLevel = (1 | iSign); // 0 -> 1; -1 -> -1 (was 1 + (iSign * 2)) + //} + + pCoef[pConstScan[iLoc].uScan] = (PixelI) iLevel;//(PixelI)(iQP * iLevel); + pScan[iLoc].uTotal++; + if (iLoc && pScan[iLoc].uTotal > pScan[iLoc - 1].uTotal) { + CAdaptiveScan cTemp = pScan[iLoc]; + pScan[iLoc] = pScan[iLoc - 1]; + pScan[iLoc - 1] = cTemp; + } + + iLoc = (iLoc + 1) & 0xf; + iNumNonzero++; + } + return iNumNonzero; +} + +/************************************************************************* + DecodeBlockAdaptive +*************************************************************************/ +static _FORCEINLINE Int DecodeBlockAdaptive (Bool bNoSkip, Bool bChroma, CAdaptiveHuffman **pAdHuff, + BitIOInfo *pIO, BitIOInfo *pIOFL, + PixelI *pCoeffs, CAdaptiveScan *pScan, + const Int iModelBits, const Int iTrim, const Int iQP, + const Int *pOrder, const Bool bSkipFlexbits) +{ + // const Int iLocation = 1; + // const Int iContextOffset = CTDC + CONTEXTX; + Int kk, iNumNonzero = 0, iFlex = iModelBits - iTrim; + + if (iFlex < 0 || bSkipFlexbits) + iFlex = 0; + + if (bNoSkip) { + const Int iQP1 = (iQP << iModelBits); + iNumNonzero = DecodeBlockHighpass (bChroma, pAdHuff, pIO, iQP1, pCoeffs, pScan); + } + if (iFlex) { + UInt k; + if (iQP + iTrim == 1) { // only iTrim = 0, iQP = 1 is legal + assert (iTrim == 0); + assert (iQP == 1); + + for (k = 1; k < 16; k++) { + PixelI *pk = pCoeffs + pOrder[k]; + if (*pk < 0) { + Int fine = _getBit16(pIOFL, iFlex); + *pk -= (PixelI)(fine); + } + else if (*pk > 0) { + Int fine = _getBit16(pIOFL, iFlex); + *pk += (PixelI)(fine); + } + else { + *pk = (PixelI)(_getBit16s(pIOFL, iFlex)); + } + } + } + else { + const Int iQP1 = iQP << iTrim; + for (k = 1; k < 16; k++) { + kk = pCoeffs[pOrder[k]]; + if (kk < 0) { + Int fine = _getBit16(pIOFL, iFlex); + pCoeffs[pOrder[k]] -= (PixelI)(iQP1 * fine); + } + else if (kk > 0) { + Int fine = _getBit16(pIOFL, iFlex); + pCoeffs[pOrder[k]] += (PixelI)(iQP1 * fine); + } + else { + pCoeffs[pOrder[k]] = (PixelI)(iQP1 * _getBit16s(pIOFL, iFlex)); + } + } + } + } + + return iNumNonzero; +} + + +/************************************************************************* + GetCoeffs +*************************************************************************/ +static _FORCEINLINE Int DecodeCoeffs (CWMImageStrCodec * pSC, CCodingContext *pContext, + Int iMBX, Int iMBY, + BitIOInfo* pIO, BitIOInfo *pIOFL) +{ + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannels = (Int) pSC->m_param.cNumChannels; + const Int iPlanes = (cf == YUV_420 || cf == YUV_422) ? 1 : iChannels; + Int iQP; + CAdaptiveScan *pScan; + PixelI *pCoeffs; + Int i, iBlock, iSubblock, iNBlocks = 4; + Int iModelBits = pContext->m_aModelAC.m_iFlcBits[0]; + Int aLaplacianMean[2] = { 0, 0}, *pLM = aLaplacianMean + 0; + const Int *pOrder = dctIndex[0]; + const Int iOrient = pSC->MBInfo.iOrientation; + Bool bChroma = FALSE; + + Int iCBPCU = pSC->MBInfo.iCBP[1]; + Int iCBPCV = pSC->MBInfo.iCBP[2]; + Int iCBPCY = pSC->MBInfo.iCBP[0]; + + UNREFERENCED_PARAMETER( iMBX ); + UNREFERENCED_PARAMETER( iMBY ); + + /** set scan arrays and other MB level constants **/ + if (iOrient == 1) { + pScan = pContext->m_aScanVert; + } + else { + pScan = pContext->m_aScanHoriz; + } + + if (cf == YUV_420) { + iNBlocks = 6; + iCBPCY += (iCBPCU << 16) + (iCBPCV << 20); + } + else if (cf == YUV_422) { + iNBlocks = 8; + iCBPCY += (iCBPCU << 16) + (iCBPCV << 24); + } + + for (i = 0; i < iPlanes; i++) { + Int iIndex = 0, iNumNonZero; + + if(pSC->WMISCP.sbSubband != SB_NO_FLEXBITS) + readIS_L1(pSC, pIOFL); + + for (iBlock = 0; iBlock < iNBlocks; iBlock++) { + + readIS_L2(pSC, pIO); + if (pIO != pIOFL) + readIS_L2(pSC, pIOFL); + + iQP = (pSC->m_param.bTranscode ? 1 : pTile->pQuantizerHP[iPlanes > 1 ? i : (iBlock > 3 ? (cf == YUV_420 ? iBlock - 3 : iBlock / 2 - 1) : 0)][pSC->MBInfo.iQIndexHP].iQP); + + for (iSubblock = 0; iSubblock < 4; iSubblock++, iIndex++, iCBPCY >>= 1) { + pCoeffs = pSC->p1MBbuffer[i] + blkOffset[iIndex & 0xf]; + + //if (iBlock < 4) {//(cf == YUV_444) { + //bBlockNoSkip = ((iTempCBPC & (1 << iIndex1)) != 0); + //pCoeffs = pSC->p1MBbuffer[iBlock >> 2] + blkOffset[iIndex & 0xf]; + //} + //else { + if (iBlock >= 4) { + if(cf == YUV_420) { + pCoeffs = pSC->p1MBbuffer[iBlock - 3] + blkOffsetUV[iSubblock]; + } + else { // YUV_422 + pCoeffs = pSC->p1MBbuffer[1 + (1 & (iBlock >> 1))] + ((iBlock & 1) * 32) + blkOffsetUV_422[iSubblock]; + } + } + + /** read AC values **/ + assert (pSC->m_Dparam->bSkipFlexbits == 0 || pSC->WMISCP.bfBitstreamFormat == FREQUENCY || pSC->WMISCP.sbSubband == SB_NO_FLEXBITS); + iNumNonZero = DecodeBlockAdaptive ((iCBPCY & 1), bChroma, pContext->m_pAHexpt, + pIO, pIOFL, pCoeffs, pScan, iModelBits, pContext->m_iTrimFlexBits, + iQP, pOrder, pSC->m_Dparam->bSkipFlexbits); + if(iNumNonZero > 16) // something is wrong! + return ICERR_ERROR; + // shouldn't this be > 15? + (*pLM) += iNumNonZero; + } + if (iBlock == 3) { + iModelBits = pContext->m_aModelAC.m_iFlcBits[1]; + pLM = aLaplacianMean + 1; + bChroma = TRUE; + } + } + + iCBPCY = pSC->MBInfo.iCBP[(i + 1) & 0xf]; + assert (MAX_CHANNELS == 16); + } + + /** update model at end of MB **/ + UpdateModelMB (cf, iChannels, aLaplacianMean, &(pContext->m_aModelAC)); + return ICERR_OK; +} + +/************************************************************************* + DecodeSignificantAbsLevel +*************************************************************************/ +#ifndef X86OPT_INLINE +static Int DecodeSignificantAbsLevel (struct CAdaptiveHuffman *pAHexpt, BitIOInfo* pIO) +#else +static __forceinline Int DecodeSignificantAbsLevel (struct CAdaptiveHuffman *pAHexpt, BitIOInfo* pIO) +#endif +{ + UInt iIndex; + Int iFixed, iLevel; + static const Int aRemap[] = { 2, 3, 4, 6, 10, 14 }; + static const Int aFixedLength[] = { 0, 0, 1, 2, 2, 2 }; + + iIndex = (UInt)getHuff (pAHexpt->m_hufDecTable, pIO); + assert(iIndex <= 6); + pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; + if (iIndex < 2) { + iLevel = iIndex + 2; // = aRemap[iIndex] + } + else if (iIndex < 6) { + iFixed = aFixedLength[iIndex]; + iLevel = aRemap[iIndex] + _getBit16 (pIO, iFixed); + } + else{ + iFixed = _getBit16 (pIO, 4) + 4; + if (iFixed == 19) { + iFixed += _getBit16 (pIO, 2); + if (iFixed == 22) { + iFixed += _getBit16 (pIO, 3); + } + } + iLevel = 2 + (1 << iFixed); + iIndex = getBit32 (pIO, iFixed); + iLevel += iIndex; + } + return iLevel; +} + +U8 decodeQPIndex(BitIOInfo* pIO,U8 cBits) +{ + if(_getBit16(pIO, 1) == 0) + return 0; + return (U8)(_getBit16(pIO, cBits) + 1); +} + +/************************************************************************* + DecodeSecondStageCoeff +*************************************************************************/ +Int DecodeMacroblockLowpass (CWMImageStrCodec * pSC, CCodingContext *pContext, + Int iMBX, Int iMBYdummy) +{ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannels = (Int) pSC->m_param.cNumChannels; + const Int iFullPlanes = (cf == YUV_420 || cf == YUV_422) ? 2 : iChannels; + Int k; + CAdaptiveScan *pScan = pContext->m_aScanLowpass; + BitIOInfo* pIO = pContext->m_pIOLP; + Int iModelBits = pContext->m_aModelLP.m_iFlcBits[0]; + Int aRLCoeffs[32], iNumNonzero = 0, iIndex = 0; + Int aLaplacianMean[2] = { 0, 0}, *pLM = aLaplacianMean; + Int iChannel, iCBP = 0; +#ifndef ARMOPT_BITIO // ARM opt always uses 32-bit version of getBits + U32 (*getBits)(BitIOInfo* pIO, U32 cBits) = _getBit16; +#endif + CWMIMBInfo * pMBInfo = &pSC->MBInfo; + I32 *aDC[MAX_CHANNELS]; + + UNREFERENCED_PARAMETER( iMBX ); + UNREFERENCED_PARAMETER( iMBYdummy ); + + readIS_L1(pSC, pIO); + if((pSC->WMISCP.bfBitstreamFormat != SPATIAL) && (pSC->pTile[pSC->cTileColumn].cBitsLP > 0)) // MB-based LP QP index + pMBInfo->iQIndexLP = decodeQPIndex(pIO, pSC->pTile[pSC->cTileColumn].cBitsLP); + + // set arrays + for (k = 0; k < (Int) pSC->m_param.cNumChannels; k++) { + aDC[k & 15] = pMBInfo->iBlockDC[k]; + } + + /** reset adaptive scan totals **/ + if (pSC->m_bResetRGITotals) { + int iScale = 2; + int iWeight = iScale * 16; + pScan[0].uTotal = MAXTOTAL; + for (k = 1; k < 16; k++) { + pScan[k].uTotal = iWeight; + iWeight -= iScale; + } + } + + /** in raw mode, this can take 6% of the bits in the extreme low rate case!!! **/ + if (cf == YUV_420 || cf == YUV_422 || cf == YUV_444) { + int iCountM = pContext->m_iCBPCountMax, iCountZ = pContext->m_iCBPCountZero; + int iMax = iFullPlanes * 4 - 5; /* actually (1 << iNChannels) - 1 **/ + if (iCountZ <= 0 || iCountM < 0) { + iCBP = 0; + if (_getBool16 (pIO)) { + iCBP = 1; + k = _getBit16 (pIO, iFullPlanes - 1); + if (k) { + iCBP = k * 2 + _getBit16(pIO, 1); + } + } + if (iCountM < iCountZ) + iCBP = iMax - iCBP; + } + else { + iCBP = _getBit16(pIO, iFullPlanes); + } + + iCountM += 1 - 4 * (iCBP == iMax);//(b + c - 2*a); + iCountZ += 1 - 4 * (iCBP == 0);//(a + b - 2*c); + if (iCountM < -8) + iCountM = -8; + else if (iCountM > 7) + iCountM = 7; + pContext->m_iCBPCountMax = iCountM; + + if (iCountZ < -8) + iCountZ = -8; + else if (iCountZ > 7) + iCountZ = 7; + pContext->m_iCBPCountZero = iCountZ; + } + else { /** 1 or N channel **/ + for (iChannel = 0; iChannel < iChannels; iChannel++) + iCBP |= (getBits (pIO, 1) << iChannel); + } + +#ifndef ARMOPT_BITIO // ARM opt always uses 32-bit version of getBits + if (pContext->m_aModelLP.m_iFlcBits[0] > 14 || pContext->m_aModelLP.m_iFlcBits[1] > 14) { + getBits = getBit32; + } +#endif + + for (iChannel = 0; iChannel < iFullPlanes; iChannel++) { + PixelI *pCoeffs = aDC[iChannel]; + + if (iCBP & 1) { + iNumNonzero = DecodeBlock (iChannel > 0, aRLCoeffs, pContext->m_pAHexpt, + CTDC, pIO, 1 + 9 * ((cf == YUV_420) && (iChannel == 1)) + + ((cf == YUV_422) && (iChannel == 1))); + + if ((cf == YUV_420 || cf == YUV_422) && iChannel) { + Int aTemp[16]; //14 required, 16 for security + static const Int aRemap[] = { 4, 1,2,3, 5,6,7 }; + const Int *pRemap = aRemap + (cf == YUV_420); + const Int iCount = (cf == YUV_420) ? 6 : 14; + + (*pLM) += iNumNonzero; + iIndex = 0; + memset (aTemp, 0, sizeof(aTemp)); + + for (k = 0; k < iNumNonzero; k++) { + iIndex += aRLCoeffs[k * 2]; + aTemp[iIndex & 0xf] = aRLCoeffs[k * 2 + 1]; + iIndex++; + } + + for (k = 0; k < iCount; k++) { + aDC[(k & 1) + 1][pRemap[k >> 1]] = aTemp[k]; + } + } + else { + (*pLM) += iNumNonzero; + iIndex = 1; + + for (k = 0; k < iNumNonzero; k++) { + iIndex += aRLCoeffs[k * 2]; + pCoeffs[pScan[iIndex].uScan] = aRLCoeffs[k * 2 + 1]; + pScan[iIndex].uTotal++; + if (pScan[iIndex].uTotal > pScan[iIndex - 1].uTotal) { + CAdaptiveScan cTemp = pScan[iIndex]; + pScan[iIndex] = pScan[iIndex - 1]; + pScan[iIndex - 1] = cTemp; + } + iIndex++; + } + } + } + + if (iModelBits) { + if ((cf == YUV_420 || cf == YUV_422) && iChannel) { + for (k = 1; k < (cf == YUV_420 ? 4 : 8); k++) { + if (aDC[1][k] > 0) { + aDC[1][k] <<= iModelBits; + aDC[1][k] += getBits (pIO, iModelBits); + } + else if (aDC[1][k] < 0) { + aDC[1][k] <<= iModelBits; + aDC[1][k] -= getBits (pIO, iModelBits); + } + else { + aDC[1][k] = getBits (pIO, iModelBits); + if (aDC[1][k] && _getBool16 (pIO)) + aDC[1][k] = -aDC[1][k]; + } + + if (aDC[2][k] > 0) { + aDC[2][k] <<= iModelBits; + aDC[2][k] += getBits (pIO, iModelBits); + } + else if (aDC[2][k] < 0) { + aDC[2][k] <<= iModelBits; + aDC[2][k] -= getBits (pIO, iModelBits); + } + else { + aDC[2][k] = getBits (pIO, iModelBits); + if (aDC[2][k] && _getBool16 (pIO)) + aDC[2][k] = -aDC[2][k]; + } + } + } + else { +#ifdef WIN32 + const Int iMask = (1 << iModelBits) - 1; +#endif // WIN32 + for (k = 1; k < 16; k++) { +#ifdef WIN32 + if (pCoeffs[k]) { + Int r1 = _rotl(pCoeffs[k], iModelBits); + pCoeffs[k] = (r1 ^ getBits(pIO, iModelBits)) - (r1 & iMask); + } +#else // WIN32 + if (pCoeffs[k] > 0) { + pCoeffs[k] <<= iModelBits; + pCoeffs[k] += getBits (pIO, iModelBits); + } + else if (pCoeffs[k] < 0) { + pCoeffs[k] <<= iModelBits; + pCoeffs[k] -= getBits (pIO, iModelBits); + } +#endif // WIN32 + else { + //pCoeffs[k] = getBits (pIO, iModelBits); + //if (pCoeffs[k] && _getBool16 (pIO)) + // pCoeffs[k] = -pCoeffs[k]; + Int r1 = _peekBit16 (pIO, iModelBits + 1); + pCoeffs[k] = ((r1 >> 1) ^ (-(r1 & 1))) + (r1 & 1); + _flushBit16 (pIO, iModelBits + (pCoeffs[k] != 0)); + } + } + } + } + pLM = aLaplacianMean + 1; + iModelBits = pContext->m_aModelLP.m_iFlcBits[1]; + + iCBP >>= 1; + } + + UpdateModelMB (cf, iChannels, aLaplacianMean, &(pContext->m_aModelLP)); + + if (pSC->m_bResetContext) { + AdaptLowpassDec(pContext); + } + + return ICERR_OK; +} + +/************************************************************************* + 8 bit YUV 420 macroblock decode function with 4x4 transform + Index order is as follows: + Y: U: V: + 0 1 4 5 16 17 20 21 + 2 3 6 7 18 19 22 23 + 8 9 12 13 + 10 11 14 15 + + DCAC coefficients stored for 4x4 - offsets (x == no storage) + Y: + x x x [0..3] + x x x [4..7] + x x x [8..11] + [16..19] [20..23] [24..27] [28..31,12..15] + + U, V: + x [0..3] + [8..11] [4..7,12..15] +*************************************************************************/ +Int DecodeMacroblockDC(CWMImageStrCodec * pSC, CCodingContext *pContext, Int iMBX, Int iMBY) +{ + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + CWMIMBInfo * pMBInfo = &pSC->MBInfo; + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannels = (Int) pSC->m_param.cNumChannels; + BitIOInfo* pIO = pContext->m_pIODC; + Int iIndex, i; + Int aLaplacianMean[2] = { 0, 0}, *pLM = aLaplacianMean; + Int iModelBits = pContext->m_aModelDC.m_iFlcBits[0]; + struct CAdaptiveHuffman *pAH; + Int iQDCY, iQDCU, iQDCV; + // const Int iChromaElements = (cf == YUV_420) ? 8 * 8 : ((cf == YUV_422) ? 8 * 16 : 16 * 16); + + UNREFERENCED_PARAMETER( iMBX ); + UNREFERENCED_PARAMETER( iMBY ); + + for (i = 0; i < iChannels; i++) + memset (pMBInfo->iBlockDC[i], 0, 16 * sizeof (I32)); + + readIS_L1(pSC, pIO); + + pMBInfo->iQIndexLP = pMBInfo->iQIndexHP = 0; + + if(pSC->WMISCP.bfBitstreamFormat == SPATIAL && pSC->WMISCP.sbSubband != SB_DC_ONLY){ + if(pTile->cBitsLP > 0) // MB-based LP QP index + pMBInfo->iQIndexLP = decodeQPIndex(pIO, pTile->cBitsLP); + if( pSC->WMISCP.sbSubband != SB_NO_HIGHPASS && pTile->cBitsHP > 0) // MB-based HP QP index + pMBInfo->iQIndexHP = decodeQPIndex(pIO, pTile->cBitsHP); + } + if(pTile->cBitsHP == 0 && pTile->cNumQPHP > 1) // use LP QP + pMBInfo->iQIndexHP = pMBInfo->iQIndexLP; + if (pMBInfo->iQIndexLP >= pTile->cNumQPLP || pMBInfo->iQIndexHP >= pTile->cNumQPHP) + return ICERR_ERROR; + + if(cf == Y_ONLY || cf == CMYK || cf == NCOMPONENT) { + for (i = 0; i < iChannels; i++) { + iQDCY = 0; + /** get luminance DC **/ + if (_getBool16 (pIO)) { + iQDCY = DecodeSignificantAbsLevel(pContext->m_pAHexpt[3], pIO) - 1; + *pLM += 1; + } + if (iModelBits) { + iQDCY = (iQDCY << iModelBits) | _getBit16(pIO, iModelBits); + } + if (iQDCY && _getBool16 (pIO)) + iQDCY = -iQDCY; + pMBInfo->iBlockDC[i][0] = iQDCY; + + pLM = aLaplacianMean + 1; + iModelBits = pContext->m_aModelDC.m_iFlcBits[1]; + } + } + else { + /** find significant level in 3D **/ + pAH = pContext->m_pAHexpt[2]; + iIndex = getHuff (pAH->m_hufDecTable, pIO); + iQDCY = iIndex >> 2; + iQDCU = (iIndex >> 1) & 1; + iQDCV = iIndex & 1; + + /** get luminance DC **/ + if (iQDCY) { + iQDCY = DecodeSignificantAbsLevel(pContext->m_pAHexpt[3], pIO) - 1; + *pLM += 1; + } + if (iModelBits) { + iQDCY = (iQDCY << iModelBits) | _getBit16(pIO, iModelBits); + } + if (iQDCY && _getBool16 (pIO)) + iQDCY = -iQDCY; + pMBInfo->iBlockDC[0][0] = iQDCY; + + /** get chrominance DC **/ + pLM = aLaplacianMean + 1; + iModelBits = pContext->m_aModelDC.m_iFlcBits[1]; + + if (iQDCU) { + iQDCU = DecodeSignificantAbsLevel(pContext->m_pAHexpt[4], pIO) - 1; + *pLM += 1; + } + if (iModelBits) { + iQDCU = (iQDCU << iModelBits) | _getBit16(pIO, iModelBits); + } + if (iQDCU && _getBool16 (pIO)) + iQDCU = -iQDCU; + pMBInfo->iBlockDC[1][0] = iQDCU; + + if (iQDCV) { + iQDCV = DecodeSignificantAbsLevel(pContext->m_pAHexpt[4], pIO) - 1; + *pLM += 1; + } + if (iModelBits) { + iQDCV = (iQDCV << iModelBits) | _getBit16(pIO, iModelBits); + } + if (iQDCV && _getBool16 (pIO)) + iQDCV = -iQDCV; + pMBInfo->iBlockDC[2][0] = iQDCV; + } + + UpdateModelMB (cf, iChannels, aLaplacianMean, &(pContext->m_aModelDC)); + + if(((!(pSC->WMISCP.bfBitstreamFormat != FREQUENCY || pSC->m_Dparam->cThumbnailScale < 16)) || pSC->WMISCP.sbSubband == SB_DC_ONLY) && pSC->m_bResetContext){ + Int kk; + for (kk = 2; kk < 5; kk++) { + if (ICERR_OK != AdaptDecFixed (pContext->m_pAHexpt[kk])) { + return ICERR_ERROR; + } + } + } + + return ICERR_OK; +} + +/************************************************************************* + DecodeMacroblockHighpass +*************************************************************************/ +Int DecodeMacroblockHighpass (CWMImageStrCodec *pSC, CCodingContext *pContext, + Int iMBX, Int iMBY) +{ + /** reset adaptive scan totals **/ + if (pSC->m_bResetRGITotals) { + int iScale = 2, k; + int iWeight = iScale * 16; + pContext->m_aScanHoriz[0].uTotal = pContext->m_aScanVert[0].uTotal = MAXTOTAL; + for (k = 1; k < 16; k++) { + pContext->m_aScanHoriz[k].uTotal = pContext->m_aScanVert[k].uTotal = iWeight; + iWeight -= iScale; + } + } + if((pSC->WMISCP.bfBitstreamFormat != SPATIAL) && (pSC->pTile[pSC->cTileColumn].cBitsHP > 0)) { // MB-based HP QP index + pSC->MBInfo.iQIndexHP = decodeQPIndex(pContext->m_pIOAC, pSC->pTile[pSC->cTileColumn].cBitsHP); + if (pSC->MBInfo.iQIndexHP >= pSC->pTile[pSC->cTileColumn].cNumQPHP) + goto ErrorExit; + } + else if(pSC->pTile[pSC->cTileColumn].cBitsHP == 0 && pSC->pTile[pSC->cTileColumn].cNumQPHP > 1) // use LP QP + pSC->MBInfo.iQIndexHP = pSC->MBInfo.iQIndexLP; + + + DecodeCBP (pSC, pContext); + predCBPDec(pSC, pContext); + + if (DecodeCoeffs (pSC, pContext, iMBX, iMBY, + pContext->m_pIOAC, pContext->m_pIOFL) != ICERR_OK) + goto ErrorExit; + + if (pSC->m_bResetContext) { + AdaptHighpassDec(pContext); + } + + return ICERR_OK; +ErrorExit: + return ICERR_ERROR; +} + +/************************************************************************* + Adapt +*************************************************************************/ +Int AdaptLowpassDec(CCodingContext * pSC) +{ + Int kk; + for (kk = 0; kk < CONTEXTX + CTDC; kk++) { + if (ICERR_OK != AdaptDecFixed (pSC->m_pAHexpt[kk])) { + goto ErrorExit; + } + } + return ICERR_OK; + +ErrorExit: + return ICERR_ERROR; + +} + +Int AdaptHighpassDec(CCodingContext * pSC) +{ + Int kk; + if (ICERR_OK != AdaptDecFixed (pSC->m_pAdaptHuffCBPCY)) { + goto ErrorExit; + } + if (ICERR_OK != AdaptDecFixed (pSC->m_pAdaptHuffCBPCY1)) { + goto ErrorExit; + } + for (kk = 0; kk < CONTEXTX; kk++) { + if (ICERR_OK != AdaptDecFixed (pSC->m_pAHexpt[kk + CONTEXTX + CTDC])) { + goto ErrorExit; + } + } + + return ICERR_OK; + +ErrorExit: + return ICERR_ERROR; +} diff --git a/libs/jxr/image/decode/strInvTransform.c b/libs/jxr/image/decode/strInvTransform.c new file mode 100644 index 00000000000..123ede63d5c --- /dev/null +++ b/libs/jxr/image/decode/strInvTransform.c @@ -0,0 +1,1888 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strTransform.h" +#include "strcodec.h" +#include "decode.h" + +/** rotation by -pi/8 **/ +#define IROTATE1(a, b) (a) -= (((b) + 1) >> 1), (b) += (((a) + 1) >> 1) // this works well too +#define IROTATE2(a, b) (a) -= (((b)*3 + 4) >> 3), (b) += (((a)*3 + 4) >> 3) // this works well too + +/** local functions **/ +static Void invOddOdd(PixelI *, PixelI *, PixelI *, PixelI *); +static Void invOddOddPost(PixelI *, PixelI *, PixelI *, PixelI *); +static Void invOdd(PixelI *, PixelI *, PixelI *, PixelI *); +static Void strHSTdec(PixelI *, PixelI *, PixelI *, PixelI *); +static Void strHSTdec1(PixelI *, PixelI *); +static Void strHSTdec1_alternate(PixelI *, PixelI *); +static Void strHSTdec1_edge(PixelI *pa, PixelI *pd); + +/** IDCT stuff **/ +/** reordering should be combined with zigzag scan **/ +/** data order before IDCT **/ +/** 0 8 4 6 **/ +/** 2 10 14 12 **/ +/** 1 11 15 13 **/ +/** 9 3 7 5 **/ +/** data order after IDCT **/ +/** 0 1 2 3 **/ +/** 4 5 6 7 **/ +/** 8 9 10 11 **/ +/** 12 13 14 15 **/ +Void strIDCT4x4Stage1(PixelI* p) +{ + /** top left corner, butterfly => butterfly **/ + strDCT2x2up(p + 0, p + 1, p + 2, p + 3); + + /** top right corner, -pi/8 rotation => butterfly **/ + invOdd(p + 5, p + 4, p + 7, p + 6); + + /** bottom left corner, butterfly => -pi/8 rotation **/ + invOdd(p + 10, p + 8, p + 11, p + 9); + + /** bottom right corner, -pi/8 rotation => -pi/8 rotation **/ + invOddOdd(p + 15, p + 14, p + 13, p + 12); + + /** butterfly **/ + //FOURBUTTERFLY(p, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + FOURBUTTERFLY_HARDCODED1(p); +} + +Void strIDCT4x4Stage2(PixelI* p) +{ + /** bottom left corner, butterfly => -pi/8 rotation **/ + invOdd(p + 32, p + 48, p + 96, p + 112); + + /** top right corner, -pi/8 rotation => butterfly **/ + invOdd(p + 128, p + 192, p + 144, p + 208); + + /** bottom right corner, -pi/8 rotation => -pi/8 rotation **/ + invOddOdd(p + 160, p + 224, p + 176, p + 240); + + /** top left corner, butterfly => butterfly **/ + strDCT2x2up(p + 0, p + 64, p + 16, p + 80); + + /** butterfly **/ + FOURBUTTERFLY(p, 0, 192, 48, 240, 64, 128, 112, 176, 16, 208, 32, 224, 80, 144, 96, 160); +} + +Void strNormalizeDec(PixelI* p, Bool bChroma) +{ + int i; + if (!bChroma) { + //for (i = 0; i < 256; i += 16) { + // p[i] <<= 2; + //} + } + else { + for (i = 0; i < 256; i += 16) { + p[i] += p[i]; + } + } +} + +/** 2x2 DCT with post-scaling - for use on decoder side **/ +Void strDCT2x2dnDec(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d, C, t; + a = *pa; + b = *pb; + C = *pc; + d = *pd; + + a += d; + b -= C; + t = ((a - b) >> 1); + c = t - d; + d = t - C; + a -= d; + b += c; + + *pa = a * 2; + *pb = b * 2; + *pc = c * 2; + *pd = d * 2; +} + + +/** post filter stuff **/ +/** 2-point post for boundaries **/ +Void strPost2(PixelI * a, PixelI * b) +{ + *b += ((*a + 4) >> 3); + *a += ((*b + 2) >> 2); + *b += ((*a + 4) >> 3); +} + +Void strPost2_alternate(PixelI * pa, PixelI * pb) +{ + PixelI a, b; + a = *pa; + b = *pb; + + /** rotate **/ + b += ((a + 2) >> 2); + a += ((b + 1) >> 1); + a += (b >> 5); + a += (b >> 9); + a += (b >> 13); + + b += ((a + 2) >> 2); + + *pa = a; + *pb = b; +} + +Void strPost2x2(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + /** butterflies **/ + a += d; + b += c; + d -= (a + 1) >> 1; + c -= (b + 1) >> 1; + + /** rotate **/ + b += ((a + 2) >> 2); + a += ((b + 1) >> 1); + b += ((a + 2) >> 2); + + /** butterflies **/ + d += (a + 1) >> 1; + c += (b + 1) >> 1; + a -= d; + b -= c; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +Void strPost2x2_alternate(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + /** butterflies **/ + a += d; + b += c; + d -= (a + 1) >> 1; + c -= (b + 1) >> 1; + + /** rotate **/ + b += ((a + 2) >> 2); + a += ((b + 1) >> 1); + a += (b >> 5); + a += (b >> 9); + a += (b >> 13); + b += ((a + 2) >> 2); + + /** butterflies **/ + d += (a + 1) >> 1; + c += (b + 1) >> 1; + a -= d; + b -= c; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +/** 4-point post for boundaries **/ +Void strPost4(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + a += d, b += c; + d -= ((a + 1) >> 1), c -= ((b + 1) >> 1); + + IROTATE1(c, d); + + d += ((a + 1) >> 1), c += ((b + 1) >> 1); + a -= d - ((d * 3 + 16) >> 5), b -= c - ((c * 3 + 16) >> 5); + d += ((a * 3 + 8) >> 4), c += ((b * 3 + 8) >> 4); + a += ((d * 3 + 16) >> 5), b += ((c * 3 + 16) >> 5); + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +Void strPost4_alternate(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + a += d, b += c; + d -= ((a + 1) >> 1), c -= ((b + 1) >> 1); + + strHSTdec1_edge(&a, &d); strHSTdec1_edge(&b, &c); + IROTATE1(c, d); + d += ((a + 1) >> 1), c += ((b + 1) >> 1); + + a -= d, b -= c; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +/***************************************************************************************** + Input data offsets: + (15)(14)|(10+64)(11+64) p0 (15)(14)|(74)(75) + (13)(12)|( 8+64)( 9+64) (13)(12)|(72)(73) + --------+-------------- --------+-------- + ( 5)( 4)|( 0+64) (1+64) p1 ( 5)( 4)|(64)(65) + ( 7)( 6)|( 2+64) (3+64) ( 7)( 6)|(66)(67) +*****************************************************************************************/ +Void DCCompensate (PixelI *a, PixelI *b, PixelI *c, PixelI *d, int iDC) +{ + iDC = iDC>>1; + *a -= iDC; + *d -= iDC; + *b += iDC; + *c += iDC; +} + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +int ClipDCL(int iDCL, int iAltDCL) +{ + int iClipDCL = 0; + if (iDCL > 0) { + if (iAltDCL > 0) + iClipDCL = min(iDCL, iAltDCL); + else + iClipDCL = 0; + } + else if (iDCL < 0) { + if (iAltDCL < 0) + iClipDCL = max(iDCL, iAltDCL); + else + iClipDCL = 0; + } + return iClipDCL; +} + +Void strPost4x4Stage1Split(PixelI *p0, PixelI *p1, Int iOffset, Int iHPQP, Bool bHPAbsent) +{ + int iDCLAlt1, iDCLAlt2, iDCLAlt3, iDCLAlt0; + int iDCL1, iDCL2, iDCL3, iDCL0; + int iTmp1, iTmp2, iTmp3, iTmp0; + + PixelI *p2 = p0 + 72 - iOffset; + PixelI *p3 = p1 + 64 - iOffset; + p0 += 12; + p1 += 4; + + /** buttefly **/ + strDCT2x2dn(p0 + 0, p2 + 0, p1 + 0, p3 + 0); + strDCT2x2dn(p0 + 1, p2 + 1, p1 + 1, p3 + 1); + strDCT2x2dn(p0 + 2, p2 + 2, p1 + 2, p3 + 2); + strDCT2x2dn(p0 + 3, p2 + 3, p1 + 3, p3 + 3); + + /** bottom right corner: -pi/8 rotation => -pi/8 rotation **/ + invOddOddPost(p3 + 0, p3 + 1, p3 + 2, p3 + 3); + + /** anti diagonal corners: rotation by -pi/8 **/ + IROTATE1(p1[2], p1[3]); + IROTATE1(p1[0], p1[1]); + IROTATE1(p2[1], p2[3]); + IROTATE1(p2[0], p2[2]); + + /** butterfly **/ + strHSTdec1(p0 + 0, p3 + 0); + strHSTdec1(p0 + 1, p3 + 1); + strHSTdec1(p0 + 2, p3 + 2); + strHSTdec1(p0 + 3, p3 + 3); + strHSTdec(p0 + 0, p2 + 0, p1 + 0, p3 + 0); + strHSTdec(p0 + 1, p2 + 1, p1 + 1, p3 + 1); + strHSTdec(p0 + 2, p2 + 2, p1 + 2, p3 + 2); + strHSTdec(p0 + 3, p2 + 3, p1 + 3, p3 + 3); + + iTmp0 = (*(p0 +0) + *(p1 +0) + *(p2 +0) + *(p3 +0))>>1; + iTmp1 = (*(p0 +1) + *(p1 +1) + *(p2 +1) + *(p3 +1))>>1; + iTmp2 = (*(p0 +2) + *(p1 +2) + *(p2 +2) + *(p3 +2))>>1; + iTmp3 = (*(p0 +3) + *(p1 +3) + *(p2 +3) + *(p3 +3))>>1; + iDCL0 = (iTmp0 * 595 + 65536)>>17; //Approximating 27/5947 + iDCL1 = (iTmp1 * 595 + 65536)>>17; + iDCL2 = (iTmp2 * 595 + 65536)>>17; + iDCL3 = (iTmp3 * 595 + 65536)>>17; + if ((abs(iDCL0) < iHPQP && iHPQP > 20) || bHPAbsent) { + iDCLAlt0 = (*(p0 +0) - *(p1 +0) - *(p2 +0) + *(p3 +0))>>1; + iDCL0 = ClipDCL (iDCL0, iDCLAlt0); + DCCompensate (p0 + 0, p2 + 0, p1 + 0, p3 + 0, iDCL0); + } + if ((abs(iDCL1) < iHPQP && iHPQP > 20) || bHPAbsent) { + iDCLAlt1 = (*(p0 +1) - *(p1 +1) - *(p2 +1) + *(p3 +1))>>1; + iDCL1 = ClipDCL (iDCL1, iDCLAlt1); + DCCompensate (p0 + 1, p2 + 1, p1 + 1, p3 + 1, iDCL1); + } + if ((abs(iDCL2) < iHPQP && iHPQP > 20) || bHPAbsent) { + iDCLAlt2 = (*(p0 +2) - *(p1 +2) - *(p2 +2) + *(p3 +2))>>1; + iDCL2 = ClipDCL (iDCL2, iDCLAlt2); + DCCompensate (p0 + 2, p2 + 2, p1 + 2, p3 + 2, iDCL2); + } + if ((abs(iDCL3) < iHPQP && iHPQP > 20) || bHPAbsent) { + iDCLAlt3 = (*(p0 +3) - *(p1 +3) - *(p2 +3) + *(p3 +3))>>1; + iDCL3 = ClipDCL (iDCL3, iDCLAlt3); + DCCompensate (p0 + 3, p2 + 3, p1 + 3, p3 + 3, iDCL3); + } +} + +Void strPost4x4Stage1(PixelI* p, Int iOffset, Int iHPQP, Bool bHPAbsent) +{ + strPost4x4Stage1Split(p, p + 16, iOffset, iHPQP, bHPAbsent); +} + +Void strPost4x4Stage1Split_alternate(PixelI *p0, PixelI *p1, Int iOffset) +{ + PixelI *p2 = p0 + 72 - iOffset; + PixelI *p3 = p1 + 64 - iOffset; + p0 += 12; + p1 += 4; + + /** buttefly **/ + strDCT2x2dn(p0 + 0, p2 + 0, p1 + 0, p3 + 0); + strDCT2x2dn(p0 + 1, p2 + 1, p1 + 1, p3 + 1); + strDCT2x2dn(p0 + 2, p2 + 2, p1 + 2, p3 + 2); + strDCT2x2dn(p0 + 3, p2 + 3, p1 + 3, p3 + 3); + + /** bottom right corner: -pi/8 rotation => -pi/8 rotation **/ + invOddOddPost(p3 + 0, p3 + 1, p3 + 2, p3 + 3); + + /** anti diagonal corners: rotation by -pi/8 **/ + IROTATE1(p1[2], p1[3]); + IROTATE1(p1[0], p1[1]); + IROTATE1(p2[1], p2[3]); + IROTATE1(p2[0], p2[2]); + + /** butterfly **/ + strHSTdec1_alternate(p0 + 0, p3 + 0); + strHSTdec1_alternate(p0 + 1, p3 + 1); + strHSTdec1_alternate(p0 + 2, p3 + 2); + strHSTdec1_alternate(p0 + 3, p3 + 3); + strHSTdec(p0 + 0, p2 + 0, p1 + 0, p3 + 0); + strHSTdec(p0 + 1, p2 + 1, p1 + 1, p3 + 1); + strHSTdec(p0 + 2, p2 + 2, p1 + 2, p3 + 2); + strHSTdec(p0 + 3, p2 + 3, p1 + 3, p3 + 3); +} + +Void strPost4x4Stage1_alternate(PixelI* p, Int iOffset) +{ + strPost4x4Stage1Split_alternate(p, p + 16, iOffset); +} + +/***************************************************************************************** + Input data offsets: + (15)(14)|(10+32)(11+32) p0 (15)(14)|(42)(43) + (13)(12)|( 8+32)( 9+32) (13)(12)|(40)(41) + --------+-------------- --------+-------- + ( 5)( 4)|( 0+32) (1+32) p1 ( 5)( 4)|(32)(33) + ( 7)( 6)|( 2+32) (3+32) ( 7)( 6)|(34)(35) +*****************************************************************************************/ + +/***************************************************************************************** + Input data offsets: + ( -96)(-32)|(32)( 96) p0 + ( -80)(-16)|(48)(112) + -----------+------------ + (-128)(-64)|( 0)( 64) p1 + (-112)(-48)|(16)( 80) +*****************************************************************************************/ +Void strPost4x4Stage2Split(PixelI* p0, PixelI* p1) +{ + /** buttefly **/ + strDCT2x2dn(p0 - 96, p0 + 96, p1 - 112, p1 + 80); + strDCT2x2dn(p0 - 32, p0 + 32, p1 - 48, p1 + 16); + strDCT2x2dn(p0 - 80, p0 + 112, p1 - 128, p1 + 64); + strDCT2x2dn(p0 - 16, p0 + 48, p1 - 64, p1 + 0); + + /** bottom right corner: -pi/8 rotation => -pi/8 rotation **/ + invOddOddPost(p1 + 0, p1 + 64, p1 + 16, p1 + 80); + + /** anti diagonal corners: rotation by -pi/8 **/ + IROTATE1(p0[ 48], p0[ 32]); + IROTATE1(p0[112], p0[ 96]); + IROTATE1(p1[-64], p1[-128]); + IROTATE1(p1[-48], p1[-112]); + + /** butterfly **/ + strHSTdec1(p0 - 96, p1 + 80); + strHSTdec1(p0 - 32, p1 + 16); + strHSTdec1(p0 - 80, p1 + 64); + strHSTdec1(p0 - 16, p1 + 0); + + strHSTdec(p0 - 96, p1 - 112, p0 + 96, p1 + 80); + strHSTdec(p0 - 32, p1 - 48, p0 + 32, p1 + 16); + strHSTdec(p0 - 80, p1 - 128, p0 + 112, p1 + 64); + strHSTdec(p0 - 16, p1 - 64, p0 + 48, p1 + 0); +} + +Void strPost4x4Stage2Split_alternate(PixelI* p0, PixelI* p1) +{ + /** buttefly **/ + strDCT2x2dn(p0 - 96, p0 + 96, p1 - 112, p1 + 80); + strDCT2x2dn(p0 - 32, p0 + 32, p1 - 48, p1 + 16); + strDCT2x2dn(p0 - 80, p0 + 112, p1 - 128, p1 + 64); + strDCT2x2dn(p0 - 16, p0 + 48, p1 - 64, p1 + 0); + + /** bottom right corner: -pi/8 rotation => -pi/8 rotation **/ + invOddOddPost(p1 + 0, p1 + 64, p1 + 16, p1 + 80); + + /** anti diagonal corners: rotation by -pi/8 **/ + IROTATE1(p0[ 48], p0[ 32]); + IROTATE1(p0[112], p0[ 96]); + IROTATE1(p1[-64], p1[-128]); + IROTATE1(p1[-48], p1[-112]); + + /** butterfly **/ + strHSTdec1_alternate(p0 - 96, p1 + 80); + strHSTdec1_alternate(p0 - 32, p1 + 16); + strHSTdec1_alternate(p0 - 80, p1 + 64); + strHSTdec1_alternate(p0 - 16, p1 + 0); + + strHSTdec(p0 - 96, p1 - 112, p0 + 96, p1 + 80); + strHSTdec(p0 - 32, p1 - 48, p0 + 32, p1 + 16); + strHSTdec(p0 - 80, p1 - 128, p0 + 112, p1 + 64); + strHSTdec(p0 - 16, p1 - 64, p0 + 48, p1 + 0); +} + +/** + Hadamard+Scale transform + for some strange reason, breaking up the function into two blocks, strHSTdec1 and strHSTdec + seems to work faster +**/ +static Void strHSTdec1(PixelI *pa, PixelI *pd) +{ + /** different realization : does rescaling as well! **/ + PixelI a, d; + a = *pa; + d = *pd; + + a += d; + d = (a >> 1) - d; + a += (d * 3 + 0) >> 3; + d += (a * 3 + 0) >> 4; + //a += (d * 3 + 4) >> 3; + + *pa = a; + *pd = d; +} + +static Void strHSTdec1_alternate(PixelI *pa, PixelI *pd) +{ + /** different realization : does rescaling as well! **/ + PixelI a, d; + a = *pa; + d = *pd; + + a += d; + d = (a >> 1) - d; + a += (d * 3 + 0) >> 3; + d += (a * 3 + 0) >> 4; + //a += (d * 3 + 4) >> 3; + + d += (a >> 7); + d -= (a >> 10); + + *pa = a; + *pd = d; +} + +static Void strHSTdec1_edge (PixelI *pa, PixelI *pd) +{ + /** different realization as compared to scaling operator for 2D case **/ + PixelI a, d; + a = *pa; + d = *pd; + + a += d; + d = (a >> 1) - d; + a += (d * 3 + 0) >> 3; + d += (a * 3 + 0) >> 4; + + //Scaling modification of adding 7/1024 in 2 steps (without multiplication by 7). + d += (a >> 7); + d -= (a >> 10); + + a += (d * 3 + 4) >> 3; + d -= (a >> 1); + a += d; + // End new operations + + *pa = a; + *pd = -d; // Negative sign needed here for 1D scaling case to ensure correct scaling. +} + +static Void strHSTdec(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + /** different realization : does rescaling as well! **/ + PixelI a, b, c, d; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + b -= c; + a += (d * 3 + 4) >> 3; + + d -= (b >> 1); + c = ((a - b) >> 1) - c; + *pc = d; + *pd = c; + *pa = a - c, *pb = b + d; +} + +/** Kron(Rotate(pi/8), Rotate(pi/8)) **/ +static Void invOddOdd(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d, t1, t2; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + /** butterflies **/ + d += a; + c -= b; + a -= (t1 = d >> 1); + b += (t2 = c >> 1); + + /** rotate pi/4 **/ + a -= (b * 3 + 3) >> 3; + b += (a * 3 + 3) >> 2; + a -= (b * 3 + 4) >> 3; + + /** butterflies **/ + b -= t2; + a += t1; + c += b; + d -= a; + + /** sign flips **/ + *pa = a; + *pb = -b; + *pc = -c; + *pd = d; +} + +/** Kron(Rotate(pi/8), Rotate(pi/8)) **/ +static Void invOddOddPost(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d, t1, t2; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + /** butterflies **/ + d += a; + c -= b; + a -= (t1 = d >> 1); + b += (t2 = c >> 1); + + /** rotate pi/4 **/ + a -= (b * 3 + 6) >> 3; + b += (a * 3 + 2) >> 2; + a -= (b * 3 + 4) >> 3; + + /** butterflies **/ + b -= t2; + a += t1; + c += b; + d -= a; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + + +/** Kron(Rotate(-pi/8), [1 1; 1 -1]/sqrt(2)) **/ +/** [D C A B] => [a b c d] **/ +Void invOdd(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + /** butterflies **/ + b += d; + a -= c; + d -= (b) >> 1; + c += (a + 1) >> 1; + + /** rotate pi/8 **/ + IROTATE2(a, b); + IROTATE2(c, d); + + /** butterflies **/ + c -= (b + 1) >> 1; + d = ((a + 1) >> 1) - d; + b += c; + a -= d; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +/************************************************************************* + Top-level function to inverse tranform possible part of a macroblock +*************************************************************************/ +Int invTransformMacroblock(CWMImageStrCodec * pSC) +{ + const OVERLAP olOverlap = pSC->WMISCP.olOverlap; + const COLORFORMAT cfColorFormat = pSC->m_param.cfColorFormat; + // const BITDEPTH_BITS bdBitDepth = pSC->WMII.bdBitDepth; + const Bool left = (pSC->cColumn == 0), right = (pSC->cColumn == pSC->cmbWidth); + const Bool top = (pSC->cRow == 0), bottom = (pSC->cRow == pSC->cmbHeight); + const Bool topORbottom = (top || bottom), leftORright = (left || right); + const Bool topORleft = (top || left), bottomORright = (bottom || right); + const size_t mbWidth = pSC->cmbWidth, mbX = pSC->cColumn; + PixelI * p = NULL;// * pt = NULL; + size_t i; + const size_t iChannels = (cfColorFormat == YUV_420 || cfColorFormat == YUV_422) ? 1 : pSC->m_param.cNumChannels; + const size_t tScale = pSC->m_Dparam->cThumbnailScale; + Int j = 0; + + Int qp[MAX_CHANNELS], dcqp[MAX_CHANNELS], iStrength = (1 << pSC->WMII.cPostProcStrength); + // ERR_CODE result = ICERR_OK; + + Bool bHPAbsent = (pSC->WMISCP.sbSubband == SB_NO_HIGHPASS || pSC->WMISCP.sbSubband == SB_DC_ONLY); + + if(pSC->WMII.cPostProcStrength > 0){ + // threshold for post processing + for(i = 0; i < iChannels; i ++){ + qp[i] = pSC->pTile[pSC->cTileColumn].pQuantizerLP[i][pSC->MBInfo.iQIndexLP].iQP * iStrength * (olOverlap == OL_NONE ? 2 : 1); + dcqp[i] = pSC->pTile[pSC->cTileColumn].pQuantizerDC[i][0].iQP * iStrength; + } + + if(left) // a new MB row + slideOneMBRow(pSC->pPostProcInfo, pSC->m_param.cNumChannels, mbWidth, top, bottom); // previous current row becomes previous row + } + + //================================================================ + // 400_Y, 444_YUV + for (i = 0; i < iChannels && tScale < 16; ++i) + { + PixelI* const p0 = pSC->p0MBbuffer[i]; + PixelI* const p1 = pSC->p1MBbuffer[i]; + + Int iHPQP = 255; + if (!bHPAbsent) + iHPQP = pSC->pTile[pSC->cTileColumn].pQuantizerHP[i][pSC->MBInfo.iQIndexHP].iQP; + + //================================ + // second level inverse transform + if (!bottomORright) + { + if(pSC->WMII.cPostProcStrength > 0) + updatePostProcInfo(pSC->pPostProcInfo, p1, mbX, i); // update postproc info before IDCT + + strIDCT4x4Stage2(p1); + if (pSC->m_param.bScaledArith) { + strNormalizeDec(p1, (i != 0)); + } + } + + //================================ + // second level inverse overlap + if (OL_TWO == olOverlap) + { + if (leftORright && (!topORbottom)) + { + j = left ? 0 : -128; + strPost4(p0 + j + 32, p0 + j + 48, p1 + j + 0, p1 + j + 16); + strPost4(p0 + j + 96, p0 + j + 112, p1 + j + 64, p1 + j + 80); + } + + if (!leftORright) + { + if (topORbottom) + { + p = top ? p1 : p0 + 32; + strPost4(p - 128, p - 64, p + 0, p + 64); + strPost4(p - 112, p - 48, p + 16, p + 80); + p = NULL; + } + else + { + strPost4x4Stage2Split(p0, p1); + } + } + } + + if(pSC->WMII.cPostProcStrength > 0) + postProcMB(pSC->pPostProcInfo, p0, p1, mbX, i, dcqp[i]); // second stage deblocking + + //================================ + // first level inverse transform + if(tScale >= 4) // bypass first level transform for 4:1 and smaller thumbnail + continue; + + if (!top) + { + for (j = (left ? 32 : -96); j < (right ? 32 : 160); j += 64) + { + strIDCT4x4Stage1(p0 + j + 0); + strIDCT4x4Stage1(p0 + j + 16); + } + } + + if (!bottom) + { + for (j = (left ? 0 : -128); j < (right ? 0 : 128); j += 64) + { + strIDCT4x4Stage1(p1 + j + 0); + strIDCT4x4Stage1(p1 + j + 16); + } + } + + //================================ + // first level inverse overlap + if (OL_NONE != olOverlap) + { + if (leftORright) + { + j = left ? 0 + 10 : -64 + 14; + if (!top) + { + p = p0 + 16 + j; + strPost4(p + 0, p - 2, p + 6, p + 8); + strPost4(p + 1, p - 1, p + 7, p + 9); + strPost4(p + 16, p + 14, p + 22, p + 24); + strPost4(p + 17, p + 15, p + 23, p + 25); + p = NULL; + } + if (!bottom) + { + p = p1 + j; + strPost4(p + 0, p - 2, p + 6, p + 8); + strPost4(p + 1, p - 1, p + 7, p + 9); + p = NULL; + } + if (!topORbottom) + { + strPost4(p0 + 48 + j + 0, p0 + 48 + j - 2, p1 - 10 + j, p1 - 8 + j); + strPost4(p0 + 48 + j + 1, p0 + 48 + j - 1, p1 - 9 + j, p1 - 7 + j); + } + } + + if (top) + { + for (j = (left ? 0 : -192); j < (right ? -64 : 64); j += 64) + { + p = p1 + j; + strPost4(p + 5, p + 4, p + 64, p + 65); + strPost4(p + 7, p + 6, p + 66, p + 67); + p = NULL; + + strPost4x4Stage1(p1 + j, 0, iHPQP, bHPAbsent); + } + } + else if (bottom) + { + for (j = (left ? 0 : -192); j < (right ? -64 : 64); j += 64) + { + strPost4x4Stage1(p0 + 16 + j, 0, iHPQP, bHPAbsent); + strPost4x4Stage1(p0 + 32 + j, 0, iHPQP, bHPAbsent); + + p = p0 + 48 + j; + strPost4(p + 15, p + 14, p + 74, p + 75); + strPost4(p + 13, p + 12, p + 72, p + 73); + p = NULL; + } + } + else + { + for (j = (left ? 0 : -192); j < (right ? -64 : 64); j += 64) + { + strPost4x4Stage1(p0 + 16 + j, 0, iHPQP, bHPAbsent); + strPost4x4Stage1(p0 + 32 + j, 0, iHPQP, bHPAbsent); + strPost4x4Stage1Split(p0 + 48 + j, p1 + j, 0, iHPQP, bHPAbsent); + strPost4x4Stage1(p1 + j, 0, iHPQP, bHPAbsent); + } + } + } + + if(pSC->WMII.cPostProcStrength > 0 && (!topORleft)) + postProcBlock(pSC->pPostProcInfo, p0, p1, mbX, i, qp[i]); // destairing and first stage deblocking + } + + //================================================================ + // 420_UV + for (i = 0; i < (YUV_420 == cfColorFormat? 2U : 0U) && tScale < 16; ++i) + { + PixelI* const p0 = pSC->p0MBbuffer[1 + i];//(0 == i ? pSC->pU0 : pSC->pV0); + PixelI* const p1 = pSC->p1MBbuffer[1 + i];//(0 == i ? pSC->pU1 : pSC->pV1); + + Int iHPQP = 255; + if (!bHPAbsent) + iHPQP = pSC->pTile[pSC->cTileColumn].pQuantizerHP[i][pSC->MBInfo.iQIndexHP].iQP; + + //======================================== + // second level inverse transform (420_UV) + if (!bottomORright) + { + if (!pSC->m_param.bScaledArith) { + strDCT2x2dn(p1, p1 + 32, p1 + 16, p1 + 48); + } + else { + strDCT2x2dnDec(p1, p1 + 32, p1 + 16, p1 + 48); + } + } + + //======================================== + // second level inverse overlap (420_UV) + if (OL_TWO == olOverlap) + { + if (leftORright && !topORbottom) + { + j = (left ? 0 : -32); + strPost2(p0 + j + 16, p1 + j); + } + + if (!leftORright) + { + if (topORbottom) + { + p = (top ? p1 : p0 + 16); + strPost2(p - 32, p); + p = NULL; + } + else{ + strPost2x2(p0 - 16, p0 + 16, p1 - 32, p1); + } + } + } + + //======================================== + // first level inverse transform (420_UV) + if(tScale >= 4) // bypass first level transform for 4:1 and smaller thumbnail + continue; + + if (!top) + { + for (j = (left ? 16 : -16); j < (right ? 16 : 48); j += 32) + { + strIDCT4x4Stage1(p0 + j); + } + } + + if (!bottom) + { + for (j = (left ? 0 : -32); j < (right ? 0 : 32); j += 32) + { + strIDCT4x4Stage1(p1 + j); + } + } + + //======================================== + // first level inverse overlap (420_UV) + if (OL_NONE != olOverlap) + { + if(!left && !top) + { + if (bottom) + { + for (j = -48; j < (right ? -16 : 16); j += 32) + { + p = p0 + j; + strPost4(p + 15, p + 14, p + 42, p + 43); + strPost4(p + 13, p + 12, p + 40, p + 41); + p = NULL; + } + } + else + { + for (j = -48; j < (right ? -16 : 16); j += 32) + { + strPost4x4Stage1Split(p0 + j, p1 - 16 + j, 32, iHPQP, bHPAbsent); + } + } + + if (right) + { + if (!bottom) + { + strPost4(p0 - 2 , p0 - 4 , p1 - 28, p1 - 26); + strPost4(p0 - 1 , p0 - 3 , p1 - 27, p1 - 25); + } + + strPost4(p0 - 18, p0 - 20, p0 - 12, p0 - 10); + strPost4(p0 - 17, p0 - 19, p0 - 11, p0 - 9); + } + else + { + strPost4x4Stage1(p0 - 32, 32, iHPQP, bHPAbsent); + } + + strPost4x4Stage1(p0 - 64, 32, iHPQP, bHPAbsent); + } + else if (top) + { + for (j = (left ? 0: -64); j < (right ? -32: 0); j += 32) + { + p = p1 + j + 4; + strPost4(p + 1, p + 0, p + 28, p + 29); + strPost4(p + 3, p + 2, p + 30, p + 31); + p = NULL; + } + } + else if (left) + { + if (!bottom) + { + strPost4(p0 + 26, p0 + 24, p1 + 0, p1 + 2); + strPost4(p0 + 27, p0 + 25, p1 + 1, p1 + 3); + } + + strPost4(p0 + 10, p0 + 8, p0 + 16, p0 + 18); + strPost4(p0 + 11, p0 + 9, p0 + 17, p0 + 19); + } + } + } + + //================================================================ + // 422_UV + for (i = 0; i < (YUV_422 == cfColorFormat? 2U : 0U) && tScale < 16; ++i) + { + PixelI* const p0 = pSC->p0MBbuffer[1 + i];//(0 == i ? pSC->pU0 : pSC->pV0); + PixelI* const p1 = pSC->p1MBbuffer[1 + i];//(0 == i ? pSC->pU1 : pSC->pV1); + + Int iHPQP = 255; + if (!bHPAbsent) + iHPQP = pSC->pTile[pSC->cTileColumn].pQuantizerHP[i][pSC->MBInfo.iQIndexHP].iQP; + + //======================================== + // second level inverse transform (422_UV) + if ((!bottomORright) && pSC->m_Dparam->cThumbnailScale < 16) + { + // 1D lossless HT + p1[0] -= ((p1[32] + 1) >> 1); + p1[32] += p1[0]; + + if (!pSC->m_param.bScaledArith) { + strDCT2x2dn(p1 + 0, p1 + 64, p1 + 16, p1 + 80); + strDCT2x2dn(p1 + 32, p1 + 96, p1 + 48, p1 + 112); + } + else { + strDCT2x2dnDec(p1 + 0, p1 + 64, p1 + 16, p1 + 80); + strDCT2x2dnDec(p1 + 32, p1 + 96, p1 + 48, p1 + 112); + } + } + + //======================================== + // second level inverse overlap (422_UV) + if (OL_TWO == olOverlap) + { + if (!bottom) + { + if (leftORright) + { + if (!top) + { + j = (left ? 0 : -64); + strPost2(p0 + 48 + j, p1 + j); + } + + j = (left ? 16 : -48); + strPost2(p1 + j, p1 + j + 16); + } + else + { + if (top) + { + strPost2(p1 - 64, p1); + } + else + { + strPost2x2(p0 - 16, p0 + 48, p1 - 64, p1); + } + + strPost2x2(p1 - 48, p1 + 16, p1 - 32, p1 + 32); + } + } + else if (!leftORright) + { + strPost2(p0 - 16, p0 + 48); + } + } + + //======================================== + // first level inverse transform (422_UV) + if(tScale >= 4) // bypass first level transform for 4:1 and smaller thumbnail + continue; + + if (!top) + { + for (j = (left ? 48 : -16); j < (right ? 48 : 112); j += 64) + { + strIDCT4x4Stage1(p0 + j); + } + } + + if (!bottom) + { + for (j = (left ? 0 : -64); j < (right ? 0 : 64); j += 64) + { + strIDCT4x4Stage1(p1 + j + 0); + strIDCT4x4Stage1(p1 + j + 16); + strIDCT4x4Stage1(p1 + j + 32); + } + } + + //======================================== + // first level inverse overlap (422_UV) + if (OL_NONE != olOverlap) + { + if (!top) + { + if (leftORright) + { + j = (left ? 32 + 10 : -32 + 14); + + p = p0 + j; + strPost4(p + 0, p - 2, p + 6, p + 8); + strPost4(p + 1, p - 1, p + 7, p + 9); + + p = NULL; + } + + for (j = (left ? 0 : -128); j < (right ? -64 : 0); j += 64) + { + strPost4x4Stage1(p0 + j + 32, 0, iHPQP, bHPAbsent); + } + } + + if (!bottom) + { + if (leftORright) + { + j = (left ? 0 + 10 : -64 + 14); + + p = p1 + j; + strPost4(p + 0, p - 2, p + 6, p + 8); + strPost4(p + 1, p - 1, p + 7, p + 9); + + p += 16; + strPost4(p + 0, p - 2, p + 6, p + 8); + strPost4(p + 1, p - 1, p + 7, p + 9); + + p = NULL; + } + + for (j = (left ? 0 : -128); j < (right ? -64 : 0); j += 64) + { + strPost4x4Stage1(p1 + j + 0, 0, iHPQP, bHPAbsent); + strPost4x4Stage1(p1 + j + 16, 0, iHPQP, bHPAbsent); + } + } + + if (topORbottom) + { + p = (top ? p1 + 5 : p0 + 48 + 13); + for (j = (left ? 0 : -128); j < (right ? -64 : 0); j += 64) + { + strPost4(p + j + 0, p + j - 1, p + j + 59, p + j + 60); + strPost4(p + j + 2, p + j + 1, p + j + 61, p + j + 62); + } + p = NULL; + } + else + { + if (leftORright) + { + j = (left ? 0 + 0 : -64 + 4); + strPost4(p0 + j + 48 + 10 + 0, p0 + j + 48 + 10 - 2, p1 + j + 0, p1 + j + 2); + strPost4(p0 + j + 48 + 10 + 1, p0 + j + 48 + 10 - 1, p1 + j + 1, p1 + j + 3); + } + + for (j = (left ? 0 : -128); j < (right ? -64 : 0); j += 64) + { + strPost4x4Stage1Split(p0 + j + 48, p1 + j + 0, 0, iHPQP, bHPAbsent); + } + } + } + } + + return ICERR_OK; +} + +Int invTransformMacroblock_alteredOperators_hard(CWMImageStrCodec * pSC) +{ + const OVERLAP olOverlap = pSC->WMISCP.olOverlap; + const COLORFORMAT cfColorFormat = pSC->m_param.cfColorFormat; + // const BITDEPTH_BITS bdBitDepth = pSC->WMII.bdBitDepth; + const Bool left = (pSC->cColumn == 0), right = (pSC->cColumn == pSC->cmbWidth); + const Bool top = (pSC->cRow == 0), bottom = (pSC->cRow == pSC->cmbHeight); + const Bool topORbottom = (top || bottom), leftORright = (left || right); + const Bool topORleft = (top || left), bottomORright = (bottom || right); + Bool leftAdjacentColumn = (pSC->cColumn == 1), rightAdjacentColumn = (pSC->cColumn == pSC->cmbWidth - 1); + // Bool topAdjacentRow = (pSC->cRow == 1), bottomAdjacentRow = (pSC->cRow == pSC->cmbHeight - 1); + const size_t mbWidth = pSC->cmbWidth; + PixelI * p = NULL;// * pt = NULL; + size_t i; + const size_t iChannels = (cfColorFormat == YUV_420 || cfColorFormat == YUV_422) ? 1 : pSC->m_param.cNumChannels; + const size_t tScale = pSC->m_Dparam->cThumbnailScale; + Int j = 0; + + Int qp[MAX_CHANNELS], dcqp[MAX_CHANNELS], iStrength = (1 << pSC->WMII.cPostProcStrength); + // ERR_CODE result = ICERR_OK; + +#define mbX pSC->mbX +#define mbY pSC->mbY +#define tileX pSC->tileX +#define tileY pSC->tileY +#define bVertTileBoundary pSC->bVertTileBoundary +#define bHoriTileBoundary pSC->bHoriTileBoundary +#define bOneMBLeftVertTB pSC->bOneMBLeftVertTB +#define bOneMBRightVertTB pSC->bOneMBRightVertTB +#define iPredBefore pSC->iPredBefore +#define iPredAfter pSC->iPredAfter + + if (pSC->WMISCP.bUseHardTileBoundaries) { + //Add tile location information + if (pSC->cColumn == 0) { + bVertTileBoundary = FALSE; + tileY = 0; + } + bOneMBLeftVertTB = bOneMBRightVertTB = FALSE; + if(tileY > 0 && tileY <= pSC->WMISCP.cNumOfSliceMinus1H && (pSC->cColumn - 1) == pSC->WMISCP.uiTileY[tileY]) + bOneMBRightVertTB = TRUE; + if(tileY < pSC->WMISCP.cNumOfSliceMinus1H && pSC->cColumn == pSC->WMISCP.uiTileY[tileY + 1]) { + bVertTileBoundary = TRUE; + tileY++; + } + else + bVertTileBoundary = FALSE; + if(tileY < pSC->WMISCP.cNumOfSliceMinus1H && (pSC->cColumn + 1) == pSC->WMISCP.uiTileY[tileY + 1]) + bOneMBLeftVertTB = TRUE; + + if (pSC->cRow == 0) { + bHoriTileBoundary = FALSE; + tileX = 0; + } + else if(mbY != pSC->cRow && tileX < pSC->WMISCP.cNumOfSliceMinus1V && pSC->cRow == pSC->WMISCP.uiTileX[tileX + 1]) { + bHoriTileBoundary = TRUE; + tileX++; + } + else if(mbY != pSC->cRow) + bHoriTileBoundary = FALSE; + } + else { + bVertTileBoundary = FALSE; + bHoriTileBoundary = FALSE; + bOneMBLeftVertTB = FALSE; + bOneMBRightVertTB = FALSE; + } + mbX = pSC->cColumn, mbY = pSC->cRow; + + if(pSC->WMII.cPostProcStrength > 0){ + // threshold for post processing + for(i = 0; i < iChannels; i ++){ + qp[i] = pSC->pTile[pSC->cTileColumn].pQuantizerLP[i][pSC->MBInfo.iQIndexLP].iQP * iStrength * (olOverlap == OL_NONE ? 2 : 1); + dcqp[i] = pSC->pTile[pSC->cTileColumn].pQuantizerDC[i][0].iQP * iStrength; + } + + if(left) // a new MB row + slideOneMBRow(pSC->pPostProcInfo, pSC->m_param.cNumChannels, mbWidth, top, bottom); // previous current row becomes previous row + } + + //================================================================ + // 400_Y, 444_YUV + for (i = 0; i < iChannels && tScale < 16; ++i) + { + PixelI* const p0 = pSC->p0MBbuffer[i]; + PixelI* const p1 = pSC->p1MBbuffer[i]; + + //================================ + // second level inverse transform + if (!bottomORright) + { + if(pSC->WMII.cPostProcStrength > 0) + updatePostProcInfo(pSC->pPostProcInfo, p1, mbX, i); // update postproc info before IDCT + + strIDCT4x4Stage2(p1); + if (pSC->m_param.bScaledArith) { + strNormalizeDec(p1, (i != 0)); + } + } + + //================================ + // second level inverse overlap + if (OL_TWO == olOverlap) + { + /* Corner operations */ + if ((top || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPost4_alternate(p1 + 0, p1 + 64, p1 + 0 + 16, p1 + 64 + 16); + if ((top || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPost4_alternate(p1 - 128, p1 - 64, p1 - 128 + 16, p1 - 64 + 16); + if ((bottom || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPost4_alternate(p0 + 32, p0 + 96, p0 + 32 + 16, p0 + 96 + 16); + if ((bottom || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPost4_alternate(p0 - 96, p0 - 32, p0 - 96 + 16, p0 - 32 + 16); + if ((leftORright || bVertTileBoundary) && (!topORbottom && !bHoriTileBoundary)) + { + if (left || bVertTileBoundary) { + j = 0; + strPost4_alternate(p0 + j + 32, p0 + j + 48, p1 + j + 0, p1 + j + 16); + strPost4_alternate(p0 + j + 96, p0 + j + 112, p1 + j + 64, p1 + j + 80); + } + if (right || bVertTileBoundary) { + j = -128; + strPost4_alternate(p0 + j + 32, p0 + j + 48, p1 + j + 0, p1 + j + 16); + strPost4_alternate(p0 + j + 96, p0 + j + 112, p1 + j + 64, p1 + j + 80); + } + } + + if (!leftORright) + { + if ((topORbottom || bHoriTileBoundary) && !bVertTileBoundary) + { + if (top || bHoriTileBoundary) { + p = p1; + strPost4_alternate(p - 128, p - 64, p + 0, p + 64); + strPost4_alternate(p - 112, p - 48, p + 16, p + 80); + p = NULL; + } + if (bottom || bHoriTileBoundary) { + p = p0 + 32; + strPost4_alternate(p - 128, p - 64, p + 0, p + 64); + strPost4_alternate(p - 112, p - 48, p + 16, p + 80); + p = NULL; + } + } + + if (!topORbottom && !bHoriTileBoundary && !bVertTileBoundary) + strPost4x4Stage2Split_alternate(p0, p1); + } + } + + if(pSC->WMII.cPostProcStrength > 0) + postProcMB(pSC->pPostProcInfo, p0, p1, mbX, i, dcqp[i]); // second stage deblocking + + //================================ + // first level inverse transform + if(tScale >= 4) // bypass first level transform for 4:1 and smaller thumbnail + continue; + + if (!top) + { + for (j = (left ? 32 : -96); j < (right ? 32 : 160); j += 64) + { + strIDCT4x4Stage1(p0 + j + 0); + strIDCT4x4Stage1(p0 + j + 16); + } + } + + if (!bottom) + { + for (j = (left ? 0 : -128); j < (right ? 0 : 128); j += 64) + { +// if(tScale == 2 && bdBitDepth != BD_1){ +// MIPgen(p1 + j + 0); +// MIPgen(p1 + j + 16); +// } + strIDCT4x4Stage1(p1 + j + 0); + strIDCT4x4Stage1(p1 + j + 16); + } + } + + //================================ + // first level inverse overlap + if (OL_NONE != olOverlap) + { + if (leftORright || bVertTileBoundary) + { + /* Corner operations */ + if ((top || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPost4_alternate(p1 + 0, p1 + 1, p1 + 2, p1 + 3); + if ((top || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPost4_alternate(p1 - 59, p1 - 60, p1 - 57, p1 - 58); + if ((bottom || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPost4_alternate(p0 + 48 + 10, p0 + 48 + 11, p0 + 48 + 8, p0 + 48 + 9); + if ((bottom || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPost4_alternate(p0 - 1, p0 - 2, p0 - 3, p0 - 4); + if (left || bVertTileBoundary) { + j = 0 + 10; + if (!top) + { + p = p0 + 16 + j; + strPost4_alternate(p + 0, p - 2, p + 6, p + 8); + strPost4_alternate(p + 1, p - 1, p + 7, p + 9); + strPost4_alternate(p + 16, p + 14, p + 22, p + 24); + strPost4_alternate(p + 17, p + 15, p + 23, p + 25); + p = NULL; + } + if (!bottom) + { + p = p1 + j; + strPost4_alternate(p + 0, p - 2, p + 6, p + 8); + strPost4_alternate(p + 1, p - 1, p + 7, p + 9); + p = NULL; + } + if (!topORbottom && !bHoriTileBoundary) + { + strPost4_alternate(p0 + 48 + j + 0, p0 + 48 + j - 2, p1 - 10 + j, p1 - 8 + j); + strPost4_alternate(p0 + 48 + j + 1, p0 + 48 + j - 1, p1 - 9 + j, p1 - 7 + j); + } + } + if (right || bVertTileBoundary) { + j = -64 + 14; + if (!top) + { + p = p0 + 16 + j; + strPost4_alternate(p + 0, p - 2, p + 6, p + 8); + strPost4_alternate(p + 1, p - 1, p + 7, p + 9); + strPost4_alternate(p + 16, p + 14, p + 22, p + 24); + strPost4_alternate(p + 17, p + 15, p + 23, p + 25); + p = NULL; + } + if (!bottom) + { + p = p1 + j; + strPost4_alternate(p + 0, p - 2, p + 6, p + 8); + strPost4_alternate(p + 1, p - 1, p + 7, p + 9); + p = NULL; + } + if (!topORbottom && !bHoriTileBoundary) + { + strPost4_alternate(p0 + 48 + j + 0, p0 + 48 + j - 2, p1 - 10 + j, p1 - 8 + j); + strPost4_alternate(p0 + 48 + j + 1, p0 + 48 + j - 1, p1 - 9 + j, p1 - 7 + j); + } + } + } + + if (top || bHoriTileBoundary) + { + for (j = (left ? 0 : -192); j < (right ? -64 : 64); j += 64) + { + if (!bVertTileBoundary || j != -64) { + p = p1 + j; + strPost4_alternate(p + 5, p + 4, p + 64, p + 65); + strPost4_alternate(p + 7, p + 6, p + 66, p + 67); + p = NULL; + + strPost4x4Stage1_alternate(p1 + j, 0); + } + } + } + + if (bottom || bHoriTileBoundary) + { + for (j = (left ? 0 : -192); j < (right ? -64 : 64); j += 64) + { + if (!bVertTileBoundary || j != -64) { + strPost4x4Stage1_alternate(p0 + 16 + j, 0); + strPost4x4Stage1_alternate(p0 + 32 + j, 0); + + p = p0 + 48 + j; + strPost4_alternate(p + 15, p + 14, p + 74, p + 75); + strPost4_alternate(p + 13, p + 12, p + 72, p + 73); + p = NULL; + } + } + } + + if (!top && !bottom && !bHoriTileBoundary) + { + for (j = (left ? 0 : -192); j < (right ? -64 : 64); j += 64) + { + if (!bVertTileBoundary || j != -64) { + strPost4x4Stage1_alternate(p0 + 16 + j, 0); + strPost4x4Stage1_alternate(p0 + 32 + j, 0); + strPost4x4Stage1Split_alternate(p0 + 48 + j, p1 + j, 0); + strPost4x4Stage1_alternate(p1 + j, 0); + } + } + } + } + + if(pSC->WMII.cPostProcStrength > 0 && (!topORleft)) + postProcBlock(pSC->pPostProcInfo, p0, p1, mbX, i, qp[i]); // destairing and first stage deblocking + } + + //================================================================ + // 420_UV + for (i = 0; i < (YUV_420 == cfColorFormat? 2U : 0U) && tScale < 16; ++i) + { + PixelI* const p0 = pSC->p0MBbuffer[1 + i];//(0 == i ? pSC->pU0 : pSC->pV0); + PixelI* const p1 = pSC->p1MBbuffer[1 + i];//(0 == i ? pSC->pU1 : pSC->pV1); + + //======================================== + // second level inverse transform (420_UV) + if (!bottomORright) + { + if (!pSC->m_param.bScaledArith) { + strDCT2x2dn(p1, p1 + 32, p1 + 16, p1 + 48); + } + else { + strDCT2x2dnDec(p1, p1 + 32, p1 + 16, p1 + 48); + } + } + + //======================================== + // second level inverse overlap (420_UV) + if (OL_TWO == olOverlap) + { + if ((leftAdjacentColumn || bOneMBRightVertTB) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p1 - 64 + 0, *(p1 - 64 + 32)); + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (top || bHoriTileBoundary)) + iPredBefore[i][0] = *(p1 + 0); + if ((right || bVertTileBoundary) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p1 - 64 + 32, iPredBefore[i][0]); + if ((leftAdjacentColumn || bOneMBRightVertTB) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p0 - 64 + 16, *(p0 - 64 + 48)); + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (bottom || bHoriTileBoundary)) + iPredBefore[i][1] = *(p0 + 16); + if ((right || bVertTileBoundary) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p0 - 64 + 48, iPredBefore[i][1]); + + if ((leftORright || bVertTileBoundary) && !topORbottom && !bHoriTileBoundary) + { + if (left || bVertTileBoundary) + strPost2_alternate(p0 + 0 + 16, p1 + 0); + if (right || bVertTileBoundary) + strPost2_alternate(p0 + -32 + 16, p1 + -32); + } + + if (!leftORright) + { + if ((topORbottom || bHoriTileBoundary) && !bVertTileBoundary) + { + if (top || bHoriTileBoundary) + strPost2_alternate(p1 - 32, p1); + if (bottom || bHoriTileBoundary) + strPost2_alternate(p0 + 16 - 32, p0 + 16); + } + else if (!topORbottom && !bHoriTileBoundary && !bVertTileBoundary) { + strPost2x2_alternate(p0 - 16, p0 + 16, p1 - 32, p1); + } + } + if ((leftAdjacentColumn || bOneMBRightVertTB) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p1 - 64 + 0, *(p1 - 64 + 32)); + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (top || bHoriTileBoundary)) + iPredAfter[i][0] = *(p1 + 0); + if ((right || bVertTileBoundary) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p1 - 64 + 32, iPredAfter[i][0]); + if ((leftAdjacentColumn || bOneMBRightVertTB) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p0 - 64 + 16, *(p0 - 64 + 48)); + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (bottom || bHoriTileBoundary)) + iPredAfter[i][1] = *(p0 + 16); + if ((right || bVertTileBoundary) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p0 - 64 + 48, iPredAfter[i][1]); + } + + //======================================== + // first level inverse transform (420_UV) + if(tScale >= 4) // bypass first level transform for 4:1 and smaller thumbnail + continue; + + if (!top) + { + // In order to allow correction operation of corner chroma overlap operators (fixed) + // processing of left most MB column must be delayed by one MB + // Thus left MB not processed until leftAdjacentColumn = 1 + for (j = ((left) ? 48 : ((leftAdjacentColumn || bOneMBRightVertTB) ? -48 : -16)); j < ((right || bVertTileBoundary) ? 16 : 48); j += 32) + { + strIDCT4x4Stage1(p0 + j); + } + } + + if (!bottom) + { + // In order to allow correction operation of corner chroma overlap operators (fixed) + // processing of left most MB column must be delayed by one MB + // Thus left MB not processed until leftAdjacentColumn = 1 + for (j = ((left) ? 32 : ((leftAdjacentColumn || bOneMBRightVertTB) ? -64 : -32)); j < ((right || bVertTileBoundary) ? 0 : 32); j += 32) + { + strIDCT4x4Stage1(p1 + j); + } + } + + //======================================== + // first level inverse overlap (420_UV) + if (OL_NONE != olOverlap) + { + /* Corner operations */ + /* Change because the top-left corner ICT will not have happened until leftAdjacentColumn ==1 */ + if ((top || bHoriTileBoundary) && (leftAdjacentColumn || bOneMBRightVertTB)) + strPost4_alternate(p1 - 64 + 0, p1 - 64 + 1, p1 - 64 + 2, p1 - 64 + 3); + if ((top || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPost4_alternate(p1 - 27, p1 - 28, p1 - 25, p1 - 26); + /* Change because the bottom-left corner ICT will not have happened until leftAdjacentColumn ==1 */ + if ((bottom || bHoriTileBoundary) && (leftAdjacentColumn || bOneMBRightVertTB)) + strPost4_alternate(p0 - 64 + 16 + 10, p0 - 64 + 16 + 11, p0 - 64 + 16 + 8, p0 - 64 + 16 + 9); + if ((bottom || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPost4_alternate(p0 - 1, p0 - 2, p0 - 3, p0 - 4); + if(!left && !top) + { + /* Change because the vertical 1-D overlap operations of the left edge pixels cannot be performed until leftAdjacentColumn ==1 */ + if (leftAdjacentColumn || bOneMBRightVertTB) + { + if (!bottom && !bHoriTileBoundary) + { + strPost4_alternate(p0 - 64 + 26, p0 - 64 + 24, p1 - 64 + 0, p1 - 64 + 2); + strPost4_alternate(p0 - 64 + 27, p0 - 64 + 25, p1 - 64 + 1, p1 - 64 + 3); + } + + strPost4_alternate(p0 - 64 + 10, p0 - 64 + 8, p0 - 64 + 16, p0 - 64 + 18); + strPost4_alternate(p0 - 64 + 11, p0 - 64 + 9, p0 - 64 + 17, p0 - 64 + 19); + } + if (bottom || bHoriTileBoundary) + { + p = p0 + -48; + strPost4_alternate(p + 15, p + 14, p + 42, p + 43); + strPost4_alternate(p + 13, p + 12, p + 40, p + 41); + p = NULL; + + if (!right && !bVertTileBoundary) + { + p = p0 + -16; + strPost4_alternate(p + 15, p + 14, p + 42, p + 43); + strPost4_alternate(p + 13, p + 12, p + 40, p + 41); + p = NULL; + } + } + else + { + strPost4x4Stage1Split_alternate(p0 + -48, p1 - 16 + -48, 32); + + if (!right && !bVertTileBoundary) + strPost4x4Stage1Split_alternate(p0 + -16, p1 - 16 + -16, 32); + } + + if (right || bVertTileBoundary) + { + if (!bottom && !bHoriTileBoundary) + { + strPost4_alternate(p0 - 2 , p0 - 4 , p1 - 28, p1 - 26); + strPost4_alternate(p0 - 1 , p0 - 3 , p1 - 27, p1 - 25); + } + + strPost4_alternate(p0 - 18, p0 - 20, p0 - 12, p0 - 10); + strPost4_alternate(p0 - 17, p0 - 19, p0 - 11, p0 - 9); + } + else + { + strPost4x4Stage1_alternate(p0 - 32, 32); + } + + strPost4x4Stage1_alternate(p0 - 64, 32); + } + + if (top || bHoriTileBoundary) + { + if (!left) + { + p = p1 + -64 + 4; + strPost4_alternate(p + 1, p + 0, p + 28, p + 29); + strPost4_alternate(p + 3, p + 2, p + 30, p + 31); + p = NULL; + } + + if (!left && !right && !bVertTileBoundary) + { + p = p1 + -32 + 4; + strPost4_alternate(p + 1, p + 0, p + 28, p + 29); + strPost4_alternate(p + 3, p + 2, p + 30, p + 31); + p = NULL; + } + } + } + } + + //================================================================ + // 422_UV + for (i = 0; i < (YUV_422 == cfColorFormat? 2U : 0U) && tScale < 16; ++i) + { + PixelI* const p0 = pSC->p0MBbuffer[1 + i];//(0 == i ? pSC->pU0 : pSC->pV0); + PixelI* const p1 = pSC->p1MBbuffer[1 + i];//(0 == i ? pSC->pU1 : pSC->pV1); + + //======================================== + // second level inverse transform (422_UV) + if ((!bottomORright) && pSC->m_Dparam->cThumbnailScale < 16) + { + // 1D lossless HT + p1[0] -= ((p1[32] + 1) >> 1); + p1[32] += p1[0]; + + if (!pSC->m_param.bScaledArith) { + strDCT2x2dn(p1 + 0, p1 + 64, p1 + 16, p1 + 80); + strDCT2x2dn(p1 + 32, p1 + 96, p1 + 48, p1 + 112); + } + else { + strDCT2x2dnDec(p1 + 0, p1 + 64, p1 + 16, p1 + 80); + strDCT2x2dnDec(p1 + 32, p1 + 96, p1 + 48, p1 + 112); + } + } + + //======================================== + // second level inverse overlap (422_UV) + if (OL_TWO == olOverlap) + { + if ((leftAdjacentColumn || bOneMBRightVertTB) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p1 - 128 + 0, *(p1 - 128 + 64)); + + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (top || bHoriTileBoundary)) + iPredBefore[i][0] = *(p1 + 0); + if ((right || bVertTileBoundary) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p1 - 128 + 64, iPredBefore[i][0]); + + if ((leftAdjacentColumn || bOneMBRightVertTB) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p0 - 128 + 48, *(p0 - 128 + 112)); + + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (bottom || bHoriTileBoundary)) + iPredBefore[i][1] = *(p0 + 48); + if ((right || bVertTileBoundary) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p0 - 128 + 112, iPredBefore[i][1]); + + if (!bottom) + { + if (leftORright || bVertTileBoundary) + { + if (!top && !bHoriTileBoundary) + { + if (left || bVertTileBoundary) + strPost2_alternate(p0 + 48 + 0, p1 + 0); + + if (right || bVertTileBoundary) + strPost2_alternate(p0 + 48 + -64, p1 + -64); + } + + if (left || bVertTileBoundary) + strPost2_alternate(p1 + 16, p1 + 16 + 16); + + if (right || bVertTileBoundary) + strPost2_alternate(p1 + -48, p1 + -48 + 16); + } + + if (!leftORright && !bVertTileBoundary) + { + if (top || bHoriTileBoundary) + strPost2_alternate(p1 - 64, p1); + else + strPost2x2_alternate(p0 - 16, p0 + 48, p1 - 64, p1); + + strPost2x2_alternate(p1 - 48, p1 + 16, p1 - 32, p1 + 32); + } + } + + if ((bottom || bHoriTileBoundary) && (!leftORright && !bVertTileBoundary)) + strPost2_alternate(p0 - 16, p0 + 48); + + if ((leftAdjacentColumn || bOneMBRightVertTB) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p1 - 128 + 0, *(p1 - 128 + 64)); + + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (top || bHoriTileBoundary)) + iPredAfter[i][0] = *(p1 + 0); + if ((right || bVertTileBoundary) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p1 - 128 + 64, iPredAfter[i][0]); + + if ((leftAdjacentColumn || bOneMBRightVertTB) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p0 - 128 + 48, *(p0 - 128 + 112)); + + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (bottom || bHoriTileBoundary)) + iPredAfter[i][1] = *(p0 + 48); + if ((right || bVertTileBoundary) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p0 - 128 + 112, iPredAfter[i][1]); + } + + //======================================== + // first level inverse transform (422_UV) + if(tScale >= 4) // bypass first level transform for 4:1 and smaller thumbnail + continue; + + if (!top) + { + // Need to delay processing of left column until leftAdjacentColumn = 1 for corner overlap operators + // Since 422 has no vertical downsampling, no top MB delay of processing is necessary + for (j = (left ? 112 : ((leftAdjacentColumn || bOneMBRightVertTB) ? -80 : -16)); j < ((right || bVertTileBoundary) ? 48 : 112); j += 64) + { + strIDCT4x4Stage1(p0 + j); + } + } + + if (!bottom) + { + // Need to delay processing of left column until leftAdjacentColumn = 1 for corner overlap operators + // Since 422 has no vertical downsampling, no top MB delay of processing is necessary + for (j = (left ? 64 : ((leftAdjacentColumn || bOneMBRightVertTB) ? -128 : -64)); j < ((right || bVertTileBoundary) ? 0 : 64); j += 64) + { + strIDCT4x4Stage1(p1 + j + 0); + strIDCT4x4Stage1(p1 + j + 16); + strIDCT4x4Stage1(p1 + j + 32); + } + } + + //======================================== + // first level inverse overlap (422_UV) + if (OL_NONE != olOverlap) + { + /* Corner operations */ + if ((top || bHoriTileBoundary) && (leftAdjacentColumn || bOneMBRightVertTB)) + strPost4_alternate(p1 - 128 + 0, p1 - 128 + 1, p1 - 128 + 2, p1 - 128 + 3); + if ((top || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPost4_alternate(p1 - 59, p1 - 60, p1 - 57, p1 - 58); + if ((bottom || bHoriTileBoundary) && (leftAdjacentColumn || bOneMBRightVertTB)) + strPost4_alternate(p0 - 128 + 48 + 10, p0 - 128 + 48 + 11, p0 - 128 + 48 + 8, p0 - 128 + 48 + 9); + if ((bottom || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPost4_alternate(p0 - 1, p0 - 2, p0 - 3, p0 - 4); + if (!top) + { + // Need to delay processing of left column until leftAdjacentColumn = 1 for corner overlap operators + if (leftAdjacentColumn || bOneMBRightVertTB) { + p = p0 + 32 + 10 - 128; + strPost4_alternate(p + 0, p - 2, p + 6, p + 8); + strPost4_alternate(p + 1, p - 1, p + 7, p + 9); + p = NULL; + } + + if (right || bVertTileBoundary) { + p = p0 + -32 + 14; + strPost4_alternate(p + 0, p - 2, p + 6, p + 8); + strPost4_alternate(p + 1, p - 1, p + 7, p + 9); + p = NULL; + } + + for (j = (left ? 0 : -128); j < ((right || bVertTileBoundary) ? -64 : 0); j += 64) + strPost4x4Stage1_alternate(p0 + j + 32, 0); + } + + if (!bottom) + { + // Need to delay processing of left column until leftAdjacentColumn = 1 for corner overlap operators + if (leftAdjacentColumn || bOneMBRightVertTB) + { + p = p1 + 0 + 10 - 128; + strPost4_alternate(p + 0, p - 2, p + 6, p + 8); + strPost4_alternate(p + 1, p - 1, p + 7, p + 9); + p += 16; + strPost4_alternate(p + 0, p - 2, p + 6, p + 8); + strPost4_alternate(p + 1, p - 1, p + 7, p + 9); + p = NULL; + } + + if (right || bVertTileBoundary) + { + p = p1 + -64 + 14; + strPost4_alternate(p + 0, p - 2, p + 6, p + 8); + strPost4_alternate(p + 1, p - 1, p + 7, p + 9); + p += 16; + strPost4_alternate(p + 0, p - 2, p + 6, p + 8); + strPost4_alternate(p + 1, p - 1, p + 7, p + 9); + p = NULL; + } + + for (j = (left ? 0 : -128); j < ((right || bVertTileBoundary) ? -64 : 0); j += 64) + { + strPost4x4Stage1_alternate(p1 + j + 0, 0); + strPost4x4Stage1_alternate(p1 + j + 16, 0); + } + } + + if (topORbottom || bHoriTileBoundary) + { + if (top || bHoriTileBoundary) { + p = p1 + 5; + for (j = (left ? 0 : -128); j < ((right || bVertTileBoundary) ? -64 : 0); j += 64) + { + strPost4_alternate(p + j + 0, p + j - 1, p + j + 59, p + j + 60); + strPost4_alternate(p + j + 2, p + j + 1, p + j + 61, p + j + 62); + } + p = NULL; + } + + if (bottom || bHoriTileBoundary) { + p = p0 + 48 + 13; + for (j = (left ? 0 : -128); j < ((right || bVertTileBoundary) ? -64 : 0); j += 64) + { + strPost4_alternate(p + j + 0, p + j - 1, p + j + 59, p + j + 60); + strPost4_alternate(p + j + 2, p + j + 1, p + j + 61, p + j + 62); + } + p = NULL; + } + } + else + { + // Need to delay processing of left column until leftAdjacentColumn = 1 for corner overlap operators + if (leftAdjacentColumn || bOneMBRightVertTB) + { + j = 0 + 0 - 128; + strPost4_alternate(p0 + j + 48 + 10 + 0, p0 + j + 48 + 10 - 2, p1 + j + 0, p1 + j + 2); + strPost4_alternate(p0 + j + 48 + 10 + 1, p0 + j + 48 + 10 - 1, p1 + j + 1, p1 + j + 3); + } + + if (right || bVertTileBoundary) + { + j = -64 + 4; + strPost4_alternate(p0 + j + 48 + 10 + 0, p0 + j + 48 + 10 - 2, p1 + j + 0, p1 + j + 2); + strPost4_alternate(p0 + j + 48 + 10 + 1, p0 + j + 48 + 10 - 1, p1 + j + 1, p1 + j + 3); + } + + for (j = (left ? 0 : -128); j < ((right || bVertTileBoundary) ? -64 : 0); j += 64) + strPost4x4Stage1Split_alternate(p0 + j + 48, p1 + j + 0, 0); + } + } + } + + return ICERR_OK; +} diff --git a/libs/jxr/image/decode/strPredQuantDec.c b/libs/jxr/image/decode/strPredQuantDec.c new file mode 100644 index 00000000000..74aca93f312 --- /dev/null +++ b/libs/jxr/image/decode/strPredQuantDec.c @@ -0,0 +1,539 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strcodec.h" + +#define DEQUANT(iRaw, iQP) ((iRaw) * (iQP)) + +Void dequantizeBlock4x4(PixelI * pRec, Int * pOrg, const Int * pIndex, Int iQPLP) +{ + Int i; + + for(i = 1; i < 16; i ++) + pRec[pIndex[i]] = DEQUANT(pOrg[i], iQPLP); +} + +Void dequantizeBlock2x2(PixelI * pRec, Int * pOrg, Int iQPLP) +{ + pRec[32] = DEQUANT(pOrg[1], iQPLP); + pRec[16] = DEQUANT(pOrg[2], iQPLP); + pRec[48] = DEQUANT(pOrg[3], iQPLP); +} + +Void dequantizeBlock4x2(PixelI * pRec, Int * pOrg, Int iQPLP) +{ + pRec[ 64] = DEQUANT(pOrg[1], iQPLP); + pRec[ 16] = DEQUANT(pOrg[2], iQPLP); + pRec[ 80] = DEQUANT(pOrg[3], iQPLP); + pRec[ 32] = DEQUANT(pOrg[4], iQPLP); + pRec[ 96] = DEQUANT(pOrg[5], iQPLP); + pRec[ 48] = DEQUANT(pOrg[6], iQPLP); + pRec[112] = DEQUANT(pOrg[7], iQPLP); +} + + +Int dequantizeMacroblock(CWMImageStrCodec * pSC) +{ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + CWMIMBInfo *pMBInfo = &pSC->MBInfo; + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + const size_t iChannels = pSC->m_param.cNumChannels; + size_t i; + + for(i = 0; i < iChannels; i ++){ + //dequantize DC + pSC->p1MBbuffer[i][0] = DEQUANT(pMBInfo->iBlockDC[i][0], pTile->pQuantizerDC[i]->iQP); + + // dequantize LP + if(pSC->WMISCP.sbSubband != SB_DC_ONLY) + if(i == 0 || (cf != YUV_422 && cf != YUV_420)) + dequantizeBlock4x4(pSC->p1MBbuffer[i] , pMBInfo->iBlockDC[i], dctIndex[2], pTile->pQuantizerLP[i][pMBInfo->iQIndexLP].iQP); + else if(cf == YUV_422) + dequantizeBlock4x2(pSC->p1MBbuffer[i], pMBInfo->iBlockDC[i], pTile->pQuantizerLP[i][pMBInfo->iQIndexLP].iQP); + else // 420 + dequantizeBlock2x2(pSC->p1MBbuffer[i], pMBInfo->iBlockDC[i], pTile->pQuantizerLP[i][pMBInfo->iQIndexLP].iQP); + } + + return ICERR_OK; +} + +/* frequency domain inverse DCAC prediction */ +Void predDCACDec(CWMImageStrCodec * pSC) +{ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannels = (cf == YUV_420 || cf == YUV_422) ? 1 : (Int) pSC->m_param.cNumChannels; + CWMIMBInfo *pMBInfo = &(pSC->MBInfo); + size_t mbX = pSC->cColumn;// mbY = pSC->cRow; + Int iDCACPredMode = getDCACPredMode(pSC, mbX); + Int iDCPredMode = (iDCACPredMode & 0x3); + Int iADPredMode = (iDCACPredMode & 0xC); + PixelI * pOrg, * pRef; + Int ii; + + for(ii = 0; ii < iChannels; ii ++){ + pOrg = pMBInfo->iBlockDC[ii];//[dcBlkIdx + (i >> 4)]; // current DC block + + /* DC prediction */ + if(iDCPredMode == 1){ // predict DC from top + pOrg[0] += pSC->PredInfoPrevRow[ii][mbX].iDC; + } + else if(iDCPredMode == 0){ // predict DC from left + pOrg[0] += (pSC->PredInfo[ii] + mbX - 1)->iDC; + } + else if(iDCPredMode == 2){// predict DC from top&left + pOrg[0] += ((pSC->PredInfo[ii] + mbX - 1)->iDC + (pSC->PredInfoPrevRow[ii] + mbX)->iDC) >> 1; + } + + /* AD prediction */ + if(iADPredMode == 4){// predict AD from top + pRef = (pSC->PredInfoPrevRow[ii] + mbX)->piAD; + pOrg[4] += pRef[3], pOrg[8] += pRef[4], pOrg[12] += pRef[5]; + } + else if(iADPredMode == 0){// predict AD from left + pRef = (pSC->PredInfo[ii] + mbX - 1)->piAD; + pOrg[1] += pRef[0], pOrg[2] += pRef[1], pOrg[3] += pRef[2]; + } + } + + if(cf == YUV_420){ + for(ii = 1; ii < 3; ii ++){ + pOrg = pMBInfo->iBlockDC[ii];//dcBlkIdx + ii]; // current DC block + + /* DC prediction */ + if(iDCPredMode == 1){ // predict DC from top + pOrg[0] += (pSC->PredInfoPrevRow[ii] + mbX)->iDC; + } + else if(iDCPredMode == 0){ // predict DC from left + pOrg[0] += (pSC->PredInfo[ii] + mbX - 1)->iDC; + } + else if(iDCPredMode == 2){ // predict DC from top&left + pOrg[0] += (((pSC->PredInfo[ii] + mbX - 1)->iDC + (pSC->PredInfoPrevRow[ii] + mbX)->iDC + 1) >> 1); + } + + /* AD prediciton */ + if(iADPredMode == 4){// predict AD from top + pOrg[2] += (pSC->PredInfoPrevRow[ii] + mbX)->piAD[1]; + } + else if(iADPredMode == 0){// predict AD from left + pOrg[1] += (pSC->PredInfo[ii] + mbX - 1)->piAD[0]; + } + } + } + else if(cf == YUV_422){ + for(ii = 1; ii < 3; ii ++){ + pOrg = pMBInfo->iBlockDC[ii];//[dcBlkIdx + ii]; // current DC block + + /* DC prediciton */ + if(iDCPredMode == 1){ // predict DC from top + pOrg[0] += (pSC->PredInfoPrevRow[ii] + mbX)->iDC; + } + else if(iDCPredMode == 0){ // predict DC from left + pOrg[0] += (pSC->PredInfo[ii] + mbX - 1)->iDC; + } + else if(iDCPredMode == 2){ // predict DC from top&left + pOrg[0] += (((pSC->PredInfo[ii] + mbX - 1)->iDC + (pSC->PredInfoPrevRow[ii] + mbX)->iDC + 1) >> 1); + } + + /* AD prediction */ + if(iADPredMode == 4){// predict AD from top + pOrg[4] += (pSC->PredInfoPrevRow[ii] + mbX)->piAD[4]; // AC of HT !!! + pOrg[2] += (pSC->PredInfoPrevRow[ii] + mbX)->piAD[3]; + pOrg[6] += pOrg[2]; + } + else if(iADPredMode == 0){// predict AD from left + pOrg[4] += (pSC->PredInfo[ii] + mbX - 1)->piAD[4]; // AC of HT !!! + pOrg[1] += (pSC->PredInfo[ii] + mbX - 1)->piAD[0]; + pOrg[5] += (pSC->PredInfo[ii] + mbX - 1)->piAD[2]; + } + else if(iDCPredMode == 1){ + pOrg[6] += pOrg[2]; + } + } + } + + pMBInfo->iOrientation = 2 - getACPredMode(pMBInfo, cf); +} + +/************************************************************************* + Frequency domain inverse AC prediction +*************************************************************************/ +Void predACDec(CWMImageStrCodec * pSC) +{ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannels = (cf == YUV_420 || cf == YUV_422) ? 1 : (Int) pSC->m_param.cNumChannels; + // size_t mbX = pSC->cColumn, mbY = pSC->cRow; + CWMIMBInfo *pMBInfo = &pSC->MBInfo; + Int iACPredMode = 2 - pMBInfo->iOrientation; + PixelI * pOrg, * pRef; + Int i, j; + + /* AC prediction */ + for(i = 0; i < iChannels; i++){ + // prediction only happens inside MB + PixelI* pSrc = pSC->p1MBbuffer[i];//0 == i ? pSC->pY1 : (1 == i ? pSC->pU1 : pSC->pV1); + + switch (iACPredMode) + { + case 1: + { + // predict from top + static U8 blkIdx[] = {1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15}; + + for (j = 0; j < sizeof(blkIdx) / sizeof(*blkIdx); ++j) + { + pOrg = pSrc + 16 * blkIdx[j]; + pRef = pOrg - 16; + + pOrg[ 2] += pRef[ 2]; + pOrg[10] += pRef[10]; + pOrg[ 9] += pRef[ 9]; + } + break; + } + + case 0: + // predict from left + for (j = 64; j < 256; j += 16) + { + pOrg = pSrc + j; + pRef = pOrg - 64; + + pOrg[1] += pRef[1]; + pOrg[5] += pRef[5]; + pOrg[6] += pRef[6]; + } + break; + + default: + // no prediction + break; + } + } + + if(cf == YUV_420){ + for(i = 16; i <= 20; i += 4){ + PixelI* pSrc = pSC->p1MBbuffer[(i >> 2) - 3];//16 == i ? pSC->pU1 : pSC->pV1; + + switch (iACPredMode) + { + case 1: + { + // predict from top + for (j = 1; j <= 3; j += 2) + { + pOrg = pSrc + 16 * j; + pRef = pOrg - 16; + + pOrg[ 2] += pRef[ 2]; + pOrg[10] += pRef[10]; + pOrg[ 9] += pRef[ 9]; + } + break; + } + + case 0: + // predict from left + for (j = 2; j <= 3; ++j) + { + pOrg = pSrc + 16 * j; + pRef = pOrg - 32; + + pOrg[1] += pRef[1]; + pOrg[5] += pRef[5]; + pOrg[6] += pRef[6]; + } + break; + + default: + // no prediction + break; + } + } + } + else if(cf == YUV_422){ + for(i = 16; i < 32; i += 8){ + PixelI* pSrc = pSC->p1MBbuffer[(i >> 3) - 1];//16 == i ? pSC->pU1 : pSC->pV1; + + switch (iACPredMode) + { + case 1: + { + // predict from top + for (j = 2; j < 8; j ++) + { + pOrg = pSrc + blkOffsetUV_422[j]; + pRef = pOrg - 16; + + pOrg[10] += pRef[10]; + pOrg[ 2] += pRef[ 2]; + pOrg[ 9] += pRef[ 9]; + } + break; + } + + case 0: + // predict from left + for (j = 1; j < 8; j += 2) + { + pOrg = pSrc + blkOffsetUV_422[j]; + pRef = pOrg - 64; + + pOrg[1] += pRef[1]; + pOrg[5] += pRef[5]; + pOrg[6] += pRef[6]; + } + break; + + default: + // no prediction + break; + } + } + } +} + +/************************************************************************* + CBP +*************************************************************************/ +static int NumOnes(int i) +{ + int retval = 0; + static const int g_Count[] = { 0,1,1,2, 1,2,2,3, 1,2,2,3, 2,3,3,4 }; + i = i & 0xffff; + while (i) { + retval += g_Count[i & 0xf]; + i >>= 4; + } + return retval; +} + +#define SATURATE32(x) if((unsigned int)(x + 16) >= 32) { if (x < 0) x = -16; else x = 15; } + +/* CBP prediction for 16 x 16 MB */ +/* block index */ +/* 0 1 4 5 */ +/* 2 3 6 7 */ +/* 8 9 12 13 */ +/* 10 11 14 15 */ +static Int predCBPCDec(CWMImageStrCodec * pSC, Int iCBP, size_t mbX, size_t mbY, size_t c, CCBPModel *pModel) +{ + Int iNOrig; + const int iNDiff = AVG_NDIFF; + size_t c1 = c ? 1 : 0; + + UNREFERENCED_PARAMETER( mbY ); + + if (pModel->m_iState[c1] == 0) { + if(pSC->m_bCtxLeft) { + if (pSC->m_bCtxTop) { + iCBP ^= 1; + } + else { + Int iTopCBP = (pSC->PredInfoPrevRow[c] + mbX)->iCBP; + iCBP ^= (iTopCBP >> 10) & 1; // left: top(10) => 0 + } + } + else { + Int iLeftCBP = (pSC->PredInfo[c] + mbX - 1)->iCBP; + iCBP ^= ((iLeftCBP >> 5) & 1); // left(5) => 0 + } + + iCBP ^= (0x02 & (iCBP << 1)); // 0 => 1 + iCBP ^= (0x10 & (iCBP << 3)); // 1 => 4 + iCBP ^= (0x20 & (iCBP << 1)); // 4 => 5 + + iCBP ^= ((iCBP & 0x33) << 2); + iCBP ^= ((iCBP & 0xcc) << 6); + iCBP ^= ((iCBP & 0x3300) << 2); + + } + else if (pModel->m_iState[c1] == 2) { + iCBP ^= 0xffff; + } + + iNOrig = NumOnes(iCBP); + + pModel->m_iCount0[c1] += iNOrig - iNDiff; + SATURATE32(pModel->m_iCount0[c1]); + + pModel->m_iCount1[c1] += 16 - iNOrig - iNDiff; + SATURATE32(pModel->m_iCount1[c1]); + + if (pModel->m_iCount0[c1] < 0) { + if (pModel->m_iCount0[c1] < pModel->m_iCount1[c1]) { + pModel->m_iState[c1] = 1; + } + else { + pModel->m_iState[c1] = 2; + } + } + else if (pModel->m_iCount1[c1] < 0) { + pModel->m_iState[c1] = 2; + } + else { + pModel->m_iState[c1] = 0; + } + return iCBP; +} + +static Int predCBPC420Dec(CWMImageStrCodec * pSC, Int iCBP, size_t mbX, size_t mbY, size_t c, CCBPModel *pModel) +{ + Int iNOrig; + const int iNDiff = AVG_NDIFF; + + UNREFERENCED_PARAMETER( mbY ); + + if (pModel->m_iState[1] == 0) { + if(pSC->m_bCtxLeft) { + if (pSC->m_bCtxTop) { + iCBP ^= 1; + } + else { + Int iTopCBP = (pSC->PredInfoPrevRow[c] + mbX)->iCBP; + iCBP ^= (iTopCBP >> 2) & 1; // left: top(2) => 0 + } + } + else { + Int iLeftCBP = (pSC->PredInfo[c] + mbX - 1)->iCBP; + iCBP ^= ((iLeftCBP >> 1) & 1); // left(1) => 0 + } + + iCBP ^= (0x02 & (iCBP << 1)); // 0 => 1 + iCBP ^= ((iCBP & 0x3) << 2); // [0 1] -> [2 3] + } + else if (pModel->m_iState[1] == 2) { + iCBP ^= 0xf; + } + + iNOrig = NumOnes(iCBP) * 4; + + pModel->m_iCount0[1] += iNOrig - iNDiff; + SATURATE32(pModel->m_iCount0[1]); + + pModel->m_iCount1[1] += 16 - iNOrig - iNDiff; + SATURATE32(pModel->m_iCount1[1]); + + if (pModel->m_iCount0[1] < 0) { + if (pModel->m_iCount0[1] < pModel->m_iCount1[1]) { + pModel->m_iState[1] = 1; + } + else { + pModel->m_iState[1] = 2; + } + } + else if (pModel->m_iCount1[1] < 0) { + pModel->m_iState[1] = 2; + } + else { + pModel->m_iState[1] = 0; + } + + return iCBP; +} + +static Int predCBPC422Dec(CWMImageStrCodec * pSC, Int iCBP, size_t mbX, size_t mbY, size_t c, CCBPModel *pModel) +{ + Int iNOrig; + const int iNDiff = AVG_NDIFF; + + UNREFERENCED_PARAMETER( mbY ); + + if (pModel->m_iState[1] == 0) { + if(pSC->m_bCtxLeft) { + if (pSC->m_bCtxTop) { + iCBP ^= 1; + } + else { + Int iTopCBP = (pSC->PredInfoPrevRow[c] + mbX)->iCBP; + iCBP ^= (iTopCBP >> 6) & 1; // left: top(6) => 0 + } + } + else { + Int iLeftCBP = (pSC->PredInfo[c] + mbX - 1)->iCBP; + iCBP ^= ((iLeftCBP >> 1) & 1); // left(1) => 0 + } + + iCBP ^= (iCBP & 0x1) << 1; // [0]->[1] + iCBP ^= (iCBP & 0x3) << 2; // [0 1]->[2 3] + iCBP ^= (iCBP & 0xc) << 2; // [2 3]->[4 5] + iCBP ^= (iCBP & 0x30) << 2; // [4 5]->[6 7] + } + else if (pModel->m_iState[1] == 2) { + iCBP ^= 0xff; + } + + iNOrig = NumOnes(iCBP) * 2; + + pModel->m_iCount0[1] += iNOrig - iNDiff; + SATURATE32(pModel->m_iCount0[1]); + + pModel->m_iCount1[1] += 16 - iNOrig - iNDiff; + SATURATE32(pModel->m_iCount1[1]); + + if (pModel->m_iCount0[1] < 0) { + if (pModel->m_iCount0[1] < pModel->m_iCount1[1]) { + pModel->m_iState[1] = 1; + } + else { + pModel->m_iState[1] = 2; + } + } + else if (pModel->m_iCount1[1] < 0) { + pModel->m_iState[1] = 2; + } + else { + pModel->m_iState[1] = 0; + } + + return iCBP; +} + + +/* Coded Block Pattern (CBP) prediction */ +Void predCBPDec(CWMImageStrCodec *pSC, CCodingContext *pContext) +{ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const size_t iChannels = (cf == YUV_420 || cf == YUV_422) ? 1 : pSC->m_param.cNumChannels; + size_t i, mbX = pSC->cColumn, mbY = pSC->cRow; + CWMIMBInfo *pMBInfo = &(pSC->MBInfo); + + for (i = 0; i < iChannels; i++) { + (pSC->PredInfo[i] + mbX)->iCBP = pMBInfo->iCBP[i] = predCBPCDec(pSC, pMBInfo->iDiffCBP[i], mbX, mbY, i, &pContext->m_aCBPModel); // Y Channel + } + + if (cf == YUV_422){ + (pSC->PredInfo[1] + mbX)->iCBP = pMBInfo->iCBP[1] = predCBPC422Dec(pSC, pMBInfo->iDiffCBP[1], mbX, mbY, 1, &pContext->m_aCBPModel); + (pSC->PredInfo[2] + mbX)->iCBP = pMBInfo->iCBP[2] = predCBPC422Dec(pSC, pMBInfo->iDiffCBP[2], mbX, mbY, 2, &pContext->m_aCBPModel); + } + else if (cf == YUV_420) { + (pSC->PredInfo[1] + mbX)->iCBP = pMBInfo->iCBP[1] = predCBPC420Dec(pSC, pMBInfo->iDiffCBP[1], mbX, mbY, 1, &pContext->m_aCBPModel); + (pSC->PredInfo[2] + mbX)->iCBP = pMBInfo->iCBP[2] = predCBPC420Dec(pSC, pMBInfo->iDiffCBP[2], mbX, mbY, 2, &pContext->m_aCBPModel); + } + //} +} + diff --git a/libs/jxr/image/decode/strdec.c b/libs/jxr/image/decode/strdec.c new file mode 100644 index 00000000000..e93b7eb4807 --- /dev/null +++ b/libs/jxr/image/decode/strdec.c @@ -0,0 +1,3628 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strcodec.h" +#include "decode.h" +#include "strTransform.h" +#include +#include "perfTimer.h" + +#ifdef MEM_TRACE +#define TRACE_MALLOC 1 +#define TRACE_NEW 0 +#define TRACE_HEAP 0 +#include "memtrace.h" +#endif + +#ifdef X86OPT_INLINE +#define _FORCEINLINE __forceinline +#else // X86OPT_INLINE +#define _FORCEINLINE +#endif // X86OPT_INLINE + +#if defined(WMP_OPT_SSE2) || defined(WMP_OPT_CC_DEC) || defined(WMP_OPT_TRFM_DEC) +void StrDecOpt(CWMImageStrCodec* pSC); +#endif // OPT defined + +Int processMacroblockDec(CWMImageStrCodec *); + +U8 readQuantizerSB(U8 pQPIndex[MAX_CHANNELS], SimpleBitIO * pIO, size_t cChannel) +{ + U8 cChMode = 0; + + if(cChannel >= MAX_CHANNELS) + return 0; + + if(cChannel > 1) + cChMode = (U8)getBit32_SB(pIO, 2); // Channel mode + + pQPIndex[0] = (U8)getBit32_SB(pIO, 8); // Y + + if(cChMode == 1) // MIXED + pQPIndex[1] = (U8)getBit32_SB(pIO, 8); // UV + else if(cChMode > 0){ // INDEPENDENT + size_t i; + + for(i = 1; i < cChannel; i ++) +#pragma prefast(suppress: __WARNING_UNRELATED_LOOP_TERMINATION_NO_SIZEEXPR, "PREfast false alarm: 1 <= i < MAX_CHANNELS, no buffer over/underrun!") + pQPIndex[i] = (U8)getBit32_SB(pIO, 8); // UV + } + + return cChMode; +} + +U8 readQuantizer(CWMIQuantizer * pQuantizer[MAX_CHANNELS], BitIOInfo * pIO, size_t cChannel, size_t iPos) +{ + U8 cChMode = 0; + + if(cChannel > 1) + cChMode = (U8)getBit16(pIO, 2); // Channel mode + + pQuantizer[0][iPos].iIndex = (U8)getBit16(pIO, 8); // Y + + if(cChMode == 1) // MIXED + pQuantizer[1][iPos].iIndex = (U8)getBit16(pIO, 8); // UV + else if(cChMode > 0){ // INDEPENDENT + size_t i; + + for(i = 1; i < cChannel; i ++) + pQuantizer[i][iPos].iIndex = (U8)getBit16(pIO, 8); // UV + } + + return cChMode; +} + +// packet header: 00000000 00000000 00000001 ?????xxx +// xxx: 000(spatial) 001(DC) 010(AD) 011(AC) 100(FL) 101-111(reserved) +// ?????: (iTileY * cNumOfSliceV + iTileX) % 32 +Int readPacketHeader(BitIOInfo * pIO, U8 ptPacketType, U8 pID) +{ + UNREFERENCED_PARAMETER( ptPacketType ); + UNREFERENCED_PARAMETER( pID ); + if(getBit16(pIO, 8) != 0 || getBit16(pIO, 8) != 0 || getBit16(pIO, 8) != 1) + return ICERR_ERROR; + getBit16(pIO, 8); + return ICERR_OK; +} + +Int readTileHeaderDC(CWMImageStrCodec * pSC, BitIOInfo * pIO) +{ + if((pSC->m_param.uQPMode & 1) != 0){ // not DC uniform + size_t iTile; + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + + if(pSC->cTileRow + pSC->cTileColumn == 0) // allocate DC QP info + for(iTile = 0; iTile <= pSC->WMISCP.cNumOfSliceMinus1V; iTile ++) + if(allocateQuantizer(pSC->pTile[iTile].pQuantizerDC, pSC->m_param.cNumChannels, 1) != ICERR_OK) + return ICERR_ERROR; + + pTile->cChModeDC = readQuantizer(pTile->pQuantizerDC, pIO, pSC->m_param.cNumChannels, 0); + formatQuantizer(pTile->pQuantizerDC, pTile->cChModeDC, pSC->m_param.cNumChannels, 0, TRUE, pSC->m_param.bScaledArith); + } + + return ICERR_OK; +} + +Int readTileHeaderLP(CWMImageStrCodec * pSC, BitIOInfo * pIO) +{ + if(pSC->WMISCP.sbSubband != SB_DC_ONLY && (pSC->m_param.uQPMode & 2) != 0){ // not LP uniform + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + U8 i; + + pTile->bUseDC = (getBit16(pIO, 1) == 1 ? TRUE : FALSE); + pTile->cBitsLP = 0; + pTile->cNumQPLP = 1; + + if(pSC->cTileRow > 0) + freeQuantizer(pTile->pQuantizerLP); + + if(pTile->bUseDC == TRUE){ + if(allocateQuantizer(pTile->pQuantizerLP, pSC->m_param.cNumChannels, pTile->cNumQPLP) != ICERR_OK) + return ICERR_ERROR; + useDCQuantizer(pSC, pSC->cTileColumn); + } + else{ + pTile->cNumQPLP = (U8)getBit16(pIO, 4) + 1; + pTile->cBitsLP = dquantBits(pTile->cNumQPLP); + + if(allocateQuantizer(pTile->pQuantizerLP, pSC->m_param.cNumChannels, pTile->cNumQPLP) != ICERR_OK) + return ICERR_ERROR; + + for(i = 0; i < pTile->cNumQPLP; i ++){ + pTile->cChModeLP[i] = readQuantizer(pTile->pQuantizerLP, pIO, pSC->m_param.cNumChannels, i); + formatQuantizer(pTile->pQuantizerLP, pTile->cChModeLP[i], pSC->m_param.cNumChannels, i, TRUE, pSC->m_param.bScaledArith); + } + } + } + + return ICERR_OK; +} + +Int readTileHeaderHP(CWMImageStrCodec * pSC, BitIOInfo * pIO) +{ + if(pSC->WMISCP.sbSubband != SB_DC_ONLY && pSC->WMISCP.sbSubband != SB_NO_HIGHPASS && (pSC->m_param.uQPMode & 4) != 0){ // not HP uniform + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + U8 i; + + pTile->bUseLP = (getBit16(pIO, 1) == 1 ? TRUE : FALSE); + pTile->cBitsHP = 0; + pTile->cNumQPHP = 1; + + if(pSC->cTileRow > 0) + freeQuantizer(pTile->pQuantizerHP); + + if(pTile->bUseLP == TRUE){ + pTile->cNumQPHP = pTile->cNumQPLP; + if(allocateQuantizer(pTile->pQuantizerHP, pSC->m_param.cNumChannels, pTile->cNumQPHP) != ICERR_OK) + return ICERR_ERROR; + useLPQuantizer(pSC, pTile->cNumQPHP, pSC->cTileColumn); + } + else{ + pTile->cNumQPHP = (U8)getBit16(pIO, 4) + 1; + pTile->cBitsHP = dquantBits(pTile->cNumQPHP); + + if(allocateQuantizer(pTile->pQuantizerHP, pSC->m_param.cNumChannels, pTile->cNumQPHP) != ICERR_OK) + return ICERR_ERROR; + + for(i = 0; i < pTile->cNumQPHP; i ++){ + pTile->cChModeHP[i] = readQuantizer(pTile->pQuantizerHP, pIO, pSC->m_param.cNumChannels, i); + formatQuantizer(pTile->pQuantizerHP, pTile->cChModeHP[i], pSC->m_param.cNumChannels, i, FALSE, pSC->m_param.bScaledArith); + } + } + } + + return ICERR_OK; +} + +Int readPackets(CWMImageStrCodec * pSC) +{ + if(pSC->cColumn == 0 && pSC->cRow == pSC->WMISCP.uiTileY[pSC->cTileRow]){ // start of a new horizontal slice + size_t k; + + if (pSC->m_bSecondary) { + if(pSC->cNumBitIO > 0){ + for(k = 0; k <= pSC->WMISCP.cNumOfSliceMinus1V; k ++){ + // reset coding contexts + ResetCodingContextDec(&pSC->m_pCodingContext[k]); + } + } + else{ // for multiple decoding calls! + ResetCodingContextDec(&pSC->m_pCodingContext[0]); + } + } + else { + // get sizes of each packet and update index table + for(k = 0; k < pSC->cNumBitIO; k ++){ + if(pSC->ppWStream != NULL){ // new API + unsigned cBands = (pSC->WMISCP.bfBitstreamFormat == SPATIAL ? 1 : pSC->cSB); + struct WMPStream ** ppWS = pSC->ppWStream + (pSC->WMISCP.cNumOfSliceMinus1V + 1) * pSC->cTileRow * cBands + + k / cBands * cBands + (k % cBands); + + if(pSC->cTileRow > 0 && pSC->m_ppBitIO[k]->pWS != NULL) // attached to the same packet of the tile on top + detachISRead(pSC, pSC->m_ppBitIO[k]); // detach it + + if(ppWS[0] != NULL) + attachISRead(pSC->m_ppBitIO[k], ppWS[0], pSC); // need to attach it + } + else{ + if(pSC->cTileRow > 0) + detachISRead(pSC, pSC->m_ppBitIO[k]); + pSC->WMISCP.pWStream->SetPos(pSC->WMISCP.pWStream, pSC->pIndexTable[pSC->cNumBitIO * pSC->cTileRow + k] + pSC->cHeaderSize); + attachISRead(pSC->m_ppBitIO[k], pSC->WMISCP.pWStream, pSC); + } + } + + if(pSC->cNumBitIO == 0){ + detachISRead(pSC, pSC->pIOHeader); + if(pSC->ppWStream != NULL){// new API + attachISRead(pSC->pIOHeader, pSC->ppWStream[0], pSC); // need to attach it + } + else{ + pSC->WMISCP.pWStream->SetPos(pSC->WMISCP.pWStream, pSC->cHeaderSize); + attachISRead(pSC->pIOHeader, pSC->WMISCP.pWStream, pSC); + } + } + + for(k = 0; k <= pSC->WMISCP.cNumOfSliceMinus1V; k ++){ + U8 pID = (U8)((pSC->cTileRow * (pSC->WMISCP.cNumOfSliceMinus1V + 1) + k) & 0x1F); + + // read packet header + if(pSC->WMISCP.bfBitstreamFormat == SPATIAL){ + BitIOInfo * pIO = (pSC->cNumBitIO == 0 ? pSC->pIOHeader : pSC->m_ppBitIO[k]); + + if(pIO->pWS == NULL || readPacketHeader(pIO, 0, pID) != ICERR_OK) + return ICERR_ERROR; + pSC->m_pCodingContext[k].m_iTrimFlexBits = (pSC->m_param.bTrimFlexbitsFlag) ? getBit16(pIO, 4) : 0; + } + else{ + if(pSC->m_ppBitIO[k * pSC->cSB + 0] == NULL || readPacketHeader(pSC->m_ppBitIO[k * pSC->cSB + 0], 1, pID) != ICERR_OK) + return ICERR_ERROR; + if(pSC->cSB > 1){ + if(pSC->m_ppBitIO[k * pSC->cSB + 1] == NULL || readPacketHeader(pSC->m_ppBitIO[k * pSC->cSB + 1], 2, pID) != ICERR_OK) + return ICERR_ERROR; + } + if(pSC->cSB > 2){ + if(pSC->m_ppBitIO[k * pSC->cSB + 2] == NULL || readPacketHeader(pSC->m_ppBitIO[k * pSC->cSB + 2], 3, pID) != ICERR_OK) + return ICERR_ERROR; +// readTileHeaderHP(pSC, pSC->m_ppBitIO[k * pSC->cSB + 2]); + } + if(pSC->cSB > 3){ + if(pSC->m_ppBitIO[k * pSC->cSB + 3] == NULL) + return ICERR_ERROR; + readPacketHeader(pSC->m_ppBitIO[k * pSC->cSB + 3], 4, pID); // bad flexbits packet doesn't generate an error + pSC->m_pCodingContext[k].m_iTrimFlexBits = (pSC->m_param.bTrimFlexbitsFlag) ? getBit16(pSC->m_ppBitIO[k * pSC->cSB + 3], 4) : 0; + } + } + + // reset coding contexts + ResetCodingContextDec(&pSC->m_pCodingContext[k]); + } + } + } + + if(pSC->m_bCtxLeft && pSC->m_bCtxTop && pSC->m_bSecondary == FALSE){ + CCodingContext *pContext = &pSC->m_pCodingContext[pSC->cTileColumn]; + + readTileHeaderDC(pSC, pContext->m_pIODC); + if(pSC->m_pNextSC != NULL) + readTileHeaderDC(pSC->m_pNextSC, pContext->m_pIODC); + if(pSC->cSB > 1){ + readTileHeaderLP(pSC, pContext->m_pIOLP); + if(pSC->m_pNextSC != NULL) + readTileHeaderLP(pSC->m_pNextSC, pContext->m_pIOLP); + } + if(pSC->cSB > 2){ + readTileHeaderHP(pSC, pContext->m_pIOAC); + if(pSC->m_pNextSC != NULL) + readTileHeaderHP(pSC->m_pNextSC, pContext->m_pIOAC); + } + } + + return ICERR_OK; +} + +/* inverse transform and overlap possible part of a macroblock */ +Int processMacroblockDec(CWMImageStrCodec * pSC) +{ + const OVERLAP olOverlap = pSC->WMISCP.olOverlap; + // const Bool left = (pSC->cColumn == 0); + const Bool /*top = (pSC->cRow == 0),*/ bottom = (pSC->cRow == pSC->cmbHeight); + const Bool bottomORright = (bottom || pSC->cColumn == pSC->cmbWidth); + // const size_t mbWidth = pSC->cmbWidth, mbX = pSC->cColumn; + // Int iQIndex = 0; + ERR_CODE result = ICERR_OK; + size_t j, jend = (pSC->m_pNextSC != NULL); + + for (j = 0; j <= jend; j++) { + if(!bottomORright){ + CCodingContext *pContext; + + getTilePos(pSC, pSC->cColumn, pSC->cRow); + + if(jend){ + pSC->m_pNextSC->cTileColumn = pSC->cTileColumn; + pSC->m_pNextSC->cTileRow = pSC->cTileRow; + } + + pContext = &pSC->m_pCodingContext[pSC->cTileColumn]; + + if(readPackets(pSC) != ICERR_OK) + return ICERR_ERROR; + + // check if we need to do entropy decode + if(!pSC->m_Dparam->bDecodeFullFrame){ + if(pSC->cColumn == pSC->WMISCP.uiTileX[pSC->cTileColumn]){ // switching to a new tile + size_t rLeft = pSC->m_Dparam->cROILeftX, rRight = pSC->m_Dparam->cROIRightX; + size_t rTop = pSC->m_Dparam->cROITopY, rBottom = pSC->m_Dparam->cROIBottomY; + size_t rExt = (olOverlap == OL_NONE ? 0 : olOverlap == OL_ONE ? 2 : 10); + size_t tLeft = pSC->cColumn * 16, tTop = pSC->WMISCP.uiTileY[pSC->cTileRow] * 16; + size_t tRight = (pSC->cTileColumn != pSC->WMISCP.cNumOfSliceMinus1V ? pSC->WMISCP.uiTileX[pSC->cTileColumn + 1] : pSC->cmbWidth) * 16; + size_t tBottom = (pSC->cTileRow != pSC->WMISCP.cNumOfSliceMinus1H ? pSC->WMISCP.uiTileY[pSC->cTileRow + 1] : pSC->cmbHeight) * 16; + + // tile overlaps with ROI? + pContext->m_bInROI = ((rLeft >= tRight + rExt || rTop >= tBottom + rExt || tLeft > rRight + rExt || + tTop > rBottom + rExt || pSC->cRow * 16 > rBottom + rExt) ? FALSE : TRUE); + } + } + + if(pSC->m_Dparam->bDecodeFullFrame || pContext->m_bInROI){ + if ((result = DecodeMacroblockDC(pSC, pContext, (Int)pSC->cColumn, (Int)pSC->cRow)) != ICERR_OK) + return result; + + if(pSC->m_Dparam->bDecodeLP){ + if ((result = DecodeMacroblockLowpass(pSC, pContext, (Int)pSC->cColumn, (Int)pSC->cRow)) != ICERR_OK) + return result; + } + + predDCACDec(pSC); + + dequantizeMacroblock(pSC); + + if(pSC->m_Dparam->bDecodeHP){ + if ((result = DecodeMacroblockHighpass(pSC, pContext, (Int)pSC->cColumn, (Int)pSC->cRow)) != ICERR_OK) + return result; + predACDec(pSC); + } + + /* keep necessary info for future prediction */ + updatePredInfo(pSC, &pSC->MBInfo, (Int)pSC->cColumn, pSC->m_param.cfColorFormat); + } + } + + if((!pSC->m_Dparam->bDecodeFullFrame) && + ((pSC->cColumn * 16 > pSC->m_Dparam->cROIRightX + 25) || (pSC->cColumn * 16 + 25 < pSC->m_Dparam->cROILeftX) + || (pSC->cRow * 16 > pSC->m_Dparam->cROIBottomY + 25) || (pSC->cRow * 16 + 25 < pSC->m_Dparam->cROITopY))) + { + // do nothing + } + else { + pSC->Transform(pSC); + } + + if (jend) { + pSC->m_pNextSC->cRow = pSC->cRow; + pSC->m_pNextSC->cColumn = pSC->cColumn; + pSC = pSC->m_pNextSC; + } + } + + return result; +} + +//================================================================ +// Inverse Color Conversion +//#define _ICC1(r, g, b) (g^=b^=g^=b, r^=g^=r^=g, b += ((g) >> 1), r += ((g) >> 1), g -= (b+3*r+2) >> 2) +//#define _ICC(r, g, b) (g^=b^=g^=b, r^=g^=r^=g, b += ((g) >> 1), r += ((g) >> 1), g -= (b+3*r+2) >> 2) +//================================================================ +//#define _ICC1(r, g, b) r -= (g >> 1), g += r, r -= ((b + 1) >> 1), b += r +//#define _ICC(r, g, b) r -= (g >> 1), g += r, r -= (b >> 1), b += r + +#define _ICC(r, g, b) (g -= ((r + 0) >> 1), r -= ((b + 1) >> 1) - g, b += r) +#define _ICC_CMYK(c, m, y, k) (k -= ((m + 1) >> 1), m -= (c >> 1) - k, c -= ((y + 1) >> 1) - m, y += c) + +#define _CLIP2(l, v, h) ((v) < (l) ? (l) : ((h) < (v) ? (h) : (v))) +#define _CLIP8(v) ((U8)_CLIP2(0, v, 255)) +#define _CLIP16(v) ((I16)_CLIP2(-32768, v, 32767)) +#define _CLIPU16(v) ((U16)_CLIP2(0, v, 65535)) + +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +//inverseConvert: Inverse conversion from float RGB to RGBE +static _FORCEINLINE void inverseConvert (PixelI iF, U8 *pRGB, U8 *pE) +{ + if (iF <= 0) { + *pRGB = *pE = 0; + } + else if ((iF >> 7) > 1) { + /** normal form **/ + *pE = (U8) (iF >> 7); //+ 1; + *pRGB = (iF & 0x7f) | 0x80; + } + else { + /** denormal form **/ + *pE = 1; + *pRGB = (U8) iF; + } +} + +#ifdef __ANSI__ +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif // __ANSI__ + +static _FORCEINLINE void inverseConvertRGBE (PixelI iFr, PixelI iFg, PixelI iFb, U8 *pR, U8 *pG, U8 *pB, U8 *pE) +{ + U8 iShift; + + U8 pR_E, pG_E, pB_E; + + inverseConvert (iFr, pR, &pR_E); + inverseConvert (iFg, pG, &pG_E); + inverseConvert (iFb, pB, &pB_E); + + *pE = max(max(pR_E, pG_E), pB_E); + + if(*pE > pR_E){ + iShift = (*pE - pR_E); + *pR = (U8)((((int)*pR) * 2 + 1) >> (iShift + 1)); + } + if(*pE > pG_E){ + iShift = (*pE - pG_E); + *pG = (U8)((((int)*pG) * 2 + 1) >> (iShift + 1)); + } + if(*pE > pB_E){ + iShift = (*pE - pB_E); + *pB = (U8)((((int)*pB) * 2 + 1) >> (iShift + 1)); + } +} + + +//pixel to float 32! +static _FORCEINLINE float pixel2float(PixelI _h, const char _c, const unsigned char _lm) +{ + union uif + { + I32 i; + float f; + } x; + + I32 s, iTempH, m, e, lmshift = (1 << _lm); + + // assert (_c <= 127); + + iTempH = (I32) _h ; + s = (iTempH >> 31); + iTempH = (iTempH ^ s) - s; // abs(iTempH) + + e = (U32) iTempH >> _lm;// & ((1 << (31 - _lm)) - 1); + m = (iTempH & (lmshift - 1)) | lmshift; // actual mantissa, with normalizer + if (e == 0) { // denormal land + m ^= lmshift; // normalizer removed + e = 1; // actual exponent + } + + e += (127 - _c); + while (m < lmshift && e > 1 && m > 0) { // denormal originally, see if normal is possible + e--; + m <<= 1; + } + if (m < lmshift) // truly denormal + e = 0; + else + m ^= lmshift; + m <<= (23 - _lm); + + x.i = (s & 0x80000000) | (e << 23) | m; + + return x.f; +} + +//convert Half-16 to internal format, only need to handle sign bit +static _FORCEINLINE U16 backwardHalf (PixelI hHalf) +{ + PixelI s; + s = hHalf >> 31; + hHalf = ((hHalf & 0x7fff) ^ s) - s; // don't worry about overflow + return (U16) hHalf; +} + + +Void interpolateUV(CWMImageStrCodec * pSC) +{ + const COLORFORMAT cfExt = pSC->WMII.cfColorFormat; + const size_t cWidth = pSC->cmbWidth * 16; + PixelI * pSrcU = pSC->a0MBbuffer[1], * pSrcV = pSC->a0MBbuffer[2]; + PixelI * pDstU = pSC->pResU, * pDstV = pSC->pResV; + size_t iRow, iColumn; + size_t iIdxS = 0, iIdxD = 0; + + if(pSC->m_param.cfColorFormat == YUV_422){ // 422 => 444, interpolate horizontally + for(iRow = 0; iRow < 16; iRow ++){ + for(iColumn = 0; iColumn < cWidth; iColumn += 2){ + iIdxS = ((iColumn >> 4) << 7) + idxCC[iRow][(iColumn >> 1) & 7]; + iIdxD = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + // copy over + pDstU[iIdxD] = pSrcU[iIdxS]; + pDstV[iIdxD] = pSrcV[iIdxS]; + + if(iColumn > 0){ + size_t iL = iColumn - 2, iIdxL = ((iL >> 4) << 8) + idxCC[iRow][iL & 15]; + size_t iC = iColumn - 1, iIdxC = ((iC >> 4) << 8) + idxCC[iRow][iC & 15]; + + // interpolate + pDstU[iIdxC] = ((pDstU[iIdxL] + pDstU[iIdxD] + 1) >> 1); + pDstV[iIdxC] = ((pDstV[iIdxL] + pDstV[iIdxD] + 1) >> 1); + } + } + + //last pixel + iIdxS = (((iColumn - 1) >> 4) << 8) + idxCC[iRow][(iColumn - 1) & 15]; + pDstU[iIdxS] = pDstU[iIdxD]; + pDstV[iIdxS] = pDstV[iIdxD]; + } + } + else{ // 420 => 422 or 444, interpolate vertically + const size_t cShift = (cfExt == YUV_422 ? 3 : 4); + + for(iColumn = 0; iColumn < cWidth; iColumn += 2){ + const size_t cMB = ((iColumn >> 4) << (4 + cShift)), cPix = (iColumn >> (4 - cShift)) & ((1 << cShift) - 1); + + for(iRow = 0; iRow < 16; iRow += 2){ + iIdxS = ((iColumn >> 4) << 6) + idxCC_420[iRow >> 1][(iColumn >> 1) & 7]; + iIdxD = cMB + idxCC[iRow][cPix]; + + // copy over + pDstU[iIdxD] = pSrcU[iIdxS]; + pDstV[iIdxD] = pSrcV[iIdxS]; + + if(iRow > 0){ + size_t iIdxT = cMB + idxCC[iRow - 2][cPix]; + size_t iIdxC = cMB + idxCC[iRow - 1][cPix]; + + // interpolate + pDstU[iIdxC] = ((pDstU[iIdxT] + pDstU[iIdxD] + 1) >> 1); + pDstV[iIdxC] = ((pDstV[iIdxT] + pDstV[iIdxD] + 1) >> 1); + } + } + + //last row + iIdxS = cMB + idxCC[15][cPix]; + if(pSC->cRow == pSC->cmbHeight){ // image boundary + pDstU[iIdxS] = pDstU[iIdxD]; + pDstV[iIdxS] = pDstV[iIdxD]; + } + else{ // need next MB row + size_t iIdxB = ((iColumn >> 4) << 6) + idxCC_420[0][(iColumn >> 1) & 7]; + + pDstU[iIdxS] = ((pSC->a1MBbuffer[1][iIdxB] + pDstU[iIdxD] + 1) >> 1); + pDstV[iIdxS] = ((pSC->a1MBbuffer[2][iIdxB] + pDstV[iIdxD] + 1) >> 1); + } + } + + if(cfExt != YUV_422){ // 420 => 444, interpolate horizontally + for(iRow = 0; iRow < 16; iRow ++){ + for(iColumn = 1; iColumn < cWidth - 2; iColumn += 2){ + size_t iIdxL = (((iColumn - 1) >> 4) << 8) + idxCC[iRow][(iColumn - 1) & 15]; + + iIdxD = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + iIdxS = (((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]; + + pDstU[iIdxD] = ((pDstU[iIdxS] + pDstU[iIdxL] + 1) >> 1); + pDstV[iIdxD] = ((pDstV[iIdxS] + pDstV[iIdxL] + 1) >> 1); + } + + // last pixel + iIdxD = (((cWidth - 1) >> 4) << 8) + idxCC[iRow][(cWidth - 1) & 15]; + pDstU[iIdxD] = pDstU[iIdxS]; + pDstV[iIdxD] = pDstV[iIdxS]; + } + } + } +} + +// write one MB row of Y_ONLY/CF_ALPHA/YUV_444/N_CHANNEL to output buffer +Void outputNChannel(CWMImageStrCodec * pSC, size_t iFirstRow, size_t iFirstColumn, size_t cWidth, size_t cHeight, size_t iShift, PixelI iBias) +{ + const CWMImageInfo* pII = &pSC->WMII; + const size_t cChannel = pII->cfColorFormat == Y_ONLY ? 1 : pSC->WMISCP.cChannel; + // const U8 cbChannels[BDB_MAX] = {-1, 1, 2, 2, 2, 4, 4, -1, -1, }; + const U8 nLen = pSC->WMISCP.nLenMantissaOrShift; + const I8 nExpBias = pSC->WMISCP.nExpBias; + + PixelI * pChannel[16]; + size_t iChannel, iRow, iColumn; + size_t * pOffsetX = pSC->m_Dparam->pOffsetX, * pOffsetY = pSC->m_Dparam->pOffsetY + (pSC->cRow - 1) * 16, iY; + + assert(cChannel <= 16); + + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pChannel[iChannel & 15] = pSC->a0MBbuffer[iChannel]; + + if(pSC->m_bUVResolutionChange) + pChannel[1] = pSC->pResU, pChannel[2] = pSC->pResV; + + switch(pSC->WMII.bdBitDepth){ + case BD_8: + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + U8 * pDst = (U8 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = ((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift); + + pDst[iChannel] = _CLIP8(p); + } + } + } + break; + + case BD_16: + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + U16 * pDst = (U16 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = ((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift); + + p <<= nLen; + pDst[iChannel] = _CLIPU16(p); + } + } + } + break; + + case BD_16S: + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + I16 * pDst = (I16 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = ((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift); + + p <<= nLen; + pDst[iChannel] = _CLIP16(p); + } + } + } + break; + + case BD_16F: + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + U16 * pDst = (U16 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = ((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] + iBias) >> iShift); + + pDst[iChannel] = backwardHalf(p); + } + } + } + break; + + case BD_32: + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + U32 * pDst = (U32 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = ((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] + iBias) >> iShift); + + p <<= nLen; + pDst[iChannel] = (U32)(p); + } + } + } + break; + + case BD_32S: + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + I32 * pDst = (I32 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = ((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] + iBias) >> iShift); + + p <<= nLen; + pDst[iChannel] = (I32)(p); + } + } + } + break; + + case BD_32F: + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + float * pDst = (float *)pSC->WMIBI.pv + iY + pOffsetX[iColumn]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = ((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] + iBias) >> iShift); + + pDst[iChannel] = pixel2float (p, nExpBias, nLen); + } + } + } + break; + + default: + assert(0); + break; + } +} + +static void fixup_Y_ONLY_to_Others( + const CWMImageStrCodec* pSC, + const CWMImageBufferInfo* pBI) +{ + const CWMImageInfo* pII = &pSC->WMII; + const CWMIStrCodecParam* pSCP = &pSC->WMISCP; + size_t cWidth = 0, cHeight = 0; + size_t idxY = 0, idxX = 0; + + if (CF_RGB != pII->cfColorFormat || Y_ONLY != pSCP->cfColorFormat) + return; + + cWidth = 0 != pII->cROIWidth ? pII->cROIWidth : pII->cWidth; + cHeight = 0 != pII->cROIHeight ? pII->cROIHeight : pII->cHeight; + +#define fixup(type, nCh) \ +for (idxY = 0; idxY < cHeight; ++idxY) \ +{ \ + type * pT = (type *)((U8*)pBI->pv + pBI->cbStride * idxY); \ + for (idxX = 0; idxX < cWidth; ++idxX) \ + { \ + pT[2] = pT[1] = pT[0]; \ + pT += nCh; \ + } \ +} \ +break + + switch (pII->bdBitDepth) + { + case BD_8: + fixup(U8, (pII->cBitsPerUnit >> 3)); + break; + + case BD_16: + case BD_16S: + case BD_16F: + fixup(U16, (pII->cBitsPerUnit >> 3) / sizeof(U16)); + break; + + case BD_32: + case BD_32S: + case BD_32F: + fixup(U32, (pII->cBitsPerUnit >> 3) / sizeof(float)); + break; + + case BD_5: + case BD_10: + case BD_565: + default: + break; + } +} + +// centralized alpha channel color conversion, small perf penalty +Int outputMBRowAlpha(CWMImageStrCodec * pSC) +{ + if(pSC->WMII.bdBitDepth == BD_8 && pSC->WMISCP.cfColorFormat == CF_RGB) // has been taken care of and optimized out + return ICERR_OK; + + if(pSC->m_bSecondary == FALSE && pSC->m_pNextSC != NULL){ // with alpha channel + const BITDEPTH_BITS bd = pSC->WMII.bdBitDepth; + const PixelI iShift = (pSC->m_param.bScaledArith ? SHIFTZERO + QPFRACBITS : 0); + const size_t cHeight = min((pSC->m_Dparam->cROIBottomY + 1) - (pSC->cRow - 1) * 16, 16); + const size_t cWidth = (pSC->m_Dparam->cROIRightX + 1); + const size_t iFirstRow = ((pSC->cRow - 1) * 16 > pSC->m_Dparam->cROITopY ? 0 : (pSC->m_Dparam->cROITopY & 0xf)), iFirstColumn = pSC->m_Dparam->cROILeftX; + const size_t iAlphaPos = pSC->WMII.cLeadingPadding + (pSC->WMII.cfColorFormat == CMYK ? 4 : 3);//only RGB and CMYK may have interleaved alpha + const PixelI * pA = pSC->m_pNextSC->a0MBbuffer[0]; + const U8 nLen = pSC->WMISCP.nLenMantissaOrShift; + const I8 nExpBias = pSC->WMISCP.nExpBias; + size_t iRow, iColumn; + size_t * pOffsetX = pSC->m_Dparam->pOffsetX, * pOffsetY = pSC->m_Dparam->pOffsetY + (pSC->cRow - 1) * 16, iY; + + if (CF_RGB != pSC->WMII.cfColorFormat && CMYK != pSC->WMII.cfColorFormat) + return ICERR_ERROR; + + if(bd == BD_8){ + const PixelI iBias = (1 << (iShift + 7)) + (iShift == 0 ? 0 : (1 << (iShift - 1))); + + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + PixelI a = ((pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift); + ((U8 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY)[iAlphaPos] = _CLIP8(a); + } + } + else if(bd == BD_16){ + const PixelI iBias = (1 << (iShift + 15)) + (iShift == 0 ? 0 : (1 << (iShift - 1))); + + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + PixelI a = (((pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift) << nLen); + ((U16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY)[iAlphaPos] = _CLIPU16(a); + } + } + else if(bd == BD_16S){ + const PixelI iBias = (iShift == 0 ? 0 : (1 << (iShift - 1))); + + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + PixelI a = (((pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift) << nLen); + ((I16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY)[iAlphaPos] = _CLIP16(a); + } + } + else if(bd == BD_16F){ + const PixelI iBias = (iShift == 0 ? 0 : (1 << (iShift - 1))); + + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + PixelI a = ((pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift); + ((U16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY)[iAlphaPos] = backwardHalf(a); + } + } + else if(bd == BD_32S){ + const PixelI iBias = (iShift == 0 ? 0 : (1 << (iShift - 1))); + + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + PixelI a = (((pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift) << nLen); + ((I32 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY)[iAlphaPos] = a; + } + } + else if(bd == BD_32F){ + const PixelI iBias = (iShift == 0 ? 0 : (1 << (iShift - 1))); + + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + PixelI a = ((pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift); + ((float *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY)[iAlphaPos] = pixel2float (a, nExpBias, nLen); + } + } + else // not supported + return ICERR_ERROR; + } + + return ICERR_OK; +} + +Int outputMBRow(CWMImageStrCodec * pSC) +{ + const COLORFORMAT cfExt = (pSC->m_param.cfColorFormat == Y_ONLY ? Y_ONLY : pSC->WMII.cfColorFormat); + const BITDEPTH_BITS bd = pSC->WMII.bdBitDepth; + const PixelI iShift = (pSC->m_param.bScaledArith ? SHIFTZERO + QPFRACBITS : 0); + const size_t cHeight = min((pSC->m_Dparam->cROIBottomY + 1) - (pSC->cRow - 1) * 16, 16); + const size_t cWidth = (pSC->m_Dparam->cROIRightX + 1); + const size_t iFirstRow = ((pSC->cRow - 1) * 16 > pSC->m_Dparam->cROITopY ? 0 : (pSC->m_Dparam->cROITopY & 0xf)), iFirstColumn = pSC->m_Dparam->cROILeftX; + const PixelI *pY = pSC->a0MBbuffer[0]; + const PixelI *pU = (pSC->m_bUVResolutionChange ? pSC->pResU : pSC->a0MBbuffer[1]); + const PixelI *pV = (pSC->m_bUVResolutionChange ? pSC->pResV : pSC->a0MBbuffer[2]); + const PixelI *pA = NULL; + const size_t iB = (pSC->WMII.bRGB ? 2 : 0); + const size_t iR = 2 - iB; + const U8 nLen = pSC->WMISCP.nLenMantissaOrShift; + const I8 nExpBias = pSC->WMISCP.nExpBias; + size_t iRow, iColumn, iIdx; + size_t * pOffsetX = pSC->m_Dparam->pOffsetX, * pOffsetY = pSC->m_Dparam->pOffsetY + (pSC->cRow - 1) * (cfExt == YUV_420 ? 8 : 16), iY; + + + if (pSC->m_pNextSC) { + assert (pSC->m_param.bScaledArith == pSC->m_pNextSC->m_param.bScaledArith); // will be relaxed later + } + + // guard output buffer + if(checkImageBuffer(pSC, pSC->WMII.oOrientation >= O_RCW ? pSC->WMII.cROIHeight : pSC->WMII.cROIWidth, cHeight - iFirstRow) != ICERR_OK) + return ICERR_ERROR; + + if(pSC->m_bUVResolutionChange) + interpolateUV(pSC); + + if(pSC->WMISCP.bYUVData){ + I32 * pDst = (I32 *)pSC->WMIBI.pv + (pSC->cRow - 1) * + (pSC->m_param.cfColorFormat == YUV_420 ? 8 : 16) * pSC->WMIBI.cbStride / sizeof(I32); + + switch(pSC->m_param.cfColorFormat){ + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + { + PixelI * pChannel[16]; + size_t iChannel; + + const size_t cChannel = pSC->WMII.cfColorFormat == Y_ONLY ? 1 : pSC->WMISCP.cChannel; + assert(cChannel <= 16); + + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pChannel[iChannel & 15] = pSC->a0MBbuffer[iChannel]; + + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + I32 * pRow = pDst; + for(iColumn = iFirstColumn; iColumn < cWidth; iColumn ++){ + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]]; + + *pRow++ = p; + } + } + pDst += pSC->WMIBI.cbStride / sizeof(I32); + } + } + break; + + case YUV_422: + { + PixelI y0, y1, u, v; + + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + I32 * pRow = pDst; + for(iColumn = iFirstColumn; iColumn < cWidth; iColumn += 2){ + iIdx = ((iColumn >> 4) << 7) + idxCC[iRow][(iColumn >> 1) & 7]; + u = pU[iIdx], v = pV[iIdx]; + + y0 = pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]]; + y1 = pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]]; + + pRow[0] = u, pRow[1] = y0, pRow[2] = v, pRow[3] = y1; + pRow += 4; + } + pDst += pSC->WMIBI.cbStride / sizeof(I32); + } + } + break; + + case YUV_420: + { + PixelI y0, y1, y2, y3, u, v; + // const size_t iS4[8][4] = {{0, 1, 2, 3}, {2, 3, 0, 1}, {1, 0, 3, 2}, {3, 2, 1, 0}, {1, 3, 0, 2}, {3, 1, 2, 0}, {0, 2, 1, 3}, {2, 0, 3, 1}}; + + for(iRow = iFirstRow; iRow < cHeight; iRow += 2){ + I32 * pRow = pDst; + for(iColumn = iFirstColumn; iColumn < cWidth; iColumn += 2){ + iIdx = ((iColumn >> 4) << 6) + idxCC_420[iRow >> 1][(iColumn >> 1) & 7]; + u = pU[iIdx], v = pV[iIdx]; + + y0 = pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]]; + y1 = pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]]; + y2 = pY[((iColumn >> 4) << 8) + idxCC[iRow + 1][iColumn & 15]]; + y3 = pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow + 1][(iColumn + 1) & 15]]; + + pRow[0] = y0, pRow[1] = y1, pRow[2] = y2, pRow[3] = y3, pRow[4] = u, pRow[5] = v; + pRow += 6; + } + pDst += pSC->WMIBI.cbStride / sizeof(I32); + } + } + break; + + default: + assert(0); + break; + } + } + else if(bd == BD_8){ + U8 * pDst; + const PixelI iBias1 = 128 << iShift; + const PixelI iBias2 = pSC->m_param.bScaledArith ? ((1 << (SHIFTZERO + QPFRACBITS - 1)) - 1) : 0; + const PixelI iBias = iBias1 + iBias2; + + switch(cfExt){ + case CF_RGB: + { + PixelI r, g, b, a; + + if (pSC->m_pNextSC && pSC->WMISCP.uAlphaMode > 0) { // RGBA + + pA = pSC->m_pNextSC->a0MBbuffer[0]; + + if (pSC->m_param.bScaledArith == FALSE) { + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + a = pA[iIdx] + iBias; + + _ICC(r, g, b); + + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + if ((g | b | r | a) & ~0xff) + pDst[iR] = _CLIP8(r), pDst[1] = _CLIP8(g), pDst[iB] = _CLIP8(b), pDst[3] = _CLIP8(a); + else + pDst[iR] = (U8)r, pDst[1] = (U8)g, pDst[iB] = (U8)b, pDst[3] = (U8)(a); + } + } + else{ + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + a = pA[iIdx] + iBias; + + _ICC(r, g, b); + + g >>= iShift, b >>= iShift, r >>= iShift, a >>= iShift; + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + if ((g | b | r | a) & ~0xff) + pDst[iR] = _CLIP8(r), pDst[1] = _CLIP8(g), pDst[iB] = _CLIP8(b), pDst[3] = _CLIP8(a); + else + pDst[iR] = (U8)r, pDst[1] = (U8)g, pDst[iB] = (U8)b, pDst[3] = (U8)(a); + } + } + } + else { + if (pSC->m_param.bScaledArith == FALSE) { + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + if ((g | b | r) & ~0xff) + pDst[iR] = _CLIP8(r), pDst[1] = _CLIP8(g), pDst[iB] = _CLIP8(b); + else + pDst[iR] = (U8)r, pDst[1] = (U8)g, pDst[iB] = (U8)b; + } + } + else{ + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + g >>= iShift, b >>= iShift, r >>= iShift; + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + if ((g | b | r) & ~0xff) + pDst[iR] = _CLIP8(r), pDst[1] = _CLIP8(g), pDst[iB] = _CLIP8(b); + else + pDst[iR] = (U8)r, pDst[1] = (U8)g, pDst[iB] = (U8)b; + } + } + } + break; + } + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannel(pSC, iFirstRow, iFirstColumn, cWidth, cHeight, iShift, iBias); + break; + + case YUV_422: + { + PixelI y0, y1, u, v; + // const ORIENTATION oO = pSC->WMII.oOrientation; + // const size_t i0 = ((oO > O_FLIPV && oO <= O_RCW_FLIPVH) ? 1 : 0), i1 = 1 - i0; + + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn += 2){ + iIdx = ((iColumn >> 4) << 7) + idxCC[iRow][(iColumn >> 1) & 7]; + u = ((pU[iIdx] + iBias) >> iShift), v = ((pV[iIdx] + iBias) >> iShift); + + y0 = ((pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift); + y1 = ((pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]] + iBias) >> iShift); + + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn >> 1] + iY; + if ((y0 | y1 | u | v) & ~0xff)//UYVY + pDst[0] = _CLIP8(u), pDst[1] = _CLIP8(y0), pDst[2] = _CLIP8(v), pDst[3] = _CLIP8(y1); + else + pDst[0] = (U8)u, pDst[1] = (U8)y0, pDst[2] = (U8)v, pDst[3] = (U8)y1; + } + } + } + break; + + case YUV_420: + { + PixelI y0, y1, y2, y3, u, v; + const size_t iS4[8][4] = {{0, 1, 2, 3}, {2, 3, 0, 1}, {1, 0, 3, 2}, {3, 2, 1, 0}, {1, 3, 0, 2}, {3, 1, 2, 0}, {0, 2, 1, 3}, {2, 0, 3, 1}}; + const ORIENTATION oO = pSC->WMII.oOrientation; + const size_t i0 = iS4[oO][0], i1 = iS4[oO][1], i2 = iS4[oO][2], i3 = iS4[oO][3]; + + for(iRow = iFirstRow; iRow < cHeight; iRow += 2){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> 1]; iColumn < cWidth; iColumn += 2){ + iIdx = ((iColumn >> 4) << 6) + idxCC_420[iRow >> 1][(iColumn >> 1) & 7]; + u = ((pU[iIdx] + iBias) >> iShift), v = ((pV[iIdx] + iBias) >> iShift); + + y0 = ((pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift); + y1 = ((pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]] + iBias) >> iShift); + y2 = ((pY[((iColumn >> 4) << 8) + idxCC[iRow + 1][iColumn & 15]] + iBias) >> iShift); + y3 = ((pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow + 1][(iColumn + 1) & 15]] + iBias) >> iShift); + + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn >> 1] + iY; + if ((y0 | y1 | y2 | y3 | u | v) & ~0xff) + pDst[i0] = _CLIP8(y0), pDst[i1] = _CLIP8(y1), pDst[i2] = _CLIP8(y2), pDst[i3] = _CLIP8(y3), pDst[4] = _CLIP8(u), pDst[5] = _CLIP8(v); + else + pDst[i0] = (U8)y0, pDst[i1] = (U8)y1, pDst[i2] = (U8)y2, pDst[i3] = (U8)y3, pDst[4] = (U8)u, pDst[5] = (U8)v; + } + } + } + break; + + case CMYK: + { + PixelI c, m, y, k; + PixelI * pK = pSC->a0MBbuffer[3]; + + for(iRow = iFirstRow; iRow < cHeight; iRow++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + m = -pY[iIdx] + iBias1, c = pU[iIdx], y = -pV[iIdx], k = pK[iIdx] + iBias2; + + _ICC_CMYK(c, m, y, k); // color conversion + + c >>= iShift, m >>= iShift, y >>= iShift, k >>= iShift; + + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + if ((c | m | y | k) & ~0xff) + pDst[0] = _CLIP8(c), pDst[1] = _CLIP8(m), pDst[2] = _CLIP8(y), pDst[3] = _CLIP8(k); + else + pDst[0] = (U8)c, pDst[1] = (U8)m, pDst[2] = (U8)y, pDst[3] = (U8)k; + } + } + } + break; + + case CF_RGBE: + { + PixelI r, g, b; + + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias2, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + + inverseConvertRGBE (r >> iShift, g >> iShift, b >> iShift, pDst, pDst + 1, pDst + 2, pDst + 3); + } + } + } + break; + + default: + assert(0); + break; + } + } + else if(bd == BD_16){ + const PixelI iBias = (((1 << 15) >> nLen) << iShift) + (iShift == 0 ? 0 : (1 << (iShift - 1))); + U16 * pDst; + + switch(cfExt){ + case CF_RGB: + { + PixelI r, g, b; + if (pSC->m_param.bScaledArith == FALSE) { + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + g <<= nLen, b <<= nLen, r <<= nLen; + + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + + if ((g | b | r) & ~0xffff) + pDst[0] = _CLIPU16(r), pDst[1] = _CLIPU16(g), pDst[2] = _CLIPU16(b); + else + pDst[0] = (U16)r, pDst[1] = (U16)g, pDst[2] = (U16)b; + } + } + else{ + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + g = (g >> iShift) << nLen, b = (b >> iShift) << nLen, r = (r >> iShift) << nLen; + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + if ((g | b | r) & ~0xffff) + pDst[0] = _CLIPU16(r), pDst[1] = _CLIPU16(g), pDst[2] = _CLIPU16(b); + else + pDst[0] = (U16)r, pDst[1] = (U16)g, pDst[2] = (U16)b; + } + } + break; + } + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannel(pSC, iFirstRow, iFirstColumn, cWidth, cHeight, iShift, iBias); + break; + + case YUV_422: + { + PixelI y0, y1, u, v; + const ORIENTATION oO = pSC->WMII.oOrientation; + const size_t i0 = ((oO == O_FLIPH || oO == O_FLIPVH || oO == O_RCW_FLIPV || oO == O_RCW_FLIPVH) ? 1 : 0), i1 = 1 - i0; + + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn += 2){ + iIdx = ((iColumn >> 4) << 7) + idxCC[iRow][(iColumn >> 1) & 7]; + u = ((pU[iIdx] + iBias) >> iShift) << nLen, v = ((pV[iIdx] + iBias) >> iShift) << nLen; + + y0 = ((pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift) << nLen; + y1 = ((pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]] + iBias) >> iShift) << nLen; + + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> 1] + iY; + if ((y0 | y1 | u | v) & ~0xffff) + { + pDst[i0] = _CLIPU16(u); + pDst[i1] = _CLIPU16(y0); + pDst[2] = _CLIPU16(v); + pDst[3] = _CLIPU16(y1); + } + else + { + pDst[i0] = (U16)(u); + pDst[i1] = (U16)(y0); + pDst[2] = (U16)(v); + pDst[3] = (U16)(y1); + } + } + } + } + break; + + case YUV_420: + { + PixelI y0, y1, y2, y3, u, v; + const size_t iS4[8][4] = {{0, 1, 2, 3}, {2, 3, 0, 1}, {1, 0, 3, 2}, {3, 2, 1, 0}, {1, 3, 0, 2}, {3, 1, 2, 0}, {0, 2, 1, 3}, {2, 0, 3, 1}}; + const ORIENTATION oO = pSC->WMII.oOrientation; + const size_t i0 = iS4[oO][0], i1 = iS4[oO][1], i2 = iS4[oO][2], i3 = iS4[oO][3]; + + for(iRow = iFirstRow; iRow < cHeight; iRow += 2){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> 1]; iColumn < cWidth; iColumn += 2){ + iIdx = ((iColumn >> 3) << 6) + idxCC[iRow][(iColumn >> 1) & 7]; + u = ((pU[iIdx] + iBias) >> iShift) << nLen, v = ((pV[iIdx] + iBias) >> iShift) << nLen; + + y0 = ((pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iBias) >> iShift) << nLen; + y1 = ((pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]] + iBias) >> iShift) << nLen; + y2 = ((pY[((iColumn >> 4) << 8) + idxCC[iRow + 1][iColumn & 15]] + iBias) >> iShift) << nLen; + y3 = ((pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow + 1][(iColumn + 1) & 15]] + iBias) >> iShift) << nLen; + + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> 1] + iY; + if ((y0 | y1 | y2 | y3 | u | v) & ~0xffff) + { + pDst[i0] = _CLIPU16(y0); + pDst[i1] = _CLIPU16(y1); + pDst[i2] = _CLIPU16(y2); + pDst[i3] = _CLIPU16(y3); + pDst[4] = _CLIPU16(u); + pDst[5] = _CLIPU16(v); + } + else + { + pDst[i0] = (U16)(y0); + pDst[i1] = (U16)(y1); + pDst[i2] = (U16)(y2); + pDst[i3] = (U16)(y3); + pDst[4] = (U16)(u); + pDst[5] = (U16)(v); + } + } + } + } + break; + + case CMYK: + { + PixelI c, m, y, k; + PixelI * pK = pSC->a0MBbuffer[3]; + const PixelI iBias1 = (32768 >> nLen) << iShift; + const PixelI iBias2 = iBias - iBias1; + + for(iRow = iFirstRow; iRow < cHeight; iRow++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + m = -pY[iIdx] + iBias1, c = pU[iIdx], y = -pV[iIdx], k = pK[iIdx] + iBias2; + + _ICC_CMYK(c, m, y, k); // color conversion + + c = (c >> iShift) << nLen, m = (m >> iShift) << nLen, y = (y >> iShift) << nLen, k = (k >> iShift) << nLen; + + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + if ((c | m | y | k) & ~0xffff) + pDst[0] = _CLIPU16(c), pDst[1] = _CLIPU16(m), pDst[2] = _CLIPU16(y), pDst[3] = _CLIPU16(k); + else + pDst[0] = (U16)(c), pDst[1] = (U16)(m), pDst[2] = (U16)(y), pDst[3] = (U16)(k); + } + } + } + break; + default: + assert(0); + break; + } + } + else if(bd == BD_16S){ + const PixelI iBias = pSC->m_param.bScaledArith ? ((1 << (SHIFTZERO + QPFRACBITS - 1)) - 1) : 0; + I16 * pDst; + + switch(cfExt){ + case CF_RGB: + { + PixelI r, g, b; + + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + r = (r >> iShift) << nLen, g = (g >> iShift) << nLen, b = (b >> iShift) << nLen; + + pDst = (I16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + pDst[0] = _CLIP16(r), pDst[1] = _CLIP16(g), pDst[2] = _CLIP16(b); + } + break; + } + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannel(pSC, iFirstRow, iFirstColumn, cWidth, cHeight, iShift, iBias); + break; + + case CMYK: + { + PixelI c, m, y, k; + PixelI * pK = pSC->a0MBbuffer[3]; + + for(iRow = iFirstRow; iRow < cHeight; iRow++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + m = -pY[iIdx], c = pU[iIdx], y = -pV[iIdx], k = pK[iIdx] + iBias; + + _ICC_CMYK(c, m, y, k); // color conversion + + c = (c >> iShift) << nLen, m = (m >> iShift) << nLen, y = (y >> iShift) << nLen, k = (k >> iShift) << nLen; + + pDst = (I16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + pDst[0] = (I16)(c), pDst[1] = (I16)(m), pDst[2] = (I16)(y), pDst[3] = (I16)(k); + } + } + } + break; + + default: + assert(0); + break; + } + } + else if(bd == BD_16F){ + const PixelI iBias = pSC->m_param.bScaledArith ? ((1 << (SHIFTZERO + QPFRACBITS - 1)) - 1) : 0; + U16 *pDst; + + switch (cfExt) + { + case CF_RGB: + { + PixelI r, g, b; + + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + pDst[0] = backwardHalf(r >> iShift); + pDst[1] = backwardHalf(g >> iShift); + pDst[2] = backwardHalf(b >> iShift); + } + } + break; + } + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannel(pSC, iFirstRow, iFirstColumn, cWidth, cHeight, iShift, iBias); + break; + + default: + assert(0); + break; + } + } + else if(bd == BD_32){ + const PixelI iBias = (((1 << 31) >> nLen) << iShift) + (iShift == 0 ? 0 : (1 << (iShift - 1))); + U32 * pDst; + + switch (cfExt) + { + case CF_RGB: + { + PixelI r, g, b; + + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + pDst = (U32 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + pDst[0] = ((r >> iShift) << nLen); + pDst[1] = ((g >> iShift) << nLen); + pDst[2] = ((b >> iShift) << nLen); + } + } + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + { + outputNChannel(pSC, iFirstRow, iFirstColumn, cWidth, cHeight, iShift, iBias); + break; + } + default: + assert(0); + break; + } + } + else if(bd == BD_32S){ + const PixelI iBias = pSC->m_param.bScaledArith ? ((1 << (SHIFTZERO + QPFRACBITS - 1)) - 1) : 0; + int * pDst; + + switch (cfExt) + { + case CF_RGB: + { + PixelI r, g, b; + + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + pDst = (int *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + pDst[0] = ((r >> iShift) << nLen); + pDst[1] = ((g >> iShift) << nLen); + pDst[2] = ((b >> iShift) << nLen); + } + } + break; + } + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannel(pSC, iFirstRow, iFirstColumn, cWidth, cHeight, iShift, iBias); + break; + + default: + assert(0); + break; + } + } + else if(bd == BD_32F){ + const PixelI iBias = pSC->m_param.bScaledArith ? ((1 << (SHIFTZERO + QPFRACBITS - 1)) - 1) : 0; + float * pDst; + + switch (cfExt) + { + case CF_RGB: + { + PixelI r, g, b; + + for(iRow = iFirstRow; iRow < cHeight; iRow ++){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + pDst = (float *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + pDst[0] = pixel2float (r >> iShift, nExpBias, nLen); + pDst[1] = pixel2float (g >> iShift, nExpBias, nLen); + pDst[2] = pixel2float (b >> iShift, nExpBias, nLen); + } + } + break; + } + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannel(pSC, iFirstRow, iFirstColumn, cWidth, cHeight, iShift, iBias); + break; + + default: + assert(0); + break; + } + } + else if(bd == BD_5){ + const PixelI iBias = (16 << iShift) + (pSC->m_param.bScaledArith ? ((1 << (SHIFTZERO + QPFRACBITS - 1)) - 1) : 0); + PixelI r, g, b; + U16 * pDst; + + assert(cfExt == CF_RGB); + + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + g >>= iShift, b >>= iShift, r >>= iShift; + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + if (pSC->m_param.bRBSwapped) + pDst[0] = (U16)_CLIP2(0, b, 31) + (((U16)_CLIP2(0, g, 31)) << 5) + (((U16)_CLIP2(0, r, 31)) << 10); + else + pDst[0] = (U16)_CLIP2(0, r, 31) + (((U16)_CLIP2(0, g, 31)) << 5) + (((U16)_CLIP2(0, b, 31)) << 10); + } + } + else if(bd == BD_565){ + const PixelI iBias = (32 << iShift) + (pSC->m_param.bScaledArith ? ((1 << (SHIFTZERO + QPFRACBITS - 1)) - 1) : 0); + PixelI r, g, b; + U16 * pDst; + + assert(cfExt == CF_RGB); + + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + g >>= iShift, b >>= iShift + 1, r >>= iShift + 1; + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + if (pSC->m_param.bRBSwapped) + pDst[0] = (U16)_CLIP2(0, b, 31) + (((U16)_CLIP2(0, g, 63)) << 5) + (((U16)_CLIP2(0, r, 31)) << 11); + else + pDst[0] = (U16)_CLIP2(0, r, 31) + (((U16)_CLIP2(0, g, 63)) << 5) + (((U16)_CLIP2(0, b, 31)) << 11); + } + } + else if(bd == BD_10){ + const PixelI iBias = (512 << iShift) + (pSC->m_param.bScaledArith ? ((1 << (SHIFTZERO + QPFRACBITS - 1)) - 1) : 0); + PixelI r, g, b; + U32 * pDst; + + assert(cfExt == CF_RGB); + + for(iRow = iFirstRow; iRow < cHeight; iRow ++) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){ + iIdx = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + g = pY[iIdx] + iBias, r = -pU[iIdx], b = pV[iIdx]; + + _ICC(r, g, b); + + g >>= iShift, b >>= iShift, r >>= iShift; + + pDst = (U32 *)pSC->WMIBI.pv + pOffsetX[iColumn] + iY; + if (pSC->m_param.bRBSwapped) + pDst[0] = (U32)_CLIP2(0, b, 1023) + + (((U32)_CLIP2(0, g, 1023)) << 10) + + (((U32)_CLIP2(0, r, 1023)) << 20); + else + pDst[0] = (U32)_CLIP2(0, r, 1023) + + (((U32)_CLIP2(0, g, 1023)) << 10) + + (((U32)_CLIP2(0, b, 1023)) << 20); + } + } + else if(bd == BD_1){ + const size_t iPos = pSC->WMII.cLeadingPadding; + const Int iTh = (iShift > 0) ? (1 << (iShift - 1)) : 1; + assert(cfExt == Y_ONLY && pSC->m_param.cfColorFormat == Y_ONLY); + + if(pSC->WMII.oOrientation < O_RCW) + for(iRow = iFirstRow; iRow < cHeight; iRow ++) { + iY = pOffsetY[iRow] + iPos; + for(iColumn = iFirstColumn; iColumn < cWidth; iColumn ++) { + U8 cByte = ((U8 *)pSC->WMIBI.pv + (pOffsetX[iColumn] >> 3) + iY)[0]; + U8 cShift = (U8)(7 - (pOffsetX[iColumn] & 7)); + ((U8 *)pSC->WMIBI.pv + (pOffsetX[iColumn] >> 3) + iY)[0] ^= // exor is used because we can't assume the byte was originally zero + (((pSC->WMISCP.bBlackWhite + (pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] >= iTh) + + (cByte >> cShift)) & 0x1) << cShift); + } + } + else + for(iRow = iFirstRow; iRow < cHeight; iRow ++) { + iY = pOffsetY[iRow] + iPos; + for(iColumn = iFirstColumn; iColumn < cWidth; iColumn ++) { + U8 cByte = ((U8 *)pSC->WMIBI.pv + pOffsetX[iColumn] + (iY >> 3))[0]; + U8 cShift = (U8)(7 - (iY & 7)); // should be optimized out + ((U8 *)pSC->WMIBI.pv + pOffsetX[iColumn] + (iY >> 3))[0] ^= // exor is used because we can't assume the byte was originally zero + (((pSC->WMISCP.bBlackWhite + (pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] >= iTh) + + (cByte >> cShift)) & 0x1) << cShift); + } + } + } + + if(pSC->WMISCP.uAlphaMode > 0) + if(outputMBRowAlpha(pSC) != ICERR_OK) + return ICERR_ERROR; + +#ifdef REENTRANT_MODE + pSC->WMIBI.cLinesDecoded = cHeight - iFirstRow; + + if (CF_RGB == pSC->WMII.cfColorFormat && Y_ONLY == pSC->WMISCP.cfColorFormat) + { + const CWMImageInfo* pII = &pSC->WMII; + +#define fixupFullSize(type, nCh) \ +for(iRow = iFirstRow; iRow < cHeight; iRow ++) {\ + size_t iOffsetY;\ + for(iColumn = iFirstColumn, iOffsetY = pOffsetY[iRow]; iColumn < cWidth; iColumn ++){\ + type *pT = (type*)(U8 *)pSC->WMIBI.pv + iOffsetY + pOffsetX[iColumn];\ + pT[2] = pT[1] = pT[0]; \ + pT += nCh; \ + } \ +} \ +break + + switch (pII->bdBitDepth) + { + case BD_8: + fixupFullSize(U8, (pII->cBitsPerUnit >> 3)); + break; + + case BD_16: + case BD_16S: + case BD_16F: + fixupFullSize(U16, (pII->cBitsPerUnit >> 3) / sizeof(U16)); + break; + + case BD_32: + case BD_32S: + case BD_32F: + fixupFullSize(U32, (pII->cBitsPerUnit >> 3) / sizeof(float)); + break; + + case BD_5: + case BD_10: + case BD_565: + default: + break; + } + } +#endif + + return ICERR_OK; +} + +// Y_ONLY/CF_ALPHA/YUV_444/N_CHANNEL thumbnail decode +Void outputNChannelThumbnail(CWMImageStrCodec * pSC, const PixelI cMul, const size_t rShiftY, size_t iFirstRow, size_t iFirstColumn) +{ + const size_t tScale = pSC->m_Dparam->cThumbnailScale; + const size_t cWidth = (pSC->m_Dparam->cROIRightX + 1); + const size_t cHeight = min((pSC->m_Dparam->cROIBottomY + 1) - (pSC->cRow - 1) * 16, 16); + const size_t cChannel = pSC->WMISCP.cChannel; + const U8 nLen = pSC->WMISCP.nLenMantissaOrShift; + const I8 nExpBias = pSC->WMISCP.nExpBias; + size_t nBits = 0; + PixelI iOffset; + PixelI * pChannel[16]; + size_t iChannel, iRow, iColumn; + size_t * pOffsetX = pSC->m_Dparam->pOffsetX, * pOffsetY = pSC->m_Dparam->pOffsetY + (pSC->cRow - 1) * 16 / tScale, iY; + + while((size_t)(1U << nBits) < tScale) + nBits ++; + + assert(cChannel <= 16); + + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pChannel[iChannel & 15] = pSC->a0MBbuffer[iChannel]; + + if(pSC->m_bUVResolutionChange) + pChannel[1] = pSC->pResU, pChannel[2] = pSC->pResV; + + switch(pSC->WMII.bdBitDepth){ + case BD_8: + for(iOffset = (128 << rShiftY) / cMul, iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + U8 * pDst = (U8 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn >> nBits]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = ((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iOffset) * cMul) >> rShiftY; + + pDst[iChannel] = _CLIP8(p); + } + } + } + break; + + case BD_16: + for(iOffset = (32768 << rShiftY) / cMul, iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + U16 * pDst = (U16 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn >> nBits]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = (((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iOffset) * cMul) >> rShiftY) << nLen; + + pDst[iChannel] = _CLIPU16(p); + } + } + } + break; + + case BD_16S: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + I16 * pDst = (I16 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn >> nBits]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = ((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] * cMul) >> rShiftY) << nLen; + + pDst[iChannel] = _CLIP16(p); + } + } + } + break; + + case BD_16F: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + U16 * pDst = (U16 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn >> nBits]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = (pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] * cMul) >> rShiftY; + + pDst[iChannel] = backwardHalf(p); + } + } + } + break; + case BD_32: + for(iOffset = (((1 << 31) >> nLen) << rShiftY) / cMul, iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + U32 * pDst = (U32 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn >> nBits]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = (((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] + iOffset) * cMul) >> rShiftY) << nLen; + + pDst[iChannel] = (U32)(p); + } + } + } + break; + case BD_32S: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + I32 * pDst = (I32 *)pSC->WMIBI.pv + iY + pOffsetX[iColumn >> nBits]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = ((pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] * cMul) >> rShiftY) << nLen; + + pDst[iChannel] = (I32)(p); + } + } + } + break; + case BD_32F: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + float * pDst = (float *)pSC->WMIBI.pv + iY + pOffsetX[iColumn >> nBits]; + + for(iChannel = 0; iChannel < cChannel; iChannel ++){ + PixelI p = (pChannel[iChannel & 15][((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] * cMul) >> rShiftY; + + pDst[iChannel] = pixel2float (p, nExpBias, nLen); + } + } + } + break; + + default: + assert(0); + break; + } +} + +// centralized alpha channel thumbnail, small perf penalty +Int decodeThumbnailAlpha(CWMImageStrCodec * pSC, const size_t nBits, const PixelI cMul, const size_t rShiftY) +{ + if(pSC->m_bSecondary == FALSE && pSC->m_pNextSC != NULL){ // with alpha channel + const size_t tScale = (size_t)(1U << nBits); + const size_t cHeight = min((pSC->m_Dparam->cROIBottomY + 1) - (pSC->cRow - 1) * 16, 16); + const size_t cWidth = (pSC->m_Dparam->cROIRightX + 1); + const size_t iFirstRow = ((((pSC->cRow - 1) * 16 > pSC->m_Dparam->cROITopY ? 0 : (pSC->m_Dparam->cROITopY & 0xf)) + tScale - 1) / tScale * tScale); + const size_t iFirstColumn = (pSC->m_Dparam->cROILeftX + tScale - 1) / tScale * tScale; + const size_t iAlphaPos = pSC->WMII.cLeadingPadding + (pSC->WMII.cfColorFormat == CMYK ? 4 : 3);//only RGB and CMYK may have interleaved alpha + const BITDEPTH_BITS bd = pSC->WMII.bdBitDepth; + const PixelI * pSrc = pSC->m_pNextSC->a0MBbuffer[0]; + const U8 nLen = pSC->m_pNextSC->WMISCP.nLenMantissaOrShift; + const I8 nExpBias = pSC->m_pNextSC->WMISCP.nExpBias; + size_t iRow, iColumn; + size_t * pOffsetX = pSC->m_Dparam->pOffsetX, * pOffsetY = pSC->m_Dparam->pOffsetY + (pSC->cRow - 1) * 16 / tScale, iY; + + if (CF_RGB != pSC->WMII.cfColorFormat && CMYK != pSC->WMII.cfColorFormat) + return ICERR_ERROR; + + if(bd == BD_8){ + const PixelI offset = (128 << rShiftY) / cMul; + + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + PixelI a = ((pSrc[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] + offset) * cMul) >> rShiftY; + + ((U8 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY)[iAlphaPos] = _CLIP8(a); + } + } + else if(bd == BD_16){ + const PixelI offset = (32768 << rShiftY) / cMul; + + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + PixelI a = (((pSrc[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] + offset) * cMul) >> rShiftY) << nLen; + + ((U16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY)[iAlphaPos] = _CLIPU16(a); + } + } + else if(bd == BD_16S){ + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + PixelI a = ((pSrc[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] * cMul) >> rShiftY) << nLen; + + ((I16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY)[iAlphaPos] = _CLIP16(a); + } + } + else if(bd == BD_16F){ + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + PixelI a = (pSrc[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] * cMul) >> rShiftY; + + ((U16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY)[iAlphaPos] = backwardHalf(a); + } + } + else if(bd == BD_32S){ + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + PixelI a = ((pSrc[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] * cMul) >> rShiftY) << nLen; + + ((I32 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY)[iAlphaPos] = a; + } + } + else if(bd == BD_32F){ + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + PixelI a = (pSrc[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] * cMul) >> rShiftY; + + ((float *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY)[iAlphaPos] = pixel2float (a, nExpBias, nLen); + } + } + else // not supported + return ICERR_ERROR; + } + + return ICERR_OK; +} + +Int decodeThumbnail(CWMImageStrCodec * pSC) +{ + const size_t tScale = pSC->m_Dparam->cThumbnailScale; + const size_t cHeight = min((pSC->m_Dparam->bDecodeFullFrame ? pSC->WMII.cHeight : pSC->m_Dparam->cROIBottomY + 1) - (pSC->cRow - 1) * 16, 16); + const size_t cWidth = (pSC->m_Dparam->bDecodeFullFrame ? pSC->WMII.cWidth : pSC->m_Dparam->cROIRightX + 1); + const size_t iFirstRow = ((((pSC->cRow - 1) * 16 > pSC->m_Dparam->cROITopY ? 0 : (pSC->m_Dparam->cROITopY & 0xf)) + tScale - 1) / tScale * tScale); + const size_t iFirstColumn = (pSC->m_Dparam->cROILeftX + tScale - 1) / tScale * tScale; + const COLORFORMAT cfInt = pSC->m_param.cfColorFormat; + const COLORFORMAT cfExt = (pSC->m_param.cfColorFormat == Y_ONLY ? Y_ONLY : pSC->WMII.cfColorFormat); + const BITDEPTH_BITS bd = pSC->WMII.bdBitDepth; + const OVERLAP ol = pSC->WMISCP.olOverlap; + const size_t iB = (pSC->WMII.bRGB ? 2 : 0); + const size_t iR = 2 - iB; + + const U8 nLen = pSC->WMISCP.nLenMantissaOrShift; + const I8 nExpBias = pSC->WMISCP.nExpBias; + PixelI offset; + size_t iRow, iColumn, iIdx1, iIdx2, iIdx3 = 0, nBits = 0; + PixelI * pSrcY = pSC->a0MBbuffer[0]; + PixelI * pSrcU = pSC->a0MBbuffer[1], * pSrcV = pSC->a0MBbuffer[2]; + size_t * pOffsetX = pSC->m_Dparam->pOffsetX, * pOffsetY = pSC->m_Dparam->pOffsetY + (pSC->cRow - 1) * 16 / tScale, iY; + const PixelI cMul = (tScale >= 16 ? (ol == OL_NONE ? 16 : (ol == OL_ONE ? 23 : 34)) : (tScale >= 4 ? (ol == OL_NONE ? 64 : 93) : 258)); + const size_t rShiftY = 8 + (pSC->m_param.bScaledArith ? (SHIFTZERO + QPFRACBITS) : 0); + const size_t rShiftUV = rShiftY - ((pSC->m_param.bScaledArith && tScale >= 16) ? ((cfInt == YUV_420 || cfInt == YUV_422) ? 2 : 1) : 0); + + while((size_t)(1U << nBits) < tScale) + nBits ++; + + assert(tScale == (size_t)(1U << nBits)); + + // guard output buffer + if(checkImageBuffer(pSC, pSC->WMII.oOrientation < O_RCW ? pSC->WMII.cROIWidth : pSC->WMII.cROIHeight, (cHeight - iFirstRow) / pSC->m_Dparam->cThumbnailScale) != ICERR_OK) + return ICERR_ERROR; + + if((((pSC->cRow - 1) * 16) % tScale) != 0) + return ICERR_OK; + + if(pSC->cRow * 16 <= pSC->m_Dparam->cROITopY || pSC->cRow * 16 > pSC->m_Dparam->cROIBottomY + 16) + return ICERR_OK; + + if((cfInt == YUV_422 || cfInt == YUV_420) && cfExt != Y_ONLY){ + PixelI * pDstU = pSC->pResU, * pDstV = pSC->pResV; + + for(iRow = 0; iRow < 16; iRow += tScale){ + for(iColumn = 0; iColumn < cWidth; iColumn += tScale){ + iIdx1 = (cfInt == YUV_422 ? ((iColumn >> 4) << 7) + idxCC[iRow][(iColumn >> 1) & 7] : ((iColumn >> 4) << 6) + idxCC_420[iRow >> 1][(iColumn >> 1) & 7]); + iIdx2 = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + + // copy over + pDstU[iIdx2] = pSrcU[iIdx1]; + pDstV[iIdx2] = pSrcV[iIdx1]; + } + } + + if(tScale == 4){ + if(cfInt == YUV_420){ + for(iColumn = 0; iColumn < cWidth; iColumn += 8){ + iIdx1 = ((iColumn >> 4) << 8) + idxCC[0][iColumn & 15]; + iIdx2 = ((iColumn >> 4) << 8) + idxCC[4][iColumn & 15]; + iIdx3 = ((iColumn >> 4) << 8) + idxCC[8][iColumn & 15]; + + pDstU[iIdx2] = ((pDstU[iIdx1] + pDstU[iIdx3] + 1) >> 1); + pDstV[iIdx2] = ((pDstV[iIdx1] + pDstV[iIdx3] + 1) >> 1); + + iIdx1 = ((iColumn >> 4) << 8) + idxCC[12][iColumn & 15]; + pDstU[iIdx1] = pDstU[iIdx3]; + pDstV[iIdx1] = pDstV[iIdx3]; + } + } + + for(iRow = 0; iRow < 16; iRow += 4){ + for(iColumn = 0; iColumn < cWidth - 8; iColumn += 8){ + iIdx1 = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]; + iIdx2 = ((iColumn >> 4) << 8) + idxCC[iRow][(iColumn + 4) & 15]; + iIdx3 = ((iColumn >> 4) << 8) + idxCC[iRow][(iColumn + 8) & 15]; + + pDstU[iIdx2] = ((pDstU[iIdx1] + pDstU[iIdx3] + 1) >> 1); + pDstV[iIdx2] = ((pDstV[iIdx1] + pDstV[iIdx3] + 1) >> 1); + } + + iIdx2 = ((iColumn >> 4) << 8) + idxCC[iRow][(iColumn + 4) & 15]; + pDstU[iIdx2] = pDstU[iIdx3]; + pDstV[iIdx2] = pDstV[iIdx3]; + } + } + + pSrcU = pDstU, pSrcV = pDstV; + } + + if(bd == BD_8){ + U8 * pDst; + + offset = (128 << rShiftY) / cMul; + + switch(cfExt){ + case CF_RGB: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = ((pSrcY[iPos] + offset) * cMul) >> rShiftY, r = -(pSrcU[iPos] * cMul) >> rShiftUV, b = (pSrcV[iPos] * cMul) >> rShiftUV; + + _ICC(r, g, b); + + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + pDst[iB] = _CLIP8(b), pDst[1] = _CLIP8(g), pDst[iR] = _CLIP8(r); + } + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannelThumbnail(pSC, cMul, rShiftY, iFirstRow, iFirstColumn); + break; + + case CF_RGBE: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = ((pSrcY[iPos] * cMul) >> rShiftY), r = - ((pSrcU[iPos] * cMul) >> rShiftUV), b = ((pSrcV[iPos] * cMul) >> rShiftUV); + + _ICC(r, g, b); + + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + inverseConvertRGBE (r, g, b, pDst, pDst + 1, pDst + 2, pDst + 3); + } + } + break; + + case CMYK: + { + PixelI * pSrcK = pSC->a0MBbuffer[3]; + PixelI iBias1 = (128 << rShiftY) / cMul, iBias2 = (((128 << rShiftUV) / cMul) >> 1); + + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI m = ((-pSrcY[iPos] + iBias1) * cMul) >> rShiftY, c = (pSrcU[iPos] * cMul) >> rShiftUV, y = -(pSrcV[iPos] * cMul) >> rShiftUV, k = ((pSrcK[iPos] + iBias2) * cMul) >> rShiftUV; + + _ICC_CMYK(c, m, y, k); + + pDst = (U8 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + pDst[0] = _CLIP8(c), pDst[1] = _CLIP8(m), pDst[2] = _CLIP8(y), pDst[3] = _CLIP8(k); + } + } + break; + } + default: + assert(0); + break; + } + } + if(bd == BD_16){ + U16 * pDst; + + offset = (((1 << 15) >> nLen) << rShiftY) / cMul; + + switch(cfExt){ + case CF_RGB: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = ((pSrcY[iPos] + offset) * cMul) >> rShiftY, r = -(pSrcU[iPos] * cMul) >> rShiftUV, b = (pSrcV[iPos] * cMul) >> rShiftUV; + + _ICC(r, g, b); + + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + r <<= nLen, g <<= nLen, b <<= nLen; + pDst[0] = _CLIPU16(r); + pDst[1] = _CLIPU16(g); + pDst[2] = _CLIPU16(b); + } + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannelThumbnail(pSC, cMul, rShiftY, iFirstRow, iFirstColumn); + break; + + case CMYK: + { + PixelI * pSrcK = pSC->a0MBbuffer[3]; + PixelI iBias1 = (32768 << rShiftY) / cMul, iBias2 = (((32768 << rShiftUV) / cMul) >> 1); + + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI m = ((-pSrcY[iPos] + iBias1) * cMul) >> rShiftY, c = (pSrcU[iPos] * cMul) >> rShiftUV, y = -(pSrcV[iPos] * cMul) >> rShiftUV, k = ((pSrcK[iPos] + iBias2) * cMul) >> rShiftUV; + + _ICC_CMYK(c, m, y, k); + + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + c <<= nLen, m <<= nLen, y <<= nLen, k <<= nLen; + pDst[0] = _CLIPU16(c); + pDst[1] = _CLIPU16(m); + pDst[2] = _CLIPU16(y); + pDst[3] = _CLIPU16(k); + } + } + break; + } + default: + assert(0); + break; + } + } + if(bd == BD_16S){ + I16 * pDst; + + switch(cfExt){ + case CF_RGB: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = (pSrcY[iPos] * cMul) >> rShiftY, r = -(pSrcU[iPos] * cMul) >> rShiftUV, b = (pSrcV[iPos] * cMul) >> rShiftUV; + + _ICC(r, g, b); + + pDst = (I16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + r <<= nLen, g <<= nLen, b <<= nLen; + pDst[0] = _CLIP16(r); + pDst[1] = _CLIP16(g); + pDst[2] = _CLIP16(b); + } + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannelThumbnail(pSC, cMul, rShiftY, iFirstRow, iFirstColumn); + break; + + case CMYK: + { + PixelI * pSrcK = pSC->a0MBbuffer[3]; + + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI m = -(pSrcY[iPos] * cMul) >> rShiftY, c = (pSrcU[iPos] * cMul) >> rShiftUV, y = -(pSrcV[iPos] * cMul) >> rShiftUV, k = (pSrcK[iPos] * cMul) >> rShiftUV; + + _ICC_CMYK(c, m, y, k); + + pDst = (I16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + c <<= nLen, m <<= nLen, y <<= nLen, k <<= nLen; + pDst[0] = _CLIP16(c); + pDst[1] = _CLIP16(m); + pDst[2] = _CLIP16(y); + pDst[3] = _CLIP16(k); + } + } + } + break; + + default: + assert(0); + break; + } + } + else if(bd == BD_16F){ + U16 * pDst; + + switch(cfExt){ + case CF_RGB: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = (pSrcY[iPos] * cMul) >> rShiftY, r = -(pSrcU[iPos] * cMul) >> rShiftUV, b = (pSrcV[iPos] * cMul) >> rShiftUV; + + _ICC(r, g, b); + + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + pDst[0] = backwardHalf (r); + pDst[1] = backwardHalf (g); + pDst[2] = backwardHalf (b); + } + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannelThumbnail(pSC, cMul, rShiftY, iFirstRow, iFirstColumn); + break; + + default: + assert(0); + break; + } + } + else if(bd == BD_32){ + U32 * pDst; + + offset = (((1 << 31) >> nLen) << rShiftY) / cMul; + + switch(cfExt){ + case CF_RGB: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = ((pSrcY[iPos] + offset) * cMul) >> rShiftY, r = -(pSrcU[iPos] * cMul) >> rShiftUV, b = (pSrcV[iPos] * cMul) >> rShiftUV; + + _ICC(r, g, b); + + pDst = (U32 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + + pDst[0] = (U32)(r << nLen); + pDst[1] = (U32)(g << nLen); + pDst[2] = (U32)(b << nLen); + } + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannelThumbnail(pSC, cMul, rShiftY, iFirstRow, iFirstColumn); + break; + + default: + assert(0); + break; + } + } + else if(bd == BD_32S){ + I32 * pDst; + + switch(cfExt){ + case CF_RGB: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = (pSrcY[iPos] * cMul) >> rShiftY, r = -(pSrcU[iPos] * cMul) >> rShiftUV, b = (pSrcV[iPos] * cMul) >> rShiftUV; + + _ICC(r, g, b); + + pDst = (I32 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + pDst[0] = (I32)(r << nLen); + pDst[1] = (I32)(g << nLen); + pDst[2] = (I32)(b << nLen); + } + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannelThumbnail(pSC, cMul, rShiftY, iFirstRow, iFirstColumn); + break; + + default: + assert(0); + break; + } + } + + else if(bd == BD_32F){ + float * pDst; + + switch(cfExt){ + case CF_RGB: + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = (pSrcY[iPos] * cMul) >> rShiftY, r = -(pSrcU[iPos] * cMul) >> rShiftUV, b = (pSrcV[iPos] * cMul) >> rShiftUV; + + _ICC(r, g, b); + + pDst = (float *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + pDst[0] = pixel2float (r, nExpBias, nLen); + pDst[1] = pixel2float (g, nExpBias, nLen); + pDst[2] = pixel2float (b, nExpBias, nLen); + } + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + outputNChannelThumbnail(pSC, cMul, rShiftY, iFirstRow, iFirstColumn); + break; + + default: + assert(0); + break; + } + } + else if(bd == BD_1){ + const size_t iPos = pSC->WMII.cLeadingPadding; + Bool bBW; + U8 cByte, cShift; + assert(cfExt == Y_ONLY && pSC->m_param.cfColorFormat == Y_ONLY); + + if(pSC->WMII.oOrientation < O_RCW){ + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits] + iPos; iColumn < cWidth; iColumn += tScale){ + bBW = (pSC->WMISCP.bBlackWhite ^ (pSrcY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] > 0)); + cByte = ((U8 *)pSC->WMIBI.pv + (pOffsetX[iColumn >> nBits] >> 3) + iY)[0]; + cShift = (U8)(7 - (pOffsetX[iColumn >> nBits] & 7)); + ((U8 *)pSC->WMIBI.pv + (pOffsetX[iColumn >> nBits] >> 3) + iY)[0] ^= ((((bBW + (cByte >> cShift)) & 0x1)) << cShift); + } + } + else{ + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale) + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits] + iPos; iColumn < cWidth; iColumn += tScale){ + bBW = (pSC->WMISCP.bBlackWhite ^ (pSrcY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] > 0)); + cByte = ((U8 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + (iY >> 3))[0]; + cShift = (U8)(7 - (iY & 7)); + ((U8 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + (iY >> 3))[0] ^= ((((bBW + (cByte >> cShift)) & 0x1)) << cShift); + } + } + } + else if(bd == BD_5){ + U16 * pDst; + + offset = (16 << rShiftY) / cMul; + + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = ((pSrcY[iPos] + offset) * cMul) >> rShiftY, r = -(pSrcU[iPos] * cMul) >> rShiftUV, b = (pSrcV[iPos] * cMul) >> rShiftUV; + + _ICC(r, g, b); + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + pDst[0] = (U16)_CLIP2(0, r, 31) + (((U16)_CLIP2(0, g, 31)) << 5) + (((U16)_CLIP2(0, b, 31)) << 10); + } + } + } + else if(bd == BD_565){ + U16 * pDst; + + offset = (32 << rShiftY) / cMul; + + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = ((pSrcY[iPos] + offset) * cMul) >> rShiftY, r = -(pSrcU[iPos] * cMul) >> rShiftUV, b = (pSrcV[iPos] * cMul) >> rShiftUV; + + _ICC(r, g, b); + r /= 2, b /= 2; + pDst = (U16 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + pDst[0] = (U16)_CLIP2(0, r, 31) + (((U16)_CLIP2(0, g, 63)) << 5) + (((U16)_CLIP2(0, b, 31)) << 11); + } + } + } + else if(bd == BD_10){ + U32 * pDst; + + offset = (512 << rShiftY) / cMul; + + for(iRow = iFirstRow; iRow < cHeight; iRow += tScale){ + for(iColumn = iFirstColumn, iY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){ + size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + PixelI g = ((pSrcY[iPos] + offset) * cMul) >> rShiftY, r = -(pSrcU[iPos] * cMul) >> rShiftUV, b = (pSrcV[iPos] * cMul) >> rShiftUV; + + _ICC(r, g, b); + pDst = (U32 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iY; + pDst[0] = (U32)_CLIP2(0, r, 1023) + + (((U32)_CLIP2(0, g, 1023)) << 10) + + (((U32)_CLIP2(0, b, 1023)) << 20); + } + } + } + + if(pSC->WMISCP.uAlphaMode > 0) + if(decodeThumbnailAlpha(pSC, nBits, cMul, rShiftY) != ICERR_OK) + return ICERR_ERROR; + +#ifdef REENTRANT_MODE + pSC->WMIBI.cLinesDecoded = ( cHeight - iFirstRow + tScale - 1 ) / tScale; + if (CF_RGB == pSC->WMII.cfColorFormat && Y_ONLY == pSC->WMISCP.cfColorFormat) + { + const CWMImageInfo* pII = &pSC->WMII; + +#define fixupThumb(type, nCh) \ +for(iRow = iFirstRow; iRow < cHeight; iRow += tScale) {\ + size_t iOffsetY;\ + for(iColumn = iFirstColumn, iOffsetY = pOffsetY[iRow >> nBits]; iColumn < cWidth; iColumn += tScale){\ + type *pT = (type*)((U8 *)pSC->WMIBI.pv + pOffsetX[iColumn >> nBits] + iOffsetY);\ + pT[iB] = pT[1] = pT[iR]; \ + } \ +} \ +break + + switch (pII->bdBitDepth) + { + case BD_8: + fixupThumb(U8, (pII->cBitsPerUnit >> 3)); + break; + + case BD_16: + case BD_16S: + case BD_16F: + fixupThumb(U16, (pII->cBitsPerUnit >> 3) / sizeof(U16)); + break; + + case BD_32: + case BD_32S: + case BD_32F: + fixupThumb(U32, (pII->cBitsPerUnit >> 3) / sizeof(float)); + break; + + case BD_5: + case BD_10: + case BD_565: + default: + break; + } + } +#endif + + return ICERR_OK; +} + +/************************************************************************* + Read variable length byte aligned integer +*************************************************************************/ +static size_t GetVLWordEsc(BitIOInfo* pIO, Int *iEscape) +{ + size_t s; + + if (iEscape) + *iEscape = 0; + + s = getBit32(pIO, 8); + if (s == 0xfd || s == 0xfe || s == 0xff) { + if (iEscape) + *iEscape = (Int) s; + s = 0; + } + else if (s < 0xfb) { + s = (s << 8) | getBit32(pIO, 8); + } + else { + s -= 0xfb; + if (s) { + s = getBit32(pIO, 16) << 16; + s = (s | getBit32(pIO, 16)) << 16; + s <<= 16; + } + s |= (getBit32(pIO, 16) << 16); + s |= getBit32(pIO, 16); + } + return s; +} + +//================================================================ +Int readIndexTable(CWMImageStrCodec * pSC) +{ + BitIOInfo* pIO = pSC->pIOHeader; + readIS_L1(pSC, pIO); + + if(pSC->cNumBitIO > 0){ + size_t *pTable = pSC->pIndexTable; + U32 iEntry = (U32)pSC->cNumBitIO * (pSC->WMISCP.cNumOfSliceMinus1H + 1), i; + + // read index table header [0x0001] - 2 bytes + if (getBit32(pIO, 16) != 1) + return ICERR_ERROR; + + //iBits = getBit16(pIO, 5) + 1; // how many bits per entry + for(i = 0; i < iEntry; i ++){ + readIS_L1(pSC, pIO); + pTable[i] = GetVLWordEsc(pIO, NULL); // escape handling is not important since the respective band is not accessed + } + } + + pSC->cHeaderSize = GetVLWordEsc(pIO, NULL); // escape handling is not important + flushToByte(pIO); + + pSC->cHeaderSize += getPosRead(pSC->pIOHeader); // get header length + + return ICERR_OK; +} + +Int StrIODecInit(CWMImageStrCodec* pSC) +{ + if(allocateBitIOInfo(pSC) != ICERR_OK){ + return ICERR_ERROR; + } + + attachISRead(pSC->pIOHeader, pSC->WMISCP.pWStream, pSC); + + readIndexTable(pSC); + + if(pSC->WMISCP.bVerbose){ + U32 i, j; + + printf("\n%d horizontal tiles:\n", pSC->WMISCP.cNumOfSliceMinus1H + 1); + for(i = 0; i <= pSC->WMISCP.cNumOfSliceMinus1H; i ++){ + printf(" offset of tile %d in MBs: %d\n", i, pSC->WMISCP.uiTileY[i]); + } + + printf("\n%d vertical tiles:\n", pSC->WMISCP.cNumOfSliceMinus1V + 1); + for(i = 0; i <= pSC->WMISCP.cNumOfSliceMinus1V; i ++){ + printf(" offset of tile %d in MBs: %d\n", i, pSC->WMISCP.uiTileX[i]); + } + + if(pSC->WMISCP.bfBitstreamFormat == SPATIAL){ + printf("\nSpatial order bitstream\n"); + } + else{ + printf("\nFrequency order bitstream\n"); + } + + if(!pSC->m_param.bIndexTable){ + printf("\nstreaming mode, no index table.\n"); + } + else if(pSC->WMISCP.bfBitstreamFormat == SPATIAL){ + for(j = 0; j <= pSC->WMISCP.cNumOfSliceMinus1H; j ++){ + for(i = 0; i <= pSC->WMISCP.cNumOfSliceMinus1V; i ++){ + size_t * p = &pSC->pIndexTable[j * (pSC->WMISCP.cNumOfSliceMinus1V + 1) + i]; + if(i + j != pSC->WMISCP.cNumOfSliceMinus1H + pSC->WMISCP.cNumOfSliceMinus1V){ + printf("bitstream size for tile (%d, %d): %d.\n", j, i, (int) (p[1] - p[0])); + } + else{ + printf("bitstream size for tile (%d, %d): unknown.\n", j, i); + } + } + } + } + else{ + for(j = 0; j <= pSC->WMISCP.cNumOfSliceMinus1H; j ++){ + for(i = 0; i <= pSC->WMISCP.cNumOfSliceMinus1V; i ++){ + size_t * p = &pSC->pIndexTable[(j * (pSC->WMISCP.cNumOfSliceMinus1V + 1) + i) * 4]; + if(i + j != pSC->WMISCP.cNumOfSliceMinus1H + pSC->WMISCP.cNumOfSliceMinus1V){ + printf("bitstream size of (DC, LP, AC, FL) for tile (%d, %d): %d %d %d %d.\n", j, i, + (int) (p[1] - p[0]), (int) (p[2] - p[1]), (int) (p[3] - p[2]), (int) (p[4] - p[3])); + } + else{ + printf("bitstream size of (DC, LP, AC, FL) for tile (%d, %d): %d %d %d unknown.\n", j, i, + (int) (p[1] - p[0]), (int) (p[2] - p[1]), (int) (p[3] - p[2])); + } + } + } + } + } + + return 0; +} + +Int StrIODecTerm(CWMImageStrCodec* pSC) +{ + detachISRead(pSC, pSC->pIOHeader); + + free(pSC->m_ppBitIO); + free(pSC->pIndexTable); + + return 0; +} + +Int initLookupTables(CWMImageStrCodec* pSC) +{ + static const U8 cbChannels[BDB_MAX] = {1, 1, 2, 2, 2, 4, 4, 4, (U8) -1, (U8) -1, (U8) -1 }; + + CWMImageInfo * pII = &pSC->WMII; + size_t cStrideX, cStrideY; + size_t w, h, i, iFirst = 0; + Bool bReverse; + + // lookup tables for rotation and flipping + if(pSC->m_Dparam->cThumbnailScale > 1) // thumbnail + w = pII->cThumbnailWidth, h = pII->cThumbnailHeight; + else + w = pII->cWidth, h = pII->cHeight; + w += (pSC->m_Dparam->cROILeftX + pSC->m_Dparam->cThumbnailScale - 1) / pSC->m_Dparam->cThumbnailScale; + h += (pSC->m_Dparam->cROITopY + pSC->m_Dparam->cThumbnailScale - 1) / pSC->m_Dparam->cThumbnailScale; + + switch(pII->bdBitDepth){ + case BD_16: + case BD_16S: + case BD_5: + case BD_565: + case BD_16F: + cStrideY = pSC->WMIBI.cbStride / 2; + break; + + case BD_32: + case BD_32S: + case BD_32F: + case BD_10: + cStrideY = pSC->WMIBI.cbStride / 4; + break; + + default: //BD_8, BD_1 + cStrideY = pSC->WMIBI.cbStride; + break; + } + + switch(pII->cfColorFormat){ + case YUV_420: + cStrideX = 6; + w >>= 1, h >>= 1; + break; + + case YUV_422: + cStrideX = 4; + w >>= 1; + break; + + default: + cStrideX = (pII->cBitsPerUnit >> 3) / cbChannels[pII->bdBitDepth]; + break; + } + + if(pII->bdBitDepth == BD_1 || pII->bdBitDepth == BD_5 || pII->bdBitDepth == BD_10 || pII->bdBitDepth == BD_565) + cStrideX = 1; + + if(pII->oOrientation > O_FLIPVH) // rotated !! + i =cStrideX, cStrideX = cStrideY, cStrideY = i; + + pSC->m_Dparam->pOffsetX = (size_t *)malloc(w * sizeof(size_t)); + if(pSC->m_Dparam->pOffsetX == NULL || w * sizeof(size_t) < w) + return ICERR_ERROR; + /* + consider a row in the source image. if it becomes a reversed row in the target, or a reversed (upside-down)column + in the target, we have to reverse the offsets. bReverse here tells us when this happened. + */ + bReverse = (pII->oOrientation == O_FLIPH || pII->oOrientation == O_FLIPVH || + pII->oOrientation == O_RCW_FLIPV || pII->oOrientation == O_RCW_FLIPVH); + if(!pSC->m_Dparam->bDecodeFullFrame) // take care of region decode here! + iFirst = (pSC->m_Dparam->cROILeftX + pSC->m_Dparam->cThumbnailScale - 1) / pSC->m_Dparam->cThumbnailScale; + for(i = 0; i + iFirst < w; i ++){ + pSC->m_Dparam->pOffsetX[i + iFirst] = pII->cLeadingPadding + (bReverse ? (pSC->m_Dparam->bDecodeFullFrame ? w : + (pSC->m_Dparam->cROIRightX - pSC->m_Dparam->cROILeftX + pSC->m_Dparam->cThumbnailScale) / pSC->m_Dparam->cThumbnailScale / ((pII->cfColorFormat == YUV_420 || pII->cfColorFormat == YUV_422) ? 2 : 1)) - 1 - i : i) * cStrideX; + } + + pSC->m_Dparam->pOffsetY = (size_t *)malloc(h * sizeof(size_t)); + if(pSC->m_Dparam->pOffsetY == NULL || h * sizeof(size_t) < h) + return ICERR_ERROR; + /* + consider a column in the source image. if it becomes an upside-down column in the target, or a reversed row + in the target, we have to reverse the offsets. bReverse here tells us when this happened. + */ + bReverse = (pII->oOrientation == O_FLIPV || pII->oOrientation == O_FLIPVH || + pII->oOrientation == O_RCW || pII->oOrientation == O_RCW_FLIPV); + if(!pSC->m_Dparam->bDecodeFullFrame) // take care of region decode here! + iFirst = (pSC->m_Dparam->cROITopY + pSC->m_Dparam->cThumbnailScale - 1) / pSC->m_Dparam->cThumbnailScale; + for(i = 0; i + iFirst < h; i ++){ + pSC->m_Dparam->pOffsetY[i + iFirst] = (bReverse ? (pSC->m_Dparam->bDecodeFullFrame ? h : + (pSC->m_Dparam->cROIBottomY - pSC->m_Dparam->cROITopY + pSC->m_Dparam->cThumbnailScale) / pSC->m_Dparam->cThumbnailScale / (pII->cfColorFormat == YUV_420 ? 2 : 1)) - 1 - i : i) * cStrideY; + } + + return ICERR_OK; +} + +Void setROI(CWMImageStrCodec* pSC) +{ + CWMImageInfo * pWMII = &pSC->WMII; + CWMIStrCodecParam * pSCP = &pSC->WMISCP; + + // inscribed image size + pWMII->cWidth -= pSC->m_param.cExtraPixelsLeft + pSC->m_param.cExtraPixelsRight; + pWMII->cHeight -= pSC->m_param.cExtraPixelsTop + pSC->m_param.cExtraPixelsBottom; + + pSC->m_Dparam->bSkipFlexbits = (pSCP->sbSubband == SB_NO_FLEXBITS); + pSC->m_Dparam->bDecodeHP = (pSCP->sbSubband == SB_ALL || pSCP->sbSubband == SB_NO_FLEXBITS); + pSC->m_Dparam->bDecodeLP = (pSCP->sbSubband != SB_DC_ONLY); + pSC->m_Dparam->cThumbnailScale = 1; + while(pSC->m_Dparam->cThumbnailScale * pWMII->cThumbnailWidth < pWMII->cWidth) + pSC->m_Dparam->cThumbnailScale <<= 1; + if(pSC->WMISCP.bfBitstreamFormat == FREQUENCY){ + if(pSC->m_Dparam->cThumbnailScale >= 4) + pSC->m_Dparam->bDecodeHP = FALSE; // no need to decode HP + if(pSC->m_Dparam->cThumbnailScale >= 16) + pSC->m_Dparam->bDecodeLP = FALSE; // only need to decode DC + } + + // original image size + pWMII->cWidth += pSC->m_param.cExtraPixelsLeft + pSC->m_param.cExtraPixelsRight; + pWMII->cHeight += pSC->m_param.cExtraPixelsTop + pSC->m_param.cExtraPixelsBottom; + + /** region decode stuff */ + pSC->m_Dparam->cROILeftX = pWMII->cROILeftX * pSC->m_Dparam->cThumbnailScale + pSC->m_param.cExtraPixelsLeft; + pSC->m_Dparam->cROIRightX = pSC->m_Dparam->cROILeftX + pWMII->cROIWidth * pSC->m_Dparam->cThumbnailScale - 1; + pSC->m_Dparam->cROITopY = pWMII->cROITopY * pSC->m_Dparam->cThumbnailScale + pSC->m_param.cExtraPixelsTop; + pSC->m_Dparam->cROIBottomY = pSC->m_Dparam->cROITopY + pWMII->cROIHeight * pSC->m_Dparam->cThumbnailScale - 1; + if(pSC->m_Dparam->cROIRightX >= pWMII->cWidth) + pSC->m_Dparam->cROIRightX = pWMII->cWidth - 1; + if(pSC->m_Dparam->cROIBottomY >= pWMII->cHeight) + pSC->m_Dparam->cROIBottomY = pWMII->cHeight - 1; + + pSC->m_Dparam->bDecodeFullFrame = (pSC->m_Dparam->cROILeftX + pSC->m_Dparam->cROITopY == 0 && + ((pSC->m_Dparam->cROIRightX + 15) / 16 >= (pWMII->cWidth + 14) / 16) && ((pSC->m_Dparam->cROIBottomY + 15) / 16 >= (pWMII->cHeight + 14) / 16)); + + pSC->m_Dparam->bDecodeFullWidth = (pSC->m_Dparam->cROILeftX == 0 && ((pSC->m_Dparam->cROIRightX + 15) / 16 >= (pWMII->cWidth + 14) / 16)); + + // inscribed image size + pWMII->cWidth -= pSC->m_param.cExtraPixelsLeft + pSC->m_param.cExtraPixelsRight; + pWMII->cHeight -= pSC->m_param.cExtraPixelsTop + pSC->m_param.cExtraPixelsBottom; + + if(pSC->WMISCP.bfBitstreamFormat == FREQUENCY && pWMII->bSkipFlexbits == TRUE) + pSC->m_Dparam->bSkipFlexbits = TRUE; + + pSC->cTileColumn = pSC->cTileRow = 0; +} + +Int StrDecInit(CWMImageStrCodec* pSC) +{ + // CWMImageInfo * pWMII = &pSC->WMII; + COLORFORMAT cfInt = pSC->m_param.cfColorFormat; + COLORFORMAT cfExt = pSC->WMII.cfColorFormat; + size_t i; + + /** color transcoding with resolution change **/ + pSC->m_bUVResolutionChange = ((cfExt != Y_ONLY) && ((cfInt == YUV_420 && cfExt != YUV_420) || + (cfInt == YUV_422 && cfExt != YUV_422))) && !pSC->WMISCP.bYUVData; + if(pSC->m_bUVResolutionChange){ + pSC->pResU = (PixelI *)malloc((cfExt == YUV_422 ? 128 : 256) * pSC->cmbWidth * sizeof(PixelI)); + pSC->pResV = (PixelI *)malloc((cfExt == YUV_422 ? 128 : 256) * pSC->cmbWidth * sizeof(PixelI)); + if(pSC->pResU == NULL || pSC->pResV == NULL || (cfExt == YUV_422 ? 128 : 256) * pSC->cmbWidth * sizeof(PixelI) < pSC->cmbWidth){ + return ICERR_ERROR; + } + } + + if(allocatePredInfo(pSC) != ICERR_OK){ + return ICERR_ERROR; + } + + if(allocateTileInfo(pSC) != ICERR_OK) + return ICERR_ERROR; + + if((pSC->m_param.uQPMode & 1) == 0){ // DC frame uniform quantization + if(allocateQuantizer(pSC->pTile[0].pQuantizerDC, pSC->m_param.cNumChannels, 1) != ICERR_OK) + return ICERR_ERROR; + setUniformQuantizer(pSC, 0); + for(i = 0; i < pSC->m_param.cNumChannels; i ++) + pSC->pTile[0].pQuantizerDC[i]->iIndex = pSC->m_param.uiQPIndexDC[i]; + formatQuantizer(pSC->pTile[0].pQuantizerDC, (pSC->m_param.uQPMode >> 3) & 3, pSC->m_param.cNumChannels, 0, TRUE, pSC->m_param.bScaledArith); + } + + if(pSC->WMISCP.sbSubband != SB_DC_ONLY){ + if((pSC->m_param.uQPMode & 2) == 0){ // LP frame uniform quantization + if(allocateQuantizer(pSC->pTile[0].pQuantizerLP, pSC->m_param.cNumChannels, 1) != ICERR_OK) + return ICERR_ERROR; + setUniformQuantizer(pSC, 1); + if((pSC->m_param.uQPMode & 0x200) == 0) // use DC quantizer + useDCQuantizer(pSC, 0); + else{ + for(i = 0; i < pSC->m_param.cNumChannels; i ++) + pSC->pTile[0].pQuantizerLP[i]->iIndex = pSC->m_param.uiQPIndexLP[i]; + formatQuantizer(pSC->pTile[0].pQuantizerLP, (pSC->m_param.uQPMode >> 5) & 3, pSC->m_param.cNumChannels, 0, TRUE, pSC->m_param.bScaledArith); + } + } + + if(pSC->WMISCP.sbSubband != SB_NO_HIGHPASS){ + if((pSC->m_param.uQPMode & 4) == 0){ // HP frame uniform quantization + if(allocateQuantizer(pSC->pTile[0].pQuantizerHP, pSC->m_param.cNumChannels, 1) != ICERR_OK) + return ICERR_ERROR; + setUniformQuantizer(pSC, 2); + + if((pSC->m_param.uQPMode & 0x400) == 0) // use LP quantizer + useLPQuantizer(pSC, 1, 0); + else{ + for(i = 0; i < pSC->m_param.cNumChannels; i ++) + pSC->pTile[0].pQuantizerHP[i]->iIndex = pSC->m_param.uiQPIndexHP[i]; + formatQuantizer(pSC->pTile[0].pQuantizerHP, (pSC->m_param.uQPMode >> 7) & 3, pSC->m_param.cNumChannels, 0, FALSE, pSC->m_param.bScaledArith); + } + } + } + } + + if(pSC->WMISCP.cNumOfSliceMinus1V >= MAX_TILES || AllocateCodingContextDec(pSC, pSC->WMISCP.cNumOfSliceMinus1V + 1) != ICERR_OK){ + return ICERR_ERROR; + } + + if (pSC->m_bSecondary) { + pSC->pIOHeader = pSC->m_pNextSC->pIOHeader; + pSC->m_ppBitIO = pSC->m_pNextSC->m_ppBitIO; + pSC->cNumBitIO = pSC->m_pNextSC->cNumBitIO; + pSC->cSB = pSC->m_pNextSC->cSB; + } + + setBitIOPointers(pSC); + + return ICERR_OK; +} + +Int StrDecTerm(CWMImageStrCodec* pSC) +{ + size_t j, jend = (pSC->m_pNextSC != NULL); + + for (j = 0; j <= jend; j++) { + if(pSC->m_bUVResolutionChange){ + if(pSC->pResU != NULL) + free(pSC->pResU); + if(pSC->pResV != NULL) + free(pSC->pResV); + } + + freePredInfo(pSC); + + freeTileInfo(pSC); + + FreeCodingContextDec(pSC); + + if (j == 0) { + StrIODecTerm(pSC); + + // free lookup tables for rotation and flipping + if(pSC->m_Dparam->pOffsetX != NULL) + free(pSC->m_Dparam->pOffsetX); + if(pSC->m_Dparam->pOffsetY != NULL) + free(pSC->m_Dparam->pOffsetY); + } + + pSC = pSC->m_pNextSC; + } + + return 0; +} + +/************************************************************************* + Read header of image plane +*************************************************************************/ +Int ReadImagePlaneHeader(CWMImageInfo* pII, CWMIStrCodecParam *pSCP, + CCoreParameters *pSC, SimpleBitIO* pSB) +{ + ERR err = WMP_errSuccess; + + pSC->cfColorFormat = getBit32_SB(pSB, 3); // internal color format + FailIf((pSC->cfColorFormat < Y_ONLY || pSC->cfColorFormat > NCOMPONENT), WMP_errUnsupportedFormat); + pSCP->cfColorFormat = pSC->cfColorFormat; // this should be removed later + pSC->bScaledArith = getBit32_SB(pSB, 1); // lossless mode + + // subbands + pSCP->sbSubband = getBit32_SB(pSB, 4); + +// color parameters + switch (pSC->cfColorFormat) { + case Y_ONLY: + pSC->cNumChannels = 1; + break; + case YUV_420: + pSC->cNumChannels = 3; + getBit32_SB(pSB, 1); + pII->cChromaCenteringX = (U8) getBit32_SB(pSB, 3); + getBit32_SB(pSB, 1); + pII->cChromaCenteringY = (U8) getBit32_SB(pSB, 3); + break; + case YUV_422: + pSC->cNumChannels = 3; + getBit32_SB(pSB, 1); + pII->cChromaCenteringX = (U8) getBit32_SB(pSB, 3); + getBit32_SB(pSB, 4); + break; + case YUV_444: + pSC->cNumChannels = 3; + getBit32_SB(pSB, 4); + getBit32_SB(pSB, 4); + break; + case NCOMPONENT: + pSC->cNumChannels = (Int) getBit32_SB(pSB, 4) + 1; + getBit32_SB(pSB, 4); + break; + case CMYK: + pSC->cNumChannels = 4; + break; + default: + break; + } + +// float and 32s additional parameters + switch (pII->bdBitDepth) { + case BD_16: + case BD_16S: + case BD_32: + case BD_32S: + pSCP->nLenMantissaOrShift = (U8) getBit32_SB(pSB, 8); + break; + case BD_32F: + pSCP->nLenMantissaOrShift = (U8) getBit32_SB(pSB, 8);//float conversion parameters + pSCP->nExpBias = (I8) getBit32_SB(pSB, 8); + break; + default: + break; + } + + // quantization + pSC->uQPMode = 0; + if(getBit32_SB(pSB, 1) == 1) // DC uniform + pSC->uQPMode += (readQuantizerSB(pSC->uiQPIndexDC, pSB, pSC->cNumChannels) << 3); + else + pSC->uQPMode ++; + if(pSCP->sbSubband != SB_DC_ONLY){ + if(getBit32_SB(pSB, 1) == 0){ // don't use DC QP + pSC->uQPMode += 0x200; + if(getBit32_SB(pSB, 1) == 1) // LP uniform + pSC->uQPMode += (readQuantizerSB(pSC->uiQPIndexLP, pSB, pSC->cNumChannels) << 5); + else + pSC->uQPMode += 2; + } + else + pSC->uQPMode += ((pSC->uQPMode & 1) << 1) + ((pSC->uQPMode & 0x18) << 2); + + if(pSCP->sbSubband != SB_NO_HIGHPASS){ + if(getBit32_SB(pSB, 1) == 0){ // don't use LP QP + pSC->uQPMode += 0x400; + if(getBit32_SB(pSB, 1) == 1) // HP uniform + pSC->uQPMode += (readQuantizerSB(pSC->uiQPIndexHP, pSB, pSC->cNumChannels) << 7); + else + pSC->uQPMode += 4; + } + else + pSC->uQPMode += ((pSC->uQPMode & 2) << 1) + ((pSC->uQPMode & 0x60) << 2); + } + } + + if(pSCP->sbSubband == SB_DC_ONLY) + pSC->uQPMode |= 0x200; + else if(pSCP->sbSubband == SB_NO_HIGHPASS) + pSC->uQPMode |= 0x400; + + + FailIf((pSC->uQPMode & 0x600) == 0, WMP_errInvalidParameter); // frame level QPs must be specified independently! + + flushToByte_SB(pSB); // remove this later + +Cleanup: + return WMP_errSuccess == err ? ICERR_OK : ICERR_ERROR; +} + +/************************************************************************* + Read header of image, and header of FIRST PLANE only +*************************************************************************/ +Int ReadWMIHeader( + CWMImageInfo* pII, + CWMIStrCodecParam *pSCP, + CCoreParameters *pSC) +{ + U32 i; + ERR err = WMP_errSuccess; + Bool bTilingPresent, bInscribed, bTileStretch, bAbbreviatedHeader; + struct WMPStream* pWS = pSCP->pWStream; + + SimpleBitIO SB = {0}; + SimpleBitIO* pSB = &SB; + + U8 szMS[8] = {0}; + U32 cbStream = 0; + + // U32 bits = 0; + // Int HEADERSIZE = 0; + + assert(pSC != NULL); + //================================ +// 0 + /** signature **/ + Call(pWS->Read(pWS, szMS, sizeof(szMS))); + FailIf(szMS != (U8 *) strstr((char *) szMS, "WMPHOTO"), WMP_errUnsupportedFormat); + //================================ + Call(attach_SB(pSB, pWS)); + +// 8 + /** codec version and subversion **/ + i = getBit32_SB(pSB, 4); + FailIf((i != CODEC_VERSION), WMP_errIncorrectCodecVersion); + pSC->cVersion = i; + i = getBit32_SB(pSB, 4); // subversion + FailIf((i != CODEC_SUBVERSION && + i != CODEC_SUBVERSION_NEWSCALING_SOFT_TILES && i != CODEC_SUBVERSION_NEWSCALING_HARD_TILES), + WMP_errIncorrectCodecSubVersion); + pSC->cSubVersion = i; + + pSC->bUseHardTileBoundaries = FALSE; + if (pSC->cSubVersion == CODEC_SUBVERSION_NEWSCALING_HARD_TILES) + pSC->bUseHardTileBoundaries = TRUE; + + pSCP->bUseHardTileBoundaries = pSC->bUseHardTileBoundaries; + +// 9 primary parameters + bTilingPresent = (Bool) getBit32_SB(pSB, 1); // tiling present + pSCP->bfBitstreamFormat = getBit32_SB(pSB, 1); // bitstream layout + pII->oOrientation = (ORIENTATION)getBit32_SB(pSB, 3); // presentation orientation + pSC->bIndexTable = getBit32_SB(pSB, 1); + i = getBit32_SB(pSB, 2); // overlap + FailIf((i == 3), WMP_errInvalidParameter); + pSCP->olOverlap = i; + +// 11 some other parameters + bAbbreviatedHeader = (Bool) getBit32_SB(pSB, 1); // short words for size and tiles + pSCP->bdBitDepth = (BITDEPTH) getBit32_SB(pSB, 1); // long word +pSCP->bdBitDepth = BD_LONG; // remove when optimization is done + bInscribed = (Bool) getBit32_SB(pSB, 1); // windowing + pSC->bTrimFlexbitsFlag = (Bool) getBit32_SB(pSB, 1); // trim flexbits flag + bTileStretch = (Bool) getBit32_SB(pSB, 1); // tile stretching flag + pSC->bRBSwapped = (Bool) getBit32_SB(pSB, 1); // red-blue swap flag + getBit32_SB(pSB, 1); // padding / reserved bit + pSC->bAlphaChannel = (Bool) getBit32_SB(pSB, 1); // alpha channel present + +// 10 - informational + pII->cfColorFormat = getBit32_SB(pSB, 4); // source color format + pII->bdBitDepth = getBit32_SB(pSB, 4); // source bit depth + + if(BD_1alt == pII->bdBitDepth) + { + pII->bdBitDepth = BD_1; + pSCP->bBlackWhite = 1; + } + +// 12 - Variable length fields +// size + pII->cWidth = getBit32_SB(pSB, bAbbreviatedHeader ? 16 : 32) + 1; + pII->cHeight = getBit32_SB(pSB, bAbbreviatedHeader ? 16 : 32) + 1; + pSC->cExtraPixelsTop = pSC->cExtraPixelsLeft = pSC->cExtraPixelsBottom = pSC->cExtraPixelsRight = 0; + if (bInscribed == FALSE && (pII->cWidth & 0xf) != 0) + pSC->cExtraPixelsRight = 0x10 - (pII->cWidth & 0xF); + if (bInscribed == FALSE && (pII->cHeight & 0xf) != 0) + pSC->cExtraPixelsBottom = 0x10 - (pII->cHeight & 0xF); + +// tiling + pSCP->cNumOfSliceMinus1V = pSCP->cNumOfSliceMinus1H = 0; + if (bTilingPresent) { + pSCP->cNumOfSliceMinus1V = getBit32_SB(pSB, LOG_MAX_TILES); // # of vertical slices along X axis + pSCP->cNumOfSliceMinus1H = getBit32_SB(pSB, LOG_MAX_TILES); // # of horizontal slices along Y axis + } + FailIf((pSC->bIndexTable == FALSE) && (pSCP->bfBitstreamFormat == FREQUENCY || pSCP->cNumOfSliceMinus1V + pSCP->cNumOfSliceMinus1H > 0), + WMP_errUnsupportedFormat); + +// tile sizes + pSCP->uiTileX[0] = pSCP->uiTileY[0] = 0; + for(i = 0; i < pSCP->cNumOfSliceMinus1V; i ++){ // width in MB of vertical slices, not needed for last slice! + pSCP->uiTileX[i + 1] = (U32) getBit32_SB(pSB, bAbbreviatedHeader ? 8 : 16) + pSCP->uiTileX[i]; + } + for(i = 0; i < pSCP->cNumOfSliceMinus1H; i ++){ // width in MB of vertical slices, not needed for last slice! + pSCP->uiTileY[i + 1] = (U32) getBit32_SB(pSB, bAbbreviatedHeader ? 8 : 16) + pSCP->uiTileY[i]; + } + if (bTileStretch) { // no handling of tile stretching enabled as of now + for (i = 0; i < (pSCP->cNumOfSliceMinus1V + 1) * (pSCP->cNumOfSliceMinus1H + 1); i++) + getBit32_SB(pSB, 8); + } + +// window due to compressed domain processing + if (bInscribed) { + pSC->cExtraPixelsTop = (U8)getBit32_SB(pSB, 6); + pSC->cExtraPixelsLeft = (U8)getBit32_SB(pSB, 6); + pSC->cExtraPixelsBottom = (U8)getBit32_SB(pSB, 6); + pSC->cExtraPixelsRight = (U8)getBit32_SB(pSB, 6); + } + + if(((pII->cWidth + pSC->cExtraPixelsLeft + pSC->cExtraPixelsRight) & 0xf) + ((pII->cHeight + pSC->cExtraPixelsTop + pSC->cExtraPixelsBottom) & 0xf) != 0){ + FailIf((pII->cWidth & 0xf) + (pII->cHeight & 0xf) + pSC->cExtraPixelsLeft + pSC->cExtraPixelsTop != 0, WMP_errInvalidParameter); + FailIf(pII->cWidth <= pSC->cExtraPixelsRight || pII->cHeight <= pSC->cExtraPixelsBottom, WMP_errInvalidParameter); + pII->cWidth -= pSC->cExtraPixelsRight, pII->cHeight -= pSC->cExtraPixelsBottom; + } + + flushToByte_SB(pSB); // redundant + + // read header of first image plane + FailIf(ReadImagePlaneHeader(pII, pSCP, pSC, pSB), WMP_errUnsupportedFormat); + + // maybe UNALIGNED!!! + + //================================ + detach_SB(pSB); + pSCP->cbStream = cbStream - getByteRead_SB(pSB); + + pSCP->uAlphaMode = (pSC->bAlphaChannel ? pSCP->uAlphaMode : 0); + pSCP->cChannel = pSC->cNumChannels; + + if((pII->bdBitDepth == BD_5 || pII->bdBitDepth == BD_10 || pII->bdBitDepth == BD_565) && + (pSCP->cfColorFormat != YUV_444 && pSCP->cfColorFormat != YUV_422 && pSCP->cfColorFormat != YUV_420 && pSCP->cfColorFormat != Y_ONLY)) + return ICERR_ERROR; + +Cleanup: + return WMP_errSuccess == err ? ICERR_OK : ICERR_ERROR; +} + +//---------------------------------------------------------------- +// streaming api init/decode/term +EXTERN_C Int ImageStrDecGetInfo( + CWMImageInfo* pII, + CWMIStrCodecParam *pSCP) +{ + ERR err = WMP_errSuccess; + size_t cMarker; + CCoreParameters aDummy; + // mark position of start of data + Call(pSCP->pWStream->GetPos(pSCP->pWStream, &cMarker)); + Call(ReadWMIHeader(pII, pSCP, &aDummy)); + // rewind to start of data + Call(pSCP->pWStream->SetPos(pSCP->pWStream, cMarker)); + return ICERR_OK; + +Cleanup: + return ICERR_ERROR; +} + +EXTERN_C Int WMPhotoValidate( + CWMImageInfo * pII, + CWMIStrCodecParam * pSCP) +{ + CWMImageInfo cII; + CWMIStrCodecParam cSCP = *pSCP; + size_t cScale = 1; + + if(ImageStrDecGetInfo(&cII, pSCP) != ICERR_OK) + return ICERR_ERROR; + + // copy over un-overwritable ImageInfo parameters + pII->bdBitDepth = cII.bdBitDepth; + pII->cWidth = cII.cWidth; + pII->cHeight = cII.cHeight; + + if(pII->cWidth == 0 || pII->cHeight == 0) + return ICERR_ERROR; + + // copy over overwritable CodecParam parameters + pSCP->bVerbose = cSCP.bVerbose; + pSCP->cbStream = cSCP.cbStream; + pSCP->pWStream = cSCP.pWStream; + if(pSCP->uAlphaMode > 1) // something + alpha + pSCP->uAlphaMode = cSCP.uAlphaMode; // something + alpha to alpha or something transcoding! + + // validate color transcoding + if(pSCP->cfColorFormat == NCOMPONENT) + pII->cfColorFormat = NCOMPONENT; + if(pSCP->cfColorFormat == CMYK && pII->cfColorFormat != Y_ONLY && pII->cfColorFormat != CF_RGB) + pII->cfColorFormat = CMYK; + if(pSCP->cfColorFormat == YUV_422 && pII->cfColorFormat == YUV_420) + pII->cfColorFormat = YUV_422; + if(pSCP->cfColorFormat == YUV_444 && (pII->cfColorFormat == YUV_422 || pII->cfColorFormat == YUV_420)) + pII->cfColorFormat = YUV_444; + if(cII.cfColorFormat == CF_RGB && pII->cfColorFormat != Y_ONLY && + pII->cfColorFormat != NCOMPONENT) // no guarantee that number of channels will be >= 3 + pII->cfColorFormat = cII.cfColorFormat; + if(cII.cfColorFormat == CF_RGBE) + pII->cfColorFormat = CF_RGBE; + + // validate thumbnail parameters + if(pII->cThumbnailWidth == 0 || pII->cThumbnailWidth > pII->cWidth) + pII->cThumbnailWidth = pII->cWidth; + if(pII->cThumbnailHeight == 0 || pII->cThumbnailHeight > pII->cHeight) + pII->cThumbnailHeight = pII->cHeight; + if((pII->cWidth + pII->cThumbnailWidth - 1) / pII->cThumbnailWidth != (pII->cHeight + pII->cThumbnailHeight - 1) / pII->cThumbnailHeight) { + while((pII->cWidth + cScale - 1) / cScale > pII->cThumbnailWidth && + (pII->cHeight + cScale - 1) / cScale > pII->cThumbnailHeight && (cScale << 1)) + cScale <<= 1; + } + else { + cScale = (pII->cWidth + pII->cThumbnailWidth - 1) / pII->cThumbnailWidth; + if (cScale == 0) + cScale = 1; + } + pII->cThumbnailWidth = (pII->cWidth + cScale - 1) / cScale; + pII->cThumbnailHeight = (pII->cHeight + cScale - 1) / cScale; + + // validate region decode parameters + if(pII->cROIHeight == 0 || pII->cROIWidth == 0){ + pII->cROILeftX = pII->cROITopY = 0; + pII->cROIWidth = pII->cThumbnailWidth; + pII->cROIHeight = pII->cThumbnailHeight; + } + if(pII->cROILeftX >= pII->cThumbnailWidth) + pII->cROILeftX = 0; + if(pII->cROITopY >= pII->cThumbnailHeight) + pII->cROITopY = 0; + if(pII->cROILeftX + pII->cROIWidth > pII->cThumbnailWidth) + pII->cROIWidth = pII->cThumbnailWidth - pII->cROILeftX; + if(pII->cROITopY + pII->cROIHeight > pII->cThumbnailHeight) + pII->cROIHeight = pII->cThumbnailHeight - pII->cROITopY; + + return ICERR_OK; +} + +/************************************************************************* + Initialization of CWMImageStrCodec struct +*************************************************************************/ +static Void InitializeStrDec(CWMImageStrCodec *pSC, + const CCoreParameters *pParams, const CWMImageStrCodec *pSCIn) +{ + // copy core parameters + memcpy (&(pSC->m_param), pParams, sizeof (CCoreParameters)); + + pSC->cbStruct = sizeof(*pSC); + pSC->WMII = pSCIn->WMII; + pSC->WMISCP = pSCIn->WMISCP; + + pSC->cRow = 0; + pSC->cColumn = 0; + + pSC->cmbWidth = (pSC->WMII.cWidth + 15) / 16; + pSC->cmbHeight = (pSC->WMII.cHeight + 15) / 16; + + pSC->Load = outputMBRow; // output decoding result (ICC, etc) + pSC->Transform = pParams->cSubVersion == CODEC_SUBVERSION ? + invTransformMacroblock : invTransformMacroblock_alteredOperators_hard; + pSC->TransformCenter = pSC->Transform; + + pSC->ProcessTopLeft = processMacroblockDec; + pSC->ProcessTop = processMacroblockDec; + pSC->ProcessTopRight = processMacroblockDec; + pSC->ProcessLeft = processMacroblockDec; + pSC->ProcessCenter = processMacroblockDec; + pSC->ProcessRight = processMacroblockDec; + pSC->ProcessBottomLeft = processMacroblockDec; + pSC->ProcessBottom = processMacroblockDec; + pSC->ProcessBottomRight = processMacroblockDec; + + pSC->m_pNextSC = NULL; + pSC->m_bSecondary = FALSE; +} + +/************************************************************************* + ImageStrDecInit +*************************************************************************/ +Int ImageStrDecInit( + CWMImageInfo* pII, + CWMIStrCodecParam *pSCP, + CTXSTRCODEC* pctxSC) +{ + static size_t cbChannels[BD_MAX] = {2, 4}; + ERR err = WMP_errSuccess; + + size_t cbChannel = 0, cblkChroma = 0; + size_t cbMacBlockStride = 0, cbMacBlockChroma = 0, cMacBlock = 0; + + CWMImageStrCodec SC = {0}; + CWMImageStrCodec *pSC = NULL, *pNextSC = NULL; + char* pb = NULL; + size_t cb = 0, i; + Bool bLossyTranscoding = FALSE; + Bool bUseHardTileBoundaries = FALSE; //default is soft tile boundaries + Bool bLessThan64Bit = sizeof(void *) < 8; + + *pctxSC = NULL; + + if(WMPhotoValidate(pII, pSCP) != ICERR_OK) + return ICERR_ERROR; + + if(pSCP->sbSubband == SB_ISOLATED) // can not do anything with isolated bitstream + return ICERR_ERROR; + + //================================================ + SC.WMISCP.pWStream = pSCP->pWStream; + if (ReadWMIHeader(&SC.WMII, &SC.WMISCP, &SC.m_param) != ICERR_OK) { + return ICERR_ERROR; + } + + bUseHardTileBoundaries = SC.WMISCP.bUseHardTileBoundaries; + if(SC.WMII.cfColorFormat == CMYK && pII->cfColorFormat == CF_RGB) + bLossyTranscoding = TRUE; + if(pSCP->cfColorFormat != CMYK && (pII->cfColorFormat == CMYK)) + return ICERR_ERROR; + + //================================================ + SC.WMISCP = *pSCP; + SC.WMII = *pII; + + // original image size + SC.WMII.cWidth += SC.m_param.cExtraPixelsLeft + SC.m_param.cExtraPixelsRight; + SC.WMII.cHeight += SC.m_param.cExtraPixelsTop + SC.m_param.cExtraPixelsBottom; + pII->cROILeftX += SC.m_param.cExtraPixelsLeft; + pII->cROITopY += SC.m_param.cExtraPixelsTop; + + //================================================ + cbChannel = cbChannels[SC.WMISCP.bdBitDepth]; + cblkChroma = cblkChromas[SC.m_param.cfColorFormat]; + + cbMacBlockStride = cbChannel * 16 * 16; + cbMacBlockChroma = cbChannel * 16 * cblkChroma; + cMacBlock = (SC.WMII.cWidth + 15) / 16; + + //================================================ + cb = sizeof(*pSC) + (128 - 1) + sizeof(CWMDecoderParameters); + cb += (PACKETLENGTH * 4 - 1) + (PACKETLENGTH * 2 ) + sizeof(*pSC->pIOHeader); + + i = (cbMacBlockStride + cbMacBlockChroma * (SC.m_param.cNumChannels - 1)) * 2; // i <= 2^15 + if (bLessThan64Bit && ((i * (cMacBlock >> 16)) & 0xffffc000)) { + /** potential overflow - 32 bit pointers insufficient to address cache **/ + return ICERR_ERROR; + } + cb += i * cMacBlock; + + pb = malloc(cb); + if(pb == NULL) + return WMP_errOutOfMemory; + memset(pb, 0, cb); + + //================================================ + pSC = (CWMImageStrCodec*)pb; pb += sizeof(*pSC); + if(pSC == NULL) + return ICERR_ERROR; + + // Set up perf timers + PERFTIMER_ONLY(pSC->m_fMeasurePerf = pSCP->fMeasurePerf); + PERFTIMER_NEW(pSC->m_fMeasurePerf, &pSC->m_ptEndToEndPerf); + PERFTIMER_NEW(pSC->m_fMeasurePerf, &pSC->m_ptEncDecPerf); + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEndToEndPerf); + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + PERFTIMER_COPYSTARTTIME(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf, pSC->m_ptEndToEndPerf); + + pSC->m_Dparam = (CWMDecoderParameters*)pb; pb += sizeof(CWMDecoderParameters); + pSC->cbChannel = cbChannel; + //pSC->cNumChannels = SC.WMISCP.cChannel; + pSC->bUseHardTileBoundaries = bUseHardTileBoundaries; + + //================================================ + InitializeStrDec(pSC, &SC.m_param, &SC); + + //================================================ + // 2 Macro Row buffers for each channel + pb = ALIGNUP(pb, 128); + for (i = 0; i < pSC->m_param.cNumChannels; i++) { + pSC->a0MBbuffer[i] = (PixelI*)pb; pb += cbMacBlockStride * pSC->cmbWidth; + pSC->a1MBbuffer[i] = (PixelI*)pb; pb += cbMacBlockStride * pSC->cmbWidth; + cbMacBlockStride = cbMacBlockChroma; + } + + //================================================ + // lay 2 aligned IO buffers just below pIO struct + pb = (char*)ALIGNUP(pb, PACKETLENGTH * 4) + PACKETLENGTH * 2; + pSC->pIOHeader = (BitIOInfo*)pb; pb += sizeof(*pSC->pIOHeader); + + // if interleaved alpha is needed + if (pSC->m_param.bAlphaChannel) { + SimpleBitIO SB = {0}; + cbMacBlockStride = cbChannel * 16 * 16; + + // 1. allocate new pNextSC info + //================================================ + cb = sizeof(*pNextSC) + (128 - 1) + cbMacBlockStride * cMacBlock * 2; + // if primary image is safe to allocate, alpha channel is certainly safe + pb = malloc(cb); + if(pb == NULL) + return WMP_errOutOfMemory; + memset(pb, 0, cb); + //================================================ + pNextSC = (CWMImageStrCodec*)pb; pb += sizeof(*pNextSC); + + // read plane header of second image plane + Call(attach_SB(&SB, pSCP->pWStream)); + InitializeStrDec(pNextSC, &SC.m_param, &SC); + ReadImagePlaneHeader(&pNextSC->WMII, &pNextSC->WMISCP, &pNextSC->m_param, &SB); + detach_SB(&SB); + + // 2. initialize pNextSC + if(pNextSC == NULL) + return ICERR_ERROR; + pNextSC->m_Dparam = pSC->m_Dparam; + pNextSC->cbChannel = cbChannel; + //================================================ + + // 3. initialize arrays +// InitializeStrDec(pNextSC, &SC.m_param, &SC); + pNextSC->m_param.cfColorFormat = Y_ONLY; + pNextSC->m_param.cNumChannels = 1; + pNextSC->m_param.bAlphaChannel = TRUE; + //================================================ + + // 2 Macro Row buffers for each channel + pb = ALIGNUP(pb, 128); + pNextSC->a0MBbuffer[0] = (PixelI*)pb; pb += cbMacBlockStride * pNextSC->cmbWidth; + pNextSC->a1MBbuffer[0] = (PixelI*)pb; + //================================================ + pNextSC->pIOHeader = pSC->pIOHeader; + //================================================ + + // 4. link pSC->pNextSC = pNextSC + pNextSC->m_pNextSC = pSC; + pNextSC->m_bSecondary = TRUE; + + } + else + pSC->WMISCP.uAlphaMode = 0; + + //================================================ + FailIf((StrIODecInit(pSC) != ICERR_OK), WMP_errOutOfMemory); + FailIf((StrDecInit(pSC) != ICERR_OK), WMP_errOutOfMemory); + if (pNextSC) { + // 5. StrEncInit + FailIf((StrDecInit(pNextSC) != ICERR_OK), WMP_errOutOfMemory); + } + + pSC->m_pNextSC = pNextSC; + //================================================ + *pII = pSC->WMII; + *pSCP = pSC->WMISCP; + *pctxSC = (CTXSTRCODEC)pSC; + + if(pSC->WMII.cPostProcStrength){ + initPostProc(pSC->pPostProcInfo, pSC->cmbWidth, pSC->m_param.cNumChannels); + if (pSC->m_param.bAlphaChannel) + initPostProc(pNextSC->pPostProcInfo, pNextSC->cmbWidth, pNextSC->m_param.cNumChannels); + } + + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + +Cleanup: + return WMP_errSuccess == err ? ICERR_OK : ICERR_ERROR; +} + +Int ImageStrDecDecode( + CTXSTRCODEC ctxSC, + const CWMImageBufferInfo* pBI +#ifdef REENTRANT_MODE + , size_t *pcDecodedLines +#endif + ) +{ + CWMImageStrCodec* pSC = (CWMImageStrCodec*)ctxSC; + CWMImageStrCodec* pNextSC = pSC->m_pNextSC; + size_t cMBRow, k; + + ImageDataProc ProcessLeft, ProcessCenter, ProcessRight; + ImageDataProc Transform = NULL; + const size_t iChromaElements = (pSC->m_param.cfColorFormat == YUV_420) ? 8 * 8 + : ((pSC->m_param.cfColorFormat == YUV_422) ? 8 * 16 : 16 * 16); + + if (sizeof(*pSC) != pSC->cbStruct) + { + return ICERR_ERROR; + } + + //================================ + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + + pSC->WMIBI = *pBI; + +#ifdef REENTRANT_MODE + if (0 == pSC->WMIBI.uiFirstMBRow) + { + setROI(pSC); + if (pNextSC) { + pNextSC->WMIBI = pSC->WMIBI; + setROI(pNextSC); + } + } +#else + setROI(pSC); + if (pNextSC) { + pNextSC->WMIBI = pSC->WMIBI; + setROI(pNextSC); + } +#endif // REENTRANT_MODE + +// optimization flags can be defined only after ROI is set! +#if defined(WMP_OPT_SSE2) || defined(WMP_OPT_CC_DEC) || defined(WMP_OPT_TRFM_DEC) + StrDecOpt(pSC); +#endif // OPT defined + + + + cMBRow = (pSC->m_Dparam->bDecodeFullFrame ? pSC->cmbHeight : ((pSC->m_Dparam->cROIBottomY + 16) >> 4)); + +#ifdef REENTRANT_MODE + if (0 == pSC->WMIBI.uiFirstMBRow) + { + if(initLookupTables(pSC) != ICERR_OK) + return ICERR_ERROR; + if (pNextSC && initLookupTables(pNextSC) != ICERR_OK) + return ICERR_ERROR; + } +#else + if(initLookupTables(pSC) != ICERR_OK) + return ICERR_ERROR; + if (pNextSC && initLookupTables(pNextSC) != ICERR_OK) + return ICERR_ERROR; +#endif // REENTRANT_MODE + +#ifndef REENTRANT_MODE + if(pSC->WMII.bdBitDepth == BD_1){ + size_t i; + + + for(i = 0; i < pSC->WMIBI.cLine; i ++) + memset(pSC->WMIBI.pv, 0, pSC->WMIBI.cbStride); + } +#endif + + //================================ + // top row +#ifdef REENTRANT_MODE +#else + pSC->cRow = 0; + ProcessLeft = pSC->ProcessTopLeft; + ProcessCenter = pSC->ProcessTop; + ProcessRight = pSC->ProcessTopRight; + Transform = pSC->m_param.cSubVersion == CODEC_SUBVERSION ? + invTransformMacroblock : invTransformMacroblock_alteredOperators_hard; +#endif // REENTRANT_MODE + +#ifdef REENTRANT_MODE + for (pSC->cRow = pSC->WMIBI.uiFirstMBRow; pSC->cRow <= pSC->WMIBI.uiLastMBRow; pSC->cRow++) + { + // const COLORFORMAT cfExt = (pSC->m_param.cfColorFormat == Y_ONLY ? Y_ONLY : pSC->WMII.cfColorFormat); + + if (0 == pSC->cRow) + { + ProcessLeft = pSC->ProcessTopLeft; + ProcessCenter = pSC->ProcessTop; + ProcessRight = pSC->ProcessTopRight; + Transform = pSC->m_param.cSubVersion == CODEC_SUBVERSION ? + invTransformMacroblock : invTransformMacroblock_alteredOperators_hard; + } + else if (cMBRow == pSC->cRow) + { + //================================ + // bottom row + ProcessLeft = pSC->ProcessBottomLeft; + ProcessCenter = pSC->ProcessBottom; + ProcessRight = pSC->ProcessBottomRight; + Transform = pSC->m_param.cSubVersion == CODEC_SUBVERSION ? + invTransformMacroblock : invTransformMacroblock_alteredOperators_hard; + } + else { // middle rows + ProcessLeft = pSC->ProcessLeft; + ProcessCenter = pSC->ProcessCenter; + ProcessRight = pSC->ProcessRight; + Transform = pSC->TransformCenter; + } +#else + //================================ + // central rows + for(pSC->cRow = 0; pSC->cRow <= cMBRow; pSC->cRow++) + { +#endif // REENTRANT_MODE + pSC->cColumn = 0; + initMRPtr(pSC); + /** zero out the transform coefficients (pull this out to once per MB row) **/ + memset(pSC->p1MBbuffer[0], 0, sizeof(PixelI) * 16 * 16 * pSC->cmbWidth); + for (k = 1; k < pSC->m_param.cNumChannels; k++) { + memset(pSC->p1MBbuffer[k], 0, sizeof(PixelI) * iChromaElements * pSC->cmbWidth); + } + if (pSC->m_pNextSC != NULL) { // alpha channel + memset(pSC->m_pNextSC->p1MBbuffer[0], 0, sizeof(PixelI) * 16 * 16 * pSC->m_pNextSC->cmbWidth); + } + + if(ProcessLeft(pSC) != ICERR_OK) + return ICERR_ERROR; + advanceMRPtr(pSC); + + pSC->Transform = Transform; + for (pSC->cColumn = 1; pSC->cColumn < pSC->cmbWidth; ++pSC->cColumn) + { + if(ProcessCenter(pSC) != ICERR_OK) + return ICERR_ERROR; + advanceMRPtr(pSC); + } + pSC->Transform = pSC->m_param.cSubVersion == CODEC_SUBVERSION ? + invTransformMacroblock : invTransformMacroblock_alteredOperators_hard; + + if(ProcessRight(pSC) != ICERR_OK) + return ICERR_ERROR; + + if (pSC->cRow) { + if(pSC->m_Dparam->cThumbnailScale < 2 && (pSC->m_Dparam->bDecodeFullFrame || + ((pSC->cRow * 16 > pSC->m_Dparam->cROITopY) && (pSC->cRow * 16 <= pSC->m_Dparam->cROIBottomY + 16)))) { + if( pSC->Load(pSC) != ICERR_OK ) // bypass CC for thumbnail decode + return ICERR_ERROR; + } + + if(pSC->m_Dparam->cThumbnailScale >= 2) // decode thumbnail + decodeThumbnail(pSC); + } + + advanceOneMBRow(pSC); + swapMRPtr(pSC); +#ifdef REENTRANT_MODE + *pcDecodedLines = pSC->WMIBI.cLinesDecoded; +#else + if (pSC->cRow == cMBRow - 1) { + //================================ + // bottom row + ProcessLeft = pSC->ProcessBottomLeft; + ProcessCenter = pSC->ProcessBottom; + ProcessRight = pSC->ProcessBottomRight; + Transform = pSC->m_param.cSubVersion == CODEC_SUBVERSION ? + invTransformMacroblock : invTransformMacroblock_alteredOperators_hard; + } + else { + ProcessLeft = pSC->ProcessLeft; + ProcessCenter = pSC->ProcessCenter; + ProcessRight = pSC->ProcessRight; + Transform = pSC->TransformCenter; + } +#endif // REENTRANT_MODE + } + +#ifndef REENTRANT_MODE + fixup_Y_ONLY_to_Others(pSC, pBI); +#endif // REENTRANT_MODE + + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + return ICERR_OK; +} + +Int ImageStrDecTerm( + CTXSTRCODEC ctxSC) +{ + CWMImageStrCodec* pSC = (CWMImageStrCodec*)ctxSC; + if (NULL == pSC) + { + return ICERR_OK; + } + if (sizeof(*pSC) != pSC->cbStruct) + { + return ICERR_ERROR; + } + + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + + StrDecTerm(pSC); + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + PERFTIMER_REPORT(pSC->m_fMeasurePerf, pSC); + PERFTIMER_DELETE(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + PERFTIMER_DELETE(pSC->m_fMeasurePerf, pSC->m_ptEndToEndPerf); + + free(pSC); + + return ICERR_OK; +} + diff --git a/libs/jxr/image/encode/encode.c b/libs/jxr/image/encode/encode.c new file mode 100644 index 00000000000..10a96721321 --- /dev/null +++ b/libs/jxr/image/encode/encode.c @@ -0,0 +1,144 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 +#include +#include "encode.h" +#include "strcodec.h" +#include "common.h" + +#ifdef MEM_TRACE +#define TRACE_MALLOC 1 +#define TRACE_NEW 0 +#define TRACE_HEAP 0 +#include "memtrace.h" +#endif + +/************************************************************************* + Context allocation + In theory it is possible to independently set uiTrimFlexBits for + each tile, but for now we assume only one user specified value is + used for the entire image +*************************************************************************/ +Int AllocateCodingContextEnc(CWMImageStrCodec *pSC, Int iNumContexts, Int iTrimFlexBits) +{ + Int i, iCBPSize, k; + static const Int aAlphabet[] = {5,4,8,7,7, 12,6,6,12,6,6,7,7, 12,6,6,12,6,6,7,7}; + + if (iTrimFlexBits < 0) + iTrimFlexBits = 0; + else if (iTrimFlexBits > 15) + iTrimFlexBits = 15; + pSC->m_param.bTrimFlexbitsFlag = (iTrimFlexBits > 0); + + if (iNumContexts < 1 || iNumContexts > MAX_TILES) // only between 1 and 256 allowed + return ICERR_ERROR; + + if (pSC == NULL) + return ICERR_ERROR; + + pSC->m_pCodingContext = malloc (iNumContexts * sizeof (CCodingContext)); + if (pSC->m_pCodingContext == NULL) { + pSC->cNumCodingContext = 0; + return ICERR_ERROR; + } + memset (pSC->m_pCodingContext, 0, iNumContexts * sizeof (CCodingContext)); + + pSC->cNumCodingContext = iNumContexts; + iCBPSize = (pSC->m_param.cfColorFormat == Y_ONLY || pSC->m_param.cfColorFormat == NCOMPONENT + || pSC->m_param.cfColorFormat == CMYK) ? 5 : 9; + + /** allocate / initialize members **/ + for (i = 0; i < iNumContexts; i++) { + CCodingContext *pContext = &(pSC->m_pCodingContext[i]); + + /** allocate adaptive Huffman encoder **/ + pContext->m_pAdaptHuffCBPCY = Allocate (iCBPSize, ENCODER); + if(pContext->m_pAdaptHuffCBPCY == NULL) { + return ICERR_ERROR; + } + pContext->m_pAdaptHuffCBPCY1 = Allocate(5, ENCODER); + if(pContext->m_pAdaptHuffCBPCY1 == NULL){ + return ICERR_ERROR; + } + + for(k = 0; k < NUMVLCTABLES; k ++){ + pContext->m_pAHexpt[k] = Allocate(aAlphabet[k], ENCODER); + if(pContext->m_pAHexpt[k] == NULL){ + return ICERR_ERROR; + } + } + + ResetCodingContextEnc(pContext); + pContext->m_iTrimFlexBits = iTrimFlexBits; + } + + return ICERR_OK; +} + +/************************************************************************* + Context reset on encoder +*************************************************************************/ +Void ResetCodingContextEnc(CCodingContext *pContext) +{ + Int k; + /** set flags **/ + pContext->m_pAdaptHuffCBPCY->m_bInitialize = FALSE; + pContext->m_pAdaptHuffCBPCY1->m_bInitialize = FALSE; + for(k = 0; k < NUMVLCTABLES; k ++) + pContext->m_pAHexpt[k]->m_bInitialize = FALSE; + + // reset VLC tables + AdaptLowpassEnc (pContext); + AdaptHighpassEnc (pContext); + + // reset zigzag patterns, totals + InitZigzagScan(pContext); + // reset bit reduction and cbp models + ResetCodingContext(pContext); +} + +/************************************************************************* + Context deletion +*************************************************************************/ +Void FreeCodingContextEnc(CWMImageStrCodec *pSC) +{ + Int iContexts = (Int)(pSC->cNumCodingContext), i, k; + if (iContexts > 0 && pSC->m_pCodingContext) { + + for (i = 0; i < iContexts; i++) { + CCodingContext *pContext = &(pSC->m_pCodingContext[i]); + Clean (pContext->m_pAdaptHuffCBPCY); + Clean (pContext->m_pAdaptHuffCBPCY1); + for (k = 0; k < NUMVLCTABLES; k++) + Clean (pContext->m_pAHexpt[k]); + } + free (pSC->m_pCodingContext); + } +} + diff --git a/libs/jxr/image/encode/encode.h b/libs/jxr/image/encode/encode.h new file mode 100644 index 00000000000..2028d04d906 --- /dev/null +++ b/libs/jxr/image/encode/encode.h @@ -0,0 +1,113 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 WMI_ENCODE_H +#define WMI_ENCODE_H + +#include "strcodec.h" + +/************************************************************************* + struct / class definitions +*************************************************************************/ + +Int EncodeMacroblockDC(CWMImageStrCodec*, CCodingContext *, Int, Int); +Int EncodeMacroblockLowpass(CWMImageStrCodec*, CCodingContext *, Int, Int); +Int EncodeMacroblockHighpass(CWMImageStrCodec*, CCodingContext *, Int, Int); + +Int quantizeMacroblock(CWMImageStrCodec *); +Void transformMacroblock(CWMImageStrCodec *); +Void predMacroblockEnc(CWMImageStrCodec *); + +Void AdaptLowpassEnc(CCodingContext *pContext); +Void AdaptHighpassEnc(CCodingContext *pContext); +Void ResetCodingContextEnc(CCodingContext *pContext); +Int AllocateCodingContextEnc(struct CWMImageStrCodec *pSC, Int iNumContexts, Int iTrimFlexBits); +Void FreeCodingContextEnc(struct CWMImageStrCodec *pSC); +Void predCBPEnc(CWMImageStrCodec *pSC, CCodingContext *pContext); + +/************************************************************************* + Forward transform definitions +*************************************************************************/ +/** 2-point pre filter for boundaries (only used in 420 UV DC subband) **/ +Void strPre2(PixelI *, PixelI *); + +/** 2x2 pre filter (only used in 420 UV DC subband) **/ +Void strPre2x2(PixelI *, PixelI *, PixelI *, PixelI *); + +/** 4-point pre filter for boundaries **/ +Void strPre4(PixelI *, PixelI *, PixelI *, PixelI *); + +/** data allocation in working buffer (first stage) **/ + +/** Y, 444 U and V **/ +/** 0 1 2 3 **/ +/** 32 33 34 35 **/ +/** 64 65 66 67 **/ +/** 96 97 98 99 **/ + +/** 420 U and V **/ +/** 0 2 4 6 **/ +/** 64 66 68 70 **/ +/** 128 130 132 134 **/ +/** 192 194 196 198 **/ + +/** 4x4 foward DCT for first stage **/ +Void strDCT4x4FirstStage(PixelI *); +Void strDCT4x4FirstStage420UV(PixelI *); + +Void strDCT4x4Stage1(PixelI*); + +/** 4x4 pre filter for first stage **/ +Void strPre4x4FirstStage(PixelI *); +Void strPre4x4FirstStage420UV(PixelI *); + +Void strPre4x4Stage1Split(PixelI* p0, PixelI* p1, Int iOffset); +Void strPre4x4Stage1(PixelI* p, Int iOffset); + +/** data allocation in working buffer (second stage)**/ + +/** Y, 444 U and V **/ +/** 0 4 8 12 **/ +/** 128 132 136 140 **/ +/** 256 260 264 268 **/ +/** 384 388 392 396 **/ + +/** 420 U and V **/ +/** 0 8 **/ +/** 256 264 **/ + +/** 4x4 foward DCT for second stage **/ +Void strDCT4x4SecondStage(PixelI *); +Void strNormalizeEnc(PixelI *, Bool); +Void strDCT2x2dnEnc(PixelI *, PixelI *, PixelI *, PixelI *); + +/** 4x4 pre filter for second stage **/ +Void strPre4x4Stage2Split(PixelI* p0, PixelI* p1); + +#endif // ENCODE_H + diff --git a/libs/jxr/image/encode/segenc.c b/libs/jxr/image/encode/segenc.c new file mode 100644 index 00000000000..d4a8cd3ae8b --- /dev/null +++ b/libs/jxr/image/encode/segenc.c @@ -0,0 +1,1186 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 +#include +#include "strcodec.h" +#include "encode.h" + +#ifdef MEM_TRACE +#define TRACE_MALLOC 1 +#define TRACE_NEW 0 +#define TRACE_HEAP 0 +#include "memtrace.h" +#endif + +/** local function definitions **/ +#ifdef X86OPT_INLINE +__forceinline +#endif +static Int EncodeBlock (Bool bChroma, const Int *aLocalCoef, Int iNumNonzero, + struct CAdaptiveHuffman **pAHexpt, + Int iContextOffset, BitIOInfo* pOut, UInt iLocation); + +/************************************************************************* + EncodeSignificantAbsLevel +*************************************************************************/ +#ifdef X86OPT_INLINE +//__forceinline +#endif +static Void EncodeSignificantAbsLevel (UInt iAbsLevel, struct CAdaptiveHuffman *pAHexpt, BitIOInfo* pOut) +{ + Int iIndex, iFixed, aIndex[] = { 0,1,2,2, 3,3,3,3, 4,4,4,4, 5,5,5,5 }; + Int aFixedLength[] = { 0, 0, 1, 2, 2, 2 }; + + assert(iAbsLevel > 0); + iAbsLevel--; + if (iAbsLevel >= 16) { + Int i = iAbsLevel; + iIndex = 6; + /** find leftmost bit **/ + i >>= 5; + iFixed = 4; + while (i) { /** caution - infinite loop if not careful **/ + iFixed++; + assert (iFixed < 30); + i >>= 1; + } + + pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; + putBit16z(pOut, pAHexpt->m_pTable[iIndex * 2 + 1], pAHexpt->m_pTable[iIndex * 2 + 2]); + if (iFixed > 18) { + putBit16z (pOut, 15, 4); + if (iFixed > 21) { + putBit16z (pOut, 3, 2); + putBit16 (pOut, iFixed - 22, 3); // 22 - 29 + } + else + putBit16z (pOut, iFixed - 19, 2); // 19 20 21 + } + else { + putBit16z(pOut, (iFixed - 4), 4); + } + putBit32(pOut, iAbsLevel, iFixed); + } + else { + iIndex = aIndex[iAbsLevel]; + iFixed = aFixedLength[iIndex]; + + pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; + putBit16z(pOut, pAHexpt->m_pTable[iIndex * 2 + 1], pAHexpt->m_pTable[iIndex * 2 + 2]); + putBit32(pOut, iAbsLevel, iFixed); + } +} + +/************************************************************************* + EncodeMacroblockDC +*************************************************************************/ + +Void encodeQPIndex(BitIOInfo* pIO, U8 iIndex,U8 cBits) +{ + if(iIndex == 0) + putBit16z(pIO, 0, 1); + else{ + putBit16z(pIO, 1, 1); + putBit16z(pIO, iIndex - 1, cBits); + } +} + +Int EncodeMacroblockDC (CWMImageStrCodec *pSC, CCodingContext *pContext, Int iMBX, Int iMBY) +{ + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + BitIOInfo* pIO = pContext->m_pIODC; + CWMIMBInfo *pMBInfo = &pSC->MBInfo; + Int iIndex, j = 0; + struct CAdaptiveHuffman *pAH; + Int aLaplacianMean[2] = { 0, 0}, *pLM = aLaplacianMean; + Int iModelBits = pContext->m_aModelDC.m_iFlcBits[0]; + COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannels = (Int) pSC->m_param.cNumChannels; + + UNREFERENCED_PARAMETER( iMBX ); + UNREFERENCED_PARAMETER( iMBY ); + + writeIS_L1(pSC, pIO); + + if(pSC->m_param.bTranscode == FALSE){ + pMBInfo->iQIndexLP = (U8)(pTile->cNumQPLP > 1 ? (rand() % pTile->cNumQPLP) : 0); + pMBInfo->iQIndexHP = (U8)(pTile->cNumQPHP > 1 ? (rand() % pTile->cNumQPHP) : 0); + } + if(pTile->cBitsHP == 0 && pTile->cNumQPHP > 1) // use LP QP + pMBInfo->iQIndexHP = pMBInfo->iQIndexLP; + + if(pSC->WMISCP.bfBitstreamFormat == SPATIAL && pSC->WMISCP.sbSubband != SB_DC_ONLY){ + if(pTile->cBitsLP > 0) // MB-based LP QP index + encodeQPIndex(pIO, pMBInfo->iQIndexLP, pTile->cBitsLP); + if( pSC->WMISCP.sbSubband != SB_NO_HIGHPASS && pTile->cBitsHP > 0) // MB-based HP QP index + encodeQPIndex(pIO, pMBInfo->iQIndexHP, pTile->cBitsHP); + } + + if(pSC->m_param.bTranscode == FALSE) + pSC->Quantize(pSC); + + predMacroblockEnc(pSC); + + /** code path for Y_ONLY, CMYK and N_CHANNEL DC **/ + if(cf == Y_ONLY || cf == CMYK || cf == NCOMPONENT) { + Int iQDC, iDC, iSign; + for (j = 0; j < iChannels; j++) { + iDC = pMBInfo->iBlockDC[j][0]; + iSign = (iDC < 0); + iDC = abs(iDC); + iQDC = iDC >> iModelBits; + + /** send luminance DC **/ + if (iQDC) { + putBit16z(pIO, 1, 1); + EncodeSignificantAbsLevel((UInt) iQDC, pContext->m_pAHexpt[3], pIO); + *pLM += 1; + } + else { + putBit16z(pIO, 0, 1); + } + + putBit16(pIO, iDC, iModelBits); + if (iDC) { + putBit16z(pIO, iSign, 1); + } + + pLM = aLaplacianMean + 1; + iModelBits = pContext->m_aModelDC.m_iFlcBits[1]; + } + } + else { /** code path for YUV DC **/ + Int iDCY, iDCU, iDCV, iQDCY, iQDCU, iQDCV; + + pAH = pContext->m_pAHexpt[2]; + iQDCY = abs(iDCY = pMBInfo->iBlockDC[0][0]); + iQDCU = abs(iDCU = pMBInfo->iBlockDC[1][0]); + iQDCV = abs(iDCV = pMBInfo->iBlockDC[2][0]); + if (iModelBits) { + iQDCY >>= iModelBits; + } + + iModelBits = pContext->m_aModelDC.m_iFlcBits[1]; + if (iModelBits) { + iQDCU >>= iModelBits; + iQDCV >>= iModelBits; + } + iModelBits = pContext->m_aModelDC.m_iFlcBits[0]; + + iIndex = (iQDCY != 0) * 4 + (iQDCU != 0) * 2 + (iQDCV != 0); + putBit16z(pIO, pAH->m_pTable[iIndex * 2 + 1], pAH->m_pTable[iIndex * 2 + 2]); + + /** send luminance DC **/ + if (iQDCY) { + EncodeSignificantAbsLevel((UInt) iQDCY, pContext->m_pAHexpt[3], pIO); + *pLM += 1; + } + putBit16(pIO, abs(iDCY), iModelBits); + if (iDCY) { + putBit16z(pIO, (iDCY < 0), 1); + } + + /** send chroma DC **/ + pLM = aLaplacianMean + 1; + iModelBits = pContext->m_aModelDC.m_iFlcBits[1]; + + if (iQDCU) { + EncodeSignificantAbsLevel((UInt) iQDCU, pContext->m_pAHexpt[4], pIO); + *pLM += 1; + } + putBit16(pIO, abs(iDCU), iModelBits); + if (iDCU) { + putBit16z(pIO, (iDCU < 0), 1); + } + + if (iQDCV) { + EncodeSignificantAbsLevel((UInt) iQDCV, pContext->m_pAHexpt[4], pIO); + *pLM += 1; + } + putBit16(pIO, abs(iDCV), iModelBits); + if (iDCV) { + putBit16z(pIO, (iDCV < 0), 1); + } + } + + UpdateModelMB (cf, iChannels, aLaplacianMean, &(pContext->m_aModelDC)); + + if (pSC->m_bResetContext && pSC->WMISCP.sbSubband == SB_DC_ONLY) { + AdaptDiscriminant(pContext->m_pAHexpt[2]); + AdaptDiscriminant(pContext->m_pAHexpt[3]); + AdaptDiscriminant(pContext->m_pAHexpt[4]); + } + + return ICERR_OK; +} + +/************************************************************************* + Scan block with zero model bits +*************************************************************************/ +#ifdef X86OPT_INLINE +__forceinline +#endif +static Int AdaptiveScanZero (const PixelI *pCoeffs, CAdaptiveScan *pScan, + Int *pRLCoeffs, const Int iCount) +{ + Int k, iRun = 1, iLevel, iNumNonzero = 0; + + iLevel = pCoeffs[pScan[1].uScan]; + if (iLevel) { + pScan[1].uTotal++; + pRLCoeffs[iNumNonzero * 2] = 0; + pRLCoeffs[iNumNonzero * 2 + 1] = iLevel; + iNumNonzero++; + iRun = 0; + } + for (k = 2; k < iCount; k++) { + iLevel = pCoeffs[pScan[k].uScan]; + iRun++; + if (iLevel) { + pScan[k].uTotal++; + if (pScan[k].uTotal > pScan[k - 1].uTotal) { + CAdaptiveScan cTemp = pScan[k]; + pScan[k] = pScan[k - 1]; + pScan[k - 1] = cTemp; + } + pRLCoeffs[iNumNonzero * 2] = iRun - 1; + pRLCoeffs[iNumNonzero * 2 + 1] = iLevel; + iNumNonzero++; + iRun = 0; + } + } + return iNumNonzero; +} + +/************************************************************************* + Scan block with nonzero model bits, all trimmed +*************************************************************************/ +#ifdef X86OPT_INLINE +__forceinline +#endif +static Int AdaptiveScanTrim (const PixelI *pCoeffs, CAdaptiveScan *pScan, + const Int iModelBits, Int *pRLCoeffs, const Int iCount) +{ + Int k, iRun = 1, iLevel, iNumNonzero = 0; + Int iTemp; + unsigned int iThOff = (1 << iModelBits) - 1, iTh = iThOff * 2 + 1; + + iLevel = pCoeffs[pScan[1].uScan]; + + if ((unsigned int)(iLevel + iThOff) >= iTh) { + iTemp = abs (iLevel) >> iModelBits; + pScan[1].uTotal++; + pRLCoeffs[iNumNonzero * 2] = 0; + pRLCoeffs[iNumNonzero * 2 + 1] = (iLevel < 0) ? -iTemp : iTemp; + iNumNonzero++; + iRun = 0; + } + for (k = 2; k < iCount; k++) { + iRun++; + iLevel = pCoeffs[pScan[k].uScan]; + if ((unsigned int)(iLevel + iThOff) >= iTh) { + iTemp = abs (iLevel) >> iModelBits; + pScan[k].uTotal++; + if (pScan[k].uTotal > pScan[k - 1].uTotal) { + CAdaptiveScan cTemp = pScan[k]; + pScan[k] = pScan[k - 1]; + pScan[k - 1] = cTemp; + } + pRLCoeffs[iNumNonzero * 2] = iRun - 1; + pRLCoeffs[iNumNonzero * 2 + 1] = (iLevel < 0) ? -iTemp : iTemp; + iNumNonzero++; + iRun = 0; + } + } + return iNumNonzero; +} + +/************************************************************************* + Scan block with nonzero model bits +*************************************************************************/ +/** saves around 1.5% at QP=1 (no SIMD opt) **/ +#define USE_GRES_LUT +#ifdef USE_GRES_LUT +static const Int gRes[] = { +65*2+1, 63*2+1, 61*2+1, 59*2+1, 57*2+1, 55*2+1, 53*2+1, 51*2+1, 49*2+1, 47*2+1, 45*2+1, 43*2+1, 41*2+1, +39*2+1, 37*2+1, 35*2+1, 33*2+1, 31*2+1, 29*2+1, 27*2+1, 25*2+1, 23*2+1, 21*2+1, 19*2+1, 17*2+1, 15*2+1, +13*2+1, 11*2+1, 9*2+1, 7*2+1, 5*2+1, 3*2+1, +0, +2*2+1, 4*2+1, 6*2+1, 8*2+1, 10*2+1, 12*2+1, 14*2+1, 16*2+1, 18*2+1, 20*2+1, 22*2+1, 24*2+1, +26*2+1, 28*2+1, 30*2+1, 32*2+1, 34*2+1, 36*2+1, 38*2+1, 40*2+1, 42*2+1, 44*2+1, 46*2+1, 48*2+1, 50*2+1, +52*2+1, 54*2+1, 56*2+1, 58*2+1, 60*2+1, 62*2+1, 64*2+1 }; +#endif // USE_GRES_LUT + +#ifdef X86OPT_INLINE +//__forceinline +#endif +static Int AdaptiveScan (const PixelI *pCoeffs, Int *pResidual, + CAdaptiveScan *pScan, + const Int iModelBits, const Int iTrimBits, + Int *pRLCoeffs, const Int iCount) +{ + if (iModelBits == 0) { + return AdaptiveScanZero (pCoeffs, pScan, pRLCoeffs, iCount); + } + else if (iModelBits <= iTrimBits) { + return AdaptiveScanTrim (pCoeffs, pScan, iModelBits, pRLCoeffs, iCount); + } + else if (iTrimBits == 0 +#ifdef USE_GRES_LUT + && iModelBits < 6 +#endif // USE_GRES_LUT + ) { + Int k, iRun = 0, iLevel, iNumNonzero = 0; + Int iTemp, iTemp1; + const unsigned int iThOff = (1 << iModelBits) - 1, iTh = iThOff * 2 + 1; + + iLevel = pCoeffs[pScan[1].uScan]; + + if ((unsigned int)(iLevel + iThOff) >= iTh) { + iTemp1 = abs (iLevel); + iTemp = iTemp1 >> iModelBits; + pResidual[pScan[1].uScan] = (iTemp1 & iThOff) * 2; + pScan[1].uTotal++; + pRLCoeffs[iNumNonzero * 2] = iRun; + pRLCoeffs[iNumNonzero * 2 + 1] = (iLevel < 0) ? -iTemp : iTemp; + iNumNonzero++; + iRun = 0; + } + else { + iRun++; +#ifdef USE_GRES_LUT + pResidual[pScan[1].uScan] = gRes[(iLevel + 32)]; +#else // USE_GRES_LUT + iTemp = -(iLevel < 0); + pResidual[pScan[1].uScan] = (iLevel ^ iTemp) * 4 + (6 & iTemp) + (iLevel != 0); +#endif // USE_GRES_LUT + } + for (k = 2; k < iCount; k++) { + const Int sk = pScan[k].uScan; + //pResidual++; + iLevel = pCoeffs[sk]; + if ((unsigned int)(iLevel + iThOff) >= iTh) { + const Int iSign = -(iLevel < 0); + iTemp1 = (iSign ^ iLevel) - iSign; + iTemp = iTemp1 >> iModelBits; + pResidual[sk] = (iTemp1 & iThOff) * 2; + pScan[k].uTotal++; + if (pScan[k].uTotal > pScan[k - 1].uTotal) { + CAdaptiveScan cTemp = pScan[k]; + pScan[k] = pScan[k - 1]; + pScan[k - 1] = cTemp; + } + pRLCoeffs[iNumNonzero * 2] = iRun; + pRLCoeffs[iNumNonzero * 2 + 1] = (iTemp ^ iSign) - iSign; + iNumNonzero++; + iRun = 0; + } + else { + iRun++; +#ifdef USE_GRES_LUT + pResidual[sk] = gRes[(iLevel + 32)]; +#else // USE_GRES_LUT + iTemp = -(iLevel < 0); + pResidual[sk] = (iLevel ^ iTemp) * 4 + (6 & iTemp) + (iLevel != 0); +#endif // USE_GRES_LUT + ////(abs(iLevel) * 4) + ((iLevel < 0) * 2) + (iLevel != 0); + } + } + return iNumNonzero; + } + else { + Int k, iRun = 0, iLevel, iNumNonzero = 0; + Int iTemp, iTemp1; + const unsigned int iThOff = (1 << iModelBits) - 1, iTh = iThOff * 2 + 1; + + iLevel = pCoeffs[pScan[1].uScan]; + //pResidual++; + if ((unsigned int)(iLevel + iThOff) >= iTh) { + iTemp1 = abs (iLevel); + iTemp = iTemp1 >> iModelBits; + pResidual[pScan[1].uScan] = ((iTemp1 & iThOff) >> iTrimBits) * 2; + pScan[1].uTotal++; + pRLCoeffs[iNumNonzero * 2] = iRun; + pRLCoeffs[iNumNonzero * 2 + 1] = (iLevel < 0) ? -iTemp : iTemp; + iNumNonzero++; + iRun = 0; + } + else { + iRun++; + iTemp = -(iLevel < 0); + iLevel = ((iLevel + iTemp) >> iTrimBits) - iTemp; // round towards zero + iTemp = -(iLevel < 0); + pResidual[pScan[1].uScan] = (iLevel ^ iTemp) * 4 + (6 & iTemp) + (iLevel != 0); + } + for (k = 2; k < iCount; k++) { + const Int sk = pScan[k].uScan; + //pResidual++; + iLevel = pCoeffs[sk]; + if ((unsigned int)(iLevel + iThOff) >= iTh) { + iTemp1 = abs (iLevel); + iTemp = iTemp1 >> iModelBits; + pResidual[sk] = ((iTemp1 & iThOff) >> iTrimBits) * 2; + pScan[k].uTotal++; + if (pScan[k].uTotal > pScan[k - 1].uTotal) { + CAdaptiveScan cTemp = pScan[k]; + pScan[k] = pScan[k - 1]; + pScan[k - 1] = cTemp; + } + pRLCoeffs[iNumNonzero * 2] = iRun; + pRLCoeffs[iNumNonzero * 2 + 1] = (iLevel < 0) ? -iTemp : iTemp; + iNumNonzero++; + iRun = 0; + } + else { + iRun++; + iTemp = -(iLevel < 0); + iLevel = ((iLevel + iTemp) >> iTrimBits) - iTemp; // round towards zero + iTemp = -(iLevel < 0); + pResidual[sk] = (iLevel ^ iTemp) * 4 + (6 & iTemp) + (iLevel != 0); + } + } + return iNumNonzero; + } +} + +/************************************************************************* + EncodeMacroblockLowpass +*************************************************************************/ +Int EncodeMacroblockLowpass (CWMImageStrCodec *pSC, CCodingContext *pContext, Int iMBX, Int iMBY) +{ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannels = (Int) pSC->m_param.cNumChannels; + Int iFullChannels = (cf == YUV_420 || cf == YUV_422) ? 1 : iChannels; + CWMIMBInfo *pMBInfo = &pSC->MBInfo; + BitIOInfo* pIO = pContext->m_pIOLP; + + CAdaptiveScan *pScan = pContext->m_aScanLowpass; + Int k, /*iPrevRun = -1,*/ iRun = 0;// iLastIndex = 0; + Int iModelBits = pContext->m_aModelLP.m_iFlcBits[0]; + PixelI aBuf[2][8]; + Int aLaplacianMean[2] = {0, 0}, *pLM = aLaplacianMean; + Int iChannel, iVal; + Int aRLCoeffs[MAX_CHANNELS][32], iNumCoeffs[MAX_CHANNELS]; + const I32 *aDC[MAX_CHANNELS]; + Int aResidual[MAX_CHANNELS][16]; + Void (*putBits)(BitIOInfo* pIO, U32 uiBits, U32 cBits) = putBit16; + + UNREFERENCED_PARAMETER( iMBX ); + UNREFERENCED_PARAMETER( iMBY ); + + if (iChannels > MAX_CHANNELS) + return ICERR_ERROR; + + if((pSC->WMISCP.bfBitstreamFormat != SPATIAL) && (pSC->pTile[pSC->cTileColumn].cBitsLP > 0)) // MB-based LP QP index + encodeQPIndex(pIO, pMBInfo->iQIndexLP, pSC->pTile[pSC->cTileColumn].cBitsLP); + + // set arrays + for (k = 0; k < iChannels; k++) { + aDC[k] = pMBInfo->iBlockDC[k]; + } + + /** reset adaptive scan totals **/ + if (pSC->m_bResetRGITotals) { + int iScale = 2; + int iWeight = iScale * 16; + pScan[0].uTotal = MAXTOTAL; + for (k = 1; k < 16; k++) { + pScan[k].uTotal = iWeight; + iWeight -= iScale; + } + } + + /** scan 4x4 transform **/ + for (iChannel = 0; iChannel < iFullChannels; iChannel++) { + iNumCoeffs[iChannel] = AdaptiveScan (aDC[iChannel], aResidual[iChannel], + pScan, iModelBits, 0, aRLCoeffs[iChannel], 16); + + iModelBits = pContext->m_aModelLP.m_iFlcBits[1]; + } + + if (cf == YUV_420 || cf == YUV_422) { /** interleave U and V **/ + static const Int aRemap[] = { 4, 1,2,3, 5,6,7 }; + const Int *pRemap = aRemap + (cf == YUV_420); + const Int iCount = (cf == YUV_420) ? 6 : 14; + Int iCoef = 0; + + iRun = 0; + iModelBits = pContext->m_aModelLP.m_iFlcBits[1]; + + for (k = 0; k < iCount; k++) { + Int iIndex = pRemap[k >> 1]; + Int iDC = aDC[(k & 1) + 1][iIndex]; + aBuf[k & 1][iIndex] = iVal = abs (iDC) >> iModelBits; + + if (iVal) { + aRLCoeffs[1][iCoef * 2] = iRun; + aRLCoeffs[1][iCoef * 2 + 1] = (iDC < 0) ? -iVal : iVal; + iCoef++; + iRun = 0; + } + else { + iRun++; + } + } + iNumCoeffs[1] = iCoef; + } + + /** in raw mode, this can take 6% of the bits in the extreme low rate case!!! **/ + if (cf == YUV_420 || cf == YUV_422) + iFullChannels = 2; + + if (cf == YUV_420 || cf == YUV_422 || cf == YUV_444) { + int iCBP, iMax = iFullChannels * 4 - 5; /* actually (1 << iNChannels) - 1 **/ + int iCountM = pContext->m_iCBPCountMax, iCountZ = pContext->m_iCBPCountZero; + iCBP = (iNumCoeffs[0] > 0) + (iNumCoeffs[1] > 0) * 2; + if (iFullChannels == 3) + iCBP += (iNumCoeffs[2] > 0) * 4; + + if (iCountZ <= 0 || iCountM < 0) { + iVal = iCBP; + if (iCountM < iCountZ) { + iVal = iMax - iCBP; + } + if (iVal == 0) + putBit16z(pIO, 0, 1); + else if (iVal == 1) + putBit16z(pIO, (iFullChannels + 1) & 0x6, iFullChannels); // 2 or 4 + else + putBit16z(pIO, iVal + iMax + 1, iFullChannels + 1); // cbp + 4 or cbp + 8 + } + else { + putBit16z(pIO, iCBP, iFullChannels); + } + + iCountM += 1 - 4 * (iCBP == iMax);//(b + c - 2*a); + iCountZ += 1 - 4 * (iCBP == 0);//(a + b - 2*c); + if (iCountM < -8) + iCountM = -8; + else if (iCountM > 7) + iCountM = 7; + pContext->m_iCBPCountMax = iCountM; + + if (iCountZ < -8) + iCountZ = -8; + else if (iCountZ > 7) + iCountZ = 7; + pContext->m_iCBPCountZero = iCountZ; + } + else { /** 1 or N channel **/ + for (iChannel = 0; iChannel < iChannels; iChannel++) { + putBit16z(pIO, (iNumCoeffs[iChannel] > 0), 1); + } + } + + // set appropriate function pointer + if (pContext->m_aModelLP.m_iFlcBits[0] > 14 || pContext->m_aModelLP.m_iFlcBits[1] > 14) { + putBits = putBit32; + } + + iModelBits = pContext->m_aModelLP.m_iFlcBits[0]; + + for (iChannel = 0; iChannel < iFullChannels; iChannel++) { + const Int *pRL = aRLCoeffs[iChannel]; + Int iCoef = iNumCoeffs[iChannel]; + + if (iCoef) { + (*pLM) += iCoef; + if(EncodeBlock (iChannel > 0, pRL, iCoef, pContext->m_pAHexpt, CTDC, + pIO, 1 + 9 * ((cf == YUV_420) && (iChannel == 1)) + ((cf == YUV_422) && (iChannel == 1))) != ICERR_OK) + return ICERR_ERROR; + } + + if (iModelBits) { + if ((cf == YUV_420 || cf == YUV_422) && iChannel) { // 420/422 chroma + for (k = 1; k < ((cf == YUV_420) ? 4 : 8); k++) { + putBits(pIO, abs(aDC[1][k]), iModelBits); + if (aBuf[0][k] == 0 && aDC[1][k]) { + putBit16z(pIO, (aDC[1][k] < 0), 1); + } + putBits(pIO, abs(aDC[2][k]), iModelBits); + if (aBuf[1][k] == 0 && aDC[2][k]) { + putBit16z(pIO, (aDC[2][k] < 0), 1); + } + } + } + else { // normal case + for (k = 1; k < 16; k++) { + putBit16z(pIO, aResidual[iChannel][k] >> 1, iModelBits + (aResidual[iChannel][k] & 1)); + } + } + } + + pLM = aLaplacianMean + 1; + iModelBits = pContext->m_aModelLP.m_iFlcBits[1]; + } + + writeIS_L1(pSC, pIO); + + UpdateModelMB (cf, iChannels, aLaplacianMean, &pContext->m_aModelLP); + + if (pSC->m_bResetContext) { + AdaptLowpassEnc(pContext); + } + + return ICERR_OK; +} + +/************************************************************************* + Adapt +*************************************************************************/ +Void AdaptLowpassEnc(CCodingContext *pSC) +{ + Int kk; + for (kk = 0; kk < CONTEXTX + CTDC; kk++) { /** adapt fixed code (index 0 and 1) as well **/ + AdaptDiscriminant (pSC->m_pAHexpt[kk]); + } +} + +Void AdaptHighpassEnc(CCodingContext *pSC) +{ + Int kk; + //Adapt (pSC->m_pAdaptHuffCBPCY, FALSE); + AdaptDiscriminant (pSC->m_pAdaptHuffCBPCY); + AdaptDiscriminant (pSC->m_pAdaptHuffCBPCY1); + for (kk = 0; kk < CONTEXTX; kk++) { /** adapt fixed code **/ + AdaptDiscriminant (pSC->m_pAHexpt[kk + CONTEXTX + CTDC]); + } +} + +/************************************************************************* + Experimental code -- encodeBlock + SR = <0 1 2> == + alphabet 12: + pAHexpt[0] == + alphabet 6: + pAHexpt[1] == + pAHexpt[2] == + alphabet 4: + pAHexpt[3] == (SR may be last or insignificant only) + alphabet f(run) (this can be extended to 6 contexts - SL and SR') + pAHexpt[4] == + alphabet f(lev) (this can be extended to 9 contexts) + pAHexpt[5-6] == first symbol + pAHexpt[7-8] == condition on SRn no use +*************************************************************************/ +#ifdef X86OPT_INLINE +__forceinline +#endif +static Void EncodeSignificantRun (Int iRun, Int iMaxRun, struct CAdaptiveHuffman *pAHexpt, BitIOInfo* pOut) +{ + Int iIndex, iFLC, iBin; + static const Int aIndex[] = { + 0,1,2,2,3,3,4,4,4,4,4,4,4,4, + 0,1,2,2,3,3,4,4,4,4,0,0,0,0, + 0,1,2,3,4,4 + }; + + if (iMaxRun < 5) { + //if (iMaxRun == 4) { + //static const Int gCode[] = { 0, 1, 1, 1 }; + static const Int gLen[] = { 3, 3, 2, 1 }; + if (iMaxRun > 1) + putBit16z(pOut, (iMaxRun != iRun), gLen[iMaxRun - iRun] - (4 - iMaxRun)); + //} + //else if (iMaxRun == 3) { + // if (iRun == 1) { + // putBit16z(pOut, 1, 1); + // } + // else { + // putBit16z(pOut, 3 ^ iRun, 2); + // } + //} + //else if (iMaxRun == 2) { + // putBit16z(pOut, 2 - iRun, 1); + //} + return; + } + + iBin = gSignificantRunBin[iMaxRun]; + iIndex = aIndex[iRun + iBin * 14 - 1]; + iFLC = gSignificantRunFixedLength[iIndex + iBin * 5]; + putBit16z(pOut, pAHexpt->m_pTable[iIndex * 2 + 1], pAHexpt->m_pTable[iIndex * 2 + 2]); + //this always uses table 0 + //pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; + putBit16(pOut, iRun + 1, iFLC); +} + +#ifdef X86OPT_INLINE +__forceinline +#endif +static Void EncodeFirstIndex (Bool bChroma, Int iLoc, Int iCont, Int iIndex, Int iSign, + struct CAdaptiveHuffman **ppAHexpt, BitIOInfo* pOut) +{ + // Int iContext = iCont + 1 + bChroma * 3; + struct CAdaptiveHuffman *pAHexpt = ppAHexpt[bChroma * 3]; + UNREFERENCED_PARAMETER( iLoc ); + UNREFERENCED_PARAMETER( iCont ); + pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; + pAHexpt->m_iDiscriminant1 += pAHexpt->m_pDelta1[iIndex]; + putBit16z(pOut, pAHexpt->m_pTable[iIndex * 2 + 1] * 2 + iSign, pAHexpt->m_pTable[iIndex * 2 + 2] + 1); + return; +} + +#ifdef X86OPT_INLINE +__forceinline +#endif +static Void EncodeIndex (Bool bChroma, Int iLoc, Int iCont, Int iIndex, Int iSign, + struct CAdaptiveHuffman **ppAHexpt, BitIOInfo* pOut) +{ + Int iContext = iCont + 1 + bChroma * 3; + + if (iLoc < 15) { + struct CAdaptiveHuffman *pAHexpt = ppAHexpt[iContext]; + pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; + pAHexpt->m_iDiscriminant1 += pAHexpt->m_pDelta1[iIndex]; + putBit16z(pOut, pAHexpt->m_pTable[iIndex * 2 + 1] * 2 + iSign, pAHexpt->m_pTable[iIndex * 2 + 2] + 1); + } + else if (iLoc == 15) { + static const U32 gCode[] = { 0, 6, 2, 7 }; + static const U32 gLen[] = { 1, 3, 2, 3 }; + putBit16z(pOut, gCode[iIndex] * 2 + iSign, gLen[iIndex] + 1); + return; + } + else {//if (iLoc == 16) { + putBit16z(pOut, iIndex * 2 + iSign, 1 + 1); + return; + } +} + +#ifdef X86OPT_INLINE +__forceinline +#endif +static Int EncodeBlock (Bool bChroma, const Int *aLocalCoef, Int iNumNonzero, + struct CAdaptiveHuffman **pAHexpt, Int iContextOffset, + BitIOInfo* pOut, UInt iLocation) +{ + Int iSR, iSL, iSRn, iIndex, k, iCont, iLev; + + /** first symbol **/ + iLev = aLocalCoef[1]; + iSR = (aLocalCoef[0] == 0); + iSL = ((unsigned int) (iLev + 1) > 2U); + iSRn = 1; + if (iNumNonzero == 1) { + iSRn = 0; + } + else if (aLocalCoef[2] > 0) { + iSRn = 2; + } + iIndex = iSRn * 4 + iSL * 2 + iSR; + EncodeFirstIndex (bChroma, iLocation, 0, iIndex, (iLev < 0), pAHexpt + iContextOffset, pOut); + iCont = iSR & iSRn; + if (iSL) { + EncodeSignificantAbsLevel ((UInt)(abs(iLev) - 1), pAHexpt[6 + iContextOffset + iCont], pOut); + } + if (iSR == 0) { + EncodeSignificantRun (aLocalCoef[0], 15 - iLocation, pAHexpt[0], pOut); + } + iLocation += aLocalCoef[0] + 1; + + for (k = 1; k < iNumNonzero; k++) { + if (iSRn == 2) { + EncodeSignificantRun (aLocalCoef[k * 2], 15 - iLocation, pAHexpt[0], pOut); + } + iLocation += aLocalCoef[k * 2] + 1; + iSRn = 1; + if (k == iNumNonzero - 1) { + iSRn = 0; + } + else if (aLocalCoef[k * 2 + 2] > 0) { + iSRn = 2; + } + //iSL = (abs(aLocalCoef[k * 2 + 1]) > 1); + iLev = aLocalCoef[k * 2 + 1]; + iSL = ((unsigned int) (iLev + 1) > 2U); + iIndex = iSRn * 2 + iSL; + EncodeIndex (bChroma, iLocation, iCont, iIndex, (iLev < 0), pAHexpt + iContextOffset, pOut); + + iCont &= iSRn; /** big difference! **/ + if (iSL) { + EncodeSignificantAbsLevel ((UInt)(abs(iLev) - 1), pAHexpt[6 + iContextOffset + iCont], pOut); + } + //else { + // putBit16z(pOut, (iLev < 0), 1); + //} + } + + return ICERR_OK; +} + +/************************************************************************* + CodeCoeffs +*************************************************************************/ +#ifdef X86OPT_INLINE +__forceinline +#endif +static Int CodeCoeffs (CWMImageStrCodec * pSC, CCodingContext *pContext, + Int iMBX, Int iMBY, BitIOInfo* pIO, BitIOInfo* pIOFL) +{ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannels = (Int) pSC->m_param.cNumChannels; + const Int iPlanes = (cf == YUV_420 || cf == YUV_422) ? 1 : iChannels; + CWMIMBInfo * pMBInfo = &pSC->MBInfo; + CAdaptiveScan *pScan; + Int iBlock, iNBlocks = 4; + Int iSubblock, iIndex = 0; + Int i, k; + const Int iNumCoeffs = 16; + Int iModelBits = pContext->m_aModelAC.m_iFlcBits[0], iFlex = 0, iTrim = 0, iMask = 0; + Int aLaplacianMean[2] = { 0, 0}, *pLM = aLaplacianMean; + Bool bChroma = FALSE; + + UNREFERENCED_PARAMETER( iMBX ); + UNREFERENCED_PARAMETER( iMBY ); + + assert (iModelBits < 16); + if (pContext->m_iTrimFlexBits <= iModelBits && pSC->WMISCP.sbSubband != SB_NO_FLEXBITS) { + iTrim = pContext->m_iTrimFlexBits; + iFlex = iModelBits - pContext->m_iTrimFlexBits; + iMask = (1 << iFlex) - 1; + } + + if(pSC->WMISCP.sbSubband != SB_NO_FLEXBITS) + writeIS_L1(pSC, pIOFL); + + /** set scan arrays **/ + if (pMBInfo->iOrientation == 1) { + pScan = pContext->m_aScanVert; + } + else { + pScan = pContext->m_aScanHoriz; + } + + /** write out coefficients **/ + for (i = 0; i < iPlanes; i++) { + Int iPattern = pMBInfo->iCBP[i]; + + if (cf == YUV_420) { + iNBlocks = 6; + iPattern += (pMBInfo->iCBP[1] << 16) + (pMBInfo->iCBP[2] << 20); + } + else if (cf == YUV_422) { + iNBlocks = 8; + iPattern += (pMBInfo->iCBP[1] << 16) + (pMBInfo->iCBP[2] << 24); + } + + for (iBlock = iIndex = 0; iBlock < iNBlocks; iBlock++) { + writeIS_L2(pSC, pIO); + if (pIO != pIOFL) + writeIS_L2(pSC, pIOFL); + + for (iSubblock = 0; iSubblock < 4; iSubblock++, iPattern >>= 1, iIndex ++) { + const PixelI *pCoeffs = NULL; + + if(iBlock < 4){ + pCoeffs = pSC->pPlane[i] + blkOffset[iIndex]; + } + else if(cf == YUV_420){ + pCoeffs = pSC->pPlane[iBlock - 3] + blkOffsetUV[iSubblock]; + } + else if(cf == YUV_422){ + pCoeffs = pSC->pPlane[1 + ((iBlock - 4) >> 1)] + blkOffsetUV_422[(iBlock & 1) * 4 + iSubblock]; + } + + /** put AC bits **/ + + if ((iPattern & 1) == 0) { + if (iFlex) { + /** FLC only, all else is skipped **/ + for (k = 1; k < iNumCoeffs; k++) { + Int data = pCoeffs[dctIndex[0][k]]; + Int atdata = (abs(data) >> iTrim); + Int word = atdata & iMask, len = iFlex; + if (atdata) { + word += word + (data < 0); + len++; + } + putBit16z(pIOFL, word, len); + } + } + } + else { +// WARNING!!! interaction between lowpass coefficients and highpass scan ordering - may lead to break in decoding when model bits is nonzero! +// Fix is to use same scan order in model bits transmission, and defer update of scan order to end of block + /** collect coefficients **/ + Int aLocalCoef[32], iNumNonzero = 0; + Int aResidual[16]; + + iNumNonzero = AdaptiveScan (pCoeffs, aResidual, + pScan, iModelBits, iTrim, aLocalCoef, 16); + (*pLM) += iNumNonzero; + EncodeBlock (bChroma, aLocalCoef, iNumNonzero, pContext->m_pAHexpt, CTDC + CONTEXTX, pIO, 1); + + if (iFlex) { + for (k = 1; k < iNumCoeffs; k++) { + putBit16z(pIOFL, aResidual[dctIndex[0][k]] >> 1, iFlex + (aResidual[dctIndex[0][k]] & 1)); + } + } + } + } + if (iBlock == 3) { + iModelBits = pContext->m_aModelAC.m_iFlcBits[1]; + assert (iModelBits < 16); + pLM = aLaplacianMean + 1; + bChroma = TRUE; + iTrim = iFlex = iMask = 0; + if (pContext->m_iTrimFlexBits <= iModelBits && pSC->WMISCP.sbSubband != SB_NO_FLEXBITS) { + iTrim = pContext->m_iTrimFlexBits; + iFlex = iModelBits - iTrim; + iMask = (1 << iFlex) - 1; + } + } + } + } + + /** update model at end of MB **/ + UpdateModelMB (cf, iChannels, aLaplacianMean, &pContext->m_aModelAC); + + return ICERR_OK; +} + + +/************************************************************************* + CodeCBP +*************************************************************************/ +static Void CodeCBP (CWMImageStrCodec * pSC, CCodingContext *pContext, + Int iMBX, Int iMBY, BitIOInfo *pIO) +{ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannel = (cf == NCOMPONENT || cf == CMYK) ? (Int) pSC->m_param.cNumChannels : 1; + Int iDiffCBPCY, iDiffCBPCU = 0, iDiffCBPCV = 0, iDY; + Int iBlock, i, k; + static const Int aNumOnes[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + static const Int aTabLen[] = { 0, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 3, 2, 2, 0 }; + static const Int aTabCode[] = { 0, 0, 1, 0, 2, 1, 4, 3, 3, 5, 6, 2, 7, 1, 0, 0 }; + CAdaptiveHuffman *pAH; + Int iCount, iPattern, iCode, iCodeU = 0, iCodeV = 0; + + UNREFERENCED_PARAMETER( iMBX ); + UNREFERENCED_PARAMETER( iMBY ); + + predCBPEnc(pSC, pContext); + writeIS_L1(pSC, pIO); + + iDiffCBPCU = pSC->MBInfo.iDiffCBP[1]; + iDiffCBPCV = pSC->MBInfo.iDiffCBP[2]; + + for (i = 0; i < iChannel; i++) { + iDiffCBPCY = pSC->MBInfo.iDiffCBP[i]; + + if(cf == YUV_420){ // PackCBP420 + iDiffCBPCY = (iDiffCBPCY & 0xf) + ((iDiffCBPCU & 1) << 4) + ((iDiffCBPCV & 1) << 5) + + ((iDiffCBPCY & 0x00f0) << 2) + ((iDiffCBPCU & 2) << 9) + ((iDiffCBPCV & 2) << 10) + + ((iDiffCBPCY & 0x0f00) << 4) + ((iDiffCBPCU & 4) << 14) + ((iDiffCBPCV & 4) << 15) + + ((iDiffCBPCY & 0xf000) << 6) + ((iDiffCBPCU & 8) << 19) + ((iDiffCBPCV & 8) << 20); + } + else if(cf == YUV_422){// PackCBP422 + iDiffCBPCY = (iDiffCBPCY & 0xf) + ((iDiffCBPCU & 1) << 4) + ((iDiffCBPCU & 4) << 3) + + ((iDiffCBPCV & 1) << 6) + ((iDiffCBPCV & 4) << 5) + + ((iDiffCBPCY & 0x00f0) << 4) + ((iDiffCBPCU & 2) << 11) + ((iDiffCBPCU & 8) << 10) + + ((iDiffCBPCV & 2) << 13) + ((iDiffCBPCV & 8) << 12) + + ((iDiffCBPCY & 0x0f00) << 8) + ((iDiffCBPCU & 16) << 16) + ((iDiffCBPCU & 64) << 15) + + ((iDiffCBPCV & 16) << 18) + ((iDiffCBPCV & 64) << 17) + + ((iDiffCBPCY & 0xf000) << 12) + ((iDiffCBPCU & 32) << 23) + ((iDiffCBPCU & 128) << 22) + + ((iDiffCBPCV & 32) << 25) + ((iDiffCBPCV & 128) << 24); + } + + /** send CBPCY **/ + iPattern = 0; + iDY = iDiffCBPCY; + if (cf == YUV_444) { + iDY |= (iDiffCBPCU | iDiffCBPCV); + } + + for (iBlock = 0; iBlock < 4; iBlock++) { + if(cf == YUV_422) { + iPattern |= ((iDY & 0xff) != 0) * 0x10; + iDY >>= 8; + } + else if (cf == YUV_420) { + iPattern |= ((iDY & 0x3f) != 0) * 0x10; + iDY >>= 6; + } + else { + iPattern |= ((iDY & 0xf) != 0) * 0x10; + iDY >>= 4; + } + iPattern >>= 1; + } + + pAH = pContext->m_pAdaptHuffCBPCY1; + iCount = aNumOnes[iPattern]; + putBit16z(pIO, pAH->m_pTable[iCount * 2 + 1], pAH->m_pTable[iCount * 2 + 2]); + pAH->m_iDiscriminant += pAH->m_pDelta[iCount]; + if (aTabLen[iPattern]) { + putBit16z(pIO, aTabCode[iPattern], aTabLen[iPattern]); + } + + for (iBlock = 0; iBlock < 4; iBlock++) { + switch (cf) { + case YUV_444: + iCode = iDiffCBPCY & 0xf; + iCodeU = iDiffCBPCU & 0xf; + iCodeV = iDiffCBPCV & 0xf; + iCode |= ((iCodeU != 0) << 4); + iCode |= ((iCodeV != 0) << 5); + iDiffCBPCY >>= 4; + iDiffCBPCU >>= 4; + iDiffCBPCV >>= 4; + break; + + case YUV_422: + iCode = iDiffCBPCY & 0xff; + iDiffCBPCY >>= 8; + break; + + case YUV_420: + iCode = iDiffCBPCY & 0x3f; + iDiffCBPCY >>= 6; + break; + + default: + iCode = iDiffCBPCY & 0xf; + iDiffCBPCY >>= 4; + } + + if (iCode) { + static const Int gTab0[16] = { 0,1,1,2, 1,3,3,4, 1,3,3,4, 2,4,4,5 }; + static const Int gFL0[16] = { 0,2,2,1, 2,2,2,2, 2,2,2,2, 1,2,2,0 }; + static const Int gCode0[16] = { 0,0,1,0, 2,0,1,0, 3,2,3,1, 1,2,3,0 }; + int val, iChroma = (iCode >> 4); + iCode &= 0xf; + + if(cf == YUV_422) { + iCodeU = (iChroma & 3); + iCodeV = ((iChroma >> 2) & 3); + iChroma = (iCodeU == 0 ? 0 : 1); + if(iCodeV != 0) { + iChroma += 2; + } + } + + if (iChroma) { + if (gTab0[iCode] > 2) { + val = 8; + } + else { + val = gTab0[iCode] + 6 - 1; + } + } + else { + val = gTab0[iCode] - 1; + } + pAH = pContext->m_pAdaptHuffCBPCY; + putBit16z(pIO, pAH->m_pTable[val * 2 + 1], pAH->m_pTable[val * 2 + 2]); + pAH->m_iDiscriminant += pAH->m_pDelta[val]; + + if (iChroma) { + if (iChroma == 1) + putBit16z(pIO, 1, 1); + else + putBit16z(pIO, 3 - iChroma, 2); + } + if (val == 8) { + if (gTab0[iCode] == 3) { + putBit16z(pIO, 1, 1); + } + else { + putBit16z(pIO, 5 - gTab0[iCode], 2); + } + } + if (gFL0[iCode]) { + putBit16z(pIO, gCode0[iCode], gFL0[iCode]); + } + + if (cf == YUV_444) { + pAH = pContext->m_pAHexpt[1]; + iPattern = iCodeU; + for (k = 0; k < 2; k++) { + if (iPattern) { + iCount = aNumOnes[iPattern]; + iCount--; + putBit16z(pIO, pAH->m_pTable[iCount * 2 + 1], pAH->m_pTable[iCount * 2 + 2]); + if (aTabLen[iPattern]) { + putBit16z(pIO, aTabCode[iPattern], aTabLen[iPattern]); + } + } + iPattern = iCodeV; + } + } + else if (cf == YUV_422){ + iPattern = iCodeU; + for(k = 0; k < 2; k ++) { + if(iPattern) { + if (iPattern == 1) + putBit16z(pIO, 1, 1); + else { + putBit16z(pIO, 3 - iPattern, 2); + } + } + iPattern = iCodeV; + } + } + } + } + } +} + +/************************************************************************* + macroblock encode function using 4x4 transforms +*************************************************************************/ +Int EncodeMacroblockHighpass(CWMImageStrCodec * pSC, CCodingContext *pContext, Int iMBX, Int iMBY) +{ + BitIOInfo* pIO = pContext->m_pIOAC; + BitIOInfo* pIOFL = pContext->m_pIOFL; + + if((pSC->WMISCP.bfBitstreamFormat != SPATIAL) && (pSC->pTile[pSC->cTileColumn].cBitsHP > 0)) // MB-based HP QP index + encodeQPIndex(pIO, pSC->MBInfo.iQIndexHP, pSC->pTile[pSC->cTileColumn].cBitsHP); + + /** reset adaptive scan totals **/ + if (pSC->m_bResetRGITotals) { + Int iScale = 2; + Int iWeight = iScale * 16; + Int k; + pContext->m_aScanHoriz[0].uTotal = pContext->m_aScanVert[0].uTotal = MAXTOTAL; + for (k = 1; k < 16; k++) { + pContext->m_aScanHoriz[k].uTotal = pContext->m_aScanVert[k].uTotal = iWeight; + iWeight -= iScale; + } + } + CodeCBP(pSC, pContext, iMBX, iMBY, pIO); + if(CodeCoeffs(pSC, pContext, iMBX, iMBY, pIO, pIOFL) != ICERR_OK) + return ICERR_ERROR; + + if (pSC->m_bResetContext) { + AdaptHighpassEnc(pContext); + } + + return ICERR_OK; +} diff --git a/libs/jxr/image/encode/strFwdTransform.c b/libs/jxr/image/encode/strFwdTransform.c new file mode 100644 index 00000000000..9f88309ecd0 --- /dev/null +++ b/libs/jxr/image/encode/strFwdTransform.c @@ -0,0 +1,1111 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strTransform.h" +#include "encode.h" + +/** rotation by pi/8 **/ +#define ROTATE1(a, b) (b) -= (((a) + 1) >> 1), (a) += (((b) + 1) >> 1) // this works well too +#define ROTATE2(a, b) (b) -= (((a)*3 + 4) >> 3), (a) += (((b)*3 + 4) >> 3) // this works well too + +/** local functions **/ +static Void fwdOddOdd(PixelI *, PixelI *, PixelI *, PixelI *); +static Void fwdOddOddPre(PixelI *, PixelI *, PixelI *, PixelI *); +static Void fwdOdd(PixelI *, PixelI *, PixelI *, PixelI *); +static Void strDCT2x2alt(PixelI * a, PixelI * b, PixelI * c, PixelI * d); +static Void strHSTenc1(PixelI *, PixelI *); +static Void strHSTenc(PixelI *, PixelI *, PixelI *, PixelI *); +static Void strHSTenc1_edge (PixelI *pa, PixelI *pd); + +//static Void scaleDownUp0(PixelI *, PixelI *); +//static Void scaleDownUp1(PixelI *, PixelI *); +//static Void scaleDownUp2(PixelI *, PixelI *); +//#define FOURBUTTERFLY_ENC_ALT(p, i00, i01, i02, i03, i10, i11, i12, i13, \ +// i20, i21, i22, i23, i30, i31, i32, i33) \ +// strHSTenc(&p[i00], &p[i01], &p[i02], &p[i03]); \ +// strHSTenc(&p[i10], &p[i11], &p[i12], &p[i13]); \ +// strHSTenc(&p[i20], &p[i21], &p[i22], &p[i23]); \ +// strHSTenc(&p[i30], &p[i31], &p[i32], &p[i33]); \ +// strHSTenc1(&p[i00], &p[i03]); \ +// strHSTenc1(&p[i10], &p[i13]); \ +// strHSTenc1(&p[i20], &p[i23]); \ +// strHSTenc1(&p[i30], &p[i33]) + +/** DCT stuff **/ +/** data order before DCT **/ +/** 0 1 2 3 **/ +/** 4 5 6 7 **/ +/** 8 9 10 11 **/ +/** 12 13 14 15 **/ +/** data order after DCT **/ +/** 0 8 4 6 **/ +/** 2 10 14 12 **/ +/** 1 11 15 13 **/ +/** 9 3 7 5 **/ +/** reordering should be combined with zigzag scan **/ + +Void strDCT4x4Stage1(PixelI * p) +{ + /** butterfly **/ + //FOURBUTTERFLY(p, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + FOURBUTTERFLY_HARDCODED1(p); + + /** top left corner, butterfly => butterfly **/ + strDCT2x2up(&p[0], &p[1], &p[2], &p[3]); + + /** bottom right corner, pi/8 rotation => pi/8 rotation **/ + fwdOddOdd(&p[15], &p[14], &p[13], &p[12]); + + /** top right corner, butterfly => pi/8 rotation **/ + fwdOdd(&p[5], &p[4], &p[7], &p[6]); + + /** bottom left corner, pi/8 rotation => butterfly **/ + fwdOdd(&p[10], &p[8], &p[11], &p[9]); +} + +Void strDCT4x4SecondStage(PixelI * p) +{ + /** butterfly **/ + FOURBUTTERFLY(p, 0, 192, 48, 240, 64, 128, 112, 176,16, 208, 32, 224, 80, 144, 96, 160); + + /** top left corner, butterfly => butterfly **/ + strDCT2x2up(&p[0], &p[64], &p[16], &p[80]); + + /** bottom right corner, pi/8 rotation => pi/8 rotation **/ + fwdOddOdd(&p[160], &p[224], &p[176], &p[240]); + + /** top right corner, butterfly => pi/8 rotation **/ + fwdOdd(&p[128], &p[192], &p[144], &p[208]); + + /** bottom left corner, pi/8 rotation => butterfly **/ + fwdOdd(&p[32], &p[48], &p[96], &p[112]); +} + +Void strNormalizeEnc(PixelI* p, Bool bChroma) +{ + int i; + if (!bChroma) { + //for (i = 0; i < 256; i += 16) { + // p[i] = (p[i] + 1) >> 2; + //} + } + else { + for (i = 0; i < 256; i += 16) { + p[i] >>= 1; + } + } +} + +/** 2x2 DCT with pre-scaling - for use on encoder side **/ +Void strDCT2x2dnEnc(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d, C, t; + a = (*pa + 0) >> 1; + b = (*pb + 0) >> 1; + C = (*pc + 0) >> 1; + d = (*pd + 0) >> 1; + //PixelI t1, t2; + + a += d; + b -= C; + t = ((a - b) >> 1); + c = t - d; + d = t - C; + a -= d; + b += c; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +/** pre filter stuff **/ +/** 2-point pre for boundaries **/ +Void strPre2(PixelI * pa, PixelI * pb) +{ + PixelI a, b; + a = *pa; + b = *pb; + + /** rotate **/ + b -= ((a + 2) >> 2); + a -= ((b + 1) >> 1); + + a -= (b >> 5); + a -= (b >> 9); + a -= (b >> 13); + + b -= ((a + 2) >> 2); + + *pa = a; + *pb = b; +} + +Void strPre2x2(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + /** butterflies **/ + a += d; + b += c; + d -= (a + 1) >> 1; + c -= (b + 1) >> 1; + + /** rotate **/ + b -= ((a + 2) >> 2); + a -= ((b + 1) >> 1); + a -= (b >> 5); + a -= (b >> 9); + a -= (b >> 13); + b -= ((a + 2) >> 2); + + /** butterflies **/ + d += (a + 1) >> 1; + c += (b + 1) >> 1; + a -= d; + b -= c; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +/** 4-point pre for boundaries **/ +Void strPre4(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + a += d, b += c; + d -= ((a + 1) >> 1), c -= ((b + 1) >> 1); + + ROTATE1(c, d); + + strHSTenc1_edge(&a, &d); strHSTenc1_edge(&b, &c); + + d += ((a + 1) >> 1), c += ((b + 1) >> 1); + a -= d, b -= c; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +/***************************************************************************************** + Input data offsets: + (15)(14)|(10+64)(11+64) p0 (15)(14)|(74)(75) + (13)(12)|( 8+64)( 9+64) (13)(12)|(72)(73) + --------+-------------- --------+-------- + ( 5)( 4)|( 0+64) (1+64) p1 ( 5)( 4)|(64)(65) + ( 7)( 6)|( 2+64) (3+64) ( 7)( 6)|(66)(67) +*****************************************************************************************/ +Void strPre4x4Stage1Split(PixelI *p0, PixelI *p1, Int iOffset) +{ + PixelI *p2 = p0 + 72 - iOffset; + PixelI *p3 = p1 + 64 - iOffset; + p0 += 12; + p1 += 4; + + /** butterfly & scaling **/ + strHSTenc(p0 + 0, p2 + 0, p1 + 0, p3 + 0); + strHSTenc(p0 + 1, p2 + 1, p1 + 1, p3 + 1); + strHSTenc(p0 + 2, p2 + 2, p1 + 2, p3 + 2); + strHSTenc(p0 + 3, p2 + 3, p1 + 3, p3 + 3); + strHSTenc1(p0 + 0, p3 + 0); + strHSTenc1(p0 + 1, p3 + 1); + strHSTenc1(p0 + 2, p3 + 2); + strHSTenc1(p0 + 3, p3 + 3); + + /** anti diagonal corners: rotation by pi/8 **/ + ROTATE1(p1[2], p1[3]); + ROTATE1(p1[0], p1[1]); + ROTATE1(p2[1], p2[3]); + ROTATE1(p2[0], p2[2]); + + /** bottom right corner: pi/8 rotation => pi/8 rotation **/ + fwdOddOddPre(p3 + 0, p3 + 1, p3 + 2, p3 + 3); + + /** butterfly **/ + strDCT2x2dn(p0 + 0, p2 + 0, p1 + 0, p3 + 0); + strDCT2x2dn(p0 + 1, p2 + 1, p1 + 1, p3 + 1); + strDCT2x2dn(p0 + 2, p2 + 2, p1 + 2, p3 + 2); + strDCT2x2dn(p0 + 3, p2 + 3, p1 + 3, p3 + 3); +} + +Void strPre4x4Stage1(PixelI* p, Int iOffset) +{ + strPre4x4Stage1Split(p, p + 16, iOffset); +} + +/***************************************************************************************** + Input data offsets: + (15)(14)|(10+32)(11+32) p0 (15)(14)|(42)(43) + (13)(12)|( 8+32)( 9+32) (13)(12)|(40)(41) + --------+-------------- --------+-------- + ( 5)( 4)|( 0+32)( 1+32) p1 ( 5)( 4)|(32)(33) + ( 7)( 6)|( 2+32)( 3+32) ( 7)( 6)|(34)(35) +*****************************************************************************************/ +Void strPre4x4Stage2Split(PixelI* p0, PixelI* p1) +{ + /** butterfly **/ + strHSTenc(p0 - 96, p0 + 96, p1 - 112, p1 + 80); + strHSTenc(p0 - 32, p0 + 32, p1 - 48, p1 + 16); + strHSTenc(p0 - 80, p0 + 112, p1 - 128, p1 + 64); + strHSTenc(p0 - 16, p0 + 48, p1 - 64, p1 + 0); + strHSTenc1(p0 - 96, p1 + 80); + strHSTenc1(p0 - 32, p1 + 16); + strHSTenc1(p0 - 80, p1 + 64); + strHSTenc1(p0 - 16, p1 + 0); + + /** anti diagonal corners: rotation **/ + ROTATE1(p1[-48], p1[-112]); + ROTATE1(p1[-64], p1[-128]); + ROTATE1(p0[112], p0[ 96]); + ROTATE1(p0[ 48], p0[ 32]); + + /** bottom right corner: pi/8 rotation => pi/8 rotation **/ + fwdOddOddPre(p1 + 0, p1 + 64, p1 + 16, p1 + 80); + + /** butterfly **/ + strDCT2x2dn(p0 - 96, p1 - 112, p0 + 96, p1 + 80); + strDCT2x2dn(p0 - 32, p1 - 48, p0 + 32, p1 + 16); + strDCT2x2dn(p0 - 80, p1 - 128, p0 + 112, p1 + 64); + strDCT2x2dn(p0 - 16, p1 - 64, p0 + 48, p1 + 0); +} + + +/** + Hadamard+Scale transform + for some strange reason, breaking up the function into two blocks, strHSTenc1 and strHSTenc + seems to work faster +**/ +static Void strHSTenc(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + /** different realization : does rescaling as well! **/ + PixelI a, b, c, d; + a = *pa; + b = *pb; + d = *pc; + c = *pd; + + a += c; + b -= d; + c = ((a - b) >> 1) - c; + d += (b >> 1); + b += c; + + a -= (d * 3 + 4) >> 3; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +static Void strHSTenc1(PixelI *pa, PixelI *pd) +{ + /** different realization : does rescaling as well! **/ + PixelI a, d; + a = *pa; + d = *pd; + + d -= (a >> 7); + d += (a >> 10); + + //a -= (d * 3 + 4) >> 3; + d -= (a * 3 + 0) >> 4; + a -= (d * 3 + 0) >> 3; + d = (a >> 1) - d; + a -= d; + + *pa = a; + *pd = d; +} + +static Void strHSTenc1_edge (PixelI *pa, PixelI *pd) +{ + /** different realizion as compared to scaling operator for 2D case **/ + PixelI a, d; + a = *pa; + d = -(*pd); // Negative sign needed here for 1D scaling case to ensure correct scaling. + + a -= d; + d += (a >> 1); + a -= (d * 3 + 4) >> 3; + // End new operations + + //Scaling modification of adding 7/1024 in two steps (without multiplication by 7). + d -= (a >> 7); + d += (a >> 10); + + d -= (a * 3 + 0) >> 4; + a -= (d * 3 + 0) >> 3; + d = (a >> 1) - d; + a -= d; + + *pa = a; + *pd = d; +} + +/** Kron(Rotate(pi/8), Rotate(pi/8)) **/\ +static Void fwdOddOdd(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d, t1, t2; + + a = *pa; + b = -*pb; + c = -*pc; + d = *pd; + + /** butterflies **/ + d += a; + c -= b; + a -= (t1 = d >> 1); + b += (t2 = c >> 1); + + /** rotate pi/4 **/ + a += (b * 3 + 4) >> 3; + b -= (a * 3 + 3) >> 2; + a += (b * 3 + 3) >> 3; + + /** butterflies **/ + b -= t2; + a += t1; + c += b; + d -= a; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} +/** Kron(Rotate(pi/8), Rotate(pi/8)) **/ +static Void fwdOddOddPre(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d, t1, t2; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + /** butterflies **/ + d += a; + c -= b; + a -= (t1 = d >> 1); + b += (t2 = c >> 1); + + /** rotate pi/4 **/ + a += (b * 3 + 4) >> 3; + b -= (a * 3 + 2) >> 2; + a += (b * 3 + 6) >> 3; + + /** butterflies **/ + b -= t2; + a += t1; + c += b; + d -= a; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +/** Kron(Rotate(pi/8), [1 1; 1 -1]/sqrt(2)) **/ +/** [a b c d] => [D C A B] **/ +Void fwdOdd(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d; + a = *pa; + b = *pb; + c = *pc; + d = *pd; + + /** butterflies **/ + b -= c; + a += d; + c += (b + 1) >> 1; + d = ((a + 1) >> 1) - d; + + /** rotate pi/8 **/ + ROTATE2(a, b); + ROTATE2(c, d); + + /** butterflies **/ + d += (b) >> 1; + c -= (a + 1) >> 1; + b -= d; + a += c; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +/************************************************************************* + Top-level function to tranform possible part of a macroblock +*************************************************************************/ +Void transformMacroblock(CWMImageStrCodec * pSC) +{ + OVERLAP olOverlap = pSC->WMISCP.olOverlap; + COLORFORMAT cfColorFormat = pSC->m_param.cfColorFormat; + Bool left = (pSC->cColumn == 0), right = (pSC->cColumn == pSC->cmbWidth); + Bool top = (pSC->cRow == 0), bottom = (pSC->cRow == pSC->cmbHeight); + Bool leftORright = (left || right), topORbottom = (top || bottom); + Bool topORleft = (left || top);// rightORbottom = (right || bottom); + Bool leftAdjacentColumn = (pSC->cColumn == 1), rightAdjacentColumn = (pSC->cColumn == pSC->cmbWidth - 1); + // Bool topAdjacentRow = (pSC->cRow == 1), bottomAdjacentRow = (pSC->cRow == pSC->cmbHeight - 1); + PixelI * p = NULL;// * pt = NULL; + Int i, j; + Int iNumChromaFullPlanes = (Int)((YUV_420 == cfColorFormat || YUV_422 == cfColorFormat) ? + 1 : pSC->m_param.cNumChannels); + +#define mbX pSC->mbX +#define mbY pSC->mbY +#define tileX pSC->tileX +#define tileY pSC->tileY +#define bVertTileBoundary pSC->bVertTileBoundary +#define bHoriTileBoundary pSC->bHoriTileBoundary +#define bOneMBLeftVertTB pSC->bOneMBLeftVertTB +#define bOneMBRightVertTB pSC->bOneMBRightVertTB +#define iPredBefore pSC->iPredBefore +#define iPredAfter pSC->iPredAfter + + if (pSC->WMISCP.bUseHardTileBoundaries) { + //Add tile location information + if (pSC->cColumn == 0) { + bVertTileBoundary = FALSE; + tileY = 0; + } + bOneMBLeftVertTB = bOneMBRightVertTB = FALSE; + if(tileY > 0 && tileY <= pSC->WMISCP.cNumOfSliceMinus1H && (pSC->cColumn - 1) == pSC->WMISCP.uiTileY[tileY]) + bOneMBRightVertTB = TRUE; + if(tileY < pSC->WMISCP.cNumOfSliceMinus1H && pSC->cColumn == pSC->WMISCP.uiTileY[tileY + 1]) { + bVertTileBoundary = TRUE; + tileY++; + } + else + bVertTileBoundary = FALSE; + if(tileY < pSC->WMISCP.cNumOfSliceMinus1H && (pSC->cColumn + 1) == pSC->WMISCP.uiTileY[tileY + 1]) + bOneMBLeftVertTB = TRUE; + + if (pSC->cRow == 0) { + bHoriTileBoundary = FALSE; + tileX = 0; + } + else if(mbY != pSC->cRow && tileX < pSC->WMISCP.cNumOfSliceMinus1V && pSC->cRow == pSC->WMISCP.uiTileX[tileX + 1]) { + bHoriTileBoundary = TRUE; + tileX++; + } + else if(mbY != pSC->cRow) + bHoriTileBoundary = FALSE; + } + else { + bVertTileBoundary = FALSE; + bHoriTileBoundary = FALSE; + bOneMBLeftVertTB = FALSE; + bOneMBRightVertTB = FALSE; + } + mbX = pSC->cColumn, mbY = pSC->cRow; + + //================================================================ + // 400_Y, 444_YUV + for(i = 0; i < iNumChromaFullPlanes; ++i) + { + PixelI* const p0 = pSC->p0MBbuffer[i];//(0 == i ? pSC->pY0 : (1 == i ? pSC->pU0 : pSC->pV0)); + PixelI* const p1 = pSC->p1MBbuffer[i];//(0 == i ? pSC->pY1 : (1 == i ? pSC->pU1 : pSC->pV1)); + + //================================ + // first level overlap + if(OL_NONE != olOverlap) + { + /* Corner operations */ + if ((top || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPre4(p1 + 0, p1 + 1, p1 + 2, p1 + 3); + if ((top || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPre4(p1 - 59, p1 - 60, p1 - 57, p1 - 58); + if ((bottom || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPre4(p0 + 48 + 10, p0 + 48 + 11, p0 + 48 + 8, p0 + 48 + 9); + if ((bottom || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPre4(p0 - 1, p0 - 2, p0 - 3, p0 - 4); + if(!right && !bottom) + { + if (top || bHoriTileBoundary) + { + + for (j = ((left || bVertTileBoundary) ? 0 : -64); j < 192; j += 64) + { + p = p1 + j; + strPre4(p + 5, p + 4, p + 64, p + 65); + strPre4(p + 7, p + 6, p + 66, p + 67); + p = NULL; + } + } + else + { + for (j = ((left || bVertTileBoundary) ? 0 : -64); j < 192; j += 64) + { + strPre4x4Stage1Split(p0 + 48 + j, p1 + j, 0); + } + } + + if (left || bVertTileBoundary) + { + if (!top && !bHoriTileBoundary) + { + strPre4(p0 + 58, p0 + 56, p1 + 0, p1 + 2); + strPre4(p0 + 59, p0 + 57, p1 + 1, p1 + 3); + } + + for (j = -64; j < -16; j += 16) + { + p = p1 + j; + strPre4(p + 74, p + 72, p + 80, p + 82); + strPre4(p + 75, p + 73, p + 81, p + 83); + p = NULL; + } + } + else + { + for (j = -64; j < -16; j += 16) + { + strPre4x4Stage1(p1 + j, 0); + } + } + + strPre4x4Stage1(p1 + 0, 0); + strPre4x4Stage1(p1 + 16, 0); + strPre4x4Stage1(p1 + 32, 0); + strPre4x4Stage1(p1 + 64, 0); + strPre4x4Stage1(p1 + 80, 0); + strPre4x4Stage1(p1 + 96, 0); + strPre4x4Stage1(p1 + 128, 0); + strPre4x4Stage1(p1 + 144, 0); + strPre4x4Stage1(p1 + 160, 0); + } + + if (bottom || bHoriTileBoundary) + { + for (j = ((left || bVertTileBoundary) ? 48 : -16); j < (right ? -16 : 240); j += 64) + { + p = p0 + j; + strPre4(p + 15, p + 14, p + 74, p + 75); + strPre4(p + 13, p + 12, p + 72, p + 73); + p = NULL; + } + } + + if ((right || bVertTileBoundary) && !bottom) + { + if (!top && !bHoriTileBoundary) + { + strPre4(p0 - 1, p0 - 3, p1 - 59, p1 - 57); + strPre4(p0 - 2, p0 - 4, p1 - 60, p1 - 58); + } + for (j = -64; j < -16; j += 16) + { + p = p1 + j; + strPre4(p + 15, p + 13, p + 21, p + 23); + strPre4(p + 14, p + 12, p + 20, p + 22); + p = NULL; + } + } + } + + //================================ + // first level transform + if (!top) + { + for (j = (left ? 48 : -16); j < (right ? 48 : 240); j += 64) + { + strDCT4x4Stage1(p0 + j); + } + } + + if (!bottom) + { + for (j = (left ? 0 : -64); j < (right ? 0 : 192); j += 64) + { + strDCT4x4Stage1(p1 + j + 0); + strDCT4x4Stage1(p1 + j + 16); + strDCT4x4Stage1(p1 + j + 32); + } + } + + //================================ + // second level overlap + if (OL_TWO == olOverlap) + { + /* Corner operations */ + if ((top || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPre4(p1 + 0, p1 + 64, p1 + 0 + 16, p1 + 64 + 16); + if ((top || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPre4(p1 - 128, p1 - 64, p1 - 128 + 16, p1 - 64 + 16); + if ((bottom || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPre4(p0 + 32, p0 + 96, p0 + 32 + 16, p0 + 96 + 16); + if ((bottom || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPre4(p0 - 96, p0 - 32, p0 - 96 + 16, p0 - 32 + 16); + if ((leftORright || bVertTileBoundary) && (!topORbottom && !bHoriTileBoundary)) + { + if (left || bVertTileBoundary) { + j = 0; + strPre4(p0 + j + 32, p0 + j + 48, p1 + j + 0, p1 + j + 16); + strPre4(p0 + j + 96, p0 + j + 112, p1 + j + 64, p1 + j + 80); + } + if (right || bVertTileBoundary) { + j = -128; + strPre4(p0 + j + 32, p0 + j + 48, p1 + j + 0, p1 + j + 16); + strPre4(p0 + j + 96, p0 + j + 112, p1 + j + 64, p1 + j + 80); + } + } + + if (!leftORright && !bVertTileBoundary) + { + if (topORbottom || bHoriTileBoundary) + { + if (top || bHoriTileBoundary) { + p = p1; + strPre4(p - 128, p - 64, p + 0, p + 64); + strPre4(p - 112, p - 48, p + 16, p + 80); + p = NULL; + } + if (bottom || bHoriTileBoundary) { + p = p0 + 32; + strPre4(p - 128, p - 64, p + 0, p + 64); + strPre4(p - 112, p - 48, p + 16, p + 80); + p = NULL; + } + } + else + { + strPre4x4Stage2Split(p0, p1); + } + } + } + + //================================ + // second level transform + if (!topORleft){ + if (pSC->m_param.bScaledArith) { + strNormalizeEnc(p0 - 256, (i != 0)); + } + strDCT4x4SecondStage(p0 - 256); + } + } + + //================================================================ + // 420_UV + for(i = 0; i < (YUV_420 == cfColorFormat? 2 : 0); ++i) + { + PixelI* const p0 = pSC->p0MBbuffer[1 + i];//(0 == i ? pSC->pU0 : pSC->pV0); + PixelI* const p1 = pSC->p1MBbuffer[1 + i];//(0 == i ? pSC->pU1 : pSC->pV1); + + //================================ + // first level overlap (420_UV) + if (OL_NONE != olOverlap) + { + /* Corner operations */ + if ((top || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPre4(p1 + 0, p1 + 1, p1 + 2, p1 + 3); + if ((top || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPre4(p1 - 27, p1 - 28, p1 - 25, p1 - 26); + if ((bottom || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPre4(p0 + 16 + 10, p0 + 16 + 11, p0 + 16 + 8, p0 + 16 + 9); + if ((bottom || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPre4(p0 - 1, p0 - 2, p0 - 3, p0 - 4); + if(!right && !bottom) + { + if (top || bHoriTileBoundary) + { + + for (j = ((left || bVertTileBoundary) ? 0 : -32); j < 32; j += 32) + { + p = p1 + j; + strPre4(p + 5, p + 4, p + 32, p + 33); + strPre4(p + 7, p + 6, p + 34, p + 35); + p = NULL; + } + } + else + { + for (j = ((left || bVertTileBoundary) ? 0: -32); j < 32; j += 32) + { + strPre4x4Stage1Split(p0 + 16 + j, p1 + j, 32); + } + } + + if (left || bVertTileBoundary) + { + if (!top && !bHoriTileBoundary) + { + strPre4(p0 + 26, p0 + 24, p1 + 0, p1 + 2); + strPre4(p0 + 27, p0 + 25, p1 + 1, p1 + 3); + } + + strPre4(p1 + 10, p1 + 8, p1 + 16, p1 + 18); + strPre4(p1 + 11, p1 + 9, p1 + 17, p1 + 19); + } + else if (!bVertTileBoundary) + { + strPre4x4Stage1(p1 - 32, 32); + } + + strPre4x4Stage1(p1, 32); + } + + if (bottom || bHoriTileBoundary) + { + for (j = ((left || bVertTileBoundary) ? 16: -16); j < (right ? -16: 32); j += 32) + { + p = p0 + j; + strPre4(p + 15, p + 14, p + 42, p + 43); + strPre4(p + 13, p + 12, p + 40, p + 41); + p = NULL; + } + } + + if ((right || bVertTileBoundary) && !bottom) + { + if (!top && !bHoriTileBoundary) + { + strPre4(p0 - 1, p0 - 3, p1 - 27, p1 - 25); + strPre4(p0 - 2, p0 - 4, p1 - 28, p1 - 26); + } + + strPre4(p1 - 17, p1 - 19, p1 - 11, p1 - 9); + strPre4(p1 - 18, p1 - 20, p1 - 12, p1 - 10); + } + } + + //================================ + // first level transform (420_UV) + if (!top) + { + for (j = (left ? 16 : -16); j < (right ? 16 : 48); j += 32) + { + strDCT4x4Stage1(p0 + j); + } + } + + if (!bottom) + { + for (j = (left ? 0 : -32); j < (right ? 0 : 32); j += 32) + { + strDCT4x4Stage1(p1 + j); + } + } + + //================================ + // second level overlap (420_UV) + if (OL_TWO == olOverlap) + { + if ((leftAdjacentColumn || bOneMBRightVertTB) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p1 - 64 + 0, *(p1 - 64 + 32)); + + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (top || bHoriTileBoundary)) + iPredBefore[i][0] = *(p1 + 0); + if ((right || bVertTileBoundary) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p1 - 64 + 32, iPredBefore[i][0]); + + if ((leftAdjacentColumn || bOneMBRightVertTB) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p0 - 64 + 16, *(p0 - 64 + 48)); + + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (bottom || bHoriTileBoundary)) + iPredBefore[i][1] = *(p0 + 16); + if ((right || bVertTileBoundary) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p0 - 64 + 48, iPredBefore[i][1]); + + if ((leftORright || bVertTileBoundary) && !topORbottom && !bHoriTileBoundary) + { + if (left || bVertTileBoundary) + strPre2(p0 + 0 + 16, p1 + 0); + if (right || bVertTileBoundary) + strPre2(p0 + -32 + 16, p1 + -32); + } + + if (!leftORright) + { + if ((topORbottom || bHoriTileBoundary) && !bVertTileBoundary) + { + if (top || bHoriTileBoundary) + strPre2(p1 - 32, p1); + if (bottom || bHoriTileBoundary) + strPre2(p0 + 16 - 32, p0 + 16); + } + else if (!topORbottom && !bHoriTileBoundary && !bVertTileBoundary) + strPre2x2(p0 - 16, p0 + 16, p1 - 32, p1); + } + if ((leftAdjacentColumn || bOneMBRightVertTB) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p1 - 64 + 0, *(p1 - 64 + 32)); + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (top || bHoriTileBoundary)) + iPredAfter[i][0] = *(p1 + 0); + if ((right || bVertTileBoundary) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p1 - 64 + 32, iPredAfter[i][0]); + if ((leftAdjacentColumn || bOneMBRightVertTB) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p0 - 64 + 16, *(p0 - 64 + 48)); + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (bottom || bHoriTileBoundary)) + iPredAfter[i][1] = *(p0 + 16); + if ((right || bVertTileBoundary) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p0 - 64 + 48, iPredAfter[i][1]); + } + + //================================ + // second level transform (420_UV) + if (!topORleft) + { + if (!pSC->m_param.bScaledArith) { + strDCT2x2dn(p0 - 64, p0 - 32, p0 - 48, p0 - 16); + } + else { + strDCT2x2dnEnc(p0 - 64, p0 - 32, p0 - 48, p0 - 16); + } + } + } + + //================================================================ + // 422_UV + for(i = 0; i < (YUV_422 == cfColorFormat? 2 : 0); ++i) + { + PixelI* const p0 = pSC->p0MBbuffer[1 + i];//(0 == i ? pSC->pU0 : pSC->pV0); + PixelI* const p1 = pSC->p1MBbuffer[1 + i];//(0 == i ? pSC->pU1 : pSC->pV1); + + //================================ + // first level overlap (422_UV) + if (OL_NONE != olOverlap) + { + /* Corner operations */ + if ((top || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPre4(p1 + 0, p1 + 1, p1 + 2, p1 + 3); + if ((top || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPre4(p1 - 59, p1 - 60, p1 - 57, p1 - 58); + if ((bottom || bHoriTileBoundary) && (left || bVertTileBoundary)) + strPre4(p0 + 48 + 10, p0 + 48 + 11, p0 + 48 + 8, p0 + 48 + 9); + if ((bottom || bHoriTileBoundary) && (right || bVertTileBoundary)) + strPre4(p0 - 1, p0 - 2, p0 - 3, p0 - 4); + if(!right && !bottom) + { + if (top || bHoriTileBoundary) + { + + for (j = ((left || bVertTileBoundary) ? 0 : -64); j < 64; j += 64) + { + p = p1 + j; + strPre4(p + 5, p + 4, p + 64, p + 65); + strPre4(p + 7, p + 6, p + 66, p + 67); + p = NULL; + } + } + else + { + for (j = ((left || bVertTileBoundary) ? 0: -64); j < 64; j += 64) + { + strPre4x4Stage1Split(p0 + 48 + j, p1 + j, 0); + } + } + + if (left || bVertTileBoundary) + { + if (!top && !bHoriTileBoundary) + { + strPre4(p0 + 58, p0 + 56, p1 + 0, p1 + 2); + strPre4(p0 + 59, p0 + 57, p1 + 1, p1 + 3); + } + + for (j = 0; j < 48; j += 16) + { + p = p1 + j; + strPre4(p + 10, p + 8, p + 16, p + 18); + strPre4(p + 11, p + 9, p + 17, p + 19); + p = NULL; + } + } + else if (!bVertTileBoundary) + { + for (j = -64; j < -16; j += 16) + { + strPre4x4Stage1(p1 + j, 0); + } + } + + strPre4x4Stage1(p1 + 0, 0); + strPre4x4Stage1(p1 + 16, 0); + strPre4x4Stage1(p1 + 32, 0); + } + + if (bottom || bHoriTileBoundary) + { + for (j = ((left || bVertTileBoundary) ? 48: -16); j < (right ? -16: 112); j += 64) + { + p = p0 + j; + strPre4(p + 15, p + 14, p + 74, p + 75); + strPre4(p + 13, p + 12, p + 72, p + 73); + p = NULL; + } + } + + if ((right || bVertTileBoundary) && !bottom) + { + if (!top && !bHoriTileBoundary) + { + strPre4(p0 - 1, p0 - 3, p1 - 59, p1 - 57); + strPre4(p0 - 2, p0 - 4, p1 - 60, p1 - 58); + } + + for (j = -64; j < -16; j += 16) + { + p = p1 + j; + strPre4(p + 15, p + 13, p + 21, p + 23); + strPre4(p + 14, p + 12, p + 20, p + 22); + p = NULL; + } + } + } + + //================================ + // first level transform (422_UV) + if (!top) + { + for (j = (left ? 48 : -16); j < (right ? 48 : 112); j += 64) + { + strDCT4x4Stage1(p0 + j); + } + } + + if (!bottom) + { + for (j = (left ? 0 : -64); j < (right ? 0 : 64); j += 64) + { + strDCT4x4Stage1(p1 + j + 0); + strDCT4x4Stage1(p1 + j + 16); + strDCT4x4Stage1(p1 + j + 32); + } + } + + //================================ + // second level overlap (422_UV) + if (OL_TWO == olOverlap) + { + if ((leftAdjacentColumn || bOneMBRightVertTB) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p1 - 128 + 0, *(p1 - 128 + 64)); + + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (top || bHoriTileBoundary)) + iPredBefore[i][0] = *(p1 + 0); + if ((right || bVertTileBoundary) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p1 - 128 + 64, iPredBefore[i][0]); + + if ((leftAdjacentColumn || bOneMBRightVertTB) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p0 - 128 + 48, *(p0 - 128 + 112)); + + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (bottom || bHoriTileBoundary)) + iPredBefore[i][1] = *(p0 + 48); + if ((right || bVertTileBoundary) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_DIFF(p0 - 128 + 112, iPredBefore[i][1]); + + if (!bottom) + { + if (leftORright || bVertTileBoundary) + { + if (!top && !bHoriTileBoundary) + { + if (left || bVertTileBoundary) + strPre2(p0 + 48 + 0, p1 + 0); + + if (right || bVertTileBoundary) + strPre2(p0 + 48 + -64, p1 + -64); + } + + if (left || bVertTileBoundary) + strPre2(p1 + 16, p1 + 16 + 16); + + if (right || bVertTileBoundary) + strPre2(p1 + -48, p1 + -48 + 16); + } + + if (!leftORright && !bVertTileBoundary) + { + if (top || bHoriTileBoundary) + strPre2(p1 - 64, p1); + else + strPre2x2(p0 - 16, p0 + 48, p1 - 64, p1); + + strPre2x2(p1 - 48, p1 + 16, p1 - 32, p1 + 32); + } + } + + if ((bottom || bHoriTileBoundary) && (!leftORright && !bVertTileBoundary)) + strPre2(p0 - 16, p0 + 48); + + if ((leftAdjacentColumn || bOneMBRightVertTB) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p1 - 128 + 0, *(p1 - 128 + 64)); + + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (top || bHoriTileBoundary)) + iPredAfter[i][0] = *(p1 + 0); + if ((right || bVertTileBoundary) && (top || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p1 - 128 + 64, iPredAfter[i][0]); + + if ((leftAdjacentColumn || bOneMBRightVertTB) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p0 - 128 + 48, *(p0 - 128 + 112)); + + if ((rightAdjacentColumn || bOneMBLeftVertTB) && (bottom || bHoriTileBoundary)) + iPredAfter[i][1] = *(p0 + 48); + if ((right || bVertTileBoundary) && (bottom || bHoriTileBoundary)) + COMPUTE_CORNER_PRED_ADD(p0 - 128 + 112, iPredAfter[i][1]); + } + + //================================ + // second level transform (422_UV) + if (!topORleft) + { + if (!pSC->m_param.bScaledArith) { + strDCT2x2dn(p0 - 128, p0 - 64, p0 - 112, p0 - 48); + strDCT2x2dn(p0 - 96, p0 - 32, p0 - 80, p0 - 16); + } + else { + strDCT2x2dnEnc(p0 - 128, p0 - 64, p0 - 112, p0 - 48); + strDCT2x2dnEnc(p0 - 96, p0 - 32, p0 - 80, p0 - 16); + } + + // 1D lossless HT + p0[- 96] -= p0[-128]; + p0[-128] += ((p0[-96] + 1) >> 1); + } + } + assert(NULL == p); +} + diff --git a/libs/jxr/image/encode/strPredQuantEnc.c b/libs/jxr/image/encode/strPredQuantEnc.c new file mode 100644 index 00000000000..f2ab001f7d6 --- /dev/null +++ b/libs/jxr/image/encode/strPredQuantEnc.c @@ -0,0 +1,511 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strcodec.h" +#include "encode.h" + +I32 QUANT_Mulless(PixelI v, PixelI o, I32 r) +{ + const I32 m = v >> 31; + + assert(sizeof(PixelI) == sizeof(U32)); + return ((((v ^ m) - m + o) >> r) ^ m) - m; +} + +I32 MUL32HR(U32 a, U32 b, U32 r) +{ + return (I32)((U32)((U64)a * b >> 32) >> r); +} + +I32 QUANT(PixelI v, PixelI o, I32 man, I32 exp) +{ + const I32 m = v >> 31; + + assert(sizeof(PixelI) == sizeof(U32)); + return (MUL32HR((v ^ m) - m + o, man, exp) ^ m) - m; +} + +Int quantizeMacroblock(CWMImageStrCodec* pSC) +{ + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + CWMIMBInfo * pMBInfo = &pSC->MBInfo; + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + int iChannel, i, j; + + if(/*pSC->m_param.bScaledArith && */pSC->m_param.bTranscode == FALSE) + for(iChannel = 0; iChannel < (int)pSC->m_param.cNumChannels; iChannel ++){ + const Bool bUV = (iChannel > 0 && (cf == YUV_444 || cf == YUV_422 || cf == YUV_420)); + const int iNumBlock = (bUV ? (cf == YUV_422 ? 8 : (cf == YUV_420 ? 4 : 16)) : 16); + const int * pOffset = (iNumBlock == 4 ? blkOffsetUV : (iNumBlock == 8 ? blkOffsetUV_422 : blkOffset)); + CWMIQuantizer * pQPDC = pTile->pQuantizerDC[iChannel]; + CWMIQuantizer * pQPLP = pTile->pQuantizerLP[iChannel] + pMBInfo->iQIndexLP; + CWMIQuantizer * pQPHP = pTile->pQuantizerHP[iChannel] + pMBInfo->iQIndexHP; + + for(j = 0; j < iNumBlock; j ++){ + PixelI * pData = pSC->pPlane[iChannel] + pOffset[j]; + + if(j == 0) // DC + pData[0] = (pQPDC->iMan == 0 ? QUANT_Mulless(pData[0], pQPDC->iOffset, pQPDC->iExp) : QUANT(pData[0], pQPDC->iOffset, pQPDC->iMan, pQPDC->iExp)); + else if(pSC->WMISCP.sbSubband != SB_DC_ONLY) // LP + pData[0] = (pQPLP->iMan == 0 ? QUANT_Mulless(pData[0], pQPLP->iOffset, pQPLP->iExp) : QUANT(pData[0], pQPLP->iOffset, pQPLP->iMan, pQPLP->iExp)); + + // quantize HP + if(pSC->WMISCP.sbSubband != SB_DC_ONLY && pSC->WMISCP.sbSubband != SB_NO_HIGHPASS) + for(i = 1; i < 16; i ++) + pData[i] = (pQPHP->iMan == 0 ? QUANT_Mulless(pData[i], pQPHP->iOffset, pQPHP->iExp) : QUANT(pData[i], pQPHP->iOffset, pQPHP->iMan, pQPHP->iExp)); + } + } + + for(iChannel = 0; iChannel < (int)pSC->m_param.cNumChannels; iChannel ++){ + I32 * pDC = pSC->MBInfo.iBlockDC[iChannel]; + PixelI * pData = pSC->pPlane[iChannel]; + + if(iChannel > 0 && cf == YUV_422){ + for(i = 0; i < 8; i ++){ + pDC[i] = pData[blkOffsetUV_422[i]]; + } + } + else if(iChannel > 0 && cf == YUV_420){ + for(i = 0; i < 4; i ++){ + pDC[i] = pData[blkOffsetUV[i]]; + } + } + else{ + for(i = 0; i < 16; i ++){ + pDC[i] = pData[dctIndex[2][i]]; + } + } + } + + return 0; +} + +/* frequency domain prediction */ +Void predMacroblockEnc(CWMImageStrCodec * pSC) +{ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Int iChannels = (cf == YUV_420 || cf == YUV_422) ? 1 : (Int) pSC->m_param.cNumChannels; + size_t mbX = pSC->cColumn - 1;// mbY = pSC->cRow - 1; + CWMIMBInfo *pMBInfo = &(pSC->MBInfo); + Int iDCACPredMode = getDCACPredMode(pSC, mbX); + Int iDCPredMode = (iDCACPredMode & 0x3); + Int iADPredMode = (iDCACPredMode & 0xC); + Int iACPredMode = getACPredMode(pMBInfo, cf); + PixelI * pOrg, * pRef; + Int i, j, k; + + pMBInfo->iOrientation = 2 - iACPredMode; + + /* keep necessary info for future prediction */ + updatePredInfo(pSC, pMBInfo, mbX, cf); + + for(i = 0; i < iChannels; i ++){ + pOrg = pMBInfo->iBlockDC[i]; // current DC block + + /* DC prediction */ + if(iDCPredMode == 1){ // predict DC from top + pOrg[0] -= (pSC->PredInfoPrevRow[i] + mbX)->iDC; + } + else if(iDCPredMode == 0){ // predict DC from left + pOrg[0] -= (pSC->PredInfo[i] + mbX - 1)->iDC; + } + else if(iDCPredMode == 2){// predict DC from top&left + pOrg[0] -= ((pSC->PredInfo[i] + mbX - 1)->iDC + (pSC->PredInfoPrevRow[i] + mbX)->iDC) >> 1; + } + + /* AD prediction */ + if(iADPredMode == 4){// predict AD from top + pRef = (pSC->PredInfoPrevRow[i] + mbX)->piAD; + pOrg[4] -= pRef[3], pOrg[8] -= pRef[4], pOrg[12] -= pRef[5]; + } + else if(iADPredMode == 0){// predict AD from left + pRef = (pSC->PredInfo[i] + mbX - 1)->piAD; + pOrg[1] -= pRef[0], pOrg[2] -= pRef[1], pOrg[3] -= pRef[2]; + } + + pOrg = pSC->pPlane[i]; + /* AC prediction */ + if(iACPredMode == 1){ // predict from top + for(k = 0; k <= 192; k += 64){ + /* inside macroblock, in reverse order */ + for(j = 48; j > 0; j -= 16){ + pOrg[k + j + 10] -= pOrg[k + j + 10 - 16]; + pOrg[k + j + 2] -= pOrg[k + j + 2 - 16]; + pOrg[k + j + 9] -= pOrg[k + j + 9 - 16]; + } + } + } + else if(iACPredMode == 0){ // predict from left + for(k = 0; k < 64; k += 16){ + /* inside macroblock, in reverse order */ + for(j = 192; j > 0; j -= 64){ + pOrg[k + j + 5] -= pOrg[k + j + 5 - 64]; + pOrg[k + j + 1] -= pOrg[k + j + 1 - 64]; + pOrg[k + j + 6] -= pOrg[k + j + 6 - 64]; + } + } + } + } + + if(cf == YUV_420){ + for(i = 1; i < 3; i ++){ + pOrg = pMBInfo->iBlockDC[i]; // current DC block + + /* DC prediciton */ + if(iDCPredMode == 1){ // predict DC from top + pOrg[0] -= (pSC->PredInfoPrevRow[i] + mbX)->iDC; + } + else if(iDCPredMode == 0){ // predict DC from left + pOrg[0] -= (pSC->PredInfo[i] + mbX - 1)->iDC; + } + else if(iDCPredMode == 2){ // predict DC from top&left + pOrg[0] -= (((pSC->PredInfo[i] + mbX - 1)->iDC + (pSC->PredInfoPrevRow[i] + mbX)->iDC + 1) >> 1); + } + + /* AD prediction */ + if(iADPredMode == 4){// predict AD from top + pOrg[2] -= (pSC->PredInfoPrevRow[i] + mbX)->piAD[1]; + } + else if(iADPredMode == 0){// predict AD from left + pOrg[1] -= (pSC->PredInfo[i] + mbX - 1)->piAD[0]; + } + + pOrg = pSC->pPlane[i]; + /* AC prediction */ + if(iACPredMode == 1){ // predict from top + for(j = 16; j <= 48; j += 32){ + /* inside macroblock */ + pOrg[j + 10] -= pOrg[j + 10 - 16]; + pOrg[j + 2] -= pOrg[j + 2 - 16]; + pOrg[j + 9] -= pOrg[j + 9 - 16]; + } + } + else if(iACPredMode == 0){ // predict from left + for(j = 32; j <= 48; j += 16){ + /* inside macroblock */ + pOrg[j + 5] -= pOrg[j + 5 - 32]; + pOrg[j + 1] -= pOrg[j + 1 - 32]; + pOrg[j + 6] -= pOrg[j + 6 - 32]; + } + } + } + } + else if(cf == YUV_422){ + for(i = 1; i < 3; i ++){ + pOrg = pMBInfo->iBlockDC[i]; // current DC block + + /* DC prediciton */ + if(iDCPredMode == 1){ // predict DC from top + pOrg[0] -= (pSC->PredInfoPrevRow[i] + mbX)->iDC; + } + else if(iDCPredMode == 0){ // predict DC from left + pOrg[0] -= (pSC->PredInfo[i] + mbX - 1)->iDC; + } + else if(iDCPredMode == 2){ // predict DC from top&left + pOrg[0] -= (((pSC->PredInfo[i] + mbX - 1)->iDC + (pSC->PredInfoPrevRow[i] + mbX)->iDC + 1) >> 1); + } + + /* AD prediction */ + if(iADPredMode == 4){// predict AD from top + pOrg[4] -= (pSC->PredInfoPrevRow[i] + mbX)->piAD[4]; // AC of HT !!! + pOrg[6] -= pOrg[2]; + pOrg[2] -= (pSC->PredInfoPrevRow[i] + mbX)->piAD[3]; + } + else if(iADPredMode == 0){// predict AD from left + pOrg[4] -= (pSC->PredInfo[i] + mbX - 1)->piAD[4]; // AC of HT !!! + pOrg[1] -= (pSC->PredInfo[i] + mbX - 1)->piAD[0]; + pOrg[5] -= (pSC->PredInfo[i] + mbX - 1)->piAD[2]; + } + else if(iDCPredMode == 1){ + pOrg[6] -= pOrg[2]; + } + + pOrg = pSC->pPlane[i]; // current MB + /* AC prediction */ + if(iACPredMode == 1){ // predict from top + for(j = 48; j > 0; j -= 16){ + for(k = 0; k <= 64; k += 64){ + /* inside macroblock */ + pOrg[j + k + 10] -= pOrg[j + k + 10 - 16]; + pOrg[j + k + 2] -= pOrg[j + k + 2 - 16]; + pOrg[j + k + 9] -= pOrg[j + k + 9 - 16]; + } + } + } + else if(iACPredMode == 0){ // predict from left + for(j = 64; j <= 112; j += 16){ + /* inside macroblock */ + pOrg[j + 5] -= pOrg[j + 5 - 64]; + pOrg[j + 1] -= pOrg[j + 1 - 64]; + pOrg[j + 6] -= pOrg[j + 6 - 64]; + } + } + } + } +} + + +/* CBP prediction for 16 x 16 MB */ +/* block index */ +/* 0 1 4 5 */ +/* 2 3 6 7 */ +/* 8 9 12 13 */ +/* 10 11 14 15 */ + +static int NumOnes(int i) +{ + int retval = 0; + static const int g_Count[] = { 0,1,1,2, 1,2,2,3, 1,2,2,3, 2,3,3,4 }; + i = i & 0xffff; + while (i) { + retval += g_Count[i & 0xf]; + i >>= 4; + } + return retval; +} + +#define SATURATE32(x) if((unsigned int)(x + 16) >= 32) { if (x < 0) x = -16; else x = 15; } + +static Int predCBPCEnc(CWMImageStrCodec *pSC, Int iCBP, size_t mbX, size_t mbY, size_t c, CCBPModel *pModel) +{ + Int iPredCBP = 0, iRetval = 0; + Int iNOrig = NumOnes(iCBP), iNDiff = AVG_NDIFF;//NumOnes(iPredCBP ^ iCBP); + + UNREFERENCED_PARAMETER( mbY ); + + /* only top left block pattern is predicted from neighbour */ + if(pSC->m_bCtxLeft) { + if (pSC->m_bCtxTop) { + iPredCBP = 1; + } + else { + Int iTopCBP = (pSC->PredInfoPrevRow[c] + mbX)->iCBP; + iPredCBP = (iTopCBP >> 10) & 1; // left: top(10) => 0 + } + } + else { + Int iLeftCBP = (pSC->PredInfo[c] + mbX - 1)->iCBP; + iPredCBP = ((iLeftCBP >> 5) & 1); // left(5) => 0 + } + + iPredCBP |= (iCBP & 0x3300) << 2; // [8 9 12 13]->[10 11 14 15] + iPredCBP |= (iCBP & 0xcc) << 6; // [2 3 6 7]->[8 9 12 13] + iPredCBP |= (iCBP & 0x33) << 2; // [0 1 4 5]->[2 3 6 7] + iPredCBP |= (iCBP & 0x11) << 1; // [0 4]->[1 5] + iPredCBP |= (iCBP & 0x2) << 3; // [1]->[4] + + if (c) c = 1; + if (pModel->m_iState[c] == 0) { + iRetval = iPredCBP ^ iCBP; + } + else if (pModel->m_iState[c] == 1) { + iRetval = iCBP; + } + else { + iRetval = iCBP ^ 0xffff; + } + + pModel->m_iCount0[c] += iNOrig - iNDiff; + SATURATE32(pModel->m_iCount0[c]); + + pModel->m_iCount1[c] += 16 - iNOrig - iNDiff; + SATURATE32(pModel->m_iCount1[c]); + + if (pModel->m_iCount0[c] < 0) { + if (pModel->m_iCount0[c] < pModel->m_iCount1[c]) { + pModel->m_iState[c] = 1; + } + else { + pModel->m_iState[c] = 2; + } + } + else if (pModel->m_iCount1[c] < 0) { + pModel->m_iState[c] = 2; + } + else { + pModel->m_iState[c] = 0; + } + return iRetval; +} + +static Int predCBPC420Enc(CWMImageStrCodec *pSC, Int iCBP, size_t mbX, size_t mbY, size_t c, CCBPModel *pModel) +{ + Int iPredCBP = 0, iRetval = 0; + Int iNOrig = NumOnes(iCBP) * 4, iNDiff = AVG_NDIFF;//NumOnes(iPredCBP ^ iCBP); + + UNREFERENCED_PARAMETER( mbY ); + + /* only top left block pattern is predicted from neighbour */ + if(pSC->m_bCtxLeft) { + if (pSC->m_bCtxTop) { + iPredCBP = 1; + } + else { + Int iTopCBP = (pSC->PredInfoPrevRow[c] + mbX)->iCBP; + iPredCBP = (iTopCBP >> 2) & 1; // left: top(2) => 0 + } + } + else { + Int iLeftCBP = (pSC->PredInfo[c] + mbX - 1)->iCBP; + iPredCBP = ((iLeftCBP >> 1) & 1); // left(1) => 0 + } + + iPredCBP |= (iCBP & 0x1) << 1; // [0]->[1] + iPredCBP |= (iCBP & 0x3) << 2; // [0 1]->[2 3] + + if (pModel->m_iState[1] == 0) { + iRetval = iPredCBP ^ iCBP; + } + else if (pModel->m_iState[1] == 1) { + iRetval = iCBP; + } + else { + iRetval = iCBP ^ 0xf; + } + + pModel->m_iCount0[1] += iNOrig - iNDiff; + SATURATE32(pModel->m_iCount0[1]); + + pModel->m_iCount1[1] += 16 - iNOrig - iNDiff; + SATURATE32(pModel->m_iCount1[1]); + + if (pModel->m_iCount0[1] < 0) { + if (pModel->m_iCount0[1] < pModel->m_iCount1[1]) { + pModel->m_iState[1] = 1; + } + else { + pModel->m_iState[1] = 2; + } + } + else if (pModel->m_iCount1[1] < 0) { + pModel->m_iState[1] = 2; + } + else { + pModel->m_iState[1] = 0; + } + return iRetval; +} + +static Int predCBPC422Enc(CWMImageStrCodec *pSC, Int iCBP, size_t mbX, size_t mbY, size_t c, CCBPModel *pModel) +{ + Int iPredCBP = 0, iRetval = 0; + Int iNOrig = NumOnes(iCBP) * 2, iNDiff = AVG_NDIFF;//NumOnes(iPredCBP ^ iCBP); + + UNREFERENCED_PARAMETER( mbY ); + + /* only top left block pattern is predicted from neighbour */ + if(pSC->m_bCtxLeft) { + if (pSC->m_bCtxTop) { + iPredCBP = 1; + } + else { + Int iTopCBP = (pSC->PredInfoPrevRow[c] + mbX)->iCBP; + iPredCBP = (iTopCBP >> 6) & 1; // left: top(6) => 0 + } + } + else { + Int iLeftCBP = (pSC->PredInfo[c] + mbX - 1)->iCBP; + iPredCBP = ((iLeftCBP >> 1) & 1); // left(1) => 0 + } + + iPredCBP |= (iCBP & 0x1) << 1; // [0]->[1] + iPredCBP |= (iCBP & 0x3) << 2; // [0 1]->[2 3] + iPredCBP |= (iCBP & 0xc) << 2; // [2 3]->[4 5] + iPredCBP |= (iCBP & 0x30) << 2; // [4 5]->[6 7] + + if (pModel->m_iState[1] == 0) { + iRetval = iPredCBP ^ iCBP; + } + else if (pModel->m_iState[1] == 1) { + iRetval = iCBP; + } + else { + iRetval = iCBP ^ 0xff; + } + + pModel->m_iCount0[1] += iNOrig - iNDiff; + SATURATE32(pModel->m_iCount0[1]); + + pModel->m_iCount1[1] += 16 - iNOrig - iNDiff; + SATURATE32(pModel->m_iCount1[1]); + + if (pModel->m_iCount0[1] < 0) { + if (pModel->m_iCount0[1] < pModel->m_iCount1[1]) { + pModel->m_iState[1] = 1; + } + else { + pModel->m_iState[1] = 2; + } + } + else if (pModel->m_iCount1[1] < 0) { + pModel->m_iState[1] = 2; + } + else { + pModel->m_iState[1] = 0; + } + return iRetval; +} + +Void predCBPEnc(CWMImageStrCodec* pSC, CCodingContext *pContext) +{ + size_t mbX = pSC->cColumn - 1, mbY = pSC->cRow - 1; + CWMIMBInfo * pMBInfo = &(pSC->MBInfo); + int iChannel, i, j; + + for(iChannel = 0; iChannel < (int)pSC->m_param.cNumChannels; iChannel ++){ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const Bool bUV = (iChannel > 0); + const int iNumBlock = (bUV ? (cf == YUV_422 ? 8 : (cf == YUV_420 ? 4 : 16)) : 16); + const int * pOffset = (iNumBlock == 4 ? blkOffsetUV : (iNumBlock == 8 ? blkOffsetUV_422 : blkOffset)); + const Int threshold = (1 << pContext->m_aModelAC.m_iFlcBits[bUV ? 1 : 0]) - 1, threshold2 = threshold * 2 + 1; + Int iCBP = 0; + + for(j = 0; j < iNumBlock; j ++){ + PixelI * pData = pSC->pPlane[iChannel] + pOffset[j]; + for(i = 1; i < 16; i ++){ + if((unsigned int)(pData[i] + threshold) >= (unsigned int) threshold2){ // significant coeff + iCBP |= (1 << j); // update CBP + break; + } + } + } + + pMBInfo->iCBP[iChannel] = (pSC->PredInfo[iChannel] + mbX)->iCBP = iCBP; + + if(iNumBlock == 16){ + pMBInfo->iDiffCBP[iChannel] = predCBPCEnc(pSC, pMBInfo->iCBP[iChannel], mbX, mbY, iChannel, &pContext->m_aCBPModel); + } + else if(iNumBlock == 8){ + pSC->MBInfo.iDiffCBP[iChannel] = predCBPC422Enc(pSC, pMBInfo->iCBP[iChannel], mbX, mbY, iChannel, &pContext->m_aCBPModel); + } + else{ + pSC->MBInfo.iDiffCBP[iChannel] = predCBPC420Enc(pSC, pMBInfo->iCBP[iChannel], mbX, mbY, iChannel, &pContext->m_aCBPModel); + } + } +} + diff --git a/libs/jxr/image/encode/strenc.c b/libs/jxr/image/encode/strenc.c new file mode 100644 index 00000000000..f0703e91f75 --- /dev/null +++ b/libs/jxr/image/encode/strenc.c @@ -0,0 +1,2370 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strcodec.h" +#include "encode.h" +#include "strTransform.h" +#include +#include "perfTimer.h" + +#ifdef MEM_TRACE +#define TRACE_MALLOC 1 +#define TRACE_NEW 0 +#define TRACE_HEAP 0 +#include "memtrace.h" +#endif + +#ifdef ADI_SYS_OPT +extern char L1WW[]; +#endif + +#ifdef X86OPT_INLINE +#define _FORCEINLINE __forceinline +#else // X86OPT_INLINE +#define _FORCEINLINE +#endif // X86OPT_INLINE + +Int inputMBRow(CWMImageStrCodec *); + +#if defined(WMP_OPT_SSE2) || defined(WMP_OPT_CC_ENC) || defined(WMP_OPT_TRFM_ENC) +void StrEncOpt(CWMImageStrCodec* pSC); +#endif // OPT defined + +#define MINIMUM_PACKET_LENGTH 4 // as long as packet header - skipped if data is not accessed (happens only for flexbits) + +Void writeQuantizer(CWMIQuantizer * pQuantizer[MAX_CHANNELS], BitIOInfo * pIO, U8 cChMode, size_t cChannel, size_t iPos) +{ + if(cChMode > 2) + cChMode = 2; + + if(cChannel > 1) + putBit16(pIO, cChMode, 2); // Channel mode + else + cChMode = 0; + + putBit16(pIO, pQuantizer[0][iPos].iIndex, 8); // Y + + if(cChMode == 1) // MIXED + putBit16(pIO, pQuantizer[1][iPos].iIndex, 8); // UV + else if(cChMode > 0){ // INDEPENDENT + size_t i; + + for(i = 1; i < cChannel; i ++) + putBit16(pIO, pQuantizer[i][iPos].iIndex, 8); // UV + } +} + +// packet header: 00000000 00000000 00000001 ?????xxx +// xxx: 000(spatial) 001(DC) 010(AD) 011(AC) 100(FL) 101-111(reserved) +// ?????: (iTileY * cNumOfSliceV + iTileX) +Void writePacketHeader(BitIOInfo * pIO, U8 ptPacketType, U8 pID) +{ + putBit16(pIO, 0, 8); + putBit16(pIO, 0, 8); + putBit16(pIO, 1, 8); + putBit16(pIO, (pID << 3) + (ptPacketType & 7), 8); +} + +Int writeTileHeaderDC(CWMImageStrCodec * pSC, BitIOInfo * pIO) +{ + size_t iTile, j = (pSC->m_pNextSC == NULL ? 1U : 2U); + + for(; j > 0; j --){ + if((pSC->m_param.uQPMode & 1) != 0){ // not DC uniform + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + size_t i; + + pTile->cChModeDC = (U8)(rand() & 3); // channel mode, just for concept proofing! + + if(pSC->cTileRow + pSC->cTileColumn == 0) // allocate DC QP info + for(iTile = 0; iTile <= pSC->WMISCP.cNumOfSliceMinus1V; iTile ++) + if(allocateQuantizer(pSC->pTile[iTile].pQuantizerDC, pSC->m_param.cNumChannels, 1) != ICERR_OK) + return ICERR_ERROR; + + for(i = 0; i < pSC->m_param.cNumChannels; i ++) + pTile->pQuantizerDC[i]->iIndex = (U8)((rand() & 0x2f) + 1); // QP indexes, just for concept proofing! + + formatQuantizer(pTile->pQuantizerDC, pTile->cChModeDC, pSC->m_param.cNumChannels, 0, TRUE, pSC->m_param.bScaledArith); + + for(i = 0; i < pSC->m_param.cNumChannels; i ++) + pTile->pQuantizerDC[i]->iOffset = (pTile->pQuantizerDC[i]->iQP >> 1); + + writeQuantizer(pTile->pQuantizerDC, pIO, pTile->cChModeDC, pSC->m_param.cNumChannels, 0); + } + + pSC = pSC->m_pNextSC; + } + + return ICERR_OK; +} + +Int writeTileHeaderLP(CWMImageStrCodec * pSC, BitIOInfo * pIO) +{ + size_t k = (pSC->m_pNextSC == NULL ? 1U : 2U); + + for(; k > 0; k --){ + if(pSC->WMISCP.sbSubband != SB_DC_ONLY && (pSC->m_param.uQPMode & 2) != 0){ // not LP uniform + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + U8 i, j; + + pTile->bUseDC = ((rand() & 1) == 0 ? TRUE : FALSE); // use DC quantizer? + putBit16(pIO, pTile->bUseDC == TRUE ? 1 : 0, 1); + pTile->cBitsLP = 0; + + pTile->cNumQPLP = (pTile->bUseDC == TRUE ? 1 : (U8)((rand() & 0xf) + 1)); // # of LP QPs + + if(pSC->cTileRow > 0) + freeQuantizer(pTile->pQuantizerLP); + + if(allocateQuantizer(pTile->pQuantizerLP, pSC->m_param.cNumChannels, pTile->cNumQPLP) != ICERR_OK) + return ICERR_ERROR; + + if(pTile->bUseDC == TRUE) + useDCQuantizer(pSC, pSC->cTileColumn); + else{ + putBit16(pIO, pTile->cNumQPLP - 1, 4); + + pTile->cBitsLP = dquantBits(pTile->cNumQPLP); + + for(i = 0; i < pTile->cNumQPLP; i ++){ + pTile->cChModeLP[i] = (U8)(rand() & 3); // channel mode, just for concept proofing! + + for(j = 0; j < pSC->m_param.cNumChannels; j ++) + pTile->pQuantizerLP[j][i].iIndex = (U8)((rand() & 0xfe) + 1); // QP indexes, just for concept proofing! + formatQuantizer(pTile->pQuantizerLP, pTile->cChModeLP[i], pSC->m_param.cNumChannels, i, TRUE, pSC->m_param.bScaledArith); + writeQuantizer(pTile->pQuantizerLP, pIO, pTile->cChModeLP[i], pSC->m_param.cNumChannels, i); + } + } + } + pSC = pSC->m_pNextSC; + } + + return ICERR_OK; +} + +Int writeTileHeaderHP(CWMImageStrCodec * pSC, BitIOInfo * pIO) +{ + size_t k = (pSC->m_pNextSC == NULL ? 1U : 2U); + + for(; k > 0; k --){ + if(pSC->WMISCP.sbSubband != SB_DC_ONLY && pSC->WMISCP.sbSubband != SB_NO_HIGHPASS && (pSC->m_param.uQPMode & 4) != 0){ // not HP uniform + CWMITile * pTile = pSC->pTile + pSC->cTileColumn; + U8 i, j; + + pTile->bUseLP = ((rand() & 1) == 0 ? TRUE : FALSE); // use LP quantizer? + putBit16(pIO, pTile->bUseLP == TRUE ? 1 : 0, 1); + pTile->cBitsHP = 0; + + pTile->cNumQPHP = (pTile->bUseLP == TRUE ? pTile->cNumQPLP : (U8)((rand() & 0xf) + 1)); // # of LP QPs + + if(pSC->cTileRow > 0) + freeQuantizer(pTile->pQuantizerHP); + + if(allocateQuantizer(pTile->pQuantizerHP, pSC->m_param.cNumChannels, pTile->cNumQPHP) != ICERR_OK) + return ICERR_ERROR; + + if(pTile->bUseLP == TRUE) + useLPQuantizer(pSC, pTile->cNumQPHP, pSC->cTileColumn); + else{ + putBit16(pIO, pTile->cNumQPHP - 1, 4); + pTile->cBitsHP = dquantBits(pTile->cNumQPHP); + + for(i = 0; i < pTile->cNumQPHP; i ++){ + pTile->cChModeHP[i] = (U8)(rand() & 3); // channel mode, just for concept proofing! + + for(j = 0; j < pSC->m_param.cNumChannels; j ++) + pTile->pQuantizerHP[j][i].iIndex = (U8)((rand() & 0xfe) + 1); // QP indexes, just for concept proofing! + formatQuantizer(pTile->pQuantizerHP, pTile->cChModeHP[i], pSC->m_param.cNumChannels, i, FALSE, pSC->m_param.bScaledArith); + writeQuantizer(pTile->pQuantizerHP, pIO, pTile->cChModeHP[i], pSC->m_param.cNumChannels, i); + } + } + } + pSC = pSC->m_pNextSC; + } + + return ICERR_OK; +} + +Int encodeMB(CWMImageStrCodec * pSC, Int iMBX, Int iMBY) +{ + CCodingContext * pContext = &pSC->m_pCodingContext[pSC->cTileColumn]; + + if(pSC->m_bCtxLeft && pSC->m_bCtxTop && pSC->m_bSecondary == FALSE && pSC->m_param.bTranscode == FALSE){ // write packet headers + U8 pID = (U8)((pSC->cTileRow * (pSC->WMISCP.cNumOfSliceMinus1V + 1) + pSC->cTileColumn) & 0x1F); + + if(pSC->WMISCP.bfBitstreamFormat == SPATIAL) { + writePacketHeader(pContext->m_pIODC, 0, pID); + if (pSC->m_param.bTrimFlexbitsFlag) + putBit16(pContext->m_pIODC, pContext->m_iTrimFlexBits, 4); + writeTileHeaderDC(pSC, pContext->m_pIODC); + writeTileHeaderLP(pSC, pContext->m_pIODC); + writeTileHeaderHP(pSC, pContext->m_pIODC); + } + else{ + writePacketHeader(pContext->m_pIODC, 1, pID); + writeTileHeaderDC(pSC, pContext->m_pIODC); + if(pSC->cSB > 1){ + writePacketHeader(pContext->m_pIOLP, 2, pID); + writeTileHeaderLP(pSC, pContext->m_pIOLP); + } + if(pSC->cSB > 2){ + writePacketHeader(pContext->m_pIOAC, 3, pID); + writeTileHeaderHP(pSC, pContext->m_pIOAC); + } + if(pSC->cSB > 3) { + writePacketHeader(pContext->m_pIOFL, 4, pID); + if (pSC->m_param.bTrimFlexbitsFlag) + putBit16(pContext->m_pIOFL, pContext->m_iTrimFlexBits, 4); + } + } + } + + if(EncodeMacroblockDC(pSC, pContext, iMBX, iMBY) != ICERR_OK) + return ICERR_ERROR; + + if(pSC->WMISCP.sbSubband != SB_DC_ONLY) + if(EncodeMacroblockLowpass(pSC, pContext, iMBX, iMBY) != ICERR_OK) + return ICERR_ERROR; + + if(pSC->WMISCP.sbSubband != SB_DC_ONLY && pSC->WMISCP.sbSubband != SB_NO_HIGHPASS) + if(EncodeMacroblockHighpass(pSC, pContext, iMBX, iMBY) != ICERR_OK) + return ICERR_ERROR; + + if(iMBX + 1 == (int) pSC->cmbWidth && (iMBY + 1 == (int) pSC->cmbHeight || + (pSC->cTileRow < pSC->WMISCP.cNumOfSliceMinus1H && iMBY == (int) pSC->WMISCP.uiTileY[pSC->cTileRow + 1] - 1))) + { // end of a horizontal slice + size_t k, l; + + // get sizes of each packet and update index table + if (pSC->m_pNextSC == NULL || pSC->m_bSecondary) { + for(k = 0; k < pSC->cNumBitIO; k ++){ + fillToByte(pSC->m_ppBitIO[k]); + pSC->ppWStream[k]->GetPos(pSC->ppWStream[k], &l); + pSC->pIndexTable[pSC->cNumBitIO * pSC->cTileRow + k] = l + getSizeWrite(pSC->m_ppBitIO[k]); // offset + } + } + + // reset coding contexts + if(iMBY + 1 != (int) pSC->cmbHeight){ + for(k = 0; k <= pSC->WMISCP.cNumOfSliceMinus1V; k ++) + ResetCodingContextEnc(&pSC->m_pCodingContext[k]); + } + } + + return ICERR_OK; +} + +/************************************************************************* + Top level function for processing a macroblock worth of input +*************************************************************************/ +Int processMacroblock(CWMImageStrCodec *pSC) +{ + Bool topORleft = (pSC->cColumn == 0 || pSC->cRow == 0); + ERR_CODE result = ICERR_OK; + size_t j, jend = (pSC->m_pNextSC != NULL); + + for (j = 0; j <= jend; j++) { + transformMacroblock(pSC); + if(!topORleft){ + getTilePos(pSC, (Int)pSC->cColumn - 1, (Int)pSC->cRow - 1); + if(jend){ + pSC->m_pNextSC->cTileRow = pSC->cTileRow; + pSC->m_pNextSC->cTileColumn = pSC->cTileColumn; + } + if ((result = encodeMB(pSC, (Int)pSC->cColumn - 1, (Int)pSC->cRow - 1)) != ICERR_OK) + return result; + } + + if (jend) { + pSC->m_pNextSC->cRow = pSC->cRow; + pSC->m_pNextSC->cColumn = pSC->cColumn; + pSC = pSC->m_pNextSC; + } + } + + return ICERR_OK; +} + +/************************************************************************* + forwardRGBE: forward conversion from RGBE to RGB +*************************************************************************/ +static _FORCEINLINE PixelI forwardRGBE (PixelI RGB, PixelI E) +{ + PixelI iResult = 0, iAppend = 1; + + if (E == 0) + return 0; + + assert (E!=0); + + E--; + while (((RGB & 0x80) == 0) && (E > 0)) { + RGB = (RGB << 1) + iAppend; + iAppend = 0; + E--; + } + + // result will always be one of 3 cases + // E RGB convert to + // 0 [0.x] [0 x] + // 0 [1.x] [1 x] + // e [1.x] [e+1 x] + if (E == 0) { + iResult = RGB; + } + else { + E++; + iResult = (RGB & 0x7f) + (E << 7); + } + + return iResult; +} + +/************************************************************************* + convert float-32 into float with (c, lm)!! +*************************************************************************/ +static _FORCEINLINE PixelI float2pixel (float f, const char _c, const unsigned char _lm) +{ + union uif + { + I32 i; + float f; + } x; + + PixelI _h, e, e1, m, s; + + if (f == 0) + { + _h = 0; + } + else + { + x.f = f; + + e = (x.i >> 23) & 0x000000ff;//here set e as e, not s! e includes s: [s e] 9 bits [31..23] + m = (x.i & 0x007fffff) | 0x800000; // actual mantissa, with normalizer + if (e == 0) { // denormal-land + m ^= 0x800000; // actual mantissa, removing normalizer + e++; // actual exponent -126 + } + + e1 = e - 127 + _c; // this is basically a division or quantization to a different exponent + // note: _c cannot be greater than 127, so e1 cannot be greater than e + //assert (_c <= 127); + if (e1 <= 1) { // denormal-land + if (e1 < 1) + m >>= (1 - e1); // shift mantissa right to make exponent 1 + e1 = 1; + if ((m & 0x800000) == 0) // if denormal, set e1 to zero else to 1 + e1 = 0; + } + m &= 0x007fffff; + + //for float-22: + _h = (e1 << _lm) + ((m + (1 << (23 - _lm - 1))) >> (23 - _lm));//take 23-bit m, shift (23-lm), get lm-bit m for float22 + s = ((PixelI) x.i) >> 31; + //padding to int-32: + _h = (_h ^ s) - s; + } + + return _h; +} + +/************************************************************************* + convert Half-16 to internal format, only need to handle sign bit +*************************************************************************/ +static _FORCEINLINE PixelI forwardHalf (PixelI hHalf) +{ + PixelI s; + s = hHalf >> 31; + hHalf = ((hHalf & 0x7fff) ^ s) - s; + return hHalf; +} + + +//================================================================ +// Color Conversion +// functions to get image data from input buffer +// this inlcudes necessary color conversion and boundary padding +//================================================================ +#define _CC(r, g, b) (b -= r, r += ((b + 1) >> 1) - g, g += ((r + 0) >> 1)) +#define _CC_CMYK(c, m, y, k) (y -= c, c += ((y + 1) >> 1) - m, m += (c >> 1) - k, k += ((m + 1) >> 1)) + +//================================================================ +// BitIOInfo init/term for encoding +const size_t MAX_MEMORY_SIZE_IN_WORDS = 64 << 20; // 1 << 20 \approx 1 million + +Int StrIOEncInit(CWMImageStrCodec* pSC) +{ + pSC->m_param.bIndexTable = !(pSC->WMISCP.bfBitstreamFormat == SPATIAL && pSC->WMISCP.cNumOfSliceMinus1H + pSC->WMISCP.cNumOfSliceMinus1V == 0); + if(allocateBitIOInfo(pSC) != ICERR_OK){ + return ICERR_ERROR; + } + + attachISWrite(pSC->pIOHeader, pSC->WMISCP.pWStream); + + if(pSC->cNumBitIO > 0){ + size_t i; +#if defined(_WINDOWS_) || defined(UNDER_CE) // tmpnam does not exist in VS2005 WinCE CRT + TCHAR szPath[MAX_PATH]; + DWORD cSize, j, k; +#endif + char * pFilename; + + pSC->ppWStream = (struct WMPStream **)malloc(pSC->cNumBitIO * sizeof(struct WMPStream *)); + if(pSC->ppWStream == NULL) return ICERR_ERROR; + memset(pSC->ppWStream, 0, pSC->cNumBitIO * sizeof(struct WMPStream *)); + + if (pSC->cmbHeight * pSC->cmbWidth * pSC->WMISCP.cChannel >= MAX_MEMORY_SIZE_IN_WORDS) { +#ifdef _WINDOWS_ + pSC->ppTempFile = (TCHAR **)malloc(pSC->cNumBitIO * sizeof(TCHAR *)); + if(pSC->ppTempFile == NULL) return ICERR_ERROR; + memset(pSC->ppTempFile, 0, pSC->cNumBitIO * sizeof(TCHAR *)); +#else + pSC->ppTempFile = (char **)malloc(pSC->cNumBitIO * sizeof(char *)); + if(pSC->ppTempFile == NULL) return ICERR_ERROR; + memset(pSC->ppTempFile, 0, pSC->cNumBitIO * sizeof(char *)); +#endif + } + + for(i = 0; i < pSC->cNumBitIO; i ++){ + if (pSC->cmbHeight * pSC->cmbWidth * pSC->WMISCP.cChannel >= MAX_MEMORY_SIZE_IN_WORDS) { +#if defined(_WINDOWS_) || defined(UNDER_CE) // tmpnam does not exist in VS2005 WinCE CRT + Bool bUnicode = sizeof(TCHAR) == 2; + pSC->ppTempFile[i] = (TCHAR *)malloc(MAX_PATH * sizeof(TCHAR)); + if(pSC->ppTempFile[i] == NULL) return ICERR_ERROR; + + pFilename = (char *)pSC->ppTempFile[i]; + + cSize = GetTempPath(MAX_PATH, szPath); + if(cSize == 0 || cSize >= MAX_PATH) + return ICERR_ERROR; + if(!GetTempFileName(szPath, TEXT("wdp"), 0, pSC->ppTempFile[i])) + return ICERR_ERROR; + + if(bUnicode){ // unicode file name + for(k = j = cSize = 0; cSize < MAX_PATH; cSize ++, j += 2){ + if(pSC->ppTempFile[i][cSize] == '\0') + break; + if(pFilename[j] != '\0') + pFilename[k ++] = pFilename[j]; + if(pFilename[j + 1] != '\0') + pFilename[k ++] = pFilename[j + 1]; + } + pFilename[cSize] = '\0'; + } + +#else //DPK needs to support ANSI + pSC->ppTempFile[i] = (char *)malloc(FILENAME_MAX * sizeof(char)); + if(pSC->ppTempFile[i] == NULL) return ICERR_ERROR; + + if ((pFilename = tmpnam(NULL)) == NULL) + return ICERR_ERROR; + strcpy(pSC->ppTempFile[i], pFilename); +#endif + if(CreateWS_File(pSC->ppWStream + i, pFilename, "w+b") != ICERR_OK) return ICERR_ERROR; + + } + else { + if(CreateWS_List(pSC->ppWStream + i) != ICERR_OK) return ICERR_ERROR; + } + attachISWrite(pSC->m_ppBitIO[i], pSC->ppWStream[i]); + } + } + + return ICERR_OK; +} + +#define PUTBITS putBit16 +/************************************************************************* + Write variable length byte aligned integer +*************************************************************************/ +static Void PutVLWordEsc(BitIOInfo* pIO, Int iEscape, size_t s) +{ + if (iEscape) { + assert(iEscape <= 0xff && iEscape > 0xfc); // fd,fe,ff are the only valid escapes + PUTBITS(pIO, iEscape, 8); + } + else if (s < 0xfb00) { + PUTBITS(pIO, (U32) s, 16); + } + else { + size_t t = s >> 16; + if ((t >> 16) == 0) { + PUTBITS(pIO, 0xfb, 8); + } + else { + t >>= 16; + PUTBITS(pIO, 0xfc, 8); + PUTBITS(pIO, (U32)(t >> 16) & 0xffff, 16); + PUTBITS(pIO, (U32) t & 0xffff, 16); + } + PUTBITS(pIO, (U32) t & 0xffff, 16); + PUTBITS(pIO, (U32) s & 0xffff, 16); + } +} + +/************************************************************************* + Write index table at start (null index table) +*************************************************************************/ +Int writeIndexTableNull(CWMImageStrCodec * pSC) +{ + if(pSC->cNumBitIO == 0){ + BitIOInfo* pIO = pSC->pIOHeader; + fillToByte(pIO); + + /* Profile / Level info */ + PutVLWordEsc(pIO, 0, 4); // 4 bytes + PUTBITS(pIO, 111, 8); // default profile idc + PUTBITS(pIO, 255, 8); // default level idc + PUTBITS(pIO, 1, 16); // LAST_FLAG + } + + return ICERR_OK; +} + +/************************************************************************* + Write index table +*************************************************************************/ +Int writeIndexTable(CWMImageStrCodec * pSC) +{ + if(pSC->cNumBitIO > 0){ + BitIOInfo* pIO = pSC->pIOHeader; + size_t *pTable = pSC->pIndexTable, iSize[4] = { 0 }; + I32 iEntry = (I32)pSC->cNumBitIO * (pSC->WMISCP.cNumOfSliceMinus1H + 1), i, k, l; + + // write index table header [0x0001] - 2 bytes + PUTBITS(pIO, 1, 16); + + for(i = pSC->WMISCP.cNumOfSliceMinus1H; i>= 0 && pSC->bTileExtraction == FALSE; i --){ + for(k = 0; k < (int)pSC->cNumBitIO; ){ + for(l = 0; l < (pSC->WMISCP.bfBitstreamFormat == FREQUENCY && pSC->WMISCP.bProgressiveMode ? pSC->cSB : 1); l ++, k ++) + { + if (i > 0) + pTable[pSC->cNumBitIO * i + k] -= pSC->pIndexTable[pSC->cNumBitIO * (i - 1) + k]; // packet length + iSize[l] += pTable[pSC->cNumBitIO * i + k]; + } + } + } + + iSize[3] = iSize[2] + iSize[1] + iSize[0]; + iSize[2] = iSize[1] + iSize[0]; + iSize[1] = iSize[0]; + iSize[0] = 0; + + for(i = 0; i < iEntry; ){ + for(l = 0; l < (pSC->WMISCP.bfBitstreamFormat == FREQUENCY && pSC->WMISCP.bProgressiveMode ? pSC->cSB : 1); l ++, i ++) + { + writeIS_L1(pSC, pIO); + PutVLWordEsc(pIO, (pTable[i] <= MINIMUM_PACKET_LENGTH) ? 0xff : 0, iSize[l]); + iSize[l] += (pTable[i] <= MINIMUM_PACKET_LENGTH) ? 0 : pTable[i]; + } + } + + writeIS_L1(pSC, pIO); + PutVLWordEsc(pIO, 0xff, 0); // escape to end + fillToByte(pIO); + } + + return ICERR_OK; +} + +Int copyTo(struct WMPStream * pSrc, struct WMPStream * pDst, size_t iBytes) +{ + char pData[PACKETLENGTH]; + + if (iBytes <= MINIMUM_PACKET_LENGTH){ + pSrc->Read(pSrc, pData, iBytes); + return ICERR_OK; + } + + while(iBytes > PACKETLENGTH){ + pSrc->Read(pSrc, pData, PACKETLENGTH); + pDst->Write(pDst, pData, PACKETLENGTH); + iBytes -= PACKETLENGTH; + } + pSrc->Read(pSrc, pData, iBytes); + pDst->Write(pDst, pData, iBytes); + + return ICERR_OK; +} + +Int StrIOEncTerm(CWMImageStrCodec* pSC) +{ + BitIOInfo * pIO = pSC->pIOHeader; + + fillToByte(pIO); + + if(pSC->WMISCP.bVerbose){ + U32 i, j; + + printf("\n%d horizontal tiles:\n", pSC->WMISCP.cNumOfSliceMinus1H + 1); + for(i = 0; i <= pSC->WMISCP.cNumOfSliceMinus1H; i ++){ + printf(" offset of tile %d in MBs: %d\n", i, pSC->WMISCP.uiTileY[i]); + } + + printf("\n%d vertical tiles:\n", pSC->WMISCP.cNumOfSliceMinus1V + 1); + for(i = 0; i <= pSC->WMISCP.cNumOfSliceMinus1V; i ++){ + printf(" offset of tile %d in MBs: %d\n", i, pSC->WMISCP.uiTileX[i]); + } + + if(pSC->WMISCP.bfBitstreamFormat == SPATIAL){ + printf("\nSpatial order bitstream\n"); + } + else{ + printf("\nFrequency order bitstream\n"); + } + + if(!pSC->m_param.bIndexTable){ + printf("\nstreaming mode, no index table.\n"); + } + else if(pSC->WMISCP.bfBitstreamFormat == SPATIAL){ + for(j = 0; j <= pSC->WMISCP.cNumOfSliceMinus1H; j ++){ + for(i = 0; i <= pSC->WMISCP.cNumOfSliceMinus1V; i ++){ + printf("bitstream size for tile (%d, %d): %d.\n", j, i, (int) pSC->pIndexTable[j * (pSC->WMISCP.cNumOfSliceMinus1V + 1) + i]); + } + } + } + else{ + for(j = 0; j <= pSC->WMISCP.cNumOfSliceMinus1H; j ++){ + for(i = 0; i <= pSC->WMISCP.cNumOfSliceMinus1V; i ++){ + size_t * p = &pSC->pIndexTable[(j * (pSC->WMISCP.cNumOfSliceMinus1V + 1) + i) * 4]; + printf("bitstream size of (DC, LP, AC, FL) for tile (%d, %d): %d %d %d %d.\n", j, i, + (int) p[0], (int) p[1], (int) p[2], (int) p[3]); + } + } + } + } + + writeIndexTable(pSC); // write index table to the header + + detachISWrite(pSC, pIO); + + if(pSC->cNumBitIO > 0){ + size_t i, j, k, l; + struct WMPStream * pDst = pSC->WMISCP.pWStream; + size_t * pTable = pSC->pIndexTable; + + for(i = 0; i < pSC->cNumBitIO; i ++){ + detachISWrite(pSC, pSC->m_ppBitIO[i]); + } + + for(i = 0; i < pSC->cNumBitIO; i ++){ + pSC->ppWStream[i]->SetPos(pSC->ppWStream[i], 0); // seek back for read + } + + for(l = 0; l < (size_t)(pSC->WMISCP.bfBitstreamFormat == FREQUENCY && pSC->WMISCP.bProgressiveMode ? pSC->cSB : 1); l ++){ + for(i = 0, k = l; i <= pSC->WMISCP.cNumOfSliceMinus1H; i ++){ // loop through tiles + for(j = 0; j <= pSC->WMISCP.cNumOfSliceMinus1V; j ++){ + + if(pSC->WMISCP.bfBitstreamFormat == SPATIAL) + copyTo(pSC->ppWStream[j], pDst, pTable[k ++]); + else if (!pSC->WMISCP.bProgressiveMode){ + copyTo(pSC->ppWStream[j * pSC->cSB + 0], pDst, pTable[k ++]); + if(pSC->cSB > 1) + copyTo(pSC->ppWStream[j * pSC->cSB + 1], pDst, pTable[k ++]); + if(pSC->cSB > 2) + copyTo(pSC->ppWStream[j * pSC->cSB + 2], pDst, pTable[k ++]); + if(pSC->cSB > 3) + copyTo(pSC->ppWStream[j * pSC->cSB + 3], pDst, pTable[k ++]); + } + else{ + copyTo(pSC->ppWStream[j * pSC->cSB + l], pDst, pTable[k]); + k += pSC->cSB; + } + } + } + } + + if (pSC->cmbHeight * pSC->cmbWidth * pSC->WMISCP.cChannel >= MAX_MEMORY_SIZE_IN_WORDS){ + for(i = 0; i < pSC->cNumBitIO; i ++){ + if(pSC->ppWStream && pSC->ppWStream[i]){ + if((*(pSC->ppWStream + i))->state.file.pFile){ + fclose((*(pSC->ppWStream + i))->state.file.pFile); +#ifdef _WINDOWS_ + if(DeleteFileA((LPCSTR)pSC->ppTempFile[i]) == 0) + return ICERR_ERROR; +#else + if (remove(pSC->ppTempFile[i]) == -1) + return ICERR_ERROR; +#endif + } + + if (*(pSC->ppWStream + i)) + free(*(pSC->ppWStream + i)); + } + if(pSC->ppTempFile){ + if(pSC->ppTempFile[i]) + free(pSC->ppTempFile[i]); + } + } + + if(pSC->ppTempFile) + free(pSC->ppTempFile); + } + else{ + for(i = 0; i < pSC->cNumBitIO; i ++){ + if(pSC->ppWStream && pSC->ppWStream[i]) + pSC->ppWStream[i]->Close(pSC->ppWStream + i); + } + } + + free(pSC->ppWStream); + + free(pSC->m_ppBitIO); + free(pSC->pIndexTable); + } + + return 0; +} + +/************************************************************************* + Write header of image plane +*************************************************************************/ +Int WriteImagePlaneHeader(CWMImageStrCodec * pSC) +{ + CWMImageInfo * pII = &pSC->WMII; + CWMIStrCodecParam * pSCP = &pSC->WMISCP; + BitIOInfo* pIO = pSC->pIOHeader; + + PUTBITS(pIO, (Int) pSC->m_param.cfColorFormat, 3); // internal color format + PUTBITS(pIO, (Int) pSC->m_param.bScaledArith, 1); // lossless mode + +// subbands + PUTBITS(pIO, (U32)pSCP->sbSubband, 4); + +// color parameters + switch (pSC->m_param.cfColorFormat) { + case YUV_420: + case YUV_422: + case YUV_444: + PUTBITS(pIO, 0, 4); + PUTBITS(pIO, 0, 4); + break; + case NCOMPONENT: + PUTBITS(pIO, (Int) pSC->m_param.cNumChannels - 1, 4); + PUTBITS(pIO, 0, 4); + break; + default: + break; + } + +// float and 32s additional parameters + switch (pII->bdBitDepth) { + case BD_16: + case BD_16S: + PUTBITS(pIO, pSCP->nLenMantissaOrShift, 8); + break; + case BD_32: + case BD_32S: + if(pSCP->nLenMantissaOrShift == 0) + pSCP->nLenMantissaOrShift = 10;//default + PUTBITS(pIO, pSCP->nLenMantissaOrShift, 8); + break; + case BD_32F: + if(pSCP->nLenMantissaOrShift == 0) + pSCP->nLenMantissaOrShift = 13;//default + PUTBITS(pIO, pSCP->nLenMantissaOrShift, 8);//float conversion parameters + PUTBITS(pIO, pSCP->nExpBias, 8); + break; + default: + break; + } + + // quantization + PUTBITS(pIO, (pSC->m_param.uQPMode & 1) == 1 ? 0 : 1, 1); // DC frame uniform quantization? + if((pSC->m_param.uQPMode & 1) == 0) + writeQuantizer(pSC->pTile[0].pQuantizerDC, pIO, (pSC->m_param.uQPMode >> 3) & 3, pSC->m_param.cNumChannels, 0); + if(pSC->WMISCP.sbSubband != SB_DC_ONLY){ + PUTBITS(pIO, (pSC->m_param.uQPMode & 0x200) == 0 ? 1 : 0, 1); // use DC quantization? + if((pSC->m_param.uQPMode & 0x200) != 0){ + PUTBITS(pIO, (pSC->m_param.uQPMode & 2) == 2 ? 0 : 1, 1); // LP frame uniform quantization? + if((pSC->m_param.uQPMode & 2) == 0) + writeQuantizer(pSC->pTile[0].pQuantizerLP, pIO, (pSC->m_param.uQPMode >> 5) & 3, pSC->m_param.cNumChannels, 0); + } + + if(pSC->WMISCP.sbSubband != SB_NO_HIGHPASS){ + PUTBITS(pIO, (pSC->m_param.uQPMode & 0x400) == 0 ? 1 : 0, 1); // use LP quantization? + if((pSC->m_param.uQPMode & 0x400) != 0){ + PUTBITS(pIO, (pSC->m_param.uQPMode & 4) == 4 ? 0 : 1, 1); // HP frame uniform quantization? + if((pSC->m_param.uQPMode & 4) == 0) + writeQuantizer(pSC->pTile[0].pQuantizerHP, pIO, (pSC->m_param.uQPMode >> 7) & 3, pSC->m_param.cNumChannels, 0); + } + } + } + + fillToByte(pIO); // remove this later + return ICERR_OK; +} + +/************************************************************************* + Write header to buffer +*************************************************************************/ +Int WriteWMIHeader(CWMImageStrCodec * pSC) +{ + CWMImageInfo * pII = &pSC->WMII; + CWMIStrCodecParam * pSCP = &pSC->WMISCP; + CCoreParameters * pCoreParam = &pSC->m_param; + BitIOInfo* pIO = pSC->pIOHeader; + U32 /*iSizeOfSize = 2,*/ i; + // temporary assignments / reserved words + // const Int HEADERSIZE = 0; + Bool bInscribed = FALSE; + Bool bAbbreviatedHeader = (((pII->cWidth + 15) / 16 > 255 || (pII->cHeight + 15) / 16 > 255) ? FALSE : TRUE); + + if(pCoreParam->bTranscode == FALSE) + pCoreParam->cExtraPixelsTop = pCoreParam->cExtraPixelsLeft = pCoreParam->cExtraPixelsRight = pCoreParam->cExtraPixelsBottom = 0; + + // num of extra boundary pixels due to compressed domain processing + bInscribed = (pCoreParam->cExtraPixelsTop || pCoreParam->cExtraPixelsLeft || pCoreParam->cExtraPixelsBottom || pCoreParam->cExtraPixelsRight); + +// 0 + /** signature **/ + for (i = 0; i < 8; PUTBITS(pSC->pIOHeader, gGDISignature[i++], 8)); + +// 8 + /** codec version and subversion **/ + PUTBITS(pIO, CODEC_VERSION, 4); // this should be changed to "profile" in RTM + if (pSC->WMISCP.bUseHardTileBoundaries) + PUTBITS(pIO, CODEC_SUBVERSION_NEWSCALING_HARD_TILES, 4); + else + PUTBITS(pIO, CODEC_SUBVERSION_NEWSCALING_SOFT_TILES, 4); + +// 9 primary parameters + PUTBITS(pIO, (pSCP->cNumOfSliceMinus1V || pSCP->cNumOfSliceMinus1H) ? 1 : 0, 1); // tiling present + PUTBITS(pIO, (Int) pSCP->bfBitstreamFormat, 1); // bitstream layout + PUTBITS(pIO, pII->oOrientation, 3); // m_iRotateFlip + PUTBITS(pIO, pSC->m_param.bIndexTable, 1); // index table present + PUTBITS(pIO, pSCP->olOverlap, 2); // overlap + +// 10 + PUTBITS(pIO, bAbbreviatedHeader, 1); // short words for size and tiles + PUTBITS(pIO, 1, 1); // long word length (use intelligence later) + PUTBITS(pIO, bInscribed, 1); // windowing + PUTBITS(pIO, pSC->m_param.bTrimFlexbitsFlag, 1); // trim flexbits flag sent + PUTBITS(pIO, 0, 1); // tile stretching parameters (not enabled) + PUTBITS(pIO, 0, 2); // reserved bits + PUTBITS(pIO, (Int) pSC->m_param.bAlphaChannel, 1); // alpha channel present + +// 11 - informational + PUTBITS(pIO, (Int) pII->cfColorFormat, 4); // source color format + if(BD_1 == pII->bdBitDepth && pSCP->bBlackWhite) + PUTBITS(pIO, (Int) BD_1alt, 4); // source bit depth + else + PUTBITS(pIO, (Int) pII->bdBitDepth, 4); // source bit depth + +// 12 - Variable length fields +// size + putBit32(pIO, (U32)(pII->cWidth - 1), bAbbreviatedHeader ? 16 : 32); + putBit32(pIO, (U32)(pII->cHeight - 1), bAbbreviatedHeader ? 16 : 32); + +// tiling + if (pSCP->cNumOfSliceMinus1V || pSCP->cNumOfSliceMinus1H) { + PUTBITS(pIO, pSCP->cNumOfSliceMinus1V, LOG_MAX_TILES); // # of vertical slices + PUTBITS(pIO, pSCP->cNumOfSliceMinus1H, LOG_MAX_TILES); // # of horizontal slices + } + +// tile sizes + for(i = 0; i < pSCP->cNumOfSliceMinus1V; i ++){ // width in MB of vertical slices, not needed for last slice! + PUTBITS(pIO, pSCP->uiTileX[i + 1] - pSCP->uiTileX[i], bAbbreviatedHeader ? 8 : 16); + } + for(i = 0; i < pSCP->cNumOfSliceMinus1H; i ++){ // width in MB of horizontal slices, not needed for last slice! + PUTBITS(pIO, pSCP->uiTileY[i + 1] - pSCP->uiTileY[i], bAbbreviatedHeader ? 8 : 16); + } + +// window due to compressed domain processing + if (bInscribed) { + PUTBITS(pIO, (U32)pCoreParam->cExtraPixelsTop, 6); + PUTBITS(pIO, (U32)pCoreParam->cExtraPixelsLeft, 6); + PUTBITS(pIO, (U32)pCoreParam->cExtraPixelsBottom, 6); + PUTBITS(pIO, (U32)pCoreParam->cExtraPixelsRight, 6); + } + fillToByte(pIO); // redundant + + // write image plane headers + WriteImagePlaneHeader(pSC); + + return ICERR_OK; +} + +// streaming codec init/term +Int StrEncInit(CWMImageStrCodec* pSC) +{ + COLORFORMAT cf = pSC->m_param.cfColorFormat; + COLORFORMAT cfE = pSC->WMII.cfColorFormat; + U16 iQPIndexY = 0, iQPIndexYLP = 0, iQPIndexYHP = 0; + U16 iQPIndexU = 0, iQPIndexULP = 0, iQPIndexUHP = 0; + U16 iQPIndexV = 0, iQPIndexVLP = 0, iQPIndexVHP = 0; + size_t i; + Bool b32bit = sizeof(size_t) == 4; + + /** color transcoding with resolution change **/ + pSC->m_bUVResolutionChange = (((cfE == CF_RGB || cfE == YUV_444 || cfE == CMYK || cfE == CF_RGBE) && + (cf == YUV_422 || cf == YUV_420)) + || (cfE == YUV_422 && cf == YUV_420)) && !pSC->WMISCP.bYUVData; + + if(pSC->m_bUVResolutionChange){ + size_t cSize = ((cfE == YUV_422 ? 128 : 256) + (cf == YUV_420 ? 32 : 0)) * pSC->cmbWidth + 256; + + if(b32bit){ // integer overlow/underflow check for 32-bit system + if(((pSC->cmbWidth >> 16) * ((cfE == YUV_422 ? 128 : 256) + (cf == YUV_420 ? 32 : 0))) & 0xffff0000) + return ICERR_ERROR; + if(cSize >= 0x3fffffff) + return ICERR_ERROR; + } + pSC->pResU = (PixelI *)malloc(cSize * sizeof(PixelI)); + pSC->pResV = (PixelI *)malloc(cSize * sizeof(PixelI)); + if(pSC->pResU == NULL || pSC->pResV == NULL){ + return ICERR_ERROR; + } + } + + pSC->cTileColumn = pSC->cTileRow = 0; + + if(allocateTileInfo(pSC) != ICERR_OK) + return ICERR_ERROR; + + if(pSC->m_param.bTranscode == FALSE){ + pSC->m_param.uQPMode = 0x150; // 101010 000 + // 000 == uniform (not per tile) DC, LP, HP + // 101010 == cChMode == 2 == independent (not same) DC, LP, HP + + /** lossless or Y component lossless condition: all subbands present, uniform quantization with QPIndex 1 **/ + pSC->m_param.bScaledArith = !((pSC->m_param.uQPMode & 7) == 0 && + 1 == pSC->WMISCP.uiDefaultQPIndex <= 1 && + pSC->WMISCP.sbSubband == SB_ALL && + pSC->m_bUVResolutionChange == FALSE) && + !pSC->WMISCP.bUnscaledArith; + if (BD_32 == pSC->WMII.bdBitDepth || BD_32S == pSC->WMII.bdBitDepth || BD_32F == pSC->WMII.bdBitDepth) { + pSC->m_param.bScaledArith = FALSE; + } + pSC->m_param.uQPMode |= 0x600; // don't use DC QP for LP, LP QP for HP + + // default QPs + iQPIndexY = pSC->m_param.bAlphaChannel && pSC->m_param.cNumChannels == 1? + pSC->WMISCP.uiDefaultQPIndexAlpha : pSC->WMISCP.uiDefaultQPIndex; + + // determine the U,V index + iQPIndexU = pSC->WMISCP.uiDefaultQPIndexU!=0? + pSC->WMISCP.uiDefaultQPIndexU: iQPIndexY; + iQPIndexV = pSC->WMISCP.uiDefaultQPIndexV!=0? + pSC->WMISCP.uiDefaultQPIndexV: iQPIndexY; + + // determine the QPIndexYLP + iQPIndexYLP = pSC->m_param.bAlphaChannel && pSC->m_param.cNumChannels == 1 ? + pSC->WMISCP.uiDefaultQPIndexAlpha : + (pSC->WMISCP.uiDefaultQPIndexYLP == 0 ? + pSC->WMISCP.uiDefaultQPIndex : pSC->WMISCP.uiDefaultQPIndexYLP); // default to QPIndex if not set + + // determine the QPIndexYHP + iQPIndexYHP = pSC->m_param.bAlphaChannel && pSC->m_param.cNumChannels == 1 ? + pSC->WMISCP.uiDefaultQPIndexAlpha : + (pSC->WMISCP.uiDefaultQPIndexYHP == 0 ? + pSC->WMISCP.uiDefaultQPIndex : pSC->WMISCP.uiDefaultQPIndexYHP); // default to QPIndex if not set + + // determine the U,V LP index + iQPIndexULP = pSC->WMISCP.uiDefaultQPIndexULP!=0? + pSC->WMISCP.uiDefaultQPIndexULP: iQPIndexU; + iQPIndexVLP = pSC->WMISCP.uiDefaultQPIndexVLP!=0? + pSC->WMISCP.uiDefaultQPIndexVLP: iQPIndexV; + + // determine the U,V HP index + iQPIndexUHP = pSC->WMISCP.uiDefaultQPIndexUHP!=0? + pSC->WMISCP.uiDefaultQPIndexUHP: iQPIndexU; + iQPIndexVHP = pSC->WMISCP.uiDefaultQPIndexVHP!=0? + pSC->WMISCP.uiDefaultQPIndexVHP: iQPIndexV; + + // clamp the QPIndex - 0 is lossless mode + if(iQPIndexY < 2) + iQPIndexY = 0; + if (iQPIndexYLP < 2) + iQPIndexYLP = 0; + if (iQPIndexYHP < 2) + iQPIndexYHP = 0; + if(iQPIndexU < 2) + iQPIndexU = 0; + if (iQPIndexULP < 2) + iQPIndexULP = 0; + if (iQPIndexUHP < 2) + iQPIndexUHP = 0; + if(iQPIndexV < 2) + iQPIndexV = 0; + if (iQPIndexVLP < 2) + iQPIndexVLP = 0; + if (iQPIndexVHP < 2) + iQPIndexVHP = 0; + } + + if((pSC->m_param.uQPMode & 1) == 0){ // DC frame uniform quantization + if(allocateQuantizer(pSC->pTile[0].pQuantizerDC, pSC->m_param.cNumChannels, 1) != ICERR_OK) + return ICERR_ERROR; + setUniformQuantizer(pSC, 0); + for(i = 0; i < pSC->m_param.cNumChannels; i ++) + if(pSC->m_param.bTranscode) + pSC->pTile[0].pQuantizerDC[i]->iIndex = pSC->m_param.uiQPIndexDC[i]; + else + pSC->pTile[0].pQuantizerDC[i]->iIndex = pSC->m_param.uiQPIndexDC[i] = (U8)(((i == 0 ? iQPIndexY : (i == 1) ? iQPIndexU: iQPIndexV)) & 0xff); + formatQuantizer(pSC->pTile[0].pQuantizerDC, (pSC->m_param.uQPMode >> 3) & 3, pSC->m_param.cNumChannels, 0, TRUE, pSC->m_param.bScaledArith); + + for(i = 0; i < pSC->m_param.cNumChannels; i ++) + pSC->pTile[0].pQuantizerDC[i]->iOffset = (pSC->pTile[0].pQuantizerDC[i]->iQP >> 1); + } + + if(pSC->WMISCP.sbSubband != SB_DC_ONLY){ + if((pSC->m_param.uQPMode & 2) == 0){ // LP frame uniform quantization + if(allocateQuantizer(pSC->pTile[0].pQuantizerLP, pSC->m_param.cNumChannels, 1) != ICERR_OK) + return ICERR_ERROR; + setUniformQuantizer(pSC, 1); + for(i = 0; i < pSC->m_param.cNumChannels; i ++) + if(pSC->m_param.bTranscode) + pSC->pTile[0].pQuantizerLP[i]->iIndex = pSC->m_param.uiQPIndexLP[i]; + else + pSC->pTile[0].pQuantizerLP[i]->iIndex = pSC->m_param.uiQPIndexLP[i] = (U8)(((i == 0 ? iQPIndexYLP : (i == 1) ? iQPIndexULP: iQPIndexVLP)) & 0xff); + formatQuantizer(pSC->pTile[0].pQuantizerLP, (pSC->m_param.uQPMode >> 5) & 3, pSC->m_param.cNumChannels, 0, TRUE, pSC->m_param.bScaledArith); + } + + if(pSC->WMISCP.sbSubband != SB_NO_HIGHPASS){ + if((pSC->m_param.uQPMode & 4) == 0){ // HP frame uniform quantization + if(allocateQuantizer(pSC->pTile[0].pQuantizerHP, pSC->m_param.cNumChannels, 1) != ICERR_OK) + return ICERR_ERROR; + setUniformQuantizer(pSC, 2); + for(i = 0; i < pSC->m_param.cNumChannels; i ++) + if(pSC->m_param.bTranscode) + pSC->pTile[0].pQuantizerHP[i]->iIndex = pSC->m_param.uiQPIndexHP[i]; + else + pSC->pTile[0].pQuantizerHP[i]->iIndex = pSC->m_param.uiQPIndexHP[i] = (U8)(((i == 0 ? iQPIndexYHP : (i == 1) ? iQPIndexUHP: iQPIndexVHP)) & 0xff); + formatQuantizer(pSC->pTile[0].pQuantizerHP, (pSC->m_param.uQPMode >> 7) & 3, pSC->m_param.cNumChannels, 0, FALSE, pSC->m_param.bScaledArith); + } + } + } + + if(allocatePredInfo(pSC) != ICERR_OK){ + return ICERR_ERROR; + } + + if(pSC->WMISCP.cNumOfSliceMinus1V >= MAX_TILES || AllocateCodingContextEnc (pSC, pSC->WMISCP.cNumOfSliceMinus1V + 1, pSC->WMISCP.uiTrimFlexBits) != ICERR_OK){ + return ICERR_ERROR; + } + + if (pSC->m_bSecondary) { + pSC->pIOHeader = pSC->m_pNextSC->pIOHeader; + pSC->m_ppBitIO = pSC->m_pNextSC->m_ppBitIO; + pSC->cNumBitIO = pSC->m_pNextSC->cNumBitIO; + pSC->cSB = pSC->m_pNextSC->cSB; + pSC->ppWStream = pSC->m_pNextSC->ppWStream; + pSC->pIndexTable = pSC->m_pNextSC->pIndexTable; + setBitIOPointers(pSC); + } + else { + StrIOEncInit(pSC); + setBitIOPointers(pSC); + WriteWMIHeader(pSC); + } + + return ICERR_OK; +} + +static Int StrEncTerm(CTXSTRCODEC ctxSC) +{ + CWMImageStrCodec* pSC = (CWMImageStrCodec*)ctxSC; + size_t j, jend = (pSC->m_pNextSC != NULL); + + for (j = 0; j <= jend; j++) { + if (sizeof(*pSC) != pSC->cbStruct) { + return ICERR_ERROR; + } + + if(pSC->m_bUVResolutionChange){ + if(pSC->pResU != NULL) + free(pSC->pResU); + if(pSC->pResV != NULL) + free(pSC->pResV); + } + + freePredInfo(pSC); + + if (j == 0) + StrIOEncTerm(pSC); + + FreeCodingContextEnc(pSC); + + freeTileInfo(pSC); + + pSC->WMISCP.nExpBias -= 128; // reset + + pSC = pSC->m_pNextSC; + } + + return 0; +} + +U32 setUniformTiling(U32 * pTile, U32 cNumTile, U32 cNumMB) +{ + U32 i, j; + + while((cNumMB + cNumTile - 1) / cNumTile > 65535) // too few tiles + cNumTile ++; + + for(i = cNumTile, j = cNumMB; i > 1; i --){ + pTile[cNumTile - i] = (j + i - 1) / i; + j -= pTile[cNumTile - i]; + } + + return cNumTile; +} + +U32 validateTiling(U32 * pTile, U32 cNumTile, U32 cNumMB) +{ + U32 i, cMBs; + + if(cNumTile == 0) + cNumTile = 1; + if(cNumTile > cNumMB) // too many tiles + cNumTile = 1; + if(cNumTile > MAX_TILES) + cNumTile = MAX_TILES; + + for(i = cMBs = 0; i + 1 < cNumTile; i ++){ + if(pTile[i] == 0 || pTile[i] > 65535){ // invalid tile setting, resetting to uniform tiling + cNumTile = setUniformTiling(pTile, cNumTile, cNumMB); + break; + } + + cMBs += pTile[i]; + + if(cMBs >= cNumMB){ + cNumTile = i + 1; + break; + } + } + + // last tile + if(cNumMB - cMBs > 65536) + cNumTile = setUniformTiling(pTile, cNumTile, cNumMB); + + for(i = 1; i < cNumTile; i ++) + pTile[i] += pTile[i - 1]; + for(i = cNumTile - 1; i > 0; i --) + pTile[i] = pTile[i - 1]; + pTile[0] = 0; + + return cNumTile; +} + +/************************************************************************* + Validate and adjust input params here +*************************************************************************/ +Int ValidateArgs(CWMImageInfo* pII, CWMIStrCodecParam *pSCP) +{ + int i; + Bool bTooNarrowTile = FALSE; + + if(pII->cWidth > (1 << 28) || pII->cHeight > (1 << 28) || pII->cWidth == 0 || pII->cHeight == 0){ + printf("Unsurpported image size!\n"); + return ICERR_ERROR; // unsurpported image size + } + + if (((pSCP->cfColorFormat == YUV_420) || (pSCP->cfColorFormat == YUV_422)) && (pSCP->olOverlap == OL_TWO) && ((Int)(((U32)pII->cWidth + 15) >> 4) < 2)) { + printf("Image width must be at least 2 MB wide for subsampled chroma and two levels of overlap!\n"); + return ICERR_ERROR; + } + + if(pSCP->sbSubband == SB_ISOLATED || pSCP->sbSubband >= SB_MAX) // not allowed + pSCP->sbSubband = SB_ALL; + + if(pII->bdBitDepth == BD_5 && (pII->cfColorFormat != CF_RGB || pII->cBitsPerUnit != 16 || pII->cLeadingPadding != 0)){ + printf("Unsupported BD_5 image format!\n"); + return ICERR_ERROR; // BD_5 must be compact RGB! + } + if(pII->bdBitDepth == BD_565 && (pII->cfColorFormat != CF_RGB || pII->cBitsPerUnit != 16 || pII->cLeadingPadding != 0)){ + printf("Unsupported BD_565 image format!\n"); + return ICERR_ERROR; // BD_5 must be compact RGB! + } + if(pII->bdBitDepth == BD_10 && (pII->cfColorFormat != CF_RGB || pII->cBitsPerUnit != 32 || pII->cLeadingPadding != 0)){ + printf("Unsupported BD_10 image format!\n"); + return ICERR_ERROR; // BD_10 must be compact RGB! + } + + if((pII->bdBitDepth == BD_5 || pII->bdBitDepth == BD_565 || pII->bdBitDepth == BD_10) && + (pSCP->cfColorFormat != YUV_420 && pSCP->cfColorFormat != YUV_422 && pSCP->cfColorFormat != Y_ONLY)) + pSCP->cfColorFormat = YUV_444; + + if(BD_1 == pII->bdBitDepth){ // binary image + if(pII->cfColorFormat != Y_ONLY){ + printf("BD_1 image must be black-and white!\n"); + return ICERR_ERROR; + } + pSCP->cfColorFormat = Y_ONLY; // can only be black white + } + + if(pSCP->bdBitDepth != BD_LONG) + pSCP->bdBitDepth = BD_LONG; // currently only support 32 bit internally + + if(pSCP->uAlphaMode > 1 && (pII->cfColorFormat == YUV_420 || pII->cfColorFormat == YUV_422 + || pII->bdBitDepth == BD_5 || pII->bdBitDepth == BD_10 + || pII->bdBitDepth == BD_1)) + { + printf("Alpha is not supported for this pixel format!\n"); + return ICERR_ERROR; + } + + if((pSCP->cfColorFormat == YUV_420 || pSCP->cfColorFormat == YUV_422) && (pII->bdBitDepth == BD_16F || pII->bdBitDepth == BD_32F || pII->cfColorFormat == CF_RGBE)) + { + printf("Float or RGBE images must be encoded with YUV 444!\n"); + return ICERR_ERROR; + } + + // adjust tiling + pSCP->cNumOfSliceMinus1V = validateTiling(pSCP->uiTileX, pSCP->cNumOfSliceMinus1V + 1, (((U32)pII->cWidth + 15) >> 4)) - 1; + pSCP->cNumOfSliceMinus1H = validateTiling(pSCP->uiTileY, pSCP->cNumOfSliceMinus1H + 1, (((U32)pII->cHeight + 15) >> 4)) - 1; + + if (pSCP->bUseHardTileBoundaries && ((pSCP->cfColorFormat == YUV_420) || (pSCP->cfColorFormat == YUV_422)) && (pSCP->olOverlap == OL_TWO)) { + for (i = 1; i < (int) (pSCP->cNumOfSliceMinus1H + 1); i++) { + if ((Int)(pSCP->uiTileY[i] - pSCP->uiTileY[i - 1]) < 2) { + bTooNarrowTile = TRUE; + break; + } + } + if ((Int)((((U32)pII->cWidth + 15) >> 4) - pSCP->uiTileY[pSCP->cNumOfSliceMinus1H]) < 2) + bTooNarrowTile = TRUE; + } + if (bTooNarrowTile) { + printf("Tile width must be at least 2 MB wide for hard tiles, subsampled chroma, and two levels of overlap!\n"); + return ICERR_ERROR; + } + + if(pSCP->cChannel > MAX_CHANNELS) + return ICERR_ERROR; + + /** supported color transcoding **/ + /** ARGB, RGB => YUV_444, YUV_422, YUV_420, Y_ONLY **/ + /** YUV_444 => YUV_422, YUV_420, Y_ONLY **/ + /** YUV_422 => YUV_420, Y_ONLY **/ + /** YUV_420 => Y_ONLY **/ + + /** unsupported color transcoding **/ + /** Y_ONLY, YUV_420, YUV_422 => YUV_444 **/ + /** Y_ONLY, YUV_420 => YUV_422 **/ + /** Y_ONLY => YUV_420 **/ + if((pII->cfColorFormat == Y_ONLY && pSCP->cfColorFormat != Y_ONLY) || + (pSCP->cfColorFormat == YUV_422 && (pII->cfColorFormat == YUV_420 || pII->cfColorFormat == Y_ONLY)) || + (pSCP->cfColorFormat == YUV_444 && (pII->cfColorFormat == YUV_422 || pII->cfColorFormat == YUV_420 || pII->cfColorFormat == Y_ONLY))){ + pSCP->cfColorFormat = pII->cfColorFormat; // force not to do color transcoding! + } + else if (pII->cfColorFormat == NCOMPONENT) { + pSCP->cfColorFormat = NCOMPONENT; // force not to do color transcoding! + } + if (CMYK == pII->cfColorFormat && pSCP->cfColorFormat == NCOMPONENT) + { + pSCP->cfColorFormat = CMYK; + } + + if(pSCP->cfColorFormat != NCOMPONENT){ + if(pSCP->cfColorFormat == Y_ONLY) + pSCP->cChannel = 1; + else if(pSCP->cfColorFormat == CMYK) + pSCP->cChannel = 4; + else + pSCP->cChannel = 3; + } + + if(pSCP->sbSubband >= SB_MAX) + pSCP->sbSubband = SB_ALL; + + + pII->cChromaCenteringX = 0; + pII->cChromaCenteringY = 0; + + return ICERR_OK; +} + +/************************************************************************* + Initialization of CWMImageStrCodec struct +*************************************************************************/ +static Void InitializeStrEnc(CWMImageStrCodec *pSC, + const CWMImageInfo* pII, const CWMIStrCodecParam *pSCP) +{ + pSC->cbStruct = sizeof(*pSC); + pSC->WMII = *pII; + pSC->WMISCP = *pSCP; + + // set nExpBias + if (pSC->WMISCP.nExpBias == 0) + pSC->WMISCP.nExpBias = 4 + 128;//default + pSC->WMISCP.nExpBias += 128; // rollover arithmetic + + pSC->cRow = 0; + pSC->cColumn = 0; + + pSC->cmbWidth = (pSC->WMII.cWidth + 15) / 16; + pSC->cmbHeight = (pSC->WMII.cHeight + 15) / 16; + + pSC->Load = inputMBRow; + pSC->Quantize = quantizeMacroblock; + pSC->ProcessTopLeft = processMacroblock; + pSC->ProcessTop = processMacroblock; + pSC->ProcessTopRight = processMacroblock; + pSC->ProcessLeft = processMacroblock; + pSC->ProcessCenter = processMacroblock; + pSC->ProcessRight = processMacroblock; + pSC->ProcessBottomLeft = processMacroblock; + pSC->ProcessBottom = processMacroblock; + pSC->ProcessBottomRight = processMacroblock; + + pSC->m_pNextSC = NULL; + pSC->m_bSecondary = FALSE; +} + +/************************************************************************* + Streaming API init +*************************************************************************/ +Int ImageStrEncInit( + CWMImageInfo* pII, + CWMIStrCodecParam *pSCP, + CTXSTRCODEC* pctxSC) +{ + static size_t cbChannels[BD_MAX] = {2, 4}; + + size_t cbChannel = 0, cblkChroma = 0, i; + size_t cbMacBlockStride = 0, cbMacBlockChroma = 0, cMacBlock = 0; + + CWMImageStrCodec* pSC = NULL, *pNextSC = NULL; + char* pb = NULL; + size_t cb = 0; + Bool b32bit = sizeof(size_t) == 4; + + Int err; + + if(ValidateArgs(pII, pSCP) != ICERR_OK){ + goto ErrorExit; + } + + //================================================ + *pctxSC = NULL; + + //================================================ + cbChannel = cbChannels[pSCP->bdBitDepth]; + cblkChroma = cblkChromas[pSCP->cfColorFormat]; + cbMacBlockStride = cbChannel * 16 * 16; + cbMacBlockChroma = cbChannel * 16 * cblkChroma; + cMacBlock = (pII->cWidth + 15) / 16; + + //================================================ + cb = sizeof(*pSC) + (128 - 1) + (PACKETLENGTH * 4 - 1) + (PACKETLENGTH * 2 ) + sizeof(*pSC->pIOHeader); + i = cbMacBlockStride + cbMacBlockChroma * (pSCP->cChannel - 1); + if(b32bit) // integer overlow/underflow check for 32-bit system + if(((cMacBlock >> 15) * i) & 0xffff0000) + return ICERR_ERROR; + i *= cMacBlock * 2; + cb += i; + + pb = malloc(cb); + if (NULL == pb) + { + goto ErrorExit; + } + memset(pb, 0, cb); + + //================================================ + pSC = (CWMImageStrCodec*)pb; pb += sizeof(*pSC); + + // Set up perf timers + PERFTIMER_ONLY(pSC->m_fMeasurePerf = pSCP->fMeasurePerf); + PERFTIMER_NEW(pSC->m_fMeasurePerf, &pSC->m_ptEndToEndPerf); + PERFTIMER_NEW(pSC->m_fMeasurePerf, &pSC->m_ptEncDecPerf); + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEndToEndPerf); + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + PERFTIMER_COPYSTARTTIME(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf, pSC->m_ptEndToEndPerf); + + pSC->m_param.cfColorFormat = pSCP->cfColorFormat; + pSC->m_param.bAlphaChannel = (pSCP->uAlphaMode == 3); + pSC->m_param.cNumChannels = pSCP->cChannel; + pSC->m_param.cExtraPixelsTop = pSC->m_param.cExtraPixelsBottom + = pSC->m_param.cExtraPixelsLeft = pSC->m_param.cExtraPixelsRight = 0; + + pSC->cbChannel = cbChannel; + + pSC->m_param.bTranscode = pSC->bTileExtraction = FALSE; + + //================================================ + InitializeStrEnc(pSC, pII, pSCP); + + //================================================ + // 2 Macro Row buffers for each channel + pb = ALIGNUP(pb, 128); + for (i = 0; i < pSC->m_param.cNumChannels; i++) { + pSC->a0MBbuffer[i] = (PixelI*)pb; pb += cbMacBlockStride * pSC->cmbWidth; + pSC->a1MBbuffer[i] = (PixelI*)pb; pb += cbMacBlockStride * pSC->cmbWidth; + cbMacBlockStride = cbMacBlockChroma; + } + + //================================================ + // lay 2 aligned IO buffers just below pIO struct + pb = (char*)ALIGNUP(pb, PACKETLENGTH * 4) + PACKETLENGTH * 2; + pSC->pIOHeader = (BitIOInfo*)pb; + + //================================================ + err = StrEncInit(pSC); + if (ICERR_OK != err) + goto ErrorExit; + + // if interleaved alpha is needed + if (pSC->m_param.bAlphaChannel) { + cbMacBlockStride = cbChannel * 16 * 16; + // 1. allocate new pNextSC info + //================================================ + cb = sizeof(*pNextSC) + (128 - 1) + cbMacBlockStride * cMacBlock * 2; + pb = malloc(cb); + if (NULL == pb) + { + goto ErrorExit; + } + memset(pb, 0, cb); + //================================================ + pNextSC = (CWMImageStrCodec*)pb; pb += sizeof(*pNextSC); + + // 2. initialize pNextSC + pNextSC->m_param.cfColorFormat = Y_ONLY; + pNextSC->m_param.cNumChannels = 1; + pNextSC->m_param.bAlphaChannel = TRUE; + pNextSC->cbChannel = cbChannel; + //================================================ + + // 3. initialize arrays + InitializeStrEnc(pNextSC, pII, pSCP); + //================================================ + + // 2 Macro Row buffers for each channel + pb = ALIGNUP(pb, 128); + pNextSC->a0MBbuffer[0] = (PixelI*)pb; pb += cbMacBlockStride * pNextSC->cmbWidth; + pNextSC->a1MBbuffer[0] = (PixelI*)pb; pb += cbMacBlockStride * pNextSC->cmbWidth; + //================================================ + pNextSC->pIOHeader = pSC->pIOHeader; + //================================================ + + // 4. link pSC->pNextSC = pNextSC + pNextSC->m_pNextSC = pSC; + pNextSC->m_bSecondary = TRUE; + + // 5. StrEncInit + StrEncInit(pNextSC); + + // 6. Write header of image plane + WriteImagePlaneHeader(pNextSC); + } + + pSC->m_pNextSC = pNextSC; + //================================================ + *pctxSC = (CTXSTRCODEC)pSC; + + writeIndexTableNull(pSC); +#if defined(WMP_OPT_SSE2) || defined(WMP_OPT_CC_ENC) || defined(WMP_OPT_TRFM_ENC) + StrEncOpt(pSC); +#endif // OPT defined + + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + return ICERR_OK; + +ErrorExit: + return ICERR_ERROR; +} + +/************************************************************************* + Streaming API encode +*************************************************************************/ +Int ImageStrEncEncode( + CTXSTRCODEC ctxSC, + const CWMImageBufferInfo* pBI) +{ + CWMImageStrCodec* pSC = (CWMImageStrCodec*)ctxSC; + CWMImageStrCodec* pNextSC = pSC->m_pNextSC; + ImageDataProc ProcessLeft, ProcessCenter, ProcessRight; + + if (sizeof(*pSC) != pSC->cbStruct) + { + return ICERR_ERROR; + } + + //================================ + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + + pSC->WMIBI = *pBI; + pSC->cColumn = 0; + initMRPtr(pSC); + if (pNextSC) + pNextSC->WMIBI = *pBI; + + if (0 == pSC->cRow) { + ProcessLeft = pSC->ProcessTopLeft; + ProcessCenter = pSC->ProcessTop; + ProcessRight = pSC->ProcessTopRight; + } + else { + ProcessLeft = pSC->ProcessLeft; + ProcessCenter = pSC->ProcessCenter; + ProcessRight = pSC->ProcessRight; + } + + if( pSC->Load(pSC) != ICERR_OK ) + return ICERR_ERROR; + if(ProcessLeft(pSC) != ICERR_OK) + return ICERR_ERROR; + advanceMRPtr(pSC); + + //================================ + for (pSC->cColumn = 1; pSC->cColumn < pSC->cmbWidth; ++pSC->cColumn) { + if(ProcessCenter(pSC) != ICERR_OK) + return ICERR_ERROR; + advanceMRPtr(pSC); + } + + //================================ + if(ProcessRight(pSC) != ICERR_OK) + return ICERR_ERROR; + if (pSC->cRow) + advanceOneMBRow(pSC); + + ++pSC->cRow; + swapMRPtr(pSC); + + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + return ICERR_OK; +} + +/************************************************************************* + Streaming API term +*************************************************************************/ +Int ImageStrEncTerm( + CTXSTRCODEC ctxSC) +{ + CWMImageStrCodec* pSC = (CWMImageStrCodec*)ctxSC; + // CWMImageStrCodec *pNextSC = pSC->m_pNextSC; + + if (sizeof(*pSC) != pSC->cbStruct) + { + return ICERR_ERROR; + } + + //================================ + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + pSC->cColumn = 0; + initMRPtr(pSC); + + pSC->ProcessBottomLeft(pSC); + advanceMRPtr(pSC); + + //================================ + for (pSC->cColumn = 1; pSC->cColumn < pSC->cmbWidth; ++pSC->cColumn) { + pSC->ProcessBottom(pSC); + advanceMRPtr(pSC); + } + + //================================ + pSC->ProcessBottomRight(pSC); + + //================================ + StrEncTerm(pSC); + + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEndToEndPerf); + PERFTIMER_REPORT(pSC->m_fMeasurePerf, pSC); + PERFTIMER_DELETE(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + PERFTIMER_DELETE(pSC->m_fMeasurePerf, pSC->m_ptEndToEndPerf); + + free(pSC); + return ICERR_OK; +} + +// centralized UV downsampling +#define DF_ODD ((((d1 + d2 + d3) << 2) + (d2 << 1) + d0 + d4 + 8) >> 4) +Void downsampleUV(CWMImageStrCodec * pSC) +{ + const COLORFORMAT cfInt = pSC->m_param.cfColorFormat; + const COLORFORMAT cfExt = pSC->WMII.cfColorFormat; + PixelI * pSrc, * pDst; + PixelI d0, d1, d2, d3, d4; + size_t iChannel, iRow, iColumn; + + for(iChannel = 1; iChannel < 3; iChannel ++){ + if(cfExt != YUV_422){ // need to do horizontal downsampling, 444 => 422 + const size_t cShift = (cfInt == YUV_422 ? 1 : 0); + + pSrc = (iChannel == 1 ? pSC->pResU : pSC->pResV); + pDst = (cfInt == YUV_422 ? pSC->p1MBbuffer[iChannel] : pSrc); + + for(iRow = 0; iRow < 16; iRow ++){ + d0 = d4 = pSrc[idxCC[iRow][2]], d1 = d3 = pSrc[idxCC[iRow][1]], d2 = pSrc[idxCC[iRow][0]]; // left boundary + + for(iColumn = 0; iColumn + 2 < pSC->cmbWidth * 16; iColumn += 2){ + pDst[((iColumn >> 4) << (8 - cShift)) + idxCC[iRow][(iColumn & 15) >> cShift]] = DF_ODD; + d0 = d2, d1 = d3, d2 = d4; + d3 = pSrc[(((iColumn + 3) >> 4) << 8) + idxCC[iRow][(iColumn + 3) & 0xf]]; + d4 = pSrc[(((iColumn + 4) >> 4) << 8) + idxCC[iRow][(iColumn + 4) & 0xf]]; + } + + d4 = d2; // right boundary + pDst[((iColumn >> 4) << (8 - cShift)) + idxCC[iRow][(iColumn & 15) >> cShift]] = DF_ODD; + } + } + + if(cfInt == YUV_420){ // need to do vertical downsampling + const size_t cShift = (cfExt == YUV_422 ? 0 : 1); + PixelI * pBuf[4]; + size_t mbOff, pxOff; + + pDst = pSC->p1MBbuffer[iChannel]; + pSrc = (iChannel == 1 ? pSC->pResU : pSC->pResV); + pBuf[0] = pSrc + (pSC->cmbWidth << (cfExt == YUV_422 ? 7 : 8)); + pBuf[1] = pBuf[0] + pSC->cmbWidth * 8, pBuf[2] = pBuf[1] + pSC->cmbWidth * 8, pBuf[3] = pBuf[2] + pSC->cmbWidth * 8; + + for(iColumn = 0; iColumn < pSC->cmbWidth * 8; iColumn ++){ + mbOff = (iColumn >> 3) << (7 + cShift); + pxOff = (iColumn & 7) << cShift; + + if(pSC->cRow == 0) // top image boundary + d0 = d4 = pSrc[mbOff + idxCC[2][pxOff]], d1 = d3 = pSrc[mbOff + idxCC[1][pxOff]], d2 = pSrc[mbOff + idxCC[0][pxOff]]; // top MB boundary + else{ + // last row of previous MB row + d0 = pBuf[0][iColumn], d1 = pBuf[1][iColumn], d2 = pBuf[2][iColumn], d3 = pBuf[3][iColumn], d4 = pSrc[mbOff + idxCC[0][pxOff]]; + pSC->p0MBbuffer[iChannel][((iColumn >> 3) << 6) + idxCC_420[7][iColumn & 7]] = DF_ODD; + + // for first row of current MB + d0 = pBuf[2][iColumn], d1 = pBuf[3][iColumn]; + d2 = pSrc[mbOff + idxCC[0][pxOff]], d3 = pSrc[mbOff + idxCC[1][pxOff]], d4 = pSrc[mbOff + idxCC[2][pxOff]]; + } + + for(iRow = 0; iRow < 12; iRow += 2){ + pDst[((iColumn >> 3) << 6) + idxCC_420[iRow >> 1][iColumn & 7]] = DF_ODD; + d0 = d2, d1 = d3, d2 = d4; + d3 = pSrc[mbOff + idxCC[iRow + 3][pxOff]]; + d4 = pSrc[mbOff + idxCC[iRow + 4][pxOff]]; + } + + //last row of current MB + pDst[((iColumn >> 3) << 6) + idxCC_420[6][iColumn & 7]] = DF_ODD; + d0 = d2, d1 = d3, d2 = d4; + d3 = pSrc[mbOff + idxCC[iRow + 3][pxOff]]; + + if(pSC->cRow + 1 == pSC->cmbHeight){ // bottom image boundary + d4 = d2; + pDst[((iColumn >> 3) << 6) + idxCC_420[7][iColumn & 7]] = DF_ODD; + } + else{ + for(iRow = 0; iRow < 4; iRow ++) + pBuf[iRow][iColumn] = pSrc[mbOff + idxCC[iRow + 12][pxOff]]; + } + } + } + } +} + +// centralized horizontal padding +Void padHorizontally(CWMImageStrCodec * pSC) +{ + if(pSC->WMII.cWidth != pSC->cmbWidth * 16){ // horizontal padding is necessary! + const COLORFORMAT cfExt = pSC->WMISCP.bYUVData ? + pSC->m_param.cfColorFormat : pSC->WMII.cfColorFormat; + size_t cFullChannel = pSC->WMISCP.cChannel; + size_t iLast = pSC->WMII.cWidth - 1; + PixelI * pCh[16]; + size_t iChannel, iColumn, iRow; + + if(cfExt == YUV_420 || cfExt == YUV_422 || cfExt == Y_ONLY) + cFullChannel = 1; + + assert(cFullChannel <= 16); + + assert(pSC->WMISCP.cChannel <= 16); + for(iChannel = 0; iChannel < pSC->WMISCP.cChannel; iChannel ++) + pCh[iChannel & 15] = pSC->p1MBbuffer[iChannel & 15]; + + if(pSC->m_bUVResolutionChange) + pCh[1] = pSC->pResU, pCh[2] = pSC->pResV; + + // pad full resoluton channels + for(iRow = 0; iRow < 16; iRow ++){ + const size_t iPosLast = ((iLast >> 4) << 8) + idxCC[iRow][iLast & 0xf]; + for(iColumn = iLast + 1; iColumn < pSC->cmbWidth * 16; iColumn ++){ + const size_t iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + for(iChannel = 0; iChannel < cFullChannel; iChannel ++) + pCh[iChannel & 15][iPos] = pCh[iChannel & 15][iPosLast]; + } + } + + if(cfExt == YUV_422) // pad YUV_422 UV + for(iLast >>= 1, iRow = 0; iRow < 16; iRow ++){ + const size_t iPosLast = ((iLast >> 3) << 7) + idxCC[iRow][iLast & 7]; + for(iColumn = iLast + 1; iColumn < pSC->cmbWidth * 8; iColumn ++){ + const size_t iPos = ((iColumn >> 3) << 7) + idxCC[iRow][iColumn & 7]; + for(iChannel = 1; iChannel < 3; iChannel ++) + pCh[iChannel][iPos] = pCh[iChannel][iPosLast]; + } + } + else if(cfExt == YUV_420) // pad YUV_420 UV + for(iLast >>= 1, iRow = 0; iRow < 8; iRow ++){ + const size_t iPosLast = ((iLast >> 3) << 6) + idxCC_420[iRow][iLast & 7]; + for(iColumn = iLast + 1; iColumn < pSC->cmbWidth * 8; iColumn ++){ + const size_t iPos = ((iColumn >> 3) << 6) + idxCC_420[iRow][iColumn & 7]; + for(iChannel = 1; iChannel < 3; iChannel ++) + pCh[iChannel][iPos] = pCh[iChannel][iPosLast]; + } + } + } +} + +// centralized alpha channel color conversion, small perf penalty +Int inputMBRowAlpha(CWMImageStrCodec* pSC) +{ + if(pSC->m_bSecondary == FALSE && pSC->m_pNextSC != NULL){ // alpha channel is present + const size_t cShift = (pSC->m_pNextSC->m_param.bScaledArith ? (SHIFTZERO + QPFRACBITS) : 0); + const BITDEPTH_BITS bdExt = pSC->WMII.bdBitDepth; + const size_t iAlphaPos = pSC->WMII.cLeadingPadding + (pSC->WMII.cfColorFormat == CMYK ? 4 : 3);//only RGB and CMYK may have interleaved alpha + const size_t cRow = pSC->WMIBI.cLine; + const size_t cColumn = pSC->WMII.cWidth; + const U8 * pSrc0 = (U8 *)pSC->WMIBI.pv; + PixelI * pA = pSC->m_pNextSC->p1MBbuffer[0]; + size_t iRow, iColumn; + + for(iRow = 0; iRow < 16; iRow ++){ + if(bdExt == BD_8){ + const size_t cStride = (pSC->WMII.cBitsPerUnit >> 3); + const U8 * pSrc = pSrc0; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride) + pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] = ((PixelI)pSrc[iAlphaPos] - (1 << 7)) << cShift; + } + else if(bdExt == BD_16){ + const size_t cStride = (pSC->WMII.cBitsPerUnit >> 3) / sizeof(U16); + const U8 nLenMantissaOrShift = pSC->m_pNextSC->WMISCP.nLenMantissaOrShift; + const U16 * pSrc = (U16 *)pSrc0; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride) + pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] = ((((PixelI)pSrc[iAlphaPos] - (1 << 15)) >> nLenMantissaOrShift) << cShift); + } + else if(bdExt == BD_16S){ + const size_t cStride = (pSC->WMII.cBitsPerUnit >> 3) / sizeof(I16); + const U8 nLenMantissaOrShift = pSC->m_pNextSC->WMISCP.nLenMantissaOrShift; + const I16 * pSrc = (I16 *)pSrc0; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride) + pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] = (((PixelI)pSrc[iAlphaPos] >> nLenMantissaOrShift) << cShift); + } + else if(bdExt == BD_16F){ + const size_t cStride = (pSC->WMII.cBitsPerUnit >> 3) / sizeof(U16); + const I16 * pSrc = (I16 *)pSrc0; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride) + pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] = forwardHalf (pSrc[iAlphaPos]) << cShift; + } + else if(bdExt == BD_32S){ + const size_t cStride = (pSC->WMII.cBitsPerUnit >> 3) / sizeof(I32); + const U8 nLenMantissaOrShift = pSC->m_pNextSC->WMISCP.nLenMantissaOrShift; + const I32 * pSrc = (I32 *)pSrc0; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride) + pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] = (((PixelI)pSrc[iAlphaPos] >> nLenMantissaOrShift) << cShift); + } + else if(bdExt == BD_32F){ + const size_t cStride = (pSC->WMII.cBitsPerUnit >> 3) / sizeof(float); + const U8 nLen = pSC->m_pNextSC->WMISCP.nLenMantissaOrShift; + const I8 nExpBias = pSC->m_pNextSC->WMISCP.nExpBias; + const float * pSrc = (float *)pSrc0; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride) + pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] = float2pixel (pSrc[iAlphaPos], nExpBias, nLen) << cShift; + } + else // not supported + return ICERR_ERROR; + + if(iRow + 1 < cRow) // vertical padding! + pSrc0 += pSC->WMIBI.cbStride; + + for(iColumn = cColumn; iColumn < pSC->cmbWidth * 16; iColumn ++) // horizontal padding + pA[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] = pA[(((cColumn - 1) >> 4) << 8) + idxCC[iRow][(cColumn - 1) & 0xf]]; + } + } + + return ICERR_OK; +} + +// input one MB row of image data from input buffer +Int inputMBRow(CWMImageStrCodec* pSC) +{ + const size_t cShift = (pSC->m_param.bScaledArith ? (SHIFTZERO + QPFRACBITS) : 0); + const BITDEPTH_BITS bdExt = pSC->WMII.bdBitDepth; + COLORFORMAT cfExt = pSC->WMII.cfColorFormat; + const COLORFORMAT cfInt = pSC->m_param.cfColorFormat; + const size_t cPixelStride = (pSC->WMII.cBitsPerUnit >> 3); + const size_t iRowStride = + (cfExt == YUV_420 || (pSC->WMISCP.bYUVData && pSC->m_param.cfColorFormat==YUV_420)) ? 2 : 1; + const size_t cRow = pSC->WMIBI.cLine; + const size_t cColumn = pSC->WMII.cWidth; + const size_t iB = (pSC->WMII.bRGB ? 2 : 0); + const size_t iR = 2 - iB; + const U8 * pSrc0 = (U8 *)pSC->WMIBI.pv; + const U8 nLen = pSC->WMISCP.nLenMantissaOrShift; + const I8 nExpBias = pSC->WMISCP.nExpBias; + + PixelI *pY = pSC->p1MBbuffer[0], *pU = pSC->p1MBbuffer[1], *pV = pSC->p1MBbuffer[2]; + size_t iRow, iColumn, iPos; + + // guard input buffer + if(checkImageBuffer(pSC, cColumn, cRow) != ICERR_OK) + return ICERR_ERROR; + + if(pSC->m_bUVResolutionChange) // will do downsampling somewhere else! + pU = pSC->pResU, pV = pSC->pResV; + else if(cfInt == Y_ONLY) // xxx to Y_ONLY transcoding! + pU = pV = pY; // write pY AFTER pU and pV so Y will overwrite U&V + + for(iRow = 0; iRow < 16; iRow += iRowStride){ + if (pSC->WMISCP.bYUVData){ + I32 * pSrc = (I32 *)pSrc0 + pSC->WMII.cLeadingPadding; + + switch(pSC->m_param.cfColorFormat){ + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + { + const size_t cChannel = pSC->m_param.cNumChannels; + PixelI * pChannel[16]; + size_t iChannel; + + assert(cChannel <= 16); + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pChannel[iChannel & 15] = pSC->p1MBbuffer[iChannel & 15]; + if(pSC->m_bUVResolutionChange) + pChannel[1] = pSC->pResU, pChannel[2] = pSC->pResV; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cChannel){ + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pChannel[iChannel & 15][iPos] = (PixelI)pSrc[iChannel & 15]; + } + } + break; + + case YUV_422: + for(iColumn = 0; iColumn < cColumn; iColumn += 2, pSrc += 4){ + if(cfInt != Y_ONLY){ + iPos = ((iColumn >> 4) << 7) + idxCC[iRow][(iColumn >> 1) & 7]; + pU[iPos] = (PixelI)pSrc[0]; + pV[iPos] = (PixelI)pSrc[2]; + } + + pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] = (PixelI)pSrc[1]; + pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]] = (PixelI)pSrc[3]; + } + break; + + case YUV_420: + for(iColumn = 0; iColumn < cColumn; iColumn += 2, pSrc += 6){ + if(cfInt != Y_ONLY){ + iPos = ((iColumn >> 4) << 6) + idxCC_420[iRow >> 1][(iColumn >> 1) & 7]; + pU[iPos] = (PixelI)pSrc[4]; + pV[iPos] = (PixelI)pSrc[5]; + } + + pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] = (PixelI)pSrc[0]; + pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]] = (PixelI)pSrc[1]; + pY[((iColumn >> 4) << 8) + idxCC[iRow + 1][iColumn & 15]] = (PixelI)pSrc[2]; + pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow + 1][(iColumn + 1) & 15]] = (PixelI)pSrc[3]; + } + break; + + default: + assert(0); + break; + } + } + else if(bdExt == BD_8){ + const U8 * pSrc = pSrc0 + pSC->WMII.cLeadingPadding; + const PixelI iOffset = (128 << cShift); + + switch(cfExt){ + case CF_RGB: + assert (pSC->m_bSecondary == FALSE); + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cPixelStride){ + PixelI r = ((PixelI)pSrc[iR]) << cShift, g = ((PixelI)pSrc[1]) << cShift, b = ((PixelI)pSrc[iB]) << cShift; + + _CC(r, g, b); // color conversion + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g - iOffset; + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + { + const size_t cChannel = pSC->m_param.cNumChannels; + PixelI * pChannel[16]; + size_t iChannel; + + assert(cChannel <= 16); + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pChannel[iChannel & 15] = pSC->p1MBbuffer[iChannel & 15]; + if(pSC->m_bUVResolutionChange) + pChannel[1] = pSC->pResU, pChannel[2] = pSC->pResV; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cPixelStride){ + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pChannel[iChannel & 15][iPos] = (((PixelI)pSrc[iChannel & 15]) << cShift) - iOffset; + } + break; + } + + case CF_RGBE: + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cPixelStride){ + PixelI iExp = (PixelI)pSrc[3]; + PixelI r = forwardRGBE (pSrc[0], iExp) << cShift; + PixelI g = forwardRGBE (pSrc[1], iExp) << cShift; + PixelI b = forwardRGBE (pSrc[2], iExp) << cShift; + + _CC(r, g, b); + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g; + } + break; + + case CMYK: + { + PixelI * pK = (cfInt == CMYK ? pSC->p1MBbuffer[3] : pY); // CMYK -> YUV_xxx transcoding! + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cPixelStride){ + PixelI c = ((PixelI)pSrc[0]) << cShift; + PixelI m = ((PixelI)pSrc[1]) << cShift; + PixelI y = ((PixelI)pSrc[2]) << cShift; + PixelI k = ((PixelI)pSrc[3]) << cShift; + + _CC_CMYK(c, m, y, k); + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = c, pV[iPos] = -y, pK[iPos] = k, pY[iPos] = iOffset - m; + } + break; + } + + case YUV_422: + for(iColumn = 0; iColumn < cColumn; iColumn += 2, pSrc += cPixelStride){ + if(cfInt != Y_ONLY){ + iPos = ((iColumn >> 4) << 7) + idxCC[iRow][(iColumn >> 1) & 7]; + pU[iPos] = (((PixelI)pSrc[0]) << cShift) - iOffset; + pV[iPos] = (((PixelI)pSrc[2]) << cShift) - iOffset; + } + + pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] = (((PixelI)pSrc[1]) << cShift) - iOffset; + pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]] = (((PixelI)pSrc[3]) << cShift) - iOffset; + } + break; + + case YUV_420: + for(iColumn = 0; iColumn < cColumn; iColumn += 2, pSrc += cPixelStride){ + if(cfInt != Y_ONLY){ + iPos = ((iColumn >> 4) << 6) + idxCC_420[iRow >> 1][(iColumn >> 1) & 7]; + pU[iPos] = (((PixelI)pSrc[4]) << cShift) - iOffset; + pV[iPos] = (((PixelI)pSrc[5]) << cShift) - iOffset; + } + + pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] = (((PixelI)pSrc[0]) << cShift) - iOffset; + pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]] = (((PixelI)pSrc[1]) << cShift) - iOffset; + pY[((iColumn >> 4) << 8) + idxCC[iRow + 1][iColumn & 15]] = (((PixelI)pSrc[2]) << cShift) - iOffset; + pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow + 1][(iColumn + 1) & 15]] = (((PixelI)pSrc[3]) << cShift) - iOffset; + } + break; + + default: + assert(0); + break; + } + } + else if(bdExt == BD_16){ + const U16 * pSrc = (U16 *)pSrc0 + pSC->WMII.cLeadingPadding; + const size_t cStride = cPixelStride / sizeof(U16); + const PixelI iOffset = ((1 << 15) >> nLen) << cShift; + + switch(cfExt){ + case CF_RGB: + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + PixelI r = ((PixelI)pSrc[0] >> nLen) << cShift, g = ((PixelI)pSrc[1] >> nLen) << cShift, b = ((PixelI)pSrc[2] >> nLen) << cShift; + + _CC(r, g, b); // color conversion + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g - iOffset; + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + { + const size_t cChannel = pSC->WMISCP.cChannel; + size_t iChannel; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pSC->p1MBbuffer[iChannel][iPos] = (((PixelI)pSrc[iChannel] >> nLen) << cShift) - iOffset; + } + break; + } + + case CMYK: + { + PixelI * pK = (cfInt == CMYK ? pSC->p1MBbuffer[3] : pY); // CMYK -> YUV_xxx transcoding! + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + PixelI c = ((PixelI)pSrc[0] >> nLen) << cShift; + PixelI m = ((PixelI)pSrc[1] >> nLen) << cShift; + PixelI y = ((PixelI)pSrc[2] >> nLen) << cShift; + PixelI k = ((PixelI)pSrc[3] >> nLen) << cShift; + + _CC_CMYK(c, m, y, k); + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = c, pV[iPos] = -y, pK[iPos] = k, pY[iPos] = iOffset - m; + } + break; + } + + case YUV_422: + for(iColumn = 0; iColumn < cColumn; iColumn += 2, pSrc += cStride){ + if(cfInt != Y_ONLY){ + iPos = ((iColumn >> 4) << 7) + idxCC[iRow][(iColumn >> 1) & 7]; + pU[iPos] = (((PixelI)pSrc[0]) << cShift) - iOffset; + pV[iPos] = (((PixelI)pSrc[2]) << cShift) - iOffset; + } + + pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] = (((PixelI)pSrc[1]) << cShift) - iOffset; + pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]] = (((PixelI)pSrc[3]) << cShift) - iOffset; + } + break; + + case YUV_420: + for(iColumn = 0; iColumn < cColumn; iColumn += 2, pSrc += cStride){ + if(cfInt != Y_ONLY){ + iPos = ((iColumn >> 4) << 6) + idxCC_420[iRow >> 1][(iColumn >> 1) & 7]; + pU[iPos] = (((PixelI)pSrc[4]) << cShift) - iOffset; + pV[iPos] = (((PixelI)pSrc[5]) << cShift) - iOffset; + } + + pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 15]] = (((PixelI)pSrc[0]) << cShift) - iOffset; + pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow][(iColumn + 1) & 15]] = (((PixelI)pSrc[1]) << cShift) - iOffset; + pY[((iColumn >> 4) << 8) + idxCC[iRow + 1][iColumn & 15]] = (((PixelI)pSrc[2]) << cShift) - iOffset; + pY[(((iColumn + 1) >> 4) << 8) + idxCC[iRow + 1][(iColumn + 1) & 15]] = (((PixelI)pSrc[3]) << cShift) - iOffset; + } + break; + + default: + assert(0); + break; + } + } + else if(bdExt == BD_16S){ + const I16 * pSrc = (I16 *)pSrc0 + pSC->WMII.cLeadingPadding; + const size_t cStride = cPixelStride / sizeof(I16); + + switch(cfExt){ + case CF_RGB: + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + PixelI r = ((PixelI)pSrc[0] >> nLen) << cShift, g = ((PixelI)pSrc[1] >> nLen) << cShift, b = ((PixelI)pSrc[2] >> nLen) << cShift; + + _CC(r, g, b); // color conversion + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g; + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + { + const size_t cChannel = pSC->WMISCP.cChannel; + size_t iChannel; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pSC->p1MBbuffer[iChannel][iPos] = (((PixelI)pSrc[iChannel] >> nLen) << cShift); + } + } + break; + + case CMYK: + { + PixelI * pK = (cfInt == CMYK ? pSC->p1MBbuffer[3] : pY); // CMYK -> YUV_xxx transcoding! + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + PixelI c = ((PixelI)pSrc[0] >> nLen) << cShift; + PixelI m = ((PixelI)pSrc[1] >> nLen) << cShift; + PixelI y = ((PixelI)pSrc[2] >> nLen) << cShift; + PixelI k = ((PixelI)pSrc[3] >> nLen) << cShift; + + _CC_CMYK(c, m, y, k); + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = c, pV[iPos] = -y, pK[iPos] = k, pY[iPos] = -m; + } + } + break; + + default: + assert(0); + break; + } + } + else if(bdExt == BD_16F){ + const I16 * pSrc = (I16 *)pSrc0 + pSC->WMII.cLeadingPadding; + const size_t cStride = cPixelStride / sizeof(U16); + + switch(cfExt){ + case CF_RGB: + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + PixelI r = forwardHalf (pSrc[0]) << cShift; + PixelI g = forwardHalf (pSrc[1]) << cShift; + PixelI b = forwardHalf (pSrc[2]) << cShift; + + _CC(r, g, b); // color conversion + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g; + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + { + const size_t cChannel = pSC->WMISCP.cChannel; // check xxx => Y_ONLY transcoding! + size_t iChannel; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pSC->p1MBbuffer[iChannel][iPos] = forwardHalf (pSrc[iChannel]) << cShift; + } + } + break; + + default: + assert(0); + break; + } + } + else if(bdExt == BD_32){ + const U32 * pSrc = (U32 *)pSrc0 + pSC->WMII.cLeadingPadding; + const size_t cStride = cPixelStride / sizeof(U32); + const PixelI iOffset = ((1 << 31) >> nLen) << cShift; + + switch(cfExt){ + case CF_RGB: + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + PixelI r = (pSrc[0] >> nLen) << cShift, g = (pSrc[1] >> nLen) << cShift, b = (pSrc[2] >> nLen) << cShift; + + _CC(r, g, b); // color conversion + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g - iOffset; + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + { + const size_t cChannel = pSC->WMISCP.cChannel; + size_t iChannel; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pSC->p1MBbuffer[iChannel][iPos] = (pSrc[iChannel] >> nLen) << cShift; + } + break; + } + + default: + assert(0); + break; + } + } + else if(bdExt == BD_32S){ + const I32 * pSrc = (I32 *)pSrc0 + pSC->WMII.cLeadingPadding; + const size_t cStride = cPixelStride / sizeof(I32); + + switch(cfExt){ + case CF_RGB: + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + PixelI r = (pSrc[0] >> nLen)<< cShift, g = (pSrc[1] >> nLen)<< cShift, b = (pSrc[2] >> nLen)<< cShift; + + _CC(r, g, b); // color conversion + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g; + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + { + const size_t cChannel = pSC->WMISCP.cChannel; // check xxx => Y_ONLY transcoding! + size_t iChannel; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pSC->p1MBbuffer[iChannel][iPos] = (pSrc[iChannel] >> nLen) << cShift; + } + } + break; + + default: + assert(0); + break; + } + } + else if(bdExt == BD_32F){ + const float * pSrc = (float *)pSrc0 + pSC->WMII.cLeadingPadding; + const size_t cStride = cPixelStride / sizeof(float); + + switch(cfExt){ + case CF_RGB: + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + PixelI r = float2pixel (pSrc[0], nExpBias, nLen) << cShift; + PixelI g = float2pixel (pSrc[1], nExpBias, nLen) << cShift; + PixelI b = float2pixel (pSrc[2], nExpBias, nLen) << cShift; + + _CC(r, g, b); // color conversion + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g; + } + break; + + case Y_ONLY: + case YUV_444: + case NCOMPONENT: + { + const size_t cChannel = pSC->WMISCP.cChannel; + size_t iChannel; + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cStride){ + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + for(iChannel = 0; iChannel < cChannel; iChannel ++) + pSC->p1MBbuffer[iChannel][iPos] = float2pixel (pSrc[iChannel], nExpBias, nLen) << cShift; + } + } + break; + default: + assert(0); + break; + } + } + else if(bdExt == BD_5){ // RGB 555, work for both big endian and small endian! + const U8 * pSrc = pSrc0; + const PixelI iOffset = (16 << cShift); + + assert(cfExt == CF_RGB); + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cPixelStride){ + PixelI r = (PixelI)pSrc[0], g = (PixelI)pSrc[1], b = ((g >> 2) & 0x1F) << cShift; + + g = ((r >> 5) + ((g & 3) << 3)) << cShift, r = (r & 0x1F) << cShift; + + _CC(r, g, b); // color conversion + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g - iOffset; + } + } + else if(bdExt == BD_565){ // RGB 555, work for both big endian and small endian! + const U8 * pSrc = pSrc0; + const PixelI iOffset = (32 << cShift); + + assert(cfExt == CF_RGB); + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cPixelStride){ + PixelI r = (PixelI)pSrc[0], g = (PixelI)pSrc[1], b = (g >> 3) << (cShift + 1); + + g = ((r >> 5) + ((g & 7) << 3)) << cShift, r = (r & 0x1F) << (cShift + 1); + + _CC(r, g, b); // color conversion + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g - iOffset; + } + } + else if(bdExt == BD_10){ //RGB 101010, work for both big endian and small endian! + const U8 * pSrc = pSrc0; + const PixelI iOffset = (512 << cShift); + + assert(cfExt == CF_RGB); + + for(iColumn = 0; iColumn < cColumn; iColumn ++, pSrc += cPixelStride){ + PixelI r = (PixelI)pSrc[0], g = (PixelI)pSrc[1], b = (PixelI)pSrc[2]; + + r = (r + ((g & 3) << 8)) << cShift, g = ((g >> 2) + ((b & 0xF) << 6)) << cShift; + b = ((b >> 4) + (((PixelI)pSrc[3] & 0x3F) << 4)) << cShift; + + _CC(r, g, b); // color conversion + + iPos = ((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]; + pU[iPos] = -r, pV[iPos] = b, pY[iPos] = g - iOffset; + } + } + else if(bdExt == BD_1){ + assert(cfExt == Y_ONLY); + for(iColumn = 0; iColumn < cColumn; iColumn ++) { + pY[((iColumn >> 4) << 8) + idxCC[iRow][iColumn & 0xf]] = ((pSC->WMISCP.bBlackWhite + (pSrc0[iColumn >> 3] >> (7 - (iColumn & 7)))) & 1) << cShift; + } + } + + if(iRow + iRowStride < cRow) // centralized vertical padding! + pSrc0 += pSC->WMIBI.cbStride; + } + + padHorizontally(pSC); // centralized horizontal padding + + // centralized down-sampling + if(pSC->m_bUVResolutionChange) + downsampleUV(pSC); + + // centralized alpha channel handdling + if (pSC->WMISCP.uAlphaMode == 3) + if(inputMBRowAlpha(pSC) != ICERR_OK) + return ICERR_ERROR; + + return ICERR_OK; +} + + diff --git a/libs/jxr/image/sys/adapthuff.c b/libs/jxr/image/sys/adapthuff.c new file mode 100644 index 00000000000..2fabc8ce9b9 --- /dev/null +++ b/libs/jxr/image/sys/adapthuff.c @@ -0,0 +1,511 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strcodec.h" + +#ifdef MEM_TRACE +#define TRACE_MALLOC 1 +#define TRACE_NEW 0 +#define TRACE_HEAP 0 +#include "memtrace.h" +#endif + +// Huffman lookup tables +static const short g4HuffLookupTable[40] = { + 19,19,19,19,27,27,27,27,10,10,10,10,10,10,10,10, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0 }; + +static const short g5HuffLookupTable[2][42] = {{ + 28,28,36,36,19,19,19,19,10,10,10,10,10,10,10,10, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0 }, + { + 11,11,11,11,19,19,19,19,27,27,27,27,35,35,35,35, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0 }}; + +static const short g6HuffLookupTable[4][44] = {{ + 13,29,44,44,19,19,19,19,34,34,34,34,34,34,34,34, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0 }, + { + 12,12,28,28,43,43,43,43,2,2,2,2,2,2,2,2, + 18,18,18,18,18,18,18,18,34,34,34,34,34,34,34,34, + 0,0,0,0,0,0,0,0,0,0,0,0 }, + { + 4,4,12,12,43,43,43,43,18,18,18,18,18,18,18,18, + 26,26,26,26,26,26,26,26,34,34,34,34,34,34,34,34, + 0,0,0,0,0,0,0,0,0,0,0,0 }, + { + 5,13,36,36,43,43,43,43,18,18,18,18,18,18,18,18, + 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, + 0,0,0,0,0,0,0,0,0,0,0,0 }}; + +static const short g7HuffLookupTable[2][46] = {{ + 45,53,36,36,27,27,27,27,2,2,2,2,2,2,2,2, + 10,10,10,10,10,10,10,10,18,18,18,18,18,18,18,18, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, + { + -32736,37,28,28,19,19,19,19,10,10,10,10,10,10,10,10, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 5,6,0,0,0,0,0,0,0,0,0,0,0,0 }}; + +static const short g8HuffLookupTable[2][48] = {{ + 53,21,28,28,11,11,11,11,43,43,43,43,59,59,59,59, + 2,2,2,2,2,2,2,2,34,34,34,34,34,34,34,34, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, + { + 52,52,20,20,3,3,3,3,11,11,11,11,27,27,27,27, + 35,35,35,35,43,43,43,43,58,58,58,58,58,58,58,58, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}; + +static const short g9HuffLookupTable[2][50] = {{ + 13,29,37,61,20,20,68,68,3,3,3,3,51,51,51,51, + 41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0 }, + { + -32736,53,28,28,11,11,11,11,19,19,19,19,43,43,43,43, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + -32734,4,7,8,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0 }}; + +static const short g12HuffLookupTable[5][56] = {{ + -32736,5,76,76,37,53,69,85,43,43,43,43,91,91,91,91, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + -32734,1,2,3,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0 }, + { + -32736,85,13,53,4,4,36,36,43,43,43,43,67,67,67,67, + 75,75,75,75,91,91,91,91,58,58,58,58,58,58,58,58, + 2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0 }, + { + -32736,37,92,92,11,11,11,11,43,43,43,43,59,59,59,59, + 67,67,67,67,75,75,75,75,2,2,2,2,2,2,2,2, + -32734,-32732,2,3,6,10,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0 }, + { + -32736,29,37,69,3,3,3,3,43,43,43,43,59,59,59,59, + 75,75,75,75,91,91,91,91,10,10,10,10,10,10,10,10, + -32734,10,2,6,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0 }, + { + -32736,93,28,28,60,60,76,76,3,3,3,3,43,43,43,43, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + -32734,-32732,-32730,2,4,8,6,10,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0 }}; + +/********************************************************************** + Allocation and dellocation +**********************************************************************/ +Void Clean (CAdaptiveHuffman *pAdHuff) +{ + if (pAdHuff == NULL) + return; + free (pAdHuff); +} + +CAdaptiveHuffman *Allocate (Int iNSymbols, CODINGMODE cm) +{ + CAdaptiveHuffman *pAdHuff = (CAdaptiveHuffman *) malloc (sizeof (CAdaptiveHuffman)); + + UNREFERENCED_PARAMETER(cm); + + if (pAdHuff == NULL) + return NULL; + if (iNSymbols > 255 || iNSymbols <= 0) + goto ErrorExit; + + memset (pAdHuff, 0, sizeof (CAdaptiveHuffman)); + pAdHuff->m_iNSymbols = iNSymbols; + + pAdHuff->m_pDelta = NULL; + pAdHuff->m_iDiscriminant = pAdHuff->m_iUpperBound = pAdHuff->m_iLowerBound = 0; + + return pAdHuff; + +ErrorExit: + Clean (pAdHuff); + return NULL; +} + +/********************************************************************** + Adapt Huffman table +**********************************************************************/ +// Alphabet size = 4 +static const Int g_Index4Table[] = { + 1,2,3,3 +}; +static const Int g4CodeTable[] = { + 4, + 1, 1, + 1, 2, + 0, 3, + 1, 3 +}; + +// Alphabet size = 5 +static const Int g_Index5Table[] = { + 1,2,3,4,4, + 1,3,3,3,3 +}; +static const Int g5CodeTable[] = { + 5, + 1, 1, + 1, 2, + 1, 3, + 0, 4, + 1, 4, + + 5, + 1, 1, + 0, 3, + 1, 3, + 2, 3, + 3, 3, +}; +static const Int g5DeltaTable[] = { 0,-1,0,1,1 }; + +// Alphabet size = 6 +static const Int g_Index6Table[] = { + 1,5,3,5,2,4, + 2,4,2,4,2,3, + 4,4,2,2,2,3, + 5,5,2,1,4,3, +}; +static const Int g6CodeTable[] = { + 6, + 1, 1, + 0, 5, + 1, 3, + 1, 5, + 1, 2, + 1, 4, + + 6, + 1, 2, + 0, 4, + 2, 2, + 1, 4, + 3, 2, + 1, 3, + + 6, + 0, 4, + 1, 4, + 1, 2, + 2, 2, + 3, 2, + 1, 3, + + 6, + 0, 5, + 1, 5, + 1, 2, + 1, 1, + 1, 4, + 1, 3 +}; +static const Int g6DeltaTable[] = { + -1, 1, 1, 1, 0, 1, + -2, 0, 0, 2, 0, 0, + -1,-1, 0, 1,-2, 0 +}; + +// Alphabet size = 7 +static const Int g_Index7Table[] = { 2,2,2,3,4,5,5, + 1,2,3,4,5,6,6 }; +static const Int g7CodeTable[] = { + 7, + 1, 2, + 2, 2, + 3, 2, + 1, 3, + 1, 4, + 0, 5, + 1, 5, + + 7, + 1, 1, + 1, 2, + 1, 3, + 1, 4, + 1, 5, + 0, 6, + 1, 6 +}; +static const Int g7DeltaTable[] = { 1,0,-1,-1,-1,-1,-1 }; + +// Alphabet size = 8 +static const Int g_Index8Table[] = { 2,3,5,4,2,3,5,3, + 3,3,4,3,3,3,4,2}; +static const Int g8CodeTable[] = { + 8, + 2, 2, + 1, 3, + 1, 5, + 1, 4, + 3, 2, + 2, 3, + 0, 5, + 3, 3, + + 8, + 1, 3, + 2, 3, + 1, 4, + 3, 3, + 4, 3, + 5, 3, + 0, 4, + 3, 2 +}; +static const Int g8DeltaTable[] = { -1,0,1,1,-1,0,1,1 }; + +static const Int g_Index9Table[] = { + 3,5,4,5,5,1,3,5,4, + 1,3,3,4,6,3,5,7,7, +}; +static const Int g9CodeTable[] = { + 9, + 2, 3, + 0, 5, + 2, 4, + 1, 5, + 2, 5, + 1, 1, + 3, 3, + 3, 5, + 3, 4, + + 9, + 1, 1, + 1, 3, + 2, 3, + 1, 4, + 1, 6, + 3, 3, + 1, 5, + 0, 7, + 1, 7, +}; +static const Int g9DeltaTable[] = { 2,2,1,1,-1,-2,-2,-2,-3 }; + +// Alphabet size = 12 +static const Int g_Index12Table[] = { // index12 is the most critical symbol + 5,6,7,7,5,3,5,1,5,4,5,3, + 4,5,6,6,4,3,5,2,3,3,5,3, + 2,3,7,7,5,3,7,3,3,3,7,4, + 3,2,7,5,5,3,7,3,5,3,6,3, + 3,1,7,4,7,3,8,4,7,4,8,5, +}; +static const Int g12CodeTable[] = { + 12, + 1, 5, + 1, 6, + 0, 7, + 1, 7, + 4, 5, + 2, 3, + 5, 5, + 1, 1, + 6, 5, + 1, 4, + 7, 5, + 3, 3, + + 12, + 2, 4, + 2, 5, + 0, 6, + 1, 6, + 3, 4, + 2, 3, + 3, 5, + 3, 2, + 3, 3, + 4, 3, + 1, 5, + 5, 3, + + 12, + 3, 2, + 1, 3, + 0, 7, + 1, 7, + 1, 5, + 2, 3, + 2, 7, + 3, 3, + 4, 3, + 5, 3, + 3, 7, + 1, 4, + + 12, + 1, 3, + 3, 2, + 0, 7, + 1, 5, + 2, 5, + 2, 3, + 1, 7, + 3, 3, + 3, 5, + 4, 3, + 1, 6, + 5, 3, + + 12, + 2, 3, + 1, 1, + 1, 7, + 1, 4, + 2, 7, + 3, 3, + 0, 8, + 2, 4, + 3, 7, + 3, 4, + 1, 8, + 1, 5 +}; +static const Int g12DeltaTable[] = { + 1, 1, 1, 1, 1, 0, 0,-1, 2, 1, 0, 0, + 2, 2,-1,-1,-1, 0,-2,-1, 0, 0,-2,-1, + -1, 1, 0, 2, 0, 0, 0, 0,-2, 0, 1, 1, + 0, 1, 0, 1,-2, 0,-1,-1,-2,-1,-2,-2 +}; + +/********************************************************************** + Adapt fixed length codes based on discriminant +**********************************************************************/ +static const Int THRESHOLD = 8; +static const Int MEMORY = 8; + +Void AdaptDiscriminant (CAdaptiveHuffman *pAdHuff) +{ + Int iSym = pAdHuff->m_iNSymbols, t, dL, dH; + const Int *pCodes, *pDelta = NULL; + Bool bChange = FALSE; + static const Int gMaxTables[] = { 0,0,0,0, 1,2, 4,2, 2,2, 0,0,5 }; + static const Int gSecondDisc[]= { 0,0,0,0, 0,0, 1,0, 0,0, 0,0,1 }; + + if (!pAdHuff->m_bInitialize) { + pAdHuff->m_bInitialize = 1; + pAdHuff->m_iDiscriminant = pAdHuff->m_iDiscriminant1 = 0; + pAdHuff->m_iTableIndex = gSecondDisc[iSym];//(gMaxTables[iSym] - 1) >> 1; + } + + dL = dH = pAdHuff->m_iDiscriminant; + if (gSecondDisc[iSym]) { + dH = pAdHuff->m_iDiscriminant1; + } + + if (dL < pAdHuff->m_iLowerBound) { + pAdHuff->m_iTableIndex--; + bChange = TRUE; + } + else if (dH > pAdHuff->m_iUpperBound) { + pAdHuff->m_iTableIndex++; + bChange = TRUE; + } + if (bChange) { + /** if initialization is fixed, we can exit on !bChange **/ + pAdHuff->m_iDiscriminant = 0; + pAdHuff->m_iDiscriminant1 = 0; + } + { + if (pAdHuff->m_iDiscriminant < -THRESHOLD * MEMORY) + pAdHuff->m_iDiscriminant = -THRESHOLD * MEMORY; + else if (pAdHuff->m_iDiscriminant > THRESHOLD * MEMORY) + pAdHuff->m_iDiscriminant = THRESHOLD * MEMORY; + + if (pAdHuff->m_iDiscriminant1 < -THRESHOLD * MEMORY) + pAdHuff->m_iDiscriminant1 = -THRESHOLD * MEMORY; + else if (pAdHuff->m_iDiscriminant1 > THRESHOLD * MEMORY) + pAdHuff->m_iDiscriminant1 = THRESHOLD * MEMORY; + } + + t = pAdHuff->m_iTableIndex; + assert (t >= 0); + assert (t < gMaxTables[iSym]); + + //pAdHuff->m_iDiscriminant >>= 1; + pAdHuff->m_iLowerBound = (t == 0) ? (-1 << 31) : -THRESHOLD; + pAdHuff->m_iUpperBound = (t == gMaxTables[iSym] - 1) ? (1 << 30) : THRESHOLD; + + switch (iSym) { + case 4: + pCodes = g4CodeTable; + pAdHuff->m_hufDecTable = (short *) g4HuffLookupTable; + break; + case 5: + pCodes = g5CodeTable + (iSym * 2 + 1) * t; + pDelta = g5DeltaTable; + pAdHuff->m_hufDecTable = g5HuffLookupTable[t]; + break; + case 6: + pCodes = g6CodeTable + (iSym * 2 + 1) * t; + pAdHuff->m_pDelta1 = g6DeltaTable + iSym * (t - (t + 1 == gMaxTables[iSym])); + pDelta = g6DeltaTable + (t - 1 + (t == 0)) * iSym; + pAdHuff->m_hufDecTable = g6HuffLookupTable[t]; + break; + case 7: + pCodes = g7CodeTable + (iSym * 2 + 1) * t; + pDelta = g7DeltaTable; + pAdHuff->m_hufDecTable = g7HuffLookupTable[t]; + break; + case 8: + //printf ("%d ", t); + pCodes = g8CodeTable;// + (iSym * 2 + 1) * t; + //pDelta = g8DeltaTable; + pAdHuff->m_hufDecTable = g8HuffLookupTable[0]; + break; + case 9: + pCodes = g9CodeTable + (iSym * 2 + 1) * t; + pDelta = g9DeltaTable; + pAdHuff->m_hufDecTable = g9HuffLookupTable[t]; + break; + case 12: + pCodes = g12CodeTable + (iSym * 2 + 1) * t; + pAdHuff->m_pDelta1 = g12DeltaTable + iSym * (t - (t + 1 == gMaxTables[iSym])); + pDelta = g12DeltaTable + (t - 1 + (t == 0)) * iSym; + pAdHuff->m_hufDecTable = g12HuffLookupTable[t]; + break; + default: + assert (0); // undefined fixed length table + return; + } + + pAdHuff->m_pTable = pCodes; + pAdHuff->m_pDelta = pDelta; +} + diff --git a/libs/jxr/image/sys/ansi.h b/libs/jxr/image/sys/ansi.h new file mode 100644 index 00000000000..05a2798916b --- /dev/null +++ b/libs/jxr/image/sys/ansi.h @@ -0,0 +1,61 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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. +// +//*@@@---@@@@****************************************************************** +#pragma once + +//================================ +// bitio functions +//================================ +#define PACKETLENGTH (1U<<12) // 4kB + +#define readIS_L1(pSC, pIO) readIS(pSC, pIO) +#define readIS_L2(pSC, pIO) (void)(pSC, pIO) + +#define writeIS_L1(pSC, pIO) writeIS(pSC, pIO) +#define writeIS_L2(pSC, pIO) (void)(pSC, pIO) + + +//================================ +// common defines +//================================ +#define FORCE_INLINE +#define CDECL +#if __LP64__ +#define UINTPTR_T unsigned long long +#define INTPTR_T long long +#else +#define UINTPTR_T unsigned int +#define INTPTR_T int +#endif + + +//================================ +// quantization optimization +//================================ +//#define RECIP_QUANT_OPT + + diff --git a/libs/jxr/image/sys/common.h b/libs/jxr/image/sys/common.h new file mode 100644 index 00000000000..80679ad3017 --- /dev/null +++ b/libs/jxr/image/sys/common.h @@ -0,0 +1,131 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 WMI_COMMON_H +#define WMI_COMMON_H + +/************************************************************************* +// Common typedef's +*************************************************************************/ +typedef enum { ENCODER = 0, DECODER = 1 } CODINGMODE; + +typedef enum tagBand +{ + BAND_HEADER = 0, + BAND_DC = 1, + BAND_LP = 2, + BAND_AC = 3, + BAND_FL = 4 +} BAND; + +/************************************************************************* + struct / class definitions +*************************************************************************/ +//#define SIGNATURE_BYTES 8 // Bytes for GDI+ signature +#define CODEC_VERSION 1 +#define CODEC_SUBVERSION 0 +#define CODEC_SUBVERSION_NEWSCALING_SOFT_TILES 1 +#define CODEC_SUBVERSION_NEWSCALING_HARD_TILES 9 + +#define CONTEXTX 8 +#define CTDC 5 +#define NUMVLCTABLES 21 // CONTEXTX * 2 + CTDC +#define AVG_NDIFF 3 + +#define MAXTOTAL 32767 // 511 should be enough + +/** Quantization related defines **/ +#define SHIFTZERO 1 /* >= 0 */ +#define QPFRACBITS 2 /* or 0 only supported */ + +/** adaptive huffman encoding / decoding struct **/ +typedef struct CAdaptiveHuffman +{ + Int m_iNSymbols; + const Int *m_pTable; + const Int *m_pDelta, *m_pDelta1; + Int m_iTableIndex; + const short *m_hufDecTable; + Bool m_bInitialize; + //Char m_pLabel[8]; // for debugging - label attached to constructor + + Int m_iDiscriminant, m_iDiscriminant1; + Int m_iUpperBound; + Int m_iLowerBound; +} CAdaptiveHuffman; + + +/************************************************************************************ + Context structures +************************************************************************************/ +typedef struct CAdaptiveModel { + Int m_iFlcState[2]; + Int m_iFlcBits[2]; + BAND m_band; +} CAdaptiveModel; + +typedef struct CCBPModel { + Int m_iCount0[2]; + Int m_iCount1[2]; + Int m_iState[2]; +} CCBPModel; + +/************************************************************************* + globals +*************************************************************************/ +extern Int grgiZigzagInv4x4_lowpass[]; +extern Int grgiZigzagInv4x4H[]; +extern Int grgiZigzagInv4x4V[]; +extern const Int gSignificantRunBin[]; +extern const Int gSignificantRunFixedLength[]; +static const Int cblkChromas[] = {0,4,8,16, 16,16,16, 0,0}; +/************************************************************************* + function declarations +*************************************************************************/ +// common utilities +Void Clean (CAdaptiveHuffman *pAdHuff); +CAdaptiveHuffman *Allocate (Int iNSymbols, CODINGMODE cm); + +/* Timing functions */ +void reset_timing(double *time); +void report_timing(const char *s, double time); +// static double timeperclock; + +/** adaptive model functions **/ +Void UpdateModelMB (COLORFORMAT cf, Int iChannels, Int iLaplacianMean[], CAdaptiveModel *m_pModel); + +/** adaptive huffman encoder / decoder functions **/ +Void Adapt (CAdaptiveHuffman *pAdHuff, Bool bFixedTables); +Void AdaptFixed (CAdaptiveHuffman *pAdHuff); +Void AdaptDiscriminant (CAdaptiveHuffman *pAdHuff); + +#ifndef _PREFAST_ +#pragma warning(disable:4068) +#endif + +#endif // WMI_COMMON_H diff --git a/libs/jxr/image/sys/image.c b/libs/jxr/image/sys/image.c new file mode 100644 index 00000000000..5605abc9027 --- /dev/null +++ b/libs/jxr/image/sys/image.c @@ -0,0 +1,183 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strcodec.h" +// #include "xplatform_image.h" + +#ifdef MEM_TRACE +#define TRACE_MALLOC 1 +#define TRACE_NEW 0 +#define TRACE_HEAP 0 +#include "memtrace.h" +#endif + +#include +#include + +#if !(defined(__ANSI__)) +// Desktop +#include +#else +// ANSI +#include +#endif + +Int grgiZigzagInv4x4_lowpass [] = { + 0, 1, 4, 5, 2, 8, 6, 9, + 3, 12, 10, 7, 13, 11, 14, 15 +}; + +Int grgiZigzagInv4x4H [] = { + 0, 1, 4, 5, 2, 8, 6, 9, + 3, 12, 10, 7, 13, 11, 14, 15 +}; +Int grgiZigzagInv4x4V [] = { + 0, 4, 8, 5, 1, 12, 9, 6, 2, 13, 3, 15, 7, 10, 14, 11 +}; + +const Int gSignificantRunBin[] = { + -1,-1,-1,-1, + 2,2,2, + 1,1,1,1, + 0,0,0,0 +}; + +const Int gSignificantRunFixedLength[] = { + 0,0,1,1,3, + 0,0,1,1,2, + 0,0,0,0,1, +}; + +/************************************************************************* + UpdateModelMB : update adaptive model at end of macroblock + (for lowest resolution only) +*************************************************************************/ +#define MODELWEIGHT 70//90 + +Void UpdateModelMB (COLORFORMAT cf, Int iChannels, Int iLaplacianMean[], CAdaptiveModel *pModel) +{ + Int j; + static const Int aWeight0[3] = { 240/*DC*/, 12/*LP*/, 1 }; + static const Int aWeight1[3][MAX_CHANNELS] = { + { 0,240,120,80, 60,48,40,34, 30,27,24,22, 20,18,17,16 }, + { 0,12,6,4, 3,2,2,2, 2,1,1,1, 1,1,1,1 }, + { 0,16,8,5, 4,3,3,2, 2,2,2,1, 1,1,1,1 } + }; + static const Int aWeight2[6] = { 120,37,2,/*420*/ 120,18,1/*422*/ }; + + iLaplacianMean[0] *= aWeight0[pModel->m_band - BAND_DC]; + if (cf == YUV_420) { + iLaplacianMean[1] *= aWeight2[pModel->m_band - BAND_DC]; + } + else if (cf == YUV_422) { + iLaplacianMean[1] *= aWeight2[3 + (pModel->m_band) - BAND_DC]; + } + else { + iLaplacianMean[1] *= aWeight1[pModel->m_band - BAND_DC][iChannels - 1]; + if (pModel->m_band == BAND_AC) + iLaplacianMean[1] >>= 4; + } + + for (j = 0; j < 2; j++) { + Int iLM = iLaplacianMean[j]; + Int iMS = pModel->m_iFlcState[j]; + Int iDelta = (iLM - MODELWEIGHT) >> 2; + + if (iDelta <= -8) { + iDelta += 4; + if (iDelta < -16) + iDelta = -16; + iMS += iDelta; + if (iMS < -8) { + if (pModel->m_iFlcBits[j] == 0) + iMS = -8; + else { + iMS = 0; + pModel->m_iFlcBits[j]--; + } + } + } + else if (iDelta >= 8) { + iDelta -= 4; + if (iDelta > 15) + iDelta = 15; + iMS += iDelta; + if (iMS > 8) { + if (pModel->m_iFlcBits[j] >= 15) { + pModel->m_iFlcBits[j] = 15; + iMS = 8; + } + else { + iMS = 0; + pModel->m_iFlcBits[j]++; + } + } + } + pModel->m_iFlcState[j] = iMS; + if (cf == Y_ONLY) + break; + } +} + + +Void ResetCodingContext(CCodingContext *pContext) +{ + // reset bit reduction models + memset (&(pContext->m_aModelAC), 0, sizeof(CAdaptiveModel)); + pContext->m_aModelAC.m_band = BAND_AC; + + memset (&(pContext->m_aModelLP), 0, sizeof(CAdaptiveModel)); + pContext->m_aModelLP.m_band = BAND_LP; + pContext->m_aModelLP.m_iFlcBits[0] = pContext->m_aModelLP.m_iFlcBits[1] = 4; + + memset (&(pContext->m_aModelDC), 0, sizeof(CAdaptiveModel)); + pContext->m_aModelDC.m_band = BAND_DC; + pContext->m_aModelDC.m_iFlcBits[0] = pContext->m_aModelDC.m_iFlcBits[1] = 8; + + // reset CBP models + pContext->m_iCBPCountMax = pContext->m_iCBPCountZero = 1; + + pContext->m_aCBPModel.m_iCount0[0] = pContext->m_aCBPModel.m_iCount0[1] = -4; + pContext->m_aCBPModel.m_iCount1[0] = pContext->m_aCBPModel.m_iCount1[1] = 4; + pContext->m_aCBPModel.m_iState[0] = pContext->m_aCBPModel.m_iState[1] = 0; +} + +/************************************************************************* + Initialize zigzag scan parameters +*************************************************************************/ +Void InitZigzagScan(CCodingContext * pContext) +{ + if (NULL != pContext) { + Int i; + for (i=0; i<16; i++) { + pContext->m_aScanLowpass[i].uScan = grgiZigzagInv4x4_lowpass[i]; + pContext->m_aScanHoriz[i].uScan = dctIndex[0][grgiZigzagInv4x4H[i]]; + pContext->m_aScanVert[i].uScan = dctIndex[0][grgiZigzagInv4x4V[i]]; + } + } +} diff --git a/libs/jxr/image/sys/perfTimer.h b/libs/jxr/image/sys/perfTimer.h new file mode 100644 index 00000000000..f57867470d6 --- /dev/null +++ b/libs/jxr/image/sys/perfTimer.h @@ -0,0 +1,115 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 __PERFTIMER_H_ +#define __PERFTIMER_H_ + +//*************************************************************************** +// Description +// +// Performance timer API used to measure codec performance. The underlying +// implementation of this API may vary - from ANSI-C implementation via clock, +// Win32 implementation via QueryPerformanceCounter or GetProcessTimes. At +// present we only support one implementation of this PerfTimer "object". +// You choose the implementation by choosing which one of the many files +// to compile and link with your application. +//*************************************************************************** + +#ifdef DISABLE_PERF_MEASUREMENT + +#define PERFTIMER_ONLY(code) +#define PERFTIMER_NEW(fPerf, ppPerfTimer) +#define PERFTIMER_DELETE(fPerf, ppPerfTimer) +#define PERFTIMER_START(fPerf, pPerfTimer) +#define PERFTIMER_STOP(fPerf, pPerfTimer) +#define PERFTIMER_GETRESULTS(fPerf, pPerfTimer, pResults) +#define PERFTIMER_COPYSTARTTIME(fPerf, pDst, pSrc) +#define PERFTIMER_REPORT(fPerf, pCodec) + +#else // DISABLE_PERF_MEASUREMENT + +#define PERFTIMER_ONLY(code) code +#define PERFTIMER_NEW(fPerf, ppPerfTimer) if (fPerf) {Bool b = b = PerfTimerNew(ppPerfTimer); assert(b);}; +#define PERFTIMER_DELETE(fPerf, pPerfTimer) if (fPerf) {PerfTimerDelete(pPerfTimer);}; +#define PERFTIMER_START(fPerf, pPerfTimer) if (fPerf) {Bool b = b = PerfTimerStart(pPerfTimer); assert(b);}; +#define PERFTIMER_STOP(fPerf, pPerfTimer) if (fPerf) {Bool b = b = PerfTimerStop(pPerfTimer); assert(b);}; +#define PERFTIMER_GETRESULTS(fPerf, pPerfTimer, pResults) \ + if (fPerf) {Bool b = b = PerfTimerGetResults((pPerfTimer), (pResults)); assert(b);}; +#define PERFTIMER_COPYSTARTTIME(fPerf, pDst, pSrc) \ + if (fPerf) {Bool b = b = PerfTimerCopyStartTime((pDst), (pSrc)); assert(b);}; +#define PERFTIMER_REPORT(fPerf, pCodec) \ + if (fPerf) {OutputPerfTimerReport(pCodec);}; +#endif // DISABLE_PERF_MEASUREMENT + +//*************************************************************************** +// Data Types +//*************************************************************************** +typedef U64 PERFTIMERTIME; +typedef struct PERFTIMERRESULTS +{ + PERFTIMERTIME iElapsedTime; // In nanoseconds or CPU cycles + PERFTIMERTIME iTicksPerSecond; // Number of ticks per second (clock frequency) + PERFTIMERTIME iZeroTimeIntervals; // Number of zero-time intervals. + // Presence of zero-time intervals may indicate insufficient clock precision +} PERFTIMERRESULTS; + +#define NANOSECONDS_PER_SECOND 1000000000 + + +//*************************************************************************** +// Data Declarations +//*************************************************************************** +typedef enum +{ + CS_UNINIT, + CS_RUNNING, + CS_STOPPED, +} CLOCKSTATE; + +typedef struct PERFTIMERSTATE +{ + CLOCKSTATE eState; + PERFTIMERTIME iElapsedTime; + PERFTIMERTIME iPrevStartTime; + PERFTIMERTIME iZeroTimeIntervals; +} PERFTIMERSTATE; + + +//*************************************************************************** +// Functions and Macros +//*************************************************************************** +Bool PerfTimerNew(PERFTIMERSTATE **ppNewPerfTimer); +void PerfTimerDelete(PERFTIMERSTATE *pThisPerfTimer); +Bool PerfTimerStart(PERFTIMERSTATE *pThisPerfTimer); +Bool PerfTimerStop(PERFTIMERSTATE *pThisPerfTimer); +Bool PerfTimerGetResults(PERFTIMERSTATE *pThisPerfTimer, + PERFTIMERRESULTS *pPerfTimerResults); +Bool PerfTimerCopyStartTime(PERFTIMERSTATE *pDestPerfTimer, + PERFTIMERSTATE *pSrcPerfTimer); + +#endif // __PERFTIMER_H_ diff --git a/libs/jxr/image/sys/strPredQuant.c b/libs/jxr/image/sys/strPredQuant.c new file mode 100644 index 00000000000..3092d23d1ad --- /dev/null +++ b/libs/jxr/image/sys/strPredQuant.c @@ -0,0 +1,306 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strcodec.h" + +#define ORIENT_WEIGHT 4 + +/* reciprocal (pMantissa, exponent) lookup table */ +typedef struct tagQPManExp +{ + int iMan; + int iExp; +} QPManExp; + +static QPManExp gs_QPRecipTable[32] = { + {0x0, 0}, // 0, invalid + {0x0, 0}, // 1, lossless + {0x0, 1}, // 2 + {0xaaaaaaab, 1}, + {0x0, 2}, // 4 + {0xcccccccd, 2}, + {0xaaaaaaab, 2}, + {0x92492493, 2}, + {0x0, 3}, // 8 + {0xe38e38e4, 3}, + {0xcccccccd, 3}, + {0xba2e8ba3, 3}, + {0xaaaaaaab, 3}, + {0x9d89d89e, 3}, + {0x92492493, 3}, + {0x88888889, 3}, + {0x0, 4}, // 16 + {0xf0f0f0f1, 4}, + {0xe38e38e4, 4}, + {0xd79435e6, 4}, + {0xcccccccd, 4}, + {0xc30c30c4, 4}, + {0xba2e8ba3, 4}, + {0xb21642c9, 4}, + {0xaaaaaaab, 4}, + {0xa3d70a3e, 4}, + {0x9d89d89e, 4}, + {0x97b425ee, 4}, + {0x92492493, 4}, + {0x8d3dcb09, 4}, + {0x88888889, 4}, + {0x84210843, 4}, +}; + +/************************************************************************* + QPRemapping +*************************************************************************/ + +Void remapQP(CWMIQuantizer * pQP, I32 iShift, Bool bScaledArith) +{ + U8 uiQPIndex = pQP->iIndex; + + if(uiQPIndex == 0) // Lossless mode! + pQP->iQP = 1, pQP->iMan = pQP->iExp = pQP->iOffset = 0; + else if (!bScaledArith) { + I32 man = 0, exp = 0; + const I32 ciShift = SHIFTZERO - (SHIFTZERO + QPFRACBITS); // == -QPFRACBITS + + if (pQP->iIndex < 32) + man = (pQP->iIndex + 3) >> 2, exp = ciShift + 2; + else if (pQP->iIndex < 48) + man = (16 + (pQP->iIndex & 0xf) + 1) >> 1, exp = ((pQP->iIndex >> 4) - 1) + 1 + ciShift; + else + man = 16 + (pQP->iIndex & 0xf), exp = ((pQP->iIndex >> 4) - 1) + ciShift; + + pQP->iQP = man << exp; + pQP->iMan = gs_QPRecipTable[man].iMan; + pQP->iExp = gs_QPRecipTable[man].iExp + exp; + pQP->iOffset = ((pQP->iQP * 3 + 1) >> 3); +#if defined(WMP_OPT_QT) + pQP->f1_QP = 1.0f / pQP->iQP; + pQP->d1_QP = 1.0 / pQP->iQP; +#endif + } + else { + I32 man = 0, exp = 0; + + if(pQP->iIndex < 16) + man = pQP->iIndex, exp = iShift; + else + man = 16 + (pQP->iIndex & 0xf), exp = ((pQP->iIndex >> 4) - 1) + iShift; + + pQP->iQP = man << exp; + pQP->iMan = gs_QPRecipTable[man].iMan; + pQP->iExp = gs_QPRecipTable[man].iExp + exp; + pQP->iOffset = ((pQP->iQP * 3 + 1) >> 3); +#if defined(WMP_OPT_QT) + pQP->f1_QP = 1.0f / pQP->iQP; + pQP->d1_QP = 1.0 / pQP->iQP; +#endif + } +} + +/* allocate PredInfo buffers */ +Int allocatePredInfo(CWMImageStrCodec *pSC) +{ + size_t i, j; + // COLORFORMAT cf = pSC->m_param.cfColorFormat; + const size_t mbWidth = pSC->cmbWidth; + const size_t iChannels = pSC->m_param.cNumChannels; + CWMIPredInfo* pMemory; + Bool b32Bit = sizeof(size_t) == 4; + + if(b32Bit) // integer overlow/underflow check for 32-bit system + if(((mbWidth >> 16) * iChannels * 2 * sizeof(CWMIPredInfo)) & 0xffff0000) + return ICERR_ERROR; + pMemory = (CWMIPredInfo *)malloc(mbWidth * iChannels * 2 * sizeof(CWMIPredInfo)); + if (pMemory == NULL) + return ICERR_ERROR; + + pSC->pPredInfoMemory = pMemory; + for(i = 0; i < iChannels; i ++){ + pSC->PredInfo[i] = pMemory; + pMemory += mbWidth; + pSC->PredInfoPrevRow[i] = pMemory; + pMemory += mbWidth; + + for(j = 0; j < mbWidth; j ++){ + pSC->PredInfo[i][j].piAD = pSC->PredInfo[i][j].iAD; + pSC->PredInfoPrevRow[i][j].piAD = pSC->PredInfoPrevRow[i][j].iAD; + } + } + + return ICERR_OK; +} + +/* clear PredInfo buffers */ +Void freePredInfo(CWMImageStrCodec *pSC) +{ + if (pSC->pPredInfoMemory) + free (pSC->pPredInfoMemory); + pSC->pPredInfoMemory = NULL; +} + +/* get AC prediction mode: 0(from left) 1(from top) 2(none) */ +Int getACPredMode(CWMIMBInfo * pMBInfo, COLORFORMAT cf) +{ + //Int blkIdx = (cf == Y_ONLY ? 16 : (cf == YUV_420 ? 24 : (cf == YUV_422 ? 32 : 48))); + PixelI * pCoeffs = pMBInfo->iBlockDC[0]; + Int StrH = abs(pCoeffs[1]) + abs(pCoeffs[2]) + abs(pCoeffs[3]); + Int StrV = abs(pCoeffs[4]) + abs(pCoeffs[8]) + abs(pCoeffs[12]); + + if(cf != Y_ONLY && cf != NCOMPONENT){ + PixelI * pCoeffsU = pMBInfo->iBlockDC[1]; + PixelI * pCoeffsV = pMBInfo->iBlockDC[2]; + + StrH += abs(pCoeffsU[1]) + abs(pCoeffsV[1]); + if(cf == YUV_420){ + StrV += abs(pCoeffsU[2]) + abs(pCoeffsV[2]); + } + else if (cf == YUV_422){ + StrV += abs(pCoeffsU[2]) + abs(pCoeffsV[2]) + abs(pCoeffsU[6]) + abs(pCoeffsV[6]); + StrH += abs(pCoeffsU[5]) + abs(pCoeffsV[5]); + } + else { // YUV_444 or CMYK + StrV += abs(pCoeffsU[4]) + abs(pCoeffsV[4]); + } + } + + return (StrH * ORIENT_WEIGHT < StrV ? 1 : (StrV * ORIENT_WEIGHT < StrH ? 0 : 2)); +} + +/* get DCAC prediction mode: 0(from left) 1(from top) 2(none) */ +Int getDCACPredMode(CWMImageStrCodec *pSC, size_t mbX) +{ + Int iDCMode, iADMode = 2; // DC: 0(left) 1(top) 2(mean) 3(no) + // AD: 0(left) 1(top) 2(no) + + if(pSC->m_bCtxLeft && pSC->m_bCtxTop){ // topleft corner, no prediction + iDCMode = 3; + } + else if(pSC->m_bCtxLeft){ + iDCMode = 1; // left column, predict from top + } + else if(pSC->m_bCtxTop){ + iDCMode = 0; // top row, predict from left + } + else{ + COLORFORMAT cf = pSC->m_param.cfColorFormat; + Int iL = pSC->PredInfo[0][mbX - 1].iDC, iT = pSC->PredInfoPrevRow[0][mbX].iDC, iTL = pSC->PredInfoPrevRow[0][mbX - 1].iDC; + Int StrH, StrV; + + if(cf == Y_ONLY || cf == NCOMPONENT){ // CMYK uses YUV metric + StrH = abs(iTL - iL); + StrV = abs(iTL - iT); + } + else{ + CWMIPredInfo * pTU = pSC->PredInfoPrevRow[1] + mbX, * pLU = pSC->PredInfo[1] + mbX - 1, * pTLU = pTU - 1; + CWMIPredInfo * pTV = pSC->PredInfoPrevRow[2] + mbX, * pLV = pSC->PredInfo[2] + mbX - 1, * pTLV = pTV - 1; + Int scale = (cf == YUV_420 ? 8 : (cf == YUV_422 ? 4 : 2)); + + StrH = abs(iTL - iL) * scale + abs(pTLU->iDC - pLU->iDC) + abs(pTLV->iDC - pLV->iDC); + StrV = abs(iTL - iT) * scale + abs(pTLU->iDC - pTU->iDC) + abs(pTLV->iDC - pTV->iDC); + } + iDCMode = (StrH * ORIENT_WEIGHT < StrV ? 1 : (StrV * ORIENT_WEIGHT < StrH ? 0 : 2)); + } + + if(iDCMode == 1 && pSC->MBInfo.iQIndexLP == pSC->PredInfoPrevRow[0][mbX].iQPIndex) + iADMode = 1; + if(iDCMode == 0 && pSC->MBInfo.iQIndexLP == pSC->PredInfo[0][mbX - 1].iQPIndex) + iADMode = 0; + + return (iDCMode + (iADMode << 2)); +} + +Void copyAC(PixelI * src, PixelI * dst) +{ + /* first row of ACs */ + dst[0] = src[1]; + dst[1] = src[2]; + dst[2] = src[3]; + + /* first column of ACs */ + dst[3] = src[4]; + dst[4] = src[8]; + dst[5] = src[12]; +} + +/* info of current MB to be saved for future prediction */ +Void updatePredInfo(CWMImageStrCodec *pSC, CWMIMBInfo * pMBInfo, size_t mbX, COLORFORMAT cf) +{ + CWMIPredInfo *pPredInfo; + PixelI * p; + Int i, iChannels = (cf == YUV_420 || cf == YUV_422) ? 1 : (Int) pSC->m_param.cNumChannels; + + for(i = 0; i < iChannels; i ++){ + pPredInfo = pSC->PredInfo[i] + mbX; + p = pMBInfo->iBlockDC[i];//[dcBlkIdx + i]; + + /* DC of DC block */ + pPredInfo->iDC = p[0]; + + /* QP Index */ + pPredInfo->iQPIndex = pMBInfo->iQIndexLP; + + /* first row and first column of ACs of DC block */ + copyAC(p, pPredInfo->piAD); + } + + if(cf == YUV_420){ // 420 UV channels + for(i = 1U; i < 3U; i ++){ + pPredInfo = pSC->PredInfo[i] + mbX; + p = pMBInfo->iBlockDC[i];//[dcBlkIdx + i]; + + /* DC of DC block */ + pPredInfo->iDC = p[0]; + + /* QP Index */ + pPredInfo->iQPIndex = pMBInfo->iQIndexLP; + /* first row and first column of ACs of DC block */ + pPredInfo->piAD[0] = p[1]; + pPredInfo->piAD[1] = p[2]; + } + } + else if(cf == YUV_422){ // 420 UV channels + for(i = 1U; i < 3U; i ++){ + pPredInfo = pSC->PredInfo[i] + mbX; + + /* QP Index */ + pPredInfo->iQPIndex = pMBInfo->iQIndexLP; + + p = pMBInfo->iBlockDC[i];//[dcBlkIdx + i]; + + /* DC of DC block */ + pPredInfo->iDC = p[0]; + + /* first row and first column of ACs of first DC block */ + pPredInfo->piAD[0] = p[1]; + pPredInfo->piAD[1] = p[2]; + /* first row and first column of ACs of second DC block */ + pPredInfo->piAD[2] = p[5]; + pPredInfo->piAD[3] = p[6]; + pPredInfo->piAD[4] = p[4]; //AC of 1D HT!!! + } + } +} diff --git a/libs/jxr/image/sys/strTransform.c b/libs/jxr/image/sys/strTransform.c new file mode 100644 index 00000000000..57ec87a5292 --- /dev/null +++ b/libs/jxr/image/sys/strTransform.c @@ -0,0 +1,85 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strTransform.h" + +/** need to swap b and c **/ +/** rounding behavior: [0 0 0 0] <-> [+ - - -] + [+ + + +] <-> [+3/4 - - -] + [- - - -] <-> [- - - -] **/ +Void strDCT2x2dn(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d, C, t; + a = *pa; + b = *pb; + C = *pc; + d = *pd; + + a += d; + b -= C; + t = ((a - b) >> 1); + c = t - d; + d = t - C; + a -= d; + b += c; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +Void strDCT2x2up(PixelI *pa, PixelI *pb, PixelI *pc, PixelI *pd) +{ + PixelI a, b, c, d, C, t; + a = *pa; + b = *pb; + C = *pc; + d = *pd; + + a += d; + b -= C; + t = ((a - b + 1) >> 1); + c = t - d; + d = t - C; + a -= d; + b += c; + + *pa = a; + *pb = b; + *pc = c; + *pd = d; +} + +Void FOURBUTTERFLY_HARDCODED1(PixelI *p) +{ + strDCT2x2dn(&p[0], &p[4], &p[8], &p[12]); + strDCT2x2dn(&p[1], &p[5], &p[9], &p[13]); + strDCT2x2dn(&p[2], &p[6], &p[10], &p[14]); + strDCT2x2dn(&p[3], &p[7], &p[11], &p[15]); +} diff --git a/libs/jxr/image/sys/strTransform.h b/libs/jxr/image/sys/strTransform.h new file mode 100644 index 00000000000..c66b754b998 --- /dev/null +++ b/libs/jxr/image/sys/strTransform.h @@ -0,0 +1,50 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 WMI_STRTRANSFORM_H +#define WMI_STRTRANSFORM_H + +#include "windowsmediaphoto.h" + +#define COMPUTE_CORNER_PRED_DIFF(a, b) (*(a) -= (b)) +#define COMPUTE_CORNER_PRED_ADD(a, b) (*(a) += (b)) + +/** 2x2 foward DCT == 2x2 inverse DCT **/ +Void strDCT2x2dn(PixelI *, PixelI *, PixelI *, PixelI *); +Void strDCT2x2up(PixelI *, PixelI *, PixelI *, PixelI *); +Void FOURBUTTERFLY_HARDCODED1(PixelI *p); + +/** 2x2 dct of a group of 4**/ +#define FOURBUTTERFLY(p, i00, i01, i02, i03, i10, i11, i12, i13,\ + i20, i21, i22, i23, i30, i31, i32, i33) \ + strDCT2x2dn(&p[i00], &p[i01], &p[i02], &p[i03]); \ + strDCT2x2dn(&p[i10], &p[i11], &p[i12], &p[i13]); \ + strDCT2x2dn(&p[i20], &p[i21], &p[i22], &p[i23]); \ + strDCT2x2dn(&p[i30], &p[i31], &p[i32], &p[i33]) + +#endif // WMI_STRTRANSFORM_H diff --git a/libs/jxr/image/sys/strcodec.c b/libs/jxr/image/sys/strcodec.c new file mode 100644 index 00000000000..0e7e8cbd8d1 --- /dev/null +++ b/libs/jxr/image/sys/strcodec.c @@ -0,0 +1,1251 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "strcodec.h" +#include "perfTimer.h" + +#ifdef MEM_TRACE +#define TRACE_MALLOC 1 +#define TRACE_NEW 0 +#define TRACE_HEAP 0 +#include "memtrace.h" +#endif + +//================================================================ +// Quantization index tables +//================================================================ +const int blkOffset[16] = {0, 64, 16, 80, 128, 192, 144, 208, 32, 96, 48, 112, 160, 224, 176, 240}; +const int blkOffsetUV[4] = {0, 32, 16, 48}; +const int blkOffsetUV_422[8] = {0, 64, 16, 80, 32, 96, 48, 112}; + +const int dctIndex[3][16] = { /** permutation matrix tailored to the transform, nothing to do with ZZS **/ + {0,5,1,6, 10,12,8,14, 2,4,3,7, 9,13,11,15}, //AC 444 + {0,5,1,6, 10,12,8,14, 2,4,3,7, 9,13,11,15}, //AC 420 + {0,128,64,208, 32,240,48,224, 16,192,80,144, 112,176,96,160 }, //DC 444 +}; + +//================================================================ +// Color conversion index table +//================================================================ +const U8 idxCC[16][16] = +{ + {0x00, 0x01, 0x05, 0x04, 0x40, 0x41, 0x45, 0x44, 0x80, 0x81, 0x85, 0x84, 0xc0, 0xc1, 0xc5, 0xc4, }, + {0x02, 0x03, 0x07, 0x06, 0x42, 0x43, 0x47, 0x46, 0x82, 0x83, 0x87, 0x86, 0xc2, 0xc3, 0xc7, 0xc6, }, + {0x0a, 0x0b, 0x0f, 0x0e, 0x4a, 0x4b, 0x4f, 0x4e, 0x8a, 0x8b, 0x8f, 0x8e, 0xca, 0xcb, 0xcf, 0xce, }, + {0x08, 0x09, 0x0d, 0x0c, 0x48, 0x49, 0x4d, 0x4c, 0x88, 0x89, 0x8d, 0x8c, 0xc8, 0xc9, 0xcd, 0xcc, }, + + {0x10, 0x11, 0x15, 0x14, 0x50, 0x51, 0x55, 0x54, 0x90, 0x91, 0x95, 0x94, 0xd0, 0xd1, 0xd5, 0xd4, }, + {0x12, 0x13, 0x17, 0x16, 0x52, 0x53, 0x57, 0x56, 0x92, 0x93, 0x97, 0x96, 0xd2, 0xd3, 0xd7, 0xd6, }, + {0x1a, 0x1b, 0x1f, 0x1e, 0x5a, 0x5b, 0x5f, 0x5e, 0x9a, 0x9b, 0x9f, 0x9e, 0xda, 0xdb, 0xdf, 0xde, }, + {0x18, 0x19, 0x1d, 0x1c, 0x58, 0x59, 0x5d, 0x5c, 0x98, 0x99, 0x9d, 0x9c, 0xd8, 0xd9, 0xdd, 0xdc, }, + + {0x20, 0x21, 0x25, 0x24, 0x60, 0x61, 0x65, 0x64, 0xa0, 0xa1, 0xa5, 0xa4, 0xe0, 0xe1, 0xe5, 0xe4, }, + {0x22, 0x23, 0x27, 0x26, 0x62, 0x63, 0x67, 0x66, 0xa2, 0xa3, 0xa7, 0xa6, 0xe2, 0xe3, 0xe7, 0xe6, }, + {0x2a, 0x2b, 0x2f, 0x2e, 0x6a, 0x6b, 0x6f, 0x6e, 0xaa, 0xab, 0xaf, 0xae, 0xea, 0xeb, 0xef, 0xee, }, + {0x28, 0x29, 0x2d, 0x2c, 0x68, 0x69, 0x6d, 0x6c, 0xa8, 0xa9, 0xad, 0xac, 0xe8, 0xe9, 0xed, 0xec, }, + + {0x30, 0x31, 0x35, 0x34, 0x70, 0x71, 0x75, 0x74, 0xb0, 0xb1, 0xb5, 0xb4, 0xf0, 0xf1, 0xf5, 0xf4, }, + {0x32, 0x33, 0x37, 0x36, 0x72, 0x73, 0x77, 0x76, 0xb2, 0xb3, 0xb7, 0xb6, 0xf2, 0xf3, 0xf7, 0xf6, }, + {0x3a, 0x3b, 0x3f, 0x3e, 0x7a, 0x7b, 0x7f, 0x7e, 0xba, 0xbb, 0xbf, 0xbe, 0xfa, 0xfb, 0xff, 0xfe, }, + {0x38, 0x39, 0x3d, 0x3c, 0x78, 0x79, 0x7d, 0x7c, 0xb8, 0xb9, 0xbd, 0xbc, 0xf8, 0xf9, 0xfd, 0xfc, }, +}; + +const U8 idxCC_420[8][8] = +{ + {0x00, 0x01, 0x05, 0x04, 0x20, 0x21, 0x25, 0x24, }, + {0x02, 0x03, 0x07, 0x06, 0x22, 0x23, 0x27, 0x26, }, + {0x0a, 0x0b, 0x0f, 0x0e, 0x2a, 0x2b, 0x2f, 0x2e, }, + {0x08, 0x09, 0x0d, 0x0c, 0x28, 0x29, 0x2d, 0x2c, }, + + {0x10, 0x11, 0x15, 0x14, 0x30, 0x31, 0x35, 0x34, }, + {0x12, 0x13, 0x17, 0x16, 0x32, 0x33, 0x37, 0x36, }, + {0x1a, 0x1b, 0x1f, 0x1e, 0x3a, 0x3b, 0x3f, 0x3e, }, + {0x18, 0x19, 0x1d, 0x1c, 0x38, 0x39, 0x3d, 0x3c, }, +}; + +/************************************************************************* + gGDISignature +*************************************************************************/ +const Char gGDISignature[] = {'W', 'M', 'P', 'H', 'O', 'T', 'O', '\0'}; + +// check if enough memory allocated for the image buffer +Int checkImageBuffer(CWMImageStrCodec * pSC, size_t cWidth, size_t cRows) +{ + const BITDEPTH_BITS bd = pSC->WMISCP.bYUVData ? + BD_32S : pSC->WMII.bdBitDepth; + const COLORFORMAT cf = pSC->WMISCP.bYUVData ? + pSC->m_param.cfColorFormat : pSC->WMII.cfColorFormat; + size_t cBytes; + Bool bLessThan64Bit = sizeof(void *) < 8; + + if(cf == YUV_420) + cRows = (cRows + 1) / 2; + if(cRows > pSC->WMIBI.cLine) + return ICERR_ERROR; + + if(cf == YUV_422 || cf == YUV_420) + cWidth = (cWidth + 1) / 2; + + if (bLessThan64Bit && (cWidth >> ((sizeof(size_t) * 8 - 5)))) { + /** potential overflow - 32 bit pointers insufficient to address cache **/ + /** this uses 2 macroblock row constraint, which is tighter than ensuring rollover doesn't occur below **/ + return ICERR_ERROR; + } + + cBytes = pSC->WMISCP.bYUVData ? cWidth * sizeof(PixelI) * + (cf == YUV_420 ? 6 : (cf == YUV_422 ? 4 : (cf == YUV_444 ? 3 : 1))) : + (bd == BD_1 ? (pSC->WMII.cBitsPerUnit * cWidth + 7) / 8 : (pSC->WMII.cBitsPerUnit + 7) / 8 * cWidth); + + return (cBytes > pSC->WMIBI.cbStride ? ICERR_ERROR : ICERR_OK); +} + +Void writeQPIndex(BitIOInfo * pIO, U8 uiIndex, U32 cBits) +{ + if(uiIndex == 0) + putBit16(pIO, 1, 1); // default QP + else{ + putBit16(pIO, 0, 1); // non default QP + putBit16(pIO, uiIndex - 1, cBits); + } +} + +U8 readQPIndex(BitIOInfo * pIO, U32 cBits) +{ + if(getBit16(pIO, 1)) + return 0; // default QP + + return (U8) getBit16(pIO, cBits) + 1; +} + +Void getTilePos(CWMImageStrCodec* pSC, size_t mbX, size_t mbY) +{ + if(mbX == 0){ // left image boundary + pSC->cTileColumn = 0; + } + else if(pSC->cTileColumn < pSC->WMISCP.cNumOfSliceMinus1V && mbX == pSC->WMISCP.uiTileX[pSC->cTileColumn + 1]){ // left tile boundary + pSC->cTileColumn ++; + } + + if(mbY == 0){ // top image boundary + pSC->cTileRow = 0; + } + else if(pSC->cTileRow < pSC->WMISCP.cNumOfSliceMinus1H && mbY == pSC->WMISCP.uiTileY[pSC->cTileRow + 1]){ // top tile boundary + pSC->cTileRow ++; + } + + pSC->m_bCtxLeft = (mbX == pSC->WMISCP.uiTileX[pSC->cTileColumn]); + pSC->m_bCtxTop = (mbY == pSC->WMISCP.uiTileY[pSC->cTileRow]); + + pSC->m_bResetContext = pSC->m_bResetRGITotals = (((mbX - pSC->WMISCP.uiTileX[pSC->cTileColumn]) & 0xf) == 0); + if(pSC->cTileColumn == pSC->WMISCP.cNumOfSliceMinus1V){ // last tile column + if(mbX + 1 == pSC->cmbWidth) + pSC->m_bResetContext = TRUE; + } + else if(mbX + 1 == pSC->WMISCP.uiTileX[pSC->cTileColumn + 1]) + pSC->m_bResetContext = TRUE; +} + +//================================================================ +// utility functions for 2 macro block rows +//================================================================ +Void initMRPtr(CWMImageStrCodec* pSC) +{ + size_t j, jend = (pSC->m_pNextSC != NULL); + + for (j = 0; j <= jend; j++) { + memcpy (pSC->p0MBbuffer, pSC->a0MBbuffer, sizeof (pSC->p0MBbuffer)); + memcpy (pSC->p1MBbuffer, pSC->a1MBbuffer, sizeof (pSC->p1MBbuffer)); + pSC = pSC->m_pNextSC; + } +} + +Void advanceMRPtr(CWMImageStrCodec* pSC) +{ + const COLORFORMAT cf = pSC->m_param.cfColorFormat; + const int cpChroma = cblkChromas[cf] * 16; + size_t i, j, jend = (pSC->m_pNextSC != NULL); + + assert(pSC->m_bSecondary == FALSE); + for (j = 0; j <= jend; j++) { + int cpStride = 16 * 16; + for (i = 0; i < pSC->m_param.cNumChannels; i++) { + pSC->pPlane[i] = pSC->p0MBbuffer[i]; + + pSC->p0MBbuffer[i] += cpStride; + pSC->p1MBbuffer[i] += cpStride; + + cpStride = cpChroma; + } + pSC = pSC->m_pNextSC; + } +} + +/* advance to next MB row */ +Void advanceOneMBRow(CWMImageStrCodec *pSC) +{ + size_t i, j, jend = (pSC->m_pNextSC != NULL); + CWMIPredInfo *pPredInfo; + + for (j = 0; j <= jend; j++) { + for(i = 0; i < pSC->m_param.cNumChannels; i ++){ // swap current row and previous row + pPredInfo = pSC->PredInfo[i]; + pSC->PredInfo[i] = pSC->PredInfoPrevRow[i]; + pSC->PredInfoPrevRow[i] = pPredInfo; + } + pSC = pSC->m_pNextSC; + } +} + +Void swapMRPtr(CWMImageStrCodec* pSC) +{ + PixelI *pTemp[MAX_CHANNELS]; + size_t j, jend = (pSC->m_pNextSC != NULL); + + for (j = 0; j <= jend; j++) { + memcpy (pTemp, pSC->a0MBbuffer, sizeof (pSC->a0MBbuffer)); + memcpy (pSC->a0MBbuffer, pSC->a1MBbuffer, sizeof (pSC->a0MBbuffer)); + memcpy (pSC->a1MBbuffer, pTemp, sizeof (pSC->a0MBbuffer)); + pSC = pSC->m_pNextSC; + } +} + +//================================================================ +// Empty function to fill slot +//================================================================ +Int IDPEmpty(CWMImageStrCodec* pSC) +{ + UNREFERENCED_PARAMETER( pSC ); + + return ICERR_OK; +} + +ERR WMPAlloc(void** ppv, size_t cb) +{ + *ppv = calloc(1, cb); + return *ppv ? WMP_errSuccess : WMP_errOutOfMemory; +} + +ERR WMPFree(void** ppv) +{ + if (*ppv) + { + free(*ppv); + *ppv = NULL; + } + + return WMP_errSuccess; +} + +//================================================================ +// Streaming I/O functions +//================================================================ +ERR CreateWS_File(struct WMPStream** ppWS, const char* szFilename, const char* szMode) +{ + ERR err = WMP_errSuccess; + struct WMPStream* pWS = NULL; + + Call(WMPAlloc((void** )ppWS, sizeof(**ppWS))); + pWS = *ppWS; + + pWS->Close = CloseWS_File; + pWS->EOS = EOSWS_File; + + pWS->Read = ReadWS_File; + pWS->Write = WriteWS_File; + //pWS->GetLine = GetLineWS_File; + + pWS->SetPos = SetPosWS_File; + pWS->GetPos = GetPosWS_File; + +#ifdef WIN32 + FailIf(0 != fopen_s(&pWS->state.file.pFile, szFilename, szMode), WMP_errFileIO); +#else + pWS->state.file.pFile = fopen(szFilename, szMode); + FailIf(NULL == pWS->state.file.pFile, WMP_errFileIO); +#endif + +Cleanup: + return err; +} + +ERR CloseWS_File(struct WMPStream** ppWS) +{ + ERR err = WMP_errSuccess; + struct WMPStream* pWS = *ppWS; + + fclose(pWS->state.file.pFile); + Call(WMPFree((void**)ppWS)); + +Cleanup: + return err; +} + +Bool EOSWS_File(struct WMPStream* pWS) +{ + return feof(pWS->state.file.pFile); +} + +ERR ReadWS_File(struct WMPStream* pWS, void* pv, size_t cb) +{ + // ERR err = WMP_errSuccess; + + return (fread(pv, cb, 1, pWS->state.file.pFile) == 1) ? WMP_errSuccess : WMP_errFileIO; +} + +ERR WriteWS_File(struct WMPStream* pWS, const void* pv, size_t cb) +{ + ERR err = WMP_errSuccess; + + if(0 != cb) + { + FailIf(1 != fwrite(pv, cb, 1, pWS->state.file.pFile), WMP_errFileIO); + } + +Cleanup: + return err; +} + +ERR SetPosWS_File(struct WMPStream* pWS, size_t offPos) +{ + ERR err = WMP_errSuccess; + + FailIf(0 != fseek(pWS->state.file.pFile, (long)offPos, SEEK_SET), WMP_errFileIO); + +Cleanup: + return err; +} + +ERR GetPosWS_File(struct WMPStream* pWS, size_t* poffPos) +{ + ERR err = WMP_errSuccess; + long lOff = 0; + + FailIf(-1 == (lOff = ftell(pWS->state.file.pFile)), WMP_errFileIO); + *poffPos = (size_t)lOff; + +Cleanup: + return err; +} + +//---------------------------------------------------------------- +ERR CreateWS_Memory(struct WMPStream** ppWS, void* pv, size_t cb) +{ + ERR err = WMP_errSuccess; + struct WMPStream* pWS = NULL; + + Call(WMPAlloc((void** )ppWS, sizeof(**ppWS))); + pWS = *ppWS; + + pWS->state.buf.pbBuf = pv; + pWS->state.buf.cbBuf = cb; + pWS->state.buf.cbCur = 0; + + pWS->Close = CloseWS_Memory; + pWS->EOS = EOSWS_Memory; + + pWS->Read = ReadWS_Memory; + pWS->Write = WriteWS_Memory; + + pWS->SetPos = SetPosWS_Memory; + pWS->GetPos = GetPosWS_Memory; + +Cleanup: + return err; +} + +ERR CloseWS_Memory(struct WMPStream** ppWS) +{ + ERR err = WMP_errSuccess; + + Call(WMPFree((void**)ppWS)); + +Cleanup: + return err; +} + +Bool EOSWS_Memory(struct WMPStream* pWS) +{ + return pWS->state.buf.cbBuf <= pWS->state.buf.cbCur; +} + +ERR ReadWS_Memory(struct WMPStream* pWS, void* pv, size_t cb) +{ + ERR err = WMP_errSuccess; + +// FailIf(pWS->state.buf.cbBuf < pWS->state.buf.cbCur, WMP_errBufferOverflow); + if(pWS->state.buf.cbBuf < pWS->state.buf.cbCur) + return err; + + FailIf(pWS->state.buf.cbCur + cb < pWS->state.buf.cbCur, WMP_errBufferOverflow); + if (pWS->state.buf.cbBuf < pWS->state.buf.cbCur + cb) + { + cb = pWS->state.buf.cbBuf - pWS->state.buf.cbCur; + } + + memcpy(pv, pWS->state.buf.pbBuf + pWS->state.buf.cbCur, cb); + pWS->state.buf.cbCur += cb; + +Cleanup: + return err; +} + +ERR WriteWS_Memory(struct WMPStream* pWS, const void* pv, size_t cb) +{ + ERR err = WMP_errSuccess; + + FailIf(pWS->state.buf.cbCur + cb < pWS->state.buf.cbCur, WMP_errBufferOverflow); + FailIf(pWS->state.buf.cbBuf < pWS->state.buf.cbCur + cb, WMP_errBufferOverflow); + + memcpy(pWS->state.buf.pbBuf + pWS->state.buf.cbCur, pv, cb); + pWS->state.buf.cbCur += cb; + +Cleanup: + return err; +} + +ERR SetPosWS_Memory(struct WMPStream* pWS, size_t offPos) +{ + ERR err = WMP_errSuccess; + + //While the following condition is possibly useful, failure occurs + //at the end of a file since packets beyond the end may be accessed + //FailIf(pWS->state.buf.cbBuf < offPos, WMP_errBufferOverflow); + pWS->state.buf.cbCur = offPos; + +//Cleanup: + return err; +} + +ERR GetPosWS_Memory(struct WMPStream* pWS, size_t* poffPos) +{ + *poffPos = pWS->state.buf.cbCur; + + return WMP_errSuccess; +} + +//================================================================= +// Linked list based WMPStream +// - for indefinite size, multiple stream out +// - reads not supported in this mode +//================================================================= +ERR CreateWS_List(struct WMPStream** ppWS) +{ + ERR err = WMP_errSuccess; + struct WMPStream* pWS = NULL; + + Call(WMPAlloc((void** )ppWS, sizeof(**ppWS) + PACKETLENGTH + sizeof(void *))); + pWS = *ppWS; + + pWS->state.buf.pbBuf = (U8 *)pWS + sizeof(**ppWS) + sizeof(void *); // first buffer points here + + memset(pWS->state.buf.pbBuf - sizeof(void *), 0, sizeof(void *)); + pWS->state.buf.cbBuf = PACKETLENGTH; + pWS->state.buf.cbCur = 0; + pWS->state.buf.cbBufCount = 0; + + pWS->Close = CloseWS_List; + pWS->EOS = NULL; // doesn't get called + + pWS->Read = ReadWS_List; + pWS->Write = WriteWS_List; + + pWS->SetPos = SetPosWS_List; + pWS->GetPos = GetPosWS_List; + + //printf ("create buffer %d: %x\n", pWS->state.buf.cbBufCount, pWS->state.buf.pbBuf); + +Cleanup: + return err; +} + +ERR CloseWS_List(struct WMPStream** ppWS) +{ + ERR err = WMP_errSuccess; + + if (ppWS) { + U8 *pBuf = (U8 *)(ppWS[0] + 1); // pointer to buffer + U8 *pNext = (U8 *)(((void **)pBuf)[0]); + while (pNext) { +//struct WMPStream *pWS = ppWS[0]; + pBuf = pNext; + pNext = (U8 *)(((void **)(pBuf))[0]); +//printf ("delete buffer %x\n", pBuf); + Call(WMPFree((void**)&pBuf)); + } + } + Call(WMPFree((void**)ppWS)); + +Cleanup: + return err; +} + +ERR ReadWS_List(struct WMPStream* pWS, void* pv, size_t cb) +{ + ERR err = WMP_errSuccess; + + FailIf(pWS->state.buf.cbCur + cb < pWS->state.buf.cbCur, WMP_errBufferOverflow); + if (pWS->state.buf.cbBuf < pWS->state.buf.cbCur + PACKETLENGTH * pWS->state.buf.cbBufCount + cb) + { + cb = pWS->state.buf.cbBuf - pWS->state.buf.cbCur - PACKETLENGTH * pWS->state.buf.cbBufCount; + } + + while (cb) { + size_t cl = PACKETLENGTH - pWS->state.buf.cbCur; + if (cl > cb) + cl = cb; + memcpy(pv, pWS->state.buf.pbBuf + pWS->state.buf.cbCur, cl); + pWS->state.buf.cbCur += cl; + pv = (void *)((U8 *)pv + cl); + cb -= cl; + if (pWS->state.buf.cbCur == PACKETLENGTH) { + pWS->state.buf.pbBuf = (U8 *)((void **)(pWS->state.buf.pbBuf - sizeof(void *)))[0] + sizeof(void *); + pWS->state.buf.cbCur = 0; + pWS->state.buf.cbBufCount++; + + //printf ("read buffer %d: %x\n", pWS->state.buf.cbBufCount, pWS->state.buf.pbBuf); + } + } + +Cleanup: + return err; +} + +ERR WriteWS_List(struct WMPStream* pWS, const void* pv, size_t cb) +{ + ERR err = WMP_errSuccess; + + FailIf(pWS->state.buf.cbCur + cb < pWS->state.buf.cbCur, WMP_errBufferOverflow); + FailIf(pWS->state.buf.cbBuf < pWS->state.buf.cbCur + cb, WMP_errBufferOverflow); + + while (cb) { + size_t cl = PACKETLENGTH - pWS->state.buf.cbCur; + if (cl > cb) + cl = cb; + memcpy(pWS->state.buf.pbBuf + pWS->state.buf.cbCur, pv, cl); + pWS->state.buf.cbCur += cl; + pv = (const void *)((U8 *)pv + cl); + cb -= cl; + if (pWS->state.buf.cbCur == PACKETLENGTH) { // allocate next packet in list + U8 *pBuf = NULL; + void **pPtrLoc = (void **)(pWS->state.buf.pbBuf - sizeof(void *)); + Call(WMPAlloc((void **)&pBuf, PACKETLENGTH + sizeof(void *))); + pPtrLoc[0] = (void *)pBuf; + pWS->state.buf.pbBuf = pBuf + sizeof(void *); + pWS->state.buf.cbBuf += PACKETLENGTH; + memset(pBuf, 0, sizeof(void *)); + pWS->state.buf.cbCur = 0; + pWS->state.buf.cbBufCount++; + + //printf ("create buffer %d: %x\n", pWS->state.buf.cbBufCount, pWS->state.buf.pbBuf); + } + } + +Cleanup: + return err; +} + +ERR SetPosWS_List(struct WMPStream* pWS, size_t offPos) +{ + ERR err = WMP_errSuccess; + + // get the first buffer + U8 *pBuf = (U8 *)(pWS + 1); // pointer to buffer + pWS->state.buf.cbCur = 0; + pWS->state.buf.cbBufCount = 0; + + while (offPos >= PACKETLENGTH && pBuf != NULL) { + pBuf = (U8 *)(((void **)pBuf)[0]); + offPos -= PACKETLENGTH; + pWS->state.buf.cbBufCount++; + } + + if (pBuf == NULL) + goto Cleanup; + + pWS->state.buf.cbCur = offPos; + pWS->state.buf.pbBuf = pBuf + sizeof(void *); + //printf ("seek buffer %d: %x\n", pWS->state.buf.cbBufCount, pWS->state.buf.pbBuf); + +Cleanup: + return err; +} + +ERR GetPosWS_List(struct WMPStream* pWS, size_t* poffPos) +{ + *poffPos = pWS->state.buf.cbCur + PACKETLENGTH * pWS->state.buf.cbBufCount; + + return WMP_errSuccess; +} + +//================================================================ +// Simple BitIO access functions +//================================================================ +// init SimpleBitIO +ERR attach_SB(SimpleBitIO* pSB, struct WMPStream* pWS) +{ + pSB->pWS = pWS; + pSB->cbRead = 0; + pSB->bAccumulator = 0; + pSB->cBitLeft = 0; + + return WMP_errSuccess; +} + +// extract upto 32bit from input stream +U32 getBit32_SB(SimpleBitIO* pSB, U32 cBits) +{ + U32 rc = 0; + + while (pSB->cBitLeft < cBits) + { + rc <<= pSB->cBitLeft; + rc |= pSB->bAccumulator >> (8 - pSB->cBitLeft); + + cBits -= pSB->cBitLeft; + + pSB->pWS->Read(pSB->pWS, &pSB->bAccumulator, 1); + pSB->cbRead++; + pSB->cBitLeft = 8; + } + + rc <<= cBits; + rc |= pSB->bAccumulator >> (8 - cBits); + pSB->bAccumulator <<= cBits; + pSB->cBitLeft -= cBits; + + return rc; +} + +// ignore input to byte boundary +Void flushToByte_SB(SimpleBitIO* pSB) +{ + pSB->bAccumulator = 0; + pSB->cBitLeft = 0; +} + +// return read byte count +U32 getByteRead_SB(SimpleBitIO* pSB) +{ + return pSB->cbRead; +} + +ERR detach_SB(SimpleBitIO* pSB) +{ + assert(0 == pSB->cBitLeft); + pSB->pWS = NULL; + + return WMP_errSuccess; +} + +//================================================================ +// Memory access functions +//================================================================ +#if (defined(WIN32) && !defined(UNDER_CE)) || (defined(UNDER_CE) && defined(_ARM_)) +// WinCE ARM and Desktop x86 +#else +// other platform +#ifdef _BIG__ENDIAN_ +#define _byteswap_ulong(x) (x) +#else // _BIG__ENDIAN_ +U32 _byteswap_ulong(U32 bits) +{ + U32 r = (bits & 0xffu) << 24; + r |= (bits << 8) & 0xff0000u; + r |= ((bits >> 8) & 0xff00u); + r |= ((bits >> 24) & 0xffu); + + return r; +} +#endif // _BIG__ENDIAN_ +#endif + +U32 load4BE(void* pv) +{ +#ifdef _BIG__ENDIAN_ + return (*(U32*)pv); +#else // _BIG__ENDIAN_ +#if defined(_M_IA64) || defined(_ARM_) + U32 v; + v = ((U16 *) pv)[0]; + v |= ((U32)((U16 *) pv)[1]) << 16; + return _byteswap_ulong(v); +#else // _M_IA64 + return _byteswap_ulong(*(U32*)pv); +#endif // _M_IA64 +#endif // _BIG__ENDIAN_ +} + +#define LOAD16 load4BE + +#ifdef _BIG__ENDIAN_ +#define WRITESWAP_ENDIAN(a) ((a)>>16) +#else // _BIG__ENDIAN_ +#define WRITESWAP_ENDIAN(a) _byteswap_ulong(a) +#endif // _BIG__ENDIAN_ + +//================================================================ +// Bit I/O functions +//================================================================ +Int allocateBitIOInfo(CWMImageStrCodec* pSC) +{ + U32 cNumBitIO; + SUBBAND sbSubband = pSC->WMISCP.sbSubband; + + pSC->cSB = (sbSubband == SB_DC_ONLY ? 1 : (sbSubband == SB_NO_HIGHPASS ? 2 : (sbSubband == SB_NO_FLEXBITS ? 3 : 4))); + + // # of additional BitIOs other than pSC->pIOHeader + if (!pSC->m_param.bIndexTable) { // pure streaming mode, no index table, no additional BitIO! + assert (pSC->WMISCP.bfBitstreamFormat == SPATIAL && pSC->WMISCP.cNumOfSliceMinus1H + pSC->WMISCP.cNumOfSliceMinus1V == 0); + cNumBitIO = 0; + } + else if(pSC->WMISCP.bfBitstreamFormat == SPATIAL) + cNumBitIO = pSC->WMISCP.cNumOfSliceMinus1V + 1; + else + cNumBitIO = (pSC->WMISCP.cNumOfSliceMinus1V + 1) * pSC->cSB; + + if(cNumBitIO > MAX_TILES * 4) + return ICERR_ERROR; + + // allocate additional BitIos + if(cNumBitIO > 0){ + U32 i = 0; + size_t cb = sizeof(BitIOInfo) * cNumBitIO + (PACKETLENGTH * 4 - 1) + PACKETLENGTH * 4 * cNumBitIO; + U8* pb = (U8*)malloc(cb); + + if (NULL == pb) return ICERR_ERROR; + memset(pb, 0, cb); + + pSC->m_ppBitIO = (BitIOInfo**)pb; + pb += sizeof(BitIOInfo) * cNumBitIO; + + pb = (U8*)ALIGNUP(pb, PACKETLENGTH * 4) + PACKETLENGTH * 2; + for (i = 0; i < cNumBitIO; ++i){ + pSC->m_ppBitIO[i] = (BitIOInfo*)pb; + pb += PACKETLENGTH * 4; + } + + // allocate index table + if(cNumBitIO > MAX_TILES * 4 || pSC->WMISCP.cNumOfSliceMinus1H >= MAX_TILES) + return ICERR_ERROR; + pSC->pIndexTable = malloc(cNumBitIO * (pSC->WMISCP.cNumOfSliceMinus1H + 1) * sizeof(size_t)); + if(NULL == pSC->pIndexTable) return ICERR_ERROR; + } + + pSC->cNumBitIO = cNumBitIO; + + return ICERR_OK; +} + +Int setBitIOPointers(CWMImageStrCodec* pSC) +{ + if(pSC->cNumBitIO > 0){ + U32 i; + + for(i = 0; i <= pSC->WMISCP.cNumOfSliceMinus1V; i ++){ + CCodingContext * pContext = &pSC->m_pCodingContext[i]; + if(pSC->WMISCP.bfBitstreamFormat == SPATIAL){ + pContext->m_pIODC = pContext->m_pIOLP = pContext->m_pIOAC = pContext->m_pIOFL = pSC->m_ppBitIO[i]; + } + else{ + U32 j = pSC->cSB; + + pContext->m_pIODC = pSC->m_ppBitIO[i * j]; + if(j > 1) + pContext->m_pIOLP = pSC->m_ppBitIO[i * j + 1]; + if(j > 2) + pContext->m_pIOAC = pSC->m_ppBitIO[i * j + 2]; + if(j > 3) + pContext->m_pIOFL = pSC->m_ppBitIO[i * j + 3]; + } + } + } + else{ // streamimg mode + CCodingContext * pContext = &pSC->m_pCodingContext[0]; + pContext->m_pIODC = pContext->m_pIOLP = pContext->m_pIOAC = pContext->m_pIOFL = pSC->pIOHeader; + } + + return ICERR_OK; +} + +Int allocateTileInfo(CWMImageStrCodec * pSC) +{ + size_t i; + + if(pSC->WMISCP.cNumOfSliceMinus1V >= MAX_TILES) + return ICERR_ERROR; + pSC->pTile = (CWMITile *)malloc((pSC->WMISCP.cNumOfSliceMinus1V + 1) * sizeof(CWMITile)); + if(pSC->pTile == NULL) + return ICERR_ERROR; + memset(pSC->pTile, 0, (pSC->WMISCP.cNumOfSliceMinus1V + 1) * sizeof(CWMITile)); + + for(i = 0; i <= pSC->WMISCP.cNumOfSliceMinus1V; i ++) + pSC->pTile[i].cNumQPHP = pSC->pTile[i].cNumQPLP = 1, pSC->pTile[i].cBitsHP = pSC->pTile[i].cBitsLP = 0; + + return ICERR_OK; +} + +Void freeTileInfo(CWMImageStrCodec * pSC) +{ + size_t iTile; + + if((pSC->m_param.uQPMode & 1) != 0) // not DC uniform + for(iTile = 0; iTile <= pSC->WMISCP.cNumOfSliceMinus1V; iTile ++) + freeQuantizer(pSC->pTile[iTile].pQuantizerDC); + else + freeQuantizer(pSC->pTile[0].pQuantizerDC); + + if(pSC->WMISCP.sbSubband != SB_DC_ONLY) + if((pSC->m_param.uQPMode & 2) != 0) // not LP uniform + for(iTile = 0; iTile <= pSC->WMISCP.cNumOfSliceMinus1V; iTile ++) + freeQuantizer(pSC->pTile[iTile].pQuantizerLP); + else + freeQuantizer(pSC->pTile[0].pQuantizerLP); + + if(pSC->WMISCP.sbSubband != SB_DC_ONLY && pSC->WMISCP.sbSubband != SB_NO_HIGHPASS) + if((pSC->m_param.uQPMode & 4) != 0) // not HP uniform + for(iTile = 0; iTile <= pSC->WMISCP.cNumOfSliceMinus1V; iTile ++) + freeQuantizer(pSC->pTile[iTile].pQuantizerHP); + else + freeQuantizer(pSC->pTile[0].pQuantizerHP); + + if(pSC->pTile != NULL) + free(pSC->pTile); +} + +Int allocateQuantizer(CWMIQuantizer * pQuantizer[MAX_CHANNELS], size_t cChannel, size_t cQP) +{ + size_t iCh; + + if(cQP > 16 || cChannel > MAX_CHANNELS) + return ICERR_ERROR; + pQuantizer[0] = (CWMIQuantizer *)malloc(cQP * sizeof(CWMIQuantizer) * cChannel); + if(pQuantizer[0] == NULL) + return ICERR_ERROR; + + for(iCh = 1; iCh < cChannel; iCh ++) + pQuantizer[iCh] = pQuantizer[iCh - 1] + cQP; + + return ICERR_OK; +} + +Void freeQuantizer(CWMIQuantizer * pQuantizer[MAX_CHANNELS]) +{ + if(pQuantizer[0] != NULL) + free(pQuantizer[0]); +} + +Void formatQuantizer(CWMIQuantizer * pQuantizer[MAX_CHANNELS], U8 cChMode, size_t cCh, size_t iPos, Bool bShiftedUV, + Bool bScaledArith) +{ + size_t iCh; + + for(iCh = 0; iCh < cCh; iCh ++){ + if(iCh > 0) + if(cChMode == 0) // uniform + pQuantizer[iCh][iPos] = pQuantizer[0][iPos]; + else if(cChMode == 1) // mixed + pQuantizer[iCh][iPos] = pQuantizer[1][iPos]; + remapQP(pQuantizer[iCh] + iPos, (iCh > 0 && bShiftedUV == TRUE) ? SHIFTZERO - 1 : SHIFTZERO, bScaledArith); + } +} + +Void setUniformQuantizer(CWMImageStrCodec * pSC, size_t sb) +{ + size_t iCh, iTile; + + for(iCh = 0; iCh < pSC->m_param.cNumChannels; iCh ++) + for(iTile = 1; iTile <= pSC->WMISCP.cNumOfSliceMinus1V; iTile ++) + if(sb == 0) // DC + pSC->pTile[iTile].pQuantizerDC[iCh] = pSC->pTile[0].pQuantizerDC[iCh]; + else if(sb == 1) // LP + pSC->pTile[iTile].pQuantizerLP[iCh] = pSC->pTile[0].pQuantizerLP[iCh]; + else // HP + pSC->pTile[iTile].pQuantizerHP[iCh] = pSC->pTile[0].pQuantizerHP[iCh]; +} + +Void useDCQuantizer(CWMImageStrCodec * pSC, size_t iTile) +{ + size_t iCh; + + for(iCh = 0; iCh < pSC->m_param.cNumChannels; iCh ++) + pSC->pTile[iTile].pQuantizerLP[iCh][0] = *pSC->pTile[iTile].pQuantizerDC[iCh]; +} + +Void useLPQuantizer(CWMImageStrCodec * pSC, size_t cQP, size_t iTile) +{ + size_t iCh, iQP; + + for(iCh = 0; iCh < pSC->m_param.cNumChannels; iCh ++) + for(iQP = 0; iQP < cQP; iQP ++) + pSC->pTile[iTile].pQuantizerHP[iCh][iQP] = pSC->pTile[iTile].pQuantizerLP[iCh][iQP]; +} + +U8 dquantBits(U8 cQP) +{ + return (cQP < 2 ? 0 : (cQP < 4 ? 1 : (cQP < 6 ? 2 : (cQP < 10 ? 3 : 4)))); +} + +#ifndef ARMOPT_BITIO +U32 peekBit16(BitIOInfo* pIO, U32 cBits) +{ + PEEKBIT16(pIO, cBits); +} + +U32 flushBit16(BitIOInfo* pIO, U32 cBits) +{ + FLUSHBIT16(pIO, cBits); +} + +U32 getBit16(BitIOInfo* pIO, U32 cBits) +{ + U32 uiRet = peekBit16(pIO, cBits); + flushBit16(pIO, cBits); + + return uiRet; +} + +U32 getBool16(BitIOInfo* pIO) +{ + U32 uiRet = peekBit16(pIO, 1); + flushBit16(pIO, 1); + return uiRet; +} + +/** this function returns cBits if zero is read, or a signed value if first cBits are not all zero **/ +I32 getBit16s(BitIOInfo* pIO, U32 cBits) +{ + U32 uiRet = peekBit16(pIO, cBits + 1); + if (uiRet < 2) { + flushBit16(pIO, cBits); + return 0; + } + else { + flushBit16(pIO, cBits + 1); + if (uiRet & 1) + return (-(I32)(uiRet >> 1)); + else + return (I32)(uiRet >> 1); + } +} + +U32 getBit32(BitIOInfo* pIO, U32 cBits) +{ + U32 uiRet = 0; + + assert(0 <= (I32)cBits && cBits <= 32); + + if (16 < cBits) + { + uiRet = getBit16(pIO, 16); + cBits -= 16; + uiRet <<= cBits; + } + + uiRet |= getBit16(pIO, cBits); + + return uiRet; +} + +U32 flushToByte(BitIOInfo* pIO) +{ + return flushBit16(pIO, (16 - pIO->cBitsUsed) & 7); +} +#endif // ARMOPT_BITIO + +//---------------------------------------------------------------- +Void putBit16z(BitIOInfo* pIO, U32 uiBits, U32 cBits) +{ + assert(cBits <= 16); + assert(0 == uiBits >> cBits); + + pIO->uiAccumulator = (pIO->uiAccumulator << cBits) | uiBits; + pIO->cBitsUsed += cBits; + + *(U16*)pIO->pbCurrent = (U16)WRITESWAP_ENDIAN(pIO->uiAccumulator << (32 - pIO->cBitsUsed)); + + pIO->pbCurrent = MASKPTR(pIO->pbCurrent + ((pIO->cBitsUsed >> 3) & 2), pIO->iMask); + pIO->cBitsUsed &= 16 - 1; +} + +Void putBit16(BitIOInfo* pIO, U32 uiBits, U32 cBits) +{ + assert(cBits <= 16); + + uiBits &= ~(-1 << cBits); + putBit16z(pIO, uiBits, cBits); +} + +Void putBit32(BitIOInfo* pIO, U32 uiBits, U32 cBits) +{ + assert(0 <= (I32)cBits && cBits <= 32); + + if (16 < cBits) + { + putBit16(pIO, uiBits >> (cBits - 16), 16); + cBits -= 16; + } + + putBit16(pIO, uiBits, cBits); +} + +Void fillToByte(BitIOInfo* pIO) +{ + putBit16z(pIO, 0, (16 - pIO->cBitsUsed) & 7); +} + +//---------------------------------------------------------------- +U32 getBit16_S(CWMImageStrCodec* pSC, BitIOInfo* pIO, U32 cBits) +{ + U32 rc = getBit16(pIO, cBits); + readIS_L1(pSC, pIO); + + return rc; +} + +U32 putBit16_S(CWMImageStrCodec* pSC, BitIOInfo* pIO, U32 uiBits, U32 cBits) +{ + putBit16(pIO, uiBits, cBits); + writeIS_L1(pSC, pIO); + + return 0; +} + + +//---------------------------------------------------------------- +// Query buffered data size held in BitIOInfo +// Write() for Enc, Read() for Dec +//---------------------------------------------------------------- +U32 getSizeRead(BitIOInfo* pIO) +{ + return (U32)(UINTPTR_T)(pIO->pbStart + PACKETLENGTH * 2 - pIO->pbCurrent) - pIO->cBitsUsed / 8; +} + +U32 getSizeWrite(BitIOInfo* pIO) +{ + return (U32)(UINTPTR_T)(pIO->pbCurrent + (pIO->pbStart <= pIO->pbCurrent ? 0 : PACKETLENGTH * 2) - pIO->pbStart) + pIO->cBitsUsed / 8; +} + +//---------------------------------------------------------------- +// Query stream offset from attached BitIO object for dec +//---------------------------------------------------------------- +U32 getPosRead(BitIOInfo* pIO) +{ + size_t cbCached = (pIO->pbStart + PACKETLENGTH * 2 - pIO->pbCurrent) - pIO->cBitsUsed / 8; + return (U32)(pIO->offRef - cbCached); +} + +//================================================================ +// Block I/O functions +//================================================================ +#ifndef ARMOPT_BITIO +ERR attachISRead(BitIOInfo* pIO, struct WMPStream* pWS, CWMImageStrCodec* pSC) +{ + UNREFERENCED_PARAMETER( pSC ); + + pWS->GetPos(pWS, &pIO->offRef); + + pIO->pbStart = (U8*)pIO - PACKETLENGTH * 2; + pIO->pbCurrent = pIO->pbStart; + + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + pWS->SetPos(pWS, pIO->offRef); + pWS->Read(pWS, pIO->pbStart, PACKETLENGTH * 2); + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + pIO->offRef += PACKETLENGTH * 2; + + pIO->uiAccumulator = load4BE(pIO->pbStart); + + pIO->cBitsUsed = 0; + pIO->iMask = ~(PACKETLENGTH * 2); + pIO->iMask &= ~1; + + pIO->pWS = pWS; + return WMP_errSuccess; +} + +ERR readIS(CWMImageStrCodec* pSC, BitIOInfo* pIO) +{ + ERR err = WMP_errSuccess; + + UNREFERENCED_PARAMETER( pSC ); + + if (PACKET1(pIO->pbStart, pIO->pbCurrent, PACKETLENGTH)) + { + struct WMPStream *pWS = pIO->pWS; + + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + //Call(0 != pIO->pWS->Read(pIO->pWS, pIO->pbStart, PACKETLENGTH)); + // TODO: add error checking code + pWS->SetPos(pWS, pIO->offRef); + pWS->Read(pWS, pIO->pbStart, PACKETLENGTH); + pIO->offRef += PACKETLENGTH; + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + + // make shadow copy for first 4B + pIO->uiShadow = *(U32*)pIO->pbStart; + + // reposition pbPacket pointer + pIO->pbStart = MASKPTR(pIO->pbStart + PACKETLENGTH, pIO->iMask); + } + +//Cleanup: + return err; +} + +ERR detachISRead(CWMImageStrCodec* pSC, BitIOInfo* pIO) +{ + ERR err = WMP_errSuccess; + + struct WMPStream* pWS = pIO->pWS; + size_t cbRemain = 0; + + // we can ONLY detach IStream at byte boundary + flushToByte(pIO); + assert(0 == (pIO->cBitsUsed % 8)); + Call(readIS_L1(pSC, pIO)); + + // set stream to right offset, undo buffering + cbRemain = (pIO->pbStart + PACKETLENGTH * 2) - (pIO->pbCurrent + pIO->cBitsUsed / 8); + pWS->SetPos(pWS, pIO->offRef - cbRemain); + + pIO->pWS = NULL; +Cleanup: + return err; +} +#endif // ARMOPT_BITIO + +//---------------------------------------------------------------- +ERR attachISWrite(BitIOInfo* pIO, struct WMPStream* pWS) +{ + pWS->GetPos(pWS, &pIO->offRef); + + pIO->pbStart = (U8*)pIO - PACKETLENGTH * 2; + pIO->pbCurrent = pIO->pbStart; + + pIO->uiAccumulator = 0; + pIO->cBitsUsed = 0; + pIO->iMask = ~(PACKETLENGTH * 2); + + pIO->pWS = pWS; + return WMP_errSuccess; +} + +// write out packet if we have >=1 packet data filled +ERR writeIS(CWMImageStrCodec* pSC, BitIOInfo* pIO) +{ + ERR err = WMP_errSuccess; + + UNREFERENCED_PARAMETER( pSC ); + + if (PACKET1(pIO->pbStart, pIO->pbCurrent, PACKETLENGTH)) + { + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + err = pIO->pWS->Write(pIO->pWS, pIO->pbStart, PACKETLENGTH); + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + Call(err); + + // reposition pbStart pointer + pIO->pbStart = MASKPTR(pIO->pbStart + PACKETLENGTH, pIO->iMask); + } + +Cleanup: + return err; +} + +// write out partially filled buffer and detach bitIO from IStream +ERR detachISWrite(CWMImageStrCodec* pSC, BitIOInfo* pIO) +{ + ERR err = WMP_errSuccess; + + // we can ONLY detach IStream at byte boundary + assert(0 == (pIO->cBitsUsed % 8)); + Call(writeIS_L1(pSC, pIO)); + + PERFTIMER_STOP(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + err = pIO->pWS->Write(pIO->pWS, pIO->pbStart, pIO->pbCurrent + pIO->cBitsUsed / 8 - pIO->pbStart); + PERFTIMER_START(pSC->m_fMeasurePerf, pSC->m_ptEncDecPerf); + Call(err); + + pIO->pWS = NULL; +Cleanup: + return err; +} + +//========================= +// Performance Measurement +//========================= +#ifndef DISABLE_PERF_MEASUREMENT + +void OutputIndivPerfTimer(struct PERFTIMERSTATE *pPerfTimer, + char *pszTimerName, + char *pszDescription, + float fltMegaPixels) +{ + PERFTIMERRESULTS rResults; + Bool fResult; + + fResult = FALSE; + printf("%s (%s): ", pszTimerName, pszDescription); + if (pPerfTimer) + { + fResult = PerfTimerGetResults(pPerfTimer, &rResults); + if (fResult) + { + printf("%.3f milliseconds, %.6f MP/sec\n", (float)rResults.iElapsedTime / 1000000, + 1000000000 * fltMegaPixels / rResults.iElapsedTime); + if (rResults.iZeroTimeIntervals > 0) + { + printf(" *** WARNING: %d time intervals were measured as zero. " + "This perf timer has insufficient precision!\n\n", + (int) rResults.iZeroTimeIntervals); + } + } + } + if (FALSE == fResult) + printf("Results not available!\n"); +} + + +void OutputPerfTimerReport(CWMImageStrCodec *pState) +{ + float fltMegaPixels; + + assert(pState->m_fMeasurePerf); + + printf("***************************************************************************\n"); + printf("* Perf Report\n"); + printf("***************************************************************************\n\n"); + + fltMegaPixels = (float)pState->WMII.cWidth * pState->WMII.cHeight / 1000000; + printf("Image Width = %d, Height = %d, total MegaPixels = %.1f MP\n", + (int) pState->WMII.cWidth, (int) pState->WMII.cHeight, fltMegaPixels); + + OutputIndivPerfTimer(pState->m_ptEncDecPerf, "m_ptEncDecPerf", "excl I/O", fltMegaPixels); + OutputIndivPerfTimer(pState->m_ptEndToEndPerf, "m_ptEndToEndPerf", "incl I/O", fltMegaPixels); +} + +#endif // DISABLE_PERF_MEASUREMENT diff --git a/libs/jxr/image/sys/strcodec.h b/libs/jxr/image/sys/strcodec.h new file mode 100644 index 00000000000..121e32b1346 --- /dev/null +++ b/libs/jxr/image/sys/strcodec.h @@ -0,0 +1,678 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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. +// +//*@@@---@@@@****************************************************************** +#pragma once + +#include + +#include "windowsmediaphoto.h" +#include "common.h" +// #include "xplatform_image.h" + +// added for Xcode PK universal binary +#ifdef __ppc__ +#define _BIG__ENDIAN_ +#endif + +//================================================================ +#ifdef ENABLE_OPTIMIZATIONS +#if defined(WIN32) && !defined(_WIN64) +#define WMP_OPT_SSE2 + +#define WMP_OPT_CC_ENC +//#define WMP_OPT_TRFM_ENC +//#define WMP_OPT_QT + +#define WMP_OPT_CC_DEC +#define WMP_OPT_TRFM_DEC + +#define X86OPT_INLINE + +#endif +#endif // ENABLE_OPTIMIZATIONS + +//================================================================ +//#ifdef WIN32 +#if defined(WIN32) && !defined(UNDER_CE) // WIN32 seems to be defined always in VS2005 for ARM platform +#define PLATFORM_X86 +#include "../x86/x86.h" +#endif + +#ifndef UNREFERENCED_PARAMETER +#define UNREFERENCED_PARAMETER(P) { (P) = (P); } +#endif + +#ifdef UNDER_CE +#define PLATFORM_WCE +#include "arm.h" +#endif + +#ifdef __ANSI__ +#define PLATFORM_ANSI +#include "ansi.h" +#endif + +//================================================================ + +#ifdef PLATFORM_ANSI +typedef unsigned long long U64; +#else // PLATFORM_ANSI +typedef unsigned __int64 U64; +#endif // PLATFORM_ANSI + +//================================================================ +#define MARKERCOUNT (PACKETLENGTH * 2) + +// The following macros depend on UINTPTR_T and INTPTR_T being properly defined +// so that they are equal to pointer width. Confirm and fail if our assumptions are wrong. +CT_ASSERT(sizeof(UINTPTR_T) == sizeof(void*), strcodec1); +CT_ASSERT(sizeof(INTPTR_T) == sizeof(void*), strcodec2); + +// wrap around pointer, s=pow(2,n), p wraps aligned to s +#define WRAPPTR(p, s) ((void*)((UINTPTR_T)(p) & ~(UINTPTR_T)(s))) + +// mask certain bit inside a pointer, simulate wrap around +#define MASKPTR(p, m) ((void*)((UINTPTR_T)(p) & (INTPTR_T)(m))) + +// test for more than 1 packet data +#define PACKET1(ps, pc, s) (((INTPTR_T)(ps) ^ (INTPTR_T)(pc)) & ((UINTPTR_T)(s))) + +// alternate pointer p between 2 values aligned to s, s=pow(2,n) +//#define ALTPTR(p, s) ((void*)((uintptr_t)(p) ^ (s))) + +// align point, s=pow(2,n), p aligns to s +#define ALIGNUP(p, s) ((void*)(((UINTPTR_T)(p) + ((UINTPTR_T)(s) - 1)) & ~((UINTPTR_T)(s) - 1))) +#define ALIGNDOWN(p, s) ((void*)((UINTPTR_T)(p) & ~((UINTPTR_T)(s) - 1))) + +//================================================================ +// timer support +//================================================================ + +#define TraceResult(a) + +//================================================================ +typedef enum tagPacketType +{ + PK_NULL = 0, + PK_DC = 1, PK_AD, PK_AC, PK_CP, + PK_MAX, +} PACKETTYPE; + +typedef struct tagIOContext +{ + U8 P0[PACKETLENGTH]; // packet circular buffer 0 + U8 P1[PACKETLENGTH]; // packet circular buffer 1 + + union + { + U8 P2[PACKETLENGTH]; + struct + { + U32 uiShadow; // shadow of P0[0]-P0[3] + + U32 uiAccumulator; // 32bit acc as bit field cache + U32 cBitsUsed; // # of bits used of acc, [0,16) + + U8* pbPacket; // packet pointer + U8* pbCurrent; // current pointer + + struct WMPStream* pWS; // pointer to WMPStream + long offPacket; // byte offset into stream + + //ULARGE_INTEGER u64Acc; + + //======================================== + // index packet, used for packet retrieval + //======================================== + U32 cIndex; // current index for index packet + long offIndex; // byte offset into stream for index packet + }State; + }P2Info; + U8 P3[PACKETLENGTH]; // index packet buffer +} IOContext; + +typedef struct tagMemReadState +{ + U8* pbBuf; + size_t cbBuf; + size_t cbCur; +} MemReadState; + +typedef struct tagBitIOInfo +{ + U32 uiShadow; // shadow of first 4B of circular buffer + + U32 uiAccumulator; // 32bit acc as bit field cache + U32 cBitsUsed; // # of bits used of acc, [0,16) +#ifdef ARMOPT_BITIO + U32 cBitsUnused; // # of bits remain unused in acc, [0,32] +#endif + + I32 iMask; // mask used simulate pointer wrap around + + U8* pbStart; // start pointer +#ifndef ARMOPT_BITIO + U8* pbCurrent; // current pointer +#else + U32* pbCurrent; // current pointer +#endif + + struct WMPStream* pWS; // pointer to WMPStream + size_t offRef; // reference offset on IStream, + // for read, it moves along the stream + // for write, it stays at the attach point +} BitIOInfo; + +//================================================================ +typedef struct tagCWMIQuantizer { + U8 iIndex; + I32 iQP; + I32 iOffset; + I32 iMan; + I32 iExp; +#if defined(WMP_OPT_QT) + float f1_QP; + double d1_QP; +#endif +} CWMIQuantizer; + +/* temporary bridge between old APIs and streaming APIs */ +typedef struct tagCWMIMBInfo { + I32 iBlockDC[MAX_CHANNELS][16]; + I32 iOrientation; + Int iCBP[MAX_CHANNELS]; + Int iDiffCBP[MAX_CHANNELS]; + U8 iQIndexLP; // 0 - 15 + U8 iQIndexHP; // 0 - 15 +} CWMIMBInfo; + +struct CWMImageStrCodec; + +typedef Int (*ImageDataProc)(struct CWMImageStrCodec*); + +/** scan model **/ +typedef struct CAdaptiveScan { + U32 uTotal; + U32 uScan; +} CAdaptiveScan; + +/** Adaptive context model **/ +typedef struct CCodingContext { + BitIOInfo * m_pIODC; + BitIOInfo * m_pIOLP; + BitIOInfo * m_pIOAC; + BitIOInfo * m_pIOFL; + + /** adaptive huffman structs **/ + CAdaptiveHuffman *m_pAdaptHuffCBPCY; + CAdaptiveHuffman *m_pAdaptHuffCBPCY1; + CAdaptiveHuffman *m_pAHexpt[NUMVLCTABLES]; + + /** 4x4 zigzag patterns */ + CAdaptiveScan m_aScanLowpass[16]; + CAdaptiveScan m_aScanHoriz[16]; + CAdaptiveScan m_aScanVert[16]; + + /** Adaptive bit reduction model **/ + CAdaptiveModel m_aModelAC; + CAdaptiveModel m_aModelLP; + CAdaptiveModel m_aModelDC; + + /** Adaptive lowpass CBP model **/ + Int m_iCBPCountZero; + Int m_iCBPCountMax; + + /** Adaptive AC CBP model **/ + CCBPModel m_aCBPModel; + + /** Trim flex bits - externally set **/ + Int m_iTrimFlexBits; + + Bool m_bInROI; // inside ROI (for region decode and compressed domain cropping)? +} CCodingContext; + +// Following stuff used to be in strPredQuant.h +/* circulant buffer for 2 MB rows: current row and previous row */ +typedef struct tagCWMIPredInfo { + Int iQPIndex; // QP Index + Int iCBP; // coded block pattern + PixelI iDC; // DC of MB + PixelI iAD[6]; + PixelI * piAD; // AC of DC block: [2] 420UV [4] 422UV [6] elsewhere +}CWMIPredInfo; + +// the following is used on decode side while reading image info +typedef struct CWMImageStrCodecParameters { + size_t cVersion; + size_t cSubVersion; + COLORFORMAT cfColorFormat; // color format + Bool bRBSwapped; // blue and red shall be swapped in BGR555,565,101010 + Bool bAlphaChannel; // alpha channel present + Bool bScaledArith; // lossless mode + Bool bIndexTable; // index table present + Bool bTrimFlexbitsFlag; // trimmed flexbits indicated in packet header + Bool bUseHardTileBoundaries; //default is soft tile boundaries + size_t cNumChannels; + size_t cExtraPixelsTop; + size_t cExtraPixelsLeft; + size_t cExtraPixelsBottom; + size_t cExtraPixelsRight; + Bool bTranscode; // transcoding flag + U32 uQPMode; // 0/1: no dquant/with dquant, first bit for DC, second bit for LP, third bit for HP + U8 uiQPIndexDC[MAX_CHANNELS]; + U8 uiQPIndexLP[MAX_CHANNELS]; + U8 uiQPIndexHP[MAX_CHANNELS]; +}CCoreParameters; + +typedef struct CWMITile +{ + CWMIQuantizer * pQuantizerDC[MAX_CHANNELS]; + CWMIQuantizer * pQuantizerLP[MAX_CHANNELS]; + CWMIQuantizer * pQuantizerHP[MAX_CHANNELS]; + U8 cNumQPLP; + U8 cNumQPHP; + U8 cBitsLP; + U8 cBitsHP; + + Bool bUseDC; + Bool bUseLP; + U8 cChModeDC; + U8 cChModeLP[16]; + U8 cChModeHP[16]; +} CWMITile; + +#ifdef ARMOPT_COLORCONVERSION_C +#include "ARM_InvColorConversion.h" +#endif + +struct tagPostProcInfo{ + Int iMBDC; // DC of MB + U8 ucMBTexture; // MB texture : 0(flat) 1(horizontal) 2(vertical) 3(bumpy) + Int iBlockDC[4][4]; // DC of block + U8 ucBlockTexture[4][4]; // block texture: 0(flat) 1(horizontal) 2(vertical) 3(bumpy) +}; + +typedef struct CWMImageStrCodec { +#ifdef ARMOPT_COLORCONVERSION_C + CWMImageStrInvCCParam InvCCParam; +#endif + + size_t cbStruct; + + CWMImageInfo WMII; + CWMIStrCodecParam WMISCP; + CWMImageBufferInfo WMIBI; + CWMIMBInfo MBInfo; + + /** core parameters **/ + CCoreParameters m_param; + + struct CWMDecoderParameters *m_Dparam; // this is specified thru pointer because the same set of parameters may be used by multiple image planes + + U8 cSB; + + Bool m_bUVResolutionChange; + + Bool bTileExtraction; + + BitIOInfo * pIOHeader; + + Bool bUseHardTileBoundaries; //default is soft tile boundaries + + PixelI * pInterU; + PixelI * pInterV; + + //============== tile related info begins here =========== + // index table + size_t *pIndexTable; + + // current tile position + size_t cTileRow; + size_t cTileColumn; + + // tile boundary + Bool m_bCtxLeft; + Bool m_bCtxTop; + + Bool m_bResetRGITotals; + Bool m_bResetContext; + + CWMITile * pTile; + + // BitIOs + BitIOInfo ** m_ppBitIO; + size_t cNumBitIO; + size_t cHeaderSize; + + // coding contexts + struct CCodingContext *m_pCodingContext; + size_t cNumCodingContext; + + //============== tile related info ends here =========== + + size_t cNumOfQPIndex; // number of QP indexes + U8 cBitsDQUANT; // number of bits to encode DQUANT + + size_t cRow; // row for current macro block + size_t cColumn; // column for current macro block + + size_t cmbWidth; // macro block/image width + size_t cmbHeight; // macro block/image height + + size_t cbChannel; // byte/channel + + size_t mbX, mbY; + size_t tileX, tileY; + Bool bVertTileBoundary, bHoriTileBoundary; + Bool bOneMBLeftVertTB, bOneMBRightVertTB; //Macroblock to the left and to the right of tile boundaries + + PixelI iPredBefore[2][2]; + PixelI iPredAfter[2][2]; + + //================================ + // input data into + // macro block 3 of 2x2 working widow + //================================ + ImageDataProc Load; + //ImageDataProc Load2; + ImageDataProc Transform; + ImageDataProc TransformCenter; + + //================================ + ImageDataProc Quantize; + //ImageDataProc QuantizeLuma; + //ImageDataProc QuantizeChroma; + + //================================ + // process and store data from + // macro block 0 of 2x2 working window + //================================ + ImageDataProc ProcessTopLeft; + ImageDataProc ProcessTop; + ImageDataProc ProcessTopRight; + ImageDataProc ProcessLeft; + ImageDataProc ProcessCenter; + ImageDataProc ProcessRight; + ImageDataProc ProcessBottomLeft; + ImageDataProc ProcessBottom; + ImageDataProc ProcessBottomRight; + + + //================================ + // 2 MB working window for encoder + //================================ + PixelI *pPlane[MAX_CHANNELS]; + + //================================ + // 2 rows of MB buffer + //================================ + PixelI *a0MBbuffer[MAX_CHANNELS]; // pointer to start of previous MB row + PixelI *a1MBbuffer[MAX_CHANNELS]; // pointer to start of current MB row + PixelI *p0MBbuffer[MAX_CHANNELS]; // working pointer to start of previous row MB + PixelI *p1MBbuffer[MAX_CHANNELS]; // working pointer to start of current row MB + + //================================ + // downsampling buffer for UV + //================================ + PixelI * pResU; + PixelI * pResV; + + //================================ + // circular buffer for 2 MB rows: current row and previous row + //================================ + CWMIPredInfo *PredInfo[MAX_CHANNELS]; + CWMIPredInfo *PredInfoPrevRow[MAX_CHANNELS]; + CWMIPredInfo *pPredInfoMemory; + + struct WMPStream ** ppWStream; + +#ifdef _WINDOWS_ + TCHAR **ppTempFile; +#else + char **ppTempFile; +#endif + + // interleaved alpha support - linked structure for Alpha channel + struct CWMImageStrCodec *m_pNextSC; + Bool m_bSecondary; + + //================================ + // Perf Timers + //================================ +#ifndef DISABLE_PERF_MEASUREMENT + Bool m_fMeasurePerf; + struct PERFTIMERSTATE *m_ptEndToEndPerf; // Measures from Init to Term, including I/O + struct PERFTIMERSTATE *m_ptEncDecPerf; // Measures time spent in ImageStrEncEncode/ImageStrDecDecode, excluding I/O +#endif // DISABLE_PERF_MEASUREMENT + + // postproc information for 2 MB rows: 0(previous row) 1(current row) + struct tagPostProcInfo * pPostProcInfo[MAX_CHANNELS][2]; +} CWMImageStrCodec; + + +//================================================================ +ERR WMPAlloc(void** ppv, size_t cb); +ERR WMPFree(void** ppv); + +//================================================================ +Void initMRPtr(CWMImageStrCodec*); +Void advanceMRPtr(CWMImageStrCodec*); +Void swapMRPtr(CWMImageStrCodec*); + +Int IDPEmpty(CWMImageStrCodec*); + +//================================================================ +extern const int dctIndex[3][16]; +extern const int blkOffset[16]; +extern const int blkOffsetUV[4]; +extern const int blkOffsetUV_422[8]; + +extern const U8 idxCC[16][16]; +extern const U8 idxCC_420[8][8]; + +extern const Char gGDISignature[]; + +//================================================================ +Int allocatePredInfo(CWMImageStrCodec*); +Void freePredInfo(CWMImageStrCodec*); +Void advanceOneMBRow(CWMImageStrCodec*); + +//================================================================ +// bit I/O +//================================================================ +Int allocateBitIOInfo(CWMImageStrCodec*); +Int setBitIOPointers(CWMImageStrCodec* pSC); + +#ifndef ARMOPT_BITIO +U32 peekBit16(BitIOInfo* pIO, U32 cBits); +U32 flushBit16(BitIOInfo* pIO, U32 cBits); +U32 getBit16(BitIOInfo* pIO, U32 cBits); +U32 getBool16(BitIOInfo* pIO); +I32 getBit16s(BitIOInfo* pIO, U32 cBits); +U32 getBit32(BitIOInfo* pIO, U32 cBits); +U32 flushToByte(BitIOInfo* pIO); +#endif // ARMOPT_BITIO + +Void putBit16z(BitIOInfo* pIO, U32 uiBits, U32 cBits); +Void putBit16(BitIOInfo* pIO, U32 uiBits, U32 cBits); +Void putBit32(BitIOInfo* pIO, U32 uiBits, U32 cBits); +Void fillToByte(BitIOInfo* pIO); + +U32 getSizeRead(BitIOInfo* pIO); +U32 getSizeWrite(BitIOInfo* pIO); + +U32 getPosRead(BitIOInfo* pIO); + +// safe function, solely for the convenience of test code +#ifndef ARMOPT_BITIO +U32 getBit16_S(CWMImageStrCodec* pSC, BitIOInfo* pIO, U32 cBits); +#endif // ARMOPT_BITIO + +//================================================================ +// packet I/O +//================================================================ +ERR attachISRead(BitIOInfo* pIO, struct WMPStream* pWS, CWMImageStrCodec* pSC); +ERR readIS(CWMImageStrCodec* pSC, BitIOInfo* pIO); +ERR detachISRead(CWMImageStrCodec* pSC, BitIOInfo* pIO); + +ERR attachISWrite(BitIOInfo* pIO, struct WMPStream* pWS); +ERR writeIS(CWMImageStrCodec* pSC, BitIOInfo* pIO); +ERR detachISWrite(CWMImageStrCodec* pSC, BitIOInfo* pIO); + + +//================================================================ +// post processing for decoder +//================================================================ +Int initPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t mbWidth, size_t iNumChannels); +Void termPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t iNumChannels); +Void slideOneMBRow(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t iNumChannels, size_t mbWidth, Bool top, Bool bottom); +Void updatePostProcInfo(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p, size_t mbX, size_t cc); +Void postProcMB(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p0, PixelI * p1, size_t mbX, size_t cc, Int threshold); +Void postProcBlock(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p0, PixelI * p1, size_t mbX, size_t cc, Int threshold); + +//================================================================ +// Simple BitIO access functions +//================================================================ +typedef struct tagSimpleBitIO +{ + struct WMPStream* pWS; + U32 cbRead; + U8 bAccumulator; + U32 cBitLeft; +} SimpleBitIO; + +ERR attach_SB(SimpleBitIO* pSB, struct WMPStream* pWS); +U32 getBit32_SB(SimpleBitIO* pSB, U32 cBits); +Void flushToByte_SB(SimpleBitIO* pSB); +U32 getByteRead_SB(SimpleBitIO* pSB); +ERR detach_SB(SimpleBitIO* pSB); + +//---------------------------------------------------------------- +EXTERN_C Bool EOSWS_File(struct WMPStream* pWS); + +EXTERN_C ERR ReadWS_File(struct WMPStream* pWS, void* pv, size_t cb); +EXTERN_C ERR WriteWS_File(struct WMPStream* pWS, const void* pv, size_t cb); +//EXTERN_C ERR GetLineWS_File(struct WMPStream* pWS, void* pv, size_t cb); + +EXTERN_C ERR SetPosWS_File(struct WMPStream* pWS, size_t offPos); +EXTERN_C ERR GetPosWS_File(struct WMPStream* pWS, size_t* poffPos); + +//---------------------------------------------------------------- +EXTERN_C Bool EOSWS_Memory(struct WMPStream* pWS); + +EXTERN_C ERR ReadWS_Memory(struct WMPStream* pWS, void* pv, size_t cb); +EXTERN_C ERR WriteWS_Memory(struct WMPStream* pWS, const void* pv, size_t cb); +//EXTERN_C ERR GetLineWS_Memory(struct WMPStream* pWS, void* pv, size_t cb); + +EXTERN_C ERR SetPosWS_Memory(struct WMPStream* pWS, size_t offPos); +EXTERN_C ERR GetPosWS_Memory(struct WMPStream* pWS, size_t* poffPos); + +//EXTERN_C ERR GetPtrWS_Memory(struct WMPStream* pWS, size_t align, U8** ppb); +//---------------------------------------------------------------- +EXTERN_C Bool EOSWS_List(struct WMPStream* pWS); + +EXTERN_C ERR ReadWS_List(struct WMPStream* pWS, void* pv, size_t cb); +EXTERN_C ERR WriteWS_List(struct WMPStream* pWS, const void* pv, size_t cb); + +EXTERN_C ERR SetPosWS_List(struct WMPStream* pWS, size_t offPos); +EXTERN_C ERR GetPosWS_List(struct WMPStream* pWS, size_t* poffPos); + +EXTERN_C ERR CreateWS_List(struct WMPStream** ppWS); +EXTERN_C ERR CloseWS_List(struct WMPStream** ppWS); + +/********************************************************************/ +// Stuff related to scale/spatial ordering +typedef struct PacketInfo +{ + BAND m_iBand; + size_t m_iSize; + size_t m_iOffset; + struct PacketInfo *m_pNext; +} PacketInfo; +/********************************************************************/ + +/********************************************************************/ +const static Int blkIdxByRow[4][4] = {{0, 1, 4, 5}, {2, 3, 6, 7}, {8, 9, 12, 13}, {10, 11, 14, 15}}; +const static Int blkIdxByColumn[4][4] = {{0, 2, 8, 10}, {1, 3, 9, 11},{4, 6, 12, 14},{5, 7, 13, 15}}; + +Int getACPredMode(CWMIMBInfo *, COLORFORMAT); +Int getDCACPredMode(CWMImageStrCodec *, size_t); +Void updatePredInfo(CWMImageStrCodec* pSC, CWMIMBInfo *, size_t, COLORFORMAT); + +Int AllocateCodingContextDec(struct CWMImageStrCodec *pSC, Int iNumContexts); +Void ResetCodingContext(CCodingContext *pContext); +Void getTilePos(CWMImageStrCodec* pSC, size_t mbX, size_t mbY); +Void InitZigzagScan(CCodingContext * pSC); +Int checkImageBuffer(CWMImageStrCodec *, size_t, size_t); + +//U32 log2(U32); + +//DQUANT stuff +EXTERN_C Void remapQP(CWMIQuantizer *, I32, Bool); +Int allocateTileInfo(CWMImageStrCodec *); +Void freeTileInfo(CWMImageStrCodec *); +Int allocateQuantizer(CWMIQuantizer * pQuantizer[MAX_CHANNELS], size_t, size_t); +Void freeQuantizer(CWMIQuantizer * pQuantizer[MAX_CHANNELS]); +Void setUniformQuantizer(CWMImageStrCodec *, size_t); +Void useDCQuantizer(CWMImageStrCodec *, size_t); +Void useLPQuantizer(CWMImageStrCodec *, size_t, size_t); +Void formatQuantizer(CWMIQuantizer * pQuantizer[MAX_CHANNELS], U8, size_t, size_t, Bool, Bool); +U8 dquantBits(U8); + +#ifdef ARMOPT_BITIO +#define peekBit16 peekBits +#define flushBit16 flushBits +#define getBit16 getBits +#define getBit32 getBits +#define getBit16s getBitsS +#define getBool16(pIO) getBits(pIO, 1) + +U32 peekBits(BitIOInfo* pIO, U32 cBits); +void flushBits(BitIOInfo* pIO, U32 cBits); +U32 getBits(BitIOInfo* pIO, U32 cBits); +U32 getBitsS(BitIOInfo* pIO, U32 cBits); +void flushToByte(BitIOInfo* pIO); +#endif // ARMOPT_BITIO + +/************************************************************************* + Bitio defines +*************************************************************************/ +#define PEEKBIT16(pIO, cBits) \ + assert(0 <= (I32)cBits && cBits <= 16);\ + return (pIO->uiAccumulator >> (32 - cBits/* - pIO->cBitsUsed*/)); + +#define FLUSHBIT16(pIO, cBits) \ + assert(0 <= (I32)cBits && cBits <= 16);\ + assert((pIO->iMask & 1) == 0);\ + pIO->cBitsUsed += cBits;\ + pIO->pbCurrent = MASKPTR(pIO->pbCurrent + ((pIO->cBitsUsed >> 3)/* & 2*/), pIO->iMask);\ + pIO->cBitsUsed &= 16 - 1;\ + pIO->uiAccumulator = LOAD16(pIO->pbCurrent) << pIO->cBitsUsed;\ + return 0; +// pIO->uiAccumulator = LOAD16(pIO->pbCurrent) & ((U32)(-1) >> pIO->cBitsUsed);\ + +void OutputPerfTimerReport(CWMImageStrCodec *pState); diff --git a/libs/jxr/image/sys/windowsmediaphoto.h b/libs/jxr/image/sys/windowsmediaphoto.h new file mode 100644 index 00000000000..fb9768b558c --- /dev/null +++ b/libs/jxr/image/sys/windowsmediaphoto.h @@ -0,0 +1,515 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 WMI_WINDOWSMEDIAPHOTO_H +#define WMI_WINDOWSMEDIAPHOTO_H + +//================================================================ +#include +#include +#include +#include + +#if defined(__cplusplus) && !defined(EXTERN_C) +#define EXTERN_C extern "C" +#elif !defined(EXTERN_C)// __cplusplus +#define EXTERN_C extern +#endif // __cplusplus + +/******************************************************************************** + Type definitions +********************************************************************************/ +typedef int Bool; +typedef char Char; +typedef double Double; +typedef int Int; +typedef signed char I8; +typedef short I16; // 16 bit int +typedef int I32; +typedef long Long; +typedef unsigned char PixelC; +typedef int PixelI; +typedef unsigned int UInt; +typedef unsigned long ULong; +typedef unsigned char U8; // 8 bit uint +typedef unsigned short U16; +typedef unsigned int U32; // 32 bit uint +typedef void Void; + +typedef void* CTXSTRCODEC; + + +#define REENTRANT_MODE 1 +/* + DESCRIPTION OF COMPILER FLAG REENTRANT_MODE: + + //#define REENTRANT_MODE 1 + + This compiler flag is related to the capability of banded decode + (decoding only one MB row of the source JPEG XR image at a time). + + With REENTRANT_MODE defined, the decoder decodes one MB row on each call to + ImageStrDecDecode(). + + The decoder acts as if it can only write to the single MBRow whose pointer was passed to it. + This acts as a proof of concept that the API would work if you passed it a small buffer + on each call to ImageStrDecDecode(). + + The REENTRANT_MODE flag only works when the output image is in Orientations 0, 1 + (vertically flipped) or 2 (horizontally flipped). + + With REENTRANT_MODE defined, the function PKImageDecode_Copy_WMP() + decodes only as far as the pRect parameter indicates. The width of the rectangle must be the width + of the image, but on each call, this function will decode the image up to the end of the MB Row + which contains the i-th pixel row, where i = pRect->Y. + + A target use of this version would be to have PKImageDecode_Copy_WMP() called in a loop, once for + each MB row. On each call, pRect would specify a 1-MB-Row-tall rectangle that is the width of the + image. The decoder state is preserved until the Decoder finishes decoding the image. + + If, at a certain point, a request is made for a rectangle _above_ the last row decoded, then the + decoder instance is terminated and re-initiated, and decoding re-starts, going from the beginning + of the image to the end of the current rectangle. + + *** + + We've chosen to uncomment-out this definition in this header file. An alternate method would be + to allow the user to define this in the PREPROCESSOR DEFINITIONS section of the properties page + for each of the following projects: CommonLib, DecodeLib, JXRDecApp and JXRGlueLib. + +*/ +/************************************************************************* + enums +*************************************************************************/ +typedef enum { + ICERR_OK = 0, ICERR_ERROR = -1 +} ERR_CODE; + +typedef enum BITDEPTH { + BD_SHORT, BD_LONG, + + /* add new BITDEPTH here */ BD_MAX +} BITDEPTH; + +typedef enum BITDEPTH_BITS { + // regular ones + BD_1, //White is foreground + BD_8, BD_16, BD_16S, BD_16F, BD_32, BD_32S, BD_32F, + + // irregular ones + BD_5, BD_10, BD_565, + + /* add new BITDEPTH_BITS here */ BDB_MAX, + + BD_1alt = 0xf, //Black is foreground +} BITDEPTH_BITS; + +typedef enum OVERLAP { + OL_NONE = 0, OL_ONE, OL_TWO, + + /* add new OVERLAP here */ OL_MAX +} OVERLAP; + +typedef enum BITSTREAMFORMAT { + SPATIAL = 0, // spatial order + FREQUENCY, // frequency order +} BITSTREAMFORMAT; + +typedef enum COLORFORMAT { + Y_ONLY = 0, + YUV_420 = 1, + YUV_422 = 2, + YUV_444 = 3, + CMYK = 4, + //CMYKDIRECT = 5, + NCOMPONENT = 6, + + // these are external-only + CF_RGB = 7, + CF_RGBE = 8, + + /* add new COLORFORMAT here */ CFT_MAX +} COLORFORMAT; + +// rotation and flip +typedef enum ORIENTATION { + // CRW: Clock Wise 90% Rotation; FlipH: Flip Horizontally; FlipV: Flip Vertically + // Peform rotation FIRST! + // CRW FlipH FlipV + O_NONE = 0, // 0 0 0 + O_FLIPV, // 0 0 1 + O_FLIPH, // 0 1 0 + O_FLIPVH, // 0 1 1 + O_RCW, // 1 0 0 + O_RCW_FLIPV, // 1 0 1 + O_RCW_FLIPH, // 1 1 0 + O_RCW_FLIPVH, // 1 1 1 + /* add new ORIENTATION here */ O_MAX +} ORIENTATION; + +typedef enum SUBBAND { + SB_ALL = 0, // keep all subbands + SB_NO_FLEXBITS, // skip flex bits + SB_NO_HIGHPASS, // skip highpass + SB_DC_ONLY, // skip lowpass and highpass, DC only + SB_ISOLATED, // not decodable + /* add new SUBBAND here */ SB_MAX +} SUBBAND; + +enum { RAW = 0, BMP = 1, PPM = 2, TIF = 3, HDR = 4, IYUV = 5, YUV422 = 6, YUV444 = 7}; + +typedef enum {ERROR_FAIL = -1, SUCCESS_DONE, PRE_READ_HDR, PRE_SETUP, PRE_DECODE, POST_READ_HDR } WMIDecoderStatus; + +#ifndef FALSE +#define FALSE 0 +#endif // FALSE + +#ifndef TRUE +#define TRUE 1 +#endif // TRUE + +#define MAX_CHANNELS 16 +#define LOG_MAX_TILES 12 +#define MAX_TILES (1 << LOG_MAX_TILES) + + +//================================================================ +// Codec-specific constants +#define MB_WIDTH_PIXEL 16 +#define MB_HEIGHT_PIXEL 16 + +#define BLK_WIDTH_PIXEL 4 +#define BLK_HEIGHT_PIXEL 4 + +#define MB_WIDTH_BLK 4 +#define MB_HEIGHT_BLK 4 + +// The codec operates most efficiently when the framebuffers for encoder input +// and decoder output are: 1) aligned on a particular boundary, and 2) the stride +// is also aligned to this boundary (so that each scanline is also aligned). +// This boundary is defined below. +#define FRAMEBUFFER_ALIGNMENT 128 + + +//================================================================ +#define WMP_errSuccess 0 + +#define WMP_errFail -1 +#define WMP_errNotYetImplemented -2 +#define WMP_errAbstractMethod -3 + +#define WMP_errOutOfMemory -101 +#define WMP_errFileIO -102 +#define WMP_errBufferOverflow -103 +#define WMP_errInvalidParameter -104 +#define WMP_errInvalidArgument -105 +#define WMP_errUnsupportedFormat -106 +#define WMP_errIncorrectCodecVersion -107 +#define WMP_errIndexNotFound -108 +#define WMP_errOutOfSequence -109 +#define WMP_errNotInitialized -110 +#define WMP_errMustBeMultipleOf16LinesUntilLastCall -111 +#define WMP_errPlanarAlphaBandedEncRequiresTempFile -112 +#define WMP_errAlphaModeCannotBeTranscoded -113 +#define WMP_errIncorrectCodecSubVersion -114 + + +//================================================================ +typedef long ERR; + +#define Failed(err) ((err)<0) + +#define CRLF "\r\n" + +#define CT_ASSERT(exp, uniq) typedef char __CT_ASSERT__##uniq[(exp) ? 1 : -1] // Caller must provide a unique tag, or this fails to compile under GCC + +#if defined(_DEBUG) || defined(DBG) +#define Report(err, szExp, szFile, nLine) \ + fprintf(stderr, "FAILED: %ld=%s" CRLF, (err), (szExp)); \ + fprintf(stderr, " %s:%ld" CRLF, (szFile), (nLine)); \ + +#else +#define Report(err, szExp, szFile, lLine) err = err +#endif + +#define Call(exp) \ + if (Failed(err = (exp))) \ + { \ + Report(err, #exp, __FILE__, (long)__LINE__); \ + goto Cleanup; \ + } \ + else err = err + +#define CallIgnoreError(errTmp, exp) \ + if (Failed(errTmp = (exp))) \ + { \ + Report(errTmp, #exp, __FILE__, (long)__LINE__); \ + } \ + else errTmp = errTmp + + +#define Test(exp, err) Call((exp) ? WMP_errSuccess : (err)) +#define FailIf(exp, err) Call((exp) ? (err) : WMP_errSuccess) + +//================================================================ +// WMPStream interface +//================================================================ +struct WMPStream +{ + union + { + struct tagFile + { + FILE* pFile; + } file; + + struct tagBuf + { + U8* pbBuf; + size_t cbBuf; + size_t cbCur; + size_t cbBufCount; + } buf; + + void* pvObj; + } state; + + Bool fMem; + + ERR (*Close)(struct WMPStream** pme); + + Bool (*EOS)(struct WMPStream* me); + + ERR (*Read)(struct WMPStream* me, void* pv, size_t cb); + ERR (*Write)(struct WMPStream* me, const void* pv, size_t cb); + //ERR (*GetLine)(struct WMPStream* me, void* pv, size_t cb); + + ERR (*SetPos)(struct WMPStream* me, size_t offPos); + ERR (*GetPos)(struct WMPStream* me, size_t* poffPos); +}; + +EXTERN_C ERR CreateWS_File(struct WMPStream** ppWS, const char* szFilename, const char* szMode); +EXTERN_C ERR CloseWS_File(struct WMPStream** ppWS); + +EXTERN_C ERR CreateWS_Memory(struct WMPStream** ppWS, void* pv, size_t cb); +EXTERN_C ERR CloseWS_Memory(struct WMPStream** ppWS); + + +//================================================================ +// Enc/Dec data structure +//================================================================ +typedef struct tagCWMImageInfo { + size_t cWidth; + size_t cHeight; + COLORFORMAT cfColorFormat; + BITDEPTH_BITS bdBitDepth; + size_t cBitsPerUnit; + size_t cLeadingPadding; // number of leading padding + Bool bRGB; // true: RGB; false: BGR + U8 cChromaCenteringX; // Relative location of Chroma w.r.t Luma + U8 cChromaCenteringY; // Relative location of Chroma w.r.t Luma + + // Region of interest decoding + size_t cROILeftX; + size_t cROIWidth; + size_t cROITopY; + size_t cROIHeight; + + // thumbnail decode + Bool bSkipFlexbits; + size_t cThumbnailWidth; + size_t cThumbnailHeight; + + // image orientation + ORIENTATION oOrientation; + + // post processing + U8 cPostProcStrength; // 0(none) 1(light) 2(medium) 3(strong) 4(very strong) + + // user buffer is always padded to whole MB + Bool fPaddedUserBuffer; +} CWMImageInfo; + +typedef struct tagCWMIStrCodecParam { + Bool bVerbose; + + // for macroblock quantization (DQUANT) + U8 uiDefaultQPIndex; + U8 uiDefaultQPIndexYLP; + U8 uiDefaultQPIndexYHP; + U8 uiDefaultQPIndexU; + U8 uiDefaultQPIndexULP; + U8 uiDefaultQPIndexUHP; + U8 uiDefaultQPIndexV; + U8 uiDefaultQPIndexVLP; + U8 uiDefaultQPIndexVHP; + U8 uiDefaultQPIndexAlpha; + + COLORFORMAT cfColorFormat; + BITDEPTH bdBitDepth; + OVERLAP olOverlap; + BITSTREAMFORMAT bfBitstreamFormat; + size_t cChannel; // number of color channels including alpha + U8 uAlphaMode; // 0:no alpha 1: alpha only else: something + alpha + SUBBAND sbSubband; // which subbands to keep + U8 uiTrimFlexBits; + + struct WMPStream* pWStream; + size_t cbStream; + + // tiling info + U32 cNumOfSliceMinus1V; // # of vertical slices + U32 uiTileX[MAX_TILES]; // width in MB of each veritical slice + U32 cNumOfSliceMinus1H; // # of horizontal slices + U32 uiTileY[MAX_TILES]; // height in MB of each horizontal slice + + //32f and 32s conversion parameters + U8 nLenMantissaOrShift; + I8 nExpBias; + + Bool bBlackWhite; + + Bool bUseHardTileBoundaries; //default is soft tile boundaries + + Bool bProgressiveMode; //default is sequential mode + + Bool bYUVData; //default is cfColorFormat data + + Bool bUnscaledArith; //force unscaled arithmetic + + // Perf measurement + Bool fMeasurePerf; +} CWMIStrCodecParam; + +typedef struct tagCWMImageBufferInfo { + void* pv; // pointer to scanline buffer + size_t cLine; // count of scanlines + size_t cbStride; // count of BYTE for stride +#ifdef REENTRANT_MODE + unsigned int uiFirstMBRow; // Current First MB Row being decoded + unsigned int uiLastMBRow; // Current Last MB Row being decoded + size_t cLinesDecoded; // Number of lines decoded and returned in low-mem mode +#endif // REENTRANT_MODE +} CWMImageBufferInfo; + + + + +/****************************************************************/ +/* Encode API */ +/****************************************************************/ +EXTERN_C Int ImageStrEncInit( + CWMImageInfo* pII, + CWMIStrCodecParam *pSCP, + CTXSTRCODEC* pctxSC); + +EXTERN_C Int ImageStrEncEncode( + CTXSTRCODEC ctxSC, + const CWMImageBufferInfo* pBI); + +EXTERN_C Int ImageStrEncTerm( + CTXSTRCODEC ctxSC); + + +/****************************************************************/ +/* Decode API */ +/****************************************************************/ +struct CWMImageStrCodec; + +EXTERN_C Int ImageStrDecGetInfo( + CWMImageInfo* pII, + CWMIStrCodecParam *pSCP); + +EXTERN_C Int ImageStrDecInit( + CWMImageInfo* pII, + CWMIStrCodecParam *pSCP, + CTXSTRCODEC* pctxSC); + +EXTERN_C Int ImageStrDecDecode( + CTXSTRCODEC ctxSC, + const CWMImageBufferInfo* pBI +#ifdef REENTRANT_MODE + , size_t *pcDecodedLines +#endif + ); + +EXTERN_C Int ImageStrDecTerm( + CTXSTRCODEC ctxSC); + +EXTERN_C Int WMPhotoValidate( + CWMImageInfo * pII, + CWMIStrCodecParam * pSCP); + + +/****************************************************************/ +/* Transcoding API */ +/****************************************************************/ +typedef struct tagCWMTranscodingParam { + size_t cLeftX; + size_t cWidth; + size_t cTopY; + size_t cHeight; // interested region + + BITSTREAMFORMAT bfBitstreamFormat; // desired bitstream format +// COLORFORMAT cfColorFormat; // desired color format + U8 uAlphaMode; // 0:no alpha 1: alpha only else: something + alpha + SUBBAND sbSubband; // which subbands to keep + ORIENTATION oOrientation; // flip / right angle rotation + Bool bIgnoreOverlap; +} CWMTranscodingParam; + +EXTERN_C Int WMPhotoTranscode( + struct WMPStream* pStreamDec, // input bitstrean + struct WMPStream* pStreamEnc, // output bitstream + CWMTranscodingParam* pParam // transcoding parameters +); + +typedef struct tagCWMDetilingParam { + size_t cWidth; + size_t cHeight; // image size + size_t cChannel; // # of channels + OVERLAP olOverlap; // overlap + BITDEPTH_BITS bdBitdepth; // bit depth + + // tiling info + U32 cNumOfSliceMinus1V; // # of vertical slices + U32 uiTileX[MAX_TILES]; // position in MB of each veritical slice + U32 cNumOfSliceMinus1H; // # of horizontal slices + U32 uiTileY[MAX_TILES]; // position in MB of each horizontal slice + + // image info + void * pImage; + size_t cbStride; +} CWMDetilingParam; + +EXTERN_C Int WMPhotoDetile( + CWMDetilingParam * pParam // detiling parameters +); + +#endif // WMI_WINDOWSMEDIAPHOTO_H + diff --git a/libs/jxr/image/sys/xplatform_image.h b/libs/jxr/image/sys/xplatform_image.h new file mode 100644 index 00000000000..b986a69ad10 --- /dev/null +++ b/libs/jxr/image/sys/xplatform_image.h @@ -0,0 +1,84 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 XPLATFORM_IMAGE_H +#define XPLATFORM_IMAGE_H + +#ifdef __ANSI__ +// ANSI +#define FORCE_INLINE +#define CDECL +#define UINTPTR_T unsigned int +#define INTPTR_T int +#define DECLSPEC_ALIGN(bytes) +#endif // __ANSI__ + + +//#if defined(WIN32) +#if defined(WIN32) && !defined(UNDER_CE) // WIN32 seems to be defined always in VS2005 for ARM platform +// x86 +//#define CDECL __cdecl +#define DECLSPEC_ALIGN(bytes) __declspec(align(bytes)) +#endif // x86 + + +#if defined(_ARM_) || defined(UNDER_CE) +// ARM, WinCE +#define FORCE_INLINE inline +#define CDECL +#define UINTPTR_T unsigned int +#define INTPTR_T int +#define DECLSPEC_ALIGN(bytes) + +// parser +#define FULL_PATH_CONFIG_FILE_ENCODE "\\ConfigFile_encode.txt" +#define FULL_PATH_CONFIG_FILE_DECODE "\\ConfigFile_decode.txt" +#define MAX_ARGC 14 +#define MaxCharReadCount 10 +#define MAX_FNAME 256 +#define DELIMITER "filelist:" +#define CODEC_ENCODE "encode" +#define CODEC_DECODE "decode" +#define PHOTON "ptn" +#define OUTRAW "raw" +#define OUTBMP "bmp" +#define OUTPPM "ppm" +#define OUTTIF "tif" +#define OUTHDR "hdr" +#define OUTIYUV "iyuv" +#define OUTYUV422 "yuv422" +#define OUTYUV444 "yuv444" +int XPLATparser(char *pcARGV[], char *pcCodec); +void freeXPLATparser(int iARGC, char *pcARGV[]); + +// WinCE intrinsic +#include +#endif // ARM, WinCE + +#endif // XPLATFORM_IMAGE_H + diff --git a/libs/jxr/image/x86/x86.h b/libs/jxr/image/x86/x86.h new file mode 100644 index 00000000000..a519137a50b --- /dev/null +++ b/libs/jxr/image/x86/x86.h @@ -0,0 +1,58 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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. +// +//*@@@---@@@@****************************************************************** +#pragma once + +#include +#include + +//================================ +// bitio functions +//================================ +#define PACKETLENGTH (1U<<12) // 4kB + +#define readIS_L1(pSC, pIO) readIS(pSC, pIO) +#define readIS_L2(pSC, pIO) (void)(pSC, pIO) + +#define writeIS_L1(pSC, pIO) writeIS(pSC, pIO) +#define writeIS_L2(pSC, pIO) (void)(pSC, pIO) + + +//================================ +// common defines +//================================ +#define FORCE_INLINE __forceinline +#define UINTPTR_T uintptr_t +#define INTPTR_T intptr_t + + +//================================ +// quantization optimization +//================================ +#define RECIP_QUANT_OPT + + diff --git a/libs/jxr/jxrgluelib/JXRGlue.c b/libs/jxr/jxrgluelib/JXRGlue.c new file mode 100644 index 00000000000..ca1663ad9e9 --- /dev/null +++ b/libs/jxr/jxrgluelib/JXRGlue.c @@ -0,0 +1,930 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 +#include + +#define INITGUID +#include + +//================================================================ +const PKIID IID_PKImageScanEncode = 1; +const PKIID IID_PKImageFrameEncode = 2; + +const PKIID IID_PKImageUnsupported = 100; +const PKIID IID_PKImageWmpEncode = 101; + +const PKIID IID_PKImageWmpDecode = 201; + +//================================================================ +// Misc supporting functions +//================================================================ +ERR PKAlloc(void** ppv, size_t cb) +{ + *ppv = calloc(1, cb); + return *ppv ? WMP_errSuccess : WMP_errOutOfMemory; +} + + +ERR PKFree(void** ppv) +{ + if (ppv) + { + free(*ppv); + *ppv = NULL; + } + + return WMP_errSuccess; +} + +ERR PKAllocAligned(void** ppv, size_t cb, size_t iAlign) +{ + U8 *pOrigPtr; + U8 *pReturnedPtr; + size_t iAlignmentCorrection; + const size_t c_cbBlockSize = cb + sizeof(void*) + iAlign - 1; + + *ppv = NULL; + pOrigPtr = calloc(1, c_cbBlockSize); + if (NULL == pOrigPtr) + return WMP_errOutOfMemory; + + iAlignmentCorrection = iAlign - ((size_t)pOrigPtr % iAlign); + if (iAlignmentCorrection < sizeof(void*)) + // Alignment correction won't leave us enough space to store pOrigPtr - advance to next block + iAlignmentCorrection += iAlign; + + assert(iAlignmentCorrection >= sizeof(void*)); // Alignment correction must have space for pOrigPtr + assert(iAlignmentCorrection + cb <= c_cbBlockSize); // Don't exceed right edge of memory block + + pReturnedPtr = pOrigPtr + iAlignmentCorrection; + *(void**)(pReturnedPtr - sizeof(void*)) = pOrigPtr; + + assert(0 == ((size_t)pReturnedPtr % iAlign)); // Are we in fact aligned? + *ppv = pReturnedPtr; + return WMP_errSuccess; +} + +ERR PKFreeAligned(void** ppv) +{ + if (ppv && *ppv) + { + U8 **ppOrigPtr = (U8**)((U8*)(*ppv) - sizeof(void*)); + assert(*ppOrigPtr <= (U8*)ppOrigPtr); // Something's wrong if pOrigPtr points forward + free(*ppOrigPtr); + *ppv = NULL; + } + return WMP_errSuccess; +} + + + +int PKStrnicmp(const char* s1, const char* s2, size_t c) +{ + for(; tolower(*s1) == tolower(*s2) && *s1 && *s2 && c; ++s1, ++s2, --c); + return c ? *s1 - *s2 : 0; +} + +static const PKPixelInfo pixelInfo[] = +{ + {&GUID_PKPixelFormatDontCare, 1, Y_ONLY, BD_8, 8, PK_pixfmtNul, 0, 0, 0, 0}, + + // Gray + //{&GUID_PKPixelFormat2bppGray, 1, Y_ONLY, BD_8, 2, PK_pixfmtNul}, + //{&GUID_PKPixelFormat4bppGray, 1, Y_ONLY, BD_8, 4, PK_pixfmtNul}, + + {&GUID_PKPixelFormatBlackWhite, 1, Y_ONLY, BD_1, 1, PK_pixfmtNul, 1, 1, 1, 1},//BlackIsZero is default for GUID_PKPixelFormatBlackWhite + {&GUID_PKPixelFormatBlackWhite, 1, Y_ONLY, BD_1, 1, PK_pixfmtNul, 0, 1, 1, 1},//WhiteIsZero + {&GUID_PKPixelFormat8bppGray, 1, Y_ONLY, BD_8, 8, PK_pixfmtNul, 1, 1, 8, 1}, + {&GUID_PKPixelFormat16bppGray, 1, Y_ONLY, BD_16, 16, PK_pixfmtNul, 1, 1, 16, 1}, + {&GUID_PKPixelFormat16bppGrayFixedPoint, 1, Y_ONLY, BD_16S, 16, PK_pixfmtNul, 1, 1, 16, 2}, + {&GUID_PKPixelFormat16bppGrayHalf, 1, Y_ONLY, BD_16F, 16, PK_pixfmtNul, 1, 1, 16, 3}, + //{&GUID_PKPixelFormat32bppGray, 1, Y_ONLY, BD_32, 32, PK_pixfmtNul, 1, 1, 32, 1}, + {&GUID_PKPixelFormat32bppGrayFixedPoint, 1, Y_ONLY, BD_32S, 32, PK_pixfmtNul, 1, 1, 32, 2}, + {&GUID_PKPixelFormat32bppGrayFloat, 1, Y_ONLY, BD_32F, 32, PK_pixfmtNul, 1, 1, 32, 3}, + + // RGB + {&GUID_PKPixelFormat24bppRGB, 3, CF_RGB, BD_8, 24, PK_pixfmtNul, 2, 3, 8, 1}, + {&GUID_PKPixelFormat24bppBGR, 3, CF_RGB, BD_8, 24, PK_pixfmtBGR, 2, 3, 8, 1}, + {&GUID_PKPixelFormat32bppRGB, 3, CF_RGB, BD_8, 32, PK_pixfmtNul, 2, 3, 8, 1}, + {&GUID_PKPixelFormat32bppBGR, 3, CF_RGB, BD_8, 32, PK_pixfmtBGR, 2, 3, 8, 1}, + {&GUID_PKPixelFormat48bppRGB, 3, CF_RGB, BD_16, 48, PK_pixfmtNul, 2, 3, 16, 1}, + {&GUID_PKPixelFormat48bppRGBFixedPoint, 3, CF_RGB, BD_16S, 48, PK_pixfmtNul, 2, 3, 16, 2}, + {&GUID_PKPixelFormat48bppRGBHalf, 3, CF_RGB, BD_16F, 48, PK_pixfmtNul, 2, 3, 16, 3}, + {&GUID_PKPixelFormat64bppRGBFixedPoint, 3, CF_RGB, BD_16S, 64, PK_pixfmtNul, 2, 3, 16, 2}, + {&GUID_PKPixelFormat64bppRGBHalf, 3, CF_RGB, BD_16F, 64, PK_pixfmtNul, 2, 3, 16, 3}, + //{&GUID_PKPixelFormat96bppRGB, 3, CF_RGB, BD_32, 96, PK_pixfmtNul, 2, 3, 32, 1}, + {&GUID_PKPixelFormat96bppRGBFixedPoint, 3, CF_RGB, BD_32S, 96, PK_pixfmtNul, 2, 3, 32, 2}, + {&GUID_PKPixelFormat96bppRGBFloat, 3, CF_RGB, BD_32F, 96, PK_pixfmtNul, 2, 3, 32, 3}, + {&GUID_PKPixelFormat128bppRGBFixedPoint, 3, CF_RGB, BD_32S, 128, PK_pixfmtNul, 2, 3, 32, 2}, + {&GUID_PKPixelFormat128bppRGBFloat, 3, CF_RGB, BD_32F, 128, PK_pixfmtNul, 2, 3, 32, 3}, + + // RGBA + {&GUID_PKPixelFormat32bppBGRA, 4, CF_RGB, BD_8, 32, PK_pixfmtHasAlpha | PK_pixfmtBGR, 2, 4, 8, 1}, + {&GUID_PKPixelFormat32bppRGBA, 4, CF_RGB, BD_8, 32, PK_pixfmtHasAlpha, 2, 4, 8, 1}, + {&GUID_PKPixelFormat64bppRGBA, 4, CF_RGB, BD_16, 64, PK_pixfmtHasAlpha, 2, 4, 16, 1}, + {&GUID_PKPixelFormat64bppRGBAFixedPoint, 4, CF_RGB, BD_16S, 64, PK_pixfmtHasAlpha, 2, 4, 16, 2}, + {&GUID_PKPixelFormat64bppRGBAHalf, 4, CF_RGB, BD_16F, 64, PK_pixfmtHasAlpha, 2, 4, 16, 3}, + //{&GUID_PKPixelFormat128bppRGBA, 4, CF_RGB, BD_32, 128, PK_pixfmtHasAlpha, 2, 4, 32, 1}, + {&GUID_PKPixelFormat128bppRGBAFixedPoint, 4, CF_RGB, BD_32S, 128, PK_pixfmtHasAlpha, 2, 4, 32, 2}, + {&GUID_PKPixelFormat128bppRGBAFloat, 4, CF_RGB, BD_32F, 128, PK_pixfmtHasAlpha, 2, 4, 32, 3}, + + // PRGBA + {&GUID_PKPixelFormat32bppPBGRA, 4, CF_RGB, BD_8, 32, PK_pixfmtHasAlpha | PK_pixfmtPreMul | PK_pixfmtBGR, 2, 4, 8, 1}, + {&GUID_PKPixelFormat32bppPRGBA, 4, CF_RGB, BD_8, 32, PK_pixfmtHasAlpha | PK_pixfmtPreMul, 2, 4, 8, 1}, + {&GUID_PKPixelFormat64bppPRGBA, 4, CF_RGB, BD_16, 64, PK_pixfmtHasAlpha | PK_pixfmtPreMul, 2, 4, 16, 1}, + //{&GUID_PKPixelFormat64bppPRGBAFixedPoint, 4, CF_RGB, BD_16S, 64, PK_pixfmtHasAlpha, 2, 4, 16, 2}, + //{&GUID_PKPixelFormat64bppPRGBAHalf, 4, CF_RGB, BD_16F, 64, PK_pixfmtHasAlpha, 2, 4, 16, 3}, + //{&GUID_PKPixelFormat128bppPRGBAFixedPoint, 4, CF_RGB, BD_32S, 128, PK_pixfmtHasAlpha, 2, 4, 32, 2}, + {&GUID_PKPixelFormat128bppPRGBAFloat, 4, CF_RGB, BD_32F, 128, PK_pixfmtHasAlpha | PK_pixfmtPreMul, 2, 4, 32, 3}, + + // Packed formats + {&GUID_PKPixelFormat16bppRGB555, 3, CF_RGB, BD_5, 16, PK_pixfmtNul, 2, 3, 5, 1}, + {&GUID_PKPixelFormat16bppRGB565, 3, CF_RGB, BD_565, 16, PK_pixfmtNul, 2, 3, 6, 1}, + {&GUID_PKPixelFormat32bppRGB101010, 3, CF_RGB, BD_10, 32, PK_pixfmtNul, 2, 3, 10, 1}, + + // CMYK + {&GUID_PKPixelFormat32bppCMYK, 4, CMYK, BD_8, 32, PK_pixfmtNul, 5, 4, 8, 1}, + {&GUID_PKPixelFormat40bppCMYKAlpha, 5, CMYK, BD_8, 40, PK_pixfmtHasAlpha, 5, 5, 8, 1}, + + {&GUID_PKPixelFormat64bppCMYK, 4, CMYK, BD_16, 64, PK_pixfmtNul, 5, 4, 16, 1}, + {&GUID_PKPixelFormat80bppCMYKAlpha, 5, CMYK, BD_16, 80, PK_pixfmtHasAlpha, 5, 5, 16, 1}, + + // N_CHANNEL + {&GUID_PKPixelFormat24bpp3Channels, 3, NCOMPONENT, BD_8, 24, PK_pixfmtNul, PK_PI_NCH, 3, 8, 1},//the N channel TIF by PS has PhotometricInterpretation of PK_PI_RGB + {&GUID_PKPixelFormat32bpp4Channels, 4, NCOMPONENT, BD_8, 32, PK_pixfmtNul, PK_PI_NCH, 4, 8, 1}, + {&GUID_PKPixelFormat40bpp5Channels, 5, NCOMPONENT, BD_8, 40, PK_pixfmtNul, PK_PI_NCH, 5, 8, 1}, + {&GUID_PKPixelFormat48bpp6Channels, 6, NCOMPONENT, BD_8, 48, PK_pixfmtNul, PK_PI_NCH, 6, 8, 1}, + {&GUID_PKPixelFormat56bpp7Channels, 7, NCOMPONENT, BD_8, 56, PK_pixfmtNul, PK_PI_NCH, 7, 8, 1}, + {&GUID_PKPixelFormat64bpp8Channels, 8, NCOMPONENT, BD_8, 64, PK_pixfmtNul, PK_PI_NCH, 8, 8, 1}, + + {&GUID_PKPixelFormat32bpp3ChannelsAlpha, 4, NCOMPONENT, BD_8, 32, PK_pixfmtHasAlpha, PK_PI_NCH, 4, 8, 1}, + {&GUID_PKPixelFormat40bpp4ChannelsAlpha, 5, NCOMPONENT, BD_8, 40, PK_pixfmtHasAlpha, PK_PI_NCH, 5, 8, 1}, + {&GUID_PKPixelFormat48bpp5ChannelsAlpha, 6, NCOMPONENT, BD_8, 48, PK_pixfmtHasAlpha, PK_PI_NCH, 6, 8, 1}, + {&GUID_PKPixelFormat56bpp6ChannelsAlpha, 7, NCOMPONENT, BD_8, 56, PK_pixfmtHasAlpha, PK_PI_NCH, 7, 8, 1}, + {&GUID_PKPixelFormat64bpp7ChannelsAlpha, 8, NCOMPONENT, BD_8, 64, PK_pixfmtHasAlpha, PK_PI_NCH, 8, 8, 1}, + {&GUID_PKPixelFormat72bpp8ChannelsAlpha, 9, NCOMPONENT, BD_8, 72, PK_pixfmtHasAlpha, PK_PI_NCH, 9, 8, 1}, + + {&GUID_PKPixelFormat48bpp3Channels, 3, NCOMPONENT, BD_16, 48, PK_pixfmtNul, PK_PI_NCH, 3, 16, 1}, + {&GUID_PKPixelFormat64bpp4Channels, 4, NCOMPONENT, BD_16, 64, PK_pixfmtNul, PK_PI_NCH, 4, 16, 1}, + {&GUID_PKPixelFormat80bpp5Channels, 5, NCOMPONENT, BD_16, 80, PK_pixfmtNul, PK_PI_NCH, 5, 16, 1}, + {&GUID_PKPixelFormat96bpp6Channels, 6, NCOMPONENT, BD_16, 96, PK_pixfmtNul, PK_PI_NCH, 6, 16, 1}, + {&GUID_PKPixelFormat112bpp7Channels, 7, NCOMPONENT, BD_16, 112, PK_pixfmtNul, PK_PI_NCH, 7, 16, 1}, + {&GUID_PKPixelFormat128bpp8Channels, 8, NCOMPONENT, BD_16, 128, PK_pixfmtNul, PK_PI_NCH, 8, 16, 1}, + + {&GUID_PKPixelFormat64bpp3ChannelsAlpha, 4, NCOMPONENT, BD_16, 64, PK_pixfmtHasAlpha, PK_PI_NCH, 4, 16, 1}, + {&GUID_PKPixelFormat80bpp4ChannelsAlpha, 5, NCOMPONENT, BD_16, 80, PK_pixfmtHasAlpha, PK_PI_NCH, 5, 16, 1}, + {&GUID_PKPixelFormat96bpp5ChannelsAlpha, 6, NCOMPONENT, BD_16, 96, PK_pixfmtHasAlpha, PK_PI_NCH, 6, 16, 1}, + {&GUID_PKPixelFormat112bpp6ChannelsAlpha, 7, NCOMPONENT, BD_16, 112, PK_pixfmtHasAlpha, PK_PI_NCH, 7, 16, 1}, + {&GUID_PKPixelFormat128bpp7ChannelsAlpha, 8, NCOMPONENT, BD_16, 128, PK_pixfmtHasAlpha, PK_PI_NCH, 8, 16, 1}, + {&GUID_PKPixelFormat144bpp8ChannelsAlpha, 9, NCOMPONENT, BD_16, 144, PK_pixfmtHasAlpha, PK_PI_NCH, 9, 16, 1}, + + //RGBE + {&GUID_PKPixelFormat32bppRGBE, 4, CF_RGBE, BD_8, 32, PK_pixfmtNul, PK_PI_RGBE, 4, 8, 1}, + + //YUV + {&GUID_PKPixelFormat12bppYUV420, 3, YUV_420, BD_8, 48, PK_pixfmtNul}, + {&GUID_PKPixelFormat16bppYUV422, 3, YUV_422, BD_8, 32, PK_pixfmtNul}, + {&GUID_PKPixelFormat24bppYUV444, 3, YUV_444, BD_8, 24, PK_pixfmtNul}, +}; + +//---------------------------------------------------------------- +//ERR GetPixelInfo(PKPixelFormatGUID enPixelFormat, const PKPixelInfo** ppPI) +ERR PixelFormatLookup(PKPixelInfo* pPI, U8 uLookupType) +{ + ERR err = WMP_errSuccess; + size_t i; + + for (i = 0; i < sizeof2(pixelInfo); ++i) + { + if (LOOKUP_FORWARD == uLookupType) + { + if (IsEqualGUID(pPI->pGUIDPixFmt, pixelInfo[i].pGUIDPixFmt)) + { + *pPI = pixelInfo[i]; + goto Cleanup; + } + } + else if (LOOKUP_BACKWARD_TIF == uLookupType) + { + if (pPI->uSamplePerPixel == pixelInfo[i].uSamplePerPixel && + pPI->uBitsPerSample == pixelInfo[i].uBitsPerSample && + pPI->uSampleFormat == pixelInfo[i].uSampleFormat && + pPI->uInterpretation == pixelInfo[i].uInterpretation) + { + // match alpha & premult + if ((pPI->grBit & (PK_pixfmtHasAlpha | PK_pixfmtPreMul)) == + (pixelInfo[i].grBit & (PK_pixfmtHasAlpha | PK_pixfmtPreMul))) + { + *pPI = pixelInfo[i]; + goto Cleanup; + } + } + } + } + Call(WMP_errUnsupportedFormat); + +Cleanup: + return err; +} + + +const PKPixelFormatGUID* GetPixelFormatFromHash(const U8 uPFHash) +{ + int i; + + for (i = 0; i < sizeof2(pixelInfo); i++) + { + if (pixelInfo[i].pGUIDPixFmt->Data4[7] == uPFHash) + return pixelInfo[i].pGUIDPixFmt; + } + + // If we reached this point, we did not find anything which matched the hash + return NULL; +} + +//---------------------------------------------------------------- +typedef struct tagPKIIDInfo +{ + const char* szExt; + const PKIID* pIIDEnc; + const PKIID* pIIDDec; +} PKIIDInfo; + +static ERR GetIIDInfo(const char* szExt, const PKIIDInfo** ppInfo) +{ + ERR err = WMP_errSuccess; + + static PKIIDInfo iidInfo[] = { + {".jxr", &IID_PKImageWmpEncode, &IID_PKImageWmpDecode}, + {".wdp", &IID_PKImageUnsupported, &IID_PKImageWmpDecode}, + {".hdp", &IID_PKImageUnsupported, &IID_PKImageWmpDecode}, + }; + size_t i = 0; + + *ppInfo = NULL; + for (i = 0; i < sizeof2(iidInfo); ++i) + { + if (0 == PKStrnicmp(szExt, iidInfo[i].szExt, strlen(iidInfo[i].szExt))) + { + *ppInfo = &iidInfo[i]; + goto Cleanup; + } + } + + Call(WMP_errUnsupportedFormat); + +Cleanup: + return err; +} + +ERR GetImageEncodeIID(const char* szExt, const PKIID** ppIID) +{ + ERR err = WMP_errSuccess; + + const PKIIDInfo* pInfo = NULL; + + Call(GetIIDInfo(szExt, &pInfo)); + *ppIID = pInfo->pIIDEnc; + +Cleanup: + return err; +} + +ERR GetImageDecodeIID(const char* szExt, const PKIID** ppIID) +{ + ERR err = WMP_errSuccess; + + const PKIIDInfo* pInfo = NULL; + + Call(GetIIDInfo(szExt, &pInfo)); + *ppIID = pInfo->pIIDDec; + +Cleanup: + return err; +} + +//================================================================ +// PKFactory +//================================================================ +ERR PKCreateFactory_CreateStream(PKStream** ppStream) +{ + ERR err = WMP_errSuccess; + + Call(PKAlloc((void **) ppStream, sizeof(**ppStream))); + +Cleanup: + return err; +} + +ERR PKCreateFactory_Release(PKFactory** ppFactory) +{ + ERR err = WMP_errSuccess; + + Call(PKFree((void **) ppFactory)); + +Cleanup: + return err; +} + +//---------------------------------------------------------------- +ERR PKCreateFactory(PKFactory** ppFactory, U32 uVersion) +{ + ERR err = WMP_errSuccess; + PKFactory* pFactory = NULL; + + UNREFERENCED_PARAMETER( uVersion ); + + Call(PKAlloc((void **) ppFactory, sizeof(**ppFactory))); + pFactory = *ppFactory; + + pFactory->CreateStream = PKCreateFactory_CreateStream; + + pFactory->CreateStreamFromFilename = CreateWS_File; + pFactory->CreateStreamFromMemory = CreateWS_Memory; + + pFactory->Release = PKCreateFactory_Release; + +Cleanup: + return err; +} + + +//================================================================ +// PKCodecFactory +//================================================================ +ERR PKCodecFactory_CreateCodec(const PKIID* iid, void** ppv) +{ + ERR err = WMP_errSuccess; + + if (IID_PKImageWmpEncode == *iid) + { + Call(PKImageEncode_Create_WMP((PKImageEncode**)ppv)); + } + else if (IID_PKImageWmpDecode == *iid) + { + Call(PKImageDecode_Create_WMP((PKImageDecode**)ppv)); + } + else + { + Call(WMP_errUnsupportedFormat); + } + +Cleanup: + return err; +} + +ERR PKCodecFactory_CreateDecoderFromFile(const char* szFilename, PKImageDecode** ppDecoder) +{ + ERR err = WMP_errSuccess; + + char *pExt = NULL; + const PKIID* pIID = NULL; + + struct WMPStream* pStream = NULL; + PKImageDecode* pDecoder = NULL; + + // get file extension + pExt = strrchr(szFilename, '.'); + FailIf(NULL == pExt, WMP_errUnsupportedFormat); + + // get decode PKIID + Call(GetImageDecodeIID(pExt, &pIID)); + + // create stream + Call(CreateWS_File(&pStream, szFilename, "rb")); + + // Create decoder + Call(PKCodecFactory_CreateCodec(pIID, (void **) ppDecoder)); + pDecoder = *ppDecoder; + + // attach stream to decoder + Call(pDecoder->Initialize(pDecoder, pStream)); + pDecoder->fStreamOwner = !0; + +Cleanup: + return err; +} + +ERR PKCodecFactory_CreateFormatConverter(PKFormatConverter** ppFConverter) +{ + ERR err = WMP_errSuccess; + PKFormatConverter* pFC = NULL; + + Call(PKAlloc((void **) ppFConverter, sizeof(**ppFConverter))); + pFC = *ppFConverter; + + pFC->Initialize = PKFormatConverter_Initialize; + pFC->InitializeConvert = PKFormatConverter_InitializeConvert; + pFC->GetPixelFormat = PKFormatConverter_GetPixelFormat; + pFC->GetSourcePixelFormat = PKFormatConverter_GetSourcePixelFormat; + pFC->GetSize = PKFormatConverter_GetSize; + pFC->GetResolution = PKFormatConverter_GetResolution; + pFC->Copy = PKFormatConverter_Copy; + pFC->Convert = PKFormatConverter_Convert; + pFC->Release = PKFormatConverter_Release; + +Cleanup: + return err; +} + +ERR PKCreateCodecFactory_Release(PKCodecFactory** ppCFactory) +{ + ERR err = WMP_errSuccess; + + Call(PKFree((void **) ppCFactory)); + +Cleanup: + return err; +} + +ERR PKCreateCodecFactory(PKCodecFactory** ppCFactory, U32 uVersion) +{ + ERR err = WMP_errSuccess; + PKCodecFactory* pCFactory = NULL; + + UNREFERENCED_PARAMETER( uVersion ); + + Call(PKAlloc((void **) ppCFactory, sizeof(**ppCFactory))); + pCFactory = *ppCFactory; + + pCFactory->CreateCodec = PKCodecFactory_CreateCodec; + pCFactory->CreateDecoderFromFile = PKCodecFactory_CreateDecoderFromFile; + pCFactory->CreateFormatConverter = PKCodecFactory_CreateFormatConverter; + pCFactory->Release = PKCreateCodecFactory_Release; + +Cleanup: + return err; +} + + +//================================================================ +// PKImageEncode +//================================================================ +ERR PKImageEncode_Initialize( + PKImageEncode* pIE, + struct WMPStream* pStream, + void* pvParam, + size_t cbParam) +{ + ERR err = WMP_errSuccess; + + UNREFERENCED_PARAMETER( pIE ); + UNREFERENCED_PARAMETER( pvParam ); + UNREFERENCED_PARAMETER( cbParam ); + + pIE->pStream = pStream; + pIE->guidPixFormat = GUID_PKPixelFormatDontCare; + pIE->fResX = 96; + pIE->fResY = 96; + pIE->cFrame = 1; + + Call(pIE->pStream->GetPos(pIE->pStream, &pIE->offStart)); + +Cleanup: + return err; +} + +ERR PKImageEncode_Terminate( + PKImageEncode* pIE) +{ + UNREFERENCED_PARAMETER( pIE ); + return WMP_errSuccess; +} + +ERR PKImageEncode_SetPixelFormat( + PKImageEncode* pIE, + PKPixelFormatGUID enPixelFormat) +{ + pIE->guidPixFormat = enPixelFormat; + + return WMP_errSuccess; +} + +ERR PKImageEncode_SetSize( + PKImageEncode* pIE, + I32 iWidth, + I32 iHeight) +{ + ERR err = WMP_errSuccess; + + pIE->uWidth = (U32)iWidth; + pIE->uHeight = (U32)iHeight; + + return err; +} + +ERR PKImageEncode_SetResolution( + PKImageEncode* pIE, + Float fResX, + Float fResY) +{ + pIE->fResX = fResX; + pIE->fResY = fResY; + + return WMP_errSuccess; +} + +ERR PKImageEncode_SetColorContext(PKImageEncode *pIE, + const U8 *pbColorContext, + U32 cbColorContext) +{ + UNREFERENCED_PARAMETER( pIE ); + UNREFERENCED_PARAMETER( pbColorContext ); + UNREFERENCED_PARAMETER( cbColorContext ); + return WMP_errNotYetImplemented; +} + + +ERR PKImageEncode_SetDescriptiveMetadata(PKImageEncode *pIE, const DESCRIPTIVEMETADATA *pDescMetadata) +{ + UNREFERENCED_PARAMETER( pIE ); + UNREFERENCED_PARAMETER( pDescMetadata ); + return WMP_errNotYetImplemented; +} + +ERR PKImageEncode_WritePixels( + PKImageEncode* pIE, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + UNREFERENCED_PARAMETER( pIE ); + UNREFERENCED_PARAMETER( cLine ); + UNREFERENCED_PARAMETER( pbPixels ); + UNREFERENCED_PARAMETER( cbStride ); + return WMP_errAbstractMethod; +} + +ERR PKImageEncode_WriteSource( + PKImageEncode* pIE, + PKFormatConverter* pFC, + PKRect* pRect) +{ + ERR err = WMP_errSuccess; + + PKPixelFormatGUID enPFFrom = GUID_PKPixelFormatDontCare; + PKPixelFormatGUID enPFTo = GUID_PKPixelFormatDontCare; + + PKPixelInfo pPIFrom; + PKPixelInfo pPITo; + + U32 cbStrideTo = 0; + U32 cbStrideFrom = 0; + U32 cbStride = 0; + + U8* pb = NULL; + + // CWMTranscodingParam* pParam = NULL; + + // get pixel format + Call(pFC->GetSourcePixelFormat(pFC, &enPFFrom)); + Call(pFC->GetPixelFormat(pFC, &enPFTo)); + FailIf(!IsEqualGUID(&pIE->guidPixFormat, &enPFTo), WMP_errUnsupportedFormat); + + // calc common stride +// Call(GetPixelInfo(enPFFrom, &pPIFrom)); + pPIFrom.pGUIDPixFmt = &enPFFrom; + PixelFormatLookup(&pPIFrom, LOOKUP_FORWARD); + +// Call(GetPixelInfo(enPFTo, &pPITo)); + pPITo.pGUIDPixFmt = &enPFTo; + PixelFormatLookup(&pPITo, LOOKUP_FORWARD); + +// cbStrideFrom = (pPIFrom->cbPixel * pRect->Width + pPIFrom->cbPixelDenom - 1) / pPIFrom->cbPixelDenom; + cbStrideFrom = (BD_1 == pPIFrom.bdBitDepth ? ((pPIFrom.cbitUnit * pRect->Width + 7) >> 3) : (((pPIFrom.cbitUnit + 7) >> 3) * pRect->Width)); + if (&GUID_PKPixelFormat12bppYUV420 == pPIFrom.pGUIDPixFmt + || &GUID_PKPixelFormat16bppYUV422 == pPIFrom.pGUIDPixFmt) + cbStrideFrom >>= 1; + +// cbStrideTo = (pPITo->cbPixel * pIE->uWidth + pPITo->cbPixelDenom - 1) / pPITo->cbPixelDenom; + cbStrideTo = (BD_1 == pPITo.bdBitDepth ? ((pPITo.cbitUnit * pIE->uWidth + 7) >> 3) : (((pPITo.cbitUnit + 7) >> 3) * pIE->uWidth)); + if (&GUID_PKPixelFormat12bppYUV420 == pPITo.pGUIDPixFmt + || &GUID_PKPixelFormat16bppYUV422 == pPITo.pGUIDPixFmt) + cbStrideTo >>= 1; + + cbStride = max(cbStrideFrom, cbStrideTo); + + // actual dec/enc with local buffer + Call(PKAllocAligned((void **) &pb, cbStride * pRect->Height, 128)); + + Call(pFC->Copy(pFC, pRect, pb, cbStride)); + + Call(pIE->WritePixels(pIE, pRect->Height, pb, cbStride)); + +Cleanup: + PKFreeAligned((void **) &pb); + return err; +} + +ERR PKImageEncode_WritePixelsBandedBegin(PKImageEncode* pEncoder, struct WMPStream *pPATempFile) +{ + UNREFERENCED_PARAMETER( pEncoder ); + UNREFERENCED_PARAMETER( pPATempFile ); + return WMP_errAbstractMethod; +} + +ERR PKImageEncode_WritePixelsBanded(PKImageEncode* pEncoder, U32 cLines, U8* pbPixels, U32 cbStride, Bool fLastCall) +{ + UNREFERENCED_PARAMETER( pEncoder ); + UNREFERENCED_PARAMETER( cLines ); + UNREFERENCED_PARAMETER( pbPixels ); + UNREFERENCED_PARAMETER( cbStride ); + UNREFERENCED_PARAMETER( fLastCall ); + return WMP_errAbstractMethod; +} + +ERR PKImageEncode_WritePixelsBandedEnd(PKImageEncode* pEncoder) +{ + UNREFERENCED_PARAMETER( pEncoder ); + return WMP_errAbstractMethod; +} + + +ERR PKImageEncode_Transcode( + PKImageEncode* pIE, + PKFormatConverter* pFC, + PKRect* pRect) +{ + ERR err = WMP_errSuccess; + + PKPixelFormatGUID enPFFrom = GUID_PKPixelFormatDontCare; + PKPixelFormatGUID enPFTo = GUID_PKPixelFormatDontCare; + + PKPixelInfo pPIFrom; + PKPixelInfo pPITo; + + U32 cbStrideTo = 0; + U32 cbStrideFrom = 0; + U32 cbStride = 0; + + U8* pb = NULL; + + CWMTranscodingParam cParam = {0}; + + // get pixel format + Call(pFC->GetSourcePixelFormat(pFC, &enPFFrom)); + Call(pFC->GetPixelFormat(pFC, &enPFTo)); + FailIf(!IsEqualGUID(&pIE->guidPixFormat, &enPFTo), WMP_errUnsupportedFormat); + + // calc common stride +// Call(GetPixelInfo(enPFFrom, &pPIFrom)); + pPIFrom.pGUIDPixFmt = &enPFFrom; + PixelFormatLookup(&pPIFrom, LOOKUP_FORWARD); + +// Call(GetPixelInfo(enPFTo, &pPITo)); + pPITo.pGUIDPixFmt = &enPFTo; + PixelFormatLookup(&pPITo, LOOKUP_FORWARD); + +// cbStrideFrom = (pPIFrom->cbPixel * pRect->Width + pPIFrom->cbPixelDenom - 1) / pPIFrom->cbPixelDenom; + cbStrideFrom = (BD_1 == pPIFrom.bdBitDepth ? ((pPIFrom.cbitUnit * pRect->Width + 7) >> 3) : (((pPIFrom.cbitUnit + 7) >> 3) * pRect->Width)); + if (&GUID_PKPixelFormat12bppYUV420 == pPIFrom.pGUIDPixFmt + || &GUID_PKPixelFormat16bppYUV422 == pPIFrom.pGUIDPixFmt) + cbStrideFrom >>= 1; + +// cbStrideTo = (pPITo->cbPixel * pIE->uWidth + pPITo->cbPixelDenom - 1) / pPITo->cbPixelDenom; + cbStrideTo = (BD_1 == pPITo.bdBitDepth ? ((pPITo.cbitUnit * pIE->uWidth + 7) >> 3) : (((pPITo.cbitUnit + 7) >> 3) * pIE->uWidth)); + if (&GUID_PKPixelFormat12bppYUV420 == pPITo.pGUIDPixFmt + || &GUID_PKPixelFormat16bppYUV422 == pPITo.pGUIDPixFmt) + cbStrideTo >>= 1; + + cbStride = max(cbStrideFrom, cbStrideTo); + + if(pIE->bWMP){ + cParam.cLeftX = pFC->pDecoder->WMP.wmiI.cROILeftX; + cParam.cTopY = pFC->pDecoder->WMP.wmiI.cROITopY; + cParam.cWidth = pFC->pDecoder->WMP.wmiI.cROIWidth; + cParam.cHeight = pFC->pDecoder->WMP.wmiI.cROIHeight; + cParam.oOrientation = pFC->pDecoder->WMP.wmiI.oOrientation; +// cParam.cfColorFormat = pFC->pDecoder->WMP.wmiI.cfColorFormat; + cParam.uAlphaMode = pFC->pDecoder->WMP.wmiSCP.uAlphaMode; + cParam.bfBitstreamFormat = pFC->pDecoder->WMP.wmiSCP.bfBitstreamFormat; + cParam.sbSubband = pFC->pDecoder->WMP.wmiSCP.sbSubband; + cParam.bIgnoreOverlap = pFC->pDecoder->WMP.bIgnoreOverlap; + + Call(pIE->Transcode(pIE, pFC->pDecoder, &cParam)); + } + else + { + // actual dec/enc with local buffer + Call(PKAllocAligned((void **) &pb, cbStride * pRect->Height, 128)); + Call(pFC->Copy(pFC, pRect, pb, cbStride)); + Call(pIE->WritePixels(pIE, pRect->Height, pb, cbStride)); + } + +Cleanup: + PKFreeAligned((void **) &pb); + return err; +} + +ERR PKImageEncode_CreateNewFrame( + PKImageEncode* pIE, + void* pvParam, + size_t cbParam) +{ + UNREFERENCED_PARAMETER( pIE ); + UNREFERENCED_PARAMETER( pvParam ); + UNREFERENCED_PARAMETER( cbParam ); + // NYI + return WMP_errSuccess; +} + +ERR PKImageEncode_Release( + PKImageEncode** ppIE) +{ + PKImageEncode *pIE = *ppIE; + pIE->pStream->Close(&pIE->pStream); + + return PKFree((void **) ppIE); +} + +ERR PKImageEncode_Create(PKImageEncode** ppIE) +{ + ERR err = WMP_errSuccess; + PKImageEncode* pIE = NULL; + + Call(PKAlloc((void **) ppIE, sizeof(**ppIE))); + + pIE = *ppIE; + pIE->Initialize = PKImageEncode_Initialize; + pIE->Terminate = PKImageEncode_Terminate; + pIE->SetPixelFormat = PKImageEncode_SetPixelFormat; + pIE->SetSize = PKImageEncode_SetSize; + pIE->SetResolution = PKImageEncode_SetResolution; + pIE->SetColorContext = PKImageEncode_SetColorContext; + pIE->SetDescriptiveMetadata = PKImageEncode_SetDescriptiveMetadata; + pIE->WritePixels = PKImageEncode_WritePixels; +// pIE->WriteSource = PKImageEncode_WriteSource; + + pIE->WritePixelsBandedBegin = PKImageEncode_WritePixelsBandedBegin; + pIE->WritePixelsBanded = PKImageEncode_WritePixelsBanded; + pIE->WritePixelsBandedEnd = PKImageEncode_WritePixelsBandedEnd; + + pIE->CreateNewFrame = PKImageEncode_CreateNewFrame; + pIE->Release = PKImageEncode_Release; + pIE->bWMP = FALSE; + +Cleanup: + return err; +} + + +//================================================================ +// PKImageDecode +//================================================================ +ERR PKImageDecode_Initialize( + PKImageDecode* pID, + struct WMPStream* pStream) +{ + ERR err = WMP_errSuccess; + + pID->pStream = pStream; + pID->guidPixFormat = GUID_PKPixelFormatDontCare; + pID->fResX = 96; + pID->fResY = 96; + pID->cFrame = 1; + + Call(pID->pStream->GetPos(pID->pStream, &pID->offStart)); + + memset(&pID->WMP.wmiDEMisc, 0, sizeof(pID->WMP.wmiDEMisc)); + +Cleanup: + return WMP_errSuccess; +} + +ERR PKImageDecode_GetPixelFormat( + PKImageDecode* pID, + PKPixelFormatGUID* pPF) +{ + *pPF = pID->guidPixFormat; + + return WMP_errSuccess; +} + +ERR PKImageDecode_GetSize( + PKImageDecode* pID, + I32* piWidth, + I32* piHeight) +{ + *piWidth = (I32)pID->uWidth; + *piHeight = (I32)pID->uHeight; + + return WMP_errSuccess; +} + +ERR PKImageDecode_GetResolution( + PKImageDecode* pID, + Float* pfResX, + Float* pfResY) +{ + *pfResX = pID->fResX; + *pfResY = pID->fResY; + + return WMP_errSuccess; +} + +ERR PKImageDecode_GetColorContext(PKImageDecode *pID, U8 *pbColorContext, U32 *pcbColorContext) +{ + UNREFERENCED_PARAMETER( pID ); + UNREFERENCED_PARAMETER( pbColorContext ); + UNREFERENCED_PARAMETER( pcbColorContext ); + return WMP_errNotYetImplemented; +} + +ERR PKImageDecode_GetDescriptiveMetadata(PKImageDecode *pIE, DESCRIPTIVEMETADATA *pDescMetadata) +{ + UNREFERENCED_PARAMETER( pIE ); + UNREFERENCED_PARAMETER( pDescMetadata ); + return WMP_errNotYetImplemented; +} + +ERR PKImageDecode_Copy( + PKImageDecode* pID, + const PKRect* pRect, + U8* pb, + U32 cbStride) +{ + UNREFERENCED_PARAMETER( pID ); + UNREFERENCED_PARAMETER( pRect ); + UNREFERENCED_PARAMETER( pb ); + UNREFERENCED_PARAMETER( cbStride ); + return WMP_errAbstractMethod; +} + +ERR PKImageDecode_GetFrameCount( + PKImageDecode* pID, + U32* puCount) +{ + *puCount = pID->cFrame; + + return WMP_errSuccess; +} + +ERR PKImageDecode_SelectFrame( + PKImageDecode* pID, + U32 uFrame) +{ + UNREFERENCED_PARAMETER( pID ); + UNREFERENCED_PARAMETER( uFrame ); + // NYI + return WMP_errSuccess; +} + +ERR PKImageDecode_Release( + PKImageDecode** ppID) +{ + PKImageDecode* pID = *ppID; + + pID->fStreamOwner && pID->pStream->Close(&pID->pStream); + + return PKFree((void **) ppID); +} + +ERR PKImageDecode_Create( + PKImageDecode** ppID) +{ + ERR err = WMP_errSuccess; + PKImageDecode* pID = NULL; + + Call(PKAlloc((void **) ppID, sizeof(**ppID))); + + pID = *ppID; + pID->Initialize = PKImageDecode_Initialize; + pID->GetPixelFormat = PKImageDecode_GetPixelFormat; + pID->GetSize = PKImageDecode_GetSize; + pID->GetResolution = PKImageDecode_GetResolution; + pID->GetColorContext = PKImageDecode_GetColorContext; + pID->GetDescriptiveMetadata = PKImageDecode_GetDescriptiveMetadata; + pID->Copy = PKImageDecode_Copy; + pID->GetFrameCount = PKImageDecode_GetFrameCount; + pID->SelectFrame = PKImageDecode_SelectFrame; + pID->Release = PKImageDecode_Release; + +Cleanup: + return err; +} + diff --git a/libs/jxr/jxrgluelib/JXRGlue.h b/libs/jxr/jxrgluelib/JXRGlue.h new file mode 100644 index 00000000000..49e69c35660 --- /dev/null +++ b/libs/jxr/jxrgluelib/JXRGlue.h @@ -0,0 +1,642 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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. +// +//*@@@---@@@@****************************************************************** +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +//================================================================ +#define WMP_SDK_VERSION 0x0101 +#define PK_SDK_VERSION 0x0101 + +#define sizeof2(array) (sizeof(array)/sizeof(*(array))) +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef min +#define min(b,a) ((a) < (b) ? (a) : (b)) +#endif +#ifdef __ANSI__ +#define STRCPY_SAFE(pszDest, cbDest, pszSrc) (strncpy((pszDest), (pszSrc), (cbDest)) == (pszDest) ? 0 : 1) +#else +#define STRCPY_SAFE(pszDest, cbDest, pszSrc) (strcpy_s((pszDest), (cbDest), (pszSrc))) +#endif // __ANSI__ + +//================================================================ +typedef struct tagPKRect +{ + I32 X; + I32 Y; + I32 Width; + I32 Height; +} PKRect; + +//================================================================ +typedef U32 PKIID; + +EXTERN_C const PKIID IID_PKImageScanEncode; +EXTERN_C const PKIID IID_PKImageFrameEncode; + +EXTERN_C const PKIID IID_PKImageWmpEncode; + +EXTERN_C const PKIID IID_PKImageWmpDecode; + +struct IFDEntry +{ + U16 uTag; + U16 uType; + U32 uCount; + U32 uValue; +}; +EXTERN_C const U32 IFDEntryTypeSizes[13]; +EXTERN_C const U32 SizeofIFDEntry; + +//================================================================ +typedef float Float; + +typedef enum tagPKStreamFlags +{ + PKStreamOpenRead = 0x00000000UL, + PKStreamOpenWrite = 0x00000001UL, + PKStreamOpenReadWrite = 0x00000002UL, + PKStreamNoLock = 0x00010000UL, + PKStreamNoSeek = 0x00020000UL, + PKStreamCompress = 0x00040000UL, +} PKStreamFlags; + +/* Undefined formats */ +#define GUID_PKPixelFormatUndefined GUID_PKPixelFormatDontCare + +DEFINE_GUID(GUID_PKPixelFormatDontCare, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x00); + +/* Indexed formats */ +//DEFINE_GUID(GUID_PKPixelFormat1bppIndexed, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x01); +//DEFINE_GUID(GUID_PKPixelFormat2bppIndexed, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x02); +//DEFINE_GUID(GUID_PKPixelFormat4bppIndexed, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x03); +//DEFINE_GUID(GUID_PKPixelFormat8bppIndexed, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x04); + +DEFINE_GUID(GUID_PKPixelFormatBlackWhite, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x05); +//DEFINE_GUID(GUID_PKPixelFormat2bppGray, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x06); +//DEFINE_GUID(GUID_PKPixelFormat4bppGray, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x07); +DEFINE_GUID(GUID_PKPixelFormat8bppGray, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x08); + +/* sRGB formats (gamma is approx. 2.2) */ +/* For a full definition, see the sRGB spec */ + +/* 16bpp formats */ +DEFINE_GUID(GUID_PKPixelFormat16bppRGB555, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x09); +DEFINE_GUID(GUID_PKPixelFormat16bppRGB565, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0a); +DEFINE_GUID(GUID_PKPixelFormat16bppGray, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0b); + +/* 24bpp formats */ +DEFINE_GUID(GUID_PKPixelFormat24bppBGR, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c); +DEFINE_GUID(GUID_PKPixelFormat24bppRGB, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d); + +/* 32bpp format */ +DEFINE_GUID(GUID_PKPixelFormat32bppBGR, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0e); +DEFINE_GUID(GUID_PKPixelFormat32bppBGRA, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f); +DEFINE_GUID(GUID_PKPixelFormat32bppPBGRA, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x10); +DEFINE_GUID(GUID_PKPixelFormat32bppGrayFloat, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x11); +DEFINE_GUID(GUID_PKPixelFormat32bppRGB, 0xd98c6b95, 0x3efe, 0x47d6, 0xbb, 0x25, 0xeb, 0x17, 0x48, 0xab, 0x0c, 0xf1); +DEFINE_GUID(GUID_PKPixelFormat32bppRGBA, 0xf5c7ad2d, 0x6a8d, 0x43dd, 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9); +DEFINE_GUID(GUID_PKPixelFormat32bppPRGBA, 0x3cc4a650, 0xa527, 0x4d37, 0xa9, 0x16, 0x31, 0x42, 0xc7, 0xeb, 0xed, 0xba); + +/* 48bpp format */ +DEFINE_GUID(GUID_PKPixelFormat48bppRGBFixedPoint, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x12); + +/* scRGB formats. Gamma is 1.0 */ +/* For a full definition, see the scRGB spec */ + +/* 16bpp format */ +DEFINE_GUID(GUID_PKPixelFormat16bppGrayFixedPoint, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x13); + +/* 32bpp format */ +DEFINE_GUID(GUID_PKPixelFormat32bppRGB101010, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x14); + +/* 48bpp format */ +DEFINE_GUID(GUID_PKPixelFormat48bppRGB, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x15); + +/* 64bpp format */ +DEFINE_GUID(GUID_PKPixelFormat64bppRGBA, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16); +DEFINE_GUID(GUID_PKPixelFormat64bppPRGBA, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x17); + +/* 96bpp format */ +DEFINE_GUID(GUID_PKPixelFormat96bppRGBFixedPoint, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x18); +DEFINE_GUID(GUID_PKPixelFormat96bppRGBFloat, 0xe3fed78f, 0xe8db, 0x4acf, 0x84, 0xc1, 0xe9, 0x7f, 0x61, 0x36, 0xb3, 0x27); + + /* Floating point scRGB formats */ +DEFINE_GUID(GUID_PKPixelFormat128bppRGBAFloat, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x19); +DEFINE_GUID(GUID_PKPixelFormat128bppPRGBAFloat, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1a); +DEFINE_GUID(GUID_PKPixelFormat128bppRGBFloat, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1b); + + /* CMYK formats. */ +DEFINE_GUID(GUID_PKPixelFormat32bppCMYK, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1c); + + /* Photon formats */ +DEFINE_GUID(GUID_PKPixelFormat64bppRGBAFixedPoint, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1d); +DEFINE_GUID(GUID_PKPixelFormat64bppRGBFixedPoint, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x40); +DEFINE_GUID(GUID_PKPixelFormat128bppRGBAFixedPoint, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1e); +DEFINE_GUID(GUID_PKPixelFormat128bppRGBFixedPoint, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x41); + +DEFINE_GUID(GUID_PKPixelFormat64bppRGBAHalf, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3a); +DEFINE_GUID(GUID_PKPixelFormat64bppRGBHalf, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x42); +DEFINE_GUID(GUID_PKPixelFormat48bppRGBHalf, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3b); + +DEFINE_GUID(GUID_PKPixelFormat32bppRGBE, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3d); + +DEFINE_GUID(GUID_PKPixelFormat16bppGrayHalf, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3e); +DEFINE_GUID(GUID_PKPixelFormat32bppGrayFixedPoint, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3f); + + +/* More CMYK formats and n-Channel formats */ +DEFINE_GUID(GUID_PKPixelFormat64bppCMYK, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1f); + +DEFINE_GUID(GUID_PKPixelFormat24bpp3Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x20); +DEFINE_GUID(GUID_PKPixelFormat32bpp4Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x21); +DEFINE_GUID(GUID_PKPixelFormat40bpp5Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x22); +DEFINE_GUID(GUID_PKPixelFormat48bpp6Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x23); +DEFINE_GUID(GUID_PKPixelFormat56bpp7Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x24); +DEFINE_GUID(GUID_PKPixelFormat64bpp8Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x25); + +DEFINE_GUID(GUID_PKPixelFormat48bpp3Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x26); +DEFINE_GUID(GUID_PKPixelFormat64bpp4Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x27); +DEFINE_GUID(GUID_PKPixelFormat80bpp5Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x28); +DEFINE_GUID(GUID_PKPixelFormat96bpp6Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x29); +DEFINE_GUID(GUID_PKPixelFormat112bpp7Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2a); +DEFINE_GUID(GUID_PKPixelFormat128bpp8Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2b); + +DEFINE_GUID(GUID_PKPixelFormat40bppCMYKAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2c); +DEFINE_GUID(GUID_PKPixelFormat80bppCMYKAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2d); + +DEFINE_GUID(GUID_PKPixelFormat32bpp3ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2e); +DEFINE_GUID(GUID_PKPixelFormat40bpp4ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2f); +DEFINE_GUID(GUID_PKPixelFormat48bpp5ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x30); +DEFINE_GUID(GUID_PKPixelFormat56bpp6ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x31); +DEFINE_GUID(GUID_PKPixelFormat64bpp7ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x32); +DEFINE_GUID(GUID_PKPixelFormat72bpp8ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x33); + +DEFINE_GUID(GUID_PKPixelFormat64bpp3ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x34); +DEFINE_GUID(GUID_PKPixelFormat80bpp4ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x35); +DEFINE_GUID(GUID_PKPixelFormat96bpp5ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x36); +DEFINE_GUID(GUID_PKPixelFormat112bpp6ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x37); +DEFINE_GUID(GUID_PKPixelFormat128bpp7ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x38); +DEFINE_GUID(GUID_PKPixelFormat144bpp8ChannelsAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x39); + +/* YCrCb from Advanced Profile */ +DEFINE_GUID(GUID_PKPixelFormat12bppYCC420, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x44); +DEFINE_GUID(GUID_PKPixelFormat16bppYCC422, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x45); +DEFINE_GUID(GUID_PKPixelFormat20bppYCC422, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x46); +DEFINE_GUID(GUID_PKPixelFormat32bppYCC422, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x47); +DEFINE_GUID(GUID_PKPixelFormat24bppYCC444, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x48); +DEFINE_GUID(GUID_PKPixelFormat30bppYCC444, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x49); +DEFINE_GUID(GUID_PKPixelFormat48bppYCC444, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x4a); +DEFINE_GUID(GUID_PKPixelFormat16bpp48bppYCC444FixedPoint, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x4b); +DEFINE_GUID(GUID_PKPixelFormat20bppYCC420Alpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x4c); +DEFINE_GUID(GUID_PKPixelFormat24bppYCC422Alpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x4d); +DEFINE_GUID(GUID_PKPixelFormat30bppYCC422Alpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x4e); +DEFINE_GUID(GUID_PKPixelFormat48bppYCC422Alpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x4f); +DEFINE_GUID(GUID_PKPixelFormat32bppYCC444Alpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x50); +DEFINE_GUID(GUID_PKPixelFormat40bppYCC444Alpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x51); +DEFINE_GUID(GUID_PKPixelFormat64bppYCC444Alpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x52); +DEFINE_GUID(GUID_PKPixelFormat64bppYCC444AlphaFixedPoint, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x53); + +//YUV +#define GUID_PKPixelFormat12bppYUV420 GUID_PKPixelFormat12bppYCC420 +#define GUID_PKPixelFormat16bppYUV422 GUID_PKPixelFormat16bppYCC422 +#define GUID_PKPixelFormat24bppYUV444 GUID_PKPixelFormat24bppYCC444 + +/* CMYKDIRECT from Advanced Profile */ +DEFINE_GUID(GUID_PKPixelFormat32bppCMYKDIRECT, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x54); +DEFINE_GUID(GUID_PKPixelFormat64bppCMYKDIRECT, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x55); +DEFINE_GUID(GUID_PKPixelFormat40bppCMYKDIRECTAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x56); +DEFINE_GUID(GUID_PKPixelFormat80bppCMYKDIRECTAlpha, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x43); + +// PhotometricInterpretation +#define PK_PI_W0 0 // WhiteIsZero +#define PK_PI_B0 1 // BlackIsZero +#define PK_PI_RGB 2 +#define PK_PI_RGBPalette 3 +#define PK_PI_TransparencyMask 4 +#define PK_PI_CMYK 5 +#define PK_PI_YCbCr 6 +#define PK_PI_CIELab 8 + +#define PK_PI_NCH 100 +#define PK_PI_RGBE 101 + +#define PK_pixfmtNul 0x00000000 +#define PK_pixfmtHasAlpha 0x00000010 +#define PK_pixfmtPreMul 0x00000020 +#define PK_pixfmtBGR 0x00000040 +#define PK_pixfmtNeedConvert 0x80000000 + +#define LOOKUP_FORWARD 0 +#define LOOKUP_BACKWARD_TIF 1 + +typedef unsigned long WMP_GRBIT; +typedef GUID PKPixelFormatGUID; + +typedef struct tagPKPixelInfo +{ + const PKPixelFormatGUID* pGUIDPixFmt; + + size_t cChannel; + COLORFORMAT cfColorFormat; + BITDEPTH_BITS bdBitDepth; + U32 cbitUnit; + + WMP_GRBIT grBit; + + // TIFF + U32 uInterpretation; + U32 uSamplePerPixel; + U32 uBitsPerSample; + U32 uSampleFormat; +} PKPixelInfo; + +//================================================================ +ERR PKAlloc(void** ppv, size_t cb); +ERR PKFree(void** ppv); + +//---------------------------------------------------------------- +//ERR GetPixelInfo(PKPixelFormatGUID enPixelFormat, const PKPixelInfo** ppPI); +ERR PixelFormatLookup(PKPixelInfo* pPI, U8 uLookupType); +const PKPixelFormatGUID* GetPixelFormatFromHash(const U8 uPFHash); + +ERR GetImageEncodeIID(const char* szExt, const PKIID** ppIID); +ERR GetImageDecodeIID(const char* szExt, const PKIID** ppIID); + + +//================================================================ +#ifdef __ANSI__ +struct tagPKFactory; +struct tagPKCodecFactory; +struct tagPKImageDecode; +struct tagPKImageEncode; +struct tagPKFormatConverter; +#define PKFactory struct tagPKFactory +#define PKCodecFactory struct tagPKCodecFactory +#define PKImageDecode struct tagPKImageDecode +#define PKImageEncode struct tagPKImageEncode +#define PKFormatConverter struct tagPKFormatConverter +#else // __ANSI__ +typedef struct tagPKFactory PKFactory; +typedef struct tagPKCodecFactory PKCodecFactory; +typedef struct tagPKImageDecode PKImageDecode; +typedef struct tagPKImageEncode PKImageEncode; +typedef struct tagPKFormatConverter PKFormatConverter; +#endif // __ANSI__ +//================================================================ +typedef struct tagPKStream +{ + ERR (*InitializeFromFilename)(const char*, ULong); + + ERR (*Release)(void); + + FILE* fp; +} PKStream; + + +//================================================================ +typedef struct tagPKFactory +{ + ERR (*CreateStream)(PKStream**); + + ERR (*CreateStreamFromFilename)(struct WMPStream**, const char*, const char*); + ERR (*CreateStreamFromMemory)(struct WMPStream**, void*, size_t); + + ERR (*Release)(PKFactory**); +#ifdef __ANSI__ +#undef PKFactory +#endif // __ANSI__ +} PKFactory; + +//---------------------------------------------------------------- +ERR PKCreateFactory_CreateStream(PKStream** ppStream); +ERR PKCreateFactory_Release(PKFactory** ppFactory); + +EXTERN_C ERR PKCreateFactory(PKFactory**, U32); + + +//================================================================ +typedef struct tagPKCodecFactory +{ + ERR (*CreateCodec)(const PKIID*, void**); + ERR (*CreateDecoderFromFile)(const char*, PKImageDecode**); + ERR (*CreateFormatConverter)(PKFormatConverter**); + + ERR (*Release)(PKCodecFactory**); +#ifdef __ANSI__ +#undef PKCodecFactory +#endif // __ANSI__ +} PKCodecFactory; + +//---------------------------------------------------------------- +ERR PKCodecFactory_CreateCodec(const PKIID* iid, void** ppv); +ERR PKCreateCodecFactory_Release(PKCodecFactory** ppCFactory); + +EXTERN_C ERR PKCreateCodecFactory(PKCodecFactory**, U32); + +//================================================================ + +typedef enum BANDEDENCSTATE +{ + BANDEDENCSTATE_UNINITIALIZED = 0, + BANDEDENCSTATE_INIT, + BANDEDENCSTATE_ENCODING, + BANDEDENCSTATE_TERMINATED, + BANDEDENCSTATE_NONBANDEDENCODE, +} BANDEDENCSTATE; + +typedef struct tagPKImageEncode +{ + //ERR (*GetPixelFormat)(MILPixelFormat*)); + ERR (*Initialize)(PKImageEncode*, struct WMPStream*, void*, size_t); + ERR (*Terminate)(PKImageEncode*); + + ERR (*SetPixelFormat)(PKImageEncode*, PKPixelFormatGUID); + ERR (*SetSize)(PKImageEncode*, I32, I32); + ERR (*SetResolution)(PKImageEncode*, Float, Float); + ERR (*SetColorContext)(PKImageEncode *pIE, const U8 *pbColorContext, + U32 cbColorContext); + ERR (*SetDescriptiveMetadata)(PKImageEncode *pIE, + const DESCRIPTIVEMETADATA *pDescMetadata); + + ERR (*WritePixels)(PKImageEncode*, U32, U8*, U32); + ERR (*WriteSource)(PKImageEncode*, PKFormatConverter*, PKRect*); + + // Banded encode API - currently only implemented for WMP encoder + ERR (*WritePixelsBandedBegin)(PKImageEncode* pEncoder, struct WMPStream *pPlanarAlphaTempFile); + ERR (*WritePixelsBanded)(PKImageEncode* pEncoder, U32 cLines, U8* pbPixels, U32 cbStride, Bool fLastCall); + ERR (*WritePixelsBandedEnd)(PKImageEncode* pEncoder); +#define TEMPFILE_COPYBUF_SIZE 8192 // Means when using tempfile for planar alpha banded encode, copy this many bytes at a time + + ERR (*Transcode)(PKImageEncode*, PKImageDecode*, CWMTranscodingParam*); + + ERR (*CreateNewFrame)(PKImageEncode*, void*, size_t); + + ERR (*Release)(PKImageEncode**); + + struct WMPStream* pStream; + size_t offStart; + + PKPixelFormatGUID guidPixFormat; + + U32 uWidth; + U32 uHeight; + U32 idxCurrentLine; + + Float fResX; + Float fResY; + + U32 cFrame; + + Bool fHeaderDone; + size_t offPixel; + size_t cbPixel; + U8 *pbColorContext; + U32 cbColorContext; + U8 *pbEXIFMetadata; + U32 cbEXIFMetadataByteCount; + U8 *pbGPSInfoMetadata; + U32 cbGPSInfoMetadataByteCount; + U8 *pbIPTCNAAMetadata; + U32 cbIPTCNAAMetadataByteCount; + U8 *pbXMPMetadata; + U32 cbXMPMetadataByteCount; + U8 *pbPhotoshopMetadata; + U32 cbPhotoshopMetadataByteCount; + DESCRIPTIVEMETADATA sDescMetadata; + + Bool bWMP;//for the encoder in decoding + + struct + { + WmpDEMisc wmiDEMisc; + CWMImageInfo wmiI; + CWMIStrCodecParam wmiSCP; + CTXSTRCODEC ctxSC; + CWMImageInfo wmiI_Alpha; + CWMIStrCodecParam wmiSCP_Alpha; + CTXSTRCODEC ctxSC_Alpha; + + Bool bHasAlpha; + Long nOffImage; + Long nCbImage; + Long nOffAlpha; + Long nCbAlpha; + + ORIENTATION oOrientation; + + // Banded encode state variables + BANDEDENCSTATE eBandedEncState; + struct WMPStream *pPATempFile; + } WMP; + +#ifdef __ANSI__ +#undef PKImageEncode +#endif // __ANSI__ +} PKImageEncode; + +//---------------------------------------------------------------- +ERR PKImageEncode_Create_WMP(PKImageEncode** ppIE); + +ERR PKImageEncode_Initialize(PKImageEncode* pIE, struct WMPStream* pStream, void* pvParam, size_t cbParam); +ERR PKImageEncode_Terminate(PKImageEncode* pIE); +ERR PKImageEncode_SetPixelFormat(PKImageEncode* pIE, PKPixelFormatGUID enPixelFormat); +ERR PKImageEncode_SetSize(PKImageEncode* pIE, I32 iWidth, I32 iHeight); +ERR PKImageEncode_SetResolution(PKImageEncode* pIE, Float rX, Float rY); +ERR PKImageEncode_SetColorContext(PKImageEncode *pIE, const U8 *pbColorContext, U32 cbColorContext); +ERR PKImageEncode_SetDescriptiveMetadata(PKImageEncode *pIE, const DESCRIPTIVEMETADATA *pDescMetadata); +ERR PKImageEncode_WritePixels(PKImageEncode* pIE, U32 cLine, U8* pbPixel, U32 cbStride); +ERR PKImageEncode_CreateNewFrame(PKImageEncode* pIE, void* pvParam, size_t cbParam); +ERR PKImageEncode_Release(PKImageEncode** ppIE); + +ERR PKImageEncode_SetXMPMetadata_WMP(PKImageEncode *pIE, const U8 *pbXMPMetadata, U32 cbXMPMetadata); +ERR PKImageEncode_SetEXIFMetadata_WMP(PKImageEncode *pIE, const U8 *pbEXIFMetadata, U32 cbEXIFMetadata); +ERR PKImageEncode_SetGPSInfoMetadata_WMP(PKImageEncode *pIE, const U8 *pbGPSInfoMetadata, U32 cbGPSInfoMetadata); +ERR PKImageEncode_SetIPTCNAAMetadata_WMP(PKImageEncode *pIE, const U8 *pbIPTCNAAMetadata, U32 cbIPTCNAAMetadata); +ERR PKImageEncode_SetPhotoshopMetadata_WMP(PKImageEncode *pIE, const U8 *pbPhotoshopMetadata, U32 cbPhotoshopMetadata); + +void FreeDescMetadata(DPKPROPVARIANT *pvar); + +ERR PKImageEncode_Create(PKImageEncode** ppIE); + +//================================================================ +typedef struct tagPKImageDecode +{ + ERR (*Initialize)(PKImageDecode*, struct WMPStream* pStream); + + ERR (*GetPixelFormat)(PKImageDecode*, PKPixelFormatGUID*); + ERR (*GetSize)(PKImageDecode*, I32*, I32*); + ERR (*GetResolution)(PKImageDecode*, Float*, Float*); + ERR (*GetColorContext)(PKImageDecode *pID, U8 *pbColorContext, + U32 *pcbColorContext); + ERR (*GetDescriptiveMetadata)(PKImageDecode *pIE, + DESCRIPTIVEMETADATA *pDescMetadata); + + ERR (*GetRawStream)(PKImageDecode*, struct WMPStream**); + + ERR (*Copy)(PKImageDecode*, const PKRect*, U8*, U32); + + ERR (*GetFrameCount)(PKImageDecode*, U32*); + ERR (*SelectFrame)(PKImageDecode*, U32); + + ERR (*Release)(PKImageDecode**); + + struct WMPStream* pStream; + Bool fStreamOwner; + size_t offStart; + + PKPixelFormatGUID guidPixFormat; + + U32 uWidth; + U32 uHeight; + U32 idxCurrentLine; + + Float fResX; + Float fResY; + + U32 cFrame; + + struct + { + WmpDEMisc wmiDEMisc; + CWMImageInfo wmiI; + CWMIStrCodecParam wmiSCP; + CTXSTRCODEC ctxSC; + CWMImageInfo wmiI_Alpha; + CWMIStrCodecParam wmiSCP_Alpha; + CTXSTRCODEC ctxSC_Alpha; + + Bool bHasAlpha; + Long nOffImage; + Long nCbImage; + Long nOffAlpha; + Long nCbAlpha; + Bool bIgnoreOverlap; + size_t DecoderCurrMBRow; + size_t DecoderCurrAlphaMBRow; + size_t cMarker; + size_t cLinesDecoded; + size_t cLinesCropped; // Lines may be cropped from the top - buffer for subsequent decodes must be adjusted + Bool fFirstNonZeroDecode; + + Bool fOrientationFromContainer; + ORIENTATION oOrientationFromContainer; // Tag 0xBC02 in HD Photo container + + DESCRIPTIVEMETADATA sDescMetadata; + } WMP; + +#ifdef __ANSI__ +#undef PKImageDecode +#endif // __ANSI__ +} PKImageDecode; + +//---------------------------------------------------------------- +ERR PKImageDecode_Create_WMP(PKImageDecode** ppID); + +ERR PKImageDecode_Initialize(PKImageDecode* pID, struct WMPStream* pStream); +ERR PKImageDecode_GetPixelFormat(PKImageDecode* pID, PKPixelFormatGUID* pPF); +ERR PKImageDecode_GetSize(PKImageDecode* pID, I32* piWidth, I32* piHeight); +ERR PKImageDecode_GetResolution(PKImageDecode* pID, Float* pfrX, Float* pfrY); +ERR PKImageDecode_GetColorContext(PKImageDecode *pID, U8 *pbColorContext, U32 *pcbColorContext); +ERR PKImageDecode_GetDescriptiveMetadata(PKImageDecode *pID, DESCRIPTIVEMETADATA *pDescMetadata); +ERR PKImageDecode_Copy(PKImageDecode* pID, const PKRect* pRect, U8* pb, U32 cbStride); +ERR PKImageDecode_GetFrameCount(PKImageDecode* pID, U32* puCount); +ERR PKImageDecode_SelectFrame(PKImageDecode* pID, U32 uFrame); +ERR PKImageDecode_Release(PKImageDecode** ppID); + +ERR PKImageDecode_GetXMPMetadata_WMP(PKImageDecode *pID, U8 *pbXMPMetadata, U32 *pcbXMPMetadata); +ERR PKImageDecode_GetEXIFMetadata_WMP(PKImageDecode *pID, U8 *pbEXIFMetadata, U32 *pcbEXIFMetadata); +ERR PKImageDecode_GetGPSInfoMetadata_WMP(PKImageDecode *pID, U8 *pbGPSInfoMetadata, U32 *pcbGPSInfoMetadata); +ERR PKImageDecode_GetIPTCNAAMetadata_WMP(PKImageDecode *pID, U8 *pbIPTCNAAMetadata, U32 *pcbIPTCNAAMetadata); +ERR PKImageDecode_GetPhotoshopMetadata_WMP(PKImageDecode *pID, U8 *pbPhotoshopMetadata, U32 *pcbPhotoshopMetadata); + +ERR PKImageDecode_Create(PKImageDecode** ppID); +ERR PKCodecFactory_CreateDecoderFromFile(const char* szFilename, PKImageDecode** ppDecoder); + +//================================================================ +typedef struct tagPKFormatConverter +{ + ERR (*Initialize)(PKFormatConverter*, PKImageDecode*, char *pExt, PKPixelFormatGUID); + ERR (*InitializeConvert)(PKFormatConverter* pFC, const PKPixelFormatGUID enPFFrom, + char *pExt, PKPixelFormatGUID enPFTTo); + + ERR (*GetPixelFormat)(PKFormatConverter*, PKPixelFormatGUID*); + ERR (*GetSourcePixelFormat)(PKFormatConverter*, PKPixelFormatGUID*); + ERR (*GetSize)(PKFormatConverter*, I32*, I32*); + ERR (*GetResolution)(PKFormatConverter*, Float*, Float*); + + ERR (*Copy)(PKFormatConverter*, const PKRect*, U8*, U32); + ERR (*Convert)(PKFormatConverter*, const PKRect*, U8*, U32); + + ERR (*Release)(PKFormatConverter**); + + PKImageDecode* pDecoder; + PKPixelFormatGUID enPixelFormat; +#ifdef __ANSI__ +#undef PKFormatConverter +#endif // __ANSI__ +} PKFormatConverter; + +//---------------------------------------------------------------- +ERR PKImageEncode_Transcode(PKImageEncode* pIE, PKFormatConverter* pFC, PKRect* pRect); +ERR PKImageEncode_WriteSource(PKImageEncode* pIE, PKFormatConverter* pFC, PKRect* pRect); +ERR PKFormatConverter_Initialize(PKFormatConverter* pFC, PKImageDecode* pID, char *pExt, PKPixelFormatGUID enPF); +ERR PKFormatConverter_InitializeConvert(PKFormatConverter* pFC, const PKPixelFormatGUID enPFFrom, + char *pExt, PKPixelFormatGUID enPFTo); +ERR PKFormatConverter_GetPixelFormat(PKFormatConverter* pFC, PKPixelFormatGUID* pPF); +ERR PKFormatConverter_GetSourcePixelFormat(PKFormatConverter* pFC, PKPixelFormatGUID* pPF); +ERR PKFormatConverter_GetSize(PKFormatConverter* pFC, I32* piWidth, I32* piHeight); +ERR PKFormatConverter_GetResolution(PKFormatConverter* pFC, Float* pfrX, Float* pfrY); +ERR PKFormatConverter_Copy(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride); +ERR PKFormatConverter_Convert(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride); +ERR PKFormatConverter_Release(PKFormatConverter** ppFC); + +// Think of this as static member of PKFormatConverter "class" +ERR PKFormatConverter_EnumConversions(const PKPixelFormatGUID *pguidSourcePF, + const U32 iIndex, + const PKPixelFormatGUID **ppguidTargetPF); + +ERR PKCodecFactory_CreateFormatConverter(PKFormatConverter** ppFConverter); + +//---------------------------------------------------------------- +ERR PKAlloc(void** ppv, size_t cb); +ERR PKFree(void** ppv); +ERR PKAllocAligned(void** ppv, size_t cb, size_t iAlign); +ERR PKFreeAligned(void** ppv); + +#ifdef __cplusplus +} // extern "C" +#endif + diff --git a/libs/jxr/jxrgluelib/JXRGlueJxr.c b/libs/jxr/jxrgluelib/JXRGlueJxr.c new file mode 100644 index 00000000000..57fa9ed6f04 --- /dev/null +++ b/libs/jxr/jxrgluelib/JXRGlueJxr.c @@ -0,0 +1,2280 @@ + +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 +#include + + +static const char szHDPhotoFormat[] = "image/vnd.ms-photo"; +const U32 IFDEntryTypeSizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 }; +const U32 SizeofIFDEntry = sizeof(struct IFDEntry); + + +void CalcMetadataSizeLPSTR(const DPKPROPVARIANT var, + U16 *pcInactiveMetadata, + U32 *pcbOffsetSize, + U32 *pcbCount) +{ + if (DPKVT_EMPTY != var.vt) + { + U32 uiLenWithNull = (U32)strlen(var.VT.pszVal) + 1; // +1 for NULL; + assert(DPKVT_LPSTR == var.vt); + + // We only use offset if size > 4 + if (uiLenWithNull > 4) + *pcbOffsetSize += uiLenWithNull; + + if (pcbCount) + *pcbCount = uiLenWithNull; + } + else + *pcInactiveMetadata += 1; +} + +void CalcMetadataSizeLPWSTR(const DPKPROPVARIANT var, + U16 *pcInactiveMetadata, + U32 *pcbOffsetSize, + U32 *pcbCount) +{ + if (DPKVT_EMPTY != var.vt) + { + U32 uiCBWithNull = sizeof(U16) * ((U32)wcslen((wchar_t *) var.VT.pwszVal) + 1); // +1 for NULL term; + assert(DPKVT_LPWSTR == var.vt); + + // We only use offset if size > 4 + if (uiCBWithNull > 4) + *pcbOffsetSize += uiCBWithNull; + + if (pcbCount) + *pcbCount = uiCBWithNull; + } + else + *pcInactiveMetadata += 1; +} + +void CalcMetadataSizeUI2(const DPKPROPVARIANT var, + U16 *pcInactiveMetadata, + U32 *pcbMetadataSize) +{ + UNREFERENCED_PARAMETER( pcbMetadataSize ); + if (DPKVT_EMPTY != var.vt) + { + assert(DPKVT_UI2 == var.vt); + // This is a single UI2, so it will not be written via offset, but rather as value + } + else + *pcInactiveMetadata += 1; +} + +void CalcMetadataSizeUI4(const DPKPROPVARIANT var, + U16 *pcInactiveMetadata, + U32 *pcbContainer) +{ + UNREFERENCED_PARAMETER( pcbContainer ); + if (DPKVT_EMPTY != var.vt) + { + assert(DPKVT_UI4 == var.vt); + // This is a single UI4, so it will not be written via offset, but rather as value + } + else + *pcInactiveMetadata += 1; +} + +ERR CalcMetadataOffsetSize(PKImageEncode* pIE, + U16 *pcInactiveMetadata, + U32 *pcbMetadataSize) +{ + ERR err = WMP_errSuccess; + + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarImageDescription, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCameraMake, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCameraModel, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarSoftware, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarDateTime, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarArtist, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCopyright, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeUI2(pIE->sDescMetadata.pvarRatingStars, pcInactiveMetadata, pcbMetadataSize); + CalcMetadataSizeUI2(pIE->sDescMetadata.pvarRatingValue, pcInactiveMetadata, pcbMetadataSize); + CalcMetadataSizeLPWSTR(pIE->sDescMetadata.pvarCaption, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarDocumentName, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarPageName, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeUI4(pIE->sDescMetadata.pvarPageNumber, pcInactiveMetadata, pcbMetadataSize); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarHostComputer, pcInactiveMetadata, pcbMetadataSize, NULL); + + return err; +} + + +ERR CopyDescMetadata(DPKPROPVARIANT *pvarDst, + const DPKPROPVARIANT varSrc) +{ + ERR err = WMP_errSuccess; + size_t uiSize; + + pvarDst->vt = varSrc.vt; + switch (varSrc.vt) + { + case DPKVT_LPSTR: + pvarDst->vt = DPKVT_LPSTR; + uiSize = strlen(varSrc.VT.pszVal) + 1; + Call(PKAlloc((void **) &pvarDst->VT.pszVal, uiSize)); + memcpy(pvarDst->VT.pszVal, varSrc.VT.pszVal, uiSize); + break; + + case DPKVT_LPWSTR: + pvarDst->vt = DPKVT_LPWSTR; + uiSize = sizeof(U16) * (wcslen((wchar_t *) varSrc.VT.pwszVal) + 1); // +1 for NULL term + Call(PKAlloc((void **) &pvarDst->VT.pszVal, uiSize)); + memcpy(pvarDst->VT.pwszVal, varSrc.VT.pwszVal, uiSize); + break; + + case DPKVT_UI2: + pvarDst->VT.uiVal = varSrc.VT.uiVal; + break; + + case DPKVT_UI4: + pvarDst->VT.ulVal = varSrc.VT.ulVal; + break; + + default: + assert(FALSE); // This case is not handled + FailIf(TRUE, WMP_errNotYetImplemented); + + // *** FALL THROUGH *** + + case DPKVT_EMPTY: + memset(pvarDst, 0, sizeof(*pvarDst)); + assert(DPKVT_EMPTY == pvarDst->vt); + break; + } + +Cleanup: + return err; +} + + +void FreeDescMetadata(DPKPROPVARIANT *pvar) +{ + switch (pvar->vt) + { + case DPKVT_LPSTR: + PKFree((void **) &pvar->VT.pszVal); + break; + + case DPKVT_LPWSTR: + PKFree((void **) &pvar->VT.pwszVal); + break; + + default: + assert(FALSE); // This case is not handled + break; + + case DPKVT_EMPTY: + case DPKVT_UI2: + case DPKVT_UI4: + break; + } +} + + +ERR WriteDescMetadata(PKImageEncode *pIE, + const DPKPROPVARIANT var, + WmpDE *pwmpDE, + U32 *puiCurrDescMetadataOffset, + size_t *poffPos) +{ + ERR err = WMP_errSuccess; + WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc; + struct WMPStream* pWS = pIE->pStream; + U32 uiMetadataOffsetSize = 0; + U32 uiCount = 0; + U32 uiDataWrittenToOffset = 0; + U16 uiTemp = 0; + + if (0 == pDEMisc->uDescMetadataOffset || 0 == pDEMisc->uDescMetadataByteCount) + goto Cleanup; // Nothing to do here + + // Sanity check before - can be equal due to remaining metadata being DPKVT_EMPTY + assert(*puiCurrDescMetadataOffset <= pDEMisc->uDescMetadataByteCount); + + switch (var.vt) + { + case DPKVT_EMPTY: + break; + + case DPKVT_LPSTR: + CalcMetadataSizeLPSTR(var, &uiTemp, &uiMetadataOffsetSize, &uiCount); + pwmpDE->uCount = uiCount; + pwmpDE->uValueOrOffset = pDEMisc->uDescMetadataOffset + *puiCurrDescMetadataOffset; + Call(WriteWmpDE(pWS, poffPos, pwmpDE, (U8*)var.VT.pszVal, &uiDataWrittenToOffset)); + break; + + case DPKVT_LPWSTR: + CalcMetadataSizeLPWSTR(var, &uiTemp, &uiMetadataOffsetSize, &uiCount); + pwmpDE->uCount = uiCount; + pwmpDE->uValueOrOffset = pDEMisc->uDescMetadataOffset + *puiCurrDescMetadataOffset; + Call(WriteWmpDE(pWS, poffPos, pwmpDE, (U8*)var.VT.pwszVal, &uiDataWrittenToOffset)); + break; + + case DPKVT_UI2: + CalcMetadataSizeUI2(var, &uiTemp, &uiMetadataOffsetSize); + pwmpDE->uCount = 1; + pwmpDE->uValueOrOffset = var.VT.uiVal; + Call(WriteWmpDE(pWS, poffPos, pwmpDE, NULL, NULL)); + break; + + case DPKVT_UI4: + CalcMetadataSizeUI4(var, &uiTemp, &uiMetadataOffsetSize); + pwmpDE->uCount = 1; + pwmpDE->uValueOrOffset = var.VT.ulVal; + Call(WriteWmpDE(pWS, poffPos, pwmpDE, NULL, NULL)); + break; + + default: + assert(FALSE); // This case is not handled + FailIf(TRUE, WMP_errNotYetImplemented); + break; + } + + *puiCurrDescMetadataOffset += uiDataWrittenToOffset; + + // Sanity check after + assert(*puiCurrDescMetadataOffset <= pDEMisc->uDescMetadataByteCount); // Can be equal + +Cleanup: + return err; +} + + + +//================================================================ +// PKImageEncode_WMP +//================================================================ +ERR WriteContainerPre( + PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + const U32 OFFSET_OF_PFD = 0x20; + struct WMPStream* pWS = pIE->pStream; + WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc; + PKPixelInfo PI; + size_t offPos = 0; + + U8 IIMM[2] = {'\x49', '\x49'}; + // const U32 cbWmpDEMisc = OFFSET_OF_PFD; + U32 cbMetadataOffsetSize = 0; + U16 cInactiveMetadata = 0; + U32 uiCurrDescMetadataOffset = 0; + + static WmpDE wmpDEs[] = + { + {WMP_tagDocumentName, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagImageDescription, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagCameraMake, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagCameraModel, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagPageName, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagPageNumber, WMP_typSHORT, 2, (U32) -1}, // Descriptive metadata + {WMP_tagSoftware, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagDateTime, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagArtist, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagHostComputer, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagRatingStars, WMP_typSHORT, 1, (U32) -1}, // Descriptive metadata + {WMP_tagRatingValue, WMP_typSHORT, 1, (U32) -1}, // Descriptive metadata + {WMP_tagCopyright, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagCaption, WMP_typBYTE, 1, (U32) -1}, // Descriptive metadata + + {WMP_tagXMPMetadata, WMP_typBYTE, 1, (U32) -1}, + {WMP_tagIPTCNAAMetadata, WMP_typBYTE, 1, (U32) -1}, + {WMP_tagPhotoshopMetadata, WMP_typBYTE, 1, (U32) -1}, + {WMP_tagEXIFMetadata, WMP_typLONG, 1, (U32) -1}, + {WMP_tagIccProfile, WMP_typUNDEFINED, 1, (U32) -1}, + {WMP_tagGPSInfoMetadata, WMP_typLONG, 1, (U32) -1}, + + {WMP_tagPixelFormat, WMP_typBYTE, 16, (U32) -1}, + {WMP_tagTransformation, WMP_typLONG, 1, (U32) -1}, + {WMP_tagImageWidth, WMP_typLONG, 1, (U32) -1}, + {WMP_tagImageHeight, WMP_typLONG, 1, (U32) -1}, + {WMP_tagWidthResolution, WMP_typFLOAT, 1, (U32) -1}, + {WMP_tagHeightResolution, WMP_typFLOAT, 1, (U32) -1}, + {WMP_tagImageOffset, WMP_typLONG, 1, (U32) -1}, + {WMP_tagImageByteCount, WMP_typLONG, 1, (U32) -1}, + {WMP_tagAlphaOffset, WMP_typLONG, 1, (U32) -1}, + {WMP_tagAlphaByteCount, WMP_typLONG, 1, (U32) -1}, + }; + U16 cWmpDEs = sizeof(wmpDEs) / sizeof(wmpDEs[0]); + WmpDE wmpDE = {0}; + size_t i = 0; + + U8* pbEXIFMetadata = NULL; + U8* pbGPSInfoMetadata = NULL; + + // const unsigned char Zero[0x20] = { 0 }; + const unsigned char Zero[sizeof(struct IFDEntry) * sizeof(wmpDEs) / sizeof(wmpDEs[0]) + sizeof(U32)] = { 0 }; + assert(SizeofIFDEntry * sizeof(wmpDEs) / sizeof(wmpDEs[0]) + sizeof(U32) > 0x20); + + //================ + Call(pWS->GetPos(pWS, &offPos)); + FailIf(0 != offPos, WMP_errUnsupportedFormat); + + //================ + // Header (8 bytes) + Call(pWS->Write(pWS, IIMM, sizeof(IIMM))); offPos += 2; + Call(PutUShort(pWS, offPos, 0x01bc)); offPos += 2; + Call(PutULong(pWS, offPos, (U32)OFFSET_OF_PFD)); offPos += 4; + + //================ + // Write overflow area + pDEMisc->uOffPixelFormat = (U32)offPos; + PI.pGUIDPixFmt = &pIE->guidPixFormat; + PixelFormatLookup(&PI, LOOKUP_FORWARD); + + //Call(pWS->Write(pWS, PI.pGUIDPixFmt, sizeof(*PI.pGUIDPixFmt))); offPos += 16; + /** following code is endian-agnostic **/ + { + unsigned char *pGuid = (unsigned char *) &pIE->guidPixFormat; + Call(PutULong(pWS, offPos, ((U32 *)pGuid)[0])); + Call(PutUShort(pWS, offPos + 4, ((U16 *)(pGuid + 4))[0])); + Call(PutUShort(pWS, offPos + 6, ((U16 *)(pGuid + 6))[0])); + Call(pWS->Write(pWS, pGuid + 8, 8)); + offPos += 16; + } + + //================ + // Tally up space required for descriptive metadata + Call(CalcMetadataOffsetSize(pIE, &cInactiveMetadata, &cbMetadataOffsetSize)); + cWmpDEs -= cInactiveMetadata; + + //================ + // PFD + assert (offPos <= OFFSET_OF_PFD); // otherwise stuff is overwritten + if (offPos < OFFSET_OF_PFD) + Call(pWS->Write(pWS, Zero, OFFSET_OF_PFD - offPos)); + offPos = (size_t)OFFSET_OF_PFD; + + if (!pIE->WMP.bHasAlpha || pIE->WMP.wmiSCP.uAlphaMode != 2) //no planar alpha + cWmpDEs -= 2; + + if (0 == pIE->cbXMPMetadataByteCount) + cWmpDEs -= 1; // No XMP metadata + + if (0 == pIE->cbIPTCNAAMetadataByteCount) + cWmpDEs -= 1; // No IPTCNAA metadata + + if (0 == pIE->cbPhotoshopMetadataByteCount) + cWmpDEs -= 1; // No Photoshop metadata + + if (0 == pIE->cbEXIFMetadataByteCount) + cWmpDEs -= 1; // No EXIF metadata + + if (0 == pIE->cbColorContext) + cWmpDEs -= 1; // No color context + + if (0 == pIE->cbGPSInfoMetadataByteCount) + cWmpDEs -= 1; // No GPSInfo metadata + + pDEMisc->uImageOffset = (U32)(offPos + sizeof(U16) + SizeofIFDEntry * cWmpDEs + sizeof(U32)); + + if (cbMetadataOffsetSize > 0) + { + pDEMisc->uDescMetadataByteCount = cbMetadataOffsetSize; + pDEMisc->uDescMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += cbMetadataOffsetSize; + } + + if (pIE->cbXMPMetadataByteCount > 0) + { + pDEMisc->uXMPMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += pIE->cbXMPMetadataByteCount; + } + + if (pIE->cbIPTCNAAMetadataByteCount > 0) + { + pDEMisc->uIPTCNAAMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += pIE->cbIPTCNAAMetadataByteCount; + } + + if (pIE->cbPhotoshopMetadataByteCount > 0) + { + pDEMisc->uPhotoshopMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += pIE->cbPhotoshopMetadataByteCount; + } + + if (pIE->cbEXIFMetadataByteCount > 0) + { + pDEMisc->uEXIFMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += (pDEMisc->uImageOffset & 1); + pDEMisc->uImageOffset += pIE->cbEXIFMetadataByteCount; + } + + if (pIE->cbColorContext > 0) + { + pDEMisc->uColorProfileOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += pIE->cbColorContext; + } + + if (pIE->cbGPSInfoMetadataByteCount > 0) + { + pDEMisc->uGPSInfoMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += (pDEMisc->uImageOffset & 1); + pDEMisc->uImageOffset += pIE->cbGPSInfoMetadataByteCount; + } + + Call(PutUShort(pWS, offPos, cWmpDEs)); offPos += 2; + Call(pWS->Write(pWS, Zero, SizeofIFDEntry * cWmpDEs + sizeof(U32))); + + //================ + wmpDE = wmpDEs[i++]; + assert(WMP_tagDocumentName == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarDocumentName, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagImageDescription == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarImageDescription, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagCameraMake == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCameraMake, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagCameraModel == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCameraModel, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagPageName == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarPageName, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagPageNumber == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarPageNumber, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagSoftware == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarSoftware, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagDateTime == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarDateTime, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagArtist == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarArtist, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagHostComputer == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarHostComputer, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagRatingStars == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarRatingStars, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagRatingValue == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarRatingValue, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagCopyright == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCopyright, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagCaption == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCaption, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + // XMP Metadata + wmpDE = wmpDEs[i++]; + assert(WMP_tagXMPMetadata == wmpDE.uTag); + if (pIE->cbXMPMetadataByteCount > 0) + { + U32 uiTemp; + wmpDE.uCount = pIE->cbXMPMetadataByteCount; + wmpDE.uValueOrOffset = pDEMisc->uXMPMetadataOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbXMPMetadata, &uiTemp)); + } + + // IPTCNAA Metadata + wmpDE = wmpDEs[i++]; + assert(WMP_tagIPTCNAAMetadata == wmpDE.uTag); + if (pIE->cbIPTCNAAMetadataByteCount > 0) + { + U32 uiTemp; + wmpDE.uCount = pIE->cbIPTCNAAMetadataByteCount; + wmpDE.uValueOrOffset = pDEMisc->uIPTCNAAMetadataOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbIPTCNAAMetadata, &uiTemp)); + } + + // Photoshop Metadata + wmpDE = wmpDEs[i++]; + assert(WMP_tagPhotoshopMetadata == wmpDE.uTag); + if (pIE->cbPhotoshopMetadataByteCount > 0) + { + U32 uiTemp; + wmpDE.uCount = pIE->cbPhotoshopMetadataByteCount; + wmpDE.uValueOrOffset = pDEMisc->uPhotoshopMetadataOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbPhotoshopMetadata, &uiTemp)); + } + + // EXIF Metadata + wmpDE = wmpDEs[i++]; + assert(WMP_tagEXIFMetadata == wmpDE.uTag); + if (pIE->cbEXIFMetadataByteCount > 0) + { + U32 uiTemp; + if ((pDEMisc->uEXIFMetadataOffset & 1) != 0) + { + Call(pWS->SetPos(pWS, pDEMisc->uEXIFMetadataOffset)); + Call(pWS->Write(pWS, Zero, 1)); + } + pDEMisc->uEXIFMetadataOffset += (pDEMisc->uEXIFMetadataOffset & 1); + wmpDE.uValueOrOffset = pDEMisc->uEXIFMetadataOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + Call(PKAlloc((void **) &pbEXIFMetadata, pIE->cbEXIFMetadataByteCount)); + uiTemp = pDEMisc->uEXIFMetadataOffset; + Call(BufferCopyIFD(pIE->pbEXIFMetadata, pIE->cbEXIFMetadataByteCount, 0, WMP_INTEL_ENDIAN, + pbEXIFMetadata - uiTemp, uiTemp + pIE->cbEXIFMetadataByteCount, &uiTemp)); + Call(pWS->SetPos(pWS, pDEMisc->uEXIFMetadataOffset)); + Call(pWS->Write(pWS, pbEXIFMetadata, pIE->cbEXIFMetadataByteCount)); + } + + // ICC Profile + wmpDE = wmpDEs[i++]; + assert(WMP_tagIccProfile == wmpDE.uTag); + if (pIE->cbColorContext > 0) + { + U32 uiTemp; + wmpDE.uCount = pIE->cbColorContext; + wmpDE.uValueOrOffset = pDEMisc->uColorProfileOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbColorContext, &uiTemp)); + } + + // GPSInfo Metadata + wmpDE = wmpDEs[i++]; + assert(WMP_tagGPSInfoMetadata == wmpDE.uTag); + if (pIE->cbGPSInfoMetadataByteCount > 0) + { + U32 uiTemp; + if ((pDEMisc->uGPSInfoMetadataOffset & 1) != 0) + { + Call(pWS->SetPos(pWS, pDEMisc->uGPSInfoMetadataOffset)); + Call(pWS->Write(pWS, Zero, 1)); + } + pDEMisc->uGPSInfoMetadataOffset += (pDEMisc->uGPSInfoMetadataOffset & 1); + wmpDE.uValueOrOffset = pDEMisc->uGPSInfoMetadataOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + Call(PKAlloc((void **) &pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount)); + uiTemp = pDEMisc->uGPSInfoMetadataOffset; + Call(BufferCopyIFD(pIE->pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount, 0, WMP_INTEL_ENDIAN, + pbGPSInfoMetadata - uiTemp, uiTemp + pIE->cbGPSInfoMetadataByteCount, &uiTemp)); + Call(pWS->SetPos(pWS, pDEMisc->uGPSInfoMetadataOffset)); + Call(pWS->Write(pWS, pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount)); + } + + wmpDE = wmpDEs[i++]; + assert(WMP_tagPixelFormat == wmpDE.uTag); + wmpDE.uValueOrOffset = pDEMisc->uOffPixelFormat; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagTransformation == wmpDE.uTag); + wmpDE.uValueOrOffset = pIE->WMP.oOrientation; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagImageWidth == wmpDE.uTag); + wmpDE.uValueOrOffset = pIE->uWidth; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagImageHeight == wmpDE.uTag); + wmpDE.uValueOrOffset = pIE->uHeight; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagWidthResolution == wmpDE.uTag); + *((float *) &wmpDE.uValueOrOffset) = pIE->fResX; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagHeightResolution == wmpDE.uTag); + *((float *) &wmpDE.uValueOrOffset) = pIE->fResY; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagImageOffset == wmpDE.uTag); + wmpDE.uValueOrOffset = pDEMisc->uImageOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + // fix up in WriteContainerPost() + wmpDE = wmpDEs[i++]; + assert(WMP_tagImageByteCount == wmpDE.uTag); + pDEMisc->uOffImageByteCount = (U32)offPos; + wmpDE.uValueOrOffset = 0; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2) + { + // fix up in WriteContainerPost() + wmpDE = wmpDEs[i++]; + assert(WMP_tagAlphaOffset == wmpDE.uTag); + pDEMisc->uOffAlphaOffset = (U32)offPos; + wmpDE.uValueOrOffset = 0; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + // fix up in WriteContainerPost() + wmpDE = wmpDEs[i++]; + assert(WMP_tagAlphaByteCount == wmpDE.uTag); + pDEMisc->uOffAlphaByteCount = (U32)offPos; + wmpDE.uValueOrOffset = 0; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + } + + //================ + Call(PutULong(pWS, offPos, 0)); offPos += 4; + + assert(0 == (offPos & 1)); + if (pDEMisc->uColorProfileOffset > 0 || pDEMisc->uDescMetadataOffset > 0 || + pDEMisc->uXMPMetadataOffset > 0 || pDEMisc->uIPTCNAAMetadataOffset > 0 || + pDEMisc->uPhotoshopMetadataOffset > 0 || pDEMisc->uEXIFMetadataOffset > 0 || + pDEMisc->uGPSInfoMetadataOffset > 0) + { + assert(pDEMisc->uColorProfileOffset == offPos || + pDEMisc->uDescMetadataOffset == offPos || + pDEMisc->uXMPMetadataOffset == offPos || + pDEMisc->uIPTCNAAMetadataOffset == offPos || + pDEMisc->uPhotoshopMetadataOffset == offPos || + pDEMisc->uEXIFMetadataOffset == offPos || + pDEMisc->uGPSInfoMetadataOffset == offPos); + + // OK, now skip to image offset + Call(pWS->SetPos(pWS, pDEMisc->uImageOffset)); + offPos = pDEMisc->uImageOffset; + } + assert(pDEMisc->uImageOffset == offPos); + +Cleanup: + if (pbEXIFMetadata != NULL) + PKFree((void **) &pbEXIFMetadata); + if (pbGPSInfoMetadata != NULL) + PKFree((void **) &pbGPSInfoMetadata); + return err; +} + + + +ERR WriteContainerPost( + PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + + struct WMPStream* pWS = pIE->pStream; + WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc; + size_t offPos; + + WmpDE deImageByteCount = {WMP_tagImageByteCount, WMP_typLONG, 1, 0}; + WmpDE deAlphaOffset = {WMP_tagAlphaOffset, WMP_typLONG, 1, 0}; + WmpDE deAlphaByteCount = {WMP_tagAlphaByteCount, WMP_typLONG, 1, 0}; + + deImageByteCount.uValueOrOffset = pIE->WMP.nCbImage; + offPos = pDEMisc->uOffImageByteCount; + Call(WriteWmpDE(pWS, &offPos, &deImageByteCount, NULL, NULL)); + + //Alpha + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2) + { + deAlphaOffset.uValueOrOffset = pIE->WMP.nOffAlpha; + offPos = pDEMisc->uOffAlphaOffset; + Call(WriteWmpDE(pWS, &offPos, &deAlphaOffset, NULL, NULL)); + + deAlphaByteCount.uValueOrOffset = pIE->WMP.nCbAlpha + pIE->WMP.nOffAlpha; + offPos = pDEMisc->uOffAlphaByteCount; + Call(WriteWmpDE(pWS, &offPos, &deAlphaByteCount, NULL, NULL)); + } + +Cleanup: + return err; +} + + +//================================================ +ERR PKImageEncode_Initialize_WMP( + PKImageEncode* pIE, + struct WMPStream* pStream, + void* pvParam, + size_t cbParam) +{ + ERR err = WMP_errSuccess; + + FailIf(sizeof(pIE->WMP.wmiSCP) != cbParam, WMP_errInvalidArgument); + + pIE->WMP.wmiSCP = *(CWMIStrCodecParam*)pvParam; + pIE->WMP.wmiSCP_Alpha = *(CWMIStrCodecParam*)pvParam; + pIE->pStream = pStream; + + pIE->WMP.wmiSCP.pWStream = pIE->pStream; + pIE->WMP.wmiSCP_Alpha.pWStream = pIE->pStream; + +Cleanup: + return err; +} + +ERR PKImageEncode_Terminate_WMP( + PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + UNREFERENCED_PARAMETER( pIE ); + return err; +} + + +ERR PKImageEncode_EncodeContent_Init( + PKImageEncode* pIE, + PKPixelInfo PI, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + + // init codec + pIE->WMP.wmiI.cWidth = pIE->uWidth; + pIE->WMP.wmiI.cHeight = pIE->uHeight; + pIE->WMP.wmiI.bdBitDepth = PI.bdBitDepth; + pIE->WMP.wmiI.cBitsPerUnit = PI.cbitUnit; + pIE->WMP.wmiI.bRGB = !(PI.grBit & PK_pixfmtBGR); + pIE->WMP.wmiI.cfColorFormat = PI.cfColorFormat; + pIE->WMP.wmiI.oOrientation = pIE->WMP.oOrientation; + + // Set the fPaddedUserBuffer if the following conditions are met + if (0 == ((size_t)pbPixels % 128) && // Frame buffer is aligned to 128-byte boundary + 0 == (pIE->uWidth % 16) && // Horizontal resolution is multiple of 16 + 0 == (cLine % 16) && // Vertical resolution is multiple of 16 + 0 == (cbStride % 128)) // Stride is a multiple of 128 bytes + { + pIE->WMP.wmiI.fPaddedUserBuffer = TRUE; + // Note that there are additional conditions in strenc_x86.c's strEncOpt + // which could prevent optimization from being engaged + } + + //if (pIE->WMP.bHasAlpha) + //{ + // pIE->WMP.wmiSCP.cChannel = PI.cChannel - 1; + // pIE->WMP.wmiI.cfColorFormat = PI.cfStripAlpha; + //} + //else + + if(PI.cfColorFormat == NCOMPONENT && (!(PI.grBit & PK_pixfmtHasAlpha)))//N-channel without Alpha + pIE->WMP.wmiSCP.cChannel = PI.cChannel; + else + pIE->WMP.wmiSCP.cChannel = PI.cChannel - 1;//other formats and (N-channel + Alpha) + + pIE->idxCurrentLine = 0; + + pIE->WMP.wmiSCP.fMeasurePerf = TRUE; + FailIf(ICERR_OK != ImageStrEncInit(&pIE->WMP.wmiI, &pIE->WMP.wmiSCP, &pIE->WMP.ctxSC), WMP_errFail); + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeContent_Encode( + PKImageEncode* pIE, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + U32 i = 0; + + //================================ + for (i = 0; i < cLine; i += 16) + { + Bool f420 = ( pIE->WMP.wmiI.cfColorFormat == YUV_420 || + (pIE->WMP.wmiSCP.bYUVData && pIE->WMP.wmiSCP.cfColorFormat==YUV_420) ); + CWMImageBufferInfo wmiBI = { 0 }; + wmiBI.pv = pbPixels + cbStride * i / (f420 ? 2 : 1); + wmiBI.cLine = min(16, cLine - i); + wmiBI.cbStride = cbStride; + FailIf(ICERR_OK != ImageStrEncEncode(pIE->WMP.ctxSC, &wmiBI), WMP_errFail); + } + pIE->idxCurrentLine += cLine; + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeContent_Term(PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + + FailIf(ICERR_OK != ImageStrEncTerm(pIE->WMP.ctxSC), WMP_errFail); + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeContent( + PKImageEncode* pIE, + PKPixelInfo PI, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + size_t offPos = 0; + + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nOffImage = (Long)offPos; + + Call(PKImageEncode_EncodeContent_Init(pIE, PI, cLine, pbPixels, cbStride)); + Call(PKImageEncode_EncodeContent_Encode(pIE, cLine, pbPixels, cbStride)); + Call(PKImageEncode_EncodeContent_Term(pIE)); + + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nCbImage = (Long)offPos - pIE->WMP.nOffImage; + +Cleanup: + return err; +} + + +ERR PKImageEncode_EncodeAlpha_Init( + PKImageEncode* pIE, + PKPixelInfo PI, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + + UNREFERENCED_PARAMETER( cLine ); + UNREFERENCED_PARAMETER( pbPixels ); + UNREFERENCED_PARAMETER( cbStride ); + + pIE->WMP.wmiI_Alpha = pIE->WMP.wmiI; + + pIE->WMP.wmiI_Alpha.cWidth = pIE->uWidth; + pIE->WMP.wmiI_Alpha.cHeight = pIE->uHeight; + pIE->WMP.wmiI_Alpha.bdBitDepth = PI.bdBitDepth; + pIE->WMP.wmiI_Alpha.cBitsPerUnit = PI.cbitUnit; + pIE->WMP.wmiI_Alpha.bRGB = !(PI.grBit & PK_pixfmtBGR); + pIE->WMP.wmiI.oOrientation = pIE->WMP.oOrientation; +// pIE->WMP.wmiI_Alpha.cLeadingPadding += pIE->WMP.wmiSCP.cChannel; +// pIE->WMP.wmiI_Alpha.cLeadingPadding += PI.cChannel - 1; + + switch (pIE->WMP.wmiI.bdBitDepth) + { + case BD_8: + pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) - 1; + break; + + case BD_16: + case BD_16S: + case BD_16F: + pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(U16) - 1; + break; + + case BD_32: + case BD_32S: + case BD_32F: + pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(float) - 1; + break; + + case BD_5: + case BD_10: + case BD_565: + default: + break; + } + +// pIE->WMP.wmiSCP_Alpha.uAlphaMode = 1; + + + //assert(pIE->WMP.wmiI_Alpha.cfColorFormat == CF_RGB); // only RGBA is supported for now! + pIE->WMP.wmiI_Alpha.cfColorFormat = Y_ONLY; + + pIE->WMP.wmiSCP_Alpha.cfColorFormat = Y_ONLY; + + pIE->idxCurrentLine = 0; + pIE->WMP.wmiSCP_Alpha.fMeasurePerf = TRUE; + FailIf(ICERR_OK != ImageStrEncInit(&pIE->WMP.wmiI_Alpha, &pIE->WMP.wmiSCP_Alpha, &pIE->WMP.ctxSC_Alpha), WMP_errFail); + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeAlpha_Encode( + PKImageEncode* pIE, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + U32 i = 0; + + //================================ + for (i = 0; i < cLine; i += 16) + { + CWMImageBufferInfo wmiBI = { 0 }; + wmiBI.pv = pbPixels + cbStride * i; + wmiBI.cLine = min(16, cLine - i); + wmiBI.cbStride = cbStride; + FailIf(ICERR_OK != ImageStrEncEncode(pIE->WMP.ctxSC_Alpha, &wmiBI), WMP_errFail); + } + pIE->idxCurrentLine += cLine; + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeAlpha_Term(PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + + FailIf(ICERR_OK != ImageStrEncTerm(pIE->WMP.ctxSC_Alpha), WMP_errFail); + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeAlpha( + PKImageEncode* pIE, + PKPixelInfo PI, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + size_t offPos = 0; + + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + if ((offPos & 1) != 0) + { + // Make the mark even if it is odd by inserting a pad byte + char zero = 0; + Call(pIE->pStream->Write(pIE->pStream, &zero, 1)); + offPos++; + } + pIE->WMP.nOffAlpha = (Long)offPos; + + Call(PKImageEncode_EncodeAlpha_Init(pIE, PI, cLine, pbPixels, cbStride)); + Call(PKImageEncode_EncodeAlpha_Encode(pIE, cLine, pbPixels, cbStride)); + Call(PKImageEncode_EncodeAlpha_Term(pIE)); + + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nCbAlpha = (Long)offPos - pIE->WMP.nOffAlpha; + +Cleanup: + return err; +} + + + +static ERR SetMetadata(PKImageEncode *pIE, const U8 *pbMetadata, U32 cbMetadata, U8** pbSet, U32* pcbSet) +{ + ERR err = WMP_errSuccess; + + // Fail if the caller called us after we've already written the header out + if (pIE->fHeaderDone) + { + assert(FALSE); // Message to programmer + err = WMP_errOutOfSequence; + goto Cleanup; + } + + // Make a copy of the metadata + PKFree((void **) pbSet); + *pcbSet = 0; + + Call(PKAlloc((void **) pbSet, cbMetadata)); + memcpy(*pbSet, pbMetadata, cbMetadata); + *pcbSet = cbMetadata; + +Cleanup: + return err; +} + + + +ERR PKImageEncode_SetColorContext_WMP(PKImageEncode *pIE, + const U8 *pbColorContext, + U32 cbColorContext) +{ + return SetMetadata(pIE, pbColorContext, cbColorContext, &pIE->pbColorContext, &pIE->cbColorContext); +} + + + +ERR PKImageEncode_SetXMPMetadata_WMP(PKImageEncode *pIE, const U8 *pbXMPMetadata, U32 cbXMPMetadata) +{ // same as the other Set's, but make sure dc:format is image/vnd.ms-photo + ERR err = WMP_errSuccess; + char* pbTemp = 0; + U32 cbTemp; + char* pszFormatBegin; + // const char* pszXMPMetadata = (const char*)pbXMPMetadata; + size_t cbBuffer; + + // Fail if the caller called us after we've already written the header out + FailIf(pIE->fHeaderDone, WMP_errOutOfSequence); + + // Free any previously set XMP metadata + PKFree((void **) &pIE->pbXMPMetadata); + pIE->cbXMPMetadataByteCount = 0; + + // allocate a block big enough for data passed in plus added trailing null plus added HD Photo dc:format + // there may already be a trailing null (but ps doesn't seem to) + // there may already be a dc:format we will replace with HD Photo's + // but anyway this block will be large enough guaranteed + cbBuffer = cbXMPMetadata + 1 + sizeof("") - 1 + sizeof("") - 1 + sizeof(szHDPhotoFormat) - 1; + Call(PKAlloc((void **) &pbTemp, cbBuffer)); + memcpy(pbTemp, pbXMPMetadata, cbXMPMetadata); // Make a copy of the metadata + pbTemp[cbXMPMetadata] = '\0'; + cbXMPMetadata = (U32)strlen(pbTemp); + pszFormatBegin = strstr(pbTemp, ""); + if ( pszFormatBegin != 0 ) + { + char* pszFormatEnd; + const char* pszLessThan; + + pszFormatEnd = strstr(pszFormatBegin, ""); + FailIf(pszFormatEnd == 0, WMP_errFail); + pszLessThan = strchr(pszFormatBegin + sizeof("") - 1, '<'); + FailIf(pszLessThan != pszFormatEnd, WMP_errFail); + pszFormatEnd += sizeof("") - 1; + + // photoshop doesn't put a trailing null, so we don't either + // hd and tiff don't put a trailing null, so we don't either + cbTemp = cbXMPMetadata - (U32) ( pszFormatEnd - pszFormatBegin ) + sizeof(szHDPhotoFormat) - 1; + assert(cbTemp <= cbBuffer); + FailIf(0 != STRCPY_SAFE(pszFormatBegin, + cbBuffer - (pszFormatBegin - pbTemp), + szHDPhotoFormat), + WMP_errBufferOverflow); + memcpy(pszFormatBegin + sizeof(szHDPhotoFormat) - 1, pbXMPMetadata + ( pszFormatEnd - pbTemp ), + cbXMPMetadata - ( pszFormatEnd - pbTemp )); + } + else + { + cbTemp = cbXMPMetadata; + } + + pIE->pbXMPMetadata = (U8 *) pbTemp; + pIE->cbXMPMetadataByteCount = cbTemp; + return ( err ); + +Cleanup: + PKFree((void **) &pbTemp); + pIE->cbXMPMetadataByteCount = 0; + return err; +} + + + +ERR PKImageEncode_SetEXIFMetadata_WMP(PKImageEncode *pIE, const U8 *pbEXIFMetadata, U32 cbEXIFMetadata) +{ + return SetMetadata(pIE, pbEXIFMetadata, cbEXIFMetadata, + &pIE->pbEXIFMetadata, &pIE->cbEXIFMetadataByteCount); +} + + + +ERR PKImageEncode_SetGPSInfoMetadata_WMP(PKImageEncode *pIE, const U8 *pbGPSInfoMetadata, U32 cbGPSInfoMetadata) +{ + return SetMetadata(pIE, pbGPSInfoMetadata, cbGPSInfoMetadata, + &pIE->pbGPSInfoMetadata, &pIE->cbGPSInfoMetadataByteCount); +} + + + +ERR PKImageEncode_SetIPTCNAAMetadata_WMP(PKImageEncode *pIE, const U8 *pbIPTCNAAMetadata, U32 cbIPTCNAAMetadata) +{ + return SetMetadata(pIE, pbIPTCNAAMetadata, cbIPTCNAAMetadata, + &pIE->pbIPTCNAAMetadata, &pIE->cbIPTCNAAMetadataByteCount); +} + + + +ERR PKImageEncode_SetPhotoshopMetadata_WMP(PKImageEncode *pIE, const U8 *pbPhotoshopMetadata, U32 cbPhotoshopMetadata) +{ + return SetMetadata(pIE, pbPhotoshopMetadata, cbPhotoshopMetadata, + &pIE->pbPhotoshopMetadata, &pIE->cbPhotoshopMetadataByteCount); +} + + + +ERR PKImageEncode_SetDescriptiveMetadata_WMP(PKImageEncode *pIE, const DESCRIPTIVEMETADATA *pSrcMeta) +{ + ERR err = WMP_errSuccess; + DESCRIPTIVEMETADATA *pDstMeta = &pIE->sDescMetadata; + + // Fail if the caller called us after we've already written the header out + if (pIE->fHeaderDone) + { + assert(FALSE); // Message to programmer + FailIf(TRUE, WMP_errOutOfSequence); + } + + // Make a copy of the descriptive metadata + Call(CopyDescMetadata(&pDstMeta->pvarImageDescription, pSrcMeta->pvarImageDescription)); + Call(CopyDescMetadata(&pDstMeta->pvarCameraMake, pSrcMeta->pvarCameraMake)); + Call(CopyDescMetadata(&pDstMeta->pvarCameraModel, pSrcMeta->pvarCameraModel)); + Call(CopyDescMetadata(&pDstMeta->pvarSoftware, pSrcMeta->pvarSoftware)); + Call(CopyDescMetadata(&pDstMeta->pvarDateTime, pSrcMeta->pvarDateTime)); + Call(CopyDescMetadata(&pDstMeta->pvarArtist, pSrcMeta->pvarArtist)); + Call(CopyDescMetadata(&pDstMeta->pvarCopyright, pSrcMeta->pvarCopyright)); + Call(CopyDescMetadata(&pDstMeta->pvarRatingStars, pSrcMeta->pvarRatingStars)); + Call(CopyDescMetadata(&pDstMeta->pvarRatingValue, pSrcMeta->pvarRatingValue)); + Call(CopyDescMetadata(&pDstMeta->pvarCaption, pSrcMeta->pvarCaption)); + Call(CopyDescMetadata(&pDstMeta->pvarDocumentName, pSrcMeta->pvarDocumentName)); + Call(CopyDescMetadata(&pDstMeta->pvarPageName, pSrcMeta->pvarPageName)); + Call(CopyDescMetadata(&pDstMeta->pvarPageNumber, pSrcMeta->pvarPageNumber)); + Call(CopyDescMetadata(&pDstMeta->pvarHostComputer, pSrcMeta->pvarHostComputer)); + +Cleanup: + return err; +} + + + +ERR PKImageEncode_WritePixels_WMP( + PKImageEncode* pIE, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + // U32 i = 0; + PKPixelInfo PI; + + // Performing non-banded encode + assert(BANDEDENCSTATE_UNINITIALIZED == pIE->WMP.eBandedEncState); + pIE->WMP.eBandedEncState = BANDEDENCSTATE_NONBANDEDENCODE; + + PI.pGUIDPixFmt = &pIE->guidPixFormat; + PixelFormatLookup(&PI, LOOKUP_FORWARD); + pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha); + + if (!pIE->fHeaderDone) + { + // write metadata + Call(WriteContainerPre(pIE)); + + pIE->fHeaderDone = !FALSE; + } + +/* if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2){ + pIE->WMP.wmiSCP_Alpha = pIE->WMP.wmiSCP; + } +*/ + Call(PKImageEncode_EncodeContent(pIE, PI, cLine, pbPixels, cbStride)); + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2){//planar alpha + Call(PKImageEncode_EncodeAlpha(pIE, PI, cLine, pbPixels, cbStride)); + } + + Call(WriteContainerPost(pIE)); + +Cleanup: + return err; +} + + +ERR PKImageEncode_WritePixelsBandedBegin_WMP(PKImageEncode* pIE, struct WMPStream *pPATempFile) +{ + ERR err = WMP_errSuccess; + + // Just make sure that we are in the correct state to begin a banded decode + assert(BANDEDENCSTATE_UNINITIALIZED == pIE->WMP.eBandedEncState); + pIE->WMP.eBandedEncState = BANDEDENCSTATE_INIT; + + // Save the planar alpha tempfile for future use + pIE->WMP.pPATempFile = pPATempFile; + +//Cleanup: + return err; +} + +ERR PKImageEncode_WritePixelsBanded_WMP(PKImageEncode* pIE, U32 cLine, U8* pbPixels, U32 cbStride, Bool fLastCall) +{ + ERR err = WMP_errSuccess; + PKPixelInfo PI = {0}; + Bool fPI = FALSE; + BANDEDENCSTATE eEncStateOrig = pIE->WMP.eBandedEncState; + struct WMPStream *pPATempFile = pIE->WMP.pPATempFile; + + // Unless this is the last call, reject inputs which are not multiples of 16 + FailIf(!fLastCall && 0 != cLine % 16, WMP_errMustBeMultipleOf16LinesUntilLastCall); + + if (!pIE->fHeaderDone || BANDEDENCSTATE_INIT == pIE->WMP.eBandedEncState) + { + PI.pGUIDPixFmt = &pIE->guidPixFormat; + PixelFormatLookup(&PI, LOOKUP_FORWARD); + pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha); + fPI = TRUE; + + // Check if this is planar alpha: banded encode requires temp file + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2) + { + FailIf(NULL == pPATempFile, WMP_errPlanarAlphaBandedEncRequiresTempFile); + } + } + + if (!pIE->fHeaderDone) + { + // write metadata + assert(fPI); + Call(WriteContainerPre(pIE)); + pIE->fHeaderDone = !FALSE; + } + + if (BANDEDENCSTATE_INIT == pIE->WMP.eBandedEncState) + { + // Record start of main content for future call to WriteContainerPost + size_t offPos; + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nOffImage = (Long)offPos; + + assert(fPI); + Call(PKImageEncode_EncodeContent_Init(pIE, PI, cLine, pbPixels, cbStride)); + pIE->WMP.eBandedEncState = BANDEDENCSTATE_ENCODING; + } + + Call(PKImageEncode_EncodeContent_Encode(pIE, cLine, pbPixels, cbStride)); + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2) + { + //planar alpha + if (BANDEDENCSTATE_INIT == eEncStateOrig) + { + size_t offStart; + + // We assume the following which allows us to avoid saving state + Call(pPATempFile->GetPos(pPATempFile, &offStart)); + assert(0 == offStart); + assert(pIE->WMP.wmiSCP_Alpha.pWStream == pIE->WMP.wmiSCP.pWStream); + + // For planar alpha, we write the file to a temp file + pIE->WMP.wmiSCP_Alpha.pWStream = pPATempFile; + Call(PKImageEncode_EncodeAlpha_Init(pIE, PI, cLine, pbPixels, cbStride)); + } + + Call(PKImageEncode_EncodeAlpha_Encode(pIE, cLine, pbPixels, cbStride)); + } + +Cleanup: + return err; +} + +ERR PKImageEncode_WritePixelsBandedEnd_WMP(PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + struct WMPStream *pMainStream = pIE->WMP.wmiSCP.pWStream; + size_t offAlpha; + + assert(BANDEDENCSTATE_ENCODING == pIE->WMP.eBandedEncState); + + // Finish off main content, update its length ptr for WriteContainerPost + Call(PKImageEncode_EncodeContent_Term(pIE)); + Call(pMainStream->GetPos(pIE->pStream, &offAlpha)); + pIE->WMP.nCbImage = (Long)offAlpha - pIE->WMP.nOffImage; + + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2) + { + size_t cbAlpha; + size_t cbBytesCopied; + struct WMPStream *pAlphaStream = pIE->WMP.wmiSCP_Alpha.pWStream; + + assert(pAlphaStream != pMainStream); // Otherwise we didn't use a temp file + + // Close it up - this causes write to temp file + Call(PKImageEncode_EncodeAlpha_Term(pIE)); + + // Calculate size of alpha bitstream and its new offset + Call(pAlphaStream->GetPos(pAlphaStream, &cbAlpha)); + + // Copy alpha bitstream to end of main stream + cbBytesCopied = 0; + Call(pAlphaStream->SetPos(pAlphaStream, 0)); + while (cbBytesCopied < cbAlpha) + { + char rgbBuf[TEMPFILE_COPYBUF_SIZE]; + size_t cbCopy; + + cbCopy = min(sizeof(rgbBuf), cbAlpha - cbBytesCopied); + Call(pAlphaStream->Read(pAlphaStream, rgbBuf, cbCopy)); + Call(pMainStream->Write(pMainStream, rgbBuf, cbCopy)); + + cbBytesCopied += cbCopy; + } + assert(cbBytesCopied == cbAlpha); + + // Update alpha offset/length for WriteContainerPost + pIE->WMP.nOffAlpha = (Long)offAlpha; + pIE->WMP.nCbAlpha = (Long)cbAlpha; + } + + Call(WriteContainerPost(pIE)); + +Cleanup: + return err; +} + + +ERR PKImageEncode_Transcode_WMP( + PKImageEncode* pIE, + PKImageDecode* pID, + CWMTranscodingParam* pParam) +{ + ERR err = WMP_errSuccess; + Float fResX = 0, fResY = 0; + PKPixelFormatGUID pixGUID = {0}; + CWMTranscodingParam tcParamAlpha; + size_t offPos = 0; + Bool fPlanarAlpha; + PKPixelInfo PI; + + struct WMPStream* pWSDec = NULL; + struct WMPStream* pWSEnc= pIE->pStream; + + // pass through metadata + Call(pID->GetPixelFormat(pID, &pixGUID)); + Call(pIE->SetPixelFormat(pIE, pixGUID)); + + Call(pIE->SetSize(pIE, (I32)pParam->cWidth, (I32)pParam->cHeight)); + + Call(pID->GetResolution(pID, &fResX, &fResY)); + Call(pIE->SetResolution(pIE, fResX, fResY)); + + PI.pGUIDPixFmt = &pIE->guidPixFormat; + PixelFormatLookup(&PI, LOOKUP_FORWARD); + pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha) && (2 == pParam->uAlphaMode); + assert(0 == pIE->WMP.bHasAlpha || (pParam->uAlphaMode == 2)); // Decode alpha mode does not match encode alpha mode! + + // Check for any situations where transcoder is being asked to convert alpha - we can't do this + // NOTE: Decoder's bHasAlpha parameter really means, "has PLANAR alpha" + PI.pGUIDPixFmt = &pixGUID; + PixelFormatLookup(&PI, LOOKUP_FORWARD); + FailIf(0 == (PI.grBit & PK_pixfmtHasAlpha) && pParam->uAlphaMode != 0, + WMP_errAlphaModeCannotBeTranscoded); // Destination is planar/interleaved, src has no alpha + FailIf(!!(PI.grBit & PK_pixfmtHasAlpha) && 2 == pParam->uAlphaMode && + FALSE == pID->WMP.bHasAlpha, WMP_errAlphaModeCannotBeTranscoded); // Destination is planar, src is interleaved + FailIf(!!(PI.grBit & PK_pixfmtHasAlpha) && 3 == pParam->uAlphaMode && + pID->WMP.bHasAlpha, WMP_errAlphaModeCannotBeTranscoded); // Destination is interleaved, src is planar + assert(/*pParam->uAlphaMode >= 0 &&*/ pParam->uAlphaMode <= 3); // All the above statements make this assumption + + fPlanarAlpha = pIE->WMP.bHasAlpha && (2 == pParam->uAlphaMode); + + // write matadata + Call(WriteContainerPre(pIE)); + + // Copy transcoding params for alpha (codec changes the struct) + if (fPlanarAlpha) + tcParamAlpha = *pParam; + + // write compressed bitstream + Call(pID->GetRawStream(pID, &pWSDec)); + + FailIf(ICERR_OK != WMPhotoTranscode(pWSDec, pWSEnc, pParam), WMP_errFail); + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nCbImage = (Long)offPos - pIE->WMP.nOffImage; + + if (fPlanarAlpha) + { + pIE->WMP.nOffAlpha = (Long)offPos; + + // Cue the stream to alpha block + assert(pID->WMP.wmiDEMisc.uAlphaOffset > 0); + Call(pWSDec->SetPos(pWSDec, pID->WMP.wmiDEMisc.uAlphaOffset)); + + FailIf(ICERR_OK != WMPhotoTranscode(pWSDec, pWSEnc, &tcParamAlpha), WMP_errFail); + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nCbAlpha = (Long)offPos - pIE->WMP.nOffAlpha; + } + + // fixup matadata + Call(WriteContainerPost(pIE)); + +Cleanup: + return err; +} + +ERR PKImageEncode_CreateNewFrame_WMP( + PKImageEncode* pIE, + void* pvParam, + size_t cbParam) +{ + ERR err = WMP_errSuccess; + + UNREFERENCED_PARAMETER( pIE ); + UNREFERENCED_PARAMETER( pvParam ); + UNREFERENCED_PARAMETER( cbParam ); + + Call(WMP_errNotYetImplemented); + +Cleanup: + return err; +} + +ERR PKImageEncode_Release_WMP( + PKImageEncode** ppIE) +{ + ERR err = WMP_errSuccess; + + PKImageEncode *pIE = *ppIE; + pIE->pStream->Close(&pIE->pStream); + + PKFree((void **) &pIE->pbColorContext); + pIE->cbColorContext = 0; + PKFree((void **) &pIE->pbXMPMetadata); + pIE->cbXMPMetadataByteCount = 0; + PKFree((void **) &pIE->pbEXIFMetadata); + pIE->cbEXIFMetadataByteCount = 0; + PKFree((void **) &pIE->pbGPSInfoMetadata); + pIE->cbGPSInfoMetadataByteCount = 0; + PKFree((void **) &pIE->pbIPTCNAAMetadata); + pIE->cbIPTCNAAMetadataByteCount = 0; + PKFree((void **) &pIE->pbPhotoshopMetadata); + pIE->cbPhotoshopMetadataByteCount = 0; + + // Free descriptive metadata + FreeDescMetadata(&pIE->sDescMetadata.pvarImageDescription); + FreeDescMetadata(&pIE->sDescMetadata.pvarCameraMake); + FreeDescMetadata(&pIE->sDescMetadata.pvarCameraModel); + FreeDescMetadata(&pIE->sDescMetadata.pvarSoftware); + FreeDescMetadata(&pIE->sDescMetadata.pvarDateTime); + FreeDescMetadata(&pIE->sDescMetadata.pvarArtist); + FreeDescMetadata(&pIE->sDescMetadata.pvarCopyright); + FreeDescMetadata(&pIE->sDescMetadata.pvarRatingStars); + FreeDescMetadata(&pIE->sDescMetadata.pvarRatingValue); + FreeDescMetadata(&pIE->sDescMetadata.pvarCaption); + FreeDescMetadata(&pIE->sDescMetadata.pvarDocumentName); + FreeDescMetadata(&pIE->sDescMetadata.pvarPageName); + FreeDescMetadata(&pIE->sDescMetadata.pvarPageNumber); + FreeDescMetadata(&pIE->sDescMetadata.pvarHostComputer); + + Call(PKFree((void **) ppIE)); + +Cleanup: + return err; +} + +//---------------------------------------------------------------- +ERR PKImageEncode_Create_WMP(PKImageEncode** ppIE) +{ + ERR err = WMP_errSuccess; + + PKImageEncode* pIE = NULL; + + Call(PKImageEncode_Create(ppIE)); + + pIE = *ppIE; + pIE->Initialize = PKImageEncode_Initialize_WMP; + pIE->Terminate = PKImageEncode_Terminate_WMP; + pIE->SetColorContext = PKImageEncode_SetColorContext_WMP; + pIE->SetDescriptiveMetadata = PKImageEncode_SetDescriptiveMetadata_WMP; + pIE->WritePixels = PKImageEncode_WritePixels_WMP; + + pIE->WritePixelsBandedBegin = PKImageEncode_WritePixelsBandedBegin_WMP; + pIE->WritePixelsBanded = PKImageEncode_WritePixelsBanded_WMP; + pIE->WritePixelsBandedEnd = PKImageEncode_WritePixelsBandedEnd_WMP; + + pIE->Transcode = PKImageEncode_Transcode_WMP; + pIE->CreateNewFrame = PKImageEncode_CreateNewFrame_WMP; + pIE->Release = PKImageEncode_Release_WMP; + pIE->bWMP = TRUE; + +Cleanup: + return err; +} + + +//================================================================ +// PKImageDecode_WMP +//================================================================ +ERR ParsePFDEntry( + PKImageDecode* pID, + U16 uTag, + U16 uType, + U32 uCount, + U32 uValue) +{ + ERR err = WMP_errSuccess; + ERR errTmp = WMP_errSuccess; + PKPixelInfo PI; + struct WMPStream* pWS = pID->pStream; + // size_t offPos = 0; + + union uf{ + U32 uVal; + Float fVal; + }ufValue = {0}; + + //================================ + switch (uTag) + { + case WMP_tagPixelFormat: + { + unsigned char *pGuid = (unsigned char *) &pID->guidPixFormat; + /** following code is endian-agnostic **/ + Call(GetULong(pWS, uValue, (U32 *)pGuid)); + Call(GetUShort(pWS, uValue + 4, (unsigned short *)(pGuid + 4))); + Call(GetUShort(pWS, uValue + 6, (unsigned short *)(pGuid + 6))); + Call(pWS->Read(pWS, pGuid + 8, 8)); + + PI.pGUIDPixFmt = &pID->guidPixFormat; + PixelFormatLookup(&PI, LOOKUP_FORWARD); + + pID->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha); + pID->WMP.wmiI.cBitsPerUnit = PI.cbitUnit; + pID->WMP.wmiI.bRGB = !(PI.grBit & PK_pixfmtBGR); + + break; + } + + case WMP_tagTransformation: + FailIf(1 != uCount, WMP_errUnsupportedFormat); + assert(uValue < O_MAX); + pID->WMP.fOrientationFromContainer = TRUE; + pID->WMP.oOrientationFromContainer = uValue; + break; + + case WMP_tagImageWidth: + FailIf(0 == uValue, WMP_errUnsupportedFormat); + break; + + case WMP_tagImageHeight: + FailIf(0 == uValue, WMP_errUnsupportedFormat); + break; + + case WMP_tagImageOffset: + FailIf(1 != uCount, WMP_errUnsupportedFormat); + pID->WMP.wmiDEMisc.uImageOffset = uValue; + break; + + case WMP_tagImageByteCount: + FailIf(1 != uCount, WMP_errUnsupportedFormat); + pID->WMP.wmiDEMisc.uImageByteCount = uValue; + break; + + case WMP_tagAlphaOffset: + FailIf(1 != uCount, WMP_errUnsupportedFormat); + pID->WMP.wmiDEMisc.uAlphaOffset = uValue; + break; + + case WMP_tagAlphaByteCount: + FailIf(1 != uCount, WMP_errUnsupportedFormat); + pID->WMP.wmiDEMisc.uAlphaByteCount = uValue; + break; + + case WMP_tagWidthResolution: + FailIf(1 != uCount, WMP_errUnsupportedFormat); + ufValue.uVal = uValue; + pID->fResX = ufValue.fVal; + break; + + case WMP_tagHeightResolution: + FailIf(1 != uCount, WMP_errUnsupportedFormat); + ufValue.uVal = uValue; + pID->fResY = ufValue.fVal; + break; + + case WMP_tagIccProfile: + pID->WMP.wmiDEMisc.uColorProfileByteCount = uCount; + pID->WMP.wmiDEMisc.uColorProfileOffset = uValue; + break; + + case WMP_tagXMPMetadata: + pID->WMP.wmiDEMisc.uXMPMetadataByteCount = uCount; + pID->WMP.wmiDEMisc.uXMPMetadataOffset = uValue; + break; + + case WMP_tagEXIFMetadata: + pID->WMP.wmiDEMisc.uEXIFMetadataOffset = uValue; + CallIgnoreError(errTmp, StreamCalcIFDSize(pWS, uValue, &pID->WMP.wmiDEMisc.uEXIFMetadataByteCount)); + break; + + case WMP_tagGPSInfoMetadata: + pID->WMP.wmiDEMisc.uGPSInfoMetadataOffset = uValue; + CallIgnoreError(errTmp, StreamCalcIFDSize(pWS, uValue, &pID->WMP.wmiDEMisc.uGPSInfoMetadataByteCount)); + break; + + case WMP_tagIPTCNAAMetadata: + pID->WMP.wmiDEMisc.uIPTCNAAMetadataByteCount = uCount; + pID->WMP.wmiDEMisc.uIPTCNAAMetadataOffset = uValue; + break; + + case WMP_tagPhotoshopMetadata: + pID->WMP.wmiDEMisc.uPhotoshopMetadataByteCount = uCount; + pID->WMP.wmiDEMisc.uPhotoshopMetadataOffset = uValue; + break; + + case WMP_tagCompression: + case WMP_tagImageType: + case WMP_tagImageDataDiscard: + case WMP_tagAlphaDataDiscard: + break; + + // Descriptive Metadata + case WMP_tagImageDescription: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarImageDescription)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarImageDescription.vt); + break; + + case WMP_tagCameraMake: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarCameraMake)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCameraMake.vt); + break; + + case WMP_tagCameraModel: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarCameraModel)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCameraModel.vt); + break; + + case WMP_tagSoftware: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarSoftware)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarSoftware.vt); + break; + + case WMP_tagDateTime: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarDateTime)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarDateTime.vt); + break; + + case WMP_tagArtist: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarArtist)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarArtist.vt); + break; + + case WMP_tagCopyright: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarCopyright)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCopyright.vt); + break; + + case WMP_tagRatingStars: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarRatingStars)); + assert(DPKVT_UI2 == pID->WMP.sDescMetadata.pvarRatingStars.vt); + break; + + case WMP_tagRatingValue: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarRatingValue)); + assert(DPKVT_UI2 == pID->WMP.sDescMetadata.pvarRatingValue.vt); + break; + + case WMP_tagCaption: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarCaption)); + assert((DPKVT_BYREF | DPKVT_UI1) == pID->WMP.sDescMetadata.pvarCaption.vt); + + // Change type from C-style byte array to LPWSTR + assert((U8*)pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal == + pID->WMP.sDescMetadata.pvarCaption.VT.pbVal); + assert(0 == pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal[uCount/sizeof(U16) - 1]); // Confirm null-term + // make sure null term (ReadPropvar allocated enough space for this) + pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal[uCount/sizeof(U16)] = 0; + pID->WMP.sDescMetadata.pvarCaption.vt = DPKVT_LPWSTR; + break; + + case WMP_tagDocumentName: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarDocumentName)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarDocumentName.vt); + break; + + case WMP_tagPageName: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarPageName)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarPageName.vt); + break; + + case WMP_tagPageNumber: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarPageNumber)); + assert(DPKVT_UI4 == pID->WMP.sDescMetadata.pvarPageNumber.vt); + break; + + case WMP_tagHostComputer: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarHostComputer)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarHostComputer.vt); + break; + + default: + fprintf(stderr, "Unrecognized WMPTag: %d(%#x), %d, %d, %#x" CRLF, + (int)uTag, (int)uTag, (int)uType, (int)uCount, (int)uValue); + break; + } + +Cleanup: + return err; +} + +ERR ParsePFD( + PKImageDecode* pID, + size_t offPos, + U16 cEntry) +{ + ERR err = WMP_errSuccess; + struct WMPStream* pWS = pID->pStream; + U16 i = 0; + + for (i = 0; i < cEntry; ++i) + { + U16 uTag = 0; + U16 uType = 0; + U32 uCount = 0; + U32 uValue = 0; + + Call(GetUShort(pWS, offPos, &uTag)); offPos += 2; + Call(GetUShort(pWS, offPos, &uType)); offPos += 2; + Call(GetULong(pWS, offPos, &uCount)); offPos += 4; + Call(GetULong(pWS, offPos, &uValue)); offPos += 4; + + Call(ParsePFDEntry(pID, uTag, uType, uCount, uValue)); + } + + pID->WMP.bHasAlpha = ((pID->WMP.bHasAlpha) && (pID->WMP.wmiDEMisc.uAlphaOffset != 0) && (pID->WMP.wmiDEMisc.uAlphaByteCount != 0));//has planar alpha + +Cleanup: + return err; +} + +ERR ReadContainer( + PKImageDecode* pID) +{ + ERR err = WMP_errSuccess; + + struct WMPStream* pWS = pID->pStream; + size_t offPos = 0; + + char szSig[2] = {0}; + U16 uWmpID = 0; + U32 offPFD = 0; + U16 cPFDEntry = 0; + U8 bVersion; + + //================================ + Call(pWS->GetPos(pWS, &offPos)); + FailIf(0 != offPos, WMP_errUnsupportedFormat); + + //================================ + // Header + Call(pWS->Read(pWS, szSig, sizeof(szSig))); offPos += 2; + FailIf(szSig != strstr(szSig, "II"), WMP_errUnsupportedFormat); + + Call(GetUShort(pWS, offPos, &uWmpID)); offPos += 2; + FailIf(WMP_valWMPhotoID != (0x00FF & uWmpID), WMP_errUnsupportedFormat); + + // We accept version 00 and version 01 bitstreams - all others rejected + bVersion = (0xFF00 & uWmpID) >> 8; + FailIf(bVersion != 0 && bVersion != 1, WMP_errUnsupportedFormat); + + Call(GetULong(pWS, offPos, &offPFD)); offPos += 4; + + //================================ + // PFD + offPos = (size_t)offPFD; + Call(GetUShort(pWS, offPos, &cPFDEntry)); offPos += 2; + FailIf(0 == cPFDEntry || USHRT_MAX == cPFDEntry, WMP_errUnsupportedFormat); + Call(ParsePFD(pID, offPos, cPFDEntry)); + + //================================ + Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uImageOffset)); + +Cleanup: + return err; +} + + +//================================================ +ERR PKImageDecode_Initialize_WMP( + PKImageDecode* pID, + struct WMPStream* pWS) +{ + ERR err = WMP_errSuccess; + + CWMImageInfo* pII = NULL; + + //================================ + Call(PKImageDecode_Initialize(pID, pWS)); + + //================================ + Call(ReadContainer(pID)); + + //================================ + pID->WMP.wmiSCP.pWStream = pWS; + pID->WMP.DecoderCurrMBRow = 0; + pID->WMP.cLinesDecoded = 0; + pID->WMP.cLinesCropped = 0; + pID->WMP.fFirstNonZeroDecode = FALSE; + + FailIf(ICERR_OK != ImageStrDecGetInfo(&pID->WMP.wmiI, &pID->WMP.wmiSCP), WMP_errFail); + assert(Y_ONLY <= pID->WMP.wmiSCP.cfColorFormat && pID->WMP.wmiSCP.cfColorFormat < CFT_MAX); + assert(BD_SHORT == pID->WMP.wmiSCP.bdBitDepth || BD_LONG == pID->WMP.wmiSCP.bdBitDepth); + + // If HD Photo container provided an orientation, this should override bitstream orientation + // If container did NOT provide an orientation, force O_NONE. This is to be consistent with + // Vista behaviour, which is to ignore bitstream orientation (only looks at container). + if (pID->WMP.fOrientationFromContainer) + { + pID->WMP.wmiI.oOrientation = pID->WMP.oOrientationFromContainer; + } + else + { + // Force to O_NONE to match Vista decode behaviour + pID->WMP.wmiI.oOrientation = O_NONE; + } + + pII = &pID->WMP.wmiI; + pID->uWidth = (U32)pII->cWidth; + pID->uHeight = (U32)pII->cHeight; + +Cleanup: + return err; +} + + +ERR PKImageDecode_GetSize_WMP( + PKImageDecode* pID, + I32* piWidth, + I32* piHeight) +{ + if (pID->WMP.wmiI.oOrientation >= O_RCW) + { + *piWidth = (I32)pID->uHeight; + *piHeight = (I32)pID->uWidth; + } + else + { + *piWidth = (I32)pID->uWidth; + *piHeight = (I32)pID->uHeight; + } + return WMP_errSuccess; +} + + +ERR PKImageDecode_GetRawStream_WMP( + PKImageDecode* pID, + struct WMPStream** ppWS) +{ + ERR err = WMP_errSuccess; + struct WMPStream* pWS = pID->pStream; + + *ppWS = NULL; + Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uImageOffset)); + *ppWS = pWS; + +Cleanup: + return err; +} + +ERR PKImageDecode_Copy_WMP( + PKImageDecode* pID, + const PKRect* pRect, + U8* pb, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + U32 cThumbnailScale; + U32 linesperMBRow; + CWMImageBufferInfo wmiBI = { 0 }; +#ifdef REENTRANT_MODE + U8 *pbLowMemAdj = NULL; + U32 i, cMBRow; + U32 cMBRowStart; +#endif // REENTRANT_MODE + struct WMPStream* pWS = pID->pStream; + U8 tempAlphaMode = 0; + wmiBI.pv = pb; + wmiBI.cLine = pRect->Height; + wmiBI.cbStride = cbStride; +#ifdef REENTRANT_MODE + // In REENTRANT_MODE, we allow rectangles with any top left corner (not just (0,0)) +#else + FailIf(0 != pRect->X, WMP_errInvalidParameter); + FailIf(0 != pRect->Y, WMP_errInvalidParameter); +#endif // REENTRANT_MODE + + cThumbnailScale = 1; + if (pID->WMP.wmiI.cThumbnailWidth > 0) + { + while(cThumbnailScale * pID->WMP.wmiI.cThumbnailWidth < pID->uWidth) + cThumbnailScale <<= 1; + } + // note the following implementation can't handle fractional linesperMBRow limiting + // us to >= 1/256 thumbnail which is unfortunate, but all the PS plugin needs is 1/256 + // and I didn't care to get into floating point or a bunch of conditional tests or + // other rewrite for a case not needed nor tested by PS plugin. sorry. + linesperMBRow = 16 / cThumbnailScale; + +#ifdef REENTRANT_MODE + if (0 == pID->WMP.DecoderCurrMBRow) + { +#endif // REENTRANT_MODE + // Set the fPaddedUserBuffer if the following conditions are met + if (0 == ((size_t)pb % 128) && // Frame buffer is aligned to 128-byte boundary + 0 == (pRect->Height % 16) && // Horizontal resolution is multiple of 16 + 0 == (pRect->Width % 16) && // Vertical resolution is multiple of 16 + 0 == (cbStride % 128)) // Stride is a multiple of 128 bytes + { + pID->WMP.wmiI.fPaddedUserBuffer = TRUE; + // Note that there are additional conditions in strdec_x86.c's strDecOpt + // which could prevent optimization from being engaged + } +#ifdef REENTRANT_MODE + } +#endif // REENTRANT_MODE + //if(pID->WMP.wmiSCP.uAlphaMode != 1) + if((!pID->WMP.bHasAlpha) || (pID->WMP.wmiSCP.uAlphaMode != 1)) + { + if(pID->WMP.bHasAlpha)//planar alpha + { + tempAlphaMode = pID->WMP.wmiSCP.uAlphaMode; + pID->WMP.wmiSCP.uAlphaMode = 0; + } + pID->WMP.wmiSCP.fMeasurePerf = TRUE; +#ifdef REENTRANT_MODE + if (0 == pID->WMP.DecoderCurrMBRow) + { + Call(pID->WMP.wmiSCP.pWStream->GetPos(pID->WMP.wmiSCP.pWStream, &(pID->WMP.cMarker))); + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail); + } + // Re-entrant mode incurs 1 MBR delay, so to get 0th MBR, we have to ask for 1st MBR + cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height + + (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR + linesperMBRow + 1; + cMBRowStart = ((U32) pID->WMP.cLinesCropped + pRect->Y) / linesperMBRow + 1; + // if current request starts before current state, then rewind. + if (cMBRowStart < pID->WMP.DecoderCurrMBRow) + { + pID->WMP.DecoderCurrMBRow = 0; + pID->WMP.cLinesDecoded = 0; + pID->WMP.cLinesCropped = 0; + pID->WMP.fFirstNonZeroDecode = FALSE; + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail); + Call(pID->WMP.wmiSCP.pWStream->SetPos(pID->WMP.wmiSCP.pWStream, pID->WMP.cMarker)); + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail); + } + + // In "Low Memory mode", we don't have full frame buffer. We therefore cannot rotate the image. + // We can flip H, V and HV, but no rotations. + FailIf(pID->WMP.wmiI.oOrientation >= O_RCW, WMP_errFail); + + // In low-memory mode, the full frame buffer is unavailable. This doesn't seem to + // matter in O_NONE and O_FLIPH, but for O_FLIPV and O_FLIPVH, outputMBRow tries to write to + // the bottom of full-frame buffer. Adjust the buffer pointer to compensate. + if (O_FLIPV == pID->WMP.wmiI.oOrientation || O_FLIPVH == pID->WMP.wmiI.oOrientation) + { + I32 iActualY2 = pRect->Y + pRect->Height; + pbLowMemAdj = pb - (pID->WMP.wmiI.cROIHeight - (iActualY2 - pID->WMP.cLinesCropped)) * cbStride; + } + else + { + pbLowMemAdj = pb - pRect->Y * cbStride; + } + wmiBI.pv = pbLowMemAdj; + + for (i = (U32)pID->WMP.DecoderCurrMBRow; i < cMBRow; i++) + { + size_t cLinesDecoded; + wmiBI.uiFirstMBRow = i; + wmiBI.uiLastMBRow = i; + FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC, &wmiBI, &cLinesDecoded), WMP_errFail); + pID->WMP.cLinesDecoded = cLinesDecoded; + if (FALSE == pID->WMP.fFirstNonZeroDecode && cLinesDecoded > 0) + { + pID->WMP.cLinesCropped += (linesperMBRow - cLinesDecoded); + pID->WMP.fFirstNonZeroDecode = TRUE; + // update cMBRow if partial MB row cropped + cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height + + (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR + linesperMBRow + 1; + } + + if (0 == cLinesDecoded && i > 0) + { + pID->WMP.cLinesCropped += linesperMBRow; + // update cMBRow if whole MB row cropped + cMBRow++; + } + } + wmiBI.pv = pbLowMemAdj; + + // If we're past the top of the image, then we're done, so terminate. + if (linesperMBRow * (cMBRow - 1) >= (U32) pID->WMP.cLinesCropped + pID->WMP.wmiI.cROIHeight) { + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail); + } + pID->WMP.DecoderCurrMBRow = cMBRow; // Set to next possible MBRow that is decodable + +#else + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail); + FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC, &wmiBI), WMP_errFail); + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail); +#endif //REENTRANT_MODE + + if(pID->WMP.bHasAlpha)//planar alpha + { + pID->WMP.wmiSCP.uAlphaMode = tempAlphaMode; + } + } + +// if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode == 2) +// if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode != 1) + if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode != 0) + { + pID->WMP.wmiI_Alpha = pID->WMP.wmiI; + pID->WMP.wmiSCP_Alpha = pID->WMP.wmiSCP; + +// assert(pID->WMP.wmiI_Alpha.cfColorFormat == CF_RGB); // only RGBA is supported for now! + pID->WMP.wmiI_Alpha.cfColorFormat = Y_ONLY; + + switch (pID->WMP.wmiI.bdBitDepth) + { + case BD_8: + pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) - 1; + break; + + case BD_16: + case BD_16S: + case BD_16F: + pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(U16) - 1; + break; + + case BD_32: + case BD_32S: + case BD_32F: + pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(float) - 1; + break; + + case BD_5: + case BD_10: + case BD_565: + default: + break; + } + + pID->WMP.wmiSCP_Alpha.fMeasurePerf = TRUE; + Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uAlphaOffset)); +#ifdef REENTRANT_MODE + if (0 == pID->WMP.DecoderCurrAlphaMBRow) // add this to WMP struct! + { + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail); + } + + // Re-entrant mode incurs 1 MBR delay, so to get 0th MBR, we have to ask for 1st MBR + cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height + + (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR + linesperMBRow + 1; + cMBRowStart = ((U32) pID->WMP.cLinesCropped + pRect->Y) / linesperMBRow + 1; + // if current request starts before current state, then rewind. + if (cMBRowStart < pID->WMP.DecoderCurrAlphaMBRow) + { + pID->WMP.DecoderCurrAlphaMBRow = 0; + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail); + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail); + } + + for (i = (U32)pID->WMP.DecoderCurrAlphaMBRow; i < cMBRow; i++) + { + size_t cLinesDecoded; + wmiBI.uiFirstMBRow = i; + wmiBI.uiLastMBRow = i; + FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC_Alpha, &wmiBI, &cLinesDecoded), WMP_errFail); + } + + // If we're past the top of the image, then we're done, so terminate + if (linesperMBRow * (cMBRow - 1) >= (U32) pID->WMP.cLinesCropped + pID->WMP.wmiI.cROIHeight) { + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail); + } + pID->WMP.DecoderCurrAlphaMBRow = cMBRow; // Set to next possible MBRow that is decodable + wmiBI.pv = pb; +#else + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail); + FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC_Alpha, &wmiBI), WMP_errFail); + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail); +#endif //REENTRANT_MODE + } + + pID->idxCurrentLine += pRect->Height; + +Cleanup: + return err; +} + + +ERR PKImageDecode_GetMetadata_WMP(PKImageDecode *pID, U32 uOffset, U32 uByteCount, U8 *pbGot, U32 *pcbGot) +{ + ERR err = WMP_errSuccess; + + if (pbGot && uOffset) + { + struct WMPStream* pWS = pID->pStream; + size_t iCurrPos; + + FailIf(*pcbGot < uByteCount, WMP_errBufferOverflow); + Call(pWS->GetPos(pWS, &iCurrPos)); + Call(pWS->SetPos(pWS, uOffset)); + Call(pWS->Read(pWS, pbGot, uByteCount)); + Call(pWS->SetPos(pWS, iCurrPos)); + } + +Cleanup: + if (Failed(err)) + *pcbGot = 0; + else + *pcbGot = uByteCount; + + return err; +} + + + +ERR PKImageDecode_GetColorContext_WMP(PKImageDecode *pID, U8 *pbColorContext, U32 *pcbColorContext) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uColorProfileOffset, + pID->WMP.wmiDEMisc.uColorProfileByteCount, pbColorContext, pcbColorContext); +} + + +ERR PKImageDecode_GetXMPMetadata_WMP(PKImageDecode *pID, U8 *pbXMPMetadata, U32 *pcbXMPMetadata) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uXMPMetadataOffset, + pID->WMP.wmiDEMisc.uXMPMetadataByteCount, pbXMPMetadata, pcbXMPMetadata); +} + + +ERR PKImageDecode_GetEXIFMetadata_WMP(PKImageDecode *pID, U8 *pbEXIFMetadata, U32 *pcbEXIFMetadata) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uEXIFMetadataOffset, + pID->WMP.wmiDEMisc.uEXIFMetadataByteCount, pbEXIFMetadata, pcbEXIFMetadata); +} + + +ERR PKImageDecode_GetGPSInfoMetadata_WMP(PKImageDecode *pID, U8 *pbGPSInfoMetadata, U32 *pcbGPSInfoMetadata) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uGPSInfoMetadataOffset, + pID->WMP.wmiDEMisc.uGPSInfoMetadataByteCount, pbGPSInfoMetadata, pcbGPSInfoMetadata); +} + + +ERR PKImageDecode_GetIPTCNAAMetadata_WMP(PKImageDecode *pID, U8 *pbIPTCNAAMetadata, U32 *pcbIPTCNAAMetadata) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uIPTCNAAMetadataOffset, + pID->WMP.wmiDEMisc.uIPTCNAAMetadataByteCount, pbIPTCNAAMetadata, pcbIPTCNAAMetadata); +} + + +ERR PKImageDecode_GetPhotoshopMetadata_WMP(PKImageDecode *pID, U8 *pbPhotoshopMetadata, U32 *pcbPhotoshopMetadata) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uPhotoshopMetadataOffset, + pID->WMP.wmiDEMisc.uPhotoshopMetadataByteCount, pbPhotoshopMetadata, pcbPhotoshopMetadata); +} + + +ERR PKImageDecode_GetDescriptiveMetadata_WMP(PKImageDecode *pID, DESCRIPTIVEMETADATA *pDescMetadata) +{ + ERR err = WMP_errSuccess; + *pDescMetadata = pID->WMP.sDescMetadata; + return err; +} + + +ERR PKImageDecode_Release_WMP(PKImageDecode** ppID) +{ + ERR err = WMP_errSuccess; + PKImageDecode *pID; + + if (NULL == ppID) + goto Cleanup; + + pID = *ppID; + + // Free descriptive metadata + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarImageDescription); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCameraMake); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCameraModel); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarSoftware); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarDateTime); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarArtist); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCopyright); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarRatingStars); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarRatingValue); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCaption); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarDocumentName); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarPageName); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarPageNumber); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarHostComputer); + + // Release base class + Call(PKImageDecode_Release(ppID)); + +Cleanup: + return err; +} + + + +ERR PKImageDecode_Create_WMP(PKImageDecode** ppID) +{ + ERR err = WMP_errSuccess; + PKImageDecode* pID = NULL; + + Call(PKImageDecode_Create(ppID)); + + pID = *ppID; + pID->Initialize = PKImageDecode_Initialize_WMP; + pID->GetSize = PKImageDecode_GetSize_WMP; + pID->GetRawStream = PKImageDecode_GetRawStream_WMP; + pID->Copy = PKImageDecode_Copy_WMP; + pID->GetColorContext = PKImageDecode_GetColorContext_WMP; + pID->GetDescriptiveMetadata = PKImageDecode_GetDescriptiveMetadata_WMP; + pID->Release = PKImageDecode_Release_WMP; + +Cleanup: + return err; +} + diff --git a/libs/jxr/jxrgluelib/JXRGluePFC.c b/libs/jxr/jxrgluelib/JXRGluePFC.c new file mode 100644 index 00000000000..e44b12c287a --- /dev/null +++ b/libs/jxr/jxrgluelib/JXRGluePFC.c @@ -0,0 +1,2338 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 + +#include +#include + +//================================================================ +// PKFormatConverter +//================================================================ +#define HLF_MIN 0.00006103515625f +#define HLF_MAX 65504.0f + +#define HLF_MIN_BITS 0x0400 +#define HLF_MAX_BITS 0x7bff + +#define HLF_MIN_BITS_NEG (HLF_MIN_BITS | 0x8000) +#define HLF_MAX_BITS_NEG (HLF_MAX_BITS | 0x8000) + +#define HLF_QNaN_BITZS 0x7fff + +// simple and slow implementation of half <-> float conversion +static U32 Convert_Half_To_Float(U16 u16) +{ + // 1s5e10m -> 1s8e23m + const U32 s = (u16 >> 15) & 0x0001; + const U32 e = (u16 >> 10) & 0x001f; + const U32 m = (u16 >> 0) & 0x03ff; + + if (0 == e) // 0, denorm + { + return s << 31; + } + else if (~(~0 << 5) == e) // inf, snan, qnan + { + return (s << 31) | ~(~0 << 8) << 23| (m << 13); + } + + return (s << 31) | ((e - 15 + 127) << 23) | (m << 13); // norm +} + + +static U16 Convert_Float_To_Half(float f) +{ + // 1s5e10m -> 1s8e23m + const U32 iFloat = *(U32*)&f; // Convert float to U32 + + if (f != f) + { + return (U16)(iFloat | HLF_QNaN_BITZS); // +QNaN, -QNaN + } + else if (f < -HLF_MAX) + { + return HLF_MAX_BITS_NEG; + } + else if (HLF_MAX < f) + { + return HLF_MAX_BITS; + } + else if (-HLF_MIN < f && f < HLF_MIN) + { + return (U16)((iFloat >> 16) & 0x8000); // +0, -0 + } + + // Cut-and-paste from C++, introduce scope so we can decl more vars + { + const U32 s = (iFloat >> 31) & 0x00000001; + const U32 e = (iFloat >> 23) & 0x000000ff; + const U32 m = (iFloat >> 0) & 0x007fffff; + + return (U16) ((s << 15) | ((e - 127 + 15) << 10) | (m >> 13)); + } +} + + +static U8 Convert_Float_To_U8(float f) +{ + // convert from linear scRGB to non-linear sRGB + if (f <= 0) + { + return 0; + } + else if (f <= 0.0031308f) + { + return (U8)((255.0f * f * 12.92f) + 0.5f); + } + else if (f < 1.0f) + { + return (U8)((255.0f * ((1.055f * (float)pow(f, 1.0 / 2.4)) - 0.055f)) + 0.5f); + } + else + { + return 255; + } +} + +static U8 Convert_AlphaFloat_To_U8(float f) +{ + // alpha is converted differently than RGB in scRGB + if (f <= 0) + { + return 0; + } + else if (f < 1.0f) + { + return (U8)((255.0f * f) + 0.5f); + } + else + { + return 255; + } +} + + +ERR RGB24_BGR24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + I32 i = 0, j = 0; + + UNREFERENCED_PARAMETER( pFC ); + + for (i = 0; i < pRect->Height; ++i) + { + for (j = 0; j < pRect->Width * 3; j += 3) + { + // swap red with blue + U8 t = pb[j]; + pb[j] = pb[j + 2]; + pb[j + 2] = t; + } + + pb += cbStride; + } + + return WMP_errSuccess; +} + +ERR BGR24_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + return RGB24_BGR24(pFC, pRect, pb, cbStride); +} + +ERR RGB24_BGR32(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + I32 i = 0, j = 0; + + UNREFERENCED_PARAMETER( pFC ); + + for (i = 0; i < pRect->Height; ++i) + { + for (j = 0; j < pRect->Width; j++) + { + // swap red with blue + U8 t = pb[3*j]; + pb[4*j] = pb[3*j + 2]; + pb[4*j + 1] = pb[3*j + 1]; + pb[4*j + 2] = t; + } + + pb += cbStride; + } + + return WMP_errSuccess; +} + +ERR BGR32_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + I32 i = 0, j = 0; + + UNREFERENCED_PARAMETER( pFC ); + + for (i = 0; i < pRect->Height; ++i) + { + for (j = 0; j < pRect->Width; j++) + { + // swap red with blue + U8 t = pb[4*j]; + pb[3*j] = pb[4*j + 2]; + pb[3*j + 1] = pb[4*j + 1]; + pb[3*j + 2] = t; + } + + pb += cbStride; + } + + return WMP_errSuccess; +} + +ERR RGB24_Gray8(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + I32 i = 0, j = 0, k = 0; + + UNREFERENCED_PARAMETER( pFC ); + + for (i = 0; i < pRect->Height; ++i) + { + for (j = 0, k = 0; j < pRect->Width * 3; j += 3, ++k) + { + U8 r = pb[j]; + U8 g = pb[j + 1]; + U8 b = pb[j + 2]; + + pb[k] = r / 4 + g / 2 + b / 8 + 16; + } + + pb += cbStride; + } + + return WMP_errSuccess; +} + +ERR BGR24_Gray8(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + ERR err = WMP_errSuccess; + + Call(BGR24_RGB24(pFC, pRect, pb, cbStride)); + Call(RGB24_Gray8(pFC, pRect, pb, cbStride)); + +Cleanup: + return err; +} + +ERR Gray8_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + I32 i = 0, j = 0, k = 0; + + UNREFERENCED_PARAMETER( pFC ); + + for (i = 0; i < pRect->Height; ++i) + { + for (j = pRect->Width - 1, k = 3 * j; 0 <= j; j--, k -= 3) + { + U8 v = pb[j]; + + pb[k] = v; + pb[k + 1] = v; + pb[k + 2] = v; + } + + pb += cbStride; + } + + return WMP_errSuccess; +} + +ERR Gray8_BGR24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + return Gray8_RGB24(pFC, pRect, pb, cbStride); +} + +#if 0 +ERR RGB48_BGR48(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + ERR err = WMP_errSuccess; + + I32 i = 0, j = 0; + + UNREFERENCED_PARAMETER( pFC ); + + Call(PKFormatConverter_Copy(pFC, pRect, pb, cbStride)); + + for (i = 0; i < pRect->Height; ++i) + { + for (j = 0; j < pRect->Width; j += 3) + { + U16* ps = (U16*)pb; + + // swap red with blue + U16 t = ps[j]; + ps[j] = ps[j + 2]; + ps[j + 2] = t; + } + + pb += cbStride; + } + +Cleanup: + return err; +} + +ERR BGR48_RGB48(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + return RGB48_BGR48(pFC, pRect, pb, cbStride); +} + +ERR RGB48_Gray16(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + ERR err = WMP_errSuccess; + + I32 i = 0, j = 0, k = 0; + + UNREFERENCED_PARAMETER( pFC ); + + Call(PKFormatConverter_Copy(pFC, pRect, pb, cbStride)); + + for (i = 0; i < pRect->Height; ++i) + { + for (j = 0, k = 0; j < pRect->Width; j += 3, ++k) + { + U16* ps = (U16*)pb; + + // Y = r / 4 + g / 2 + b / 8 + 16 + U16 r = ps[j]; + U16 g = ps[j + 1]; + U16 b = ps[j + 2]; + + ps[k] = r / 4 + g / 2 + b / 8 + 16; + } + + pb += cbStride; + } + +Cleanup: + return err; +} +#endif + +ERR RGBA128Fixed_RGBA128Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX4 = 4 * pRect->Width; // 4 == R, G, B, A + const float fltCvtFactor = 1.0F / (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const I32 *piSrcPixel = (I32*)pfltDstPixel; + + for (x = 0; x < iWidthX4; x++) + pfltDstPixel[x] = piSrcPixel[x] * fltCvtFactor; + } + + return WMP_errSuccess; +} + + +ERR RGBA128Float_RGBA128Fixed(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX4 = 4 * pRect->Width; // 4 == R, G, B, A + const float fltCvtFactor = (float)(1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + I32 *piDstPixel = (I32*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidthX4; x++) + piDstPixel[x] = (I32) (pfltSrcPixel[x] * fltCvtFactor + 0.5F); + } + + return WMP_errSuccess; +} + + + +ERR RGB96Fixed_RGB96Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX3 = 3 * pRect->Width; // 3 == R, G, B + const float fltCvtFactor = 1.0F / (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const I32 *piSrcPixel = (I32*)pfltDstPixel; + + for (x = 0; x < iWidthX3; x++) + pfltDstPixel[x] = piSrcPixel[x] * fltCvtFactor; + } + + return WMP_errSuccess; +} + + +ERR RGB128Fixed_RGB96Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const I32 *piSrcPixel = (I32*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + pfltDstPixel[3*x] = piSrcPixel[4*x] * fltCvtFactor; + pfltDstPixel[3*x+1] = piSrcPixel[4*x+1] * fltCvtFactor; + pfltDstPixel[3*x+2] = piSrcPixel[4*x+2] * fltCvtFactor; + } + } + + return WMP_errSuccess; +} + + + +ERR RGB96Float_RGB96Fixed(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX3 = 3 * pRect->Width; // 3 == R, G, B + const float fltCvtFactor = (float) (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + I32 *piDstPixel = (I32*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidthX3; x++) + piDstPixel[x] = (I32)(pfltSrcPixel[x] * fltCvtFactor + 0.5F); + } + + return WMP_errSuccess; +} + + +ERR RGB96Float_RGB128Fixed(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = (float) (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + assert(iWidth > 2); // Otherwise, we corrupt source data in inner loop + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + I32 *piDstPixel = (I32*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + { + piDstPixel[4*x] = (I32)(pfltSrcPixel[3*x] * fltCvtFactor + 0.5F); + piDstPixel[4*x+1] = (I32)(pfltSrcPixel[3*x+1] * fltCvtFactor + 0.5F); + piDstPixel[4*x+2] = (I32)(pfltSrcPixel[3*x+2] * fltCvtFactor + 0.5F); + piDstPixel[4*x+3] = 0; // Zero out the alpha channel + } + } + + return WMP_errSuccess; +} + + +ERR RGB96Float_RGB128Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + assert(iWidth > 2); // Otherwise, we corrupt source data in inner loop + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)pfltDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + { + pfltDstPixel[4*x] = pfltSrcPixel[3*x]; + pfltDstPixel[4*x+1] = pfltSrcPixel[3*x+1]; + pfltDstPixel[4*x+2] = pfltSrcPixel[3*x+2]; + pfltDstPixel[4*x+3] = 0.0F; // Zero out the alpha channel + } + } + + return WMP_errSuccess; +} + + +ERR RGB128Float_RGB96Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + pfltDstPixel[3*x] = pfltSrcPixel[4*x]; + pfltDstPixel[3*x+1] = pfltSrcPixel[4*x+1]; + pfltDstPixel[3*x+2] = pfltSrcPixel[4*x+2]; + } + } + + return WMP_errSuccess; +} + + +ERR RGB48Half_RGB64Half(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + assert(iWidth > 2); // Otherwise, we corrupt source data in inner loop + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + I16 *piDstPixel = (I16*)(pb + cbStride*y); + const I16 *piSrcPixel = (I16*)piDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + { + piDstPixel[4*x] = piSrcPixel[3*x]; + piDstPixel[4*x+1] = piSrcPixel[3*x+1]; + piDstPixel[4*x+2] = piSrcPixel[3*x+2]; + piDstPixel[4*x+3] = 0; // Zero out the alpha channel + } + } + + return WMP_errSuccess; +} + + +ERR RGB64Half_RGB48Half(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + I16 *piDstPixel = (I16*)(pb + cbStride*y); + const short *piSrcPixel = (I16*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + piDstPixel[3*x] = piSrcPixel[4*x]; + piDstPixel[3*x+1] = piSrcPixel[4*x+1]; + piDstPixel[3*x+2] = piSrcPixel[4*x+2]; + } + } + + return WMP_errSuccess; +} + + +ERR BGR24_BGR32(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + assert(iWidth > 2); // Otherwise, we corrupt source data in inner loop + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + U8 *piDstPixel = pb + cbStride*y; + const U8 *piSrcPixel = piDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + { + piDstPixel[4*x] = piSrcPixel[3*x]; + piDstPixel[4*x+1] = piSrcPixel[3*x+1]; + piDstPixel[4*x+2] = piSrcPixel[3*x+2]; + piDstPixel[4*x+3] = 0; // Zero out the alpha channel + } + } + + return WMP_errSuccess; +} + + +ERR BGR32_BGR24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = pb + cbStride*y; + const U8 *piSrcPixel = piDstPixel; + + for (x = 0; x < iWidth; x++) + { + piDstPixel[3*x] = piSrcPixel[4*x]; + piDstPixel[3*x+1] = piSrcPixel[4*x+1]; + piDstPixel[3*x+2] = piSrcPixel[4*x+2]; + } + } + + return WMP_errSuccess; +} + + +ERR Gray32Fixed_Gray32Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const I32 *piSrcPixel = (I32*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + pfltDstPixel[x] = piSrcPixel[x] * fltCvtFactor; + } + + return WMP_errSuccess; +} + + +ERR Gray32Float_Gray32Fixed(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = (float) (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + I32 *piDstPixel = (I32*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidth; x++) + piDstPixel[x] = (I32)(pfltSrcPixel[x] * fltCvtFactor + 0.5F); + } + + return WMP_errSuccess; +} + + + +ERR Gray16Fixed_Gray32Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + pfltDstPixel[x] = piSrcPixel[x] * fltCvtFactor; + } + + return WMP_errSuccess; +} + + +ERR Gray32Float_Gray16Fixed(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = (float) (1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + I16 *piDstPixel = (I16*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidth; x++) + piDstPixel[x] = (I16)(pfltSrcPixel[x] * fltCvtFactor + 0.5F); + } + + return WMP_errSuccess; +} + + +ERR RGB48Fixed_RGB96Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX3 = 3 * pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = iWidthX3 - 1; x >= 0; x--) + pfltDstPixel[x] = piSrcPixel[x] * fltCvtFactor; + } + + return WMP_errSuccess; +} + + +ERR RGB96Float_RGB48Fixed(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX3 = 3 * pRect->Width; + const float fltCvtFactor = (float)(1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + I16 *piDstPixel = (I16*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidthX3; x++) + piDstPixel[x] = (I16)(pfltSrcPixel[x] * fltCvtFactor + 0.5F); + } + + return WMP_errSuccess; +} + + +ERR RGB64Fixed_RGB96Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + { + pfltDstPixel[3*x] = piSrcPixel[4*x] * fltCvtFactor; + pfltDstPixel[3*x+1] = piSrcPixel[4*x+1] * fltCvtFactor; + pfltDstPixel[3*x+2] = piSrcPixel[4*x+2] * fltCvtFactor; + } + } + + return WMP_errSuccess; +} + + +ERR RGB96Float_RGB64Fixed(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = (float)(1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + I16 *piDstPixel = (I16*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + piDstPixel[4*x] = (I16)(pfltSrcPixel[3*x] * fltCvtFactor + 0.5F); + piDstPixel[4*x+1] = (I16)(pfltSrcPixel[3*x+1] * fltCvtFactor + 0.5F); + piDstPixel[4*x+2] = (I16)(pfltSrcPixel[3*x+2] * fltCvtFactor + 0.5F); + piDstPixel[4*x+3] = 0; // Zero out the alpha channel + } + } + + return WMP_errSuccess; +} + + +ERR RGBA64Fixed_RGBA128Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX4 = 4 * pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = iWidthX4 - 1; x >= 0; x--) + pfltDstPixel[x] = piSrcPixel[x] * fltCvtFactor; + } + + return WMP_errSuccess; +} + + + +ERR RGBA128Float_RGBA64Fixed(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX4 = 4 * pRect->Width; + const float fltCvtFactor = (float)(1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + I16 *piDstPixel = (I16*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidthX4; x++) + piDstPixel[x] = (I16)(pfltSrcPixel[x] * fltCvtFactor + 0.5F); + } + + return WMP_errSuccess; +} + + + +ERR RGBE_RGB96Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + float *pfltDstPixel = (float*)(pb + cbStride*y); + const U8 *piSrcPixel = (U8*)pfltDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + { + // First read the exponent + const U8 rawExp = piSrcPixel[4*x+3]; + + if (0 == rawExp) + { + pfltDstPixel[3*x] = 0.0F; + pfltDstPixel[3*x+1] = 0.0F; + pfltDstPixel[3*x+2] = 0.0F; + } + else + { + const I32 adjExp = (I32)rawExp - 128 - 8; // Can be negative + float fltExp; + + if (adjExp > -32 && adjExp < 32) + { + fltExp = (float) (((U32)1) << abs(adjExp)); + if (adjExp < 0) + fltExp = 1.0F / fltExp; + } + else + { + fltExp = (float)ldexp(1.0F, adjExp); + } + + pfltDstPixel[3*x] = piSrcPixel[4*x] * fltExp; + pfltDstPixel[3*x + 1] = piSrcPixel[4*x + 1] * fltExp; + pfltDstPixel[3*x + 2] = piSrcPixel[4*x + 2] * fltExp; + } + } + } + + return WMP_errSuccess; +} + + +ERR RGB96Float_RGBE(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + assert(iWidth > 2); // Otherwise, we corrupt source data in inner loop + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + // We clamp source RGB values at zero (don't allow negative numbers) + const float fltRed = max(pfltSrcPixel[3*x], 0.0F); + const float fltGreen = max(pfltSrcPixel[3*x+1], 0.0F); + const float fltBlue = max(pfltSrcPixel[3*x+2], 0.0F); + float fltMaxPos = fltRed; + + if (fltGreen > fltMaxPos) + fltMaxPos = fltGreen; + + if (fltBlue > fltMaxPos) + fltMaxPos = fltBlue; + + if (fltMaxPos < 1e-32) + { + piDstPixel[4*x] = 0; // R + piDstPixel[4*x+1] = 0; // G + piDstPixel[4*x+2] = 0; // B + piDstPixel[4*x+3] = 0; // E + } + else + { + int e; + const float fltScale = (float)frexp(fltMaxPos, &e) * 256 / fltMaxPos; + + // rounding SHOULD NOT be added - it has the potential to roll over to zero (and yes, 256 is the correct multiplier above) + piDstPixel[4*x] = (U8)(fltRed * fltScale); // R + piDstPixel[4*x+1] = (U8)(fltGreen * fltScale); // G + piDstPixel[4*x+2] = (U8)(fltBlue * fltScale); // B + piDstPixel[4*x+3] = (U8)(e + 128); // E + } + } + } + + return WMP_errSuccess; +} + + +ERR RGBA64Half_RGBA128Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX4 = 4 * pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + U32 *pfltDstPixel = (U32*)(pb + cbStride*y); // It's really float, but use U32 ptr + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = iWidthX4 - 1; x >= 0; x--) + pfltDstPixel[x] = Convert_Half_To_Float(piSrcPixel[x]); + } + + return WMP_errSuccess; +} + + +ERR RGBA128Float_RGBA64Half(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX4 = 4 * pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + I16 *piDstPixel = (I16*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidthX4; x++) + piDstPixel[x] = Convert_Float_To_Half(pfltSrcPixel[x]); + } + + return WMP_errSuccess; +} + + +ERR RGB64Half_RGB96Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + U32 *pfltDstPixel = (U32*)(pb + cbStride*y); // It's really float, but use U32 ptr + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + { + pfltDstPixel[3*x] = Convert_Half_To_Float(piSrcPixel[4*x]); + pfltDstPixel[3*x+1] = Convert_Half_To_Float(piSrcPixel[4*x+1]); + pfltDstPixel[3*x+2] = Convert_Half_To_Float(piSrcPixel[4*x+2]); + } + } + + return WMP_errSuccess; +} + + +ERR RGB96Float_RGB64Half(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + I16 *piDstPixel = (I16*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + piDstPixel[4*x] = Convert_Float_To_Half(pfltSrcPixel[3*x]); + piDstPixel[4*x+1] = Convert_Float_To_Half(pfltSrcPixel[3*x+1]); + piDstPixel[4*x+2] = Convert_Float_To_Half(pfltSrcPixel[3*x+2]); + piDstPixel[4*x+3] = 0; // Zero out the alpha channel + } + } + + return WMP_errSuccess; +} + + +ERR RGB48Half_RGB96Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX3 = 3*pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + U32 *pfltDstPixel = (U32*)(pb + cbStride*y); // It's really float, but use U32 ptr + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = iWidthX3 - 1; x >= 0; x--) + pfltDstPixel[x] = Convert_Half_To_Float(piSrcPixel[x]); + } + + return WMP_errSuccess; +} + + +ERR RGB96Float_RGB48Half(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX3 = 3*pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + I16 *piDstPixel = (I16*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidthX3; x++) + piDstPixel[x] = Convert_Float_To_Half(pfltSrcPixel[x]); + } + + return WMP_errSuccess; +} + + +ERR Gray16Half_Gray32Float(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + U32 *pfltDstPixel = (U32*)(pb + cbStride*y); // It's really float, but use U32 ptr + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + pfltDstPixel[x] = Convert_Half_To_Float(piSrcPixel[x]); + } + + return WMP_errSuccess; +} + + +ERR Gray32Float_Gray16Half(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + I16 *piDstPixel = (I16*)(pb + cbStride*y); + const float *pfltSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidth; x++) + piDstPixel[x] = Convert_Float_To_Half(pfltSrcPixel[x]); + } + + return WMP_errSuccess; +} + +ERR RGB555_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + U8 *piDstPixel = (pb + cbStride*y); + const U16 *piSrcPixel = (U16*)piDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + { + const U16 v = piSrcPixel[x]; + const unsigned int r = ((v >> 10) & 0x1f); + const unsigned int g = ((v >> 5) & 0x1f); + const unsigned int b = (v & 0x1f); + + piDstPixel[3*x] = (U8)(r << 3); // R + piDstPixel[3*x+1] = (U8)(g << 3); // G + piDstPixel[3*x+2] = (U8)(b << 3); // B + } + } + + return WMP_errSuccess; +} + + +ERR RGB101010_RGB48(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + U16 *piDstPixel = (U16*)(pb + cbStride*y); + const U32 *piSrcPixel = (U32*)piDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + { + const U32 v = piSrcPixel[x]; + const unsigned int r = ((v >> 20) & 0x3FF); + const unsigned int g = ((v >> 10) & 0x3FF); + const unsigned int b = (v & 0x3FF); + + piDstPixel[3*x] = (U16)(r << 6); // R + piDstPixel[3*x+1] = (U16)(g << 6); // G + piDstPixel[3*x+2] = (U16)(b << 6); // B + } + } + + return WMP_errSuccess; +} + + +ERR RGB24_RGB555(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U16 *piDstPixel = (U16*)(pb + cbStride*y); + const U8 *piSrcPixel = (U8*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const unsigned int r = piSrcPixel[3*x]; + const unsigned int g = piSrcPixel[3*x+1]; + const unsigned int b = piSrcPixel[3*x+2]; + + piDstPixel[x] = (U16) ( + ((r & 0xF8) << 7) | + ((g & 0xF8) << 2) | + (b >> 3)); + } + } + + return WMP_errSuccess; +} + + + +ERR RGB48_RGB101010(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U32 *piDstPixel = (U32*)(pb + cbStride*y); + const U16 *piSrcPixel = (U16*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const unsigned int r = piSrcPixel[3*x]; + const unsigned int g = piSrcPixel[3*x+1]; + const unsigned int b = piSrcPixel[3*x+2]; + + piDstPixel[x] = (3 << 30) | // For compatibility with D3D's 2-10-10-10 format. + ((r & 0x0000FFC0) << 14) | + ((g & 0x0000FFC0) << 4) | + (b >> 6); + } + } + + return WMP_errSuccess; +} + + + +ERR RGB565_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + U8 *piDstPixel = (pb + cbStride*y); + const U16 *piSrcPixel = (U16*)piDstPixel; + + for (x = iWidth - 1; x >= 0; x--) + { + const U16 v = piSrcPixel[x]; + const unsigned int r = ((v >> 11) & 0x1f); + const unsigned int g = ((v >> 5) & 0x3f); + const unsigned int b = (v & 0x1f); + + piDstPixel[3*x] = (U8)(r << 3); // R + piDstPixel[3*x+1] = (U8)(g << 2); // G + piDstPixel[3*x+2] = (U8)(b << 3); // B + } + } + + return WMP_errSuccess; +} + + + +ERR RGB24_RGB565(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U16 *piDstPixel = (U16*)(pb + cbStride*y); + const U8 *piSrcPixel = (U8*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const unsigned int r = piSrcPixel[3*x]; + const unsigned int g = piSrcPixel[3*x+1]; + const unsigned int b = piSrcPixel[3*x+2]; + + piDstPixel[x] = (U16) ( + ((r & 0xF8) << 8) | + ((g & 0xFC) << 3) | + (b >> 3)); + } + } + + return WMP_errSuccess; +} + + +ERR RGBA32_BGRA32(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidthX4 = 4 * pRect->Width; // 4 == R, G, B, A + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piPixel = (U8*)(pb + cbStride*y); + + for (x = 0; x < iWidthX4; x += 4) + { + // Swap R and B + U8 bTemp = piPixel[x]; + piPixel[x] = piPixel[x+2]; + piPixel[x+2] = bTemp; + } + } + + return WMP_errSuccess; +} + + +ERR BGRA32_RGBA32(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + return RGBA32_BGRA32(pFC, pRect, pb, cbStride); +} + + +ERR BlackWhite_Gray8(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + Bool bBlackWhite = pFC->pDecoder->WMP.wmiSCP.bBlackWhite; + I32 y; + + // Stride is assumed to be same for src/dst + for (y = iHeight - 1; y >= 0; y--) + { + I32 x; + I32 n; + U8 *piDstPixel = (pb + cbStride*y); + const U8 *piSrcPixel = (U8*)piDstPixel; + + if (iWidth % 8 != 0) + { + const U8 v = piSrcPixel[iWidth / 8]; + + for (n = 0; n < iWidth % 8; n++) + { + piDstPixel[iWidth/8*8+n] = (((v >> (7 - n)) & 0x1) != 0) ^ bBlackWhite ? 0xFF : 0x00; + } + } + + for (x = iWidth / 8 - 1; x >= 0; x--) + { + const U8 v = piSrcPixel[x]; + + for (n = 0; n < 8; n++) + { + piDstPixel[8*x+n] = (((v >> (7 - n)) & 0x1) != 0) ^ bBlackWhite ? 0xFF : 0x00; + } + } + } + + return WMP_errSuccess; +} + + +ERR Gray16_Gray8(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + I32 i = 0, j = 0; + + UNREFERENCED_PARAMETER( pFC ); + + for (i = 0; i < pRect->Height; ++i) + { + for (j = 0; j < pRect->Width; ++j) + { + U16 v = ((U16*)pb)[j]; + + pb[j] = v >> 8; + } + + pb += cbStride; + } + + return WMP_errSuccess; +} + +ERR RGB48_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const U16 *piSrcPixel = (U16*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const U16 r = piSrcPixel[3*x]; + const U16 g = piSrcPixel[3*x+1]; + const U16 b = piSrcPixel[3*x+2]; + + piDstPixel[3*x] = r >> 8; + piDstPixel[3*x+1] = g >> 8; + piDstPixel[3*x+2] = b >> 8; + } + } + + return WMP_errSuccess; +} + +ERR RGBA64_RGBA32(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const U16 *piSrcPixel = (U16*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const U16 r = piSrcPixel[4*x]; + const U16 g = piSrcPixel[4*x+1]; + const U16 b = piSrcPixel[4*x+2]; + const U16 a = piSrcPixel[4*x+3]; + + piDstPixel[4*x] = r >> 8; + piDstPixel[4*x+1] = g >> 8; + piDstPixel[4*x+2] = b >> 8; + piDstPixel[4*x+3] = a >> 8; + } + } + + return WMP_errSuccess; +} + +ERR Gray32Float_Gray8(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const float *piSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const float v = piSrcPixel[x]; + + piDstPixel[x] = Convert_Float_To_U8(v); + } + } + + return WMP_errSuccess; +} + +ERR RGB96Float_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const float *piSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const float r = piSrcPixel[3*x]; + const float g = piSrcPixel[3*x+1]; + const float b = piSrcPixel[3*x+2]; + + piDstPixel[3*x] = Convert_Float_To_U8(r); + piDstPixel[3*x+1] = Convert_Float_To_U8(g); + piDstPixel[3*x+2] = Convert_Float_To_U8(b); + } + } + + return WMP_errSuccess; +} + +ERR RGB128Float_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const float *piSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const float r = piSrcPixel[4*x]; + const float g = piSrcPixel[4*x+1]; + const float b = piSrcPixel[4*x+2]; + + piDstPixel[3*x] = Convert_Float_To_U8(r); + piDstPixel[3*x+1] = Convert_Float_To_U8(g); + piDstPixel[3*x+2] = Convert_Float_To_U8(b); + } + } + + return WMP_errSuccess; +} + +ERR RGBA128Float_RGBA32(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const float *piSrcPixel = (float*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const float r = piSrcPixel[4*x]; + const float g = piSrcPixel[4*x+1]; + const float b = piSrcPixel[4*x+2]; + const float a = piSrcPixel[4*x+3]; + + piDstPixel[4*x] = Convert_Float_To_U8(r); + piDstPixel[4*x+1] = Convert_Float_To_U8(g); + piDstPixel[4*x+2] = Convert_Float_To_U8(b); + piDstPixel[4*x+3] = Convert_AlphaFloat_To_U8(a); + } + } + + return WMP_errSuccess; +} + +ERR Gray16Fixed_Gray8(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const I16 *piSrcPixel = (I16*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + piDstPixel[x] = Convert_Float_To_U8(piSrcPixel[x] * fltCvtFactor); + } + } + + return WMP_errSuccess; +} + +ERR Gray32Fixed_Gray8(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const I32 *piSrcPixel = (I32*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + piDstPixel[x] = Convert_Float_To_U8(piSrcPixel[x] * fltCvtFactor); + } + } + + return WMP_errSuccess; +} + +ERR RGB48Fixed_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *pfltDstPixel = (U8*)(pb + cbStride*y); + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + pfltDstPixel[3*x] = Convert_Float_To_U8(piSrcPixel[3*x] * fltCvtFactor); + pfltDstPixel[3*x+1] = Convert_Float_To_U8(piSrcPixel[3*x+1] * fltCvtFactor); + pfltDstPixel[3*x+2] = Convert_Float_To_U8(piSrcPixel[3*x+2] * fltCvtFactor); + } + } + + return WMP_errSuccess; +} + +ERR RGB64Fixed_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *pfltDstPixel = (U8*)(pb + cbStride*y); + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + pfltDstPixel[3*x] = Convert_Float_To_U8(piSrcPixel[4*x] * fltCvtFactor); + pfltDstPixel[3*x+1] = Convert_Float_To_U8(piSrcPixel[4*x+1] * fltCvtFactor); + pfltDstPixel[3*x+2] = Convert_Float_To_U8(piSrcPixel[4*x+2] * fltCvtFactor); + } + } + + return WMP_errSuccess; +} + +ERR RGB96Fixed_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *pfltDstPixel = (U8*)(pb + cbStride*y); + const I32 *piSrcPixel = (I32*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + pfltDstPixel[3*x] = Convert_Float_To_U8(piSrcPixel[3*x] * fltCvtFactor); + pfltDstPixel[3*x+1] = Convert_Float_To_U8(piSrcPixel[3*x+1] * fltCvtFactor); + pfltDstPixel[3*x+2] = Convert_Float_To_U8(piSrcPixel[3*x+2] * fltCvtFactor); + } + } + + return WMP_errSuccess; +} + +ERR RGB128Fixed_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *pfltDstPixel = (U8*)(pb + cbStride*y); + const I32 *piSrcPixel = (I32*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + pfltDstPixel[3*x] = Convert_Float_To_U8(piSrcPixel[4*x] * fltCvtFactor); + pfltDstPixel[3*x+1] = Convert_Float_To_U8(piSrcPixel[4*x+1] * fltCvtFactor); + pfltDstPixel[3*x+2] = Convert_Float_To_U8(piSrcPixel[4*x+2] * fltCvtFactor); + } + } + + return WMP_errSuccess; +} + +ERR RGBA64Fixed_RGBA32(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 13); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *pfltDstPixel = (U8*)(pb + cbStride*y); + const I16 *piSrcPixel = (I16*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + pfltDstPixel[4*x] = Convert_Float_To_U8(piSrcPixel[4*x] * fltCvtFactor); + pfltDstPixel[4*x+1] = Convert_Float_To_U8(piSrcPixel[4*x+1] * fltCvtFactor); + pfltDstPixel[4*x+2] = Convert_Float_To_U8(piSrcPixel[4*x+2] * fltCvtFactor); + pfltDstPixel[4*x+3] = Convert_AlphaFloat_To_U8(piSrcPixel[4*x+3] * fltCvtFactor); + } + } + + return WMP_errSuccess; +} + +ERR RGBA128Fixed_RGBA32(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + const float fltCvtFactor = 1.0F / (1 << 24); + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *pfltDstPixel = (U8*)(pb + cbStride*y); + const I32 *piSrcPixel = (I32*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + pfltDstPixel[4*x] = Convert_Float_To_U8(piSrcPixel[4*x] * fltCvtFactor); + pfltDstPixel[4*x+1] = Convert_Float_To_U8(piSrcPixel[4*x+1] * fltCvtFactor); + pfltDstPixel[4*x+2] = Convert_Float_To_U8(piSrcPixel[4*x+2] * fltCvtFactor); + pfltDstPixel[4*x+3] = Convert_AlphaFloat_To_U8(piSrcPixel[4*x+3] * fltCvtFactor); + } + } + + return WMP_errSuccess; +} + +ERR Gray16Half_Gray8(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const U16 *piSrcPixel = (U16*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const U32 v = Convert_Half_To_Float(piSrcPixel[x]); + + piDstPixel[x] = Convert_Float_To_U8(*(float*)&v); + } + } + + return WMP_errSuccess; +} + +ERR RGB48Half_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *pfltDstPixel = (U8*)(pb + cbStride*y); + const U16 *piSrcPixel = (U16*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + const U32 r = Convert_Half_To_Float(piSrcPixel[3*x]); + const U32 g = Convert_Half_To_Float(piSrcPixel[3*x+1]); + const U32 b = Convert_Half_To_Float(piSrcPixel[3*x+2]); + + pfltDstPixel[3*x] = Convert_Float_To_U8(*(float*)&r); + pfltDstPixel[3*x+1] = Convert_Float_To_U8(*(float*)&g); + pfltDstPixel[3*x+2] = Convert_Float_To_U8(*(float*)&b); + } + } + + return WMP_errSuccess; +} + +ERR RGB64Half_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *pfltDstPixel = (U8*)(pb + cbStride*y); + const U16 *piSrcPixel = (U16*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + const U32 r = Convert_Half_To_Float(piSrcPixel[4*x]); + const U32 g = Convert_Half_To_Float(piSrcPixel[4*x+1]); + const U32 b = Convert_Half_To_Float(piSrcPixel[4*x+2]); + + pfltDstPixel[3*x] = Convert_Float_To_U8(*(float*)&r); + pfltDstPixel[3*x+1] = Convert_Float_To_U8(*(float*)&g); + pfltDstPixel[3*x+2] = Convert_Float_To_U8(*(float*)&b); + } + } + + return WMP_errSuccess; +} + +ERR RGBA64Half_RGBA32(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *pfltDstPixel = (U8*)(pb + cbStride*y); + const U16 *piSrcPixel = (U16*)pfltDstPixel; + + for (x = 0; x < iWidth; x++) + { + const U32 r = Convert_Half_To_Float(piSrcPixel[4*x]); + const U32 g = Convert_Half_To_Float(piSrcPixel[4*x+1]); + const U32 b = Convert_Half_To_Float(piSrcPixel[4*x+2]); + const U32 a = Convert_Half_To_Float(piSrcPixel[4*x+3]); + + pfltDstPixel[4*x] = Convert_Float_To_U8(*(float*)&r); + pfltDstPixel[4*x+1] = Convert_Float_To_U8(*(float*)&g); + pfltDstPixel[4*x+2] = Convert_Float_To_U8(*(float*)&b); + pfltDstPixel[4*x+3] = Convert_AlphaFloat_To_U8(*(float*)&a); + } + } + + return WMP_errSuccess; +} + +ERR RGB101010_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + const I32 iHeight = pRect->Height; + const I32 iWidth = pRect->Width; + I32 y; + + UNREFERENCED_PARAMETER( pFC ); + + // Stride is assumed to be same for src/dst + for (y = 0; y < iHeight; y++) + { + I32 x; + U8 *piDstPixel = (U8*)(pb + cbStride*y); + const U32 *piSrcPixel = (U32*)piDstPixel; + + for (x = 0; x < iWidth; x++) + { + const U32 v = piSrcPixel[x]; + const unsigned int r = ((v >> 20) & 0x3FF); + const unsigned int g = ((v >> 10) & 0x3FF); + const unsigned int b = (v & 0x3FF); + + piDstPixel[3*x] = (U8) (r >> 2); + piDstPixel[3*x+1] = (U8) (g >> 2); + piDstPixel[3*x+2] = (U8) (b >> 2); + } + } + + return WMP_errSuccess; +} + +ERR RGBE_RGB24(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + I32 i = 0, j = 0; + + UNREFERENCED_PARAMETER( pFC ); + + for (i = 0; i < pRect->Height; ++i) + { + for (j = 0; j < pRect->Width; j++) + { + // First read the exponent + const U8 rawExp = pb[4*j+3]; + + if (0 == rawExp) + { + pb[3*j] = 0; + pb[3*j+1] = 0; + pb[3*j+2] = 0; + } + else + { + const I32 adjExp = (I32)rawExp - 128 - 8; // Can be negative + float fltExp; + + if (adjExp > -32 && adjExp < 32) + { + fltExp = (float) (((U32)1) << abs(adjExp)); + if (adjExp < 0) + fltExp = 1.0F / fltExp; + } + else + { + fltExp = (float)ldexp(1.0F, adjExp); + } + + pb[3*j] = Convert_Float_To_U8(pb[4*j] * fltExp); + pb[3*j + 1] = Convert_Float_To_U8(pb[4*j + 1] * fltExp); + pb[3*j + 2] = Convert_Float_To_U8(pb[4*j + 2] * fltExp); + } + } + + pb += cbStride; + } + + return WMP_errSuccess; +} + +//================================================================ +typedef struct tagPKPixelConverterInfo +{ + const PKPixelFormatGUID* pGUIDPixFmtFrom; + const PKPixelFormatGUID* pGUIDPixFmtTo; + + ERR (*Convert)(PKFormatConverter*, const PKRect*, U8*, U32); +} PKPixelConverterInfo; + +static PKPixelConverterInfo s_pcInfo[] = { + {&GUID_PKPixelFormat24bppRGB, &GUID_PKPixelFormat24bppBGR, RGB24_BGR24}, // Fwd + {&GUID_PKPixelFormat24bppBGR, &GUID_PKPixelFormat24bppRGB, BGR24_RGB24}, // Rev + {&GUID_PKPixelFormat24bppRGB, &GUID_PKPixelFormat32bppBGR, RGB24_BGR32}, // Fwd + {&GUID_PKPixelFormat32bppBGR, &GUID_PKPixelFormat24bppRGB, BGR32_RGB24}, // Rev + + // The following are not to be exposed when building the Adobe Photoshop plugin +#ifndef ADOBE_PS_PLUGIN + {&GUID_PKPixelFormat24bppRGB, &GUID_PKPixelFormat8bppGray, RGB24_Gray8}, // Fwd + {&GUID_PKPixelFormat8bppGray, &GUID_PKPixelFormat24bppRGB, Gray8_RGB24}, // Rev + {&GUID_PKPixelFormat24bppBGR, &GUID_PKPixelFormat8bppGray, BGR24_Gray8}, // Fwd + {&GUID_PKPixelFormat8bppGray, &GUID_PKPixelFormat24bppBGR, Gray8_BGR24}, // Rev +#endif // ADOBE_PS_PLUGIN + + {&GUID_PKPixelFormat128bppRGBAFixedPoint, &GUID_PKPixelFormat128bppRGBAFloat, RGBA128Fixed_RGBA128Float}, // Fwd + {&GUID_PKPixelFormat128bppRGBAFloat, &GUID_PKPixelFormat128bppRGBAFixedPoint, RGBA128Float_RGBA128Fixed}, // Rev + {&GUID_PKPixelFormat96bppRGBFixedPoint, &GUID_PKPixelFormat96bppRGBFloat, RGB96Fixed_RGB96Float}, // Fwd + {&GUID_PKPixelFormat96bppRGBFloat, &GUID_PKPixelFormat96bppRGBFixedPoint, RGB96Float_RGB96Fixed}, // Rev + {&GUID_PKPixelFormat96bppRGBFloat, &GUID_PKPixelFormat128bppRGBFloat, RGB96Float_RGB128Float}, // Fwd + {&GUID_PKPixelFormat128bppRGBFloat, &GUID_PKPixelFormat96bppRGBFloat, RGB128Float_RGB96Float}, // Rev + {&GUID_PKPixelFormat96bppRGBFixedPoint, &GUID_PKPixelFormat128bppRGBFixedPoint, RGB96Float_RGB128Float}, // Fwd + {&GUID_PKPixelFormat128bppRGBFixedPoint, &GUID_PKPixelFormat96bppRGBFixedPoint, RGB128Float_RGB96Float}, // Rev + {&GUID_PKPixelFormat64bppRGBHalf, &GUID_PKPixelFormat48bppRGBHalf, RGB64Half_RGB48Half}, // Fwd + {&GUID_PKPixelFormat48bppRGBHalf, &GUID_PKPixelFormat64bppRGBHalf, RGB48Half_RGB64Half}, // Rev + {&GUID_PKPixelFormat64bppRGBFixedPoint, &GUID_PKPixelFormat48bppRGBFixedPoint, RGB64Half_RGB48Half}, // Fwd + {&GUID_PKPixelFormat48bppRGBFixedPoint, &GUID_PKPixelFormat64bppRGBFixedPoint, RGB48Half_RGB64Half}, // Rev + {&GUID_PKPixelFormat32bppBGR, &GUID_PKPixelFormat24bppBGR, BGR32_BGR24}, // Fwd + {&GUID_PKPixelFormat24bppBGR, &GUID_PKPixelFormat32bppBGR, BGR24_BGR32}, // Rev + {&GUID_PKPixelFormat96bppRGBFloat, &GUID_PKPixelFormat128bppRGBFixedPoint, RGB96Float_RGB128Fixed}, // Fwd + {&GUID_PKPixelFormat128bppRGBFixedPoint, &GUID_PKPixelFormat96bppRGBFloat, RGB128Fixed_RGB96Float}, // Rev + {&GUID_PKPixelFormat32bppGrayFixedPoint, &GUID_PKPixelFormat32bppGrayFloat, Gray32Fixed_Gray32Float}, // Fwd + {&GUID_PKPixelFormat32bppGrayFloat, &GUID_PKPixelFormat32bppGrayFixedPoint, Gray32Float_Gray32Fixed}, // Rev + {&GUID_PKPixelFormat16bppGrayFixedPoint, &GUID_PKPixelFormat32bppGrayFloat, Gray16Fixed_Gray32Float}, // Fwd + {&GUID_PKPixelFormat32bppGrayFloat, &GUID_PKPixelFormat16bppGrayFixedPoint, Gray32Float_Gray16Fixed}, // Rev + {&GUID_PKPixelFormat48bppRGBFixedPoint, &GUID_PKPixelFormat96bppRGBFloat, RGB48Fixed_RGB96Float}, // Fwd + {&GUID_PKPixelFormat96bppRGBFloat, &GUID_PKPixelFormat48bppRGBFixedPoint, RGB96Float_RGB48Fixed}, // Rev + {&GUID_PKPixelFormat64bppRGBFixedPoint, &GUID_PKPixelFormat96bppRGBFloat, RGB64Fixed_RGB96Float}, // Fwd + {&GUID_PKPixelFormat96bppRGBFloat, &GUID_PKPixelFormat64bppRGBFixedPoint, RGB96Float_RGB64Fixed}, // Rev + {&GUID_PKPixelFormat64bppRGBAFixedPoint, &GUID_PKPixelFormat128bppRGBAFloat, RGBA64Fixed_RGBA128Float}, // Fwd + {&GUID_PKPixelFormat128bppRGBAFloat, &GUID_PKPixelFormat64bppRGBAFixedPoint, RGBA128Float_RGBA64Fixed}, // Rev + {&GUID_PKPixelFormat32bppRGBE, &GUID_PKPixelFormat96bppRGBFloat, RGBE_RGB96Float}, // Fwd + {&GUID_PKPixelFormat96bppRGBFloat, &GUID_PKPixelFormat32bppRGBE, RGB96Float_RGBE}, // Rev + {&GUID_PKPixelFormat64bppRGBAHalf, &GUID_PKPixelFormat128bppRGBAFloat, RGBA64Half_RGBA128Float}, // Fwd + {&GUID_PKPixelFormat128bppRGBAFloat, &GUID_PKPixelFormat64bppRGBAHalf, RGBA128Float_RGBA64Half}, // Rev + {&GUID_PKPixelFormat64bppRGBHalf, &GUID_PKPixelFormat96bppRGBFloat, RGB64Half_RGB96Float}, // Fwd + {&GUID_PKPixelFormat96bppRGBFloat, &GUID_PKPixelFormat64bppRGBHalf, RGB96Float_RGB64Half}, // Rev + {&GUID_PKPixelFormat48bppRGBHalf, &GUID_PKPixelFormat96bppRGBFloat, RGB48Half_RGB96Float}, // Fwd + {&GUID_PKPixelFormat96bppRGBFloat, &GUID_PKPixelFormat48bppRGBHalf, RGB96Float_RGB48Half}, // Rev + {&GUID_PKPixelFormat16bppGrayHalf, &GUID_PKPixelFormat32bppGrayFloat, Gray16Half_Gray32Float}, // Fwd + {&GUID_PKPixelFormat32bppGrayFloat, &GUID_PKPixelFormat16bppGrayHalf, Gray32Float_Gray16Half}, // Rev + {&GUID_PKPixelFormat16bppRGB555, &GUID_PKPixelFormat24bppRGB, RGB555_RGB24}, // Fwd + {&GUID_PKPixelFormat24bppRGB, &GUID_PKPixelFormat16bppRGB555, RGB24_RGB555}, // Rev + {&GUID_PKPixelFormat16bppRGB565, &GUID_PKPixelFormat24bppRGB, RGB565_RGB24}, // Fwd + {&GUID_PKPixelFormat24bppRGB, &GUID_PKPixelFormat16bppRGB565, RGB24_RGB565}, // Rev + {&GUID_PKPixelFormat32bppRGB101010, &GUID_PKPixelFormat48bppRGB, RGB101010_RGB48}, // Fwd + {&GUID_PKPixelFormat48bppRGB, &GUID_PKPixelFormat32bppRGB101010, RGB48_RGB101010}, // Rev + {&GUID_PKPixelFormat32bppRGBA, &GUID_PKPixelFormat32bppBGRA, RGBA32_BGRA32}, // Fwd + {&GUID_PKPixelFormat32bppBGRA, &GUID_PKPixelFormat32bppRGBA, BGRA32_RGBA32}, // Rev + {&GUID_PKPixelFormat32bppPRGBA, &GUID_PKPixelFormat32bppPBGRA, RGBA32_BGRA32}, // Fwd + {&GUID_PKPixelFormat32bppPBGRA, &GUID_PKPixelFormat32bppPRGBA, BGRA32_RGBA32}, // Rev + + // conversions to 8bppGray / 24bppRGB / 32bppRGBA + {&GUID_PKPixelFormatBlackWhite, &GUID_PKPixelFormat8bppGray, BlackWhite_Gray8}, + {&GUID_PKPixelFormat16bppGray, &GUID_PKPixelFormat8bppGray, Gray16_Gray8}, + {&GUID_PKPixelFormat48bppRGB, &GUID_PKPixelFormat24bppRGB, RGB48_RGB24}, + {&GUID_PKPixelFormat64bppRGBA, &GUID_PKPixelFormat32bppRGBA, RGBA64_RGBA32}, + {&GUID_PKPixelFormat32bppGrayFloat, &GUID_PKPixelFormat8bppGray, Gray32Float_Gray8}, + {&GUID_PKPixelFormat96bppRGBFloat, &GUID_PKPixelFormat24bppRGB, RGB96Float_RGB24}, + {&GUID_PKPixelFormat128bppRGBFloat, &GUID_PKPixelFormat24bppRGB, RGB128Float_RGB24}, + {&GUID_PKPixelFormat128bppRGBAFloat, &GUID_PKPixelFormat32bppRGBA, RGBA128Float_RGBA32}, + {&GUID_PKPixelFormat16bppGrayFixedPoint, &GUID_PKPixelFormat8bppGray, Gray16Fixed_Gray8}, + {&GUID_PKPixelFormat32bppGrayFixedPoint, &GUID_PKPixelFormat8bppGray, Gray32Fixed_Gray8}, + {&GUID_PKPixelFormat48bppRGBFixedPoint, &GUID_PKPixelFormat24bppRGB, RGB48Fixed_RGB24}, + {&GUID_PKPixelFormat64bppRGBFixedPoint, &GUID_PKPixelFormat24bppRGB, RGB64Fixed_RGB24}, + {&GUID_PKPixelFormat96bppRGBFixedPoint, &GUID_PKPixelFormat24bppRGB, RGB96Fixed_RGB24}, + {&GUID_PKPixelFormat128bppRGBFixedPoint, &GUID_PKPixelFormat24bppRGB, RGB128Fixed_RGB24}, + {&GUID_PKPixelFormat64bppRGBAFixedPoint, &GUID_PKPixelFormat32bppRGBA, RGBA64Fixed_RGBA32}, + {&GUID_PKPixelFormat128bppRGBAFixedPoint, &GUID_PKPixelFormat32bppRGBA, RGBA128Fixed_RGBA32}, + {&GUID_PKPixelFormat16bppGrayHalf, &GUID_PKPixelFormat8bppGray, Gray16Half_Gray8}, + {&GUID_PKPixelFormat48bppRGBHalf, &GUID_PKPixelFormat24bppRGB, RGB48Half_RGB24}, + {&GUID_PKPixelFormat64bppRGBHalf, &GUID_PKPixelFormat24bppRGB, RGB64Half_RGB24}, + {&GUID_PKPixelFormat64bppRGBAHalf, &GUID_PKPixelFormat32bppRGBA, RGBA64Half_RGBA32}, + {&GUID_PKPixelFormat32bppRGB101010, &GUID_PKPixelFormat24bppRGB, RGB101010_RGB24}, + {&GUID_PKPixelFormat32bppRGBE, &GUID_PKPixelFormat24bppRGB, RGBE_RGB24} +}; + +/* auxiliary data structure and hack to support valid encoding from/to configurations that +// don't actually require any color conversion. This is a conservative approach, where we +// include as few formats as necessary to encode situations that we're currently aware of. +*/ +typedef struct tagPKPixelConverter2Info +{ + const PKPixelFormatGUID* pGUIDPixFmtFrom; + const PKPixelFormatGUID* pGUIDPixFmtTo; + +} PKPixelConverter2Info; + +static PKPixelConverter2Info s_pcInfo2[] = { + // This allows us to view an RGBA input file as RGB, for when we create a planar alpha file + {&GUID_PKPixelFormat128bppRGBFloat, &GUID_PKPixelFormat128bppRGBAFloat}, + // 16- and 32-bpp RGB input files are given the "DontCare" GUID, so the next three + // from/to combinations are ok, and allowed on encoding: + {&GUID_PKPixelFormatDontCare, &GUID_PKPixelFormat16bppRGB555}, + {&GUID_PKPixelFormatDontCare, &GUID_PKPixelFormat16bppRGB565}, + {&GUID_PKPixelFormatDontCare, &GUID_PKPixelFormat32bppBGRA} +}; + +ERR PKFormatConverter_Initialize(PKFormatConverter* pFC, PKImageDecode* pID, char *pExt, PKPixelFormatGUID enPF) +{ + ERR err; + PKPixelFormatGUID enPFFrom; + + Call(pID->GetPixelFormat(pID, &enPFFrom)); + Call(PKFormatConverter_InitializeConvert(pFC, enPFFrom, pExt, enPF)); + + pFC->pDecoder = pID; + +Cleanup: + return err; +} + + +extern int PKStrnicmp(const char* s1, const char* s2, size_t c); + +ERR PKFormatConverter_InitializeConvert(PKFormatConverter* pFC, const PKPixelFormatGUID enPFFrom, + char *pExt, PKPixelFormatGUID enPFTo) +{ + ERR err = WMP_errSuccess; + + //================================ + pFC->enPixelFormat = enPFTo; + + if (pExt != NULL && IsEqualGUID(&enPFTo, &GUID_PKPixelFormat24bppRGB) && + 0 == PKStrnicmp(pExt, ".bmp", strlen(pExt))) + enPFTo = GUID_PKPixelFormat24bppBGR; + if (pExt != NULL && (0 == PKStrnicmp(pExt, ".tif", strlen(pExt)) || 0 == PKStrnicmp(pExt, ".tiff", strlen(pExt)))) + { + if (IsEqualGUID(&enPFTo, &GUID_PKPixelFormat32bppBGRA)) + enPFTo = GUID_PKPixelFormat32bppRGBA; + if (IsEqualGUID(&enPFTo, &GUID_PKPixelFormat32bppPBGRA)) + enPFTo = GUID_PKPixelFormat32bppPRGBA; + } + + //================================ + if (!IsEqualGUID(&enPFFrom, &enPFTo)) + { + size_t i = 0; + for (i = 0; i < sizeof2(s_pcInfo); ++i) + { + PKPixelConverterInfo* pPCI = s_pcInfo + i; + + if (IsEqualGUID(&enPFFrom, pPCI->pGUIDPixFmtFrom) && IsEqualGUID(&enPFTo, pPCI->pGUIDPixFmtTo)) + { + pFC->Convert= pPCI->Convert; + goto Cleanup; + } + } + // Bugfix to allow legitimate encoding from/to combinations that don't actually + // involve color conversions. + for (i = 0; i < sizeof2(s_pcInfo2); ++i) + { + PKPixelConverter2Info* pPCI = s_pcInfo2 + i; + + if (IsEqualGUID(&enPFFrom, pPCI->pGUIDPixFmtFrom) && IsEqualGUID(&enPFTo, pPCI->pGUIDPixFmtTo)) + { + goto Cleanup; + } + } + // If we failed the original check, and this bugfix check, then exit with error + Call(WMP_errUnsupportedFormat); + } + +Cleanup: + return err; +} + +ERR PKFormatConverter_EnumConversions(const PKPixelFormatGUID *pguidSourcePF, + const U32 iIndex, + const PKPixelFormatGUID **ppguidTargetPF) +{ + U32 iCurrIdx = 0; + U32 i; + ERR errResult = WMP_errIndexNotFound; + + *ppguidTargetPF = &GUID_PKPixelFormatDontCare; // Init return value + for (i = 0; i < sizeof2(s_pcInfo); i++) + { + if (IsEqualGUID(s_pcInfo[i].pGUIDPixFmtFrom, pguidSourcePF)) + { + if (iCurrIdx == iIndex) + { + // Found our target + errResult = WMP_errSuccess; + *ppguidTargetPF = s_pcInfo[i].pGUIDPixFmtTo; + break; + } + iCurrIdx += 1; + } + } + + return errResult; +} + +ERR PKFormatConverter_GetPixelFormat(PKFormatConverter* pFC, PKPixelFormatGUID* pPF) +{ + *pPF = pFC->enPixelFormat; + + return WMP_errSuccess; +} + +ERR PKFormatConverter_GetSourcePixelFormat(PKFormatConverter* pFC, PKPixelFormatGUID* pPF) +{ + return pFC->pDecoder->GetPixelFormat(pFC->pDecoder, pPF); +} + +ERR PKFormatConverter_GetSize(PKFormatConverter* pFC, I32* piWidth, I32* piHeight) +{ + return pFC->pDecoder->GetSize(pFC->pDecoder, piWidth, piHeight); +} + +ERR PKFormatConverter_GetResolution(PKFormatConverter* pFC, Float* pfrX, Float* pfrY) +{ + return pFC->pDecoder->GetResolution(pFC->pDecoder, pfrX, pfrY); +} + +ERR PKFormatConverter_Copy(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + ERR err = WMP_errSuccess; + + Call(pFC->pDecoder->Copy(pFC->pDecoder, pRect, pb, cbStride)); + Call(pFC->Convert(pFC, pRect, pb, cbStride)); + +Cleanup: + return err; +} + +ERR PKFormatConverter_Convert(PKFormatConverter* pFC, const PKRect* pRect, U8* pb, U32 cbStride) +{ + UNREFERENCED_PARAMETER( pFC ); + UNREFERENCED_PARAMETER( pRect ); + UNREFERENCED_PARAMETER( pb ); + UNREFERENCED_PARAMETER( cbStride ); + + return WMP_errSuccess; +} + +ERR PKFormatConverter_Release(PKFormatConverter** ppFC) +{ + ERR err = WMP_errSuccess; + + Call(PKFree((void **) ppFC)); + +Cleanup: + return err; +} + diff --git a/libs/jxr/jxrgluelib/JXRMeta.c b/libs/jxr/jxrgluelib/JXRMeta.c new file mode 100644 index 00000000000..020c324bf71 --- /dev/null +++ b/libs/jxr/jxrgluelib/JXRMeta.c @@ -0,0 +1,905 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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 "JXRMeta.h" +#include "JXRGlue.h" + + + +// read and write big and little endian words/dwords from a buffer on both big and little endian cpu's +// with full buffer overflow checking + + + +ERR getbfcpy(U8* pbdest, const U8* pb, size_t cb, size_t ofs, U32 n) +{ + ERR err = WMP_errSuccess; + FailIf(ofs + n > cb, WMP_errBufferOverflow); + memcpy(pbdest, &pb[ofs], n); +Cleanup: + return err; +} + + + +ERR getbfw(const U8* pb, size_t cb, size_t ofs, U16* pw) +{ + ERR err = WMP_errSuccess; + FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow); + *pw = (U16)( pb[ofs] + ( pb[ofs + 1] << 8 ) ); +Cleanup: + return err; +} + + + +ERR getbfdw(const U8* pb, size_t cb, size_t ofs, U32* pdw) +{ + ERR err = WMP_errSuccess; + FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow); + *pdw = pb[ofs] + ( pb[ofs + 1] << 8 ) + ( pb[ofs + 2] << 16UL ) + ( pb[ofs + 3] << 24UL ); +Cleanup: + return err; +} + + + +ERR getbfwbig(const U8* pb, size_t cb, size_t ofs, U16* pw) +{ + ERR err = WMP_errSuccess; + FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow); + *pw = (U16)( pb[ofs + 1] + ( pb[ofs] << 8 ) ); +Cleanup: + return err; +} + + + +ERR getbfdwbig(const U8* pb, size_t cb, size_t ofs, U32* pdw) +{ + ERR err = WMP_errSuccess; + FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow); + *pdw = pb[ofs + 3] + ( pb[ofs + 2] << 8 ) + ( pb[ofs + 1] << 16UL ) + ( pb[ofs] << 24UL ); +Cleanup: + return err; +} + + + +ERR getbfwe(const U8* pb, size_t cb, size_t ofs, U16* pw, U8 endian) +{ + if ( endian == WMP_INTEL_ENDIAN ) + return ( getbfw(pb, cb, ofs, pw) ); + else + return ( getbfwbig(pb, cb, ofs, pw) ); +} + + + +ERR getbfdwe(const U8* pb, size_t cb, size_t ofs, U32* pdw, U8 endian) +{ + if ( endian == WMP_INTEL_ENDIAN ) + return ( getbfdw(pb, cb, ofs, pdw) ); + else + return ( getbfdwbig(pb, cb, ofs, pdw) ); +} + + + +ERR setbfcpy(U8* pb, size_t cb, size_t ofs, const U8* pbset, size_t cbset) +{ + ERR err = WMP_errSuccess; + FailIf(ofs + cbset > cb, WMP_errBufferOverflow); + memcpy(&pb[ofs], pbset, cbset); +Cleanup: + return err; +} + + + +ERR setbfw(U8* pb, size_t cb, size_t ofs, U16 dw) +{ + ERR err = WMP_errSuccess; + FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow); + pb[ofs] = (U8)dw; + pb[ofs + 1] = (U8)( dw >> 8 ); +Cleanup: + return err; +} + + + +ERR setbfdw(U8* pb, size_t cb, size_t ofs, U32 dw) +{ + ERR err = WMP_errSuccess; + FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow); + pb[ofs] = (U8)dw; + pb[ofs + 1] = (U8)( dw >> 8 ); + pb[ofs + 2] = (U8)( dw >> 16 ); + pb[ofs + 3] = (U8)( dw >> 24 ); +Cleanup: + return err; +} + + + +ERR setbfwbig(U8* pb, size_t cb, size_t ofs, U16 dw) +{ + ERR err = WMP_errSuccess; + FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow); + pb[ofs + 1] = (U8)dw; + pb[ofs] = (U8)( dw >> 8 ); +Cleanup: + return err; +} + + + +ERR setbfdwbig(U8* pb, size_t cb, size_t ofs, U32 dw) +{ + ERR err = WMP_errSuccess; + FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow); + pb[ofs + 3] = (U8)dw; + pb[ofs + 2] = (U8)( dw >> 8 ); + pb[ofs + 1] = (U8)( dw >> 16 ); + pb[ofs] = (U8)( dw >> 24 ); +Cleanup: + return err; +} + + + +//================================================================ +// BufferCalcIFDSize (arbitrary endian) +// StreamCalcIFDSize (little endian) +// +// count up the number of bytes needed to store the IFD and all +// associated data including a subordinate interoperability IFD if any +//================================================================ + + + +ERR BufferCalcIFDSize(const U8* pbdata, size_t cbdata, U32 ofsifd, U8 endian, U32* pcbifd) +{ + ERR err = WMP_errSuccess; + U16 cDir; + U16 i; + U32 ofsdir; + U32 cbifd = 0; + U32 cbEXIFIFD = 0; + U32 cbGPSInfoIFD = 0; + U32 cbInteroperabilityIFD = 0; + + *pcbifd = 0; + Call(getbfwe(pbdata, cbdata, ofsifd, &cDir, endian)); + + cbifd = sizeof(U16) + cDir * SizeofIFDEntry + sizeof(U32); + ofsdir = ofsifd + sizeof(U16); + for ( i = 0; i < cDir; i++ ) + { + U16 tag; + U16 type; + U32 count; + U32 value; + U32 datasize; + + Call(getbfwe(pbdata, cbdata, ofsdir, &tag, endian)); + Call(getbfwe(pbdata, cbdata, ofsdir + sizeof(U16), &type, endian)); + Call(getbfdwe(pbdata, cbdata, ofsdir + 2 * sizeof(U16), &count, endian)); + Call(getbfdwe(pbdata, cbdata, ofsdir + 2 * sizeof(U16) + sizeof(U32), &value, endian)); + FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail); + if ( tag == WMP_tagEXIFMetadata ) + { + Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbEXIFIFD)); + } + else if ( tag == WMP_tagGPSInfoMetadata ) + { + Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbGPSInfoIFD)); + } + else if ( tag == WMP_tagInteroperabilityIFD ) + { + Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbInteroperabilityIFD)); + } + else + { + datasize = IFDEntryTypeSizes[type] * count; + if ( datasize > 4 ) + cbifd += datasize; + } + ofsdir += SizeofIFDEntry; + } + if ( cbEXIFIFD != 0 ) + cbifd += ( cbifd & 1 ) + cbEXIFIFD; + if ( cbGPSInfoIFD != 0 ) + cbifd += ( cbifd & 1 ) + cbGPSInfoIFD; + if ( cbInteroperabilityIFD != 0 ) + cbifd += ( cbifd & 1 ) + cbInteroperabilityIFD; + + *pcbifd = cbifd; + +Cleanup: + return err; +} + + +ERR StreamCalcIFDSize(struct WMPStream* pWS, U32 uIFDOfs, U32 *pcbifd) +{ + ERR err = WMP_errSuccess; + size_t offCurPos = 0; + Bool GetPosOK = FALSE; + U16 cDir; + U32 i; + U32 ofsdir; + U32 cbifd = 0; + U32 cbEXIFIFD = 0; + U32 cbGPSInfoIFD = 0; + U32 cbInteroperabilityIFD = 0; + + *pcbifd = 0; + Call(pWS->GetPos(pWS, &offCurPos)); + GetPosOK = TRUE; + + Call(GetUShort(pWS, uIFDOfs, &cDir)); + cbifd = sizeof(U16) + cDir * SizeofIFDEntry + sizeof(U32); + ofsdir = uIFDOfs + sizeof(U16); + for ( i = 0; i < cDir; i++ ) + { + U16 tag; + U16 type; + U32 count; + U32 value; + U32 datasize; + + Call(GetUShort(pWS, ofsdir, &tag)); + Call(GetUShort(pWS, ofsdir + sizeof(U16), &type)); + Call(GetULong(pWS, ofsdir + 2 * sizeof(U16), &count)); + Call(GetULong(pWS, ofsdir + 2 * sizeof(U16) + sizeof(U32), &value)); + FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errUnsupportedFormat); + if ( tag == WMP_tagEXIFMetadata ) + { + Call(StreamCalcIFDSize(pWS, value, &cbEXIFIFD)); + } + else if ( tag == WMP_tagGPSInfoMetadata ) + { + Call(StreamCalcIFDSize(pWS, value, &cbGPSInfoIFD)); + } + else if ( tag == WMP_tagInteroperabilityIFD ) + { + Call(StreamCalcIFDSize(pWS, value, &cbInteroperabilityIFD)); + } + else + { + datasize = IFDEntryTypeSizes[type] * count; + if ( datasize > 4 ) + cbifd += datasize; + } + ofsdir += SizeofIFDEntry; + } + if ( cbEXIFIFD != 0 ) + cbifd += ( cbifd & 1 ) + cbEXIFIFD; + if ( cbGPSInfoIFD != 0 ) + cbifd += ( cbifd & 1 ) + cbGPSInfoIFD; + if ( cbInteroperabilityIFD != 0 ) + cbifd += ( cbifd & 1 ) + cbInteroperabilityIFD; + *pcbifd = cbifd; + +Cleanup: + if ( GetPosOK ) + Call(pWS->SetPos(pWS, offCurPos)); + return ( err ); +} + + + +// src IFD copied to dst IFD with any nested IFD's +// src IFD is arbitrary endian, arbitrary data arrangement +// dst IFD is little endian, data arranged in tag order +// dst IFD tags are ordered the same as src IFD so src IFD tags must be in order +ERR BufferCopyIFD(const U8* pbsrc, U32 cbsrc, U32 ofssrc, U8 endian, U8* pbdst, U32 cbdst, U32* pofsdst) +{ + ERR err = WMP_errSuccess; + U16 cDir; + U16 i; + U16 ofsEXIFIFDEntry = 0; + U16 ofsGPSInfoIFDEntry = 0; + U16 ofsInteroperabilityIFDEntry = 0; + U32 ofsEXIFIFD = 0; + U32 ofsGPSInfoIFD = 0; + U32 ofsInteroperabilityIFD = 0; + U32 ofsdstnextdata; + U32 ofsdst = *pofsdst; + U32 ofssrcdir; + U32 ofsdstdir; + U32 ofsnextifd; + + Call(getbfwe(pbsrc, cbsrc, ofssrc, &cDir, endian)); + Call(setbfw(pbdst, cbdst, ofsdst, cDir)); + ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir; + ofsdstnextdata = ofsnextifd + sizeof(U32); + + ofssrcdir = ofssrc + sizeof(U16); + ofsdstdir = ofsdst + sizeof(U16); + for ( i = 0; i < cDir; i++ ) + { + U16 tag; + U16 type; + U32 count; + U32 value; + U32 size; + + Call(getbfwe(pbsrc, cbsrc, ofssrcdir, &tag, endian)); + Call(setbfw(pbdst, cbdst, ofsdstdir, tag)); + + Call(getbfwe(pbsrc, cbsrc, ofssrcdir + sizeof(U16), &type, endian)); + Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type)); + + Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16), &count, endian)); + Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count)); + + Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value, endian)); + Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0)); + + FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail); + if ( tag == WMP_tagEXIFMetadata ) + { + ofsEXIFIFDEntry = (U16) ofsdstdir; + ofsEXIFIFD = value; + } + else if ( tag == WMP_tagGPSInfoMetadata ) + { + ofsGPSInfoIFDEntry = (U16) ofsdstdir; + ofsGPSInfoIFD = value; + } + else if ( tag == WMP_tagInteroperabilityIFD ) + { + ofsInteroperabilityIFDEntry = (U16) ofsdstdir; + ofsInteroperabilityIFD = value; + } + else + { + U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32); + U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32); + size = count * IFDEntryTypeSizes[type]; + if ( size > 4 ) + { + ofssrcdata = value; + Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata)); + ofsdstdata = ofsdstnextdata; + ofsdstnextdata += size; + } + FailIf(ofssrcdata + size > cbsrc || ofsdstdata + size > cbdst, WMP_errBufferOverflow); + if ( size == count || endian == WMP_INTEL_ENDIAN ) + // size == count means 8-bit data means endian doesn't matter + memcpy(&pbdst[ofsdstdata], &pbsrc[ofssrcdata], size); + else + { // big endian source and endian matters + U32 j; + + switch ( IFDEntryTypeSizes[type] ) + { + case 2: + for ( j = 0; j < count; j++ ) + { + U16 w; + getbfwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U16), &w); + setbfw(pbdst, cbdst, ofsdstdata + j * sizeof(U16), w); + } + break; + case 8: + if ( type == WMP_typDOUBLE ) + { + for ( j = 0; j < count; j++ ) + { + U32 dwlo; + U32 dwhi; + getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8, &dwhi); + getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8 + sizeof(U32), &dwlo); + setbfdw(pbdst, cbdst, ofsdstdata + j * 8, dwlo); + setbfdw(pbdst, cbdst, ofsdstdata + j * 8 + sizeof(U32), dwhi); + } + break; + } + count *= 2; + // RATIONAL's fall through to be handled as LONG's + case 4: + for ( j = 0; j < count; j++ ) + { + U32 dw; + getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U32), &dw); + setbfdw(pbdst, cbdst, ofsdstdata + j * sizeof(U32), dw); + } + break; + } + } + } + ofssrcdir += SizeofIFDEntry; + ofsdstdir += SizeofIFDEntry; + } + Call(setbfdw(pbdst, cbdst, ofsnextifd, 0)); // no nextIFD + + if ( ofsEXIFIFDEntry != 0 ) + { + ofsdstnextdata += ( ofsdstnextdata & 1 ); + Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); + Call(BufferCopyIFD(pbsrc, cbsrc, ofsEXIFIFD, endian, pbdst, cbdst, &ofsdstnextdata)); + } + if ( ofsGPSInfoIFDEntry != 0 ) + { + ofsdstnextdata += ( ofsdstnextdata & 1 ); + Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); + Call(BufferCopyIFD(pbsrc, cbsrc, ofsGPSInfoIFD, endian, pbdst, cbdst, &ofsdstnextdata)); + } + if ( ofsInteroperabilityIFDEntry != 0 ) + { + ofsdstnextdata += ( ofsdstnextdata & 1 ); + Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); + Call(BufferCopyIFD(pbsrc, cbsrc, ofsInteroperabilityIFD, endian, pbdst, cbdst, &ofsdstnextdata)); + } + *pofsdst = ofsdstnextdata; + +Cleanup: + return err; +} + + + +// src IFD copied to dst IFD with any nested IFD's +// src IFD is little endian, arbitrary data arrangement +// dst IFD is little endian, data arranged in tag order +// dst IFD tags are ordered the same as src IFD so src IFD tags must be in order +ERR StreamCopyIFD(struct WMPStream* pWS, U32 ofssrc, U8* pbdst, U32 cbdst, U32* pofsdst) +{ + ERR err = WMP_errSuccess; + size_t offCurPos = 0; + Bool GetPosOK = FALSE; + U16 cDir; + U16 i; + U16 ofsEXIFIFDEntry = 0; + U16 ofsGPSInfoIFDEntry = 0; + U16 ofsInteroperabilityIFDEntry = 0; + U32 ofsEXIFIFD = 0; + U32 ofsGPSInfoIFD = 0; + U32 ofsInteroperabilityIFD = 0; + U32 ofsdstnextdata; + U32 ofsdst = *pofsdst; + U32 ofssrcdir; + U32 ofsdstdir; + U32 ofsnextifd; + + Call(pWS->GetPos(pWS, &offCurPos)); + GetPosOK = TRUE; + + Call(GetUShort(pWS, ofssrc, &cDir)); + Call(setbfw(pbdst, cbdst, ofsdst, cDir)); + + ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir; + ofsdstnextdata = ofsnextifd + sizeof(U32); + + ofssrcdir = ofssrc + sizeof(U16); + ofsdstdir = ofsdst + sizeof(U16); + for ( i = 0; i < cDir; i++ ) + { + U16 tag; + U16 type; + U32 count; + U32 value; + U32 size; + + Call(GetUShort(pWS, ofssrcdir, &tag)); + Call(setbfw(pbdst, cbdst, ofsdstdir, tag)); + + Call(GetUShort(pWS, ofssrcdir + sizeof(U16), &type)); + Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type)); + + Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16), &count)); + Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count)); + + Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value)); + Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0)); + + FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail); + if ( tag == WMP_tagEXIFMetadata ) + { + ofsEXIFIFDEntry = (U16) ofsdstdir; + ofsEXIFIFD = value; + } + else if ( tag == WMP_tagGPSInfoMetadata ) + { + ofsGPSInfoIFDEntry = (U16) ofsdstdir; + ofsGPSInfoIFD = value; + } + else if ( tag == WMP_tagInteroperabilityIFD ) + { + ofsInteroperabilityIFDEntry = (U16) ofsdstdir; + ofsInteroperabilityIFD = value; + } + else + { + U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32); + U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32); + size = count * IFDEntryTypeSizes[type]; + if ( size > 4 ) + { + ofssrcdata = value; + Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata)); + ofsdstdata = ofsdstnextdata; + ofsdstnextdata += size; + } + FailIf(ofsdstdata + size > cbdst, WMP_errBufferOverflow); + Call(pWS->SetPos(pWS, ofssrcdata)); + Call(pWS->Read(pWS, &pbdst[ofsdstdata], size)); + } + ofssrcdir += SizeofIFDEntry; + ofsdstdir += SizeofIFDEntry; + } + Call(setbfdw(pbdst, cbdst, ofsnextifd, 0)); // no nextIFD + + if ( ofsEXIFIFDEntry != 0 ) + { + ofsdstnextdata += ( ofsdstnextdata & 1 ); + Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); + Call(StreamCopyIFD(pWS, ofsEXIFIFD, pbdst, cbdst, &ofsdstnextdata)); + } + if ( ofsGPSInfoIFDEntry != 0 ) + { + ofsdstnextdata += ( ofsdstnextdata & 1 ); + Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); + Call(StreamCopyIFD(pWS, ofsGPSInfoIFD, pbdst, cbdst, &ofsdstnextdata)); + } + if ( ofsInteroperabilityIFDEntry != 0 ) + { + ofsdstnextdata += ( ofsdstnextdata & 1 ); + Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); + Call(StreamCopyIFD(pWS, ofsInteroperabilityIFD, pbdst, cbdst, &ofsdstnextdata)); + } + *pofsdst = ofsdstnextdata; + +Cleanup: + if ( GetPosOK ) + Call(pWS->SetPos(pWS, offCurPos)); + return err; +} + + + +//================================================================ +ERR GetUShort( + __in_ecount(1) struct WMPStream* pWS, + size_t offPos, + __out_ecount(1) U16* puValue) +{ + ERR err = WMP_errSuccess; + U8 cVal; + + Call(pWS->SetPos(pWS, offPos)); + Call(pWS->Read(pWS, &cVal, sizeof(cVal))); + puValue[0] = (U16) cVal; + Call(pWS->Read(pWS, &cVal, sizeof(cVal))); + puValue[0] += ((U16) cVal) << 8; + +Cleanup: + return err; +} + +ERR PutUShort( + __in_ecount(1) struct WMPStream* pWS, + size_t offPos, + U16 uValue) +{ + ERR err = WMP_errSuccess; + U8 cVal = (U8) uValue; + + Call(pWS->SetPos(pWS, offPos)); + Call(pWS->Write(pWS, &cVal, sizeof(cVal))); + cVal = (U8) (uValue >> 8); + Call(pWS->Write(pWS, &cVal, sizeof(cVal))); + +Cleanup: + return err; +} + +ERR GetULong( + __in_ecount(1) struct WMPStream* pWS, + size_t offPos, + __out_ecount(1) U32* puValue) +{ + ERR err = WMP_errSuccess; + U8 cVal; + + Call(pWS->SetPos(pWS, offPos)); + Call(pWS->Read(pWS, &cVal, sizeof(cVal))); + puValue[0] = (U32) cVal; + Call(pWS->Read(pWS, &cVal, sizeof(cVal))); + puValue[0] += ((U32) cVal) << 8; + Call(pWS->Read(pWS, &cVal, sizeof(cVal))); + puValue[0] += ((U32) cVal) << 16; + Call(pWS->Read(pWS, &cVal, sizeof(cVal))); + puValue[0] += ((U32) cVal) << 24; + +Cleanup: + return err; +} + +ERR PutULong( + __in_ecount(1) struct WMPStream* pWS, + size_t offPos, + U32 uValue) +{ + ERR err = WMP_errSuccess; + U8 cVal = (U8) uValue; + + Call(pWS->SetPos(pWS, offPos)); + Call(pWS->Write(pWS, &cVal, sizeof(cVal))); + cVal = (U8) (uValue >> 8); + Call(pWS->Write(pWS, &cVal, sizeof(cVal))); + cVal = (U8) (uValue >> 16); + Call(pWS->Write(pWS, &cVal, sizeof(cVal))); + cVal = (U8) (uValue >> 24); + Call(pWS->Write(pWS, &cVal, sizeof(cVal))); + +Cleanup: + return err; +} + + +ERR ReadBinaryData(__in_ecount(1) struct WMPStream* pWS, + const __in_win U32 uCount, + const __in_win U32 uValue, + U8 **ppbData) +{ + ERR err = WMP_errSuccess; + U8 *pbData = NULL; + + Call(PKAlloc((void **) &pbData, uCount + 2)); // Allocate buffer to store data with space for an added ascii or unicode null + if (uCount <= 4) + { + unsigned int i; + for (i = 0; i < uCount; i++) + pbData[i] = ((U8*)&uValue)[i]; // Copy least sig bytes - we assume 'II' type TIFF files + } + else + { + size_t offPosPrev; + + Call(pWS->GetPos(pWS, &offPosPrev)); + Call(pWS->SetPos(pWS, uValue)); + Call(pWS->Read(pWS, pbData, uCount)); + Call(pWS->SetPos(pWS, offPosPrev)); + } + + *ppbData = pbData; + +Cleanup: + if (Failed(err)) + { + if (pbData) + PKFree((void **) &pbData); + } + return err; +} + + +ERR ReadPropvar(__in_ecount(1) struct WMPStream* pWS, + const __in_win U16 uType, + const __in_win U32 uCount, + const __in_win U32 uValue, + __out_win DPKPROPVARIANT *pvar) +{ + ERR err = WMP_errSuccess; + // U8 *pbData = NULL; + + memset(pvar, 0, sizeof(*pvar)); + if (uCount == 0) + goto Cleanup; // Nothing to read in here + + switch (uType) + { + case WMP_typASCII: + pvar->vt = DPKVT_LPSTR; + Call(ReadBinaryData(pWS, uCount, uValue, (U8 **) &pvar->VT.pszVal)); + assert(0 == pvar->VT.pszVal[uCount - 1]); // Check that it's null-terminated + // make sure (ReadBinaryData allocated uCount + 2 so this and unicode can have forced nulls) + pvar->VT.pszVal[uCount] = 0; + break; + + case WMP_typBYTE: + case WMP_typUNDEFINED: + // Return as regular C array rather than safearray, as this type is sometimes + // used to convey unicode (which does not require a count field). Caller knows + // uCount and can convert to safearray if necessary. + pvar->vt = (DPKVT_BYREF | DPKVT_UI1); + Call(ReadBinaryData(pWS, uCount, uValue, &pvar->VT.pbVal)); + break; + + case WMP_typSHORT: + if (1 == uCount) + { + pvar->vt = DPKVT_UI2; + pvar->VT.uiVal = (U16)(uValue & 0x0000FFFF); + } + else if (2 == uCount) + { + pvar->vt = DPKVT_UI4; + pvar->VT.ulVal = uValue; + } + else + { + assert(FALSE); // NYI + FailIf(TRUE, WMP_errNotYetImplemented); + } + break; + + default: + assert(FALSE); // Unhandled type + FailIf(TRUE, WMP_errNotYetImplemented); + break; + } + +Cleanup: + return err; +} + + +ERR WriteWmpDE( + __in_ecount(1) struct WMPStream* pWS, + size_t *pOffPos, + const __in_ecount(1) WmpDE* pDE, + const U8 *pbData, + U32 *pcbDataWrittenToOffset) +{ + ERR err = WMP_errSuccess; + size_t offPos = *pOffPos; + + assert(-1 != pDE->uCount); + assert(-1 != pDE->uValueOrOffset); + + if (pcbDataWrittenToOffset) + { + assert(pbData); // Makes no sense to provide this arg without pbData + *pcbDataWrittenToOffset = 0; + } + + Call(PutUShort(pWS, offPos, pDE->uTag)); offPos += 2; + Call(PutUShort(pWS, offPos, pDE->uType)); offPos += 2; + Call(PutULong(pWS, offPos, pDE->uCount)); offPos += 4; + + switch (pDE->uType) + { + + case WMP_typASCII: + case WMP_typUNDEFINED: + case WMP_typBYTE: + if (pDE->uCount <= 4) + { + U8 pad[4] = {0}; + Call(pWS->SetPos(pWS, offPos)); + + if (NULL == pbData) + pbData = (U8*)&pDE->uValueOrOffset; + + Call(pWS->Write(pWS, pbData, pDE->uCount)); + Call(pWS->Write(pWS, pad, 4 - pDE->uCount)); offPos += 4; + } + else + { + Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4; + + // Write the data if requested to do so + if (pbData) + { + Call(pWS->SetPos(pWS, pDE->uValueOrOffset)); + Call(pWS->Write(pWS, pbData, pDE->uCount)); + Call(pWS->SetPos(pWS, offPos)); + *pcbDataWrittenToOffset = pDE->uCount; + } + } + break; + + case WMP_typSHORT: + if (pDE->uCount <= 2) + { + U16 uiShrt1 = 0; + U16 uiShrt2 = 0; + + if (NULL == pbData) + pbData = (U8*)&pDE->uValueOrOffset; + + if (pDE->uCount > 0) + uiShrt1 = *((U16*)pbData); + + if (pDE->uCount > 1) + { + assert(FALSE); // Untested - remove this assert after this has been tested + uiShrt2 = *(U16*)(pbData + 2); + } + + Call(PutUShort(pWS, offPos, uiShrt1)); offPos += 2; + Call(PutUShort(pWS, offPos, uiShrt2)); offPos += 2; + } + else + { + assert(FALSE); // Untested - remove this assert after this has been tested + Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4; + + // Write the data if requested to do so + if (pbData) + { + U32 i; + Call(pWS->SetPos(pWS, pDE->uValueOrOffset)); + for (i = 0; i < pDE->uCount; i++) + { + const U16 uiShort = *(U16*)(pbData + i*sizeof(U16)); + Call(PutUShort(pWS, offPos, uiShort)); // Write one at a time for endian purposes - but inefficient + } + Call(pWS->SetPos(pWS, offPos)); + *pcbDataWrittenToOffset = pDE->uCount * sizeof(U16); + } + + } + break; + + case WMP_typFLOAT: + case WMP_typLONG: + if (pDE->uCount <= 1) + { + if (NULL == pbData) + pbData = (U8*)&pDE->uValueOrOffset; + + Call(PutULong(pWS, offPos, *(U32*)pbData)); offPos += 4; + } + else + { + assert(FALSE); // Untested - remove this assert after this has been tested + Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4; + + // Write the data if requested to do so + if (pbData) + { + U32 i; + Call(pWS->SetPos(pWS, pDE->uValueOrOffset)); + for (i = 0; i < pDE->uCount; i++) + { + const U32 uLong = *(U32*)(pbData + i*sizeof(U32)); + Call(PutULong(pWS, offPos, uLong)); // Write one at a time for endian purposes - but inefficient + } + Call(pWS->SetPos(pWS, offPos)); + *pcbDataWrittenToOffset = pDE->uCount * sizeof(U32); + } + } + break; + + default: + assert(FALSE); // Alert the programmer + Call(WMP_errInvalidParameter); + break; + } + +Cleanup: + *pOffPos = offPos; + return err; +} + diff --git a/libs/jxr/jxrgluelib/JXRMeta.h b/libs/jxr/jxrgluelib/JXRMeta.h new file mode 100644 index 00000000000..53215041d70 --- /dev/null +++ b/libs/jxr/jxrgluelib/JXRMeta.h @@ -0,0 +1,258 @@ +//*@@@+++@@@@****************************************************************** +// +// Copyright © Microsoft Corp. +// 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 HOLDER 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. +// +//*@@@---@@@@****************************************************************** +#pragma once + +#include +#ifndef WIN32 +#include +#endif + +#ifndef UNREFERENCED_PARAMETER +#define UNREFERENCED_PARAMETER(P) { (P) = (P); } +#endif + +//================================================================ +// Container +//================================================================ + +// Keep these in sort order so that we can easily confirm we are outputting tags in ascending order +#define WMP_tagNull 0 + +#define WMP_tagDocumentName 0x010d // Descriptive metadata tag +#define WMP_tagImageDescription 0x010e // Descriptive metadata tag +#define WMP_tagCameraMake 0x010f // Descriptive metadata tag +#define WMP_tagCameraModel 0x0110 // Descriptive metadata tag +#define WMP_tagPageName 0x011d // Descriptive metadata tag +#define WMP_tagPageNumber 0x0129 // Descriptive metadata tag +#define WMP_tagSoftware 0x0131 // Descriptive metadata tag +#define WMP_tagDateTime 0x0132 // Descriptive metadata tag +#define WMP_tagArtist 0x013b // Descriptive metadata tag +#define WMP_tagHostComputer 0x013c // Descriptive metadata tag + +#define WMP_tagXMPMetadata 0x02bc + +#define WMP_tagRatingStars 0x4746 // Descriptive metadata tag +#define WMP_tagRatingValue 0x4749 // Descriptive metadata tag +#define WMP_tagCopyright 0x8298 // Descriptive metadata tag + +#define WMP_tagEXIFMetadata 0x8769 +#define WMP_tagGPSInfoMetadata 0x8825 +#define WMP_tagIPTCNAAMetadata 0x83bb +#define WMP_tagPhotoshopMetadata 0x8649 +#define WMP_tagInteroperabilityIFD 0xa005 +#define WMP_tagIccProfile 0x8773 // Need to use same tag as TIFF!! + +#define WMP_tagCaption 0x9c9b // Descriptive metadata tag + +#define WMP_tagPixelFormat 0xbc01 +#define WMP_tagTransformation 0xbc02 +#define WMP_tagCompression 0xbc03 +#define WMP_tagImageType 0xbc04 + +#define WMP_tagImageWidth 0xbc80 +#define WMP_tagImageHeight 0xbc81 + +#define WMP_tagWidthResolution 0xbc82 +#define WMP_tagHeightResolution 0xbc83 + +#define WMP_tagImageOffset 0xbcc0 +#define WMP_tagImageByteCount 0xbcc1 +#define WMP_tagAlphaOffset 0xbcc2 +#define WMP_tagAlphaByteCount 0xbcc3 +#define WMP_tagImageDataDiscard 0xbcc4 +#define WMP_tagAlphaDataDiscard 0xbcc5 + + +#define WMP_typBYTE 1 +#define WMP_typASCII 2 +#define WMP_typSHORT 3 +#define WMP_typLONG 4 +#define WMP_typRATIONAL 5 +#define WMP_typSBYTE 6 +#define WMP_typUNDEFINED 7 +#define WMP_typSSHORT 8 +#define WMP_typSLONG 9 +#define WMP_typSRATIONAL 10 +#define WMP_typFLOAT 11 +#define WMP_typDOUBLE 12 + + +#define WMP_valCompression 0xbc +#define WMP_valWMPhotoID WMP_valCompression + + +#ifdef WIN32 +#define __in_win __in +#define __out_win __out +#endif + + +//================================================================ + +typedef enum +{ + DPKVT_EMPTY = 0, + DPKVT_UI1 = 17, + DPKVT_UI2 = 18, + DPKVT_UI4 = 19, + DPKVT_LPSTR = 30, + DPKVT_LPWSTR = 31, + DPKVT_BYREF = 0x4000, +} DPKVARTYPE; + +typedef struct DPKPROPVARIANT +{ + DPKVARTYPE vt; + union + { + U8 bVal; // DPKVT_UI1 + U16 uiVal; // DPKVT_UI2 + U32 ulVal; // DPKVT_UI4 + char *pszVal; // DPKVT_LPSTR + U16 *pwszVal; // DPKVT_LPWSTR + U8 *pbVal; // DPKVT_BYREF | DPKVT_UI1 + } VT; +} DPKPROPVARIANT; + +typedef struct DESCRIPTIVEMETADATA +{ + DPKPROPVARIANT pvarImageDescription; // WMP_tagImageDescription + DPKPROPVARIANT pvarCameraMake; // WMP_tagCameraMake + DPKPROPVARIANT pvarCameraModel; // WMP_tagCameraModel + DPKPROPVARIANT pvarSoftware; // WMP_tagSoftware + DPKPROPVARIANT pvarDateTime; // WMP_tagDateTime + DPKPROPVARIANT pvarArtist; // WMP_tagArtist + DPKPROPVARIANT pvarCopyright; // WMP_tagCopyright + DPKPROPVARIANT pvarRatingStars; // WMP_tagRatingStars + DPKPROPVARIANT pvarRatingValue; // WMP_tagRatingValue + DPKPROPVARIANT pvarCaption; // WMP_tagCaption + DPKPROPVARIANT pvarDocumentName; // WMP_tagDocumentName + DPKPROPVARIANT pvarPageName; // WMP_tagPageName + DPKPROPVARIANT pvarPageNumber; // WMP_tagPageNumber + DPKPROPVARIANT pvarHostComputer; // WMP_tagHostComputer +} DESCRIPTIVEMETADATA; + +typedef struct tagWmpDE +{ + U16 uTag; + U16 uType; + U32 uCount; + U32 uValueOrOffset; +} WmpDE; + +typedef struct tagWmpDEMisc +{ + U32 uImageOffset; + U32 uImageByteCount; + U32 uAlphaOffset; + U32 uAlphaByteCount; + + U32 uOffPixelFormat; + U32 uOffImageByteCount; + U32 uOffAlphaOffset; + U32 uOffAlphaByteCount; + U32 uColorProfileOffset; + U32 uColorProfileByteCount; + U32 uXMPMetadataOffset; + U32 uXMPMetadataByteCount; + U32 uEXIFMetadataOffset; + U32 uEXIFMetadataByteCount; + U32 uGPSInfoMetadataOffset; + U32 uGPSInfoMetadataByteCount; + U32 uIPTCNAAMetadataOffset; + U32 uIPTCNAAMetadataByteCount; + U32 uPhotoshopMetadataOffset; + U32 uPhotoshopMetadataByteCount; + U32 uDescMetadataOffset; + U32 uDescMetadataByteCount; +} WmpDEMisc; + + +//================================================================ +EXTERN_C ERR GetUShort( + __in_ecount(1) struct WMPStream* pWS, + size_t offPos, + __out_ecount(1) U16* puValue +); + +EXTERN_C ERR PutUShort( + __in_ecount(1) struct WMPStream* pWS, + size_t offPos, + U16 uValue +); + +EXTERN_C ERR GetULong( + __in_ecount(1) struct WMPStream* pWS, + size_t offPos, + __out_ecount(1) U32* puValue +); + +EXTERN_C ERR PutULong( + __in_ecount(1) struct WMPStream* pWS, + size_t offPos, + U32 uValue +); + +EXTERN_C ERR WriteWmpDE( + __in_ecount(1) struct WMPStream* pWS, + size_t *pOffPos, + const __in_ecount(1) WmpDE* pDE, + const U8 *pbData, + U32 *pcbDataWrittenToOffset +); + + +EXTERN_C ERR ReadPropvar(__in_ecount(1) struct WMPStream* pWS, + const __in_win U16 uType, + const __in_win U32 uCount, + const __in_win U32 uValue, + __out_win DPKPROPVARIANT *pvar); + + + +// read and write little endian words/dwords from a buffer on both big and little endian cpu's +// with full buffer overflow checking + +#define WMP_INTEL_ENDIAN ('I') + +EXTERN_C ERR getbfcpy(U8* pbdest, const U8* pb, size_t cb, size_t ofs, U32 n); +EXTERN_C ERR getbfw(const U8* pb, size_t cb, size_t ofs, U16* pw); +EXTERN_C ERR getbfdw(const U8* pb, size_t cb, size_t ofs, U32* pdw); +EXTERN_C ERR getbfwbig(const U8* pb, size_t cb, size_t ofs, U16* pw); +EXTERN_C ERR getbfdwbig(const U8* pb, size_t cb, size_t ofs, U32* pdw); +EXTERN_C ERR getbfwe(const U8* pb, size_t cb, size_t ofs, U16* pw, U8 endian); +EXTERN_C ERR getbfdwe(const U8* pb, size_t cb, size_t ofs, U32* pdw, U8 endian); +EXTERN_C ERR setbfcpy(U8* pb, size_t cb, size_t ofs, const U8* pbset, size_t cbset); +EXTERN_C ERR setbfw(U8* pb, size_t cb, size_t ofs, U16 dw); +EXTERN_C ERR setbfdw(U8* pb, size_t cb, size_t ofs, U32 dw); +EXTERN_C ERR setbfwbig(U8* pb, size_t cb, size_t ofs, U16 dw); +EXTERN_C ERR setbfdwbig(U8* pb, size_t cb, size_t ofs, U32 dw); +EXTERN_C ERR BufferCalcIFDSize(const U8* pb, size_t cb, U32 uIFDOfs, U8 endian, U32 *pcbifd); +EXTERN_C ERR StreamCalcIFDSize(struct WMPStream* pWS, U32 uIFDOfs, U32 *pcbifd); +EXTERN_C ERR BufferCopyIFD(const U8* pbsrc, U32 cbsrc, U32 ofssrc, U8 endian, U8* pbdest, U32 cbdest, U32* pofsdest); +EXTERN_C ERR StreamCopyIFD(struct WMPStream* pWS, U32 ofssrc, U8* pbdest, U32 cbdest, U32* pofsdest);