Add HEVC decoder

Initially written by Guillaume Martres <smarter@ubuntu.com> as a GSoC
project. Further contributions by the OpenHEVC project and other
developers, namely:

Mickaël Raulet <mraulet@insa-rennes.fr>
Seppo Tomperi <seppo.tomperi@vtt.fi>
Gildas Cocherel <gildas.cocherel@laposte.net>
Khaled Jerbi <khaled_jerbi@yahoo.fr>
Wassim Hamidouche <wassim.hamidouche@insa-rennes.fr>
Vittorio Giovara <vittorio.giovara@gmail.com>
Jan Ekström <jeebjp@gmail.com>
Anton Khirnov <anton@khirnov.net>
Martin Storsjö <martin@martin.st>
Luca Barbato <lu_zero@gentoo.org>
Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
Reimar Döffinger <Reimar.Doeffinger@gmx.de>
Diego Biurrun <diego@biurrun.de>

Signed-off-by: Anton Khirnov <anton@khirnov.net>
pull/45/head
Guillaume Martres 12 years ago committed by Anton Khirnov
parent 0a9e94bba8
commit 064698d381
  1. 1
      Changelog
  2. 1
      configure
  3. 1
      doc/general.texi
  4. 4
      libavcodec/Makefile
  5. 2
      libavcodec/allcodecs.c
  6. 1
      libavcodec/avcodec.h
  7. 20
      libavcodec/cabac_functions.h
  8. 7
      libavcodec/codec_desc.c
  9. 3117
      libavcodec/hevc.c
  10. 1066
      libavcodec/hevc.h
  11. 872
      libavcodec/hevc_cabac.c
  12. 745
      libavcodec/hevc_filter.c
  13. 816
      libavcodec/hevc_mvs.c
  14. 125
      libavcodec/hevc_parser.c
  15. 1329
      libavcodec/hevc_ps.c
  16. 489
      libavcodec/hevc_refs.c
  17. 124
      libavcodec/hevc_sei.c
  18. 190
      libavcodec/hevcdsp.c
  19. 1340
      libavcodec/hevcdsp_template.c
  20. 65
      libavcodec/hevcpred.c
  21. 560
      libavcodec/hevcpred_template.c
  22. 2
      libavcodec/version.h

@ -41,6 +41,7 @@ version 10:
- Enhanced Low Delay AAC (ER AAC ELD) decoding (no LD SBR support)
- F4V muxer
- HNM version 4 demuxer and video decoder
- HEVC decoder
version 9:

1
configure vendored

@ -1599,6 +1599,7 @@ h263i_decoder_select="h263_decoder"
h263p_encoder_select="h263_encoder"
h264_decoder_select="golomb h264chroma h264dsp h264pred h264qpel videodsp"
h264_decoder_suggest="error_resilience"
hevc_decoder_select="dsputil golomb videodsp"
huffyuv_decoder_select="dsputil"
huffyuv_encoder_select="dsputil huffman"
iac_decoder_select="dsputil fft mdct sinewin"

@ -526,6 +526,7 @@ following image formats are supported:
@item H.263+ / H.263-1998 / H.263 version 2 @tab X @tab X
@item H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 @tab E @tab X
@tab encoding supported through external library libx264
@item HEVC @tab @tab X
@item HNM version 4 @tab @tab X
@item HuffYUV @tab X @tab X
@item HuffYUV FFmpeg variant @tab X @tab X

@ -196,6 +196,9 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o \
h264_loopfilter.o h264_direct.o \
cabac.o h264_sei.o h264_ps.o \
h264_refs.o h264_cavlc.o h264_cabac.o
OBJS-$(CONFIG_HEVC_DECODER) += hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o \
hevc_cabac.o hevc_refs.o hevcpred.o \
hevcdsp.o hevc_filter.o cabac.o
OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o
OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o
OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o
@ -635,6 +638,7 @@ OBJS-$(CONFIG_H264_PARSER) += h264_parser.o h264.o \
h264_refs.o h264_sei.o h264_direct.o \
h264_loopfilter.o h264_cabac.o \
h264_cavlc.o h264_ps.o
OBJS-$(CONFIG_HEVC_PARSER) += hevc_parser.o
OBJS-$(CONFIG_MJPEG_PARSER) += mjpeg_parser.o
OBJS-$(CONFIG_MLP_PARSER) += mlp_parser.o mlp.o
OBJS-$(CONFIG_MPEG4VIDEO_PARSER) += mpeg4video_parser.o h263.o \

@ -153,6 +153,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(H263I, h263i);
REGISTER_ENCODER(H263P, h263p);
REGISTER_DECODER(H264, h264);
REGISTER_DECODER(HEVC, hevc);
REGISTER_DECODER(HNM4_VIDEO, hnm4_video);
REGISTER_ENCDEC (HUFFYUV, huffyuv);
REGISTER_DECODER(IDCIN, idcin);
@ -453,6 +454,7 @@ void avcodec_register_all(void)
REGISTER_PARSER(H261, h261);
REGISTER_PARSER(H263, h263);
REGISTER_PARSER(H264, h264);
REGISTER_PARSER(HEVC, hevc);
REGISTER_PARSER(MJPEG, mjpeg);
REGISTER_PARSER(MLP, mlp);
REGISTER_PARSER(MPEG4VIDEO, mpeg4video);

@ -275,6 +275,7 @@ enum AVCodecID {
AV_CODEC_ID_G2M,
AV_CODEC_ID_WEBP,
AV_CODEC_ID_HNM4_VIDEO,
AV_CODEC_ID_HEVC,
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs

@ -162,4 +162,24 @@ static int av_unused get_cabac_terminate(CABACContext *c){
}
}
/**
* Skip @p n bytes and reset the decoder.
* @return the address of the first skipped byte or NULL if there's less than @p n bytes left
*/
static av_unused const uint8_t* skip_bytes(CABACContext *c, int n) {
const uint8_t *ptr = c->bytestream;
if (c->low & 0x1)
ptr--;
#if CABAC_BITS == 16
if (c->low & 0x1FF)
ptr--;
#endif
if ((int) (c->bytestream_end - ptr) < n)
return NULL;
ff_init_cabac_decoder(c, ptr + n, c->bytestream_end - ptr - n);
return ptr;
}
#endif /* AVCODEC_CABAC_FUNCTIONS_H */

