Merge "Initial checkin for software AVC encoder" into gingerbread

This commit is contained in:
James Dong
2010-07-13 10:59:34 -07:00
committed by Android (Google) Code Review
27 changed files with 17910 additions and 1 deletions

View File

@@ -868,17 +868,19 @@ status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) {
sp<MetaData> meta = cameraSource->getFormat();
int32_t width, height, stride, sliceHeight;
int32_t width, height, stride, sliceHeight, colorFormat;
CHECK(meta->findInt32(kKeyWidth, &width));
CHECK(meta->findInt32(kKeyHeight, &height));
CHECK(meta->findInt32(kKeyStride, &stride));
CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height);
enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
enc_meta->setInt32(kKeyStride, stride);
enc_meta->setInt32(kKeySliceHeight, sliceHeight);
enc_meta->setInt32(kKeyColorFormat, colorFormat);
if (mVideoEncoderProfile != -1) {
enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
}

View File

@@ -66,6 +66,7 @@ LOCAL_STATIC_LIBRARIES := \
libstagefright_amrwbdec \
libstagefright_amrwbenc \
libstagefright_avcdec \
libstagefright_avcenc \
libstagefright_m4vh263dec \
libstagefright_mp3dec \
libstagefright_vorbisdec \

View File

@@ -25,6 +25,7 @@
#include "include/AMRWBDecoder.h"
#include "include/AMRWBEncoder.h"
#include "include/AVCDecoder.h"
#include "include/AVCEncoder.h"
#include "include/M4vH263Decoder.h"
#include "include/MP3Decoder.h"
#include "include/VorbisDecoder.h"
@@ -81,6 +82,7 @@ FACTORY_CREATE(VPXDecoder)
FACTORY_CREATE_ENCODER(AMRNBEncoder)
FACTORY_CREATE_ENCODER(AMRWBEncoder)
FACTORY_CREATE_ENCODER(AACEncoder)
FACTORY_CREATE_ENCODER(AVCEncoder)
static sp<MediaSource> InstantiateSoftwareEncoder(
const char *name, const sp<MediaSource> &source,
@@ -94,6 +96,7 @@ static sp<MediaSource> InstantiateSoftwareEncoder(
FACTORY_REF(AMRNBEncoder)
FACTORY_REF(AMRWBEncoder)
FACTORY_REF(AACEncoder)
FACTORY_REF(AVCEncoder)
};
for (size_t i = 0;
i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
@@ -186,6 +189,7 @@ static const CodecInfo kEncoderInfo[] = {
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "AVCEncoder" },
// { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
};

View File

@@ -0,0 +1,492 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "AVCEncoder"
#include <utils/Log.h>
#include "AVCEncoder.h"
#include "avcenc_api.h"
#include "avcenc_int.h"
#include "OMX_Video.h"
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
namespace android {
inline static void ConvertYUV420SemiPlanarToYUV420Planar(
uint8_t *inyuv, uint8_t* outyuv,
int32_t width, int32_t height) {
int32_t outYsize = width * height;
uint32_t *outy = (uint32_t *) outyuv;
uint16_t *outcb = (uint16_t *) (outyuv + outYsize);
uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2));
/* Y copying */
memcpy(outy, inyuv, outYsize);
/* U & V copying */
uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
for (int32_t i = height >> 1; i > 0; --i) {
for (int32_t j = width >> 2; j > 0; --j) {
uint32_t temp = *inyuv_4++;
uint32_t tempU = temp & 0xFF;
tempU = tempU | ((temp >> 8) & 0xFF00);
uint32_t tempV = (temp >> 8) & 0xFF;
tempV = tempV | ((temp >> 16) & 0xFF00);
// Flip U and V
*outcb++ = tempV;
*outcr++ = tempU;
}
}
}
static int32_t MallocWrapper(
void *userData, int32_t size, int32_t attrs) {
return reinterpret_cast<int32_t>(malloc(size));
}
static void FreeWrapper(void *userData, int32_t ptr) {
free(reinterpret_cast<void *>(ptr));
}
static int32_t DpbAllocWrapper(void *userData,
unsigned int sizeInMbs, unsigned int numBuffers) {
AVCEncoder *encoder = static_cast<AVCEncoder *>(userData);
CHECK(encoder != NULL);
return encoder->allocOutputBuffers(sizeInMbs, numBuffers);
}
static int32_t BindFrameWrapper(
void *userData, int32_t index, uint8_t **yuv) {
AVCEncoder *encoder = static_cast<AVCEncoder *>(userData);
CHECK(encoder != NULL);
return encoder->bindOutputBuffer(index, yuv);
}
static void UnbindFrameWrapper(void *userData, int32_t index) {
AVCEncoder *encoder = static_cast<AVCEncoder *>(userData);
CHECK(encoder != NULL);
return encoder->unbindOutputBuffer(index);
}
AVCEncoder::AVCEncoder(
const sp<MediaSource>& source,
const sp<MetaData>& meta)
: mSource(source),
mMeta(meta),
mNumInputFrames(-1),
mStarted(false),
mInputBuffer(NULL),
mInputFrameData(NULL),
mGroup(NULL) {
LOGV("Construct software AVCEncoder");
mHandle = new tagAVCHandle;
memset(mHandle, 0, sizeof(tagAVCHandle));
mHandle->AVCObject = NULL;
mHandle->userData = this;
mHandle->CBAVC_DPBAlloc = DpbAllocWrapper;
mHandle->CBAVC_FrameBind = BindFrameWrapper;
mHandle->CBAVC_FrameUnbind = UnbindFrameWrapper;
mHandle->CBAVC_Malloc = MallocWrapper;
mHandle->CBAVC_Free = FreeWrapper;
mInitCheck = initCheck(meta);
}
AVCEncoder::~AVCEncoder() {
LOGV("Destruct software AVCEncoder");
if (mStarted) {
stop();
}
delete mEncParams;
delete mHandle;
}
status_t AVCEncoder::initCheck(const sp<MetaData>& meta) {
LOGV("initCheck");
CHECK(meta->findInt32(kKeyWidth, &mVideoWidth));
CHECK(meta->findInt32(kKeyHeight, &mVideoHeight));
CHECK(meta->findInt32(kKeySampleRate, &mVideoFrameRate));
CHECK(meta->findInt32(kKeyBitRate, &mVideoBitRate));
// XXX: Add more color format support
CHECK(meta->findInt32(kKeyColorFormat, &mVideoColorFormat));
if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
if (mVideoColorFormat != OMX_COLOR_FormatYUV420SemiPlanar) {
LOGE("Color format %d is not supported", mVideoColorFormat);
return BAD_VALUE;
}
// Allocate spare buffer only when color conversion is needed.
// Assume the color format is OMX_COLOR_FormatYUV420SemiPlanar.
mInputFrameData =
(uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1);
CHECK(mInputFrameData);
}
// XXX: Remove this restriction
if (mVideoWidth % 16 != 0 || mVideoHeight % 16 != 0) {
LOGE("Video frame size %dx%d must be a multiple of 16",
mVideoWidth, mVideoHeight);
return BAD_VALUE;
}
mEncParams = new tagAVCEncParam;
memset(mEncParams, 0, sizeof(mEncParams));
mEncParams->width = mVideoWidth;
mEncParams->height = mVideoHeight;
mEncParams->frame_rate = 1000 * mVideoFrameRate; // In frames/ms!
mEncParams->rate_control = AVC_ON;
mEncParams->bitrate = mVideoBitRate;
mEncParams->initQP = 0;
mEncParams->init_CBP_removal_delay = 1600;
mEncParams->CPB_size = (uint32_t) (mVideoBitRate >> 1);
mEncParams->intramb_refresh = 0;
mEncParams->auto_scd = AVC_ON;
mEncParams->out_of_band_param_set = AVC_ON;
mEncParams->poc_type = 2;
mEncParams->log2_max_poc_lsb_minus_4 = 12;
mEncParams->delta_poc_zero_flag = 0;
mEncParams->offset_poc_non_ref = 0;
mEncParams->offset_top_bottom = 0;
mEncParams->num_ref_in_cycle = 0;
mEncParams->offset_poc_ref = NULL;
mEncParams->num_ref_frame = 1;
mEncParams->num_slice_group = 1;
mEncParams->fmo_type = 0;
mEncParams->db_filter = AVC_ON;
mEncParams->disable_db_idc = 0;
mEncParams->alpha_offset = 0;
mEncParams->beta_offset = 0;
mEncParams->constrained_intra_pred = AVC_OFF;
mEncParams->data_par = AVC_OFF;
mEncParams->fullsearch = AVC_OFF;
mEncParams->search_range = 16;
mEncParams->sub_pel = AVC_OFF;
mEncParams->submb_pred = AVC_OFF;
mEncParams->rdopt_mode = AVC_OFF;
mEncParams->bidir_pred = AVC_OFF;
int32_t nMacroBlocks = ((((mVideoWidth + 15) >> 4) << 4) *
(((mVideoHeight + 15) >> 4) << 4)) >> 8;
uint32_t *sliceGroup = (uint32_t *) malloc(sizeof(uint32_t) * nMacroBlocks);
for (int ii = 0, idx = 0; ii < nMacroBlocks; ++ii) {
sliceGroup[ii] = idx++;
if (idx >= mEncParams->num_slice_group) {
idx = 0;
}
}
mEncParams->slice_group = sliceGroup;
mEncParams->use_overrun_buffer = AVC_OFF;
// Set IDR frame refresh interval
int32_t iFramesIntervalSec;
CHECK(meta->findInt32(kKeyIFramesInterval, &iFramesIntervalSec));
if (iFramesIntervalSec < 0) {
mEncParams->idr_period = -1;
} else if (iFramesIntervalSec == 0) {
mEncParams->idr_period = 1; // All I frames
} else {
mEncParams->idr_period =
(iFramesIntervalSec * mVideoFrameRate);
}
LOGV("idr_period: %d, I-frames interval: %d seconds, and frame rate: %d",
mEncParams->idr_period, iFramesIntervalSec, mVideoFrameRate);
// Set profile and level
// If profile and level setting is not correct, failure
// is reported when the encoder is initialized.
mEncParams->profile = AVC_BASELINE;
mEncParams->level = AVC_LEVEL3_2;
int32_t profile, level;
if (meta->findInt32(kKeyVideoProfile, &profile)) {
mEncParams->profile = (AVCProfile) profile;
}
if (meta->findInt32(kKeyVideoLevel, &level)) {
mEncParams->level = (AVCLevel) level;
}
mFormat = new MetaData;
mFormat->setInt32(kKeyWidth, mVideoWidth);
mFormat->setInt32(kKeyHeight, mVideoHeight);
mFormat->setInt32(kKeyBitRate, mVideoBitRate);
mFormat->setInt32(kKeySampleRate, mVideoFrameRate);
mFormat->setInt32(kKeyColorFormat, mVideoColorFormat);
mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
mFormat->setCString(kKeyDecoderComponent, "AVCEncoder");
return OK;
}
status_t AVCEncoder::start(MetaData *params) {
LOGV("start");
if (mInitCheck != OK) {
return mInitCheck;
}
if (mStarted) {
LOGW("Call start() when encoder already started");
return OK;
}
AVCEnc_Status err;
err = PVAVCEncInitialize(mHandle, mEncParams, NULL, NULL);
if (err != AVCENC_SUCCESS) {
LOGE("Failed to initialize the encoder: %d", err);
return UNKNOWN_ERROR;
}
mGroup = new MediaBufferGroup();
int32_t maxSize;
if (AVCENC_SUCCESS !=
PVAVCEncGetMaxOutputBufferSize(mHandle, &maxSize)) {
maxSize = 31584; // Magic #
}
mGroup->add_buffer(new MediaBuffer(maxSize));
mSource->start(params);
mNumInputFrames = -2; // 1st two buffers contain SPS and PPS
mStarted = true;
mSpsPpsHeaderReceived = false;
mReadyForNextFrame = true;
mIsIDRFrame = 0;
return OK;
}
status_t AVCEncoder::stop() {
LOGV("stop");
if (!mStarted) {
LOGW("Call stop() when encoder has not started");
return OK;
}
if (mInputBuffer) {
mInputBuffer->release();
mInputBuffer = NULL;
}
if (mGroup) {
delete mGroup;
mGroup = NULL;
}
if (mInputFrameData) {
delete mInputFrameData;
mInputFrameData = NULL;
}
PVAVCCleanUpEncoder(mHandle);
mSource->stop();
releaseOutputBuffers();
mStarted = false;
return OK;
}
void AVCEncoder::releaseOutputBuffers() {
LOGV("releaseOutputBuffers");
for (size_t i = 0; i < mOutputBuffers.size(); ++i) {
MediaBuffer *buffer = mOutputBuffers.editItemAt(i);
buffer->setObserver(NULL);
buffer->release();
}
mOutputBuffers.clear();
}
sp<MetaData> AVCEncoder::getFormat() {
LOGV("getFormat");
return mFormat;
}
status_t AVCEncoder::read(
MediaBuffer **out, const ReadOptions *options) {
CHECK(!options);
*out = NULL;
MediaBuffer *outputBuffer;
CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
uint8_t *outPtr = (uint8_t *) outputBuffer->data();
uint32_t dataLength = outputBuffer->size();
int32_t type;
AVCEnc_Status encoderStatus = AVCENC_SUCCESS;
// Return SPS and PPS for the first two buffers
if (!mSpsPpsHeaderReceived) {
encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
if (encoderStatus == AVCENC_WRONG_STATE) {
mSpsPpsHeaderReceived = true;
CHECK_EQ(0, mNumInputFrames); // 1st video frame is 0
} else {
switch (type) {
case AVC_NALTYPE_SPS:
case AVC_NALTYPE_PPS:
LOGV("%s received",
(type == AVC_NALTYPE_SPS)? "SPS": "PPS");
++mNumInputFrames;
outputBuffer->set_range(0, dataLength);
*out = outputBuffer;
return OK;
default:
LOGE("Nal type (%d) other than SPS/PPS is unexpected", type);
return UNKNOWN_ERROR;
}
}
}
// Get next input video frame
if (mReadyForNextFrame) {
if (mInputBuffer) {
mInputBuffer->release();
mInputBuffer = NULL;
}
status_t err = mSource->read(&mInputBuffer, options);
if (err != OK) {
LOGE("Failed to read input video frame: %d", err);
outputBuffer->release();
return err;
}
int64_t timeUs;
CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
outputBuffer->meta_data()->setInt64(kKeyTime, timeUs);
AVCFrameIO videoInput;
memset(&videoInput, 0, sizeof(videoInput));
videoInput.height = ((mVideoHeight + 15) >> 4) << 4;
videoInput.pitch = ((mVideoWidth + 15) >> 4) << 4;
videoInput.coding_timestamp = (timeUs + 500) / 1000; // in ms
uint8_t *inputData = (uint8_t *) mInputBuffer->data();
if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
CHECK(mInputFrameData);
CHECK(mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar);
ConvertYUV420SemiPlanarToYUV420Planar(
inputData, mInputFrameData, mVideoWidth, mVideoHeight);
inputData = mInputFrameData;
}
CHECK(inputData != NULL);
videoInput.YCbCr[0] = inputData;
videoInput.YCbCr[1] = videoInput.YCbCr[0] + videoInput.height * videoInput.pitch;
videoInput.YCbCr[2] = videoInput.YCbCr[1] +
((videoInput.height * videoInput.pitch) >> 2);
videoInput.disp_order = mNumInputFrames;
encoderStatus = PVAVCEncSetInput(mHandle, &videoInput);
if (encoderStatus == AVCENC_SUCCESS ||
encoderStatus == AVCENC_NEW_IDR) {
mReadyForNextFrame = false;
++mNumInputFrames;
if (encoderStatus == AVCENC_NEW_IDR) {
mIsIDRFrame = 1;
}
} else {
if (encoderStatus < AVCENC_SUCCESS) {
outputBuffer->release();
return UNKNOWN_ERROR;
} else {
outputBuffer->set_range(0, 0);
*out = outputBuffer;
return OK;
}
}
}
// Encode an input video frame
CHECK(encoderStatus == AVCENC_SUCCESS ||
encoderStatus == AVCENC_NEW_IDR);
dataLength = outputBuffer->size(); // Reset the output buffer length
encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
if (encoderStatus == AVCENC_SUCCESS) {
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
} else if (encoderStatus == AVCENC_PICTURE_READY) {
CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
if (mIsIDRFrame) {
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
mIsIDRFrame = 0;
LOGV("Output an IDR frame");
}
mReadyForNextFrame = true;
AVCFrameIO recon;
if (PVAVCEncGetRecon(mHandle, &recon) == AVCENC_SUCCESS) {
PVAVCEncReleaseRecon(mHandle, &recon);
}
} else {
dataLength = 0;
mReadyForNextFrame = true;
}
if (encoderStatus < AVCENC_SUCCESS) {
outputBuffer->release();
return UNKNOWN_ERROR;
}
outputBuffer->set_range(0, dataLength);
*out = outputBuffer;
return OK;
}
int32_t AVCEncoder::allocOutputBuffers(
unsigned int sizeInMbs, unsigned int numBuffers) {
CHECK(mOutputBuffers.isEmpty());
size_t frameSize = (sizeInMbs << 7) * 3;
for (unsigned int i = 0; i < numBuffers; ++i) {
MediaBuffer *buffer = new MediaBuffer(frameSize);
buffer->setObserver(this);
mOutputBuffers.push(buffer);
}
return 1;
}
void AVCEncoder::unbindOutputBuffer(int32_t index) {
CHECK(index >= 0);
}
int32_t AVCEncoder::bindOutputBuffer(int32_t index, uint8_t **yuv) {
CHECK(index >= 0);
CHECK(index < (int32_t) mOutputBuffers.size());
int64_t timeUs;
CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
mOutputBuffers[index]->meta_data()->setInt64(kKeyTime, timeUs);
*yuv = (uint8_t *) mOutputBuffers[index]->data();
return 1;
}
void AVCEncoder::signalBufferReturned(MediaBuffer *buffer) {
}
} // namespace android

View File

@@ -0,0 +1,34 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
AVCEncoder.cpp \
src/avcenc_api.cpp \
src/bitstream_io.cpp \
src/block.cpp \
src/findhalfpel.cpp \
src/header.cpp \
src/init.cpp \
src/intra_est.cpp \
src/motion_comp.cpp \
src/motion_est.cpp \
src/rate_control.cpp \
src/residual.cpp \
src/sad.cpp \
src/sad_halfpel.cpp \
src/slice.cpp \
src/vlc_encode.cpp
LOCAL_MODULE := libstagefright_avcenc
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/src \
$(LOCAL_PATH)/../common/include \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
$(TOP)/frameworks/base/media/libstagefright/include
LOCAL_CFLAGS := \
-DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
include $(BUILD_STATIC_LIBRARY)

View File

@@ -0,0 +1,744 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "avcenc_api.h"
#include "avcenc_lib.h"
/* ======================================================================== */
/* Function : PVAVCGetNALType() */
/* Date : 11/4/2003 */
/* Purpose : Sniff NAL type from the bitstream */
/* In/out : */
/* Return : AVCENC_SUCCESS if succeed, AVCENC_FAIL if fail. */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncGetNALType(unsigned char *bitstream, int size,
int *nal_type, int *nal_ref_idc)
{
int forbidden_zero_bit;
if (size > 0)
{
forbidden_zero_bit = bitstream[0] >> 7;
if (forbidden_zero_bit != 0)
return AVCENC_FAIL;
*nal_ref_idc = (bitstream[0] & 0x60) >> 5;
*nal_type = bitstream[0] & 0x1F;
return AVCENC_SUCCESS;
}
return AVCENC_FAIL;
}
/* ======================================================================== */
/* Function : PVAVCEncInitialize() */
/* Date : 3/18/2004 */
/* Purpose : Initialize the encoder library, allocate memory and verify */
/* the profile/level support/settings. */
/* In/out : Encoding parameters. */
/* Return : AVCENC_SUCCESS for success. */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncInitialize(AVCHandle *avcHandle, AVCEncParams *encParam,
void* extSPS, void* extPPS)
{
AVCEnc_Status status;
AVCEncObject *encvid;
AVCCommonObj *video;
uint32 *userData = (uint32*) avcHandle->userData;
int framesize;
if (avcHandle->AVCObject != NULL)
{
return AVCENC_ALREADY_INITIALIZED; /* It's already initialized, need to cleanup first */
}
/* not initialized */
/* allocate videoObject */
avcHandle->AVCObject = (void*)avcHandle->CBAVC_Malloc(userData, sizeof(AVCEncObject), DEFAULT_ATTR);
if (avcHandle->AVCObject == NULL)
{
return AVCENC_MEMORY_FAIL;
}
encvid = (AVCEncObject*) avcHandle->AVCObject;
memset(encvid, 0, sizeof(AVCEncObject)); /* reset everything */
encvid->enc_state = AVCEnc_Initializing;
encvid->avcHandle = avcHandle;
encvid->common = (AVCCommonObj*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCCommonObj), DEFAULT_ATTR);
if (encvid->common == NULL)
{
return AVCENC_MEMORY_FAIL;
}
video = encvid->common;
memset(video, 0, sizeof(AVCCommonObj));
/* allocate bitstream structure */
encvid->bitstream = (AVCEncBitstream*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCEncBitstream), DEFAULT_ATTR);
if (encvid->bitstream == NULL)
{
return AVCENC_MEMORY_FAIL;
}
encvid->bitstream->encvid = encvid; /* to point back for reallocation */
/* allocate sequence parameter set structure */
video->currSeqParams = (AVCSeqParamSet*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCSeqParamSet), DEFAULT_ATTR);
if (video->currSeqParams == NULL)
{
return AVCENC_MEMORY_FAIL;
}
memset(video->currSeqParams, 0, sizeof(AVCSeqParamSet));
/* allocate picture parameter set structure */
video->currPicParams = (AVCPicParamSet*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCPicParamSet), DEFAULT_ATTR);
if (video->currPicParams == NULL)
{
return AVCENC_MEMORY_FAIL;
}
memset(video->currPicParams, 0, sizeof(AVCPicParamSet));
/* allocate slice header structure */
video->sliceHdr = (AVCSliceHeader*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCSliceHeader), DEFAULT_ATTR);
if (video->sliceHdr == NULL)
{
return AVCENC_MEMORY_FAIL;
}
memset(video->sliceHdr, 0, sizeof(AVCSliceHeader));
/* allocate encoded picture buffer structure*/
video->decPicBuf = (AVCDecPicBuffer*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCDecPicBuffer), DEFAULT_ATTR);
if (video->decPicBuf == NULL)
{
return AVCENC_MEMORY_FAIL;
}
memset(video->decPicBuf, 0, sizeof(AVCDecPicBuffer));
/* allocate rate control structure */
encvid->rateCtrl = (AVCRateControl*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCRateControl), DEFAULT_ATTR);
if (encvid->rateCtrl == NULL)
{
return AVCENC_MEMORY_FAIL;
}
memset(encvid->rateCtrl, 0, sizeof(AVCRateControl));
/* reset frame list, not really needed */
video->currPic = NULL;
video->currFS = NULL;
encvid->currInput = NULL;
video->prevRefPic = NULL;
/* now read encParams, and allocate dimension-dependent variables */
/* such as mblock */
status = SetEncodeParam(avcHandle, encParam, extSPS, extPPS); /* initialized variables to be used in SPS*/
if (status != AVCENC_SUCCESS)
{
return status;
}
if (encParam->use_overrun_buffer == AVC_ON)
{
/* allocate overrun buffer */
encvid->oBSize = encvid->rateCtrl->cpbSize;
if (encvid->oBSize > DEFAULT_OVERRUN_BUFFER_SIZE)
{
encvid->oBSize = DEFAULT_OVERRUN_BUFFER_SIZE;
}
encvid->overrunBuffer = (uint8*) avcHandle->CBAVC_Malloc(userData, encvid->oBSize, DEFAULT_ATTR);
if (encvid->overrunBuffer == NULL)
{
return AVCENC_MEMORY_FAIL;
}
}
else
{
encvid->oBSize = 0;
encvid->overrunBuffer = NULL;
}
/* allocate frame size dependent structures */
framesize = video->FrameHeightInMbs * video->PicWidthInMbs;
video->mblock = (AVCMacroblock*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCMacroblock) * framesize, DEFAULT_ATTR);
if (video->mblock == NULL)
{
return AVCENC_MEMORY_FAIL;
}
video->MbToSliceGroupMap = (int*) avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits * 2, DEFAULT_ATTR);
if (video->MbToSliceGroupMap == NULL)
{
return AVCENC_MEMORY_FAIL;
}
encvid->mot16x16 = (AVCMV*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCMV) * framesize, DEFAULT_ATTR);
if (encvid->mot16x16 == NULL)
{
return AVCENC_MEMORY_FAIL;
}
memset(encvid->mot16x16, 0, sizeof(AVCMV)*framesize);
encvid->intraSearch = (uint8*) avcHandle->CBAVC_Malloc(userData, sizeof(uint8) * framesize, DEFAULT_ATTR);
if (encvid->intraSearch == NULL)
{
return AVCENC_MEMORY_FAIL;
}
encvid->min_cost = (int*) avcHandle->CBAVC_Malloc(userData, sizeof(int) * framesize, DEFAULT_ATTR);
if (encvid->min_cost == NULL)
{
return AVCENC_MEMORY_FAIL;
}
/* initialize motion search related memory */
if (AVCENC_SUCCESS != InitMotionSearchModule(avcHandle))
{
return AVCENC_MEMORY_FAIL;
}
if (AVCENC_SUCCESS != InitRateControlModule(avcHandle))
{
return AVCENC_MEMORY_FAIL;
}
/* intialize function pointers */
encvid->functionPointer = (AVCEncFuncPtr*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCEncFuncPtr), DEFAULT_ATTR);
if (encvid->functionPointer == NULL)
{
return AVCENC_MEMORY_FAIL;
}
encvid->functionPointer->SAD_Macroblock = &AVCSAD_Macroblock_C;
encvid->functionPointer->SAD_MB_HalfPel[0] = NULL;
encvid->functionPointer->SAD_MB_HalfPel[1] = &AVCSAD_MB_HalfPel_Cxh;
encvid->functionPointer->SAD_MB_HalfPel[2] = &AVCSAD_MB_HalfPel_Cyh;
encvid->functionPointer->SAD_MB_HalfPel[3] = &AVCSAD_MB_HalfPel_Cxhyh;
/* initialize timing control */
encvid->modTimeRef = 0; /* ALWAYS ASSUME THAT TIMESTAMP START FROM 0 !!!*/
video->prevFrameNum = 0;
encvid->prevCodedFrameNum = 0;
encvid->dispOrdPOCRef = 0;
if (encvid->outOfBandParamSet == TRUE)
{
encvid->enc_state = AVCEnc_Encoding_SPS;
}
else
{
encvid->enc_state = AVCEnc_Analyzing_Frame;
}
return AVCENC_SUCCESS;
}
/* ======================================================================== */
/* Function : PVAVCEncGetMaxOutputSize() */
/* Date : 11/29/2008 */
/* Purpose : Return max output buffer size that apps should allocate for */
/* output buffer. */
/* In/out : */
/* Return : AVCENC_SUCCESS for success. */
/* Modified : size */
/* ======================================================================== */
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncGetMaxOutputBufferSize(AVCHandle *avcHandle, int* size)
{
AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
if (encvid == NULL)
{
return AVCENC_UNINITIALIZED;
}
*size = encvid->rateCtrl->cpbSize;
return AVCENC_SUCCESS;
}
/* ======================================================================== */
/* Function : PVAVCEncSetInput() */
/* Date : 4/18/2004 */
/* Purpose : To feed an unencoded original frame to the encoder library. */
/* In/out : */
/* Return : AVCENC_SUCCESS for success. */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncSetInput(AVCHandle *avcHandle, AVCFrameIO *input)
{
AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
AVCEnc_Status status;
uint frameNum;
if (encvid == NULL)
{
return AVCENC_UNINITIALIZED;
}
if (encvid->enc_state == AVCEnc_WaitingForBuffer)
{
goto RECALL_INITFRAME;
}
else if (encvid->enc_state != AVCEnc_Analyzing_Frame)
{
return AVCENC_FAIL;
}
if (input->pitch > 0xFFFF)
{
return AVCENC_NOT_SUPPORTED; // we use 2-bytes for pitch
}
/***********************************/
/* Let's rate control decide whether to encode this frame or not */
/* Also set video->nal_unit_type, sliceHdr->slice_type, video->slice_type */
if (AVCENC_SUCCESS != RCDetermineFrameNum(encvid, rateCtrl, input->coding_timestamp, &frameNum))
{
return AVCENC_SKIPPED_PICTURE; /* not time to encode, thus skipping */
}
/* we may not need this line */
//nextFrmModTime = (uint32)((((frameNum+1)*1000)/rateCtrl->frame_rate) + modTimeRef); /* rec. time */
//encvid->nextModTime = nextFrmModTime - (encvid->frameInterval>>1) - 1; /* between current and next frame */
encvid->currInput = input;
encvid->currInput->coding_order = frameNum;
RECALL_INITFRAME:
/* initialize and analyze the frame */
status = InitFrame(encvid);
if (status == AVCENC_SUCCESS)
{
encvid->enc_state = AVCEnc_Encoding_Frame;
}
else if (status == AVCENC_NEW_IDR)
{
if (encvid->outOfBandParamSet == TRUE)
{
encvid->enc_state = AVCEnc_Encoding_Frame;
}
else // assuming that in-band paramset keeps sending new SPS and PPS.
{
encvid->enc_state = AVCEnc_Encoding_SPS;
//video->currSeqParams->seq_parameter_set_id++;
//if(video->currSeqParams->seq_parameter_set_id > 31) // range check
{
video->currSeqParams->seq_parameter_set_id = 0; // reset
}
}
video->sliceHdr->idr_pic_id++;
if (video->sliceHdr->idr_pic_id > 65535) // range check
{
video->sliceHdr->idr_pic_id = 0; // reset
}
}
/* the following logics need to be revisited */
else if (status == AVCENC_PICTURE_READY) // no buffers returned back to the encoder
{
encvid->enc_state = AVCEnc_WaitingForBuffer; // Input accepted but can't continue
// need to free up some memory before proceeding with Encode
}
return status; // return status, including the AVCENC_FAIL case and all 3 above.
}
/* ======================================================================== */
/* Function : PVAVCEncodeNAL() */
/* Date : 4/29/2004 */
/* Purpose : To encode one NAL/slice. */
/* In/out : */
/* Return : AVCENC_SUCCESS for success. */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncodeNAL(AVCHandle *avcHandle, unsigned char *buffer, unsigned int *buf_nal_size, int *nal_type)
{
AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
AVCCommonObj *video = encvid->common;
AVCEncBitstream *bitstream = encvid->bitstream;
AVCEnc_Status status;
if (encvid == NULL)
{
return AVCENC_UNINITIALIZED;
}
switch (encvid->enc_state)
{
case AVCEnc_Initializing:
return AVCENC_UNINITIALIZED;
case AVCEnc_Encoding_SPS:
/* initialized the structure */
BitstreamEncInit(bitstream, buffer, *buf_nal_size, NULL, 0);
BitstreamWriteBits(bitstream, 8, (1 << 5) | AVC_NALTYPE_SPS);
/* encode SPS */
status = EncodeSPS(encvid, bitstream);
if (status != AVCENC_SUCCESS)
{
return status;
}
/* closing the NAL with trailing bits */
status = BitstreamTrailingBits(bitstream, buf_nal_size);
if (status == AVCENC_SUCCESS)
{
encvid->enc_state = AVCEnc_Encoding_PPS;
video->currPicParams->seq_parameter_set_id = video->currSeqParams->seq_parameter_set_id;
video->currPicParams->pic_parameter_set_id++;
*nal_type = AVC_NALTYPE_SPS;
*buf_nal_size = bitstream->write_pos;
}
break;
case AVCEnc_Encoding_PPS:
/* initialized the structure */
BitstreamEncInit(bitstream, buffer, *buf_nal_size, NULL, 0);
BitstreamWriteBits(bitstream, 8, (1 << 5) | AVC_NALTYPE_PPS);
/* encode PPS */
status = EncodePPS(encvid, bitstream);
if (status != AVCENC_SUCCESS)
{
return status;
}
/* closing the NAL with trailing bits */
status = BitstreamTrailingBits(bitstream, buf_nal_size);
if (status == AVCENC_SUCCESS)
{
if (encvid->outOfBandParamSet == TRUE) // already extract PPS, SPS
{
encvid->enc_state = AVCEnc_Analyzing_Frame;
}
else // SetInput has been called before SPS and PPS.
{
encvid->enc_state = AVCEnc_Encoding_Frame;
}
*nal_type = AVC_NALTYPE_PPS;
*buf_nal_size = bitstream->write_pos;
}
break;
case AVCEnc_Encoding_Frame:
/* initialized the structure */
BitstreamEncInit(bitstream, buffer, *buf_nal_size, encvid->overrunBuffer, encvid->oBSize);
BitstreamWriteBits(bitstream, 8, (video->nal_ref_idc << 5) | (video->nal_unit_type));
/* Re-order the reference list according to the ref_pic_list_reordering() */
/* We don't have to reorder the list for the encoder here. This can only be done
after we encode this slice. We can run thru a second-pass to see if new ordering
would save more bits. Too much delay !! */
/* status = ReOrderList(video);*/
status = InitSlice(encvid);
if (status != AVCENC_SUCCESS)
{
return status;
}
/* when we have everything, we encode the slice header */
status = EncodeSliceHeader(encvid, bitstream);
if (status != AVCENC_SUCCESS)
{
return status;
}
status = AVCEncodeSlice(encvid);
video->slice_id++;
/* closing the NAL with trailing bits */
BitstreamTrailingBits(bitstream, buf_nal_size);
*buf_nal_size = bitstream->write_pos;
encvid->rateCtrl->numFrameBits += ((*buf_nal_size) << 3);
*nal_type = video->nal_unit_type;
if (status == AVCENC_PICTURE_READY)
{
status = RCUpdateFrame(encvid);
if (status == AVCENC_SKIPPED_PICTURE) /* skip current frame */
{
DPBReleaseCurrentFrame(avcHandle, video);
encvid->enc_state = AVCEnc_Analyzing_Frame;
return status;
}
/* perform loop-filtering on the entire frame */
DeblockPicture(video);
/* update the original frame array */
encvid->prevCodedFrameNum = encvid->currInput->coding_order;
/* store the encoded picture in the DPB buffer */
StorePictureInDPB(avcHandle, video);
if (video->currPic->isReference)
{
video->PrevRefFrameNum = video->sliceHdr->frame_num;
}
/* update POC related variables */
PostPOC(video);
encvid->enc_state = AVCEnc_Analyzing_Frame;
status = AVCENC_PICTURE_READY;
}
break;
default:
status = AVCENC_WRONG_STATE;
}
return status;
}
/* ======================================================================== */
/* Function : PVAVCEncGetOverrunBuffer() */
/* Purpose : To retrieve the overrun buffer. Check whether overrun buffer */
/* is used or not before returning */
/* In/out : */
/* Return : Pointer to the internal overrun buffer. */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF uint8* PVAVCEncGetOverrunBuffer(AVCHandle* avcHandle)
{
AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
AVCEncBitstream *bitstream = encvid->bitstream;
if (bitstream->overrunBuffer == bitstream->bitstreamBuffer) /* OB is used */
{
return encvid->overrunBuffer;
}
else
{
return NULL;
}
}
/* ======================================================================== */
/* Function : PVAVCEncGetRecon() */
/* Date : 4/29/2004 */
/* Purpose : To retrieve the most recently encoded frame. */
/* assume that user will make a copy if they want to hold on */
/* to it. Otherwise, it is not guaranteed to be reserved. */
/* Most applications prefer to see original frame rather than */
/* reconstructed frame. So, we are staying aware from complex */
/* buffering mechanism. If needed, can be added later. */
/* In/out : */
/* Return : AVCENC_SUCCESS for success. */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncGetRecon(AVCHandle *avcHandle, AVCFrameIO *recon)
{
AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
AVCCommonObj *video = encvid->common;
AVCFrameStore *currFS = video->currFS;
if (encvid == NULL)
{
return AVCENC_UNINITIALIZED;
}
recon->YCbCr[0] = currFS->frame.Sl;
recon->YCbCr[1] = currFS->frame.Scb;
recon->YCbCr[2] = currFS->frame.Scr;
recon->height = currFS->frame.height;
recon->pitch = currFS->frame.pitch;
recon->disp_order = currFS->PicOrderCnt;
recon->coding_order = currFS->FrameNum;
recon->id = (uint32) currFS->base_dpb; /* use the pointer as the id */
currFS->IsOutputted |= 1;
return AVCENC_SUCCESS;
}
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncReleaseRecon(AVCHandle *avcHandle, AVCFrameIO *recon)
{
OSCL_UNUSED_ARG(avcHandle);
OSCL_UNUSED_ARG(recon);
return AVCENC_SUCCESS; //for now
}
/* ======================================================================== */
/* Function : PVAVCCleanUpEncoder() */
/* Date : 4/18/2004 */
/* Purpose : To clean up memories allocated by PVAVCEncInitialize() */
/* In/out : */
/* Return : AVCENC_SUCCESS for success. */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF void PVAVCCleanUpEncoder(AVCHandle *avcHandle)
{
AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
AVCCommonObj *video;
uint32 *userData = (uint32*) avcHandle->userData;
if (encvid != NULL)
{
CleanMotionSearchModule(avcHandle);
CleanupRateControlModule(avcHandle);
if (encvid->functionPointer != NULL)
{
avcHandle->CBAVC_Free(userData, (int)encvid->functionPointer);
}
if (encvid->min_cost)
{
avcHandle->CBAVC_Free(userData, (int)encvid->min_cost);
}
if (encvid->intraSearch)
{
avcHandle->CBAVC_Free(userData, (int)encvid->intraSearch);
}
if (encvid->mot16x16)
{
avcHandle->CBAVC_Free(userData, (int)encvid->mot16x16);
}
if (encvid->rateCtrl)
{
avcHandle->CBAVC_Free(userData, (int)encvid->rateCtrl);
}
if (encvid->overrunBuffer)
{
avcHandle->CBAVC_Free(userData, (int)encvid->overrunBuffer);
}
video = encvid->common;
if (video != NULL)
{
if (video->MbToSliceGroupMap)
{
avcHandle->CBAVC_Free(userData, (int)video->MbToSliceGroupMap);
}
if (video->mblock != NULL)
{
avcHandle->CBAVC_Free(userData, (int)video->mblock);
}
if (video->decPicBuf != NULL)
{
CleanUpDPB(avcHandle, video);
avcHandle->CBAVC_Free(userData, (int)video->decPicBuf);
}
if (video->sliceHdr != NULL)
{
avcHandle->CBAVC_Free(userData, (int)video->sliceHdr);
}
if (video->currPicParams != NULL)
{
if (video->currPicParams->slice_group_id)
{
avcHandle->CBAVC_Free(userData, (int)video->currPicParams->slice_group_id);
}
avcHandle->CBAVC_Free(userData, (int)video->currPicParams);
}
if (video->currSeqParams != NULL)
{
avcHandle->CBAVC_Free(userData, (int)video->currSeqParams);
}
if (encvid->bitstream != NULL)
{
avcHandle->CBAVC_Free(userData, (int)encvid->bitstream);
}
if (video != NULL)
{
avcHandle->CBAVC_Free(userData, (int)video);
}
}
avcHandle->CBAVC_Free(userData, (int)encvid);
avcHandle->AVCObject = NULL;
}
return ;
}
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateBitRate(AVCHandle *avcHandle, uint32 bitrate)
{
OSCL_UNUSED_ARG(avcHandle);
OSCL_UNUSED_ARG(bitrate);
return AVCENC_FAIL;
}
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateFrameRate(AVCHandle *avcHandle, uint32 num, uint32 denom)
{
OSCL_UNUSED_ARG(avcHandle);
OSCL_UNUSED_ARG(num);
OSCL_UNUSED_ARG(denom);
return AVCENC_FAIL;
}
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateIDRInterval(AVCHandle *avcHandle, int IDRInterval)
{
OSCL_UNUSED_ARG(avcHandle);
OSCL_UNUSED_ARG(IDRInterval);
return AVCENC_FAIL;
}
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncIDRRequest(AVCHandle *avcHandle)
{
OSCL_UNUSED_ARG(avcHandle);
return AVCENC_FAIL;
}
OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateIMBRefresh(AVCHandle *avcHandle, int numMB)
{
OSCL_UNUSED_ARG(avcHandle);
OSCL_UNUSED_ARG(numMB);
return AVCENC_FAIL;
}
void PVAVCEncGetFrameStats(AVCHandle *avcHandle, AVCEncFrameStats *avcStats)
{
AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
AVCRateControl *rateCtrl = encvid->rateCtrl;
avcStats->avgFrameQP = GetAvgFrameQP(rateCtrl);
avcStats->numIntraMBs = encvid->numIntraMB;
return ;
}

