178e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar/* 278e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * Copyright (C) 2007-2008 ARM Limited 378e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * 478e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * Licensed under the Apache License, Version 2.0 (the "License"); 578e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * you may not use this file except in compliance with the License. 678e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * You may obtain a copy of the License at 778e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * 878e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * http://www.apache.org/licenses/LICENSE-2.0 978e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * 1078e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * Unless required by applicable law or agreed to in writing, software 1178e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * distributed under the License is distributed on an "AS IS" BASIS, 1278e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1378e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * See the License for the specific language governing permissions and 1478e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * limitations under the License. 1578e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar * 1678e52bfac041d71ce53b5b13c2abf78af742b09dLajos Molnar */ 170c1bc742181ded4930842b46e9507372f0b1b963James Dong/** 180c1bc742181ded4930842b46e9507372f0b1b963James Dong * 190c1bc742181ded4930842b46e9507372f0b1b963James Dong * File Name: omxVCM4P10_SubAndTransformQDQResidual.c 200c1bc742181ded4930842b46e9507372f0b1b963James Dong * OpenMAX DL: v1.0.2 210c1bc742181ded4930842b46e9507372f0b1b963James Dong * Revision: 9641 220c1bc742181ded4930842b46e9507372f0b1b963James Dong * Date: Thursday, February 7, 2008 230c1bc742181ded4930842b46e9507372f0b1b963James Dong * 240c1bc742181ded4930842b46e9507372f0b1b963James Dong * 250c1bc742181ded4930842b46e9507372f0b1b963James Dong * 260c1bc742181ded4930842b46e9507372f0b1b963James Dong * Description: 270c1bc742181ded4930842b46e9507372f0b1b963James Dong * This function will calculate SAD for 4x4 blocks 280c1bc742181ded4930842b46e9507372f0b1b963James Dong * 290c1bc742181ded4930842b46e9507372f0b1b963James Dong */ 300c1bc742181ded4930842b46e9507372f0b1b963James Dong 310c1bc742181ded4930842b46e9507372f0b1b963James Dong#include "omxtypes.h" 320c1bc742181ded4930842b46e9507372f0b1b963James Dong#include "armOMX.h" 330c1bc742181ded4930842b46e9507372f0b1b963James Dong#include "omxVC.h" 340c1bc742181ded4930842b46e9507372f0b1b963James Dong 350c1bc742181ded4930842b46e9507372f0b1b963James Dong#include "armCOMM.h" 360c1bc742181ded4930842b46e9507372f0b1b963James Dong#include "armVC.h" 370c1bc742181ded4930842b46e9507372f0b1b963James Dong 380c1bc742181ded4930842b46e9507372f0b1b963James Dong/** 390c1bc742181ded4930842b46e9507372f0b1b963James Dong * Function: omxVCM4P10_SubAndTransformQDQResidual (6.3.5.8.1) 400c1bc742181ded4930842b46e9507372f0b1b963James Dong * 410c1bc742181ded4930842b46e9507372f0b1b963James Dong * Description: 420c1bc742181ded4930842b46e9507372f0b1b963James Dong * This function subtracts the prediction signal from the original signal to 430c1bc742181ded4930842b46e9507372f0b1b963James Dong * produce the difference signal and then performs a 4x4 integer transform and 440c1bc742181ded4930842b46e9507372f0b1b963James Dong * quantization. The quantized transformed coefficients are stored as 450c1bc742181ded4930842b46e9507372f0b1b963James Dong * pDstQuantCoeff. This function can also output dequantized coefficients or 460c1bc742181ded4930842b46e9507372f0b1b963James Dong * unquantized DC coefficients optionally by setting the pointers 470c1bc742181ded4930842b46e9507372f0b1b963James Dong * pDstDeQuantCoeff, pDCCoeff. 480c1bc742181ded4930842b46e9507372f0b1b963James Dong * 490c1bc742181ded4930842b46e9507372f0b1b963James Dong * Input Arguments: 500c1bc742181ded4930842b46e9507372f0b1b963James Dong * 510c1bc742181ded4930842b46e9507372f0b1b963James Dong * pSrcOrg - Pointer to original signal. 4-byte alignment required. 520c1bc742181ded4930842b46e9507372f0b1b963James Dong * pSrcPred - Pointer to prediction signal. 4-byte alignment required. 530c1bc742181ded4930842b46e9507372f0b1b963James Dong * iSrcOrgStep - Step of the original signal buffer; must be a multiple of 540c1bc742181ded4930842b46e9507372f0b1b963James Dong * 4. 550c1bc742181ded4930842b46e9507372f0b1b963James Dong * iSrcPredStep - Step of the prediction signal buffer; must be a multiple 560c1bc742181ded4930842b46e9507372f0b1b963James Dong * of 4. 570c1bc742181ded4930842b46e9507372f0b1b963James Dong * pNumCoeff -Number of non-zero coefficients after quantization. If this 580c1bc742181ded4930842b46e9507372f0b1b963James Dong * parameter is not required, it is set to NULL. 590c1bc742181ded4930842b46e9507372f0b1b963James Dong * nThreshSAD - Zero-block early detection threshold. If this parameter is 600c1bc742181ded4930842b46e9507372f0b1b963James Dong * not required, it is set to 0. 610c1bc742181ded4930842b46e9507372f0b1b963James Dong * iQP - Quantization parameter; must be in the range [0,51]. 620c1bc742181ded4930842b46e9507372f0b1b963James Dong * bIntra - Indicates whether this is an INTRA block, either 1-INTRA or 630c1bc742181ded4930842b46e9507372f0b1b963James Dong * 0-INTER 640c1bc742181ded4930842b46e9507372f0b1b963James Dong * 650c1bc742181ded4930842b46e9507372f0b1b963James Dong * Output Arguments: 660c1bc742181ded4930842b46e9507372f0b1b963James Dong * 670c1bc742181ded4930842b46e9507372f0b1b963James Dong * pDstQuantCoeff - Pointer to the quantized transformed coefficients. 680c1bc742181ded4930842b46e9507372f0b1b963James Dong * 8-byte alignment required. 690c1bc742181ded4930842b46e9507372f0b1b963James Dong * pDstDeQuantCoeff - Pointer to the dequantized transformed coefficients 700c1bc742181ded4930842b46e9507372f0b1b963James Dong * if this parameter is not equal to NULL. 8-byte alignment 710c1bc742181ded4930842b46e9507372f0b1b963James Dong * required. 720c1bc742181ded4930842b46e9507372f0b1b963James Dong * pDCCoeff - Pointer to the unquantized DC coefficient if this parameter 730c1bc742181ded4930842b46e9507372f0b1b963James Dong * is not equal to NULL. 740c1bc742181ded4930842b46e9507372f0b1b963James Dong * 750c1bc742181ded4930842b46e9507372f0b1b963James Dong * Return Value: 760c1bc742181ded4930842b46e9507372f0b1b963James Dong * 770c1bc742181ded4930842b46e9507372f0b1b963James Dong * OMX_Sts_NoErr - no error 780c1bc742181ded4930842b46e9507372f0b1b963James Dong * OMX_Sts_BadArgErr - bad arguments; returned if any of the following 790c1bc742181ded4930842b46e9507372f0b1b963James Dong * conditions are true: 800c1bc742181ded4930842b46e9507372f0b1b963James Dong * - at least one of the following pointers is NULL: 810c1bc742181ded4930842b46e9507372f0b1b963James Dong * pSrcOrg, pSrcPred, pNumCoeff, pDstQuantCoeff, 820c1bc742181ded4930842b46e9507372f0b1b963James Dong * pDstDeQuantCoeff, pDCCoeff 830c1bc742181ded4930842b46e9507372f0b1b963James Dong * - pSrcOrg is not aligned on a 4-byte boundary 840c1bc742181ded4930842b46e9507372f0b1b963James Dong * - pSrcPred is not aligned on a 4-byte boundary 850c1bc742181ded4930842b46e9507372f0b1b963James Dong * - iSrcOrgStep is not a multiple of 4 860c1bc742181ded4930842b46e9507372f0b1b963James Dong * - iSrcPredStep is not a multiple of 4 870c1bc742181ded4930842b46e9507372f0b1b963James Dong * - pDstQuantCoeff or pDstDeQuantCoeff is not aligned on an 8-byte boundary 880c1bc742181ded4930842b46e9507372f0b1b963James Dong * 890c1bc742181ded4930842b46e9507372f0b1b963James Dong */ 900c1bc742181ded4930842b46e9507372f0b1b963James Dong OMXResult omxVCM4P10_SubAndTransformQDQResidual ( 910c1bc742181ded4930842b46e9507372f0b1b963James Dong const OMX_U8* pSrcOrg, 920c1bc742181ded4930842b46e9507372f0b1b963James Dong const OMX_U8* pSrcPred, 930c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_U32 iSrcOrgStep, 940c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_U32 iSrcPredStep, 950c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_S16* pDstQuantCoeff, 960c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_S16* pDstDeQuantCoeff, 970c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_S16* pDCCoeff, 980c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_S8* pNumCoeff, 990c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_U32 nThreshSAD, 1000c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_U32 iQP, 1010c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_U8 bIntra 1020c1bc742181ded4930842b46e9507372f0b1b963James Dong) 1030c1bc742181ded4930842b46e9507372f0b1b963James Dong{ 1040c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_INT i, j; 1050c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_S8 NumCoeff = 0; 1060c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_S16 Buf[16], m[16]; 1070c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_U32 QBits, QPper, QPmod, f; 1080c1bc742181ded4930842b46e9507372f0b1b963James Dong OMX_S32 Value, MF, ThreshDC; 1090c1bc742181ded4930842b46e9507372f0b1b963James Dong 1100c1bc742181ded4930842b46e9507372f0b1b963James Dong /* check for argument error */ 1110c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(pSrcOrg == NULL, OMX_Sts_BadArgErr) 1120c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(pDstDeQuantCoeff == NULL, OMX_Sts_BadArgErr) 1130c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(pNumCoeff == NULL, OMX_Sts_BadArgErr) 1140c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(pDCCoeff == NULL, OMX_Sts_BadArgErr) 1150c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(armNot4ByteAligned(pSrcOrg), OMX_Sts_BadArgErr) 1160c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(pSrcPred == NULL, OMX_Sts_BadArgErr) 1170c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(armNot4ByteAligned(pSrcPred), OMX_Sts_BadArgErr) 1180c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(pDstQuantCoeff == NULL, OMX_Sts_BadArgErr) 1190c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(armNot8ByteAligned(pDstQuantCoeff), OMX_Sts_BadArgErr) 1200c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf((pDstDeQuantCoeff != NULL) && 1210c1bc742181ded4930842b46e9507372f0b1b963James Dong armNot8ByteAligned(pDstDeQuantCoeff), OMX_Sts_BadArgErr) 1220c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf((bIntra != 0) && (bIntra != 1), OMX_Sts_BadArgErr) 1230c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(iQP > 51, OMX_Sts_BadArgErr) 1240c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(iSrcOrgStep == 0, OMX_Sts_BadArgErr) 1250c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(iSrcPredStep == 0, OMX_Sts_BadArgErr) 1260c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(iSrcOrgStep & 3, OMX_Sts_BadArgErr) 1270c1bc742181ded4930842b46e9507372f0b1b963James Dong armRetArgErrIf(iSrcPredStep & 3, OMX_Sts_BadArgErr) 1280c1bc742181ded4930842b46e9507372f0b1b963James Dong 1290c1bc742181ded4930842b46e9507372f0b1b963James Dong /* 1300c1bc742181ded4930842b46e9507372f0b1b963James Dong * Zero-Block Early detection using nThreshSAD param 1310c1bc742181ded4930842b46e9507372f0b1b963James Dong */ 1320c1bc742181ded4930842b46e9507372f0b1b963James Dong 1330c1bc742181ded4930842b46e9507372f0b1b963James Dong QPper = iQP / 6; 1340c1bc742181ded4930842b46e9507372f0b1b963James Dong QPmod = iQP % 6; 1350c1bc742181ded4930842b46e9507372f0b1b963James Dong QBits = 15 + QPper; 1360c1bc742181ded4930842b46e9507372f0b1b963James Dong 1370c1bc742181ded4930842b46e9507372f0b1b963James Dong f = (1 << QBits) / (bIntra ? 3 : 6); 1380c1bc742181ded4930842b46e9507372f0b1b963James Dong 1390c1bc742181ded4930842b46e9507372f0b1b963James Dong /* Do Zero-Block Early detection if enabled */ 1400c1bc742181ded4930842b46e9507372f0b1b963James Dong if (nThreshSAD) 1410c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1420c1bc742181ded4930842b46e9507372f0b1b963James Dong ThreshDC = ((1 << QBits) - f) / armVCM4P10_MFMatrix[QPmod][0]; 1430c1bc742181ded4930842b46e9507372f0b1b963James Dong if (nThreshSAD < ThreshDC) 1440c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1450c1bc742181ded4930842b46e9507372f0b1b963James Dong /* Set block to zero */ 1460c1bc742181ded4930842b46e9507372f0b1b963James Dong if (pDCCoeff != NULL) 1470c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1480c1bc742181ded4930842b46e9507372f0b1b963James Dong *pDCCoeff = 0; 1490c1bc742181ded4930842b46e9507372f0b1b963James Dong } 1500c1bc742181ded4930842b46e9507372f0b1b963James Dong 1510c1bc742181ded4930842b46e9507372f0b1b963James Dong for (j = 0; j < 4; j++) 1520c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1530c1bc742181ded4930842b46e9507372f0b1b963James Dong for (i = 0; i < 4; i++) 1540c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1550c1bc742181ded4930842b46e9507372f0b1b963James Dong pDstQuantCoeff [4 * j + i] = 0; 1560c1bc742181ded4930842b46e9507372f0b1b963James Dong if (pDstDeQuantCoeff != NULL) 1570c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1580c1bc742181ded4930842b46e9507372f0b1b963James Dong pDstDeQuantCoeff [4 * j + i] = 0; 1590c1bc742181ded4930842b46e9507372f0b1b963James Dong } 1600c1bc742181ded4930842b46e9507372f0b1b963James Dong } 1610c1bc742181ded4930842b46e9507372f0b1b963James Dong } 1620c1bc742181ded4930842b46e9507372f0b1b963James Dong 1630c1bc742181ded4930842b46e9507372f0b1b963James Dong if (pNumCoeff != NULL) 1640c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1650c1bc742181ded4930842b46e9507372f0b1b963James Dong *pNumCoeff = 0; 1660c1bc742181ded4930842b46e9507372f0b1b963James Dong } 1670c1bc742181ded4930842b46e9507372f0b1b963James Dong return OMX_Sts_NoErr; 1680c1bc742181ded4930842b46e9507372f0b1b963James Dong } 1690c1bc742181ded4930842b46e9507372f0b1b963James Dong } 1700c1bc742181ded4930842b46e9507372f0b1b963James Dong 1710c1bc742181ded4930842b46e9507372f0b1b963James Dong 1720c1bc742181ded4930842b46e9507372f0b1b963James Dong /* Calculate difference */ 1730c1bc742181ded4930842b46e9507372f0b1b963James Dong for (j = 0; j < 4; j++) 1740c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1750c1bc742181ded4930842b46e9507372f0b1b963James Dong for (i = 0; i < 4; i++) 1760c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1770c1bc742181ded4930842b46e9507372f0b1b963James Dong Buf [j * 4 + i] = 1780c1bc742181ded4930842b46e9507372f0b1b963James Dong pSrcOrg [j * iSrcOrgStep + i] - pSrcPred [j * iSrcPredStep + i]; 1790c1bc742181ded4930842b46e9507372f0b1b963James Dong } 1800c1bc742181ded4930842b46e9507372f0b1b963James Dong } 1810c1bc742181ded4930842b46e9507372f0b1b963James Dong 1820c1bc742181ded4930842b46e9507372f0b1b963James Dong /* Residual Transform */ 1830c1bc742181ded4930842b46e9507372f0b1b963James Dong armVCM4P10_FwdTransformResidual4x4 (m, Buf); 1840c1bc742181ded4930842b46e9507372f0b1b963James Dong 1850c1bc742181ded4930842b46e9507372f0b1b963James Dong if (pDCCoeff != NULL) 1860c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1870c1bc742181ded4930842b46e9507372f0b1b963James Dong /* Copy unquantized DC value into pointer */ 1880c1bc742181ded4930842b46e9507372f0b1b963James Dong *pDCCoeff = m[0]; 1890c1bc742181ded4930842b46e9507372f0b1b963James Dong } 1900c1bc742181ded4930842b46e9507372f0b1b963James Dong 1910c1bc742181ded4930842b46e9507372f0b1b963James Dong /* Quantization */ 1920c1bc742181ded4930842b46e9507372f0b1b963James Dong for (j = 0; j < 4; j++) 1930c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1940c1bc742181ded4930842b46e9507372f0b1b963James Dong for (i = 0; i < 4; i++) 1950c1bc742181ded4930842b46e9507372f0b1b963James Dong { 1960c1bc742181ded4930842b46e9507372f0b1b963James Dong MF = armVCM4P10_MFMatrix[QPmod][armVCM4P10_PosToVCol4x4[j * 4 + i]]; 1970c1bc742181ded4930842b46e9507372f0b1b963James Dong Value = armAbs(m[j * 4 + i]) * MF + f; 1980c1bc742181ded4930842b46e9507372f0b1b963James Dong Value >>= QBits; 1990c1bc742181ded4930842b46e9507372f0b1b963James Dong Value = m[j * 4 + i] < 0 ? -Value : Value; 2000c1bc742181ded4930842b46e9507372f0b1b963James Dong Buf[4 * j + i] = pDstQuantCoeff [4 * j + i] = (OMX_S16)Value; 2010c1bc742181ded4930842b46e9507372f0b1b963James Dong if ((pNumCoeff != NULL) && Value) 2020c1bc742181ded4930842b46e9507372f0b1b963James Dong { 2030c1bc742181ded4930842b46e9507372f0b1b963James Dong NumCoeff++; 2040c1bc742181ded4930842b46e9507372f0b1b963James Dong } 2050c1bc742181ded4930842b46e9507372f0b1b963James Dong } 2060c1bc742181ded4930842b46e9507372f0b1b963James Dong } 2070c1bc742181ded4930842b46e9507372f0b1b963James Dong 2080c1bc742181ded4930842b46e9507372f0b1b963James Dong /* Output number of non-zero Coeffs */ 2090c1bc742181ded4930842b46e9507372f0b1b963James Dong if (pNumCoeff != NULL) 2100c1bc742181ded4930842b46e9507372f0b1b963James Dong { 2110c1bc742181ded4930842b46e9507372f0b1b963James Dong *pNumCoeff = NumCoeff; 2120c1bc742181ded4930842b46e9507372f0b1b963James Dong } 2130c1bc742181ded4930842b46e9507372f0b1b963James Dong 2140c1bc742181ded4930842b46e9507372f0b1b963James Dong /* Residual Inv Transform */ 2150c1bc742181ded4930842b46e9507372f0b1b963James Dong if (pDstDeQuantCoeff != NULL) 2160c1bc742181ded4930842b46e9507372f0b1b963James Dong { 2170c1bc742181ded4930842b46e9507372f0b1b963James Dong /* Re Scale */ 2180c1bc742181ded4930842b46e9507372f0b1b963James Dong for (j = 0; j < 4; j++) 2190c1bc742181ded4930842b46e9507372f0b1b963James Dong { 2200c1bc742181ded4930842b46e9507372f0b1b963James Dong for (i = 0; i < 4; i++) 2210c1bc742181ded4930842b46e9507372f0b1b963James Dong { 2220c1bc742181ded4930842b46e9507372f0b1b963James Dong m [j * 4 + i] = Buf [j * 4 + i] * (1 << QPper) * 2230c1bc742181ded4930842b46e9507372f0b1b963James Dong armVCM4P10_VMatrix[QPmod][armVCM4P10_PosToVCol4x4[j * 4 + i]]; 2240c1bc742181ded4930842b46e9507372f0b1b963James Dong } 2250c1bc742181ded4930842b46e9507372f0b1b963James Dong } 2260c1bc742181ded4930842b46e9507372f0b1b963James Dong armVCM4P10_TransformResidual4x4 (pDstDeQuantCoeff, m); 2270c1bc742181ded4930842b46e9507372f0b1b963James Dong } 2280c1bc742181ded4930842b46e9507372f0b1b963James Dong 2290c1bc742181ded4930842b46e9507372f0b1b963James Dong return OMX_Sts_NoErr; 2300c1bc742181ded4930842b46e9507372f0b1b963James Dong} 2310c1bc742181ded4930842b46e9507372f0b1b963James Dong 2320c1bc742181ded4930842b46e9507372f0b1b963James Dong/***************************************************************************** 2330c1bc742181ded4930842b46e9507372f0b1b963James Dong * END OF FILE 2340c1bc742181ded4930842b46e9507372f0b1b963James Dong *****************************************************************************/ 2350c1bc742181ded4930842b46e9507372f0b1b963James Dong 236