blob: 01dac057d8bfe992af0ea481b7b0389281019b92 [file] [log] [blame]
/*------------------------------------------------------------------------------
-- --
-- This software is confidential and proprietary and may be used --
-- only as expressly authorized by a licensing agreement from --
-- --
-- Hantro Products Oy. --
-- --
-- (C) COPYRIGHT 2006 HANTRO PRODUCTS OY --
-- ALL RIGHTS RESERVED --
-- --
-- The entire notice above must be reproduced --
-- on all copies and should not be removed. --
-- --
--------------------------------------------------------------------------------
*/
#include "vp8header.h"
#include <memory.h>
#include "vp8entropy.h"
static void Segmentation(vp8buffer* buffer, sps* sps, ppss* ppss,
entropy* entropy, mbs* mbs);
static void FilterLevelDelta(vp8buffer* buffer, sps* sps);
void VP8FrameHeader(vp8Instance_s* container) {
refPic* cur_pic = container->picBuffer.cur_pic;
refPic* refPicList = container->picBuffer.refPicList;
entropy* entropy = container->entropy;
sps* sps = &container->sps; /* Sequence container */
pps* pps = container->ppss.pps;
vp8buffer* buffer = &container->buffer[1]; /* "Frame header" buffer */
/* Color space and pixel Type (Key frames only) */
if (cur_pic->i_frame) {
VP8PutLit(buffer, sps->colorType, 1);
COMMENT("Frame header, buffer 1, color space type");
VP8PutLit(buffer, sps->clampType, 1);
COMMENT("Frame header, buffer 1, clamping type");
}
/* Segmentation */
VP8PutLit(buffer, pps->segmentEnabled, 1);
COMMENT("Frame header, buffer 1, segmentation flag");
if (pps->segmentEnabled) {
Segmentation(buffer, &container->sps, &container->ppss,
entropy, &container->mbs);
}
VP8PutLit(buffer, sps->filterType, 1);
COMMENT("Frame header, buffer 1, filter type");
VP8PutLit(buffer, sps->filterLevel, 6);
COMMENT("Frame header, buffer 1, filter level");
VP8PutLit(buffer, sps->filterSharpness, 3);
COMMENT("Frame header, buffer 1, filter sharpness level");
/* Loop filter adjustments */
VP8PutLit(buffer, sps->filterDeltaEnable, 1);
COMMENT("Frame header, buffer 1, loop filter adjustments");
if (sps->filterDeltaEnable) {
/* Filter level delta references reset by key frame */
if (cur_pic->i_frame) {
memset(sps->oldRefDelta, 0, sizeof(sps->refDelta));
memset(sps->oldModeDelta, 0, sizeof(sps->modeDelta));
}
FilterLevelDelta(buffer, sps);
}
VP8PutLit(buffer, sps->dctPartitions, 2);
COMMENT("Frame header, buffer 1, token partition");
VP8PutLit(buffer, container->rateControl.qpHdr, 7);
COMMENT("Frame header, buffer 1, YacQi quantizer index");
/* TODO: delta quantization index */
VP8PutLit(buffer, 0, 1);
COMMENT("Frame header, buffer 1, YdcDelta flag");
VP8PutLit(buffer, 0, 1);
COMMENT("Frame header, buffer 1, Y2dcDelta flag");
VP8PutLit(buffer, 0, 1);
COMMENT("Frame header, buffer 1, Y2acDelta flag");
VP8PutLit(buffer, 0, 1);
COMMENT("Frame header, buffer 1, UVdcDelta flag");
VP8PutLit(buffer, 0, 1);
COMMENT("Frame header, buffer 1, UVacDelta flag");
/* Update grf and arf buffers and sing bias, see decodframe.c 863.
* TODO swaping arg->grf and grf->arf in the same time is not working
* because of bug in the libvpx? */
if (!cur_pic->i_frame) {
/* Input picture after reconstruction is set to new grf/arf */
VP8PutLit(buffer, cur_pic->grf, 1); /* Grf refresh */
COMMENT("Frame header, buffer 1, grf refresh");
VP8PutLit(buffer, cur_pic->arf, 1); /* Arf refresh */
COMMENT("Frame header, buffer 1, arf refresh");
if (!cur_pic->grf) {
if (refPicList[0].grf) {
VP8PutLit(buffer, 1, 2); /* Ipf -> grf */
COMMENT("Frame header, buffer 1, ipf -> grf");
} else if (refPicList[2].grf) {
VP8PutLit(buffer, 2, 2); /* Arf -> grf */
COMMENT("Frame header, buffer 1, arf -> grf");
} else {
VP8PutLit(buffer, 0, 2); /* Not updated */
COMMENT("Frame header, buffer 1, no update");
}
}
if (!cur_pic->arf) {
if (refPicList[0].arf) {
VP8PutLit(buffer, 1, 2); /* Ipf -> arf */
COMMENT("Frame header, buffer 1, ipf -> arf");
} else if (refPicList[1].arf) {
VP8PutLit(buffer, 2, 2); /* Grf -> arf */
COMMENT("Frame header, buffer 1, grf -> arf");
} else {
VP8PutLit(buffer, 0, 2); /* Not updated */
COMMENT("Frame header, buffer 1, no update");
}
}
/* Sing bias. TODO adaptive sing bias. */
VP8PutLit(buffer, sps->singBias[1], 1); /* Grf */
COMMENT("Frame header, buffer 1, grf sign bias");
VP8PutLit(buffer, sps->singBias[2], 1); /* Arf */
COMMENT("Frame header, buffer 1, arf sign bias");
}
/* RefreshEntropyProbs, if 0 -> put default proabilities. If 1
* use previous frame probabilities */
VP8PutLit(buffer, sps->refreshEntropy, 1);
COMMENT("Frame header, buffer 1, Refresh entropy probs flag");
/* RefreshLastFrame flag. Note that key frame always updates ipf */
if (!cur_pic->i_frame) {
VP8PutLit(buffer, cur_pic->ipf, 1);
COMMENT("Frame header, buffer 1, ipf refresh last frame flag");
}
/* Coeff probabilities, TODO: real updates */
CoeffProb(buffer, entropy->coeffProb, entropy->oldCoeffProb);
/* mb_no_coeff_skip . This flag indicates at the frame level if
* skipping of macroblocks with no non-zero coefficients is enabled.
* If it is set to 0 then prob_skip_false is not read and
* mb_skip_coeff is forced to 0 for all macroblocks (see Sections 11.1
* and 12.1). TODO */
VP8PutLit(buffer, 1, 1);
COMMENT("Frame header, buffer 1, mb no coeff skip");
/* Probability used for decoding noCoeff flag, depens above flag TODO*/
VP8PutLit(buffer, entropy->skipFalseProb, 8);
COMMENT("Frame header, buffer 1, skip false prob");
if (cur_pic->i_frame) return;
/* The rest are inter frame only */
/* Macroblock is intra predicted probability */
VP8PutLit(buffer, entropy->intraProb, 8);
COMMENT("Frame header, buffer 1, intra prob");
/* Inter is predicted from immediately previous frame probability */
VP8PutLit(buffer, entropy->lastProb, 8);
COMMENT("Frame header, buffer 1, last prob");
/* Inter is predicted from golden frame probability */
VP8PutLit(buffer, entropy->gfProb, 8);
COMMENT("Frame header, buffer 1, gf prob");
/* Intra mode probability updates not supported yet TODO */
VP8PutLit(buffer, 0, 1);
COMMENT("Frame header, buffer 1, intra mode prob update");
/* Intra chroma probability updates not supported yet TODO */
VP8PutLit(buffer, 0, 1);
COMMENT("Frame header, buffer 1, intra chroma prob update");
/* Motion vector probability update not supported yet TOTO real updates */
MvProb(buffer, entropy->mvProb, entropy->oldMvProb);
}
/*------------------------------------------------------------------------------
FrameTag
------------------------------------------------------------------------------*/
void VP8FrameTag(vp8Instance_s* container) {
picBuffer* picBuffer = &container->picBuffer;
refPic* cur_pic = picBuffer->cur_pic;
sps* sps = &container->sps; /* Sequence container */
vp8buffer* buffer = &container->buffer[0]; /* Frame tag buffer */
int32_t tmp;
/* Frame tag contains (lsb first):
* 1. A 1-bit frame type (0 for key frames, 1 for inter frames)
* 2. A 3-bit version number (0 - 3 are defined as 4 different profiles
* 3. A 1-bit showFrame flag (1 when current frame is display)
* 4. A 19-bit size of the first data partition in bytes
* Note that frame tag is written to the stream in little endian mode */
tmp = ((container->buffer[1].byteCnt) << 5) |
((cur_pic->show ? 1 : 0) << 4) |
(container->sps.profile << 1) |
(cur_pic->i_frame ? 0 : 1);
/* Note that frame tag is written _really_ literal to buffer, don't use
* VP8PutLit() use VP8PutBit() instead */
VP8PutByte(buffer, tmp & 0xff);
COMMENT("Frame tag, buffer 0, The first byte");
VP8PutByte(buffer, (tmp >> 8) & 0xff);
COMMENT("Frame tag, buffer 0, The second byte");
VP8PutByte(buffer, (tmp >> 16) & 0xff);
COMMENT("Frame tag, buffer 0, The third byte");
if (!cur_pic->i_frame) return;
/* For key frames this is followed by a further 7 bytes of uncompressed
* data as follows */
VP8PutByte(buffer, 0x9d);
COMMENT("Frame tag, buffer 0, next byte");
VP8PutByte(buffer, 0x01);
COMMENT("Frame tag, buffer 0, next byte");
VP8PutByte(buffer, 0x2a);
COMMENT("Frame tag, buffer 0, next byte");
tmp = sps->picWidthInPixel | (sps->horizontalScaling << 14);
VP8PutByte(buffer, tmp & 0xff);
COMMENT("Frame tag, buffer 0, next byte");
VP8PutByte(buffer, tmp >> 8);
COMMENT("Frame tag, buffer 0, next byte");
tmp = sps->picHeightInPixel | (sps->verticalScaling << 14);
VP8PutByte(buffer, tmp & 0xff);
COMMENT("Frame tag, buffer 0, next byte");
VP8PutByte(buffer, tmp >> 8);
COMMENT("Frame tag, buffer 0, next byte");
}
/*------------------------------------------------------------------------------
Segmentation
------------------------------------------------------------------------------*/
void Segmentation(vp8buffer* buffer, sps* sps, ppss* ppss, entropy* entropy,
mbs* mbs) {
pps* pps = ppss->pps;
sgm* sgm = &ppss->pps->sgm; /* New segmentation data */
int32_t i, tmp;
bool dataModified = false;
/* Do we need to updata segmentation data */
if (memcmp(ppss->qpSgm, pps->qpSgm, sizeof(ppss->qpSgm)))
dataModified = true;
if (memcmp(ppss->levelSgm, pps->levelSgm, sizeof(ppss->levelSgm)))
dataModified = true;
/* Update segmentation map only if there are no previous map or
* previous map differs or previous frame did not use segmentation at
* all. Note also that API set mapModified=true if user changes
* segmentation map */
if (!ppss->prevPps) {
sgm->mapModified = true;
}
COMMENT("Frame header, buffer 1, segmentation map modified");
VP8PutLit(buffer, sgm->mapModified, 1);
COMMENT("Frame header, buffer 1, segmentation data modified");
VP8PutLit(buffer, dataModified, 1);
if (dataModified) {
COMMENT("Frame header, buffer 1, segmentation data abs");
/* ABS=1 vs. Deltas=0 */
VP8PutLit(buffer, 1, 1);
for (i = 0; i < SGM_CNT; i++) {
tmp = pps->qpSgm[i];
VP8PutLit(buffer, 1, 1);
VP8PutLit(buffer, ABS(tmp), 7);
VP8PutLit(buffer, tmp < 0, 1);
}
for (i = 0; i < SGM_CNT; i++) {
tmp = pps->levelSgm[i];
VP8PutLit(buffer, 1, 1);
VP8PutLit(buffer, ABS(tmp), 6);
VP8PutLit(buffer, tmp < 0, 1);
}
}
/* Segmentation map probabilities */
if (sgm->mapModified) {
int32_t sum1 = sgm->idCnt[0] + sgm->idCnt[1];
int32_t sum2 = sgm->idCnt[2] + sgm->idCnt[3];
ASSERT(sum1);
ASSERT(sum2);
tmp = 255 * sum1 / (sum1 + sum2);
entropy->segmentProb[0] = CLIP3(tmp, 1, 255);
tmp = sum1 ? 255 * sgm->idCnt[0] / sum1 : 255;
entropy->segmentProb[1] = CLIP3(tmp, 1, 255);
tmp = sum2 ? 255 * sgm->idCnt[2] / sum2 : 255;
entropy->segmentProb[2] = CLIP3(tmp, 1, 255);
for (i = 0; i < 3; i++) {
if (sgm->idCnt[i] != 0) {
COMMENT("Frame header, buffer 1, segment prob");
VP8PutLit(buffer, 1, 1);
VP8PutLit(buffer, entropy->segmentProb[i], 8);
} else {
COMMENT("Frame header, buffer 1, no segment prob");
VP8PutLit(buffer, 0, 1);
}
}
}
/* This point new segmentation data is written to the stream, save new
* values because they are reference values of next frame */
memcpy(ppss->qpSgm, pps->qpSgm, sizeof(ppss->qpSgm));
memcpy(ppss->levelSgm, pps->levelSgm, sizeof(ppss->levelSgm));
}
/*------------------------------------------------------------------------------
FilterLevelDelta
------------------------------------------------------------------------------*/
void FilterLevelDelta(vp8buffer* buffer, sps* sps) {
int32_t i, tmp;
int32_t modeUpdate[4];
int32_t refUpdate[4];
bool update = false;
/* Find out what delta values are changed */
for (i = 0; i < 4; i++) {
modeUpdate[i] = sps->modeDelta[i] != sps->oldModeDelta[i];
refUpdate[i] = sps->refDelta[i] != sps->oldRefDelta[i];
if (modeUpdate[i] || refUpdate[i])
update = true;
}
/* With error resilient mode update the level values for every frame. */
if (!sps->refreshEntropy)
update = true;
/* Do the deltas need to be updated */
VP8PutLit(buffer, update, 1);
if (!update) return;
/* Reference frame mode based deltas */
for (i = 0; i < 4; i++) {
VP8PutLit(buffer, refUpdate[i], 1);
if (refUpdate[i]) {
tmp = sps->refDelta[i];
VP8PutLit(buffer, ABS(tmp), 6); /* Delta */
VP8PutLit(buffer, tmp < 0, 1); /* Sign */
}
}
/* Macroblock mode based deltas */
for (i = 0; i < 4; i++) {
VP8PutLit(buffer, modeUpdate[i], 1);
if (modeUpdate[i]) {
tmp = sps->modeDelta[i];
VP8PutLit(buffer, ABS(tmp), 6); /* Delta */
VP8PutLit(buffer, tmp < 0, 1); /* Sign */
}
}
/* Store the new values as reference for next frame */
memcpy(sps->oldRefDelta, sps->refDelta, sizeof(sps->refDelta));
memcpy(sps->oldModeDelta, sps->modeDelta, sizeof(sps->modeDelta));
}