View File

@@ -0,0 +1,320 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
/**
This file contains application function interfaces to the AVC encoder library
and necessary type defitionitions and enumerations.
@publishedAll
*/
#ifndef AVCENC_API_H_INCLUDED
#define AVCENC_API_H_INCLUDED
#ifndef AVCAPI_COMMON_H_INCLUDED
#include "avcapi_common.h"
#endif
/**
This enumeration is used for the status returned from the library interface.
*/
typedef enum
{
/**
Fail information, need to add more error code for more specific info
*/
AVCENC_TRAILINGONES_FAIL = -35,
AVCENC_SLICE_EMPTY = -34,
AVCENC_POC_FAIL = -33,
AVCENC_CONSECUTIVE_NONREF = -32,
AVCENC_CABAC_FAIL = -31,
AVCENC_PRED_WEIGHT_TAB_FAIL = -30,
AVCENC_DEC_REF_PIC_MARK_FAIL = -29,
AVCENC_SPS_FAIL = -28,
AVCENC_BITSTREAM_BUFFER_FULL = -27,
AVCENC_BITSTREAM_INIT_FAIL = -26,
AVCENC_CHROMA_QP_FAIL = -25,
AVCENC_INIT_QS_FAIL = -24,
AVCENC_INIT_QP_FAIL = -23,
AVCENC_WEIGHTED_BIPRED_FAIL = -22,
AVCENC_INVALID_INTRA_PERIOD = -21,
AVCENC_INVALID_CHANGE_RATE = -20,
AVCENC_INVALID_BETA_OFFSET = -19,
AVCENC_INVALID_ALPHA_OFFSET = -18,
AVCENC_INVALID_DEBLOCK_IDC = -17,
AVCENC_INVALID_REDUNDANT_PIC = -16,
AVCENC_INVALID_FRAMERATE = -15,
AVCENC_INVALID_NUM_SLICEGROUP = -14,
AVCENC_INVALID_POC_LSB = -13,
AVCENC_INVALID_NUM_REF = -12,
AVCENC_INVALID_FMO_TYPE = -11,
AVCENC_ENCPARAM_MEM_FAIL = -10,
AVCENC_LEVEL_NOT_SUPPORTED = -9,
AVCENC_LEVEL_FAIL = -8,
AVCENC_PROFILE_NOT_SUPPORTED = -7,
AVCENC_TOOLS_NOT_SUPPORTED = -6,
AVCENC_WRONG_STATE = -5,
AVCENC_UNINITIALIZED = -4,
AVCENC_ALREADY_INITIALIZED = -3,
AVCENC_NOT_SUPPORTED = -2,
AVCENC_MEMORY_FAIL = AVC_MEMORY_FAIL,
AVCENC_FAIL = AVC_FAIL,
/**
Generic success value
*/
AVCENC_SUCCESS = AVC_SUCCESS,
AVCENC_PICTURE_READY = 2,
AVCENC_NEW_IDR = 3, /* upon getting this, users have to call PVAVCEncodeSPS and PVAVCEncodePPS to get a new SPS and PPS*/
AVCENC_SKIPPED_PICTURE = 4 /* continuable error message */
} AVCEnc_Status;
#define MAX_NUM_SLICE_GROUP 8 /* maximum for all the profiles */
/**
This structure contains the encoding parameters.
*/
typedef struct tagAVCEncParam
{
/* if profile/level is set to zero, encoder will choose the closest one for you */
AVCProfile profile; /* profile of the bitstream to be compliant with*/
AVCLevel level; /* level of the bitstream to be compliant with*/
int width; /* width of an input frame in pixel */
int height; /* height of an input frame in pixel */
int poc_type; /* picture order count mode, 0,1 or 2 */
/* for poc_type == 0 */
uint log2_max_poc_lsb_minus_4; /* specify maximum value of POC Lsb, range 0..12*/
/* for poc_type == 1 */
uint delta_poc_zero_flag; /* delta POC always zero */
int offset_poc_non_ref; /* offset for non-reference pic */
int offset_top_bottom; /* offset between top and bottom field */
uint num_ref_in_cycle; /* number of reference frame in one cycle */
int *offset_poc_ref; /* array of offset for ref pic, dimension [num_ref_in_cycle] */
int num_ref_frame; /* number of reference frame used */
int num_slice_group; /* number of slice group */
int fmo_type; /* 0: interleave, 1: dispersed, 2: foreground with left-over
3: box-out, 4:raster scan, 5:wipe, 6:explicit */
/* for fmo_type == 0 */
uint run_length_minus1[MAX_NUM_SLICE_GROUP]; /* array of size num_slice_group, in round robin fasion */
/* fmo_type == 2*/
uint top_left[MAX_NUM_SLICE_GROUP-1]; /* array of co-ordinates of each slice_group */
uint bottom_right[MAX_NUM_SLICE_GROUP-1]; /* except the last one which is the background. */
/* fmo_type == 3,4,5 */
AVCFlag change_dir_flag; /* slice group change direction flag */
uint change_rate_minus1;
/* fmo_type == 6 */
uint *slice_group; /* array of size MBWidth*MBHeight */
AVCFlag db_filter; /* enable deblocking loop filter */
int disable_db_idc; /* 0: filter everywhere, 1: no filter, 2: no filter across slice boundary */
int alpha_offset; /* alpha offset range -6,...,6 */
int beta_offset; /* beta offset range -6,...,6 */
AVCFlag constrained_intra_pred; /* constrained intra prediction flag */
AVCFlag auto_scd; /* scene change detection on or off */
int idr_period; /* idr frame refresh rate in number of target encoded frame (no concept of actual time).*/
int intramb_refresh; /* minimum number of intra MB per frame */
AVCFlag data_par; /* enable data partitioning */
AVCFlag fullsearch; /* enable full-pel full-search mode */
int search_range; /* search range for motion vector in (-search_range,+search_range) pixels */
AVCFlag sub_pel; /* enable sub pel prediction */
AVCFlag submb_pred; /* enable sub MB partition mode */
AVCFlag rdopt_mode; /* RD optimal mode selection */
AVCFlag bidir_pred; /* enable bi-directional for B-slice, this flag forces the encoder to encode
any frame with POC less than the previously encoded frame as a B-frame.
If it's off, then such frames will remain P-frame. */
AVCFlag rate_control; /* rate control enable, on: RC on, off: constant QP */
int initQP; /* initial QP */
uint32 bitrate; /* target encoding bit rate in bits/second */
uint32 CPB_size; /* coded picture buffer in number of bits */
uint32 init_CBP_removal_delay; /* initial CBP removal delay in msec */
uint32 frame_rate; /* frame rate in the unit of frames per 1000 second */
/* note, frame rate is only needed by the rate control, AVC is timestamp agnostic. */
AVCFlag out_of_band_param_set; /* flag to set whether param sets are to be retrieved up front or not */
AVCFlag use_overrun_buffer; /* do not throw away the frame if output buffer is not big enough.
copy excess bits to the overrun buffer */
} AVCEncParams;
/**
This structure contains current frame encoding statistics for debugging purpose.
*/
typedef struct tagAVCEncFrameStats
{
int avgFrameQP; /* average frame QP */
int numIntraMBs; /* number of intra MBs */
int numFalseAlarm;
int numMisDetected;
int numDetected;
} AVCEncFrameStats;
#ifdef __cplusplus
extern "C"
{
#endif
/** THE FOLLOWINGS ARE APIS */
/**
This function initializes the encoder library. It verifies the validity of the
encoding parameters against the specified profile/level and the list of supported
tools by this library. It allocates necessary memories required to perform encoding.
For re-encoding application, if users want to setup encoder in a more precise way,
users can give the external SPS and PPS to the encoder to follow.
\param "avcHandle" "Handle to the AVC encoder library object."
\param "encParam" "Pointer to the encoding parameter structure."
\param "extSPS" "External SPS used for re-encoding purpose. NULL if not present"
\param "extPPS" "External PPS used for re-encoding purpose. NULL if not present"
\return "AVCENC_SUCCESS for success,
AVCENC_NOT_SUPPORTED for the use of unsupported tools,
AVCENC_MEMORY_FAIL for memory allocation failure,
AVCENC_FAIL for generic failure."
*/
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncInitialize(AVCHandle *avcHandle, AVCEncParams *encParam, void* extSPS, void* extPPS);
/**
Since the output buffer size is not known prior to encoding a frame, users need to
allocate big enough buffer otherwise, that frame will be dropped. This function returns
the size of the output buffer to be allocated by the users that guarantees to hold one frame.
It follows the CPB spec for a particular level. However, when the users set use_overrun_buffer
flag, this API is useless as excess output bits are saved in the overrun buffer waiting to be
copied out in small chunks, i.e. users can allocate any size of output buffer.
\param "avcHandle" "Handle to the AVC encoder library object."
\param "size" "Pointer to the size to be modified."
\return "AVCENC_SUCCESS for success, AVCENC_UNINITIALIZED when level is not known.
*/
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncGetMaxOutputBufferSize(AVCHandle *avcHandle, int* size);
/**
Users call this function to provide an input structure to the encoder library which will keep
a list of input structures it receives in case the users call this function many time before
calling PVAVCEncodeSlice. The encoder library will encode them according to the frame_num order.
Users should not modify the content of a particular frame until this frame is encoded and
returned thru CBAVCEnc_ReturnInput() callback function.
\param "avcHandle" "Handle to the AVC encoder library object."
\param "input" "Pointer to the input structure."
\return "AVCENC_SUCCESS for success,
AVCENC_FAIL if the encoder is not in the right state to take a new input frame.
AVCENC_NEW_IDR for the detection or determination of a new IDR, with this status,
the returned NAL is an SPS NAL,
AVCENC_NO_PICTURE if the input frame coding timestamp is too early, users must
get next frame or adjust the coding timestamp."
*/
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncSetInput(AVCHandle *avcHandle, AVCFrameIO *input);
/**
This function is called to encode a NAL unit which can be an SPS NAL, a PPS NAL or
a VCL (video coding layer) NAL which contains one slice of data. It could be a
fixed number of macroblocks, as specified in the encoder parameters set, or the
maximum number of macroblocks fitted into the given input argument "buffer". The
input frame is taken from the oldest unencoded input frame retrieved by users by
PVAVCEncGetInput API.
\param "avcHandle" "Handle to the AVC encoder library object."
\param "buffer" "Pointer to the output AVC bitstream buffer, the format will be EBSP,
not RBSP."
\param "buf_nal_size" "As input, the size of the buffer in bytes.
This is the physical limitation of the buffer. As output, the size of the EBSP."
\param "nal_type" "Pointer to the NAL type of the returned buffer."
\return "AVCENC_SUCCESS for success of encoding one slice,
AVCENC_PICTURE_READY for the completion of a frame encoding,
AVCENC_FAIL for failure (this should not occur, though)."
*/
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncodeNAL(AVCHandle *avcHandle, uint8 *buffer, uint *buf_nal_size, int *nal_type);
/**
This function sniffs the nal_unit_type such that users can call corresponding APIs.
This function is identical to PVAVCDecGetNALType() in the decoder.
\param "bitstream" "Pointer to the beginning of a NAL unit (start with forbidden_zero_bit, etc.)."
\param "size" "size of the bitstream (NumBytesInNALunit + 1)."
\param "nal_unit_type" "Pointer to the return value of nal unit type."
\return "AVCENC_SUCCESS if success, AVCENC_FAIL otherwise."
*/
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncGetNALType(uint8 *bitstream, int size, int *nal_type, int *nal_ref_idc);
/**
This function returns the pointer to internal overrun buffer. Users can call this to query
whether the overrun buffer has been used to encode the current NAL.
\param "avcHandle" "Pointer to the handle."
\return "Pointer to overrun buffer if it is used, otherwise, NULL."
*/
OSCL_IMPORT_REF uint8* PVAVCEncGetOverrunBuffer(AVCHandle* avcHandle);
/**
This function returns the reconstructed frame of the most recently encoded frame.
Note that this frame is not returned to the users yet. Users should only read the
content of this frame.
\param "avcHandle" "Handle to the AVC encoder library object."
\param "output" "Pointer to the input structure."
\return "AVCENC_SUCCESS for success, AVCENC_NO_PICTURE if no picture to be outputted."
*/
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncGetRecon(AVCHandle *avcHandle, AVCFrameIO *recon);
/**
This function is used to return the recontructed frame back to the AVC encoder library
in order to be re-used for encoding operation. If users want the content of it to remain
unchanged for a long time, they should make a copy of it and release the memory back to
the encoder. The encoder relies on the id element in the AVCFrameIO structure,
thus users should not change the id value.
\param "avcHandle" "Handle to the AVC decoder library object."
\param "output" "Pointer to the AVCFrameIO structure."
\return "AVCENC_SUCCESS for success, AVCENC_FAIL for fail for id not found."
*/
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncReleaseRecon(AVCHandle *avcHandle, AVCFrameIO *recon);
/**
This function performs clean up operation including memory deallocation.
The encoder will also clear the list of input structures it has not released.
This implies that users must keep track of the number of input structure they have allocated
and free them accordingly.
\param "avcHandle" "Handle to the AVC encoder library object."
*/
OSCL_IMPORT_REF void PVAVCCleanUpEncoder(AVCHandle *avcHandle);
/**
This function extracts statistics of the current frame. If the encoder has not finished
with the current frame, the result is not accurate.
\param "avcHandle" "Handle to the AVC encoder library object."
\param "avcStats" "Pointer to AVCEncFrameStats structure."
\return "void."
*/
void PVAVCEncGetFrameStats(AVCHandle *avcHandle, AVCEncFrameStats *avcStats);
/**
These functions are used for the modification of encoding parameters.
To be polished.
*/
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateBitRate(AVCHandle *avcHandle, uint32 bitrate);
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateFrameRate(AVCHandle *avcHandle, uint32 num, uint32 denom);
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateIDRInterval(AVCHandle *avcHandle, int IDRInterval);
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncIDRRequest(AVCHandle *avcHandle);
OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateIMBRefresh(AVCHandle *avcHandle, int numMB);
#ifdef __cplusplus
}
#endif
#endif /* _AVCENC_API_H_ */

View File

@@ -0,0 +1,471 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
/**
This file contains application function interfaces to the AVC encoder library
and necessary type defitionitions and enumerations.
@publishedAll
*/
#ifndef AVCENC_INT_H_INCLUDED
#define AVCENC_INT_H_INCLUDED
#ifndef AVCINT_COMMON_H_INCLUDED
#include "avcint_common.h"
#endif
#ifndef AVCENC_API_H_INCLUDED
#include "avcenc_api.h"
#endif
typedef float OsclFloat;
/* Definition for the structures below */
#define DEFAULT_ATTR 0 /* default memory attribute */
#define MAX_INPUT_FRAME 30 /* some arbitrary number, it can be much higher than this. */
#define MAX_REF_FRAME 16 /* max size of the RefPicList0 and RefPicList1 */
#define MAX_REF_PIC_LIST 33
#define MIN_QP 0
#define MAX_QP 51
#define SHIFT_QP 12
#define LAMBDA_ACCURACY_BITS 16
#define LAMBDA_FACTOR(lambda) ((int)((double)(1<<LAMBDA_ACCURACY_BITS)*lambda+0.5))
#define DISABLE_THRESHOLDING 0
// for better R-D performance
#define _LUMA_COEFF_COST_ 4 //!< threshold for luma coeffs
#define _CHROMA_COEFF_COST_ 4 //!< threshold for chroma coeffs, used to be 7
#define _LUMA_MB_COEFF_COST_ 5 //!< threshold for luma coeffs of inter Macroblocks
#define _LUMA_8x8_COEFF_COST_ 5 //!< threshold for luma coeffs of 8x8 Inter Partition
#define MAX_VALUE 999999 //!< used for start value for some variables
#define WEIGHTED_COST(factor,bits) (((factor)*(bits))>>LAMBDA_ACCURACY_BITS)
#define MV_COST(f,s,cx,cy,px,py) (WEIGHTED_COST(f,mvbits[((cx)<<(s))-px]+mvbits[((cy)<<(s))-py]))
#define MV_COST_S(f,cx,cy,px,py) (WEIGHTED_COST(f,mvbits[cx-px]+mvbits[cy-py]))
/* for sub-pel search and interpolation */
#define SUBPEL_PRED_BLK_SIZE 576 // 24x24
#define REF_CENTER 75
#define V2Q_H0Q 1
#define V0Q_H2Q 2
#define V2Q_H2Q 3
/*
#define V3Q_H0Q 1
#define V3Q_H1Q 2
#define V0Q_H1Q 3
#define V1Q_H1Q 4
#define V1Q_H0Q 5
#define V1Q_H3Q 6
#define V0Q_H3Q 7
#define V3Q_H3Q 8
#define V2Q_H3Q 9
#define V2Q_H0Q 10
#define V2Q_H1Q 11
#define V2Q_H2Q 12
#define V3Q_H2Q 13
#define V0Q_H2Q 14
#define V1Q_H2Q 15
*/
#define DEFAULT_OVERRUN_BUFFER_SIZE 1000
// associated with the above cost model
const uint8 COEFF_COST[2][16] =
{
{3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}
};
//! convert from H.263 QP to H.264 quant given by: quant=pow(2,QP/6)
const int QP2QUANT[40] =
{
1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 4, 4, 4, 5, 6,
6, 7, 8, 9, 10, 11, 13, 14,
16, 18, 20, 23, 25, 29, 32, 36,
40, 45, 51, 57, 64, 72, 81, 91
};
/**
This enumeration keeps track of the internal status of the encoder whether it is doing
something. The encoding flow follows the order in which these states are.
@publishedAll
*/
typedef enum
{
AVCEnc_Initializing = 0,
AVCEnc_Encoding_SPS,
AVCEnc_Encoding_PPS,
AVCEnc_Analyzing_Frame,
AVCEnc_WaitingForBuffer, // pending state
AVCEnc_Encoding_Frame,
} AVCEnc_State ;
/**
Bitstream structure contains bitstream related parameters such as the pointer
to the buffer, the current byte position and bit position. The content of the
bitstreamBuffer will be in EBSP format as the emulation prevention codes are
automatically inserted as the RBSP is recorded.
@publishedAll
*/
typedef struct tagEncBitstream
{
uint8 *bitstreamBuffer; /* pointer to buffer memory */
int buf_size; /* size of the buffer memory */
int write_pos; /* next position to write to bitstreamBuffer */
int count_zeros; /* count number of consecutive zero */
uint current_word; /* byte-swapped (MSB left) current word to write to buffer */
int bit_left; /* number of bit left in current_word */
uint8 *overrunBuffer; /* extra output buffer to prevent current skip due to output buffer overrun*/
int oBSize; /* size of allocated overrun buffer */
void *encvid; /* pointer to the main object */
} AVCEncBitstream;
/**
This structure is used for rate control purpose and other performance related control
variables such as, RD cost, statistics, motion search stuffs, etc.
should be in this structure.
@publishedAll
*/
typedef struct tagRDInfo
{
int QP;
int actual_bits;
OsclFloat mad;
OsclFloat R_D;
} RDInfo;
typedef struct tagMultiPass
{
/* multipass rate control data */
int target_bits; /* target bits for current frame, = rc->T */
int actual_bits; /* actual bits for current frame obtained after encoding, = rc->Rc*/
int QP; /* quantization level for current frame, = rc->Qc*/
int prev_QP; /* quantization level for previous frame */
int prev_prev_QP; /* quantization level for previous frame before last*/
OsclFloat mad; /* mad for current frame, = video->avgMAD*/
int bitrate; /* bitrate for current frame */
OsclFloat framerate; /* framerate for current frame*/
int nRe_Quantized; /* control variable for multipass encoding, */
/* 0 : first pass */
/* 1 : intermediate pass(quantization and VLC loop only) */
/* 2 : final pass(de-quantization, idct, etc) */
/* 3 : macroblock level rate control */
int encoded_frames; /* counter for all encoded frames */
int re_encoded_frames; /* counter for all multipass encoded frames*/
int re_encoded_times; /* counter for all times of multipass frame encoding */
/* Multiple frame prediction*/
RDInfo **pRDSamples; /* pRDSamples[30][32], 30->30fps, 32 -> 5 bit quantizer, 32 candidates*/
int framePos; /* specific position in previous multiple frames*/
int frameRange; /* number of overall previous multiple frames */
int samplesPerFrame[30]; /* number of samples per frame, 30->30fps */
/* Bit allocation for scene change frames and high motion frames */
OsclFloat sum_mad;
int counter_BTsrc; /* BT = Bit Transfer, bit transfer from low motion frames or less complicatedly compressed frames */
int counter_BTdst; /* BT = Bit Transfer, bit transfer to scene change frames or high motion frames or more complicatedly compressed frames */
OsclFloat sum_QP;
int diff_counter; /* diff_counter = -diff_counter_BTdst, or diff_counter_BTsrc */
/* For target bitrate or framerate update */
OsclFloat target_bits_per_frame; /* = C = bitrate/framerate */
OsclFloat target_bits_per_frame_prev; /* previous C */
OsclFloat aver_mad; /* so-far average mad could replace sum_mad */
OsclFloat aver_mad_prev; /* previous average mad */
int overlapped_win_size; /* transition period of time */
int encoded_frames_prev; /* previous encoded_frames */
} MultiPass;
typedef struct tagdataPointArray
{
int Qp;
int Rp;
OsclFloat Mp; /* for MB-based RC */
struct tagdataPointArray *next;
struct tagdataPointArray *prev;
} dataPointArray;
typedef struct tagAVCRateControl
{
/* these parameters are initialized by the users AVCEncParams */
/* bitrate-robustness tradeoff */
uint scdEnable; /* enable scene change detection */
int idrPeriod; /* IDR period in number of frames */
int intraMBRate; /* intra MB refresh rate per frame */
uint dpEnable; /* enable data partitioning */
/* quality-complexity tradeoff */
uint subPelEnable; /* enable quarter pel search */
int mvRange; /* motion vector search range in +/- pixel */
uint subMBEnable; /* enable sub MB prediction mode (4x4, 4x8, 8x4) */
uint rdOptEnable; /* enable RD-opt mode selection */
uint twoPass; /* flag for 2 pass encoding ( for future )*/
uint bidirPred; /* bi-directional prediction for B-frame. */
uint rcEnable; /* enable rate control, '1' on, '0' const QP */
int initQP; /* initial QP */
/* note the following 3 params are for HRD, these triplets can be a series
of triplets as the generalized HRD allows. SEI message must be generated in this case. */
/* We no longer have to differentiate between CBR and VBR. The users to the
AVC encoder lib will do the mapping from CBR/VBR to these parameters. */
int32 bitRate; /* target bit rate for the overall clip in bits/second*/
int32 cpbSize; /* coded picture buffer size in bytes */
int32 initDelayOffset; /* initial CBP removal delay in bits */
OsclFloat frame_rate; /* frame rate */
int srcInterval; /* source frame rate in msec */
int basicUnit; /* number of macroblocks per BU */
/* Then internal parameters for the operation */
uint first_frame; /* a flag for the first frame */
int lambda_mf; /* for example */
int totalSAD; /* SAD of current frame */
/*******************************************/
/* this part comes from MPEG4 rate control */
int alpha; /* weight for I frame */
int Rs; /*bit rate for the sequence (or segment) e.g., 24000 bits/sec */
int Rc; /*bits used for the current frame. It is the bit count obtained after encoding. */
int Rp; /*bits to be removed from the buffer per picture. */
/*? is this the average one, or just the bits coded for the previous frame */
int Rps; /*bit to be removed from buffer per src frame */
OsclFloat Ts; /*number of seconds for the sequence (or segment). e.g., 10 sec */
OsclFloat Ep;
OsclFloat Ec; /*mean absolute difference for the current frame after motion compensation.*/
/*If the macroblock is intra coded, the original spatial pixel values are summed.*/
int Qc; /*quantization level used for the current frame. */
int Nr; /*number of P frames remaining for encoding.*/
int Rr; /*number of bits remaining for encoding this sequence (or segment).*/
int Rr_Old;
int T; /*target bit to be used for the current frame.*/
int S; /*number of bits used for encoding the previous frame.*/
int Hc; /*header and motion vector bits used in the current frame. It includes all the information except to the residual information.*/
int Hp; /*header and motion vector bits used in the previous frame. It includes all the information except to the residual information.*/
int Ql; /*quantization level used in the previous frame */
int Bs; /*buffer size e.g., R/2 */
int B; /*current buffer level e.g., R/4 - start from the middle of the buffer */
OsclFloat X1;
OsclFloat X2;
OsclFloat X11;
OsclFloat M; /*safe margin for the buffer */
OsclFloat smTick; /*ratio of src versus enc frame rate */
double remnant; /*remainder frame of src/enc frame for fine frame skipping */
int timeIncRes; /* vol->timeIncrementResolution */
dataPointArray *end; /*quantization levels for the past (20) frames */
int frameNumber; /* ranging from 0 to 20 nodes*/
int w;
int Nr_Original;
int Nr_Old, Nr_Old2;
int skip_next_frame;
int Qdep; /* smooth Q adjustment */
int VBR_Enabled;
int totalFrameNumber; /* total coded frames, for debugging!!*/
char oFirstTime;
int numFrameBits; /* keep track of number of bits of the current frame */
int NumberofHeaderBits;
int NumberofTextureBits;
int numMBHeaderBits;
int numMBTextureBits;
double *MADofMB;
int32 bitsPerFrame;
/* BX rate control, something like TMN8 rate control*/
MultiPass *pMP;
int TMN_W;
int TMN_TH;
int VBV_fullness;
int max_BitVariance_num; /* the number of the maximum bit variance within the given buffer with the unit of 10% of bitrate/framerate*/
int encoded_frames; /* counter for all encoded frames */
int low_bound; /* bound for underflow detection, usually low_bound=-Bs/2, but could be changed in H.263 mode */
int VBV_fullness_offset; /* offset of VBV_fullness, usually is zero, but can be changed in H.263 mode*/
/* End BX */
} AVCRateControl;
/**
This structure is for the motion vector information. */
typedef struct tagMV
{
int x;
int y;
uint sad;
} AVCMV;
/**
This structure contains function pointers for different platform dependent implementation of
functions. */
typedef struct tagAVCEncFuncPtr
{
int (*SAD_MB_HalfPel[4])(uint8*, uint8*, int, void *);
int (*SAD_Macroblock)(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
} AVCEncFuncPtr;
/**
This structure contains information necessary for correct padding.
*/
typedef struct tagPadInfo
{
int i;
int width;
int j;
int height;
} AVCPadInfo;
#ifdef HTFM
typedef struct tagHTFM_Stat
{
int abs_dif_mad_avg;
uint countbreak;
int offsetArray[16];
int offsetRef[16];
} HTFM_Stat;
#endif
/**
This structure is the main object for AVC encoder library providing access to all
global variables. It is allocated at PVAVCInitEncoder and freed at PVAVCCleanUpEncoder.
@publishedAll
*/
typedef struct tagEncObject
{
AVCCommonObj *common;
AVCEncBitstream *bitstream; /* for current NAL */
uint8 *overrunBuffer; /* extra output buffer to prevent current skip due to output buffer overrun*/
int oBSize; /* size of allocated overrun buffer */
/* rate control */
AVCRateControl *rateCtrl; /* pointer to the rate control structure */
/* encoding operation */
AVCEnc_State enc_state; /* encoding state */
AVCFrameIO *currInput; /* pointer to the current input frame */
int currSliceGroup; /* currently encoded slice group id */
int level[24][16], run[24][16]; /* scratch memory */
int leveldc[16], rundc[16]; /* for DC component */
int levelcdc[16], runcdc[16]; /* for chroma DC component */
int numcoefcdc[2]; /* number of coefficient for chroma DC */
int numcoefdc; /* number of coefficients for DC component */
int qp_const;
int qp_const_c;
/********* intra prediction scratch memory **********************/
uint8 pred_i16[AVCNumI16PredMode][256]; /* save prediction for MB */
uint8 pred_i4[AVCNumI4PredMode][16]; /* save prediction for blk */
uint8 pred_ic[AVCNumIChromaMode][128]; /* for 2 chroma */
int mostProbableI4Mode[16]; /* in raster scan order */
/********* motion compensation related variables ****************/
AVCMV *mot16x16; /* Saved motion vectors for 16x16 block*/
AVCMV(*mot16x8)[2]; /* Saved motion vectors for 16x8 block*/
AVCMV(*mot8x16)[2]; /* Saved motion vectors for 8x16 block*/
AVCMV(*mot8x8)[4]; /* Saved motion vectors for 8x8 block*/
/********* subpel position **************************************/
uint32 subpel_pred[SUBPEL_PRED_BLK_SIZE/*<<2*/]; /* all 16 sub-pel positions */
uint8 *hpel_cand[9]; /* pointer to half-pel position */
int best_hpel_pos; /* best position */
uint8 qpel_cand[8][24*16]; /* pointer to quarter-pel position */
int best_qpel_pos;
uint8 *bilin_base[9][4]; /* pointer to 4 position at top left of bilinear quarter-pel */
/* need for intra refresh rate */
uint8 *intraSearch; /* Intra Array for MBs to be intra searched */
uint firstIntraRefreshMBIndx; /* keep track for intra refresh */
int i4_sad; /* temporary for i4 mode SAD */
int *min_cost; /* Minimum cost for the all MBs */
int lambda_mode; /* Lagrange parameter for mode selection */
int lambda_motion; /* Lagrange parameter for MV selection */
uint8 *mvbits_array; /* Table for bits spent in the cost funciton */
uint8 *mvbits; /* An offset to the above array. */
/* to speedup the SAD calculation */
void *sad_extra_info;
uint8 currYMB[256]; /* interleaved current macroblock in HTFM order */
#ifdef HTFM
int nrmlz_th[48]; /* Threshold for fast SAD calculation using HTFM */
HTFM_Stat htfm_stat; /* For statistics collection */
#endif
/* statistics */
int numIntraMB; /* keep track of number of intra MB */
/* encoding complexity control */
uint fullsearch_enable; /* flag to enable full-pel full-search */
/* misc.*/
bool outOfBandParamSet; /* flag to enable out-of-band param set */
AVCSeqParamSet extSPS; /* for external SPS */
AVCPicParamSet extPPS; /* for external PPS */
/* time control */
uint32 prevFrameNum; /* previous frame number starting from modTimeRef */
uint32 modTimeRef; /* Reference modTime update every I-Vop*/
uint32 wrapModTime; /* Offset to modTime Ref, rarely used */
uint prevProcFrameNum; /* previously processed frame number, could be skipped */
uint prevCodedFrameNum; /* previously encoded frame number */
/* POC related variables */
uint32 dispOrdPOCRef; /* reference POC is displayer order unit. */
/* Function pointers */
AVCEncFuncPtr *functionPointer; /* store pointers to platform specific functions */
/* Application control data */
AVCHandle *avcHandle;
} AVCEncObject;
#endif /*AVCENC_INT_H_INCLUDED*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,336 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "avcenc_lib.h"
#define WORD_SIZE 32
/* array for trailing bit pattern as function of number of bits */
/* the first one is unused. */
const static uint8 trailing_bits[9] = {0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
/* ======================================================================== */
/* Function : BitstreamInit() */
/* Date : 11/4/2003 */
/* Purpose : Populate bitstream structure with bitstream buffer and size */
/* it also initializes internal data */
/* In/out : */
/* Return : AVCENC_SUCCESS if successed, AVCENC_FAIL if failed. */
/* Modified : */
/* ======================================================================== */
/* |--------|--------|----~~~~~-----|---------|---------|---------|
^ ^write_pos ^buf_size
bitstreamBuffer <--------->
current_word
|-----xxxxxxxxxxxxx| = current_word 32 or 16 bits
<---->
bit_left
======================================================================== */
AVCEnc_Status BitstreamEncInit(AVCEncBitstream *stream, uint8 *buffer, int buf_size,
uint8 *overrunBuffer, int oBSize)
{
if (stream == NULL || buffer == NULL || buf_size <= 0)
{
return AVCENC_BITSTREAM_INIT_FAIL;
}
stream->bitstreamBuffer = buffer;
stream->buf_size = buf_size;
stream->write_pos = 0;
stream->count_zeros = 0;
stream->current_word = 0;
stream->bit_left = WORD_SIZE;
stream->overrunBuffer = overrunBuffer;
stream->oBSize = oBSize;
return AVCENC_SUCCESS;
}
/* ======================================================================== */
/* Function : AVCBitstreamSaveWord() */
/* Date : 3/29/2004 */
/* Purpose : Save the current_word into the buffer, byte-swap, and */
/* add emulation prevention insertion. */
/* In/out : */
/* Return : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is */
/* full. */
/* Modified : */
/* ======================================================================== */
AVCEnc_Status AVCBitstreamSaveWord(AVCEncBitstream *stream)
{
int num_bits;
uint8 *write_pnt, byte;
uint current_word;
/* check number of bytes in current_word, must always be byte-aligned!!!! */
num_bits = WORD_SIZE - stream->bit_left; /* must be multiple of 8 !!*/
if (stream->buf_size - stream->write_pos <= (num_bits >> 3) + 2) /* 2 more bytes for possible EPBS */
{
if (AVCENC_SUCCESS != AVCBitstreamUseOverrunBuffer(stream, (num_bits >> 3) + 2))
{
return AVCENC_BITSTREAM_BUFFER_FULL;
}
}
/* write word, byte-by-byte */
write_pnt = stream->bitstreamBuffer + stream->write_pos;
current_word = stream->current_word;
while (num_bits) /* no need to check stream->buf_size and stream->write_pos, taken care already */
{
num_bits -= 8;
byte = (current_word >> num_bits) & 0xFF;
if (byte != 0)
{
*write_pnt++ = byte;
stream->write_pos++;
stream->count_zeros = 0;
}
else
{
stream->count_zeros++;
*write_pnt++ = byte;
stream->write_pos++;
if (stream->count_zeros == 2)
{ /* for num_bits = 32, this can add 2 more bytes extra for EPBS */
*write_pnt++ = 0x3;
stream->write_pos++;
stream->count_zeros = 0;
}
}
}
/* reset current_word and bit_left */
stream->current_word = 0;
stream->bit_left = WORD_SIZE;
return AVCENC_SUCCESS;
}
/* ======================================================================== */
/* Function : BitstreamWriteBits() */
/* Date : 3/29/2004 */
/* Purpose : Write up to machine word. */
/* In/out : Unused bits in 'code' must be all zeros. */
/* Return : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is */
/* full. */
/* Modified : */
/* ======================================================================== */
AVCEnc_Status BitstreamWriteBits(AVCEncBitstream *stream, int nBits, uint code)
{
AVCEnc_Status status = AVCENC_SUCCESS;
int bit_left = stream->bit_left;
uint current_word = stream->current_word;
//DEBUG_LOG(userData,AVC_LOGTYPE_INFO,"BitstreamWriteBits",nBits,-1);
if (nBits > WORD_SIZE) /* has to be taken care of specially */
{
return AVCENC_FAIL; /* for now */
/* otherwise, break it down to 2 write of less than 16 bits at a time. */
}
if (nBits <= bit_left) /* more bits left in current_word */
{
stream->current_word = (current_word << nBits) | code;
stream->bit_left -= nBits;
if (stream->bit_left == 0) /* prepare for the next word */
{
status = AVCBitstreamSaveWord(stream);
return status;
}
}
else
{
stream->current_word = (current_word << bit_left) | (code >> (nBits - bit_left));
nBits -= bit_left;
stream->bit_left = 0;
status = AVCBitstreamSaveWord(stream); /* save current word */
stream->bit_left = WORD_SIZE - nBits;
stream->current_word = code; /* no extra masking for code, must be handled before saving */
}
return status;
}
/* ======================================================================== */
/* Function : BitstreamWrite1Bit() */
/* Date : 3/30/2004 */
/* Purpose : Write 1 bit */
/* In/out : Unused bits in 'code' must be all zeros. */
/* Return : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is */
/* full. */
/* Modified : */
/* ======================================================================== */
AVCEnc_Status BitstreamWrite1Bit(AVCEncBitstream *stream, uint code)
{
AVCEnc_Status status;
uint current_word = stream->current_word;
//DEBUG_LOG(userData,AVC_LOGTYPE_INFO,"BitstreamWrite1Bit",code,-1);
//if(1 <= bit_left) /* more bits left in current_word */
/* we can assume that there always be positive bit_left in the current word */
stream->current_word = (current_word << 1) | code;
stream->bit_left--;
if (stream->bit_left == 0) /* prepare for the next word */
{
status = AVCBitstreamSaveWord(stream);
return status;
}
return AVCENC_SUCCESS;
}
/* ======================================================================== */
/* Function : BitstreamTrailingBits() */
/* Date : 3/31/2004 */
/* Purpose : Add trailing bits and report the final EBSP size. */
/* In/out : */
/* Return : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is */
/* full. */
/* Modified : */
/* ======================================================================== */
AVCEnc_Status BitstreamTrailingBits(AVCEncBitstream *bitstream, uint *nal_size)
{
(void)(nal_size);
AVCEnc_Status status;
int bit_left = bitstream->bit_left;
bit_left &= 0x7; /* modulo by 8 */
if (bit_left == 0) bit_left = 8;
/* bitstream->bit_left == 0 cannot happen here since it would have been Saved already */
status = BitstreamWriteBits(bitstream, bit_left, trailing_bits[bit_left]);
if (status != AVCENC_SUCCESS)
{
return status;
}
/* if it's not saved, save it. */
//if(bitstream->bit_left<(WORD_SIZE<<3)) /* in fact, no need to check */
{
status = AVCBitstreamSaveWord(bitstream);
}
return status;
}
/* check whether it's byte-aligned */
bool byte_aligned(AVCEncBitstream *stream)
{
if (stream->bit_left % 8)
return false;
else
return true;
}
/* determine whether overrun buffer can be used or not */
AVCEnc_Status AVCBitstreamUseOverrunBuffer(AVCEncBitstream* stream, int numExtraBytes)
{
AVCEncObject *encvid = (AVCEncObject*)stream->encvid;
if (stream->overrunBuffer != NULL) // overrunBuffer is set
{
if (stream->bitstreamBuffer != stream->overrunBuffer) // not already used
{
if (stream->write_pos + numExtraBytes >= stream->oBSize)
{
stream->oBSize = stream->write_pos + numExtraBytes + 100;
stream->oBSize &= (~0x3); // make it multiple of 4
// allocate new overrun Buffer
if (encvid->overrunBuffer)
{
encvid->avcHandle->CBAVC_Free((uint32*)encvid->avcHandle->userData,
(int)encvid->overrunBuffer);
}
encvid->oBSize = stream->oBSize;
encvid->overrunBuffer = (uint8*) encvid->avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
stream->oBSize, DEFAULT_ATTR);
stream->overrunBuffer = encvid->overrunBuffer;
if (stream->overrunBuffer == NULL)
{
return AVCENC_FAIL;
}
}
// copy everything to overrun buffer and start using it.
memcpy(stream->overrunBuffer, stream->bitstreamBuffer, stream->write_pos);
stream->bitstreamBuffer = stream->overrunBuffer;
stream->buf_size = stream->oBSize;
}
else // overrun buffer is already used
{
stream->oBSize = stream->write_pos + numExtraBytes + 100;
stream->oBSize &= (~0x3); // make it multiple of 4
// allocate new overrun buffer
encvid->oBSize = stream->oBSize;
encvid->overrunBuffer = (uint8*) encvid->avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
stream->oBSize, DEFAULT_ATTR);
if (encvid->overrunBuffer == NULL)
{
return AVCENC_FAIL;
}
// copy from the old buffer to new buffer
memcpy(encvid->overrunBuffer, stream->overrunBuffer, stream->write_pos);
// free old buffer
encvid->avcHandle->CBAVC_Free((uint32*)encvid->avcHandle->userData,
(int)stream->overrunBuffer);
// assign pointer to new buffer
stream->overrunBuffer = encvid->overrunBuffer;
stream->bitstreamBuffer = stream->overrunBuffer;
stream->buf_size = stream->oBSize;
}
return AVCENC_SUCCESS;
}
else // overrunBuffer is not enable.
{
return AVCENC_FAIL;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,622 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "avcenc_lib.h"
/* 3/29/01 fast half-pel search based on neighboring guess */
/* value ranging from 0 to 4, high complexity (more accurate) to
low complexity (less accurate) */
#define HP_DISTANCE_TH 5 // 2 /* half-pel distance threshold */
#define PREF_16_VEC 129 /* 1MV bias versus 4MVs*/
const static int distance_tab[9][9] = /* [hp_guess][k] */
{
{0, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 2, 3, 4, 3, 2, 1},
{1, 0, 0, 0, 1, 2, 3, 2, 1},
{1, 2, 1, 0, 1, 2, 3, 4, 3},
{1, 2, 1, 0, 0, 0, 1, 2, 3},
{1, 4, 3, 2, 1, 0, 1, 2, 3},
{1, 2, 3, 2, 1, 0, 0, 0, 1},
{1, 2, 3, 4, 3, 2, 1, 0, 1},
{1, 0, 1, 2, 3, 2, 1, 0, 0}
};
#define CLIP_RESULT(x) if((uint)x > 0xFF){ \
x = 0xFF & (~(x>>31));}
#define CLIP_UPPER16(x) if((uint)x >= 0x20000000){ \
x = 0xFF0000 & (~(x>>31));} \
else { \
x = (x>>5)&0xFF0000; \
}
/*=====================================================================
Function: AVCFindHalfPelMB
Date: 10/31/2007
Purpose: Find half pel resolution MV surrounding the full-pel MV
=====================================================================*/
int AVCFindHalfPelMB(AVCEncObject *encvid, uint8 *cur, AVCMV *mot, uint8 *ncand,
int xpos, int ypos, int hp_guess, int cmvx, int cmvy)
{
AVCPictureData *currPic = encvid->common->currPic;
int lx = currPic->pitch;
int d, dmin, satd_min;
uint8* cand;
int lambda_motion = encvid->lambda_motion;
uint8 *mvbits = encvid->mvbits;
int mvcost;
/* list of candidate to go through for half-pel search*/
uint8 *subpel_pred = (uint8*) encvid->subpel_pred; // all 16 sub-pel positions
uint8 **hpel_cand = (uint8**) encvid->hpel_cand; /* half-pel position */
int xh[9] = {0, 0, 2, 2, 2, 0, -2, -2, -2};
int yh[9] = {0, -2, -2, 0, 2, 2, 2, 0, -2};
int xq[8] = {0, 1, 1, 1, 0, -1, -1, -1};
int yq[8] = { -1, -1, 0, 1, 1, 1, 0, -1};
int h, hmin, q, qmin;
OSCL_UNUSED_ARG(xpos);
OSCL_UNUSED_ARG(ypos);
OSCL_UNUSED_ARG(hp_guess);
GenerateHalfPelPred(subpel_pred, ncand, lx);
cur = encvid->currYMB; // pre-load current original MB
cand = hpel_cand[0];
// find cost for the current full-pel position
dmin = SATD_MB(cand, cur, 65535); // get Hadamaard transform SAD
mvcost = MV_COST_S(lambda_motion, mot->x, mot->y, cmvx, cmvy);
satd_min = dmin;
dmin += mvcost;
hmin = 0;
/* find half-pel */
for (h = 1; h < 9; h++)
{
d = SATD_MB(hpel_cand[h], cur, dmin);
mvcost = MV_COST_S(lambda_motion, mot->x + xh[h], mot->y + yh[h], cmvx, cmvy);
d += mvcost;
if (d < dmin)
{
dmin = d;
hmin = h;
satd_min = d - mvcost;
}
}
mot->sad = dmin;
mot->x += xh[hmin];
mot->y += yh[hmin];
encvid->best_hpel_pos = hmin;
/*** search for quarter-pel ****/
GenerateQuartPelPred(encvid->bilin_base[hmin], &(encvid->qpel_cand[0][0]), hmin);
encvid->best_qpel_pos = qmin = -1;
for (q = 0; q < 8; q++)
{
d = SATD_MB(encvid->qpel_cand[q], cur, dmin);
mvcost = MV_COST_S(lambda_motion, mot->x + xq[q], mot->y + yq[q], cmvx, cmvy);
d += mvcost;
if (d < dmin)
{
dmin = d;
qmin = q;
satd_min = d - mvcost;
}
}
if (qmin != -1)
{
mot->sad = dmin;
mot->x += xq[qmin];
mot->y += yq[qmin];
encvid->best_qpel_pos = qmin;
}
return satd_min;
}
/** This function generates sub-pel prediction around the full-pel candidate.
Each sub-pel position array is 20 pixel wide (for word-alignment) and 17 pixel tall. */
/** The sub-pel position is labeled in spiral manner from the center. */
void GenerateHalfPelPred(uint8* subpel_pred, uint8 *ncand, int lx)
{
/* let's do straightforward way first */
uint8 *ref;
uint8 *dst;
uint8 tmp8;
int32 tmp32;
int16 tmp_horz[18*22], *dst_16, *src_16;
register int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; // temp register
int msk;
int i, j;
/* first copy full-pel to the first array */
/* to be optimized later based on byte-offset load */
ref = ncand - 3 - lx - (lx << 1); /* move back (-3,-3) */
dst = subpel_pred;
dst -= 4; /* offset */
for (j = 0; j < 22; j++) /* 24x22 */
{
i = 6;
while (i > 0)
{
tmp32 = *ref++;
tmp8 = *ref++;
tmp32 |= (tmp8 << 8);
tmp8 = *ref++;
tmp32 |= (tmp8 << 16);
tmp8 = *ref++;
tmp32 |= (tmp8 << 24);
*((uint32*)(dst += 4)) = tmp32;
i--;
}
ref += (lx - 24);
}
/* from the first array, we do horizontal interp */
ref = subpel_pred + 2;
dst_16 = tmp_horz; /* 17 x 22 */
for (j = 4; j > 0; j--)
{
for (i = 16; i > 0; i -= 4)
{
a = ref[-2];
b = ref[-1];
c = ref[0];
d = ref[1];
e = ref[2];
f = ref[3];
*dst_16++ = a + f - 5 * (b + e) + 20 * (c + d);
a = ref[4];
*dst_16++ = b + a - 5 * (c + f) + 20 * (d + e);
b = ref[5];
*dst_16++ = c + b - 5 * (d + a) + 20 * (e + f);
c = ref[6];
*dst_16++ = d + c - 5 * (e + b) + 20 * (f + a);
ref += 4;
}
/* do the 17th column here */
d = ref[3];
*dst_16 = e + d - 5 * (f + c) + 20 * (a + b);
dst_16 += 2; /* stride for tmp_horz is 18 */
ref += 8; /* stride for ref is 24 */
if (j == 3) // move 18 lines down
{
dst_16 += 324;//18*18;
ref += 432;//18*24;
}
}
ref -= 480;//20*24;
dst_16 -= 360;//20*18;
dst = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE; /* go to the 14th array 17x18*/
for (j = 18; j > 0; j--)
{
for (i = 16; i > 0; i -= 4)
{
a = ref[-2];
b = ref[-1];
c = ref[0];
d = ref[1];
e = ref[2];
f = ref[3];
tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
*dst_16++ = tmp32;
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*dst++ = tmp32;
a = ref[4];
tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
*dst_16++ = tmp32;
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*dst++ = tmp32;
b = ref[5];
tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
*dst_16++ = tmp32;
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*dst++ = tmp32;
c = ref[6];
tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
*dst_16++ = tmp32;
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*dst++ = tmp32;
ref += 4;
}
/* do the 17th column here */
d = ref[3];
tmp32 = e + d - 5 * (f + c) + 20 * (a + b);
*dst_16 = tmp32;
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*dst = tmp32;
dst += 8; /* stride for dst is 24 */
dst_16 += 2; /* stride for tmp_horz is 18 */
ref += 8; /* stride for ref is 24 */
}
/* Do middle point filtering*/
src_16 = tmp_horz; /* 17 x 22 */
dst = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE; /* 12th array 17x17*/
dst -= 24; // offset
for (i = 0; i < 17; i++)
{
for (j = 16; j > 0; j -= 4)
{
a = *src_16;
b = *(src_16 += 18);
c = *(src_16 += 18);
d = *(src_16 += 18);
e = *(src_16 += 18);
f = *(src_16 += 18);
tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
tmp32 = (tmp32 + 512) >> 10;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32;
a = *(src_16 += 18);
tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
tmp32 = (tmp32 + 512) >> 10;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32;
b = *(src_16 += 18);
tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
tmp32 = (tmp32 + 512) >> 10;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32;
c = *(src_16 += 18);
tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
tmp32 = (tmp32 + 512) >> 10;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32;
src_16 -= (18 << 2);
}
d = src_16[90]; // 18*5
tmp32 = e + d - 5 * (f + c) + 20 * (a + b);
tmp32 = (tmp32 + 512) >> 10;
CLIP_RESULT(tmp32)
dst[24] = tmp32;
src_16 -= ((18 << 4) - 1);
dst -= ((24 << 4) - 1);
}
/* do vertical interpolation */
ref = subpel_pred + 2;
dst = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE; /* 10th array 18x17 */
dst -= 24; // offset
for (i = 2; i > 0; i--)
{
for (j = 16; j > 0; j -= 4)
{
a = *ref;
b = *(ref += 24);
c = *(ref += 24);
d = *(ref += 24);
e = *(ref += 24);
f = *(ref += 24);
tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32; // 10th
a = *(ref += 24);
tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32; // 10th
b = *(ref += 24);
tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32; // 10th
c = *(ref += 24);
tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32; // 10th
ref -= (24 << 2);
}
d = ref[120]; // 24*5
tmp32 = e + d - 5 * (f + c) + 20 * (a + b);
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
dst[24] = tmp32; // 10th
dst -= ((24 << 4) - 1);
ref -= ((24 << 4) - 1);
}
// note that using SIMD here doesn't help much, the cycle almost stays the same
// one can just use the above code and change the for(i=2 to for(i=18
for (i = 16; i > 0; i -= 4)
{
msk = 0;
for (j = 17; j > 0; j--)
{
a = *((uint32*)ref); /* load 4 bytes */
b = (a >> 8) & 0xFF00FF; /* second and fourth byte */
a &= 0xFF00FF;
c = *((uint32*)(ref + 120));
d = (c >> 8) & 0xFF00FF;
c &= 0xFF00FF;
a += c;
b += d;
e = *((uint32*)(ref + 72)); /* e, f */
f = (e >> 8) & 0xFF00FF;
e &= 0xFF00FF;
c = *((uint32*)(ref + 48)); /* c, d */
d = (c >> 8) & 0xFF00FF;
c &= 0xFF00FF;
c += e;
d += f;
a += 20 * c;
b += 20 * d;
a += 0x100010;
b += 0x100010;
e = *((uint32*)(ref += 24)); /* e, f */
f = (e >> 8) & 0xFF00FF;
e &= 0xFF00FF;
c = *((uint32*)(ref + 72)); /* c, d */
d = (c >> 8) & 0xFF00FF;
c &= 0xFF00FF;
c += e;
d += f;
a -= 5 * c;
b -= 5 * d;
c = a << 16;
d = b << 16;
CLIP_UPPER16(a)
CLIP_UPPER16(c)
CLIP_UPPER16(b)
CLIP_UPPER16(d)
a |= (c >> 16);
b |= (d >> 16);
// a>>=5;
// b>>=5;
/* clip */
// msk |= b; msk|=a;
// a &= 0xFF00FF;
// b &= 0xFF00FF;
a |= (b << 8); /* pack it back */
*((uint16*)(dst += 24)) = a & 0xFFFF; //dst is not word-aligned.
*((uint16*)(dst + 2)) = a >> 16;
}
dst -= 404; // 24*17-4
ref -= 404;
/* if(msk & 0xFF00FF00) // need clipping
{
VertInterpWClip(dst,ref); // re-do 4 column with clip
}*/
}
return ;
}
void VertInterpWClip(uint8 *dst, uint8 *ref)
{
int i, j;
int a, b, c, d, e, f;
int32 tmp32;
dst -= 4;
ref -= 4;
for (i = 4; i > 0; i--)
{
for (j = 16; j > 0; j -= 4)
{
a = *ref;
b = *(ref += 24);
c = *(ref += 24);
d = *(ref += 24);
e = *(ref += 24);
f = *(ref += 24);
tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32; // 10th
a = *(ref += 24);
tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32; // 10th
b = *(ref += 24);
tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32; // 10th
c = *(ref += 24);
tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
*(dst += 24) = tmp32; // 10th
ref -= (24 << 2);
}
d = ref[120]; // 24*5
tmp32 = e + d - 5 * (f + c) + 20 * (a + b);
tmp32 = (tmp32 + 16) >> 5;
CLIP_RESULT(tmp32)
dst[24] = tmp32; // 10th
dst -= ((24 << 4) - 1);
ref -= ((24 << 4) - 1);
}
return ;
}
void GenerateQuartPelPred(uint8 **bilin_base, uint8 *qpel_cand, int hpel_pos)
{
// for even value of hpel_pos, start with pattern 1, otherwise, start with pattern 2
int i, j;
uint8 *c1 = qpel_cand;
uint8 *tl = bilin_base[0];
uint8 *tr = bilin_base[1];
uint8 *bl = bilin_base[2];
uint8 *br = bilin_base[3];
int a, b, c, d;
int offset = 1 - (384 * 7);
if (!(hpel_pos&1)) // diamond pattern
{
j = 16;
while (j--)
{
i = 16;
while (i--)
{
d = tr[24];
a = *tr++;
b = bl[1];
c = *br++;
*c1 = (c + a + 1) >> 1;
*(c1 += 384) = (b + a + 1) >> 1; /* c2 */
*(c1 += 384) = (b + c + 1) >> 1; /* c3 */
*(c1 += 384) = (b + d + 1) >> 1; /* c4 */
b = *bl++;
*(c1 += 384) = (c + d + 1) >> 1; /* c5 */
*(c1 += 384) = (b + d + 1) >> 1; /* c6 */
*(c1 += 384) = (b + c + 1) >> 1; /* c7 */
*(c1 += 384) = (b + a + 1) >> 1; /* c8 */
c1 += offset;
}
// advance to the next line, pitch is 24
tl += 8;
tr += 8;
bl += 8;
br += 8;
c1 += 8;
}
}
else // star pattern
{
j = 16;
while (j--)
{
i = 16;
while (i--)
{
a = *br++;
b = *tr++;
c = tl[1];
*c1 = (a + b + 1) >> 1;
b = bl[1];
*(c1 += 384) = (a + c + 1) >> 1; /* c2 */
c = tl[25];
*(c1 += 384) = (a + b + 1) >> 1; /* c3 */
b = tr[23];
*(c1 += 384) = (a + c + 1) >> 1; /* c4 */
c = tl[24];
*(c1 += 384) = (a + b + 1) >> 1; /* c5 */
b = *bl++;
*(c1 += 384) = (a + c + 1) >> 1; /* c6 */
c = *tl++;
*(c1 += 384) = (a + b + 1) >> 1; /* c7 */
*(c1 += 384) = (a + c + 1) >> 1; /* c8 */
c1 += offset;
}
// advance to the next line, pitch is 24
tl += 8;
tr += 8;
bl += 8;
br += 8;
c1 += 8;
}
}
return ;
}
/* assuming cand always has a pitch of 24 */
int SATD_MB(uint8 *cand, uint8 *cur, int dmin)
{
int cost;
dmin = (dmin << 16) | 24;
cost = AVCSAD_Macroblock_C(cand, cur, dmin, NULL);
return cost;
}

View File

