am 9d8bea11: Merge "Initial checkin for software AVC encoder" into gingerbread
Merge commit '9d8bea11892a43eeab2a1119d68740845a8894e5' into gingerbread-plus-aosp * commit '9d8bea11892a43eeab2a1119d68740845a8894e5': Initial checkin for software AVC encoder
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ LOCAL_STATIC_LIBRARIES := \
|
||||
libstagefright_amrwbdec \
|
||||
libstagefright_amrwbenc \
|
||||
libstagefright_avcdec \
|
||||
libstagefright_avcenc \
|
||||
libstagefright_m4vh263dec \
|
||||
libstagefright_mp3dec \
|
||||
libstagefright_vorbisdec \
|
||||
|
||||
@@ -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" },
|
||||
};
|
||||
|
||||
|
||||
492
media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
Normal file
492
media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
Normal 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
|
||||
34
media/libstagefright/codecs/avc/enc/Android.mk
Normal file
34
media/libstagefright/codecs/avc/enc/Android.mk
Normal 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)
|
||||
744
media/libstagefright/codecs/avc/enc/src/avcenc_api.cpp
Normal file
744
media/libstagefright/codecs/avc/enc/src/avcenc_api.cpp
Normal 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 ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
320
media/libstagefright/codecs/avc/enc/src/avcenc_api.h
Normal file
320
media/libstagefright/codecs/avc/enc/src/avcenc_api.h
Normal 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_ */
|
||||
|
||||
471
media/libstagefright/codecs/avc/enc/src/avcenc_int.h
Normal file
471
media/libstagefright/codecs/avc/enc/src/avcenc_int.h
Normal 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*/
|
||||
|
||||
1020
media/libstagefright/codecs/avc/enc/src/avcenc_lib.h
Normal file
1020
media/libstagefright/codecs/avc/enc/src/avcenc_lib.h
Normal file
File diff suppressed because it is too large
Load Diff
336
media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp
Normal file
336
media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
1283
media/libstagefright/codecs/avc/enc/src/block.cpp
Normal file
1283
media/libstagefright/codecs/avc/enc/src/block.cpp
Normal file
File diff suppressed because it is too large
Load Diff
622
media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
Normal file
622
media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
917
media/libstagefright/codecs/avc/enc/src/header.cpp
Normal file
917
media/libstagefright/codecs/avc/enc/src/header.cpp
Normal 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;
|
||||
}
|
||||
|
||||
899
media/libstagefright/codecs/avc/enc/src/init.cpp
Normal file
899
media/libstagefright/codecs/avc/enc/src/init.cpp
Normal 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;
|
||||
}
|
||||
|
||||
2199
media/libstagefright/codecs/avc/enc/src/intra_est.cpp
Normal file
2199
media/libstagefright/codecs/avc/enc/src/intra_est.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2156
media/libstagefright/codecs/avc/enc/src/motion_comp.cpp
Normal file
2156
media/libstagefright/codecs/avc/enc/src/motion_comp.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1774
media/libstagefright/codecs/avc/enc/src/motion_est.cpp
Normal file
1774
media/libstagefright/codecs/avc/enc/src/motion_est.cpp
Normal file
File diff suppressed because it is too large
Load Diff
981
media/libstagefright/codecs/avc/enc/src/rate_control.cpp
Normal file
981
media/libstagefright/codecs/avc/enc/src/rate_control.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
389
media/libstagefright/codecs/avc/enc/src/residual.cpp
Normal file
389
media/libstagefright/codecs/avc/enc/src/residual.cpp
Normal 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;
|
||||
}
|
||||
290
media/libstagefright/codecs/avc/enc/src/sad.cpp
Normal file
290
media/libstagefright/codecs/avc/enc/src/sad.cpp
Normal 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 */
|
||||
|
||||
|
||||
|
||||
629
media/libstagefright/codecs/avc/enc/src/sad_halfpel.cpp
Normal file
629
media/libstagefright/codecs/avc/enc/src/sad_halfpel.cpp
Normal 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 */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
96
media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h
Normal file
96
media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h
Normal 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_
|
||||
|
||||
488
media/libstagefright/codecs/avc/enc/src/sad_inline.h
Normal file
488
media/libstagefright/codecs/avc/enc/src/sad_inline.h
Normal 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_
|
||||
|
||||
311
media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h
Normal file
311
media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h
Normal 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
|
||||
|
||||
1025
media/libstagefright/codecs/avc/enc/src/slice.cpp
Normal file
1025
media/libstagefright/codecs/avc/enc/src/slice.cpp
Normal file
File diff suppressed because it is too large
Load Diff
336
media/libstagefright/codecs/avc/enc/src/vlc_encode.cpp
Normal file
336
media/libstagefright/codecs/avc/enc/src/vlc_encode.cpp
Normal 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;
|
||||
}
|
||||
90
media/libstagefright/include/AVCEncoder.h
Normal file
90
media/libstagefright/include/AVCEncoder.h
Normal 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_
|
||||
Reference in New Issue
Block a user