blob: 01e80f1d2bb824947a1fb6edaf5e668dfca964ad [file] [log] [blame]
/*!
*************************************************************************************
* \file q_offsets.c
*
* \brief
* read Quantization Offset matrix parameters from input file: q_OffsetMatrix.cfg
*
*************************************************************************************
*/
#include <stdlib.h>
#include <string.h>
#include "global.h"
#include "memalloc.h"
extern char *GetConfigFileContent (char *Filename, int error_type);
#define MAX_ITEMS_TO_PARSE 1000
int offset4x4_check[6] = { 0, 0, 0, 0, 0, 0 };
int offset8x8_check[2] = { 0, 0 };
static const char OffsetType4x4[15][24] = {
"INTRA4X4_LUMA_INTRA",
"INTRA4X4_CHROMAU_INTRA",
"INTRA4X4_CHROMAV_INTRA",
"INTRA4X4_LUMA_INTERP",
"INTRA4X4_CHROMAU_INTERP",
"INTRA4X4_CHROMAV_INTERP",
"INTRA4X4_LUMA_INTERB",
"INTRA4X4_CHROMAU_INTERB",
"INTRA4X4_CHROMAV_INTERB",
"INTER4X4_LUMA_INTERP",
"INTER4X4_CHROMAU_INTERP",
"INTER4X4_CHROMAV_INTERP",
"INTER4X4_LUMA_INTERB",
"INTER4X4_CHROMAU_INTERB",
"INTER4X4_CHROMAV_INTERB"
};
static const char OffsetType8x8[5][24] = {
"INTRA8X8_LUMA_INTRA",
"INTRA8X8_LUMA_INTERP",
"INTRA8X8_LUMA_INTERB",
"INTER8X8_LUMA_INTERP",
"INTER8X8_LUMA_INTERB"
};
int ****LevelOffset4x4Luma;
int *****LevelOffset4x4Chroma;
int ****LevelOffset8x8Luma;
int AdaptRndWeight;
int AdaptRndCrWeight;
short **OffsetList4x4input;
short **OffsetList8x8input;
short **OffsetList4x4;
short **OffsetList8x8;
void InitOffsetParam ();
const int OffsetBits = 11;
static const short Offset_intra_default_intra[16] = {
682, 682, 682, 682,
682, 682, 682, 682,
682, 682, 682, 682,
682, 682, 682, 682
};
static const short Offset_intra_default_chroma[16] = {
682, 682, 682, 682,
682, 682, 682, 682,
682, 682, 682, 682,
682, 682, 682, 682
};
static const short Offset_intra_default_inter[16] = {
342, 342, 342, 342,
342, 342, 342, 342,
342, 342, 342, 342,
342, 342, 342, 342,
};
static const short Offset_inter_default[16] = {
342, 342, 342, 342,
342, 342, 342, 342,
342, 342, 342, 342,
342, 342, 342, 342,
};
static const short Offset8_intra_default_intra[64] = {
682, 682, 682, 682, 682, 682, 682, 682,
682, 682, 682, 682, 682, 682, 682, 682,
682, 682, 682, 682, 682, 682, 682, 682,
682, 682, 682, 682, 682, 682, 682, 682,
682, 682, 682, 682, 682, 682, 682, 682,
682, 682, 682, 682, 682, 682, 682, 682,
682, 682, 682, 682, 682, 682, 682, 682,
682, 682, 682, 682, 682, 682, 682, 682
};
static const short Offset8_intra_default_inter[64] = {
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342
};
static const short Offset8_inter_default[64] = {
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342,
342, 342, 342, 342, 342, 342, 342, 342
};
/*!
***********************************************************************
* \brief
* Allocate Q matrix arrays
***********************************************************************
*/
void allocate_QOffsets ()
{
int max_qp_per_luma = (3 + 6*(input->BitDepthLuma) - MIN_QP)/6 + 1;
int max_qp_per_cr = (3 + 6*(input->BitDepthChroma) - MIN_QP)/6 + 1;
int max_qp_per = imax(max_qp_per_luma,max_qp_per_cr);
get_mem4Dint(&LevelOffset4x4Luma, 2, max_qp_per, 4, 4);
get_mem5Dint(&LevelOffset4x4Chroma, 2, 2, max_qp_per, 4, 4);
get_mem4Dint(&LevelOffset8x8Luma, 2, max_qp_per, 8, 8);
get_mem2Dshort(&OffsetList4x4input, 15, 16);
get_mem2Dshort(&OffsetList8x8input, 5, 64);
get_mem2Dshort(&OffsetList4x4, 15, 16);
get_mem2Dshort(&OffsetList8x8, 5, 64);
}
/*!
***********************************************************************
* \brief
* Free Q matrix arrays
***********************************************************************
*/
void free_QOffsets ()
{
int max_qp_per_luma = (3 + 6*(input->BitDepthLuma) - MIN_QP)/6 + 1;
int max_qp_per_cr = (3 + 6*(input->BitDepthChroma) - MIN_QP)/6 + 1;
int max_qp_per = imax(max_qp_per_luma,max_qp_per_cr);
free_mem4Dint(LevelOffset4x4Luma, 2, max_qp_per);
free_mem5Dint(LevelOffset4x4Chroma, 2, 2, max_qp_per);
free_mem4Dint(LevelOffset8x8Luma, 2, max_qp_per);
free_mem2Dshort(OffsetList8x8);
free_mem2Dshort(OffsetList4x4);
free_mem2Dshort(OffsetList8x8input);
free_mem2Dshort(OffsetList4x4input);
}
/*!
***********************************************************************
* \brief
* Check the parameter name.
* \param s
* parameter name string
* \param type
* 4x4 or 8x8 offset matrix type
* \return
* the index number if the string is a valid parameter name, \n
* -1 for error
***********************************************************************
*/
int CheckOffsetParameterName (char *s, int *type)
{
int i = 0;
*type = 0;
while ((OffsetType4x4[i] != NULL) && (i < 15))
{
if (0 == strcmp (OffsetType4x4[i], s))
return i;
else
i++;
}
i = 0;
*type = 1;
while ((OffsetType8x8[i] != NULL) && (i < 5))
{
if (0 == strcmp (OffsetType8x8[i], s))
return i;
else
i++;
}
return -1;
}
/*!
***********************************************************************
* \brief
* Parse the Q Offset Matrix values read from cfg file.
* \param buf
* buffer to be parsed
* \param bufsize
* buffer size of buffer
***********************************************************************
*/
void ParseQOffsetMatrix (char *buf, int bufsize)
{
char *items[MAX_ITEMS_TO_PARSE];
int MapIdx;
int item = 0;
int InString = 0, InItem = 0;
char *p = buf;
char *bufend = &buf[bufsize];
int IntContent;
int i, j, range, type, cnt;
short *OffsetList;
while (p < bufend)
{
switch (*p)
{
case 13:
p++;
break;
case '#': // Found comment
*p = '\0'; // Replace '#' with '\0' in case of comment immediately following integer or string
while (*p != '\n' && p < bufend) // Skip till EOL or EOF, whichever comes first
p++;
InString = 0;
InItem = 0;
break;
case '\n':
InItem = 0;
InString = 0;
*p++ = '\0';
break;
case ' ':
case '\t': // Skip whitespace, leave state unchanged
if (InString)
p++;
else
{ // Terminate non-strings once whitespace is found
*p++ = '\0';
InItem = 0;
}
break;
case '"': // Begin/End of String
*p++ = '\0';
if (!InString)
{
items[item++] = p;
InItem = ~InItem;
}
else
InItem = 0;
InString = ~InString; // Toggle
break;
case ',':
p++;
InItem = 0;
break;
default:
if (!InItem)
{
items[item++] = p;
InItem = ~InItem;
}
p++;
}
}
item--;
for (i = 0; i < item; i += cnt)
{
cnt = 0;
if (0 > (MapIdx = CheckOffsetParameterName (items[i + cnt], &type)))
{
snprintf (errortext, ET_SIZE,
" Parsing error in config file: Parameter Name '%s' not recognized.",
items[i + cnt]);
error (errortext, 300);
}
cnt++;
if (strcmp ("=", items[i + cnt]))
{
snprintf (errortext, ET_SIZE,
" Parsing error in config file: '=' expected as the second token in each item.");
error (errortext, 300);
}
cnt++;
if (!type) //4x4 Matrix
{
range = 16;
OffsetList = OffsetList4x4input[MapIdx];
offset4x4_check[MapIdx] = 1; //to indicate matrix found in cfg file
}
else //8x8 matrix
{
range = 64;
OffsetList = OffsetList8x8input[MapIdx];
offset8x8_check[MapIdx] = 1; //to indicate matrix found in cfg file
}
for (j = 0; j < range; j++)
{
if (1 != sscanf (items[i + cnt + j], "%d", &IntContent))
{
snprintf (errortext, ET_SIZE,
" Parsing error: Expected numerical value for Parameter of %s, found '%s'.",
items[i], items[i + cnt + j]);
error (errortext, 300);
}
OffsetList[j] = (short) IntContent; //save value in matrix
}
cnt += j;
printf (".");
}
}
/*!
***********************************************************************
* \brief
* Initialise Q offset matrix values.
***********************************************************************
*/
void Init_QOffsetMatrix ()
{
char *content;
allocate_QOffsets ();
if (input->OffsetMatrixPresentFlag)
{
printf ("Parsing Quantization Offset Matrix file %s ",
input->QOffsetMatrixFile);
content = GetConfigFileContent (input->QOffsetMatrixFile, 0);
if (content != '\0')
ParseQOffsetMatrix (content, strlen (content));
else
{
printf
("\nError: %s\nProceeding with default values for all matrices.",
errortext);
input->OffsetMatrixPresentFlag = 0;
}
printf ("\n");
free (content);
}
//! Now set up all offset params. This process could be reused if we wish to re-init offsets
InitOffsetParam ();
}
/*!
************************************************************************
* \brief
* Intit quantization offset params
*
* \par Input:
* none
*
* \par Output:
* none
************************************************************************
*/
void InitOffsetParam ()
{
int k;
if (input->OffsetMatrixPresentFlag)
{
memcpy(&(OffsetList4x4[0][0]),&(OffsetList4x4input[0][0]), 15 * 16 * sizeof(short));
memcpy(&(OffsetList8x8[0][0]),&(OffsetList8x8input[0][0]), 5 * 64 * sizeof(short));
}
else
{
memcpy(&(OffsetList4x4[0][0]),&(Offset_intra_default_intra[0]), 16 * sizeof(short));
for (k = 1; k < 3; k++)
memcpy(&(OffsetList4x4[k][0]),&(Offset_intra_default_chroma[0]), 16 * sizeof(short));
for (k = 3; k < 9; k++)
memcpy(&(OffsetList4x4[k][0]),&(Offset_intra_default_inter[0]), 16 * sizeof(short));
for (k = 9; k < 15; k++)
memcpy(&(OffsetList4x4[k][0]),&(Offset_inter_default[0]), 16 * sizeof(short));
memcpy(&(OffsetList8x8[0][0]),&(Offset8_intra_default_intra[0]), 64 * sizeof(short));
memcpy(&(OffsetList8x8[1][0]),&(Offset8_intra_default_inter[0]), 64 * sizeof(short));
memcpy(&(OffsetList8x8[2][0]),&(Offset8_intra_default_inter[0]), 64 * sizeof(short));
memcpy(&(OffsetList8x8[3][0]),&(Offset8_inter_default[0]), 64 * sizeof(short));
memcpy(&(OffsetList8x8[4][0]),&(Offset8_inter_default[0]), 64 * sizeof(short));
}
}
/*!
************************************************************************
* \brief
* Calculation of the quantization offset params at the frame level
*
* \par Input:
* none
*
* \par Output:
* none
************************************************************************
*/
void CalculateOffsetParam ()
{
int i, j, k, temp;
int qp_per;
int img_type = (img->type == SI_SLICE ? I_SLICE : (img->type == SP_SLICE ? P_SLICE : img->type));
int max_qp_per_luma = qp_per_matrix[(51 + img->bitdepth_luma_qp_scale - MIN_QP)] + 1;
int max_qp_per_cr = qp_per_matrix[(51 + img->bitdepth_chroma_qp_scale - MIN_QP)] + 1;
AdaptRndWeight = input->AdaptRndWFactor[img->nal_reference_idc!=0][img_type];
AdaptRndCrWeight = input->AdaptRndCrWFactor[img->nal_reference_idc!=0][img_type];
for (k = 0; k < imax(max_qp_per_luma,max_qp_per_cr); k++)
{
qp_per = Q_BITS + k - OffsetBits;
for (j = 0; j < 4; j++)
{
for (i = 0; i < 4; i++)
{
temp = (j << 2) + i;
if (img_type == I_SLICE)
{
LevelOffset4x4Luma[1][k][j][i] =
(int) OffsetList4x4[0][temp] << qp_per;
LevelOffset4x4Chroma[0][1][k][j][i] =
(int) OffsetList4x4[1][temp] << qp_per;
LevelOffset4x4Chroma[1][1][k][j][i] =
(int) OffsetList4x4[2][temp] << qp_per;
}
else if (img_type == B_SLICE)
{
LevelOffset4x4Luma[1][k][j][i] =
(int) OffsetList4x4[6][temp] << qp_per;
LevelOffset4x4Chroma[0][1][k][j][i] =
(int) OffsetList4x4[7][temp] << qp_per;
LevelOffset4x4Chroma[1][1][k][j][i] =
(int) OffsetList4x4[8][temp] << qp_per;
}
else
{
LevelOffset4x4Luma[1][k][j][i] =
(int) OffsetList4x4[3][temp] << qp_per;
LevelOffset4x4Chroma[0][1][k][j][i] =
(int) OffsetList4x4[4][temp] << qp_per;
LevelOffset4x4Chroma[1][1][k][j][i] =
(int) OffsetList4x4[5][temp] << qp_per;
}
if (img_type == B_SLICE)
{
LevelOffset4x4Luma[0][k][j][i] =
(int) OffsetList4x4[12][temp] << qp_per;
LevelOffset4x4Chroma[0][0][k][j][i] =
(int) OffsetList4x4[13][temp] << qp_per;
LevelOffset4x4Chroma[1][0][k][j][i] =
(int) OffsetList4x4[14][temp] << qp_per;
}
else
{
LevelOffset4x4Luma[0][k][j][i] =
(int) OffsetList4x4[9][temp] << qp_per;
LevelOffset4x4Chroma[0][0][k][j][i] =
(int) OffsetList4x4[10][temp] << qp_per;
LevelOffset4x4Chroma[1][0][k][j][i] =
(int) OffsetList4x4[11][temp] << qp_per;
}
}
}
}
}
/*!
************************************************************************
* \brief
* Calculate the quantisation offset parameters
*
************************************************************************
*/
void CalculateOffset8Param ()
{
int i, j, k, temp;
int q_bits;
int max_qp_per_luma = qp_per_matrix[(51 + img->bitdepth_luma_qp_scale - MIN_QP)] + 1;
int max_qp_per_cr = qp_per_matrix[(51 + img->bitdepth_chroma_qp_scale - MIN_QP)] + 1;
for (k = 0; k < imax(max_qp_per_luma,max_qp_per_cr); k++)
{
q_bits = Q_BITS_8 + k - OffsetBits;
for (j = 0; j < 8; j++)
{
for (i = 0; i < 8; i++)
{
temp = (j << 3) + i;
if (img->type == I_SLICE)
LevelOffset8x8Luma[1][k][j][i] =
(int) OffsetList8x8[0][temp] << q_bits;
else if (img->type == B_SLICE)
LevelOffset8x8Luma[1][k][j][i] =
(int) OffsetList8x8[2][temp] << q_bits;
else
LevelOffset8x8Luma[1][k][j][i] =
(int) OffsetList8x8[1][temp] << q_bits;
if (img->type == B_SLICE)
LevelOffset8x8Luma[0][k][j][i] =
(int) OffsetList8x8[4][temp] << q_bits;
else
LevelOffset8x8Luma[0][k][j][i] =
(int) OffsetList8x8[3][temp] << q_bits;
}
}
}
}