@@ -0,0 +1,917 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "avcenc_lib.h"
#include "avcenc_api.h"
/** see subclause 7.4.2.1 */
/* no need for checking the valid range , already done in SetEncodeParam(),
if we have to send another SPS, the ranges should be verified first before
users call PVAVCEncodeSPS() */
AVCEnc_Status EncodeSPS(AVCEncObject *encvid, AVCEncBitstream *stream)
{
AVCCommonObj *video = encvid->common;
AVCSeqParamSet *seqParam = video->currSeqParams;
AVCVUIParams *vui = &(seqParam->vui_parameters);
int i;
AVCEnc_Status status = AVCENC_SUCCESS;
//DEBUG_LOG(userData,AVC_LOGTYPE_INFO,"EncodeSPS",-1,-1);
status = BitstreamWriteBits(stream, 8, seqParam->profile_idc);
status = BitstreamWrite1Bit(stream, seqParam->constrained_set0_flag);
status = BitstreamWrite1Bit(stream, seqParam->constrained_set1_flag);
status = BitstreamWrite1Bit(stream, seqParam->constrained_set2_flag);
status = BitstreamWrite1Bit(stream, seqParam->constrained_set3_flag);
status = BitstreamWriteBits(stream, 4, 0); /* forbidden zero bits */
if (status != AVCENC_SUCCESS) /* we can check after each write also */
{
return status;
}
status = BitstreamWriteBits(stream, 8, seqParam->level_idc);
status = ue_v(stream, seqParam->seq_parameter_set_id);
status = ue_v(stream, seqParam->log2_max_frame_num_minus4);
status = ue_v(stream, seqParam->pic_order_cnt_type);
if (status != AVCENC_SUCCESS)
{
return status;
}
if (seqParam->pic_order_cnt_type == 0)
{
status = ue_v(stream, seqParam->log2_max_pic_order_cnt_lsb_minus4);
}
else if (seqParam->pic_order_cnt_type == 1)
{
status = BitstreamWrite1Bit(stream, seqParam->delta_pic_order_always_zero_flag);
status = se_v(stream, seqParam->offset_for_non_ref_pic); /* upto 32 bits */
status = se_v(stream, seqParam->offset_for_top_to_bottom_field); /* upto 32 bits */
status = ue_v(stream, seqParam->num_ref_frames_in_pic_order_cnt_cycle);
for (i = 0; i < (int)(seqParam->num_ref_frames_in_pic_order_cnt_cycle); i++)
{
status = se_v(stream, seqParam->offset_for_ref_frame[i]); /* upto 32 bits */
}
}
if (status != AVCENC_SUCCESS)
{
return status;
}
status = ue_v(stream, seqParam->num_ref_frames);
status = BitstreamWrite1Bit(stream, seqParam->gaps_in_frame_num_value_allowed_flag);
status = ue_v(stream, seqParam->pic_width_in_mbs_minus1);
status = ue_v(stream, seqParam->pic_height_in_map_units_minus1);
status = BitstreamWrite1Bit(stream, seqParam->frame_mbs_only_flag);
if (status != AVCENC_SUCCESS)
{
return status;
}
/* if frame_mbs_only_flag is 0, then write, mb_adaptive_frame_field_frame here */
status = BitstreamWrite1Bit(stream, seqParam->direct_8x8_inference_flag);
status = BitstreamWrite1Bit(stream, seqParam->frame_cropping_flag);
if (seqParam->frame_cropping_flag)
{
status = ue_v(stream, seqParam->frame_crop_left_offset);
status = ue_v(stream, seqParam->frame_crop_right_offset);
status = ue_v(stream, seqParam->frame_crop_top_offset);
status = ue_v(stream, seqParam->frame_crop_bottom_offset);
}
if (status != AVCENC_SUCCESS)
{
return status;
}
status = BitstreamWrite1Bit(stream, seqParam->vui_parameters_present_flag);
if (seqParam->vui_parameters_present_flag)
{
/* not supported */
//return AVCENC_SPS_FAIL;
EncodeVUI(stream, vui);
}
return status;
}
void EncodeVUI(AVCEncBitstream* stream, AVCVUIParams* vui)
{
int temp;
temp = vui->aspect_ratio_info_present_flag;
BitstreamWrite1Bit(stream, temp);
if (temp)
{
BitstreamWriteBits(stream, 8, vui->aspect_ratio_idc);
if (vui->aspect_ratio_idc == 255)
{
BitstreamWriteBits(stream, 16, vui->sar_width);
BitstreamWriteBits(stream, 16, vui->sar_height);
}
}
temp = vui->overscan_info_present_flag;
BitstreamWrite1Bit(stream, temp);
if (temp)
{
BitstreamWrite1Bit(stream, vui->overscan_appropriate_flag);
}
temp = vui->video_signal_type_present_flag;
BitstreamWrite1Bit(stream, temp);
if (temp)
{
BitstreamWriteBits(stream, 3, vui->video_format);
BitstreamWrite1Bit(stream, vui->video_full_range_flag);
temp = vui->colour_description_present_flag;
BitstreamWrite1Bit(stream, temp);
if (temp)
{
BitstreamWriteBits(stream, 8, vui->colour_primaries);
BitstreamWriteBits(stream, 8, vui->transfer_characteristics);
BitstreamWriteBits(stream, 8, vui->matrix_coefficients);
}
}
temp = vui->chroma_location_info_present_flag;
BitstreamWrite1Bit(stream, temp);
if (temp)
{
ue_v(stream, vui->chroma_sample_loc_type_top_field);
ue_v(stream, vui->chroma_sample_loc_type_bottom_field);
}
temp = vui->timing_info_present_flag;
BitstreamWrite1Bit(stream, temp);
if (temp)
{
BitstreamWriteBits(stream, 32, vui->num_units_in_tick);
BitstreamWriteBits(stream, 32, vui->time_scale);
BitstreamWrite1Bit(stream, vui->fixed_frame_rate_flag);
}
temp = vui->nal_hrd_parameters_present_flag;
BitstreamWrite1Bit(stream, temp);
if (temp)
{
EncodeHRD(stream, &(vui->nal_hrd_parameters));
}
temp = vui->vcl_hrd_parameters_present_flag;
BitstreamWrite1Bit(stream, temp);
if (temp)
{
EncodeHRD(stream, &(vui->vcl_hrd_parameters));
}
if (vui->nal_hrd_parameters_present_flag || vui->vcl_hrd_parameters_present_flag)
{
BitstreamWrite1Bit(stream, vui->low_delay_hrd_flag);
}
BitstreamWrite1Bit(stream, vui->pic_struct_present_flag);
temp = vui->bitstream_restriction_flag;
BitstreamWrite1Bit(stream, temp);
if (temp)
{
BitstreamWrite1Bit(stream, vui->motion_vectors_over_pic_boundaries_flag);
ue_v(stream, vui->max_bytes_per_pic_denom);
ue_v(stream, vui->max_bits_per_mb_denom);
ue_v(stream, vui->log2_max_mv_length_horizontal);
ue_v(stream, vui->log2_max_mv_length_vertical);
ue_v(stream, vui->max_dec_frame_reordering);
ue_v(stream, vui->max_dec_frame_buffering);
}
return ;
}
void EncodeHRD(AVCEncBitstream* stream, AVCHRDParams* hrd)
{
int i;
ue_v(stream, hrd->cpb_cnt_minus1);
BitstreamWriteBits(stream, 4, hrd->bit_rate_scale);
BitstreamWriteBits(stream, 4, hrd->cpb_size_scale);
for (i = 0; i <= (int)hrd->cpb_cnt_minus1; i++)
{
ue_v(stream, hrd->bit_rate_value_minus1[i]);
ue_v(stream, hrd->cpb_size_value_minus1[i]);
ue_v(stream, hrd->cbr_flag[i]);
}
BitstreamWriteBits(stream, 5, hrd->initial_cpb_removal_delay_length_minus1);
BitstreamWriteBits(stream, 5, hrd->cpb_removal_delay_length_minus1);
BitstreamWriteBits(stream, 5, hrd->dpb_output_delay_length_minus1);
BitstreamWriteBits(stream, 5, hrd->time_offset_length);
return ;
}
/** see subclause 7.4.2.2 */
/* no need for checking the valid range , already done in SetEncodeParam().
If we have to send another SPS, the ranges should be verified first before
users call PVAVCEncodeSPS()*/
AVCEnc_Status EncodePPS(AVCEncObject *encvid, AVCEncBitstream *stream)
{
AVCCommonObj *video = encvid->common;
AVCEnc_Status status = AVCENC_SUCCESS;
AVCPicParamSet *picParam = video->currPicParams;
int i, iGroup, numBits;
uint temp;
status = ue_v(stream, picParam->pic_parameter_set_id);
status = ue_v(stream, picParam->seq_parameter_set_id);
status = BitstreamWrite1Bit(stream, picParam->entropy_coding_mode_flag);
status = BitstreamWrite1Bit(stream, picParam->pic_order_present_flag);
if (status != AVCENC_SUCCESS)
{
return status;
}
status = ue_v(stream, picParam->num_slice_groups_minus1);
if (picParam->num_slice_groups_minus1 > 0)
{
status = ue_v(stream, picParam->slice_group_map_type);
if (picParam->slice_group_map_type == 0)
{
for (iGroup = 0; iGroup <= (int)picParam->num_slice_groups_minus1; iGroup++)
{
status = ue_v(stream, picParam->run_length_minus1[iGroup]);
}
}
else if (picParam->slice_group_map_type == 2)
{
for (iGroup = 0; iGroup < (int)picParam->num_slice_groups_minus1; iGroup++)
{
status = ue_v(stream, picParam->top_left[iGroup]);
status = ue_v(stream, picParam->bottom_right[iGroup]);
}
}
else if (picParam->slice_group_map_type == 3 ||
picParam->slice_group_map_type == 4 ||
picParam->slice_group_map_type == 5)
{
status = BitstreamWrite1Bit(stream, picParam->slice_group_change_direction_flag);
status = ue_v(stream, picParam->slice_group_change_rate_minus1);
}
else /*if(picParam->slice_group_map_type == 6)*/
{
status = ue_v(stream, picParam->pic_size_in_map_units_minus1);
numBits = 0;/* ceil(log2(num_slice_groups_minus1+1)) bits */
i = picParam->num_slice_groups_minus1;
while (i > 0)
{
numBits++;
i >>= 1;
}
for (i = 0; i <= (int)picParam->pic_size_in_map_units_minus1; i++)
{
status = BitstreamWriteBits(stream, numBits, picParam->slice_group_id[i]);
}
}
}
if (status != AVCENC_SUCCESS)
{
return status;
}
status = ue_v(stream, picParam->num_ref_idx_l0_active_minus1);
status = ue_v(stream, picParam->num_ref_idx_l1_active_minus1);
status = BitstreamWrite1Bit(stream, picParam->weighted_pred_flag);
status = BitstreamWriteBits(stream, 2, picParam->weighted_bipred_idc);
if (status != AVCENC_SUCCESS)
{
return status;
}
status = se_v(stream, picParam->pic_init_qp_minus26);
status = se_v(stream, picParam->pic_init_qs_minus26);
status = se_v(stream, picParam->chroma_qp_index_offset);
temp = picParam->deblocking_filter_control_present_flag << 2;
temp |= (picParam->constrained_intra_pred_flag << 1);
temp |= picParam->redundant_pic_cnt_present_flag;
status = BitstreamWriteBits(stream, 3, temp);
return status;
}
/** see subclause 7.4.3 */
AVCEnc_Status EncodeSliceHeader(AVCEncObject *encvid, AVCEncBitstream *stream)
{
AVCCommonObj *video = encvid->common;
AVCSliceHeader *sliceHdr = video->sliceHdr;
AVCPicParamSet *currPPS = video->currPicParams;
AVCSeqParamSet *currSPS = video->currSeqParams;
AVCEnc_Status status = AVCENC_SUCCESS;
int slice_type, temp, i;
int num_bits;
num_bits = (stream->write_pos << 3) - stream->bit_left;
status = ue_v(stream, sliceHdr->first_mb_in_slice);
slice_type = video->slice_type;
if (video->mbNum == 0) /* first mb in frame */
{
status = ue_v(stream, sliceHdr->slice_type);
}
else
{
status = ue_v(stream, slice_type);
}
status = ue_v(stream, sliceHdr->pic_parameter_set_id);
status = BitstreamWriteBits(stream, currSPS->log2_max_frame_num_minus4 + 4, sliceHdr->frame_num);
if (status != AVCENC_SUCCESS)
{
return status;
}
/* if frame_mbs_only_flag is 0, encode field_pic_flag, bottom_field_flag here */
if (video->nal_unit_type == AVC_NALTYPE_IDR)
{
status = ue_v(stream, sliceHdr->idr_pic_id);
}
if (currSPS->pic_order_cnt_type == 0)
{
status = BitstreamWriteBits(stream, currSPS->log2_max_pic_order_cnt_lsb_minus4 + 4,
sliceHdr->pic_order_cnt_lsb);
if (currPPS->pic_order_present_flag && !sliceHdr->field_pic_flag)
{
status = se_v(stream, sliceHdr->delta_pic_order_cnt_bottom); /* 32 bits */
}
}
if (currSPS->pic_order_cnt_type == 1 && !currSPS->delta_pic_order_always_zero_flag)
{
status = se_v(stream, sliceHdr->delta_pic_order_cnt[0]); /* 32 bits */
if (currPPS->pic_order_present_flag && !sliceHdr->field_pic_flag)
{
status = se_v(stream, sliceHdr->delta_pic_order_cnt[1]); /* 32 bits */
}
}
if (currPPS->redundant_pic_cnt_present_flag)
{
status = ue_v(stream, sliceHdr->redundant_pic_cnt);
}
if (slice_type == AVC_B_SLICE)
{
status = BitstreamWrite1Bit(stream, sliceHdr->direct_spatial_mv_pred_flag);
}
if (status != AVCENC_SUCCESS)
{
return status;
}
if (slice_type == AVC_P_SLICE || slice_type == AVC_SP_SLICE || slice_type == AVC_B_SLICE)
{
status = BitstreamWrite1Bit(stream, sliceHdr->num_ref_idx_active_override_flag);
if (sliceHdr->num_ref_idx_active_override_flag)
{
/* we shouldn't enter this part at all */
status = ue_v(stream, sliceHdr->num_ref_idx_l0_active_minus1);
if (slice_type == AVC_B_SLICE)
{
status = ue_v(stream, sliceHdr->num_ref_idx_l1_active_minus1);
}
}
}
if (status != AVCENC_SUCCESS)
{
return status;
}
/* ref_pic_list_reordering() */
status = ref_pic_list_reordering(video, stream, sliceHdr, slice_type);
if (status != AVCENC_SUCCESS)
{
return status;
}
if ((currPPS->weighted_pred_flag && (slice_type == AVC_P_SLICE || slice_type == AVC_SP_SLICE)) ||
(currPPS->weighted_bipred_idc == 1 && slice_type == AVC_B_SLICE))
{
// pred_weight_table(); // not supported !!
return AVCENC_PRED_WEIGHT_TAB_FAIL;
}
if (video->nal_ref_idc != 0)
{
status = dec_ref_pic_marking(video, stream, sliceHdr);
if (status != AVCENC_SUCCESS)
{
return status;
}
}
if (currPPS->entropy_coding_mode_flag && slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE)
{
return AVCENC_CABAC_FAIL;
/* ue_v(stream,&(sliceHdr->cabac_init_idc));
if(sliceHdr->cabac_init_idc > 2){
// not supported !!!!
}*/
}
status = se_v(stream, sliceHdr->slice_qp_delta);
if (status != AVCENC_SUCCESS)
{
return status;
}
if (slice_type == AVC_SP_SLICE || slice_type == AVC_SI_SLICE)
{
if (slice_type == AVC_SP_SLICE)
{
status = BitstreamWrite1Bit(stream, sliceHdr->sp_for_switch_flag);
/* if sp_for_switch_flag is 0, P macroblocks in SP slice is decoded using
SP decoding process for non-switching pictures in 8.6.1 */
/* else, P macroblocks in SP slice is decoded using SP and SI decoding
process for switching picture in 8.6.2 */
}
status = se_v(stream, sliceHdr->slice_qs_delta);
if (status != AVCENC_SUCCESS)
{
return status;
}
}
if (currPPS->deblocking_filter_control_present_flag)
{
status = ue_v(stream, sliceHdr->disable_deblocking_filter_idc);
if (sliceHdr->disable_deblocking_filter_idc != 1)
{
status = se_v(stream, sliceHdr->slice_alpha_c0_offset_div2);
status = se_v(stream, sliceHdr->slice_beta_offset_div_2);
}
if (status != AVCENC_SUCCESS)
{
return status;
}
}
if (currPPS->num_slice_groups_minus1 > 0 && currPPS->slice_group_map_type >= 3
&& currPPS->slice_group_map_type <= 5)
{
/* Ceil(Log2(PicSizeInMapUnits/(float)SliceGroupChangeRate + 1)) */
temp = video->PicSizeInMapUnits / video->SliceGroupChangeRate;
if (video->PicSizeInMapUnits % video->SliceGroupChangeRate)
{
temp++;
}
i = 0;
while (temp > 1)
{
temp >>= 1;
i++;
}
BitstreamWriteBits(stream, i, sliceHdr->slice_group_change_cycle);
}
encvid->rateCtrl->NumberofHeaderBits += (stream->write_pos << 3) - stream->bit_left - num_bits;
return AVCENC_SUCCESS;
}
/** see subclause 7.4.3.1 */
AVCEnc_Status ref_pic_list_reordering(AVCCommonObj *video, AVCEncBitstream *stream, AVCSliceHeader *sliceHdr, int slice_type)
{
(void)(video);
int i;
AVCEnc_Status status = AVCENC_SUCCESS;
if (slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE)
{
status = BitstreamWrite1Bit(stream, sliceHdr->ref_pic_list_reordering_flag_l0);
if (sliceHdr->ref_pic_list_reordering_flag_l0)
{
i = 0;
do
{
status = ue_v(stream, sliceHdr->reordering_of_pic_nums_idc_l0[i]);
if (sliceHdr->reordering_of_pic_nums_idc_l0[i] == 0 ||
sliceHdr->reordering_of_pic_nums_idc_l0[i] == 1)
{
status = ue_v(stream, sliceHdr->abs_diff_pic_num_minus1_l0[i]);
/* this check should be in InitSlice(), if we ever use it */
/*if(sliceHdr->reordering_of_pic_nums_idc_l0[i] == 0 &&
sliceHdr->abs_diff_pic_num_minus1_l0[i] > video->MaxPicNum/2 -1)
{
return AVCENC_REF_PIC_REORDER_FAIL; // out of range
}
if(sliceHdr->reordering_of_pic_nums_idc_l0[i] == 1 &&
sliceHdr->abs_diff_pic_num_minus1_l0[i] > video->MaxPicNum/2 -2)
{
return AVCENC_REF_PIC_REORDER_FAIL; // out of range
}*/
}
else if (sliceHdr->reordering_of_pic_nums_idc_l0[i] == 2)
{
status = ue_v(stream, sliceHdr->long_term_pic_num_l0[i]);
}
i++;
}
while (sliceHdr->reordering_of_pic_nums_idc_l0[i] != 3
&& i <= (int)sliceHdr->num_ref_idx_l0_active_minus1 + 1) ;
}
}
if (slice_type == AVC_B_SLICE)
{
status = BitstreamWrite1Bit(stream, sliceHdr->ref_pic_list_reordering_flag_l1);
if (sliceHdr->ref_pic_list_reordering_flag_l1)
{
i = 0;
do
{
status = ue_v(stream, sliceHdr->reordering_of_pic_nums_idc_l1[i]);
if (sliceHdr->reordering_of_pic_nums_idc_l1[i] == 0 ||
sliceHdr->reordering_of_pic_nums_idc_l1[i] == 1)
{
status = ue_v(stream, sliceHdr->abs_diff_pic_num_minus1_l1[i]);
/* This check should be in InitSlice() if we ever use it
if(sliceHdr->reordering_of_pic_nums_idc_l1[i] == 0 &&
sliceHdr->abs_diff_pic_num_minus1_l1[i] > video->MaxPicNum/2 -1)
{
return AVCENC_REF_PIC_REORDER_FAIL; // out of range
}
if(sliceHdr->reordering_of_pic_nums_idc_l1[i] == 1 &&
sliceHdr->abs_diff_pic_num_minus1_l1[i] > video->MaxPicNum/2 -2)
{
return AVCENC_REF_PIC_REORDER_FAIL; // out of range
}*/
}
else if (sliceHdr->reordering_of_pic_nums_idc_l1[i] == 2)
{
status = ue_v(stream, sliceHdr->long_term_pic_num_l1[i]);
}
i++;
}
while (sliceHdr->reordering_of_pic_nums_idc_l1[i] != 3
&& i <= (int)sliceHdr->num_ref_idx_l1_active_minus1 + 1) ;
}
}
return status;
}
/** see subclause 7.4.3.3 */
AVCEnc_Status dec_ref_pic_marking(AVCCommonObj *video, AVCEncBitstream *stream, AVCSliceHeader *sliceHdr)
{
int i;
AVCEnc_Status status = AVCENC_SUCCESS;
if (video->nal_unit_type == AVC_NALTYPE_IDR)
{
status = BitstreamWrite1Bit(stream, sliceHdr->no_output_of_prior_pics_flag);
status = BitstreamWrite1Bit(stream, sliceHdr->long_term_reference_flag);
if (sliceHdr->long_term_reference_flag == 0) /* used for short-term */
{
video->MaxLongTermFrameIdx = -1; /* no long-term frame indx */
}
else /* used for long-term */
{
video->MaxLongTermFrameIdx = 0;
video->LongTermFrameIdx = 0;
}
}
else
{
status = BitstreamWrite1Bit(stream, sliceHdr->adaptive_ref_pic_marking_mode_flag); /* default to zero */
if (sliceHdr->adaptive_ref_pic_marking_mode_flag)
{
i = 0;
do
{
status = ue_v(stream, sliceHdr->memory_management_control_operation[i]);
if (sliceHdr->memory_management_control_operation[i] == 1 ||
sliceHdr->memory_management_control_operation[i] == 3)
{
status = ue_v(stream, sliceHdr->difference_of_pic_nums_minus1[i]);
}
if (sliceHdr->memory_management_control_operation[i] == 2)
{
status = ue_v(stream, sliceHdr->long_term_pic_num[i]);
}
if (sliceHdr->memory_management_control_operation[i] == 3 ||
sliceHdr->memory_management_control_operation[i] == 6)
{
status = ue_v(stream, sliceHdr->long_term_frame_idx[i]);
}
if (sliceHdr->memory_management_control_operation[i] == 4)
{
status = ue_v(stream, sliceHdr->max_long_term_frame_idx_plus1[i]);
}
i++;
}
while (sliceHdr->memory_management_control_operation[i] != 0 && i < MAX_DEC_REF_PIC_MARKING);
if (i >= MAX_DEC_REF_PIC_MARKING && sliceHdr->memory_management_control_operation[i] != 0)
{
return AVCENC_DEC_REF_PIC_MARK_FAIL; /* we're screwed!!, not enough memory */
}
}
}
return status;
}
/* see subclause 8.2.1 Decoding process for picture order count.
See also PostPOC() for initialization of some variables. */
AVCEnc_Status InitPOC(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCSeqParamSet *currSPS = video->currSeqParams;
AVCSliceHeader *sliceHdr = video->sliceHdr;
AVCFrameIO *currInput = encvid->currInput;
int i;
switch (currSPS->pic_order_cnt_type)
{
case 0: /* POC MODE 0 , subclause 8.2.1.1 */
/* encoding part */
if (video->nal_unit_type == AVC_NALTYPE_IDR)
{
encvid->dispOrdPOCRef = currInput->disp_order;
}
while (currInput->disp_order < encvid->dispOrdPOCRef)
{
encvid->dispOrdPOCRef -= video->MaxPicOrderCntLsb;
}
sliceHdr->pic_order_cnt_lsb = currInput->disp_order - encvid->dispOrdPOCRef;
while (sliceHdr->pic_order_cnt_lsb >= video->MaxPicOrderCntLsb)
{
sliceHdr->pic_order_cnt_lsb -= video->MaxPicOrderCntLsb;
}
/* decoding part */
/* Calculate the MSBs of current picture */
if (video->nal_unit_type == AVC_NALTYPE_IDR)
{
video->prevPicOrderCntMsb = 0;
video->prevPicOrderCntLsb = 0;
}
if (sliceHdr->pic_order_cnt_lsb < video->prevPicOrderCntLsb &&
(video->prevPicOrderCntLsb - sliceHdr->pic_order_cnt_lsb) >= (video->MaxPicOrderCntLsb / 2))
video->PicOrderCntMsb = video->prevPicOrderCntMsb + video->MaxPicOrderCntLsb;
else if (sliceHdr->pic_order_cnt_lsb > video->prevPicOrderCntLsb &&
(sliceHdr->pic_order_cnt_lsb - video->prevPicOrderCntLsb) > (video->MaxPicOrderCntLsb / 2))
video->PicOrderCntMsb = video->prevPicOrderCntMsb - video->MaxPicOrderCntLsb;
else
video->PicOrderCntMsb = video->prevPicOrderCntMsb;
/* JVT-I010 page 81 is different from JM7.3 */
if (!sliceHdr->field_pic_flag || !sliceHdr->bottom_field_flag)
{
video->PicOrderCnt = video->TopFieldOrderCnt = video->PicOrderCntMsb + sliceHdr->pic_order_cnt_lsb;
}
if (!sliceHdr->field_pic_flag)
{
video->BottomFieldOrderCnt = video->TopFieldOrderCnt + sliceHdr->delta_pic_order_cnt_bottom;
}
else if (sliceHdr->bottom_field_flag)
{
video->PicOrderCnt = video->BottomFieldOrderCnt = video->PicOrderCntMsb + sliceHdr->pic_order_cnt_lsb;
}
if (!sliceHdr->field_pic_flag)
{
video->PicOrderCnt = AVC_MIN(video->TopFieldOrderCnt, video->BottomFieldOrderCnt);
}
if (video->currPicParams->pic_order_present_flag && !sliceHdr->field_pic_flag)
{
sliceHdr->delta_pic_order_cnt_bottom = 0; /* defaulted to zero */
}
break;
case 1: /* POC MODE 1, subclause 8.2.1.2 */
/* calculate FrameNumOffset */
if (video->nal_unit_type == AVC_NALTYPE_IDR)
{
encvid->dispOrdPOCRef = currInput->disp_order; /* reset the reference point */
video->prevFrameNumOffset = 0;
video->FrameNumOffset = 0;
}
else if (video->prevFrameNum > sliceHdr->frame_num)
{
video->FrameNumOffset = video->prevFrameNumOffset + video->MaxFrameNum;
}
else
{
video->FrameNumOffset = video->prevFrameNumOffset;
}
/* calculate absFrameNum */
if (currSPS->num_ref_frames_in_pic_order_cnt_cycle)
{
video->absFrameNum = video->FrameNumOffset + sliceHdr->frame_num;
}
else
{
video->absFrameNum = 0;
}
if (video->absFrameNum > 0 && video->nal_ref_idc == 0)
{
video->absFrameNum--;
}
/* derive picOrderCntCycleCnt and frameNumInPicOrderCntCycle */
if (video->absFrameNum > 0)
{
video->picOrderCntCycleCnt = (video->absFrameNum - 1) / currSPS->num_ref_frames_in_pic_order_cnt_cycle;
video->frameNumInPicOrderCntCycle = (video->absFrameNum - 1) % currSPS->num_ref_frames_in_pic_order_cnt_cycle;
}
/* derive expectedDeltaPerPicOrderCntCycle, this value can be computed up front. */
video->expectedDeltaPerPicOrderCntCycle = 0;
for (i = 0; i < (int)currSPS->num_ref_frames_in_pic_order_cnt_cycle; i++)
{
video->expectedDeltaPerPicOrderCntCycle += currSPS->offset_for_ref_frame[i];
}
/* derive expectedPicOrderCnt */
if (video->absFrameNum)
{
video->expectedPicOrderCnt = video->picOrderCntCycleCnt * video->expectedDeltaPerPicOrderCntCycle;
for (i = 0; i <= video->frameNumInPicOrderCntCycle; i++)
{
video->expectedPicOrderCnt += currSPS->offset_for_ref_frame[i];
}
}
else
{
video->expectedPicOrderCnt = 0;
}
if (video->nal_ref_idc == 0)
{
video->expectedPicOrderCnt += currSPS->offset_for_non_ref_pic;
}
/* derive TopFieldOrderCnt and BottomFieldOrderCnt */
/* encoding part */
if (!currSPS->delta_pic_order_always_zero_flag)
{
sliceHdr->delta_pic_order_cnt[0] = currInput->disp_order - encvid->dispOrdPOCRef - video->expectedPicOrderCnt;
if (video->currPicParams->pic_order_present_flag && !sliceHdr->field_pic_flag)
{
sliceHdr->delta_pic_order_cnt[1] = sliceHdr->delta_pic_order_cnt[0]; /* should be calculated from currInput->bottom_field->disp_order */
}
else
{
sliceHdr->delta_pic_order_cnt[1] = 0;
}
}
else
{
sliceHdr->delta_pic_order_cnt[0] = sliceHdr->delta_pic_order_cnt[1] = 0;
}
if (sliceHdr->field_pic_flag == 0)
{
video->TopFieldOrderCnt = video->expectedPicOrderCnt + sliceHdr->delta_pic_order_cnt[0];
video->BottomFieldOrderCnt = video->TopFieldOrderCnt + currSPS->offset_for_top_to_bottom_field + sliceHdr->delta_pic_order_cnt[1];
video->PicOrderCnt = AVC_MIN(video->TopFieldOrderCnt, video->BottomFieldOrderCnt);
}
else if (sliceHdr->bottom_field_flag == 0)
{
video->TopFieldOrderCnt = video->expectedPicOrderCnt + sliceHdr->delta_pic_order_cnt[0];
video->PicOrderCnt = video->TopFieldOrderCnt;
}
else
{
video->BottomFieldOrderCnt = video->expectedPicOrderCnt + currSPS->offset_for_top_to_bottom_field + sliceHdr->delta_pic_order_cnt[0];
video->PicOrderCnt = video->BottomFieldOrderCnt;
}
break;
case 2: /* POC MODE 2, subclause 8.2.1.3 */
/* decoding order must be the same as display order */
/* we don't check for that. The decoder will just output in decoding order. */
/* Check for 2 consecutive non-reference frame */
if (video->nal_ref_idc == 0)
{
if (encvid->dispOrdPOCRef == 1)
{
return AVCENC_CONSECUTIVE_NONREF;
}
encvid->dispOrdPOCRef = 1; /* act as a flag for non ref */
}
else
{
encvid->dispOrdPOCRef = 0;
}
if (video->nal_unit_type == AVC_NALTYPE_IDR)
{
video->FrameNumOffset = 0;
}
else if (video->prevFrameNum > sliceHdr->frame_num)
{
video->FrameNumOffset = video->prevFrameNumOffset + video->MaxFrameNum;
}
else
{
video->FrameNumOffset = video->prevFrameNumOffset;
}
/* derive tempPicOrderCnt, we just use PicOrderCnt */
if (video->nal_unit_type == AVC_NALTYPE_IDR)
{
video->PicOrderCnt = 0;
}
else if (video->nal_ref_idc == 0)
{
video->PicOrderCnt = 2 * (video->FrameNumOffset + sliceHdr->frame_num) - 1;
}
else
{
video->PicOrderCnt = 2 * (video->FrameNumOffset + sliceHdr->frame_num);
}
/* derive TopFieldOrderCnt and BottomFieldOrderCnt */
if (sliceHdr->field_pic_flag == 0)
{
video->TopFieldOrderCnt = video->BottomFieldOrderCnt = video->PicOrderCnt;
}
else if (sliceHdr->bottom_field_flag)
{
video->BottomFieldOrderCnt = video->PicOrderCnt;
}
else
{
video->TopFieldOrderCnt = video->PicOrderCnt;
}
break;
default:
return AVCENC_POC_FAIL;
}
return AVCENC_SUCCESS;
}
/** see subclause 8.2.1 */
AVCEnc_Status PostPOC(AVCCommonObj *video)
{
AVCSliceHeader *sliceHdr = video->sliceHdr;
AVCSeqParamSet *currSPS = video->currSeqParams;
video->prevFrameNum = sliceHdr->frame_num;
switch (currSPS->pic_order_cnt_type)
{
case 0: /* subclause 8.2.1.1 */
if (video->mem_mgr_ctrl_eq_5)
{
video->prevPicOrderCntMsb = 0;
video->prevPicOrderCntLsb = video->TopFieldOrderCnt;
}
else
{
video->prevPicOrderCntMsb = video->PicOrderCntMsb;
video->prevPicOrderCntLsb = sliceHdr->pic_order_cnt_lsb;
}
break;
case 1: /* subclause 8.2.1.2 and 8.2.1.3 */
case 2:
if (video->mem_mgr_ctrl_eq_5)
{
video->prevFrameNumOffset = 0;
}
else
{
video->prevFrameNumOffset = video->FrameNumOffset;
}
break;
}
return AVCENC_SUCCESS;
}

View File

