📄 h263_enc_frame.cpp
字号:
/* ///////////////////////////////////////////////////////////////////////
//
// 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) 2005-2007 Intel Corporation. All Rights Reserved.
//
// Description: class ippVideoEncoderH263 (encode Pics)
// Contents:
// EncodeFrame
//
// References:
// Fast ME algorithm
// IEEE Transactions on image processing, vol. 9, N. 2, Feb 2000
// "A new Diamond Search Algorithm for Fast Block-Matching Motion Estimation"
// Shan Zhu and Kai-Kuang Ma
// Fast half-pel algorithm
// V. Bhaskaran, K. Konstantinides
// "Image And Video Compression Standarts"
*/
#include <stdlib.h>
#ifdef PRINT_INFO
#include <math.h>
#endif
#include "h263_enc.hpp"
#pragma warning(disable : 981) // operands are evaluated in unspecified order
#pragma warning(disable : 279) // controlling expression is constant
//--------------------- defines to control ME process -------------------------
//#define ME_FULLSEARCH_RECT // using rectangle instead of involute search
//#define ME_USE_THRESHOLD // using threshold in ME (faster)
const Ipp32s SAD_FAVOR_ZERO = 129 /4;
const Ipp32s SAD_FAVOR_DIRECT = 129 /2;
const Ipp32s SAD_FAVOR_INTER = 512 /2; // 500 H.263 App III
const Ipp32s SAD_FAVOR_16x16 = 200; //129; // 200 H.263 App III
const Ipp32s SAD_FAVOR_PRED = - SAD_FAVOR_ZERO / 2;
const Ipp32s rangeME_8x8 = 1; // radius for search 8x8 MVs from 16x16 approximation
const Ipp32s SAD_NOTCODED_THR_LUMA = 10;
const Ipp32s SAD_NOTCODED_THR_CHROMA = 20;
const Ipp32s DEV_FAVOR_INTRA = 100;
const Ipp32s MAX_SAD = 16 * 16 * 256;
//---------------------- aux defines and functions ----------------------------
#define H263_MV_OFF_HP(dx, dy, step) \
(((dx) >> 1) + (step) * ((dy) >> 1))
#define H263_MV_ACC_HP(dx, dy) \
((((dy) & 1) << 1) + ((dx) & 1))
#define H263_MV_OFF_QP(dx, dy, step) \
(((dx) >> 2) + (step) * ((dy) >> 2))
#define H263_MV_ACC_QP(dx, dy) \
((((dy) & 3) << 2) + ((dx) & 3))
#define h263e_Copy8x4HP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \
ippiCopy8x4HP_8u_C1R(pSrc + H263_MV_OFF_HP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, H263_MV_ACC_HP((mv)->dx, (mv)->dy), rc)
#define h263e_Copy8x8HP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \
ippiCopy8x8HP_8u_C1R(pSrc + H263_MV_OFF_HP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, H263_MV_ACC_HP((mv)->dx, (mv)->dy), rc)
#define h263e_Copy16x8HP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \
ippiCopy16x8HP_8u_C1R(pSrc + H263_MV_OFF_HP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, H263_MV_ACC_HP((mv)->dx, (mv)->dy), rc)
#define h263e_Copy16x16HP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \
ippiCopy16x16HP_8u_C1R(pSrc + H263_MV_OFF_HP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, H263_MV_ACC_HP((mv)->dx, (mv)->dy), rc)
#define h263e_Copy8x8QP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \
ippiCopy8x8QP_H263_8u_C1R(pSrc + H263_MV_OFF_QP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, H263_MV_ACC_QP((mv)->dx, (mv)->dy), rc)
#define h263e_Copy16x8QP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \
ippiCopy16x8QP_H263_8u_C1R(pSrc + H263_MV_OFF_QP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, H263_MV_ACC_QP((mv)->dx, (mv)->dy), rc)
#define h263e_Copy16x16QP_8u(pSrc, srcStep, pDst, dstStep, mv, rc) \
ippiCopy16x16QP_H263_8u_C1R(pSrc + H263_MV_OFF_QP((mv)->dx, (mv)->dy, srcStep), srcStep, pDst, dstStep, H263_MV_ACC_QP((mv)->dx, (mv)->dy), rc)
#define h263e_Add8x8_16s8u(pSrcDst, pResid, srcDstStep) \
ippiAdd8x8_16s8u_C1IRS(pResid, 16, pSrcDst, srcDstStep)
inline void h263e_ComputeChromaMV(const IppMotionVector *mvLuma, IppMotionVector *mvChroma)
{
mvChroma->dx = (Ipp16s)h263e_Div2Round(mvLuma->dx);
mvChroma->dy = (Ipp16s)h263e_Div2Round(mvLuma->dy);
}
static void h263e_ComputeChroma4MV(const IppMotionVector mvLuma[4], IppMotionVector *mvChroma)
{
Ipp32s 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 = h263e_Abs(dx);
ady = h263e_Abs(dy);
cdx = h263e_cCbCrMvRound16_[adx & 15] + (adx >> 4) * 2;
cdy = h263e_cCbCrMvRound16_[ady & 15] + (ady >> 4) * 2;
mvChroma->dx = (Ipp16s)((dx >= 0) ? cdx : -cdx);
mvChroma->dy = (Ipp16s)((dy >= 0) ? cdy : -cdy);
}
static void h263e_Set8x8_8u(Ipp8u *p, Ipp32s step, Ipp8u level)
{
Ipp32u val;
val = level + (level << 8);
val += val << 16;
((Ipp32u*)p)[0] = val; ((Ipp32u*)p)[1] = val; p += step;
((Ipp32u*)p)[0] = val; ((Ipp32u*)p)[1] = val; p += step;
((Ipp32u*)p)[0] = val; ((Ipp32u*)p)[1] = val; p += step;
((Ipp32u*)p)[0] = val; ((Ipp32u*)p)[1] = val; p += step;
((Ipp32u*)p)[0] = val; ((Ipp32u*)p)[1] = val; p += step;
((Ipp32u*)p)[0] = val; ((Ipp32u*)p)[1] = val; p += step;
((Ipp32u*)p)[0] = val; ((Ipp32u*)p)[1] = val; p += step;
((Ipp32u*)p)[0] = val; ((Ipp32u*)p)[1] = val;
}
inline Ipp32s h263e_CalcMSE_16x16(Ipp8u *pSrc1, Ipp32s stepSrc1, Ipp8u *pSrc2, Ipp32s stepSrc2)
{
Ipp32s e;
ippiSqrDiff16x16_8u32s(pSrc1, stepSrc1, pSrc2, stepSrc2, IPPVC_MC_APX_FF, &e);
return e;
}
inline Ipp32s h263e_CalcMSE_8x8(Ipp8u *pSrc1, Ipp32s stepSrc1, Ipp8u *pSrc2, Ipp32s stepSrc2)
{
Ipp32s e;
ippiSSD8x8_8u32s_C1R(pSrc1, stepSrc1, pSrc2, stepSrc2, &e, IPPVC_MC_APX_FF);
return e;
}
inline Ipp16s h263e_Median(Ipp16s a, Ipp16s b, Ipp16s c)
{
if (a > b) {
Ipp16s t = a; a = b; b = t;
}
return (b <= c) ? b : (c >= a) ? c : a;
}
inline void h263e_MV_CheckRange(IppMotionVector *mvD, Ipp32s umv)
{
Ipp32s fMin, fMax;
if (!umv) {
fMin = -32;
fMax = 31;
} else {
fMin = -63;
fMax = 63;
}
if (mvD->dx < fMin)
mvD->dx = (Ipp16s)(mvD->dx + 64);
else if (mvD->dx > fMax)
mvD->dx = (Ipp16s)(mvD->dx - 64);
if (mvD->dy < fMin)
mvD->dy = (Ipp16s)(mvD->dy + 64);
else if (mvD->dy > fMax)
mvD->dy = (Ipp16s)(mvD->dy - 64);
}
#define h263e_SetPatternInter(pattern, nzCount) \
pattern = 0; \
pattern |= (nzCount[0] > 0) ? 32 : 0; \
pattern |= (nzCount[1] > 0) ? 16 : 0; \
pattern |= (nzCount[2] > 0) ? 8 : 0; \
pattern |= (nzCount[3] > 0) ? 4 : 0; \
pattern |= (nzCount[4] > 0) ? 2 : 0; \
pattern |= (nzCount[5] > 0) ? 1 : 0
#define h263e_SetPatternIntra(pattern, nzCount, thresh) \
{ \
pattern = 0; \
pattern |= (nzCount[0] > thresh) ? 32 : 0; \
pattern |= (nzCount[1] > thresh) ? 16 : 0; \
pattern |= (nzCount[2] > thresh) ? 8 : 0; \
pattern |= (nzCount[3] > thresh) ? 4 : 0; \
pattern |= (nzCount[4] > thresh) ? 2 : 0; \
pattern |= (nzCount[5] > thresh) ? 1 : 0; \
}
inline void h263e_NonZeroCount(Ipp16s *coeff, Ipp32s *nzCount)
{
Ipp32s i;
Ipp32u c;
for (i = 0; i < 6; i ++) {
ippiCountZeros8x8_16s_C1(coeff+i*64, &c);
nzCount[i] = 64 - c;
}
}
Ipp32s ippVideoEncoderH263::EncodePic(Ipp32s picType, Ipp32s nt)
{
Ipp32s sts = H263_STS_NOERR;
mFrameSkipped = 0;
// mQuantAvg = 0;
mPSNR_Y = mPSNR_U = mPSNR_V = 0;
mNumIntraMB = 0;
mVideoPicture.picture_coding_type = picType;
if (mSkipFrame) {
mFrameSkipped = 1;
sts = H263_STS_SKIPPED_FRAME;
} else {
if (mVideoPicture.picture_coding_type == H263e_PIC_TYPE_I) {
mVideoPicture.pic_quant = mQuantIPic;
EncodePicture_Header();
EncodeIPic();
} else if (mVideoPicture.picture_coding_type == H263e_PIC_TYPE_P) {
mVideoPicture.pic_quant = mQuantPPic;
EncodePicture_Header();
EncodePPic();
}
// else
// EncodeBPic();
}
if (mNumIntraMB > mSceneChangeThreshold)
return H263_STS_NOERR;
mBitsEncodedFrame = cBS.GetFullness() << 3;
mBitsEncodedTotal += mBitsEncodedFrame;
// mQuantAvg = mVideoPicture.pic_quant;
if (mRateControl)
PostFrameRC();
/*
if (mVideoPicture.plusptype && mVideoPicture.picture_coding_type != H263e_PIC_TYPE_B) {
if (mVideoPicture.picture_coding_type == H263e_PIC_TYPE_I) {
mVideoPicture.pic_rounding_type = 0; // reset rounding_type for next P-mVideoPicture
} else
mVideoPicture.pic_rounding_type ^= 1; // switch rounding_type
}
*/
return sts;
}
Ipp32s ippVideoEncoderH263::EncodeFrame(Ipp32s noMoreData)
{
Ipp32s isIPic, isPPic, isBPic, nt, sts;
Ipp32s minBufSize;
Ipp32s bufTooSmall;
if (!mIsInit)
return H263_STS_ERR_NOTINIT;
/* ??? !!!
needs to be modified when adding custom format support:
the buffer allocated in the app for small pictures can be smaller than mBPPmax which is >= 8 kB
according to the Standard
*/
if (mRateControl)
minBufSize = IPP_MIN(mBitsDesiredFrame * 2, mBPPmax);
else
minBufSize = mBPPmax;
minBufSize >>= 3; // bits -> bytes
bufTooSmall = (cBS.mBuffSize - cBS.GetFullness() < minBufSize);
// without B-frames
if (mBPicdist == 0) {
if (noMoreData)
return H263_STS_NODATA;
if (bufTooSmall)
return H263_STS_ERR_BUFOVER;
//isIPic = !(mFrameCount % mIPicdist);
isIPic = (mFrameCount - mLastIPic >= mIPicdist);
if (isIPic) {
sts = EncodePic(H263e_PIC_TYPE_I, 0);
if (sts != H263_STS_SKIPPED_FRAME)
mLastIPic = mFrameCount;
} else {
sts = EncodePic(H263e_PIC_TYPE_P, 0);
if (mNumIntraMB > mSceneChangeThreshold/* || sts == H263_STS_ERR_BUFOVER*/) {
mVideoPicture.picture_coding_type = H263e_PIC_TYPE_I;
mQuantIPic = mQuantPPic;
cBS.Reset();
sts = EncodePic(H263e_PIC_TYPE_I, 0);
mLastIPic = mFrameCount;
}
}
if (sts != H263_STS_SKIPPED_FRAME)
if (mIPicdist != 1) {
ExpandFrame(mFrameC->pY, mFrameC->pU, mFrameC->pV);
h263e_Swap(mFrameF, mFrameC);
}
#ifdef PRINT_INFO
if (mCalcPSNR)
printf("%f \n", 10.0 * log10(255.0 * 255.0 * mSourceWidth * mSourceHeight) - 10.0 * log10((double)mPSNR_Y));
#endif
mVideoPicture.temporal_reference += mVideoPicture.temporal_reference_increment;
mPictime += mVideoSequence.fixed_pic_time_increment;
mFrameCount++;
return sts;
}
// with B-frames
if (noMoreData) {
if (mNumOfFrames == -1)
mNumOfFrames = mFrameCount;
if (mFrameCount >= mNumOfFrames + mBPicdist)
return H263_STS_NODATA;
if (bufTooSmall)
return H263_STS_ERR_BUFOVER;
// last not closed B-frames are coded as P
if (mFrameCount >= mNumOfFrames + mBPicdist - (mNumOfFrames - 1) % mPPicdist) {
Ipp32s bIndx;
bIndx = mIndxBPic + 1;
if (bIndx > 2 + mBPicdist)
bIndx = 2;
mFrameC = &mFrame[bIndx];
// set mVideoPicture time
nt = (Ipp32s)(mPictime - mBPicdist * mVideoSequence.fixed_pic_time_increment - mSyncTime);
EncodePic(H263e_PIC_TYPE_P, nt);
mSyncTimeB = nt;
// reset Sync Time
if (mVideoPicture.modulo_time_base != 0)
mSyncTime = mPictime - mVideoPicture.pic_time_increment;
mIndxBPic ++;
if (mIndxBPic > 2 + mBPicdist)
mIndxBPic = 2;
ExpandFrame(mFrameC->pY, mFrameC->pU, mFrameC->pV);
h263e_Swap(mFrameF, mFrameC);
mPictime += mVideoSequence.fixed_pic_time_increment;
mFrameCount ++;
return H263_STS_NOERR;
}
}
if (bufTooSmall)
return H263_STS_ERR_BUFOVER;
isIPic = !(mFrameCount % mIPicdist);
isPPic = !(mFrameCount % mPPicdist);
isBPic = !(isIPic || isPPic);
if (!isBPic) {
mFrameC = mFrameB;
// set mVideoPicture time
nt = (Ipp32s)(mPictime - mSyncTime);
if (isIPic)
EncodePic(H263e_PIC_TYPE_I, nt);
else
EncodePic(H263e_PIC_TYPE_P, nt);
mSyncTimeB = nt;
// reset Sync Time
if (mVideoPicture.modulo_time_base != 0)
mSyncTime = mPictime - mVideoPicture.pic_time_increment;
if (mIPicdist != 1)
ExpandFrame(mFrameC->pY, mFrameC->pU, mFrameC->pV);
} else if (mFrameCount > mBPicdist) {
Ipp32s bIndx;
bIndx = mIndxBPic + 1;
if (bIndx > 2 + mBPicdist)
bIndx = 2;
mFrameC = &mFrame[bIndx];
// set mVideoPicture time
nt = mSyncTimeB - (mBPicdist - mNumBPic) * mVideoSequence.fixed_pic_time_increment;
mTRD = mBPicdist + 1;
mTRB = mNumBPic + 1;
EncodePic(H263e_PIC_TYPE_B, nt);
}
// setup next frame
if (isBPic) {
mIndxBPic++;
if (mIndxBPic > 2 + mBPicdist)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -