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>tags/n2.2-rc1
| @@ -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: | |||
| @@ -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" */ | |||
| { | |||
| @@ -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, | |||
| }; | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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, \ | |||