@@ -0,0 +1,899 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "avcenc_lib.h"
#include "avcenc_api.h"
#define LOG2_MAX_FRAME_NUM_MINUS4 12 /* 12 default */
#define SLICE_GROUP_CHANGE_CYCLE 1 /* default */
/* initialized variables to be used in SPS*/
AVCEnc_Status SetEncodeParam(AVCHandle* avcHandle, AVCEncParams* encParam,
void* extSPS, void* extPPS)
{
AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
AVCCommonObj *video = encvid->common;
AVCSeqParamSet *seqParam = video->currSeqParams;
AVCPicParamSet *picParam = video->currPicParams;
AVCSliceHeader *sliceHdr = video->sliceHdr;
AVCRateControl *rateCtrl = encvid->rateCtrl;
AVCEnc_Status status;
void *userData = avcHandle->userData;
int ii, maxFrameNum;
AVCSeqParamSet* extS = NULL;
AVCPicParamSet* extP = NULL;
if (extSPS) extS = (AVCSeqParamSet*) extSPS;
if (extPPS) extP = (AVCPicParamSet*) extPPS;
/* This part sets the default values of the encoding options this
library supports in seqParam, picParam and sliceHdr structures and
also copy the values from the encParam into the above 3 structures.
Some parameters will be assigned later when we encode SPS or PPS such as
the seq_parameter_id or pic_parameter_id. Also some of the slice parameters
have to be re-assigned per slice basis such as frame_num, slice_type,
first_mb_in_slice, pic_order_cnt_lsb, slice_qp_delta, slice_group_change_cycle */
/* profile_idc, constrained_setx_flag and level_idc is set by VerifyProfile(),
and VerifyLevel() functions later. */
encvid->fullsearch_enable = encParam->fullsearch;
encvid->outOfBandParamSet = ((encParam->out_of_band_param_set == AVC_ON) ? TRUE : FALSE);
/* parameters derived from the the encParam that are used in SPS */
if (extS)
{
video->MaxPicOrderCntLsb = 1 << (extS->log2_max_pic_order_cnt_lsb_minus4 + 4);
video->PicWidthInMbs = extS->pic_width_in_mbs_minus1 + 1;
video->PicHeightInMapUnits = extS->pic_height_in_map_units_minus1 + 1 ;
video->FrameHeightInMbs = (2 - extS->frame_mbs_only_flag) * video->PicHeightInMapUnits ;
}
else
{
video->MaxPicOrderCntLsb = 1 << (encParam->log2_max_poc_lsb_minus_4 + 4);
video->PicWidthInMbs = (encParam->width + 15) >> 4; /* round it to multiple of 16 */
video->FrameHeightInMbs = (encParam->height + 15) >> 4; /* round it to multiple of 16 */
video->PicHeightInMapUnits = video->FrameHeightInMbs;
}
video->PicWidthInSamplesL = video->PicWidthInMbs * 16 ;
if (video->PicWidthInSamplesL + 32 > 0xFFFF)
{
return AVCENC_NOT_SUPPORTED; // we use 2-bytes for pitch
}
video->PicWidthInSamplesC = video->PicWidthInMbs * 8 ;
video->PicHeightInMbs = video->FrameHeightInMbs;
video->PicSizeInMapUnits = video->PicWidthInMbs * video->PicHeightInMapUnits ;
video->PicHeightInSamplesL = video->PicHeightInMbs * 16;
video->PicHeightInSamplesC = video->PicHeightInMbs * 8;
video->PicSizeInMbs = video->PicWidthInMbs * video->PicHeightInMbs;
if (!extS && !extP)
{
maxFrameNum = (encParam->idr_period == -1) ? (1 << 16) : encParam->idr_period;
ii = 0;
while (maxFrameNum > 0)
{
ii++;
maxFrameNum >>= 1;
}
if (ii < 4) ii = 4;
else if (ii > 16) ii = 16;
seqParam->log2_max_frame_num_minus4 = ii - 4;//LOG2_MAX_FRAME_NUM_MINUS4; /* default */
video->MaxFrameNum = 1 << ii; //(LOG2_MAX_FRAME_NUM_MINUS4 + 4); /* default */
video->MaxPicNum = video->MaxFrameNum;
/************* set the SPS *******************/
seqParam->seq_parameter_set_id = 0; /* start with zero */
/* POC */
seqParam->pic_order_cnt_type = encParam->poc_type; /* POC type */
if (encParam->poc_type == 0)
{
if (/*encParam->log2_max_poc_lsb_minus_4<0 || (no need, it's unsigned)*/
encParam->log2_max_poc_lsb_minus_4 > 12)
{
return AVCENC_INVALID_POC_LSB;
}
seqParam->log2_max_pic_order_cnt_lsb_minus4 = encParam->log2_max_poc_lsb_minus_4;
}
else if (encParam->poc_type == 1)
{
seqParam->delta_pic_order_always_zero_flag = encParam->delta_poc_zero_flag;
seqParam->offset_for_non_ref_pic = encParam->offset_poc_non_ref;
seqParam->offset_for_top_to_bottom_field = encParam->offset_top_bottom;
seqParam->num_ref_frames_in_pic_order_cnt_cycle = encParam->num_ref_in_cycle;
if (encParam->offset_poc_ref == NULL)
{
return AVCENC_ENCPARAM_MEM_FAIL;
}
for (ii = 0; ii < encParam->num_ref_frame; ii++)
{
seqParam->offset_for_ref_frame[ii] = encParam->offset_poc_ref[ii];
}
}
/* number of reference frame */
if (encParam->num_ref_frame > 16 || encParam->num_ref_frame < 0)
{
return AVCENC_INVALID_NUM_REF;
}
seqParam->num_ref_frames = encParam->num_ref_frame; /* num reference frame range 0...16*/
seqParam->gaps_in_frame_num_value_allowed_flag = FALSE;
seqParam->pic_width_in_mbs_minus1 = video->PicWidthInMbs - 1;
seqParam->pic_height_in_map_units_minus1 = video->PicHeightInMapUnits - 1;
seqParam->frame_mbs_only_flag = TRUE;
seqParam->mb_adaptive_frame_field_flag = FALSE;
seqParam->direct_8x8_inference_flag = FALSE; /* default */
seqParam->frame_cropping_flag = FALSE;
seqParam->frame_crop_bottom_offset = 0;
seqParam->frame_crop_left_offset = 0;
seqParam->frame_crop_right_offset = 0;
seqParam->frame_crop_top_offset = 0;
seqParam->vui_parameters_present_flag = FALSE; /* default */
}
else if (extS) // use external SPS and PPS
{
seqParam->seq_parameter_set_id = extS->seq_parameter_set_id;
seqParam->log2_max_frame_num_minus4 = extS->log2_max_frame_num_minus4;
video->MaxFrameNum = 1 << (extS->log2_max_frame_num_minus4 + 4);
video->MaxPicNum = video->MaxFrameNum;
if (encParam->idr_period > (int)(video->MaxFrameNum) || (encParam->idr_period == -1))
{
encParam->idr_period = (int)video->MaxFrameNum;
}
seqParam->pic_order_cnt_type = extS->pic_order_cnt_type;
if (seqParam->pic_order_cnt_type == 0)
{
if (/*extS->log2_max_pic_order_cnt_lsb_minus4<0 || (no need it's unsigned)*/
extS->log2_max_pic_order_cnt_lsb_minus4 > 12)
{
return AVCENC_INVALID_POC_LSB;
}
seqParam->log2_max_pic_order_cnt_lsb_minus4 = extS->log2_max_pic_order_cnt_lsb_minus4;
}
else if (seqParam->pic_order_cnt_type == 1)
{
seqParam->delta_pic_order_always_zero_flag = extS->delta_pic_order_always_zero_flag;
seqParam->offset_for_non_ref_pic = extS->offset_for_non_ref_pic;
seqParam->offset_for_top_to_bottom_field = extS->offset_for_top_to_bottom_field;
seqParam->num_ref_frames_in_pic_order_cnt_cycle = extS->num_ref_frames_in_pic_order_cnt_cycle;
if (extS->offset_for_ref_frame == NULL)
{
return AVCENC_ENCPARAM_MEM_FAIL;
}
for (ii = 0; ii < (int) extS->num_ref_frames; ii++)
{
seqParam->offset_for_ref_frame[ii] = extS->offset_for_ref_frame[ii];
}
}
/* number of reference frame */
if (extS->num_ref_frames > 16 /*|| extS->num_ref_frames<0 (no need, it's unsigned)*/)
{
return AVCENC_INVALID_NUM_REF;
}
seqParam->num_ref_frames = extS->num_ref_frames; /* num reference frame range 0...16*/
seqParam->gaps_in_frame_num_value_allowed_flag = extS->gaps_in_frame_num_value_allowed_flag;
seqParam->pic_width_in_mbs_minus1 = extS->pic_width_in_mbs_minus1;
seqParam->pic_height_in_map_units_minus1 = extS->pic_height_in_map_units_minus1;
seqParam->frame_mbs_only_flag = extS->frame_mbs_only_flag;
if (extS->frame_mbs_only_flag != TRUE)
{
return AVCENC_NOT_SUPPORTED;
}
seqParam->mb_adaptive_frame_field_flag = extS->mb_adaptive_frame_field_flag;
if (extS->mb_adaptive_frame_field_flag != FALSE)
{
return AVCENC_NOT_SUPPORTED;
}
seqParam->direct_8x8_inference_flag = extS->direct_8x8_inference_flag;
seqParam->frame_cropping_flag = extS->frame_cropping_flag ;
if (extS->frame_cropping_flag != FALSE)
{
return AVCENC_NOT_SUPPORTED;
}
seqParam->frame_crop_bottom_offset = 0;
seqParam->frame_crop_left_offset = 0;
seqParam->frame_crop_right_offset = 0;
seqParam->frame_crop_top_offset = 0;
seqParam->vui_parameters_present_flag = extS->vui_parameters_present_flag;
if (extS->vui_parameters_present_flag)
{
memcpy(&(seqParam->vui_parameters), &(extS->vui_parameters), sizeof(AVCVUIParams));
}
}
else
{
return AVCENC_NOT_SUPPORTED;
}
/***************** now PPS ******************************/
if (!extP && !extS)
{
picParam->pic_parameter_set_id = (uint)(-1); /* start with zero */
picParam->seq_parameter_set_id = (uint)(-1); /* start with zero */
picParam->entropy_coding_mode_flag = 0; /* default to CAVLC */
picParam->pic_order_present_flag = 0; /* default for now, will need it for B-slice */
/* FMO */
if (encParam->num_slice_group < 1 || encParam->num_slice_group > MAX_NUM_SLICE_GROUP)
{
return AVCENC_INVALID_NUM_SLICEGROUP;
}
picParam->num_slice_groups_minus1 = encParam->num_slice_group - 1;
if (picParam->num_slice_groups_minus1 > 0)
{
picParam->slice_group_map_type = encParam->fmo_type;
switch (encParam->fmo_type)
{
case 0:
for (ii = 0; ii <= (int)picParam->num_slice_groups_minus1; ii++)
{
picParam->run_length_minus1[ii] = encParam->run_length_minus1[ii];
}
break;
case 2:
for (ii = 0; ii < (int)picParam->num_slice_groups_minus1; ii++)
{
picParam->top_left[ii] = encParam->top_left[ii];
picParam->bottom_right[ii] = encParam->bottom_right[ii];
}
break;
case 3:
case 4:
case 5:
if (encParam->change_dir_flag == AVC_ON)
{
picParam->slice_group_change_direction_flag = TRUE;
}
else
{
picParam->slice_group_change_direction_flag = FALSE;
}
if (/*encParam->change_rate_minus1 < 0 || (no need it's unsigned) */
encParam->change_rate_minus1 > video->PicSizeInMapUnits - 1)
{
return AVCENC_INVALID_CHANGE_RATE;
}
picParam->slice_group_change_rate_minus1 = encParam->change_rate_minus1;
video->SliceGroupChangeRate = picParam->slice_group_change_rate_minus1 + 1;
break;
case 6:
picParam->pic_size_in_map_units_minus1 = video->PicSizeInMapUnits - 1;
/* allocate picParam->slice_group_id */
picParam->slice_group_id = (uint*)avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits, DEFAULT_ATTR);
if (picParam->slice_group_id == NULL)
{
return AVCENC_MEMORY_FAIL;
}
if (encParam->slice_group == NULL)
{
return AVCENC_ENCPARAM_MEM_FAIL;
}
for (ii = 0; ii < (int)video->PicSizeInMapUnits; ii++)
{
picParam->slice_group_id[ii] = encParam->slice_group[ii];
}
break;
default:
return AVCENC_INVALID_FMO_TYPE;
}
}
picParam->num_ref_idx_l0_active_minus1 = encParam->num_ref_frame - 1; /* assume frame only */
picParam->num_ref_idx_l1_active_minus1 = 0; /* default value */
picParam->weighted_pred_flag = 0; /* no weighted prediction supported */
picParam->weighted_bipred_idc = 0; /* range 0,1,2 */
if (/*picParam->weighted_bipred_idc < 0 || (no need, it's unsigned) */
picParam->weighted_bipred_idc > 2)
{
return AVCENC_WEIGHTED_BIPRED_FAIL;
}
picParam->pic_init_qp_minus26 = 0; /* default, will be changed at slice level anyway */
if (picParam->pic_init_qp_minus26 < -26 || picParam->pic_init_qp_minus26 > 25)
{
return AVCENC_INIT_QP_FAIL; /* out of range */
}
picParam->pic_init_qs_minus26 = 0;
if (picParam->pic_init_qs_minus26 < -26 || picParam->pic_init_qs_minus26 > 25)
{
return AVCENC_INIT_QS_FAIL; /* out of range */
}
picParam->chroma_qp_index_offset = 0; /* default to zero for now */
if (picParam->chroma_qp_index_offset < -12 || picParam->chroma_qp_index_offset > 12)
{
return AVCENC_CHROMA_QP_FAIL; /* out of range */
}
/* deblocking */
picParam->deblocking_filter_control_present_flag = (encParam->db_filter == AVC_ON) ? TRUE : FALSE ;
/* constrained intra prediction */
picParam->constrained_intra_pred_flag = (encParam->constrained_intra_pred == AVC_ON) ? TRUE : FALSE;
picParam->redundant_pic_cnt_present_flag = 0; /* default */
}
else if (extP)// external PPS
{
picParam->pic_parameter_set_id = extP->pic_parameter_set_id - 1; /* to be increased by one */
picParam->seq_parameter_set_id = extP->seq_parameter_set_id;
picParam->entropy_coding_mode_flag = extP->entropy_coding_mode_flag;
if (extP->entropy_coding_mode_flag != 0) /* default to CAVLC */
{
return AVCENC_NOT_SUPPORTED;
}
picParam->pic_order_present_flag = extP->pic_order_present_flag; /* default for now, will need it for B-slice */
if (extP->pic_order_present_flag != 0)
{
return AVCENC_NOT_SUPPORTED;
}
/* FMO */
if (/*(extP->num_slice_groups_minus1<0) || (no need it's unsigned) */
(extP->num_slice_groups_minus1 > MAX_NUM_SLICE_GROUP - 1))
{
return AVCENC_INVALID_NUM_SLICEGROUP;
}
picParam->num_slice_groups_minus1 = extP->num_slice_groups_minus1;
if (picParam->num_slice_groups_minus1 > 0)
{
picParam->slice_group_map_type = extP->slice_group_map_type;
switch (extP->slice_group_map_type)
{
case 0:
for (ii = 0; ii <= (int)extP->num_slice_groups_minus1; ii++)
{
picParam->run_length_minus1[ii] = extP->run_length_minus1[ii];
}
break;
case 2:
for (ii = 0; ii < (int)picParam->num_slice_groups_minus1; ii++)
{
picParam->top_left[ii] = extP->top_left[ii];
picParam->bottom_right[ii] = extP->bottom_right[ii];
}
break;
case 3:
case 4:
case 5:
picParam->slice_group_change_direction_flag = extP->slice_group_change_direction_flag;
if (/*extP->slice_group_change_rate_minus1 < 0 || (no need, it's unsigned) */
extP->slice_group_change_rate_minus1 > video->PicSizeInMapUnits - 1)
{
return AVCENC_INVALID_CHANGE_RATE;
}
picParam->slice_group_change_rate_minus1 = extP->slice_group_change_rate_minus1;
video->SliceGroupChangeRate = picParam->slice_group_change_rate_minus1 + 1;
break;
case 6:
if (extP->pic_size_in_map_units_minus1 != video->PicSizeInMapUnits - 1)
{
return AVCENC_NOT_SUPPORTED;
}
picParam->pic_size_in_map_units_minus1 = extP->pic_size_in_map_units_minus1;
/* allocate picParam->slice_group_id */
picParam->slice_group_id = (uint*)avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits, DEFAULT_ATTR);
if (picParam->slice_group_id == NULL)
{
return AVCENC_MEMORY_FAIL;
}
if (extP->slice_group_id == NULL)
{
return AVCENC_ENCPARAM_MEM_FAIL;
}
for (ii = 0; ii < (int)video->PicSizeInMapUnits; ii++)
{
picParam->slice_group_id[ii] = extP->slice_group_id[ii];
}
break;
default:
return AVCENC_INVALID_FMO_TYPE;
}
}
picParam->num_ref_idx_l0_active_minus1 = extP->num_ref_idx_l0_active_minus1;
picParam->num_ref_idx_l1_active_minus1 = extP->num_ref_idx_l1_active_minus1; /* default value */
if (picParam->num_ref_idx_l1_active_minus1 != 0)
{
return AVCENC_NOT_SUPPORTED;
}
if (extP->weighted_pred_flag)
{
return AVCENC_NOT_SUPPORTED;
}
picParam->weighted_pred_flag = 0; /* no weighted prediction supported */
picParam->weighted_bipred_idc = extP->weighted_bipred_idc; /* range 0,1,2 */
if (/*picParam->weighted_bipred_idc < 0 || (no need, it's unsigned) */
picParam->weighted_bipred_idc > 2)
{
return AVCENC_WEIGHTED_BIPRED_FAIL;
}
picParam->pic_init_qp_minus26 = extP->pic_init_qp_minus26; /* default, will be changed at slice level anyway */
if (picParam->pic_init_qp_minus26 < -26 || picParam->pic_init_qp_minus26 > 25)
{
return AVCENC_INIT_QP_FAIL; /* out of range */
}
picParam->pic_init_qs_minus26 = extP->pic_init_qs_minus26;
if (picParam->pic_init_qs_minus26 < -26 || picParam->pic_init_qs_minus26 > 25)
{
return AVCENC_INIT_QS_FAIL; /* out of range */
}
picParam->chroma_qp_index_offset = extP->chroma_qp_index_offset; /* default to zero for now */
if (picParam->chroma_qp_index_offset < -12 || picParam->chroma_qp_index_offset > 12)
{
return AVCENC_CHROMA_QP_FAIL; /* out of range */
}
/* deblocking */
picParam->deblocking_filter_control_present_flag = extP->deblocking_filter_control_present_flag;
/* constrained intra prediction */
picParam->constrained_intra_pred_flag = extP->constrained_intra_pred_flag;
if (extP->redundant_pic_cnt_present_flag != 0)
{
return AVCENC_NOT_SUPPORTED;
}
picParam->redundant_pic_cnt_present_flag = extP->redundant_pic_cnt_present_flag; /* default */
}
else
{
return AVCENC_NOT_SUPPORTED;
}
/****************** now set up some SliceHeader parameters ***********/
if (picParam->deblocking_filter_control_present_flag == TRUE)
{
/* these values only present when db_filter is ON */
if (encParam->disable_db_idc > 2)
{
return AVCENC_INVALID_DEBLOCK_IDC; /* out of range */
}
sliceHdr->disable_deblocking_filter_idc = encParam->disable_db_idc;
if (encParam->alpha_offset < -6 || encParam->alpha_offset > 6)
{
return AVCENC_INVALID_ALPHA_OFFSET;
}
sliceHdr->slice_alpha_c0_offset_div2 = encParam->alpha_offset;
if (encParam->beta_offset < -6 || encParam->beta_offset > 6)
{
return AVCENC_INVALID_BETA_OFFSET;
}
sliceHdr->slice_beta_offset_div_2 = encParam->beta_offset;
}
if (encvid->outOfBandParamSet == TRUE)
{
sliceHdr->idr_pic_id = 0;
}
else
{
sliceHdr->idr_pic_id = (uint)(-1); /* start with zero */
}
sliceHdr->field_pic_flag = FALSE;
sliceHdr->bottom_field_flag = FALSE; /* won't be used anyway */
video->MbaffFrameFlag = (seqParam->mb_adaptive_frame_field_flag && !sliceHdr->field_pic_flag);
/* the rest will be set in InitSlice() */
/* now the rate control and performance related parameters */
rateCtrl->scdEnable = (encParam->auto_scd == AVC_ON) ? TRUE : FALSE;
rateCtrl->idrPeriod = encParam->idr_period + 1;
rateCtrl->intraMBRate = encParam->intramb_refresh;
rateCtrl->dpEnable = (encParam->data_par == AVC_ON) ? TRUE : FALSE;
rateCtrl->subPelEnable = (encParam->sub_pel == AVC_ON) ? TRUE : FALSE;
rateCtrl->mvRange = encParam->search_range;
rateCtrl->subMBEnable = (encParam->submb_pred == AVC_ON) ? TRUE : FALSE;
rateCtrl->rdOptEnable = (encParam->rdopt_mode == AVC_ON) ? TRUE : FALSE;
rateCtrl->bidirPred = (encParam->bidir_pred == AVC_ON) ? TRUE : FALSE;
rateCtrl->rcEnable = (encParam->rate_control == AVC_ON) ? TRUE : FALSE;
rateCtrl->initQP = encParam->initQP;
rateCtrl->initQP = AVC_CLIP3(0, 51, rateCtrl->initQP);
rateCtrl->bitRate = encParam->bitrate;
rateCtrl->cpbSize = encParam->CPB_size;
rateCtrl->initDelayOffset = (rateCtrl->bitRate * encParam->init_CBP_removal_delay / 1000);
if (encParam->frame_rate == 0)
{
return AVCENC_INVALID_FRAMERATE;
}
rateCtrl->frame_rate = (OsclFloat)(encParam->frame_rate * 1.0 / 1000);
// rateCtrl->srcInterval = encParam->src_interval;
rateCtrl->first_frame = 1; /* set this flag for the first time */
/* contrained_setx_flag will be set inside the VerifyProfile called below.*/
if (!extS && !extP)
{
seqParam->profile_idc = encParam->profile;
seqParam->constrained_set0_flag = FALSE;
seqParam->constrained_set1_flag = FALSE;
seqParam->constrained_set2_flag = FALSE;
seqParam->constrained_set3_flag = FALSE;
seqParam->level_idc = encParam->level;
}
else
{
seqParam->profile_idc = extS->profile_idc;
seqParam->constrained_set0_flag = extS->constrained_set0_flag;
seqParam->constrained_set1_flag = extS->constrained_set1_flag;
seqParam->constrained_set2_flag = extS->constrained_set2_flag;
seqParam->constrained_set3_flag = extS->constrained_set3_flag;
seqParam->level_idc = extS->level_idc;
}
status = VerifyProfile(encvid, seqParam, picParam);
if (status != AVCENC_SUCCESS)
{
return status;
}
status = VerifyLevel(encvid, seqParam, picParam);
if (status != AVCENC_SUCCESS)
{
return status;
}
return AVCENC_SUCCESS;
}
/* verify the profile setting */
AVCEnc_Status VerifyProfile(AVCEncObject *encvid, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam)
{
AVCRateControl *rateCtrl = encvid->rateCtrl;
AVCEnc_Status status = AVCENC_SUCCESS;
if (seqParam->profile_idc == 0) /* find profile for this setting */
{
/* find the right profile for it */
if (seqParam->direct_8x8_inference_flag == TRUE &&
picParam->entropy_coding_mode_flag == FALSE &&
picParam->num_slice_groups_minus1 <= 7 /*&&
picParam->num_slice_groups_minus1>=0 (no need, it's unsigned) */)
{
seqParam->profile_idc = AVC_EXTENDED;
seqParam->constrained_set2_flag = TRUE;
}
if (rateCtrl->dpEnable == FALSE &&
picParam->num_slice_groups_minus1 == 0 &&
picParam->redundant_pic_cnt_present_flag == FALSE)
{
seqParam->profile_idc = AVC_MAIN;
seqParam->constrained_set1_flag = TRUE;
}
if (rateCtrl->bidirPred == FALSE &&
rateCtrl->dpEnable == FALSE &&
seqParam->frame_mbs_only_flag == TRUE &&
picParam->weighted_pred_flag == FALSE &&
picParam->weighted_bipred_idc == 0 &&
picParam->entropy_coding_mode_flag == FALSE &&
picParam->num_slice_groups_minus1 <= 7 /*&&
picParam->num_slice_groups_minus1>=0 (no need, it's unsigned)*/)
{
seqParam->profile_idc = AVC_BASELINE;
seqParam->constrained_set0_flag = TRUE;
}
if (seqParam->profile_idc == 0) /* still zero */
{
return AVCENC_PROFILE_NOT_SUPPORTED;
}
}
/* check the list of supported profile by this library */
switch (seqParam->profile_idc)
{
case AVC_BASELINE:
if (rateCtrl->bidirPred == TRUE ||
rateCtrl->dpEnable == TRUE ||
seqParam->frame_mbs_only_flag != TRUE ||
picParam->weighted_pred_flag == TRUE ||
picParam->weighted_bipred_idc != 0 ||
picParam->entropy_coding_mode_flag == TRUE ||
picParam->num_slice_groups_minus1 > 7 /*||
picParam->num_slice_groups_minus1<0 (no need, it's unsigned) */)
{
status = AVCENC_TOOLS_NOT_SUPPORTED;
}
break;
case AVC_MAIN:
case AVC_EXTENDED:
status = AVCENC_PROFILE_NOT_SUPPORTED;
}
return status;
}
/* verify the level setting */
AVCEnc_Status VerifyLevel(AVCEncObject *encvid, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam)
{
(void)(picParam);
AVCRateControl *rateCtrl = encvid->rateCtrl;
AVCCommonObj *video = encvid->common;
int mb_per_sec, ii;
int lev_idx;
int dpb_size;
mb_per_sec = (int)(video->PicSizeInMbs * rateCtrl->frame_rate + 0.5);
dpb_size = (seqParam->num_ref_frames * video->PicSizeInMbs * 3) >> 6;
if (seqParam->level_idc == 0) /* find level for this setting */
{
for (ii = 0; ii < MAX_LEVEL_IDX; ii++)
{
if (mb_per_sec <= MaxMBPS[ii] &&
video->PicSizeInMbs <= (uint)MaxFS[ii] &&
rateCtrl->bitRate <= (int32)MaxBR[ii]*1000 &&
rateCtrl->cpbSize <= (int32)MaxCPB[ii]*1000 &&
rateCtrl->mvRange <= MaxVmvR[ii] &&
dpb_size <= MaxDPBX2[ii]*512)
{
seqParam->level_idc = mapIdx2Lev[ii];
break;
}
}
if (seqParam->level_idc == 0)
{
return AVCENC_LEVEL_NOT_SUPPORTED;
}
}
/* check if this level is supported by this library */
lev_idx = mapLev2Idx[seqParam->level_idc];
if (seqParam->level_idc == AVC_LEVEL1_B)
{
seqParam->constrained_set3_flag = 1;
}
if (lev_idx == 255) /* not defined */
{
return AVCENC_LEVEL_NOT_SUPPORTED;
}
/* check if the encoding setting complies with the level */
if (mb_per_sec > MaxMBPS[lev_idx] ||
video->PicSizeInMbs > (uint)MaxFS[lev_idx] ||
rateCtrl->bitRate > (int32)MaxBR[lev_idx]*1000 ||
rateCtrl->cpbSize > (int32)MaxCPB[lev_idx]*1000 ||
rateCtrl->mvRange > MaxVmvR[lev_idx])
{
return AVCENC_LEVEL_FAIL;
}
return AVCENC_SUCCESS;
}
/* initialize variables at the beginning of each frame */
/* determine the picture type */
/* encode POC */
/* maybe we should do more stuff here. MotionEstimation+SCD and generate a new SPS and PPS */
AVCEnc_Status InitFrame(AVCEncObject *encvid)
{
AVCStatus ret;
AVCEnc_Status status;
AVCCommonObj *video = encvid->common;
AVCSliceHeader *sliceHdr = video->sliceHdr;
/* look for the next frame in coding_order and look for available picture
in the DPB. Note, video->currFS->PicOrderCnt, currFS->FrameNum and currPic->PicNum
are set to wrong number in this function (right for decoder). */
if (video->nal_unit_type == AVC_NALTYPE_IDR)
{
// call init DPB in here.
ret = AVCConfigureSequence(encvid->avcHandle, video, TRUE);
if (ret != AVC_SUCCESS)
{
return AVCENC_FAIL;
}
}
/* flexible macroblock ordering (every frame)*/
/* populate video->mapUnitToSliceGroupMap and video->MbToSliceGroupMap */
/* It changes once per each PPS. */
FMOInit(video);
ret = DPBInitBuffer(encvid->avcHandle, video); // get new buffer
if (ret != AVC_SUCCESS)
{
return (AVCEnc_Status)ret; // AVCENC_PICTURE_READY, FAIL
}
DPBInitPic(video, 0); /* 0 is dummy */
/************* determine picture type IDR or non-IDR ***********/
video->currPicType = AVC_FRAME;
video->slice_data_partitioning = FALSE;
encvid->currInput->is_reference = 1; /* default to all frames */
video->nal_ref_idc = 1; /* need to set this for InitPOC */
video->currPic->isReference = TRUE;
/************* set frame_num ********************/
if (video->nal_unit_type == AVC_NALTYPE_IDR)
{
video->prevFrameNum = video->MaxFrameNum;
video->PrevRefFrameNum = 0;
sliceHdr->frame_num = 0;
}
/* otherwise, it's set to previous reference frame access unit's frame_num in decoding order,
see the end of PVAVCDecodeSlice()*/
/* There's also restriction on the frame_num, see page 59 of JVT-I1010.doc. */
/* Basically, frame_num can't be repeated unless it's opposite fields or non reference fields */
else
{
sliceHdr->frame_num = (video->PrevRefFrameNum + 1) % video->MaxFrameNum;
}
video->CurrPicNum = sliceHdr->frame_num; /* for field_pic_flag = 0 */
//video->CurrPicNum = 2*sliceHdr->frame_num + 1; /* for field_pic_flag = 1 */
/* assign pic_order_cnt, video->PicOrderCnt */
status = InitPOC(encvid);
if (status != AVCENC_SUCCESS) /* incorrigable fail */
{
return status;
}
/* Initialize refListIdx for this picture */
RefListInit(video);
/************* motion estimation and scene analysis ************/
// , to move this to MB-based MV search for comparison
// use sub-optimal QP for mv search
AVCMotionEstimation(encvid); /* AVCENC_SUCCESS or AVCENC_NEW_IDR */
/* after this point, the picture type will be fixed to either IDR or non-IDR */
video->currFS->PicOrderCnt = video->PicOrderCnt;
video->currFS->FrameNum = video->sliceHdr->frame_num;
video->currPic->PicNum = video->CurrPicNum;
video->mbNum = 0; /* start from zero MB */
encvid->currSliceGroup = 0; /* start from slice group #0 */
encvid->numIntraMB = 0; /* reset this counter */
if (video->nal_unit_type == AVC_NALTYPE_IDR)
{
RCInitGOP(encvid);
/* calculate picture QP */
RCInitFrameQP(encvid);
return AVCENC_NEW_IDR;
}
/* calculate picture QP */
RCInitFrameQP(encvid); /* get QP after MV search */
return AVCENC_SUCCESS;
}
/* initialize variables for this slice */
AVCEnc_Status InitSlice(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCSliceHeader *sliceHdr = video->sliceHdr;
AVCPicParamSet *currPPS = video->currPicParams;
AVCSeqParamSet *currSPS = video->currSeqParams;
int slice_type = video->slice_type;
sliceHdr->first_mb_in_slice = video->mbNum;
if (video->mbNum) // not first slice of a frame
{
video->sliceHdr->slice_type = (AVCSliceType)slice_type;
}
/* sliceHdr->slice_type already set in InitFrame */
sliceHdr->pic_parameter_set_id = video->currPicParams->pic_parameter_set_id;
/* sliceHdr->frame_num already set in InitFrame */
if (!currSPS->frame_mbs_only_flag) /* we shouldn't need this check */
{
sliceHdr->field_pic_flag = sliceHdr->bottom_field_flag = FALSE;
return AVCENC_TOOLS_NOT_SUPPORTED;
}
/* sliceHdr->idr_pic_id already set in PVAVCEncodeNAL
sliceHdr->pic_order_cnt_lsb already set in InitFrame..InitPOC
sliceHdr->delta_pic_order_cnt_bottom already set in InitPOC
sliceHdr->delta_pic_order_cnt[0] already set in InitPOC
sliceHdr->delta_pic_order_cnt[1] already set in InitPOC
*/
sliceHdr->redundant_pic_cnt = 0; /* default if(currPPS->redundant_pic_cnt_present_flag), range 0..127 */
sliceHdr->direct_spatial_mv_pred_flag = 0; // default if(slice_type == AVC_B_SLICE)
sliceHdr->num_ref_idx_active_override_flag = FALSE; /* default, if(slice_type== P,SP or B)*/
sliceHdr->num_ref_idx_l0_active_minus1 = 0; /* default, if (num_ref_idx_active_override_flag) */
sliceHdr->num_ref_idx_l1_active_minus1 = 0; /* default, if above and B_slice */
/* the above 2 values range from 0..15 for frame picture and 0..31 for field picture */
/* ref_pic_list_reordering(), currently we don't do anything */
sliceHdr->ref_pic_list_reordering_flag_l0 = FALSE; /* default */
sliceHdr->ref_pic_list_reordering_flag_l1 = FALSE; /* default */
/* if the above are TRUE, some other params must be set */
if ((currPPS->weighted_pred_flag && (slice_type == AVC_P_SLICE || slice_type == AVC_SP_SLICE)) ||
(currPPS->weighted_bipred_idc == 1 && slice_type == AVC_B_SLICE))
{
// pred_weight_table(); // not supported !!
return AVCENC_TOOLS_NOT_SUPPORTED;
}
/* dec_ref_pic_marking(), this will be done later*/
sliceHdr->no_output_of_prior_pics_flag = FALSE; /* default */
sliceHdr->long_term_reference_flag = FALSE; /* for IDR frame, do not make it long term */
sliceHdr->adaptive_ref_pic_marking_mode_flag = FALSE; /* default */
/* other params are not set here because they are not used */
sliceHdr->cabac_init_idc = 0; /* default, if entropy_coding_mode_flag && slice_type==I or SI, range 0..2 */
sliceHdr->slice_qp_delta = 0; /* default for now */
sliceHdr->sp_for_switch_flag = FALSE; /* default, if slice_type == SP */
sliceHdr->slice_qs_delta = 0; /* default, if slice_type == SP or SI */
/* derived variables from encParam */
/* deblocking filter */
video->FilterOffsetA = video->FilterOffsetB = 0;
if (currPPS->deblocking_filter_control_present_flag == TRUE)
{
video->FilterOffsetA = sliceHdr->slice_alpha_c0_offset_div2 << 1;
video->FilterOffsetB = sliceHdr->slice_beta_offset_div_2 << 1;
}
/* flexible macroblock ordering */
/* populate video->mapUnitToSliceGroupMap and video->MbToSliceGroupMap */
/* We already call it at the end of PVAVCEncInitialize(). It changes once per each PPS. */
if (video->currPicParams->num_slice_groups_minus1 > 0 && video->currPicParams->slice_group_map_type >= 3
&& video->currPicParams->slice_group_map_type <= 5)
{
sliceHdr->slice_group_change_cycle = SLICE_GROUP_CHANGE_CYCLE; /* default, don't understand how to set it!!!*/
video->MapUnitsInSliceGroup0 =
AVC_MIN(sliceHdr->slice_group_change_cycle * video->SliceGroupChangeRate, video->PicSizeInMapUnits);
FMOInit(video);
}
/* calculate SliceQPy first */
/* calculate QSy first */
sliceHdr->slice_qp_delta = video->QPy - 26 - currPPS->pic_init_qp_minus26;
//sliceHdr->slice_qs_delta = video->QSy - 26 - currPPS->pic_init_qs_minus26;
return AVCENC_SUCCESS;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,981 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "avcenc_lib.h"
#include <math.h>
/* rate control variables */
#define RC_MAX_QUANT 51
#define RC_MIN_QUANT 0 //cap to 10 to prevent rate fluctuation
#define MAD_MIN 1 /* handle the case of devision by zero in RC */
/* local functions */
double QP2Qstep(int QP);
int Qstep2QP(double Qstep);
double ComputeFrameMAD(AVCCommonObj *video, AVCRateControl *rateCtrl);
void targetBitCalculation(AVCEncObject *encvid, AVCCommonObj *video, AVCRateControl *rateCtrl, MultiPass *pMP);
void calculateQuantizer_Multipass(AVCEncObject *encvid, AVCCommonObj *video,
AVCRateControl *rateCtrl, MultiPass *pMP);
void updateRC_PostProc(AVCRateControl *rateCtrl, MultiPass *pMP);
void AVCSaveRDSamples(MultiPass *pMP, int counter_samples);
void updateRateControl(AVCRateControl *rateControl, int nal_type);
int GetAvgFrameQP(AVCRateControl *rateCtrl)
{
return rateCtrl->Qc;
}
AVCEnc_Status RCDetermineFrameNum(AVCEncObject *encvid, AVCRateControl *rateCtrl, uint32 modTime, uint *frameNum)
{
AVCCommonObj *video = encvid->common;
AVCSliceHeader *sliceHdr = video->sliceHdr;
uint32 modTimeRef = encvid->modTimeRef;
int32 currFrameNum ;
int frameInc;
/* check with the buffer fullness to make sure that we have enough bits to encode this frame */
/* we can use a threshold to guarantee minimum picture quality */
/**********************************/
/* for now, the default is to encode every frame, To Be Changed */
if (rateCtrl->first_frame)
{
encvid->modTimeRef = modTime;
encvid->wrapModTime = 0;
encvid->prevFrameNum = 0;
encvid->prevProcFrameNum = 0;
*frameNum = 0;
/* set frame type to IDR-frame */
video->nal_unit_type = AVC_NALTYPE_IDR;
sliceHdr->slice_type = AVC_I_ALL_SLICE;
video->slice_type = AVC_I_SLICE;
return AVCENC_SUCCESS;
}
else
{
if (modTime < modTimeRef) /* modTime wrapped around */
{
encvid->wrapModTime += ((uint32)0xFFFFFFFF - modTimeRef) + 1;
encvid->modTimeRef = modTimeRef = 0;
}
modTime += encvid->wrapModTime; /* wrapModTime is non zero after wrap-around */
currFrameNum = (int32)(((modTime - modTimeRef) * rateCtrl->frame_rate + 200) / 1000); /* add small roundings */
if (currFrameNum <= (int32)encvid->prevProcFrameNum)
{
return AVCENC_FAIL; /* this is a late frame do not encode it */
}
frameInc = currFrameNum - encvid->prevProcFrameNum;
if (frameInc < rateCtrl->skip_next_frame + 1)
{
return AVCENC_FAIL; /* frame skip required to maintain the target bit rate. */
}
RCUpdateBuffer(video, rateCtrl, frameInc - rateCtrl->skip_next_frame); /* in case more frames dropped */
*frameNum = currFrameNum;
/* This part would be similar to DetermineVopType of m4venc */
if ((*frameNum >= (uint)rateCtrl->idrPeriod && rateCtrl->idrPeriod > 0) || (*frameNum > video->MaxFrameNum)) /* first frame or IDR*/
{
/* set frame type to IDR-frame */
if (rateCtrl->idrPeriod)
{
encvid->modTimeRef += (uint32)(rateCtrl->idrPeriod * 1000 / rateCtrl->frame_rate);
*frameNum -= rateCtrl->idrPeriod;
}
else
{
encvid->modTimeRef += (uint32)(video->MaxFrameNum * 1000 / rateCtrl->frame_rate);
*frameNum -= video->MaxFrameNum;
}
video->nal_unit_type = AVC_NALTYPE_IDR;
sliceHdr->slice_type = AVC_I_ALL_SLICE;
video->slice_type = AVC_I_SLICE;
encvid->prevProcFrameNum = *frameNum;
}
else
{
video->nal_unit_type = AVC_NALTYPE_SLICE;
sliceHdr->slice_type = AVC_P_ALL_SLICE;
video->slice_type = AVC_P_SLICE;
encvid->prevProcFrameNum = currFrameNum;
}
}
return AVCENC_SUCCESS;
}
void RCUpdateBuffer(AVCCommonObj *video, AVCRateControl *rateCtrl, int frameInc)
{
int tmp;
MultiPass *pMP = rateCtrl->pMP;
OSCL_UNUSED_ARG(video);
if (rateCtrl->rcEnable == TRUE)
{
if (frameInc > 1)
{
tmp = rateCtrl->bitsPerFrame * (frameInc - 1);
rateCtrl->VBV_fullness -= tmp;
pMP->counter_BTsrc += 10 * (frameInc - 1);
/* Check buffer underflow */
if (rateCtrl->VBV_fullness < rateCtrl->low_bound)
{
rateCtrl->VBV_fullness = rateCtrl->low_bound; // -rateCtrl->Bs/2;
rateCtrl->TMN_W = rateCtrl->VBV_fullness - rateCtrl->low_bound;
pMP->counter_BTsrc = pMP->counter_BTdst + (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
}
}
}
}
AVCEnc_Status InitRateControlModule(AVCHandle *avcHandle)
{
AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
double L1, L2, L3, bpp;
int qp;
int i, j;
rateCtrl->basicUnit = video->PicSizeInMbs;
rateCtrl->MADofMB = (double*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
video->PicSizeInMbs * sizeof(double), DEFAULT_ATTR);
if (!rateCtrl->MADofMB)
{
goto CLEANUP_RC;
}
if (rateCtrl->rcEnable == TRUE)
{
rateCtrl->pMP = (MultiPass*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, sizeof(MultiPass), DEFAULT_ATTR);
if (!rateCtrl->pMP)
{
goto CLEANUP_RC;
}
memset(rateCtrl->pMP, 0, sizeof(MultiPass));
rateCtrl->pMP->encoded_frames = -1; /* forget about the very first I frame */
/* RDInfo **pRDSamples */
rateCtrl->pMP->pRDSamples = (RDInfo **)avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, (30 * sizeof(RDInfo *)), DEFAULT_ATTR);
if (!rateCtrl->pMP->pRDSamples)
{
goto CLEANUP_RC;
}
for (i = 0; i < 30; i++)
{
rateCtrl->pMP->pRDSamples[i] = (RDInfo *)avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, (32 * sizeof(RDInfo)), DEFAULT_ATTR);
if (!rateCtrl->pMP->pRDSamples[i])
{
goto CLEANUP_RC;
}
for (j = 0; j < 32; j++) memset(&(rateCtrl->pMP->pRDSamples[i][j]), 0, sizeof(RDInfo));
}
rateCtrl->pMP->frameRange = (int)(rateCtrl->frame_rate * 1.0); /* 1.0s time frame*/
rateCtrl->pMP->frameRange = AVC_MAX(rateCtrl->pMP->frameRange, 5);
rateCtrl->pMP->frameRange = AVC_MIN(rateCtrl->pMP->frameRange, 30);
rateCtrl->pMP->framePos = -1;
rateCtrl->bitsPerFrame = (int32)(rateCtrl->bitRate / rateCtrl->frame_rate);
/* BX rate control */
rateCtrl->skip_next_frame = 0; /* must be initialized */
rateCtrl->Bs = rateCtrl->cpbSize;
rateCtrl->TMN_W = 0;
rateCtrl->VBV_fullness = (int)(rateCtrl->Bs * 0.5); /* rateCtrl->Bs */
rateCtrl->encoded_frames = 0;
rateCtrl->TMN_TH = rateCtrl->bitsPerFrame;
rateCtrl->max_BitVariance_num = (int)((OsclFloat)(rateCtrl->Bs - rateCtrl->VBV_fullness) / (rateCtrl->bitsPerFrame / 10.0)) - 5;
if (rateCtrl->max_BitVariance_num < 0) rateCtrl->max_BitVariance_num += 5;
// Set the initial buffer fullness
/* According to the spec, the initial buffer fullness needs to be set to 1/3 */
rateCtrl->VBV_fullness = (int)(rateCtrl->Bs / 3.0 - rateCtrl->Bs / 2.0); /* the buffer range is [-Bs/2, Bs/2] */
rateCtrl->pMP->counter_BTsrc = (int)((rateCtrl->Bs / 2.0 - rateCtrl->Bs / 3.0) / (rateCtrl->bitsPerFrame / 10.0));
rateCtrl->TMN_W = (int)(rateCtrl->VBV_fullness + rateCtrl->pMP->counter_BTsrc * (rateCtrl->bitsPerFrame / 10.0));
rateCtrl->low_bound = -rateCtrl->Bs / 2;
rateCtrl->VBV_fullness_offset = 0;
/* Setting the bitrate and framerate */
rateCtrl->pMP->bitrate = rateCtrl->bitRate;
rateCtrl->pMP->framerate = rateCtrl->frame_rate;
rateCtrl->pMP->target_bits_per_frame = rateCtrl->pMP->bitrate / rateCtrl->pMP->framerate;
/*compute the initial QP*/
bpp = 1.0 * rateCtrl->bitRate / (rateCtrl->frame_rate * (video->PicSizeInMbs << 8));
if (video->PicWidthInSamplesL == 176)
{
L1 = 0.1;
L2 = 0.3;
L3 = 0.6;
}
else if (video->PicWidthInSamplesL == 352)
{
L1 = 0.2;
L2 = 0.6;
L3 = 1.2;
}
else
{
L1 = 0.6;
L2 = 1.4;
L3 = 2.4;
}
if (rateCtrl->initQP == 0)
{
if (bpp <= L1)
qp = 35;
else if (bpp <= L2)
qp = 25;
else if (bpp <= L3)
qp = 20;
else
qp = 15;
rateCtrl->initQP = qp;
}
rateCtrl->Qc = rateCtrl->initQP;
}
return AVCENC_SUCCESS;
CLEANUP_RC:
CleanupRateControlModule(avcHandle);
return AVCENC_MEMORY_FAIL;
}
void CleanupRateControlModule(AVCHandle *avcHandle)
{
AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
AVCRateControl *rateCtrl = encvid->rateCtrl;
int i;
if (rateCtrl->MADofMB)
{
avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->MADofMB));
}
if (rateCtrl->pMP)
{
if (rateCtrl->pMP->pRDSamples)
{
for (i = 0; i < 30; i++)
{
if (rateCtrl->pMP->pRDSamples[i])
{
avcHandle->CBAVC_Free(avcHandle->userData, (int)rateCtrl->pMP->pRDSamples[i]);
}
}
avcHandle->CBAVC_Free(avcHandle->userData, (int)rateCtrl->pMP->pRDSamples);
}
avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->pMP));
}
return ;
}
void RCInitGOP(AVCEncObject *encvid)
{
/* in BX RC, there's no GOP-level RC */
OSCL_UNUSED_ARG(encvid);
return ;
}
void RCInitFrameQP(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
AVCPicParamSet *picParam = video->currPicParams;
MultiPass *pMP = rateCtrl->pMP;
if (rateCtrl->rcEnable == TRUE)
{
/* frame layer rate control */
if (rateCtrl->encoded_frames == 0)
{
video->QPy = rateCtrl->Qc = rateCtrl->initQP;
}
else
{
calculateQuantizer_Multipass(encvid, video, rateCtrl, pMP);
video->QPy = rateCtrl->Qc;
}
rateCtrl->NumberofHeaderBits = 0;
rateCtrl->NumberofTextureBits = 0;
rateCtrl->numFrameBits = 0; // reset
/* update pMP->framePos */
if (++pMP->framePos == pMP->frameRange) pMP->framePos = 0;
if (rateCtrl->T == 0)
{
pMP->counter_BTdst = (int)(rateCtrl->frame_rate * 7.5 + 0.5); /* 0.75s time frame */
pMP->counter_BTdst = AVC_MIN(pMP->counter_BTdst, (int)(rateCtrl->max_BitVariance_num / 2 * 0.40)); /* 0.75s time frame may go beyond VBV buffer if we set the buffer size smaller than 0.75s */
pMP->counter_BTdst = AVC_MAX(pMP->counter_BTdst, (int)((rateCtrl->Bs / 2 - rateCtrl->VBV_fullness) * 0.30 / (rateCtrl->TMN_TH / 10.0) + 0.5)); /* At least 30% of VBV buffer size/2 */
pMP->counter_BTdst = AVC_MIN(pMP->counter_BTdst, 20); /* Limit the target to be smaller than 3C */
pMP->target_bits = rateCtrl->T = rateCtrl->TMN_TH = (int)(rateCtrl->TMN_TH * (1.0 + pMP->counter_BTdst * 0.1));
pMP->diff_counter = pMP->counter_BTdst;
}
/* collect the necessary data: target bits, actual bits, mad and QP */
pMP->target_bits = rateCtrl->T;
pMP->QP = video->QPy;
pMP->mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs; //ComputeFrameMAD(video, rateCtrl);
if (pMP->mad < MAD_MIN) pMP->mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */
pMP->bitrate = rateCtrl->bitRate; /* calculated in RCVopQPSetting */
pMP->framerate = rateCtrl->frame_rate;
/* first pass encoding */
pMP->nRe_Quantized = 0;
} // rcEnable
else
{
video->QPy = rateCtrl->initQP;
}
// printf(" %d ",video->QPy);
if (video->CurrPicNum == 0 && encvid->outOfBandParamSet == FALSE)
{
picParam->pic_init_qs_minus26 = 0;
picParam->pic_init_qp_minus26 = video->QPy - 26;
}
// need this for motion estimation
encvid->lambda_mode = QP2QUANT[AVC_MAX(0, video->QPy-SHIFT_QP)];
encvid->lambda_motion = LAMBDA_FACTOR(encvid->lambda_mode);
return ;
}
/* Mad based variable bit allocation + QP calculation with a new quadratic method */
void calculateQuantizer_Multipass(AVCEncObject *encvid, AVCCommonObj *video,
AVCRateControl *rateCtrl, MultiPass *pMP)
{
int prev_actual_bits = 0, curr_target, /*pos=0,*/i, j;
OsclFloat Qstep, prev_QP = 0.625;
OsclFloat curr_mad, prev_mad, curr_RD, prev_RD, average_mad, aver_QP;
/* Mad based variable bit allocation */
targetBitCalculation(encvid, video, rateCtrl, pMP);
if (rateCtrl->T <= 0 || rateCtrl->totalSAD == 0)
{
if (rateCtrl->T < 0) rateCtrl->Qc = RC_MAX_QUANT;
return;
}
/* ---------------------------------------------------------------------------------------------------*/
/* current frame QP estimation */
curr_target = rateCtrl->T;
curr_mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs;
if (curr_mad < MAD_MIN) curr_mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */
curr_RD = (OsclFloat)curr_target / curr_mad;
if (rateCtrl->skip_next_frame == -1) // previous was skipped
{
i = pMP->framePos;
prev_mad = pMP->pRDSamples[i][0].mad;
prev_QP = pMP->pRDSamples[i][0].QP;
prev_actual_bits = pMP->pRDSamples[i][0].actual_bits;
}
else
{
/* Another version of search the optimal point */
prev_mad = 0.0;
i = 0;
while (i < pMP->frameRange && prev_mad < 0.001) /* find first one with nonzero prev_mad */
{
prev_mad = pMP->pRDSamples[i][0].mad;
i++;
}
if (i < pMP->frameRange)
{
prev_actual_bits = pMP->pRDSamples[i-1][0].actual_bits;
for (j = 0; i < pMP->frameRange; i++)
{
if (pMP->pRDSamples[i][0].mad != 0 &&
AVC_ABS(prev_mad - curr_mad) > AVC_ABS(pMP->pRDSamples[i][0].mad - curr_mad))
{
prev_mad = pMP->pRDSamples[i][0].mad;
prev_actual_bits = pMP->pRDSamples[i][0].actual_bits;
j = i;
}
}
prev_QP = QP2Qstep(pMP->pRDSamples[j][0].QP);
for (i = 1; i < pMP->samplesPerFrame[j]; i++)
{
if (AVC_ABS(prev_actual_bits - curr_target) > AVC_ABS(pMP->pRDSamples[j][i].actual_bits - curr_target))
{
prev_actual_bits = pMP->pRDSamples[j][i].actual_bits;
prev_QP = QP2Qstep(pMP->pRDSamples[j][i].QP);
}
}
}
}
// quadratic approximation
if (prev_mad > 0.001) // only when prev_mad is greater than 0, otherwise keep using the same QP
{
prev_RD = (OsclFloat)prev_actual_bits / prev_mad;
//rateCtrl->Qc = (Int)(prev_QP * sqrt(prev_actual_bits/curr_target) + 0.4);
if (prev_QP == 0.625) // added this to allow getting out of QP = 0 easily
{
Qstep = (int)(prev_RD / curr_RD + 0.5);
}
else
{
// rateCtrl->Qc =(Int)(prev_QP * M4VENC_SQRT(prev_RD/curr_RD) + 0.9);
if (prev_RD / curr_RD > 0.5 && prev_RD / curr_RD < 2.0)
Qstep = (int)(prev_QP * (sqrt(prev_RD / curr_RD) + prev_RD / curr_RD) / 2.0 + 0.9); /* Quadratic and linear approximation */
else
Qstep = (int)(prev_QP * (sqrt(prev_RD / curr_RD) + pow(prev_RD / curr_RD, 1.0 / 3.0)) / 2.0 + 0.9);
}
// lower bound on Qc should be a function of curr_mad
// When mad is already low, lower bound on Qc doesn't have to be small.
// Note, this doesn't work well for low complexity clip encoded at high bit rate
// it doesn't hit the target bit rate due to this QP lower bound.
/// if((curr_mad < 8) && (rateCtrl->Qc < 12)) rateCtrl->Qc = 12;
// else if((curr_mad < 128) && (rateCtrl->Qc < 3)) rateCtrl->Qc = 3;
rateCtrl->Qc = Qstep2QP(Qstep);
if (rateCtrl->Qc < RC_MIN_QUANT) rateCtrl->Qc = RC_MIN_QUANT;
if (rateCtrl->Qc > RC_MAX_QUANT) rateCtrl->Qc = RC_MAX_QUANT;
}
/* active bit resource protection */
aver_QP = (pMP->encoded_frames == 0 ? 0 : pMP->sum_QP / (OsclFloat)pMP->encoded_frames);
average_mad = (pMP->encoded_frames == 0 ? 0 : pMP->sum_mad / (OsclFloat)pMP->encoded_frames); /* this function is called from the scond encoded frame*/
if (pMP->diff_counter == 0 &&
((OsclFloat)rateCtrl->Qc <= aver_QP*1.1 || curr_mad <= average_mad*1.1) &&
pMP->counter_BTsrc <= (pMP->counter_BTdst + (int)(pMP->framerate*1.0 + 0.5)))
{
rateCtrl->TMN_TH -= (int)(pMP->target_bits_per_frame / 10.0);
rateCtrl->T = rateCtrl->TMN_TH - rateCtrl->TMN_W;
pMP->counter_BTsrc++;
pMP->diff_counter--;
}
}
void targetBitCalculation(AVCEncObject *encvid, AVCCommonObj *video, AVCRateControl *rateCtrl, MultiPass *pMP)
{
OSCL_UNUSED_ARG(encvid);
OsclFloat curr_mad;//, average_mad;
int diff_counter_BTsrc, diff_counter_BTdst, prev_counter_diff, curr_counter_diff, bound;
/* BT = Bit Transfer, for pMP->counter_BTsrc, pMP->counter_BTdst */
/* some stuff about frame dropping remained here to be done because pMP cannot be inserted into updateRateControl()*/
updateRC_PostProc(rateCtrl, pMP);
/* update pMP->counter_BTsrc and pMP->counter_BTdst to avoid interger overflow */
if (pMP->counter_BTsrc > 1000 && pMP->counter_BTdst > 1000)
{
pMP->counter_BTsrc -= 1000;
pMP->counter_BTdst -= 1000;
}
/* ---------------------------------------------------------------------------------------------------*/
/* target calculation */
curr_mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs;
if (curr_mad < MAD_MIN) curr_mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */
diff_counter_BTsrc = diff_counter_BTdst = 0;
pMP->diff_counter = 0;
/*1.calculate average mad */
pMP->sum_mad += curr_mad;
//average_mad = (pMP->encoded_frames < 1 ? curr_mad : pMP->sum_mad/(OsclFloat)(pMP->encoded_frames+1)); /* this function is called from the scond encoded frame*/
//pMP->aver_mad = average_mad;
if (pMP->encoded_frames >= 0) /* pMP->encoded_frames is set to -1 initially, so forget about the very first I frame */
pMP->aver_mad = (pMP->aver_mad * pMP->encoded_frames + curr_mad) / (pMP->encoded_frames + 1);
if (pMP->overlapped_win_size > 0 && pMP->encoded_frames_prev >= 0)
pMP->aver_mad_prev = (pMP->aver_mad_prev * pMP->encoded_frames_prev + curr_mad) / (pMP->encoded_frames_prev + 1);
/*2.average_mad, mad ==> diff_counter_BTsrc, diff_counter_BTdst */
if (pMP->overlapped_win_size == 0)
{
/* original verison */
if (curr_mad > pMP->aver_mad*1.1)
{
if (curr_mad / (pMP->aver_mad + 0.0001) > 2)
diff_counter_BTdst = (int)(sqrt(curr_mad / (pMP->aver_mad + 0.0001)) * 10 + 0.4) - 10;
//diff_counter_BTdst = (int)((sqrt(curr_mad/pMP->aver_mad)*2+curr_mad/pMP->aver_mad)/(3*0.1) + 0.4) - 10;
else
diff_counter_BTdst = (int)(curr_mad / (pMP->aver_mad + 0.0001) * 10 + 0.4) - 10;
}
else /* curr_mad <= average_mad*1.1 */
//diff_counter_BTsrc = 10 - (int)((sqrt(curr_mad/pMP->aver_mad) + pow(curr_mad/pMP->aver_mad, 1.0/3.0))/(2.0*0.1) + 0.4);
diff_counter_BTsrc = 10 - (int)(sqrt(curr_mad / (pMP->aver_mad + 0.0001)) * 10 + 0.5);
/* actively fill in the possible gap */
if (diff_counter_BTsrc == 0 && diff_counter_BTdst == 0 &&
curr_mad <= pMP->aver_mad*1.1 && pMP->counter_BTsrc < pMP->counter_BTdst)
diff_counter_BTsrc = 1;
}
else if (pMP->overlapped_win_size > 0)
{
/* transition time: use previous average mad "pMP->aver_mad_prev" instead of the current average mad "pMP->aver_mad" */
if (curr_mad > pMP->aver_mad_prev*1.1)
{
if (curr_mad / pMP->aver_mad_prev > 2)
diff_counter_BTdst = (int)(sqrt(curr_mad / (pMP->aver_mad_prev + 0.0001)) * 10 + 0.4) - 10;
//diff_counter_BTdst = (int)((M4VENC_SQRT(curr_mad/pMP->aver_mad_prev)*2+curr_mad/pMP->aver_mad_prev)/(3*0.1) + 0.4) - 10;
else
diff_counter_BTdst = (int)(curr_mad / (pMP->aver_mad_prev + 0.0001) * 10 + 0.4) - 10;
}
else /* curr_mad <= average_mad*1.1 */
//diff_counter_BTsrc = 10 - (Int)((sqrt(curr_mad/pMP->aver_mad_prev) + pow(curr_mad/pMP->aver_mad_prev, 1.0/3.0))/(2.0*0.1) + 0.4);
diff_counter_BTsrc = 10 - (int)(sqrt(curr_mad / (pMP->aver_mad_prev + 0.0001)) * 10 + 0.5);
/* actively fill in the possible gap */
if (diff_counter_BTsrc == 0 && diff_counter_BTdst == 0 &&
curr_mad <= pMP->aver_mad_prev*1.1 && pMP->counter_BTsrc < pMP->counter_BTdst)
diff_counter_BTsrc = 1;
if (--pMP->overlapped_win_size <= 0) pMP->overlapped_win_size = 0;
}
/* if difference is too much, do clipping */
/* First, set the upper bound for current bit allocation variance: 80% of available buffer */
bound = (int)((rateCtrl->Bs / 2 - rateCtrl->VBV_fullness) * 0.6 / (pMP->target_bits_per_frame / 10)); /* rateCtrl->Bs */
diff_counter_BTsrc = AVC_MIN(diff_counter_BTsrc, bound);
diff_counter_BTdst = AVC_MIN(diff_counter_BTdst, bound);
/* Second, set another upper bound for current bit allocation: 4-5*bitrate/framerate */
bound = 50;
// if(video->encParams->RC_Type == CBR_LOWDELAY)
// not necessary bound = 10; -- For Low delay */
diff_counter_BTsrc = AVC_MIN(diff_counter_BTsrc, bound);
diff_counter_BTdst = AVC_MIN(diff_counter_BTdst, bound);
/* Third, check the buffer */
prev_counter_diff = pMP->counter_BTdst - pMP->counter_BTsrc;
curr_counter_diff = prev_counter_diff + (diff_counter_BTdst - diff_counter_BTsrc);
if (AVC_ABS(prev_counter_diff) >= rateCtrl->max_BitVariance_num || AVC_ABS(curr_counter_diff) >= rateCtrl->max_BitVariance_num)
{ //diff_counter_BTsrc = diff_counter_BTdst = 0;
if (curr_counter_diff > rateCtrl->max_BitVariance_num && diff_counter_BTdst)
{
diff_counter_BTdst = (rateCtrl->max_BitVariance_num - prev_counter_diff) + diff_counter_BTsrc;
if (diff_counter_BTdst < 0) diff_counter_BTdst = 0;
}
else if (curr_counter_diff < -rateCtrl->max_BitVariance_num && diff_counter_BTsrc)
{
diff_counter_BTsrc = diff_counter_BTdst - (-rateCtrl->max_BitVariance_num - prev_counter_diff);
if (diff_counter_BTsrc < 0) diff_counter_BTsrc = 0;
}
}
/*3.diff_counter_BTsrc, diff_counter_BTdst ==> TMN_TH */
rateCtrl->TMN_TH = (int)(pMP->target_bits_per_frame);
pMP->diff_counter = 0;
if (diff_counter_BTsrc)
{
rateCtrl->TMN_TH -= (int)(pMP->target_bits_per_frame * diff_counter_BTsrc * 0.1);
pMP->diff_counter = -diff_counter_BTsrc;
}
else if (diff_counter_BTdst)
{
rateCtrl->TMN_TH += (int)(pMP->target_bits_per_frame * diff_counter_BTdst * 0.1);
pMP->diff_counter = diff_counter_BTdst;
}
/*4.update pMP->counter_BTsrc, pMP->counter_BTdst */
pMP->counter_BTsrc += diff_counter_BTsrc;
pMP->counter_BTdst += diff_counter_BTdst;
/*5.target bit calculation */
rateCtrl->T = rateCtrl->TMN_TH - rateCtrl->TMN_W;
return ;
}
void updateRC_PostProc(AVCRateControl *rateCtrl, MultiPass *pMP)
{
if (rateCtrl->skip_next_frame > 0) /* skip next frame */
{
pMP->counter_BTsrc += 10 * rateCtrl->skip_next_frame;
}
else if (rateCtrl->skip_next_frame == -1) /* skip current frame */
{
pMP->counter_BTdst -= pMP->diff_counter;
pMP->counter_BTsrc += 10;
pMP->sum_mad -= pMP->mad;
pMP->aver_mad = (pMP->aver_mad * pMP->encoded_frames - pMP->mad) / (pMP->encoded_frames - 1 + 0.0001);
pMP->sum_QP -= pMP->QP;
pMP->encoded_frames --;
}
/* some stuff in update VBV_fullness remains here */
//if(rateCtrl->VBV_fullness < -rateCtrl->Bs/2) /* rateCtrl->Bs */
if (rateCtrl->VBV_fullness < rateCtrl->low_bound)
{
rateCtrl->VBV_fullness = rateCtrl->low_bound; // -rateCtrl->Bs/2;
rateCtrl->TMN_W = rateCtrl->VBV_fullness - rateCtrl->low_bound;
pMP->counter_BTsrc = pMP->counter_BTdst + (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
}
}
void RCInitChromaQP(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCMacroblock *currMB = video->currMB;
int q_bits;
/* we have to do the same thing for AVC_CLIP3(0,51,video->QSy) */
video->QPy_div_6 = (currMB->QPy * 43) >> 8;
video->QPy_mod_6 = currMB->QPy - 6 * video->QPy_div_6;
currMB->QPc = video->QPc = mapQPi2QPc[AVC_CLIP3(0, 51, currMB->QPy + video->currPicParams->chroma_qp_index_offset)];
video->QPc_div_6 = (video->QPc * 43) >> 8;
video->QPc_mod_6 = video->QPc - 6 * video->QPc_div_6;
/* pre-calculate this to save computation */
q_bits = 4 + video->QPy_div_6;
if (video->slice_type == AVC_I_SLICE)
{
encvid->qp_const = 682 << q_bits; // intra
}
else
{
encvid->qp_const = 342 << q_bits; // inter
}
q_bits = 4 + video->QPc_div_6;
if (video->slice_type == AVC_I_SLICE)
{
encvid->qp_const_c = 682 << q_bits; // intra
}
else
{
encvid->qp_const_c = 342 << q_bits; // inter
}
encvid->lambda_mode = QP2QUANT[AVC_MAX(0, currMB->QPy-SHIFT_QP)];
encvid->lambda_motion = LAMBDA_FACTOR(encvid->lambda_mode);
return ;
}
void RCInitMBQP(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCMacroblock *currMB = video->currMB;
currMB->QPy = video->QPy; /* set to previous value or picture level */
RCInitChromaQP(encvid);
}
void RCPostMB(AVCCommonObj *video, AVCRateControl *rateCtrl, int num_header_bits, int num_texture_bits)
{
OSCL_UNUSED_ARG(video);
rateCtrl->numMBHeaderBits = num_header_bits;
rateCtrl->numMBTextureBits = num_texture_bits;
rateCtrl->NumberofHeaderBits += rateCtrl->numMBHeaderBits;
rateCtrl->NumberofTextureBits += rateCtrl->numMBTextureBits;
}
void RCRestoreQP(AVCMacroblock *currMB, AVCCommonObj *video, AVCEncObject *encvid)
{
currMB->QPy = video->QPy; /* use previous QP */
RCInitChromaQP(encvid);
return ;
}
void RCCalculateMAD(AVCEncObject *encvid, AVCMacroblock *currMB, uint8 *orgL, int orgPitch)
{
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
uint32 dmin_lx;
if (rateCtrl->rcEnable == TRUE)
{
if (currMB->mb_intra)
{
if (currMB->mbMode == AVC_I16)
{
dmin_lx = (0xFFFF << 16) | orgPitch;
rateCtrl->MADofMB[video->mbNum] = AVCSAD_Macroblock_C(orgL,
encvid->pred_i16[currMB->i16Mode], dmin_lx, NULL);
}
else /* i4 */
{
rateCtrl->MADofMB[video->mbNum] = encvid->i4_sad / 256.;
}
}
/* for INTER, we have already saved it with the MV search */
}
return ;
}
AVCEnc_Status RCUpdateFrame(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
AVCEnc_Status status = AVCENC_SUCCESS;
MultiPass *pMP = rateCtrl->pMP;
int diff_BTCounter;
int nal_type = video->nal_unit_type;
/* update the complexity weight of I, P, B frame */
if (rateCtrl->rcEnable == TRUE)
{
pMP->actual_bits = rateCtrl->numFrameBits;
pMP->mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs; //ComputeFrameMAD(video, rateCtrl);
AVCSaveRDSamples(pMP, 0);
pMP->encoded_frames++;
/* for pMP->samplesPerFrame */
pMP->samplesPerFrame[pMP->framePos] = 0;
pMP->sum_QP += pMP->QP;
/* update pMP->counter_BTsrc, pMP->counter_BTdst */
/* re-allocate the target bit again and then stop encoding */
diff_BTCounter = (int)((OsclFloat)(rateCtrl->TMN_TH - rateCtrl->TMN_W - pMP->actual_bits) /
(pMP->bitrate / (pMP->framerate + 0.0001) + 0.0001) / 0.1);
if (diff_BTCounter >= 0)
pMP->counter_BTsrc += diff_BTCounter; /* pMP->actual_bits is smaller */
else
pMP->counter_BTdst -= diff_BTCounter; /* pMP->actual_bits is bigger */
rateCtrl->TMN_TH -= (int)((OsclFloat)pMP->bitrate / (pMP->framerate + 0.0001) * (diff_BTCounter * 0.1));
rateCtrl->T = pMP->target_bits = rateCtrl->TMN_TH - rateCtrl->TMN_W;
pMP->diff_counter -= diff_BTCounter;
rateCtrl->Rc = rateCtrl->numFrameBits; /* Total Bits for current frame */
rateCtrl->Hc = rateCtrl->NumberofHeaderBits; /* Total Bits in Header and Motion Vector */
/* BX_RC */
updateRateControl(rateCtrl, nal_type);
if (rateCtrl->skip_next_frame == -1) // skip current frame
{
status = AVCENC_SKIPPED_PICTURE;
}
}
rateCtrl->first_frame = 0; // reset here after we encode the first frame.
return status;
}
void AVCSaveRDSamples(MultiPass *pMP, int counter_samples)
{
/* for pMP->pRDSamples */
pMP->pRDSamples[pMP->framePos][counter_samples].QP = pMP->QP;
pMP->pRDSamples[pMP->framePos][counter_samples].actual_bits = pMP->actual_bits;
pMP->pRDSamples[pMP->framePos][counter_samples].mad = pMP->mad;
pMP->pRDSamples[pMP->framePos][counter_samples].R_D = (OsclFloat)pMP->actual_bits / (pMP->mad + 0.0001);
return ;
}
void updateRateControl(AVCRateControl *rateCtrl, int nal_type)
{
int frame_bits;
MultiPass *pMP = rateCtrl->pMP;
/* BX rate contro\l */
frame_bits = (int)(rateCtrl->bitRate / rateCtrl->frame_rate);
rateCtrl->TMN_W += (rateCtrl->Rc - rateCtrl->TMN_TH);
rateCtrl->VBV_fullness += (rateCtrl->Rc - frame_bits); //rateCtrl->Rp);
//if(rateCtrl->VBV_fullness < 0) rateCtrl->VBV_fullness = -1;
rateCtrl->encoded_frames++;
/* frame dropping */
rateCtrl->skip_next_frame = 0;
if ((rateCtrl->VBV_fullness > rateCtrl->Bs / 2) && nal_type != AVC_NALTYPE_IDR) /* skip the current frame */ /* rateCtrl->Bs */
{
rateCtrl->TMN_W -= (rateCtrl->Rc - rateCtrl->TMN_TH);
rateCtrl->VBV_fullness -= rateCtrl->Rc;
rateCtrl->skip_next_frame = -1;
}
else if ((OsclFloat)(rateCtrl->VBV_fullness - rateCtrl->VBV_fullness_offset) > (rateCtrl->Bs / 2 - rateCtrl->VBV_fullness_offset)*0.95) /* skip next frame */
{
rateCtrl->VBV_fullness -= frame_bits; //rateCtrl->Rp;
rateCtrl->skip_next_frame = 1;
pMP->counter_BTsrc -= (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
/* BX_1, skip more than 1 frames */
//while(rateCtrl->VBV_fullness > rateCtrl->Bs*0.475)
while ((rateCtrl->VBV_fullness - rateCtrl->VBV_fullness_offset) > (rateCtrl->Bs / 2 - rateCtrl->VBV_fullness_offset)*0.95)
{
rateCtrl->VBV_fullness -= frame_bits; //rateCtrl->Rp;
rateCtrl->skip_next_frame++;
pMP->counter_BTsrc -= (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
}
/* END BX_1 */
}
}
double ComputeFrameMAD(AVCCommonObj *video, AVCRateControl *rateCtrl)
{
double TotalMAD;
int i;
TotalMAD = 0.0;
for (i = 0; i < (int)video->PicSizeInMbs; i++)
TotalMAD += rateCtrl->MADofMB[i];
TotalMAD /= video->PicSizeInMbs;
return TotalMAD;
}
/* convert from QP to Qstep */
double QP2Qstep(int QP)
{
int i;
double Qstep;
static const double QP2QSTEP[6] = { 0.625, 0.6875, 0.8125, 0.875, 1.0, 1.125 };
Qstep = QP2QSTEP[QP % 6];
for (i = 0; i < (QP / 6); i++)
Qstep *= 2;
return Qstep;
}
/* convert from step size to QP */
int Qstep2QP(double Qstep)
{
int q_per = 0, q_rem = 0;
// assert( Qstep >= QP2Qstep(0) && Qstep <= QP2Qstep(51) );
if (Qstep < QP2Qstep(0))
return 0;
else if (Qstep > QP2Qstep(51))
return 51;
while (Qstep > QP2Qstep(5))
{
Qstep /= 2;
q_per += 1;
}
if (Qstep <= (0.625 + 0.6875) / 2)
{
Qstep = 0.625;
q_rem = 0;
}
else if (Qstep <= (0.6875 + 0.8125) / 2)
{
Qstep = 0.6875;
q_rem = 1;
}
else if (Qstep <= (0.8125 + 0.875) / 2)
{
Qstep = 0.8125;
q_rem = 2;
}
else if (Qstep <= (0.875 + 1.0) / 2)
{
Qstep = 0.875;
q_rem = 3;
}
else if (Qstep <= (1.0 + 1.125) / 2)
{
Qstep = 1.0;
q_rem = 4;
}
else
{
Qstep = 1.125;
q_rem = 5;
}
return (q_per * 6 + q_rem);
}

View File

@@ -0,0 +1,389 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "avcenc_lib.h"
AVCEnc_Status EncodeIntraPCM(AVCEncObject *encvid)
{
AVCEnc_Status status = AVCENC_SUCCESS;
AVCCommonObj *video = encvid->common;
AVCFrameIO *currInput = encvid->currInput;
AVCEncBitstream *stream = encvid->bitstream;
int x_position = (video->mb_x << 4);
int y_position = (video->mb_y << 4);
int orgPitch = currInput->pitch;
int offset1 = y_position * orgPitch + x_position;
int i, j;
int offset;
uint8 *pDst, *pSrc;
uint code;
ue_v(stream, 25);
i = stream->bit_left & 0x7;
if (i) /* not byte-aligned */
{
BitstreamWriteBits(stream, 0, i);
}
pSrc = currInput->YCbCr[0] + offset1;
pDst = video->currPic->Sl + offset1;
offset = video->PicWidthInSamplesL - 16;
/* at this point bitstream is byte-aligned */
j = 16;
while (j > 0)
{
#if (WORD_SIZE==32)
for (i = 0; i < 4; i++)
{
code = *((uint*)pSrc);
pSrc += 4;
*((uint*)pDst) = code;
pDst += 4;
status = BitstreamWriteBits(stream, 32, code);
}
#else
for (i = 0; i < 8; i++)
{
code = *((uint*)pSrc);
pSrc += 2;
*((uint*)pDst) = code;
pDst += 2;
status = BitstreamWriteBits(stream, 16, code);
}
#endif
pDst += offset;
pSrc += offset;
j--;
}
if (status != AVCENC_SUCCESS) /* check only once per line */
return status;
pDst = video->currPic->Scb + ((offset1 + x_position) >> 2);
pSrc = currInput->YCbCr[1] + ((offset1 + x_position) >> 2);
offset >>= 1;
j = 8;
while (j > 0)
{
#if (WORD_SIZE==32)
for (i = 0; i < 2; i++)
{
code = *((uint*)pSrc);
pSrc += 4;
*((uint*)pDst) = code;
pDst += 4;
status = BitstreamWriteBits(stream, 32, code);
}
#else
for (i = 0; i < 4; i++)
{
code = *((uint*)pSrc);
pSrc += 2;
*((uint*)pDst) = code;
pDst += 2;
status = BitstreamWriteBits(stream, 16, code);
}
#endif
pDst += offset;
pSrc += offset;
j--;
}
if (status != AVCENC_SUCCESS) /* check only once per line */
return status;
pDst = video->currPic->Scr + ((offset1 + x_position) >> 2);
pSrc = currInput->YCbCr[2] + ((offset1 + x_position) >> 2);
j = 8;
while (j > 0)
{
#if (WORD_SIZE==32)
for (i = 0; i < 2; i++)
{
code = *((uint*)pSrc);
pSrc += 4;
*((uint*)pDst) = code;
pDst += 4;
status = BitstreamWriteBits(stream, 32, code);
}
#else
for (i = 0; i < 4; i++)
{
code = *((uint*)pSrc);
pSrc += 2;
*((uint*)pDst) = code;
pDst += 2;
status = BitstreamWriteBits(stream, 16, code);
}
#endif
pDst += offset;
pSrc += offset;
j--;
}
return status;
}
AVCEnc_Status enc_residual_block(AVCEncObject *encvid, AVCResidualType type, int cindx, AVCMacroblock *currMB)
{
AVCEnc_Status status = AVCENC_SUCCESS;
AVCCommonObj *video = encvid->common;
int i, maxNumCoeff, nC;
int cdc = 0, cac = 0;
int TrailingOnes;
AVCEncBitstream *stream = encvid->bitstream;
uint trailing_ones_sign_flag;
int zerosLeft;
int *level, *run;
int TotalCoeff;
const static int incVlc[] = {0, 3, 6, 12, 24, 48, 32768}; // maximum vlc = 6
int escape, numPrefix, sufmask, suffix, shift, sign, value, absvalue, vlcnum, level_two_or_higher;
int bindx = blkIdx2blkXY[cindx>>2][cindx&3] ; // raster scan index
switch (type)
{
case AVC_Luma:
maxNumCoeff = 16;
level = encvid->level[cindx];
run = encvid->run[cindx];
TotalCoeff = currMB->nz_coeff[bindx];
break;
case AVC_Intra16DC:
maxNumCoeff = 16;
level = encvid->leveldc;
run = encvid->rundc;
TotalCoeff = cindx; /* special case */
bindx = 0;
cindx = 0;
break;
case AVC_Intra16AC:
maxNumCoeff = 15;
level = encvid->level[cindx];
run = encvid->run[cindx];
TotalCoeff = currMB->nz_coeff[bindx];
break;
case AVC_ChromaDC: /* how to differentiate Cb from Cr */
maxNumCoeff = 4;
cdc = 1;
if (cindx >= 8)
{
level = encvid->levelcdc + 4;
run = encvid->runcdc + 4;
TotalCoeff = cindx - 8; /* special case */
}
else
{
level = encvid->levelcdc;
run = encvid->runcdc;
TotalCoeff = cindx; /* special case */
}
break;
case AVC_ChromaAC:
maxNumCoeff = 15;
cac = 1;
level = encvid->level[cindx];
run = encvid->run[cindx];
cindx -= 16;
bindx = 16 + blkIdx2blkXY[cindx>>2][cindx&3];
cindx += 16;
TotalCoeff = currMB->nz_coeff[bindx];
break;
default:
return AVCENC_FAIL;
}
/* find TrailingOnes */
TrailingOnes = 0;
zerosLeft = 0;
i = TotalCoeff - 1;
nC = 1;
while (i >= 0)
{
zerosLeft += run[i];
if (nC && (level[i] == 1 || level[i] == -1))
{
TrailingOnes++;
}
else
{
nC = 0;
}
i--;
}
if (TrailingOnes > 3)
{
TrailingOnes = 3; /* clip it */
}
if (!cdc)
{
if (!cac) /* not chroma */
{
nC = predict_nnz(video, bindx & 3, bindx >> 2);
}
else /* chroma ac but not chroma dc */
{
nC = predict_nnz_chroma(video, bindx & 3, bindx >> 2);
}
status = ce_TotalCoeffTrailingOnes(stream, TrailingOnes, TotalCoeff, nC);
}
else
{
nC = -1; /* Chroma DC level */
status = ce_TotalCoeffTrailingOnesChromaDC(stream, TrailingOnes, TotalCoeff);
}
/* This part is done quite differently in ReadCoef4x4_CAVLC() */
if (TotalCoeff > 0)
{
i = TotalCoeff - 1;
if (TrailingOnes) /* keep reading the sign of those trailing ones */
{
nC = TrailingOnes;
trailing_ones_sign_flag = 0;
while (nC)
{
trailing_ones_sign_flag <<= 1;
trailing_ones_sign_flag |= ((uint32)level[i--] >> 31); /* 0 or positive, 1 for negative */
nC--;
}
/* instead of writing one bit at a time, read the whole thing at once */
status = BitstreamWriteBits(stream, TrailingOnes, trailing_ones_sign_flag);
}
level_two_or_higher = 1;
if (TotalCoeff > 3 && TrailingOnes == 3)
{
level_two_or_higher = 0;
}
if (TotalCoeff > 10 && TrailingOnes < 3)
{
vlcnum = 1;
}
else
{
vlcnum = 0;
}
/* then do this TotalCoeff-TrailingOnes times */
for (i = TotalCoeff - TrailingOnes - 1; i >= 0; i--)
{
value = level[i];
absvalue = (value >= 0) ? value : -value;
if (level_two_or_higher)
{
if (value > 0) value--;
else value++;
level_two_or_higher = 0;
}
if (value >= 0)
{
sign = 0;
}
else
{
sign = 1;
value = -value;
}
if (vlcnum == 0) // VLC1
{
if (value < 8)
{
status = BitstreamWriteBits(stream, value * 2 + sign - 1, 1);
}
else if (value < 8 + 8)
{
status = BitstreamWriteBits(stream, 14 + 1 + 4, (1 << 4) | ((value - 8) << 1) | sign);
}
else
{
status = BitstreamWriteBits(stream, 14 + 2 + 12, (1 << 12) | ((value - 16) << 1) | sign) ;
}
}
else // VLCN
{
shift = vlcnum - 1;
escape = (15 << shift) + 1;
numPrefix = (value - 1) >> shift;
sufmask = ~((0xffffffff) << shift);
suffix = (value - 1) & sufmask;
if (value < escape)
{
status = BitstreamWriteBits(stream, numPrefix + vlcnum + 1, (1 << (shift + 1)) | (suffix << 1) | sign);
}
else
{
status = BitstreamWriteBits(stream, 28, (1 << 12) | ((value - escape) << 1) | sign);
}
}
if (absvalue > incVlc[vlcnum])
vlcnum++;
if (i == TotalCoeff - TrailingOnes - 1 && absvalue > 3)
vlcnum = 2;
}
if (status != AVCENC_SUCCESS) /* occasionally check the bitstream */
{
return status;
}
if (TotalCoeff < maxNumCoeff)
{
if (!cdc)
{
ce_TotalZeros(stream, zerosLeft, TotalCoeff);
}
else
{
ce_TotalZerosChromaDC(stream, zerosLeft, TotalCoeff);
}
}
else
{
zerosLeft = 0;
}
i = TotalCoeff - 1;
while (i > 0) /* don't do the last one */
{
if (zerosLeft > 0)
{
ce_RunBefore(stream, run[i], zerosLeft);
}
zerosLeft = zerosLeft - run[i];
i--;
}
}
return status;
}

View File

@@ -0,0 +1,290 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "avcenc_lib.h"
#include "sad_inline.h"
#define Cached_lx 176
#ifdef _SAD_STAT
uint32 num_sad_MB = 0;
uint32 num_sad_Blk = 0;
uint32 num_sad_MB_call = 0;
uint32 num_sad_Blk_call = 0;
#define NUM_SAD_MB_CALL() num_sad_MB_call++
#define NUM_SAD_MB() num_sad_MB++
#define NUM_SAD_BLK_CALL() num_sad_Blk_call++
#define NUM_SAD_BLK() num_sad_Blk++
#else
#define NUM_SAD_MB_CALL()
#define NUM_SAD_MB()
#define NUM_SAD_BLK_CALL()
#define NUM_SAD_BLK()
#endif
/* consist of
int AVCSAD_Macroblock_C(uint8 *ref,uint8 *blk,int dmin,int lx,void *extra_info)
int AVCSAD_MB_HTFM_Collect(uint8 *ref,uint8 *blk,int dmin,int lx,void *extra_info)
int AVCSAD_MB_HTFM(uint8 *ref,uint8 *blk,int dmin,int lx,void *extra_info)
*/
/*==================================================================
Function: SAD_Macroblock
Date: 09/07/2000
Purpose: Compute SAD 16x16 between blk and ref.
To do: Uniform subsampling will be inserted later!
Hypothesis Testing Fast Matching to be used later!
Changes:
11/7/00: implemented MMX
1/24/01: implemented SSE
==================================================================*/
/********** C ************/
int AVCSAD_Macroblock_C(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info)
{
(void)(extra_info);
int32 x10;
int dmin = (uint32)dmin_lx >> 16;
int lx = dmin_lx & 0xFFFF;
NUM_SAD_MB_CALL();
x10 = simd_sad_mb(ref, blk, dmin, lx);
return x10;
}
#ifdef HTFM /* HTFM with uniform subsampling implementation 2/28/01 */
/*===============================================================
Function: AVCAVCSAD_MB_HTFM_Collect and AVCSAD_MB_HTFM
Date: 3/2/1
Purpose: Compute the SAD on a 16x16 block using
uniform subsampling and hypothesis testing fast matching
for early dropout. SAD_MB_HP_HTFM_Collect is to collect
the statistics to compute the thresholds to be used in
SAD_MB_HP_HTFM.
Input/Output:
Changes:
===============================================================*/
int AVCAVCSAD_MB_HTFM_Collect(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info)
{
int i;
int sad = 0;
uint8 *p1;
int lx4 = (dmin_lx << 2) & 0x3FFFC;
uint32 cur_word;
int saddata[16], tmp, tmp2; /* used when collecting flag (global) is on */
int difmad;
int madstar;
HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
uint *countbreak = &(htfm_stat->countbreak);
int *offsetRef = htfm_stat->offsetRef;
madstar = (uint32)dmin_lx >> 20;
NUM_SAD_MB_CALL();
blk -= 4;
for (i = 0; i < 16; i++)
{
p1 = ref + offsetRef[i];
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = (cur_word >> 24) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[8];
tmp2 = (cur_word >> 16) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[4];
tmp2 = (cur_word >> 8) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[0];
p1 += lx4;
tmp2 = (cur_word & 0xFF);
sad = SUB_SAD(sad, tmp, tmp2);
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = (cur_word >> 24) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[8];
tmp2 = (cur_word >> 16) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[4];
tmp2 = (cur_word >> 8) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[0];
p1 += lx4;
tmp2 = (cur_word & 0xFF);
sad = SUB_SAD(sad, tmp, tmp2);
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = (cur_word >> 24) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[8];
tmp2 = (cur_word >> 16) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[4];
tmp2 = (cur_word >> 8) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[0];
p1 += lx4;
tmp2 = (cur_word & 0xFF);
sad = SUB_SAD(sad, tmp, tmp2);
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = (cur_word >> 24) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[8];
tmp2 = (cur_word >> 16) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[4];
tmp2 = (cur_word >> 8) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[0];
p1 += lx4;
tmp2 = (cur_word & 0xFF);
sad = SUB_SAD(sad, tmp, tmp2);
NUM_SAD_MB();
saddata[i] = sad;
if (i > 0)
{
if ((uint32)sad > ((uint32)dmin_lx >> 16))
{
difmad = saddata[0] - ((saddata[1] + 1) >> 1);
(*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
(*countbreak)++;
return sad;
}
}
}
difmad = saddata[0] - ((saddata[1] + 1) >> 1);
(*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
(*countbreak)++;
return sad;
}
int AVCSAD_MB_HTFM(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info)
{
int sad = 0;
uint8 *p1;
int i;
int tmp, tmp2;
int lx4 = (dmin_lx << 2) & 0x3FFFC;
int sadstar = 0, madstar;
int *nrmlz_th = (int*) extra_info;
int *offsetRef = (int*) extra_info + 32;
uint32 cur_word;
madstar = (uint32)dmin_lx >> 20;
NUM_SAD_MB_CALL();
blk -= 4;
for (i = 0; i < 16; i++)
{
p1 = ref + offsetRef[i];
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = (cur_word >> 24) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[8];
tmp2 = (cur_word >> 16) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[4];
tmp2 = (cur_word >> 8) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[0];
p1 += lx4;
tmp2 = (cur_word & 0xFF);
sad = SUB_SAD(sad, tmp, tmp2);
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = (cur_word >> 24) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[8];
tmp2 = (cur_word >> 16) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[4];
tmp2 = (cur_word >> 8) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[0];
p1 += lx4;
tmp2 = (cur_word & 0xFF);
sad = SUB_SAD(sad, tmp, tmp2);
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = (cur_word >> 24) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[8];
tmp2 = (cur_word >> 16) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[4];
tmp2 = (cur_word >> 8) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[0];
p1 += lx4;
tmp2 = (cur_word & 0xFF);
sad = SUB_SAD(sad, tmp, tmp2);
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = (cur_word >> 24) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[8];
tmp2 = (cur_word >> 16) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[4];
tmp2 = (cur_word >> 8) & 0xFF;
sad = SUB_SAD(sad, tmp, tmp2);
tmp = p1[0];
p1 += lx4;
tmp2 = (cur_word & 0xFF);
sad = SUB_SAD(sad, tmp, tmp2);
NUM_SAD_MB();
sadstar += madstar;
if (((uint32)sad <= ((uint32)dmin_lx >> 16)) && (sad <= (sadstar - *nrmlz_th++)))
;
else
return 65536;
}
return sad;
}
#endif /* HTFM */

View File

@@ -0,0 +1,629 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
/* contains
int AVCHalfPel1_SAD_MB(uint8 *ref,uint8 *blk,int dmin,int width,int ih,int jh)
int AVCHalfPel2_SAD_MB(uint8 *ref,uint8 *blk,int dmin,int width)
int AVCHalfPel1_SAD_Blk(uint8 *ref,uint8 *blk,int dmin,int width,int ih,int jh)
int AVCHalfPel2_SAD_Blk(uint8 *ref,uint8 *blk,int dmin,int width)
int AVCSAD_MB_HalfPel_C(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
int AVCSAD_MB_HP_HTFM_Collect(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
int AVCSAD_MB_HP_HTFM(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
int AVCSAD_Blk_HalfPel_C(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
*/
#include "avcenc_lib.h"
#include "sad_halfpel_inline.h"
#ifdef _SAD_STAT
uint32 num_sad_HP_MB = 0;
uint32 num_sad_HP_Blk = 0;
uint32 num_sad_HP_MB_call = 0;
uint32 num_sad_HP_Blk_call = 0;
#define NUM_SAD_HP_MB_CALL() num_sad_HP_MB_call++
#define NUM_SAD_HP_MB() num_sad_HP_MB++
#define NUM_SAD_HP_BLK_CALL() num_sad_HP_Blk_call++
#define NUM_SAD_HP_BLK() num_sad_HP_Blk++
#else
#define NUM_SAD_HP_MB_CALL()
#define NUM_SAD_HP_MB()
#define NUM_SAD_HP_BLK_CALL()
#define NUM_SAD_HP_BLK()
#endif
/*===============================================================
Function: SAD_MB_HalfPel
Date: 09/17/2000
Purpose: Compute the SAD on the half-pel resolution
Input/Output: hmem is assumed to be a pointer to the starting
point of the search in the 33x33 matrix search region
Changes:
11/7/00: implemented MMX
===============================================================*/
/*==================================================================
Function: AVCSAD_MB_HalfPel_C
Date: 04/30/2001
Purpose: Compute SAD 16x16 between blk and ref in halfpel
resolution,
Changes:
==================================================================*/
/* One component is half-pel */
int AVCSAD_MB_HalfPel_Cxhyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
{
(void)(extra_info);
int i, j;
int sad = 0;
uint8 *kk, *p1, *p2, *p3, *p4;
// int sumref=0;
int temp;
int rx = dmin_rx & 0xFFFF;
NUM_SAD_HP_MB_CALL();
p1 = ref;
p2 = ref + 1;
p3 = ref + rx;
p4 = ref + rx + 1;
kk = blk;
for (i = 0; i < 16; i++)
{
for (j = 0; j < 16; j++)
{
temp = ((p1[j] + p2[j] + p3[j] + p4[j] + 2) >> 2) - *kk++;
sad += AVC_ABS(temp);
}
NUM_SAD_HP_MB();
if (sad > (int)((uint32)dmin_rx >> 16))
return sad;
p1 += rx;
p3 += rx;
p2 += rx;
p4 += rx;
}
return sad;
}
int AVCSAD_MB_HalfPel_Cyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
{
(void)(extra_info);
int i, j;
int sad = 0;
uint8 *kk, *p1, *p2;
// int sumref=0;
int temp;
int rx = dmin_rx & 0xFFFF;
NUM_SAD_HP_MB_CALL();
p1 = ref;
p2 = ref + rx; /* either left/right or top/bottom pixel */
kk = blk;
for (i = 0; i < 16; i++)
{
for (j = 0; j < 16; j++)
{
temp = ((p1[j] + p2[j] + 1) >> 1) - *kk++;
sad += AVC_ABS(temp);
}
NUM_SAD_HP_MB();
if (sad > (int)((uint32)dmin_rx >> 16))
return sad;
p1 += rx;
p2 += rx;
}
return sad;
}
int AVCSAD_MB_HalfPel_Cxh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
{
(void)(extra_info);
int i, j;
int sad = 0;
uint8 *kk, *p1;
int temp;
int rx = dmin_rx & 0xFFFF;
NUM_SAD_HP_MB_CALL();
p1 = ref;
kk = blk;
for (i = 0; i < 16; i++)
{
for (j = 0; j < 16; j++)
{
temp = ((p1[j] + p1[j+1] + 1) >> 1) - *kk++;
sad += AVC_ABS(temp);
}
NUM_SAD_HP_MB();
if (sad > (int)((uint32)dmin_rx >> 16))
return sad;
p1 += rx;
}
return sad;
}
#ifdef HTFM /* HTFM with uniform subsampling implementation, 2/28/01 */
//Checheck here
int AVCAVCSAD_MB_HP_HTFM_Collectxhyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
{
int i, j;
int sad = 0;
uint8 *p1, *p2;
int rx = dmin_rx & 0xFFFF;
int refwx4 = rx << 2;
int saddata[16]; /* used when collecting flag (global) is on */
int difmad, tmp, tmp2;
int madstar;
HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
UInt *countbreak = &(htfm_stat->countbreak);
int *offsetRef = htfm_stat->offsetRef;
uint32 cur_word;
madstar = (uint32)dmin_rx >> 20;
NUM_SAD_HP_MB_CALL();
blk -= 4;
for (i = 0; i < 16; i++) /* 16 stages */
{
p1 = ref + offsetRef[i];
p2 = p1 + rx;
j = 4;/* 4 lines */
do
{
cur_word = *((uint32*)(blk += 4));
tmp = p1[12] + p2[12];
tmp2 = p1[13] + p2[13];
tmp += tmp2;
tmp2 = (cur_word >> 24) & 0xFF;
tmp += 2;
sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[8] + p2[8];
tmp2 = p1[9] + p2[9];
tmp += tmp2;
tmp2 = (cur_word >> 16) & 0xFF;
tmp += 2;
sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[4] + p2[4];
tmp2 = p1[5] + p2[5];
tmp += tmp2;
tmp2 = (cur_word >> 8) & 0xFF;
tmp += 2;
sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
tmp2 = p1[1] + p2[1];
tmp = p1[0] + p2[0];
p1 += refwx4;
p2 += refwx4;
tmp += tmp2;
tmp2 = (cur_word & 0xFF);
tmp += 2;
sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
}
while (--j);
NUM_SAD_HP_MB();
saddata[i] = sad;
if (i > 0)
{
if (sad > ((uint32)dmin_rx >> 16))
{
difmad = saddata[0] - ((saddata[1] + 1) >> 1);
(*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
(*countbreak)++;
return sad;
}
}
}
difmad = saddata[0] - ((saddata[1] + 1) >> 1);
(*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
(*countbreak)++;
return sad;
}
int AVCAVCSAD_MB_HP_HTFM_Collectyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
{
int i, j;
int sad = 0;
uint8 *p1, *p2;
int rx = dmin_rx & 0xFFFF;
int refwx4 = rx << 2;
int saddata[16]; /* used when collecting flag (global) is on */
int difmad, tmp, tmp2;
int madstar;
HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
UInt *countbreak = &(htfm_stat->countbreak);
int *offsetRef = htfm_stat->offsetRef;
uint32 cur_word;
madstar = (uint32)dmin_rx >> 20;
NUM_SAD_HP_MB_CALL();
blk -= 4;
for (i = 0; i < 16; i++) /* 16 stages */
{
p1 = ref + offsetRef[i];
p2 = p1 + rx;
j = 4;
do
{
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = p2[12];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 24) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[8];
tmp2 = p2[8];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 16) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[4];
tmp2 = p2[4];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 8) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[0];
p1 += refwx4;
tmp2 = p2[0];
p2 += refwx4;
tmp++;
tmp2 += tmp;
tmp = (cur_word & 0xFF);
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
}
while (--j);
NUM_SAD_HP_MB();
saddata[i] = sad;
if (i > 0)
{
if (sad > ((uint32)dmin_rx >> 16))
{
difmad = saddata[0] - ((saddata[1] + 1) >> 1);
(*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
(*countbreak)++;
return sad;
}
}
}
difmad = saddata[0] - ((saddata[1] + 1) >> 1);
(*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
(*countbreak)++;
return sad;
}
int AVCAVCSAD_MB_HP_HTFM_Collectxh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
{
int i, j;
int sad = 0;
uint8 *p1;
int rx = dmin_rx & 0xFFFF;
int refwx4 = rx << 2;
int saddata[16]; /* used when collecting flag (global) is on */
int difmad, tmp, tmp2;
int madstar;
HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
UInt *countbreak = &(htfm_stat->countbreak);
int *offsetRef = htfm_stat->offsetRef;
uint32 cur_word;
madstar = (uint32)dmin_rx >> 20;
NUM_SAD_HP_MB_CALL();
blk -= 4;
for (i = 0; i < 16; i++) /* 16 stages */
{
p1 = ref + offsetRef[i];
j = 4; /* 4 lines */
do
{
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = p1[13];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 24) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[8];
tmp2 = p1[9];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 16) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[4];
tmp2 = p1[5];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 8) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[0];
tmp2 = p1[1];
p1 += refwx4;
tmp++;
tmp2 += tmp;
tmp = (cur_word & 0xFF);
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
}
while (--j);
NUM_SAD_HP_MB();
saddata[i] = sad;
if (i > 0)
{
if (sad > ((uint32)dmin_rx >> 16))
{
difmad = saddata[0] - ((saddata[1] + 1) >> 1);
(*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
(*countbreak)++;
return sad;
}
}
}
difmad = saddata[0] - ((saddata[1] + 1) >> 1);
(*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
(*countbreak)++;
return sad;
}
int AVCSAD_MB_HP_HTFMxhyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
{
int i, j;
int sad = 0, tmp, tmp2;
uint8 *p1, *p2;
int rx = dmin_rx & 0xFFFF;
int refwx4 = rx << 2;
int sadstar = 0, madstar;
int *nrmlz_th = (int*) extra_info;
int *offsetRef = nrmlz_th + 32;
uint32 cur_word;
madstar = (uint32)dmin_rx >> 20;
NUM_SAD_HP_MB_CALL();
blk -= 4;
for (i = 0; i < 16; i++) /* 16 stages */
{
p1 = ref + offsetRef[i];
p2 = p1 + rx;
j = 4; /* 4 lines */
do
{
cur_word = *((uint32*)(blk += 4));
tmp = p1[12] + p2[12];
tmp2 = p1[13] + p2[13];
tmp += tmp2;
tmp2 = (cur_word >> 24) & 0xFF;
tmp += 2;
sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[8] + p2[8];
tmp2 = p1[9] + p2[9];
tmp += tmp2;
tmp2 = (cur_word >> 16) & 0xFF;
tmp += 2;
sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[4] + p2[4];
tmp2 = p1[5] + p2[5];
tmp += tmp2;
tmp2 = (cur_word >> 8) & 0xFF;
tmp += 2;
sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
tmp2 = p1[1] + p2[1];
tmp = p1[0] + p2[0];
p1 += refwx4;
p2 += refwx4;
tmp += tmp2;
tmp2 = (cur_word & 0xFF);
tmp += 2;
sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
}
while (--j);
NUM_SAD_HP_MB();
sadstar += madstar;
if (sad > sadstar - nrmlz_th[i] || sad > ((uint32)dmin_rx >> 16))
{
return 65536;
}
}
return sad;
}
int AVCSAD_MB_HP_HTFMyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
{
int i, j;
int sad = 0, tmp, tmp2;
uint8 *p1, *p2;
int rx = dmin_rx & 0xFFFF;
int refwx4 = rx << 2;
int sadstar = 0, madstar;
int *nrmlz_th = (int*) extra_info;
int *offsetRef = nrmlz_th + 32;
uint32 cur_word;
madstar = (uint32)dmin_rx >> 20;
NUM_SAD_HP_MB_CALL();
blk -= 4;
for (i = 0; i < 16; i++) /* 16 stages */
{
p1 = ref + offsetRef[i];
p2 = p1 + rx;
j = 4;
do
{
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = p2[12];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 24) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[8];
tmp2 = p2[8];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 16) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[4];
tmp2 = p2[4];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 8) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[0];
p1 += refwx4;
tmp2 = p2[0];
p2 += refwx4;
tmp++;
tmp2 += tmp;
tmp = (cur_word & 0xFF);
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
}
while (--j);
NUM_SAD_HP_MB();
sadstar += madstar;
if (sad > sadstar - nrmlz_th[i] || sad > ((uint32)dmin_rx >> 16))
{
return 65536;
}
}
return sad;
}
int AVCSAD_MB_HP_HTFMxh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
{
int i, j;
int sad = 0, tmp, tmp2;
uint8 *p1;
int rx = dmin_rx & 0xFFFF;
int refwx4 = rx << 2;
int sadstar = 0, madstar;
int *nrmlz_th = (int*) extra_info;
int *offsetRef = nrmlz_th + 32;
uint32 cur_word;
madstar = (uint32)dmin_rx >> 20;
NUM_SAD_HP_MB_CALL();
blk -= 4;
for (i = 0; i < 16; i++) /* 16 stages */
{
p1 = ref + offsetRef[i];
j = 4;/* 4 lines */
do
{
cur_word = *((uint32*)(blk += 4));
tmp = p1[12];
tmp2 = p1[13];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 24) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[8];
tmp2 = p1[9];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 16) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[4];
tmp2 = p1[5];
tmp++;
tmp2 += tmp;
tmp = (cur_word >> 8) & 0xFF;
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
tmp = p1[0];
tmp2 = p1[1];
p1 += refwx4;
tmp++;
tmp2 += tmp;
tmp = (cur_word & 0xFF);
sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
}
while (--j);
NUM_SAD_HP_MB();
sadstar += madstar;
if (sad > sadstar - nrmlz_th[i] || sad > ((uint32)dmin_rx >> 16))
{
return 65536;
}
}
return sad;
}
#endif /* HTFM */