@ -1243,6 +1243,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("HNM 4 video"),
.props = AV_CODEC_PROP_LOSSY,
},
{
.id = AV_CODEC_ID_HEVC,
.type = AVMEDIA_TYPE_VIDEO,
.name = "hevc",
.long_name = NULL_IF_CONFIG_SMALL("HEVC (High Efficiency Video Coding)"),
.props = AV_CODEC_PROP_LOSSY,
},
/* various PCM "codecs" */
{

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,872 @@
/*
* HEVC CABAC decoding
*
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2012 - 2013 Gildas Cocherel
*
* This file is part of Libav.
*
* Libav 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 2.1 of the License, or (at your option) any later version.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/attributes.h"
#include "libavutil/common.h"
#include "cabac_functions.h"
#include "hevc.h"
#define CABAC_MAX_BIN 100
/**
* number of bin by SyntaxElement.
*/
static const int8_t num_bins_in_se[] = {
1, // sao_merge_flag
1, // sao_type_idx
0, // sao_eo_class
0, // sao_band_position
0, // sao_offset_abs
0, // sao_offset_sign
0, // end_of_slice_flag
3, // split_coding_unit_flag
1, // cu_transquant_bypass_flag
3, // skip_flag
3, // cu_qp_delta
1, // pred_mode
4, // part_mode
0, // pcm_flag
1, // prev_intra_luma_pred_mode
0, // mpm_idx
0, // rem_intra_luma_pred_mode
2, // intra_chroma_pred_mode
1, // merge_flag
1, // merge_idx
5, // inter_pred_idc
2, // ref_idx_l0
2, // ref_idx_l1
2, // abs_mvd_greater0_flag
2, // abs_mvd_greater1_flag
0, // abs_mvd_minus2
0, // mvd_sign_flag
1, // mvp_lx_flag
1, // no_residual_data_flag
3, // split_transform_flag
2, // cbf_luma
4, // cbf_cb, cbf_cr
2, // transform_skip_flag[][]
18, // last_significant_coeff_x_prefix
18, // last_significant_coeff_y_prefix
0, // last_significant_coeff_x_suffix
0, // last_significant_coeff_y_suffix
4, // significant_coeff_group_flag
42, // significant_coeff_flag
24, // coeff_abs_level_greater1_flag
6, // coeff_abs_level_greater2_flag
0, // coeff_abs_level_remaining
0, // coeff_sign_flag
};
/**
* Offset to ctxIdx 0 in init_values and states, indexed by SyntaxElement.
*/
static const int elem_offset[sizeof(num_bins_in_se)] = {
0,
1,
2,
2,
2,
2,
2,
2,
5,
6,
9,
12,
13,
17,
17,
18,
18,
18,
20,
21,
22,
27,
29,
31,
33,
35,
35,
35,
36,
37,
40,
42,
46,
48,
66,
84,
84,
84,
88,
130,
154,
160,
160,
};
#define CNU 154
/**
* Indexed by init_type
*/
static const uint8_t init_values[3][HEVC_CONTEXTS] = {
{ // sao_merge_flag
153,
// sao_type_idx
200,
// split_coding_unit_flag
139, 141, 157,
// cu_transquant_bypass_flag
154,
// skip_flag
CNU, CNU, CNU,
// cu_qp_delta
154, 154, 154,
// pred_mode
CNU,
// part_mode
184, CNU, CNU, CNU,
// prev_intra_luma_pred_mode
184,
// intra_chroma_pred_mode
63, 139,
// merge_flag
CNU,
// merge_idx
CNU,
// inter_pred_idc
CNU, CNU, CNU, CNU, CNU,
// ref_idx_l0
CNU, CNU,
// ref_idx_l1
CNU, CNU,
// abs_mvd_greater1_flag
CNU, CNU,
// abs_mvd_greater1_flag
CNU, CNU,
// mvp_lx_flag
CNU,
// no_residual_data_flag
CNU,
// split_transform_flag
153, 138, 138,
// cbf_luma
111, 141,
// cbf_cb, cbf_cr
94, 138, 182, 154,
// transform_skip_flag
139, 139,
// last_significant_coeff_x_prefix
110, 110, 124, 125, 140, 153, 125, 127, 140, 109, 111, 143, 127, 111,
79, 108, 123, 63,
// last_significant_coeff_y_prefix
110, 110, 124, 125, 140, 153, 125, 127, 140, 109, 111, 143, 127, 111,
79, 108, 123, 63,
// significant_coeff_group_flag
91, 171, 134, 141,
// significant_coeff_flag
111, 111, 125, 110, 110, 94, 124, 108, 124, 107, 125, 141, 179, 153,
125, 107, 125, 141, 179, 153, 125, 107, 125, 141, 179, 153, 125, 140,
139, 182, 182, 152, 136, 152, 136, 153, 136, 139, 111, 136, 139, 111,
// coeff_abs_level_greater1_flag
140, 92, 137, 138, 140, 152, 138, 139, 153, 74, 149, 92, 139, 107,
122, 152, 140, 179, 166, 182, 140, 227, 122, 197,
// coeff_abs_level_greater2_flag
138, 153, 136, 167, 152, 152, },
{ // sao_merge_flag
153,
// sao_type_idx
185,
// split_coding_unit_flag
107, 139, 126,
// cu_transquant_bypass_flag
154,
// skip_flag
197, 185, 201,
// cu_qp_delta
154, 154, 154,
// pred_mode
149,
// part_mode
154, 139, 154, 154,
// prev_intra_luma_pred_mode
154,
// intra_chroma_pred_mode
152, 139,
// merge_flag
110,
// merge_idx
122,
// inter_pred_idc
95, 79, 63, 31, 31,
// ref_idx_l0
153, 153,
// ref_idx_l1
153, 153,
// abs_mvd_greater1_flag
140, 198,
// abs_mvd_greater1_flag
140, 198,
// mvp_lx_flag
168,
// no_residual_data_flag
79,
// split_transform_flag
124, 138, 94,
// cbf_luma
153, 111,
// cbf_cb, cbf_cr
149, 107, 167, 154,
// transform_skip_flag
139, 139,
// last_significant_coeff_x_prefix
125, 110, 94, 110, 95, 79, 125, 111, 110, 78, 110, 111, 111, 95,
94, 108, 123, 108,
// last_significant_coeff_y_prefix
125, 110, 94, 110, 95, 79, 125, 111, 110, 78, 110, 111, 111, 95,
94, 108, 123, 108,
// significant_coeff_group_flag
121, 140, 61, 154,
// significant_coeff_flag
155, 154, 139, 153, 139, 123, 123, 63, 153, 166, 183, 140, 136, 153,
154, 166, 183, 140, 136, 153, 154, 166, 183, 140, 136, 153, 154, 170,
153, 123, 123, 107, 121, 107, 121, 167, 151, 183, 140, 151, 183, 140,
// coeff_abs_level_greater1_flag
154, 196, 196, 167, 154, 152, 167, 182, 182, 134, 149, 136, 153, 121,
136, 137, 169, 194, 166, 167, 154, 167, 137, 182,
// coeff_abs_level_greater2_flag
107, 167, 91, 122, 107, 167, },
{ // sao_merge_flag
153,
// sao_type_idx
160,
// split_coding_unit_flag
107, 139, 126,
// cu_transquant_bypass_flag
154,
// skip_flag
197, 185, 201,
// cu_qp_delta
154, 154, 154,
// pred_mode
134,
// part_mode
154, 139, 154, 154,
// prev_intra_luma_pred_mode
183,
// intra_chroma_pred_mode
152, 139,
// merge_flag
154,
// merge_idx
137,
// inter_pred_idc
95, 79, 63, 31, 31,
// ref_idx_l0
153, 153,
// ref_idx_l1
153, 153,
// abs_mvd_greater1_flag
169, 198,
// abs_mvd_greater1_flag
169, 198,
// mvp_lx_flag
168,
// no_residual_data_flag
79,
// split_transform_flag
224, 167, 122,
// cbf_luma
153, 111,
// cbf_cb, cbf_cr
149, 92, 167, 154,
// transform_skip_flag
139, 139,
// last_significant_coeff_x_prefix
125, 110, 124, 110, 95, 94, 125, 111, 111, 79, 125, 126, 111, 111,
79, 108, 123, 93,
// last_significant_coeff_y_prefix
125, 110, 124, 110, 95, 94, 125, 111, 111, 79, 125, 126, 111, 111,
79, 108, 123, 93,
// significant_coeff_group_flag
121, 140, 61, 154,
// significant_coeff_flag
170, 154, 139, 153, 139, 123, 123, 63, 124, 166, 183, 140, 136, 153,
154, 166, 183, 140, 136, 153, 154, 166, 183, 140, 136, 153, 154, 170,
153, 138, 138, 122, 121, 122, 121, 167, 151, 183, 140, 151, 183, 140,
// coeff_abs_level_greater1_flag
154, 196, 167, 167, 154, 152, 167, 182, 182, 134, 149, 136, 153, 121,
136, 122, 169, 208, 166, 167, 154, 152, 167, 182,
// coeff_abs_level_greater2_flag
107, 167, 91, 107, 107, 167, },
};
void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts)
{
if (s->pps->entropy_coding_sync_enabled_flag &&
(ctb_addr_ts % s->sps->ctb_width == 2 ||
(s->sps->ctb_width == 2 &&
ctb_addr_ts % s->sps->ctb_width == 0))) {
memcpy(s->cabac_state, s->HEVClc.cabac_state, HEVC_CONTEXTS);
}
}
static void load_states(HEVCContext *s)
{
memcpy(s->HEVClc.cabac_state, s->cabac_state, HEVC_CONTEXTS);
}
static void cabac_reinit(HEVCLocalContext *lc)
{
skip_bytes(&lc->cc, 0);
}
static void cabac_init_decoder(HEVCContext *s)
{
GetBitContext *gb = &s->HEVClc.gb;
skip_bits(gb, 1);
align_get_bits(gb);
ff_init_cabac_decoder(&s->HEVClc.cc,
gb->buffer + get_bits_count(gb) / 8,
(get_bits_left(gb) + 7) / 8);
}
static void cabac_init_state(HEVCContext *s)
{
int init_type = 2 - s->sh.slice_type;
int i;
if (s->sh.cabac_init_flag && s->sh.slice_type != I_SLICE)
init_type ^= 3;
for (i = 0; i < HEVC_CONTEXTS; i++) {
int init_value = init_values[init_type][i];
int m = (init_value >> 4) * 5 - 45;
int n = ((init_value & 15) << 3) - 16;
int pre = 2 * (((m * av_clip_c(s->sh.slice_qp, 0, 51)) >> 4) + n) - 127;
pre ^= pre >> 31;
if (pre > 124)
pre = 124 + (pre & 1);
s->HEVClc.cabac_state[i] = pre;
}
}
void ff_hevc_cabac_init(HEVCContext *s, int ctb_addr_ts)
{
if (ctb_addr_ts == s->pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs]) {
cabac_init_decoder(s);
if (s->sh.dependent_slice_segment_flag == 0 ||
(s->pps->tiles_enabled_flag &&
s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1]))
cabac_init_state(s);
if (!s->sh.first_slice_in_pic_flag &&
s->pps->entropy_coding_sync_enabled_flag) {
if (ctb_addr_ts % s->sps->ctb_width == 0) {
if (s->sps->ctb_width == 1)
cabac_init_state(s);
else if (s->sh.dependent_slice_segment_flag == 1)
load_states(s);
}
}
} else {
if (s->pps->tiles_enabled_flag &&
s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1]) {
cabac_reinit(&s->HEVClc);
cabac_init_state(s);
}
if (s->pps->entropy_coding_sync_enabled_flag) {
if (ctb_addr_ts % s->sps->ctb_width == 0) {
get_cabac_terminate(&s->HEVClc.cc);
cabac_reinit(&s->HEVClc);
if (s->sps->ctb_width == 1)
cabac_init_state(s);
else
load_states(s);
}
}
}
}
#define GET_CABAC(ctx) get_cabac(&s->HEVClc.cc, &s->HEVClc.cabac_state[ctx])
int ff_hevc_sao_merge_flag_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[SAO_MERGE_FLAG]);
}
int ff_hevc_sao_type_idx_decode(HEVCContext *s)
{
if (!GET_CABAC(elem_offset[SAO_TYPE_IDX]))
return 0;
if (!get_cabac_bypass(&s->HEVClc.cc))
return SAO_BAND;
return SAO_EDGE;
}
int ff_hevc_sao_band_position_decode(HEVCContext *s)
{
int i;
int value = get_cabac_bypass(&s->HEVClc.cc);
for (i = 0; i < 4; i++)
value = (value << 1) | get_cabac_bypass(&s->HEVClc.cc);
return value;
}
int ff_hevc_sao_offset_abs_decode(HEVCContext *s)
{
int i = 0;
int length = (1 << (FFMIN(s->sps->bit_depth, 10) - 5)) - 1;
while (i < length && get_cabac_bypass(&s->HEVClc.cc))
i++;
return i;
}
int ff_hevc_sao_offset_sign_decode(HEVCContext *s)
{
return get_cabac_bypass(&s->HEVClc.cc);
}
int ff_hevc_sao_eo_class_decode(HEVCContext *s)
{
int ret = get_cabac_bypass(&s->HEVClc.cc) << 1;
ret |= get_cabac_bypass(&s->HEVClc.cc);
return ret;
}
int ff_hevc_end_of_slice_flag_decode(HEVCContext *s)
{
return get_cabac_terminate(&s->HEVClc.cc);
}
int ff_hevc_cu_transquant_bypass_flag_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[CU_TRANSQUANT_BYPASS_FLAG]);
}
int ff_hevc_skip_flag_decode(HEVCContext *s, int x0, int y0, int x_cb, int y_cb)
{
int min_cb_width = s->sps->min_cb_width;
int inc = 0;
int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
if (s->HEVClc.ctb_left_flag || x0b)
inc = !!SAMPLE_CTB(s->skip_flag, x_cb - 1, y_cb);
if (s->HEVClc.ctb_up_flag || y0b)
inc += !!SAMPLE_CTB(s->skip_flag, x_cb, y_cb - 1);
return GET_CABAC(elem_offset[SKIP_FLAG] + inc);
}
int ff_hevc_cu_qp_delta_abs(HEVCContext *s)
{
int prefix_val = 0;
int suffix_val = 0;
int inc = 0;
while (prefix_val < 5 && GET_CABAC(elem_offset[CU_QP_DELTA] + inc)) {
prefix_val++;
inc = 1;
}
if (prefix_val >= 5) {
int k = 0;
while (k < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc.cc)) {
suffix_val += 1 << k;
k++;
}
if (k == CABAC_MAX_BIN)
av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", k);
while (k--)
suffix_val += get_cabac_bypass(&s->HEVClc.cc) << k;
}
return prefix_val + suffix_val;
}
int ff_hevc_cu_qp_delta_sign_flag(HEVCContext *s)
{
return get_cabac_bypass(&s->HEVClc.cc);
}
int ff_hevc_pred_mode_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[PRED_MODE_FLAG]);
}
int ff_hevc_split_coding_unit_flag_decode(HEVCContext *s, int ct_depth, int x0, int y0)
{
int inc = 0, depth_left = 0, depth_top = 0;
int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
int x_cb = x0 >> s->sps->log2_min_cb_size;
int y_cb = y0 >> s->sps->log2_min_cb_size;
if (s->HEVClc.ctb_left_flag || x0b)
depth_left = s->tab_ct_depth[(y_cb) * s->sps->min_cb_width + x_cb - 1];
if (s->HEVClc.ctb_up_flag || y0b)
depth_top = s->tab_ct_depth[(y_cb - 1) * s->sps->min_cb_width + x_cb];
inc += (depth_left > ct_depth);
inc += (depth_top > ct_depth);
return GET_CABAC(elem_offset[SPLIT_CODING_UNIT_FLAG] + inc);
}
int ff_hevc_part_mode_decode(HEVCContext *s, int log2_cb_size)
{
if (GET_CABAC(elem_offset[PART_MODE])) // 1
return PART_2Nx2N;
if (log2_cb_size == s->sps->log2_min_cb_size) {
if (s->HEVClc.cu.pred_mode == MODE_INTRA) // 0
return PART_NxN;
if (GET_CABAC(elem_offset[PART_MODE] + 1)) // 01
return PART_2NxN;
if (log2_cb_size == 3) // 00
return PART_Nx2N;
if (GET_CABAC(elem_offset[PART_MODE] + 2)) // 001
return PART_Nx2N;
return PART_NxN; // 000
}
if (!s->sps->amp_enabled_flag) {
if (GET_CABAC(elem_offset[PART_MODE] + 1)) // 01
return PART_2NxN;
return PART_Nx2N;
}
if (GET_CABAC(elem_offset[PART_MODE] + 1)) { // 01X, 01XX
if (GET_CABAC(elem_offset[PART_MODE] + 3)) // 011
return PART_2NxN;
if (get_cabac_bypass(&s->HEVClc.cc)) // 0101
return PART_2NxnD;
return PART_2NxnU; // 0100
}
if (GET_CABAC(elem_offset[PART_MODE] + 3)) // 001
return PART_Nx2N;
if (get_cabac_bypass(&s->HEVClc.cc)) // 0001
return PART_nRx2N;
return PART_nLx2N; // 0000
}
int ff_hevc_pcm_flag_decode(HEVCContext *s)
{
return get_cabac_terminate(&s->HEVClc.cc);
}
int ff_hevc_prev_intra_luma_pred_flag_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[PREV_INTRA_LUMA_PRED_FLAG]);
}
int ff_hevc_mpm_idx_decode(HEVCContext *s)
{
int i = 0;
while (i < 2 && get_cabac_bypass(&s->HEVClc.cc))
i++;
return i;
}
int ff_hevc_rem_intra_luma_pred_mode_decode(HEVCContext *s)
{
int i;
int value = get_cabac_bypass(&s->HEVClc.cc);
for (i = 0; i < 4; i++)
value = (value << 1) | get_cabac_bypass(&s->HEVClc.cc);
return value;
}
int ff_hevc_intra_chroma_pred_mode_decode(HEVCContext *s)
{
int ret;
if (!GET_CABAC(elem_offset[INTRA_CHROMA_PRED_MODE]))
return 4;
ret = get_cabac_bypass(&s->HEVClc.cc) << 1;
ret |= get_cabac_bypass(&s->HEVClc.cc);
return ret;
}
int ff_hevc_merge_idx_decode(HEVCContext *s)
{
int i = GET_CABAC(elem_offset[MERGE_IDX]);
if (i != 0) {
while (i < s->sh.max_num_merge_cand-1 && get_cabac_bypass(&s->HEVClc.cc))
i++;
}
return i;
}
int ff_hevc_merge_flag_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[MERGE_FLAG]);
}
int ff_hevc_inter_pred_idc_decode(HEVCContext *s, int nPbW, int nPbH)
{
if (nPbW + nPbH == 12)
return GET_CABAC(elem_offset[INTER_PRED_IDC] + 4);
if (GET_CABAC(elem_offset[INTER_PRED_IDC] + s->HEVClc.ct.depth))
return PRED_BI;
return GET_CABAC(elem_offset[INTER_PRED_IDC] + 4);
}
int ff_hevc_ref_idx_lx_decode(HEVCContext *s, int num_ref_idx_lx)
{
int i = 0;
int max = num_ref_idx_lx - 1;
int max_ctx = FFMIN(max, 2);
while (i < max_ctx && GET_CABAC(elem_offset[REF_IDX_L0] + i))
i++;
if (i == 2) {
while (i < max && get_cabac_bypass(&s->HEVClc.cc))
i++;
}
return i;
}
int ff_hevc_mvp_lx_flag_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[MVP_LX_FLAG]);
}
int ff_hevc_no_residual_syntax_flag_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[NO_RESIDUAL_DATA_FLAG]);
}
int ff_hevc_abs_mvd_greater0_flag_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[ABS_MVD_GREATER0_FLAG]);
}
int ff_hevc_abs_mvd_greater1_flag_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[ABS_MVD_GREATER1_FLAG] + 1);
}
int ff_hevc_mvd_decode(HEVCContext *s)
{
int ret = 2;
int k = 1;
while (k < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc.cc)) {
ret += 1 << k;
k++;
}
if (k == CABAC_MAX_BIN)
av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", k);
while (k--)
ret += get_cabac_bypass(&s->HEVClc.cc) << k;
return get_cabac_bypass_sign(&s->HEVClc.cc, -ret);
}
int ff_hevc_mvd_sign_flag_decode(HEVCContext *s)
{
return get_cabac_bypass_sign(&s->HEVClc.cc, -1);
}
int ff_hevc_split_transform_flag_decode(HEVCContext *s, int log2_trafo_size)
{
return GET_CABAC(elem_offset[SPLIT_TRANSFORM_FLAG] + 5 - log2_trafo_size);
}
int ff_hevc_cbf_cb_cr_decode(HEVCContext *s, int trafo_depth)
{
return GET_CABAC(elem_offset[CBF_CB_CR] + trafo_depth);
}
int ff_hevc_cbf_luma_decode(HEVCContext *s, int trafo_depth)
{
return GET_CABAC(elem_offset[CBF_LUMA] + !trafo_depth);
}
int ff_hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx)
{
return GET_CABAC(elem_offset[TRANSFORM_SKIP_FLAG] + !!c_idx);
}
#define LAST_SIG_COEFF(elem) \
int i = 0; \
int max = (log2_size << 1) - 1; \
int ctx_offset, ctx_shift; \
\
if (c_idx == 0) { \
ctx_offset = 3 * (log2_size - 2) + ((log2_size - 1) >> 2); \
ctx_shift = (log2_size + 1) >> 2; \
} else { \
ctx_offset = 15; \
ctx_shift = log2_size - 2; \
} \
while (i < max && \
GET_CABAC(elem_offset[elem] + (i >> ctx_shift) + ctx_offset)) \
i++; \
return i;
int ff_hevc_last_significant_coeff_x_prefix_decode(HEVCContext *s, int c_idx,
int log2_size)
{
LAST_SIG_COEFF(LAST_SIGNIFICANT_COEFF_X_PREFIX)
}
int ff_hevc_last_significant_coeff_y_prefix_decode(HEVCContext *s, int c_idx,
int log2_size)
{
LAST_SIG_COEFF(LAST_SIGNIFICANT_COEFF_Y_PREFIX)
}
int ff_hevc_last_significant_coeff_suffix_decode(HEVCContext *s,
int last_significant_coeff_prefix)
{
int i;
int length = (last_significant_coeff_prefix >> 1) - 1;
int value = get_cabac_bypass(&s->HEVClc.cc);
for (i = 1; i < length; i++)
value = (value << 1) | get_cabac_bypass(&s->HEVClc.cc);
return value;
}
int ff_hevc_significant_coeff_group_flag_decode(HEVCContext *s, int c_idx, int ctx_cg)
{
int inc;
inc = FFMIN(ctx_cg, 1) + (c_idx>0 ? 2 : 0);
return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_GROUP_FLAG] + inc);
}
int ff_hevc_significant_coeff_flag_decode(HEVCContext *s, int c_idx, int x_c, int y_c,
int log2_trafo_size, int scan_idx, int prev_sig)
{
static const uint8_t ctx_idx_map[] = {
0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8
};
int x_cg = x_c >> 2;
int y_cg = y_c >> 2;
int sig_ctx, inc;
if (x_c + y_c == 0) {
sig_ctx = 0;
} else if (log2_trafo_size == 2) {
sig_ctx = ctx_idx_map[(y_c << 2) + x_c];
} else {
switch (prev_sig) {
case 0: {
int x_off = x_c & 3;
int y_off = y_c & 3;
sig_ctx = ((x_off + y_off) == 0) ? 2 : ((x_off + y_off) <= 2) ? 1 : 0;
}
break;
case 1:
sig_ctx = 2 - FFMIN(y_c & 3, 2);
break;
case 2:
sig_ctx = 2 - FFMIN(x_c & 3, 2);
break;
default:
sig_ctx = 2;
}
if (c_idx == 0 && (x_cg > 0 || y_cg > 0))
sig_ctx += 3;
if (log2_trafo_size == 3) {
sig_ctx += (scan_idx == SCAN_DIAG) ? 9 : 15;
} else {
sig_ctx += c_idx ? 12 : 21;
}
}
if (c_idx == 0)
inc = sig_ctx;
else
inc = sig_ctx + 27;
return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + inc);
}
int ff_hevc_coeff_abs_level_greater1_flag_decode(HEVCContext *s, int c_idx, int inc)
{
if (c_idx > 0)
inc += 16;
return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER1_FLAG] + inc);
}
int ff_hevc_coeff_abs_level_greater2_flag_decode(HEVCContext *s, int c_idx, int inc)
{
if (c_idx > 0)
inc += 4;
return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER2_FLAG] + inc);
}
int ff_hevc_coeff_abs_level_remaining(HEVCContext *s, int base_level, int rc_rice_param)
{
int prefix = 0;
int suffix = 0;
int last_coeff_abs_level_remaining;
int i;
while (prefix < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc.cc))
prefix++;
if (prefix == CABAC_MAX_BIN)
av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", prefix);
if (prefix < 3) {
for (i = 0; i < rc_rice_param; i++)
suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc.cc);
last_coeff_abs_level_remaining = (prefix << rc_rice_param) + suffix;
} else {
int prefix_minus3 = prefix - 3;
for (i = 0; i < prefix_minus3 + rc_rice_param; i++)
suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc.cc);
last_coeff_abs_level_remaining = (((1 << prefix_minus3) + 3 - 1)
<< rc_rice_param) + suffix;
}
return last_coeff_abs_level_remaining;
}
int ff_hevc_coeff_sign_flag(HEVCContext *s, uint8_t nb)
{
int i;
int ret = 0;
for (i = 0; i < nb; i++)
ret = (ret << 1) | get_cabac_bypass(&s->HEVClc.cc);
return ret;
}

