diff options
Diffstat (limited to 'Src/mpeg4dec')
-rw-r--r-- | Src/mpeg4dec/mp4dec.h | 708 | ||||
-rw-r--r-- | Src/mpeg4dec/mp4decvop.c | 1983 | ||||
-rw-r--r-- | Src/mpeg4dec/mp4decvopb.c | 831 | ||||
-rw-r--r-- | Src/mpeg4dec/mp4decvopi.c | 408 | ||||
-rw-r--r-- | Src/mpeg4dec/mp4decvopp.c | 1079 | ||||
-rw-r--r-- | Src/mpeg4dec/mp4decvops.c | 655 | ||||
-rw-r--r-- | Src/mpeg4dec/mp4def.h | 975 | ||||
-rw-r--r-- | Src/mpeg4dec/mp4parse.c | 1109 | ||||
-rw-r--r-- | Src/mpeg4dec/mp4stream.c | 326 | ||||
-rw-r--r-- | Src/mpeg4dec/mp4tbl.c | 153 | ||||
-rw-r--r-- | Src/mpeg4dec/mpeg4dec.sln | 20 | ||||
-rw-r--r-- | Src/mpeg4dec/mpeg4dec.vcproj | 214 | ||||
-rw-r--r-- | Src/mpeg4dec/mpeg4vid_api.c | 661 | ||||
-rw-r--r-- | Src/mpeg4dec/mpeg4vid_api.h | 54 |
14 files changed, 9176 insertions, 0 deletions
diff --git a/Src/mpeg4dec/mp4dec.h b/Src/mpeg4dec/mp4dec.h new file mode 100644 index 00000000..9959e1de --- /dev/null +++ b/Src/mpeg4dec/mp4dec.h @@ -0,0 +1,708 @@ +/* /////////////////////////////////////////////////////////////////////// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 2001-2007 Intel Corporation. All Rights Reserved. +// +// Description: MPEG-4 header. +// +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +//#ifdef __INTEL_COMPILER +//#include <emmintrin.h> +//#define USE_INTRINSIC_EMM +//#else +#undef USE_INTRINSIC_XMM +#undef USE_INTRINSIC_EMM +//#endif + +#define USE_TABLE_INTRA_DIV + +#define mp4_Div2(a) ((a) >= 0 ? ((a) >> 1) : (((a)+1) >> 1)) +#define mp4_Div2Round(a) (((a) >> 1) | ((a) & 1)) +#define mp4_DivRoundInf(a, b) ((((a) + (((a) >= 0) ? ((b) >> 1) : -((b) >> 1))) / (b))) +#ifndef USE_TABLE_INTRA_DIV +#define mp4_DivIntraDC(a, b) (((a) + ((b) >> 1)) / (b)) +#define mp4_DivIntraAC(a, b) mp4_DivRoundInf(a, b) +#else +// tested on (-2047..2047) // (1..46) +#define mp4_DivIntraDC(a, b) (((a) * mp4_DivIntraDivisor[b] + (1 << 17)) >> 18) +#define mp4_DivIntraAC(a, b) mp4_DivIntraDC(a, b) +#endif + +__INLINE int16_t mp4_Median(int16_t a, int16_t b, int16_t c) +{ + if (a > b) { + int16_t t = a; a = b; b = t; + } + return (int16_t)((b <= c) ? b : (c >= a) ? c : a); +} + +__INLINE void mp4_ComputeChromaMV(const IppMotionVector *mvLuma, IppMotionVector *mvChroma) +{ + mvChroma->dx = (int16_t)mp4_Div2Round(mvLuma->dx); + mvChroma->dy = (int16_t)mp4_Div2Round(mvLuma->dy); +} + +__INLINE void mp4_ComputeChromaMVQ(const IppMotionVector *mvLuma, IppMotionVector *mvChroma) +{ + int32_t dx, dy; + + dx = mp4_Div2(mvLuma->dx); + dy = mp4_Div2(mvLuma->dy); + mvChroma->dx = (int16_t)mp4_Div2Round(dx); + mvChroma->dy = (int16_t)mp4_Div2Round(dy); +} + +__INLINE void mp4_ComputeChroma4MV(const IppMotionVector mvLuma[4], IppMotionVector *mvChroma) +{ + int32_t dx, dy, cdx, cdy, adx, ady; + + dx = mvLuma[0].dx + mvLuma[1].dx + mvLuma[2].dx + mvLuma[3].dx; + dy = mvLuma[0].dy + mvLuma[1].dy + mvLuma[2].dy + mvLuma[3].dy; + adx = abs(dx); + ady = abs(dy); + cdx = mp4_cCbCrMvRound16[adx & 15] + (adx >> 4) * 2; + cdy = mp4_cCbCrMvRound16[ady & 15] + (ady >> 4) * 2; + mvChroma->dx = (int16_t)((dx >= 0) ? cdx : -cdx); + mvChroma->dy = (int16_t)((dy >= 0) ? cdy : -cdy); +} + +__INLINE void mp4_ComputeChroma4MVQ(const IppMotionVector mvLuma[4], IppMotionVector *mvChroma) +{ + int32_t dx, dy, cdx, cdy, adx, ady; + + dx = mp4_Div2(mvLuma[0].dx) + mp4_Div2(mvLuma[1].dx) + mp4_Div2(mvLuma[2].dx) + mp4_Div2(mvLuma[3].dx); + dy = mp4_Div2(mvLuma[0].dy) + mp4_Div2(mvLuma[1].dy) + mp4_Div2(mvLuma[2].dy) + mp4_Div2(mvLuma[3].dy); + adx = abs(dx); + ady = abs(dy); + cdx = mp4_cCbCrMvRound16[adx & 15] + (adx >> 4) * 2; + cdy = mp4_cCbCrMvRound16[ady & 15] + (ady >> 4) * 2; + mvChroma->dx = (int16_t)((dx >= 0) ? cdx : -cdx); + mvChroma->dy = (int16_t)((dy >= 0) ? cdy : -cdy); +} + +#define limitMV(dx, xmin, xmax, mvd) \ +{ \ + if ((dx) < (xmin)) \ + mvd = (int16_t)(xmin); \ + else if ((dx) >= (xmax)) \ + mvd = (int16_t)(xmax); \ + else \ + mvd = (int16_t)(dx); \ +} + +__INLINE void mp4_LimitMV(const IppMotionVector *pSrcMV, IppMotionVector *pDstMV, const IppiRect *limitRect, int32_t x, int32_t y, int32_t size) +{ + limitMV(pSrcMV->dx, (limitRect->x - x) << 1, (limitRect->x - x + limitRect->width - size) << 1, pDstMV->dx); + limitMV(pSrcMV->dy, (limitRect->y - y) << 1, (limitRect->y - y + limitRect->height - size) << 1, pDstMV->dy); +} + +__INLINE void mp4_LimitMVQ(const IppMotionVector *pSrcMV, IppMotionVector *pDstMV, const IppiRect *limitRect, int32_t x, int32_t y, int32_t size) +{ + limitMV(pSrcMV->dx, (limitRect->x - x) << 2, (limitRect->x - x + limitRect->width - size) << 2, pDstMV->dx); + limitMV(pSrcMV->dy, (limitRect->y - y) << 2, (limitRect->y - y + limitRect->height - size) << 2, pDstMV->dy); +} + +__INLINE void mp4_Limit4MV(const IppMotionVector *pSrcMV, IppMotionVector *pDstMV, const IppiRect *limitRect, int32_t x, int32_t y, int32_t size) +{ + mp4_LimitMV(&pSrcMV[0], &pDstMV[0], limitRect, x , y, size); + mp4_LimitMV(&pSrcMV[1], &pDstMV[1], limitRect, x + size, y, size); + mp4_LimitMV(&pSrcMV[2], &pDstMV[2], limitRect, x , y + size, size); + mp4_LimitMV(&pSrcMV[3], &pDstMV[3], limitRect, x + size, y + size, size); +} + +__INLINE void mp4_Limit4MVQ(const IppMotionVector *pSrcMV, IppMotionVector *pDstMV, const IppiRect *limitRect, int32_t x, int32_t y, int32_t size) +{ + mp4_LimitMVQ(&pSrcMV[0], &pDstMV[0], limitRect, x , y, size); + mp4_LimitMVQ(&pSrcMV[1], &pDstMV[1], limitRect, x + size, y, size); + mp4_LimitMVQ(&pSrcMV[2], &pDstMV[2], limitRect, x , y + size, size); + mp4_LimitMVQ(&pSrcMV[3], &pDstMV[3], limitRect, x + size, y + size, size); +} + +__INLINE void mp4_LimitFMV(const IppMotionVector *pSrcMV, IppMotionVector *pDstMV, const IppiRect *limitRect, int32_t x, int32_t y, int32_t size) +{ + limitMV(pSrcMV->dx, (limitRect->x - x) << 1, (limitRect->x - x + limitRect->width - size) << 1, pDstMV->dx); + limitMV(pSrcMV->dy << 1, (limitRect->y - y) << 1, (limitRect->y - y + limitRect->height - size) << 1, pDstMV->dy); + pDstMV->dy >>= 1; +} + +__INLINE void mp4_LimitFMVQ(const IppMotionVector *pSrcMV, IppMotionVector *pDstMV, const IppiRect *limitRect, int32_t x, int32_t y, int32_t size) +{ + limitMV(pSrcMV->dx, (limitRect->x - x) << 2, (limitRect->x - x + limitRect->width - size) << 2, pDstMV->dx); + limitMV(pSrcMV->dy << 1, (limitRect->y - y) << 2, (limitRect->y - y + limitRect->height - size) << 2, pDstMV->dy); + pDstMV->dy >>= 1; +} + +#define MP4_MV_OFF_HP(dx, dy, step) \ + (((dx) >> 1) + (step) * ((dy) >> 1)) + +#define MP4_MV_ACC_HP(dx, dy) \ + ((((dy) & 1) << 1) + ((dx) & 1)) + +#define MP4_MV_OFF_QP(dx, dy, step) \ + (((dx) >> 2) + (step) * ((dy) >> 2)) + +#define MP4_MV_ACC_QP(dx, dy) \ + ((((dy) & 3) << 2) + ((dx) & 3)) + +#define mp4_Copy8x4HP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \ + ippiCopy8x4HP_8u_C1R(pSrc + MP4_MV_OFF_HP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, MP4_MV_ACC_HP((mv)->dx, (mv)->dy), rc) + +#define mp4_Copy8x8HP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \ + ippiCopy8x8HP_8u_C1R(pSrc + MP4_MV_OFF_HP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, MP4_MV_ACC_HP((mv)->dx, (mv)->dy), rc) + +#define mp4_Copy16x8HP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \ + ippiCopy16x8HP_8u_C1R(pSrc + MP4_MV_OFF_HP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, MP4_MV_ACC_HP((mv)->dx, (mv)->dy), rc) + +#define mp4_Copy16x16HP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \ + ippiCopy16x16HP_8u_C1R(pSrc + MP4_MV_OFF_HP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, MP4_MV_ACC_HP((mv)->dx, (mv)->dy), rc) + +#define mp4_Copy8x8QP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \ + ippiCopy8x8QP_MPEG4_8u_C1R(pSrc + MP4_MV_OFF_QP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, MP4_MV_ACC_QP((mv)->dx, (mv)->dy), rc) + +#define mp4_Copy16x8QP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \ + ippiCopy16x8QP_MPEG4_8u_C1R(pSrc + MP4_MV_OFF_QP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, MP4_MV_ACC_QP((mv)->dx, (mv)->dy), rc) + +#define mp4_Copy16x16QP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \ + ippiCopy16x16QP_MPEG4_8u_C1R(pSrc + MP4_MV_OFF_QP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, MP4_MV_ACC_QP((mv)->dx, (mv)->dy), rc) + +#define mp4_Add8x8HP_16s8u(pSrc, srcStep, pResid, pDst, dstStep, mv, rc) \ + ippiAdd8x8HP_16s8u_C1RS(pResid, 16, pSrc + MP4_MV_OFF_HP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, MP4_MV_ACC_HP((mv)->dx, (mv)->dy), rc) + +#define mp4_Add8x8_16s8u(pSrcDst, pResid, srcDstStep) \ + ippiAdd8x8_16s8u_C1IRS(pResid, 16, pSrcDst, srcDstStep) + + +#define mp4_UpdateQuant(pInfo, quant) \ +{ \ + quant += mp4_dquant[mp4_GetBits9(pInfo, 2)]; \ + mp4_CLIP(quant, 1, (1 << pInfo->VisualObject.VideoObject.quant_precision) - 1); \ +} + +#define mp4_UpdateQuant_B(pInfo, quant) \ +if (mp4_GetBit(pInfo) != 0) { \ + quant += (mp4_GetBit(pInfo) == 0) ? -2 : 2; \ + mp4_CLIP(quant, 1, (1 << pInfo->VisualObject.VideoObject.quant_precision) - 1); \ +} + +__INLINE void mp4_Set8x8_8u(uint8_t *p, int32_t step, uint8_t v) +{ +#if defined(USE_INTRINSIC_XMM) || defined(USE_INTRINSIC_EMM) + __m64 _p_v = _mm_set1_pi8(v); + *(__m64*)p = _p_v; + *(__m64*)(p+step) = _p_v; + p += 2 * step; + *(__m64*)p = _p_v; + *(__m64*)(p+step) = _p_v; + p += 2 * step; + *(__m64*)p = _p_v; + *(__m64*)(p+step) = _p_v; + p += 2 * step; + *(__m64*)p = _p_v; + *(__m64*)(p+step) = _p_v; + _mm_empty(); +#else + uint32_t val; + + val = v + (v << 8); + val += val << 16; + ((uint32_t*)p)[0] = val; ((uint32_t*)p)[1] = val; p += step; + ((uint32_t*)p)[0] = val; ((uint32_t*)p)[1] = val; p += step; + ((uint32_t*)p)[0] = val; ((uint32_t*)p)[1] = val; p += step; + ((uint32_t*)p)[0] = val; ((uint32_t*)p)[1] = val; p += step; + ((uint32_t*)p)[0] = val; ((uint32_t*)p)[1] = val; p += step; + ((uint32_t*)p)[0] = val; ((uint32_t*)p)[1] = val; p += step; + ((uint32_t*)p)[0] = val; ((uint32_t*)p)[1] = val; p += step; + ((uint32_t*)p)[0] = val; ((uint32_t*)p)[1] = val; +#endif +} + +__INLINE void mp4_Set16x16_8u(uint8_t *p, int32_t step, uint8_t val) +{ + int32_t i, j; + + for (i = 0; i < 16; i ++) { + for (j = 0; j < 16; j ++) + p[j] = val; + p += step; + } +} + +#if defined(USE_INTRINSIC_XMM) || defined(USE_INTRINSIC_EMM) + +#define mp4_Zero4MV(mv) \ + memset(mv, 0, 4 * sizeof(IppMotionVector)); + +#if defined(USE_INTRINSIC_XMM) + +#define mp4_Zero64_16s(pDst) \ +{ \ + __m64 _p_zero = _mm_setzero_si64(); \ + ((__m64*)(pDst))[0] = _p_zero; \ + ((__m64*)(pDst))[1] = _p_zero; \ + ((__m64*)(pDst))[2] = _p_zero; \ + ((__m64*)(pDst))[3] = _p_zero; \ + ((__m64*)(pDst))[4] = _p_zero; \ + ((__m64*)(pDst))[5] = _p_zero; \ + ((__m64*)(pDst))[6] = _p_zero; \ + ((__m64*)(pDst))[7] = _p_zero; \ + ((__m64*)(pDst))[8] = _p_zero; \ + ((__m64*)(pDst))[9] = _p_zero; \ + ((__m64*)(pDst))[10] = _p_zero; \ + ((__m64*)(pDst))[11] = _p_zero; \ + ((__m64*)(pDst))[12] = _p_zero; \ + ((__m64*)(pDst))[13] = _p_zero; \ + ((__m64*)(pDst))[14] = _p_zero; \ + ((__m64*)(pDst))[15] = _p_zero; \ + _m_empty(); \ +} + +#define mp4_Set64_16s(val, pDst) \ +{ \ + __m64 _p_val = _mm_set1_pi16((int16_t)(val)); \ + ((__m64*)(pDst))[0] = _p_val; \ + ((__m64*)(pDst))[1] = _p_val; \ + ((__m64*)(pDst))[2] = _p_val; \ + ((__m64*)(pDst))[3] = _p_val; \ + ((__m64*)(pDst))[4] = _p_val; \ + ((__m64*)(pDst))[5] = _p_val; \ + ((__m64*)(pDst))[6] = _p_val; \ + ((__m64*)(pDst))[7] = _p_val; \ + ((__m64*)(pDst))[8] = _p_val; \ + ((__m64*)(pDst))[9] = _p_val; \ + ((__m64*)(pDst))[10] = _p_val; \ + ((__m64*)(pDst))[11] = _p_val; \ + ((__m64*)(pDst))[12] = _p_val; \ + ((__m64*)(pDst))[13] = _p_val; \ + ((__m64*)(pDst))[14] = _p_val; \ + ((__m64*)(pDst))[15] = _p_val; \ + _m_empty(); \ +} + +#elif defined(USE_INTRINSIC_EMM) + +#define mp4_Zero64_16s(pDst) \ +{ \ + __m128i _p_val = _mm_setzero_si128(); \ + ((__m128i*)(pDst))[0] = _p_val; \ + ((__m128i*)(pDst))[1] = _p_val; \ + ((__m128i*)(pDst))[2] = _p_val; \ + ((__m128i*)(pDst))[3] = _p_val; \ + ((__m128i*)(pDst))[4] = _p_val; \ + ((__m128i*)(pDst))[5] = _p_val; \ + ((__m128i*)(pDst))[6] = _p_val; \ + ((__m128i*)(pDst))[7] = _p_val; \ +} + +#define mp4_Set64_16s(val, pDst) \ +{ \ + __m128i _p_val = _mm_set1_epi16((int16_t)(val)); \ + ((__m128i*)(pDst))[0] = _p_val; \ + ((__m128i*)(pDst))[1] = _p_val; \ + ((__m128i*)(pDst))[2] = _p_val; \ + ((__m128i*)(pDst))[3] = _p_val; \ + ((__m128i*)(pDst))[4] = _p_val; \ + ((__m128i*)(pDst))[5] = _p_val; \ + ((__m128i*)(pDst))[6] = _p_val; \ + ((__m128i*)(pDst))[7] = _p_val; \ +} + +#endif + +#else + +#define mp4_Zero4MV(mv) \ + (mv)[0].dx = (mv)[0].dy = (mv)[1].dx = (mv)[1].dy = (mv)[2].dx = (mv)[2].dy = (mv)[3].dx = (mv)[3].dy = 0 + +#define mp4_Zero64_16s(pDst) \ +{ \ + int32_t i; \ + for (i = 0; i < 32; i += 8) { \ + ((uint32_t*)(pDst))[i] = 0; \ + ((uint32_t*)(pDst))[i+1] = 0; \ + ((uint32_t*)(pDst))[i+2] = 0; \ + ((uint32_t*)(pDst))[i+3] = 0; \ + ((uint32_t*)(pDst))[i+4] = 0; \ + ((uint32_t*)(pDst))[i+5] = 0; \ + ((uint32_t*)(pDst))[i+6] = 0; \ + ((uint32_t*)(pDst))[i+7] = 0; \ + } \ +} + +#define mp4_Set64_16s(val, pDst) \ +{ \ + int32_t i; \ + uint32_t v; \ + v = ((val) << 16) + (Ipp16u)(val); \ + for (i = 0; i < 32; i += 8) { \ + ((uint32_t*)(pDst))[i] = v; \ + ((uint32_t*)(pDst))[i+1] = v; \ + ((uint32_t*)(pDst))[i+2] = v; \ + ((uint32_t*)(pDst))[i+3] = v; \ + ((uint32_t*)(pDst))[i+4] = v; \ + ((uint32_t*)(pDst))[i+5] = v; \ + ((uint32_t*)(pDst))[i+6] = v; \ + ((uint32_t*)(pDst))[i+7] = v; \ + } \ +} + +#endif + +#define mp4_MC_HP(pat, pRef, stepRef, pCur, stepCur, coeffMB, mv, rc) \ +{ \ + if (pat) { \ + mp4_Add8x8HP_16s8u(pRef, stepRef, coeffMB, pCur, stepCur, mv, rc); \ + } else { \ + mp4_Copy8x8HP_8u(pRef, stepRef, pCur, stepCur, mv, rc); \ + } \ +} + +#define mp4_AddResidual(pat, pc, stepc, coeffMB) \ +{ \ + if (pat) { \ + mp4_Add8x8_16s8u(pc, coeffMB, stepc); \ + } \ +} + +#define mp4_DCTInvCoeffsIntraMB(coeffMB, lnz, pFc, stepFc) \ +{ \ + int32_t i; \ + for (i = 0; i < 6; i ++) { \ + if (lnz[i] > 0) \ + ippiDCT8x8Inv_16s8u_C1R(&coeffMB[i*64], pFc[i], stepFc[i]); \ + else { \ + int k = (coeffMB[i*64] + 4) >> 3; \ + mp4_CLIP(k, 0, 255); \ + mp4_Set8x8_8u(pFc[i], stepFc[i], (uint8_t)k); \ + } \ + } \ +} + +#define mp4_ReconstructCoeffsIntraMB_SVH(pInfo, coeffMB, lnz, pat, quant, err) \ +{ \ + int32_t i, pm = 32; \ + for (i = 0; i < 6; i ++) { \ + if (ippiReconstructCoeffsIntra_H263_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeffMB+i*64, &lnz[i], pat & pm, quant, 0, IPPVC_SCAN_ZIGZAG, 0) != ippStsNoErr) { \ + mp4_Error("Error: decoding coefficients of Intra block"); \ + goto err; \ + } \ + if (pat & pm) { \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTRA_AC); \ + } else { \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTRA_DC); \ + } \ + pm >>= 1; \ + } \ +} + +#define mp4_ReconstructCoeffsInterMB_SVH(pInfo, coeffMB, lnz, pat, quant, err) \ +{ \ + if (pat) { \ + int32_t i, pm = 32; \ + for (i = 0; i < 6; i ++) { \ + if (pat & pm) { \ + if (ippiReconstructCoeffsInter_H263_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeffMB+i*64, &lnz[i], quant, 0) != ippStsNoErr) { \ + mp4_Error("Error: decoding coefficients of Inter block"); \ + goto err; \ + } \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_C); \ + } else { \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); \ + } \ + pm >>= 1; \ + } \ + } else { \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); \ + } \ +} + +#define mp4_DCTInvCoeffsInterMB_SVH(coeffMB, lastNZ, pat) \ +if (pat) { \ + int32_t i, lnz, pm = 32; \ + int16_t *coeff = coeffMB; \ + for (i = 0; i < 6; i ++) { \ + if ((pat) & pm) { \ + lnz = lastNZ[i]; \ + if (lnz != 0) { \ + if ((lnz <= 4) && (coeff[16] == 0)) \ + ippiDCT8x8Inv_2x2_16s_C1I(coeff); \ + else if ((lnz <= 13) && (coeff[32] == 0)) \ + ippiDCT8x8Inv_4x4_16s_C1I(coeff); \ + else \ + ippiDCT8x8Inv_16s_C1I(coeff); \ + } else \ + mp4_Set64_16s((int16_t)((coeff[0] + 4) >> 3), coeff); \ + } \ + pm >>= 1; \ + coeff += 64; \ + } \ +} + +#define mp4_DecodeMCInterBlock_SVH(pInfo, quant, pat, pRef, pCur, step, coeffMB, mv, err) \ +{ \ + if (pat) { \ + int32_t lnz; \ + if (ippiReconstructCoeffsInter_H263_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeffMB, &lnz, quant, 0) != ippStsNoErr) { \ + mp4_Error("Error: decoding coefficients of Inter block"); \ + goto err; \ + } \ + if (lnz != 0) { \ + if ((lnz <= 4) && (coeffMB[16] == 0)) \ + ippiDCT8x8Inv_2x2_16s_C1I(coeffMB); \ + else if ((lnz <= 13) && (coeffMB[32] == 0)) \ + ippiDCT8x8Inv_4x4_16s_C1I(coeffMB); \ + else \ + ippiDCT8x8Inv_16s_C1I(coeffMB); \ + } else { \ + mp4_Set64_16s((int16_t)((coeffMB[0] + 4) >> 3), coeffMB); \ + } \ + mp4_Add8x8HP_16s8u(pRef, step, coeffMB, pCur, step, mv, 0); \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_C); \ + } else { \ + mp4_Copy8x8HP_8u(pRef, step, pCur, step, mv, 0); \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); \ + } \ +} + +// reset Intra prediction buffer on new Video_packet +#define mp4_ResetIntraPredBuffer(pInfo) \ +{ \ + mp4_IntraPredBlock *b = pInfo->VisualObject.VideoObject.IntraPredBuff.dcB; \ + int32_t i; \ + b[3].dct_dc = b[4].dct_dc = b[5].dct_dc = -1; \ + b = pInfo->VisualObject.VideoObject.IntraPredBuff.block; \ + for (i = 0; i <= pInfo->VisualObject.VideoObject.MacroBlockPerRow; i ++) { \ + b[i*6+0].dct_dc = b[i*6+1].dct_dc = b[i*6+2].dct_dc = b[i*6+3].dct_dc = b[i*6+4].dct_dc = b[i*6+5].dct_dc = -1; \ + } \ +} + +// reset B-prediction blocks on new row +#define mp4_ResetIntraPredBblock(pInfo) \ +{ \ + pInfo->VisualObject.VideoObject.IntraPredBuff.dcB[3].dct_dc = \ + pInfo->VisualObject.VideoObject.IntraPredBuff.dcB[4].dct_dc = \ + pInfo->VisualObject.VideoObject.IntraPredBuff.dcB[5].dct_dc = -1; \ +} + +// mark current MB as invalid for Intra prediction and rotate buffer +#define mp4_UpdateIntraPredBuffInvalid(pInfo, colNum) \ +{ \ + mp4_IntraPredBlock *b = &pInfo->VisualObject.VideoObject.IntraPredBuff.block[colNum*6+6]; \ + pInfo->VisualObject.VideoObject.IntraPredBuff.dcB[3].dct_dc = b[3].dct_dc; \ + pInfo->VisualObject.VideoObject.IntraPredBuff.dcB[4].dct_dc = b[4].dct_dc; \ + pInfo->VisualObject.VideoObject.IntraPredBuff.dcB[5].dct_dc = b[5].dct_dc; \ + b[0].dct_dc = b[1].dct_dc = b[2].dct_dc = b[3].dct_dc = b[4].dct_dc = b[5].dct_dc = -1; \ + /* pInfo->VisualObject.VideoObject.IntraPredBuff.quant[colNum+1] = (uint8_t)quant; */ \ +} + + +/* 2x2 and 4x4 DCT decision suitable for Classical Zigzag Scan only */ +#define mp4_DecodeMCBlockInter_MPEG4(pat, pr, stepr, pc, stepc, mv, rt, err) \ +{ \ + if (pat) { \ + int32_t lnz; \ + if (ippiReconstructCoeffsInter_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeffMB, &lnz, rvlc, scan, pInfo->VisualObject.VideoObject.QuantInvInterSpec, quant) != ippStsNoErr) { \ + mp4_Error("Error: decoding coefficients of Inter block"); \ + goto err; \ + } \ + if (pInfo->VisualObject.VideoObject.quant_type == 0 || (coeffMB[63] == 0)) { \ + if (lnz != 0) { \ + if ((lnz <= 4) && (coeffMB[16] == 0)) \ + ippiDCT8x8Inv_2x2_16s_C1I(coeffMB); \ + else if ((lnz <= 13) && (coeffMB[32] == 0)) \ + ippiDCT8x8Inv_4x4_16s_C1I(coeffMB); \ + else \ + ippiDCT8x8Inv_16s_C1I(coeffMB); \ + } else { \ + mp4_Set64_16s((int16_t)((coeffMB[0] + 4) >> 3), coeffMB); \ + } \ + } else { \ + ippiDCT8x8Inv_16s_C1I(coeffMB); \ + } \ + mp4_Add8x8HP_16s8u(pr, stepr, coeffMB, pc, stepc, &mv, rt); \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_C); \ + } else { \ + mp4_Copy8x8HP_8u(pr, stepr, pc, stepc, &mv, rt); \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); \ + } \ +} + +/* 2x2 and 4x4 DCT decision suitable for Classical Zigzag Scan only */ +#define mp4_DecodeReconBlockInter_MPEG4(pat, pc, stepc, err) \ +{ \ + if (pat) { \ + int32_t lnz; \ + if (ippiReconstructCoeffsInter_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeffMB, &lnz, rvlc, scan, pInfo->VisualObject.VideoObject.QuantInvInterSpec, quant) != ippStsNoErr) { \ + mp4_Error("Error: decoding coefficients of Inter block"); \ + goto err; \ + } \ + if (pInfo->VisualObject.VideoObject.quant_type == 0 || (coeffMB[63] == 0)) { \ + if (lnz != 0) { \ + if ((lnz <= 4) && (coeffMB[16] == 0)) \ + ippiDCT8x8Inv_2x2_16s_C1I(coeffMB); \ + else if ((lnz <= 13) && (coeffMB[32] == 0)) \ + ippiDCT8x8Inv_4x4_16s_C1I(coeffMB); \ + else \ + ippiDCT8x8Inv_16s_C1I(coeffMB); \ + } else { \ + mp4_Set64_16s((int16_t)((coeffMB[0] + 4) >> 3), coeffMB); \ + } \ + } else { \ + ippiDCT8x8Inv_16s_C1I(coeffMB); \ + } \ + mp4_Add8x8_16s8u(pc, coeffMB, stepc); \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_C); \ + } else { \ + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); \ + } \ +} + +__INLINE int32_t mp4_GetMacroBlockNumberSize(int32_t nmb) +{ + int32_t nb = 0; + nmb --; + do { + nmb >>= 1; + nb ++; + } while (nmb); + return nb; +} + +__INLINE int32_t mp4_GetConvRatio(mp4_Info* pInfo) +{ + if (mp4_GetBit(pInfo) == 1) + return 0; + else + return (mp4_GetBit(pInfo) == 0 ? 2 : 4); +} + +// decode cbpy for Inter nontransparent MB +__INLINE mp4_Status mp4_DecodeCBPY_P(mp4_Info* pInfo, int32_t *yPattern, int32_t mbType) +{ + uint32_t code; + + code = mp4_ShowBits9(pInfo, 6); + if (mbType < IPPVC_MBTYPE_INTRA) + *yPattern = 15 - mp4_cbpy4[code].code; + else + *yPattern = mp4_cbpy4[code].code; + if (mp4_cbpy4[code].len == 255) { + mp4_Error("Error: decoding CBPY"); + return MP4_STATUS_ERROR; + } else { + mp4_FlushBits(pInfo, mp4_cbpy4[code].len); + return MP4_STATUS_OK; + } +} + +// decode cbpy for Intra nontransparent MB + +__INLINE mp4_Status mp4_DecodeCBPY_I(mp4_Info* pInfo, int32_t *yPattern) +{ + uint32_t code; + + code = mp4_ShowBits9(pInfo, 6); + *yPattern = mp4_cbpy4[code].code; + if (mp4_cbpy4[code].len == 255) { + mp4_Error("Error: decoding CBPY"); + return MP4_STATUS_ERROR; + } else { + mp4_FlushBits(pInfo, mp4_cbpy4[code].len); + return MP4_STATUS_OK; + } +} + +extern mp4_Status mp4_DecodeMVD(mp4_Info *pInfo, int32_t *mvdx, int32_t *mvdy, int32_t fcode); +extern mp4_Status mp4_DecodeMV(mp4_Info *pInfo, IppMotionVector *mv, int32_t fcode); +extern mp4_Status mp4_Decode4MV(mp4_Info *pInfo, IppMotionVector *mv, int32_t fcode); +extern mp4_Status mp4_DecodeMV_Direct(mp4_Info *pInfo, IppMotionVector mvC[4], IppMotionVector mvForw[4], IppMotionVector mvBack[4], int32_t TRB, int32_t TRD, int32_t modb, int32_t comb_type); +extern mp4_Status mp4_DecodeMV_DirectField(mp4_Info *pInfo, int32_t mb_ftfr, int32_t mb_fbfr, IppMotionVector *mvTop, IppMotionVector *mvBottom, IppMotionVector *mvForwTop, IppMotionVector *mvForwBottom, IppMotionVector *mvBackTop, IppMotionVector *mvBackBottom, int32_t TRB, int32_t TRD, int32_t modb); +extern mp4_Status mp4_DecodeIntraMB_SVH(mp4_Info *pInfo, int32_t pat, int32_t quant, uint8_t *pR[], int32_t stepR[]); +extern mp4_Status mp4_DecodeIntraMB_DP(mp4_Info *pInfo, int16_t dct_dc[], int32_t x, int32_t pat, int32_t quant, int32_t dcVLC, int32_t ac_pred_flag, uint8_t *pR[], int32_t stepR[]); +extern mp4_Status mp4_DecodeIntraMB(mp4_Info *pInfo, int32_t x, int32_t pat, int32_t quant, int32_t dcVLC, int32_t ac_pred_flag, uint8_t *pR[], int32_t stepR[]); +extern mp4_Status mp4_DecodeInterMB_SVH(mp4_Info *pInfo, int16_t *coeffMB, int32_t quant, int32_t pat); +extern mp4_Status mp4_DecodeInterMB(mp4_Info *pInfo, int16_t *coeffMB, int32_t quant, int32_t pat, int32_t scan); +extern mp4_Status mp4_ReconstructCoeffsIntraMB(mp4_Info *pInfo, int32_t x, int32_t pat, int32_t quant, int32_t dcVLC, int32_t ac_pred_flag, int16_t *coeff, int32_t lnz[]); +extern mp4_Status mp4_DecodeMCBPC_P(mp4_Info* pInfo, int32_t *mbType, int32_t *mbPattern, int32_t stat); +extern mp4_Status mp4_PredictDecode1MV(mp4_Info *pInfo, mp4_MacroBlock *MBcurr, int32_t y, int32_t x); +extern mp4_Status mp4_PredictDecode4MV(mp4_Info *pInfo, mp4_MacroBlock *MBcurr, int32_t y, int32_t x); +extern mp4_Status mp4_PredictDecodeFMV(mp4_Info *pInfo, mp4_MacroBlock *MBcurr, int32_t y, int32_t x, IppMotionVector *mvT, IppMotionVector *mvB); +extern mp4_Status mp4_DecodeVideoObjectPlane(mp4_Info* pInfo); +extern mp4_Status mp4_DecodeVOP_I(mp4_Info* pInfo); +extern mp4_Status mp4_DecodeVOP_P(mp4_Info* pInfo); +extern mp4_Status mp4_DecodeVOP_B(mp4_Info* pInfo); +extern mp4_Status mp4_DecodeVOP_S(mp4_Info* pInfo); +extern mp4_Status mp4_DecodeVOP_I_MT(mp4_Info* pInfo); +extern mp4_Status mp4_DecodeVOP_P_MT(mp4_Info* pInfo); +extern mp4_Status mp4_DecodeVOP_B_MT(mp4_Info* pInfo); +extern mp4_Status mp4_DecodeVOP_S_MT(mp4_Info* pInfo); +extern void mp4_DCTInvCoeffsInterMB(mp4_Info *pInfo, int16_t *coeffMB, int32_t lnz[], int32_t pat, int32_t scan); +extern void mp4_PadFrame(mp4_Info* pInfo); +extern void mp4_OBMC(mp4_Info *pInfo, mp4_MacroBlock *pMBinfo, IppMotionVector *mvCur, int32_t colNum, int32_t rowNum, IppiRect limitRectL, uint8_t *pYc, int32_t stepYc, uint8_t *pYr, int32_t stepYr, int32_t cbpy, int16_t *coeffMB, int32_t dct_type); +extern mp4_Status mp4_CheckDecodeVideoPacket(mp4_Info* pInfo, int32_t *found); +extern int32_t mp4_CheckDecodeGOB_SVH(mp4_Info* pInfo); +extern void mp4_CopyMacroBlocks(const mp4_Frame *rFrame, mp4_Frame *cFrame, int32_t mbPerRow, int32_t rowNum, int32_t colNum, int32_t n); + +extern mp4_Status mp4_Sprite_Trajectory(mp4_Info* pInfo); +extern mp4_Status mp4_PredictDecodeMV(mp4_Info *pInfo, mp4_MacroBlock *MBcurr, int32_t frGOB, int32_t y, int32_t x); +extern mp4_Status mp4_DecodeMCBPC_I(mp4_Info* pInfo, int32_t *mbType, int32_t *mbPattern); + +#ifdef FLOAT_POINT_IDCT + +static void fIDCT_16s8u_C1R(int16_t *coeff, uint8_t *pR, int stepR) +{ + __ALIGN16(Ipp32f, c, 64); + int i, j; + + for (i = 0; i < 64; i ++) + c[i] = coeff[i]; + ippiDCT8x8Inv_32f_C1I(c); + for (i = 0; i < 8; i ++) + for (j = 0; j < 8; j ++) + pR[i*stepR+j] = c[i*8+j] < 0 ? 0 : c[i*8+j] > 255 ? 255 : (int16_t)(c[i*8+j] + 0.5f); +} + +static void fIDCT_16s_C1I(int16_t *coeff) +{ + __ALIGN16(Ipp32f, c, 64); + int i; + + for (i = 0; i < 64; i ++) + c[i] = coeff[i]; + ippiDCT8x8Inv_32f_C1I(c); + for (i = 0; i < 64; i ++) + coeff[i] = c[i] < 0 ? (int16_t)(c[i] - 0.5f) : (int16_t)(c[i] + 0.5f); +} + +#define ippiDCT8x8Inv_16s8u_C1R(coeff, pR, stepR) \ + fIDCT_16s8u_C1R(coeff, pR, stepR) + +#define ippiDCT8x8Inv_2x2_16s_C1I(coeff) \ + fIDCT_16s_C1I(coeff) + +#define ippiDCT8x8Inv_4x4_16s_C1I(coeff) \ + fIDCT_16s_C1I(coeff) + +#define ippiDCT8x8Inv_16s_C1I(coeff) \ + fIDCT_16s_C1I(coeff) + +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/Src/mpeg4dec/mp4decvop.c b/Src/mpeg4dec/mp4decvop.c new file mode 100644 index 00000000..3bd8b2a2 --- /dev/null +++ b/Src/mpeg4dec/mp4decvop.c @@ -0,0 +1,1983 @@ +/* /////////////////////////////////////////////////////////////////////// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 2001-2008 Intel Corporation. All Rights Reserved. +// +// Description: Decodes MPEG-4 bitstream. +// +*/ + +#include "mp4def.h" +#include "mp4dec.h" + +#pragma warning(disable : 188) // enumerated type mixed with another type ICL + +void mp4_ResetVOL(mp4_Info *pInfo) +{ + pInfo->VisualObject.VideoObject.VOPindex = 0; + pInfo->VisualObject.VideoObject.prevPlaneIsB = 0; + pInfo->VisualObject.VideoObject.GroupOfVideoObjectPlane.time_code = 0; + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + pInfo->VisualObject.cFrame=0; + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + pInfo->VisualObject.rFrame=0; + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.nFrame); + pInfo->VisualObject.nFrame=0; + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.sFrame); + pInfo->VisualObject.sFrame=0; +} + +static int AllocateInitFrame(mp4_Frame* pFrame) +{ + int32_t w, h; + + w = (pFrame->mbPerRow + 2 * MP4_NUM_EXT_MB) << 4; + h = (pFrame->mbPerCol + 2 * MP4_NUM_EXT_MB) << 4; + pFrame->mid = malloc(w * h + (w * h >> 1)); + if (!pFrame->mid) + return 1; // out of memory + + ippsSet_8u(0, pFrame->mid, w * h); + ippsSet_8u(128, pFrame->mid + w * h, w * h >> 1); + + pFrame->stepY = w; + pFrame->stepCb = w >> 1; + pFrame->stepCr = w >> 1; + + /* benski> stuff from LockFrame... */ + pFrame->apY = pFrame->mid; + pFrame->pY = pFrame->apY + w * 16 + 16; + pFrame->apCb = pFrame->apY + w * h; + w >>= 1; + h >>= 1; + pFrame->pCb = pFrame->apCb + w * 8 + 8; + pFrame->apCr = pFrame->apCb + w * h; + pFrame->pCr = pFrame->apCr + w * 8 + 8; + + return 0; +} + +static mp4_Status mp4_AllocInitFrame(mp4_Frame* pFrame, int32_t mbPerRow, int32_t mbPerCol) +{ + int32_t w, h; + + w = (mbPerRow + 2 * MP4_NUM_EXT_MB) << 4; + h = (mbPerCol + 2 * MP4_NUM_EXT_MB) << 4; + pFrame->stepY = w; + pFrame->apY = ippsMalloc_8u(w * h); + if (!pFrame->apY) + return MP4_STATUS_NO_MEM; + ippsSet_8u(0, pFrame->apY, w * h); + pFrame->pY = pFrame->apY + w * 16 + 16; + w >>= 1; + h >>= 1; + pFrame->stepCb = w; + pFrame->apCb = ippsMalloc_8u(w * h); + if (!pFrame->apCb) + return MP4_STATUS_NO_MEM; + ippsSet_8u(128, pFrame->apCb, w * h); + pFrame->pCb = pFrame->apCb + w * 8 + 8; + pFrame->stepCr = w; + pFrame->apCr = ippsMalloc_8u(w * h); + if (!pFrame->apCr) + return MP4_STATUS_NO_MEM; + pFrame->pCr = pFrame->apCr + w * 8 + 8; + ippsSet_8u(128, pFrame->apCr, w * h); + return MP4_STATUS_OK; +} + +/* +// mp4_Info for decoding of Video Object Layer +*/ +mp4_Status mp4_InitVOL(mp4_Info* pInfo) +{ + int32_t mbPerRow, mbPerCol, specSize; + + if (pInfo->VisualObject.VideoObject.short_video_header) { + pInfo->noBVOPs = 1; + } else { + if (pInfo->strictSyntaxCheck) { + if (pInfo->VisualObject.VideoObject.random_accessible_vol) + pInfo->noPVOPs = pInfo->noBVOPs = 1; + if (pInfo->VisualObject.VideoObject.type_indication == MP4_VIDEO_OBJECT_TYPE_SIMPLE || + pInfo->VisualObject.VideoObject.type_indication == MP4_VIDEO_OBJECT_TYPE_ADVANCED_REAL_TIME_SIMPLE || + pInfo->VisualObject.VideoObject.VOLControlParameters.low_delay) { + pInfo->noBVOPs = 1; + } + } + } + if (pInfo->VisualObject.VideoObject.shape == MP4_SHAPE_TYPE_RECTANGULAR) + { + mbPerRow = (pInfo->VisualObject.VideoObject.width + 15) >> 4; + mbPerCol = (pInfo->VisualObject.VideoObject.height + 15) >> 4; + // current frame +// if (mp4_AllocInitFrame(&pInfo->VisualObject.cFrame, mbPerRow, mbPerCol) != MP4_STATUS_OK) +// return MP4_STATUS_NO_MEM; + if (pInfo->VisualObject.VideoObject.sprite_enable != MP4_SPRITE_STATIC) + { + // ref in past frame +// if (mp4_AllocInitFrame(&pInfo->VisualObject.rFrame, mbPerRow, mbPerCol) != MP4_STATUS_OK) +// return MP4_STATUS_NO_MEM; + // ref in future frame +// if (mp4_AllocInitFrame(&pInfo->VisualObject.nFrame, mbPerRow, mbPerCol) != MP4_STATUS_OK) +// return MP4_STATUS_NO_MEM; + // motion info (not needed for Sprites) + pInfo->VisualObject.VideoObject.MBinfo = (mp4_MacroBlock*)ippsMalloc_8u(mbPerRow*mbPerCol*sizeof(mp4_MacroBlock)); + if (!pInfo->VisualObject.VideoObject.MBinfo) return MP4_STATUS_NO_MEM; +#ifdef USE_NOTCODED_STATE + // not_coded MB state + pInfo->VisualObject.VideoObject.ncState = ippsMalloc_8u(mbPerCol * mbPerRow); + if (!pInfo->VisualObject.VideoObject.ncState) return MP4_STATUS_NO_MEM; + pInfo->VisualObject.VideoObject.ncStateCleared = 0; +#endif + } + else + { // data for static sprite + mbPerRow = pInfo->VisualObject.sFrame->mbPerRow = (pInfo->VisualObject.VideoObject.sprite_width + 15) >> 4; + mbPerCol = pInfo->VisualObject.sFrame->mbPerCol = (pInfo->VisualObject.VideoObject.sprite_height + 15) >> 4; +// if (mp4_AllocInitFrame(&pInfo->VisualObject.sFrame, mbPerRow, mbPerCol) != MP4_STATUS_OK) +// return MP4_STATUS_NO_MEM; + } + pInfo->VisualObject.VideoObject.MacroBlockPerRow = mbPerRow; + pInfo->VisualObject.VideoObject.MacroBlockPerCol = mbPerCol; + pInfo->VisualObject.VideoObject.MacroBlockPerVOP = mbPerRow * mbPerCol; + pInfo->VisualObject.VideoObject.mbns = mp4_GetMacroBlockNumberSize(pInfo->VisualObject.VideoObject.MacroBlockPerVOP); + + if (!pInfo->VisualObject.VideoObject.short_video_header) + { + // Intra Prediction info (not needed for SVH) + pInfo->VisualObject.VideoObject.IntraPredBuff.quant = ippsMalloc_8u(mbPerRow + 1); + if (!pInfo->VisualObject.VideoObject.IntraPredBuff.quant) return MP4_STATUS_NO_MEM; + pInfo->VisualObject.VideoObject.IntraPredBuff.block = (mp4_IntraPredBlock*)ippsMalloc_8u((mbPerRow + 1)*6*sizeof(mp4_IntraPredBlock)); + if (!pInfo->VisualObject.VideoObject.IntraPredBuff.block) return MP4_STATUS_NO_MEM; + { + mp4_IntraPredBlock *mbCurr = pInfo->VisualObject.VideoObject.IntraPredBuff.block; + mp4_IntraPredBlock *mbA = mbCurr, *mbB = pInfo->VisualObject.VideoObject.IntraPredBuff.dcB, *mbC = mbCurr + 6; + int32_t j; + + for (j = 0; j < mbPerRow; j ++) { + mbCurr[0].predA = &mbA[1]; mbCurr[0].predB = &mbB[3]; mbCurr[0].predC = &mbC[2]; + mbCurr[1].predA = &mbC[0]; mbCurr[1].predB = &mbC[2]; mbCurr[1].predC = &mbC[3]; + mbCurr[2].predA = &mbA[3]; mbCurr[2].predB = &mbA[1]; mbCurr[2].predC = &mbC[0]; + mbCurr[3].predA = &mbC[2]; mbCurr[3].predB = &mbC[0]; mbCurr[3].predC = &mbC[1]; + mbCurr[4].predA = &mbA[4]; mbCurr[4].predB = &mbB[4]; mbCurr[4].predC = &mbC[4]; + mbCurr[5].predA = &mbA[5]; mbCurr[5].predB = &mbB[5]; mbCurr[5].predC = &mbC[5]; + mbCurr += 6; mbA += 6; mbC += 6; + } + } + if (pInfo->VisualObject.VideoObject.data_partitioned) { + // DataPart info + pInfo->VisualObject.VideoObject.DataPartBuff = (mp4_DataPartMacroBlock*)ippsMalloc_8u(mbPerRow*mbPerCol*sizeof(mp4_DataPartMacroBlock)); + if (!pInfo->VisualObject.VideoObject.DataPartBuff) return MP4_STATUS_NO_MEM; + } + if (pInfo->VisualObject.VideoObject.interlaced) { + // Field MV for B-VOP + pInfo->VisualObject.VideoObject.FieldMV = (IppMotionVector*)ippsMalloc_8u(mbPerRow*mbPerCol*sizeof(IppMotionVector)*2); + if (!pInfo->VisualObject.VideoObject.FieldMV) return MP4_STATUS_NO_MEM; + } + ippiQuantInvIntraGetSize_MPEG4(&specSize); + pInfo->VisualObject.VideoObject.QuantInvIntraSpec = (IppiQuantInvIntraSpec_MPEG4*)ippsMalloc_8u(specSize); + ippiQuantInvIntraInit_MPEG4(pInfo->VisualObject.VideoObject.quant_type ? pInfo->VisualObject.VideoObject.intra_quant_mat : NULL, pInfo->VisualObject.VideoObject.QuantInvIntraSpec, 8); + ippiQuantInvInterGetSize_MPEG4(&specSize); + pInfo->VisualObject.VideoObject.QuantInvInterSpec = (IppiQuantInvInterSpec_MPEG4*)ippsMalloc_8u(specSize); + ippiQuantInvInterInit_MPEG4(pInfo->VisualObject.VideoObject.quant_type ? pInfo->VisualObject.VideoObject.nonintra_quant_mat : NULL, pInfo->VisualObject.VideoObject.QuantInvInterSpec, 8); + ippiWarpGetSize_MPEG4(&specSize); + pInfo->VisualObject.VideoObject.WarpSpec = (IppiWarpSpec_MPEG4*)ippsMalloc_8u(specSize); + } + } + return MP4_STATUS_OK; +} + +/* +// Free memory allocated for mp4_Info +*/ +mp4_Status mp4_FreeVOL(mp4_Info* pInfo) +{ + if (pInfo->VisualObject.VideoObject.shape == MP4_SHAPE_TYPE_RECTANGULAR) { + if (pInfo->VisualObject.VideoObject.sprite_enable != MP4_SPRITE_STATIC) { + ippsFree(pInfo->VisualObject.VideoObject.MBinfo); pInfo->VisualObject.VideoObject.MBinfo = NULL; +#ifdef USE_NOTCODED_STATE + ippsFree(pInfo->VisualObject.VideoObject.ncState); +#endif + } else { + } + if (!pInfo->VisualObject.VideoObject.short_video_header) { + ippsFree(pInfo->VisualObject.VideoObject.IntraPredBuff.quant); pInfo->VisualObject.VideoObject.IntraPredBuff.quant = NULL; + ippsFree(pInfo->VisualObject.VideoObject.IntraPredBuff.block); pInfo->VisualObject.VideoObject.IntraPredBuff.block = NULL; + if (pInfo->VisualObject.VideoObject.data_partitioned) { + ippsFree(pInfo->VisualObject.VideoObject.DataPartBuff); pInfo->VisualObject.VideoObject.DataPartBuff = NULL; + } + if (pInfo->VisualObject.VideoObject.interlaced) { + ippsFree(pInfo->VisualObject.VideoObject.FieldMV); pInfo->VisualObject.VideoObject.FieldMV = NULL; + } + ippsFree(pInfo->VisualObject.VideoObject.QuantInvIntraSpec); pInfo->VisualObject.VideoObject.QuantInvIntraSpec = NULL; + ippsFree(pInfo->VisualObject.VideoObject.QuantInvInterSpec); pInfo->VisualObject.VideoObject.QuantInvInterSpec = NULL; + ippsFree(pInfo->VisualObject.VideoObject.WarpSpec); pInfo->VisualObject.VideoObject.WarpSpec = NULL; + } + + } + return MP4_STATUS_OK; +} + + +mp4_Status mp4_DecodeMVD(mp4_Info *pInfo, int32_t *mvdx, int32_t *mvdy, int32_t fcode) +{ + const mp4_VLC1 *pTab; + int32_t mvd, sign; + uint32_t code; + int32_t factor = fcode - 1; + + /* decode MVDx */ + code = mp4_ShowBits(pInfo, 12); + if (code >= 128) + pTab = mp4_MVD_B12_2 + ((code - 128) >> 5); + else if (code >= 2) + pTab = mp4_MVD_B12_1 + (code - 2); + else { + mp4_Error("Error: decoding MVD"); + return MP4_STATUS_ERROR; + } + mvd = pTab->code; + mp4_FlushBits(pInfo, pTab->len); + if (mvd) { + sign = mp4_GetBit(pInfo); + if (factor) { + code = mp4_GetBits9(pInfo, factor); + mvd = ((mvd - 1) << factor) + code + 1; + } + if (sign) + mvd = -mvd; + } + *mvdx = mvd; + /* decode MVDy */ + code = mp4_ShowBits(pInfo, 12); + if (code >= 128) + pTab = mp4_MVD_B12_2 + ((code - 128) >> 5); + else if (code >= 2) + pTab = mp4_MVD_B12_1 + (code - 2); + else { + mp4_Error("Error: decoding MVD"); + return MP4_STATUS_ERROR; + } + mvd = pTab->code; + mp4_FlushBits(pInfo, pTab->len); + if (mvd) { + sign = mp4_GetBit(pInfo); + if (factor) { + code = mp4_GetBits9(pInfo, factor); + mvd = ((mvd - 1) << factor) + code + 1; + } + if (sign) + mvd = -mvd; + } + *mvdy = mvd; + return MP4_STATUS_OK; +} + +mp4_Status mp4_DecodeMV(mp4_Info *pInfo, IppMotionVector *mv, int32_t fcode) +{ + int32_t mvdx, mvdy, range, range2, dx, dy; + + if (mp4_DecodeMVD(pInfo, &mvdx, &mvdy, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + range = 16 << fcode; + range2 = range + range; + dx = mv->dx + mvdx; + if (dx < -range) + dx += range2; + else if (dx >= range) + dx -= range2; + mv->dx = (int16_t)dx; + dy = mv->dy + mvdy; + if (dy < -range) + dy += range2; + else if (dy >= range) + dy -= range2; + mv->dy = (int16_t)dy; + return MP4_STATUS_OK; +} + +mp4_Status mp4_Decode4MV(mp4_Info *pInfo, IppMotionVector *mv, int32_t fcode) +{ + int32_t i, mvdx, mvdy, range, range2, dx, dy; + + range = 16 << fcode; + range2 = range + range; + for (i = 0; i < 4; i ++) { + if (mp4_DecodeMVD(pInfo, &mvdx, &mvdy, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + dx = mv[i].dx + mvdx; + if (dx < -range) + dx += range2; + else if (dx >= range) + dx -= range2; + mv[i].dx = (int16_t)dx; + dy = mv[i].dy + mvdy; + if (dy < -range) + dy += range2; + else if (dy >= range) + dy -= range2; + mv[i].dy = (int16_t)dy; + } + return MP4_STATUS_OK; +} + +mp4_Status mp4_DecodeMV_Direct(mp4_Info *pInfo, IppMotionVector mvC[4], IppMotionVector mvForw[4], IppMotionVector mvBack[4], int32_t TRB, int32_t TRD, int32_t modb, int32_t comb_type) +{ + int32_t mvdx, mvdy, i; + + if (modb == 2) { + if (comb_type != IPPVC_MBTYPE_INTER4V) { + mvForw[0].dx = mvForw[1].dx = mvForw[2].dx = mvForw[3].dx = (int16_t)((TRB * mvC[0].dx) / TRD); + mvForw[0].dy = mvForw[1].dy = mvForw[2].dy = mvForw[3].dy = (int16_t)((TRB * mvC[0].dy) / TRD); + mvBack[0].dx = mvBack[1].dx = mvBack[2].dx = mvBack[3].dx = (int16_t)(((TRB - TRD) * mvC[0].dx) / TRD); + mvBack[0].dy = mvBack[1].dy = mvBack[2].dy = mvBack[3].dy = (int16_t)(((TRB - TRD) * mvC[0].dy) / TRD); + } else + for (i = 0; i < 4; i ++) { + mvForw[i].dx = (int16_t)((TRB * mvC[i].dx) / TRD); + mvForw[i].dy = (int16_t)((TRB * mvC[i].dy) / TRD); + mvBack[i].dx = (int16_t)(((TRB - TRD) * mvC[i].dx) / TRD); + mvBack[i].dy = (int16_t)(((TRB - TRD) * mvC[i].dy) / TRD); + } + } else { + if (mp4_DecodeMVD(pInfo, &mvdx, &mvdy, 1) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + if (comb_type != IPPVC_MBTYPE_INTER4V) { + mvForw[0].dx = mvForw[1].dx = mvForw[2].dx = mvForw[3].dx = (int16_t)((TRB * mvC[0].dx) / TRD + mvdx); + mvForw[0].dy = mvForw[1].dy = mvForw[2].dy = mvForw[3].dy = (int16_t)((TRB * mvC[0].dy) / TRD + mvdy); + if (mvdx == 0) + mvBack[0].dx = mvBack[1].dx = mvBack[2].dx = mvBack[3].dx = (int16_t)(((TRB - TRD) * mvC[0].dx) / TRD); + else + mvBack[0].dx = mvBack[1].dx = mvBack[2].dx = mvBack[3].dx = (int16_t)(mvForw[0].dx - mvC[0].dx); + if (mvdy == 0) + mvBack[0].dy = mvBack[1].dy = mvBack[2].dy = mvBack[3].dy = (int16_t)(((TRB - TRD) * mvC[0].dy) / TRD); + else + mvBack[0].dy = mvBack[1].dy = mvBack[2].dy = mvBack[3].dy = (int16_t)(mvForw[0].dy - mvC[0].dy); + } else + for (i = 0; i < 4; i++) { + mvForw[i].dx = (int16_t)((TRB * mvC[i].dx) / TRD + mvdx); + mvForw[i].dy = (int16_t)((TRB * mvC[i].dy) / TRD + mvdy); + if (mvdx == 0) + mvBack[i].dx = (int16_t)(((TRB - TRD) * mvC[i].dx) / TRD); + else + mvBack[i].dx = (int16_t)(mvForw[i].dx - mvC[i].dx); + if (mvdy == 0) + mvBack[i].dy = (int16_t)(((TRB - TRD) * mvC[i].dy) / TRD); + else + mvBack[i].dy = (int16_t)(mvForw[i].dy - mvC[i].dy); + } + } + return MP4_STATUS_OK; +} + +mp4_Status mp4_DecodeMV_DirectField(mp4_Info *pInfo, int32_t mb_ftfr, int32_t mb_fbfr, IppMotionVector *mvTop, IppMotionVector *mvBottom, IppMotionVector *mvForwTop, IppMotionVector *mvForwBottom, IppMotionVector *mvBackTop, IppMotionVector *mvBackBottom, int32_t TRB, int32_t TRD, int32_t modb) +{ + // field direct mode + int32_t TRDt, TRDb, TRBt, TRBb, deltaTop, deltaBottom, mvdx, mvdy; + + deltaTop = mb_ftfr; + deltaBottom = mb_fbfr - 1; + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.top_field_first) { + deltaTop = -deltaTop; + deltaBottom = -deltaBottom; + } + TRDt = mp4_DivRoundInf(TRD, pInfo->VisualObject.VideoObject.Tframe) * 2 + deltaTop; + TRDb = mp4_DivRoundInf(TRD, pInfo->VisualObject.VideoObject.Tframe) * 2 + deltaBottom; + TRBt = mp4_DivRoundInf(TRB, pInfo->VisualObject.VideoObject.Tframe) * 2 + deltaTop; + TRBb = mp4_DivRoundInf(TRB, pInfo->VisualObject.VideoObject.Tframe) * 2 + deltaBottom; + if (modb == 2) { + // delta == 0 + mvdx = mvdy = 0; + } else { + if (mp4_DecodeMVD(pInfo, &mvdx, &mvdy, 1) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + } + mvForwTop->dx = (int16_t)((TRBt * mvTop->dx) / TRDt + mvdx); + if (mvdx == 0) + mvBackTop->dx = (int16_t)(((TRBt - TRDt) * mvTop->dx) / TRDt); + else + mvBackTop->dx = (int16_t)(mvForwTop->dx - mvTop->dx); + mvForwTop->dy = (int16_t)((TRBt * mvTop->dy * 2) / TRDt + mvdy); + if (mvdy == 0) + mvBackTop->dy = (int16_t)(((TRBt - TRDt) * mvTop->dy * 2) / TRDt); + else + mvBackTop->dy = (int16_t)(mvForwTop->dy - mvTop->dy * 2); + mvForwBottom->dx = (int16_t)((TRBb * mvBottom->dx) / TRDb + mvdx); + if (mvdx == 0) + mvBackBottom->dx = (int16_t)(((TRBb - TRDb) * mvBottom->dx) / TRDb); + else + mvBackBottom->dx = (int16_t)(mvForwBottom->dx - mvBottom->dx); + mvForwBottom->dy = (int16_t)((TRBb * mvBottom->dy * 2) / TRDb + mvdy); + if (mvdy == 0) + mvBackBottom->dy = (int16_t)(((TRBb - TRDb) * mvBottom->dy * 2) / TRDb); + else + mvBackBottom->dy = (int16_t)(mvForwBottom->dy - mvBottom->dy * 2); + mvForwTop->dy >>= 1; + mvBackTop->dy >>= 1; + mvForwBottom->dy >>= 1; + mvBackBottom->dy >>= 1; + return MP4_STATUS_OK; +} + +/*static*/ void mp4_ExpandFrameReplicate(uint8_t *pSrcDstPlane, int32_t frameWidth, int32_t frameHeight, int32_t expandPels, int32_t step) +{ + uint8_t *pDst1, *pDst2, *pSrc1, *pSrc2; + int32_t i, j; + uint32_t t1, t2; + + pDst1 = pSrcDstPlane + step * expandPels; + pDst2 = pDst1 + frameWidth + expandPels; + if (expandPels == 8) { + for (i = 0; i < frameHeight; i ++) { + t1 = pDst1[8] + (pDst1[8] << 8); + t2 = pDst2[-1] + (pDst2[-1] << 8); + t1 = (t1 << 16) + t1; + t2 = (t2 << 16) + t2; + ((uint32_t*)pDst1)[0] = t1; + ((uint32_t*)pDst1)[1] = t1; + ((uint32_t*)pDst2)[0] = t2; + ((uint32_t*)pDst2)[1] = t2; + pDst1 += step; + pDst2 += step; + } + } else if (expandPels == 16) { + for (i = 0; i < frameHeight; i ++) { + t1 = pDst1[16] + (pDst1[16] << 8); + t2 = pDst2[-1] + (pDst2[-1] << 8); + t1 = (t1 << 16) + t1; + t2 = (t2 << 16) + t2; + ((uint32_t*)pDst1)[0] = t1; + ((uint32_t*)pDst1)[1] = t1; + ((uint32_t*)pDst1)[2] = t1; + ((uint32_t*)pDst1)[3] = t1; + ((uint32_t*)pDst2)[0] = t2; + ((uint32_t*)pDst2)[1] = t2; + ((uint32_t*)pDst2)[2] = t2; + ((uint32_t*)pDst2)[3] = t2; + pDst1 += step; + pDst2 += step; + } + } else { + for (i = 0; i < frameHeight; i ++) { + ippsSet_8u(pDst1[expandPels], pDst1, expandPels); + ippsSet_8u(pDst2[-1], pDst2, expandPels); + pDst1 += step; + pDst2 += step; + } + } + pDst1 = pSrcDstPlane; + pSrc1 = pSrcDstPlane + expandPels * step; + pDst2 = pSrc1 + frameHeight * step; + pSrc2 = pDst2 - step; + j = frameWidth + 2 * expandPels; + for (i = 0; i < expandPels; i ++) { + ippsCopy_8u(pSrc1, pDst1, j); + ippsCopy_8u(pSrc2, pDst2, j); + pDst1 += step; + pDst2 += step; + } +} + +void mp4_PadFrame(mp4_Info* pInfo) +{ +#if 0 + /* + // padding VOP (for not complete blocks padd by + // 0 for DivX(tm) 5.0 AVI streams + // 128 for QuickTime(tm) MP4 streams + // replication for other + */ + int32_t wL, hL, wC, hC, i; + + //if (pInfo->VisualObject.VideoObject.short_video_header) + // return; + wL = pInfo->VisualObject.VideoObject.width; + hL = pInfo->VisualObject.VideoObject.height; + wC = pInfo->VisualObject.VideoObject.width >> 1; + hC = pInfo->VisualObject.VideoObject.height >> 1; + if ((pInfo->VisualObject.VideoObject.width & 15 || pInfo->VisualObject.VideoObject.height & 15) && + ((pInfo->ftype == 1 && pInfo->ftype_f == 0) || (pInfo->ftype == 2 && pInfo->ftype_f == 1))) { + uint8_t pad = (uint8_t)(pInfo->ftype == 1 ? 128 : 0); + + if (pInfo->VisualObject.VideoObject.width & 15) { + uint8_t *p; + // pad one col + p = pInfo->VisualObject.cFrame.pY + pInfo->VisualObject.VideoObject.width; + for (i = 0; i < pInfo->VisualObject.VideoObject.height; i ++) { + *p = pad; + p += pInfo->VisualObject.cFrame.stepY; + } + p = pInfo->VisualObject.cFrame.pCb + (pInfo->VisualObject.VideoObject.width >> 1); + for (i = 0; i < pInfo->VisualObject.VideoObject.height >> 1; i ++) { + *p = pad; + p += pInfo->VisualObject.cFrame.stepCb; + } + p = pInfo->VisualObject.cFrame.pCr + (pInfo->VisualObject.VideoObject.width >> 1); + for (i = 0; i < pInfo->VisualObject.VideoObject.height >> 1; i ++) { + *p = pad; + p += pInfo->VisualObject.cFrame.stepCr; + } + wL ++; + wC ++; + } + if (pInfo->VisualObject.VideoObject.height & 15) { + // pad one row + ippsSet_8u(pad, pInfo->VisualObject.cFrame.pY + pInfo->VisualObject.cFrame.stepY * pInfo->VisualObject.VideoObject.height, pInfo->VisualObject.VideoObject.width); + ippsSet_8u(pad, pInfo->VisualObject.cFrame.pCb + pInfo->VisualObject.cFrame.stepCb * (pInfo->VisualObject.VideoObject.height >> 1), pInfo->VisualObject.VideoObject.width >> 1); + ippsSet_8u(pad, pInfo->VisualObject.cFrame.pCr + pInfo->VisualObject.cFrame.stepCr * (pInfo->VisualObject.VideoObject.height >> 1), pInfo->VisualObject.VideoObject.width >> 1); + hL ++; + hC ++; + } + } +#else + /* + // padding VOP for not complete blocks + // replication from macroblock boundary for DIVX and MP4 and from frame boundary for other + */ + int32_t wL, hL, wC, hC; + + if ((pInfo->ftype == 1 && pInfo->ftype_f == 0) || (pInfo->ftype == 2 && pInfo->ftype_f == 1)) { + wL = pInfo->VisualObject.VideoObject.MacroBlockPerRow * 16; + hL = pInfo->VisualObject.VideoObject.MacroBlockPerCol * 16; + } else { + wL = pInfo->VisualObject.VideoObject.width; + hL = pInfo->VisualObject.VideoObject.height; + } + wC = wL >> 1; + hC = hL >> 1; +#endif + mp4_ExpandFrameReplicate(pInfo->VisualObject.cFrame->apY, wL, hL, 16 * MP4_NUM_EXT_MB, pInfo->VisualObject.cFrame->stepY); + mp4_ExpandFrameReplicate(pInfo->VisualObject.cFrame->apCb, wC, hC, 8 * MP4_NUM_EXT_MB, pInfo->VisualObject.cFrame->stepCb); + mp4_ExpandFrameReplicate(pInfo->VisualObject.cFrame->apCr, wC, hC, 8 * MP4_NUM_EXT_MB, pInfo->VisualObject.cFrame->stepCr); + +} + +mp4_Status mp4_DecodeVideoObjectPlane(mp4_Info* pInfo) +{ + mp4_Status status = MP4_STATUS_OK; + Ipp64s vop_time; + + // set VOP time + if (pInfo->VisualObject.VideoObject.short_video_header) + { + vop_time = pInfo->VisualObject.VideoObject.vop_sync_time + pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.temporal_reference * 1001; + if (pInfo->VisualObject.cFrame && pInfo->VisualObject.cFrame->time > vop_time) + { + pInfo->VisualObject.VideoObject.vop_sync_time += 256 * 1001; + vop_time += 256 * 1001; + } + } + else + { + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coding_type == MP4_VOP_TYPE_B) + { + vop_time = pInfo->VisualObject.VideoObject.vop_sync_time_b + pInfo->VisualObject.VideoObject.VideoObjectPlane.modulo_time_base * pInfo->VisualObject.VideoObject.vop_time_increment_resolution + pInfo->VisualObject.VideoObject.VideoObjectPlane.time_increment; + } + else + { + if (pInfo->VisualObject.VideoObject.GroupOfVideoObjectPlane.time_code > pInfo->VisualObject.VideoObject.vop_sync_time) + pInfo->VisualObject.VideoObject.vop_sync_time = pInfo->VisualObject.VideoObject.GroupOfVideoObjectPlane.time_code; + vop_time = pInfo->VisualObject.VideoObject.vop_sync_time + pInfo->VisualObject.VideoObject.VideoObjectPlane.modulo_time_base * pInfo->VisualObject.VideoObject.vop_time_increment_resolution + pInfo->VisualObject.VideoObject.VideoObjectPlane.time_increment; + if (pInfo->VisualObject.VideoObject.vop_sync_time_b < pInfo->VisualObject.VideoObject.vop_sync_time) + pInfo->VisualObject.VideoObject.vop_sync_time_b = pInfo->VisualObject.VideoObject.vop_sync_time; + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.modulo_time_base != 0) { + pInfo->VisualObject.VideoObject.vop_sync_time = vop_time - pInfo->VisualObject.VideoObject.VideoObjectPlane.time_increment; + } + } + } +// if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coded || vop_time != pInfo->VisualObject.rFrame.time) { + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coded || + ( (!pInfo->VisualObject.cFrame || vop_time != pInfo->VisualObject.cFrame->time) && + (!pInfo->VisualObject.rFrame || vop_time != pInfo->VisualObject.rFrame->time) && + (!pInfo->VisualObject.nFrame || vop_time != pInfo->VisualObject.nFrame->time) + )) + { + switch (pInfo->VisualObject.VideoObject.VideoObjectPlane.coding_type) + { + case MP4_VOP_TYPE_I : + // set new video frame + if (pInfo->VisualObject.VideoObject.sprite_enable == MP4_SPRITE_STATIC) + { + // TODO: verify + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.sFrame); + pInfo->VisualObject.sFrame = pInfo->VisualObject.cFrame; + pInfo->VisualObject.cFrame = 0; + } + else + { + if (pInfo->noPVOPs) + { + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + pInfo->VisualObject.cFrame=0; + } + else if (pInfo->noBVOPs) + { + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + pInfo->VisualObject.rFrame = pInfo->VisualObject.cFrame; + pInfo->VisualObject.cFrame = 0; + } + else + { + if (pInfo->VisualObject.VideoObject.VOPindex > 0) + { + if (pInfo->VisualObject.VideoObject.prevPlaneIsB) + { + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + pInfo->VisualObject.cFrame = 0; + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.nFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + pInfo->VisualObject.rFrame = pInfo->VisualObject.nFrame; + pInfo->VisualObject.nFrame = 0; + pInfo->VisualObject.VideoObject.prevPlaneIsB=0; + } + else + { + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + pInfo->VisualObject.rFrame = pInfo->VisualObject.cFrame; + pInfo->VisualObject.cFrame = 0; + } + + } + } + } + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coded) + { + if (pInfo->VisualObject.VideoObject.shape == MP4_SHAPE_TYPE_RECTANGULAR) + { + status = mp4_DecodeVOP_I(pInfo); + } //f else + //f status = mp4_DecodeVOP_I_Shape(pInfo); + if (pInfo->VisualObject.VideoObject.sprite_enable == MP4_SPRITE_STATIC && pInfo->VisualObject.VideoObject.VOPindex == 0) + { + // TODO: verify (was: mp4_SWAP(mp4_Frame, pInfo->VisualObject.sFrame, pInfo->VisualObject.cFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.sFrame); + pInfo->VisualObject.sFrame = pInfo->VisualObject.cFrame; + pInfo->VisualObject.cFrame = 0; + mp4_ExpandFrameReplicate(pInfo->VisualObject.sFrame->apY, pInfo->VisualObject.VideoObject.sprite_width, pInfo->VisualObject.VideoObject.sprite_height, 16, pInfo->VisualObject.sFrame->stepY); + mp4_ExpandFrameReplicate(pInfo->VisualObject.sFrame->apCb, pInfo->VisualObject.VideoObject.sprite_width >> 1, pInfo->VisualObject.VideoObject.sprite_height >> 1, 8, pInfo->VisualObject.sFrame->stepCb); + mp4_ExpandFrameReplicate(pInfo->VisualObject.sFrame->apCr, pInfo->VisualObject.VideoObject.sprite_width >> 1, pInfo->VisualObject.VideoObject.sprite_height >> 1, 8, pInfo->VisualObject.sFrame->stepCr); + } else { + mp4_PadFrame(pInfo); + } + // set past and future time for B-VOP + pInfo->VisualObject.VideoObject.rTime = pInfo->VisualObject.VideoObject.nTime; + pInfo->VisualObject.VideoObject.nTime = vop_time; +#ifdef USE_NOTCODED_STATE + // Clear not_coded MB state + if ((pInfo->VisualObject.VideoObject.sprite_enable != MP4_SPRITE_STATIC) && pInfo->VisualObject.VideoObject.obmc_disable && !pInfo->VisualObject.VideoObject.ncStateCleared) { + ippsZero_8u(pInfo->VisualObject.VideoObject.ncState, pInfo->VisualObject.VideoObject.MacroBlockPerVOP); + pInfo->VisualObject.VideoObject.ncStateCleared = 1; + } +#endif + } + mp4_StatisticInc(&pInfo->VisualObject.Statistic.nVOP_I); + break; + case MP4_VOP_TYPE_P : + // set new video frame + if (pInfo->noBVOPs) + { + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + pInfo->VisualObject.rFrame = pInfo->VisualObject.cFrame; + pInfo->VisualObject.cFrame = 0; + } + else + { + if (pInfo->VisualObject.VideoObject.VOPindex > 0) + { + if (pInfo->VisualObject.VideoObject.prevPlaneIsB) + { + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + pInfo->VisualObject.cFrame=0; + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.nFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + pInfo->VisualObject.rFrame = pInfo->VisualObject.nFrame; + pInfo->VisualObject.nFrame = 0; + pInfo->VisualObject.VideoObject.prevPlaneIsB = 0; + } + else + { + if (pInfo->VisualObject.cFrame) + { + int w, h; + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + pInfo->VisualObject.rFrame = pInfo->VisualObject.cFrame; + pInfo->VisualObject.cFrame=0; + + pInfo->VisualObject.cFrame = CreateFrame(&pInfo->VisualObject); + w = (pInfo->VisualObject.cFrame->mbPerRow + 2 * MP4_NUM_EXT_MB) << 4; + h = (pInfo->VisualObject.cFrame->mbPerCol + 2 * MP4_NUM_EXT_MB) << 4; + memcpy(pInfo->VisualObject.cFrame->mid, pInfo->VisualObject.rFrame->mid, w * h + (w * h >> 1)); + } + } + + } + } + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coded) + { + status = mp4_DecodeVOP_P(pInfo); + mp4_PadFrame(pInfo); + // set past and future time for B-VOP + pInfo->VisualObject.VideoObject.rTime = pInfo->VisualObject.VideoObject.nTime; + pInfo->VisualObject.VideoObject.nTime = vop_time; + } + mp4_StatisticInc(&pInfo->VisualObject.Statistic.nVOP_P); +#ifdef USE_NOTCODED_STATE + pInfo->VisualObject.VideoObject.ncStateCleared = 0; +#endif + break; + case MP4_VOP_TYPE_B : + status = MP4_STATUS_OK; + // after reset it is need to skip first B-frames + //if (pInfo->VisualObject.VideoObject.VOPindex >= 2) + //DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + + if (!pInfo->VisualObject.VideoObject.prevPlaneIsB) + { + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.nFrame); + pInfo->VisualObject.nFrame = pInfo->VisualObject.cFrame; + pInfo->VisualObject.cFrame = 0; + pInfo->VisualObject.VideoObject.prevPlaneIsB = 1; + } + else + { + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + pInfo->VisualObject.cFrame=0; + } + if (pInfo->VisualObject.VideoObject.VOPindex < 2) + { + // if we don't have both reference frames + if (pInfo->ftype == 2) + { + //repeat last frame for AVI timing reasons + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.nFrame); + if (pInfo->VisualObject.nFrame) + pInfo->VisualObject.nFrame->outputted = 0; + } + mp4_StatisticInc(&pInfo->VisualObject.Statistic.nVOP_B); + break; + } + + // set Tframe for direct interlaced mode + if (!pInfo->VisualObject.VideoObject.Tframe) + pInfo->VisualObject.VideoObject.Tframe = (int32_t)(vop_time - pInfo->VisualObject.rFrame->time); + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coded) + { + pInfo->VisualObject.VideoObject.TRB = (int32_t)(vop_time - pInfo->VisualObject.VideoObject.rTime); + pInfo->VisualObject.VideoObject.TRD = (int32_t)(pInfo->VisualObject.VideoObject.nTime - pInfo->VisualObject.VideoObject.rTime); + // defense from bad streams when B-VOPs are before Past and/or Future + if (pInfo->VisualObject.VideoObject.TRB <= 0) + pInfo->VisualObject.VideoObject.TRB = 1; + if (pInfo->VisualObject.VideoObject.TRD <= 0) + pInfo->VisualObject.VideoObject.TRD = 2; + if (pInfo->VisualObject.VideoObject.TRD <= pInfo->VisualObject.VideoObject.TRB) + { + pInfo->VisualObject.VideoObject.TRB = 1; + pInfo->VisualObject.VideoObject.TRD = 2; + } + if (pInfo->VisualObject.VideoObject.Tframe >= pInfo->VisualObject.VideoObject.TRD) + pInfo->VisualObject.VideoObject.Tframe = pInfo->VisualObject.VideoObject.TRB; + status = mp4_DecodeVOP_B(pInfo); + } + mp4_StatisticInc(&pInfo->VisualObject.Statistic.nVOP_B); + break; + case MP4_VOP_TYPE_S : + // set new video frame + if (pInfo->VisualObject.VideoObject.sprite_enable == MP4_SPRITE_GMC) + { + if (pInfo->VisualObject.VideoObject.VOPindex > 0) + { + if (pInfo->VisualObject.VideoObject.prevPlaneIsB) + { + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + pInfo->VisualObject.cFrame=0; + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.nFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + pInfo->VisualObject.rFrame = pInfo->VisualObject.nFrame; + pInfo->VisualObject.nFrame = 0; + pInfo->VisualObject.VideoObject.prevPlaneIsB = 0; + } + else + { + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + pInfo->VisualObject.rFrame = pInfo->VisualObject.cFrame; + pInfo->VisualObject.cFrame = 0; + } + } + } + else + { + DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + ReleaseFrame(&pInfo->VisualObject, pInfo->VisualObject.cFrame); + pInfo->VisualObject.cFrame=0; + } + + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coded) + { + status = mp4_DecodeVOP_S(pInfo); + if (pInfo->VisualObject.VideoObject.sprite_enable == MP4_SPRITE_GMC) + { + mp4_PadFrame(pInfo); + // set past and future time for B-VOP + pInfo->VisualObject.VideoObject.rTime = pInfo->VisualObject.VideoObject.nTime; + pInfo->VisualObject.VideoObject.nTime = vop_time; + } +#ifdef USE_NOTCODED_STATE + // Clear not_coded MB state + if ((pInfo->VisualObject.VideoObject.sprite_enable != MP4_SPRITE_STATIC) && pInfo->VisualObject.VideoObject.obmc_disable && !pInfo->VisualObject.VideoObject.ncStateCleared) + { + ippsZero_8u(pInfo->VisualObject.VideoObject.ncState, pInfo->VisualObject.VideoObject.MacroBlockPerVOP); + pInfo->VisualObject.VideoObject.ncStateCleared = 1; + } +#endif + } + mp4_StatisticInc(&pInfo->VisualObject.Statistic.nVOP_S); + break; + } + if (!pInfo->VisualObject.VideoObject.VideoObjectPlane.coded) + { + //pInfo->VisualObject.rFrame->outputted = 0; + //pInfo->VisualObject.cFrame = pInfo->VisualObject.rFrame; + //pInfo->VisualObject.rFrame=0; + //DisplayFrame(&pInfo->VisualObject, pInfo->VisualObject.rFrame); + //ippsCopy_8u(pInfo->VisualObject.rFrame->apY, pInfo->VisualObject.cFrame->apY, pInfo->VisualObject.cFrame->stepY * ((pInfo->VisualObject.VideoObject.MacroBlockPerCol + 2) << 4)); + //ippsCopy_8u(pInfo->VisualObject.rFrame->apCb, pInfo->VisualObject.cFrame->apCb, pInfo->VisualObject.cFrame->stepCb * ((pInfo->VisualObject.VideoObject.MacroBlockPerCol + 2) << 3)); + //ippsCopy_8u(pInfo->VisualObject.rFrame->apCr, pInfo->VisualObject.cFrame->apCr, pInfo->VisualObject.cFrame->stepCr * ((pInfo->VisualObject.VideoObject.MacroBlockPerCol + 2) << 3)); +#ifdef USE_NOTCODED_STATE + ippsSet_8u(1, pInfo->VisualObject.VideoObject.ncState, pInfo->VisualObject.VideoObject.MacroBlockPerVOP); + pInfo->VisualObject.VideoObject.ncStateCleared = 0; +#endif + } + mp4_StatisticInc(&pInfo->VisualObject.Statistic.nVOP); + } + if (pInfo->VisualObject.cFrame) + { + // save current VOP type + pInfo->VisualObject.cFrame->type = pInfo->VisualObject.VideoObject.VideoObjectPlane.coding_type; + // save current VOP time + pInfo->VisualObject.cFrame->time = vop_time; + } + return status; +} + +/* +// Intra DC and AC reconstruction for SVH macroblock +*/ +mp4_Status mp4_DecodeIntraMB_SVH(mp4_Info *pInfo, int32_t pat, int32_t quant, uint8_t *pR[], int32_t stepR[]) +{ + __ALIGN16(int16_t, coeff, 64); + int32_t blockNum, pm = 32, lnz; + + for (blockNum = 0; blockNum < 6; blockNum ++) { + if (ippiReconstructCoeffsIntra_H263_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeff, &lnz, pat & pm, quant, 0, IPPVC_SCAN_ZIGZAG, 0) != ippStsNoErr) { + mp4_Error("Error: decoding coefficients of Inter block"); + return MP4_STATUS_ERROR; + } + if (lnz > 0) { + ippiDCT8x8Inv_16s8u_C1R(coeff, pR[blockNum], stepR[blockNum]); + } else { + mp4_Set8x8_8u(pR[blockNum], stepR[blockNum], (uint8_t)((coeff[0] + 4) >> 3)); + } + if (pat & pm) { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTRA_AC); + } else { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTRA_DC); + } + pm >>= 1; + } + return MP4_STATUS_OK; +} + + +mp4_Status mp4_DecodeInterMB_SVH(mp4_Info *pInfo, int16_t *coeffMB, int32_t quant, int32_t pat) +{ + int32_t i, lnz, pm = 32; + int16_t *coeff = coeffMB; + + for (i = 0; i < 6; i ++) { + if ((pat) & pm) { + if (ippiReconstructCoeffsInter_H263_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeff, &lnz, quant, 0) != ippStsNoErr) { + mp4_Error("Error: decoding coefficients of Inter block"); + return MP4_STATUS_ERROR; + } + if (lnz != 0) { + if ((lnz <= 4) && (coeff[16] == 0)) + ippiDCT8x8Inv_2x2_16s_C1I(coeff); + else if ((lnz <= 13) && (coeff[32] == 0)) + ippiDCT8x8Inv_4x4_16s_C1I(coeff); + else + ippiDCT8x8Inv_16s_C1I(coeff); + } else { + mp4_Set64_16s((int16_t)((coeff[0] + 4) >> 3), coeff); + } + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_C); + } else { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + } + pm >>= 1; + coeff += 64; + } + return MP4_STATUS_OK; +} + +/* +// Intra DC and AC reconstruction for macroblock +*/ +mp4_Status mp4_DecodeIntraMB(mp4_Info *pInfo, int32_t x, int32_t pat, int32_t quant, int32_t dcVLC, int32_t ac_pred_flag, uint8_t *pR[], int32_t stepR[]) +{ + __ALIGN16(int16_t, coeff, 64); + int32_t blockNum, lnz, predDir, scan, dc, dcA, dcB, dcC, dcP, k, nz, predQuantA, predQuantC, dcScaler, pm = 32; + int16_t *predAcA, *predAcC, sDC = 0; + mp4_IntraPredBlock *bCurr; + + for (blockNum = 0; blockNum < 6; blockNum ++) { + // find prediction direction + bCurr = &pInfo->VisualObject.VideoObject.IntraPredBuff.block[6*x+blockNum]; + dcA = bCurr->predA->dct_dc >= 0 ? bCurr->predA->dct_dc : 1024; + dcB = bCurr->predB->dct_dc >= 0 ? bCurr->predB->dct_dc : 1024; + dcC = bCurr->predC->dct_dc >= 0 ? bCurr->predC->dct_dc : 1024; + if (mp4_ABS(dcA - dcB) < mp4_ABS(dcB - dcC)) { + predDir = IPPVC_SCAN_HORIZONTAL; + dcP = dcC; + } else { + predDir = IPPVC_SCAN_VERTICAL; + dcP = dcA; + } + scan = IPPVC_SCAN_ZIGZAG; + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.alternate_vertical_scan_flag) + scan = IPPVC_SCAN_VERTICAL; + else if (ac_pred_flag) + scan = predDir; + // decode coeffs + if (dcVLC) { + if (ippiDecodeDCIntra_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeff, (blockNum < 4) ? IPPVC_BLOCK_LUMA : IPPVC_BLOCK_CHROMA) != ippStsNoErr) { + mp4_Error("Error: decoding DC coefficient of Intra block"); + return MP4_STATUS_ERROR; + } + } + if (pat & pm) { + if (ippiDecodeCoeffsIntra_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeff, &lnz, 0, dcVLC, scan) != ippStsNoErr) { + mp4_Error("Error: decoding coefficients of Intra block"); + return MP4_STATUS_ERROR; + } + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTRA_AC); + } else { + if (dcVLC) + sDC = coeff[0]; + mp4_Zero64_16s(coeff); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTRA_DC); + lnz = 0; + if (dcVLC) + coeff[0] = sDC; + } + // predict DC + dcScaler = (blockNum < 4) ? mp4_DCScalerLuma[quant] : mp4_DCScalerChroma[quant]; + dc = coeff[0] + mp4_DivIntraDC(dcP, dcScaler); + mp4_CLIP(dc, -2048, 2047); + coeff[0] = (int16_t)dc; + // predict AC + nz = 0; + if (ac_pred_flag) { + if (predDir == IPPVC_SCAN_HORIZONTAL && (bCurr->predC->dct_dc >= 0)) { + predAcC = bCurr->predC->dct_acC; + predQuantC = (blockNum == 2 || blockNum == 3) ? quant : pInfo->VisualObject.VideoObject.IntraPredBuff.quant[x+1]; + if (predQuantC == quant) + for (k = 1; k < 8; k ++) { + coeff[k] = (int16_t)(coeff[k] + predAcC[k]); + if (coeff[k]) { + mp4_CLIP(coeff[k], -2048, 2047); + nz = 1; + } + } + else + for (k = 1; k < 8; k ++) { + coeff[k] = (int16_t)(coeff[k] + mp4_DivIntraAC(predAcC[k] * predQuantC, quant)); + if (coeff[k]) { + mp4_CLIP(coeff[k], -2048, 2047); + nz = 1; + } + } + } else if (predDir == IPPVC_SCAN_VERTICAL && (bCurr->predA->dct_dc >= 0)) { + predAcA = bCurr->predA->dct_acA; + predQuantA = (blockNum == 1 || blockNum == 3) ? quant : pInfo->VisualObject.VideoObject.IntraPredBuff.quant[x]; + if (predQuantA == quant) + for (k = 1; k < 8; k ++) { + coeff[k*8] = (int16_t)(coeff[k*8] + predAcA[k]); + if (coeff[k*8]) { + mp4_CLIP(coeff[k*8], -2048, 2047); + nz = 1; + } + } + else + for (k = 1; k < 8; k ++) { + coeff[k*8] = (int16_t)(coeff[k*8] + mp4_DivIntraAC(predAcA[k] * predQuantA, quant)); + if (coeff[k*8]) { + mp4_CLIP(coeff[k*8], -2048, 2047); + nz = 1; + } + } + } + } + // copy predicted AC for future Prediction + for (k = 1; k < 8; k ++) { + bCurr[6].dct_acC[k] = coeff[k]; + bCurr[6].dct_acA[k] = coeff[k*8]; + } + if ((nz | lnz) || (pInfo->VisualObject.VideoObject.quant_type == 1)) { + ippiQuantInvIntra_MPEG4_16s_C1I(coeff, 63, pInfo->VisualObject.VideoObject.QuantInvIntraSpec, quant, (blockNum < 4) ? IPPVC_BLOCK_LUMA : IPPVC_BLOCK_CHROMA); + ippiDCT8x8Inv_16s8u_C1R(coeff, pR[blockNum], stepR[blockNum]); + } else { + k = coeff[0] * dcScaler; + mp4_CLIP(k, -2048, 2047); + coeff[0] = (int16_t)k; + k = (k + 4) >> 3; + mp4_CLIP(k, 0, 255); + mp4_Set8x8_8u(pR[blockNum], stepR[blockNum], (uint8_t)k); + } + // copy DC for future Prediction + if (blockNum >= 3) + pInfo->VisualObject.VideoObject.IntraPredBuff.dcB[blockNum].dct_dc = bCurr[6].dct_dc; + bCurr[6].dct_dc = coeff[0]; + // copy quant + if (blockNum == 5) + pInfo->VisualObject.VideoObject.IntraPredBuff.quant[x+1] = (uint8_t)quant; + pm >>= 1; + } + return MP4_STATUS_OK; +} + +/* +// Intra DC and AC reconstruction for DP macroblock +*/ +mp4_Status mp4_DecodeIntraMB_DP(mp4_Info *pInfo, int16_t dct_dc[], int32_t x, int32_t pat, int32_t quant, int32_t dcVLC, int32_t ac_pred_flag, uint8_t *pR[], int32_t stepR[]) +{ + __ALIGN16(int16_t, coeff, 64); + int32_t blockNum, lnz, predDir, scan, dc, dcA, dcB, dcC, dcP, k, nz, predQuantA, predQuantC, dcScaler, pm = 32; + int16_t *predAcA, *predAcC; + mp4_IntraPredBlock *bCurr; + + for (blockNum = 0; blockNum < 6; blockNum ++) { + // find prediction direction + bCurr = &pInfo->VisualObject.VideoObject.IntraPredBuff.block[6*x+blockNum]; + dcA = bCurr->predA->dct_dc >= 0 ? bCurr->predA->dct_dc : 1024; + dcB = bCurr->predB->dct_dc >= 0 ? bCurr->predB->dct_dc : 1024; + dcC = bCurr->predC->dct_dc >= 0 ? bCurr->predC->dct_dc : 1024; + if (mp4_ABS(dcA - dcB) < mp4_ABS(dcB - dcC)) { + predDir = IPPVC_SCAN_HORIZONTAL; + dcP = dcC; + } else { + predDir = IPPVC_SCAN_VERTICAL; + dcP = dcA; + } + scan = (ac_pred_flag) ? predDir : IPPVC_SCAN_ZIGZAG; + // decode coeffs + if (pat & pm) { + if (ippiDecodeCoeffsIntra_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeff, &lnz, pInfo->VisualObject.VideoObject.reversible_vlc, dcVLC, scan) != ippStsNoErr) { + mp4_Error("Error: decoding coefficients of Intra block"); + return MP4_STATUS_ERROR; + } + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTRA_AC); + } else { + mp4_Zero64_16s(coeff); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTRA_DC); + lnz = 0; + } + if (dcVLC) + coeff[0] = dct_dc[blockNum]; + // predict DC + dcScaler = (blockNum < 4) ? mp4_DCScalerLuma[quant] : mp4_DCScalerChroma[quant]; + dc = coeff[0] + mp4_DivIntraDC(dcP, dcScaler); + mp4_CLIP(dc, -2048, 2047); + coeff[0] = (int16_t)dc; + // predict AC + nz = 0; + if (ac_pred_flag) { + if (predDir == IPPVC_SCAN_HORIZONTAL && (bCurr->predC->dct_dc >= 0)) { + predAcC = bCurr->predC->dct_acC; + predQuantC = (blockNum == 2 || blockNum == 3) ? quant : pInfo->VisualObject.VideoObject.IntraPredBuff.quant[x+1]; + if (predQuantC == quant) + for (k = 1; k < 8; k ++) { + coeff[k] = (int16_t)(coeff[k] + predAcC[k]); // clip ?? + if (coeff[k]) { + mp4_CLIP(coeff[k], -2048, 2047); + nz = 1; + } + } + else + for (k = 1; k < 8; k ++) { + coeff[k] = (int16_t)(coeff[k] + mp4_DivIntraAC(predAcC[k] * predQuantC, quant)); + if (coeff[k]) { + mp4_CLIP(coeff[k], -2048, 2047); + nz = 1; + } + } + } else if (predDir == IPPVC_SCAN_VERTICAL && (bCurr->predA->dct_dc >= 0)) { + predAcA = bCurr->predA->dct_acA; + predQuantA = (blockNum == 1 || blockNum == 3) ? quant : pInfo->VisualObject.VideoObject.IntraPredBuff.quant[x]; + if (predQuantA == quant) + for (k = 1; k < 8; k ++) { + coeff[k*8] = (int16_t)(coeff[k*8] + predAcA[k]); + if (coeff[k*8]) { + mp4_CLIP(coeff[k*8], -2048, 2047); + nz = 1; + } + } + else + for (k = 1; k < 8; k ++) { + coeff[k*8] = (int16_t)(coeff[k*8] + mp4_DivIntraAC(predAcA[k] * predQuantA, quant)); + if (coeff[k*8]) { + mp4_CLIP(coeff[k*8], -2048, 2047); + nz = 1; + } + } + } + } + // copy predicted AC for future Prediction + for (k = 1; k < 8; k ++) { + bCurr[6].dct_acC[k] = coeff[k]; + bCurr[6].dct_acA[k] = coeff[k*8]; + } + if ((nz | lnz) || (pInfo->VisualObject.VideoObject.quant_type == 1)) { + ippiQuantInvIntra_MPEG4_16s_C1I(coeff, 63, pInfo->VisualObject.VideoObject.QuantInvIntraSpec, quant, (blockNum < 4) ? IPPVC_BLOCK_LUMA : IPPVC_BLOCK_CHROMA); + ippiDCT8x8Inv_16s8u_C1R(coeff, pR[blockNum], stepR[blockNum]); + } else { + k = coeff[0] * dcScaler; + mp4_CLIP(k, -2048, 2047); + coeff[0] = (int16_t)k; + k = (k + 4) >> 3; + mp4_CLIP(k, 0, 255); + mp4_Set8x8_8u(pR[blockNum], stepR[blockNum], (uint8_t)k); + } + // copy DC for future Prediction + if (blockNum >= 3) + pInfo->VisualObject.VideoObject.IntraPredBuff.dcB[blockNum].dct_dc = bCurr[6].dct_dc; + bCurr[6].dct_dc = coeff[0]; + // copy quant + if (blockNum == 5) + pInfo->VisualObject.VideoObject.IntraPredBuff.quant[x+1] = (uint8_t)quant; + pm >>= 1; + } + return MP4_STATUS_OK; +} + +/* +// Intra DC and AC reconstruction for macroblock (w/o iDCT) +*/ +mp4_Status mp4_ReconstructCoeffsIntraMB(mp4_Info *pInfo, int32_t x, int32_t pat, int32_t quant, int32_t dcVLC, int32_t ac_pred_flag, int16_t *coeffMB, int32_t lastNZ[]) +{ + int32_t blockNum, lnz, predDir, scan, dc, dcA, dcB, dcC, dcP, k, nz, predQuantA, predQuantC, dcScaler, pm = 32; + int16_t *predAcA, *predAcC, sDC = 0, *coeff = coeffMB; + mp4_IntraPredBlock *bCurr; + + for (blockNum = 0; blockNum < 6; blockNum ++) { + // find prediction direction + bCurr = &pInfo->VisualObject.VideoObject.IntraPredBuff.block[6*x+blockNum]; + dcA = bCurr->predA->dct_dc >= 0 ? bCurr->predA->dct_dc : 1024; + dcB = bCurr->predB->dct_dc >= 0 ? bCurr->predB->dct_dc : 1024; + dcC = bCurr->predC->dct_dc >= 0 ? bCurr->predC->dct_dc : 1024; + if (mp4_ABS(dcA - dcB) < mp4_ABS(dcB - dcC)) { + predDir = IPPVC_SCAN_HORIZONTAL; + dcP = dcC; + } else { + predDir = IPPVC_SCAN_VERTICAL; + dcP = dcA; + } + scan = IPPVC_SCAN_ZIGZAG; + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.alternate_vertical_scan_flag) + scan = IPPVC_SCAN_VERTICAL; + else if (ac_pred_flag) + scan = predDir; + // decode coeffs + if (dcVLC) { + if (ippiDecodeDCIntra_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeff, (blockNum < 4) ? IPPVC_BLOCK_LUMA : IPPVC_BLOCK_CHROMA) != ippStsNoErr) { + mp4_Error("Error: decoding DC coefficient of Intra block"); + return MP4_STATUS_ERROR; + } + } + if (pat & pm) { + if (ippiDecodeCoeffsIntra_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeff, &lnz, 0, dcVLC, scan) != ippStsNoErr) { + mp4_Error("Error: decoding coefficients of Intra block"); + return MP4_STATUS_ERROR; + } + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTRA_AC); + } else { + if (dcVLC) + sDC = coeff[0]; + mp4_Zero64_16s(coeff); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTRA_DC); + lnz = 0; + if (dcVLC) + coeff[0] = sDC; + } + // predict DC + dcScaler = (blockNum < 4) ? mp4_DCScalerLuma[quant] : mp4_DCScalerChroma[quant]; + dc = coeff[0] + mp4_DivIntraDC(dcP, dcScaler); + mp4_CLIP(dc, -2048, 2047); + coeff[0] = (int16_t)dc; + // predict AC + nz = 0; + if (ac_pred_flag) { + if (predDir == IPPVC_SCAN_HORIZONTAL && (bCurr->predC->dct_dc >= 0)) { + predAcC = bCurr->predC->dct_acC; + predQuantC = (blockNum == 2 || blockNum == 3) ? quant : pInfo->VisualObject.VideoObject.IntraPredBuff.quant[x+1]; + if (predQuantC == quant) + for (k = 1; k < 8; k ++) { + coeff[k] = (int16_t)(coeff[k] + predAcC[k]); + if (coeff[k]) { + mp4_CLIP(coeff[k], -2048, 2047); + nz = 1; + } + } + else + for (k = 1; k < 8; k ++) { + coeff[k] = (int16_t)(coeff[k] + mp4_DivIntraAC(predAcC[k] * predQuantC, quant)); + if (coeff[k]) { + mp4_CLIP(coeff[k], -2048, 2047); + nz = 1; + } + } + } else if (predDir == IPPVC_SCAN_VERTICAL && (bCurr->predA->dct_dc >= 0)) { + predAcA = bCurr->predA->dct_acA; + predQuantA = (blockNum == 1 || blockNum == 3) ? quant : pInfo->VisualObject.VideoObject.IntraPredBuff.quant[x]; + if (predQuantA == quant) + for (k = 1; k < 8; k ++) { + coeff[k*8] = (int16_t)(coeff[k*8] + predAcA[k]); + if (coeff[k*8]) { + mp4_CLIP(coeff[k*8], -2048, 2047); + nz = 1; + } + } + else + for (k = 1; k < 8; k ++) { + coeff[k*8] = (int16_t)(coeff[k*8] + mp4_DivIntraAC(predAcA[k] * predQuantA, quant)); + if (coeff[k*8]) { + mp4_CLIP(coeff[k*8], -2048, 2047); + nz = 1; + } + } + } + } + // copy predicted AC for future Prediction + for (k = 1; k < 8; k ++) { + bCurr[6].dct_acC[k] = coeff[k]; + bCurr[6].dct_acA[k] = coeff[k*8]; + } + if ((nz | lnz) || (pInfo->VisualObject.VideoObject.quant_type == 1)) { + ippiQuantInvIntra_MPEG4_16s_C1I(coeff, 63, pInfo->VisualObject.VideoObject.QuantInvIntraSpec, quant, (blockNum < 4) ? IPPVC_BLOCK_LUMA : IPPVC_BLOCK_CHROMA); + lnz = 63; + } else { + k = coeff[0] * dcScaler; + mp4_CLIP(k, -2048, 2047); + coeff[0] = (int16_t)k; + } + // copy DC for future Prediction + if (blockNum >= 3) + pInfo->VisualObject.VideoObject.IntraPredBuff.dcB[blockNum].dct_dc = bCurr[6].dct_dc; + bCurr[6].dct_dc = coeff[0]; + // copy quant + if (blockNum == 5) + pInfo->VisualObject.VideoObject.IntraPredBuff.quant[x+1] = (uint8_t)quant; + lastNZ[blockNum] = lnz; + pm >>= 1; + coeff += 64; + } + return MP4_STATUS_OK; +} + +mp4_Status mp4_DecodeInterMB(mp4_Info *pInfo, int16_t *coeffMB, int32_t quant, int32_t pat, int32_t scan) +{ + int32_t i, lnz, pm = 32; + int16_t *coeff = coeffMB; + + for (i = 0; i < 6; i ++) { + if ((pat) & pm) { + if (ippiReconstructCoeffsInter_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, coeff, &lnz, pInfo->VisualObject.VideoObject.reversible_vlc, scan, pInfo->VisualObject.VideoObject.QuantInvInterSpec, quant) != ippStsNoErr) { + mp4_Error("Error: decoding coefficients of Inter block"); + return MP4_STATUS_ERROR; + } + if (pInfo->VisualObject.VideoObject.quant_type == 0 || (coeff[63] == 0)) { + if (lnz != 0) { + if (scan == IPPVC_SCAN_ZIGZAG) { + if ((lnz <= 4) && (coeff[16] == 0)) + ippiDCT8x8Inv_2x2_16s_C1I(coeff); + else if ((lnz <= 13) && (coeff[32] == 0)) + ippiDCT8x8Inv_4x4_16s_C1I(coeff); + else + ippiDCT8x8Inv_16s_C1I(coeff); + } else { // IPPVC_SCAN_VERTICAL + if ((lnz <= 5) && (coeff[16] == 0) && (coeff[24] == 0)) + ippiDCT8x8Inv_2x2_16s_C1I(coeff); + else if (lnz <= 9) + ippiDCT8x8Inv_4x4_16s_C1I(coeff); + else + ippiDCT8x8Inv_16s_C1I(coeff); + } + } else { + mp4_Set64_16s((int16_t)((coeff[0] + 4) >> 3), coeff); + } + } else { + ippiDCT8x8Inv_16s_C1I(coeff); + } + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_C); + } else { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + } + pm >>= 1; + coeff += 64; + } + return MP4_STATUS_OK; +} + +void mp4_DCTInvCoeffsInterMB(mp4_Info *pInfo, int16_t *coeffMB, int32_t lastNZ[], int32_t pat, int32_t scan) +{ + int32_t i, lnz, pm = 32; + int16_t *coeff = coeffMB; + + for (i = 0; i < 6; i ++) { + if ((pat) & pm) { + if (pInfo->VisualObject.VideoObject.quant_type == 0 || (coeff[63] == 0)) { + lnz = lastNZ[i]; + if (lnz != 0) { + if (scan == IPPVC_SCAN_ZIGZAG) { + if ((lnz <= 4) && (coeff[16] == 0)) + ippiDCT8x8Inv_2x2_16s_C1I(coeff); + else if ((lnz <= 13) && (coeff[32] == 0)) + ippiDCT8x8Inv_4x4_16s_C1I(coeff); + else + ippiDCT8x8Inv_16s_C1I(coeff); + } else { // IPPVC_SCAN_VERTICAL + if ((lnz <= 5) && (coeff[16] == 0) && (coeff[24] == 0)) + ippiDCT8x8Inv_2x2_16s_C1I(coeff); + else if (lnz <= 9) + ippiDCT8x8Inv_4x4_16s_C1I(coeff); + else + ippiDCT8x8Inv_16s_C1I(coeff); + } + } else { + mp4_Set64_16s((int16_t)((coeff[0] + 4) >> 3), coeff); + } + } else { + ippiDCT8x8Inv_16s_C1I(coeff); + } + } + pm >>= 1; + coeff += 64; + } +} + +/* +// decode mcbpc and set MBtype and ChromaPattern +*/ +mp4_Status mp4_DecodeMCBPC_P(mp4_Info* pInfo, int32_t *mbType, int32_t *mbPattern, int32_t stat) +{ + uint32_t code; + int32_t type, pattern; + + code = mp4_ShowBits9(pInfo, 9); + if (code >= 256) { + type = IPPVC_MBTYPE_INTER; + pattern = 0; + mp4_FlushBits(pInfo, 1); + } else { + type = mp4_PVOPmb_type[code]; + pattern = mp4_PVOPmb_cbpc[code]; + mp4_FlushBits(pInfo, mp4_PVOPmb_bits[code]); + } + if (code == 0) { + mp4_Error("Error: decoding MCBPC"); + return MP4_STATUS_ERROR; + } + *mbType = type; + *mbPattern = pattern; + if (stat) { + if (type == IPPVC_MBTYPE_INTER) + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_INTER); + else if (type == IPPVC_MBTYPE_INTER_Q) + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_INTER_Q); + else if (type == IPPVC_MBTYPE_INTRA) + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_INTRA); + else if (type == IPPVC_MBTYPE_INTRA_Q) + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_INTRA_Q); + else if (type == IPPVC_MBTYPE_INTER4V) + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_INTER4V); + } + return MP4_STATUS_OK; +} + +mp4_Status mp4_PredictDecode1MV(mp4_Info *pInfo, mp4_MacroBlock *MBcurr, int32_t y, int32_t x) +{ + IppMotionVector *mvLeft, *mvTop, *mvRight, *mvCurr; + int32_t mbInRow = pInfo->VisualObject.VideoObject.MacroBlockPerRow; + int32_t fcode = pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_forward; + int32_t resync_marker_disable = pInfo->VisualObject.VideoObject.resync_marker_disable; + + // block 0 + mvCurr = MBcurr[0].mv; + mvLeft = MBcurr[-1].mv; + mvTop = MBcurr[-mbInRow].mv; + mvRight = MBcurr[-mbInRow+1].mv; + if (resync_marker_disable) { + if ((y | x) == 0) { + mvCurr[0].dx = mvCurr[0].dy = 0; + } else if (x == 0) { + mvCurr[0].dx = mp4_Median(0, mvTop[2].dx, mvRight[2].dx); + mvCurr[0].dy = mp4_Median(0, mvTop[2].dy, mvRight[2].dy); + } else if (y == 0) { + mvCurr[0] = mvLeft[1]; + } else if (x == mbInRow - 1) { + mvCurr[0].dx = mp4_Median(0, mvLeft[1].dx, mvTop[2].dx); + mvCurr[0].dy = mp4_Median(0, mvLeft[1].dy, mvTop[2].dy); + } else { + mvCurr[0].dx = mp4_Median(mvLeft[1].dx, mvTop[2].dx, mvRight[2].dx); + mvCurr[0].dy = mp4_Median(mvLeft[1].dy, mvTop[2].dy, mvRight[2].dy); + } + } else { + int32_t validLeft, validTop, validRight; + + if (x > 0) + validLeft = MBcurr[-1].validPred; + else + validLeft = 0; + if (y > 0) + validTop = MBcurr[-mbInRow].validPred; + else + validTop = 0; + if ((y > 0) && (x < mbInRow - 1)) + validRight = MBcurr[-mbInRow+1].validPred; + else + validRight = 0; + switch ((validLeft << 2) | (validTop << 1) | validRight) { + case 7: + mvCurr[0].dx = mp4_Median(mvLeft[1].dx, mvTop[2].dx, mvRight[2].dx); + mvCurr[0].dy = mp4_Median(mvLeft[1].dy, mvTop[2].dy, mvRight[2].dy); + break; + case 6: + mvCurr[0].dx = mp4_Median(mvLeft[1].dx, mvTop[2].dx, 0); + mvCurr[0].dy = mp4_Median(mvLeft[1].dy, mvTop[2].dy, 0); + break; + case 5: + mvCurr[0].dx = mp4_Median(mvLeft[1].dx, 0, mvRight[2].dx); + mvCurr[0].dy = mp4_Median(mvLeft[1].dy, 0, mvRight[2].dy); + break; + case 4: + mvCurr[0] = mvLeft[1]; + break; + case 3: + mvCurr[0].dx = mp4_Median(0, mvTop[2].dx, mvRight[2].dx); + mvCurr[0].dy = mp4_Median(0, mvTop[2].dy, mvRight[2].dy); + break; + case 2: + mvCurr[0] = mvTop[2]; + break; + case 1: + mvCurr[0] = mvRight[2]; + break; + default: + mvCurr[0].dx = mvCurr[0].dy = 0; + break; + } + } + return mp4_DecodeMV(pInfo, mvCurr, fcode); +} + +mp4_Status mp4_PredictDecode4MV(mp4_Info *pInfo, mp4_MacroBlock *MBcurr, int32_t y, int32_t x) +{ + IppMotionVector *mvLeft, *mvTop, *mvRight, *mvCurr; + int32_t mbInRow = pInfo->VisualObject.VideoObject.MacroBlockPerRow; + int32_t fcode = pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_forward; + int32_t resync_marker_disable = pInfo->VisualObject.VideoObject.resync_marker_disable; + + mvCurr = MBcurr[0].mv; + mvLeft = MBcurr[-1].mv; + mvTop = MBcurr[-mbInRow].mv; + mvRight = MBcurr[-mbInRow+1].mv; + if (resync_marker_disable) { + // block 0 + if ((y | x) == 0) { + mvCurr[0].dx = mvCurr[0].dy = 0; + } else if (x == 0) { + mvCurr[0].dx = mp4_Median(0, mvTop[2].dx, mvRight[2].dx); + mvCurr[0].dy = mp4_Median(0, mvTop[2].dy, mvRight[2].dy); + } else if (y == 0) { + mvCurr[0] = mvLeft[1]; + } else if (x == mbInRow - 1) { + mvCurr[0].dx = mp4_Median(0, mvLeft[1].dx, mvTop[2].dx); + mvCurr[0].dy = mp4_Median(0, mvLeft[1].dy, mvTop[2].dy); + } else { + mvCurr[0].dx = mp4_Median(mvLeft[1].dx, mvTop[2].dx, mvRight[2].dx); + mvCurr[0].dy = mp4_Median(mvLeft[1].dy, mvTop[2].dy, mvRight[2].dy); + } + if (mp4_DecodeMV(pInfo, mvCurr, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + // block 1 + if (y == 0) { + mvCurr[1] = mvCurr[0]; + } else if (x == mbInRow - 1) { + mvCurr[1].dx = mp4_Median(mvCurr[0].dx, mvTop[3].dx, 0); + mvCurr[1].dy = mp4_Median(mvCurr[0].dy, mvTop[3].dy, 0); + } else { + mvCurr[1].dx = mp4_Median(mvCurr[0].dx, mvTop[3].dx, mvRight[2].dx); + mvCurr[1].dy = mp4_Median(mvCurr[0].dy, mvTop[3].dy, mvRight[2].dy); + } + if (mp4_DecodeMV(pInfo, mvCurr+1, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + // block 2 + if (x == 0) { + mvCurr[2].dx = mp4_Median(0, mvCurr[0].dx, mvCurr[1].dx); + mvCurr[2].dy = mp4_Median(0, mvCurr[0].dy, mvCurr[1].dy); + } else { + mvCurr[2].dx = mp4_Median(mvLeft[3].dx, mvCurr[0].dx, mvCurr[1].dx); + mvCurr[2].dy = mp4_Median(mvLeft[3].dy, mvCurr[0].dy, mvCurr[1].dy); + } + if (mp4_DecodeMV(pInfo, mvCurr+2, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + // block 3 + mvCurr[3].dx = mp4_Median(mvCurr[2].dx, mvCurr[0].dx, mvCurr[1].dx); + mvCurr[3].dy = mp4_Median(mvCurr[2].dy, mvCurr[0].dy, mvCurr[1].dy); + if (mp4_DecodeMV(pInfo, mvCurr+3, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + } else { + int32_t validLeft, validTop, validRight; + + if (x > 0) + validLeft = MBcurr[-1].validPred; + else + validLeft = 0; + if (y > 0) + validTop = MBcurr[-mbInRow].validPred; + else + validTop = 0; + if ((y > 0) && (x < mbInRow - 1)) + validRight = MBcurr[-mbInRow+1].validPred; + else + validRight = 0; + // block 0 + switch ((validLeft << 2) | (validTop << 1) | validRight) { + case 7: + mvCurr[0].dx = mp4_Median(mvLeft[1].dx, mvTop[2].dx, mvRight[2].dx); + mvCurr[0].dy = mp4_Median(mvLeft[1].dy, mvTop[2].dy, mvRight[2].dy); + break; + case 6: + mvCurr[0].dx = mp4_Median(mvLeft[1].dx, mvTop[2].dx, 0); + mvCurr[0].dy = mp4_Median(mvLeft[1].dy, mvTop[2].dy, 0); + break; + case 5: + mvCurr[0].dx = mp4_Median(mvLeft[1].dx, 0, mvRight[2].dx); + mvCurr[0].dy = mp4_Median(mvLeft[1].dy, 0, mvRight[2].dy); + break; + case 4: + mvCurr[0] = mvLeft[1]; + break; + case 3: + mvCurr[0].dx = mp4_Median(0, mvTop[2].dx, mvRight[2].dx); + mvCurr[0].dy = mp4_Median(0, mvTop[2].dy, mvRight[2].dy); + break; + case 2: + mvCurr[0] = mvTop[2]; + break; + case 1: + mvCurr[0] = mvRight[2]; + break; + default: + mvCurr[0].dx = mvCurr[0].dy = 0; + break; + } + if (mp4_DecodeMV(pInfo, mvCurr, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + // block 1 + switch ((validTop << 1) | validRight) { + case 3: + mvCurr[1].dx = mp4_Median(mvCurr[0].dx, mvTop[3].dx, mvRight[2].dx); + mvCurr[1].dy = mp4_Median(mvCurr[0].dy, mvTop[3].dy, mvRight[2].dy); + break; + case 2: + mvCurr[1].dx = mp4_Median(mvCurr[0].dx, mvTop[3].dx, 0); + mvCurr[1].dy = mp4_Median(mvCurr[0].dy, mvTop[3].dy, 0); + break; + case 1: + mvCurr[1].dx = mp4_Median(mvCurr[0].dx, 0, mvRight[2].dx); + mvCurr[1].dy = mp4_Median(mvCurr[0].dy, 0, mvRight[2].dy); + break; + default: + mvCurr[1] = mvCurr[0]; + break; + } + if (mp4_DecodeMV(pInfo, mvCurr+1, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + // block 2 + if (validLeft) { + mvCurr[2].dx = mp4_Median(mvLeft[3].dx, mvCurr[0].dx, mvCurr[1].dx); + mvCurr[2].dy = mp4_Median(mvLeft[3].dy, mvCurr[0].dy, mvCurr[1].dy); + } else { + mvCurr[2].dx = mp4_Median(0, mvCurr[0].dx, mvCurr[1].dx); + mvCurr[2].dy = mp4_Median(0, mvCurr[0].dy, mvCurr[1].dy); + } + if (mp4_DecodeMV(pInfo, mvCurr+2, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + // block 3 + mvCurr[3].dx = mp4_Median(mvCurr[2].dx, mvCurr[0].dx, mvCurr[1].dx); + mvCurr[3].dy = mp4_Median(mvCurr[2].dy, mvCurr[0].dy, mvCurr[1].dy); + if (mp4_DecodeMV(pInfo, mvCurr+3, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + } + return MP4_STATUS_OK; +} + +mp4_Status mp4_PredictDecodeFMV(mp4_Info *pInfo, mp4_MacroBlock *MBcurr, int32_t y, int32_t x, IppMotionVector *mvT, IppMotionVector *mvB) +{ + IppMotionVector mvLeft = {0, 0}, mvTop = {0, 0}, mvRight = {0, 0}, mvPred; + int32_t mbInRow = pInfo->VisualObject.VideoObject.MacroBlockPerRow; + int32_t fcode = pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_forward; + int32_t resync_marker_disable = pInfo->VisualObject.VideoObject.resync_marker_disable; + + if (x > 0) { + mvLeft = MBcurr[-1].mv[1]; + mvLeft.dy = (int16_t)mp4_Div2(mvLeft.dy); + } + if (y > 0) { + mvTop = MBcurr[-mbInRow].mv[2]; + mvTop.dy = (int16_t)mp4_Div2(mvTop.dy); + if (x < (mbInRow - 1)) { + mvRight = MBcurr[-mbInRow+1].mv[2]; + mvRight.dy = (int16_t)mp4_Div2(mvRight.dy); + } + } + if (resync_marker_disable) { + if ((y | x) == 0) { + mvPred.dx = mvPred.dy = 0; + } else if (x == 0) { + mvPred.dx = mp4_Median(0, mvTop.dx, mvRight.dx); + mvPred.dy = mp4_Median(0, mvTop.dy, mvRight.dy); + } else if (y == 0) { + mvPred = mvLeft; + } else if (x == mbInRow - 1) { + mvPred.dx = mp4_Median(0, mvLeft.dx, mvTop.dx); + mvPred.dy = mp4_Median(0, mvLeft.dy, mvTop.dy); + } else { + mvPred.dx = mp4_Median(mvLeft.dx, mvTop.dx, mvRight.dx); + mvPred.dy = mp4_Median(mvLeft.dy, mvTop.dy, mvRight.dy); + } + } else { + int32_t validLeft, validTop, validRight; + + if (x > 0) + validLeft = MBcurr[-1].validPred; + else + validLeft = 0; + if (y > 0) + validTop = MBcurr[-mbInRow].validPred; + else + validTop = 0; + if ((y > 0) && (x < mbInRow - 1)) + validRight = MBcurr[-mbInRow+1].validPred; + else + validRight = 0; + switch ((validLeft << 2) | (validTop << 1) | validRight) { + case 7: + mvPred.dx = mp4_Median(mvLeft.dx, mvTop.dx, mvRight.dx); + mvPred.dy = mp4_Median(mvLeft.dy, mvTop.dy, mvRight.dy); + break; + case 6: + mvPred.dx = mp4_Median(mvLeft.dx, mvTop.dx, 0); + mvPred.dy = mp4_Median(mvLeft.dy, mvTop.dy, 0); + break; + case 5: + mvPred.dx = mp4_Median(mvLeft.dx, 0, mvRight.dx); + mvPred.dy = mp4_Median(mvLeft.dy, 0, mvRight.dy); + break; + case 4: + mvPred = mvLeft; + break; + case 3: + mvPred.dx = mp4_Median(0, mvTop.dx, mvRight.dx); + mvPred.dy = mp4_Median(0, mvTop.dy, mvRight.dy); + break; + case 2: + mvPred = mvTop; + break; + case 1: + mvPred = mvRight; + break; + default: + mvPred.dx = mvPred.dy = 0; + break; + } + } + *mvT = mvPred; + if (mp4_DecodeMV(pInfo, mvT, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + *mvB = mvPred; + if (mp4_DecodeMV(pInfo, mvB, fcode) != MP4_STATUS_OK) + return MP4_STATUS_ERROR; + // update MV buffer for future prediction + MBcurr->mv[0].dx = MBcurr->mv[1].dx = MBcurr->mv[2].dx = MBcurr->mv[3].dx = (int16_t)mp4_Div2Round(mvT->dx + mvB->dx); + MBcurr->mv[0].dy = MBcurr->mv[1].dy = MBcurr->mv[2].dy = MBcurr->mv[3].dy = (int16_t)(mvT->dy + mvB->dy); + return MP4_STATUS_OK; +} + +void mp4_OBMC(mp4_Info *pInfo, mp4_MacroBlock *pMBinfo, IppMotionVector *mvCur, int32_t colNum, int32_t rowNum, IppiRect limitRectL, uint8_t *pYc, int32_t stepYc, uint8_t *pYr, int32_t stepYr, int32_t cbpy, int16_t *coeffMB, int32_t dct_type) +{ + IppMotionVector mvOBMCL, mvOBMCU, mvOBMCR, mvOBMCB, *mvLeft, *mvUpper, *mvRight; + int32_t mbPerRow = pInfo->VisualObject.VideoObject.MacroBlockPerRow, dx, dy, rt; + + // get Right MV + if (colNum == mbPerRow - 1) + mvRight = &mvCur[1]; + else if (pMBinfo[1].type >= IPPVC_MBTYPE_INTRA) + mvRight = &mvCur[1]; + else + mvRight = pMBinfo[1].mv; + // get Left MV + if (colNum == 0) + mvLeft = mvCur - 1; + else if (pMBinfo[-1].type >= IPPVC_MBTYPE_INTRA) + mvLeft = mvCur - 1; + else + mvLeft = pMBinfo[-1].mv; + // get Upper MV + if (rowNum == 0) + mvUpper = mvCur - 2; + else if (pMBinfo[-mbPerRow].type >= IPPVC_MBTYPE_INTRA) + mvUpper = mvCur - 2; + else + mvUpper = pMBinfo[-mbPerRow].mv; + dx = colNum * 16; + dy = rowNum * 16; + rt = pInfo->VisualObject.VideoObject.VideoObjectPlane.rounding_type; + if (pInfo->VisualObject.VideoObject.quarter_sample) { + mp4_LimitMVQ(&mvLeft[1], &mvOBMCL, &limitRectL, dx, dy, 8); + mp4_LimitMVQ(&mvUpper[2], &mvOBMCU, &limitRectL, dx, dy, 8); + mp4_LimitMVQ(&mvCur[1], &mvOBMCR, &limitRectL, dx, dy, 8); + mp4_LimitMVQ(&mvCur[2], &mvOBMCB, &limitRectL, dx, dy, 8); + ippiOBMC8x8QP_MPEG4_8u_C1R(pYr, stepYr, pYc, stepYc, &mvCur[0], &mvOBMCL, &mvOBMCR, &mvOBMCU, &mvOBMCB, rt); + mp4_LimitMVQ(&mvCur[0], &mvOBMCL, &limitRectL, dx+8, dy, 8); + mp4_LimitMVQ(&mvUpper[3], &mvOBMCU, &limitRectL, dx+8, dy, 8); + mp4_LimitMVQ(&mvRight[0], &mvOBMCR, &limitRectL, dx+8, dy, 8); + mp4_LimitMVQ(&mvCur[3], &mvOBMCB, &limitRectL, dx+8, dy, 8); + ippiOBMC8x8QP_MPEG4_8u_C1R(pYr+8, stepYr, pYc+8, stepYc, &mvCur[1], &mvOBMCL, &mvOBMCR, &mvOBMCU, &mvOBMCB, rt); + mp4_LimitMVQ(&mvLeft[3], &mvOBMCL, &limitRectL, dx, dy+8, 8); + mp4_LimitMVQ(&mvCur[0], &mvOBMCU, &limitRectL, dx, dy+8, 8); + mp4_LimitMVQ(&mvCur[3], &mvOBMCR, &limitRectL, dx, dy+8, 8); + ippiOBMC8x8QP_MPEG4_8u_C1R(pYr+stepYr*8, stepYr, pYc+stepYc*8, stepYc, &mvCur[2], &mvOBMCL, &mvOBMCR, &mvOBMCU, &mvCur[2], rt); + mp4_LimitMVQ(&mvCur[2], &mvOBMCL, &limitRectL, dx+8, dy+8, 8); + mp4_LimitMVQ(&mvCur[1], &mvOBMCU, &limitRectL, dx+8, dy+8, 8); + mp4_LimitMVQ(&mvRight[2], &mvOBMCR, &limitRectL, dx+8, dy+8, 8); + ippiOBMC8x8QP_MPEG4_8u_C1R(pYr+8+stepYr*8, stepYr, pYc+8+stepYc*8, stepYc, &mvCur[3], &mvOBMCL, &mvOBMCR, &mvOBMCU, &mvCur[3], rt); + } else { + mp4_LimitMV(&mvLeft[1], &mvOBMCL, &limitRectL, dx, dy, 8); + mp4_LimitMV(&mvUpper[2], &mvOBMCU, &limitRectL, dx, dy, 8); + mp4_LimitMV(&mvCur[1], &mvOBMCR, &limitRectL, dx, dy, 8); + mp4_LimitMV(&mvCur[2], &mvOBMCB, &limitRectL, dx, dy, 8); + ippiOBMC8x8HP_MPEG4_8u_C1R(pYr, stepYr, pYc, stepYc, &mvCur[0], &mvOBMCL, &mvOBMCR, &mvOBMCU, &mvOBMCB, rt); + mp4_LimitMV(&mvCur[0], &mvOBMCL, &limitRectL, dx+8, dy, 8); + mp4_LimitMV(&mvUpper[3], &mvOBMCU, &limitRectL, dx+8, dy, 8); + mp4_LimitMV(&mvRight[0], &mvOBMCR, &limitRectL, dx+8, dy, 8); + mp4_LimitMV(&mvCur[3], &mvOBMCB, &limitRectL, dx+8, dy, 8); + ippiOBMC8x8HP_MPEG4_8u_C1R(pYr+8, stepYr, pYc+8, stepYc, &mvCur[1], &mvOBMCL, &mvOBMCR, &mvOBMCU, &mvOBMCB, rt); + mp4_LimitMV(&mvLeft[3], &mvOBMCL, &limitRectL, dx, dy+8, 8); + mp4_LimitMV(&mvCur[0], &mvOBMCU, &limitRectL, dx, dy+8, 8); + mp4_LimitMV(&mvCur[3], &mvOBMCR, &limitRectL, dx, dy+8, 8); + ippiOBMC8x8HP_MPEG4_8u_C1R(pYr+stepYr*8, stepYr, pYc+stepYc*8, stepYc, &mvCur[2], &mvOBMCL, &mvOBMCR, &mvOBMCU, &mvCur[2], rt); + mp4_LimitMV(&mvCur[2], &mvOBMCL, &limitRectL, dx+8, dy+8, 8); + mp4_LimitMV(&mvCur[1], &mvOBMCU, &limitRectL, dx+8, dy+8, 8); + mp4_LimitMV(&mvRight[2], &mvOBMCR, &limitRectL, dx+8, dy+8, 8); + ippiOBMC8x8HP_MPEG4_8u_C1R(pYr+8+stepYr*8, stepYr, pYc+8+stepYc*8, stepYc, &mvCur[3], &mvOBMCL, &mvOBMCR, &mvOBMCU, &mvCur[3], rt); + } + if (!dct_type) { + mp4_AddResidual(cbpy & 8, pYc, stepYc, coeffMB); + mp4_AddResidual(cbpy & 4, pYc+8, stepYc, coeffMB+64); + mp4_AddResidual(cbpy & 2, pYc+stepYc*8, stepYc, coeffMB+128); + mp4_AddResidual(cbpy & 1, pYc+stepYc*8+8, stepYc, coeffMB+192); + } else { + mp4_AddResidual(cbpy & 8, pYc, stepYc*2, coeffMB); + mp4_AddResidual(cbpy & 4, pYc+8, stepYc*2, coeffMB+64); + mp4_AddResidual(cbpy & 2, pYc+stepYc, stepYc*2, coeffMB+128); + mp4_AddResidual(cbpy & 1, pYc+stepYc+8, stepYc*2, coeffMB+192); + } +} + + +void mp4_CopyMacroBlocks(const mp4_Frame *rFrame, mp4_Frame *cFrame, int32_t mbPerRow, int32_t rowNum, int32_t colNum, int32_t n) +{ + int32_t i, stepYr, stepYc, stepCbr, stepCbc, stepCrr, stepCrc; + uint8_t *pYc, *pCbc, *pCrc, *pYr, *pCbr, *pCrr; + + if (n <= 0) + return; + stepYc = cFrame->stepY; + stepCbc = cFrame->stepCb; + stepCrc = cFrame->stepCr; + stepYr = rFrame->stepY; + stepCbr = rFrame->stepCb; + stepCrr = rFrame->stepCr; + pYc = cFrame->pY + (rowNum * stepYc + colNum) * 16; + pCbc = cFrame->pCb + (rowNum * stepCbc + colNum) * 8; + pCrc = cFrame->pCr + (rowNum * stepCrc + colNum) * 8; + pYr = rFrame->pY + (rowNum * stepYr + colNum) * 16; + pCbr = rFrame->pCb + (rowNum * stepCbr + colNum) * 8; + pCrr = rFrame->pCr + (rowNum * stepCrr + colNum) * 8; + for (i = rowNum * mbPerRow + colNum; i < rowNum * mbPerRow + colNum + n; i ++) { + ippiCopy16x16_8u_C1R(pYr, stepYr, pYc, stepYc); + ippiCopy8x8_8u_C1R(pCbr, stepCbr, pCbc, stepCbc); + ippiCopy8x8_8u_C1R(pCrr, stepCrr, pCrc, stepCrc); + if ((i + 1) % mbPerRow == 0) { + pYc += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pCbc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pCrc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + pYr += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYr << 4) - stepYr; + pCbr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbr << 3) - stepCbr; + pCrr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrr << 3) - stepCrr; + } else { + pYc += 16; pCrc += 8; pCbc += 8; + pYr += 16; pCrr += 8; pCbr += 8; + } + } +} + + +// added by benski +mp4_Frame *CreateFrame(mp4_VisualObject *object) +{ + if (object->frame_cache) + { + mp4_Frame *ret = object->frame_cache; + object->frame_cache = ret->next; + ret->next = 0; + ret->reference_count = 1; + return ret; + } + else + { + mp4_Frame *ret = (mp4_Frame *)calloc(1, sizeof(mp4_Frame)); + ret->reference_count = 1; + ret->sprite = 0; + ret->mbPerRow = (object->VideoObject.width + 15) >> 4; + ret->mbPerCol = (object->VideoObject.height + 15) >> 4; + AllocateInitFrame(ret); + return ret; + } +} + +mp4_Frame *CreateSpriteFrame(mp4_VisualObject *object) +{ + if (object->sprite_cache) + { + mp4_Frame *ret = object->sprite_cache; + object->sprite_cache = ret->next; + ret->next = 0; + ret->reference_count = 1; + return ret; + } + else + { + mp4_Frame *ret = (mp4_Frame *)calloc(1, sizeof(mp4_Frame)); + ret->reference_count = 1; + ret->sprite = 1; + ret->mbPerRow = (object->VideoObject.sprite_width + 15) >> 4; + ret->mbPerCol = (object->VideoObject.sprite_height + 15) >> 4; + AllocateInitFrame(ret); + return ret; + } +} + +/* to delete +free(decoder->dec.VisualObject.cFrame.mid); +decoder->dec.VisualObject.cFrame.mid = 0; +*/ +void ReleaseFrame(mp4_VisualObject *object, mp4_Frame *frame) +{ + if (frame && --frame->reference_count == 0) + { + if (frame->outputted == 0) + { +// DebugBreak(); + } + frame->outputted = 0; + if (frame->sprite) + { + frame->next = object->sprite_cache; + object->sprite_cache = frame; + } + else + { + frame->next = object->frame_cache; + object->frame_cache = frame; + } + } +} + +mp4_Frame *GetDisplayFrame(mp4_VisualObject *object) +{ + mp4_Frame *ret = object->display_frames; + if (ret) + { + object->display_frames = ret->next; + ret->next = 0; + } + return ret; +} + +void DisplayFrame(mp4_VisualObject *object, mp4_Frame *frame) +{ + if (frame) + { + mp4_Frame *tail = object->display_frames; + if (frame->outputted) + { + DebugBreak(); + } + frame->outputted = 1; + frame->reference_count++; + if (tail) + { + while (tail->next) + { + tail = tail->next; + } + tail->next = frame; + frame->next = 0; + } + else + { + object->display_frames = frame; + frame->next = 0; + } + } +} + +void FreeCache(mp4_VisualObject *object) +{ + while (object->display_frames) + { + mp4_Frame *frame = object->display_frames; + object->display_frames = frame->next; + free(frame->mid); + free(frame); + } + + while (object->frame_cache) + { + mp4_Frame *frame = object->frame_cache; + object->frame_cache = frame->next; + free(frame->mid); + free(frame); + } + + while (object->sprite_cache) + { + mp4_Frame *frame = object->frame_cache; + object->frame_cache = frame->next; + free(frame->mid); + free(frame); + } +} diff --git a/Src/mpeg4dec/mp4decvopb.c b/Src/mpeg4dec/mp4decvopb.c new file mode 100644 index 00000000..7b65ae02 --- /dev/null +++ b/Src/mpeg4dec/mp4decvopb.c @@ -0,0 +1,831 @@ +/* /////////////////////////////////////////////////////////////////////// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 2001-2007 Intel Corporation. All Rights Reserved. +// +// Description: Decodes B-VOPs +// +*/ + + +#include "mp4def.h" +#include "mp4dec.h" + +/* +// Purpose: decode MPEG-4 BVOP +*/ +mp4_Status mp4_DecodeVOP_B(mp4_Info* pInfo) +{ + __ALIGN16(int16_t, coeffMB, 64*6); + __ALIGN16(uint8_t, tmpMB, 64*4); + uint32_t code; + uint8_t *pYc, *pCbc, *pCrc, *pYp, *pCbp, *pCrp, *pYn, *pCbn, *pCrn, *pc, *pr, *pn; + int32_t stepYp, stepYc, stepYn, stepCbp, stepCbc, stepCbn, stepCrp, stepCrc, stepCrn, mbPerRow, mbPerCol; + int32_t dx, dy, TRB, TRD, quant, mbCurr, mbInVideoPacket, colNum, rowNum; + IppiRect limitRectL, limitRectC; + int32_t quarter_sample, modb, mb_type, cbpb, dct_type, field_prediction, rvlc = 0, scan; + int32_t mb_ftfr, mb_fbfr, mb_btfr, mb_bbfr, fcode_forward, fcode_backward; + mp4_MacroBlock *pMBinfo; + mp4_Status sts; + + sts = MP4_STATUS_OK; + + if (!pInfo->VisualObject.cFrame) + pInfo->VisualObject.cFrame = CreateFrame(&pInfo->VisualObject); + stepYc = pInfo->VisualObject.cFrame->stepY; + stepYp = pInfo->VisualObject.rFrame->stepY; + stepYn = pInfo->VisualObject.nFrame->stepY; + stepCbc = pInfo->VisualObject.cFrame->stepCb; + stepCbp = pInfo->VisualObject.rFrame->stepCb; + stepCbn = pInfo->VisualObject.nFrame->stepCb; + stepCrc = pInfo->VisualObject.cFrame->stepCr; + stepCrp = pInfo->VisualObject.rFrame->stepCr; + stepCrn = pInfo->VisualObject.nFrame->stepCr; + pYc = pInfo->VisualObject.cFrame->pY; + pCbc = pInfo->VisualObject.cFrame->pCb; + pCrc = pInfo->VisualObject.cFrame->pCr; + pYp = pInfo->VisualObject.rFrame->pY; + pCbp = pInfo->VisualObject.rFrame->pCb; + pCrp = pInfo->VisualObject.rFrame->pCr; + pYn = pInfo->VisualObject.nFrame->pY; + pCbn = pInfo->VisualObject.nFrame->pCb; + pCrn = pInfo->VisualObject.nFrame->pCr; + quarter_sample = pInfo->VisualObject.VideoObject.quarter_sample; + scan = pInfo->VisualObject.VideoObject.VideoObjectPlane.alternate_vertical_scan_flag ? IPPVC_SCAN_VERTICAL : IPPVC_SCAN_ZIGZAG; + fcode_forward = pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_forward; + fcode_backward = pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_backward; + // Bounding rectangles for MV limitation + limitRectL.x = - 16 * MP4_NUM_EXT_MB; + limitRectL.y = - 16 * MP4_NUM_EXT_MB; + limitRectL.width = pInfo->VisualObject.VideoObject.width + 16 * 2 * MP4_NUM_EXT_MB; + limitRectL.height = pInfo->VisualObject.VideoObject.height + 16 * 2 * MP4_NUM_EXT_MB; + limitRectC.x = -8 * MP4_NUM_EXT_MB; + limitRectC.y = -8 * MP4_NUM_EXT_MB; + limitRectC.width = (pInfo->VisualObject.VideoObject.width >> 1) + 8 * 2 * MP4_NUM_EXT_MB; + limitRectC.height = (pInfo->VisualObject.VideoObject.height >> 1) + 8 * 2 * MP4_NUM_EXT_MB; + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant; + mbPerRow = pInfo->VisualObject.VideoObject.MacroBlockPerRow; + mbPerCol = pInfo->VisualObject.VideoObject.MacroBlockPerCol; + mbCurr = colNum = rowNum = 0; + TRD = pInfo->VisualObject.VideoObject.TRD; + TRB = pInfo->VisualObject.VideoObject.TRB; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo; +// decode interlaced B-VOP + if (pInfo->VisualObject.VideoObject.interlaced) { + IppMotionVector mvCbCrF, mvCbCrB, mvForwT, mvBackT, mvForwB, mvBackB, mvForw[4], mvBack[4], mvCbCrFFT, mvCbCrFFB, mvCbCrBFT, mvCbCrBFB, *mvField = pInfo->VisualObject.VideoObject.FieldMV; + + // warning "variable may be used without having been initialized" + mvCbCrF.dx = mvCbCrF.dy = mvCbCrB.dx = mvCbCrB.dy = mvCbCrFFT.dx = mvCbCrFFT.dy = mvCbCrFFB.dx = mvCbCrFFB.dy = mvCbCrBFT.dx = mvCbCrBFT.dy = mvCbCrBFB.dx = mvCbCrBFB.dy = 0; + mb_ftfr = mb_fbfr = mb_btfr = mb_bbfr = 0; + for (;;) { + mbInVideoPacket = 0; + // reset MV predictors at new VideoPacket + mvForwT.dx = mvForwT.dy = mvBackT.dx = mvBackT.dy = mvForwB.dx = mvForwB.dy = mvBackB.dx = mvBackB.dy = 0; + // decode B-VOP macroblocks + for (;;) { + if (pMBinfo->not_coded) { + ippiCopy16x16_8u_C1R(pYp, stepYp, pYc, stepYc); + ippiCopy8x8_8u_C1R(pCbp, stepCbp, pCbc, stepCbc); + ippiCopy8x8_8u_C1R(pCrp, stepCrp, pCrc, stepCrc); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_NOTCODED); + } else { + cbpb = 0; + if (mp4_GetBit(pInfo)) { + modb = 2; + mb_type = IPPVC_MBTYPE_DIRECT; + } else { + modb = mp4_GetBit(pInfo); + // decode mb_type + code = mp4_ShowBits9(pInfo, 4); + if (code != 0) { + mb_type = mp4_BVOPmb_type[code].code; + mp4_FlushBits(pInfo, mp4_BVOPmb_type[code].len); + } else { + mp4_Error("Error when decode mb_type of B-VOP macroblock"); + goto Err_1; + } + if (modb == 0) + cbpb = mp4_GetBits9(pInfo, 6); + if (mb_type != IPPVC_MBTYPE_DIRECT && cbpb != 0) + mp4_UpdateQuant_B(pInfo, quant); + } + dct_type = 0; + field_prediction = 0; + if (cbpb != 0) + dct_type = mp4_GetBit(pInfo); + if (mb_type != IPPVC_MBTYPE_DIRECT) { + field_prediction = mp4_GetBit(pInfo); + if (field_prediction) { + if (mb_type != IPPVC_MBTYPE_BACKWARD) { + mb_ftfr = mp4_GetBit(pInfo); + mb_fbfr = mp4_GetBit(pInfo); + } + if (mb_type != IPPVC_MBTYPE_FORWARD) { + mb_btfr = mp4_GetBit(pInfo); + mb_bbfr = mp4_GetBit(pInfo); + } + } + } + // coordinates of current MB for limitation + dx = colNum * 16; + dy = rowNum * 16; + if (mb_type == IPPVC_MBTYPE_FORWARD) { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_FORWARD); + if (!field_prediction) { + if (mp4_DecodeMV(pInfo, &mvForwT, fcode_forward) != MP4_STATUS_OK) + goto Err_1; + if (quarter_sample) { + mp4_LimitMVQ(&mvForwT, &mvForw[0], &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(&mvForw[0], &mvCbCrF); + mp4_Copy16x16QP_8u(pYp, stepYp, pYc, stepYc, &mvForw[0], 0); + } else { + mp4_LimitMV(&mvForwT, &mvForw[0], &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(&mvForw[0], &mvCbCrF); + mp4_Copy16x16HP_8u(pYp, stepYp, pYc, stepYc, &mvForw[0], 0); + } + //mvForw[1] = mvForw[2] = mvForw[3] = mvForw[0]; + mvForwB = mvForwT; + } else { + mvForwT.dy = (int16_t)mp4_Div2(mvForwT.dy); + if (mp4_DecodeMV(pInfo, &mvForwT, fcode_forward) != MP4_STATUS_OK) + goto Err_1; + mvForwB.dy = (int16_t)mp4_Div2(mvForwB.dy); + if (mp4_DecodeMV(pInfo, &mvForwB, fcode_forward) != MP4_STATUS_OK) + goto Err_1; + if (quarter_sample) { + mp4_LimitFMVQ(&mvForwT, &mvForw[0], &limitRectL, dx, dy, 16); + mp4_Copy16x8QP_8u(pYp+(mb_ftfr ? stepYp : 0), stepYp*2, pYc, stepYc*2, &mvForw[0], 0); + mvForw[0].dx = (int16_t)mp4_Div2(mvForw[0].dx); + mvForw[0].dy = (int16_t)(mp4_Div2(mvForw[0].dy*2) >> 1); + mp4_LimitFMVQ(&mvForwB, &mvForw[2], &limitRectL, dx, dy, 16); + mp4_Copy16x8QP_8u(pYp+(mb_fbfr ? stepYp : 0), stepYp*2, pYc+stepYc, stepYc*2, &mvForw[2], 0); + mvForw[2].dx = (int16_t)mp4_Div2(mvForw[2].dx); + mvForw[2].dy = (int16_t)(mp4_Div2(mvForw[2].dy*2) >> 1); + } else { + mp4_LimitFMV(&mvForwT, &mvForw[0], &limitRectL, dx, dy, 16); + mp4_Copy16x8HP_8u(pYp+(mb_ftfr ? stepYp : 0), stepYp*2, pYc, stepYc*2, &mvForw[0], 0); + mp4_LimitFMV(&mvForwB, &mvForw[2], &limitRectL, dx, dy, 16); + mp4_Copy16x8HP_8u(pYp+(mb_fbfr ? stepYp : 0), stepYp*2, pYc+stepYc, stepYc*2, &mvForw[2], 0); + } + mvForwT.dy <<= 1; + mvForwB.dy <<= 1; + //mvForw[1] = mvForw[0]; + //mvForw[3] = mvForw[2]; + mp4_ComputeChromaMV(&mvForw[0], &mvCbCrFFT); + mp4_ComputeChromaMV(&mvForw[2], &mvCbCrFFB); + } + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, cbpb, scan) != MP4_STATUS_OK) + goto Err_1; + if (!dct_type) { + mp4_AddResidual(cbpb & 32, pYc, stepYc, coeffMB); + mp4_AddResidual(cbpb & 16, pYc+8, stepYc, coeffMB+64); + mp4_AddResidual(cbpb & 8, pYc+stepYc*8, stepYc, coeffMB+128); + mp4_AddResidual(cbpb & 4, pYc+stepYc*8+8, stepYc, coeffMB+192); + } else { + mp4_AddResidual(cbpb & 32, pYc, stepYc*2, coeffMB); + mp4_AddResidual(cbpb & 16, pYc+8, stepYc*2, coeffMB+64); + mp4_AddResidual(cbpb & 8, pYc+stepYc, stepYc*2, coeffMB+128); + mp4_AddResidual(cbpb & 4, pYc+stepYc+8, stepYc*2, coeffMB+192); + } + if (!field_prediction) { + mp4_MC_HP(cbpb & 2, pCbp, stepCbp, pCbc, stepCbc, coeffMB+256, &mvCbCrF, 0); + mp4_MC_HP(cbpb & 1, pCrp, stepCrp, pCrc, stepCrc, coeffMB+320, &mvCbCrF, 0); + } else { + mp4_Copy8x4HP_8u(pCbp+(mb_ftfr ? stepCbp : 0), stepCbp*2, pCbc, stepCbc*2, &mvCbCrFFT, 0); + mp4_Copy8x4HP_8u(pCrp+(mb_ftfr ? stepCrp : 0), stepCrp*2, pCrc, stepCrc*2, &mvCbCrFFT, 0); + mp4_Copy8x4HP_8u(pCbp+(mb_fbfr ? stepCbp : 0), stepCbp*2, pCbc+stepCbc, stepCbc*2, &mvCbCrFFB, 0); + mp4_Copy8x4HP_8u(pCrp+(mb_fbfr ? stepCrp : 0), stepCrp*2, pCrc+stepCrc, stepCrc*2, &mvCbCrFFB, 0); + mp4_AddResidual(cbpb & 2, pCbc, stepCbc, coeffMB+256); + mp4_AddResidual(cbpb & 1, pCrc, stepCrc, coeffMB+320); + } + } else if (mb_type == IPPVC_MBTYPE_BACKWARD) { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_BACKWARD); + if (!field_prediction) { + if (mp4_DecodeMV(pInfo, &mvBackT, fcode_backward) != MP4_STATUS_OK) + goto Err_1; + if (quarter_sample) { + mp4_LimitMVQ(&mvBackT, &mvBack[0], &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(&mvBack[0], &mvCbCrB); + mp4_Copy16x16QP_8u(pYn, stepYn, pYc, stepYc, &mvBack[0], 0); + } else { + mp4_LimitMV(&mvBackT, &mvBack[0], &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(&mvBack[0], &mvCbCrB); + mp4_Copy16x16HP_8u(pYn, stepYn, pYc, stepYc, &mvBack[0], 0); + } + //mvBack[1] = mvBack[2] = mvBack[3] = mvBack[0]; + mvBackB = mvBackT; + } else { + mvBackT.dy = (int16_t)mp4_Div2(mvBackT.dy); + if (mp4_DecodeMV(pInfo, &mvBackT, fcode_backward) != MP4_STATUS_OK) + goto Err_1; + mvBackB.dy = (int16_t)mp4_Div2(mvBackB.dy); + if (mp4_DecodeMV(pInfo, &mvBackB, fcode_backward) != MP4_STATUS_OK) + goto Err_1; + if (quarter_sample) { + mp4_LimitFMVQ(&mvBackT, &mvBack[0], &limitRectL, dx, dy, 16); + mp4_Copy16x8QP_8u(pYn+(mb_btfr ? stepYn : 0), stepYn*2, pYc, stepYc*2, &mvBack[0], 0); + mvBack[0].dx = (int16_t)mp4_Div2(mvBack[0].dx); + mvBack[0].dy = (int16_t)(mp4_Div2(mvBack[0].dy*2) >> 1); + mp4_LimitFMVQ(&mvBackB, &mvBack[2], &limitRectL, dx, dy, 16); + mp4_Copy16x8QP_8u(pYn+(mb_bbfr ? stepYn : 0), stepYn*2, pYc+stepYc, stepYc*2, &mvBack[2], 0); + mvBack[2].dx = (int16_t)mp4_Div2(mvBack[2].dx); + mvBack[2].dy = (int16_t)(mp4_Div2(mvBack[2].dy*2) >> 1); + } else { + mp4_LimitFMV(&mvBackT, &mvBack[0], &limitRectL, dx, dy, 16); + mp4_Copy16x8HP_8u(pYn+(mb_btfr ? stepYn : 0), stepYn*2, pYc, stepYc*2, &mvBack[0], 0); + mp4_LimitFMV(&mvBackB, &mvBack[2], &limitRectL, dx, dy, 16); + mp4_Copy16x8HP_8u(pYn+(mb_bbfr ? stepYn : 0), stepYn*2, pYc+stepYc, stepYc*2, &mvBack[2], 0); + } + mvBackT.dy <<= 1; + mvBackB.dy <<= 1; + //mvBack[1] = mvBack[0]; + //mvBack[3] = mvBack[2]; + mp4_ComputeChromaMV(&mvBack[0], &mvCbCrBFT); + mp4_ComputeChromaMV(&mvBack[2], &mvCbCrBFB); + } + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, cbpb, scan) != MP4_STATUS_OK) + goto Err_1; + if (!dct_type) { + mp4_AddResidual(cbpb & 32, pYc, stepYc, coeffMB); + mp4_AddResidual(cbpb & 16, pYc+8, stepYc, coeffMB+64); + mp4_AddResidual(cbpb & 8, pYc+stepYc*8, stepYc, coeffMB+128); + mp4_AddResidual(cbpb & 4, pYc+stepYc*8+8, stepYc, coeffMB+192); + } else { + mp4_AddResidual(cbpb & 32, pYc, stepYc*2, coeffMB); + mp4_AddResidual(cbpb & 16, pYc+8, stepYc*2, coeffMB+64); + mp4_AddResidual(cbpb & 8, pYc+stepYc, stepYc*2, coeffMB+128); + mp4_AddResidual(cbpb & 4, pYc+stepYc+8, stepYc*2, coeffMB+192); + } + if (!field_prediction) { + mp4_MC_HP(cbpb & 2, pCbn, stepCbn, pCbc, stepCbc, coeffMB+256, &mvCbCrB, 0); + mp4_MC_HP(cbpb & 1, pCrn, stepCrn, pCrc, stepCrc, coeffMB+320, &mvCbCrB, 0); + } else { + mp4_Copy8x4HP_8u(pCbn+(mb_btfr ? stepCbn : 0), stepCbn*2, pCbc, stepCbc*2, &mvCbCrBFT, 0); + mp4_Copy8x4HP_8u(pCrn+(mb_btfr ? stepCrn : 0), stepCrn*2, pCrc, stepCrc*2, &mvCbCrBFT, 0); + mp4_Copy8x4HP_8u(pCbn+(mb_bbfr ? stepCbn : 0), stepCbn*2, pCbc+stepCbc, stepCbc*2, &mvCbCrBFB, 0); + mp4_Copy8x4HP_8u(pCrn+(mb_bbfr ? stepCrn : 0), stepCrn*2, pCrc+stepCrc, stepCrc*2, &mvCbCrBFB, 0); + mp4_AddResidual(cbpb & 2, pCbc, stepCbc, coeffMB+256); + mp4_AddResidual(cbpb & 1, pCrc, stepCrc, coeffMB+320); + } + } else if (mb_type == IPPVC_MBTYPE_INTERPOLATE) { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_INTERPOLATE); + if (!field_prediction) { + if (mp4_DecodeMV(pInfo, &mvForwT, fcode_forward) != MP4_STATUS_OK) + goto Err_1; + if (mp4_DecodeMV(pInfo, &mvBackT, fcode_backward) != MP4_STATUS_OK) + goto Err_1; + if (quarter_sample) { + mp4_LimitMVQ(&mvForwT, &mvForw[0], &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(&mvForw[0], &mvCbCrF); + mp4_Copy16x16QP_8u(pYp, stepYp, pYc, stepYc, &mvForw[0], 0); + mp4_LimitMVQ(&mvBackT, &mvBack[0], &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(&mvBack[0], &mvCbCrB); + mp4_Copy16x16QP_8u(pYn, stepYn, tmpMB, 16, &mvBack[0], 0); + } else { + mp4_LimitMV(&mvForwT, &mvForw[0], &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(&mvForw[0], &mvCbCrF); + mp4_Copy16x16HP_8u(pYp, stepYp, pYc, stepYc, &mvForw[0], 0); + mp4_LimitMV(&mvBackT, &mvBack[0], &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(&mvBack[0], &mvCbCrB); + mp4_Copy16x16HP_8u(pYn, stepYn, tmpMB, 16, &mvBack[0], 0); + } + //mvForw[1] = mvForw[2] = mvForw[3] = mvForw[0]; + mvForwB = mvForwT; + //mvBack[1] = mvBack[2] = mvBack[3] = mvBack[0]; + mvBackB = mvBackT; + } else { + mvForwT.dy = (int16_t)mp4_Div2(mvForwT.dy); + if (mp4_DecodeMV(pInfo, &mvForwT, fcode_forward) != MP4_STATUS_OK) + goto Err_1; + mvForwB.dy = (int16_t)mp4_Div2(mvForwB.dy); + if (mp4_DecodeMV(pInfo, &mvForwB, fcode_forward) != MP4_STATUS_OK) + goto Err_1; + mvBackT.dy = (int16_t)mp4_Div2(mvBackT.dy); + if (mp4_DecodeMV(pInfo, &mvBackT, fcode_backward) != MP4_STATUS_OK) + goto Err_1; + mvBackB.dy = (int16_t)mp4_Div2(mvBackB.dy); + if (mp4_DecodeMV(pInfo, &mvBackB, fcode_backward) != MP4_STATUS_OK) + goto Err_1; + if (quarter_sample) { + mp4_LimitFMVQ(&mvForwT, &mvForw[0], &limitRectL, dx, dy, 16); + mp4_Copy16x8QP_8u(pYp+(mb_ftfr ? stepYp : 0), stepYp*2, pYc, stepYc*2, &mvForw[0], 0); + mvForw[0].dx = (int16_t)mp4_Div2(mvForw[0].dx); + mvForw[0].dy = (int16_t)(mp4_Div2(mvForw[0].dy*2) >> 1); + mp4_LimitFMVQ(&mvForwB, &mvForw[2], &limitRectL, dx, dy, 16); + mp4_Copy16x8QP_8u(pYp+(mb_fbfr ? stepYp : 0), stepYp*2, pYc+stepYc, stepYc*2, &mvForw[2], 0); + mvForw[2].dx = (int16_t)mp4_Div2(mvForw[2].dx); + mvForw[2].dy = (int16_t)(mp4_Div2(mvForw[2].dy*2) >> 1); + mp4_LimitFMVQ(&mvBackT, &mvBack[0], &limitRectL, dx, dy, 16); + mp4_Copy16x8QP_8u(pYn+(mb_btfr ? stepYn : 0), stepYn*2, tmpMB, 32, &mvBack[0], 0); + mvBack[0].dx = (int16_t)mp4_Div2(mvBack[0].dx); + mvBack[0].dy = (int16_t)(mp4_Div2(mvBack[0].dy*2) >> 1); + mp4_LimitFMVQ(&mvBackB, &mvBack[2], &limitRectL, dx, dy, 16); + mp4_Copy16x8QP_8u(pYn+(mb_bbfr ? stepYn : 0), stepYn*2, tmpMB+16, 32, &mvBack[2], 0); + mvBack[2].dx = (int16_t)mp4_Div2(mvBack[2].dx); + mvBack[2].dy = (int16_t)(mp4_Div2(mvBack[2].dy*2) >> 1); + } else { + mp4_LimitFMV(&mvForwT, &mvForw[0], &limitRectL, dx, dy, 16); + mp4_Copy16x8HP_8u(pYp+(mb_ftfr ? stepYp : 0), stepYp*2, pYc, stepYc*2, &mvForw[0], 0); + mp4_LimitFMV(&mvForwB, &mvForw[2], &limitRectL, dx, dy, 16); + mp4_Copy16x8HP_8u(pYp+(mb_fbfr ? stepYp : 0), stepYp*2, pYc+stepYc, stepYc*2, &mvForw[2], 0); + mp4_LimitFMV(&mvBackT, &mvBack[0], &limitRectL, dx, dy, 16); + mp4_Copy16x8HP_8u(pYn+(mb_btfr ? stepYn : 0), stepYn*2, tmpMB, 32, &mvBack[0], 0); + mp4_LimitFMV(&mvBackB, &mvBack[2], &limitRectL, dx, dy, 16); + mp4_Copy16x8HP_8u(pYn+(mb_bbfr ? stepYn : 0), stepYn*2, tmpMB+16, 32, &mvBack[2], 0); + } + mvForwT.dy <<= 1; + mvForwB.dy <<= 1; + mvBackT.dy <<= 1; + mvBackB.dy <<= 1; + //mvForw[1] = mvForw[0]; + //mvForw[3] = mvForw[2]; + //mvBack[1] = mvBack[0]; + //mvBack[3] = mvBack[2]; + mp4_ComputeChromaMV(&mvForw[0], &mvCbCrFFT); + mp4_ComputeChromaMV(&mvForw[2], &mvCbCrFFB); + mp4_ComputeChromaMV(&mvBack[0], &mvCbCrBFT); + mp4_ComputeChromaMV(&mvBack[2], &mvCbCrBFB); + } + ippiAverage16x16_8u_C1IR(tmpMB, 16, pYc, stepYc); + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, cbpb, scan) != MP4_STATUS_OK) + goto Err_1; + if (!dct_type) { + mp4_AddResidual(cbpb & 32, pYc, stepYc, coeffMB); + mp4_AddResidual(cbpb & 16, pYc+8, stepYc, coeffMB+64); + mp4_AddResidual(cbpb & 8, pYc+stepYc*8, stepYc, coeffMB+128); + mp4_AddResidual(cbpb & 4, pYc+stepYc*8+8, stepYc, coeffMB+192); + } else { + mp4_AddResidual(cbpb & 32, pYc, stepYc*2, coeffMB); + mp4_AddResidual(cbpb & 16, pYc+8, stepYc*2, coeffMB+64); + mp4_AddResidual(cbpb & 8, pYc+stepYc, stepYc*2, coeffMB+128); + mp4_AddResidual(cbpb & 4, pYc+stepYc+8, stepYc*2, coeffMB+192); + } + if (!field_prediction) { + mp4_Copy8x8HP_8u(pCbp, stepCbp, pCbc, stepCbc, &mvCbCrF, 0); + mp4_Copy8x8HP_8u(pCrp, stepCrp, pCrc, stepCrc, &mvCbCrF, 0); + mp4_Copy8x8HP_8u(pCbn, stepCbn, tmpMB, 8, &mvCbCrB, 0); + mp4_Copy8x8HP_8u(pCrn, stepCrn, tmpMB+64, 8, &mvCbCrB, 0); + } else { + mp4_Copy8x4HP_8u(pCbp+(mb_ftfr ? stepCbp : 0), stepCbp*2, pCbc, stepCbc*2, &mvCbCrFFT, 0); + mp4_Copy8x4HP_8u(pCrp+(mb_ftfr ? stepCrp : 0), stepCrp*2, pCrc, stepCrc*2, &mvCbCrFFT, 0); + mp4_Copy8x4HP_8u(pCbp+(mb_fbfr ? stepCbp : 0), stepCbp*2, pCbc+stepCbc, stepCbc*2, &mvCbCrFFB, 0); + mp4_Copy8x4HP_8u(pCrp+(mb_fbfr ? stepCrp : 0), stepCrp*2, pCrc+stepCrc, stepCrc*2, &mvCbCrFFB, 0); + mp4_Copy8x4HP_8u(pCbn+(mb_btfr ? stepCbn : 0), stepCbn*2, tmpMB, 16, &mvCbCrBFT, 0); + mp4_Copy8x4HP_8u(pCrn+(mb_btfr ? stepCrn : 0), stepCrn*2, tmpMB+64, 16, &mvCbCrBFT, 0); + mp4_Copy8x4HP_8u(pCbn+(mb_bbfr ? stepCbn : 0), stepCbn*2, tmpMB+8, 16, &mvCbCrBFB, 0); + mp4_Copy8x4HP_8u(pCrn+(mb_bbfr ? stepCrn : 0), stepCrn*2, tmpMB+64+8, 16, &mvCbCrBFB, 0); + } + ippiAverage8x8_8u_C1IR(tmpMB, 8, pCbc, stepCbc); + ippiAverage8x8_8u_C1IR(tmpMB+64, 8, pCrc, stepCrc); + mp4_AddResidual(cbpb & 2, pCbc, stepCbc, coeffMB+256); + mp4_AddResidual(cbpb & 1, pCrc, stepCrc, coeffMB+320); + } else { // IPPVC_MBTYPE_DIRECT + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_DIRECT); + field_prediction = pMBinfo->field_info & 1; + if (!field_prediction) { + // frame direct mode + if (mp4_DecodeMV_Direct(pInfo, pMBinfo->mv, mvForw, mvBack, TRB, TRD, modb, pMBinfo->type) != MP4_STATUS_OK) + goto Err_1; + if (quarter_sample) { + mp4_ComputeChroma4MVQ(mvForw, &mvCbCrF); + mp4_Limit4MVQ(mvForw, mvForw, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MVQ(mvBack, &mvCbCrB); + mp4_Limit4MVQ(mvBack, mvBack, &limitRectL, dx, dy, 8); + pc = pYc; + pr = pYp; + pn = pYn; + mp4_Copy8x8QP_8u(pr, stepYp, pc, stepYc, &mvForw[0], 0); + mp4_Copy8x8QP_8u(pn, stepYn, tmpMB, 16, &mvBack[0], 0); + mp4_Copy8x8QP_8u(pr+8, stepYp, pc+8, stepYc, &mvForw[1], 0); + mp4_Copy8x8QP_8u(pn+8, stepYn, tmpMB+8, 16, &mvBack[1], 0); + pc = pYc + stepYc * 8; + pr = pYp + stepYp * 8; + pn = pYn + stepYn * 8; + mp4_Copy8x8QP_8u(pr, stepYp, pc, stepYc, &mvForw[2], 0); + mp4_Copy8x8QP_8u(pn, stepYn, tmpMB+128, 16, &mvBack[2], 0); + mp4_Copy8x8QP_8u(pr+8, stepYp, pc+8, stepYc, &mvForw[3], 0); + mp4_Copy8x8QP_8u(pn+8, stepYn, tmpMB+136, 16, &mvBack[3], 0); + } else { + mp4_ComputeChroma4MV(mvForw, &mvCbCrF); + mp4_Limit4MV(mvForw, mvForw, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MV(mvBack, &mvCbCrB); + mp4_Limit4MV(mvBack, mvBack, &limitRectL, dx, dy, 8); + pc = pYc; + pr = pYp; + pn = pYn; + mp4_Copy8x8HP_8u(pr, stepYp, pc, stepYc, &mvForw[0], 0); + mp4_Copy8x8HP_8u(pn, stepYn, tmpMB, 16, &mvBack[0], 0); + mp4_Copy8x8HP_8u(pr+8, stepYp, pc+8, stepYc, &mvForw[1], 0); + mp4_Copy8x8HP_8u(pn+8, stepYn, tmpMB+8, 16, &mvBack[1], 0); + pc = pYc + stepYc * 8; + pr = pYp + stepYp * 8; + pn = pYn + stepYn * 8; + mp4_Copy8x8HP_8u(pr, stepYp, pc, stepYc, &mvForw[2], 0); + mp4_Copy8x8HP_8u(pn, stepYn, tmpMB+128, 16, &mvBack[2], 0); + mp4_Copy8x8HP_8u(pr+8, stepYp, pc+8, stepYc, &mvForw[3], 0); + mp4_Copy8x8HP_8u(pn+8, stepYn, tmpMB+136, 16, &mvBack[3], 0); + } + mp4_LimitMV(&mvCbCrF, &mvCbCrF, &limitRectC, dx >> 1, dy >> 1, 8); + mp4_LimitMV(&mvCbCrB, &mvCbCrB, &limitRectC, dx >> 1, dy >> 1, 8); + } else { + mb_ftfr = (pMBinfo->field_info >> 1) & 1; + mb_fbfr = (pMBinfo->field_info >> 2) & 1; + if (mp4_DecodeMV_DirectField(pInfo, mb_ftfr, mb_fbfr, &mvField[0], &mvField[1], &mvForw[0], &mvForw[2], &mvBack[0], &mvBack[2], TRB, TRD, modb) != MP4_STATUS_OK) + goto Err_1; + if (quarter_sample) { + mp4_LimitFMVQ(&mvForw[0], &mvForw[0], &limitRectL, dx, dy, 16); + mp4_LimitFMVQ(&mvForw[2], &mvForw[2], &limitRectL, dx, dy, 16); + mp4_LimitFMVQ(&mvBack[0], &mvBack[0], &limitRectL, dx, dy, 16); + mp4_LimitFMVQ(&mvBack[2], &mvBack[2], &limitRectL, dx, dy, 16); + mp4_Copy16x8QP_8u(pYp+(mb_ftfr ? stepYp : 0), stepYp*2, pYc, stepYc*2, &mvForw[0], 0); + mp4_Copy16x8QP_8u(pYp+(mb_fbfr ? stepYp : 0), stepYp*2, pYc+stepYc, stepYc*2, &mvForw[2], 0); + mp4_Copy16x8QP_8u(pYn/*+stepYn*mb_btfr*/, stepYn*2, tmpMB, 32, &mvBack[0], 0); + mp4_Copy16x8QP_8u(pYn+stepYn/**mb_bbfr*/, stepYn*2, tmpMB+16, 32, &mvBack[2], 0); + mvForw[0].dx = (int16_t)mp4_Div2(mvForw[0].dx); + mvForw[0].dy = (int16_t)(mp4_Div2(mvForw[0].dy*2) >> 1); + mvForw[2].dx = (int16_t)mp4_Div2(mvForw[2].dx); + mvForw[2].dy = (int16_t)(mp4_Div2(mvForw[2].dy*2) >> 1); + mvBack[0].dx = (int16_t)mp4_Div2(mvBack[0].dx); + mvBack[0].dy = (int16_t)(mp4_Div2(mvBack[0].dy*2) >> 1); + mvBack[2].dx = (int16_t)mp4_Div2(mvBack[2].dx); + mvBack[2].dy = (int16_t)(mp4_Div2(mvBack[2].dy*2) >> 1); + } else { + mp4_LimitFMV(&mvForw[0], &mvForw[0], &limitRectL, dx, dy, 16); + mp4_LimitFMV(&mvForw[2], &mvForw[2], &limitRectL, dx, dy, 16); + mp4_LimitFMV(&mvBack[0], &mvBack[0], &limitRectL, dx, dy, 16); + mp4_LimitFMV(&mvBack[2], &mvBack[2], &limitRectL, dx, dy, 16); + mp4_Copy16x8HP_8u(pYp+(mb_ftfr ? stepYp : 0), stepYp*2, pYc, stepYc*2, &mvForw[0], 0); + mp4_Copy16x8HP_8u(pYp+(mb_fbfr ? stepYp : 0), stepYp*2, pYc+stepYc, stepYc*2, &mvForw[2], 0); + mp4_Copy16x8HP_8u(pYn/*+stepYn*mb_btfr*/, stepYn*2, tmpMB, 32, &mvBack[0], 0); + mp4_Copy16x8HP_8u(pYn+stepYn/**mb_bbfr*/, stepYn*2, tmpMB+16, 32, &mvBack[2], 0); + } + mp4_ComputeChromaMV(&mvForw[0], &mvCbCrFFT); + mp4_ComputeChromaMV(&mvForw[2], &mvCbCrFFB); + mp4_ComputeChromaMV(&mvBack[0], &mvCbCrBFT); + mp4_ComputeChromaMV(&mvBack[2], &mvCbCrBFB); + } + ippiAverage16x16_8u_C1IR(tmpMB, 16, pYc, stepYc); + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, cbpb, scan) != MP4_STATUS_OK) + goto Err_1; + if (!dct_type) { + mp4_AddResidual(cbpb & 32, pYc, stepYc, coeffMB); + mp4_AddResidual(cbpb & 16, pYc+8, stepYc, coeffMB+64); + mp4_AddResidual(cbpb & 8, pYc+stepYc*8, stepYc, coeffMB+128); + mp4_AddResidual(cbpb & 4, pYc+stepYc*8+8, stepYc, coeffMB+192); + } else { + mp4_AddResidual(cbpb & 32, pYc, stepYc*2, coeffMB); + mp4_AddResidual(cbpb & 16, pYc+8, stepYc*2, coeffMB+64); + mp4_AddResidual(cbpb & 8, pYc+stepYc, stepYc*2, coeffMB+128); + mp4_AddResidual(cbpb & 4, pYc+stepYc+8, stepYc*2, coeffMB+192); + } + if (!field_prediction) { + mp4_Copy8x8HP_8u(pCbp, stepCbp, pCbc, stepCbc, &mvCbCrF, 0); + mp4_Copy8x8HP_8u(pCrp, stepCrp, pCrc, stepCrc, &mvCbCrF, 0); + mp4_Copy8x8HP_8u(pCbn, stepCbn, tmpMB, 8, &mvCbCrB, 0); + mp4_Copy8x8HP_8u(pCrn, stepCrn, tmpMB+64, 8, &mvCbCrB, 0); + } else { + mp4_Copy8x4HP_8u(pCbp+(mb_ftfr ? stepCbp : 0), stepCbp*2, pCbc, stepCbc*2, &mvCbCrFFT, 0); + mp4_Copy8x4HP_8u(pCrp+(mb_ftfr ? stepCrp : 0), stepCrp*2, pCrc, stepCrc*2, &mvCbCrFFT, 0); + mp4_Copy8x4HP_8u(pCbp+(mb_fbfr ? stepCbp : 0), stepCbp*2, pCbc+stepCbc, stepCbc*2, &mvCbCrFFB, 0); + mp4_Copy8x4HP_8u(pCrp+(mb_fbfr ? stepCrp : 0), stepCrp*2, pCrc+stepCrc, stepCrc*2, &mvCbCrFFB, 0); + mp4_Copy8x4HP_8u(pCbn/*+(mb_btfr ? stepCbn : 0)*/, stepCbn*2, tmpMB, 16, &mvCbCrBFT, 0); + mp4_Copy8x4HP_8u(pCrn/*+(mb_btfr ? stepCrn : 0)*/, stepCrn*2, tmpMB+64, 16, &mvCbCrBFT, 0); + mp4_Copy8x4HP_8u(pCbn+/*(mb_bbfr ? */stepCbn/* : 0)*/, stepCbn*2, tmpMB+8, 16, &mvCbCrBFB, 0); + mp4_Copy8x4HP_8u(pCrn+/*(mb_bbfr ? */stepCrn/* : 0)*/, stepCrn*2, tmpMB+64+8, 16, &mvCbCrBFB, 0); + } + ippiAverage8x8_8u_C1IR(tmpMB, 8, pCbc, stepCbc); + ippiAverage8x8_8u_C1IR(tmpMB+64, 8, pCrc, stepCrc); + mp4_AddResidual(cbpb & 2, pCbc, stepCbc, coeffMB+256); + mp4_AddResidual(cbpb & 1, pCrc, stepCrc, coeffMB+320); + } + } + //mbCurr ++; + mbInVideoPacket ++; + colNum ++; + pMBinfo ++; + mvField += 2; + if (colNum == mbPerRow) { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) + return sts; + pYc += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pCbc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pCrc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + pYp += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYp << 4) - stepYp; + pCbp += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbp << 3) - stepCbp; + pCrp += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrp << 3) - stepCrp; + pYn += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYn << 4) - stepYn; + pCbn += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbn << 3) - stepCbn; + pCrn += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrn << 3) - stepCrn; + // reset MV predictors at new row + mvForwT.dx = mvForwT.dy = mvBackT.dx = mvBackT.dy = mvForwB.dx = mvForwB.dy = mvBackB.dx = mvBackB.dy = 0; + } else { + pYc += 16; pCrc += 8; pCbc += 8; + pYp += 16; pCrp += 8; pCbp += 8; + pYn += 16; pCrn += 8; pCbn += 8; + } + if (!pInfo->VisualObject.VideoObject.resync_marker_disable) { + int32_t found; +ErrRet_1: + if (mp4_CheckDecodeVideoPacket(pInfo, &found) == MP4_STATUS_OK) { + if (found) { + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant_scale; + mbCurr = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, mbCurr - rowNum * mbPerRow - colNum); + rowNum = mbCurr / mbPerRow; + colNum = mbCurr % mbPerRow; + pYc = pInfo->VisualObject.cFrame->pY + (rowNum * stepYc + colNum) * 16; pCbc = pInfo->VisualObject.cFrame->pCb + (rowNum * stepCbc + colNum) * 8; pCrc = pInfo->VisualObject.cFrame->pCr + (rowNum * stepCrc + colNum) * 8; + pYp = pInfo->VisualObject.rFrame->pY + (rowNum * stepYp + colNum) * 16; pCbp = pInfo->VisualObject.rFrame->pCb + (rowNum * stepCbp + colNum) * 8; pCrp = pInfo->VisualObject.rFrame->pCr + (rowNum * stepCrp + colNum) * 8; + pYn = pInfo->VisualObject.nFrame->pY + (rowNum * stepYn + colNum) * 16; pCbn = pInfo->VisualObject.nFrame->pCb + (rowNum * stepCbn + colNum) * 8; pCrn = pInfo->VisualObject.nFrame->pCr + (rowNum * stepCrn + colNum) * 8; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo + mbCurr; + break; + } + } else + goto Err_1; + } + } + } +Err_1: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (pInfo->VisualObject.VideoObject.resync_marker_disable || !mp4_SeekResyncMarker(pInfo)) + { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_1; + } +// decode usual B-VOP + for (;;) { + IppMotionVector mvCbCrF, mvCbCrB, mvForw, mvBack, mvForwLim, mvBackLim; + + mbInVideoPacket = 0; + // reset MV predictors at new VideoPacket + mvForw.dx = mvForw.dy = mvBack.dx = mvBack.dy = 0; + // decode B-VOP macroblocks + for (;;) { + if (pMBinfo->not_coded) { + ippiCopy16x16_8u_C1R(pYp, stepYp, pYc, stepYc); + ippiCopy8x8_8u_C1R(pCbp, stepCbp, pCbc, stepCbc); + ippiCopy8x8_8u_C1R(pCrp, stepCrp, pCrc, stepCrc); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_NOTCODED); + } else { + cbpb = 0; + if (mp4_GetBit(pInfo)) { + modb = 2; + mb_type = IPPVC_MBTYPE_DIRECT; + } else { + modb = mp4_GetBit(pInfo); + // decode mb_type + code = mp4_ShowBits9(pInfo, 4); + if (code != 0) { + mb_type = mp4_BVOPmb_type[code].code; + mp4_FlushBits(pInfo, mp4_BVOPmb_type[code].len); + } else { + mp4_Error("Error when decode mb_type of B-VOP macroblock"); + goto Err_2; + } + if (modb == 0) + cbpb = mp4_GetBits9(pInfo, 6); + if (mb_type != IPPVC_MBTYPE_DIRECT && cbpb != 0) + mp4_UpdateQuant_B(pInfo, quant); + } + // coordinates of current MB for limitation + dx = colNum * 16; + dy = rowNum * 16; + if (mb_type == IPPVC_MBTYPE_FORWARD) { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_FORWARD); + if (mp4_DecodeMV(pInfo, &mvForw, fcode_forward) != MP4_STATUS_OK) + goto Err_2; + if (quarter_sample) { + mp4_LimitMVQ(&mvForw, &mvForwLim, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(&mvForwLim, &mvCbCrF); + mp4_Copy16x16QP_8u(pYp, stepYp, pYc, stepYc, &mvForwLim, 0); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 32, pYc, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 16, pYc+8, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 8, pYc+8*stepYc, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 4, pYc+8*stepYc+8, stepYc, Err_2); + } else { + mp4_LimitMV(&mvForw, &mvForwLim, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(&mvForwLim, &mvCbCrF); + if (cbpb & 60) { + mp4_DecodeMCBlockInter_MPEG4(cbpb & 32, pYp, stepYp, pYc, stepYc, mvForwLim, 0, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpb & 16, pYp+8, stepYp, pYc+8, stepYc, mvForwLim, 0, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpb & 8, pYp+8*stepYp, stepYp, pYc+8*stepYc, stepYc, mvForwLim, 0, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpb & 4, pYp+8*stepYp+8, stepYp, pYc+8*stepYc+8, stepYc, mvForwLim, 0, Err_2); + } else { + mp4_Copy16x16HP_8u(pYp, stepYp, pYc, stepYc, &mvForwLim, 0); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + } + } + mp4_DecodeMCBlockInter_MPEG4(cbpb & 2, pCbp, stepCbp, pCbc, stepCbc, mvCbCrF, 0, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpb & 1, pCrp, stepCrp, pCrc, stepCrc, mvCbCrF, 0, Err_2); + } else if (mb_type == IPPVC_MBTYPE_BACKWARD) { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_BACKWARD); + if (mp4_DecodeMV(pInfo, &mvBack, fcode_backward) != MP4_STATUS_OK) + goto Err_2; + if (quarter_sample) { + mp4_LimitMVQ(&mvBack, &mvBackLim, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(&mvBackLim, &mvCbCrB); + mp4_Copy16x16QP_8u(pYn, stepYn, pYc, stepYc, &mvBackLim, 0); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 32, pYc, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 16, pYc+8, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 8, pYc+8*stepYc, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 4, pYc+8*stepYc+8, stepYc, Err_2); + } else { + mp4_LimitMV(&mvBack, &mvBackLim, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(&mvBackLim, &mvCbCrB); + if (cbpb & 60) { + mp4_DecodeMCBlockInter_MPEG4(cbpb & 32, pYn, stepYn, pYc, stepYc, mvBackLim, 0, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpb & 16, pYn+8, stepYn, pYc+8, stepYc, mvBackLim, 0, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpb & 8, pYn+8*stepYn, stepYp, pYc+8*stepYc, stepYc, mvBackLim, 0, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpb & 4, pYn+8*stepYn+8, stepYp, pYc+8*stepYc+8, stepYc, mvBackLim, 0, Err_2); + } else { + mp4_Copy16x16HP_8u(pYn, stepYn, pYc, stepYc, &mvBackLim, 0); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + } + } + mp4_DecodeMCBlockInter_MPEG4(cbpb & 2, pCbn, stepCbn, pCbc, stepCbc, mvCbCrB, 0, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpb & 1, pCrn, stepCrn, pCrc, stepCrc, mvCbCrB, 0, Err_2); + } + else if (mb_type == IPPVC_MBTYPE_INTERPOLATE) + { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_INTERPOLATE); + if (mp4_DecodeMV(pInfo, &mvForw, fcode_forward) != MP4_STATUS_OK) + goto Err_2; + if (mp4_DecodeMV(pInfo, &mvBack, fcode_backward) != MP4_STATUS_OK) + goto Err_2; + if (quarter_sample) + { + mp4_LimitMVQ(&mvForw, &mvForwLim, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(&mvForwLim, &mvCbCrF); + mp4_Copy16x16QP_8u(pYp, stepYp, pYc, stepYc, &mvForwLim, 0); + mp4_LimitMVQ(&mvBack, &mvBackLim, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(&mvBackLim, &mvCbCrB); + mp4_Copy16x16QP_8u(pYn, stepYn, tmpMB, 16, &mvBackLim, 0); + } + else + { + mp4_LimitMV(&mvForw, &mvForwLim, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(&mvForwLim, &mvCbCrF); + mp4_Copy16x16HP_8u(pYp, stepYp, pYc, stepYc, &mvForwLim, 0); + mp4_LimitMV(&mvBack, &mvBackLim, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(&mvBackLim, &mvCbCrB); + mp4_Copy16x16HP_8u(pYn, stepYn, tmpMB, 16, &mvBackLim, 0); + } + ippiAverage16x16_8u_C1IR(tmpMB, 16, pYc, stepYc); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 32, pYc, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 16, pYc+8, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 8, pYc+8*stepYc, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 4, pYc+8*stepYc+8, stepYc, Err_2); + mp4_Copy8x8HP_8u(pCbp, stepCbp, pCbc, stepCbc, &mvCbCrF, 0); + mp4_Copy8x8HP_8u(pCbn, stepCbn, tmpMB, 8, &mvCbCrB, 0); + ippiAverage8x8_8u_C1IR(tmpMB, 8, pCbc, stepCbc); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 2, pCbc, stepCbc, Err_2); + mp4_Copy8x8HP_8u(pCrp, stepCrp, pCrc, stepCrc, &mvCbCrF, 0); + mp4_Copy8x8HP_8u(pCrn, stepCrn, tmpMB, 8, &mvCbCrB, 0); + ippiAverage8x8_8u_C1IR(tmpMB, 8, pCrc, stepCrc); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 1, pCrc, stepCrc, Err_2); + } + else + { // IPPVC_MBTYPE_DIRECT + IppMotionVector mvForw[4], mvBack[4], mvForwLim[4], mvBackLim[4]; + + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_DIRECT); + //f MVs of collocated block of recently decoded I or P frame used in Direct mode + if (mp4_DecodeMV_Direct(pInfo, pMBinfo->mv, mvForw, mvBack, TRB, TRD, modb, pMBinfo->type) != MP4_STATUS_OK) + goto Err_2; + if (quarter_sample) + { + mp4_Limit4MVQ(mvForw, mvForwLim, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MVQ(mvForw, &mvCbCrF); + mp4_Limit4MVQ(mvBack, mvBackLim, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MVQ(mvBack, &mvCbCrB); + mp4_Copy8x8QP_8u(pYp, stepYp, pYc, stepYc, &mvForwLim[0], 0); + mp4_Copy8x8QP_8u(pYn, stepYn, tmpMB, 16, &mvBackLim[0], 0); + mp4_Copy8x8QP_8u(pYp+8, stepYp, pYc+8, stepYc, &mvForwLim[1], 0); + mp4_Copy8x8QP_8u(pYn+8, stepYn, tmpMB+8, 16, &mvBackLim[1], 0); + mp4_Copy8x8QP_8u(pYp+8*stepYp, stepYp, pYc+8*stepYc, stepYc, &mvForwLim[2], 0); + mp4_Copy8x8QP_8u(pYn+8*stepYn, stepYn, tmpMB+8*16, 16, &mvBackLim[2], 0); + mp4_Copy8x8QP_8u(pYp+8*stepYp+8, stepYp, pYc+8*stepYc+8, stepYc, &mvForwLim[3], 0); + mp4_Copy8x8QP_8u(pYn+8*stepYn+8, stepYn, tmpMB+8*16+8, 16, &mvBackLim[3], 0); + } + else + { + if (pMBinfo->type == IPPVC_MBTYPE_INTER4V) { + mp4_Limit4MV(mvForw, mvForwLim, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MV(mvForw, &mvCbCrF); + mp4_Limit4MV(mvBack, mvBackLim, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MV(mvBack, &mvCbCrB); + mp4_Copy8x8HP_8u(pYp, stepYp, pYc, stepYc, &mvForwLim[0], 0); + mp4_Copy8x8HP_8u(pYn, stepYn, tmpMB, 16, &mvBackLim[0], 0); + mp4_Copy8x8HP_8u(pYp+8, stepYp, pYc+8, stepYc, &mvForwLim[1], 0); + mp4_Copy8x8HP_8u(pYn+8, stepYn, tmpMB+8, 16, &mvBackLim[1], 0); + mp4_Copy8x8HP_8u(pYp+8*stepYp, stepYp, pYc+8*stepYc, stepYc, &mvForwLim[2], 0); + mp4_Copy8x8HP_8u(pYn+8*stepYn, stepYn, tmpMB+8*16, 16, &mvBackLim[2], 0); + mp4_Copy8x8HP_8u(pYp+8*stepYp+8, stepYp, pYc+8*stepYc+8, stepYc, &mvForwLim[3], 0); + mp4_Copy8x8HP_8u(pYn+8*stepYn+8, stepYn, tmpMB+8*16+8, 16, &mvBackLim[3], 0); + } + else + { + mp4_LimitMV(mvForw, mvForwLim, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(mvForwLim, &mvCbCrF); + mp4_LimitMV(mvBack, mvBackLim, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(mvBackLim, &mvCbCrB); + mp4_Copy16x16HP_8u(pYp, stepYp, pYc, stepYc, &mvForwLim[0], 0); + mp4_Copy16x16HP_8u(pYn, stepYn, tmpMB, 16, &mvBackLim[0], 0); + } + } + ippiAverage16x16_8u_C1IR(tmpMB, 16, pYc, stepYc); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 32, pYc, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 16, pYc+8, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 8, pYc+8*stepYc, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 4, pYc+8*stepYc+8, stepYc, Err_2); + mp4_LimitMV(&mvCbCrF, &mvCbCrF, &limitRectC, dx >> 1, dy >> 1, 8); + mp4_LimitMV(&mvCbCrB, &mvCbCrB, &limitRectC, dx >> 1, dy >> 1, 8); + mp4_Copy8x8HP_8u(pCbp, stepCbp, pCbc, stepCbc, &mvCbCrF, 0); + mp4_Copy8x8HP_8u(pCbn, stepCbn, tmpMB, 8, &mvCbCrB, 0); + ippiAverage8x8_8u_C1IR(tmpMB, 8, pCbc, stepCbc); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 2, pCbc, stepCbc, Err_2); + mp4_Copy8x8HP_8u(pCrp, stepCrp, pCrc, stepCrc, &mvCbCrF, 0); + mp4_Copy8x8HP_8u(pCrn, stepCrn, tmpMB, 8, &mvCbCrB, 0); + ippiAverage8x8_8u_C1IR(tmpMB, 8, pCrc, stepCrc); + mp4_DecodeReconBlockInter_MPEG4(cbpb & 1, pCrc, stepCrc, Err_2); + } + } + //mbCurr ++; + mbInVideoPacket ++; + colNum ++; + pMBinfo ++; + if (colNum == mbPerRow) + { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) + return sts; + pYc += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pCbc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pCrc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + pYp += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYp << 4) - stepYp; + pCbp += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbp << 3) - stepCbp; + pCrp += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrp << 3) - stepCrp; + pYn += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYn << 4) - stepYn; + pCbn += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbn << 3) - stepCbn; + pCrn += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrn << 3) - stepCrn; + // reset MV predictors at new row + mvForw.dx = mvForw.dy = mvBack.dx = mvBack.dy = 0; + } + else + { + pYc += 16; pCrc += 8; pCbc += 8; + pYp += 16; pCrp += 8; pCbp += 8; + pYn += 16; pCrn += 8; pCbn += 8; + } + if (!pInfo->VisualObject.VideoObject.resync_marker_disable) + { + int32_t found; +ErrRet_2: + if (mp4_CheckDecodeVideoPacket(pInfo, &found) == MP4_STATUS_OK) + { + if (found) + { + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant_scale; + mbCurr = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, mbCurr - rowNum * mbPerRow - colNum); + rowNum = mbCurr / mbPerRow; + colNum = mbCurr % mbPerRow; + pYc = pInfo->VisualObject.cFrame->pY + (rowNum * stepYc + colNum) * 16; pCbc = pInfo->VisualObject.cFrame->pCb + (rowNum * stepCbc + colNum) * 8; pCrc = pInfo->VisualObject.cFrame->pCr + (rowNum * stepCrc + colNum) * 8; + pYp = pInfo->VisualObject.rFrame->pY + (rowNum * stepYp + colNum) * 16; pCbp = pInfo->VisualObject.rFrame->pCb + (rowNum * stepCbp + colNum) * 8; pCrp = pInfo->VisualObject.rFrame->pCr + (rowNum * stepCrp + colNum) * 8; + pYn = pInfo->VisualObject.nFrame->pY + (rowNum * stepYn + colNum) * 16; pCbn = pInfo->VisualObject.nFrame->pCb + (rowNum * stepCbn + colNum) * 8; pCrn = pInfo->VisualObject.nFrame->pCr + (rowNum * stepCrn + colNum) * 8; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo + mbCurr; + break; + } + } + else + goto Err_2; + } + } + } +Err_2: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (pInfo->VisualObject.VideoObject.resync_marker_disable || !mp4_SeekResyncMarker(pInfo)) + { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_2; +} + diff --git a/Src/mpeg4dec/mp4decvopi.c b/Src/mpeg4dec/mp4decvopi.c new file mode 100644 index 00000000..2ec2fb84 --- /dev/null +++ b/Src/mpeg4dec/mp4decvopi.c @@ -0,0 +1,408 @@ +/* /////////////////////////////////////////////////////////////////////// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 2001-2007 Intel Corporation. All Rights Reserved. +// +// Description: Decodes I-VOPs +// +*/ + +#include "mp4def.h" +#include "mp4dec.h" + +/* +// decode mcbpc and set MBtype and ChromaPattern +*/ +/*static*/ mp4_Status mp4_DecodeMCBPC_I(mp4_Info* pInfo, int32_t *mbType, int32_t *mbPattern) +{ + uint32_t code; + int32_t type, pattern, fb; + + code = mp4_ShowBits9(pInfo, 9); + if (code == 1) { + type = IPPVC_MB_STUFFING; + pattern = 0; + fb = 9; + } else if (code >= 64) { + type = IPPVC_MBTYPE_INTRA; + pattern = code >> 6; + if (pattern >= 4) { + pattern = 0; + fb = 1; + } else + fb = 3; + } else { + type = IPPVC_MBTYPE_INTRA_Q; + pattern = code >> 3; + if (pattern >= 4) { + pattern = 0; + fb = 4; + } else if (code >= 8) { + fb = 6; + } else { + mp4_Error("Error: decoding MCBPC"); + return MP4_STATUS_ERROR; + } + } + mp4_FlushBits(pInfo, fb); + *mbType = type; + *mbPattern = pattern; + if (type == IPPVC_MBTYPE_INTRA) + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_INTRA); + else if (type == IPPVC_MBTYPE_INTRA_Q) + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_INTRA_Q); + return MP4_STATUS_OK; +} + + +/* +// decode IVOP +*/ +mp4_Status mp4_DecodeVOP_I(mp4_Info* pInfo) +{ + int32_t quant, quantPred, dcVLC, mb_type, cbpc, cbpy, ac_pred_flag; + int32_t i, j, nmb, nmbgob, stepYc, stepCbc, stepCrc, stepFc[6], mbCurr, mbInVideoPacket, colNum, rowNum, mbPerRow, mbPerCol; + uint8_t *pFc[6]; + mp4_Status sts; + + if (pInfo->VisualObject.cFrame) + { + DebugBreak(); + } + pInfo->VisualObject.cFrame = CreateFrame(&pInfo->VisualObject); + stepYc = pInfo->VisualObject.cFrame->stepY; + stepCbc = pInfo->VisualObject.cFrame->stepCb; + stepCrc = pInfo->VisualObject.cFrame->stepCr; + mbPerRow = pInfo->VisualObject.VideoObject.MacroBlockPerRow; + mbPerCol = pInfo->VisualObject.VideoObject.MacroBlockPerCol; + stepFc[0] = stepFc[1] = stepFc[2] = stepFc[3] = stepYc; stepFc[4] = stepCbc; stepFc[5] = stepCrc; + pFc[0] = pInfo->VisualObject.cFrame->pY; pFc[1] = pInfo->VisualObject.cFrame->pY + 8; + pFc[2] = pInfo->VisualObject.cFrame->pY + 8 * stepYc; pFc[3] = pInfo->VisualObject.cFrame->pY + 8 * stepYc + 8; + pFc[4] = pInfo->VisualObject.cFrame->pCb; pFc[5] = pInfo->VisualObject.cFrame->pCr; + nmb = pInfo->VisualObject.VideoObject.MacroBlockPerVOP; + mbCurr = colNum = rowNum = 0; + sts = MP4_STATUS_OK; +// decode short_video_header I-VOP + if (pInfo->VisualObject.VideoObject.short_video_header) + { + quant = pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.vop_quant; + nmbgob = 0; + pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_number = 0; + for (;;) + { + do + { + if (mp4_DecodeMCBPC_I(pInfo, &mb_type, &cbpc) != MP4_STATUS_OK) + goto Err_1; + } while (mb_type == IPPVC_MB_STUFFING); + if (mp4_DecodeCBPY_I(pInfo, &cbpy) != MP4_STATUS_OK) + goto Err_1; + if (mb_type == IPPVC_MBTYPE_INTRA_Q) + mp4_UpdateQuant(pInfo, quant); + if (mp4_DecodeIntraMB_SVH(pInfo, (cbpy << 2) + cbpc, quant, pFc, stepFc) != MP4_STATUS_OK) + goto Err_1; + colNum ++; + if (colNum == mbPerRow) { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) + break; + pFc[0] += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pFc[1] += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pFc[2] += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pFc[3] += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pFc[4] += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pFc[5] += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + } + else + { + pFc[0] += 16; pFc[1] += 16; pFc[2] += 16; pFc[3] += 16; pFc[4] += 8; pFc[5] += 8; + } + nmbgob ++; + if (nmbgob == pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.num_macroblocks_in_gob && pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_number < (pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.num_gobs_in_vop - 1)) { +ErrRet_1: + if (mp4_CheckDecodeGOB_SVH(pInfo) != MP4_STATUS_OK) + goto Err_1; + if (!pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_header_empty) + { + quant = pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.quant_scale; + i = pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_number * pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.num_rows_in_gob; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, (i - rowNum) * mbPerRow - colNum); + rowNum = i; + colNum = 0; + pFc[0] = pInfo->VisualObject.cFrame->pY + i * stepYc * 16; pFc[1] = pFc[0] + 8; pFc[2] = pFc[0] + 8 * stepYc; pFc[3] = pFc[2] + 8; + pFc[4] = pInfo->VisualObject.cFrame->pCb + i * stepCbc * 8; pFc[5] = pInfo->VisualObject.cFrame->pCr + i * stepCrc * 8; + } + nmbgob = 0; + } + } + mp4_AlignBits(pInfo); + return sts; +Err_1: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (!mp4_SeekGOBMarker(pInfo)) + { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_1; + } + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant; + if (pInfo->VisualObject.VideoObject.sprite_enable != MP4_SPRITE_STATIC) + ippsZero_8u((uint8_t*)pInfo->VisualObject.VideoObject.MBinfo, nmb * sizeof(mp4_MacroBlock)); +// decode data_partitioned I-VOP + if (pInfo->VisualObject.VideoObject.data_partitioned) + { + mp4_DataPartMacroBlock *pMBdp; + + for (;;) + { + // reset Intra prediction buffer on new Video_packet + mp4_ResetIntraPredBuffer(pInfo); + mbInVideoPacket = 0; + pMBdp = &pInfo->VisualObject.VideoObject.DataPartBuff[mbCurr]; + // decode mb_type/cbpc/dquant/DC part + for (;;) + { + if (mp4_DecodeMCBPC_I(pInfo, &mb_type, &cbpc) != MP4_STATUS_OK) + goto Err_2; + if (mb_type != IPPVC_MB_STUFFING) + { + if (mbInVideoPacket == nmb - mbCurr) + { + mp4_Error("DC Marker missed"); + goto Err_2; + } + quantPred = quant; + if (mb_type == IPPVC_MBTYPE_INTRA_Q) + mp4_UpdateQuant(pInfo, quant); + if (mbInVideoPacket == 0) + quantPred = quant; + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + if (dcVLC) { + for (i = 0; i < 6; i ++) { + if (ippiDecodeDCIntra_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, &pMBdp->dct_dc[i], (i < 4) ? IPPVC_BLOCK_LUMA : IPPVC_BLOCK_CHROMA) != ippStsNoErr) + goto Err_2; + } + } + pMBdp->quant = (uint8_t)quant; + pMBdp->type = (uint8_t)mb_type; + pMBdp->pat = (uint8_t)cbpc; + pMBdp ++; + mbInVideoPacket ++; + } + if (mp4_ShowBits(pInfo, 19) == MP4_DC_MARKER) + { + mp4_GetBits(pInfo, 19); + break; + } + } + pMBdp = &pInfo->VisualObject.VideoObject.DataPartBuff[mbCurr]; + // decode ac_pred_flag/cbpy part + for (i = 0; i < mbInVideoPacket; i ++) + { + pMBdp[i].ac_pred_flag = (uint8_t)mp4_GetBit(pInfo); + if (mp4_DecodeCBPY_I(pInfo, &cbpy) != MP4_STATUS_OK) + { + if (pInfo->stopOnErr) + goto Err_2; + for (j = i + 1; j < mbInVideoPacket; j ++) + pMBdp[j].ac_pred_flag = 1; + break; + } + pMBdp[i].pat = (uint8_t)((cbpy << 2) + pMBdp[i].pat); + } + // decode AC part and reconstruct macroblocks + for (i = 0; i < mbInVideoPacket; i ++) { + if (colNum == 0) { + // reset B-prediction blocks on new row + mp4_ResetIntraPredBblock(pInfo); + } + quant = pMBdp[i].quant; + quantPred = (i == 0) ? quant : pMBdp[i-1].quant; + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + ac_pred_flag = pMBdp[i].ac_pred_flag; + if (mp4_DecodeIntraMB_DP(pInfo, pMBdp[i].dct_dc, colNum, pMBdp[i].pat, quant, dcVLC, ac_pred_flag, pFc, stepFc) != MP4_STATUS_OK) + //if (!pInfo->VisualObject.VideoObject.reversible_vlc) + goto Err_2; + //else + // goto Err_RVLC; + colNum ++; + if (colNum == mbPerRow) + { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) + return sts; + pFc[0] += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pFc[1] += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pFc[2] += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pFc[3] += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pFc[4] += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pFc[5] += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + } + else + { + pFc[0] += 16; pFc[1] += 16; pFc[2] += 16; pFc[3] += 16; pFc[4] += 8; pFc[5] += 8; + } + } + mbCurr += mbInVideoPacket; + if (!pInfo->VisualObject.VideoObject.resync_marker_disable) + { + int32_t found; +ErrRet_2: + if (mp4_CheckDecodeVideoPacket(pInfo, &found) == MP4_STATUS_OK) + { + if (found) + { + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant_scale; + mbCurr = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, mbCurr - rowNum * mbPerRow - colNum); + rowNum = mbCurr / mbPerRow; + colNum = mbCurr % mbPerRow; + pFc[0] = pInfo->VisualObject.cFrame->pY + (rowNum * stepYc + colNum) * 16; pFc[1] = pFc[0] + 8; pFc[2] = pFc[0] + stepYc * 8; pFc[3] = pFc[2] + 8; + pFc[4] = pInfo->VisualObject.cFrame->pCb + (rowNum * stepCbc + colNum) * 8; pFc[5] = pInfo->VisualObject.cFrame->pCr + (rowNum * stepCrc + colNum) * 8; + } + else + goto Err_2; + } + else + goto Err_2; + } + } +Err_2: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (pInfo->VisualObject.VideoObject.resync_marker_disable || !mp4_SeekResyncMarker(pInfo)) + { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_2; +#if 0 +Err_RVLC: + { + uint8_t *sBufptr = pInfo->bufptr; + int32_t sBitoff = pInfo->bitoff; + + pInfo->bitoff --; + if (pInfo->bitoff == -1) { + pInfo->bitoff = 7; + pInfo->bufptr --; + } + // decode AC part and reconstruct macroblocks + for (j = mbInVideoPacket - 1; j >= i; j --) { + int32_t lnz, quantPred, dcVLC; + + quantPred = ((j == 0) ? pMBdp[j].quant : pMBdp[j-1].quant); + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + if (ippiDecodeCoeffsIntraRVLCBack_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, pDCTdp[j*64*6], &lnz, dcVLC) != ippStsNoErr) + break; + } + pInfo->bufptr = sBufptr; + pInfo->bitoff = sBitoff; + } + goto ErrRet_2; +#endif + } +// decode not data partitioned I-VOP + else { + int32_t stepY = stepYc, dct_type = 0, pYoff23 = 8 * stepYc; + for (;;) { + // reset Intra prediction buffer on new Video_packet + mp4_ResetIntraPredBuffer(pInfo); + mbInVideoPacket = 0; + // decode blocks + for (;;) { + if (colNum == 0) { + // reset B-prediction blocks on new row + mp4_ResetIntraPredBblock(pInfo); + } + if (mp4_DecodeMCBPC_I(pInfo, &mb_type, &cbpc) != MP4_STATUS_OK) + goto Err_3; + if (mb_type != IPPVC_MB_STUFFING) { + ac_pred_flag = mp4_GetBit(pInfo); + if (mp4_DecodeCBPY_I(pInfo, &cbpy) != MP4_STATUS_OK) + goto Err_3; + quantPred = quant; + if (mb_type == IPPVC_MBTYPE_INTRA_Q) + mp4_UpdateQuant(pInfo, quant); + if (mbInVideoPacket == 0) + quantPred = quant; + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + if (pInfo->VisualObject.VideoObject.interlaced) { + dct_type = mp4_GetBit(pInfo); + if (dct_type) { + stepY = stepYc * 2; + pYoff23 = stepYc; + } else { + stepY = stepYc; + pYoff23 = 8 * stepYc; + } + stepFc[0] = stepFc[1] = stepFc[2] = stepFc[3] = stepY; + } + pFc[2] = pFc[0] + pYoff23; pFc[3] = pFc[1] + pYoff23; + if (mp4_DecodeIntraMB(pInfo, colNum, (cbpy << 2) + cbpc, quant, dcVLC, ac_pred_flag, pFc, stepFc) != MP4_STATUS_OK) + goto Err_3; + mbInVideoPacket ++; + colNum ++; + if (colNum == mbPerRow) { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) { + // skip stuffing + while (mp4_ShowBits9(pInfo, 9) == 1) + mp4_FlushBits(pInfo, 9); + return sts; + } + pFc[0] += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pFc[1] += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pFc[4] += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pFc[5] += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + } else { + pFc[0] += 16; pFc[1] += 16; pFc[4] += 8; pFc[5] += 8; + } + } + if (!pInfo->VisualObject.VideoObject.resync_marker_disable) + { + int32_t found; +ErrRet_3: + if (mp4_CheckDecodeVideoPacket(pInfo, &found) == MP4_STATUS_OK) + { + if (found) + { + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant_scale; + mbCurr = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, mbCurr - rowNum * mbPerRow - colNum); + rowNum = mbCurr / mbPerRow; + colNum = mbCurr % mbPerRow; + pFc[0] = pInfo->VisualObject.cFrame->pY + (rowNum * stepYc + colNum) * 16; pFc[1] = pFc[0] + 8; + pFc[4] = pInfo->VisualObject.cFrame->pCb + (rowNum * stepCbc + colNum) * 8; pFc[5] = pInfo->VisualObject.cFrame->pCr + (rowNum * stepCrc + colNum) * 8; + break; + } + } + else + goto Err_3; + } + } + } +Err_3: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (pInfo->VisualObject.VideoObject.resync_marker_disable || !mp4_SeekResyncMarker(pInfo)) + { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_3; + } +} + + diff --git a/Src/mpeg4dec/mp4decvopp.c b/Src/mpeg4dec/mp4decvopp.c new file mode 100644 index 00000000..10ec2c1d --- /dev/null +++ b/Src/mpeg4dec/mp4decvopp.c @@ -0,0 +1,1079 @@ +/* /////////////////////////////////////////////////////////////////////// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 2001-2008 Intel Corporation. All Rights Reserved. +// +// Description: Decodes P-VOPs +// +*/ + +#include "mp4def.h" +#include "mp4dec.h" + +/* +// used for short_viseo_header +*/ +/*static*/ mp4_Status mp4_PredictDecodeMV(mp4_Info *pInfo, mp4_MacroBlock *MBcurr, int32_t frGOB, int32_t y, int32_t x) +{ + IppMotionVector *mvLeft, *mvTop, *mvRight, *mvCurr; + int32_t mbInRow = pInfo->VisualObject.VideoObject.MacroBlockPerRow; + + mvCurr = MBcurr[0].mv; + mvLeft = MBcurr[-1].mv; + mvTop = MBcurr[-mbInRow].mv; + mvRight = MBcurr[-mbInRow+1].mv; + if (y == frGOB && x == 0) { + mvCurr->dx = mvCurr->dy = 0; + } else if (x == 0) { + mvCurr->dx = mp4_Median(0, mvTop[0].dx, mvRight[0].dx); + mvCurr->dy = mp4_Median(0, mvTop[0].dy, mvRight[0].dy); + } else if (y == frGOB) { + MBcurr->mv[0] = mvLeft[0]; + } else if (x == mbInRow - 1) { + mvCurr->dx = mp4_Median(0, mvLeft[0].dx, mvTop[0].dx); + mvCurr->dy = mp4_Median(0, mvLeft[0].dy, mvTop[0].dy); + } else { + mvCurr->dx = mp4_Median(mvLeft[0].dx, mvTop[0].dx, mvRight[0].dx); + mvCurr->dy = mp4_Median(mvLeft[0].dy, mvTop[0].dy, mvRight[0].dy); + } + return mp4_DecodeMV(pInfo, mvCurr, 1); +} + +/* +// decode MPEG-4 PVOP +*/ +mp4_Status mp4_DecodeVOP_P(mp4_Info* pInfo) +{ + __ALIGN16(int16_t, coeffMB, 64*6); + int32_t stepYr, stepYc, stepCbr, stepCbc, stepCrr, stepCrc, stepFc[6]; + int32_t i, j, nmb, nmbgob, dx, dy, mbCurr, mbInVideoPacket, colNum, rowNum, mbPerRow, mbPerCol; + uint8_t *pYr, *pCbr, *pCrr; + uint8_t *pYc, *pCbc, *pCrc, *pFc[6]; + int32_t mb_not_coded, mb_type, cbpc, cbpy, ac_pred_flag, cbpyPrev; + int32_t dcVLC, quant, quantPred, rvlc, scan, obmc_disable, rt, quarter_sample; + IppiRect limitRectL, limitRectC; + IppMotionVector mvCur[4], mvPrev[4], mvTmp[4], mvCbCr; + mp4_MacroBlock *pMBinfo; + mp4_Status sts; +#ifdef USE_NOTCODED_STATE + uint8_t *ncState = pInfo->VisualObject.VideoObject.ncState; +#endif + if (!pInfo->VisualObject.cFrame) + pInfo->VisualObject.cFrame = CreateFrame(&pInfo->VisualObject); + mbPerRow = pInfo->VisualObject.VideoObject.MacroBlockPerRow; + mbPerCol = pInfo->VisualObject.VideoObject.MacroBlockPerCol; + + stepYc = pInfo->VisualObject.cFrame->stepY; + stepYr = pInfo->VisualObject.rFrame->stepY; + stepCbc = pInfo->VisualObject.cFrame->stepCb; + stepCbr = pInfo->VisualObject.rFrame->stepCb; + stepCrc = pInfo->VisualObject.cFrame->stepCr; + stepCrr = pInfo->VisualObject.rFrame->stepCr; + pYc = pInfo->VisualObject.cFrame->pY; + pCbc = pInfo->VisualObject.cFrame->pCb; + pCrc = pInfo->VisualObject.cFrame->pCr; + pYr = pInfo->VisualObject.rFrame->pY; + pCbr = pInfo->VisualObject.rFrame->pCb; + pCrr = pInfo->VisualObject.rFrame->pCr; + stepFc[0] = stepFc[1] = stepFc[2] = stepFc[3] = stepYc; stepFc[4] = stepCbc; stepFc[5] = stepCrc; + // Bounding rectangle for MV limitation + limitRectL.x = - 16 * MP4_NUM_EXT_MB; + limitRectL.y = - 16 * MP4_NUM_EXT_MB; + limitRectL.width = pInfo->VisualObject.VideoObject.width + 16 * 2 * MP4_NUM_EXT_MB; + limitRectL.height = pInfo->VisualObject.VideoObject.height + 16 * 2 * MP4_NUM_EXT_MB; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo; + // warning "variable may be used without having been initialized" + cbpc = cbpy = mb_type = 0; + nmb = pInfo->VisualObject.VideoObject.MacroBlockPerVOP; + mbCurr = colNum = rowNum = 0; + sts = MP4_STATUS_OK; + // decode short_video_header P-VOP + if (pInfo->VisualObject.VideoObject.short_video_header) + { + int32_t frGOB; + IppMotionVector mvCur; + + quant = pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.vop_quant; + nmbgob = 0; + pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_number = 0; + frGOB = 0; + for (;;) + { + do + { + mb_not_coded = mp4_GetBit(pInfo); + if (mb_not_coded) + break; + if (mp4_DecodeMCBPC_P(pInfo, &mb_type, &cbpc, 1) != MP4_STATUS_OK) + goto Err_1; + } while (mb_type == IPPVC_MB_STUFFING); + if (mb_not_coded) + { +#ifdef USE_NOTCODED_STATE + if (!(*ncState)) + { + *ncState = 1; +#endif + ippiCopy16x16_8u_C1R(pYr, stepYr, pYc, stepYc); + ippiCopy8x8_8u_C1R(pCbr, stepCbr, pCbc, stepCbc); + ippiCopy8x8_8u_C1R(pCrr, stepCrr, pCrc, stepCrc); +#ifdef USE_NOTCODED_STATE + } +#endif + pMBinfo->mv[0].dx = pMBinfo->mv[0].dy = 0; + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_NOTCODED); + } + else + { +#ifdef USE_NOTCODED_STATE + // clear not_coded MB state + *ncState = 0; +#endif + if (mb_type == IPPVC_MBTYPE_INTER4V || mb_type == IPPVC_MBTYPE_INTER4V_Q) + { + mp4_Error("Error: 4MV shall not be used for short_video_header"); + goto Err_1; + } + if (mp4_DecodeCBPY_P(pInfo, &cbpy, mb_type) != MP4_STATUS_OK) + goto Err_1; + if (mb_type == IPPVC_MBTYPE_INTER_Q || mb_type == IPPVC_MBTYPE_INTRA_Q) + mp4_UpdateQuant(pInfo, quant); + if (mb_type >= IPPVC_MBTYPE_INTRA) + { + pFc[0] = pYc; pFc[1] = pYc + 8; pFc[2] = pYc + 8 * stepYc; pFc[3] = pYc + 8 * stepYc + 8; pFc[4] = pCbc; pFc[5] = pCrc; + if (mp4_DecodeIntraMB_SVH(pInfo, (cbpy << 2) + cbpc, quant, pFc, stepFc) != MP4_STATUS_OK) + goto Err_1; + pMBinfo->mv[0].dx = pMBinfo->mv[0].dy = 0; + } + else + { + if (mp4_PredictDecodeMV(pInfo, pMBinfo, frGOB, rowNum, colNum) != MP4_STATUS_OK) + goto Err_1; + mp4_LimitMV(&pMBinfo->mv[0], &mvCur, &limitRectL, colNum * 16, rowNum * 16, 16); + mp4_ComputeChromaMV(&mvCur, &mvCbCr); + + // decode and MC blocks + if (cbpy) + { + mp4_DecodeMCInterBlock_SVH(pInfo, quant, cbpy & 8, pYr, pYc, stepYr, coeffMB, &mvCur, Err_1); + mp4_DecodeMCInterBlock_SVH(pInfo, quant, cbpy & 4, pYr+8, pYc+8, stepYr, coeffMB, &mvCur, Err_1); + mp4_DecodeMCInterBlock_SVH(pInfo, quant, cbpy & 2, pYr+stepYr*8, pYc+stepYc*8, stepYr, coeffMB, &mvCur, Err_1); + mp4_DecodeMCInterBlock_SVH(pInfo, quant, cbpy & 1, pYr+8+stepYr*8, pYc+8+stepYc*8, stepYr, coeffMB, &mvCur, Err_1); + } + else + { + mp4_Copy16x16HP_8u(pYr, stepYr, pYc, stepYc, &mvCur, 0); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + } + mp4_DecodeMCInterBlock_SVH(pInfo, quant, cbpc & 2, pCbr, pCbc, stepCbr, coeffMB, &mvCbCr, Err_1); + mp4_DecodeMCInterBlock_SVH(pInfo, quant, cbpc & 1, pCrr, pCrc, stepCrr, coeffMB, &mvCbCr, Err_1); + } + } + pMBinfo ++; +#ifdef USE_NOTCODED_STATE + ncState ++; +#endif + colNum ++; + if (colNum == mbPerRow) + { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) + break; + pYc += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pCbc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pCrc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + pYr += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYr << 4) - stepYr; + pCbr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbr << 3) - stepCbr; + pCrr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrr << 3) - stepCrr; + } + else + { + pYc += 16; pCrc += 8; pCbc += 8; + pYr += 16; pCrr += 8; pCbr += 8; + } + nmbgob ++; + if (nmbgob == pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.num_macroblocks_in_gob && pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_number < (pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.num_gobs_in_vop - 1)) + { +ErrRet_1: + if (mp4_CheckDecodeGOB_SVH(pInfo) != MP4_STATUS_OK) + goto Err_1; + if (!pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_header_empty) + { + quant = pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.quant_scale; + i = pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_number * pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.num_rows_in_gob; + frGOB = i; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, (i - rowNum) * mbPerRow - colNum); + rowNum = i; + colNum = 0; + pYc = pInfo->VisualObject.cFrame->pY + i * stepYc * 16; pCbc = pInfo->VisualObject.cFrame->pCb + i * stepCbc * 8; pCrc = pInfo->VisualObject.cFrame->pCr + i * stepCrc * 8; + pYr = pInfo->VisualObject.rFrame->pY + i * stepYr * 16; pCbr = pInfo->VisualObject.rFrame->pCb + i * stepCbr * 8; pCrr = pInfo->VisualObject.rFrame->pCr + i * stepCrr * 8; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo + i * mbPerRow; +#ifdef USE_NOTCODED_STATE + ncState = pInfo->VisualObject.VideoObject.ncState + i * mbPerRow; +#endif + } + nmbgob = 0; + } + } + mp4_AlignBits(pInfo); + return sts; +Err_1: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (!mp4_SeekGOBMarker(pInfo)) + { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_1; + } + rt = pInfo->VisualObject.VideoObject.VideoObjectPlane.rounding_type; + quarter_sample = pInfo->VisualObject.VideoObject.quarter_sample; + obmc_disable = pInfo->VisualObject.VideoObject.obmc_disable; + rvlc = pInfo->VisualObject.VideoObject.reversible_vlc; + scan = pInfo->VisualObject.VideoObject.VideoObjectPlane.alternate_vertical_scan_flag ? IPPVC_SCAN_VERTICAL : IPPVC_SCAN_ZIGZAG; + // Bounding rectangles for MV limitation + limitRectC.x = -8 * MP4_NUM_EXT_MB; + limitRectC.y = -8 * MP4_NUM_EXT_MB; + limitRectC.width = (pInfo->VisualObject.VideoObject.width >> 1) + 8 * 2 * MP4_NUM_EXT_MB; + limitRectC.height = (pInfo->VisualObject.VideoObject.height >> 1) + 8 * 2 * MP4_NUM_EXT_MB; + quant = quantPred = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant; + // warning "variable may be used without having been initialized" + ac_pred_flag = cbpyPrev = 0; + mvCbCr.dx = mvCbCr.dy = 0; + //ippsZero_8u((uint8_t*)pInfo->VisualObject.VideoObject.MBinfo, nmb * sizeof(mp4_MacroBlock)); + // decode data_partitioned P-VOP + if (pInfo->VisualObject.VideoObject.data_partitioned) { + for (;;) { + mp4_DataPartMacroBlock *pMBdp; + int32_t x, y; + + x = colNum; + y = rowNum; + // reset Intra prediction buffer on new Video_packet + mp4_ResetIntraPredBuffer(pInfo); + pMBdp = &pInfo->VisualObject.VideoObject.DataPartBuff[mbCurr]; + pMBinfo = &pInfo->VisualObject.VideoObject.MBinfo[mbCurr]; + mbInVideoPacket = 0; + // decode not_coded/mb_type/cbpc/MV part + for (;;) { + mb_not_coded = mp4_GetBit(pInfo); + if (mb_not_coded) { + mb_type = IPPVC_MBTYPE_INTER; + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_NOTCODED); + } else { + if (mp4_DecodeMCBPC_P(pInfo, &mb_type, &cbpc, 1) != MP4_STATUS_OK) + goto Err_2; + } + if (mb_type != IPPVC_MB_STUFFING) { + if (mbInVideoPacket == nmb - mbCurr) { + mp4_Error("DC Marker missed"); + goto Err_2; + } + pMBinfo->validPred = 1; + if (!mb_not_coded && (mb_type <= IPPVC_MBTYPE_INTER4V)) { + if (mb_type != IPPVC_MBTYPE_INTER4V) { + if (mp4_PredictDecode1MV(pInfo, pMBinfo, y, x) != MP4_STATUS_OK) + goto Err_2; + pMBinfo->mv[1] = pMBinfo->mv[2] = pMBinfo->mv[3] = pMBinfo->mv[0]; + } else { + if (mp4_PredictDecode4MV(pInfo, pMBinfo, y, x) != MP4_STATUS_OK) + goto Err_2; + } + } else { + mp4_Zero4MV(pMBinfo->mv); + } + pMBinfo->not_coded = (uint8_t)mb_not_coded; + pMBinfo->type = (uint8_t)mb_type; + pMBinfo ++; + pMBdp->pat = (uint8_t)cbpc; + pMBdp ++; + mbInVideoPacket ++; + x ++; + if (x == mbPerRow) { + x = 0; + y ++; + } + } + if (mp4_ShowBits(pInfo, 17) == MP4_MV_MARKER) { + mp4_GetBits(pInfo, 17); + break; + } + } + pMBdp = &pInfo->VisualObject.VideoObject.DataPartBuff[mbCurr]; + pMBinfo = &pInfo->VisualObject.VideoObject.MBinfo[mbCurr]; + // decode ac_pred_flag/cbpy/dquant/IntraDC part + for (i = 0; i < mbInVideoPacket; i ++) { + if (!pMBinfo->not_coded) { + mb_type = pMBinfo->type; + if (mb_type >= IPPVC_MBTYPE_INTRA) + pMBdp->ac_pred_flag = (uint8_t)mp4_GetBit(pInfo); + if (mp4_DecodeCBPY_P(pInfo, &cbpy, mb_type) != MP4_STATUS_OK) + goto Err_2; + pMBdp->pat = (uint8_t)((cbpy << 2) + pMBdp->pat); + quantPred = quant; + if (mb_type == IPPVC_MBTYPE_INTER_Q || mb_type == IPPVC_MBTYPE_INTRA_Q) + mp4_UpdateQuant(pInfo, quant); + pMBdp->quant = (uint8_t)quant; + if (i == 0) + quantPred = quant; + // decode DC coefficient of Intra blocks + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + if ((mb_type >= IPPVC_MBTYPE_INTRA) && dcVLC) { + for (j = 0; j < 6; j ++) { + if (ippiDecodeDCIntra_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, &pMBdp->dct_dc[j], j < 4 ? IPPVC_BLOCK_LUMA : IPPVC_BLOCK_CHROMA) != ippStsNoErr) + goto Err_2; + } + } + } + pMBdp ++; + pMBinfo ++; + } + if (mbCurr + mbInVideoPacket < nmb) + pMBinfo->type = IPPVC_MBTYPE_INTRA; // for OBMC set first MB of the next videopacket as invalid for right MV + pMBdp = &pInfo->VisualObject.VideoObject.DataPartBuff[mbCurr]; + pMBinfo = &pInfo->VisualObject.VideoObject.MBinfo[mbCurr]; + // decode coeffs and reconstruct macroblocks + for (i = 0; i < mbInVideoPacket; i ++) { + if (colNum == 0) { + // reset B-prediction blocks on new row + mp4_ResetIntraPredBblock(pInfo); + } + quant = pMBdp->quant; + mb_type = pMBinfo->type; + if (mb_type >= IPPVC_MBTYPE_INTRA) { + quantPred = (i == 0) ? quant : pMBdp[-1].quant; + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + pFc[0] = pYc; pFc[1] = pYc + 8; pFc[2] = pYc + 8 * stepYc; pFc[3] = pYc + 8 * stepYc + 8; pFc[4] = pCbc; pFc[5] = pCrc; + if (mp4_DecodeIntraMB_DP(pInfo, pMBdp->dct_dc, colNum, pMBdp->pat, quant, dcVLC, pMBdp->ac_pred_flag, pFc, stepFc) != MP4_STATUS_OK) + goto Err_2; + } else { + mp4_UpdateIntraPredBuffInvalid(pInfo, colNum); + mb_not_coded = pMBinfo->not_coded; + if (!mb_not_coded) { + dx = colNum * 16; + dy = rowNum * 16; + cbpy = pMBdp->pat >> 2; + cbpc = pMBdp->pat & 3; + if (mb_type == IPPVC_MBTYPE_INTER4V) { + if (quarter_sample) { + mp4_Limit4MVQ(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MVQ(pMBinfo->mv, &mvCbCr); + } else { + mp4_Limit4MV(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MV(pMBinfo->mv, &mvCbCr); + } + mp4_LimitMV(&mvCbCr, &mvCbCr, &limitRectC, dx >> 1, dy >> 1, 8); + } else { + if (quarter_sample) { + mp4_LimitMVQ(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(mvCur, &mvCbCr); + } else { + mp4_LimitMV(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(mvCur, &mvCbCr); + } + mvCur[1] = mvCur[2] = mvCur[3] = mvCur[0]; + } + } + if (obmc_disable) { + if (mb_not_coded) { + ippiCopy16x16_8u_C1R(pYr, stepYr, pYc, stepYc); + ippiCopy8x8_8u_C1R(pCbr, stepCbr, pCbc, stepCbc); + ippiCopy8x8_8u_C1R(pCrr, stepCrr, pCrc, stepCrc); + } else { + if (quarter_sample) { + if (mb_type == IPPVC_MBTYPE_INTER4V) { + mp4_Copy8x8QP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_Copy8x8QP_8u(pYr+8, stepYr, pYc+8, stepYc, &mvCur[1], rt); + mp4_Copy8x8QP_8u(pYr+8*stepYr, stepYr, pYc+8*stepYc, stepYc, &mvCur[2], rt); + mp4_Copy8x8QP_8u(pYr+8*stepYr+8, stepYr, pYc+8*stepYc+8, stepYc, &mvCur[3], rt); + } else + mp4_Copy16x16QP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_DecodeReconBlockInter_MPEG4(cbpy & 8, pYc, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpy & 4, pYc+8, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpy & 2, pYc+8*stepYc, stepYc, Err_2); + mp4_DecodeReconBlockInter_MPEG4(cbpy & 1, pYc+8*stepYc+8, stepYc, Err_2); + } else { + if (cbpy || mb_type == IPPVC_MBTYPE_INTER4V) { + mp4_DecodeMCBlockInter_MPEG4(cbpy & 8, pYr, stepYr, pYc, stepYc, mvCur[0], rt, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpy & 4, pYr+8, stepYr, pYc+8, stepYc, mvCur[1], rt, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpy & 2, pYr+8*stepYr, stepYr, pYc+8*stepYc, stepYc, mvCur[2], rt, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpy & 1, pYr+8*stepYr+8, stepYr, pYc+8*stepYc+8, stepYc, mvCur[3], rt, Err_2); + } else { + mp4_Copy16x16HP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + } + } + mp4_DecodeMCBlockInter_MPEG4(cbpc & 2, pCbr, stepCbr, pCbc, stepCbc, mvCbCr, rt, Err_2); + mp4_DecodeMCBlockInter_MPEG4(cbpc & 1, pCrr, stepCrr, pCrc, stepCrc, mvCbCr, rt, Err_2); + } + } else { + if (mb_not_coded) { + cbpy = 0; + mp4_Zero4MV(mvCur); + ippiCopy8x8_8u_C1R(pCbr, stepCbr, pCbc, stepCbc); + ippiCopy8x8_8u_C1R(pCrr, stepCrr, pCrc, stepCrc); + } else { + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, (cbpy << 2) + cbpc, scan) != MP4_STATUS_OK) + goto Err_2; + mp4_MC_HP(cbpc & 2, pCbr, stepCbr, pCbc, stepCbc, coeffMB+256, &mvCbCr, rt); + mp4_MC_HP(cbpc & 1, pCrr, stepCrr, pCrc, stepCrc, coeffMB+320, &mvCbCr, rt); + } + mp4_OBMC(pInfo, pMBinfo, mvCur, colNum, rowNum, limitRectL, pYc, stepYc, pYr, stepYr, cbpy, coeffMB, 0); + } + } + pMBinfo ++; + pMBdp ++; + colNum ++; + if (colNum == mbPerRow) { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) + return sts; + pYc += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pCbc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pCrc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + pYr += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYr << 4) - stepYr; + pCbr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbr << 3) - stepCbr; + pCrr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrr << 3) - stepCrr; + } + else + { + pYc += 16; pCrc += 8; pCbc += 8; + pYr += 16; pCrr += 8; pCbr += 8; + } + } + //mbCurr += mbInVideoPacket; + if (!pInfo->VisualObject.VideoObject.resync_marker_disable) + { + int32_t found; +ErrRet_2: + if (mp4_CheckDecodeVideoPacket(pInfo, &found) == MP4_STATUS_OK) + { + if (found) + { + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant_scale; + mbInVideoPacket = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num - mbCurr; + mbCurr = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, mbCurr - rowNum * mbPerRow - colNum); + rowNum = mbCurr / mbPerRow; + colNum = mbCurr % mbPerRow; + pYc = pInfo->VisualObject.cFrame->pY + (rowNum * stepYc + colNum) * 16; pCbc = pInfo->VisualObject.cFrame->pCb + (rowNum * stepCbc + colNum) * 8; pCrc = pInfo->VisualObject.cFrame->pCr + (rowNum * stepCrc + colNum) * 8; + pYr = pInfo->VisualObject.rFrame->pY + (rowNum * stepYr + colNum) * 16; pCbr = pInfo->VisualObject.rFrame->pCb + (rowNum * stepCbr + colNum) * 8; pCrr = pInfo->VisualObject.rFrame->pCr + (rowNum * stepCrr + colNum) * 8; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo + mbCurr; + } + else + goto Err_2; + } + else + goto Err_2; + } + // mark MBs the previous videopacket as invalid for prediction + for (i = 1; i <= IPP_MIN(mbInVideoPacket, mbPerRow + 1); i ++) + pMBinfo[-i].validPred = 0; + } +Err_2: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (pInfo->VisualObject.VideoObject.resync_marker_disable || !mp4_SeekResyncMarker(pInfo)) + { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_2; + } + // decode interlaced P-VOP + if (pInfo->VisualObject.VideoObject.interlaced) + { + int32_t stepY, pYoff23, field_prediction, dct_type, dct_typePrev, mb_ftfr, mb_fbfr; + IppMotionVector mvCbCrT, mvCbCrB, *mvField = pInfo->VisualObject.VideoObject.FieldMV; + + // warning "variable may be used without having been initialized" + dct_type = dct_typePrev = mb_ftfr = mb_fbfr = 0; + mvCbCrT.dx = mvCbCrT.dy = mvCbCrB.dx = mvCbCrB.dy = 0; + for (;;) { + // reset Intra prediction buffer on new Video_packet + mp4_ResetIntraPredBuffer(pInfo); + mbInVideoPacket = 0; + // decode blocks + for (;;) + { + if (colNum == 0) + { + // reset B-prediction blocks on new row + mp4_ResetIntraPredBblock(pInfo); + } + mb_not_coded = mp4_GetBit(pInfo); + mb_type = IPPVC_MBTYPE_INTER; + if (!mb_not_coded) + { + if (mp4_DecodeMCBPC_P(pInfo, &mb_type, &cbpc, 1) != MP4_STATUS_OK) + goto Err_3; + } + if (mb_type != IPPVC_MB_STUFFING) + { + if (!mb_not_coded) + { + if (mb_type >= IPPVC_MBTYPE_INTRA) + ac_pred_flag = mp4_GetBit(pInfo); + if (mp4_DecodeCBPY_P(pInfo, &cbpy, mb_type) != MP4_STATUS_OK) + goto Err_3; + quantPred = quant; + if (mb_type == IPPVC_MBTYPE_INTER_Q || mb_type == IPPVC_MBTYPE_INTRA_Q) + mp4_UpdateQuant(pInfo, quant); + dct_type = 0; + field_prediction = 0; + if (mb_type >= IPPVC_MBTYPE_INTRA || (cbpy + cbpc) != 0) + dct_type = mp4_GetBit(pInfo); + if (mb_type == IPPVC_MBTYPE_INTER || mb_type == IPPVC_MBTYPE_INTER_Q) { + field_prediction = mp4_GetBit(pInfo); + if (field_prediction) { + mb_ftfr = mp4_GetBit(pInfo); + mb_fbfr = mp4_GetBit(pInfo); + } + } + } + else + { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_NOTCODED); + mp4_Zero4MV(pMBinfo->mv); + field_prediction = 0; + } + pMBinfo->validPred = 1; + pMBinfo->not_coded = (uint8_t)mb_not_coded; + pMBinfo->type = (uint8_t)mb_type; + pMBinfo->field_info = (uint8_t)(field_prediction + (mb_ftfr << 1) + (mb_fbfr << 2)); + if (mb_type >= IPPVC_MBTYPE_INTRA) + { + if (mbInVideoPacket == 0) + quantPred = quant; + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + if (dct_type) + { + stepY = stepYc * 2; + pYoff23 = stepYc; + } + else + { + stepY = stepYc; + pYoff23 = 8 * stepYc; + } + stepFc[0] = stepFc[1] = stepFc[2] = stepFc[3] = stepY; + pFc[0] = pYc; pFc[1] = pYc + 8; pFc[2] = pYc + pYoff23; pFc[3] = pYc + pYoff23 + 8; pFc[4] = pCbc; pFc[5] = pCrc; + if (mp4_DecodeIntraMB(pInfo, colNum, (cbpy << 2) + cbpc, quant, dcVLC, ac_pred_flag, pFc, stepFc) != MP4_STATUS_OK) + goto Err_3; + mp4_Zero4MV(pMBinfo->mv); +#ifdef USE_NOTCODED_STATE + // clear not_coded MB state + *ncState = 0; +#endif + } + else + { + mp4_UpdateIntraPredBuffInvalid(pInfo, colNum); + if (!mb_not_coded) + { + dx = colNum * 16; + dy = rowNum * 16; + if (!field_prediction) + { + if (mb_type != IPPVC_MBTYPE_INTER4V) + { + if (mp4_PredictDecode1MV(pInfo, pMBinfo, rowNum, colNum) != MP4_STATUS_OK) + goto Err_3; + pMBinfo->mv[1] = pMBinfo->mv[2] = pMBinfo->mv[3] = pMBinfo->mv[0]; + if (quarter_sample) + { + mp4_LimitMVQ(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(mvCur, &mvCbCr); + } + else + { + mp4_LimitMV(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(mvCur, &mvCbCr); + } + mvCur[1] = mvCur[2] = mvCur[3] = mvCur[0]; + } + else + { + if (mp4_PredictDecode4MV(pInfo, pMBinfo, rowNum, colNum) != MP4_STATUS_OK) + goto Err_3; + if (quarter_sample) + { + mp4_Limit4MVQ(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MVQ(pMBinfo->mv, &mvCbCr); + } + else + { + mp4_Limit4MV(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MV(pMBinfo->mv, &mvCbCr); + } + mp4_LimitMV(&mvCbCr, &mvCbCr, &limitRectC, dx >> 1, dy >> 1, 8); + } + } + else + { + IppMotionVector mvFT, mvFB; + if (mp4_PredictDecodeFMV(pInfo, pMBinfo, rowNum, colNum, &mvFT, &mvFB) != MP4_STATUS_OK) + goto Err_3; + mvField[0] = mvFT; mvField[1] = mvFB; + if (quarter_sample) + { + mp4_LimitFMVQ(&mvFT, &mvCur[0], &limitRectL, dx, dy, 16); + mp4_LimitFMVQ(&mvFB, &mvCur[2], &limitRectL, dx, dy, 16); + mvTmp[0].dx = (int16_t)mp4_Div2(mvCur[0].dx); + mvTmp[0].dy = (int16_t)(mp4_Div2(mvCur[0].dy << 1) >> 1); + mvTmp[2].dx = (int16_t)mp4_Div2(mvCur[2].dx); + mvTmp[2].dy = (int16_t)(mp4_Div2(mvCur[2].dy << 1) >> 1); + mp4_ComputeChromaMV(&mvTmp[0], &mvCbCrT); + mp4_ComputeChromaMV(&mvTmp[2], &mvCbCrB); + } + else + { + mp4_LimitFMV(&mvFT, &mvCur[0], &limitRectL, dx, dy, 16); + mp4_LimitFMV(&mvFB, &mvCur[2], &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(&mvCur[0], &mvCbCrT); + mp4_ComputeChromaMV(&mvCur[2], &mvCbCrB); + } + } + } + } + if (!obmc_disable) + { + // OBMC for previous MB + if (colNum > 0) + if (pMBinfo[-1].type < IPPVC_MBTYPE_INTRA && !(pMBinfo[-1].field_info & 1)) + mp4_OBMC(pInfo, pMBinfo - 1, mvPrev, colNum - 1, rowNum, limitRectL, pYc - 16, stepYc, pYr - 16, stepYr, cbpyPrev, coeffMB, dct_typePrev); + if (mb_type < IPPVC_MBTYPE_INTRA && !field_prediction) + { + if (mb_not_coded) + { + cbpyPrev = 0; + mp4_Zero4MV(mvPrev); + ippiCopy8x8_8u_C1R(pCbr, stepCbr, pCbc, stepCbc); + ippiCopy8x8_8u_C1R(pCrr, stepCrr, pCrc, stepCrc); + } + else + { + cbpyPrev = cbpy; + dct_typePrev = dct_type; + mvPrev[0] = mvCur[0]; mvPrev[1] = mvCur[1]; mvPrev[2] = mvCur[2]; mvPrev[3] = mvCur[3]; + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, (cbpy << 2) + cbpc, scan) != MP4_STATUS_OK) + goto Err_3; + mp4_MC_HP(cbpc & 2, pCbr, stepCbr, pCbc, stepCbc, coeffMB+256, &mvCbCr, rt); + mp4_MC_HP(cbpc & 1, pCrr, stepCrr, pCrc, stepCrc, coeffMB+320, &mvCbCr, rt); + } + // OBMC current MB if it is the last in the row + if (colNum == mbPerRow - 1) + mp4_OBMC(pInfo, pMBinfo, mvPrev, colNum, rowNum, limitRectL, pYc, stepYc, pYr, stepYr, cbpyPrev, coeffMB, dct_typePrev); + } + } + if (mb_type < IPPVC_MBTYPE_INTRA && (obmc_disable || field_prediction)) + { + if (mb_not_coded) + { +#ifdef USE_NOTCODED_STATE + if (!(*ncState)) + { + *ncState = 1; +#endif + ippiCopy16x16_8u_C1R(pYr, stepYr, pYc, stepYc); + ippiCopy8x8_8u_C1R(pCbr, stepCbr, pCbc, stepCbc); + ippiCopy8x8_8u_C1R(pCrr, stepCrr, pCrc, stepCrc); +#ifdef USE_NOTCODED_STATE + } +#endif + } + else + { +#ifdef USE_NOTCODED_STATE + // clear not_coded MB state + *ncState = 0; +#endif + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, (cbpy << 2) + cbpc, scan) != MP4_STATUS_OK) + goto Err_3; + if (quarter_sample) + { + if (!field_prediction) + { + if (mb_type == IPPVC_MBTYPE_INTER4V) + { + mp4_Copy8x8QP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_Copy8x8QP_8u(pYr+8, stepYr, pYc+8, stepYc, &mvCur[1], rt); + mp4_Copy8x8QP_8u(pYr+stepYr*8, stepYr, pYc+stepYc*8, stepYc, &mvCur[2], rt); + mp4_Copy8x8QP_8u(pYr+8+stepYr*8, stepYr, pYc+8+stepYc*8, stepYc, &mvCur[3], rt); + } + else + mp4_Copy16x16QP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + } + else + { + mp4_Copy16x8QP_8u(pYr+stepYr*mb_ftfr, stepYr*2, pYc, stepYc*2, &mvCur[0], rt); + mp4_Copy16x8QP_8u(pYr+stepYr*mb_fbfr, stepYr*2, pYc+stepYc, stepYc*2, &mvCur[2], rt); + } + } + else + { + if (!field_prediction) + { + if (mb_type == IPPVC_MBTYPE_INTER4V) + { + mp4_Copy8x8HP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_Copy8x8HP_8u(pYr+8, stepYr, pYc+8, stepYc, &mvCur[1], rt); + mp4_Copy8x8HP_8u(pYr+stepYr*8, stepYr, pYc+stepYc*8, stepYc, &mvCur[2], rt); + mp4_Copy8x8HP_8u(pYr+8+stepYr*8, stepYr, pYc+8+stepYc*8, stepYc, &mvCur[3], rt); + } + else + { + mp4_Copy16x16HP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + } + } + else + { + mp4_Copy16x8HP_8u(pYr+stepYr*mb_ftfr, stepYr*2, pYc, stepYc*2, &mvCur[0], rt); + mp4_Copy16x8HP_8u(pYr+stepYr*mb_fbfr, stepYr*2, pYc+stepYc, stepYc*2, &mvCur[2], rt); + } + } + if (!dct_type) + { + mp4_AddResidual(cbpy & 8, pYc, stepYc, coeffMB); + mp4_AddResidual(cbpy & 4, pYc+8, stepYc, coeffMB+64); + mp4_AddResidual(cbpy & 2, pYc+stepYc*8, stepYc, coeffMB+128); + mp4_AddResidual(cbpy & 1, pYc+stepYc*8+8, stepYc, coeffMB+192); + } else { + mp4_AddResidual(cbpy & 8, pYc, stepYc*2, coeffMB); + mp4_AddResidual(cbpy & 4, pYc+8, stepYc*2, coeffMB+64); + mp4_AddResidual(cbpy & 2, pYc+stepYc, stepYc*2, coeffMB+128); + mp4_AddResidual(cbpy & 1, pYc+stepYc+8, stepYc*2, coeffMB+192); + } + if (!field_prediction) { + mp4_MC_HP(cbpc & 2, pCbr, stepCbr, pCbc, stepCbc, coeffMB+256, &mvCbCr, rt); + mp4_MC_HP(cbpc & 1, pCrr, stepCrr, pCrc, stepCrc, coeffMB+320, &mvCbCr, rt); + } else { + mp4_Copy8x4HP_8u(pCbr+(mb_ftfr ? stepCbr : 0), stepCbr*2, pCbc, stepCbc*2, &mvCbCrT, rt); + mp4_Copy8x4HP_8u(pCrr+(mb_ftfr ? stepCrr : 0), stepCrr*2, pCrc, stepCrc*2, &mvCbCrT, rt); + mp4_Copy8x4HP_8u(pCbr+(mb_fbfr ? stepCbr : 0), stepCbr*2, pCbc+stepCbc, stepCbc*2, &mvCbCrB, rt); + mp4_Copy8x4HP_8u(pCrr+(mb_fbfr ? stepCrr : 0), stepCrr*2, pCrc+stepCrc, stepCrc*2, &mvCbCrB, rt); + mp4_AddResidual(cbpc & 2, pCbc, stepCbc, coeffMB+256); + mp4_AddResidual(cbpc & 1, pCrc, stepCrc, coeffMB+320); + } + } + } +#ifdef USE_NOTCODED_STATE + ncState ++; +#endif + pMBinfo ++; + mvField += 2; + mbInVideoPacket ++; + colNum ++; + if (colNum == mbPerRow) { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) { + // skip stuffing + while (mp4_ShowBits(pInfo, 10) == 1) + mp4_FlushBits(pInfo, 10); + return sts; + } + pYc += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pCbc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pCrc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + pYr += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYr << 4) - stepYr; + pCbr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbr << 3) - stepCbr; + pCrr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrr << 3) - stepCrr; + } else { + pYc += 16; pCrc += 8; pCbc += 8; + pYr += 16; pCrr += 8; pCbr += 8; + } + } + if (!pInfo->VisualObject.VideoObject.resync_marker_disable) { + int32_t found; +ErrRet_3: + if (mp4_CheckDecodeVideoPacket(pInfo, &found) == MP4_STATUS_OK) { + if (found) { + mbInVideoPacket = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num - mbCurr; + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant_scale; + mbCurr = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, mbCurr - rowNum * mbPerRow - colNum); + rowNum = mbCurr / mbPerRow; + colNum = mbCurr % mbPerRow; + pYc = pInfo->VisualObject.cFrame->pY + (rowNum * stepYc + colNum) * 16; pCbc = pInfo->VisualObject.cFrame->pCb + (rowNum * stepCbc + colNum) * 8; pCrc = pInfo->VisualObject.cFrame->pCr + (rowNum * stepCrc + colNum) * 8; + pYr = pInfo->VisualObject.rFrame->pY + (rowNum * stepYr + colNum) * 16; pCbr = pInfo->VisualObject.rFrame->pCb + (rowNum * stepCbr + colNum) * 8; pCrr = pInfo->VisualObject.rFrame->pCr + (rowNum * stepCrr + colNum) * 8; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo + mbCurr; +#ifdef USE_NOTCODED_STATE + ncState = pInfo->VisualObject.VideoObject.ncState + mbCurr; +#endif + mvField = pInfo->VisualObject.VideoObject.FieldMV + 2 * mbCurr; + break; + } + } else + goto Err_3; + } + } + // mark MBs the previous videopacket as invalid for prediction + for (i = 1; i <= IPP_MIN(mbInVideoPacket, mbPerRow + 1); i ++) { + pMBinfo[-i].validPred = 0; + } + } +Err_3: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (pInfo->VisualObject.VideoObject.resync_marker_disable || !mp4_SeekResyncMarker(pInfo)) + { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_3; + } + // decode usual P-VOP + { + for (;;) + { + // reset Intra prediction buffer on new Video_packet + mp4_ResetIntraPredBuffer(pInfo); + mbInVideoPacket = 0; + // decode blocks + for (;;) + { + if (colNum == 0) + { + // reset B-prediction blocks on new row + mp4_ResetIntraPredBblock(pInfo); + } + mb_not_coded = mp4_GetBit(pInfo); + mb_type = IPPVC_MBTYPE_INTER; + if (!mb_not_coded) + if (mp4_DecodeMCBPC_P(pInfo, &mb_type, &cbpc, 1) != MP4_STATUS_OK) + goto Err_4; + if (mb_type != IPPVC_MB_STUFFING) + { + if (!mb_not_coded) + { + if (mb_type >= IPPVC_MBTYPE_INTRA) + ac_pred_flag = mp4_GetBit(pInfo); + if (mp4_DecodeCBPY_P(pInfo, &cbpy, mb_type) != MP4_STATUS_OK) + goto Err_4; + quantPred = quant; + if (mb_type == IPPVC_MBTYPE_INTER_Q || mb_type == IPPVC_MBTYPE_INTRA_Q) + mp4_UpdateQuant(pInfo, quant); + } + else + { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_NOTCODED); + mp4_Zero4MV(pMBinfo->mv); + } + pMBinfo->validPred = 1; + pMBinfo->not_coded = (uint8_t)mb_not_coded; + pMBinfo->type = (uint8_t)mb_type; + if (mb_type >= IPPVC_MBTYPE_INTRA) { + if (mbInVideoPacket == 0) + quantPred = quant; + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + pFc[0] = pYc; pFc[1] = pYc + 8; pFc[2] = pYc + 8 * stepYc; pFc[3] = pYc + 8 * stepYc + 8; pFc[4] = pCbc; pFc[5] = pCrc; + if (mp4_DecodeIntraMB(pInfo, colNum, (cbpy << 2) + cbpc, quant, dcVLC, ac_pred_flag, pFc, stepFc) != MP4_STATUS_OK) + goto Err_4; + mp4_Zero4MV(pMBinfo->mv); +#ifdef USE_NOTCODED_STATE + // clear not_coded MB state + *ncState = 0; +#endif + } else { + mp4_UpdateIntraPredBuffInvalid(pInfo, colNum); + if (!mb_not_coded) { + dx = colNum * 16; + dy = rowNum * 16; + if (mb_type != IPPVC_MBTYPE_INTER4V) { + if (mp4_PredictDecode1MV(pInfo, pMBinfo, rowNum, colNum) != MP4_STATUS_OK) + goto Err_4; + pMBinfo->mv[1] = pMBinfo->mv[2] = pMBinfo->mv[3] = pMBinfo->mv[0]; + if (quarter_sample) { + mp4_LimitMVQ(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(mvCur, &mvCbCr); + } else { + mp4_LimitMV(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(mvCur, &mvCbCr); + } + mvCur[1] = mvCur[2] = mvCur[3] = mvCur[0]; + } else { + if (mp4_PredictDecode4MV(pInfo, pMBinfo, rowNum, colNum) != MP4_STATUS_OK) + goto Err_4; + if (quarter_sample) { + mp4_Limit4MVQ(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MVQ(pMBinfo->mv, &mvCbCr); + } else { + mp4_Limit4MV(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MV(pMBinfo->mv, &mvCbCr); + } + mp4_LimitMV(&mvCbCr, &mvCbCr, &limitRectC, dx >> 1, dy >> 1, 8); + } + } + if (obmc_disable) { + if (mb_not_coded) { +#ifdef USE_NOTCODED_STATE + if (!(*ncState)) { + *ncState = 1; +#endif + ippiCopy16x16_8u_C1R(pYr, stepYr, pYc, stepYc); + ippiCopy8x8_8u_C1R(pCbr, stepCbr, pCbc, stepCbc); + ippiCopy8x8_8u_C1R(pCrr, stepCrr, pCrc, stepCrc); +#ifdef USE_NOTCODED_STATE + } +#endif + } else { +#ifdef USE_NOTCODED_STATE + // clear not_coded MB state + *ncState = 0; +#endif + if (quarter_sample) { + if (mb_type == IPPVC_MBTYPE_INTER4V) { + mp4_Copy8x8QP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_Copy8x8QP_8u(pYr+8, stepYr, pYc+8, stepYc, &mvCur[1], rt); + mp4_Copy8x8QP_8u(pYr+8*stepYr, stepYr, pYc+8*stepYc, stepYc, &mvCur[2], rt); + mp4_Copy8x8QP_8u(pYr+8*stepYr+8, stepYr, pYc+8*stepYc+8, stepYc, &mvCur[3], rt); + } else + mp4_Copy16x16QP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_DecodeReconBlockInter_MPEG4(cbpy & 8, pYc, stepYc, Err_4); + mp4_DecodeReconBlockInter_MPEG4(cbpy & 4, pYc+8, stepYc, Err_4); + mp4_DecodeReconBlockInter_MPEG4(cbpy & 2, pYc+8*stepYc, stepYc, Err_4); + mp4_DecodeReconBlockInter_MPEG4(cbpy & 1, pYc+8*stepYc+8, stepYc, Err_4); + } else { + if (cbpy || mb_type == IPPVC_MBTYPE_INTER4V) { + mp4_DecodeMCBlockInter_MPEG4(cbpy & 8, pYr, stepYr, pYc, stepYc, mvCur[0], rt, Err_4); + mp4_DecodeMCBlockInter_MPEG4(cbpy & 4, pYr+8, stepYr, pYc+8, stepYc, mvCur[1], rt, Err_4); + mp4_DecodeMCBlockInter_MPEG4(cbpy & 2, pYr+8*stepYr, stepYr, pYc+8*stepYc, stepYc, mvCur[2], rt, Err_4); + mp4_DecodeMCBlockInter_MPEG4(cbpy & 1, pYr+8*stepYr+8, stepYr, pYc+8*stepYc+8, stepYc, mvCur[3], rt, Err_4); + } else { + mp4_Copy16x16HP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nB_INTER_NC); + //if (cbpy) { + // mp4_DecodeReconBlockInter_MPEG4(cbpy & 8, pYc, stepYc); + // mp4_DecodeReconBlockInter_MPEG4(cbpy & 4, pYc+8, stepYc); + // mp4_DecodeReconBlockInter_MPEG4(cbpy & 2, pYc+8*stepYc, stepYc); + // mp4_DecodeReconBlockInter_MPEG4(cbpy & 1, pYc+8*stepYc+8, stepYc); + //} + } + } + mp4_DecodeMCBlockInter_MPEG4(cbpc & 2, pCbr, stepCbr, pCbc, stepCbc, mvCbCr, rt, Err_4); + mp4_DecodeMCBlockInter_MPEG4(cbpc & 1, pCrr, stepCrr, pCrc, stepCrc, mvCbCr, rt, Err_4); + } + } + } + if (!obmc_disable) { + // OBMC for previous MB + if (colNum > 0) + if (pMBinfo[-1].type < IPPVC_MBTYPE_INTRA) + mp4_OBMC(pInfo, pMBinfo - 1, mvPrev, colNum - 1, rowNum, limitRectL, pYc - 16, stepYc, pYr - 16, stepYr, cbpyPrev, coeffMB, 0); + if (mb_type < IPPVC_MBTYPE_INTRA) { + if (mb_not_coded) + { + cbpyPrev = 0; + mp4_Zero4MV(mvPrev); + ippiCopy8x8_8u_C1R(pCbr, stepCbr, pCbc, stepCbc); + ippiCopy8x8_8u_C1R(pCrr, stepCrr, pCrc, stepCrc); + } + else + { + cbpyPrev = cbpy; + mvPrev[0] = mvCur[0]; mvPrev[1] = mvCur[1]; mvPrev[2] = mvCur[2]; mvPrev[3] = mvCur[3]; + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, (cbpy << 2) + cbpc, scan) != MP4_STATUS_OK) + goto Err_4; + mp4_MC_HP(cbpc & 2, pCbr, stepCbr, pCbc, stepCbc, coeffMB+256, &mvCbCr, rt); + mp4_MC_HP(cbpc & 1, pCrr, stepCrr, pCrc, stepCrc, coeffMB+320, &mvCbCr, rt); + } + // OBMC current MB if it is the last in the row + if (colNum == mbPerRow - 1) + mp4_OBMC(pInfo, pMBinfo, mvPrev, colNum, rowNum, limitRectL, pYc, stepYc, pYr, stepYr, cbpyPrev, coeffMB, 0); + } + } +#ifdef USE_NOTCODED_STATE + ncState ++; +#endif + pMBinfo ++; + mbInVideoPacket ++; + colNum ++; + if (colNum == mbPerRow) + { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) + { + // skip stuffing + while (mp4_ShowBits(pInfo, 10) == 1) + mp4_FlushBits(pInfo, 10); + return sts; + } + pYc += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pCbc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pCrc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + pYr += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYr << 4) - stepYr; + pCbr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbr << 3) - stepCbr; + pCrr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrr << 3) - stepCrr; + } + else + { + pYc += 16; pCrc += 8; pCbc += 8; + pYr += 16; pCrr += 8; pCbr += 8; + } + } + if (!pInfo->VisualObject.VideoObject.resync_marker_disable) + { + int32_t found; +ErrRet_4: + if (mp4_CheckDecodeVideoPacket(pInfo, &found) == MP4_STATUS_OK) + { + if (found) { + mbInVideoPacket = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num - mbCurr; + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant_scale; + mbCurr = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, mbCurr - rowNum * mbPerRow - colNum); + rowNum = mbCurr / mbPerRow; + colNum = mbCurr % mbPerRow; + pYc = pInfo->VisualObject.cFrame->pY + (rowNum * stepYc + colNum) * 16; pCbc = pInfo->VisualObject.cFrame->pCb + (rowNum * stepCbc + colNum) * 8; pCrc = pInfo->VisualObject.cFrame->pCr + (rowNum * stepCrc + colNum) * 8; + pYr = pInfo->VisualObject.rFrame->pY + (rowNum * stepYr + colNum) * 16; pCbr = pInfo->VisualObject.rFrame->pCb + (rowNum * stepCbr + colNum) * 8; pCrr = pInfo->VisualObject.rFrame->pCr + (rowNum * stepCrr + colNum) * 8; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo + mbCurr; +#ifdef USE_NOTCODED_STATE + ncState = pInfo->VisualObject.VideoObject.ncState + mbCurr; +#endif + break; + } + } + else + goto Err_4; + } + } + // mark MBs the previous videopacket as invalid for prediction + for (i = 1; i <= IPP_MIN(mbInVideoPacket, mbPerRow + 1); i ++) + { + pMBinfo[-i].validPred = 0; + } + } +Err_4: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (pInfo->VisualObject.VideoObject.resync_marker_disable || !mp4_SeekResyncMarker(pInfo)) + { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_4; + } +} + + diff --git a/Src/mpeg4dec/mp4decvops.c b/Src/mpeg4dec/mp4decvops.c new file mode 100644 index 00000000..4a331964 --- /dev/null +++ b/Src/mpeg4dec/mp4decvops.c @@ -0,0 +1,655 @@ +/* /////////////////////////////////////////////////////////////////////// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 2001-2007 Intel Corporation. All Rights Reserved. +// +// Description: Decodes S-VOPs +// +*/ + +#include "mp4def.h" +#include "mp4dec.h" + +/* +// decode MPEG-4 SVOP +*/ +mp4_Status mp4_DecodeVOP_S(mp4_Info* pInfo) +{ + __ALIGN16(int16_t, coeffMB, 64*6); + int32_t quant, quantPred, i, j, dcVLC, nmb, dx, dy, pat; + int32_t stepYr, stepYc, stepCbr, stepCbc, stepCrr, stepCrc, mbPerRow, mbPerCol; + int32_t mbCurr, mbInVideoPacket, colNum, rowNum, stepF[6]; + uint8_t *pYc, *pCbc, *pCrc, *pYr, *pCbr, *pCrr, *pF[6]; + int32_t mb_not_coded, mb_type, cbpc, cbpy, ac_pred_flag, cbpyPrev, mcsel; + int32_t scan, obmc_disable, rt, quarter_sample, interlaced, fcode_forward; + IppiRect limitRectL, limitRectC; + IppMotionVector mvCur[4], mvPrev[4], mvTmp[4], mvCbCr; + mp4_MacroBlock *pMBinfo; + IppiRect spriteRect, vopRect; + mp4_Status sts; + + if (!pInfo->VisualObject.cFrame) + pInfo->VisualObject.cFrame = CreateFrame(&pInfo->VisualObject); + + mbPerRow = pInfo->VisualObject.VideoObject.MacroBlockPerRow; + mbPerCol = pInfo->VisualObject.VideoObject.MacroBlockPerCol; + stepYc = pInfo->VisualObject.cFrame->stepY; + stepYr = pInfo->VisualObject.rFrame->stepY; + stepCbc = pInfo->VisualObject.cFrame->stepCb; + stepCbr = pInfo->VisualObject.rFrame->stepCb; + stepCrc = pInfo->VisualObject.cFrame->stepCr; + stepCrr = pInfo->VisualObject.rFrame->stepCr; + pYc = pInfo->VisualObject.cFrame->pY; + pCbc = pInfo->VisualObject.cFrame->pCb; + pCrc = pInfo->VisualObject.cFrame->pCr; + pYr = pInfo->VisualObject.rFrame->pY; + pCbr = pInfo->VisualObject.rFrame->pCb; + pCrr = pInfo->VisualObject.rFrame->pCr; + stepF[0] = stepF[1] = stepF[2] = stepF[3] = stepYc; stepF[4] = stepCbc; stepF[5] = stepCrc; + // Bounding rectangle for MV limitation + limitRectL.x = - 16 * MP4_NUM_EXT_MB; + limitRectL.y = - 16 * MP4_NUM_EXT_MB; + limitRectL.width = pInfo->VisualObject.VideoObject.width + 16 * 2 * MP4_NUM_EXT_MB; + limitRectL.height = pInfo->VisualObject.VideoObject.height + 16 * 2 * MP4_NUM_EXT_MB; + limitRectC.x = -8 * MP4_NUM_EXT_MB; + limitRectC.y = -8 * MP4_NUM_EXT_MB; + limitRectC.width = (pInfo->VisualObject.VideoObject.width >> 1) + 8 * 2 * MP4_NUM_EXT_MB; + limitRectC.height = (pInfo->VisualObject.VideoObject.height >> 1) + 8 * 2 * MP4_NUM_EXT_MB; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo; + rt = pInfo->VisualObject.VideoObject.VideoObjectPlane.rounding_type; + quarter_sample = pInfo->VisualObject.VideoObject.quarter_sample; + obmc_disable = pInfo->VisualObject.VideoObject.obmc_disable; + interlaced = pInfo->VisualObject.VideoObject.interlaced; + scan = pInfo->VisualObject.VideoObject.VideoObjectPlane.alternate_vertical_scan_flag ? IPPVC_SCAN_VERTICAL : IPPVC_SCAN_ZIGZAG; + nmb = pInfo->VisualObject.VideoObject.MacroBlockPerVOP; + quant = quantPred = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant; + mbCurr = colNum = rowNum = 0; + cbpc = 0; + // init WarpSpec for Sprites or GMC + vopRect.x = 0; + vopRect.y = 0; + vopRect.width = pInfo->VisualObject.VideoObject.width; + vopRect.height = pInfo->VisualObject.VideoObject.height; + if (pInfo->VisualObject.VideoObject.sprite_enable == MP4_SPRITE_STATIC) { + spriteRect.x = pInfo->VisualObject.VideoObject.sprite_left_coordinate; + spriteRect.y = pInfo->VisualObject.VideoObject.sprite_top_coordinate; + spriteRect.width = pInfo->VisualObject.VideoObject.sprite_width; + spriteRect.height = pInfo->VisualObject.VideoObject.sprite_height; + fcode_forward = 1; + } else { + spriteRect = vopRect; // for shapes they may be different !!!!!! + fcode_forward = pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_forward; + } + ippiWarpInit_MPEG4(pInfo->VisualObject.VideoObject.WarpSpec, + pInfo->VisualObject.VideoObject.VideoObjectPlane.warping_mv_code_du, + pInfo->VisualObject.VideoObject.VideoObjectPlane.warping_mv_code_dv, + pInfo->VisualObject.VideoObject.sprite_warping_points, + pInfo->VisualObject.VideoObject.sprite_enable, + pInfo->VisualObject.VideoObject.sprite_warping_accuracy, + rt, quarter_sample, fcode_forward, + &spriteRect, &vopRect); +// decode basic sprites + if (pInfo->VisualObject.VideoObject.sprite_enable == MP4_SPRITE_STATIC) + { + //if (pInfo->VisualObject.VideoObject.shape != MP4_SHAPE_TYPE_RECTANGULAR) { + // if (mp4_InitVOPShape(pInfo) != MP4_STATUS_OK) + // return MP4_STATUS_ERROR; + //} + ippiWarpLuma_MPEG4_8u_C1R(pInfo->VisualObject.sFrame->pY, pInfo->VisualObject.sFrame->stepY, + pYc, stepYc, &vopRect, pInfo->VisualObject.VideoObject.WarpSpec); + if (pInfo->VisualObject.VideoObject.sprite_brightness_change) + ippiChangeSpriteBrightness_MPEG4_8u_C1IR(pYc, stepYc, vopRect.width, vopRect.height, pInfo->VisualObject.VideoObject.VideoObjectPlane.brightness_change_factor); + vopRect.width >>= 1; vopRect.height >>= 1; + ippiWarpChroma_MPEG4_8u_P2R(pInfo->VisualObject.sFrame->pCb, pInfo->VisualObject.sFrame->stepCb, + pInfo->VisualObject.sFrame->pCr, pInfo->VisualObject.sFrame->stepCr, + pCbc, stepCbc, pCrc, stepCrc, &vopRect, pInfo->VisualObject.VideoObject.WarpSpec); + return MP4_STATUS_OK; + } + sts = MP4_STATUS_OK; +// decode data_partitioned S(GMC)-VOP + if (pInfo->VisualObject.VideoObject.data_partitioned) { + for (;;) { + mp4_DataPartMacroBlock *pMBdp; + int32_t x, y; + + x = colNum; + y = rowNum; + // reset Intra prediction buffer on new Video_packet + mp4_ResetIntraPredBuffer(pInfo); + pMBdp = &pInfo->VisualObject.VideoObject.DataPartBuff[mbCurr]; + pMBinfo = &pInfo->VisualObject.VideoObject.MBinfo[mbCurr]; + mbInVideoPacket = 0; + // decode not_coded/mcsel/mb_type/cbpc/MV part + for (;;) { + mb_not_coded = mp4_GetBit(pInfo); + if (mb_not_coded) { + mb_type = IPPVC_MBTYPE_INTER; + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_NOTCODED); + } else { + if (mp4_DecodeMCBPC_P(pInfo, &mb_type, &cbpc, 1) != MP4_STATUS_OK) + goto Err_2; + } + if (mb_type != IPPVC_MB_STUFFING) { + if (mbInVideoPacket == nmb - mbCurr) { + mp4_Error("DC Marker missed"); + goto Err_2; + } + pMBinfo->validPred = 1; + if (mb_type < IPPVC_MBTYPE_INTER4V && !mb_not_coded) + mcsel = mp4_GetBit(pInfo); + else + mcsel = mb_not_coded; + if (!mcsel) { + if (mb_type <= IPPVC_MBTYPE_INTER4V) { + if (mb_type != IPPVC_MBTYPE_INTER4V) { + if (mp4_PredictDecode1MV(pInfo, pMBinfo, y, x) != MP4_STATUS_OK) + goto Err_2; + pMBinfo->mv[1] = pMBinfo->mv[2] = pMBinfo->mv[3] = pMBinfo->mv[0]; + } else { + if (mp4_PredictDecode4MV(pInfo, pMBinfo, y, x) != MP4_STATUS_OK) + goto Err_2; + } + } else { + mp4_Zero4MV(pMBinfo->mv); + } + } else { + ippiCalcGlobalMV_MPEG4(x << 4, y << 4, pMBinfo->mv, pInfo->VisualObject.VideoObject.WarpSpec); + pMBinfo->mv[1] = pMBinfo->mv[2] = pMBinfo->mv[3] = pMBinfo->mv[0]; + } + pMBinfo->not_coded = (uint8_t)mb_not_coded; + pMBinfo->type = (uint8_t)mb_type; + pMBinfo ++; + pMBdp->pat = (uint8_t)cbpc; + pMBdp->mcsel = (uint8_t)mcsel; + pMBdp ++; + mbInVideoPacket ++; + x ++; + if (x == mbPerRow) { + x = 0; + y ++; + } + } + if (mp4_ShowBits(pInfo, 17) == MP4_MV_MARKER) { + mp4_GetBits(pInfo, 17); + break; + } + } + pMBdp = &pInfo->VisualObject.VideoObject.DataPartBuff[mbCurr]; + pMBinfo = &pInfo->VisualObject.VideoObject.MBinfo[mbCurr]; + // decode ac_pred_flag/cbpy/dquant/IntraDC part + for (i = 0; i < mbInVideoPacket; i ++) { + if (!pMBinfo->not_coded) { + mb_type = pMBinfo->type; + if (mb_type >= IPPVC_MBTYPE_INTRA) + pMBdp->ac_pred_flag = (uint8_t)mp4_GetBit(pInfo); + if (mp4_DecodeCBPY_P(pInfo, &cbpy, mb_type) != MP4_STATUS_OK) + goto Err_2; + pMBdp->pat = (uint8_t)((cbpy << 2) + pMBdp->pat); + quantPred = quant; + if (mb_type == IPPVC_MBTYPE_INTER_Q || mb_type == IPPVC_MBTYPE_INTRA_Q) + mp4_UpdateQuant(pInfo, quant); + pMBdp->quant = (uint8_t)quant; + if (i == 0) + quantPred = quant; + // decode DC coefficient of Intra blocks + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + if ((mb_type >= IPPVC_MBTYPE_INTRA) && dcVLC) { + for (j = 0; j < 6; j ++) { + if (ippiDecodeDCIntra_MPEG4_1u16s(&pInfo->bufptr, &pInfo->bitoff, &pMBdp->dct_dc[j], j < 4 ? IPPVC_BLOCK_LUMA : IPPVC_BLOCK_CHROMA) != ippStsNoErr) + goto Err_2; + } + } + } else + pMBdp->pat = 0; + pMBinfo->not_coded = 0; // for B-VOP all MB have MVs + if (pMBdp->mcsel) + pMBinfo->type = IPPVC_MBTYPE_INTRA; // for OBMC MVs + pMBdp ++; + pMBinfo ++; + } + if (mbCurr + mbInVideoPacket < nmb) + pMBinfo->type = IPPVC_MBTYPE_INTRA; // for OBMC set first MB of the next videopacket as invalid for right MV + pMBdp = &pInfo->VisualObject.VideoObject.DataPartBuff[mbCurr]; + pMBinfo = &pInfo->VisualObject.VideoObject.MBinfo[mbCurr]; + // decode coeffs and reconstruct macroblocks + for (i = 0; i < mbInVideoPacket; i ++) { + if (colNum == 0) { + // reset B-prediction blocks on new row + mp4_ResetIntraPredBblock(pInfo); + } + quant = pMBdp->quant; + mb_type = pMBinfo->type; + mcsel = pMBdp->mcsel; + if (!mcsel && (mb_type >= IPPVC_MBTYPE_INTRA)) { + quantPred = (i == 0) ? quant : pMBdp[-1].quant; + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + pF[0] = pYc; pF[1] = pYc + 8; pF[2] = pYc + 8 * stepYc; pF[3] = pYc + 8 * stepYc + 8; pF[4] = pCbc; pF[5] = pCrc; + if (mp4_DecodeIntraMB_DP(pInfo, pMBdp->dct_dc, colNum, pMBdp->pat, quant, dcVLC, pMBdp->ac_pred_flag, pF, stepF) != MP4_STATUS_OK) + goto Err_2; + } else { + mp4_UpdateIntraPredBuffInvalid(pInfo, colNum); + dx = colNum * 16; + dy = rowNum * 16; + pat = pMBdp->pat; + cbpy = pat >> 2; + cbpc = pat & 3; + if (pat) + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, pat, scan) != MP4_STATUS_OK) + goto Err_2; + if (!mcsel) { + if (mb_type == IPPVC_MBTYPE_INTER4V) { + if (quarter_sample) { + mp4_Limit4MVQ(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MVQ(pMBinfo->mv, &mvCbCr); + } else { + mp4_Limit4MV(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MV(pMBinfo->mv, &mvCbCr); + } + mp4_LimitMV(&mvCbCr, &mvCbCr, &limitRectC, dx >> 1, dy >> 1, 8); + } else { + if (quarter_sample) { + mp4_LimitMVQ(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(mvCur, &mvCbCr); + } else { + mp4_LimitMV(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(mvCur, &mvCbCr); + } + mvCur[1] = mvCur[2] = mvCur[3] = mvCur[0]; + } + if (obmc_disable) { + if (quarter_sample) { + if (mb_type == IPPVC_MBTYPE_INTER4V) { + mp4_Copy8x8QP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_Copy8x8QP_8u(pYr+8, stepYr, pYc+8, stepYc, &mvCur[1], rt); + mp4_Copy8x8QP_8u(pYr+8*stepYr, stepYr, pYc+8*stepYc, stepYc, &mvCur[2], rt); + mp4_Copy8x8QP_8u(pYr+8*stepYr+8, stepYr, pYc+8*stepYc+8, stepYc, &mvCur[3], rt); + } else + mp4_Copy16x16QP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + } else { + if (mb_type == IPPVC_MBTYPE_INTER4V) { + mp4_Copy8x8HP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_Copy8x8HP_8u(pYr+8, stepYr, pYc+8, stepYc, &mvCur[1], rt); + mp4_Copy8x8HP_8u(pYr+8*stepYr, stepYr, pYc+8*stepYc, stepYc, &mvCur[2], rt); + mp4_Copy8x8HP_8u(pYr+8*stepYr+8, stepYr, pYc+8*stepYc+8, stepYc, &mvCur[3], rt); + } else + mp4_Copy16x16HP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + } + mp4_AddResidual(cbpy & 8, pYc, stepYc, coeffMB); + mp4_AddResidual(cbpy & 4, pYc+8, stepYc, coeffMB+64); + mp4_AddResidual(cbpy & 2, pYc+stepYc*8, stepYc, coeffMB+128); + mp4_AddResidual(cbpy & 1, pYc+stepYc*8+8, stepYc, coeffMB+192); + } else { + mp4_OBMC(pInfo, pMBinfo, mvCur, colNum, rowNum, limitRectL, pYc, stepYc, pYr, stepYr, cbpy, coeffMB, 0); + } + mp4_MC_HP(cbpc & 2, pCbr, stepCbr, pCbc, stepCbc, coeffMB+256, &mvCbCr, rt); + mp4_MC_HP(cbpc & 1, pCrr, stepCrr, pCrc, stepCrc, coeffMB+320, &mvCbCr, rt); + } else { + IppiRect mbRect; + + mbRect.x = dx; mbRect.y = dy; mbRect.width = mbRect.height = 16; + ippiWarpLuma_MPEG4_8u_C1R(pInfo->VisualObject.rFrame->pY, stepYr, pYc, stepYc, &mbRect, pInfo->VisualObject.VideoObject.WarpSpec); + mbRect.x >>= 1; mbRect.y >>= 1; mbRect.width = mbRect.height = 8; + ippiWarpChroma_MPEG4_8u_P2R(pInfo->VisualObject.rFrame->pCb, stepCbr, pInfo->VisualObject.rFrame->pCr, stepCrr, pCbc, stepCbc, pCrc, stepCrc, &mbRect, pInfo->VisualObject.VideoObject.WarpSpec); + if (pat) { + mp4_AddResidual(cbpy & 8, pYc, stepYc, coeffMB); + mp4_AddResidual(cbpy & 4, pYc+8, stepYc, coeffMB+64); + mp4_AddResidual(cbpy & 2, pYc+stepYc*8, stepYc, coeffMB+128); + mp4_AddResidual(cbpy & 1, pYc+stepYc*8+8, stepYc, coeffMB+192); + mp4_AddResidual(cbpc & 2, pCbc, stepCbc, coeffMB+256); + mp4_AddResidual(cbpc & 1, pCrc, stepCrc, coeffMB+320); + } + } + } + pMBinfo ++; + pMBdp ++; + colNum ++; + if (colNum == mbPerRow) { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) + return sts; + pYc += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pCbc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pCrc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + pYr += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYr << 4) - stepYr; + pCbr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbr << 3) - stepCbr; + pCrr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrr << 3) - stepCrr; + } + else + { + pYc += 16; pCrc += 8; pCbc += 8; + pYr += 16; pCrr += 8; pCbr += 8; + } + } + //mbCurr += mbInVideoPacket; + if (!pInfo->VisualObject.VideoObject.resync_marker_disable) + { + int32_t found; +ErrRet_2: + if (mp4_CheckDecodeVideoPacket(pInfo, &found) == MP4_STATUS_OK) + { + if (found) + { + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant_scale; + mbInVideoPacket = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num - mbCurr; + mbCurr = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, mbCurr - rowNum * mbPerRow - colNum); + rowNum = mbCurr / mbPerRow; + colNum = mbCurr % mbPerRow; + pYc = pInfo->VisualObject.cFrame->pY + (rowNum * stepYc + colNum) * 16; pCbc = pInfo->VisualObject.cFrame->pCb + (rowNum * stepCbc + colNum) * 8; pCrc = pInfo->VisualObject.cFrame->pCr + (rowNum * stepCrc + colNum) * 8; + pYr = pInfo->VisualObject.rFrame->pY + (rowNum * stepYr + colNum) * 16; pCbr = pInfo->VisualObject.rFrame->pCb + (rowNum * stepCbr + colNum) * 8; pCrr = pInfo->VisualObject.rFrame->pCr + (rowNum * stepCrr + colNum) * 8; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo + mbCurr; + } else + goto Err_2; + } else + goto Err_2; + } + // mark MBs the previous videopacket as invalid for prediction + for (i = 1; i <= IPP_MIN(mbInVideoPacket, mbPerRow + 1); i ++) + pMBinfo[-i].validPred = 0; + } +Err_2: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (pInfo->VisualObject.VideoObject.resync_marker_disable || !mp4_SeekResyncMarker(pInfo)) + { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_2; + } +// decode not data_partitioned S-VOP + { + int32_t stepY, pYoff23, field_prediction, dct_type, dct_typePrev, mb_ftfr, mb_fbfr; + IppMotionVector mvCbCrT, mvCbCrB, *mvField = pInfo->VisualObject.VideoObject.FieldMV; + + // warning "variable may be used without having been initialized" + dx = dy = ac_pred_flag = cbpy = cbpyPrev = field_prediction = dct_type = dct_typePrev = mb_ftfr = mb_fbfr = 0; + mvCbCr.dx = mvCbCr.dy = mvCbCrT.dx = mvCbCrT.dy = mvCbCrB.dx = mvCbCrB.dy = 0; + for (;;) { + // reset Intra prediction buffer on new Video_packet + mp4_ResetIntraPredBuffer(pInfo); + mbInVideoPacket = 0; + // decode blocks + for (;;) { + if (colNum == 0) { + // reset B-prediction blocks on new row + mp4_ResetIntraPredBblock(pInfo); + } + mb_not_coded = mp4_GetBit(pInfo); + mb_type = IPPVC_MBTYPE_INTER; + if (!mb_not_coded) { + if (mp4_DecodeMCBPC_P(pInfo, &mb_type, &cbpc, 1) != MP4_STATUS_OK) + goto Err_3; + } + if (mb_type != IPPVC_MB_STUFFING) { + if (!mb_not_coded) { + mcsel = (mb_type < IPPVC_MBTYPE_INTER4V) ? mp4_GetBit(pInfo) : 0; + if (mb_type >= IPPVC_MBTYPE_INTRA) + ac_pred_flag = mp4_GetBit(pInfo); + if (mp4_DecodeCBPY_P(pInfo, &cbpy, mb_type) != MP4_STATUS_OK) + goto Err_3; + quantPred = quant; + if (mb_type == IPPVC_MBTYPE_INTER_Q || mb_type == IPPVC_MBTYPE_INTRA_Q) + mp4_UpdateQuant(pInfo, quant); + if (interlaced) { + dct_type = 0; + field_prediction = 0; + if (mb_type >= IPPVC_MBTYPE_INTRA || (cbpy + cbpc) != 0) + dct_type = mp4_GetBit(pInfo); + if ((mb_type == IPPVC_MBTYPE_INTER || mb_type == IPPVC_MBTYPE_INTER_Q) && !mcsel) { + field_prediction = mp4_GetBit(pInfo); + if (field_prediction) { + mb_ftfr = mp4_GetBit(pInfo); + mb_fbfr = mp4_GetBit(pInfo); + } + } + } + } else { + mp4_StatisticInc_(&pInfo->VisualObject.Statistic.nMB_NOTCODED); + mcsel = 1; + field_prediction = 0; + } + pMBinfo->validPred = 1; + pMBinfo->not_coded = 0; // for B-VOP all MB have MVs + pMBinfo->type = (uint8_t)(mcsel ? IPPVC_MBTYPE_INTRA : mb_type); // for OBMC MVs + pMBinfo->field_info = (uint8_t)(field_prediction + (mb_ftfr << 1) + (mb_fbfr << 2)); + if (mb_type >= IPPVC_MBTYPE_INTRA) { + if (mbInVideoPacket == 0) + quantPred = quant; + dcVLC = (quantPred < mp4_DC_vlc_Threshold[pInfo->VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr]) ? 1 : 0; + if (dct_type) { + stepY = stepYc * 2; + pYoff23 = stepYc; + } else { + stepY = stepYc; + pYoff23 = 8 * stepYc; + } + stepF[0] = stepF[1] = stepF[2] = stepF[3] = stepY; + pF[0] = pYc; pF[1] = pYc + 8; pF[2] = pYc + pYoff23; pF[3] = pYc + pYoff23 + 8; pF[4] = pCbc; pF[5] = pCrc; + if (mp4_DecodeIntraMB(pInfo, colNum, (cbpy << 2) + cbpc, quant, dcVLC, ac_pred_flag, pF, stepF) != MP4_STATUS_OK) + goto Err_3; + mp4_Zero4MV(pMBinfo->mv); + } else { + mp4_UpdateIntraPredBuffInvalid(pInfo, colNum); + dx = colNum * 16; + dy = rowNum * 16; + if (!mcsel) { + if (!field_prediction) { + if (mb_type != IPPVC_MBTYPE_INTER4V) { + if (mp4_PredictDecode1MV(pInfo, pMBinfo, rowNum, colNum) != MP4_STATUS_OK) + goto Err_3; + pMBinfo->mv[1] = pMBinfo->mv[2] = pMBinfo->mv[3] = pMBinfo->mv[0]; + if (quarter_sample) { + mp4_LimitMVQ(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMVQ(mvCur, &mvCbCr); + } else { + mp4_LimitMV(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(mvCur, &mvCbCr); + } + mvCur[1] = mvCur[2] = mvCur[3] = mvCur[0]; + } else { + if (mp4_PredictDecode4MV(pInfo, pMBinfo, rowNum, colNum) != MP4_STATUS_OK) + goto Err_3; + if (quarter_sample) { + mp4_Limit4MVQ(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MVQ(pMBinfo->mv, &mvCbCr); + } else { + mp4_Limit4MV(pMBinfo->mv, mvCur, &limitRectL, dx, dy, 8); + mp4_ComputeChroma4MV(pMBinfo->mv, &mvCbCr); + } + mp4_LimitMV(&mvCbCr, &mvCbCr, &limitRectC, dx >> 1, dy >> 1, 8); + } + } else { + IppMotionVector mvFT, mvFB; + if (mp4_PredictDecodeFMV(pInfo, pMBinfo, rowNum, colNum, &mvFT, &mvFB) != MP4_STATUS_OK) + goto Err_3; + mvField[0] = mvFT; mvField[1] = mvFB; + if (quarter_sample) { + mp4_LimitFMVQ(&mvFT, &mvCur[0], &limitRectL, dx, dy, 16); + mp4_LimitFMVQ(&mvFB, &mvCur[2], &limitRectL, dx, dy, 16); + mvTmp[0].dx = (int16_t)mp4_Div2(mvCur[0].dx); + mvTmp[0].dy = (int16_t)(mp4_Div2(mvCur[0].dy << 1) >> 1); + mvTmp[2].dx = (int16_t)mp4_Div2(mvCur[2].dx); + mvTmp[2].dy = (int16_t)(mp4_Div2(mvCur[2].dy << 1) >> 1); + mp4_ComputeChromaMV(&mvTmp[0], &mvCbCrT); + mp4_ComputeChromaMV(&mvTmp[2], &mvCbCrB); + } else { + mp4_LimitFMV(&mvFT, &mvCur[0], &limitRectL, dx, dy, 16); + mp4_LimitFMV(&mvFB, &mvCur[2], &limitRectL, dx, dy, 16); + mp4_ComputeChromaMV(&mvCur[0], &mvCbCrT); + mp4_ComputeChromaMV(&mvCur[2], &mvCbCrB); + } + } + } else { + ippiCalcGlobalMV_MPEG4(dx, dy, pMBinfo->mv, pInfo->VisualObject.VideoObject.WarpSpec); + pMBinfo->mv[1] = pMBinfo->mv[2] = pMBinfo->mv[3] = pMBinfo->mv[0]; + } + } + if (!obmc_disable) { + // OBMC for previous MB + if (colNum > 0) + if (pMBinfo[-1].type < IPPVC_MBTYPE_INTRA && !(pMBinfo[-1].field_info & 1)) // previous is marked as INTRA if it was mcsel + mp4_OBMC(pInfo, pMBinfo - 1, mvPrev, colNum - 1, rowNum, limitRectL, pYc - 16, stepYc, pYr - 16, stepYr, cbpyPrev, coeffMB, dct_typePrev); + if (mb_type < IPPVC_MBTYPE_INTRA && !field_prediction && !mcsel) { + cbpyPrev = cbpy; + dct_typePrev = dct_type; + mvPrev[0] = mvCur[0]; mvPrev[1] = mvCur[1]; mvPrev[2] = mvCur[2]; mvPrev[3] = mvCur[3]; + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, (cbpy << 2) + cbpc, scan) != MP4_STATUS_OK) + goto Err_3; + mp4_MC_HP(cbpc & 2, pCbr, stepCbr, pCbc, stepCbc, coeffMB+256, &mvCbCr, rt); + mp4_MC_HP(cbpc & 1, pCrr, stepCrr, pCrc, stepCrc, coeffMB+320, &mvCbCr, rt); + // OBMC current MB if it is the last in the row + if (colNum == mbPerRow - 1) + mp4_OBMC(pInfo, pMBinfo, mvPrev, colNum, rowNum, limitRectL, pYc, stepYc, pYr, stepYr, cbpyPrev, coeffMB, dct_typePrev); + } + } + if (mb_type < IPPVC_MBTYPE_INTRA && (obmc_disable || field_prediction || mcsel)) { + pat = mb_not_coded ? 0 : ((cbpy << 2) + cbpc); + if (pat) + if (mp4_DecodeInterMB(pInfo, coeffMB, quant, pat, scan) != MP4_STATUS_OK) + goto Err_3; + if (!mcsel) { + if (quarter_sample) { + if (!field_prediction) { + if (mb_type == IPPVC_MBTYPE_INTER4V) { + mp4_Copy8x8QP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_Copy8x8QP_8u(pYr+8, stepYr, pYc+8, stepYc, &mvCur[1], rt); + mp4_Copy8x8QP_8u(pYr+stepYr*8, stepYr, pYc+stepYc*8, stepYc, &mvCur[2], rt); + mp4_Copy8x8QP_8u(pYr+8+stepYr*8, stepYr, pYc+8+stepYc*8, stepYc, &mvCur[3], rt); + } else { + mp4_Copy16x16QP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + } + } else { + mp4_Copy16x8QP_8u(pYr+stepYr*mb_ftfr, stepYr*2, pYc, stepYc*2, &mvCur[0], rt); + mp4_Copy16x8QP_8u(pYr+stepYr*mb_fbfr, stepYr*2, pYc+stepYc, stepYc*2, &mvCur[2], rt); + } + } else { + if (!field_prediction) { + if (mb_type == IPPVC_MBTYPE_INTER4V) { + mp4_Copy8x8HP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + mp4_Copy8x8HP_8u(pYr+8, stepYr, pYc+8, stepYc, &mvCur[1], rt); + mp4_Copy8x8HP_8u(pYr+stepYr*8, stepYr, pYc+stepYc*8, stepYc, &mvCur[2], rt); + mp4_Copy8x8HP_8u(pYr+8+stepYr*8, stepYr, pYc+8+stepYc*8, stepYc, &mvCur[3], rt); + } else { + mp4_Copy16x16HP_8u(pYr, stepYr, pYc, stepYc, &mvCur[0], rt); + } + } else { + mp4_Copy16x8HP_8u(pYr+stepYr*mb_ftfr, stepYr*2, pYc, stepYc*2, &mvCur[0], rt); + mp4_Copy16x8HP_8u(pYr+stepYr*mb_fbfr, stepYr*2, pYc+stepYc, stepYc*2, &mvCur[2], rt); + } + } + if (!dct_type) { + mp4_AddResidual(cbpy & 8, pYc, stepYc, coeffMB); + mp4_AddResidual(cbpy & 4, pYc+8, stepYc, coeffMB+64); + mp4_AddResidual(cbpy & 2, pYc+stepYc*8, stepYc, coeffMB+128); + mp4_AddResidual(cbpy & 1, pYc+stepYc*8+8, stepYc, coeffMB+192); + } else { + mp4_AddResidual(cbpy & 8, pYc, stepYc*2, coeffMB); + mp4_AddResidual(cbpy & 4, pYc+8, stepYc*2, coeffMB+64); + mp4_AddResidual(cbpy & 2, pYc+stepYc, stepYc*2, coeffMB+128); + mp4_AddResidual(cbpy & 1, pYc+stepYc+8, stepYc*2, coeffMB+192); + } + if (!field_prediction) { + mp4_MC_HP(cbpc & 2, pCbr, stepCbr, pCbc, stepCbc, coeffMB+256, &mvCbCr, rt); + mp4_MC_HP(cbpc & 1, pCrr, stepCrr, pCrc, stepCrc, coeffMB+320, &mvCbCr, rt); + } else { + mp4_Copy8x4HP_8u(pCbr+(mb_ftfr ? stepCbr : 0), stepCbr*2, pCbc, stepCbc*2, &mvCbCrT, rt); + mp4_Copy8x4HP_8u(pCrr+(mb_ftfr ? stepCrr : 0), stepCrr*2, pCrc, stepCrc*2, &mvCbCrT, rt); + mp4_Copy8x4HP_8u(pCbr+(mb_fbfr ? stepCbr : 0), stepCbr*2, pCbc+stepCbc, stepCbc*2, &mvCbCrB, rt); + mp4_Copy8x4HP_8u(pCrr+(mb_fbfr ? stepCrr : 0), stepCrr*2, pCrc+stepCrc, stepCrc*2, &mvCbCrB, rt); + mp4_AddResidual(cbpc & 2, pCbc, stepCbc, coeffMB+256); + mp4_AddResidual(cbpc & 1, pCrc, stepCrc, coeffMB+320); + } + } else { + IppiRect mbRect; + + mbRect.x = dx; mbRect.y = dy; mbRect.width = mbRect.height = 16; + ippiWarpLuma_MPEG4_8u_C1R(pInfo->VisualObject.rFrame->pY, stepYr, pYc, stepYc, &mbRect, pInfo->VisualObject.VideoObject.WarpSpec); + mbRect.x >>= 1; mbRect.y >>= 1; mbRect.width = mbRect.height = 8; + ippiWarpChroma_MPEG4_8u_P2R(pInfo->VisualObject.rFrame->pCb, stepCbr, pInfo->VisualObject.rFrame->pCr, stepCrr, pCbc, stepCbc, pCrc, stepCrc, &mbRect, pInfo->VisualObject.VideoObject.WarpSpec); + if (pat) { + if (!dct_type) { + mp4_AddResidual(cbpy & 8, pYc, stepYc, coeffMB); + mp4_AddResidual(cbpy & 4, pYc+8, stepYc, coeffMB+64); + mp4_AddResidual(cbpy & 2, pYc+stepYc*8, stepYc, coeffMB+128); + mp4_AddResidual(cbpy & 1, pYc+stepYc*8+8, stepYc, coeffMB+192); + } else { + mp4_AddResidual(cbpy & 8, pYc, stepYc*2, coeffMB); + mp4_AddResidual(cbpy & 4, pYc+8, stepYc*2, coeffMB+64); + mp4_AddResidual(cbpy & 2, pYc+stepYc, stepYc*2, coeffMB+128); + mp4_AddResidual(cbpy & 1, pYc+stepYc+8, stepYc*2, coeffMB+192); + } + mp4_AddResidual(cbpc & 2, pCbc, stepCbc, coeffMB+256); + mp4_AddResidual(cbpc & 1, pCrc, stepCrc, coeffMB+320); + } + } + } + pMBinfo ++; + mvField += 2; + mbInVideoPacket ++; + colNum ++; + if (colNum == mbPerRow) { + colNum = 0; + rowNum ++; + if (rowNum == mbPerCol) { + // skip stuffing + while (mp4_ShowBits(pInfo, 10) == 1) + mp4_FlushBits(pInfo, 10); + return sts; + } + pYc += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYc << 4) - stepYc; + pCbc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbc << 3) - stepCbc; + pCrc += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrc << 3) - stepCrc; + pYr += (2 * MP4_NUM_EXT_MB + 1) * 16 + (stepYr << 4) - stepYr; + pCbr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCbr << 3) - stepCbr; + pCrr += (2 * MP4_NUM_EXT_MB + 1) * 8 + (stepCrr << 3) - stepCrr; + } else { + pYc += 16; pCrc += 8; pCbc += 8; + pYr += 16; pCrr += 8; pCbr += 8; + } + } + if (!pInfo->VisualObject.VideoObject.resync_marker_disable) { + int32_t found; +ErrRet_3: + if (mp4_CheckDecodeVideoPacket(pInfo, &found) == MP4_STATUS_OK) { + if (found) { + mbInVideoPacket = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num - mbCurr; + quant = pInfo->VisualObject.VideoObject.VideoObjectPlane.quant_scale; + mbCurr = pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num; + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, mbCurr - rowNum * mbPerRow - colNum); + rowNum = mbCurr / mbPerRow; + colNum = mbCurr % mbPerRow; + pYc = pInfo->VisualObject.cFrame->pY + (rowNum * stepYc + colNum) * 16; pCbc = pInfo->VisualObject.cFrame->pCb + (rowNum * stepCbc + colNum) * 8; pCrc = pInfo->VisualObject.cFrame->pCr + (rowNum * stepCrc + colNum) * 8; + pYr = pInfo->VisualObject.rFrame->pY + (rowNum * stepYr + colNum) * 16; pCbr = pInfo->VisualObject.rFrame->pCb + (rowNum * stepCbr + colNum) * 8; pCrr = pInfo->VisualObject.rFrame->pCr + (rowNum * stepCrr + colNum) * 8; + pMBinfo = pInfo->VisualObject.VideoObject.MBinfo + mbCurr; + mvField = pInfo->VisualObject.VideoObject.FieldMV + 2 * mbCurr; + break; + } + } else + goto Err_3; + } + } + // mark MBs the previous videopacket as invalid for prediction + for (i = 1; i <= IPP_MIN(mbInVideoPacket, mbPerRow + 1); i ++) { + pMBinfo[-i].validPred = 0; + } + } +Err_3: + sts = MP4_STATUS_ERROR; + if (pInfo->stopOnErr) + return sts; + if (pInfo->VisualObject.VideoObject.resync_marker_disable || !mp4_SeekResyncMarker(pInfo)) { + mp4_CopyMacroBlocks(pInfo->VisualObject.rFrame, pInfo->VisualObject.cFrame, mbPerRow, rowNum, colNum, pInfo->VisualObject.VideoObject.MacroBlockPerVOP - rowNum * mbPerRow - colNum); + return sts; + } + goto ErrRet_3; + } +} + + + diff --git a/Src/mpeg4dec/mp4def.h b/Src/mpeg4dec/mp4def.h new file mode 100644 index 00000000..603ebf2d --- /dev/null +++ b/Src/mpeg4dec/mp4def.h @@ -0,0 +1,975 @@ +/* /////////////////////////////////////////////////////////////////////// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 2001-2008 Intel Corporation. All Rights Reserved. +// +// Description: MPEG-4 header. +// +*/ + +#pragma once + +#include <bfc/platform/types.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "../tools/staticlib/ipp_px.h" +#include "ippdefs.h" +#include "ippcore.h" +#include "ipps.h" +#include "ippi.h" +#include "ippvc.h" +//#include "vm_debug.h" +//#include "vm_thread.h" + +#pragma warning(disable : 4710) // function not inlined +#pragma warning(disable : 4514) // unreferenced inline function has been removed CL +#pragma warning(disable : 4100) // unreferenced formal parameter CL + +#ifdef __cplusplus +extern "C" { +#endif + +//#define USE_INLINE_BITS_FUNC +#define USE_NOTCODED_STATE + +#if defined(__INTEL_COMPILER) || defined(_MSC_VER) + #define __INLINE static __inline +#elif defined( __GNUC__ ) + #define __INLINE static __inline__ +#else + #define __INLINE static +#endif + +#if defined(__INTEL_COMPILER) && !defined(_WIN32_WCE) + #define __ALIGN16(type, name, size) \ + __declspec (align(16)) type name[size] +#else + #if defined(_WIN64) || defined(WIN64) || defined(LINUX64) + #define __ALIGN16(type, name, size) \ + uint8_t _a16_##name[(size)*sizeof(type)+15]; type *name = (type*)(((int64_t)(_a16_##name) + 15) & ~15) + #else + #define __ALIGN16(type, name, size) \ + uint8_t _a16_##name[(size)*sizeof(type)+15]; type *name = (type*)(((int32_t)(_a16_##name) + 15) & ~15) + #endif +#endif + +#define mp4_CLIP(x, min, max) if ((x) < (min)) (x) = (min); else if ((x) > (max)) (x) = (max) +#define mp4_CLIPR(x, max) if ((x) > (max)) (x) = (max) +#define mp4_SWAP(type, x, y) {mp4_Frame *t = (x); (x) = (y); (y) = t;} +#define mp4_ABS(a) ((a) >= 0 ? (a) : -(a)) + +/* Timer Info */ +#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64) + +#include <windows.h> + + typedef struct _mp4_Timer { + LARGE_INTEGER count; + LARGE_INTEGER start; + LARGE_INTEGER stop; + int32_t calls; + } mp4_Timer; + + __INLINE void mp4_TimerStart(mp4_Timer *t) + { + QueryPerformanceCounter(&t->start); + } + + __INLINE void mp4_TimerStop(mp4_Timer *t) + { + QueryPerformanceCounter(&t->stop); + t->count.QuadPart += t->stop.QuadPart - t->start.QuadPart; + t->calls ++; + } + +#define TIMER_FREQ_TYPE LARGE_INTEGER + + __INLINE void mp4_GetTimerFreq(TIMER_FREQ_TYPE *f) + { + QueryPerformanceFrequency(f); + } + + __INLINE double mp4_GetTimerSec(mp4_Timer *t, TIMER_FREQ_TYPE f) + { + return (double)t->count.QuadPart / (double)f.QuadPart; + } + +#else // LINUX + +#include <time.h> + + typedef struct _mp4_Timer { + clock_t count; + clock_t start; + clock_t stop; + int32_t calls; + } mp4_Timer; + + __INLINE void mp4_TimerStart(mp4_Timer *t) + { + t->start = clock(); + } + + __INLINE void mp4_TimerStop(mp4_Timer *t) + { + t->stop = clock(); + t->count += t->stop - t->start; + t->calls ++; + } + +#define TIMER_FREQ_TYPE int32_t + + __INLINE void mp4_GetTimerFreq(TIMER_FREQ_TYPE *f) + { + *f = CLOCKS_PER_SEC; + } + + __INLINE double mp4_GetTimerSec(mp4_Timer *t, TIMER_FREQ_TYPE f) + { + return (double)t->count / (double)f; + } + +#endif + +/* number of exterior MB */ +#define MP4_NUM_EXT_MB 1 + +/* Statistic Info */ +typedef struct _mp4_Statistic { + // VideoObjectLayer Info + int32_t nVOP; + int32_t nVOP_I; + int32_t nVOP_P; + int32_t nVOP_B; + int32_t nVOP_S; + int32_t nMB; + int32_t nMB_INTER; + int32_t nMB_INTER_Q; + int32_t nMB_INTRA; + int32_t nMB_INTRA_Q; + int32_t nMB_INTER4V; + int32_t nMB_DIRECT; + int32_t nMB_INTERPOLATE; + int32_t nMB_BACKWARD; + int32_t nMB_FORWARD; + int32_t nMB_NOTCODED; + int32_t nB_INTRA_DC; + int32_t nB_INTRA_AC; + int32_t nB_INTER_C; + int32_t nB_INTER_NC; + // app Timing Info + mp4_Timer time_DecodeShow; // decode + draw + file reading + mp4_Timer time_Decode; // decode + file reading + mp4_Timer time_DecodeOnly; // decode only +} mp4_Statistic; + +__INLINE void mp4_StatisticInc(int32_t *s) +{ + *s = (*s) + 1; +} + +// when using Full Statistic, FPS is less +#ifdef MP4_FULL_STAT +#define mp4_StatisticInc_(s) mp4_StatisticInc(s) +#define mp4_TimerStart_(t) mp4_TimerStart(t) +#define mp4_TimerStop_(t) mp4_TimerStop(t) +#else +#define mp4_StatisticInc_(s) +#define mp4_TimerStart_(t) +#define mp4_TimerStop_(t) +#endif + +/* status codes */ +typedef enum { + MP4_STATUS_OK = 0, // no error + MP4_STATUS_NO_MEM = -1, // out of memory + MP4_STATUS_FILE_ERROR = -2, // file error + MP4_STATUS_NOTSUPPORT = -3, // not supported mode + MP4_STATUS_PARSE_ERROR = -4, // fail in parse MPEG-4 stream + MP4_STATUS_ERROR = -5 // unknown/unspecified error +} mp4_Status; + +/* MPEG-4 start code values */ +// ISO/IEC 14496-2: table 6-3 +enum { + MP4_VIDEO_OBJECT_MIN_SC = 0x00, + MP4_VIDEO_OBJECT_MAX_SC = 0x1F, + MP4_VIDEO_OBJECT_LAYER_MIN_SC = 0x20, + MP4_VIDEO_OBJECT_LAYER_MAX_SC = 0x2F, + MP4_FGS_BP_MIN_SC = 0x40, + MP4_FGS_BP_MAX_SC = 0x5F, + MP4_VISUAL_OBJECT_SEQUENCE_SC = 0xB0, + MP4_VISUAL_OBJECT_SEQUENCE_EC = 0xB1, + MP4_USER_DATA_SC = 0xB2, + MP4_GROUP_OF_VOP_SC = 0xB3, + MP4_VIDEO_SESSION_ERROR_SC = 0xB4, + MP4_VISUAL_OBJECT_SC = 0xB5, + MP4_VIDEO_OBJECT_PLANE_SC = 0xB6, + MP4_SLICE_SC = 0xB7, + MP4_EXTENSION_SC = 0xB8, + MP4_FGS_VOP_SC = 0xB9, + MP4_FBA_OBJECT_SC = 0xBA, + MP4_FBA_OBJECT_PLANE_SC = 0xBB, + MP4_MESH_OBJECT_SC = 0xBC, + MP4_MESH_OBJECT_PLANE_SC = 0xBD, + MP4_STILL_TEXTURE_OBJECT_SC = 0xBE, + MP4_TEXTURE_SPATIAL_LAYER_SC = 0xBF, + MP4_TEXTURE_SNR_LAYER_SC = 0xC0, + MP4_TEXTURE_TILE_SC = 0xC1, + MP4_TEXTURE_SHAPE_LAYER_SC = 0xC2, + MP4_STUFFING_SC = 0xC3 +}; + +/* MPEG-4 code values */ +// ISO/IEC 14496-2:2004 table 6-6 +enum { + MP4_VISUAL_OBJECT_TYPE_VIDEO = 1, + MP4_VISUAL_OBJECT_TYPE_TEXTURE = 2, + MP4_VISUAL_OBJECT_TYPE_MESH = 3, + MP4_VISUAL_OBJECT_TYPE_FBA = 4, + MP4_VISUAL_OBJECT_TYPE_3DMESH = 5 +}; + +// ISO/IEC 14496-2:2004 table 6-7 +enum { + MP4_VIDEO_FORMAT_COMPONENT = 0, + MP4_VIDEO_FORMAT_PAL = 1, + MP4_VIDEO_FORMAT_NTSC = 2, + MP4_VIDEO_FORMAT_SECAM = 3, + MP4_VIDEO_FORMAT_MAC = 4, + MP4_VIDEO_FORMAT_UNSPECIFIED = 5 +}; + +// ISO/IEC 14496-2:2004 table 6-8..10 +enum { + MP4_VIDEO_COLORS_FORBIDDEN = 0, + MP4_VIDEO_COLORS_ITU_R_BT_709 = 1, + MP4_VIDEO_COLORS_UNSPECIFIED = 2, + MP4_VIDEO_COLORS_RESERVED = 3, + MP4_VIDEO_COLORS_ITU_R_BT_470_2_M = 4, + MP4_VIDEO_COLORS_ITU_R_BT_470_2_BG = 5, + MP4_VIDEO_COLORS_SMPTE_170M = 6, + MP4_VIDEO_COLORS_SMPTE_240M = 7, + MP4_VIDEO_COLORS_GENERIC_FILM = 8 +}; + +// ISO/IEC 14496-2:2004 table 6-11 +enum { + MP4_VIDEO_OBJECT_TYPE_SIMPLE = 1, + MP4_VIDEO_OBJECT_TYPE_SIMPLE_SCALABLE = 2, + MP4_VIDEO_OBJECT_TYPE_CORE = 3, + MP4_VIDEO_OBJECT_TYPE_MAIN = 4, + MP4_VIDEO_OBJECT_TYPE_NBIT = 5, + MP4_VIDEO_OBJECT_TYPE_2DTEXTURE = 6, + MP4_VIDEO_OBJECT_TYPE_2DMESH = 7, + MP4_VIDEO_OBJECT_TYPE_SIMPLE_FACE = 8, + MP4_VIDEO_OBJECT_TYPE_STILL_SCALABLE_TEXTURE = 9, + MP4_VIDEO_OBJECT_TYPE_ADVANCED_REAL_TIME_SIMPLE = 10, + MP4_VIDEO_OBJECT_TYPE_CORE_SCALABLE = 11, + MP4_VIDEO_OBJECT_TYPE_ADVANCED_CODING_EFFICIENCY = 12, + MP4_VIDEO_OBJECT_TYPE_ADVANCED_SCALABLE_TEXTURE = 13, + MP4_VIDEO_OBJECT_TYPE_SIMPLE_FBA = 14, + MP4_VIDEO_OBJECT_TYPE_SIMPLE_STUDIO = 15, + MP4_VIDEO_OBJECT_TYPE_CORE_STUDIO = 16, + MP4_VIDEO_OBJECT_TYPE_ADVANCED_SIMPLE = 17, + MP4_VIDEO_OBJECT_TYPE_FINE_GRANULARITY_SCALABLE = 18 +}; + +// ISO/IEC 14496-2:2004 table 6.17 (maximum defined video_object_layer_shape_extension) +#define MP4_SHAPE_EXT_NUM 13 +// ISO/IEC 14496-2:2004 table 6-14 +enum { + MP4_ASPECT_RATIO_FORBIDDEN = 0, + MP4_ASPECT_RATIO_1_1 = 1, + MP4_ASPECT_RATIO_12_11 = 2, + MP4_ASPECT_RATIO_10_11 = 3, + MP4_ASPECT_RATIO_16_11 = 4, + MP4_ASPECT_RATIO_40_33 = 5, + MP4_ASPECT_RATIO_EXTPAR = 15 +}; + +// ISO/IEC 14496-2:2004 table 6-15 +#define MP4_CHROMA_FORMAT_420 1 +// ISO/IEC 14496-2:2004 table 6-16 +enum { + MP4_SHAPE_TYPE_RECTANGULAR = 0, + MP4_SHAPE_TYPE_BINARY = 1, + MP4_SHAPE_TYPE_BINARYONLY = 2, + MP4_SHAPE_TYPE_GRAYSCALE = 3 +}; + +// ISO/IEC 14496-2:2004 table 6-19 +#define MP4_SPRITE_STATIC 1 +#define MP4_SPRITE_GMC 2 +// ISO/IEC 14496-2:2004 table 6-24 +enum { + MP4_VOP_TYPE_I = 0, + MP4_VOP_TYPE_P = 1, + MP4_VOP_TYPE_B = 2, + MP4_VOP_TYPE_S = 3 +}; + +// ISO/IEC 14496-2:2004 table 6-26 +enum { + MP4_SPRITE_TRANSMIT_MODE_STOP = 0, + MP4_SPRITE_TRANSMIT_MODE_PIECE = 1, + MP4_SPRITE_TRANSMIT_MODE_UPDATE = 2, + MP4_SPRITE_TRANSMIT_MODE_PAUSE = 3 +}; + +// ISO/IEC 14496-2:2004 table 7-3 +enum { + MP4_BAB_TYPE_MVDSZ_NOUPDATE = 0, + MP4_BAB_TYPE_MVDSNZ_NOUPDATE = 1, + MP4_BAB_TYPE_TRANSPARENT = 2, + MP4_BAB_TYPE_OPAQUE = 3, + MP4_BAB_TYPE_INTRACAE = 4, + MP4_BAB_TYPE_MVDSZ_INTERCAE = 5, + MP4_BAB_TYPE_MVDSNZ_INTERCAE = 6 +}; + +#define MP4_DC_MARKER 0x6B001 // 110 1011 0000 0000 0001 +#define MP4_MV_MARKER 0x1F001 // 1 1111 0000 0000 0001 + +// ISO/IEC 14496-2:2004 table G.1 +enum { + MP4_SIMPLE_PROFILE_LEVEL_1 = 0x01, + MP4_SIMPLE_PROFILE_LEVEL_2 = 0x02, + MP4_SIMPLE_PROFILE_LEVEL_3 = 0x03, + MP4_SIMPLE_PROFILE_LEVEL_0 = 0x08, + MP4_SIMPLE_SCALABLE_PROFILE_LEVEL_0 = 0x10, + MP4_SIMPLE_SCALABLE_PROFILE_LEVEL_1 = 0x11, + MP4_SIMPLE_SCALABLE_PROFILE_LEVEL_2 = 0x12, + MP4_CORE_PROFILE_LEVEL_1 = 0x21, + MP4_CORE_PROFILE_LEVEL_2 = 0x22, + MP4_MAIN_PROFILE_LEVEL_2 = 0x32, + MP4_MAIN_PROFILE_LEVEL_3 = 0x33, + MP4_MAIN_PROFILE_LEVEL_4 = 0x34, + MP4_NBIT_PROFILE_LEVEL_2 = 0x42, + MP4_SCALABLE_TEXTURE_PROFILE_LEVEL_1 = 0x51, + MP4_SIMPLE_FACE_ANIMATION_PROFILE_LEVEL_1 = 0x61, + MP4_SIMPLE_FACE_ANIMATION_PROFILE_LEVEL_2 = 0x62, + MP4_SIMPLE_FBA_PROFILE_LEVEL_1 = 0x63, + MP4_SIMPLE_FBA_PROFILE_LEVEL_2 = 0x64, + MP4_BASIC_ANIMATED_TEXTURE_PROFILE_LEVEL_1 = 0x71, + MP4_BASIC_ANIMATED_TEXTURE_PROFILE_LEVEL_2 = 0x72, + MP4_HYBRID_PROFILE_LEVEL_1 = 0x81, + MP4_HYBRID_PROFILE_LEVEL_2 = 0x82, + MP4_ADVANCED_REAL_TIME_SIMPLE_PROFILE_LEVEL_1 = 0x91, + MP4_ADVANCED_REAL_TIME_SIMPLE_PROFILE_LEVEL_2 = 0x92, + MP4_ADVANCED_REAL_TIME_SIMPLE_PROFILE_LEVEL_3 = 0x93, + MP4_ADVANCED_REAL_TIME_SIMPLE_PROFILE_LEVEL_4 = 0x94, + MP4_CORE_SCALABLE_PROFILE_LEVEL_1 = 0xA1, + MP4_CORE_SCALABLE_PROFILE_LEVEL_2 = 0xA2, + MP4_CORE_SCALABLE_PROFILE_LEVEL_3 = 0xA3, + MP4_ADVANCED_CODING_EFFICIENCY_PROFILE_LEVEL_1 = 0xB1, + MP4_ADVANCED_CODING_EFFICIENCY_PROFILE_LEVEL_2 = 0xB2, + MP4_ADVANCED_CODING_EFFICIENCY_PROFILE_LEVEL_3 = 0xB3, + MP4_ADVANCED_CODING_EFFICIENCY_PROFILE_LEVEL_4 = 0xB4, + MP4_ADVANCED_CORE_PROFILE_LEVEL_1 = 0xC1, + MP4_ADVANCED_CORE_PROFILE_LEVEL_2 = 0xC2, + MP4_ADVANCED_SCALABLE_TEXTURE_PROFILE_LEVEL_1 = 0xD1, + MP4_ADVANCED_SCALABLE_TEXTURE_PROFILE_LEVEL_2 = 0xD2, + MP4_ADVANCED_SCALABLE_TEXTURE_PROFILE_LEVEL_3 = 0xD3, + MP4_SIMPLE_STUDIO_PROFILE_LEVEL_1 = 0xE1, + MP4_SIMPLE_STUDIO_PROFILE_LEVEL_2 = 0xE2, + MP4_SIMPLE_STUDIO_PROFILE_LEVEL_3 = 0xE3, + MP4_SIMPLE_STUDIO_PROFILE_LEVEL_4 = 0xE4, + MP4_CORE_STUDIO_PROFILE_LEVEL_1 = 0xE5, + MP4_CORE_STUDIO_PROFILE_LEVEL_2 = 0xE6, + MP4_CORE_STUDIO_PROFILE_LEVEL_3 = 0xE7, + MP4_CORE_STUDIO_PROFILE_LEVEL_4 = 0xE8, + MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_0 = 0xF0, + MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_1 = 0xF1, + MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_2 = 0xF2, + MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_3 = 0xF3, + MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_4 = 0xF4, + MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_5 = 0xF5, + MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_3B = 0xF7, + MP4_FGS_PROFILE_LEVEL_0 = 0xF8, + MP4_FGS_PROFILE_LEVEL_1 = 0xF9, + MP4_FGS_PROFILE_LEVEL_2 = 0xFA, + MP4_FGS_PROFILE_LEVEL_3 = 0xFB, + MP4_FGS_PROFILE_LEVEL_4 = 0xFC, + MP4_FGS_PROFILE_LEVEL_5 = 0xFD +}; + +/* Frame Info */ +typedef struct _mp4_Frame { + uint8_t* apY; // allocated with border + uint8_t* apCb; // allocated with border + uint8_t* apCr; // allocated with border + int32_t stepY; + int32_t stepCr; + int32_t stepCb; + uint8_t* pY; // real pointer + uint8_t* pCb; // real pointer + uint8_t* pCr; // real pointer + int32_t type; + int64_t time; + int32_t mbPerRow; // info for realloc VOP with Shape + int32_t mbPerCol; + uint8_t* apB; // for binary mask + uint8_t* pB; + uint8_t* apA[3]; // for aux components + uint8_t* pA[3]; + uint8_t* mid; + uint64_t timestamp; // user-provided timestamp + int QP; + unsigned int reference_count; + int outputted; // for debugging purposes + int sprite; // 0 - frame, 1 - sprite + struct _mp4_Frame *next; // benski> for linked list of display & free frames +} mp4_Frame; + +/* Block Info for Intra Prediction */ +typedef struct _mp4_IntraPredBlock { + struct _mp4_IntraPredBlock *predA; + struct _mp4_IntraPredBlock *predB; + struct _mp4_IntraPredBlock *predC; + int16_t dct_acA[8]; + int16_t dct_acC[8]; + int16_t dct_dc; +} mp4_IntraPredBlock; + +/* Buffer for Intra Prediction */ +typedef struct _mp4_IntraPredBuff { + uint8_t *quant; // quant buffer; + mp4_IntraPredBlock dcB[6]; // blocks for Left-Top DC only + mp4_IntraPredBlock *block; +} mp4_IntraPredBuff; + +/* MacroBlock Info Data Partitioned mode */ +typedef struct _mp4_DataPartMacroBlock { + int16_t dct_dc[6]; + uint8_t type; + uint8_t not_coded; + uint8_t mcsel; + uint8_t ac_pred_flag; + uint8_t pat; + uint8_t quant; +} mp4_DataPartMacroBlock; + +/* MacroBlock Info for Motion */ +typedef struct _mp4_MacroBlock { + IppMotionVector mv[4]; + uint8_t validPred; // for MV pred, OBMC + uint8_t type; // for OBMC, BVOP + uint8_t not_coded; // for OBMC, BVOP + uint8_t field_info; // for Interlaced BVOP Direct mode +} mp4_MacroBlock; + +/* Group Of Video Object Plane Info */ +typedef struct _mp4_GroupOfVideoObjectPlane { + int64_t time_code; + int32_t closed_gov; + int32_t broken_link; +} mp4_GroupOfVideoObjectPlane; + +/* Video Object Plane Info */ +typedef struct _mp4_VideoObjectPlane { + int32_t coding_type; + int32_t modulo_time_base; + int32_t time_increment; + int32_t coded; + int32_t id; // verid != 1 (newpred) + int32_t id_for_prediction_indication; // verid != 1 (newpred) + int32_t id_for_prediction; // verid != 1 (newpred) + int32_t rounding_type; + int32_t reduced_resolution; // verid != 1 + int32_t vop_width; + int32_t vop_height; + int32_t vop_horizontal_mc_spatial_ref; + int32_t vop_vertical_mc_spatial_ref; + int32_t background_composition; + int32_t change_conv_ratio_disable; + int32_t vop_constant_alpha; + int32_t vop_constant_alpha_value; + int32_t intra_dc_vlc_thr; + int32_t top_field_first; + int32_t alternate_vertical_scan_flag; + int32_t sprite_transmit_mode; + int32_t warping_mv_code_du[4]; + int32_t warping_mv_code_dv[4]; + int32_t brightness_change_factor; + int32_t quant; + int32_t alpha_quant[3]; + int32_t fcode_forward; + int32_t fcode_backward; + int32_t shape_coding_type; + int32_t load_backward_shape; + int32_t ref_select_code; + int32_t dx; + int32_t dy; + int32_t quant_scale; + int32_t macroblock_num; + int32_t vop_id; + int32_t vop_id_for_prediction_indication; + int32_t vop_id_for_prediction; +} mp4_VideoObjectPlane; + +/* mp4_ComplexityEstimation Info */ +typedef struct _mp4_ComplexityEstimation { + int32_t estimation_method; + int32_t shape_complexity_estimation_disable; + int32_t opaque; + int32_t transparent; + int32_t intra_cae; + int32_t inter_cae; + int32_t no_update; + int32_t upsampling; + int32_t texture_complexity_estimation_set_1_disable; + int32_t intra_blocks; + int32_t inter_blocks; + int32_t inter4v_blocks; + int32_t not_coded_blocks; + int32_t texture_complexity_estimation_set_2_disable; + int32_t dct_coefs; + int32_t dct_lines; + int32_t vlc_symbols; + int32_t vlc_bits; + int32_t motion_compensation_complexity_disable; + int32_t apm; + int32_t npm; + int32_t interpolate_mc_q; + int32_t forw_back_mc_q; + int32_t halfpel2; + int32_t halfpel4; + int32_t version2_complexity_estimation_disable; // verid != 1 + int32_t sadct; // verid != 1 + int32_t quarterpel; // verid != 1 + int32_t dcecs_opaque; + int32_t dcecs_transparent; + int32_t dcecs_intra_cae; + int32_t dcecs_inter_cae; + int32_t dcecs_no_update; + int32_t dcecs_upsampling; + int32_t dcecs_intra_blocks; + int32_t dcecs_inter_blocks; + int32_t dcecs_inter4v_blocks; + int32_t dcecs_not_coded_blocks; + int32_t dcecs_dct_coefs; + int32_t dcecs_dct_lines; + int32_t dcecs_vlc_symbols; + int32_t dcecs_vlc_bits; + int32_t dcecs_apm; + int32_t dcecs_npm; + int32_t dcecs_interpolate_mc_q; + int32_t dcecs_forw_back_mc_q; + int32_t dcecs_halfpel2; + int32_t dcecs_halfpel4; + int32_t dcecs_sadct; // verid != 1 + int32_t dcecs_quarterpel; // verid != 1 +} mp4_ComplexityEstimation; + +/* mp4_Scalability Info */ +typedef struct _mp4_ScalabilityParameters { + int32_t dummy; +} mp4_ScalabilityParameters; + +/* VOLControlParameters Info */ +typedef struct _mp4_VOLControlParameters { + int32_t chroma_format; + int32_t low_delay; + int32_t vbv_parameters; + int32_t bit_rate; + int32_t vbv_buffer_size; + int32_t vbv_occupancy; +} mp4_VOLControlParameters; + +/* Video Object Plane with int16_t header Info */ +typedef struct _mp4_VideoObjectPlaneH263 { + int32_t temporal_reference; + int32_t split_screen_indicator; + int32_t document_camera_indicator; + int32_t full_picture_freeze_release; + int32_t source_format; + int32_t picture_coding_type; + int32_t vop_quant; + int32_t gob_number; + int32_t num_gobs_in_vop; + int32_t num_macroblocks_in_gob; + int32_t gob_header_empty; + int32_t gob_frame_id; + int32_t quant_scale; + int32_t num_rows_in_gob; +} mp4_VideoObjectPlaneH263; + +/* Video Object Info */ +typedef struct _mp4_VideoObject { +// iso part + int32_t id; + int32_t short_video_header; + int32_t random_accessible_vol; + int32_t type_indication; + int32_t is_identifier; + int32_t verid; + int32_t priority; + int32_t aspect_ratio_info; + int32_t aspect_ratio_info_par_width; + int32_t aspect_ratio_info_par_height; + int32_t is_vol_control_parameters; + mp4_VOLControlParameters VOLControlParameters; + int32_t shape; + int32_t shape_extension; // verid != 1 + int32_t vop_time_increment_resolution; + int32_t vop_time_increment_resolution_bits; + int32_t fixed_vop_rate; + int32_t fixed_vop_time_increment; + int32_t width; + int32_t height; + int32_t interlaced; + int32_t obmc_disable; + int32_t sprite_enable; // if verid != 1 (2 bit GMC is added) + int32_t sprite_width; + int32_t sprite_height; + int32_t sprite_left_coordinate; + int32_t sprite_top_coordinate; + int32_t sprite_warping_points; + int32_t sprite_warping_accuracy; + int32_t sprite_brightness_change; + int32_t low_latency_sprite_enable; + int32_t sadct_disable; // verid != 1 + int32_t not_8_bit; + int32_t quant_precision; + int32_t bits_per_pixel; + int32_t no_gray_quant_update; + int32_t composition_method; + int32_t linear_composition; + int32_t quant_type; + int32_t load_intra_quant_mat; + uint8_t intra_quant_mat[64]; + int32_t load_nonintra_quant_mat; + uint8_t nonintra_quant_mat[64]; + int32_t load_intra_quant_mat_grayscale[3]; + uint8_t intra_quant_mat_grayscale[3][64]; + int32_t load_nonintra_quant_mat_grayscale[3]; + uint8_t nonintra_quant_mat_grayscale[3][64]; + int32_t quarter_sample; // verid != 1 + int32_t complexity_estimation_disable; + mp4_ComplexityEstimation ComplexityEstimation; + int32_t resync_marker_disable; + int32_t data_partitioned; + int32_t reversible_vlc; + int32_t newpred_enable; // verid != 1 + int32_t requested_upstream_message_type;// verid != 1 + int32_t newpred_segment_type; // verid != 1 + int32_t reduced_resolution_vop_enable; // verid != 1 + int32_t scalability; + mp4_ScalabilityParameters ScalabilityParameters; + mp4_GroupOfVideoObjectPlane GroupOfVideoObjectPlane; + mp4_VideoObjectPlane VideoObjectPlane; + mp4_VideoObjectPlaneH263 VideoObjectPlaneH263; +// app part + int32_t VOPindex; + int32_t MacroBlockPerRow; + int32_t MacroBlockPerCol; + int32_t MacroBlockPerVOP; + int32_t mbns; // num bits for MacroBlockPerVOP + mp4_MacroBlock* MBinfo; + mp4_IntraPredBuff IntraPredBuff; + mp4_DataPartMacroBlock* DataPartBuff; + IppiQuantInvIntraSpec_MPEG4* QuantInvIntraSpec; + IppiQuantInvInterSpec_MPEG4* QuantInvInterSpec; + IppiWarpSpec_MPEG4* WarpSpec; + // for B-VOP + int32_t prevPlaneIsB; + // for interlaced B-VOP direct mode + int32_t Tframe; + IppMotionVector* FieldMV; + // for B-VOP direct mode + int32_t TRB, TRD; + // time increment of past and future VOP for B-VOP + int64_t rTime, nTime; + // VOP global time + int64_t vop_sync_time, vop_sync_time_b; +#ifdef USE_NOTCODED_STATE + // not_coded MB state + uint8_t* ncState; + int32_t ncStateCleared; +#endif +} mp4_VideoObject; + +/* StillTexture Object Info */ +typedef struct _mp4_StillTextureObject { + int32_t dummy; +} mp4_StillTextureObject; + +/* Mesh Object Info */ +typedef struct _mp4_MeshObject { + int32_t dummy; +} mp4_MeshObject; + +/* Face Object Info */ +typedef struct _mp4_FaceObject { + int32_t dummy; +} mp4_FaceObject; + +/* video_signal_type Info */ +typedef struct _mp4_VideoSignalType { + int32_t is_video_signal_type; + int32_t video_format; + int32_t video_range; + int32_t is_colour_description; + int32_t colour_primaries; + int32_t transfer_characteristics; + int32_t matrix_coefficients; +} mp4_VideoSignalType; + +/* Visual Object Info */ +typedef struct _mp4_VisualObject { + int32_t is_identifier; + int32_t verid; + int32_t priority; + int32_t type; + mp4_VideoSignalType VideoSignalType; + mp4_VideoObject VideoObject; + mp4_StillTextureObject StillTextureObject; + mp4_MeshObject MeshObject; + mp4_FaceObject FaceObject; + mp4_Frame *sFrame; // static sprite + mp4_Frame *cFrame; // current TODO make pointer + mp4_Frame *rFrame; // reference in past TODO make pointer + mp4_Frame *nFrame; // reference in future TODO make pointer + int32_t frameCount; + int32_t frameInterval; + int32_t frameScale; + mp4_Statistic Statistic; + mp4_Frame *frame_cache; // linked list of available frames (malloc cache) + mp4_Frame *sprite_cache; // linked list of available sprite (malloc cache) + mp4_Frame *display_frames; // linked list of display frames +} mp4_VisualObject; + +/* Full Info */ +typedef struct _mp4_Info { + int32_t ftype; // 0 - raw, 1 - mp4, 2 - avi + int32_t ftype_f; // ftype == 1 (0 - QuickTime(tm)), ftype == 2 (0 - DivX(tm) v. < 5, XVID, 1 - DivX(tm) v. >= 5) + uint8_t* buffer; /* buffer header for saving MPEG-4 stream */ + size_t buflen; /* total buffer length */ + size_t len; /* valid data in buffer */ + uint8_t* bufptr; /* current frame, point to header or data */ + int32_t bitoff; /* mostly point to next frame header or PSC */ + int32_t profile_and_level_indication; + mp4_VisualObject VisualObject; + int32_t stopOnErr; + int strictSyntaxCheck; + int noPVOPs; + int noBVOPs; +} mp4_Info; + +/* bitstream functions */ +extern uint8_t* mp4_FindStartCodePtr(mp4_Info* pInfo); +extern uint8_t* mp4_FindStartCodeOrShortPtr(mp4_Info* pInfo); +extern int32_t mp4_SeekStartCodePtr(mp4_Info* pInfo); +extern int32_t mp4_SeekStartCodeOrShortPtr(mp4_Info* pInfo); +extern int32_t mp4_SeekStartCodeValue(mp4_Info* pInfo, uint8_t code); +extern uint8_t* mp4_FindShortVideoStartMarkerPtr(mp4_Info* pInfo); +extern int32_t mp4_SeekShortVideoStartMarker(mp4_Info* pInfo); +extern int32_t mp4_SeekGOBMarker(mp4_Info* pInfo); +extern int32_t mp4_SeekResyncMarker(mp4_Info* pInfo); +extern int32_t mp4_FindResyncMarker(mp4_Info* pInfo); +extern int mp4_IsStartCodeOrShort(mp4_Info* pInfo); +extern int mp4_IsStartCodeValue(mp4_Info* pInfo, int min, int max); +extern int mp4_IsShortCode(mp4_Info* pInfo); + +/* tables */ +typedef struct _mp4_VLC1 { + uint8_t code; + uint8_t len; +} mp4_VLC1; + +extern const uint8_t mp4_DefaultIntraQuantMatrix[]; +extern const uint8_t mp4_DefaultNonIntraQuantMatrix[]; +extern const uint8_t mp4_ClassicalZigzag[]; +extern const uint8_t mp4_DCScalerLuma[]; +extern const uint8_t mp4_DCScalerChroma[]; +extern const uint8_t mp4_cCbCrMvRound16[]; +extern const uint8_t mp4_cCbCrMvRound12[]; +extern const uint8_t mp4_cCbCrMvRound8[]; +extern const uint8_t mp4_cCbCrMvRound4[]; +extern const Ipp8s mp4_dquant[]; +extern const mp4_VLC1 mp4_cbpy1[]; +extern const mp4_VLC1 mp4_cbpy2[]; +extern const mp4_VLC1 mp4_cbpy3[]; +extern const mp4_VLC1 mp4_cbpy4[]; +extern const mp4_VLC1* mp4_cbpy_t[]; +extern const uint8_t mp4_cbpy_b[]; +extern const int32_t mp4_DC_vlc_Threshold[]; +extern const uint8_t mp4_PVOPmb_type[]; +extern const uint8_t mp4_PVOPmb_cbpc[]; +extern const uint8_t mp4_PVOPmb_bits[]; +extern const mp4_VLC1 mp4_BVOPmb_type[]; +extern const mp4_VLC1 mp4_MVD_B12_1[]; +extern const mp4_VLC1 mp4_MVD_B12_2[]; +extern const int32_t mp4_H263_width[]; +extern const int32_t mp4_H263_height[]; +extern const int32_t mp4_H263_mbgob[]; +extern const int32_t mp4_H263_gobvop[]; +extern const int32_t mp4_H263_rowgob[]; +extern const uint8_t mp4_aux_comp_count[]; +extern const uint8_t mp4_aux_comp_is_alpha[]; +extern const uint8_t mp4_BABtypeIntra[][3]; +extern const int32_t mp4_DivIntraDivisor[]; + +// project functions +extern void mp4_Error(const char *str); +//#define mp4_Error(str) puts(str) +extern mp4_Status mp4_InitVOL(mp4_Info *pInfo); +extern mp4_Status mp4_FreeVOL(mp4_Info *pInfo); +extern void mp4_ResetVOL(mp4_Info *pInfo); +//extern void mp4_ShowFrame(mp4_Frame *frame); +#define mp4_ShowFrame(frame) +extern mp4_Status mp4_Parse_VisualObjectSequence(mp4_Info* pInfo); +extern mp4_Status mp4_Parse_VisualObject(mp4_Info* pInfo); +extern mp4_Status mp4_Parse_VideoObject(mp4_Info* pInfo); +extern mp4_Status mp4_Parse_GroupOfVideoObjectPlane(mp4_Info* pInfo); +extern mp4_Status mp4_Parse_VideoObjectPlane(mp4_Info* pInfo); +extern mp4_Status mp4_DecodeVideoObjectPlane(mp4_Info* pInfo); + +#ifndef USE_INLINE_BITS_FUNC +extern uint32_t mp4_ShowBits(mp4_Info* pInfo, int32_t n); +extern uint32_t mp4_ShowBit(mp4_Info* pInfo); +extern uint32_t mp4_ShowBits9(mp4_Info* pInfo, int32_t n); +extern void mp4_FlushBits(mp4_Info* pInfo, int32_t n); +extern uint32_t mp4_GetBits(mp4_Info* pInfo, int32_t n); +//extern uint32_t mp4_GetBit(mp4_Info* pInfo); +extern uint32_t mp4_GetBits9(mp4_Info* pInfo, int32_t n); +extern void mp4_AlignBits(mp4_Info* pInfo); +extern void mp4_AlignBits7F(mp4_Info* pInfo); +extern uint32_t mp4_ShowBitsAlign(mp4_Info* pInfo, int32_t n); +extern uint32_t mp4_ShowBitsAlign7F(mp4_Info* pInfo, int32_t n); +#else +__INLINE uint32_t mp4_ShowBits(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bufptr; + uint32_t tmp = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); + tmp <<= pInfo->bitoff; + tmp >>= 32 - n; + return tmp; +} + +__INLINE uint32_t mp4_ShowBit(mp4_Info* pInfo) +{ + uint32_t tmp = pInfo->bufptr[0]; + tmp >>= 7 - pInfo->bitoff; + return (tmp & 1); +} + +__INLINE uint32_t mp4_ShowBits9(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bufptr; + uint32_t tmp = (ptr[0] << 8) | ptr[1]; + tmp <<= (pInfo->bitoff + 16); + tmp >>= 32 - n; + return tmp; +} + +__INLINE void mp4_FlushBits(mp4_Info* pInfo, int32_t n) +{ + n = n + pInfo->bitoff; + pInfo->bufptr += n >> 3; + pInfo->bitoff = n & 7; +} + +__INLINE uint32_t mp4_GetBits(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bufptr; + uint32_t tmp = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); + tmp <<= pInfo->bitoff; + tmp >>= 32 - n; + n = n + pInfo->bitoff; + pInfo->bufptr += n >> 3; + pInfo->bitoff = n & 7; + return tmp; +} + +__INLINE uint32_t mp4_GetBits9(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bufptr; + uint32_t tmp = (ptr[0] << 8) | ptr[1]; + tmp <<= (pInfo->bitoff + 16); + tmp >>= 32 - n; + n = n + pInfo->bitoff; + pInfo->bufptr += n >> 3; + pInfo->bitoff = n & 7; + return tmp; +} + +__INLINE void mp4_AlignBits(mp4_Info* pInfo) +{ + if (pInfo->bitoff > 0) { + pInfo->bitoff = 0; + (pInfo->bufptr)++; + } +} + +__INLINE void mp4_AlignBits7F(mp4_Info* pInfo) +{ + if (pInfo->bitoff > 0) { + pInfo->bitoff = 0; + (pInfo->bufptr)++; + } else { + if (*pInfo->bufptr == 0x7F) + (pInfo->bufptr)++; + } +} + +__INLINE uint32_t mp4_ShowBitsAlign(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bitoff ? (pInfo->bufptr + 1) : pInfo->bufptr; + uint32_t tmp = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); + tmp >>= 32 - n; + return tmp; +} + +__INLINE uint32_t mp4_ShowBitsAlign7F(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bitoff ? (pInfo->bufptr + 1) : pInfo->bufptr; + uint32_t tmp; + if (!pInfo->bitoff) { + if (*ptr == 0x7F) + ptr ++; + } + tmp = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); + tmp >>= 32 - n; + return tmp; +} + +#endif // USE_INLINE_BITS_FUNC + +__INLINE uint32_t mp4_GetBit(mp4_Info* pInfo) +{ + uint32_t tmp = pInfo->bufptr[0]; + if (pInfo->bitoff != 7) { + tmp >>= 7 - pInfo->bitoff; + pInfo->bitoff ++; + } else { + pInfo->bitoff = 0; + pInfo->bufptr ++; + } + return (tmp & 1); +} + +__INLINE int32_t mp4_GetMarkerBit(mp4_Info* pInfo) { + if (!mp4_GetBit(pInfo)) { + mp4_Error("Error: wrong marker bit"); + return 0; + } + return 1; +} + +// added by benski +extern mp4_Frame *CreateFrame(mp4_VisualObject *object); +extern void ReleaseFrame(mp4_VisualObject *object, mp4_Frame *frame); +extern mp4_Frame *GetDisplayFrame(mp4_VisualObject *object); +extern void DisplayFrame(mp4_VisualObject *object, mp4_Frame *frame); +extern void FreeCache(mp4_VisualObject *object); + +#ifdef __cplusplus +} +#endif + diff --git a/Src/mpeg4dec/mp4parse.c b/Src/mpeg4dec/mp4parse.c new file mode 100644 index 00000000..2db9308b --- /dev/null +++ b/Src/mpeg4dec/mp4parse.c @@ -0,0 +1,1109 @@ +/* /////////////////////////////////////////////////////////////////////// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 2001-2007 Intel Corporation. All Rights Reserved. +// +// Description: Parses MPEG-4 headers +// +*/ + +#include "mp4def.h" + + +mp4_Status mp4_Parse_VisualObjectSequence(mp4_Info* pInfo) +{ + pInfo->profile_and_level_indication = mp4_GetBits9(pInfo, 8); + if (pInfo->profile_and_level_indication != MP4_SIMPLE_PROFILE_LEVEL_1 && + pInfo->profile_and_level_indication != MP4_SIMPLE_PROFILE_LEVEL_2 && + pInfo->profile_and_level_indication != MP4_SIMPLE_PROFILE_LEVEL_3 && + pInfo->profile_and_level_indication != MP4_SIMPLE_PROFILE_LEVEL_0 && + pInfo->profile_and_level_indication != MP4_CORE_PROFILE_LEVEL_1 && + pInfo->profile_and_level_indication != MP4_CORE_PROFILE_LEVEL_2 && + pInfo->profile_and_level_indication != MP4_MAIN_PROFILE_LEVEL_2 && + pInfo->profile_and_level_indication != MP4_MAIN_PROFILE_LEVEL_3 && + pInfo->profile_and_level_indication != MP4_MAIN_PROFILE_LEVEL_4 && + pInfo->profile_and_level_indication != MP4_ADVANCED_REAL_TIME_SIMPLE_PROFILE_LEVEL_1 && + pInfo->profile_and_level_indication != MP4_ADVANCED_REAL_TIME_SIMPLE_PROFILE_LEVEL_2 && + pInfo->profile_and_level_indication != MP4_ADVANCED_REAL_TIME_SIMPLE_PROFILE_LEVEL_3 && + pInfo->profile_and_level_indication != MP4_ADVANCED_REAL_TIME_SIMPLE_PROFILE_LEVEL_4 && + pInfo->profile_and_level_indication != MP4_ADVANCED_CODING_EFFICIENCY_PROFILE_LEVEL_1 && + pInfo->profile_and_level_indication != MP4_ADVANCED_CODING_EFFICIENCY_PROFILE_LEVEL_2 && + pInfo->profile_and_level_indication != MP4_ADVANCED_CODING_EFFICIENCY_PROFILE_LEVEL_3 && + pInfo->profile_and_level_indication != MP4_ADVANCED_CODING_EFFICIENCY_PROFILE_LEVEL_4 && + pInfo->profile_and_level_indication != MP4_ADVANCED_CORE_PROFILE_LEVEL_1 && + pInfo->profile_and_level_indication != MP4_ADVANCED_CORE_PROFILE_LEVEL_2 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_0 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_1 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_2 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_3 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_4 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_5 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_3B) { + mp4_Error("Warning: Unsupported profile_and_level_indication"); + if (pInfo->strictSyntaxCheck) + return MP4_STATUS_NOTSUPPORT; + } + if (pInfo->profile_and_level_indication != MP4_SIMPLE_PROFILE_LEVEL_1 && + pInfo->profile_and_level_indication != MP4_SIMPLE_PROFILE_LEVEL_2 && + pInfo->profile_and_level_indication != MP4_SIMPLE_PROFILE_LEVEL_3 && + pInfo->profile_and_level_indication != MP4_SIMPLE_PROFILE_LEVEL_0 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_0 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_1 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_2 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_3 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_4 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_5 && + pInfo->profile_and_level_indication != MP4_ADVANCED_SIMPLE_PROFILE_LEVEL_3B) { + mp4_Error("Warning: Some features of present profile_and_level_indication may be not supported"); + } + return MP4_STATUS_OK; +} + + +mp4_Status mp4_Parse_VisualObject(mp4_Info* pInfo) +{ + mp4_VisualObject *VO = &pInfo->VisualObject; + + VO->is_identifier = mp4_GetBit(pInfo); + if (VO->is_identifier) { + VO->verid = mp4_GetBits9(pInfo, 4); + if ((VO->verid != 1) && (VO->verid != 2) && (VO->verid != 4) && (VO->verid != 5)) { + VO->verid = 1; + mp4_Error("Warning: Unsupported visual_object_verid"); + //f if (pInfo->strictSyntaxCheck) + //f return MP4_STATUS_NOTSUPPORT; + } + VO->priority = mp4_GetBits9(pInfo, 3); + if (VO->priority == 0) { + mp4_Error("Warning: Wrong value of visual_object_priority"); + //f if (pInfo->strictSyntaxCheck) + //f return MP4_STATUS_PARSE_ERROR; + } + } else + VO->verid = 1; + VO->type = mp4_GetBits9(pInfo, 4); + if (VO->type != MP4_VISUAL_OBJECT_TYPE_VIDEO) { + mp4_Error("Error: Unsupported object: visual_object_type != video ID"); + return MP4_STATUS_NOTSUPPORT; + } + VO->VideoSignalType.video_format = MP4_VIDEO_FORMAT_UNSPECIFIED; + VO->VideoSignalType.video_range = 0; + VO->VideoSignalType.colour_primaries = MP4_VIDEO_COLORS_ITU_R_BT_709; + VO->VideoSignalType.transfer_characteristics = MP4_VIDEO_COLORS_ITU_R_BT_709; + VO->VideoSignalType.matrix_coefficients = MP4_VIDEO_COLORS_ITU_R_BT_709; + if (VO->type == MP4_VISUAL_OBJECT_TYPE_VIDEO || VO->type == MP4_VISUAL_OBJECT_TYPE_TEXTURE) { + VO->VideoSignalType.is_video_signal_type = mp4_GetBit(pInfo); + if (VO->VideoSignalType.is_video_signal_type) { + VO->VideoSignalType.video_format = mp4_GetBits9(pInfo, 3); + if (VO->VideoSignalType.video_format > MP4_VIDEO_FORMAT_UNSPECIFIED) { + mp4_Error("Warning: Wrong value of video_format"); + //f if (pInfo->strictSyntaxCheck) + //f return MP4_STATUS_PARSE_ERROR; + } + VO->VideoSignalType.video_range = mp4_GetBit(pInfo); + VO->VideoSignalType.is_colour_description = mp4_GetBit(pInfo); + if (VO->VideoSignalType.is_colour_description) { + VO->VideoSignalType.colour_primaries = mp4_GetBits9(pInfo, 8); + if (VO->VideoSignalType.colour_primaries == MP4_VIDEO_COLORS_FORBIDDEN) { + mp4_Error("Error: Wrong value of colour_primaries"); + if (pInfo->strictSyntaxCheck) + return MP4_STATUS_PARSE_ERROR; + } + if (VO->VideoSignalType.colour_primaries > MP4_VIDEO_COLORS_GENERIC_FILM) { + mp4_Error("Warning: Wrong value of colour_primaries"); + //f if (pInfo->strictSyntaxCheck) + //f return MP4_STATUS_PARSE_ERROR; + } + VO->VideoSignalType.transfer_characteristics = mp4_GetBits9(pInfo, 8); + if (VO->VideoSignalType.transfer_characteristics == 0) { + mp4_Error("Error: Wrong value of transfer_characteristics"); + if (pInfo->strictSyntaxCheck) + return MP4_STATUS_PARSE_ERROR; + } + if (VO->VideoSignalType.transfer_characteristics > 10) { + mp4_Error("Warning: Wrong value of transfer_characteristics"); + //f if (pInfo->strictSyntaxCheck) + //f return MP4_STATUS_PARSE_ERROR; + } + VO->VideoSignalType.matrix_coefficients = mp4_GetBits9(pInfo, 8); + if (VO->VideoSignalType.matrix_coefficients == 0) { + mp4_Error("Error: Wrong value of matrix_coefficients"); + if (pInfo->strictSyntaxCheck) + return MP4_STATUS_PARSE_ERROR; + } + if (VO->VideoSignalType.matrix_coefficients > 8) { + mp4_Error("Warning: Wrong value of matrix_coefficients"); + //f if (pInfo->strictSyntaxCheck) + //f return MP4_STATUS_PARSE_ERROR; + } + } + } + } + return MP4_STATUS_OK; +} + + +static mp4_Status mp4_Parse_QuantMatrix(mp4_Info* pInfo, uint8_t pQM[64]) +{ + uint32_t code; + int32_t i; + + for (i = 0; i < 64; i ++) { + code = mp4_GetBits9(pInfo, 8); + if (code == 0) break; + pQM[mp4_ClassicalZigzag[i]] = (uint8_t)code; + } + if (i > 0) { + code = pQM[mp4_ClassicalZigzag[i-1]]; + for (; i < 64; i ++) + pQM[mp4_ClassicalZigzag[i]] = (uint8_t)code; + } else { + for (i = 1; i < 64; i ++) + pQM[mp4_ClassicalZigzag[i]] = (uint8_t)mp4_ClassicalZigzag[0]; + } + return MP4_STATUS_OK; +} + + +mp4_Status mp4_Parse_VideoObject(mp4_Info* pInfo) +{ + uint32_t code; + int32_t i; + mp4_VisualObject *VO = &pInfo->VisualObject; + mp4_VideoObject *VOL = &pInfo->VisualObject.VideoObject; + + code = mp4_ShowBits(pInfo, 32); + // check short_video_start_marker + if ((code & (~0x3FF)) == 0x8000) { + VOL->short_video_header = 1; + VOL->quant_precision = 5; + VOL->shape = MP4_SHAPE_TYPE_RECTANGULAR; + VOL->obmc_disable = 1; + VOL->quant_type = 0; + VOL->resync_marker_disable = 1; + VOL->data_partitioned = 0; + VOL->reversible_vlc = 0; + VOL->VideoObjectPlane.rounding_type = 0; + VOL->VideoObjectPlane.fcode_forward = 1; + VOL->VideoObjectPlane.coded = 1; + VOL->interlaced = 0; + VOL->complexity_estimation_disable = 1; + VOL->scalability = 0; + VOL->not_8_bit = 0; + VOL->bits_per_pixel = 8; + VO->VideoSignalType.colour_primaries = 1; + VO->VideoSignalType.transfer_characteristics = 1; + VO->VideoSignalType.matrix_coefficients = 6; + VO->VideoObject.VideoObjectPlaneH263.source_format = (pInfo->bufptr[4] >> 2) & 0x7; + i = VO->VideoObject.VideoObjectPlaneH263.source_format - 1; + if (i < 0 || i > 4) { + mp4_Error("Error: Bad value for VideoPlaneWithShortHeader.source_format"); + return MP4_STATUS_PARSE_ERROR; + } + VOL->width = mp4_H263_width[i]; + VOL->height = mp4_H263_height[i]; + VOL->VideoObjectPlaneH263.num_gobs_in_vop = mp4_H263_gobvop[i]; + VOL->VideoObjectPlaneH263.num_macroblocks_in_gob = mp4_H263_mbgob[i]; + VOL->VideoObjectPlaneH263.num_rows_in_gob = mp4_H263_rowgob[i]; + VOL->vop_time_increment_resolution = 30000; + // VOL->VideoObjectPlane.time_increment = -1001; + VOL->VOLControlParameters.low_delay = 1; + return MP4_STATUS_OK; + } + if (code < 256 + MP4_VIDEO_OBJECT_LAYER_MIN_SC || code > 256 + MP4_VIDEO_OBJECT_LAYER_MAX_SC) { + mp4_Error("Error: Bad start code for VideoObjectLayer"); + return MP4_STATUS_PARSE_ERROR; + } + mp4_FlushBits(pInfo, 32); + // video_object_start_code is founded + VOL->id = code & 15; + VOL->short_video_header = 0; + VOL->random_accessible_vol = mp4_GetBit(pInfo); + VOL->type_indication = mp4_GetBits9(pInfo, 8); + if (VOL->type_indication != MP4_VIDEO_OBJECT_TYPE_SIMPLE && + VOL->type_indication != MP4_VIDEO_OBJECT_TYPE_CORE && + VOL->type_indication != MP4_VIDEO_OBJECT_TYPE_MAIN && + VOL->type_indication != MP4_VIDEO_OBJECT_TYPE_ADVANCED_REAL_TIME_SIMPLE && + VOL->type_indication != MP4_VIDEO_OBJECT_TYPE_ADVANCED_CODING_EFFICIENCY && + VOL->type_indication != MP4_VIDEO_OBJECT_TYPE_ADVANCED_SIMPLE) { + mp4_Error("Warning: Unsupported video_object_type_indication, some features may be not supported"); + //f if (pInfo->strictSyntaxCheck) + //f return MP4_STATUS_NOTSUPPORT; + } + VOL->is_identifier = mp4_GetBit(pInfo); + if (VOL->is_identifier) { + VOL->verid = mp4_GetBits9(pInfo, 4); + if ((VOL->verid != 1) && (VOL->verid != 2) && (VOL->verid != 4) && (VOL->verid != 5)) { + mp4_Error("Warning: Unsupported video_object_layer_verid"); + VOL->verid = VO->verid; + //f if (pInfo->strictSyntaxCheck) + //f return MP4_STATUS_NOTSUPPORT; + } + VOL->priority = mp4_GetBits9(pInfo, 3); + if (VOL->priority == 0) { + mp4_Error("Warning: Wrong value of video_object_layer_priority"); + //f if (pInfo->strictSyntaxCheck) + //f return MP4_STATUS_PARSE_ERROR; + } + } else + VOL->verid = VO->verid; + VOL->aspect_ratio_info = mp4_GetBits9(pInfo, 4); + if (VOL->aspect_ratio_info == MP4_ASPECT_RATIO_FORBIDDEN) { + mp4_Error("Error: Wrong value of aspect_ratio_info"); + if (pInfo->strictSyntaxCheck) + return MP4_STATUS_PARSE_ERROR; + } + if (VOL->aspect_ratio_info > MP4_ASPECT_RATIO_40_33 && VOL->aspect_ratio_info < MP4_ASPECT_RATIO_EXTPAR) { + mp4_Error("Warning: Wrong value of aspect_ratio_info"); + //f if (pInfo->strictSyntaxCheck) + //f return MP4_STATUS_PARSE_ERROR; + } + if (VOL->aspect_ratio_info == MP4_ASPECT_RATIO_EXTPAR) { + VOL->aspect_ratio_info_par_width = mp4_GetBits9(pInfo, 8); + if (VOL->aspect_ratio_info_par_width == 0) { + mp4_Error("Error: Wrong value of par_width"); + if (pInfo->strictSyntaxCheck) + return MP4_STATUS_PARSE_ERROR; + } + VOL->aspect_ratio_info_par_height = mp4_GetBits9(pInfo, 8); + if (VOL->aspect_ratio_info_par_height == 0) { + mp4_Error("Error: Wrong value of par_height"); + if (pInfo->strictSyntaxCheck) + return MP4_STATUS_PARSE_ERROR; + } + } + VOL->is_vol_control_parameters = mp4_GetBit(pInfo); + if (VOL->type_indication == MP4_VIDEO_OBJECT_TYPE_SIMPLE || VOL->type_indication != MP4_VIDEO_OBJECT_TYPE_ADVANCED_REAL_TIME_SIMPLE) + VOL->VOLControlParameters.low_delay = 1; + if (VOL->is_vol_control_parameters) { + VOL->VOLControlParameters.chroma_format = mp4_GetBits9(pInfo, 2); + if (VOL->VOLControlParameters.chroma_format != MP4_CHROMA_FORMAT_420) { + mp4_Error("Error: chroma_format != 4:2:0"); + return MP4_STATUS_PARSE_ERROR; + } + VOL->VOLControlParameters.low_delay = mp4_GetBit(pInfo); + VOL->VOLControlParameters.vbv_parameters = mp4_GetBit(pInfo); + if (VOL->VOLControlParameters.vbv_parameters) { + VOL->VOLControlParameters.bit_rate = mp4_GetBits(pInfo, 15) << 15; + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOL->VOLControlParameters.bit_rate += mp4_GetBits(pInfo, 15); + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + if (VOL->VOLControlParameters.bit_rate == 0) { + mp4_Error("Error: vbv_parameters bit_rate == 0"); + return MP4_STATUS_PARSE_ERROR; + } + VOL->VOLControlParameters.vbv_buffer_size = mp4_GetBits(pInfo, 15) << 3; + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOL->VOLControlParameters.vbv_buffer_size += mp4_GetBits9(pInfo, 3); + if (VOL->VOLControlParameters.vbv_buffer_size == 0) { + mp4_Error("Error: vbv_parameters vbv_buffer_size == 0"); + return MP4_STATUS_PARSE_ERROR; + } + VOL->VOLControlParameters.vbv_occupancy = mp4_GetBits(pInfo, 11) << 15; + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOL->VOLControlParameters.vbv_occupancy += mp4_GetBits(pInfo, 15); + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + } + } + VOL->shape = mp4_GetBits9(pInfo, 2); + if (VOL->shape != MP4_SHAPE_TYPE_RECTANGULAR) { + mp4_Error("Error: video_object_layer_shape != rectangular (not supported)"); + return MP4_STATUS_PARSE_ERROR; + } + if (VOL->verid != 1 && VOL->shape == MP4_SHAPE_TYPE_GRAYSCALE) { + VOL->shape_extension = mp4_GetBits9(pInfo, 4); + if (VOL->shape_extension >= MP4_SHAPE_EXT_NUM) { + mp4_Error("Error: wrong value of video_object_layer_shape_extension"); + return MP4_STATUS_PARSE_ERROR; + } + } else + VOL->shape_extension = MP4_SHAPE_EXT_NUM; + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOL->vop_time_increment_resolution = mp4_GetBits(pInfo, 16); + if (VOL->vop_time_increment_resolution == 0) { + mp4_Error("Error: wrong value of vop_time_increment_resolution"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + // define number bits in vop_time_increment_resolution + code = VOL->vop_time_increment_resolution - 1; + i = 0; + do { + code >>= 1; + i ++; + } while (code); + VOL->vop_time_increment_resolution_bits = i; + VOL->fixed_vop_rate = mp4_GetBit(pInfo); + if (VOL->fixed_vop_rate) { + VOL->fixed_vop_time_increment = mp4_GetBits(pInfo, VOL->vop_time_increment_resolution_bits); + if (VOL->fixed_vop_time_increment == 0) { + mp4_Error("Error: wrong value of fixed_vop_time_increment"); + return MP4_STATUS_PARSE_ERROR; + } + } + if (VOL->shape != MP4_SHAPE_TYPE_BINARYONLY) { + if (VOL->shape == MP4_SHAPE_TYPE_RECTANGULAR) { + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOL->width = mp4_GetBits(pInfo, 13); + if (VOL->width == 0) { + mp4_Error("Error: wrong value of video_object_layer_width"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOL->height = mp4_GetBits(pInfo, 13); + if (VOL->height == 0) { + mp4_Error("Error: wrong value of video_object_layer_height"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + } + VOL->interlaced = mp4_GetBit(pInfo); + VOL->obmc_disable = mp4_GetBit(pInfo); + VOL->sprite_enable = mp4_GetBits9(pInfo, VOL->verid != 1 ? 2 : 1); + if (VOL->sprite_enable == MP4_SPRITE_STATIC || VOL->sprite_enable == MP4_SPRITE_GMC) { + if (VOL->sprite_enable == MP4_SPRITE_STATIC) { + VOL->sprite_width = mp4_GetBits(pInfo, 13); + if (VOL->sprite_width == 0) { + mp4_Error("Error: wrong value of sprite_width"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOL->sprite_height = mp4_GetBits(pInfo, 13); + if (VOL->sprite_height == 0) { + mp4_Error("Error: wrong value of sprite_height"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOL->sprite_left_coordinate = mp4_GetBits(pInfo, 13); + VOL->sprite_left_coordinate <<= (32 - 13); + VOL->sprite_left_coordinate >>= (32 - 13); + if (VOL->sprite_left_coordinate & 1) { + mp4_Error("Error: sprite_left_coordinate must be divisible by 2"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOL->sprite_top_coordinate = mp4_GetBits(pInfo, 13); + VOL->sprite_top_coordinate <<= (32 - 13); + VOL->sprite_top_coordinate >>= (32 - 13); + if (VOL->sprite_top_coordinate & 1) { + mp4_Error("Error: sprite_top_coordinate must be divisible by 2"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + } + VOL->sprite_warping_points = mp4_GetBits9(pInfo, 6); + if (VOL->sprite_warping_points > 4 || (VOL->sprite_warping_points == 4 && VOL->sprite_enable == MP4_SPRITE_GMC)) { + mp4_Error("Error: bad no_of_sprite_warping_points"); + return MP4_STATUS_PARSE_ERROR; + } + VOL->sprite_warping_accuracy = mp4_GetBits9(pInfo, 2); + VOL->sprite_brightness_change = mp4_GetBit(pInfo); + if (VOL->sprite_enable == MP4_SPRITE_GMC) { + if (VOL->sprite_brightness_change) { + mp4_Error("Error: sprite_brightness_change should be 0 for GMC sprites"); + return MP4_STATUS_PARSE_ERROR; + } + } + if (VOL->sprite_enable != MP4_SPRITE_GMC) { + VOL->low_latency_sprite_enable = mp4_GetBit(pInfo); + if (VOL->low_latency_sprite_enable) { + mp4_Error("Error: low_latency_sprite is not supported"); + return MP4_STATUS_PARSE_ERROR; + } + } + } + if (VOL->verid != 1 && VOL->shape != MP4_SHAPE_TYPE_RECTANGULAR) { + VOL->sadct_disable = mp4_GetBit(pInfo); + if (!VOL->sadct_disable) { + mp4_Error("Error: Shape Adaptive DCT is not supported"); + return MP4_STATUS_PARSE_ERROR; + } + } + VOL->not_8_bit = mp4_GetBit(pInfo); + if (VOL->not_8_bit) { + mp4_Error("Error: only 8-bits data is supported"); + return MP4_STATUS_PARSE_ERROR; + } + if (VOL->not_8_bit) { + VOL->quant_precision = mp4_GetBits9(pInfo, 4); + if (VOL->quant_precision < 3 || VOL->quant_precision > 9) { + mp4_Error("Error: quant_precision must be in range [3; 9]"); + return MP4_STATUS_PARSE_ERROR; + } + VOL->bits_per_pixel = mp4_GetBits9(pInfo, 4); + if (VOL->bits_per_pixel < 4 || VOL->bits_per_pixel > 12) { + mp4_Error("Error: bits_per_pixel must be in range [4; 12]"); + return MP4_STATUS_PARSE_ERROR; + } + } else { + VOL->quant_precision = 5; + VOL->bits_per_pixel = 8; + } + if (VOL->shape == MP4_SHAPE_TYPE_GRAYSCALE) { + VOL->no_gray_quant_update = mp4_GetBit(pInfo); + VOL->composition_method = mp4_GetBit(pInfo); + VOL->linear_composition = mp4_GetBit(pInfo); + } + VOL->quant_type = mp4_GetBit(pInfo); + if (VOL->quant_type) { + VOL->load_intra_quant_mat = mp4_GetBit(pInfo); + if (VOL->load_intra_quant_mat) { + if (mp4_Parse_QuantMatrix(pInfo, VOL->intra_quant_mat) != MP4_STATUS_OK) + return MP4_STATUS_PARSE_ERROR; + } else + ippsCopy_8u(mp4_DefaultIntraQuantMatrix, VOL->intra_quant_mat, 64); + VOL->load_nonintra_quant_mat = mp4_GetBit(pInfo); + if (VOL->load_nonintra_quant_mat) { + if (mp4_Parse_QuantMatrix(pInfo, VOL->nonintra_quant_mat) != MP4_STATUS_OK) + return MP4_STATUS_PARSE_ERROR; + } else + ippsCopy_8u(mp4_DefaultNonIntraQuantMatrix, VOL->nonintra_quant_mat, 64); + if (VOL->shape == MP4_SHAPE_TYPE_GRAYSCALE) { + int32_t ac, i; + + ac = mp4_aux_comp_count[VOL->shape_extension]; + for (i = 0; i < ac; i ++) { + VOL->load_intra_quant_mat_grayscale[i] = mp4_GetBit(pInfo); + if (VOL->load_intra_quant_mat_grayscale[i]) { + if (mp4_Parse_QuantMatrix(pInfo, VOL->intra_quant_mat_grayscale[i]) != MP4_STATUS_OK) + return MP4_STATUS_PARSE_ERROR; + } else + ippsCopy_8u(mp4_DefaultIntraQuantMatrix, VOL->intra_quant_mat_grayscale[i], 64); + VOL->load_nonintra_quant_mat_grayscale[i] = mp4_GetBit(pInfo); + if (VOL->load_nonintra_quant_mat_grayscale[i]) { + if (mp4_Parse_QuantMatrix(pInfo, VOL->nonintra_quant_mat_grayscale[i]) != MP4_STATUS_OK) + return MP4_STATUS_PARSE_ERROR; + } else + ippsCopy_8u(mp4_DefaultNonIntraQuantMatrix, VOL->nonintra_quant_mat_grayscale[i], 64); + } + } + } + if (VOL->verid != 1) + VOL->quarter_sample = mp4_GetBit(pInfo); + VOL->complexity_estimation_disable = mp4_GetBit(pInfo); + if (!VOL->complexity_estimation_disable) { + VOL->ComplexityEstimation.estimation_method = mp4_GetBits9(pInfo, 2); + if (VOL->ComplexityEstimation.estimation_method <= 1) { + VOL->ComplexityEstimation.shape_complexity_estimation_disable = mp4_GetBit(pInfo); + if (!VOL->ComplexityEstimation.shape_complexity_estimation_disable) { + VOL->ComplexityEstimation.opaque = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.transparent = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.intra_cae = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.inter_cae = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.no_update = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.upsampling = mp4_GetBit(pInfo); + } + VOL->ComplexityEstimation.texture_complexity_estimation_set_1_disable = mp4_GetBit(pInfo); + if (!VOL->ComplexityEstimation.texture_complexity_estimation_set_1_disable) { + VOL->ComplexityEstimation.intra_blocks = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.inter_blocks = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.inter4v_blocks = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.not_coded_blocks = mp4_GetBit(pInfo); + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOL->ComplexityEstimation.texture_complexity_estimation_set_2_disable = mp4_GetBit(pInfo); + if (!VOL->ComplexityEstimation.texture_complexity_estimation_set_2_disable) { + VOL->ComplexityEstimation.dct_coefs = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.dct_lines = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.vlc_symbols = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.vlc_bits = mp4_GetBit(pInfo); + } + VOL->ComplexityEstimation.motion_compensation_complexity_disable = mp4_GetBit(pInfo); + if (!VOL->ComplexityEstimation.motion_compensation_complexity_disable) { + VOL->ComplexityEstimation.apm = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.npm = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.interpolate_mc_q = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.forw_back_mc_q = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.halfpel2 = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.halfpel4 = mp4_GetBit(pInfo); + } + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + if (VOL->ComplexityEstimation.estimation_method == 1) { + // verid != 1 + VOL->ComplexityEstimation.version2_complexity_estimation_disable = mp4_GetBit(pInfo); + if (!VOL->ComplexityEstimation.version2_complexity_estimation_disable) { + VOL->ComplexityEstimation.sadct = mp4_GetBit(pInfo); + VOL->ComplexityEstimation.quarterpel = mp4_GetBit(pInfo); + } + } + } + VOL->resync_marker_disable = mp4_GetBit(pInfo); + VOL->data_partitioned = mp4_GetBit(pInfo); +//f GrayScale Shapes does not support data_part + if (VOL->data_partitioned) + VOL->reversible_vlc = mp4_GetBit(pInfo); + if (VOL->verid != 1) { + VOL->newpred_enable = mp4_GetBit(pInfo); + if (VOL->newpred_enable) { + VOL->requested_upstream_message_type = mp4_GetBits9(pInfo, 2); + VOL->newpred_segment_type = mp4_GetBit(pInfo); + mp4_Error("Warning: NEWPRED mode is not fully supported"); +//f return MP4_STATUS_PARSE_ERROR; + } + VOL->reduced_resolution_vop_enable = mp4_GetBit(pInfo); + if (VOL->reduced_resolution_vop_enable) { + mp4_Error("Error: Reduced Resolution VOP is not supported"); + return MP4_STATUS_PARSE_ERROR; + } + } + VOL->scalability = mp4_GetBit(pInfo); + if (VOL->scalability) { + mp4_Error("Error: VOL scalability is not supported"); + return MP4_STATUS_PARSE_ERROR; + } + } else { + if (VOL->verid != 1) { + VOL->scalability = mp4_GetBit(pInfo); + if (VOL->scalability) { + mp4_Error("Error: VOL scalability is not supported"); + return MP4_STATUS_PARSE_ERROR; + } + } + VOL->resync_marker_disable = mp4_GetBit(pInfo); + } + VOL->VideoObjectPlane.sprite_transmit_mode = MP4_SPRITE_TRANSMIT_MODE_PIECE; +#if 0 + { + uint8_t *sbp = pInfo->bufptr; + int32_t v, b, i; + if (mp4_SeekStartCodeValue(pInfo, MP4_USER_DATA_SC)) { + if (pInfo->bufptr[0] == 'D' && pInfo->bufptr[1] == 'i' && pInfo->bufptr[2] == 'v' && pInfo->bufptr[3] == 'X') { + pInfo->ftype = 2; + v = (pInfo->bufptr[4] - '0') * 100 + (pInfo->bufptr[5] - '0') * 10 + (pInfo->bufptr[6] - '0'); + if (v < 503) + pInfo->ftype_f = 1; + else if (v == 503) { + i = 8; + b = 0; + while (pInfo->bufptr[i] != 0) { + if (pInfo->bufptr[i] >= '0' && pInfo->bufptr[i] <= '9') + b = b * 10 + (pInfo->bufptr[i] - '0'); + i ++; + } + pInfo->ftype_f = (b < 959) ? 1 : 0; + } else + pInfo->ftype_f = 0; + } + } + pInfo->bufptr = sbp; + } +#else + { + uint8_t *sbp = pInfo->bufptr; + if (mp4_SeekStartCodeValue(pInfo, MP4_USER_DATA_SC)) { + if (pInfo->bufptr[0] == 'D' && pInfo->bufptr[1] == 'i' && pInfo->bufptr[2] == 'v' && pInfo->bufptr[3] == 'X') { + pInfo->ftype = 2; + pInfo->ftype_f = 1; + } + } + pInfo->bufptr = sbp; + } +#endif + return MP4_STATUS_OK; +} + + +/*static */mp4_Status mp4_Sprite_Trajectory(mp4_Info* pInfo) { + int32_t i, dmv_code, dmv_length, fb; + uint32_t code; + + for (i = 0; i < pInfo->VisualObject.VideoObject.sprite_warping_points; i ++) { + code = mp4_ShowBits9(pInfo, 3); + if (code == 7) { + mp4_FlushBits(pInfo, 3); + code = mp4_ShowBits9(pInfo, 9); + fb = 1; + while (code & 256) { + code <<= 1; + fb ++; + } + if (fb > 9) { + mp4_Error("Error when decode sprite_trajectory"); + return MP4_STATUS_PARSE_ERROR; + } + dmv_length = fb + 5; + } else { + fb = (code <= 1) ? 2 : 3; + dmv_length = code - 1; + } + mp4_FlushBits(pInfo, fb); + if (dmv_length <= 0) + dmv_code = 0; + else { + dmv_code = mp4_GetBits(pInfo, dmv_length); + if ((dmv_code & (1 << (dmv_length - 1))) == 0) + dmv_code -= (1 << dmv_length) - 1; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + pInfo->VisualObject.VideoObject.VideoObjectPlane.warping_mv_code_du[i] = dmv_code; + code = mp4_ShowBits9(pInfo, 3); + if (code == 7) { + mp4_FlushBits(pInfo, 3); + code = mp4_ShowBits9(pInfo, 9); + fb = 1; + while (code & 256) { + code <<= 1; + fb ++; + } + if (fb > 9) { + mp4_Error("Error when decode sprite_trajectory"); + return MP4_STATUS_PARSE_ERROR; + } + dmv_length = fb + 5; + } else { + fb = (code <= 1) ? 2 : 3; + dmv_length = code - 1; + } + mp4_FlushBits(pInfo, fb); + if (dmv_length <= 0) + dmv_code = 0; + else { + dmv_code = mp4_GetBits(pInfo, dmv_length); + if ((dmv_code & (1 << (dmv_length - 1))) == 0) + dmv_code -= (1 << dmv_length) - 1; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + pInfo->VisualObject.VideoObject.VideoObjectPlane.warping_mv_code_dv[i] = dmv_code; + } + return MP4_STATUS_OK; +} + + +mp4_Status mp4_Parse_GroupOfVideoObjectPlane(mp4_Info* pInfo) +{ + uint32_t hour, min, sec; + + hour = mp4_GetBits9(pInfo, 5); + min = mp4_GetBits9(pInfo, 6); + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + sec = mp4_GetBits9(pInfo, 6); + pInfo->VisualObject.VideoObject.GroupOfVideoObjectPlane.time_code = sec + min * 60 + hour * 3600; + pInfo->VisualObject.VideoObject.GroupOfVideoObjectPlane.time_code *= pInfo->VisualObject.VideoObject.vop_time_increment_resolution; + pInfo->VisualObject.VideoObject.GroupOfVideoObjectPlane.closed_gov = mp4_GetBit(pInfo); + pInfo->VisualObject.VideoObject.GroupOfVideoObjectPlane.broken_link = mp4_GetBit(pInfo); + return MP4_STATUS_OK; +} + + +mp4_Status mp4_Parse_VideoObjectPlane(mp4_Info* pInfo) +{ + uint32_t code; + mp4_VideoObject *VOL = &pInfo->VisualObject.VideoObject; + mp4_VideoObjectPlane *VOP = &pInfo->VisualObject.VideoObject.VideoObjectPlane; + mp4_VideoObjectPlaneH263 *VOPSH = &pInfo->VisualObject.VideoObject.VideoObjectPlaneH263; + + if (VOL->short_video_header) { + code = mp4_GetBits9(pInfo, 6); // read rest bits of short_video_start_marker + VOPSH->temporal_reference = mp4_GetBits9(pInfo, 8); + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + code = mp4_GetBit(pInfo); // zero_bit + VOPSH->split_screen_indicator = mp4_GetBit(pInfo); + VOPSH->document_camera_indicator = mp4_GetBit(pInfo); + VOPSH->full_picture_freeze_release = mp4_GetBit(pInfo); + VOPSH->source_format = mp4_GetBits9(pInfo, 3); + if (VOPSH->source_format == 0 || VOPSH->source_format > 5) { + mp4_Error("Error: Bad value for VideoPlaneWithShortHeader.source_format"); + return MP4_STATUS_PARSE_ERROR; + } + VOPSH->picture_coding_type = mp4_GetBit(pInfo); + VOP->coding_type = VOPSH->picture_coding_type; + code = mp4_GetBits9(pInfo, 4); // four_reserved_zero_bits + VOPSH->vop_quant = mp4_GetBits9(pInfo, 5); + code = mp4_GetBit(pInfo); // zero_bit + for (;;) { + code = mp4_GetBit(pInfo); // pei + if (!code) + break; + code = mp4_GetBits9(pInfo, 8); // psupp + } + return MP4_STATUS_OK; + } + VOP->coding_type = mp4_GetBits9(pInfo, 2); + if (((VOP->coding_type != MP4_VOP_TYPE_I) && (pInfo->noPVOPs)) || ((VOP->coding_type == MP4_VOP_TYPE_B) && (pInfo->noBVOPs))) { + mp4_Error("Error: Bad vop_coding_type"); + return MP4_STATUS_PARSE_ERROR; + } + VOP->modulo_time_base = 0; + do { + code = mp4_GetBit(pInfo); + VOP->modulo_time_base += code; + } while (code); + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + if (VOL->vop_time_increment_resolution_bits != 0 ) { + VOP->time_increment = mp4_GetBits(pInfo, VOL->vop_time_increment_resolution_bits); + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOP->coded = mp4_GetBit(pInfo); + if (!VOP->coded) + return MP4_STATUS_OK; + if (VOL->newpred_enable) { + int vop_id_length = VOL->vop_time_increment_resolution_bits + 3; + if (vop_id_length > 15) + vop_id_length = 15; + VOP->vop_id = mp4_GetBits(pInfo, vop_id_length); + VOP->vop_id_for_prediction_indication = mp4_GetBit(pInfo); + if (VOP->vop_id_for_prediction_indication) + VOP->vop_id_for_prediction = mp4_GetBits(pInfo, vop_id_length); + if (!mp4_GetMarkerBit(pInfo)) + return MP4_STATUS_PARSE_ERROR; + } + if (VOL->shape != MP4_SHAPE_TYPE_BINARYONLY && (VOP->coding_type == MP4_VOP_TYPE_P || + (VOP->coding_type == MP4_VOP_TYPE_S && VOL->sprite_enable == MP4_SPRITE_GMC))) + VOP->rounding_type = mp4_GetBit(pInfo); + if (VOL->reduced_resolution_vop_enable && VOL->shape == MP4_SHAPE_TYPE_RECTANGULAR && + (VOP->coding_type == MP4_VOP_TYPE_I || VOP->coding_type == MP4_VOP_TYPE_P)) { + VOP->reduced_resolution = mp4_GetBit(pInfo); + if (VOP->reduced_resolution) { + mp4_Error("Error: Reduced Resolution VOP is not supported"); + return MP4_STATUS_PARSE_ERROR; + } + } + if (VOL->shape != MP4_SHAPE_TYPE_RECTANGULAR) { + if (!(VOL->sprite_enable == MP4_SPRITE_STATIC && VOP->coding_type == MP4_VOP_TYPE_I)) { + VOP->vop_width = mp4_GetBits(pInfo, 13); + if (VOP->vop_width == 0) { + mp4_Error("Error: wrong value of vop_width"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOP->vop_height = mp4_GetBits(pInfo, 13); + if (VOP->vop_height == 0) { + mp4_Error("Error: wrong value of vop_height"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOP->vop_horizontal_mc_spatial_ref = mp4_GetBits(pInfo, 13); + VOP->vop_horizontal_mc_spatial_ref <<= (32 - 13); + VOP->vop_horizontal_mc_spatial_ref >>= (32 - 13); + if (VOP->vop_horizontal_mc_spatial_ref & 1) { + mp4_Error("Error: vop_horizontal_mc_spatial_ref must be divisible by 2"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + VOP->vop_vertical_mc_spatial_ref = mp4_GetBits(pInfo, 13); + VOP->vop_vertical_mc_spatial_ref <<= (32 - 13); + VOP->vop_vertical_mc_spatial_ref >>= (32 - 13); + if (VOP->vop_vertical_mc_spatial_ref & 1) { + mp4_Error("Error: vop_vertical_mc_spatial_ref must be divisible by 2"); + return MP4_STATUS_PARSE_ERROR; + } + if (!mp4_GetMarkerBit(pInfo)) return MP4_STATUS_PARSE_ERROR; + } +//f if ((VOL->shape != MP4_SHAPE_TYPE_BINARYONLY) && VOL->scalability && enhancement_type) +//f background_composition = mp4_GetBit(pInfo); + VOP->change_conv_ratio_disable = mp4_GetBit(pInfo); + VOP->vop_constant_alpha = mp4_GetBit(pInfo); + if (VOP->vop_constant_alpha) + VOP->vop_constant_alpha_value = mp4_GetBits9(pInfo, 8); + else + VOP->vop_constant_alpha_value = 255; + } + if (VOL->shape != MP4_SHAPE_TYPE_BINARYONLY) { + if (!VOL->complexity_estimation_disable) { + if (VOL->ComplexityEstimation.estimation_method == 0) { + if (VOP->coding_type == MP4_VOP_TYPE_I) { + if (VOL->ComplexityEstimation.opaque) VOL->ComplexityEstimation.dcecs_opaque = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.transparent) VOL->ComplexityEstimation.dcecs_transparent = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.intra_cae) VOL->ComplexityEstimation.dcecs_intra_cae = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.inter_cae) VOL->ComplexityEstimation.dcecs_inter_cae = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.no_update) VOL->ComplexityEstimation.dcecs_no_update = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.upsampling) VOL->ComplexityEstimation.dcecs_upsampling = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.intra_blocks) VOL->ComplexityEstimation.dcecs_intra_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.not_coded_blocks) VOL->ComplexityEstimation.dcecs_not_coded_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.dct_coefs) VOL->ComplexityEstimation.dcecs_dct_coefs = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.dct_lines) VOL->ComplexityEstimation.dcecs_dct_lines = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.vlc_symbols) VOL->ComplexityEstimation.dcecs_vlc_symbols = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.vlc_bits) VOL->ComplexityEstimation.dcecs_vlc_bits = mp4_GetBits9(pInfo, 4); + if (VOL->ComplexityEstimation.sadct) VOL->ComplexityEstimation.dcecs_sadct = mp4_GetBits9(pInfo, 8); + } + if (VOP->coding_type == MP4_VOP_TYPE_P) { + if (VOL->ComplexityEstimation.opaque) VOL->ComplexityEstimation.dcecs_opaque = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.transparent) VOL->ComplexityEstimation.dcecs_transparent = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.intra_cae) VOL->ComplexityEstimation.dcecs_intra_cae = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.inter_cae) VOL->ComplexityEstimation.dcecs_inter_cae = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.no_update) VOL->ComplexityEstimation.dcecs_no_update = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.upsampling) VOL->ComplexityEstimation.dcecs_upsampling = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.intra_blocks) VOL->ComplexityEstimation.dcecs_intra_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.not_coded_blocks) VOL->ComplexityEstimation.dcecs_not_coded_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.dct_coefs) VOL->ComplexityEstimation.dcecs_dct_coefs = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.dct_lines) VOL->ComplexityEstimation.dcecs_dct_lines = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.vlc_symbols) VOL->ComplexityEstimation.dcecs_vlc_symbols = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.vlc_bits) VOL->ComplexityEstimation.dcecs_vlc_bits = mp4_GetBits9(pInfo, 4); + if (VOL->ComplexityEstimation.inter_blocks) VOL->ComplexityEstimation.dcecs_inter_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.inter4v_blocks) VOL->ComplexityEstimation.dcecs_inter4v_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.apm) VOL->ComplexityEstimation.dcecs_apm = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.npm) VOL->ComplexityEstimation.dcecs_npm = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.forw_back_mc_q) VOL->ComplexityEstimation.dcecs_forw_back_mc_q = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.halfpel2) VOL->ComplexityEstimation.dcecs_halfpel2 = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.halfpel4) VOL->ComplexityEstimation.dcecs_halfpel4 = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.sadct) VOL->ComplexityEstimation.dcecs_sadct = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.quarterpel) VOL->ComplexityEstimation.dcecs_quarterpel = mp4_GetBits9(pInfo, 8); + } + if (VOP->coding_type == MP4_VOP_TYPE_B) { + if (VOL->ComplexityEstimation.opaque) VOL->ComplexityEstimation.dcecs_opaque = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.transparent) VOL->ComplexityEstimation.dcecs_transparent = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.intra_cae) VOL->ComplexityEstimation.dcecs_intra_cae = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.inter_cae) VOL->ComplexityEstimation.dcecs_inter_cae = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.no_update) VOL->ComplexityEstimation.dcecs_no_update = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.upsampling) VOL->ComplexityEstimation.dcecs_upsampling = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.intra_blocks) VOL->ComplexityEstimation.dcecs_intra_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.not_coded_blocks) VOL->ComplexityEstimation.dcecs_not_coded_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.dct_coefs) VOL->ComplexityEstimation.dcecs_dct_coefs = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.dct_lines) VOL->ComplexityEstimation.dcecs_dct_lines = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.vlc_symbols) VOL->ComplexityEstimation.dcecs_vlc_symbols = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.vlc_bits) VOL->ComplexityEstimation.dcecs_vlc_bits = mp4_GetBits9(pInfo, 4); + if (VOL->ComplexityEstimation.inter_blocks) VOL->ComplexityEstimation.dcecs_inter_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.inter4v_blocks) VOL->ComplexityEstimation.dcecs_inter4v_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.apm) VOL->ComplexityEstimation.dcecs_apm = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.npm) VOL->ComplexityEstimation.dcecs_npm = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.forw_back_mc_q) VOL->ComplexityEstimation.dcecs_forw_back_mc_q = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.halfpel2) VOL->ComplexityEstimation.dcecs_halfpel2 = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.halfpel4) VOL->ComplexityEstimation.dcecs_halfpel4 = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.interpolate_mc_q) VOL->ComplexityEstimation.dcecs_interpolate_mc_q = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.sadct) VOL->ComplexityEstimation.dcecs_sadct = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.quarterpel) VOL->ComplexityEstimation.dcecs_quarterpel = mp4_GetBits9(pInfo, 8); + } + if (VOP->coding_type == MP4_VOP_TYPE_S && VOL->sprite_enable == MP4_SPRITE_STATIC) { + if (VOL->ComplexityEstimation.intra_blocks) VOL->ComplexityEstimation.dcecs_intra_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.not_coded_blocks) VOL->ComplexityEstimation.dcecs_not_coded_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.dct_coefs) VOL->ComplexityEstimation.dcecs_dct_coefs = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.dct_lines) VOL->ComplexityEstimation.dcecs_dct_lines = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.vlc_symbols) VOL->ComplexityEstimation.dcecs_vlc_symbols = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.vlc_bits) VOL->ComplexityEstimation.dcecs_vlc_bits = mp4_GetBits9(pInfo, 4); + if (VOL->ComplexityEstimation.inter_blocks) VOL->ComplexityEstimation.dcecs_inter_blocks = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.inter4v_blocks) VOL->ComplexityEstimation.dcecs_inter4v_blocks = mp4_GetBits(pInfo, 8); + if (VOL->ComplexityEstimation.apm) VOL->ComplexityEstimation.dcecs_apm = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.npm) VOL->ComplexityEstimation.dcecs_npm = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.forw_back_mc_q) VOL->ComplexityEstimation.dcecs_forw_back_mc_q = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.halfpel2) VOL->ComplexityEstimation.dcecs_halfpel2 = mp4_GetBits9(pInfo, 8); + if (VOL->ComplexityEstimation.halfpel4) VOL->ComplexityEstimation.dcecs_halfpel4 = mp4_GetBits(pInfo, 8); + if (VOL->ComplexityEstimation.interpolate_mc_q) VOL->ComplexityEstimation.dcecs_interpolate_mc_q = mp4_GetBits9(pInfo, 8); + } + } + } + VOP->intra_dc_vlc_thr = mp4_GetBits9(pInfo, 3); + if (VOL->interlaced) { + VOP->top_field_first = mp4_GetBit(pInfo); + VOP->alternate_vertical_scan_flag = mp4_GetBit(pInfo); + } + } + if ((VOL->sprite_enable == MP4_SPRITE_STATIC || VOL->sprite_enable == MP4_SPRITE_GMC) && VOP->coding_type == MP4_VOP_TYPE_S) { + if (VOL->sprite_warping_points > 0) + if (mp4_Sprite_Trajectory(pInfo) != MP4_STATUS_OK) + return MP4_STATUS_PARSE_ERROR; + if (VOL->sprite_brightness_change) { + code = mp4_ShowBits9(pInfo, 4); + if (code == 15) { + mp4_FlushBits(pInfo, 4); + VOP->brightness_change_factor = 625 + mp4_GetBits(pInfo, 10); + } else if (code == 14) { + mp4_FlushBits(pInfo, 4); + VOP->brightness_change_factor = 113 + mp4_GetBits9(pInfo, 9); + } else if (code >= 12) { + mp4_FlushBits(pInfo, 3); + code = mp4_GetBits9(pInfo, 7); + VOP->brightness_change_factor = (code < 64) ? code - 112 : code - 15; + } else if (code >= 8) { + mp4_FlushBits(pInfo, 2); + code = mp4_GetBits9(pInfo, 6); + VOP->brightness_change_factor = (code < 32) ? code - 48 : code - 15; + } else { + mp4_FlushBits(pInfo, 1); + code = mp4_GetBits9(pInfo, 5); + VOP->brightness_change_factor = (code < 16) ? code - 16 : code - 15; + } + } else + VOP->brightness_change_factor = 0; + if (VOL->sprite_enable == MP4_SPRITE_STATIC) + return MP4_STATUS_OK; + } + if (VOL->shape != MP4_SHAPE_TYPE_BINARYONLY) { + VOP->quant = mp4_GetBits9(pInfo, VOL->quant_precision); + if (VOL->shape == MP4_SHAPE_TYPE_GRAYSCALE) { + int32_t ac, i; + + ac = mp4_aux_comp_count[VOL->shape_extension]; + for (i = 0; i < ac; i ++) + VOP->alpha_quant[i] = mp4_GetBits9(pInfo, 6); + } + if (VOP->coding_type != MP4_VOP_TYPE_I) { + VOP->fcode_forward = mp4_GetBits9(pInfo, 3); + if (VOP->fcode_forward == 0) { + mp4_Error("Error: vop_fcode_forward == 0"); + return MP4_STATUS_PARSE_ERROR; + } + } + if (VOP->coding_type == MP4_VOP_TYPE_B) { + VOP->fcode_backward = mp4_GetBits9(pInfo, 3); + if (VOP->fcode_backward == 0) { + mp4_Error("Error: vop_fcode_backward == 0"); + return MP4_STATUS_PARSE_ERROR; + } + } + if (!VOL->scalability) { + if (VOL->shape != MP4_SHAPE_TYPE_RECTANGULAR && VOP->coding_type != MP4_VOP_TYPE_I) + VOP->shape_coding_type = mp4_GetBit(pInfo); + } else { + //f if (VOL->enhancement_type) { + //f VOP->load_backward_shape = mp4_GetBit(pInfo); + //f if (VOP->load_backward_shape) { + //f shape + //f } + //f } + VOP->ref_select_code = mp4_GetBits9(pInfo, 2); + } + } + return MP4_STATUS_OK; +} + +/* +// decode VideoPacket +*/ +mp4_Status mp4_CheckDecodeVideoPacket(mp4_Info* pInfo, int32_t *found) +{ + uint32_t code; + int32_t header_extension_code, rml; + mp4_VideoObject *VOL = &pInfo->VisualObject.VideoObject; + mp4_VideoObjectPlane *VOP = &pInfo->VisualObject.VideoObject.VideoObjectPlane; + + *found = 0; + // check stuffing bits + if (mp4_ShowBit(pInfo) != 0) + return MP4_STATUS_OK; + if (mp4_ShowBits9(pInfo, 8 - pInfo->bitoff) != (uint32_t)((1 << (7 - pInfo->bitoff)) - 1)) + return MP4_STATUS_OK; + if (VOP->coding_type == MP4_VOP_TYPE_I) + rml = 17; + else if (VOP->coding_type == MP4_VOP_TYPE_B) + rml = 16 + IPP_MAX(VOP->fcode_forward, VOP->fcode_backward); + else + rml = 16 + VOP->fcode_forward; + code = (pInfo->bufptr[1] << 16) | (pInfo->bufptr[2] << 8) | pInfo->bufptr[3]; + code >>= 24 - rml; + if (code == 1) { // is resync_marker + mp4_FlushBits(pInfo, rml + 8 - pInfo->bitoff); + header_extension_code = 0; + if (VOL->shape != MP4_SHAPE_TYPE_RECTANGULAR) { + header_extension_code = mp4_GetBit(pInfo); + if (header_extension_code && !(VOL->sprite_enable == MP4_SPRITE_STATIC && VOP->coding_type == MP4_VOP_TYPE_I)) { + VOP->vop_width = mp4_GetBits(pInfo, 13); + if (!mp4_GetBit(pInfo)) + if (pInfo->stopOnErr) + goto Err; + VOP->vop_height = mp4_GetBits(pInfo, 13); + if (!mp4_GetBit(pInfo)) + if (pInfo->stopOnErr) + goto Err; + VOP->vop_horizontal_mc_spatial_ref = mp4_GetBits(pInfo, 13); + if (!mp4_GetBit(pInfo)) + if (pInfo->stopOnErr) + goto Err; + VOP->vop_vertical_mc_spatial_ref = mp4_GetBits(pInfo, 13); + if (!mp4_GetBit(pInfo)) + if (pInfo->stopOnErr) + goto Err; + } + } + pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num = mp4_GetBits(pInfo, pInfo->VisualObject.VideoObject.mbns); + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.macroblock_num >= pInfo->VisualObject.VideoObject.MacroBlockPerVOP) + goto Err; + if (VOL->shape != MP4_SHAPE_TYPE_BINARYONLY) { + pInfo->VisualObject.VideoObject.VideoObjectPlane.quant_scale = mp4_GetBits9(pInfo, VOL->quant_precision); // quant_scale + } + if (VOL->shape == MP4_SHAPE_TYPE_RECTANGULAR) { + header_extension_code = mp4_GetBit(pInfo); + } + if (header_extension_code) { + //f ignore modulo_time_base + do { + code = mp4_GetBit(pInfo); + } while (code); + if (!mp4_GetBit(pInfo)) + if (pInfo->stopOnErr) + goto Err; + //f ignore vop_time_increment + if (VOL->vop_time_increment_resolution_bits != 0 ) { + code = mp4_GetBits(pInfo, VOL->vop_time_increment_resolution_bits); + } + if (!mp4_GetBit(pInfo)) + if (pInfo->stopOnErr) + goto Err; + //f ignore vop_coding_type + code = mp4_GetBits9(pInfo, 2); + if (VOL->shape != MP4_SHAPE_TYPE_RECTANGULAR) { + VOP->change_conv_ratio_disable = mp4_GetBit(pInfo); + if (VOP->coding_type != MP4_VOP_TYPE_I) + VOP->shape_coding_type = mp4_GetBit(pInfo); + } + if (VOL->shape != MP4_SHAPE_TYPE_BINARYONLY) { + //f ignore intra_dc_vlc_thr + code = mp4_GetBits9(pInfo, 3); + if (VOL->sprite_enable == MP4_SPRITE_GMC && VOP->coding_type == MP4_VOP_TYPE_S && VOL->sprite_warping_points > 0) + if (mp4_Sprite_Trajectory(pInfo) != MP4_STATUS_OK) + if (pInfo->stopOnErr) + goto Err; + //f ignore vop_reduced_resolution + if (VOL->reduced_resolution_vop_enable && VOL->shape == MP4_SHAPE_TYPE_RECTANGULAR && + (VOP->coding_type == MP4_VOP_TYPE_I || VOP->coding_type == MP4_VOP_TYPE_P)) + code = mp4_GetBit(pInfo); + if (VOP->coding_type != MP4_VOP_TYPE_I) + VOP->fcode_forward = mp4_GetBits9(pInfo, 3); + if (VOP->coding_type == MP4_VOP_TYPE_B) + VOP->fcode_backward = mp4_GetBits9(pInfo, 3); + } + } + if (VOL->newpred_enable) { + int vop_id_length = VOL->vop_time_increment_resolution_bits + 3; + if (vop_id_length > 15) + vop_id_length = 15; + VOP->vop_id = mp4_GetBits(pInfo, vop_id_length); + VOP->vop_id_for_prediction_indication = mp4_GetBit(pInfo); + if (VOP->vop_id_for_prediction_indication) + VOP->vop_id_for_prediction = mp4_GetBits(pInfo, vop_id_length); + if (!mp4_GetMarkerBit(pInfo)) + if (pInfo->stopOnErr) + goto Err; + } + *found = 1; + return MP4_STATUS_OK; + } + return MP4_STATUS_OK; +Err: + mp4_Error("Error: decoding Video Packet Header"); + return MP4_STATUS_PARSE_ERROR; +} + +int32_t mp4_CheckDecodeGOB_SVH(mp4_Info* pInfo) +{ + int32_t code; + + pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_number ++; + pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_header_empty = 1; + code = mp4_ShowBits(pInfo, 17); /* check gob_resync_marker */ + if (code != 1) { + code = mp4_ShowBitsAlign(pInfo, 17); /* check next aligned bits are gob_resync_marker */ + if (code == 1) + mp4_AlignBits(pInfo); + } + if (code == 1) { + mp4_FlushBits(pInfo, 17); + pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_header_empty = 0; + code = mp4_GetBits9(pInfo, 5); /* gob_number */ + pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_frame_id = mp4_GetBits9(pInfo, 2); + pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.quant_scale = mp4_GetBits9(pInfo, 5); + // check gob_number is valid + //if (code > pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_number && code <= pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.num_gobs_in_vop) + if (code <= pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.num_gobs_in_vop) + pInfo->VisualObject.VideoObject.VideoObjectPlaneH263.gob_number = code; + else { + mp4_Error("Error: bad gob_number in GOB header"); + return MP4_STATUS_ERROR; + } + } + return MP4_STATUS_OK; +} + diff --git a/Src/mpeg4dec/mp4stream.c b/Src/mpeg4dec/mp4stream.c new file mode 100644 index 00000000..9c11d169 --- /dev/null +++ b/Src/mpeg4dec/mp4stream.c @@ -0,0 +1,326 @@ +/* /////////////////////////////////////////////////////////////////////// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 2001-2008 Intel Corporation. All Rights Reserved. +// +// Description: Decodes MPEG-4 bitstream. +// +*/ + + +#include "mp4def.h" + +#ifndef USE_INLINE_BITS_FUNC + +uint32_t mp4_ShowBits(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bufptr; + uint32_t tmp = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); + tmp <<= pInfo->bitoff; + tmp >>= 32 - n; + return tmp; +} + +uint32_t mp4_ShowBit(mp4_Info* pInfo) +{ + uint32_t tmp = pInfo->bufptr[0]; + tmp >>= 7 - pInfo->bitoff; + return (tmp & 1); +} + +uint32_t mp4_ShowBits9(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bufptr; + uint32_t tmp = (ptr[0] << 8) | ptr[1]; + tmp <<= (pInfo->bitoff + 16); + tmp >>= 32 - n; + return tmp; +} + +void mp4_FlushBits(mp4_Info* pInfo, int32_t n) +{ + n = n + pInfo->bitoff; + pInfo->bufptr += n >> 3; + pInfo->bitoff = n & 7; +} + +uint32_t mp4_GetBits(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bufptr; + uint32_t tmp = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); + tmp <<= pInfo->bitoff; + tmp >>= 32 - n; + n = n + pInfo->bitoff; + pInfo->bufptr += n >> 3; + pInfo->bitoff = n & 7; + return tmp; +} + +uint32_t mp4_GetBits9(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bufptr; + uint32_t tmp = (ptr[0] << 8) | ptr[1]; + tmp <<= (pInfo->bitoff + 16); + tmp >>= 32 - n; + n = n + pInfo->bitoff; + pInfo->bufptr += n >> 3; + pInfo->bitoff = n & 7; + return tmp; +} + +void mp4_AlignBits(mp4_Info* pInfo) +{ + if (pInfo->bitoff > 0) { + pInfo->bitoff = 0; + (pInfo->bufptr)++; + } +} + +void mp4_AlignBits7F(mp4_Info* pInfo) +{ + if (pInfo->bitoff > 0) { + pInfo->bitoff = 0; + (pInfo->bufptr)++; + } else { + if (*pInfo->bufptr == 0x7F) + (pInfo->bufptr)++; + } +} + +uint32_t mp4_ShowBitsAlign(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bitoff ? (pInfo->bufptr + 1) : pInfo->bufptr; + uint32_t tmp = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); + tmp >>= 32 - n; + return tmp; +} + +uint32_t mp4_ShowBitsAlign7F(mp4_Info* pInfo, int32_t n) +{ + uint8_t* ptr = pInfo->bitoff ? (pInfo->bufptr + 1) : pInfo->bufptr; + uint32_t tmp; + if (!pInfo->bitoff) { + if (*ptr == 0x7F) + ptr ++; + } + tmp = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); + tmp >>= 32 - n; + return tmp; +} + +#endif + +uint8_t* mp4_FindStartCodePtr(mp4_Info* pInfo) +{ + int32_t i, len = pInfo->buflen - (pInfo->bufptr - pInfo->buffer); + uint8_t* ptr = pInfo->bufptr; + for (i = 0; i < len - 3; i++) { + if (ptr[i] == 0 && ptr[i + 1] == 0 && ptr[i + 2] == 1) { + return ptr + i + 3; + } + } + return NULL; +} + +uint8_t* mp4_FindStartCodeOrShortPtr(mp4_Info* pInfo) +{ + int32_t i, len = pInfo->buflen - (pInfo->bufptr - pInfo->buffer); + uint8_t* ptr = pInfo->bufptr; + for (i = 0; i < len - 3; i++) { + if (ptr[i] == 0 && ptr[i + 1] == 0 && ptr[i + 2] == 1) { + return ptr + i + 3; + } + // short_video_header + if (ptr[i] == 0 && ptr[i + 1] == 0 && (ptr[i + 2] & 0xFC) == 0x80) { + return ptr + i; + } + } + return NULL; +} + +int32_t mp4_SeekStartCodePtr(mp4_Info* pInfo) +{ + uint8_t* ptr; + + if (pInfo->bitoff) { + pInfo->bufptr ++; + pInfo->bitoff = 0; + } + ptr = mp4_FindStartCodePtr(pInfo); + if (ptr) { + pInfo->bufptr = ptr; + return 1; + } else { + pInfo->bufptr = pInfo->buffer + (pInfo->buflen > 3 ? pInfo->buflen - 3 : 0); + return 0; + } +} + +int32_t mp4_SeekStartCodeOrShortPtr(mp4_Info* pInfo) +{ + uint8_t* ptr; + + if (pInfo->bitoff) { + pInfo->bufptr ++; + pInfo->bitoff = 0; + } + ptr = mp4_FindStartCodeOrShortPtr(pInfo); + if (ptr) { + pInfo->bufptr = ptr; + return 1; + } else { + pInfo->bufptr = pInfo->buffer + (pInfo->buflen > 3 ? pInfo->buflen - 3 : 0); + return 0; + } +} + +int32_t mp4_SeekStartCodeValue(mp4_Info* pInfo, uint8_t code) +{ + while (mp4_SeekStartCodePtr(pInfo)) { + if (*(pInfo->bufptr) == code) { + (pInfo->bufptr) ++; + return 1; + } + } + return 0; +} + +uint8_t* mp4_FindShortVideoStartMarkerPtr(mp4_Info* pInfo) +{ + int32_t i, len = pInfo->buflen - (pInfo->bufptr - pInfo->buffer); + uint8_t* ptr = pInfo->bufptr; + for (i = 0; i < len - 3; i++) { + if (ptr[i] == 0 && ptr[i + 1] == 0 && (ptr[i + 2] & (~3)) == 0x80) { + return ptr + i + 2; + } + } + return NULL; +} + +int32_t mp4_SeekShortVideoStartMarker(mp4_Info* pInfo) +{ + uint8_t* ptr; + + if (pInfo->bitoff) { + pInfo->bufptr ++; + pInfo->bitoff = 0; + } + ptr = mp4_FindShortVideoStartMarkerPtr(pInfo); + if (ptr) { + pInfo->bufptr = ptr; + return 1; + } else { + pInfo->bufptr = pInfo->buffer + (pInfo->buflen > 3 ? pInfo->buflen - 3 : 0); + return 0; + } +} + +//changed pInfo->len on pInfo->buflen!!! +int32_t mp4_SeekGOBMarker(mp4_Info* pInfo) +{ + for (; pInfo->bufptr < pInfo->buffer + pInfo->buflen - 2; pInfo->bufptr ++) { + if (pInfo->bufptr[0] == 0) { + pInfo->bitoff = 0; + if (pInfo->bufptr[0] == 0 && pInfo->bufptr[1] == 0 && (pInfo->bufptr[2] & (~3)) == 0x80) + return 0; + pInfo->bufptr --; + for (pInfo->bitoff = 1; pInfo->bitoff <= 7; pInfo->bitoff ++) { + if (mp4_ShowBits(pInfo, 17) == 1) + return 1; + } + pInfo->bufptr ++; + for (pInfo->bitoff = 0; pInfo->bitoff <= 7; pInfo->bitoff ++) { + if (mp4_ShowBits(pInfo, 17) == 1) + return 1; + } + pInfo->bufptr ++; + } + } + return 0; +} + +int32_t mp4_SeekResyncMarker(mp4_Info* pInfo) +{ + int32_t rml; + + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coding_type == MP4_VOP_TYPE_I) + rml = 17; + else if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coding_type == MP4_VOP_TYPE_B) + rml = 16 + IPP_MAX(pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_forward, pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_backward); + else + rml = 16 + pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_forward; + pInfo->bitoff = 0; + for (; pInfo->bufptr < pInfo->buffer + pInfo->buflen - 2; pInfo->bufptr ++) { + if (pInfo->bufptr[0] == 0) { + if (pInfo->bufptr[0] == 0 && pInfo->bufptr[1] == 0 && pInfo->bufptr[2] == 1) + return 0; + if (mp4_ShowBits(pInfo, rml) == 1) { + // check stuffing bits + pInfo->bufptr --; + pInfo->bitoff = 7; + while (pInfo->bitoff > 0 && mp4_ShowBit(pInfo)) + pInfo->bitoff --; + if (pInfo->bitoff == 0 && mp4_ShowBit(pInfo)) { + // stuffing bits are invalid + pInfo->bufptr[0] = 0x7f; + } + return 1; + } + pInfo->bufptr += 2; + } + } + return 0; +} + +int32_t mp4_FindResyncMarker(mp4_Info* pInfo) +{ + int32_t rml; + + if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coding_type == MP4_VOP_TYPE_I) + rml = 17; + else if (pInfo->VisualObject.VideoObject.VideoObjectPlane.coding_type == MP4_VOP_TYPE_B) + rml = 16 + IPP_MAX(pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_forward, pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_backward); + else + rml = 16 + pInfo->VisualObject.VideoObject.VideoObjectPlane.fcode_forward; + pInfo->bitoff = 0; + for (; pInfo->bufptr < pInfo->buffer + pInfo->buflen - 2; pInfo->bufptr ++) { + if (pInfo->bufptr[0] == 0) + { + if (pInfo->bufptr[0] == 0 && pInfo->bufptr[1] == 0 && pInfo->bufptr[2] == 1) + return 0; + if (mp4_ShowBits(pInfo, rml) == 1) + { + return rml; + } + } + } + return 0; +} + +int mp4_IsStartCodeOrShort(mp4_Info* pInfo) +{ + if (pInfo->bufptr[0] == 0 && pInfo->bufptr[1] == 0 && (pInfo->bufptr[2] == 1 || ((pInfo->bufptr[2] & 0xFC) == 0x80))) + return 1; + return 0; +} + + +int mp4_IsStartCodeValue(mp4_Info* pInfo, int min, int max) +{ + if (pInfo->bufptr[0-3] == 0 && pInfo->bufptr[1-3] == 0 && pInfo->bufptr[2-3] == 1) + if (pInfo->bufptr[3-3] >= min && pInfo->bufptr[3-3] <= max) + return 1; + return 0; +} + + +int mp4_IsShortCode(mp4_Info* pInfo) +{ + if (pInfo->bufptr[0] == 0 && pInfo->bufptr[1] == 0 && ((pInfo->bufptr[2] & 0xFC) == 0x80)) + return 1; + return 0; +} + diff --git a/Src/mpeg4dec/mp4tbl.c b/Src/mpeg4dec/mp4tbl.c new file mode 100644 index 00000000..7c0521d7 --- /dev/null +++ b/Src/mpeg4dec/mp4tbl.c @@ -0,0 +1,153 @@ +/* /////////////////////////////////////////////////////////////////////// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 2001-2007 Intel Corporation. All Rights Reserved. +// +// Description: MPEG-4 related tables. +// +*/ + + + +#include "mp4def.h" + +#define DI(b) ((1 << 18) + b) / b + +const int32_t mp4_DivIntraDivisor[47] = { + DI( 1), DI( 1), DI( 2), DI( 3), DI( 4), DI( 5), DI( 6), DI( 7), DI( 8), DI( 9), + DI(10), DI(11), DI(12), DI(13), DI(14), DI(15), DI(16), DI(17), DI(18), DI(19), + DI(20), DI(21), DI(22), DI(23), DI(24), DI(25), DI(26), DI(27), DI(28), DI(29), + DI(30), DI(31), DI(32), DI(33), DI(34), DI(35), DI(36), DI(37), DI(38), DI(39), + DI(40), DI(41), DI(42), DI(43), DI(44), DI(45), DI(46) +}; + +#define DCSL(q) (q <= 4) ? 8 : (q <= 8) ? (q << 1) : (q <= 24) ? (q + 8) : ((q << 1) - 16) + +const uint8_t mp4_DCScalerLuma[32] = { + DCSL( 0), DCSL( 1), DCSL( 2), DCSL( 3), DCSL( 4), DCSL( 5), DCSL( 6), DCSL( 7), + DCSL( 8), DCSL( 9), DCSL(10), DCSL(11), DCSL(12), DCSL(13), DCSL(14), DCSL(15), + DCSL(16), DCSL(17), DCSL(18), DCSL(19), DCSL(20), DCSL(21), DCSL(22), DCSL(23), + DCSL(24), DCSL(25), DCSL(26), DCSL(27), DCSL(28), DCSL(29), DCSL(30), DCSL(31) +}; + +#define DCSC(q) (q <= 4) ? 8 : (q <= 24) ? ((q + 13) >> 1) : (q - 6) + +const uint8_t mp4_DCScalerChroma[32] = { + DCSC( 0), DCSC( 1), DCSC( 2), DCSC( 3), DCSC( 4), DCSC( 5), DCSC( 6), DCSC( 7), + DCSC( 8), DCSC( 9), DCSC(10), DCSC(11), DCSC(12), DCSC(13), DCSC(14), DCSC(15), + DCSC(16), DCSC(17), DCSC(18), DCSC(19), DCSC(20), DCSC(21), DCSC(22), DCSC(23), + DCSC(24), DCSC(25), DCSC(26), DCSC(27), DCSC(28), DCSC(29), DCSC(30), DCSC(31) +}; + +const uint8_t mp4_DefaultIntraQuantMatrix[64] = { + 8, 17, 18, 19, 21, 23, 25, 27, 17, 18, 19, 21, 23, 25, 27, 28, + 20, 21, 22, 23, 24, 26, 28, 30, 21, 22, 23, 24, 26, 28, 30, 32, + 22, 23, 24, 26, 28, 30, 32, 35, 23, 24, 26, 28, 30, 32, 35, 38, + 25, 26, 28, 30, 32, 35, 38, 41, 27, 28, 30, 32, 35, 38, 41, 45 +}; + +const uint8_t mp4_DefaultNonIntraQuantMatrix[64] = { + 16, 17, 18, 19, 20, 21, 22, 23, 17, 18, 19, 20, 21, 22, 23, 24, + 18, 19, 20, 21, 22, 23, 24, 25, 19, 20, 21, 22, 23, 24, 26, 27, + 20, 21, 22, 23, 25, 26, 27, 28, 21, 22, 23, 24, 26, 27, 28, 30, + 22, 23, 24, 26, 27, 28, 30, 31, 23, 24, 25, 27, 28, 30, 31, 33 +}; + +const uint8_t mp4_ClassicalZigzag[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + +const uint8_t mp4_cCbCrMvRound16[16] = {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2}; +const uint8_t mp4_cCbCrMvRound12[12] = {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2}; +const uint8_t mp4_cCbCrMvRound8[8] = {0, 0, 1, 1, 1, 1, 1, 2}; +const uint8_t mp4_cCbCrMvRound4[4] = {0, 1, 1, 1}; + +const Ipp8s mp4_dquant[4] = {-1, -2, 1, 2}; + +const mp4_VLC1 mp4_cbpy1[4] = {{0,255},{0,2},{1,1},{1,1}}; +const mp4_VLC1 mp4_cbpy2[16] = {{0,255},{0,4},{1,3},{1,3},{2,2},{2,2},{2,2},{2,2},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1},{3,1}}; +const mp4_VLC1 mp4_cbpy3[64] = {{1,255},{1,6},{2,5},{2,5},{4,5},{4,5},{5,5},{5,5},{6,3},{6,3},{6,3},{6,3},{6,3},{6,3},{6,3},{6,3},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},{0,3},{0,3},{0,3},{0,3},{0,3},{0,3},{0,3},{0,3},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1},{7,1}}; +const mp4_VLC1 mp4_cbpy4[64] = {{16,255},{16,255},{6,6},{9,6},{8,5},{8,5},{4,5},{4,5},{2,5},{2,5},{1,5},{1,5},{0,4},{0,4},{0,4},{0,4},{12,4},{12,4},{12,4},{12,4},{10,4},{10,4},{10,4},{10,4},{14,4},{14,4},{14,4},{14,4},{5,4},{5,4},{5,4},{5,4},{13,4},{13,4},{13,4},{13,4},{3,4},{3,4},{3,4},{3,4},{11,4},{11,4},{11,4},{11,4},{7,4},{7,4},{7,4},{7,4},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2},{15,2}}; +const mp4_VLC1* mp4_cbpy_t[4] = {mp4_cbpy1, mp4_cbpy2, mp4_cbpy3, mp4_cbpy4}; +const uint8_t mp4_cbpy_b[4] = {2, 4, 6, 6}; + +const int32_t mp4_DC_vlc_Threshold[8] = {512, 13, 15, 17, 19, 21, 23, 0}; + +const uint8_t mp4_PVOPmb_type[256] = {255,255,4,4,4,1,3,3,3,3,2,2,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +const uint8_t mp4_PVOPmb_cbpc[256] = {0,0,3,2,1,3,2,2,1,1,3,3,3,3,3,3,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +const uint8_t mp4_PVOPmb_bits[256] = {9,9,9,9,9,9,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3}; + +const mp4_VLC1 mp4_BVOPmb_type[16] = { + {255, 255}, {IPPVC_MBTYPE_FORWARD, 4}, {IPPVC_MBTYPE_BACKWARD, 3}, {IPPVC_MBTYPE_BACKWARD, 3}, + {IPPVC_MBTYPE_INTERPOLATE, 2}, {IPPVC_MBTYPE_INTERPOLATE, 2}, {IPPVC_MBTYPE_INTERPOLATE, 2}, {IPPVC_MBTYPE_INTERPOLATE, 2}, + {IPPVC_MBTYPE_DIRECT, 1}, {IPPVC_MBTYPE_DIRECT, 1}, {IPPVC_MBTYPE_DIRECT, 1}, {IPPVC_MBTYPE_DIRECT, 1}, + {IPPVC_MBTYPE_DIRECT, 1}, {IPPVC_MBTYPE_DIRECT, 1}, {IPPVC_MBTYPE_DIRECT, 1}, {IPPVC_MBTYPE_DIRECT, 1} +}; + +const mp4_VLC1 mp4_MVD_B12_1[] = { + {32,12},{31,12}, + {30,11},{30,11},{29,11},{29,11},{28,11},{28,11}, + {27,11},{27,11},{26,11},{26,11},{25,11},{25,11}, + {24,10},{24,10},{24,10},{24,10},{23,10},{23,10},{23,10},{23,10}, + {22,10},{22,10},{22,10},{22,10},{21,10},{21,10},{21,10},{21,10}, + {20,10},{20,10},{20,10},{20,10},{19,10},{19,10},{19,10},{19,10}, + {18,10},{18,10},{18,10},{18,10},{17,10},{17,10},{17,10},{17,10}, + {16,10},{16,10},{16,10},{16,10},{15,10},{15,10},{15,10},{15,10}, + {14,10},{14,10},{14,10},{14,10},{13,10},{13,10},{13,10},{13,10}, + {12,10},{12,10},{12,10},{12,10},{11,10},{11,10},{11,10},{11,10}, + {10, 9},{10, 9},{10, 9},{10, 9},{10, 9},{10, 9},{10, 9},{10, 9}, + { 9, 9},{ 9, 9},{ 9, 9},{ 9, 9},{ 9, 9},{ 9, 9},{ 9, 9},{ 9, 9}, + { 8, 9},{ 8, 9},{ 8, 9},{ 8, 9},{ 8, 9},{ 8, 9},{ 8, 9},{ 8, 9}, + {0x7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7}, + {0x7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7}, + {0x7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7}, + {0x7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7},{ 7, 7}, +}; + +const mp4_VLC1 mp4_MVD_B12_2[] = { + { 6, 7},{ 5, 7},{ 4, 6},{ 4, 6}, + { 3, 4},{ 3, 4},{ 3, 4},{ 3, 4},{ 3, 4},{ 3, 4},{ 3, 4},{ 3, 4}, + { 2, 3},{ 2, 3},{ 2, 3},{ 2, 3},{ 2, 3},{ 2, 3},{ 2, 3},{ 2, 3}, + { 2, 3},{ 2, 3},{ 2, 3},{ 2, 3},{ 2, 3},{ 2, 3},{ 2, 3},{ 2, 3}, + { 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2}, + { 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2}, + { 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2}, + { 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2},{ 1, 2}, + { 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1}, + { 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1}, + { 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1}, + { 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1}, + { 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1}, + { 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1}, + { 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1}, + { 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1},{ 0, 1}, +}; + +const int32_t mp4_H263_width[5] = {128, 176, 352, 704, 1408}; +const int32_t mp4_H263_height[5] = {96, 144, 288, 576, 1152}; +const int32_t mp4_H263_mbgob[5] = {8, 11, 22, 88, 352}; +const int32_t mp4_H263_gobvop[5] = {6, 9, 18, 18, 18}; +const int32_t mp4_H263_rowgob[5] = {1, 1, 1, 2, 4}; + +const uint8_t mp4_aux_comp_count[MP4_SHAPE_EXT_NUM+1] = {1, 1, 2, 2, 3, 1, 2, 1, 1, 2, 3, 2, 3, 0}; +const uint8_t mp4_aux_comp_is_alpha[MP4_SHAPE_EXT_NUM+1] = {1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0}; +const uint8_t mp4_BABtypeIntra[81][3] = { + 2, 4, 3, 4, 3, 2, 4, 2, 3, 2, 4, 3, 2, 3, 4, 2, 3, 4, 2, 4, 3, 2, 3, 4, + 4, 2, 3, 4, 3, 2, 2, 3, 4, 2, 3, 4, 4, 3, 2, 2, 3, 4, 3, 2, 4, 4, 3, 2, + 2, 3, 4, 2, 3, 4, 4, 2, 3, 2, 3, 4, 4, 3, 2, 4, 2, 3, 2, 3, 4, 4, 3, 2, + 4, 2, 3, 4, 3, 2, 4, 3, 2, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, + 2, 3, 4, 2, 3, 4, 2, 3, 4, 4, 3, 2, 2, 3, 4, 4, 3, 2, 4, 3, 2, 2, 3, 4, + 3, 4, 2, 4, 3, 2, 2, 3, 4, 3, 4, 2, 4, 3, 2, 2, 3, 4, 4, 3, 2, 4, 2, 3, + 2, 3, 4, 4, 3, 2, 4, 2, 3, 2, 4, 3, 3, 4, 2, 4, 2, 3, 2, 4, 3, 4, 2, 3, + 4, 2, 3, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 4, 2, 3, 2, 3, 4, + 4, 3, 2, 4, 3, 2, 4, 2, 3, 3, 4, 2, 3, 4, 2, 4, 2, 3, 3, 4, 2, 4, 3, 2, + 2, 4, 3, 4, 3, 2, 4, 2, 3, 4, 2, 3, 3, 4, 2, 4, 3, 2, 2, 4, 3, 3, 4, 2, + 4, 3, 2 +}; + diff --git a/Src/mpeg4dec/mpeg4dec.sln b/Src/mpeg4dec/mpeg4dec.sln new file mode 100644 index 00000000..47c19334 --- /dev/null +++ b/Src/mpeg4dec/mpeg4dec.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpeg4dec", "mpeg4dec.vcproj", "{F082AB20-F012-4CB0-AA60-A8F7177AEBC1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F082AB20-F012-4CB0-AA60-A8F7177AEBC1}.Debug|Win32.ActiveCfg = Debug|Win32 + {F082AB20-F012-4CB0-AA60-A8F7177AEBC1}.Debug|Win32.Build.0 = Debug|Win32 + {F082AB20-F012-4CB0-AA60-A8F7177AEBC1}.Release|Win32.ActiveCfg = Release|Win32 + {F082AB20-F012-4CB0-AA60-A8F7177AEBC1}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Src/mpeg4dec/mpeg4dec.vcproj b/Src/mpeg4dec/mpeg4dec.vcproj new file mode 100644 index 00000000..eb5685a9 --- /dev/null +++ b/Src/mpeg4dec/mpeg4dec.vcproj @@ -0,0 +1,214 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="mpeg4dec" + ProjectGUID="{F082AB20-F012-4CB0-AA60-A8F7177AEBC1}" + RootNamespace="mpeg4dec" + Keyword="Win32Proj" + TargetFrameworkVersion="196613" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="4" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="../Wasabi;"$(ProgramFiles)\Intel\IPP\6.1.1.035\ia32\include"" + PreprocessorDefinitions="WIN32;_DEBUG;_LIB" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="4" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="3" + InlineFunctionExpansion="2" + EnableIntrinsicFunctions="true" + FavorSizeOrSpeed="1" + AdditionalIncludeDirectories="../Wasabi;"$(ProgramFiles)\Intel\IPP\6.1.1.035\ia32\include"" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB" + StringPooling="true" + RuntimeLibrary="2" + BufferSecurityCheck="false" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\mp4decvop.c" + > + </File> + <File + RelativePath=".\mp4decvopb.c" + > + </File> + <File + RelativePath=".\mp4decvopi.c" + > + </File> + <File + RelativePath=".\mp4decvopp.c" + > + </File> + <File + RelativePath=".\mp4decvops.c" + > + </File> + <File + RelativePath=".\mp4parse.c" + > + </File> + <File + RelativePath=".\mp4stream.c" + > + </File> + <File + RelativePath=".\mp4tbl.c" + > + </File> + <File + RelativePath=".\mpeg4vid_api.c" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath=".\mp4dec.h" + > + </File> + <File + RelativePath=".\mp4def.h" + > + </File> + <File + RelativePath=".\mpeg4vid_api.h" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/Src/mpeg4dec/mpeg4vid_api.c b/Src/mpeg4dec/mpeg4vid_api.c new file mode 100644 index 00000000..3c800462 --- /dev/null +++ b/Src/mpeg4dec/mpeg4vid_api.c @@ -0,0 +1,661 @@ +#include "mpeg4vid_api.h" +#include "mp4def.h" +#include "mp4dec.h" + +/* TODO: we havn't implemented "end of stream" yet, but when we do +we need to flush out the buffered frames +m_decInfo->VisualObject.vFrame = m_decInfo->VisualObject.VideoObject.prevPlaneIsB ? +&m_decInfo->VisualObject.nFrame : &m_decInfo->VisualObject.cFrame; +*/ + +// disable post processing for now, doesn't seem to be working out too well +//#define MP4V_DO_POST_PROCESS + +#define MAX_CODED_FRAME 8000000 // TODO: benski> verify +typedef struct +{ + mp4_Info dec; + int initted; + int resetting; + int skip_b_frames; +#ifdef MP4V_DO_POST_PROCESS + mp4_Frame ppFrame0, ppFrame1; +#endif + __declspec(align(32)) uint8_t buffer[MAX_CODED_FRAME]; +} MPEG4VideoDecoder; + +static int FreeBuffers(MPEG4VideoDecoder *decoder); + +void mp4_Error(const char *str) +{ + puts(str); +} + +mpeg4vid_decoder_t MPEG4Video_CreateDecoder(int filetype, int codec) +{ + MPEG4VideoDecoder *decoder = (MPEG4VideoDecoder *)malloc(sizeof(MPEG4VideoDecoder)); + memset(decoder, 0, sizeof(MPEG4VideoDecoder)); + + // set configuration stuff + decoder->dec.stopOnErr = 0; + decoder->dec.strictSyntaxCheck = 0; + decoder->dec.VisualObject.verid = 1; + decoder->dec.ftype = filetype; + decoder->dec.ftype_f = codec; + + return decoder; +} + +void MPEG4Video_DestroyDecoder(mpeg4vid_decoder_t d) +{ + MPEG4VideoDecoder *decoder = (MPEG4VideoDecoder *)d; + if (decoder) + { +#ifdef MP4V_DO_POST_PROCESS + free(decoder->ppFrame0.mid); + free(decoder->ppFrame1.mid); +#endif + FreeBuffers(decoder); + free(decoder); + } +} + +void MPEG4Video_Flush(mpeg4vid_decoder_t d) +{ + MPEG4VideoDecoder *decoder = (MPEG4VideoDecoder *)d; + if (decoder && decoder->initted) + { + mp4_ResetVOL(&decoder->dec); + decoder->resetting = 1; + } +} + +static int AllocateInitFrame(mp4_Frame* pFrame) +{ + int32_t w, h; + + w = (pFrame->mbPerRow + 2 * MP4_NUM_EXT_MB) << 4; + h = (pFrame->mbPerCol + 2 * MP4_NUM_EXT_MB) << 4; + pFrame->mid = malloc(w * h + (w * h >> 1)); + if (!pFrame->mid) + return 1; // out of memory + + ippsSet_8u(0, pFrame->mid, w * h); + ippsSet_8u(128, pFrame->mid + w * h, w * h >> 1); + + pFrame->stepY = w; + pFrame->stepCb = w >> 1; + pFrame->stepCr = w >> 1; + + /* benski> stuff from LockFrame... */ + pFrame->apY = pFrame->mid; + pFrame->pY = pFrame->apY + w * 16 + 16; + pFrame->apCb = pFrame->apY + w * h; + w >>= 1; + h >>= 1; + pFrame->pCb = pFrame->apCb + w * 8 + 8; + pFrame->apCr = pFrame->apCb + w * h; + pFrame->pCr = pFrame->apCr + w * 8 + 8; + + return 0; +} + +static int AllocateBuffers(MPEG4VideoDecoder *decoder) +{ + if (mp4_InitVOL(&decoder->dec) != MP4_STATUS_OK) + { + mp4_Error("Error: No memory to allocate internal buffers\n"); + return 1;//UMC_ERR_ALLOC; + } + return 0; +} + +static int InsideInit(MPEG4VideoDecoder *decoder) +{ + int status; + uint32_t code; + int h_vo_found = 0, h_vos_found = 0; + + for (;;) + { + if (!mp4_SeekStartCodeOrShortPtr(&decoder->dec)) + { + mp4_Error("Error: Can't find Visual Object or Video Object start codes or short_video_start_marker\n"); + return 1;//UMC_ERR_SYNC; + } + // check short_video_start_marker + if (mp4_IsShortCode(&decoder->dec)) + { + if ((mp4_Parse_VideoObject(&decoder->dec)) != MP4_STATUS_OK) + return 1;//UMC_ERR_INVALID_STREAM; + break; + } + code = mp4_GetBits(&decoder->dec, 8); + if (!h_vos_found && code == MP4_VISUAL_OBJECT_SEQUENCE_SC) + { + h_vos_found = 1; + if ((mp4_Parse_VisualObjectSequence(&decoder->dec)) != MP4_STATUS_OK) + return 1;//UMC_ERR_INVALID_STREAM; + } + + if (!h_vo_found && code == MP4_VISUAL_OBJECT_SC) + { + h_vo_found = 1; + if ((mp4_Parse_VisualObject(&decoder->dec)) != MP4_STATUS_OK) + return 1;//UMC_ERR_INVALID_STREAM; + } + // some streams can start with video_object_layer + if ((int32_t)code >= MP4_VIDEO_OBJECT_LAYER_MIN_SC && code <= MP4_VIDEO_OBJECT_LAYER_MAX_SC) { + decoder->dec.bufptr -= 4; + if ((mp4_Parse_VideoObject(&decoder->dec)) != MP4_STATUS_OK) + return 1;//UMC_ERR_INVALID_STREAM; + break; + } + } + + status = AllocateBuffers(decoder); + if (status) + return status; + + +#if 0 // don't really care about this, but might be useful code for later? + // set profile/level info + decoder->profile = decoder->dec.profile_and_level_indication >> 4; + decoder->level = decoder->dec.profile_and_level_indication & 15; + if (decoder->profile == MPEG4_PROFILE_SIMPLE) + if (decoder->level == 8) + decoder->level = MPEG4_LEVEL_0; + if (decoder->profile == MPEG4_PROFILE_ADVANCED_SIMPLE) { + if (decoder->level == 7) + decoder->level = MPEG4_LEVEL_3B; + if (decoder->level > 7) { + decoder->profile = MPEG4_PROFILE_FGS; + decoder->level -= 8; + } + } +#endif + decoder->initted = 1; + + return 0; +} + +static int FreeBuffers(MPEG4VideoDecoder *decoder) +{ + int status = 0; + + ReleaseFrame(&decoder->dec.VisualObject, decoder->dec.VisualObject.cFrame); + decoder->dec.VisualObject.cFrame=0; + ReleaseFrame(&decoder->dec.VisualObject, decoder->dec.VisualObject.rFrame); + decoder->dec.VisualObject.rFrame=0; + ReleaseFrame(&decoder->dec.VisualObject, decoder->dec.VisualObject.nFrame); + decoder->dec.VisualObject.nFrame=0; + ReleaseFrame(&decoder->dec.VisualObject, decoder->dec.VisualObject.sFrame); + decoder->dec.VisualObject.sFrame=0; + FreeCache(&decoder->dec.VisualObject); + + mp4_FreeVOL(&decoder->dec); + return status; +} + +static int PostProcess(MPEG4VideoDecoder *decoder, mp4_Frame *inout) +{ +#ifdef MP4V_DO_POST_PROCESS + int w, h, i, j, k, QP, width, height; + IppiSize size; + Ipp8u *pSrc[3], *pDst[3]; + int srcPitch[3], dstPitch[3], threshold[6]; + int m_DeblockingProcPlane[3] = {1,1,1}; // TODO: configurable + int m_DeringingProcPlane[3] = {1,1,1}; // TODO: configurable + int32_t m_DeblockingTHR1 = 2; // TODO + int32_t m_DeblockingTHR2 = 6; // TODO + QP = inout->QP; + width = (decoder->dec.VisualObject.VideoObject.width + 7) & (~7); + height = (decoder->dec.VisualObject.VideoObject.height + 7) & (~7); + if (m_DeblockingProcPlane[0] || m_DeblockingProcPlane[1] || m_DeblockingProcPlane[2]) { + pSrc[0] = inout->pY; + srcPitch[0] = inout->stepY; + pDst[0] = decoder->ppFrame0.pY; + dstPitch[0] = decoder->ppFrame0.stepY; + pSrc[1] = inout->pCb; + srcPitch[1] = inout->stepCb; + pDst[1] = decoder->ppFrame0.pCb; + dstPitch[1] = decoder->ppFrame0.stepCb; + pSrc[2] = inout->pCr; + srcPitch[2] = inout->stepCr; + pDst[2] = decoder->ppFrame0.pCr; + dstPitch[2] = decoder->ppFrame0.stepCr; + for (k = 0; k < 3; k ++) { + if (m_DeblockingProcPlane[k]) { + size.height = 8; + if (k == 0) { + size.width = width; + h = height >> 3; + w = width >> 3; + } else { + size.width = width >> 1; + h = height >> 4; + w = width >> 4; + } + for (i = 0; i < h; i ++) { + ippiCopy_8u_C1R(pSrc[k], srcPitch[k], pDst[k], dstPitch[k], size); + if (i > 0) { + for (j = 0; j < w; j ++) + ippiFilterDeblocking8x8HorEdge_MPEG4_8u_C1IR(pDst[k] + 8 * j, dstPitch[k], QP, m_DeblockingTHR1, m_DeblockingTHR2); + for (j = 1; j < w; j ++) + ippiFilterDeblocking8x8VerEdge_MPEG4_8u_C1IR(pDst[k] - 8 * dstPitch[k] + 8 * j, dstPitch[k], QP, m_DeblockingTHR1, m_DeblockingTHR2); + } + if (i == h - 1) { + for (j = 1; j < w; j ++) + ippiFilterDeblocking8x8VerEdge_MPEG4_8u_C1IR(pDst[k] + 8 * j, dstPitch[k], QP, m_DeblockingTHR1, m_DeblockingTHR2); + } + pSrc[k] += srcPitch[k] * 8; + pDst[k] += dstPitch[k] * 8; + } + } else { + if (k == 0) { + size.width = width; + size.height = height; + } else { + size.width = width >> 1; + size.height = height >> 1; + } + ippiCopy_8u_C1R(pSrc[k], srcPitch[k], pDst[k], dstPitch[k], size); + } + } + *inout = decoder->ppFrame0; + } + if (m_DeringingProcPlane[0] || m_DeringingProcPlane[1] || m_DeringingProcPlane[2]) { + pSrc[0] = inout->pY; + srcPitch[0] = inout->stepY; + pDst[0] = decoder->ppFrame1.pY; + dstPitch[0] = decoder->ppFrame1.stepY; + if (!m_DeringingProcPlane[0]) { + size.width = width; + size.height = height; + ippiCopy_8u_C1R(pSrc[0], srcPitch[0], pDst[0], dstPitch[0], size); + } + pSrc[1] = inout->pCb; + srcPitch[1] = inout->stepCb; + pDst[1] = decoder->ppFrame1.pCb; + dstPitch[1] = decoder->ppFrame1.stepCb; + if (!m_DeringingProcPlane[1]) { + size.width = width >> 1; + size.height = height >> 1; + ippiCopy_8u_C1R(pSrc[1], srcPitch[1], pDst[1], dstPitch[1], size); + } + pSrc[2] = inout->pCr; + srcPitch[2] = inout->stepCr; + pDst[2] = decoder->ppFrame1.pCr; + dstPitch[2] = decoder->ppFrame1.stepCr; + if (!m_DeringingProcPlane[2]) { + size.width = width >> 1; + size.height = height >> 1; + ippiCopy_8u_C1R(pSrc[2], srcPitch[2], pDst[2], dstPitch[2], size); + } + h = inout->mbPerCol; + w = inout->mbPerRow; + for (i = 0; i < h; i ++) { + for (j = 0; j < w; j ++) { + ippiFilterDeringingThreshold_MPEG4_8u_P3R(pSrc[0]+ 16 * j, srcPitch[0], pSrc[1] + 8 * j, srcPitch[1], pSrc[2] + 8 * j, srcPitch[2], threshold); + // copy border macroblocks + if (i == 0 || i == h - 1 || j == 0 || j == w - 1) { + if (m_DeringingProcPlane[0]) + ippiCopy16x16_8u_C1R(pSrc[0] + 16 * j, srcPitch[0], pDst[0] + 16 * j, dstPitch[0]); + if (m_DeringingProcPlane[1]) + ippiCopy8x8_8u_C1R(pSrc[1] + 8 * j, srcPitch[1], pDst[1] + 8 * j, dstPitch[1]); + if (m_DeringingProcPlane[2]) + ippiCopy8x8_8u_C1R(pSrc[2] + 8 * j, srcPitch[2], pDst[2] + 8 * j, dstPitch[2]); + } + if (m_DeringingProcPlane[0]) { + if (i != 0 && j != 0) + ippiFilterDeringingSmooth8x8_MPEG4_8u_C1R(pSrc[0] + 16 * j, srcPitch[0], pDst[0] + 16 * j, dstPitch[0], QP, threshold[0]); + if (i != 0 && j != w - 1) + ippiFilterDeringingSmooth8x8_MPEG4_8u_C1R(pSrc[0] + 16 * j + 8, srcPitch[0], pDst[0] + 16 * j + 8, dstPitch[0], QP, threshold[1]); + if (i != h - 1 && j != 0) + ippiFilterDeringingSmooth8x8_MPEG4_8u_C1R(pSrc[0] + 16 * j + 8 * srcPitch[0], srcPitch[0], pDst[0] + 16 * j + 8 * dstPitch[0], dstPitch[0], QP, threshold[2]); + if (i != h - 1 && j != w - 1) + ippiFilterDeringingSmooth8x8_MPEG4_8u_C1R(pSrc[0] + 16 * j + 8 * srcPitch[0] + 8, srcPitch[0], pDst[0] + 16 * j + 8 * dstPitch[0] + 8, dstPitch[0], QP, threshold[3]); + } + if (i != 0 && j != 0 && i != h - 1 && j != w - 1) { + if (m_DeringingProcPlane[1]) + ippiFilterDeringingSmooth8x8_MPEG4_8u_C1R(pSrc[1] + 8 * j, srcPitch[1], pDst[1] + 8 * j, dstPitch[1], QP, threshold[4]); + if (m_DeringingProcPlane[2]) + ippiFilterDeringingSmooth8x8_MPEG4_8u_C1R(pSrc[2] + 8 * j, srcPitch[2], pDst[2] + 8 * j, dstPitch[2], QP, threshold[5]); + } + } + pSrc[0] += srcPitch[0] * 16; + pDst[0] += dstPitch[0] * 16; + pSrc[1] += srcPitch[1] * 8; + pDst[1] += dstPitch[1] * 8; + pSrc[2] += srcPitch[2] * 8; + pDst[2] += dstPitch[2] * 8; + } + *inout = decoder->ppFrame1; + } +#endif + return 0; +} + +void MPEG4Video_DecodeFrame(mpeg4vid_decoder_t d, const void *buffer, size_t bufferlen, uint64_t time_code) +{ + int status=0; + int code; + MPEG4VideoDecoder *decoder = (MPEG4VideoDecoder *)d; + + if (bufferlen > (MAX_CODED_FRAME-32)) + return; + + if (buffer) + { + memcpy(decoder->buffer, buffer, bufferlen); + memset(decoder->buffer+bufferlen, 0, 32); + decoder->dec.bitoff = 0; + decoder->dec.bufptr = decoder->dec.buffer = (uint8_t *)decoder->buffer; + decoder->dec.buflen = bufferlen; + } + + if (!decoder->initted) // initialize off the first packet + { + status = InsideInit(decoder); + if (status) + return; + } + + for (;;) + { + // Seeking the VOP start_code, and then begin the vop decoding + if (decoder->dec.VisualObject.VideoObject.short_video_header) + { + if (!mp4_SeekShortVideoStartMarker(&decoder->dec)) + { + mp4_Error("Error: Failed seeking short_video_start_marker\n"); + status = 1;//UMC_ERR_SYNC; + break; + } + } + else + { + for (;;) + { + if (!mp4_SeekStartCodePtr(&decoder->dec)) { + mp4_Error("Error: Failed seeking GOV or VOP Start Code"); + status = 1;//UMC_ERR_SYNC; + break; + } + code = decoder->dec.bufptr[0]; + decoder->dec.bufptr++; + // parse repeated VOS, VO and VOL headers because stream may be glued from different streams + if (code == MP4_VISUAL_OBJECT_SEQUENCE_SC) + { + if (mp4_Parse_VisualObjectSequence(&decoder->dec) != MP4_STATUS_OK) + { + status = 1;//UMC_ERR_INVALID_STREAM; + break; + } + } + else if (code == MP4_VISUAL_OBJECT_SC) + { + if (mp4_Parse_VisualObject(&decoder->dec) != MP4_STATUS_OK) + { + status = 1;//UMC_ERR_INVALID_STREAM; + break; + } + } + else if (code >= MP4_VIDEO_OBJECT_LAYER_MIN_SC && code <= MP4_VIDEO_OBJECT_LAYER_MAX_SC) + { + // save parameters which can affect on reinit + Ipp32s interlaced = decoder->dec.VisualObject.VideoObject.interlaced; + Ipp32s data_partitioned = decoder->dec.VisualObject.VideoObject.data_partitioned; + Ipp32s sprite_enable = decoder->dec.VisualObject.VideoObject.sprite_enable; + Ipp32s width = decoder->dec.VisualObject.VideoObject.width; + Ipp32s height = decoder->dec.VisualObject.VideoObject.height; + + // in repeated headers check only VOL header + decoder->dec.bufptr -= 4; + + if (mp4_Parse_VideoObject(&decoder->dec) != MP4_STATUS_OK) { + status = 1;//UMC_ERR_INVALID_STREAM; + break; + } + // realloc if something was changed + if (interlaced != decoder->dec.VisualObject.VideoObject.interlaced || + data_partitioned != decoder->dec.VisualObject.VideoObject.data_partitioned || + sprite_enable != decoder->dec.VisualObject.VideoObject.sprite_enable || + width != decoder->dec.VisualObject.VideoObject.width || + height != decoder->dec.VisualObject.VideoObject.height) + { + // TODO: return a code so we can return MP4_VIDEO_OUTPUT_FORMAT_CHANGED + if (decoder->dec.strictSyntaxCheck) + { + mp4_Error("Error: Repeated VOL header is different from previous"); + status = 1;//UMC_ERR_INVALID_STREAM; + break; + } + + // UnlockBuffers(); + status = FreeBuffers(decoder); + if (status) + break; + + status = AllocateBuffers(decoder); + if (status) + break; + + // free buffers for MPEG-4 post-processing +#ifdef MP4V_DO_POST_PROCESS + free(decoder->ppFrame0.mid); + decoder->ppFrame0.mid = 0; + + free(decoder->ppFrame1.mid); + decoder->ppFrame1.mid = 0; +#endif + + // TODO: clear cache and display frames + } + // reinit quant matrix + ippiQuantInvIntraInit_MPEG4(decoder->dec.VisualObject.VideoObject.quant_type ? decoder->dec.VisualObject.VideoObject.intra_quant_mat : NULL, decoder->dec.VisualObject.VideoObject.QuantInvIntraSpec, 8); + ippiQuantInvInterInit_MPEG4(decoder->dec.VisualObject.VideoObject.quant_type ? decoder->dec.VisualObject.VideoObject.nonintra_quant_mat : NULL, decoder->dec.VisualObject.VideoObject.QuantInvInterSpec, 8); + } + else if (code == MP4_GROUP_OF_VOP_SC) + { + if (mp4_Parse_GroupOfVideoObjectPlane(&decoder->dec) != MP4_STATUS_OK) + { + status = 1;//UMC_ERR_INVALID_STREAM; + break; + } + } + else if (decoder->dec.bufptr[-1] == MP4_VIDEO_OBJECT_PLANE_SC) + { + break; + } + } + if (status) + break; + + } + + // parse VOP header + if ((mp4_Parse_VideoObjectPlane(&decoder->dec)) != MP4_STATUS_OK) + { + //status = UMC_WRN_INVALID_STREAM; + status = 0; + break; + } + + if (decoder->resetting && decoder->dec.VisualObject.VideoObject.VideoObjectPlane.coding_type != MP4_VOP_TYPE_I) + { + //UnlockBuffers(); + //return UMC_ERR_NOT_ENOUGH_DATA; +// decoder->dec.VisualObject.vFrame = NULL; + status = 1;//UMC_ERR_NOT_ENOUGH_DATA; + break; + } + if (decoder->dec.VisualObject.VideoObject.VideoObjectPlane.coding_type == MP4_VOP_TYPE_B) + { + if (decoder->skip_b_frames) + { + decoder->dec.bufptr = decoder->dec.buffer+ decoder->dec.buflen; + status = 1;//UMC_ERR_NOT_ENOUGH_DATA; + break; + } + } + + // decode VOP + if ((mp4_DecodeVideoObjectPlane(&decoder->dec)) != MP4_STATUS_OK) + { + status = 1;//UMC_WRN_INVALID_STREAM; + } + if (decoder->dec.VisualObject.cFrame) + { + decoder->dec.VisualObject.cFrame->timestamp = time_code; + decoder->dec.VisualObject.cFrame->QP = decoder->dec.VisualObject.VideoObject.short_video_header ? decoder->dec.VisualObject.VideoObject.VideoObjectPlaneH263.vop_quant : decoder->dec.VisualObject.VideoObject.VideoObjectPlane.quant; + } + + // after reset it is need to skip first B-frames + if (decoder->dec.VisualObject.VideoObject.VOPindex < 2 && decoder->dec.VisualObject.VideoObject.VideoObjectPlane.coding_type == MP4_VOP_TYPE_B) + { + status = 1;//UMC_ERR_NOT_ENOUGH_DATA; + break; + } + + // do not count not_coded P frames with same vop_time as reference (in AVI) + + if (decoder->dec.VisualObject.VideoObject.VideoObjectPlane.coded || + ( + decoder->dec.VisualObject.cFrame && + (!decoder->dec.VisualObject.rFrame || (decoder->dec.VisualObject.rFrame->time != decoder->dec.VisualObject.cFrame->time)) && + (!decoder->dec.VisualObject.nFrame || (decoder->dec.VisualObject.nFrame->time != decoder->dec.VisualObject.cFrame->time)) + ) + ) + { + decoder->dec.VisualObject.VideoObject.VOPindex++; + } + else + { + status = 1;//UMC_ERR_NOT_ENOUGH_DATA; + break; + } + if (decoder->resetting && decoder->dec.VisualObject.VideoObject.VideoObjectPlane.coding_type == MP4_VOP_TYPE_I) + { + // TODO: ???m_time_reset = (Ipp32s)decoder->dec.VisualObject.cFrame.time; + //decoder->dec.VisualObject.vFrame = NULL; + decoder->resetting = 0; + } + + } + // return status; +} + +void MPEG4Video_GetPicture(mpeg4vid_decoder_t d, mp4_Frame **frame) +{ + int status = 0; + MPEG4VideoDecoder *decoder = (MPEG4VideoDecoder *)d; + + mp4_Frame *rendFrame = GetDisplayFrame(&decoder->dec.VisualObject); + if (rendFrame) + { + uint64_t timestamp = rendFrame->timestamp; +#ifdef MP4V_DO_POST_PROCESS + if (1 /* TODO: disable deblocking and deringing on request*/) + { + if (!decoder->ppFrame0.mid) + { + decoder->ppFrame0.mbPerRow = decoder->dec.VisualObject.vFrame->mbPerRow; + decoder->ppFrame0.mbPerCol = decoder->dec.VisualObject.vFrame->mbPerCol; + status = AllocateInitFrame(&decoder->ppFrame0); + if (status) + return ; + } + if (!decoder->ppFrame1.mid) + { + decoder->ppFrame1.mbPerRow = decoder->dec.VisualObject.vFrame->mbPerRow; + decoder->ppFrame1.mbPerCol = decoder->dec.VisualObject.vFrame->mbPerCol; + status = AllocateInitFrame(&decoder->ppFrame1); + if (status) + return ; + } + + PostProcess(decoder, rendFrame); + } +#endif + //if (m_LastDecodedFrame.GetColorFormat() != YUV420) { + // m_LastDecodedFrame.Init(decoder->dec.VisualObject.VideoObject.width, decoder->dec.VisualObject.VideoObject.height, YUV420); + //} + + // TODO ??? m_LastDecodedFrame.SetTime(pts); + *frame = rendFrame; + rendFrame->timestamp = timestamp; + } + else + *frame = 0; +} + +void MPEG4Video_ReleaseFrame(mpeg4vid_decoder_t d, mp4_Frame *frame) +{ + MPEG4VideoDecoder *decoder = (MPEG4VideoDecoder *)d; + ReleaseFrame(&decoder->dec.VisualObject, frame); +} + +static double GetAspectRatio(mp4_VideoObject *video_object) +{ + int aspect_ratio_width=1, aspect_ratio_height=1; + switch (video_object->aspect_ratio_info) + { + case MP4_ASPECT_RATIO_FORBIDDEN: + case MP4_ASPECT_RATIO_1_1: + aspect_ratio_width = 1; + aspect_ratio_height = 1; + break; + case MP4_ASPECT_RATIO_12_11: + aspect_ratio_width = 12; + aspect_ratio_height = 11; + break; + case MP4_ASPECT_RATIO_10_11: + aspect_ratio_width = 10; + aspect_ratio_height = 11; + break; + case MP4_ASPECT_RATIO_16_11: + aspect_ratio_width = 16; + aspect_ratio_height = 11; + break; + case MP4_ASPECT_RATIO_40_33: + aspect_ratio_width = 40; + aspect_ratio_height = 33; + break; + default: + aspect_ratio_width = video_object->aspect_ratio_info_par_width; + aspect_ratio_height = video_object->aspect_ratio_info_par_height; + break; + } + return (double)aspect_ratio_width / (double)aspect_ratio_height; +} + +int MPEG4Video_GetOutputFormat(mpeg4vid_decoder_t d, int *width, int *height, double *aspect_ratio) +{ + MPEG4VideoDecoder *decoder = (MPEG4VideoDecoder *)d; + if (decoder && decoder->initted) + { + *width = decoder->dec.VisualObject.VideoObject.width; + *height = decoder->dec.VisualObject.VideoObject.height; + *aspect_ratio = GetAspectRatio(&decoder->dec.VisualObject.VideoObject); + return 0; + } + return 1; +} + +void MPEG4Video_HurryUp(mpeg4vid_decoder_t d, int state) +{ + MPEG4VideoDecoder *decoder = (MPEG4VideoDecoder *)d; + if (decoder) + { + decoder->skip_b_frames = state; + } +} +void MPEG4Video_EndOfStream(mpeg4vid_decoder_t d) +{ + MPEG4VideoDecoder *decoder = (MPEG4VideoDecoder *)d; + if (decoder) + { + // TODO + } +}
\ No newline at end of file diff --git a/Src/mpeg4dec/mpeg4vid_api.h b/Src/mpeg4dec/mpeg4vid_api.h new file mode 100644 index 00000000..bdfdbad8 --- /dev/null +++ b/Src/mpeg4dec/mpeg4vid_api.h @@ -0,0 +1,54 @@ +#pragma once +#ifdef __cplusplus +extern "C" +{ +#endif +#include <bfc/platform/types.h> +#include "mp4def.h" +typedef void *mpeg4vid_decoder_t; + +mpeg4vid_decoder_t MPEG4Video_CreateDecoder(int filetype, int codec); +void MPEG4Video_DestroyDecoder(mpeg4vid_decoder_t decoder); +void MPEG4Video_DecodeFrame(mpeg4vid_decoder_t decoder, const void *buffer, size_t bufferlen, uint64_t time_code); +void MPEG4Video_GetPicture(mpeg4vid_decoder_t decoder, mp4_Frame **frame); +int MPEG4Video_GetOutputFormat(mpeg4vid_decoder_t decoder, int *width, int *height, double *aspect_ratio); +void MPEG4Video_Flush(mpeg4vid_decoder_t decoder); +void MPEG4Video_HurryUp(mpeg4vid_decoder_t decoder, int state); +void MPEG4Video_EndOfStream(mpeg4vid_decoder_t decoder); +void MPEG4Video_ReleaseFrame(mpeg4vid_decoder_t d, mp4_Frame *frame); +#define MPEG4_PROFILE_SIMPLE 0 +#define MPEG4_PROFILE_SIMPLE_SCALABLE 1 +#define MPEG4_PROFILE_CORE 2 +#define MPEG4_PROFILE_MAIN 3 +#define MPEG4_PROFILE_NBIT 4 +#define MPEG4_PROFILE_SCALABLE_TEXTURE 5 +#define MPEG4_PROFILE_SIMPLE_FACE 6 +#define MPEG4_PROFILE_BASIC_ANIMATED_TEXTURE 7 +#define MPEG4_PROFILE_HYBRID 8 +#define MPEG4_PROFILE_ADVANCED_REAL_TIME_SIMPLE 9 +#define MPEG4_PROFILE_CORE_SCALABLE 10 +#define MPEG4_PROFILE_ADVANCED_CODE_EFFICIENCY 11 +#define MPEG4_PROFILE_ADVANCED_CORE 12 +#define MPEG4_PROFILE_ADVANCED_SCALABLE_TEXTURE 13 +#define MPEG4_PROFILE_STUDIO 14 +#define MPEG4_PROFILE_ADVANCED_SIMPLE 15 +#define MPEG4_PROFILE_FGS 16 + +#define MPEG4_LEVEL_0 0 +#define MPEG4_LEVEL_1 1 +#define MPEG4_LEVEL_2 2 +#define MPEG4_LEVEL_3 3 +#define MPEG4_LEVEL_4 4 +#define MPEG4_LEVEL_5 5 +#define MPEG4_LEVEL_3B 13 + +#define MPEG4_FILETYPE_RAW 0 +#define MPEG4_FILETYPE_MP4 1 +#define MPEG4_FILETYPE_AVI 2 + +#define MPEG4_CODEC_DEFAULT 0 +#define MPEG4_CODEC_DIVX5 1 + +#ifdef __cplusplus +} +#endif
\ No newline at end of file |