You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

365 lines
11 KiB

/*
* H.265 video codec.
* Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
*
* This file is part of libde265.
*
* libde265 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libde265 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libde265. If not, see <http://www.gnu.org/licenses/>.
*/
#include "intrapred.h"
#include "transform.h"
#include "util.h"
#include <assert.h>
#include <sys/types.h>
#include <string.h>
void fillIntraPredModeCandidates(enum IntraPredMode candModeList[3],
enum IntraPredMode candIntraPredModeA,
enum IntraPredMode candIntraPredModeB)
{
// build candidate list
if (candIntraPredModeA == candIntraPredModeB) {
if (candIntraPredModeA < 2) {
candModeList[0] = INTRA_PLANAR;
candModeList[1] = INTRA_DC;
candModeList[2] = INTRA_ANGULAR_26;
}
else {
candModeList[0] = candIntraPredModeA;
candModeList[1] = (enum IntraPredMode)(2 + ((candIntraPredModeA-2 -1 +32) % 32));
candModeList[2] = (enum IntraPredMode)(2 + ((candIntraPredModeA-2 +1 ) % 32));
}
}
else {
candModeList[0] = candIntraPredModeA;
candModeList[1] = candIntraPredModeB;
if (candIntraPredModeA != INTRA_PLANAR &&
candIntraPredModeB != INTRA_PLANAR) {
candModeList[2] = INTRA_PLANAR;
}
else if (candIntraPredModeA != INTRA_DC &&
candIntraPredModeB != INTRA_DC) {
candModeList[2] = INTRA_DC;
}
else {
candModeList[2] = INTRA_ANGULAR_26;
}
}
/*
printf("candModeList: %d %d %d\n",
candModeList[0],
candModeList[1],
candModeList[2]
);
*/
}
void fillIntraPredModeCandidates(enum IntraPredMode candModeList[3], int x,int y, int PUidx,
bool availableA, // left
bool availableB, // top
const de265_image* img)
{
const seq_parameter_set* sps = &img->get_sps();
// block on left side
enum IntraPredMode candIntraPredModeA, candIntraPredModeB;
if (availableA==false) {
candIntraPredModeA=INTRA_DC;
}
else if (img->get_pred_mode(x-1,y) != MODE_INTRA ||
img->get_pcm_flag (x-1,y)) {
candIntraPredModeA=INTRA_DC;
}
else {
candIntraPredModeA = img->get_IntraPredMode_atIndex(PUidx-1);
}
// block above
if (availableB==false) {
candIntraPredModeB=INTRA_DC;
}
else if (img->get_pred_mode(x,y-1) != MODE_INTRA ||
img->get_pcm_flag (x,y-1)) {
candIntraPredModeB=INTRA_DC;
}
else if (y-1 < ((y >> sps->Log2CtbSizeY) << sps->Log2CtbSizeY)) {
candIntraPredModeB=INTRA_DC;
}
else {
candIntraPredModeB = img->get_IntraPredMode_atIndex(PUidx-sps->PicWidthInMinPUs);
}
logtrace(LogSlice,"%d;%d candA:%d / candB:%d\n", x,y,
availableA ? candIntraPredModeA : -999,
availableB ? candIntraPredModeB : -999);
fillIntraPredModeCandidates(candModeList,
candIntraPredModeA,
candIntraPredModeB);
}
int find_intra_pred_mode(enum IntraPredMode mode,
enum IntraPredMode candModeList[3])
{
// check whether the mode is in the candidate list
for (int i=0;i<3;i++) {
if (candModeList[i] == mode) {
return i;
}
}
// sort candModeList
if (candModeList[0] > candModeList[1]) {
std::swap(candModeList[0],candModeList[1]);
}
if (candModeList[0] > candModeList[2]) {
std::swap(candModeList[0],candModeList[2]);
}
if (candModeList[1] > candModeList[2]) {
std::swap(candModeList[1],candModeList[2]);
}
// skip modes already in the candidate list
int intraMode = mode;
for (int i=2;i>=0;i--) {
if (intraMode >= candModeList[i]) { intraMode--; }
}
return -intraMode-1;
}
void list_chroma_pred_candidates(enum IntraPredMode chroma_mode[5],
enum IntraPredMode luma_mode)
{
enum IntraPredMode chroma_cand[5];
chroma_cand[0] = INTRA_PLANAR;
chroma_cand[1] = INTRA_ANGULAR_26;
chroma_cand[2] = INTRA_ANGULAR_10;
chroma_cand[3] = INTRA_DC;
chroma_cand[4] = luma_mode;
switch (luma_mode) {
case INTRA_PLANAR: chroma_cand[0] = INTRA_ANGULAR_34; break;
case INTRA_ANGULAR_26: chroma_cand[1] = INTRA_ANGULAR_34; break;
case INTRA_ANGULAR_10: chroma_cand[2] = INTRA_ANGULAR_34; break;
case INTRA_DC: chroma_cand[3] = INTRA_ANGULAR_34; break;
default:
// use defaults from above
break;
}
}
int get_intra_scan_idx(int log2TrafoSize, enum IntraPredMode intraPredMode, int cIdx,
const seq_parameter_set* sps)
{
if (log2TrafoSize==2 ||
(log2TrafoSize==3 && (cIdx==0 ||
sps->ChromaArrayType==CHROMA_444))) {
/**/ if (intraPredMode >= 6 && intraPredMode <= 14) return 2;
else if (intraPredMode >= 22 && intraPredMode <= 30) return 1;
else return 0;
}
else { return 0; }
}
int get_intra_scan_idx_luma(int log2TrafoSize, enum IntraPredMode intraPredMode)
{
if (log2TrafoSize==2 || log2TrafoSize==3) {
/**/ if (intraPredMode >= 6 && intraPredMode <= 14) return 2;
else if (intraPredMode >= 22 && intraPredMode <= 30) return 1;
else return 0;
}
else { return 0; }
}
int get_intra_scan_idx_chroma(int log2TrafoSize, enum IntraPredMode intraPredMode)
{
if (log2TrafoSize==1 || log2TrafoSize==2) {
/**/ if (intraPredMode >= 6 && intraPredMode <= 14) return 2;
else if (intraPredMode >= 22 && intraPredMode <= 30) return 1;
else return 0;
}
else { return 0; }
}
enum IntraPredMode lumaPredMode_to_chromaPredMode(enum IntraPredMode luma,
enum IntraChromaPredMode chroma)
{
switch (chroma) {
case INTRA_CHROMA_LIKE_LUMA:
return luma;
case INTRA_CHROMA_PLANAR_OR_34:
if (luma==INTRA_PLANAR) return INTRA_ANGULAR_34;
else return INTRA_PLANAR;
case INTRA_CHROMA_ANGULAR_26_OR_34:
if (luma==INTRA_ANGULAR_26) return INTRA_ANGULAR_34;
else return INTRA_ANGULAR_26;
case INTRA_CHROMA_ANGULAR_10_OR_34:
if (luma==INTRA_ANGULAR_10) return INTRA_ANGULAR_34;
else return INTRA_ANGULAR_10;
case INTRA_CHROMA_DC_OR_34:
if (luma==INTRA_DC) return INTRA_ANGULAR_34;
else return INTRA_DC;
}
assert(false);
return INTRA_DC;
}
// (8.4.4.2.2)
template <class pixel_t>
void fill_border_samples(de265_image* img,
int xB,int yB, // in component specific resolution
int nT, int cIdx,
pixel_t* out_border)
{
intra_border_computer<pixel_t> c;
c.init(out_border, img, nT, cIdx, xB, yB);
c.preproc();
c.fill_from_image();
c.reference_sample_substitution();
}
const int intraPredAngle_table[1+34] =
{ 0, 0,32,26,21,17,13, 9, 5, 2, 0,-2,-5,-9,-13,-17,-21,-26,
-32,-26,-21,-17,-13,-9,-5,-2,0,2,5,9,13,17,21,26,32 };
const int invAngle_table[25-10] =
{ -4096,-1638,-910,-630,-482,-390,-315,-256,
-315,-390,-482,-630,-910,-1638,-4096 };
template <class pixel_t>
void decode_intra_prediction_internal(de265_image* img,
int xB0,int yB0,
enum IntraPredMode intraPredMode,
pixel_t* dst, int dstStride,
int nT, int cIdx)
{
pixel_t border_pixels_mem[4*MAX_INTRA_PRED_BLOCK_SIZE+1];
pixel_t* border_pixels = &border_pixels_mem[2*MAX_INTRA_PRED_BLOCK_SIZE];
fill_border_samples(img, xB0,yB0, nT, cIdx, border_pixels);
if (img->get_sps().range_extension.intra_smoothing_disabled_flag == 0 &&
(cIdx==0 || img->get_sps().ChromaArrayType==CHROMA_444))
{
intra_prediction_sample_filtering(img->get_sps(), border_pixels, nT, cIdx, intraPredMode);
}
switch (intraPredMode) {
case INTRA_PLANAR:
intra_prediction_planar(dst,dstStride, nT,cIdx, border_pixels);
break;
case INTRA_DC:
intra_prediction_DC(dst,dstStride, nT,cIdx, border_pixels);
break;
default:
{
int bit_depth = img->get_bit_depth(cIdx);
bool disableIntraBoundaryFilter =
(img->get_sps().range_extension.implicit_rdpcm_enabled_flag &&
img->get_cu_transquant_bypass(xB0,yB0));
intra_prediction_angular(dst,dstStride, bit_depth,disableIntraBoundaryFilter,
xB0,yB0,intraPredMode,nT,cIdx, border_pixels);
}
break;
}
}
// (8.4.4.2.1)
void decode_intra_prediction(de265_image* img,
int xB0,int yB0,
enum IntraPredMode intraPredMode,
int nT, int cIdx)
{
logtrace(LogIntraPred,"decode_intra_prediction xy0:%d/%d mode=%d nT=%d, cIdx=%d\n",
xB0,yB0, intraPredMode, nT,cIdx);
/*
printf("decode_intra_prediction xy0:%d/%d mode=%d nT=%d, cIdx=%d\n",
xB0,yB0, intraPredMode, nT,cIdx);
*/
if (img->high_bit_depth(cIdx)) {
decode_intra_prediction_internal<uint16_t>(img,xB0,yB0, intraPredMode,
img->get_image_plane_at_pos_NEW<uint16_t>(cIdx,xB0,yB0),
img->get_image_stride(cIdx),
nT,cIdx);
}
else {
decode_intra_prediction_internal<uint8_t>(img,xB0,yB0, intraPredMode,
img->get_image_plane_at_pos_NEW<uint8_t>(cIdx,xB0,yB0),
img->get_image_stride(cIdx),
nT,cIdx);
}
}
// TODO: remove this
template <> void decode_intra_prediction<uint8_t>(de265_image* img,
int xB0,int yB0,
enum IntraPredMode intraPredMode,
uint8_t* dst, int nT, int cIdx)
{
decode_intra_prediction_internal<uint8_t>(img,xB0,yB0, intraPredMode,
dst,nT,
nT,cIdx);
}
// TODO: remove this
template <> void decode_intra_prediction<uint16_t>(de265_image* img,
int xB0,int yB0,
enum IntraPredMode intraPredMode,
uint16_t* dst, int nT, int cIdx)
{
decode_intra_prediction_internal<uint16_t>(img,xB0,yB0, intraPredMode,
dst,nT,
nT,cIdx);
}