@ -0,0 +1,745 @@
/*
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2013 Seppo Tomperi
* Copyright (C) 2013 Wassim Hamidouche
*
* This file is part of Libav.
*
* Libav 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 2.1 of the License, or (at your option) any later version.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/common.h"
#include "libavutil/internal.h"
#include "cabac_functions.h"
#include "golomb.h"
#include "hevc.h"
#define LUMA 0
#define CB 1
#define CR 2
static const uint8_t tctable[54] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // QP 0...18
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, // QP 19...37
5, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 24 // QP 38...53
};
static const uint8_t betatable[52] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, // QP 0...18
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, // QP 19...37
38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64 // QP 38...51
};
static int chroma_tc(HEVCContext *s, int qp_y, int c_idx, int tc_offset)
{
static const int qp_c[] = {
29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37
};
int qp, qp_i, offset, idxt;
// slice qp offset is not used for deblocking
if (c_idx == 1)
offset = s->pps->cb_qp_offset;
else
offset = s->pps->cr_qp_offset;
qp_i = av_clip_c(qp_y + offset, 0, 57);
if (qp_i < 30)
qp = qp_i;
else if (qp_i > 43)
qp = qp_i - 6;
else
qp = qp_c[qp_i - 30];
idxt = av_clip_c(qp + DEFAULT_INTRA_TC_OFFSET + tc_offset, 0, 53);
return tctable[idxt];
}
static int get_qPy_pred(HEVCContext *s, int xC, int yC,
int xBase, int yBase, int log2_cb_size)
{
HEVCLocalContext *lc = &s->HEVClc;
int ctb_size_mask = (1 << s->sps->log2_ctb_size) - 1;
int MinCuQpDeltaSizeMask = (1 << (s->sps->log2_ctb_size -
s->pps->diff_cu_qp_delta_depth)) - 1;
int xQgBase = xBase - (xBase & MinCuQpDeltaSizeMask);
int yQgBase = yBase - (yBase & MinCuQpDeltaSizeMask);
int min_cb_width = s->sps->min_cb_width;
int min_cb_height = s->sps->min_cb_height;
int x_cb = xQgBase >> s->sps->log2_min_cb_size;
int y_cb = yQgBase >> s->sps->log2_min_cb_size;
int availableA = (xBase & ctb_size_mask) &&
(xQgBase & ctb_size_mask);
int availableB = (yBase & ctb_size_mask) &&
(yQgBase & ctb_size_mask);
int qPy_pred, qPy_a, qPy_b;
// qPy_pred
if (lc->first_qp_group) {
lc->first_qp_group = !lc->tu.is_cu_qp_delta_coded;
qPy_pred = s->sh.slice_qp;
} else {
qPy_pred = lc->qp_y;
if (log2_cb_size < s->sps->log2_ctb_size -
s->pps->diff_cu_qp_delta_depth) {
static const int offsetX[8][8] = {
{ -1, 1, 3, 1, 7, 1, 3, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 3, 1, 3, 1, 3, 1, 3 },
{ 2, 2, 2, 2, 2, 2, 2, 2 },
{ 3, 5, 7, 5, 3, 5, 7, 5 },
{ 4, 4, 4, 4, 4, 4, 4, 4 },
{ 5, 7, 5, 7, 5, 7, 5, 7 },
{ 6, 6, 6, 6, 6, 6, 6, 6 }
};
static const int offsetY[8][8] = {
{ 7, 0, 1, 2, 3, 4, 5, 6 },
{ 0, 1, 2, 3, 4, 5, 6, 7 },
{ 1, 0, 3, 2, 5, 4, 7, 6 },
{ 0, 1, 2, 3, 4, 5, 6, 7 },
{ 3, 0, 1, 2, 7, 4, 5, 6 },
{ 0, 1, 2, 3, 4, 5, 6, 7 },
{ 1, 0, 3, 2, 5, 4, 7, 6 },
{ 0, 1, 2, 3, 4, 5, 6, 7 }
};
int xC0b = (xC - (xC & ctb_size_mask)) >> s->sps->log2_min_cb_size;
int yC0b = (yC - (yC & ctb_size_mask)) >> s->sps->log2_min_cb_size;
int idxX = (xQgBase & ctb_size_mask) >> s->sps->log2_min_cb_size;
int idxY = (yQgBase & ctb_size_mask) >> s->sps->log2_min_cb_size;
int idx_mask = ctb_size_mask >> s->sps->log2_min_cb_size;
int x, y;
x = FFMIN(xC0b + offsetX[idxX][idxY], min_cb_width - 1);
y = FFMIN(yC0b + (offsetY[idxX][idxY] & idx_mask), min_cb_height - 1);
if (xC0b == (lc->start_of_tiles_x >> s->sps->log2_min_cb_size) &&
offsetX[idxX][idxY] == -1) {
x = (lc->end_of_tiles_x >> s->sps->log2_min_cb_size) - 1;
y = yC0b - 1;
}
qPy_pred = s->qp_y_tab[y * min_cb_width + x];
}
}
// qPy_a
if (availableA == 0)
qPy_a = qPy_pred;
else
qPy_a = s->qp_y_tab[(x_cb - 1) + y_cb * min_cb_width];
// qPy_b
if (availableB == 0)
qPy_b = qPy_pred;
else
qPy_b = s->qp_y_tab[x_cb + (y_cb - 1) * min_cb_width];
return (qPy_a + qPy_b + 1) >> 1;
}
void ff_hevc_set_qPy(HEVCContext *s, int xC, int yC,
int xBase, int yBase, int log2_cb_size)
{
int qp_y = get_qPy_pred(s, xC, yC, xBase, yBase, log2_cb_size);
if (s->HEVClc.tu.cu_qp_delta != 0) {
int off = s->sps->qp_bd_offset;
s->HEVClc.qp_y = ((qp_y + s->HEVClc.tu.cu_qp_delta + 52 + 2 * off) %
(52 + off)) - off;
} else
s->HEVClc.qp_y = qp_y;
}
static int get_qPy(HEVCContext *s, int xC, int yC)
{
int log2_min_cb_size = s->sps->log2_min_cb_size;
int x = xC >> log2_min_cb_size;
int y = yC >> log2_min_cb_size;
return s->qp_y_tab[x + y * s->sps->min_cb_width];
}
static void copy_CTB(uint8_t *dst, uint8_t *src,
int width, int height, int stride)
{
int i;
for (i = 0; i < height; i++) {
memcpy(dst, src, width);
dst += stride;
src += stride;
}
}
#define CTB(tab, x, y) ((tab)[(y) * s->sps->ctb_width + (x)])
static void sao_filter_CTB(HEVCContext *s, int x, int y)
{
// TODO: This should be easily parallelizable
// TODO: skip CBs when (cu_transquant_bypass_flag || (pcm_loop_filter_disable_flag && pcm_flag))
int c_idx = 0;
int class = 1, class_index;
int edges[4]; // 0 left 1 top 2 right 3 bottom
SAOParams *sao[4];
int classes[4];
int x_shift = 0, y_shift = 0;
int x_ctb = x >> s->sps->log2_ctb_size;
int y_ctb = y >> s->sps->log2_ctb_size;
int ctb_addr_rs = y_ctb * s->sps->ctb_width + x_ctb;
int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[ctb_addr_rs];
// flags indicating unfilterable edges
uint8_t vert_edge[] = { 0, 0, 0, 0 };
uint8_t horiz_edge[] = { 0, 0, 0, 0 };
uint8_t diag_edge[] = { 0, 0, 0, 0 };
uint8_t lfase[3]; // current, above, left
uint8_t no_tile_filter = s->pps->tiles_enabled_flag &&
!s->pps->loop_filter_across_tiles_enabled_flag;
uint8_t left_tile_edge = 0, up_tile_edge = 0;
sao[0] = &CTB(s->sao, x_ctb, y_ctb);
edges[0] = x_ctb == 0;
edges[1] = y_ctb == 0;
edges[2] = x_ctb == s->sps->ctb_width - 1;
edges[3] = y_ctb == s->sps->ctb_height - 1;
lfase[0] = CTB(s->filter_slice_edges, x_ctb, y_ctb);
classes[0] = 0;
if (!edges[0]) {
left_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs-1]];
sao[class] = &CTB(s->sao, x_ctb - 1, y_ctb);
vert_edge[0] = (!lfase[0] && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb)) || left_tile_edge;
vert_edge[2] = vert_edge[0];
lfase[2] = CTB(s->filter_slice_edges, x_ctb - 1, y_ctb);
classes[class] = 2;
class++;
x_shift = 8;
}
if (!edges[1]) {
up_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs - s->sps->ctb_width]];
sao[class] = &CTB(s->sao, x_ctb, y_ctb - 1);
horiz_edge[0] = (!lfase[0] && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) || up_tile_edge;
horiz_edge[1] = horiz_edge[0];
lfase[1] = CTB(s->filter_slice_edges, x_ctb, y_ctb - 1);
classes[class] = 1;
class++;
y_shift = 4;
if (!edges[0]) {
classes[class] = 3;
sao[class] = &CTB(s->sao, x_ctb - 1, y_ctb - 1);
class++;
// Tile check here is done current CTB row/col, not above/left like you'd expect,
//but that is because the tile boundary always extends through the whole pic
vert_edge[1] = (!lfase[1] && CTB(s->tab_slice_address, x_ctb, y_ctb - 1) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || left_tile_edge;
vert_edge[3] = vert_edge[1];
horiz_edge[2] = (!lfase[2] && CTB(s->tab_slice_address, x_ctb - 1, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || up_tile_edge;
horiz_edge[3] = horiz_edge[2];
diag_edge[0] = (!lfase[0] && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || left_tile_edge || up_tile_edge;
diag_edge[3] = diag_edge[0];
// Does left CTB comes after above CTB?
if (CTB(s->tab_slice_address, x_ctb - 1, y_ctb) >
CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) {
diag_edge[2] = !lfase[2] || left_tile_edge || up_tile_edge;
diag_edge[1] = diag_edge[2];
} else if (CTB(s->tab_slice_address, x_ctb - 1, y_ctb) <
CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) {
diag_edge[1] = !lfase[1] || left_tile_edge || up_tile_edge;
diag_edge[2] = diag_edge[1];
} else {
// Same slice, only consider tiles
diag_edge[2] = left_tile_edge || up_tile_edge;
diag_edge[1] = diag_edge[2];
}
}
}
for (c_idx = 0; c_idx < 3; c_idx++) {
int chroma = c_idx ? 1 : 0;
int x0 = x >> chroma;
int y0 = y >> chroma;
int stride = s->frame->linesize[c_idx];
int ctb_size = (1 << (s->sps->log2_ctb_size)) >> s->sps->hshift[c_idx];
int width = FFMIN(ctb_size,
(s->sps->width >> s->sps->hshift[c_idx]) - x0);
int height = FFMIN(ctb_size,
(s->sps->height >> s->sps->vshift[c_idx]) - y0);
uint8_t *src = &s->frame->data[c_idx][y0 * stride + (x0 << s->sps->pixel_shift)];
uint8_t *dst = &s->sao_frame->data[c_idx][y0 * stride + (x0 << s->sps->pixel_shift)];
int offset = (y_shift >> chroma) * stride + ((x_shift >> chroma) << s->sps->pixel_shift);
copy_CTB(dst - offset, src - offset,
(edges[2] ? width + (x_shift >> chroma) : width) << s->sps->pixel_shift,
(edges[3] ? height + (y_shift >> chroma) : height), stride);
for (class_index = 0; class_index < class; class_index++) {
switch (sao[class_index]->type_idx[c_idx]) {
case SAO_BAND:
s->hevcdsp.sao_band_filter[classes[class_index]](dst, src,
stride,
sao[class_index],
edges, width,
height, c_idx);
break;
case SAO_EDGE:
s->hevcdsp.sao_edge_filter[classes[class_index]](dst, src,
stride,
sao[class_index],
edges, width,
height, c_idx,
vert_edge[classes[class_index]],
horiz_edge[classes[class_index]],
diag_edge[classes[class_index]]);
break;
}
}
}
}
static int get_pcm(HEVCContext *s, int x, int y)
{
int log2_min_pu_size = s->sps->log2_min_pu_size;
int x_pu = x >> log2_min_pu_size;
int y_pu = y >> log2_min_pu_size;
if (x < 0 || x_pu >= s->sps->min_pu_width ||
y < 0 || y_pu >= s->sps->min_pu_height)
return 2;
return s->is_pcm[y_pu * s->sps->min_pu_width + x_pu];
}
#define TC_CALC(qp, bs) \
tctable[av_clip((qp) + DEFAULT_INTRA_TC_OFFSET * ((bs) - 1) + \
(tc_offset >> 1 << 1), \
0, MAX_QP + DEFAULT_INTRA_TC_OFFSET)]
static void deblocking_filter_CTB(HEVCContext *s, int x0, int y0)
{
uint8_t *src;
int x, y, x_end, y_end, chroma;
int c_tc[2], beta[2], tc[2];
uint8_t no_p[2] = { 0 };
uint8_t no_q[2] = { 0 };
int log2_ctb_size = s->sps->log2_ctb_size;
int ctb_size = 1 << log2_ctb_size;
int ctb = (x0 >> log2_ctb_size) +
(y0 >> log2_ctb_size) * s->sps->ctb_width;
int cur_tc_offset = s->deblock[ctb].tc_offset;
int cur_beta_offset = s->deblock[ctb].beta_offset;
int tc_offset, left_tc_offset, beta_offset, left_beta_offset;
int pcmf = (s->sps->pcm_enabled_flag &&
s->sps->pcm.loop_filter_disable_flag) ||
s->pps->transquant_bypass_enable_flag;
if (x0) {
left_tc_offset = s->deblock[ctb - 1].tc_offset;
left_beta_offset = s->deblock[ctb - 1].beta_offset;
}
x_end = x0 + ctb_size;
if (x_end > s->sps->width)
x_end = s->sps->width;
y_end = y0 + ctb_size;
if (y_end > s->sps->height)
y_end = s->sps->height;
tc_offset = cur_tc_offset;
beta_offset = cur_beta_offset;
// vertical filtering luma
for (y = y0; y < y_end; y += 8) {
for (x = x0 ? x0 : 8; x < x_end; x += 8) {
const int bs0 = s->vertical_bs[(x >> 3) + (y >> 2) * s->bs_width];
const int bs1 = s->vertical_bs[(x >> 3) + ((y + 4) >> 2) * s->bs_width];
if (bs0 || bs1) {
const int qp0 = (get_qPy(s, x - 1, y) + get_qPy(s, x, y) + 1) >> 1;
const int qp1 = (get_qPy(s, x - 1, y + 4) + get_qPy(s, x, y + 4) + 1) >> 1;
beta[0] = betatable[av_clip(qp0 + (beta_offset >> 1 << 1), 0, MAX_QP)];
beta[1] = betatable[av_clip(qp1 + (beta_offset >> 1 << 1), 0, MAX_QP)];
tc[0] = bs0 ? TC_CALC(qp0, bs0) : 0;
tc[1] = bs1 ? TC_CALC(qp1, bs1) : 0;
src = &s->frame->data[LUMA][y * s->frame->linesize[LUMA] + (x << s->sps->pixel_shift)];
if (pcmf) {
no_p[0] = get_pcm(s, x - 1, y);
no_p[1] = get_pcm(s, x - 1, y + 4);
no_q[0] = get_pcm(s, x, y);
no_q[1] = get_pcm(s, x, y + 4);
s->hevcdsp.hevc_v_loop_filter_luma_c(src,
s->frame->linesize[LUMA],
beta, tc, no_p, no_q);
} else
s->hevcdsp.hevc_v_loop_filter_luma(src,
s->frame->linesize[LUMA],
beta, tc, no_p, no_q);
}
}
}
// vertical filtering chroma
for (chroma = 1; chroma <= 2; chroma++) {
for (y = y0; y < y_end; y += 16) {
for (x = x0 ? x0 : 16; x < x_end; x += 16) {
const int bs0 = s->vertical_bs[(x >> 3) + (y >> 2) * s->bs_width];
const int bs1 = s->vertical_bs[(x >> 3) + ((y + 8) >> 2) * s->bs_width];
if ((bs0 == 2) || (bs1 == 2)) {
const int qp0 = (get_qPy(s, x - 1, y) + get_qPy(s, x, y) + 1) >> 1;
const int qp1 = (get_qPy(s, x - 1, y + 8) + get_qPy(s, x, y + 8) + 1) >> 1;
c_tc[0] = (bs0 == 2) ? chroma_tc(s, qp0, chroma, tc_offset) : 0;
c_tc[1] = (bs1 == 2) ? chroma_tc(s, qp1, chroma, tc_offset) : 0;
src = &s->frame->data[chroma][y / 2 * s->frame->linesize[chroma] + ((x / 2) << s->sps->pixel_shift)];
if (pcmf) {
no_p[0] = get_pcm(s, x - 1, y);
no_p[1] = get_pcm(s, x - 1, y + 8);
no_q[0] = get_pcm(s, x, y);
no_q[1] = get_pcm(s, x, y + 8);
s->hevcdsp.hevc_v_loop_filter_chroma_c(src,
s->frame->linesize[chroma],
c_tc, no_p, no_q);
} else
s->hevcdsp.hevc_v_loop_filter_chroma(src,
s->frame->linesize[chroma],
c_tc, no_p, no_q);
}
}
}
}
// horizontal filtering luma
if (x_end != s->sps->width)
x_end -= 8;
for (y = y0 ? y0 : 8; y < y_end; y += 8) {
for (x = x0 ? x0 - 8 : 0; x < x_end; x += 8) {
const int bs0 = s->horizontal_bs[(x + y * s->bs_width) >> 2];
const int bs1 = s->horizontal_bs[(x + 4 + y * s->bs_width) >> 2];
if (bs0 || bs1) {
const int qp0 = (get_qPy(s, x, y - 1) + get_qPy(s, x, y) + 1) >> 1;
const int qp1 = (get_qPy(s, x + 4, y - 1) + get_qPy(s, x + 4, y) + 1) >> 1;
tc_offset = x >= x0 ? cur_tc_offset : left_tc_offset;
beta_offset = x >= x0 ? cur_beta_offset : left_beta_offset;
beta[0] = betatable[av_clip(qp0 + (beta_offset >> 1 << 1), 0, MAX_QP)];
beta[1] = betatable[av_clip(qp1 + (beta_offset >> 1 << 1), 0, MAX_QP)];
tc[0] = bs0 ? TC_CALC(qp0, bs0) : 0;
tc[1] = bs1 ? TC_CALC(qp1, bs1) : 0;
src = &s->frame->data[LUMA][y * s->frame->linesize[LUMA] + (x << s->sps->pixel_shift)];
if (pcmf) {
no_p[0] = get_pcm(s, x, y - 1);
no_p[1] = get_pcm(s, x + 4, y - 1);
no_q[0] = get_pcm(s, x, y);
no_q[1] = get_pcm(s, x + 4, y);
s->hevcdsp.hevc_h_loop_filter_luma_c(src,
s->frame->linesize[LUMA],
beta, tc, no_p, no_q);
} else
s->hevcdsp.hevc_h_loop_filter_luma(src,
s->frame->linesize[LUMA],
beta, tc, no_p, no_q);
}
}
}
// horizontal filtering chroma
for (chroma = 1; chroma <= 2; chroma++) {
for (y = y0 ? y0 : 16; y < y_end; y += 16) {
for (x = x0 - 8; x < x_end; x += 16) {
int bs0, bs1;
// to make sure no memory access over boundary when x = -8
// TODO: simplify with row based deblocking
if (x < 0) {
bs0 = 0;
bs1 = s->horizontal_bs[(x + 8 + y * s->bs_width) >> 2];
} else if (x >= x_end - 8) {
bs0 = s->horizontal_bs[(x + y * s->bs_width) >> 2];
bs1 = 0;
} else {
bs0 = s->horizontal_bs[(x + y * s->bs_width) >> 2];
bs1 = s->horizontal_bs[(x + 8 + y * s->bs_width) >> 2];
}
if ((bs0 == 2) || (bs1 == 2)) {
const int qp0 = bs0 == 2 ? (get_qPy(s, x, y - 1) + get_qPy(s, x, y) + 1) >> 1 : 0;
const int qp1 = bs1 == 2 ? (get_qPy(s, x + 8, y - 1) + get_qPy(s, x + 8, y) + 1) >> 1 : 0;
tc_offset = x >= x0 ? cur_tc_offset : left_tc_offset;
c_tc[0] = bs0 == 2 ? chroma_tc(s, qp0, chroma, tc_offset) : 0;
c_tc[1] = bs1 == 2 ? chroma_tc(s, qp1, chroma, cur_tc_offset) : 0;
src = &s->frame->data[chroma][y / 2 * s->frame->linesize[chroma] + ((x / 2) << s->sps->pixel_shift)];
if (pcmf) {
no_p[0] = get_pcm(s, x, y - 1);
no_p[1] = get_pcm(s, x + 8, y - 1);
no_q[0] = get_pcm(s, x, y);
no_q[1] = get_pcm(s, x + 8, y);
s->hevcdsp.hevc_h_loop_filter_chroma_c(src,
s->frame->linesize[chroma],
c_tc, no_p, no_q);
} else
s->hevcdsp.hevc_h_loop_filter_chroma(src,
s->frame->linesize[chroma],
c_tc, no_p, no_q);
}
}
}
}
}
static int boundary_strength(HEVCContext *s, MvField *curr,
uint8_t curr_cbf_luma, MvField *neigh,
uint8_t neigh_cbf_luma,
RefPicList *neigh_refPicList,
int tu_border)
{
int mvs = curr->pred_flag[0] + curr->pred_flag[1];
if (tu_border) {
if (curr->is_intra || neigh->is_intra)
return 2;
if (curr_cbf_luma || neigh_cbf_luma)
return 1;
}
if (mvs == neigh->pred_flag[0] + neigh->pred_flag[1]) {
if (mvs == 2) {
// same L0 and L1
if (s->ref->refPicList[0].list[curr->ref_idx[0]] == neigh_refPicList[0].list[neigh->ref_idx[0]] &&
s->ref->refPicList[0].list[curr->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]] &&
neigh_refPicList[0].list[neigh->ref_idx[0]] == neigh_refPicList[1].list[neigh->ref_idx[1]]) {
if ((abs(neigh->mv[0].x - curr->mv[0].x) >= 4 || abs(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
abs(neigh->mv[1].x - curr->mv[1].x) >= 4 || abs(neigh->mv[1].y - curr->mv[1].y) >= 4) &&
(abs(neigh->mv[1].x - curr->mv[0].x) >= 4 || abs(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
abs(neigh->mv[0].x - curr->mv[1].x) >= 4 || abs(neigh->mv[0].y - curr->mv[1].y) >= 4))
return 1;
else
return 0;
} else if (neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[0].list[curr->ref_idx[0]] &&
neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) {
if (abs(neigh->mv[0].x - curr->mv[0].x) >= 4 || abs(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
abs(neigh->mv[1].x - curr->mv[1].x) >= 4 || abs(neigh->mv[1].y - curr->mv[1].y) >= 4)
return 1;
else
return 0;
} else if (neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[0].list[curr->ref_idx[0]] &&
neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) {
if (abs(neigh->mv[1].x - curr->mv[0].x) >= 4 || abs(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
abs(neigh->mv[0].x - curr->mv[1].x) >= 4 || abs(neigh->mv[0].y - curr->mv[1].y) >= 4)
return 1;
else
return 0;
} else {
return 1;
}
} else { // 1 MV
Mv A, B;
int ref_A, ref_B;
if (curr->pred_flag[0]) {
A = curr->mv[0];
ref_A = s->ref->refPicList[0].list[curr->ref_idx[0]];
} else {
A = curr->mv[1];
ref_A = s->ref->refPicList[1].list[curr->ref_idx[1]];
}
if (neigh->pred_flag[0]) {
B = neigh->mv[0];
ref_B = neigh_refPicList[0].list[neigh->ref_idx[0]];
} else {
B = neigh->mv[1];
ref_B = neigh_refPicList[1].list[neigh->ref_idx[1]];
}
if (ref_A == ref_B) {
if (abs(A.x - B.x) >= 4 || abs(A.y - B.y) >= 4)
return 1;
else
return 0;
} else
return 1;
}
}
return 1;
}
void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0,
int log2_trafo_size,
int slice_or_tiles_up_boundary,
int slice_or_tiles_left_boundary)
{
MvField *tab_mvf = s->ref->tab_mvf;
int log2_min_pu_size = s->sps->log2_min_pu_size;
int log2_min_tu_size = s->sps->log2_min_tb_size;
int min_pu_width = s->sps->min_pu_width;
int min_tu_width = s->sps->min_tb_width;
int is_intra = tab_mvf[(y0 >> log2_min_pu_size) * min_pu_width +
(x0 >> log2_min_pu_size)].is_intra;
int i, j, bs;
if (y0 > 0 && (y0 & 7) == 0) {
int yp_pu = (y0 - 1) >> log2_min_pu_size;
int yq_pu = y0 >> log2_min_pu_size;
int yp_tu = (y0 - 1) >> log2_min_tu_size;
int yq_tu = y0 >> log2_min_tu_size;
for (i = 0; i < (1 << log2_trafo_size); i += 4) {
int x_pu = (x0 + i) >> log2_min_pu_size;
int x_tu = (x0 + i) >> log2_min_tu_size;
MvField *top = &tab_mvf[yp_pu * min_pu_width + x_pu];
MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu];
uint8_t top_cbf_luma = s->cbf_luma[yp_tu * min_tu_width + x_tu];
uint8_t curr_cbf_luma = s->cbf_luma[yq_tu * min_tu_width + x_tu];
RefPicList *top_refPicList = ff_hevc_get_ref_list(s, s->ref,
x0 + i, y0 - 1);
bs = boundary_strength(s, curr, curr_cbf_luma,
top, top_cbf_luma, top_refPicList, 1);
if (!s->sh.slice_loop_filter_across_slices_enabled_flag &&
(slice_or_tiles_up_boundary & 1) &&
(y0 % (1 << s->sps->log2_ctb_size)) == 0)
bs = 0;
else if (!s->pps->loop_filter_across_tiles_enabled_flag &&
(slice_or_tiles_up_boundary & 2) &&
(y0 % (1 << s->sps->log2_ctb_size)) == 0)
bs = 0;
if (y0 == 0 || s->sh.disable_deblocking_filter_flag == 1)
bs = 0;
if (bs)
s->horizontal_bs[((x0 + i) + y0 * s->bs_width) >> 2] = bs;
}
}
// bs for TU internal horizontal PU boundaries
if (log2_trafo_size > s->sps->log2_min_pu_size && !is_intra)
for (j = 8; j < (1 << log2_trafo_size); j += 8) {
int yp_pu = (y0 + j - 1) >> log2_min_pu_size;
int yq_pu = (y0 + j) >> log2_min_pu_size;
int yp_tu = (y0 + j - 1) >> log2_min_tu_size;
int yq_tu = (y0 + j) >> log2_min_tu_size;
for (i = 0; i < (1 << log2_trafo_size); i += 4) {
int x_pu = (x0 + i) >> log2_min_pu_size;
int x_tu = (x0 + i) >> log2_min_tu_size;
MvField *top = &tab_mvf[yp_pu * min_pu_width + x_pu];
MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu];
uint8_t top_cbf_luma = s->cbf_luma[yp_tu * min_tu_width + x_tu];
uint8_t curr_cbf_luma = s->cbf_luma[yq_tu * min_tu_width + x_tu];
RefPicList *top_refPicList = ff_hevc_get_ref_list(s, s->ref,
x0 + i,
y0 + j - 1);
bs = boundary_strength(s, curr, curr_cbf_luma,
top, top_cbf_luma, top_refPicList, 0);
if (s->sh.disable_deblocking_filter_flag == 1)
bs = 0;
if (bs)
s->horizontal_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs;
}
}
// bs for vertical TU boundaries
if (x0 > 0 && (x0 & 7) == 0) {
int xp_pu = (x0 - 1) >> log2_min_pu_size;
int xq_pu = x0 >> log2_min_pu_size;
int xp_tu = (x0 - 1) >> log2_min_tu_size;
int xq_tu = x0 >> log2_min_tu_size;
for (i = 0; i < (1 << log2_trafo_size); i += 4) {
int y_pu = (y0 + i) >> log2_min_pu_size;
int y_tu = (y0 + i) >> log2_min_tu_size;
MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];
uint8_t left_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xp_tu];
uint8_t curr_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xq_tu];
RefPicList *left_refPicList = ff_hevc_get_ref_list(s, s->ref,
x0 - 1, y0 + i);
bs = boundary_strength(s, curr, curr_cbf_luma,
left, left_cbf_luma, left_refPicList, 1);
if (!s->sh.slice_loop_filter_across_slices_enabled_flag &&
(slice_or_tiles_left_boundary & 1) &&
(x0 % (1 << s->sps->log2_ctb_size)) == 0)
bs = 0;
else if (!s->pps->loop_filter_across_tiles_enabled_flag &&
(slice_or_tiles_left_boundary & 2) &&
(x0 % (1 << s->sps->log2_ctb_size)) == 0)
bs = 0;
if (x0 == 0 || s->sh.disable_deblocking_filter_flag == 1)
bs = 0;
if (bs)
s->vertical_bs[(x0 >> 3) + ((y0 + i) >> 2) * s->bs_width] = bs;
}
}
// bs for TU internal vertical PU boundaries
if (log2_trafo_size > log2_min_pu_size && !is_intra)
for (j = 0; j < (1 << log2_trafo_size); j += 4) {
int y_pu = (y0 + j) >> log2_min_pu_size;
int y_tu = (y0 + j) >> log2_min_tu_size;
for (i = 8; i < (1 << log2_trafo_size); i += 8) {
int xp_pu = (x0 + i - 1) >> log2_min_pu_size;
int xq_pu = (x0 + i) >> log2_min_pu_size;
int xp_tu = (x0 + i - 1) >> log2_min_tu_size;
int xq_tu = (x0 + i) >> log2_min_tu_size;
MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];
uint8_t left_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xp_tu];
uint8_t curr_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xq_tu];
RefPicList *left_refPicList = ff_hevc_get_ref_list(s, s->ref,
x0 + i - 1,
y0 + j);
bs = boundary_strength(s, curr, curr_cbf_luma,
left, left_cbf_luma, left_refPicList, 0);
if (s->sh.disable_deblocking_filter_flag == 1)
bs = 0;
if (bs)
s->vertical_bs[((x0 + i) >> 3) + ((y0 + j) >> 2) * s->bs_width] = bs;
}
}
}
#undef LUMA
#undef CB
#undef CR
void ff_hevc_hls_filter(HEVCContext *s, int x, int y)
{
deblocking_filter_CTB(s, x, y);
if (s->sps->sao_enabled)
sao_filter_CTB(s, x, y);
}
void ff_hevc_hls_filters(HEVCContext *s, int x_ctb, int y_ctb, int ctb_size)
{
if (y_ctb && x_ctb)
ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb - ctb_size);
if (y_ctb && x_ctb >= s->sps->width - ctb_size) {
ff_hevc_hls_filter(s, x_ctb, y_ctb - ctb_size);
ff_thread_report_progress(&s->ref->tf, y_ctb - ctb_size, 0);
}
if (x_ctb && y_ctb >= s->sps->height - ctb_size)
ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb);
}

@ -0,0 +1,816 @@
/*
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2013 Anand Meher Kotra
*
* This file is part of Libav.
*
* Libav 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 2.1 of the License, or (at your option) any later version.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "hevc.h"
static const uint8_t l0_l1_cand_idx[12][2] = {
{ 0, 1, },
{ 1, 0, },
{ 0, 2, },
{ 2, 0, },
{ 1, 2, },
{ 2, 1, },
{ 0, 3, },
{ 3, 0, },
{ 1, 3, },
{ 3, 1, },
{ 2, 3, },
{ 3, 2, },
};
void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0,
int nPbW, int nPbH)
{
HEVCLocalContext *lc = &s->HEVClc;
int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
lc->na.cand_up = (lc->ctb_up_flag || y0b);
lc->na.cand_left = (lc->ctb_left_flag || x0b);
lc->na.cand_up_left = (!x0b && !y0b) ? lc->ctb_up_left_flag : lc->na.cand_left && lc->na.cand_up;
lc->na.cand_up_right_sap =
((x0b + nPbW) == (1 << s->sps->log2_ctb_size)) ?
lc->ctb_up_right_flag && !y0b : lc->na.cand_up;
lc->na.cand_up_right =
((x0b + nPbW) == (1 << s->sps->log2_ctb_size) ?
lc->ctb_up_right_flag && !y0b : lc->na.cand_up )
&& (x0 + nPbW) < lc->end_of_tiles_x;
lc->na.cand_bottom_left = ((y0 + nPbH) >= lc->end_of_tiles_y) ? 0 : lc->na.cand_left;
}
/*
* 6.4.1 Derivation process for z-scan order block availability
*/
static int z_scan_block_avail(HEVCContext *s, int xCurr, int yCurr,
int xN, int yN)
{
#define MIN_TB_ADDR_ZS(x, y) \
s->pps->min_tb_addr_zs[(y) * s->sps->min_tb_width + (x)]
int Curr = MIN_TB_ADDR_ZS(xCurr >> s->sps->log2_min_tb_size,
yCurr >> s->sps->log2_min_tb_size);
int N;
if (xN < 0 || yN < 0 ||
xN >= s->sps->width ||
yN >= s->sps->height)
return 0;
N = MIN_TB_ADDR_ZS(xN >> s->sps->log2_min_tb_size,
yN >> s->sps->log2_min_tb_size);
return N <= Curr;
}
static int same_prediction_block(HEVCLocalContext *lc, int log2_cb_size,
int x0, int y0, int nPbW, int nPbH,
int xA1, int yA1, int partIdx)
{
return !(nPbW << 1 == 1 << log2_cb_size &&
nPbH << 1 == 1 << log2_cb_size && partIdx == 1 &&
lc->cu.x + nPbW > xA1 &&
lc->cu.y + nPbH <= yA1);
}
/*
* 6.4.2 Derivation process for prediction block availability
*/
static int check_prediction_block_available(HEVCContext *s, int log2_cb_size,
int x0, int y0, int nPbW, int nPbH,
int xA1, int yA1, int partIdx)
{
HEVCLocalContext *lc = &s->HEVClc;
if (lc->cu.x < xA1 && lc->cu.y < yA1 &&
(lc->cu.x + (1 << log2_cb_size)) > xA1 &&
(lc->cu.y + (1 << log2_cb_size)) > yA1)
return same_prediction_block(lc, log2_cb_size, x0, y0,
nPbW, nPbH, xA1, yA1, partIdx);
else
return z_scan_block_avail(s, x0, y0, xA1, yA1);
}
//check if the two luma locations belong to the same mostion estimation region
static int isDiffMER(HEVCContext *s, int xN, int yN, int xP, int yP)
{
uint8_t plevel = s->pps->log2_parallel_merge_level;
return xN >> plevel == xP >> plevel &&
yN >> plevel == yP >> plevel;
}
#define MATCH(x) (A.x == B.x)
// check if the mv's and refidx are the same between A and B
static int compareMVrefidx(struct MvField A, struct MvField B)
{
if (A.pred_flag[0] && A.pred_flag[1] && B.pred_flag[0] && B.pred_flag[1])
return MATCH(ref_idx[0]) && MATCH(mv[0].x) && MATCH(mv[0].y) &&
MATCH(ref_idx[1]) && MATCH(mv[1].x) && MATCH(mv[1].y);
if (A.pred_flag[0] && !A.pred_flag[1] && B.pred_flag[0] && !B.pred_flag[1])
return MATCH(ref_idx[0]) && MATCH(mv[0].x) && MATCH(mv[0].y);
if (!A.pred_flag[0] && A.pred_flag[1] && !B.pred_flag[0] && B.pred_flag[1])
return MATCH(ref_idx[1]) && MATCH(mv[1].x) && MATCH(mv[1].y);
return 0;
}
static av_always_inline void mv_scale(Mv *dst, Mv *src, int td, int tb)
{
int tx, scale_factor;
td = av_clip_int8_c(td);
tb = av_clip_int8_c(tb);
tx = (0x4000 + abs(td / 2)) / td;
scale_factor = av_clip_c((tb * tx + 32) >> 6, -4096, 4095);
dst->x = av_clip_int16_c((scale_factor * src->x + 127 +
(scale_factor * src->x < 0)) >> 8);
dst->y = av_clip_int16_c((scale_factor * src->y + 127 +
(scale_factor * src->y < 0)) >> 8);
}
static int check_mvset(Mv *mvLXCol, Mv *mvCol,
int colPic, int poc,
RefPicList *refPicList, int X, int refIdxLx,
RefPicList *refPicList_col, int listCol, int refidxCol)
{
int cur_lt = refPicList[X].isLongTerm[refIdxLx];
int col_lt = refPicList_col[listCol].isLongTerm[refidxCol];
int col_poc_diff, cur_poc_diff;
if (cur_lt != col_lt) {
mvLXCol->x = 0;
mvLXCol->y = 0;
return 0;
}
col_poc_diff = colPic - refPicList_col[listCol].list[refidxCol];
cur_poc_diff = poc - refPicList[X].list[refIdxLx];
if (!col_poc_diff)
col_poc_diff = 1; // error resilience
if (cur_lt || col_poc_diff == cur_poc_diff) {
mvLXCol->x = mvCol->x;
mvLXCol->y = mvCol->y;
} else {
mv_scale(mvLXCol, mvCol, col_poc_diff, cur_poc_diff);
}
return 1;
}
#define CHECK_MVSET(l) \
check_mvset(mvLXCol, temp_col.mv + l, \
colPic, s->poc, \
refPicList, X, refIdxLx, \
refPicList_col, L ## l, temp_col.ref_idx[l])
// derive the motion vectors section 8.5.3.1.8
static int derive_temporal_colocated_mvs(HEVCContext *s, MvField temp_col,
int refIdxLx, Mv *mvLXCol, int X,
int colPic, RefPicList *refPicList_col)
{
RefPicList *refPicList = s->ref->refPicList;
if (temp_col.is_intra) {
mvLXCol->x = 0;
mvLXCol->y = 0;
return 0;
}
if (temp_col.pred_flag[0] == 0)
return CHECK_MVSET(1);
else if (temp_col.pred_flag[0] == 1 && temp_col.pred_flag[1] == 0)
return CHECK_MVSET(0);
else if (temp_col.pred_flag[0] == 1 && temp_col.pred_flag[1] == 1) {
int check_diffpicount = 0;
int i = 0;
for (i = 0; i < refPicList[0].nb_refs; i++) {
if (refPicList[0].list[i] > s->poc)
check_diffpicount++;
}
for (i = 0; i < refPicList[1].nb_refs; i++) {
if (refPicList[1].list[i] > s->poc)
check_diffpicount++;
}
if (check_diffpicount == 0 && X == 0)
return CHECK_MVSET(0);
else if (check_diffpicount == 0 && X == 1)
return CHECK_MVSET(1);
else {
if (s->sh.collocated_list == L1)
return CHECK_MVSET(0);
else
return CHECK_MVSET(1);
}
}
return 0;
}
#define TAB_MVF(x, y) \
tab_mvf[(y) * min_pu_width + x]
#define TAB_MVF_PU(v) \
TAB_MVF(x ## v ## _pu, y ## v ## _pu)
#define DERIVE_TEMPORAL_COLOCATED_MVS \
derive_temporal_colocated_mvs(s, temp_col, \
refIdxLx, mvLXCol, X, colPic, \
ff_hevc_get_ref_list(s, ref, x, y))
/*
* 8.5.3.1.7 temporal luma motion vector prediction
*/
static int temporal_luma_motion_vector(HEVCContext *s, int x0, int y0,
int nPbW, int nPbH, int refIdxLx,
Mv *mvLXCol, int X)
{
MvField *tab_mvf;
MvField temp_col;
int x, y, x_pu, y_pu;
int min_pu_width = s->sps->min_pu_width;
int availableFlagLXCol = 0;
int colPic;
HEVCFrame *ref = s->ref->collocated_ref;
if (!ref)
return 0;
tab_mvf = ref->tab_mvf;
colPic = ref->poc;
//bottom right collocated motion vector
x = x0 + nPbW;
y = y0 + nPbH;
ff_thread_await_progress(&ref->tf, y, 0);
if (tab_mvf &&
(y0 >> s->sps->log2_ctb_size) == (y >> s->sps->log2_ctb_size) &&
y < s->sps->height &&
x < s->sps->width) {
x = ((x >> 4) << 4);
y = ((y >> 4) << 4);
x_pu = x >> s->sps->log2_min_pu_size;
y_pu = y >> s->sps->log2_min_pu_size;
temp_col = TAB_MVF(x_pu, y_pu);
availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS;
}
// derive center collocated motion vector
if (tab_mvf && !availableFlagLXCol) {
x = x0 + (nPbW >> 1);
y = y0 + (nPbH >> 1);
x = ((x >> 4) << 4);
y = ((y >> 4) << 4);
x_pu = x >> s->sps->log2_min_pu_size;
y_pu = y >> s->sps->log2_min_pu_size;
temp_col = TAB_MVF(x_pu, y_pu);
availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS;
}
return availableFlagLXCol;
}
#define AVAILABLE(cand, v) \
(cand && !TAB_MVF_PU(v).is_intra)
#define PRED_BLOCK_AVAILABLE(v) \
check_prediction_block_available(s, log2_cb_size, \
x0, y0, nPbW, nPbH, \
x ## v, y ## v, part_idx)
#define COMPARE_MV_REFIDX(a, b) \
compareMVrefidx(TAB_MVF_PU(a), TAB_MVF_PU(b))
/*
* 8.5.3.1.2 Derivation process for spatial merging candidates
*/
static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
int nPbW, int nPbH,
int log2_cb_size,
int singleMCLFlag, int part_idx,
struct MvField mergecandlist[])
{
HEVCLocalContext *lc = &s->HEVClc;
RefPicList *refPicList = s->ref->refPicList;
MvField *tab_mvf = s->ref->tab_mvf;
const int min_pu_width = s->sps->min_pu_width;
const int cand_bottom_left = lc->na.cand_bottom_left;
const int cand_left = lc->na.cand_left;
const int cand_up_left = lc->na.cand_up_left;
const int cand_up = lc->na.cand_up;
const int cand_up_right = lc->na.cand_up_right_sap;
const int xA1 = x0 - 1;
const int yA1 = y0 + nPbH - 1;
const int xA1_pu = xA1 >> s->sps->log2_min_pu_size;
const int yA1_pu = yA1 >> s->sps->log2_min_pu_size;
const int xB1 = x0 + nPbW - 1;
const int yB1 = y0 - 1;
const int xB1_pu = xB1 >> s->sps->log2_min_pu_size;
const int yB1_pu = yB1 >> s->sps->log2_min_pu_size;
const int xB0 = x0 + nPbW;
const int yB0 = y0 - 1;
const int xB0_pu = xB0 >> s->sps->log2_min_pu_size;
const int yB0_pu = yB0 >> s->sps->log2_min_pu_size;
const int xA0 = x0 - 1;
const int yA0 = y0 + nPbH;
const int xA0_pu = xA0 >> s->sps->log2_min_pu_size;
const int yA0_pu = yA0 >> s->sps->log2_min_pu_size;
const int xB2 = x0 - 1;
const int yB2 = y0 - 1;
const int xB2_pu = xB2 >> s->sps->log2_min_pu_size;
const int yB2_pu = yB2 >> s->sps->log2_min_pu_size;
const int nb_refs = (s->sh.slice_type == P_SLICE) ?
s->sh.nb_refs[0] : FFMIN(s->sh.nb_refs[0], s->sh.nb_refs[1]);
int check_MER = 1;
int check_MER_1 = 1;
int zero_idx = 0;
int nb_merge_cand = 0;
int nb_orig_merge_cand = 0;
int is_available_a0;
int is_available_a1;
int is_available_b0;
int is_available_b1;
int is_available_b2;
int check_B0;
int check_A0;
//first left spatial merge candidate
is_available_a1 = AVAILABLE(cand_left, A1);
if (!singleMCLFlag && part_idx == 1 &&
(lc->cu.part_mode == PART_Nx2N ||
lc->cu.part_mode == PART_nLx2N ||
lc->cu.part_mode == PART_nRx2N) ||
isDiffMER(s, xA1, yA1, x0, y0)) {
is_available_a1 = 0;
}
if (is_available_a1)
mergecandlist[nb_merge_cand++] = TAB_MVF_PU(A1);
// above spatial merge candidate
is_available_b1 = AVAILABLE(cand_up, B1);
if (!singleMCLFlag && part_idx == 1 &&
(lc->cu.part_mode == PART_2NxN ||
lc->cu.part_mode == PART_2NxnU ||
lc->cu.part_mode == PART_2NxnD) ||
isDiffMER(s, xB1, yB1, x0, y0)) {
is_available_b1 = 0;
}
if (is_available_a1 && is_available_b1)
check_MER = !COMPARE_MV_REFIDX(B1, A1);
if (is_available_b1 && check_MER)
mergecandlist[nb_merge_cand++] = TAB_MVF_PU(B1);
// above right spatial merge candidate
check_MER = 1;
check_B0 = PRED_BLOCK_AVAILABLE(B0);
is_available_b0 = check_B0 && AVAILABLE(cand_up_right, B0);
if (isDiffMER(s, xB0, yB0, x0, y0))
is_available_b0 = 0;
if (is_available_b1 && is_available_b0)
check_MER = !COMPARE_MV_REFIDX(B0, B1);
if (is_available_b0 && check_MER)
mergecandlist[nb_merge_cand++] = TAB_MVF_PU(B0);
// left bottom spatial merge candidate
check_MER = 1;
check_A0 = PRED_BLOCK_AVAILABLE(A0);
is_available_a0 = check_A0 && AVAILABLE(cand_bottom_left, A0);
if (isDiffMER(s, xA0, yA0, x0, y0))
is_available_a0 = 0;
if (is_available_a1 && is_available_a0)
check_MER = !COMPARE_MV_REFIDX(A0, A1);
if (is_available_a0 && check_MER)
mergecandlist[nb_merge_cand++] = TAB_MVF_PU(A0);
// above left spatial merge candidate
check_MER = 1;
is_available_b2 = AVAILABLE(cand_up_left, B2);
if (isDiffMER(s, xB2, yB2, x0, y0))
is_available_b2 = 0;
if (is_available_a1 && is_available_b2)
check_MER = !COMPARE_MV_REFIDX(B2, A1);
if (is_available_b1 && is_available_b2)
check_MER_1 = !COMPARE_MV_REFIDX(B2, B1);
if (is_available_b2 && check_MER && check_MER_1 && nb_merge_cand != 4)
mergecandlist[nb_merge_cand++] = TAB_MVF_PU(B2);
// temporal motion vector candidate
if (s->sh.slice_temporal_mvp_enabled_flag &&
nb_merge_cand < s->sh.max_num_merge_cand) {
Mv mv_l0_col, mv_l1_col;
int available_l0 = temporal_luma_motion_vector(s, x0, y0, nPbW, nPbH,
0, &mv_l0_col, 0);
int available_l1 = (s->sh.slice_type == B_SLICE) ?
temporal_luma_motion_vector(s, x0, y0, nPbW, nPbH,
0, &mv_l1_col, 1) : 0;
if (available_l0 || available_l1) {
mergecandlist[nb_merge_cand].is_intra = 0;
mergecandlist[nb_merge_cand].pred_flag[0] = available_l0;
mergecandlist[nb_merge_cand].pred_flag[1] = available_l1;
if (available_l0) {
mergecandlist[nb_merge_cand].mv[0] = mv_l0_col;
mergecandlist[nb_merge_cand].ref_idx[0] = 0;
}
if (available_l1) {
mergecandlist[nb_merge_cand].mv[1] = mv_l1_col;
mergecandlist[nb_merge_cand].ref_idx[1] = 0;
}
nb_merge_cand++;
}
}
nb_orig_merge_cand = nb_merge_cand;
// combined bi-predictive merge candidates (applies for B slices)
if (s->sh.slice_type == B_SLICE && nb_orig_merge_cand > 1 &&
nb_orig_merge_cand < s->sh.max_num_merge_cand) {
int comb_idx;
for (comb_idx = 0; nb_merge_cand < s->sh.max_num_merge_cand &&
comb_idx < nb_orig_merge_cand * (nb_orig_merge_cand - 1); comb_idx++) {
int l0_cand_idx = l0_l1_cand_idx[comb_idx][0];
int l1_cand_idx = l0_l1_cand_idx[comb_idx][1];
MvField l0_cand = mergecandlist[l0_cand_idx];
MvField l1_cand = mergecandlist[l1_cand_idx];
if (l0_cand.pred_flag[0] && l1_cand.pred_flag[1] &&
(refPicList[0].list[l0_cand.ref_idx[0]] !=
refPicList[1].list[l1_cand.ref_idx[1]] ||
l0_cand.mv[0].x != l1_cand.mv[1].x ||
l0_cand.mv[0].y != l1_cand.mv[1].y)) {
mergecandlist[nb_merge_cand].ref_idx[0] = l0_cand.ref_idx[0];
mergecandlist[nb_merge_cand].ref_idx[1] = l1_cand.ref_idx[1];
mergecandlist[nb_merge_cand].pred_flag[0] = 1;
mergecandlist[nb_merge_cand].pred_flag[1] = 1;
mergecandlist[nb_merge_cand].mv[0].x = l0_cand.mv[0].x;
mergecandlist[nb_merge_cand].mv[0].y = l0_cand.mv[0].y;
mergecandlist[nb_merge_cand].mv[1].x = l1_cand.mv[1].x;
mergecandlist[nb_merge_cand].mv[1].y = l1_cand.mv[1].y;
mergecandlist[nb_merge_cand].is_intra = 0;
nb_merge_cand++;
}
}
}
// append Zero motion vector candidates
while (nb_merge_cand < s->sh.max_num_merge_cand) {
mergecandlist[nb_merge_cand].pred_flag[0] = 1;
mergecandlist[nb_merge_cand].pred_flag[1] = s->sh.slice_type == B_SLICE;
mergecandlist[nb_merge_cand].mv[0].x = 0;
mergecandlist[nb_merge_cand].mv[0].y = 0;
mergecandlist[nb_merge_cand].mv[1].x = 0;
mergecandlist[nb_merge_cand].mv[1].y = 0;
mergecandlist[nb_merge_cand].is_intra = 0;
mergecandlist[nb_merge_cand].ref_idx[0] = zero_idx < nb_refs ? zero_idx : 0;
mergecandlist[nb_merge_cand].ref_idx[1] = zero_idx < nb_refs ? zero_idx : 0;
nb_merge_cand++;
zero_idx++;
}
}
/*
* 8.5.3.1.1 Derivation process of luma Mvs for merge mode
*/
void ff_hevc_luma_mv_merge_mode(HEVCContext *s, int x0, int y0, int nPbW,
int nPbH, int log2_cb_size, int part_idx,
int merge_idx, MvField *mv)
{
int singleMCLFlag = 0;
int nCS = 1 << log2_cb_size;
struct MvField mergecand_list[MRG_MAX_NUM_CANDS] = { { { { 0 } } } };
int nPbW2 = nPbW;
int nPbH2 = nPbH;
HEVCLocalContext *lc = &s->HEVClc;
if (s->pps->log2_parallel_merge_level > 2 && nCS == 8) {
singleMCLFlag = 1;
x0 = lc->cu.x;
y0 = lc->cu.y;
nPbW = nCS;
nPbH = nCS;
part_idx = 0;
}
ff_hevc_set_neighbour_available(s, x0, y0, nPbW, nPbH);
derive_spatial_merge_candidates(s, x0, y0, nPbW, nPbH, log2_cb_size,
singleMCLFlag, part_idx, mergecand_list);
if (mergecand_list[merge_idx].pred_flag[0] == 1 &&
mergecand_list[merge_idx].pred_flag[1] == 1 &&
(nPbW2 + nPbH2) == 12) {
mergecand_list[merge_idx].ref_idx[1] = -1;
mergecand_list[merge_idx].pred_flag[1] = 0;
}
*mv = mergecand_list[merge_idx];
}
static av_always_inline void dist_scale(HEVCContext *s, Mv *mv,
int min_pu_width, int x, int y,
int elist, int ref_idx_curr, int ref_idx)
{
RefPicList *refPicList = s->ref->refPicList;
MvField *tab_mvf = s->ref->tab_mvf;
int ref_pic_elist = refPicList[elist].list[TAB_MVF(x, y).ref_idx[elist]];
int ref_pic_curr = refPicList[ref_idx_curr].list[ref_idx];
if (ref_pic_elist != ref_pic_curr)
mv_scale(mv, mv, s->poc - ref_pic_elist, s->poc - ref_pic_curr);
}
static int mv_mp_mode_mx(HEVCContext *s, int x, int y, int pred_flag_index,
Mv *mv, int ref_idx_curr, int ref_idx)
{
MvField *tab_mvf = s->ref->tab_mvf;
int min_pu_width = s->sps->min_pu_width;
RefPicList *refPicList = s->ref->refPicList;
if (TAB_MVF(x, y).pred_flag[pred_flag_index] == 1 &&
refPicList[pred_flag_index].list[TAB_MVF(x, y).ref_idx[pred_flag_index]] == refPicList[ref_idx_curr].list[ref_idx]) {
*mv = TAB_MVF(x, y).mv[pred_flag_index];
return 1;
}
return 0;
}
static int mv_mp_mode_mx_lt(HEVCContext *s, int x, int y, int pred_flag_index,
Mv *mv, int ref_idx_curr, int ref_idx)
{
MvField *tab_mvf = s->ref->tab_mvf;
int min_pu_width = s->sps->min_pu_width;
RefPicList *refPicList = s->ref->refPicList;
int currIsLongTerm = refPicList[ref_idx_curr].isLongTerm[ref_idx];
int colIsLongTerm =
refPicList[pred_flag_index].isLongTerm[(TAB_MVF(x, y).ref_idx[pred_flag_index])];
if (TAB_MVF(x, y).pred_flag[pred_flag_index] &&
colIsLongTerm == currIsLongTerm) {
*mv = TAB_MVF(x, y).mv[pred_flag_index];
if (!currIsLongTerm)
dist_scale(s, mv, min_pu_width, x, y,
pred_flag_index, ref_idx_curr, ref_idx);
return 1;
}
return 0;
}
#define MP_MX(v, pred, mx) \
mv_mp_mode_mx(s, x ## v ## _pu, y ## v ## _pu, pred, \
&mx, ref_idx_curr, ref_idx)
#define MP_MX_LT(v, pred, mx) \
mv_mp_mode_mx_lt(s, x ## v ## _pu, y ## v ## _pu, pred, \
&mx, ref_idx_curr, ref_idx)
void ff_hevc_luma_mv_mvp_mode(HEVCContext *s, int x0, int y0, int nPbW,
int nPbH, int log2_cb_size, int part_idx,
int merge_idx, MvField *mv,
int mvp_lx_flag, int LX)
{
HEVCLocalContext *lc = &s->HEVClc;
MvField *tab_mvf = s->ref->tab_mvf;
int isScaledFlag_L0 = 0;
int availableFlagLXA0 = 0;
int availableFlagLXB0 = 0;
int numMVPCandLX = 0;
int min_pu_width = s->sps->min_pu_width;
int xA0, yA0;
int xA0_pu, yA0_pu;
int is_available_a0;
int xA1, yA1;
int xA1_pu, yA1_pu;
int is_available_a1;
int xB0, yB0;
int xB0_pu, yB0_pu;
int is_available_b0;
int xB1, yB1;
int xB1_pu = 0, yB1_pu = 0;
int is_available_b1 = 0;
int xB2, yB2;
int xB2_pu = 0, yB2_pu = 0;
int is_available_b2 = 0;
Mv mvpcand_list[2] = { { 0 } };
Mv mxA = { 0 };
Mv mxB = { 0 };
int ref_idx_curr = 0;
int ref_idx = 0;
int pred_flag_index_l0;
int pred_flag_index_l1;
int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
int cand_up = (lc->ctb_up_flag || y0b);
int cand_left = (lc->ctb_left_flag || x0b);
int cand_up_left =
(!x0b && !y0b) ? lc->ctb_up_left_flag : cand_left && cand_up;
int cand_up_right =
(x0b + nPbW == (1 << s->sps->log2_ctb_size) ||
x0 + nPbW >= lc->end_of_tiles_x) ? lc->ctb_up_right_flag && !y0b
: cand_up;
int cand_bottom_left = (y0 + nPbH >= lc->end_of_tiles_y) ? 0 : cand_left;
ref_idx_curr = LX;
ref_idx = mv->ref_idx[LX];
pred_flag_index_l0 = LX;
pred_flag_index_l1 = !LX;
// left bottom spatial candidate
xA0 = x0 - 1;
yA0 = y0 + nPbH;
xA0_pu = xA0 >> s->sps->log2_min_pu_size;
yA0_pu = yA0 >> s->sps->log2_min_pu_size;
is_available_a0 = PRED_BLOCK_AVAILABLE(A0) && AVAILABLE(cand_bottom_left, A0);
//left spatial merge candidate
xA1 = x0 - 1;
yA1 = y0 + nPbH - 1;
xA1_pu = xA1 >> s->sps->log2_min_pu_size;
yA1_pu = yA1 >> s->sps->log2_min_pu_size;
is_available_a1 = AVAILABLE(cand_left, A1);
if (is_available_a0 || is_available_a1)
isScaledFlag_L0 = 1;
if (is_available_a0) {
availableFlagLXA0 = MP_MX(A0, pred_flag_index_l0, mxA);
if (!availableFlagLXA0)
availableFlagLXA0 = MP_MX(A0, pred_flag_index_l1, mxA);
}
if (is_available_a1 && !availableFlagLXA0) {
availableFlagLXA0 = MP_MX(A1, pred_flag_index_l0, mxA);
if (!availableFlagLXA0)
availableFlagLXA0 = MP_MX(A1, pred_flag_index_l1, mxA);
}
if (is_available_a0 && !availableFlagLXA0) {
availableFlagLXA0 = MP_MX_LT(A0, pred_flag_index_l0, mxA);
if (!availableFlagLXA0)
availableFlagLXA0 = MP_MX_LT(A0, pred_flag_index_l1, mxA);
}
if (is_available_a1 && !availableFlagLXA0) {
availableFlagLXA0 = MP_MX_LT(A1, pred_flag_index_l0, mxA);
if (!availableFlagLXA0)
availableFlagLXA0 = MP_MX_LT(A1, pred_flag_index_l1, mxA);
}
// B candidates
// above right spatial merge candidate
xB0 = x0 + nPbW;
yB0 = y0 - 1;
xB0_pu = xB0 >> s->sps->log2_min_pu_size;
yB0_pu = yB0 >> s->sps->log2_min_pu_size;
is_available_b0 = PRED_BLOCK_AVAILABLE(B0) && AVAILABLE(cand_up_right, B0);
if (is_available_b0) {
availableFlagLXB0 = MP_MX(B0, pred_flag_index_l0, mxB);
if (!availableFlagLXB0)
availableFlagLXB0 = MP_MX(B0, pred_flag_index_l1, mxB);
}
if (!availableFlagLXB0) {
// above spatial merge candidate
xB1 = x0 + nPbW - 1;
yB1 = y0 - 1;
xB1_pu = xB1 >> s->sps->log2_min_pu_size;
yB1_pu = yB1 >> s->sps->log2_min_pu_size;
is_available_b1 = AVAILABLE(cand_up, B1);
if (is_available_b1) {
availableFlagLXB0 = MP_MX(B1, pred_flag_index_l0, mxB);
if (!availableFlagLXB0)
availableFlagLXB0 = MP_MX(B1, pred_flag_index_l1, mxB);
}
}
if (!availableFlagLXB0) {
// above left spatial merge candidate
xB2 = x0 - 1;
yB2 = y0 - 1;
xB2_pu = xB2 >> s->sps->log2_min_pu_size;
yB2_pu = yB2 >> s->sps->log2_min_pu_size;
is_available_b2 = AVAILABLE(cand_up_left, B2);
if (is_available_b2) {
availableFlagLXB0 = MP_MX(B2, pred_flag_index_l0, mxB);
if (!availableFlagLXB0)
availableFlagLXB0 = MP_MX(B2, pred_flag_index_l1, mxB);
}
}
if (isScaledFlag_L0 == 0) {
if (availableFlagLXB0) {
availableFlagLXA0 = 1;
mxA = mxB;
}
availableFlagLXB0 = 0;
// XB0 and L1
if (is_available_b0) {
availableFlagLXB0 = MP_MX_LT(B0, pred_flag_index_l0, mxB);
if (!availableFlagLXB0)
availableFlagLXB0 = MP_MX_LT(B0, pred_flag_index_l1, mxB);
}
if (is_available_b1 && !availableFlagLXB0) {
availableFlagLXB0 = MP_MX_LT(B1, pred_flag_index_l0, mxB);
if (!availableFlagLXB0)
availableFlagLXB0 = MP_MX_LT(B1, pred_flag_index_l1, mxB);
}
if (is_available_b2 && !availableFlagLXB0) {
availableFlagLXB0 = MP_MX_LT(B2, pred_flag_index_l0, mxB);
if (!availableFlagLXB0)
availableFlagLXB0 = MP_MX_LT(B2, pred_flag_index_l1, mxB);
}
}
if (availableFlagLXA0)
mvpcand_list[numMVPCandLX++] = mxA;
if (availableFlagLXB0 && (!availableFlagLXA0 || mxA.x != mxB.x || mxA.y != mxB.y))
mvpcand_list[numMVPCandLX++] = mxB;
//temporal motion vector prediction candidate
if (numMVPCandLX < 2 && s->sh.slice_temporal_mvp_enabled_flag) {
Mv mv_col;
int available_col = temporal_luma_motion_vector(s, x0, y0, nPbW,
nPbH, ref_idx,
&mv_col, LX);
if (available_col)
mvpcand_list[numMVPCandLX++] = mv_col;
}
// insert zero motion vectors when the number of available candidates are less than 2
while (numMVPCandLX < 2)
mvpcand_list[numMVPCandLX++] = (Mv){ 0, 0 };
mv->mv[LX].x = mvpcand_list[mvp_lx_flag].x;
mv->mv[LX].y = mvpcand_list[mvp_lx_flag].y;
}

@ -0,0 +1,125 @@
/*
* HEVC Annex B format parser
*
* Copyright (C) 2012 - 2013 Guillaume Martres
*
* This file is part of Libav.
*
* Libav 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 2.1 of the License, or (at your option) any later version.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/common.h"
#include "parser.h"
#include "hevc.h"
#define START_CODE 0x000001 ///< start_code_prefix_one_3bytes
/**
* Find the end of the current frame in the bitstream.
* @return the position of the first byte of the next frame, or END_NOT_FOUND
*/
static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf,
int buf_size)
{
int i;
ParseContext *pc = s->priv_data;
for (i = 0; i < buf_size; i++) {
int nut;
pc->state64 = (pc->state64 << 8) | buf[i];
if (((pc->state64 >> 3 * 8) & 0xFFFFFF) != START_CODE)
continue;
nut = (pc->state64 >> 2 * 8 + 1) & 0x3F;
// Beginning of access unit
if ((nut >= NAL_VPS && nut <= NAL_AUD) || nut == NAL_SEI_PREFIX ||
(nut >= 41 && nut <= 44) || (nut >= 48 && nut <= 55)) {
if (pc->frame_start_found) {
pc->frame_start_found = 0;
return i - 5;
}
} else if (nut <= NAL_RASL_R ||
(nut >= NAL_BLA_W_LP && nut <= NAL_CRA_NUT)) {
int first_slice_segment_in_pic_flag = buf[i] >> 7;
if (first_slice_segment_in_pic_flag) {
if (!pc->frame_start_found) {
pc->frame_start_found = 1;
s->key_frame = nut >= NAL_BLA_W_LP && nut <= NAL_CRA_NUT;
} else { // First slice of next frame found
pc->frame_start_found = 0;
return i - 5;
}
}
}
}
return END_NOT_FOUND;
}
static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx,
const uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size)
{
int next;
ParseContext *pc = s->priv_data;
if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
next = buf_size;
} else {
next = hevc_find_frame_end(s, buf, buf_size);
if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
*poutbuf = NULL;
*poutbuf_size = 0;
return buf_size;
}
}
*poutbuf = buf;
*poutbuf_size = buf_size;
return next;
}
// Split after the parameter sets at the beginning of the stream if they exist.
static int hevc_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
{
int i;
uint32_t state = -1;
int has_ps = 0;
for (i = 0; i < buf_size; i++) {
state = (state << 8) | buf[i];
if (((state >> 8) & 0xFFFFFF) == START_CODE) {
int nut = (state >> 1) & 0x3F;
if (nut >= NAL_VPS && nut <= NAL_PPS)
has_ps = 1;
else if (has_ps)
return i - 3;
else // no parameter set at the beginning of the stream
return 0;
}
}
return 0;
}
AVCodecParser ff_hevc_parser = {
.codec_ids = { AV_CODEC_ID_HEVC },
.priv_data_size = sizeof(ParseContext),
.parser_parse = hevc_parse,
.parser_close = ff_parse_close,
.split = hevc_split,
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,489 @@
/*
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2012 - 2013 Gildas Cocherel
*
* This file is part of Libav.
*
* Libav 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 2.1 of the License, or (at your option) any later version.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/pixdesc.h"
#include "internal.h"
#include "thread.h"
#include "hevc.h"
void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags)
{
/* frame->frame can be NULL if context init failed */
if (!frame->frame || !frame->frame->buf[0])
return;
frame->flags &= ~flags;
if (!frame->flags) {
ff_thread_release_buffer(s->avctx, &frame->tf);
av_buffer_unref(&frame->tab_mvf_buf);
frame->tab_mvf = NULL;
av_buffer_unref(&frame->rpl_buf);
av_buffer_unref(&frame->rpl_tab_buf);
frame->rpl_tab = NULL;
frame->refPicList = NULL;
frame->collocated_ref = NULL;
}
}
RefPicList *ff_hevc_get_ref_list(HEVCContext *s, HEVCFrame *ref, int x0, int y0)
{
if (x0 < 0 || y0 < 0) {
return s->ref->refPicList;
} else {
int x_cb = x0 >> s->sps->log2_ctb_size;
int y_cb = y0 >> s->sps->log2_ctb_size;
int pic_width_cb = (s->sps->width + (1 << s->sps->log2_ctb_size) - 1) >>
s->sps->log2_ctb_size;
int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[y_cb * pic_width_cb + x_cb];
return (RefPicList *)ref->rpl_tab[ctb_addr_ts];
}
}
void ff_hevc_clear_refs(HEVCContext *s)
{
int i;
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++)
ff_hevc_unref_frame(s, &s->DPB[i],
HEVC_FRAME_FLAG_SHORT_REF |
HEVC_FRAME_FLAG_LONG_REF);
}
void ff_hevc_flush_dpb(HEVCContext *s)
{
int i;
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++)
ff_hevc_unref_frame(s, &s->DPB[i], ~0);
}
static HEVCFrame *alloc_frame(HEVCContext *s)
{
int i, j, ret;
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *frame = &s->DPB[i];
if (frame->frame->buf[0])
continue;
ret = ff_thread_get_buffer(s->avctx, &frame->tf,
AV_GET_BUFFER_FLAG_REF);
if (ret < 0)
return NULL;
frame->rpl_buf = av_buffer_allocz(s->nb_nals * sizeof(RefPicListTab));
if (!frame->rpl_buf)
goto fail;
frame->tab_mvf_buf = av_buffer_pool_get(s->tab_mvf_pool);
if (!frame->tab_mvf_buf)
goto fail;
frame->tab_mvf = (MvField *)frame->tab_mvf_buf->data;
frame->rpl_tab_buf = av_buffer_pool_get(s->rpl_tab_pool);
if (!frame->rpl_tab_buf)
goto fail;
frame->rpl_tab = (RefPicListTab **)frame->rpl_tab_buf->data;
frame->ctb_count = s->sps->ctb_width * s->sps->ctb_height;
for (j = 0; j < frame->ctb_count; j++)
frame->rpl_tab[j] = (RefPicListTab *)frame->rpl_buf->data;
return frame;
fail:
ff_hevc_unref_frame(s, frame, ~0);
return NULL;
}
av_log(s->avctx, AV_LOG_ERROR, "Error allocating frame, DPB full.\n");
return NULL;
}
int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc)
{
HEVCFrame *ref;
int i;
/* check that this POC doesn't already exist */
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *frame = &s->DPB[i];
if (frame->frame->buf[0] && frame->sequence == s->seq_decode &&
frame->poc == poc) {
av_log(s->avctx, AV_LOG_ERROR, "Duplicate POC in a sequence: %d.\n",
poc);
return AVERROR_INVALIDDATA;
}
}
ref = alloc_frame(s);
if (!ref)
return AVERROR(ENOMEM);
*frame = ref->frame;
s->ref = ref;
ref->poc = poc;
ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF;
ref->sequence = s->seq_decode;
ref->window = s->sps->output_window;
return 0;
}
int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
{
do {
int nb_output = 0;
int min_poc = INT_MAX;
int i, min_idx, ret;
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *frame = &s->DPB[i];
if ((frame->flags & HEVC_FRAME_FLAG_OUTPUT) &&
frame->sequence == s->seq_output) {
nb_output++;
if (frame->poc < min_poc) {
min_poc = frame->poc;
min_idx = i;
}
}
}
/* wait for more frames before output */
if (!flush && s->seq_output == s->seq_decode && s->sps &&
nb_output <= s->sps->temporal_layer[s->sps->max_sub_layers - 1].num_reorder_pics)
return 0;
if (nb_output) {
HEVCFrame *frame = &s->DPB[min_idx];
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->frame->format);
int pixel_shift;
if (!desc)
return AVERROR_BUG;
pixel_shift = desc->comp[0].depth_minus1 > 7;
ret = av_frame_ref(out, frame->frame);
ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT);
if (ret < 0)
return ret;
for (i = 0; i < 3; i++) {
int hshift = (i > 0) ? desc->log2_chroma_w : 0;
int vshift = (i > 0) ? desc->log2_chroma_h : 0;
int off = ((frame->window.left_offset >> hshift) << pixel_shift) +
(frame->window.top_offset >> vshift) * out->linesize[i];
out->data[i] += off;
}
av_log(s->avctx, AV_LOG_DEBUG,
"Output frame with POC %d.\n", frame->poc);
return 1;
}
if (s->seq_output != s->seq_decode)
s->seq_output = (s->seq_output + 1) & 0xff;
else
break;
} while (1);
return 0;
}
static int init_slice_rpl(HEVCContext *s)
{
HEVCFrame *frame = s->ref;
int ctb_count = frame->ctb_count;
int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[s->sh.slice_segment_addr];
int i;
if (s->slice_idx >= frame->rpl_buf->size / sizeof(RefPicListTab))
return AVERROR_INVALIDDATA;
for (i = ctb_addr_ts; i < ctb_count; i++)
frame->rpl_tab[i] = (RefPicListTab *)frame->rpl_buf->data + s->slice_idx;
frame->refPicList = (RefPicList *)frame->rpl_tab[ctb_addr_ts];
return 0;
}
int ff_hevc_slice_rpl(HEVCContext *s)
{
SliceHeader *sh = &s->sh;
uint8_t nb_list = sh->slice_type == B_SLICE ? 2 : 1;
uint8_t list_idx;
int i, j, ret;
ret = init_slice_rpl(s);
if (ret < 0)
return ret;
if (!(s->rps[ST_CURR_BEF].nb_refs + s->rps[ST_CURR_AFT].nb_refs +
s->rps[LT_CURR].nb_refs)) {
av_log(s->avctx, AV_LOG_ERROR, "Zero refs in the frame RPS.\n");
return AVERROR_INVALIDDATA;
}
for (list_idx = 0; list_idx < nb_list; list_idx++) {
RefPicList rpl_tmp = { { 0 } };
RefPicList *rpl = &s->ref->refPicList[list_idx];
/* The order of the elements is
* ST_CURR_BEF - ST_CURR_AFT - LT_CURR for the L0 and
* ST_CURR_AFT - ST_CURR_BEF - LT_CURR for the L1 */
int cand_lists[3] = { list_idx ? ST_CURR_AFT : ST_CURR_BEF,
list_idx ? ST_CURR_BEF : ST_CURR_AFT,
LT_CURR };
/* concatenate the candidate lists for the current frame */
while (rpl_tmp.nb_refs < sh->nb_refs[list_idx]) {
for (i = 0; i < FF_ARRAY_ELEMS(cand_lists); i++) {
RefPicList *rps = &s->rps[cand_lists[i]];
for (j = 0; j < rps->nb_refs && rpl_tmp.nb_refs < MAX_REFS; j++) {
rpl_tmp.list[rpl_tmp.nb_refs] = rps->list[j];
rpl_tmp.ref[rpl_tmp.nb_refs] = rps->ref[j];
rpl_tmp.isLongTerm[rpl_tmp.nb_refs] = i == 2;
rpl_tmp.nb_refs++;
}
}
}
/* reorder the references if necessary */
if (sh->rpl_modification_flag[list_idx]) {
for (i = 0; i < sh->nb_refs[list_idx]; i++) {
int idx = sh->list_entry_lx[list_idx][i];
if (idx >= rpl_tmp.nb_refs) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid reference index.\n");
return AVERROR_INVALIDDATA;
}
rpl->list[i] = rpl_tmp.list[idx];
rpl->ref[i] = rpl_tmp.ref[idx];
rpl->isLongTerm[i] = rpl_tmp.isLongTerm[idx];
rpl->nb_refs++;
}
} else {
memcpy(rpl, &rpl_tmp, sizeof(*rpl));
rpl->nb_refs = FFMIN(rpl->nb_refs, sh->nb_refs[list_idx]);
}
if (sh->collocated_list == list_idx &&
sh->collocated_ref_idx < rpl->nb_refs)
s->ref->collocated_ref = rpl->ref[sh->collocated_ref_idx];
}
return 0;
}
static HEVCFrame *find_ref_idx(HEVCContext *s, int poc)
{
int i;
int LtMask = (1 << s->sps->log2_max_poc_lsb) - 1;
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *ref = &s->DPB[i];
if (ref->frame->buf[0] && (ref->sequence == s->seq_decode)) {
if ((ref->poc & LtMask) == poc)
return ref;
}
}
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *ref = &s->DPB[i];
if (ref->frame->buf[0] && ref->sequence == s->seq_decode) {
if (ref->poc == poc || (ref->poc & LtMask) == poc)
return ref;
}
}
av_log(s->avctx, AV_LOG_ERROR,
"Could not find ref with POC %d\n", poc);
return NULL;
}
static void mark_ref(HEVCFrame *frame, int flag)
{
frame->flags &= ~(HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF);
frame->flags |= flag;
}
static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc)
{
HEVCFrame *frame;
int i, x, y;
frame = alloc_frame(s);
if (!frame)
return NULL;
if (!s->sps->pixel_shift) {
for (i = 0; frame->frame->buf[i]; i++)
memset(frame->frame->buf[i]->data, 1 << (s->sps->bit_depth - 1),
frame->frame->buf[i]->size);
} else {
for (i = 0; frame->frame->data[i]; i++)
for (y = 0; y < (s->sps->height >> s->sps->vshift[i]); y++)
for (x = 0; x < (s->sps->width >> s->sps->hshift[i]); x++) {
AV_WN16(frame->frame->data[i] + y * frame->frame->linesize[i] + 2 * x,
1 << (s->sps->bit_depth - 1));
}
}
frame->poc = poc;
frame->sequence = s->seq_decode;
frame->flags = 0;
ff_thread_report_progress(&frame->tf, INT_MAX, 0);
return frame;
}
/* add a reference with the given poc to the list and mark it as used in DPB */
static int add_candidate_ref(HEVCContext *s, RefPicList *list,
int poc, int ref_flag)
{
HEVCFrame *ref = find_ref_idx(s, poc);
if (ref == s->ref)
return AVERROR_INVALIDDATA;
if (!ref) {
ref = generate_missing_ref(s, poc);
if (!ref)
return AVERROR(ENOMEM);
}
list->list[list->nb_refs] = ref->poc;
list->ref[list->nb_refs] = ref;
list->nb_refs++;
mark_ref(ref, ref_flag);
return 0;
}
int ff_hevc_frame_rps(HEVCContext *s)
{
const ShortTermRPS *short_rps = s->sh.short_term_rps;
const LongTermRPS *long_rps = &s->sh.long_term_rps;
RefPicList *rps = s->rps;
int i, ret;
if (!short_rps) {
rps[0].nb_refs = rps[1].nb_refs = 0;
return 0;
}
/* clear the reference flags on all frames except the current one */
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *frame = &s->DPB[i];
if (frame == s->ref)
continue;
mark_ref(frame, 0);
}
for (i = 0; i < NB_RPS_TYPE; i++)
rps[i].nb_refs = 0;
/* add the short refs */
for (i = 0; i < short_rps->num_delta_pocs; i++) {
int poc = s->poc + short_rps->delta_poc[i];
int list;
if (!short_rps->used[i])
list = ST_FOLL;
else if (i < short_rps->num_negative_pics)
list = ST_CURR_BEF;
else
list = ST_CURR_AFT;
ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_SHORT_REF);
if (ret < 0)
return ret;
}
/* add the long refs */
for (i = 0; i < long_rps->nb_refs; i++) {
int poc = long_rps->poc[i];
int list = long_rps->used[i] ? LT_CURR : LT_FOLL;
ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_LONG_REF);
if (ret < 0)
return ret;
}
/* release any frames that are now unused */
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++)
ff_hevc_unref_frame(s, &s->DPB[i], 0);
return 0;
}
int ff_hevc_compute_poc(HEVCContext *s, int poc_lsb)
{
int max_poc_lsb = 1 << s->sps->log2_max_poc_lsb;
int prev_poc_lsb = s->pocTid0 % max_poc_lsb;
int prev_poc_msb = s->pocTid0 - prev_poc_lsb;
int poc_msb;
if (poc_lsb < prev_poc_lsb && prev_poc_lsb - poc_lsb >= max_poc_lsb / 2)
poc_msb = prev_poc_msb + max_poc_lsb;
else if (poc_lsb > prev_poc_lsb && poc_lsb - prev_poc_lsb > max_poc_lsb / 2)
poc_msb = prev_poc_msb - max_poc_lsb;
else
poc_msb = prev_poc_msb;
// For BLA picture types, POCmsb is set to 0.
if (s->nal_unit_type == NAL_BLA_W_LP ||
s->nal_unit_type == NAL_BLA_W_RADL ||
s->nal_unit_type == NAL_BLA_N_LP)
poc_msb = 0;
return poc_msb + poc_lsb;
}
int ff_hevc_frame_nb_refs(HEVCContext *s)
{
int ret = 0;
int i;
const ShortTermRPS *rps = s->sh.short_term_rps;
LongTermRPS *long_rps = &s->sh.long_term_rps;
if (rps) {
for (i = 0; i < rps->num_negative_pics; i++)
ret += !!rps->used[i];
for (; i < rps->num_delta_pocs; i++)
ret += !!rps->used[i];
}
if (long_rps) {
for (i = 0; i < long_rps->nb_refs; i++)
ret += !!long_rps->used[i];
}
return ret;
}