View File

@@ -0,0 +1,96 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#ifndef _SAD_HALFPEL_INLINE_H_
#define _SAD_HALFPEL_INLINE_H_
#ifdef __cplusplus
extern "C"
{
#endif
#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER */
__inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
tmp = (tmp2 >> 1) - tmp;
if (tmp > 0) sad += tmp;
else sad -= tmp;
return sad;
}
__inline int32 INTERP2_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
tmp = (tmp >> 2) - tmp2;
if (tmp > 0) sad += tmp;
else sad -= tmp;
return sad;
}
#elif defined(__CC_ARM) /* only work with arm v5 */
__inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
__asm
{
rsbs tmp, tmp, tmp2, asr #1 ;
rsbmi tmp, tmp, #0 ;
add sad, sad, tmp ;
}
return sad;
}
__inline int32 INTERP2_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
__asm
{
rsbs tmp, tmp2, tmp, asr #2 ;
rsbmi tmp, tmp, #0 ;
add sad, sad, tmp ;
}
return sad;
}
#elif defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER */
__inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
__asm__ volatile("rsbs %1, %1, %2, asr #1\n\trsbmi %1, %1, #0\n\tadd %0, %0, %1": "=r"(sad), "=r"(tmp): "r"(tmp2));
return sad;
}
__inline int32 INTERP2_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
__asm__ volatile("rsbs %1, %2, %1, asr #2\n\trsbmi %1, %1, #0\n\tadd %0, %0, %1": "=r"(sad), "=r"(tmp): "r"(tmp2));
return sad;
}
#endif
#ifdef __cplusplus
}
#endif
#endif //_SAD_HALFPEL_INLINE_H_