@ -0,0 +1,124 @@
/*
* HEVC Supplementary Enhancement Information messages
*
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2012 - 2013 Gildas Cocherel
* Copyright (C) 2013 Vittorio Giovara
*
* This file is part of Libav.
*
* Libav 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 2.1 of the License, or (at your option) any later version.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "golomb.h"
#include "hevc.h"
static void decode_nal_sei_decoded_picture_hash(HEVCContext *s,
int payload_size)
{
int cIdx, i;
GetBitContext *gb = &s->HEVClc.gb;
uint8_t hash_type = get_bits(gb, 8);
for (cIdx = 0; cIdx < 3; cIdx++) {
if (hash_type == 0) {
s->is_md5 = 1;
for (i = 0; i < 16; i++)
s->md5[cIdx][i] = get_bits(gb, 8);
} else if (hash_type == 1) {
// picture_crc = get_bits(gb, 16);
skip_bits(gb, 16);
} else if (hash_type == 2) {
// picture_checksum = get_bits(gb, 32);
skip_bits(gb, 32);
}
}
}
static void decode_nal_sei_frame_packing_arrangement(HEVCLocalContext *lc)
{
GetBitContext *gb = &lc->gb;
int cancel, type, quincunx;
get_ue_golomb(gb); // frame_packing_arrangement_id
cancel = get_bits1(gb); // frame_packing_cancel_flag
if (cancel == 0) {
type = get_bits(gb, 7); // frame_packing_arrangement_type
quincunx = get_bits1(gb); // quincunx_sampling_flag
skip_bits(gb, 6); // content_interpretation_type
// the following skips spatial_flipping_flag frame0_flipped_flag
// field_views_flag current_frame_is_frame0_flag
// frame0_self_contained_flag frame1_self_contained_flag
skip_bits(gb, 6);
if (quincunx == 0 && type != 5)
skip_bits(gb, 16); // frame[01]_grid_position_[xy]
skip_bits(gb, 8); // frame_packing_arrangement_reserved_byte
skip_bits1(gb); // frame_packing_arrangement_persistance_flag
}
skip_bits1(gb); // upsampled_aspect_ratio_flag
}
static int decode_nal_sei_message(HEVCContext *s)
{
GetBitContext *gb = &s->HEVClc.gb;
int payload_type = 0;
int payload_size = 0;
int byte = 0xFF;
av_log(s->avctx, AV_LOG_DEBUG, "Decoding SEI\n");
while (byte == 0xFF) {
byte = get_bits(gb, 8);
payload_type += byte;
}
byte = 0xFF;
while (byte == 0xFF) {
byte = get_bits(gb, 8);
payload_size += byte;
}
if (s->nal_unit_type == NAL_SEI_PREFIX) {
if (payload_type == 256)
decode_nal_sei_decoded_picture_hash(s, payload_size);
else if (payload_type == 45)
decode_nal_sei_frame_packing_arrangement(&s->HEVClc);
else {
av_log(s->avctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", payload_type);
skip_bits(gb, 8 * payload_size);
}
} else { /* nal_unit_type == NAL_SEI_SUFFIX */
if (payload_type == 132)
decode_nal_sei_decoded_picture_hash(s, payload_size);
else {
av_log(s->avctx, AV_LOG_DEBUG, "Skipped SUFFIX SEI %d\n", payload_type);
skip_bits(gb, 8 * payload_size);
}
}
return 0;
}
static int more_rbsp_data(GetBitContext *gb)
{
return get_bits_left(gb) > 0 && show_bits(gb, 8) != 0x80;
}
int ff_hevc_decode_nal_sei(HEVCContext *s)
{
do {
decode_nal_sei_message(s);
} while (more_rbsp_data(&s->HEVClc.gb));
return 0;
}

@ -0,0 +1,190 @@
/*
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
*
* This file is part of Libav.
*
* Libav 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 2.1 of the License, or (at your option) any later version.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "hevc.h"
static const int8_t transform[32][32] = {
{ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 },
{ 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4,
-4, -13, -22, -31, -38, -46, -54, -61, -67, -73, -78, -82, -85, -88, -90, -90 },
{ 90, 87, 80, 70, 57, 43, 25, 9, -9, -25, -43, -57, -70, -80, -87, -90,
-90, -87, -80, -70, -57, -43, -25, -9, 9, 25, 43, 57, 70, 80, 87, 90 },
{ 90, 82, 67, 46, 22, -4, -31, -54, -73, -85, -90, -88, -78, -61, -38, -13,
13, 38, 61, 78, 88, 90, 85, 73, 54, 31, 4, -22, -46, -67, -82, -90 },
{ 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89,
89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89 },
{ 88, 67, 31, -13, -54, -82, -90, -78, -46, -4, 38, 73, 90, 85, 61, 22,
-22, -61, -85, -90, -73, -38, 4, 46, 78, 90, 82, 54, 13, -31, -67, -88 },
{ 87, 57, 9, -43, -80, -90, -70, -25, 25, 70, 90, 80, 43, -9, -57, -87,
-87, -57, -9, 43, 80, 90, 70, 25, -25, -70, -90, -80, -43, 9, 57, 87 },
{ 85, 46, -13, -67, -90, -73, -22, 38, 82, 88, 54, -4, -61, -90, -78, -31,
31, 78, 90, 61, 4, -54, -88, -82, -38, 22, 73, 90, 67, 13, -46, -85 },
{ 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83,
83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83 },
{ 82, 22, -54, -90, -61, 13, 78, 85, 31, -46, -90, -67, 4, 73, 88, 38,
-38, -88, -73, -4, 67, 90, 46, -31, -85, -78, -13, 61, 90, 54, -22, -82 },
{ 80, 9, -70, -87, -25, 57, 90, 43, -43, -90, -57, 25, 87, 70, -9, -80,
-80, -9, 70, 87, 25, -57, -90, -43, 43, 90, 57, -25, -87, -70, 9, 80 },
{ 78, -4, -82, -73, 13, 85, 67, -22, -88, -61, 31, 90, 54, -38, -90, -46,
46, 90, 38, -54, -90, -31, 61, 88, 22, -67, -85, -13, 73, 82, 4, -78 },
{ 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75,
75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75 },
{ 73, -31, -90, -22, 78, 67, -38, -90, -13, 82, 61, -46, -88, -4, 85, 54,
-54, -85, 4, 88, 46, -61, -82, 13, 90, 38, -67, -78, 22, 90, 31, -73 },
{ 70, -43, -87, 9, 90, 25, -80, -57, 57, 80, -25, -90, -9, 87, 43, -70,
-70, 43, 87, -9, -90, -25, 80, 57, -57, -80, 25, 90, 9, -87, -43, 70 },
{ 67, -54, -78, 38, 85, -22, -90, 4, 90, 13, -88, -31, 82, 46, -73, -61,
61, 73, -46, -82, 31, 88, -13, -90, -4, 90, 22, -85, -38, 78, 54, -67 },
{ 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64,
64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64 },
{ 61, -73, -46, 82, 31, -88, -13, 90, -4, -90, 22, 85, -38, -78, 54, 67,
-67, -54, 78, 38, -85, -22, 90, 4, -90, 13, 88, -31, -82, 46, 73, -61 },
{ 57, -80, -25, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 25, 80, -57,
-57, 80, 25, -90, 9, 87, -43, -70, 70, 43, -87, -9, 90, -25, -80, 57 },
{ 54, -85, -4, 88, -46, -61, 82, 13, -90, 38, 67, -78, -22, 90, -31, -73,
73, 31, -90, 22, 78, -67, -38, 90, -13, -82, 61, 46, -88, 4, 85, -54 },
{ 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50,
50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50 },
{ 46, -90, 38, 54, -90, 31, 61, -88, 22, 67, -85, 13, 73, -82, 4, 78,
-78, -4, 82, -73, -13, 85, -67, -22, 88, -61, -31, 90, -54, -38, 90, -46 },
{ 43, -90, 57, 25, -87, 70, 9, -80, 80, -9, -70, 87, -25, -57, 90, -43,
-43, 90, -57, -25, 87, -70, -9, 80, -80, 9, 70, -87, 25, 57, -90, 43 },
{ 38, -88, 73, -4, -67, 90, -46, -31, 85, -78, 13, 61, -90, 54, 22, -82,
82, -22, -54, 90, -61, -13, 78, -85, 31, 46, -90, 67, 4, -73, 88, -38 },
{ 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36,
36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36 },
{ 31, -78, 90, -61, 4, 54, -88, 82, -38, -22, 73, -90, 67, -13, -46, 85,
-85, 46, 13, -67, 90, -73, 22, 38, -82, 88, -54, -4, 61, -90, 78, -31 },
{ 25, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -25,
-25, 70, -90, 80, -43, -9, 57, -87, 87, -57, 9, 43, -80, 90, -70, 25 },
{ 22, -61, 85, -90, 73, -38, -4, 46, -78, 90, -82, 54, -13, -31, 67, -88,
88, -67, 31, 13, -54, 82, -90, 78, -46, 4, 38, -73, 90, -85, 61, -22 },
{ 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18,
18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18 },
{ 13, -38, 61, -78, 88, -90, 85, -73, 54, -31, 4, 22, -46, 67, -82, 90,
-90, 82, -67, 46, -22, -4, 31, -54, 73, -85, 90, -88, 78, -61, 38, -13 },
{ 9, -25, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 25, -9,
-9, 25, -43, 57, -70, 80, -87, 90, -90, 87, -80, 70, -57, 43, -25, 9 },
{ 4, -13, 22, -31, 38, -46, 54, -61, 67, -73, 78, -82, 85, -88, 90, -90,
90, -90, 88, -85, 82, -78, 73, -67, 61, -54, 46, -38, 31, -22, 13, -4 },
};
DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters[7][16]) = {
{ -2, 58, 10, -2, -2, 58, 10, -2, -2, 58, 10, -2, -2, 58, 10, -2 },
{ -4, 54, 16, -2, -4, 54, 16, -2, -4, 54, 16, -2, -4, 54, 16, -2 },
{ -6, 46, 28, -4, -6, 46, 28, -4, -6, 46, 28, -4, -6, 46, 28, -4 },
{ -4, 36, 36, -4, -4, 36, 36, -4, -4, 36, 36, -4, -4, 36, 36, -4 },
{ -4, 28, 46, -6, -4, 28, 46, -6, -4, 28, 46, -6, -4, 28, 46, -6 },
{ -2, 16, 54, -4, -2, 16, 54, -4, -2, 16, 54, -4, -2, 16, 54, -4 },
{ -2, 10, 58, -2, -2, 10, 58, -2, -2, 10, 58, -2, -2, 10, 58, -2 },
};
#define BIT_DEPTH 8
#include "hevcdsp_template.c"
#undef BIT_DEPTH
#define BIT_DEPTH 9
#include "hevcdsp_template.c"
#undef BIT_DEPTH
#define BIT_DEPTH 10
#include "hevcdsp_template.c"
#undef BIT_DEPTH
void ff_hevc_dsp_init(HEVCDSPContext *hevcdsp, int bit_depth)
{
#undef FUNC
#define FUNC(a, depth) a ## _ ## depth
#define HEVC_DSP(depth) \
hevcdsp->put_pcm = FUNC(put_pcm, depth); \
hevcdsp->transquant_bypass[0] = FUNC(transquant_bypass4x4, depth); \
hevcdsp->transquant_bypass[1] = FUNC(transquant_bypass8x8, depth); \
hevcdsp->transquant_bypass[2] = FUNC(transquant_bypass16x16, depth); \
hevcdsp->transquant_bypass[3] = FUNC(transquant_bypass32x32, depth); \
hevcdsp->transform_skip = FUNC(transform_skip, depth); \
hevcdsp->transform_4x4_luma_add = FUNC(transform_4x4_luma_add, depth); \
hevcdsp->transform_add[0] = FUNC(transform_4x4_add, depth); \
hevcdsp->transform_add[1] = FUNC(transform_8x8_add, depth); \
hevcdsp->transform_add[2] = FUNC(transform_16x16_add, depth); \
hevcdsp->transform_add[3] = FUNC(transform_32x32_add, depth); \
\
hevcdsp->sao_band_filter[0] = FUNC(sao_band_filter_0, depth); \
hevcdsp->sao_band_filter[1] = FUNC(sao_band_filter_1, depth); \
hevcdsp->sao_band_filter[2] = FUNC(sao_band_filter_2, depth); \
hevcdsp->sao_band_filter[3] = FUNC(sao_band_filter_3, depth); \
\
hevcdsp->sao_edge_filter[0] = FUNC(sao_edge_filter_0, depth); \
hevcdsp->sao_edge_filter[1] = FUNC(sao_edge_filter_1, depth); \
hevcdsp->sao_edge_filter[2] = FUNC(sao_edge_filter_2, depth); \
hevcdsp->sao_edge_filter[3] = FUNC(sao_edge_filter_3, depth); \
\
hevcdsp->put_hevc_qpel[0][0] = FUNC(put_hevc_qpel_pixels, depth); \
hevcdsp->put_hevc_qpel[0][1] = FUNC(put_hevc_qpel_h1, depth); \
hevcdsp->put_hevc_qpel[0][2] = FUNC(put_hevc_qpel_h2, depth); \
hevcdsp->put_hevc_qpel[0][3] = FUNC(put_hevc_qpel_h3, depth); \
hevcdsp->put_hevc_qpel[1][0] = FUNC(put_hevc_qpel_v1, depth); \
hevcdsp->put_hevc_qpel[1][1] = FUNC(put_hevc_qpel_h1v1, depth); \
hevcdsp->put_hevc_qpel[1][2] = FUNC(put_hevc_qpel_h2v1, depth); \
hevcdsp->put_hevc_qpel[1][3] = FUNC(put_hevc_qpel_h3v1, depth); \
hevcdsp->put_hevc_qpel[2][0] = FUNC(put_hevc_qpel_v2, depth); \
hevcdsp->put_hevc_qpel[2][1] = FUNC(put_hevc_qpel_h1v2, depth); \
hevcdsp->put_hevc_qpel[2][2] = FUNC(put_hevc_qpel_h2v2, depth); \
hevcdsp->put_hevc_qpel[2][3] = FUNC(put_hevc_qpel_h3v2, depth); \
hevcdsp->put_hevc_qpel[3][0] = FUNC(put_hevc_qpel_v3, depth); \
hevcdsp->put_hevc_qpel[3][1] = FUNC(put_hevc_qpel_h1v3, depth); \
hevcdsp->put_hevc_qpel[3][2] = FUNC(put_hevc_qpel_h2v3, depth); \
hevcdsp->put_hevc_qpel[3][3] = FUNC(put_hevc_qpel_h3v3, depth); \
\
hevcdsp->put_hevc_epel[0][0] = FUNC(put_hevc_epel_pixels, depth); \
hevcdsp->put_hevc_epel[0][1] = FUNC(put_hevc_epel_h, depth); \
hevcdsp->put_hevc_epel[1][0] = FUNC(put_hevc_epel_v, depth); \
hevcdsp->put_hevc_epel[1][1] = FUNC(put_hevc_epel_hv, depth); \
\
hevcdsp->put_unweighted_pred = FUNC(put_unweighted_pred, depth); \
hevcdsp->put_weighted_pred_avg = FUNC(put_weighted_pred_avg, depth); \
\
hevcdsp->weighted_pred = FUNC(weighted_pred, depth); \
hevcdsp->weighted_pred_avg = FUNC(weighted_pred_avg, depth); \
\
hevcdsp->hevc_h_loop_filter_luma = FUNC(hevc_h_loop_filter_luma, depth); \
hevcdsp->hevc_v_loop_filter_luma = FUNC(hevc_v_loop_filter_luma, depth); \
hevcdsp->hevc_h_loop_filter_chroma = FUNC(hevc_h_loop_filter_chroma, depth); \
hevcdsp->hevc_v_loop_filter_chroma = FUNC(hevc_v_loop_filter_chroma, depth); \
hevcdsp->hevc_h_loop_filter_luma_c = FUNC(hevc_h_loop_filter_luma, depth); \
hevcdsp->hevc_v_loop_filter_luma_c = FUNC(hevc_v_loop_filter_luma, depth); \
hevcdsp->hevc_h_loop_filter_chroma_c = FUNC(hevc_h_loop_filter_chroma, depth); \
hevcdsp->hevc_v_loop_filter_chroma_c = FUNC(hevc_v_loop_filter_chroma, depth);
switch (bit_depth) {
case 9:
HEVC_DSP(9);
break;
case 10:
HEVC_DSP(10);
break;
default:
HEVC_DSP(8);
break;
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,65 @@
/*
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
*
* This file is part of Libav.
*
* Libav 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 2.1 of the License, or (at your option) any later version.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "hevc.h"
#define BIT_DEPTH 8
#include "hevcpred_template.c"
#undef BIT_DEPTH
#define BIT_DEPTH 9
#include "hevcpred_template.c"
#undef BIT_DEPTH
#define BIT_DEPTH 10
#include "hevcpred_template.c"
#undef BIT_DEPTH
void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth)
{
#undef FUNC
#define FUNC(a, depth) a ## _ ## depth
#define HEVC_PRED(depth) \
hpc->intra_pred = FUNC(intra_pred, depth); \
hpc->pred_planar[0] = FUNC(pred_planar_0, depth); \
hpc->pred_planar[1] = FUNC(pred_planar_1, depth); \
hpc->pred_planar[2] = FUNC(pred_planar_2, depth); \
hpc->pred_planar[3] = FUNC(pred_planar_3, depth); \
hpc->pred_dc = FUNC(pred_dc, depth); \
hpc->pred_angular[0] = FUNC(pred_angular_0, depth); \
hpc->pred_angular[1] = FUNC(pred_angular_1, depth); \
hpc->pred_angular[2] = FUNC(pred_angular_2, depth); \
hpc->pred_angular[3] = FUNC(pred_angular_3, depth);
switch (bit_depth) {
case 9:
HEVC_PRED(9);
break;
case 10:
HEVC_PRED(10);
break;
default:
HEVC_PRED(8);
break;
}
}

@ -0,0 +1,560 @@
/*
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
*
* This file is part of Libav.
*
* Libav 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 2.1 of the License, or (at your option) any later version.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/pixdesc.h"
#include "hevc.h"
#include "bit_depth_template.c"
#define POS(x, y) src[(x) + stride * (y)]
static void FUNC(intra_pred)(HEVCContext *s, int x0, int y0, int log2_size, int c_idx)
{
#define PU(x) \
((x) >> s->sps->log2_min_pu_size)
#define MVF(x, y) \
(s->ref->tab_mvf[(x) + (y) * min_pu_width])
#define MVF_PU(x, y) \
MVF(PU(x0 + ((x) << hshift)), PU(y0 + ((y) << vshift)))
#define IS_INTRA(x, y) \
MVF_PU(x, y).is_intra
#define MIN_TB_ADDR_ZS(x, y) \
s->pps->min_tb_addr_zs[(y) * s->sps->min_tb_width + (x)]
#define EXTEND_LEFT(ptr, start, length) \
for (i = (start); i > (start) - (length); i--) \
ptr[i - 1] = ptr[i]
#define EXTEND_RIGHT(ptr, start, length) \
for (i = (start); i < (start) + (length); i++) \
ptr[i] = ptr[i - 1]
#define EXTEND_UP(ptr, start, length) EXTEND_LEFT(ptr, start, length)
#define EXTEND_DOWN(ptr, start, length) EXTEND_RIGHT(ptr, start, length)
#define EXTEND_LEFT_CIP(ptr, start, length) \
for (i = (start); i > (start) - (length); i--) \
if (!IS_INTRA(i - 1, -1)) \
ptr[i - 1] = ptr[i]
#define EXTEND_RIGHT_CIP(ptr, start, length) \
for (i = (start); i < (start) + (length); i++) \
if (!IS_INTRA(i, -1)) \
ptr[i] = ptr[i - 1]
#define EXTEND_UP_CIP(ptr, start, length) \
for (i = (start); i > (start) - (length); i--) \
if (!IS_INTRA(-1, i - 1)) \
ptr[i - 1] = ptr[i]
#define EXTEND_UP_CIP_0(ptr, start, length) \
for (i = (start); i > (start) - (length); i--) \
ptr[i - 1] = ptr[i]
#define EXTEND_DOWN_CIP(ptr, start, length) \
for (i = (start); i < (start) + (length); i++) \
if (!IS_INTRA(-1, i)) \
ptr[i] = ptr[i - 1]
HEVCLocalContext *lc = &s->HEVClc;
int i;
int hshift = s->sps->hshift[c_idx];
int vshift = s->sps->vshift[c_idx];
int size = (1 << log2_size);
int size_in_luma = size << hshift;
int size_in_tbs = size_in_luma >> s->sps->log2_min_tb_size;
int x = x0 >> hshift;
int y = y0 >> vshift;
int x_tb = x0 >> s->sps->log2_min_tb_size;
int y_tb = y0 >> s->sps->log2_min_tb_size;
int cur_tb_addr = MIN_TB_ADDR_ZS(x_tb, y_tb);
ptrdiff_t stride = s->frame->linesize[c_idx] / sizeof(pixel);
pixel *src = (pixel*)s->frame->data[c_idx] + x + y * stride;
int min_pu_width = s->sps->min_pu_width;
enum IntraPredMode mode = c_idx ? lc->pu.intra_pred_mode_c :
lc->tu.cur_intra_pred_mode;
pixel left_array[2 * MAX_TB_SIZE + 1];
pixel filtered_left_array[2 * MAX_TB_SIZE + 1];
pixel top_array[2 * MAX_TB_SIZE + 1];
pixel filtered_top_array[2 * MAX_TB_SIZE + 1];
pixel *left = left_array + 1;
pixel *top = top_array + 1;
pixel *filtered_left = filtered_left_array + 1;
pixel *filtered_top = filtered_top_array + 1;
int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > MIN_TB_ADDR_ZS(x_tb - 1, y_tb + size_in_tbs);
int cand_left = lc->na.cand_left;
int cand_up_left = lc->na.cand_up_left;
int cand_up = lc->na.cand_up;
int cand_up_right = lc->na.cand_up_right && cur_tb_addr > MIN_TB_ADDR_ZS(x_tb + size_in_tbs, y_tb - 1);
int bottom_left_size = (FFMIN(y0 + 2 * size_in_luma, s->sps->height) -
(y0 + size_in_luma)) >> vshift;
int top_right_size = (FFMIN(x0 + 2 * size_in_luma, s->sps->width) -
(x0 + size_in_luma)) >> hshift;
if (s->pps->constrained_intra_pred_flag == 1) {
int size_in_luma_pu = PU(size_in_luma);
int on_pu_edge_x = !(x0 & ((1 << s->sps->log2_min_pu_size) - 1));
int on_pu_edge_y = !(y0 & ((1 << s->sps->log2_min_pu_size) - 1));
if (!size_in_luma_pu)
size_in_luma_pu++;
if (cand_bottom_left == 1 && on_pu_edge_x) {
int x_left_pu = PU(x0 - 1);
int y_bottom_pu = PU(y0 + size_in_luma);
int max = FFMIN(size_in_luma_pu, s->sps->min_pu_height - y_bottom_pu);
cand_bottom_left = 0;
for (i = 0; i < max; i++)
cand_bottom_left |= MVF(x_left_pu, y_bottom_pu + i).is_intra;
}
if (cand_left == 1 && on_pu_edge_x) {
int x_left_pu = PU(x0 - 1);
int y_left_pu = PU(y0);
int max = FFMIN(size_in_luma_pu, s->sps->min_pu_height - y_left_pu);
cand_left = 0;
for (i = 0; i < max; i++)
cand_left |= MVF(x_left_pu, y_left_pu + i).is_intra;
}
if (cand_up_left == 1) {
int x_left_pu = PU(x0 - 1);
int y_top_pu = PU(y0 - 1);
cand_up_left = MVF(x_left_pu, y_top_pu).is_intra;
}
if (cand_up == 1 && on_pu_edge_y) {
int x_top_pu = PU(x0);
int y_top_pu = PU(y0 - 1);
int max = FFMIN(size_in_luma_pu, s->sps->min_pu_width - x_top_pu);
cand_up = 0;
for (i = 0; i < max; i++)
cand_up |= MVF(x_top_pu + i, y_top_pu).is_intra;
}
if (cand_up_right == 1 && on_pu_edge_y) {
int y_top_pu = PU(y0 - 1);
int x_right_pu = PU(x0 + size_in_luma);
int max = FFMIN(size_in_luma_pu, s->sps->min_pu_width - x_right_pu);
cand_up_right = 0;
for (i = 0; i < max; i++)
cand_up_right |= MVF(x_right_pu + i, y_top_pu).is_intra;
}
for (i = 0; i < 2 * MAX_TB_SIZE; i++) {
left[i] = 128;
top[i] = 128;
}
}
if (cand_bottom_left) {
for (i = size + bottom_left_size; i < (size << 1); i++)
if (IS_INTRA(-1, size + bottom_left_size - 1) ||
!s->pps->constrained_intra_pred_flag)
left[i] = POS(-1, size + bottom_left_size - 1);
for (i = size + bottom_left_size - 1; i >= size; i--)
if (IS_INTRA(-1, i) || !s->pps->constrained_intra_pred_flag)
left[i] = POS(-1, i);
}
if (cand_left)
for (i = size - 1; i >= 0; i--)
if (IS_INTRA(-1, i) || !s->pps->constrained_intra_pred_flag)
left[i] = POS(-1, i);
if (cand_up_left)
if (IS_INTRA(-1, -1) || !s->pps->constrained_intra_pred_flag) {
left[-1] = POS(-1, -1);
top[-1] = left[-1];
}
if (cand_up)
for (i = size - 1; i >= 0; i--)
if (IS_INTRA(i, -1) || !s->pps->constrained_intra_pred_flag)
top[i] = POS(i, -1);
if (cand_up_right) {
for (i = size + top_right_size; i < (size << 1); i++)
if (IS_INTRA(size + top_right_size - 1, -1) ||
!s->pps->constrained_intra_pred_flag)
top[i] = POS(size + top_right_size - 1, -1);
for (i = size + top_right_size - 1; i >= size; i--)
if (IS_INTRA(i, -1) || !s->pps->constrained_intra_pred_flag)
top[i] = POS(i, -1);
}
if (s->pps->constrained_intra_pred_flag == 1) {
if (cand_bottom_left || cand_left || cand_up_left || cand_up || cand_up_right) {
int size_max_x = x0 + ((2 * size) << hshift) < s->sps->width ?
2 * size : (s->sps->width - x0) >> hshift;
int size_max_y = y0 + ((2 * size) << vshift) < s->sps->height ?
2 * size : (s->sps->height - y0) >> vshift;
int j = size + (cand_bottom_left? bottom_left_size: 0) -1;
if (!cand_up_right) {
size_max_x = x0 + ((size) << hshift) < s->sps->width ?
size : (s->sps->width - x0) >> hshift;
}
if (!cand_bottom_left) {
size_max_y = y0 + (( size) << vshift) < s->sps->height ?
size : (s->sps->height - y0) >> vshift;
}
if (cand_bottom_left || cand_left || cand_up_left) {
while (j > -1 && !IS_INTRA(-1, j))
j--;
if (!IS_INTRA(-1, j)) {
j = 0;
while (j < size_max_x && !IS_INTRA(j, -1))
j++;
EXTEND_LEFT_CIP(top, j, j + 1);
left[-1] = top[-1];
j = 0;
}
} else {
j = 0;
while (j < size_max_x && !IS_INTRA(j, -1))
j++;
if (j > 0)
if (x0 > 0) {
EXTEND_LEFT_CIP(top, j, j + 1);
} else {
EXTEND_LEFT_CIP(top, j, j);
top[-1] = top[0];
}
left[-1] = top[-1];
j = 0;
}
if (cand_bottom_left || cand_left) {
EXTEND_DOWN_CIP(left, j, size_max_y - j);
}
if (!cand_left) {
EXTEND_DOWN(left, 0, size);
}
if (!cand_bottom_left) {
EXTEND_DOWN(left, size, size);
}
if (x0 != 0 && y0 != 0) {
EXTEND_UP_CIP(left, size_max_y - 1, size_max_y);
} else if (x0 == 0) {
EXTEND_UP_CIP_0(left, size_max_y - 1, size_max_y);
} else {
EXTEND_UP_CIP(left, size_max_y - 1, size_max_y - 1);
}
top[-1] = left[-1];
if (y0 != 0) {
EXTEND_RIGHT_CIP(top, 0, size_max_x);
}
}
}
// Infer the unavailable samples
if (!cand_bottom_left) {
if (cand_left) {
EXTEND_DOWN(left, size, size);
} else if (cand_up_left) {
EXTEND_DOWN(left, 0, 2 * size);
cand_left = 1;
} else if (cand_up) {
left[-1] = top[0];
EXTEND_DOWN(left, 0, 2 * size);
cand_up_left = 1;
cand_left = 1;
} else if (cand_up_right) {
EXTEND_LEFT(top, size, size);
left[-1] = top[0];
EXTEND_DOWN(left, 0, 2 * size);
cand_up = 1;
cand_up_left = 1;
cand_left = 1;
} else { // No samples available
top[0] = left[-1] = (1 << (BIT_DEPTH - 1));
EXTEND_RIGHT(top, 1, 2 * size - 1);
EXTEND_DOWN(left, 0, 2 * size);
}
}
if (!cand_left) {
EXTEND_UP(left, size, size);
}
if (!cand_up_left) {
left[-1] = left[0];
}
if (!cand_up) {
top[0] = left[-1];
EXTEND_RIGHT(top, 1, size - 1);
}
if (!cand_up_right) {
EXTEND_RIGHT(top, size, size);
}
top[-1] = left[-1];
// Filtering process
if (c_idx == 0 && mode != INTRA_DC && size != 4) {
int intra_hor_ver_dist_thresh[] = { 7, 1, 0 };
int min_dist_vert_hor = FFMIN(FFABS((int)mode - 26),
FFABS((int)mode - 10));
if (min_dist_vert_hor > intra_hor_ver_dist_thresh[log2_size - 3]) {
int threshold = 1 << (BIT_DEPTH - 5);
if (s->sps->sps_strong_intra_smoothing_enable_flag &&
log2_size == 5 &&
FFABS(top[-1] + top[63] - 2 * top[31]) < threshold &&
FFABS(left[-1] + left[63] - 2 * left[31]) < threshold) {
// We can't just overwrite values in top because it could be
// a pointer into src
filtered_top[-1] = top[-1];
filtered_top[63] = top[63];
for (i = 0; i < 63; i++)
filtered_top[i] = ((64 - (i + 1)) * top[-1] +
(i + 1) * top[63] + 32) >> 6;
for (i = 0; i < 63; i++)
left[i] = ((64 - (i + 1)) * left[-1] +
(i + 1) * left[63] + 32) >> 6;
top = filtered_top;
} else {
filtered_left[2 * size - 1] = left[2 * size - 1];
filtered_top[2 * size - 1] = top[2 * size - 1];
for (i = 2 * size - 2; i >= 0; i--)
filtered_left[i] = (left[i + 1] + 2 * left[i] +
left[i - 1] + 2) >> 2;
filtered_top[-1] =
filtered_left[-1] = (left[0] + 2 * left[-1] + top[0] + 2) >> 2;
for (i = 2 * size - 2; i >= 0; i--)
filtered_top[i] = (top[i + 1] + 2 * top[i] +
top[i - 1] + 2) >> 2;
left = filtered_left;
top = filtered_top;
}
}
}
switch (mode) {
case INTRA_PLANAR:
s->hpc.pred_planar[log2_size - 2]((uint8_t *)src, (uint8_t *)top,
(uint8_t *)left, stride);
break;
case INTRA_DC:
s->hpc.pred_dc((uint8_t *)src, (uint8_t *)top,
(uint8_t *)left, stride, log2_size, c_idx);
break;
default:
s->hpc.pred_angular[log2_size - 2]((uint8_t *)src, (uint8_t *)top,
(uint8_t *)left, stride, c_idx,
mode);
break;
}
}
static void FUNC(pred_planar_0)(uint8_t *_src, const uint8_t *_top,
const uint8_t *_left,
ptrdiff_t stride)
{
int x, y;
pixel *src = (pixel *)_src;
const pixel *top = (const pixel *)_top;
const pixel *left = (const pixel *)_left;
for (y = 0; y < 4; y++)
for (x = 0; x < 4; x++)
POS(x, y) = ((3 - x) * left[y] + (x + 1) * top[4] +
(3 - y) * top[x] + (y + 1) * left[4] + 4) >> 3;
}
static void FUNC(pred_planar_1)(uint8_t *_src, const uint8_t *_top,
const uint8_t *_left, ptrdiff_t stride)
{
int x, y;
pixel *src = (pixel *)_src;
const pixel *top = (const pixel *)_top;
const pixel *left = (const pixel *)_left;
for (y = 0; y < 8; y++)
for (x = 0; x < 8; x++)
POS(x, y) = ((7 - x) * left[y] + (x + 1) * top[8] +
(7 - y) * top[x] + (y + 1) * left[8] + 8) >> 4;
}
static void FUNC(pred_planar_2)(uint8_t *_src, const uint8_t *_top,
const uint8_t *_left, ptrdiff_t stride)
{
int x, y;
pixel *src = (pixel *)_src;
const pixel *top = (const pixel *)_top;
const pixel *left = (const pixel *)_left;
for (y = 0; y < 16; y++)
for (x = 0; x < 16; x++)
POS(x, y) = ((15 - x) * left[y] + (x + 1) * top[16] +
(15 - y) * top[x] + (y + 1) * left[16] + 16) >> 5;
}
static void FUNC(pred_planar_3)(uint8_t *_src, const uint8_t *_top,
const uint8_t *_left, ptrdiff_t stride)
{
int x, y;
pixel *src = (pixel *)_src;
const pixel *top = (const pixel *)_top;
const pixel *left = (const pixel *)_left;
for (y = 0; y < 32; y++)
for (x = 0; x < 32; x++)
POS(x, y) = ((31 - x) * left[y] + (x + 1) * top[32] +
(31 - y) * top[x] + (y + 1) * left[32] + 32) >> 6;
}
static void FUNC(pred_dc)(uint8_t *_src, const uint8_t *_top,
const uint8_t *_left,
ptrdiff_t stride, int log2_size, int c_idx)
{
int i, j, x, y;
int size = (1 << log2_size);
pixel *src = (pixel *)_src;
const pixel *top = (const pixel *)_top;
const pixel *left = (const pixel *)_left;
int dc = size;
pixel4 a;
for (i = 0; i < size; i++)
dc += left[i] + top[i];
dc >>= log2_size + 1;
a = PIXEL_SPLAT_X4(dc);
for (i = 0; i < size; i++)
for (j = 0; j < size / 4; j++)
AV_WN4PA(&POS(j * 4, i), a);
if (c_idx == 0 && size < 32) {
POS(0, 0) = (left[0] + 2 * dc + top[0] + 2) >> 2;
for (x = 1; x < size; x++)
POS(x, 0) = (top[x] + 3 * dc + 2) >> 2;
for (y = 1; y < size; y++)
POS(0, y) = (left[y] + 3 * dc + 2) >> 2;
}
}
static av_always_inline void FUNC(pred_angular)(uint8_t *_src,
const uint8_t *_top,
const uint8_t *_left,
ptrdiff_t stride, int c_idx,
int mode, int size)
{
int x, y;
pixel *src = (pixel *)_src;
const pixel *top = (const pixel *)_top;
const pixel *left = (const pixel *)_left;
static const int intra_pred_angle[] = {
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
};
static const int inv_angle[] = {
-4096, -1638, -910, -630, -482, -390, -315, -256, -315, -390, -482,
-630, -910, -1638, -4096
};
int angle = intra_pred_angle[mode - 2];
pixel ref_array[3 * MAX_TB_SIZE + 1];
pixel *ref_tmp = ref_array + size;
const pixel *ref;
int last = (size * angle) >> 5;
if (mode >= 18) {
ref = top - 1;
if (angle < 0 && last < -1) {
for (x = 0; x <= size; x++)
ref_tmp[x] = top[x - 1];
for (x = last; x <= -1; x++)
ref_tmp[x] = left[-1 + ((x * inv_angle[mode - 11] + 128) >> 8)];
ref = ref_tmp;
}
for (y = 0; y < size; y++) {
int idx = ((y + 1) * angle) >> 5;
int fact = ((y + 1) * angle) & 31;
if (fact) {
for (x = 0; x < size; x++) {
POS(x, y) = ((32 - fact) * ref[x + idx + 1] +
fact * ref[x + idx + 2] + 16) >> 5;
}
} else {
for (x = 0; x < size; x++)
POS(x, y) = ref[x + idx + 1];
}
}
if (mode == 26 && c_idx == 0 && size < 32) {
for (y = 0; y < size; y++)
POS(0, y) = av_clip_pixel(top[0] + ((left[y] - left[-1]) >> 1));
}
} else {
ref = left - 1;
if (angle < 0 && last < -1) {
for (x = 0; x <= size; x++)
ref_tmp[x] = left[x - 1];
for (x = last; x <= -1; x++)
ref_tmp[x] = top[-1 + ((x * inv_angle[mode - 11] + 128) >> 8)];
ref = ref_tmp;
}
for (x = 0; x < size; x++) {
int idx = ((x + 1) * angle) >> 5;
int fact = ((x + 1) * angle) & 31;
if (fact) {
for (y = 0; y < size; y++) {
POS(x, y) = ((32 - fact) * ref[y + idx + 1] +
fact * ref[y + idx + 2] + 16) >> 5;
}
} else {
for (y = 0; y < size; y++)
POS(x, y) = ref[y + idx + 1];
}
}
if (mode == 10 && c_idx == 0 && size < 32) {
for (x = 0; x < size; x++)
POS(x, 0) = av_clip_pixel(left[0] + ((top[x] - top[-1]) >> 1));
}
}
}
static void FUNC(pred_angular_0)(uint8_t *src, const uint8_t *top,
const uint8_t *left,
ptrdiff_t stride, int c_idx, int mode)
{
FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 2);
}
static void FUNC(pred_angular_1)(uint8_t *src, const uint8_t *top,
const uint8_t *left,
ptrdiff_t stride, int c_idx, int mode)
{
FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 3);
}
static void FUNC(pred_angular_2)(uint8_t *src, const uint8_t *top,
const uint8_t *left,
ptrdiff_t stride, int c_idx, int mode)
{
FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 4);
}
static void FUNC(pred_angular_3)(uint8_t *src, const uint8_t *top,
const uint8_t *left,
ptrdiff_t stride, int c_idx, int mode)
{
FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 5);
}
#undef EXTEND_LEFT_CIP
#undef EXTEND_RIGHT_CIP
#undef EXTEND_UP_CIP
#undef EXTEND_DOWN_CIP
#undef IS_INTRA
#undef MVF_PU
#undef MVF
#undef PU
#undef EXTEND_LEFT
#undef EXTEND_RIGHT
#undef EXTEND_UP
#undef EXTEND_DOWN
#undef MIN_TB_ADDR_ZS
#undef POS

@ -27,7 +27,7 @@
*/
#define LIBAVCODEC_VERSION_MAJOR 55
#define LIBAVCODEC_VERSION_MINOR 23
#define LIBAVCODEC_VERSION_MINOR 24
#define LIBAVCODEC_VERSION_MICRO 0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \

Loading…
Cancel
Save