View File

@@ -0,0 +1,488 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#ifndef _SAD_INLINE_H_
#define _SAD_INLINE_H_
#ifdef __cplusplus
extern "C"
{
#endif
#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER */
__inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
tmp = tmp - tmp2;
if (tmp > 0) sad += tmp;
else sad -= tmp;
return sad;
}
__inline int32 sad_4pixel(int32 src1, int32 src2, int32 mask)
{
int32 x7;
x7 = src2 ^ src1; /* check odd/even combination */
if ((uint32)src2 >= (uint32)src1)
{
src1 = src2 - src1; /* subs */
}
else
{
src1 = src1 - src2;
}
x7 = x7 ^ src1; /* only odd bytes need to add carry */
x7 = mask & ((uint32)x7 >> 1);
x7 = (x7 << 8) - x7;
src1 = src1 + (x7 >> 7); /* add 0xFF to the negative byte, add back carry */
src1 = src1 ^(x7 >> 7); /* take absolute value of negative byte */
return src1;
}
#define NUMBER 3
#define SHIFT 24
#include "sad_mb_offset.h"
#undef NUMBER
#define NUMBER 2
#undef SHIFT
#define SHIFT 16
#include "sad_mb_offset.h"
#undef NUMBER
#define NUMBER 1
#undef SHIFT
#define SHIFT 8
#include "sad_mb_offset.h"
__inline int32 simd_sad_mb(uint8 *ref, uint8 *blk, int dmin, int lx)
{
int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
x9 = 0x80808080; /* const. */
x8 = (uint32)ref & 0x3;
if (x8 == 3)
goto SadMBOffset3;
if (x8 == 2)
goto SadMBOffset2;
if (x8 == 1)
goto SadMBOffset1;
// x5 = (x4<<8)-x4; /* x5 = x4*255; */
x4 = x5 = 0;
x6 = 0xFFFF00FF;
ref -= lx;
blk -= 16;
x8 = 16;
LOOP_SAD0:
/****** process 8 pixels ******/
x10 = *((uint32*)(ref += lx));
x11 = *((uint32*)(ref + 4));
x12 = *((uint32*)(blk += 16));
x14 = *((uint32*)(blk + 4));
/* process x11 & x14 */
x11 = sad_4pixel(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixel(x10, x12, x9);
x5 = x5 + x10; /* accumulate low bytes */
x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
x5 = x5 + x11; /* accumulate low bytes */
x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
x4 = x4 + ((uint32)x11 >> 8); /* accumulate high bytes */
/****** process 8 pixels ******/
x10 = *((uint32*)(ref + 8));
x11 = *((uint32*)(ref + 12));
x12 = *((uint32*)(blk + 8));
x14 = *((uint32*)(blk + 12));
/* process x11 & x14 */
x11 = sad_4pixel(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixel(x10, x12, x9);
x5 = x5 + x10; /* accumulate low bytes */
x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
x5 = x5 + x11; /* accumulate low bytes */
x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
x4 = x4 + ((uint32)x11 >> 8); /* accumulate high bytes */
/****************/
x10 = x5 - (x4 << 8); /* extract low bytes */
x10 = x10 + x4; /* add with high bytes */
x10 = x10 + (x10 << 16); /* add with lower half word */
if ((int)((uint32)x10 >> 16) <= dmin) /* compare with dmin */
{
if (--x8)
{
goto LOOP_SAD0;
}
}
return ((uint32)x10 >> 16);
SadMBOffset3:
return sad_mb_offset3(ref, blk, lx, dmin);
SadMBOffset2:
return sad_mb_offset2(ref, blk, lx, dmin);
SadMBOffset1:
return sad_mb_offset1(ref, blk, lx, dmin);
}
#elif defined(__CC_ARM) /* only work with arm v5 */
__inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
__asm
{
rsbs tmp, tmp, tmp2 ;
rsbmi tmp, tmp, #0 ;
add sad, sad, tmp ;
}
return sad;
}
__inline int32 sad_4pixel(int32 src1, int32 src2, int32 mask)
{
int32 x7;
__asm
{
EOR x7, src2, src1; /* check odd/even combination */
SUBS src1, src2, src1;
EOR x7, x7, src1;
AND x7, mask, x7, lsr #1;
ORRCC x7, x7, #0x80000000;
RSB x7, x7, x7, lsl #8;
ADD src1, src1, x7, asr #7; /* add 0xFF to the negative byte, add back carry */
EOR src1, src1, x7, asr #7; /* take absolute value of negative byte */
}
return src1;
}
__inline int32 sad_4pixelN(int32 src1, int32 src2, int32 mask)
{
int32 x7;
__asm
{
EOR x7, src2, src1; /* check odd/even combination */
ADDS src1, src2, src1;
EOR x7, x7, src1; /* only odd bytes need to add carry */
ANDS x7, mask, x7, rrx;
RSB x7, x7, x7, lsl #8;
SUB src1, src1, x7, asr #7; /* add 0xFF to the negative byte, add back carry */
EOR src1, src1, x7, asr #7; /* take absolute value of negative byte */
}
return src1;
}
#define sum_accumulate __asm{ SBC x5, x5, x10; /* accumulate low bytes */ \
BIC x10, x6, x10; /* x10 & 0xFF00FF00 */ \
ADD x4, x4, x10,lsr #8; /* accumulate high bytes */ \
SBC x5, x5, x11; /* accumulate low bytes */ \
BIC x11, x6, x11; /* x11 & 0xFF00FF00 */ \
ADD x4, x4, x11,lsr #8; } /* accumulate high bytes */
#define NUMBER 3
#define SHIFT 24
#define INC_X8 0x08000001
#include "sad_mb_offset.h"
#undef NUMBER
#define NUMBER 2
#undef SHIFT
#define SHIFT 16
#undef INC_X8
#define INC_X8 0x10000001
#include "sad_mb_offset.h"
#undef NUMBER
#define NUMBER 1
#undef SHIFT
#define SHIFT 8
#undef INC_X8
#define INC_X8 0x08000001
#include "sad_mb_offset.h"
__inline int32 simd_sad_mb(uint8 *ref, uint8 *blk, int dmin, int lx)
{
int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
x9 = 0x80808080; /* const. */
x4 = x5 = 0;
__asm
{
MOVS x8, ref, lsl #31 ;
BHI SadMBOffset3;
BCS SadMBOffset2;
BMI SadMBOffset1;
MVN x6, #0xFF00;
}
LOOP_SAD0:
/****** process 8 pixels ******/
x11 = *((int32*)(ref + 12));
x10 = *((int32*)(ref + 8));
x14 = *((int32*)(blk + 12));
x12 = *((int32*)(blk + 8));
/* process x11 & x14 */
x11 = sad_4pixel(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixel(x10, x12, x9);
x5 = x5 + x10; /* accumulate low bytes */
x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
x5 = x5 + x11; /* accumulate low bytes */
x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
x4 = x4 + ((uint32)x11 >> 8); /* accumulate high bytes */
__asm
{
/****** process 8 pixels ******/
LDR x11, [ref, #4];
LDR x10, [ref], lx ;
LDR x14, [blk, #4];
LDR x12, [blk], #16 ;
}
/* process x11 & x14 */
x11 = sad_4pixel(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixel(x10, x12, x9);
x5 = x5 + x10; /* accumulate low bytes */
x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
x5 = x5 + x11; /* accumulate low bytes */
x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
x4 = x4 + ((uint32)x11 >> 8); /* accumulate high bytes */
/****************/
x10 = x5 - (x4 << 8); /* extract low bytes */
x10 = x10 + x4; /* add with high bytes */
x10 = x10 + (x10 << 16); /* add with lower half word */
__asm
{
/****************/
RSBS x11, dmin, x10, lsr #16;
ADDLSS x8, x8, #0x10000001;
BLS LOOP_SAD0;
}
return ((uint32)x10 >> 16);
SadMBOffset3:
return sad_mb_offset3(ref, blk, lx, dmin, x8);
SadMBOffset2:
return sad_mb_offset2(ref, blk, lx, dmin, x8);
SadMBOffset1:
return sad_mb_offset1(ref, blk, lx, dmin, x8);
}
#elif defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER */
__inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
__asm__ volatile("rsbs %1, %1, %2\n\trsbmi %1, %1, #0\n\tadd %0, %0, %1": "=r"(sad): "r"(tmp), "r"(tmp2));
return sad;
}
__inline int32 sad_4pixel(int32 src1, int32 src2, int32 mask)
{
int32 x7;
__asm__ volatile("EOR %1, %2, %0\n\tSUBS %0, %2, %0\n\tEOR %1, %1, %0\n\tAND %1, %3, %1, lsr #1\n\tORRCC %1, %1, #0x80000000\n\tRSB %1, %1, %1, lsl #8\n\tADD %0, %0, %1, asr #7\n\tEOR %0, %0, %1, asr #7": "=r"(src1), "=&r"(x7): "r"(src2), "r"(mask));
return src1;
}
__inline int32 sad_4pixelN(int32 src1, int32 src2, int32 mask)
{
int32 x7;
__asm__ volatile("EOR %1, %2, %0\n\tADDS %0, %2, %0\n\tEOR %1, %1, %0\n\tANDS %1, %3, %1, rrx\n\tRSB %1, %1, %1, lsl #8\n\tSUB %0, %0, %1, asr #7\n\tEOR %0, %0, %1, asr #7": "=r"(src1), "=&r"(x7): "r"(src2), "r"(mask));
return src1;
}
#define sum_accumulate __asm__ volatile("SBC %0, %0, %1\n\tBIC %1, %4, %1\n\tADD %2, %2, %1, lsr #8\n\tSBC %0, %0, %3\n\tBIC %3, %4, %3\n\tADD %2, %2, %3, lsr #8": "=&r" (x5), "=&r" (x10), "=&r" (x4), "=&r" (x11): "r" (x6));
#define NUMBER 3
#define SHIFT 24
#define INC_X8 0x08000001
#include "sad_mb_offset.h"
#undef NUMBER
#define NUMBER 2
#undef SHIFT
#define SHIFT 16
#undef INC_X8
#define INC_X8 0x10000001
#include "sad_mb_offset.h"
#undef NUMBER
#define NUMBER 1
#undef SHIFT
#define SHIFT 8
#undef INC_X8
#define INC_X8 0x08000001
#include "sad_mb_offset.h"
__inline int32 simd_sad_mb(uint8 *ref, uint8 *blk, int dmin, int lx)
{
int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
x9 = 0x80808080; /* const. */
x4 = x5 = 0;
x8 = (uint32)ref & 0x3;
if (x8 == 3)
goto SadMBOffset3;
if (x8 == 2)
goto SadMBOffset2;
if (x8 == 1)
goto SadMBOffset1;
x8 = 16;
///
__asm__ volatile("MVN %0, #0xFF00": "=r"(x6));
LOOP_SAD0:
/****** process 8 pixels ******/
x11 = *((int32*)(ref + 12));
x10 = *((int32*)(ref + 8));
x14 = *((int32*)(blk + 12));
x12 = *((int32*)(blk + 8));
/* process x11 & x14 */
x11 = sad_4pixel(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixel(x10, x12, x9);
x5 = x5 + x10; /* accumulate low bytes */
x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
x5 = x5 + x11; /* accumulate low bytes */
x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
x4 = x4 + ((uint32)x11 >> 8); /* accumulate high bytes */
/****** process 8 pixels ******/
x11 = *((int32*)(ref + 4));
__asm__ volatile("LDR %0, [%1], %2": "=&r"(x10), "=r"(ref): "r"(lx));
//x10 = *((int32*)ref); ref+=lx;
x14 = *((int32*)(blk + 4));
__asm__ volatile("LDR %0, [%1], #16": "=&r"(x12), "=r"(blk));
/* process x11 & x14 */
x11 = sad_4pixel(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixel(x10, x12, x9);
x5 = x5 + x10; /* accumulate low bytes */
x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
x5 = x5 + x11; /* accumulate low bytes */
x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
x4 = x4 + ((uint32)x11 >> 8); /* accumulate high bytes */
/****************/
x10 = x5 - (x4 << 8); /* extract low bytes */
x10 = x10 + x4; /* add with high bytes */
x10 = x10 + (x10 << 16); /* add with lower half word */
/****************/
if (((uint32)x10 >> 16) <= dmin) /* compare with dmin */
{
if (--x8)
{
goto LOOP_SAD0;
}
}
return ((uint32)x10 >> 16);
SadMBOffset3:
return sad_mb_offset3(ref, blk, lx, dmin);
SadMBOffset2:
return sad_mb_offset2(ref, blk, lx, dmin);
SadMBOffset1:
return sad_mb_offset1(ref, blk, lx, dmin);
}
#endif
#ifdef __cplusplus
}
#endif
#endif // _SAD_INLINE_H_

View File

@@ -0,0 +1,311 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER */
#if (NUMBER==3)
__inline int32 sad_mb_offset3(uint8 *ref, uint8 *blk, int lx, int dmin)
#elif (NUMBER==2)
__inline int32 sad_mb_offset2(uint8 *ref, uint8 *blk, int lx, int dmin)
#elif (NUMBER==1)
__inline int32 sad_mb_offset1(uint8 *ref, uint8 *blk, int lx, int dmin)
#endif
{
int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
// x5 = (x4<<8) - x4;
x4 = x5 = 0;
x6 = 0xFFFF00FF;
x9 = 0x80808080; /* const. */
ref -= NUMBER; /* bic ref, ref, #3 */
ref -= lx;
blk -= 16;
x8 = 16;
#if (NUMBER==3)
LOOP_SAD3:
#elif (NUMBER==2)
LOOP_SAD2:
#elif (NUMBER==1)
LOOP_SAD1:
#endif
/****** process 8 pixels ******/
x10 = *((uint32*)(ref += lx)); /* D C B A */
x11 = *((uint32*)(ref + 4)); /* H G F E */
x12 = *((uint32*)(ref + 8)); /* L K J I */
x10 = ((uint32)x10 >> SHIFT); /* 0 0 0 D */
x10 = x10 | (x11 << (32 - SHIFT)); /* G F E D */
x11 = ((uint32)x11 >> SHIFT); /* 0 0 0 H */
x11 = x11 | (x12 << (32 - SHIFT)); /* K J I H */
x12 = *((uint32*)(blk += 16));
x14 = *((uint32*)(blk + 4));
/* process x11 & x14 */
x11 = sad_4pixel(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixel(x10, x12, x9);
x5 = x5 + x10; /* accumulate low bytes */
x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
x5 = x5 + x11; /* accumulate low bytes */
x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
x4 = x4 + ((uint32)x11 >> 8); /* accumulate high bytes */
/****** process 8 pixels ******/
x10 = *((uint32*)(ref + 8)); /* D C B A */
x11 = *((uint32*)(ref + 12)); /* H G F E */
x12 = *((uint32*)(ref + 16)); /* L K J I */
x10 = ((uint32)x10 >> SHIFT); /* mvn x10, x10, lsr #24 = 0xFF 0xFF 0xFF ~D */
x10 = x10 | (x11 << (32 - SHIFT)); /* bic x10, x10, x11, lsl #8 = ~G ~F ~E ~D */
x11 = ((uint32)x11 >> SHIFT); /* 0xFF 0xFF 0xFF ~H */
x11 = x11 | (x12 << (32 - SHIFT)); /* ~K ~J ~I ~H */
x12 = *((uint32*)(blk + 8));
x14 = *((uint32*)(blk + 12));
/* process x11 & x14 */
x11 = sad_4pixel(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixel(x10, x12, x9);
x5 = x5 + x10; /* accumulate low bytes */
x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
x5 = x5 + x11; /* accumulate low bytes */
x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
x4 = x4 + ((uint32)x11 >> 8); /* accumulate high bytes */
/****************/
x10 = x5 - (x4 << 8); /* extract low bytes */
x10 = x10 + x4; /* add with high bytes */
x10 = x10 + (x10 << 16); /* add with lower half word */
if ((int)((uint32)x10 >> 16) <= dmin) /* compare with dmin */
{
if (--x8)
{
#if (NUMBER==3)
goto LOOP_SAD3;
#elif (NUMBER==2)
goto LOOP_SAD2;
#elif (NUMBER==1)
goto LOOP_SAD1;
#endif
}
}
return ((uint32)x10 >> 16);
}
#elif defined(__CC_ARM) /* only work with arm v5 */
#if (NUMBER==3)
__inline int32 sad_mb_offset3(uint8 *ref, uint8 *blk, int lx, int dmin, int32 x8)
#elif (NUMBER==2)
__inline int32 sad_mb_offset2(uint8 *ref, uint8 *blk, int lx, int dmin, int32 x8)
#elif (NUMBER==1)
__inline int32 sad_mb_offset1(uint8 *ref, uint8 *blk, int lx, int dmin, int32 x8)
#endif
{
int32 x4, x5, x6, x9, x10, x11, x12, x14;
x9 = 0x80808080; /* const. */
x4 = x5 = 0;
__asm{
MVN x6, #0xff0000;
#if (NUMBER==3)
LOOP_SAD3:
#elif (NUMBER==2)
LOOP_SAD2:
#elif (NUMBER==1)
LOOP_SAD1:
#endif
BIC ref, ref, #3;
}
/****** process 8 pixels ******/
x11 = *((int32*)(ref + 12));
x12 = *((int32*)(ref + 16));
x10 = *((int32*)(ref + 8));
x14 = *((int32*)(blk + 12));
__asm{
MVN x10, x10, lsr #SHIFT;
BIC x10, x10, x11, lsl #(32-SHIFT);
MVN x11, x11, lsr #SHIFT;
BIC x11, x11, x12, lsl #(32-SHIFT);
LDR x12, [blk, #8];
}
/* process x11 & x14 */
x11 = sad_4pixelN(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixelN(x10, x12, x9);
sum_accumulate;
__asm{
/****** process 8 pixels ******/
LDR x11, [ref, #4];
LDR x12, [ref, #8];
LDR x10, [ref], lx ;
LDR x14, [blk, #4];
MVN x10, x10, lsr #SHIFT;
BIC x10, x10, x11, lsl #(32-SHIFT);
MVN x11, x11, lsr #SHIFT;
BIC x11, x11, x12, lsl #(32-SHIFT);
LDR x12, [blk], #16;
}
/* process x11 & x14 */
x11 = sad_4pixelN(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixelN(x10, x12, x9);
sum_accumulate;
/****************/
x10 = x5 - (x4 << 8); /* extract low bytes */
x10 = x10 + x4; /* add with high bytes */
x10 = x10 + (x10 << 16); /* add with lower half word */
__asm{
RSBS x11, dmin, x10, lsr #16
ADDLSS x8, x8, #INC_X8
#if (NUMBER==3)
BLS LOOP_SAD3;
#elif (NUMBER==2)
BLS LOOP_SAD2;
#elif (NUMBER==1)
BLS LOOP_SAD1;
#endif
}
return ((uint32)x10 >> 16);
}
#elif defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER */
#if (NUMBER==3)
__inline int32 sad_mb_offset3(uint8 *ref, uint8 *blk, int lx, int dmin)
#elif (NUMBER==2)
__inline int32 sad_mb_offset2(uint8 *ref, uint8 *blk, int lx, int dmin)
#elif (NUMBER==1)
__inline int32 sad_mb_offset1(uint8 *ref, uint8 *blk, int lx, int dmin)
#endif
{
int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
x9 = 0x80808080; /* const. */
x4 = x5 = 0;
x8 = 16; //<<===========*******
__asm__ volatile("MVN %0, #0xFF0000": "=r"(x6));
#if (NUMBER==3)
LOOP_SAD3:
#elif (NUMBER==2)
LOOP_SAD2:
#elif (NUMBER==1)
LOOP_SAD1:
#endif
__asm__ volatile("BIC %0, %0, #3": "=r"(ref));
/****** process 8 pixels ******/
x11 = *((int32*)(ref + 12));
x12 = *((int32*)(ref + 16));
x10 = *((int32*)(ref + 8));
x14 = *((int32*)(blk + 12));
#if (SHIFT==8)
__asm__ volatile("MVN %0, %0, lsr #8\n\tBIC %0, %0, %1,lsl #24\n\tMVN %1, %1,lsr #8\n\tBIC %1, %1, %2,lsl #24": "=&r"(x10), "=&r"(x11): "r"(x12));
#elif (SHIFT==16)
__asm__ volatile("MVN %0, %0, lsr #16\n\tBIC %0, %0, %1,lsl #16\n\tMVN %1, %1,lsr #16\n\tBIC %1, %1, %2,lsl #16": "=&r"(x10), "=&r"(x11): "r"(x12));
#elif (SHIFT==24)
__asm__ volatile("MVN %0, %0, lsr #24\n\tBIC %0, %0, %1,lsl #8\n\tMVN %1, %1,lsr #24\n\tBIC %1, %1, %2,lsl #8": "=&r"(x10), "=&r"(x11): "r"(x12));
#endif
x12 = *((int32*)(blk + 8));
/* process x11 & x14 */
x11 = sad_4pixelN(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixelN(x10, x12, x9);
sum_accumulate;
/****** process 8 pixels ******/
x11 = *((int32*)(ref + 4));
x12 = *((int32*)(ref + 8));
x10 = *((int32*)ref); ref += lx;
x14 = *((int32*)(blk + 4));
#if (SHIFT==8)
__asm__ volatile("MVN %0, %0, lsr #8\n\tBIC %0, %0, %1,lsl #24\n\tMVN %1, %1,lsr #8\n\tBIC %1, %1, %2,lsl #24": "=&r"(x10), "=&r"(x11): "r"(x12));
#elif (SHIFT==16)
__asm__ volatile("MVN %0, %0, lsr #16\n\tBIC %0, %0, %1,lsl #16\n\tMVN %1, %1,lsr #16\n\tBIC %1, %1, %2,lsl #16": "=&r"(x10), "=&r"(x11): "r"(x12));
#elif (SHIFT==24)
__asm__ volatile("MVN %0, %0, lsr #24\n\tBIC %0, %0, %1,lsl #8\n\tMVN %1, %1,lsr #24\n\tBIC %1, %1, %2,lsl #8": "=&r"(x10), "=&r"(x11): "r"(x12));
#endif
__asm__ volatile("LDR %0, [%1], #16": "=&r"(x12), "=r"(blk));
/* process x11 & x14 */
x11 = sad_4pixelN(x11, x14, x9);
/* process x12 & x10 */
x10 = sad_4pixelN(x10, x12, x9);
sum_accumulate;
/****************/
x10 = x5 - (x4 << 8); /* extract low bytes */
x10 = x10 + x4; /* add with high bytes */
x10 = x10 + (x10 << 16); /* add with lower half word */
if (((uint32)x10 >> 16) <= (uint32)dmin) /* compare with dmin */
{
if (--x8)
{
#if (NUMBER==3)
goto LOOP_SAD3;
#elif (NUMBER==2)
goto LOOP_SAD2;
#elif (NUMBER==1)
goto LOOP_SAD1;
#endif
}
}
return ((uint32)x10 >> 16);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,336 @@
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "avcenc_lib.h"
/**
See algorithm in subclause 9.1, Table 9-1, Table 9-2. */
AVCEnc_Status ue_v(AVCEncBitstream *bitstream, uint codeNum)
{
if (AVCENC_SUCCESS != SetEGBitstring(bitstream, codeNum))
return AVCENC_FAIL;
return AVCENC_SUCCESS;
}
/**
See subclause 9.1.1, Table 9-3 */
AVCEnc_Status se_v(AVCEncBitstream *bitstream, int value)
{
uint codeNum;
AVCEnc_Status status;
if (value <= 0)
{
codeNum = -value * 2;
}
else
{
codeNum = value * 2 - 1;
}
status = ue_v(bitstream, codeNum);
return status;
}
AVCEnc_Status te_v(AVCEncBitstream *bitstream, uint value, uint range)
{
AVCEnc_Status status;
if (range > 1)
{
return ue_v(bitstream, value);
}
else
{
status = BitstreamWrite1Bit(bitstream, 1 - value);
return status;
}
}
/**
See subclause 9.1, Table 9-1, 9-2. */
// compute leadingZeros and inforbits
//codeNum = (1<<leadingZeros)-1+infobits;
AVCEnc_Status SetEGBitstring(AVCEncBitstream *bitstream, uint codeNum)
{
AVCEnc_Status status;
int leadingZeros;
int infobits;
if (!codeNum)
{
status = BitstreamWrite1Bit(bitstream, 1);
return status;
}
/* calculate leadingZeros and infobits */
leadingZeros = 1;
while ((uint)(1 << leadingZeros) < codeNum + 2)
{
leadingZeros++;
}
leadingZeros--;
infobits = codeNum - (1 << leadingZeros) + 1;
status = BitstreamWriteBits(bitstream, leadingZeros, 0);
infobits |= (1 << leadingZeros);
status = BitstreamWriteBits(bitstream, leadingZeros + 1, infobits);
return status;
}
/* see Table 9-4 assignment of codeNum to values of coded_block_pattern. */
const static uint8 MapCBP2code[48][2] =
{
{3, 0}, {29, 2}, {30, 3}, {17, 7}, {31, 4}, {18, 8}, {37, 17}, {8, 13}, {32, 5}, {38, 18}, {19, 9}, {9, 14},
{20, 10}, {10, 15}, {11, 16}, {2, 11}, {16, 1}, {33, 32}, {34, 33}, {21, 36}, {35, 34}, {22, 37}, {39, 44}, {4, 40},
{36, 35}, {40, 45}, {23, 38}, {5, 41}, {24, 39}, {6, 42}, {7, 43}, {1, 19}, {41, 6}, {42, 24}, {43, 25}, {25, 20},
{44, 26}, {26, 21}, {46, 46}, {12, 28}, {45, 27}, {47, 47}, {27, 22}, {13, 29}, {28, 23}, {14, 30}, {15, 31}, {0, 12}
};
AVCEnc_Status EncodeCBP(AVCMacroblock *currMB, AVCEncBitstream *stream)
{
AVCEnc_Status status;
uint codeNum;
if (currMB->mbMode == AVC_I4)
{
codeNum = MapCBP2code[currMB->CBP][0];
}
else
{
codeNum = MapCBP2code[currMB->CBP][1];
}
status = ue_v(stream, codeNum);
return status;
}
AVCEnc_Status ce_TotalCoeffTrailingOnes(AVCEncBitstream *stream, int TrailingOnes, int TotalCoeff, int nC)
{
const static uint8 totCoeffTrailOne[3][4][17][2] =
{
{ // 0702
{{1, 1}, {6, 5}, {8, 7}, {9, 7}, {10, 7}, {11, 7}, {13, 15}, {13, 11}, {13, 8}, {14, 15}, {14, 11}, {15, 15}, {15, 11}, {16, 15}, {16, 11}, {16, 7}, {16, 4}},
{{0, 0}, {2, 1}, {6, 4}, {8, 6}, {9, 6}, {10, 6}, {11, 6}, {13, 14}, {13, 10}, {14, 14}, {14, 10}, {15, 14}, {15, 10}, {15, 1}, {16, 14}, {16, 10}, {16, 6}},
{{0, 0}, {0, 0}, {3, 1}, {7, 5}, {8, 5}, {9, 5}, {10, 5}, {11, 5}, {13, 13}, {13, 9}, {14, 13}, {14, 9}, {15, 13}, {15, 9}, {16, 13}, {16, 9}, {16, 5}},
{{0, 0}, {0, 0}, {0, 0}, {5, 3}, {6, 3}, {7, 4}, {8, 4}, {9, 4}, {10, 4}, {11, 4}, {13, 12}, {14, 12}, {14, 8}, {15, 12}, {15, 8}, {16, 12}, {16, 8}},
},
{
{{2, 3}, {6, 11}, {6, 7}, {7, 7}, {8, 7}, {8, 4}, {9, 7}, {11, 15}, {11, 11}, {12, 15}, {12, 11}, {12, 8}, {13, 15}, {13, 11}, {13, 7}, {14, 9}, {14, 7}},
{{0, 0}, {2, 2}, {5, 7}, {6, 10}, {6, 6}, {7, 6}, {8, 6}, {9, 6}, {11, 14}, {11, 10}, {12, 14}, {12, 10}, {13, 14}, {13, 10}, {14, 11}, {14, 8}, {14, 6}},
{{0, 0}, {0, 0}, {3, 3}, {6, 9}, {6, 5}, {7, 5}, {8, 5}, {9, 5}, {11, 13}, {11, 9}, {12, 13}, {12, 9}, {13, 13}, {13, 9}, {13, 6}, {14, 10}, {14, 5}},
{{0, 0}, {0, 0}, {0, 0}, {4, 5}, {4, 4}, {5, 6}, {6, 8}, {6, 4}, {7, 4}, {9, 4}, {11, 12}, {11, 8}, {12, 12}, {13, 12}, {13, 8}, {13, 1}, {14, 4}},
},
{
{{4, 15}, {6, 15}, {6, 11}, {6, 8}, {7, 15}, {7, 11}, {7, 9}, {7, 8}, {8, 15}, {8, 11}, {9, 15}, {9, 11}, {9, 8}, {10, 13}, {10, 9}, {10, 5}, {10, 1}},
{{0, 0}, {4, 14}, {5, 15}, {5, 12}, {5, 10}, {5, 8}, {6, 14}, {6, 10}, {7, 14}, {8, 14}, {8, 10}, {9, 14}, {9, 10}, {9, 7}, {10, 12}, {10, 8}, {10, 4}},
{{0, 0}, {0, 0}, {4, 13}, {5, 14}, {5, 11}, {5, 9}, {6, 13}, {6, 9}, {7, 13}, {7, 10}, {8, 13}, {8, 9}, {9, 13}, {9, 9}, {10, 11}, {10, 7}, {10, 3}},
{{0, 0}, {0, 0}, {0, 0}, {4, 12}, {4, 11}, {4, 10}, {4, 9}, {4, 8}, {5, 13}, {6, 12}, {7, 12}, {8, 12}, {8, 8}, {9, 12}, {10, 10}, {10, 6}, {10, 2}}
}
};
AVCEnc_Status status = AVCENC_SUCCESS;
uint code, len;
int vlcnum;
if (TrailingOnes > 3)
{
return AVCENC_TRAILINGONES_FAIL;
}
if (nC >= 8)
{
if (TotalCoeff)
{
code = ((TotalCoeff - 1) << 2) | (TrailingOnes);
}
else
{
code = 3;
}
status = BitstreamWriteBits(stream, 6, code);
}
else
{
if (nC < 2)
{
vlcnum = 0;
}
else if (nC < 4)
{
vlcnum = 1;
}
else
{
vlcnum = 2;
}
len = totCoeffTrailOne[vlcnum][TrailingOnes][TotalCoeff][0];
code = totCoeffTrailOne[vlcnum][TrailingOnes][TotalCoeff][1];
status = BitstreamWriteBits(stream, len, code);
}
return status;
}
AVCEnc_Status ce_TotalCoeffTrailingOnesChromaDC(AVCEncBitstream *stream, int TrailingOnes, int TotalCoeff)
{
const static uint8 totCoeffTrailOneChrom[4][5][2] =
{
{ {2, 1}, {6, 7}, {6, 4}, {6, 3}, {6, 2}},
{ {0, 0}, {1, 1}, {6, 6}, {7, 3}, {8, 3}},
{ {0, 0}, {0, 0}, {3, 1}, {7, 2}, {8, 2}},
{ {0, 0}, {0, 0}, {0, 0}, {6, 5}, {7, 0}},
};
AVCEnc_Status status = AVCENC_SUCCESS;
uint code, len;
len = totCoeffTrailOneChrom[TrailingOnes][TotalCoeff][0];
code = totCoeffTrailOneChrom[TrailingOnes][TotalCoeff][1];
status = BitstreamWriteBits(stream, len, code);
return status;
}
/* see Table 9-7 and 9-8 */
AVCEnc_Status ce_TotalZeros(AVCEncBitstream *stream, int total_zeros, int TotalCoeff)
{
const static uint8 lenTotalZeros[15][16] =
{
{ 1, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9},
{ 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6},
{ 4, 3, 3, 3, 4, 4, 3, 3, 4, 5, 5, 6, 5, 6},
{ 5, 3, 4, 4, 3, 3, 3, 4, 3, 4, 5, 5, 5},
{ 4, 4, 4, 3, 3, 3, 3, 3, 4, 5, 4, 5},
{ 6, 5, 3, 3, 3, 3, 3, 3, 4, 3, 6},
{ 6, 5, 3, 3, 3, 2, 3, 4, 3, 6},
{ 6, 4, 5, 3, 2, 2, 3, 3, 6},
{ 6, 6, 4, 2, 2, 3, 2, 5},
{ 5, 5, 3, 2, 2, 2, 4},
{ 4, 4, 3, 3, 1, 3},
{ 4, 4, 2, 1, 3},
{ 3, 3, 1, 2},
{ 2, 2, 1},
{ 1, 1},
};
const static uint8 codTotalZeros[15][16] =
{
{1, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 1},
{7, 6, 5, 4, 3, 5, 4, 3, 2, 3, 2, 3, 2, 1, 0},
{5, 7, 6, 5, 4, 3, 4, 3, 2, 3, 2, 1, 1, 0},
{3, 7, 5, 4, 6, 5, 4, 3, 3, 2, 2, 1, 0},
{5, 4, 3, 7, 6, 5, 4, 3, 2, 1, 1, 0},
{1, 1, 7, 6, 5, 4, 3, 2, 1, 1, 0},
{1, 1, 5, 4, 3, 3, 2, 1, 1, 0},
{1, 1, 1, 3, 3, 2, 2, 1, 0},
{1, 0, 1, 3, 2, 1, 1, 1, },
{1, 0, 1, 3, 2, 1, 1, },
{0, 1, 1, 2, 1, 3},
{0, 1, 1, 1, 1},
{0, 1, 1, 1},
{0, 1, 1},
{0, 1},
};
int len, code;
AVCEnc_Status status;
len = lenTotalZeros[TotalCoeff-1][total_zeros];
code = codTotalZeros[TotalCoeff-1][total_zeros];
status = BitstreamWriteBits(stream, len, code);
return status;
}
/* see Table 9-9 */
AVCEnc_Status ce_TotalZerosChromaDC(AVCEncBitstream *stream, int total_zeros, int TotalCoeff)
{
const static uint8 lenTotalZerosChromaDC[3][4] =
{
{ 1, 2, 3, 3, },
{ 1, 2, 2, 0, },
{ 1, 1, 0, 0, },
};
const static uint8 codTotalZerosChromaDC[3][4] =
{
{ 1, 1, 1, 0, },
{ 1, 1, 0, 0, },
{ 1, 0, 0, 0, },
};
int len, code;
AVCEnc_Status status;
len = lenTotalZerosChromaDC[TotalCoeff-1][total_zeros];
code = codTotalZerosChromaDC[TotalCoeff-1][total_zeros];
status = BitstreamWriteBits(stream, len, code);
return status;
}
/* see Table 9-10 */
AVCEnc_Status ce_RunBefore(AVCEncBitstream *stream, int run_before, int zerosLeft)
{
const static uint8 lenRunBefore[7][16] =
{
{1, 1},
{1, 2, 2},
{2, 2, 2, 2},
{2, 2, 2, 3, 3},
{2, 2, 3, 3, 3, 3},
{2, 3, 3, 3, 3, 3, 3},
{3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11},
};
const static uint8 codRunBefore[7][16] =
{
{1, 0},
{1, 1, 0},
{3, 2, 1, 0},
{3, 2, 1, 1, 0},
{3, 2, 3, 2, 1, 0},
{3, 0, 1, 3, 2, 5, 4},
{7, 6, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};
int len, code;
AVCEnc_Status status;
if (zerosLeft <= 6)
{
len = lenRunBefore[zerosLeft-1][run_before];
code = codRunBefore[zerosLeft-1][run_before];
}
else
{
len = lenRunBefore[6][run_before];
code = codRunBefore[6][run_before];
}
status = BitstreamWriteBits(stream, len, code);
return status;
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AVC_ENCODER_H_
#define AVC_ENCODER_H_
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaSource.h>
#include <utils/Vector.h>
struct tagAVCHandle;
struct tagAVCEncParam;
namespace android {
struct MediaBuffer;
struct MediaBufferGroup;
struct AVCEncoder : public MediaSource,
public MediaBufferObserver {
AVCEncoder(const sp<MediaSource> &source,
const sp<MetaData>& meta);
virtual status_t start(MetaData *params);
virtual status_t stop();
virtual sp<MetaData> getFormat();
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options);
virtual void signalBufferReturned(MediaBuffer *buffer);
// Callbacks required by the encoder
int32_t allocOutputBuffers(unsigned int sizeInMbs, unsigned int numBuffers);
void unbindOutputBuffer(int32_t index);
int32_t bindOutputBuffer(int32_t index, uint8_t **yuv);
protected:
virtual ~AVCEncoder();
private:
sp<MediaSource> mSource;
sp<MetaData> mFormat;
sp<MetaData> mMeta;
int32_t mVideoWidth;
int32_t mVideoHeight;
int32_t mVideoFrameRate;
int32_t mVideoBitRate;
int32_t mVideoColorFormat;
int64_t mNumInputFrames;
status_t mInitCheck;
bool mStarted;
bool mSpsPpsHeaderReceived;
bool mReadyForNextFrame;
int32_t mIsIDRFrame; // for set kKeyIsSyncFrame
tagAVCHandle *mHandle;
tagAVCEncParam *mEncParams;
MediaBuffer *mInputBuffer;
uint8_t *mInputFrameData;
MediaBufferGroup *mGroup;
Vector<MediaBuffer *> mOutputBuffers;
status_t initCheck(const sp<MetaData>& meta);
void releaseOutputBuffers();
AVCEncoder(const AVCEncoder &);
AVCEncoder &operator=(const AVCEncoder &);
};
} // namespace android
#endif // AVC_ENCODER_H_