mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
lavc: add a HEVC decoder.
Initially written by Guillaume Martres <smarter@ubuntu.com> as a GSoC project. Further contributions by the OpenHEVC project and other developers, namely: Mickaël Raulet <mraulet@insa-rennes.fr> Seppo Tomperi <seppo.tomperi@vtt.fi> Gildas Cocherel <gildas.cocherel@laposte.net> Khaled Jerbi <khaled_jerbi@yahoo.fr> Wassim Hamidouche <wassim.hamidouche@insa-rennes.fr> Vittorio Giovara <vittorio.giovara@gmail.com> Jan Ekström <jeebjp@gmail.com> Anton Khirnov <anton@khirnov.net> Martin Storsjö <martin@martin.st> Luca Barbato <lu_zero@gentoo.org> Yusuke Nakamura <muken.the.vfrmaniac@gmail.com> Signed-off-by: Anton Khirnov <anton@khirnov.net> Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
parent
2a19fcc123
commit
c8dd048ab8
1
configure
vendored
1
configure
vendored
@ -1809,6 +1809,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"
|
||||
|
@ -233,6 +233,10 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o \
|
||||
cabac.o h264_sei.o h264_ps.o \
|
||||
h264_refs.o h264_cavlc.o h264_cabac.o
|
||||
OBJS-$(CONFIG_H264_VDA_DECODER) += vda_h264_dec.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_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o
|
||||
OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o
|
||||
OBJS-$(CONFIG_IAC_DECODER) += imc.o
|
||||
@ -758,6 +762,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 \
|
||||
|
@ -164,6 +164,7 @@ void avcodec_register_all(void)
|
||||
REGISTER_DECODER(H264_CRYSTALHD, h264_crystalhd);
|
||||
REGISTER_DECODER(H264_VDA, h264_vda);
|
||||
REGISTER_DECODER(H264_VDPAU, h264_vdpau);
|
||||
REGISTER_DECODER(HEVC, hevc);
|
||||
REGISTER_ENCDEC (HUFFYUV, huffyuv);
|
||||
REGISTER_DECODER(IDCIN, idcin);
|
||||
REGISTER_DECODER(IFF_BYTERUN1, iff_byterun1);
|
||||
@ -534,6 +535,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);
|
||||
|
@ -160,4 +160,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 */
|
||||
|
3118
libavcodec/hevc.c
Normal file
3118
libavcodec/hevc.c
Normal file
File diff suppressed because it is too large
Load Diff
988
libavcodec/hevc.h
Normal file
988
libavcodec/hevc.h
Normal file
@ -0,0 +1,988 @@
|
||||
/*
|
||||
* HEVC video Decoder
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Guillaume Martres
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_HEVC_H
|
||||
#define AVCODEC_HEVC_H
|
||||
|
||||
#include "libavutil/buffer.h"
|
||||
#include "libavutil/md5.h"
|
||||
|
||||
#include "avcodec.h"
|
||||
#include "cabac.h"
|
||||
#include "dsputil.h"
|
||||
#include "get_bits.h"
|
||||
#include "hevcpred.h"
|
||||
#include "hevcdsp.h"
|
||||
#include "internal.h"
|
||||
#include "thread.h"
|
||||
#include "videodsp.h"
|
||||
|
||||
#define MAX_DPB_SIZE 16 // A.4.1
|
||||
#define MAX_REFS 16
|
||||
|
||||
/**
|
||||
* 7.4.2.1
|
||||
*/
|
||||
#define MAX_SUB_LAYERS 7
|
||||
#define MAX_VPS_COUNT 16
|
||||
#define MAX_SPS_COUNT 32
|
||||
#define MAX_PPS_COUNT 256
|
||||
#define MAX_SHORT_TERM_RPS_COUNT 64
|
||||
#define MAX_CU_SIZE 128
|
||||
|
||||
//TODO: check if this is really the maximum
|
||||
#define MAX_TRANSFORM_DEPTH 5
|
||||
|
||||
#define MAX_TB_SIZE 32
|
||||
#define MAX_PB_SIZE 64
|
||||
#define MAX_LOG2_CTB_SIZE 6
|
||||
#define MAX_QP 51
|
||||
#define DEFAULT_INTRA_TC_OFFSET 2
|
||||
|
||||
#define HEVC_CONTEXTS 183
|
||||
|
||||
#define MRG_MAX_NUM_CANDS 5
|
||||
|
||||
#define L0 0
|
||||
#define L1 1
|
||||
|
||||
#define EPEL_EXTRA_BEFORE 1
|
||||
#define EPEL_EXTRA_AFTER 2
|
||||
#define EPEL_EXTRA 3
|
||||
|
||||
/**
|
||||
* Value of the luma sample at position (x, y) in the 2D array tab.
|
||||
*/
|
||||
#define SAMPLE(tab, x, y) ((tab)[(y) * s->sps->width + (x)])
|
||||
#define SAMPLE_CTB(tab, x, y) ((tab)[(y) * pic_width_in_ctb + (x)])
|
||||
#define SAMPLE_CBF(tab, x, y) ((tab)[((y) & ((1<<log2_trafo_size)-1)) * MAX_CU_SIZE + ((x) & ((1<<log2_trafo_size)-1))])
|
||||
|
||||
#define IS_IDR(s) (s->nal_unit_type == NAL_IDR_W_RADL || s->nal_unit_type == NAL_IDR_N_LP)
|
||||
#define IS_BLA(s) (s->nal_unit_type == NAL_BLA_W_RADL || s->nal_unit_type == NAL_BLA_W_LP || \
|
||||
s->nal_unit_type == NAL_BLA_N_LP)
|
||||
|
||||
/**
|
||||
* Table 7-3: NAL unit type codes
|
||||
*/
|
||||
enum NALUnitType {
|
||||
NAL_TRAIL_N = 0,
|
||||
NAL_TRAIL_R = 1,
|
||||
NAL_TSA_N = 2,
|
||||
NAL_TSA_R = 3,
|
||||
NAL_STSA_N = 4,
|
||||
NAL_STSA_R = 5,
|
||||
NAL_RADL_N = 6,
|
||||
NAL_RADL_R = 7,
|
||||
NAL_RASL_N = 8,
|
||||
NAL_RASL_R = 9,
|
||||
NAL_BLA_W_LP = 16,
|
||||
NAL_BLA_W_RADL = 17,
|
||||
NAL_BLA_N_LP = 18,
|
||||
NAL_IDR_W_RADL = 19,
|
||||
NAL_IDR_N_LP = 20,
|
||||
NAL_CRA_NUT = 21,
|
||||
NAL_VPS = 32,
|
||||
NAL_SPS = 33,
|
||||
NAL_PPS = 34,
|
||||
NAL_AUD = 35,
|
||||
NAL_EOS_NUT = 36,
|
||||
NAL_EOB_NUT = 37,
|
||||
NAL_FD_NUT = 38,
|
||||
NAL_SEI_PREFIX = 39,
|
||||
NAL_SEI_SUFFIX = 40,
|
||||
};
|
||||
|
||||
enum RPSType {
|
||||
ST_CURR_BEF = 0,
|
||||
ST_CURR_AFT,
|
||||
ST_FOLL,
|
||||
LT_CURR,
|
||||
LT_FOLL,
|
||||
NB_RPS_TYPE,
|
||||
};
|
||||
|
||||
enum SliceType {
|
||||
B_SLICE = 0,
|
||||
P_SLICE = 1,
|
||||
I_SLICE = 2,
|
||||
};
|
||||
|
||||
enum SyntaxElement {
|
||||
SAO_MERGE_FLAG = 0,
|
||||
SAO_TYPE_IDX,
|
||||
SAO_EO_CLASS,
|
||||
SAO_BAND_POSITION,
|
||||
SAO_OFFSET_ABS,
|
||||
SAO_OFFSET_SIGN,
|
||||
END_OF_SLICE_FLAG,
|
||||
SPLIT_CODING_UNIT_FLAG,
|
||||
CU_TRANSQUANT_BYPASS_FLAG,
|
||||
SKIP_FLAG,
|
||||
CU_QP_DELTA,
|
||||
PRED_MODE_FLAG,
|
||||
PART_MODE,
|
||||
PCM_FLAG,
|
||||
PREV_INTRA_LUMA_PRED_FLAG,
|
||||
MPM_IDX,
|
||||
REM_INTRA_LUMA_PRED_MODE,
|
||||
INTRA_CHROMA_PRED_MODE,
|
||||
MERGE_FLAG,
|
||||
MERGE_IDX,
|
||||
INTER_PRED_IDC,
|
||||
REF_IDX_L0,
|
||||
REF_IDX_L1,
|
||||
ABS_MVD_GREATER0_FLAG,
|
||||
ABS_MVD_GREATER1_FLAG,
|
||||
ABS_MVD_MINUS2,
|
||||
MVD_SIGN_FLAG,
|
||||
MVP_LX_FLAG,
|
||||
NO_RESIDUAL_DATA_FLAG,
|
||||
SPLIT_TRANSFORM_FLAG,
|
||||
CBF_LUMA,
|
||||
CBF_CB_CR,
|
||||
TRANSFORM_SKIP_FLAG,
|
||||
LAST_SIGNIFICANT_COEFF_X_PREFIX,
|
||||
LAST_SIGNIFICANT_COEFF_Y_PREFIX,
|
||||
LAST_SIGNIFICANT_COEFF_X_SUFFIX,
|
||||
LAST_SIGNIFICANT_COEFF_Y_SUFFIX,
|
||||
SIGNIFICANT_COEFF_GROUP_FLAG,
|
||||
SIGNIFICANT_COEFF_FLAG,
|
||||
COEFF_ABS_LEVEL_GREATER1_FLAG,
|
||||
COEFF_ABS_LEVEL_GREATER2_FLAG,
|
||||
COEFF_ABS_LEVEL_REMAINING,
|
||||
COEFF_SIGN_FLAG,
|
||||
};
|
||||
|
||||
enum PartMode {
|
||||
PART_2Nx2N = 0,
|
||||
PART_2NxN = 1,
|
||||
PART_Nx2N = 2,
|
||||
PART_NxN = 3,
|
||||
PART_2NxnU = 4,
|
||||
PART_2NxnD = 5,
|
||||
PART_nLx2N = 6,
|
||||
PART_nRx2N = 7,
|
||||
};
|
||||
|
||||
enum PredMode {
|
||||
MODE_INTER = 0,
|
||||
MODE_INTRA,
|
||||
MODE_SKIP,
|
||||
};
|
||||
|
||||
enum InterPredIdc {
|
||||
PRED_L0 = 0,
|
||||
PRED_L1,
|
||||
PRED_BI,
|
||||
};
|
||||
|
||||
enum IntraPredMode {
|
||||
INTRA_PLANAR = 0,
|
||||
INTRA_DC,
|
||||
INTRA_ANGULAR_2,
|
||||
INTRA_ANGULAR_3,
|
||||
INTRA_ANGULAR_4,
|
||||
INTRA_ANGULAR_5,
|
||||
INTRA_ANGULAR_6,
|
||||
INTRA_ANGULAR_7,
|
||||
INTRA_ANGULAR_8,
|
||||
INTRA_ANGULAR_9,
|
||||
INTRA_ANGULAR_10,
|
||||
INTRA_ANGULAR_11,
|
||||
INTRA_ANGULAR_12,
|
||||
INTRA_ANGULAR_13,
|
||||
INTRA_ANGULAR_14,
|
||||
INTRA_ANGULAR_15,
|
||||
INTRA_ANGULAR_16,
|
||||
INTRA_ANGULAR_17,
|
||||
INTRA_ANGULAR_18,
|
||||
INTRA_ANGULAR_19,
|
||||
INTRA_ANGULAR_20,
|
||||
INTRA_ANGULAR_21,
|
||||
INTRA_ANGULAR_22,
|
||||
INTRA_ANGULAR_23,
|
||||
INTRA_ANGULAR_24,
|
||||
INTRA_ANGULAR_25,
|
||||
INTRA_ANGULAR_26,
|
||||
INTRA_ANGULAR_27,
|
||||
INTRA_ANGULAR_28,
|
||||
INTRA_ANGULAR_29,
|
||||
INTRA_ANGULAR_30,
|
||||
INTRA_ANGULAR_31,
|
||||
INTRA_ANGULAR_32,
|
||||
INTRA_ANGULAR_33,
|
||||
INTRA_ANGULAR_34,
|
||||
};
|
||||
|
||||
enum SAOType {
|
||||
SAO_NOT_APPLIED = 0,
|
||||
SAO_BAND,
|
||||
SAO_EDGE,
|
||||
};
|
||||
|
||||
enum SAOEOClass {
|
||||
SAO_EO_HORIZ = 0,
|
||||
SAO_EO_VERT,
|
||||
SAO_EO_135D,
|
||||
SAO_EO_45D,
|
||||
};
|
||||
|
||||
enum ScanType {
|
||||
SCAN_DIAG = 0,
|
||||
SCAN_HORIZ,
|
||||
SCAN_VERT,
|
||||
};
|
||||
|
||||
typedef struct ShortTermRPS {
|
||||
int num_negative_pics;
|
||||
int num_delta_pocs;
|
||||
int32_t delta_poc[32];
|
||||
uint8_t used[32];
|
||||
} ShortTermRPS;
|
||||
|
||||
typedef struct LongTermRPS {
|
||||
int poc[32];
|
||||
uint8_t used[32];
|
||||
uint8_t nb_refs;
|
||||
} LongTermRPS;
|
||||
|
||||
typedef struct RefPicList {
|
||||
struct HEVCFrame *ref[MAX_REFS];
|
||||
int list[MAX_REFS];
|
||||
int isLongTerm[MAX_REFS];
|
||||
int nb_refs;
|
||||
} RefPicList;
|
||||
|
||||
typedef struct RefPicListTab {
|
||||
RefPicList refPicList[2];
|
||||
} RefPicListTab;
|
||||
|
||||
typedef struct HEVCWindow {
|
||||
int left_offset;
|
||||
int right_offset;
|
||||
int top_offset;
|
||||
int bottom_offset;
|
||||
} HEVCWindow;
|
||||
|
||||
typedef struct VUI {
|
||||
AVRational sar;
|
||||
|
||||
int overscan_info_present_flag;
|
||||
int overscan_appropriate_flag;
|
||||
|
||||
int video_signal_type_present_flag;
|
||||
int video_format;
|
||||
int video_full_range_flag;
|
||||
int colour_description_present_flag;
|
||||
uint8_t colour_primaries;
|
||||
uint8_t transfer_characteristic;
|
||||
uint8_t matrix_coeffs;
|
||||
|
||||
int chroma_loc_info_present_flag;
|
||||
int chroma_sample_loc_type_top_field;
|
||||
int chroma_sample_loc_type_bottom_field;
|
||||
int neutra_chroma_indication_flag;
|
||||
|
||||
int field_seq_flag;
|
||||
int frame_field_info_present_flag;
|
||||
|
||||
int default_display_window_flag;
|
||||
HEVCWindow def_disp_win;
|
||||
|
||||
int vui_timing_info_present_flag;
|
||||
uint32_t vui_num_units_in_tick;
|
||||
uint32_t vui_time_scale;
|
||||
int vui_poc_proportional_to_timing_flag;
|
||||
int vui_num_ticks_poc_diff_one_minus1;
|
||||
int vui_hrd_parameters_present_flag;
|
||||
|
||||
int bitstream_restriction_flag;
|
||||
int tiles_fixed_structure_flag;
|
||||
int motion_vectors_over_pic_boundaries_flag;
|
||||
int restricted_ref_pic_lists_flag;
|
||||
int min_spatial_segmentation_idc;
|
||||
int max_bytes_per_pic_denom;
|
||||
int max_bits_per_min_cu_denom;
|
||||
int log2_max_mv_length_horizontal;
|
||||
int log2_max_mv_length_vertical;
|
||||
} VUI;
|
||||
|
||||
typedef struct PTL {
|
||||
int general_profile_space;
|
||||
uint8_t general_tier_flag;
|
||||
int general_profile_idc;
|
||||
int general_profile_compatibility_flag[32];
|
||||
int general_level_idc;
|
||||
|
||||
uint8_t sub_layer_profile_present_flag[MAX_SUB_LAYERS];
|
||||
uint8_t sub_layer_level_present_flag[MAX_SUB_LAYERS];
|
||||
|
||||
int sub_layer_profile_space[MAX_SUB_LAYERS];
|
||||
uint8_t sub_layer_tier_flag[MAX_SUB_LAYERS];
|
||||
int sub_layer_profile_idc[MAX_SUB_LAYERS];
|
||||
uint8_t sub_layer_profile_compatibility_flags[MAX_SUB_LAYERS][32];
|
||||
int sub_layer_level_idc[MAX_SUB_LAYERS];
|
||||
} PTL;
|
||||
|
||||
typedef struct VPS {
|
||||
uint8_t vps_temporal_id_nesting_flag;
|
||||
int vps_max_layers;
|
||||
int vps_max_sub_layers; ///< vps_max_temporal_layers_minus1 + 1
|
||||
|
||||
PTL ptl;
|
||||
int vps_sub_layer_ordering_info_present_flag;
|
||||
unsigned int vps_max_dec_pic_buffering[MAX_SUB_LAYERS];
|
||||
unsigned int vps_num_reorder_pics[MAX_SUB_LAYERS];
|
||||
unsigned int vps_max_latency_increase[MAX_SUB_LAYERS];
|
||||
int vps_max_layer_id;
|
||||
int vps_num_layer_sets; ///< vps_num_layer_sets_minus1 + 1
|
||||
uint8_t vps_timing_info_present_flag;
|
||||
uint32_t vps_num_units_in_tick;
|
||||
uint32_t vps_time_scale;
|
||||
uint8_t vps_poc_proportional_to_timing_flag;
|
||||
int vps_num_ticks_poc_diff_one; ///< vps_num_ticks_poc_diff_one_minus1 + 1
|
||||
int vps_num_hrd_parameters;
|
||||
} VPS;
|
||||
|
||||
typedef struct ScalingList {
|
||||
// This is a little wasteful, since sizeID 0 only needs 8 coeffs, and size ID 3 only has 2 arrays, not 6.
|
||||
uint8_t sl[4][6][64];
|
||||
uint8_t sl_dc[2][6];
|
||||
} ScalingList;
|
||||
|
||||
typedef struct HEVCSPS {
|
||||
int vps_id;
|
||||
int chroma_format_idc;
|
||||
uint8_t separate_colour_plane_flag;
|
||||
|
||||
///< output (i.e. cropped) values
|
||||
int output_width, output_height;
|
||||
HEVCWindow output_window;
|
||||
|
||||
HEVCWindow pic_conf_win;
|
||||
|
||||
int bit_depth;
|
||||
int pixel_shift;
|
||||
enum AVPixelFormat pix_fmt;
|
||||
|
||||
unsigned int log2_max_poc_lsb;
|
||||
int pcm_enabled_flag;
|
||||
|
||||
int max_sub_layers;
|
||||
struct {
|
||||
int max_dec_pic_buffering;
|
||||
int num_reorder_pics;
|
||||
int max_latency_increase;
|
||||
} temporal_layer[MAX_SUB_LAYERS];
|
||||
|
||||
VUI vui;
|
||||
PTL ptl;
|
||||
|
||||
uint8_t scaling_list_enable_flag;
|
||||
ScalingList scaling_list;
|
||||
|
||||
unsigned int nb_st_rps;
|
||||
ShortTermRPS st_rps[MAX_SHORT_TERM_RPS_COUNT];
|
||||
|
||||
uint8_t amp_enabled_flag;
|
||||
uint8_t sao_enabled;
|
||||
|
||||
uint8_t long_term_ref_pics_present_flag;
|
||||
uint16_t lt_ref_pic_poc_lsb_sps[32];
|
||||
uint8_t used_by_curr_pic_lt_sps_flag[32];
|
||||
uint8_t num_long_term_ref_pics_sps;
|
||||
|
||||
struct {
|
||||
uint8_t bit_depth;
|
||||
unsigned int log2_min_pcm_cb_size;
|
||||
unsigned int log2_max_pcm_cb_size;
|
||||
uint8_t loop_filter_disable_flag;
|
||||
} pcm;
|
||||
uint8_t sps_temporal_mvp_enabled_flag;
|
||||
uint8_t sps_strong_intra_smoothing_enable_flag;
|
||||
|
||||
unsigned int log2_min_coding_block_size;
|
||||
unsigned int log2_diff_max_min_coding_block_size;
|
||||
unsigned int log2_min_transform_block_size;
|
||||
unsigned int log2_max_trafo_size;
|
||||
unsigned int log2_ctb_size;
|
||||
unsigned int log2_min_pu_size;
|
||||
|
||||
int max_transform_hierarchy_depth_inter;
|
||||
int max_transform_hierarchy_depth_intra;
|
||||
|
||||
///< coded frame dimension in various units
|
||||
int width;
|
||||
int height;
|
||||
int ctb_width;
|
||||
int ctb_height;
|
||||
int ctb_size;
|
||||
int min_cb_width;
|
||||
int min_cb_height;
|
||||
int min_tb_width;
|
||||
int min_tb_height;
|
||||
|
||||
int hshift[3];
|
||||
int vshift[3];
|
||||
|
||||
int qp_bd_offset;
|
||||
} HEVCSPS;
|
||||
|
||||
typedef struct HEVCPPS {
|
||||
int sps_id; ///< seq_parameter_set_id
|
||||
|
||||
uint8_t sign_data_hiding_flag;
|
||||
|
||||
uint8_t cabac_init_present_flag;
|
||||
|
||||
int num_ref_idx_l0_default_active; ///< num_ref_idx_l0_default_active_minus1 + 1
|
||||
int num_ref_idx_l1_default_active; ///< num_ref_idx_l1_default_active_minus1 + 1
|
||||
int pic_init_qp_minus26;
|
||||
|
||||
uint8_t constrained_intra_pred_flag;
|
||||
uint8_t transform_skip_enabled_flag;
|
||||
|
||||
uint8_t cu_qp_delta_enabled_flag;
|
||||
int diff_cu_qp_delta_depth;
|
||||
|
||||
int cb_qp_offset;
|
||||
int cr_qp_offset;
|
||||
uint8_t pic_slice_level_chroma_qp_offsets_present_flag;
|
||||
uint8_t weighted_pred_flag;
|
||||
uint8_t weighted_bipred_flag;
|
||||
uint8_t output_flag_present_flag;
|
||||
uint8_t transquant_bypass_enable_flag;
|
||||
|
||||
uint8_t dependent_slice_segments_enabled_flag;
|
||||
uint8_t tiles_enabled_flag;
|
||||
uint8_t entropy_coding_sync_enabled_flag;
|
||||
|
||||
int num_tile_columns; ///< num_tile_columns_minus1 + 1
|
||||
int num_tile_rows; ///< num_tile_rows_minus1 + 1
|
||||
uint8_t uniform_spacing_flag;
|
||||
uint8_t loop_filter_across_tiles_enabled_flag;
|
||||
|
||||
uint8_t seq_loop_filter_across_slices_enabled_flag;
|
||||
|
||||
uint8_t deblocking_filter_control_present_flag;
|
||||
uint8_t deblocking_filter_override_enabled_flag;
|
||||
uint8_t pps_disable_deblocking_filter_flag;
|
||||
int beta_offset; ///< beta_offset_div2 * 2
|
||||
int tc_offset; ///< tc_offset_div2 * 2
|
||||
|
||||
int pps_scaling_list_data_present_flag;
|
||||
ScalingList scaling_list;
|
||||
|
||||
uint8_t lists_modification_present_flag;
|
||||
int log2_parallel_merge_level; ///< log2_parallel_merge_level_minus2 + 2
|
||||
int num_extra_slice_header_bits;
|
||||
uint8_t slice_header_extension_present_flag;
|
||||
|
||||
uint8_t pps_extension_flag;
|
||||
uint8_t pps_extension_data_flag;
|
||||
|
||||
// Inferred parameters
|
||||
int *column_width; ///< ColumnWidth
|
||||
int *row_height; ///< RowHeight
|
||||
int *col_bd; ///< ColBd
|
||||
int *row_bd; ///< RowBd
|
||||
int *col_idxX;
|
||||
|
||||
int *ctb_addr_rs_to_ts; ///< CtbAddrRSToTS
|
||||
int *ctb_addr_ts_to_rs; ///< CtbAddrTSToRS
|
||||
int *tile_id; ///< TileId
|
||||
int *tile_pos_rs; ///< TilePosRS
|
||||
int *min_cb_addr_zs; ///< MinCbAddrZS
|
||||
int *min_tb_addr_zs; ///< MinTbAddrZS
|
||||
} HEVCPPS;
|
||||
|
||||
typedef struct SliceHeader {
|
||||
int pps_id;
|
||||
|
||||
///< address (in raster order) of the first block in the current slice segment
|
||||
unsigned int slice_segment_addr;
|
||||
///< address (in raster order) of the first block in the current slice
|
||||
unsigned int slice_addr;
|
||||
|
||||
enum SliceType slice_type;
|
||||
|
||||
int pic_order_cnt_lsb;
|
||||
|
||||
uint8_t first_slice_in_pic_flag;
|
||||
uint8_t dependent_slice_segment_flag;
|
||||
uint8_t pic_output_flag;
|
||||
uint8_t colour_plane_id;
|
||||
|
||||
///< RPS coded in the slice header itself is stored here
|
||||
ShortTermRPS slice_rps;
|
||||
const ShortTermRPS *short_term_rps;
|
||||
LongTermRPS long_term_rps;
|
||||
uint8_t rpl_modification_flag[2];
|
||||
unsigned int list_entry_lx[2][32];
|
||||
|
||||
uint8_t no_output_of_prior_pics_flag;
|
||||
|
||||
uint8_t slice_sample_adaptive_offset_flag[3];
|
||||
|
||||
uint8_t slice_temporal_mvp_enabled_flag;
|
||||
unsigned int nb_refs[2];
|
||||
|
||||
uint8_t mvd_l1_zero_flag;
|
||||
uint8_t cabac_init_flag;
|
||||
uint8_t collocated_list;
|
||||
unsigned int collocated_ref_idx;
|
||||
int slice_qp_delta;
|
||||
int slice_cb_qp_offset;
|
||||
int slice_cr_qp_offset;
|
||||
|
||||
uint8_t disable_deblocking_filter_flag; ///< slice_header_disable_deblocking_filter_flag
|
||||
int beta_offset; ///< beta_offset_div2 * 2
|
||||
int tc_offset; ///< tc_offset_div2 * 2
|
||||
|
||||
int max_num_merge_cand; ///< 5 - 5_minus_max_num_merge_cand
|
||||
|
||||
uint8_t slice_loop_filter_across_slices_enabled_flag;
|
||||
|
||||
int num_entry_point_offsets;
|
||||
|
||||
uint8_t luma_log2_weight_denom;
|
||||
int16_t chroma_log2_weight_denom;
|
||||
|
||||
int16_t luma_weight_l0[16];
|
||||
int16_t chroma_weight_l0[16][2];
|
||||
int16_t chroma_weight_l1[16][2];
|
||||
int16_t luma_weight_l1[16];
|
||||
|
||||
|
||||
int16_t luma_offset_l0[16];
|
||||
int16_t chroma_offset_l0[16][2];
|
||||
|
||||
int16_t luma_offset_l1[16];
|
||||
int16_t chroma_offset_l1[16][2];
|
||||
|
||||
// Inferred parameters
|
||||
int8_t slice_qp;
|
||||
int slice_ctb_addr_rs;
|
||||
} SliceHeader;
|
||||
|
||||
typedef struct CodingTree {
|
||||
int depth; ///< ctDepth
|
||||
} CodingTree;
|
||||
|
||||
typedef struct CodingUnit {
|
||||
uint8_t cu_transquant_bypass_flag;
|
||||
|
||||
enum PredMode pred_mode; ///< PredMode
|
||||
enum PartMode part_mode; ///< PartMode
|
||||
uint8_t rqt_root_cbf;
|
||||
|
||||
uint8_t pcm_flag;
|
||||
|
||||
// Inferred parameters
|
||||
uint8_t intra_split_flag; ///< IntraSplitFlag
|
||||
uint8_t max_trafo_depth; ///< MaxTrafoDepth
|
||||
|
||||
int x;
|
||||
int y;
|
||||
|
||||
} CodingUnit;
|
||||
|
||||
typedef struct Mv {
|
||||
int16_t x; ///< horizontal component of motion vector
|
||||
int16_t y; ///< vertical component of motion vector
|
||||
} Mv;
|
||||
|
||||
typedef struct MvField {
|
||||
Mv mv[2];
|
||||
int8_t ref_idx[2];
|
||||
int8_t pred_flag[2];
|
||||
uint8_t is_intra;
|
||||
} MvField;
|
||||
|
||||
typedef struct NeighbourAvailable {
|
||||
int cand_bottom_left;
|
||||
int cand_left;
|
||||
int cand_up;
|
||||
int cand_up_left;
|
||||
int cand_up_right;
|
||||
int cand_up_right_sap;
|
||||
} NeighbourAvailable;
|
||||
|
||||
typedef struct PredictionUnit {
|
||||
uint8_t merge_flag;
|
||||
int mpm_idx;
|
||||
int rem_intra_luma_pred_mode;
|
||||
uint8_t intra_pred_mode[4];
|
||||
uint8_t intra_pred_mode_c;
|
||||
Mv mvd;
|
||||
} PredictionUnit;
|
||||
|
||||
typedef struct TransformTree {
|
||||
uint8_t cbf_cb[MAX_TRANSFORM_DEPTH][MAX_CU_SIZE * MAX_CU_SIZE];
|
||||
uint8_t cbf_cr[MAX_TRANSFORM_DEPTH][MAX_CU_SIZE * MAX_CU_SIZE];
|
||||
uint8_t cbf_luma;
|
||||
|
||||
// Inferred parameters
|
||||
uint8_t inter_split_flag;
|
||||
} TransformTree;
|
||||
|
||||
typedef struct TransformUnit {
|
||||
int cu_qp_delta;
|
||||
|
||||
// Inferred parameters;
|
||||
uint8_t is_cu_qp_delta_coded;
|
||||
int cur_intra_pred_mode;
|
||||
} TransformUnit;
|
||||
|
||||
typedef struct ResidualCoding {
|
||||
uint8_t significant_coeff_group_flag[8][8];
|
||||
} ResidualCoding;
|
||||
|
||||
typedef struct SAOParams {
|
||||
uint8_t type_idx[3]; ///< sao_type_idx
|
||||
|
||||
int offset_abs[3][4]; ///< sao_offset_abs
|
||||
int offset_sign[3][4]; ///< sao_offset_sign
|
||||
|
||||
int band_position[3]; ///< sao_band_position
|
||||
|
||||
int eo_class[3]; ///< sao_eo_class
|
||||
|
||||
// Inferred parameters
|
||||
int offset_val[3][5]; ///<SaoOffsetVal
|
||||
} SAOParams;
|
||||
|
||||
typedef struct DBParams {
|
||||
uint8_t disable;
|
||||
int beta_offset;
|
||||
int tc_offset;
|
||||
} DBParams;
|
||||
|
||||
#define HEVC_FRAME_FLAG_OUTPUT (1 << 0)
|
||||
#define HEVC_FRAME_FLAG_SHORT_REF (1 << 1)
|
||||
#define HEVC_FRAME_FLAG_LONG_REF (1 << 2)
|
||||
|
||||
typedef struct HEVCFrame {
|
||||
AVFrame *frame;
|
||||
ThreadFrame tf;
|
||||
int poc;
|
||||
MvField *tab_mvf;
|
||||
RefPicList *refPicList;
|
||||
RefPicListTab **rpl_tab;
|
||||
int ctb_count;
|
||||
struct HEVCFrame *collocated_ref;
|
||||
|
||||
/**
|
||||
* A combination of HEVC_FRAME_FLAG_*
|
||||
*/
|
||||
uint8_t flags;
|
||||
|
||||
/**
|
||||
* A sequence counter, so that old frames are output first
|
||||
* after a POC reset
|
||||
*/
|
||||
uint16_t sequence;
|
||||
|
||||
HEVCWindow window;
|
||||
|
||||
AVBufferRef *tab_mvf_buf;
|
||||
AVBufferRef *rpl_tab_buf;
|
||||
AVBufferRef *rpl_buf;
|
||||
} HEVCFrame;
|
||||
|
||||
typedef struct FilterData {
|
||||
int x;
|
||||
int y;
|
||||
int size;
|
||||
int slice_or_tiles_left_boundary;
|
||||
int slice_or_tiles_up_boundary;
|
||||
} FilterData;
|
||||
|
||||
typedef struct HEVCNAL {
|
||||
uint8_t *rbsp_buffer;
|
||||
int rbsp_buffer_size;
|
||||
const uint8_t *data;
|
||||
int size;
|
||||
} HEVCNAL;
|
||||
|
||||
typedef struct HEVCLocalContext {
|
||||
uint8_t cabac_state[HEVC_CONTEXTS];
|
||||
int ctx_set;
|
||||
int greater1_ctx;
|
||||
int last_coeff_abs_level_greater1_flag;
|
||||
int c_rice_param;
|
||||
int last_coeff_abs_level_remaining;
|
||||
GetBitContext gb;
|
||||
CABACContext cc;
|
||||
TransformTree tt;
|
||||
TransformUnit tu;
|
||||
ResidualCoding rc;
|
||||
uint8_t first_qp_group;
|
||||
int8_t qp_y;
|
||||
int8_t curr_qp_y;
|
||||
uint8_t slice_or_tiles_left_boundary;
|
||||
uint8_t slice_or_tiles_up_boundary;
|
||||
uint8_t ctb_left_flag;
|
||||
uint8_t ctb_up_flag;
|
||||
uint8_t ctb_up_right_flag;
|
||||
uint8_t ctb_up_left_flag;
|
||||
int start_of_tiles_x;
|
||||
int end_of_tiles_x;
|
||||
int end_of_tiles_y;
|
||||
uint8_t *edge_emu_buffer;
|
||||
int edge_emu_buffer_size;
|
||||
CodingTree ct;
|
||||
CodingUnit cu;
|
||||
PredictionUnit pu;
|
||||
NeighbourAvailable na;
|
||||
DECLARE_ALIGNED(16, int16_t, mc_buffer[(MAX_PB_SIZE + 7) * MAX_PB_SIZE]);
|
||||
FilterData *save_boundary_strengths;
|
||||
int nb_saved;
|
||||
} HEVCLocalContext;
|
||||
|
||||
typedef struct HEVCContext {
|
||||
const AVClass *c; // needed by private avoptions
|
||||
AVCodecContext *avctx;
|
||||
|
||||
HEVCLocalContext HEVClc;
|
||||
|
||||
int disable_au;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
uint8_t cabac_state[HEVC_CONTEXTS];
|
||||
|
||||
AVFrame *frame;
|
||||
AVFrame *sao_frame;
|
||||
AVFrame *tmp_frame;
|
||||
AVFrame *output_frame;
|
||||
VPS *vps;
|
||||
const HEVCSPS *sps;
|
||||
HEVCPPS *pps;
|
||||
VPS *vps_list[MAX_VPS_COUNT];
|
||||
AVBufferRef *sps_list[MAX_SPS_COUNT];
|
||||
AVBufferRef *pps_list[MAX_PPS_COUNT];
|
||||
|
||||
///< candidate references for the current frame
|
||||
RefPicList rps[5];
|
||||
|
||||
SliceHeader sh;
|
||||
SAOParams *sao;
|
||||
DBParams *deblock;
|
||||
enum NALUnitType nal_unit_type;
|
||||
int temporal_id; ///< temporal_id_plus1 - 1
|
||||
HEVCFrame *ref;
|
||||
HEVCFrame DPB[32];
|
||||
int poc;
|
||||
int pocTid0;
|
||||
int slice_idx; ///< number of the slice being currently decoded
|
||||
int eos; ///< current packet contains an EOS/EOB NAL
|
||||
int max_ra;
|
||||
int bs_width;
|
||||
int bs_height;
|
||||
|
||||
int is_decoded;
|
||||
|
||||
HEVCPredContext hpc;
|
||||
HEVCDSPContext hevcdsp;
|
||||
VideoDSPContext vdsp;
|
||||
DSPContext dsp;
|
||||
int8_t *qp_y_tab;
|
||||
uint8_t *split_cu_flag;
|
||||
uint8_t *horizontal_bs;
|
||||
uint8_t *vertical_bs;
|
||||
|
||||
int32_t *tab_slice_address;
|
||||
|
||||
// CU
|
||||
uint8_t *skip_flag;
|
||||
uint8_t *tab_ct_depth;
|
||||
// PU
|
||||
uint8_t *tab_ipm;
|
||||
|
||||
|
||||
uint8_t *cbf_luma; // cbf_luma of colocated TU
|
||||
uint8_t *is_pcm;
|
||||
|
||||
// CTB-level flags affecting loop filter operation
|
||||
uint8_t *filter_slice_edges;
|
||||
|
||||
/** used on BE to byteswap the lines for checksumming */
|
||||
uint8_t *checksum_buf;
|
||||
int checksum_buf_size;
|
||||
|
||||
/**
|
||||
* Sequence counters for decoded and output frames, so that old
|
||||
* frames are output first after a POC reset
|
||||
*/
|
||||
uint16_t seq_decode;
|
||||
uint16_t seq_output;
|
||||
|
||||
HEVCNAL *nals;
|
||||
int nb_nals;
|
||||
int nals_allocated;
|
||||
|
||||
int nuh_layer_id;
|
||||
|
||||
// for checking the frame checksums
|
||||
struct AVMD5 *md5_ctx;
|
||||
uint8_t md5[3][16];
|
||||
uint8_t is_md5;
|
||||
|
||||
/** 1 if the independent slice segment header was successfully parsed */
|
||||
uint8_t slice_initialized;
|
||||
int strict_def_disp_win;
|
||||
|
||||
int context_initialized;
|
||||
int is_nalff; ///< this flag is != 0 if bitstream is encapsulated
|
||||
///< as a format defined in 14496-15
|
||||
int nal_length_size; ///< Number of bytes used for nal length (1, 2 or 4)
|
||||
|
||||
|
||||
AVBufferPool *tab_mvf_pool;
|
||||
AVBufferPool *rpl_tab_pool;
|
||||
} HEVCContext;
|
||||
|
||||
int ff_hevc_decode_short_term_rps(HEVCContext *s, ShortTermRPS *rps,
|
||||
const HEVCSPS *sps, int is_slice_header);
|
||||
int ff_hevc_decode_nal_vps(HEVCContext *s);
|
||||
int ff_hevc_decode_nal_sps(HEVCContext *s);
|
||||
int ff_hevc_decode_nal_pps(HEVCContext *s);
|
||||
int ff_hevc_decode_nal_sei(HEVCContext *s);
|
||||
|
||||
/**
|
||||
* Mark all frames in DPB as unused for reference.
|
||||
*/
|
||||
void ff_hevc_clear_refs(HEVCContext *s);
|
||||
|
||||
/**
|
||||
* Drop all frames currently in DPB.
|
||||
*/
|
||||
void ff_hevc_flush_dpb(HEVCContext *s);
|
||||
|
||||
/**
|
||||
* Compute POC of the current frame and return it.
|
||||
*/
|
||||
int ff_hevc_compute_poc(HEVCContext *s, int poc_lsb);
|
||||
|
||||
RefPicList* ff_hevc_get_ref_list(HEVCContext *s, HEVCFrame *frame, int x0, int y0);
|
||||
|
||||
/**
|
||||
* Construct the reference picture sets for the current frame.
|
||||
*/
|
||||
int ff_hevc_frame_rps(HEVCContext *s);
|
||||
|
||||
/**
|
||||
* Construct the reference picture list(s) for the current slice.
|
||||
*/
|
||||
int ff_hevc_slice_rpl(HEVCContext *s);
|
||||
|
||||
void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts);
|
||||
void ff_hevc_cabac_init(HEVCContext *s, int ctb_addr_ts);
|
||||
int ff_hevc_sao_merge_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_sao_type_idx_decode(HEVCContext *s);
|
||||
int ff_hevc_sao_band_position_decode(HEVCContext *s);
|
||||
int ff_hevc_sao_offset_abs_decode(HEVCContext *s);
|
||||
int ff_hevc_sao_offset_sign_decode(HEVCContext *s);
|
||||
int ff_hevc_sao_eo_class_decode(HEVCContext *s);
|
||||
int ff_hevc_end_of_slice_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_cu_transquant_bypass_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_skip_flag_decode(HEVCContext *s, int x0, int y0, int x_cb, int y_cb);
|
||||
int ff_hevc_pred_mode_decode(HEVCContext *s);
|
||||
int ff_hevc_split_coding_unit_flag_decode(HEVCContext *s, int ct_depth, int x0, int y0);
|
||||
int ff_hevc_part_mode_decode(HEVCContext *s, int log2_cb_size);
|
||||
int ff_hevc_pcm_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_prev_intra_luma_pred_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_mpm_idx_decode(HEVCContext *s);
|
||||
int ff_hevc_rem_intra_luma_pred_mode_decode(HEVCContext *s);
|
||||
int ff_hevc_intra_chroma_pred_mode_decode(HEVCContext *s);
|
||||
int ff_hevc_merge_idx_decode(HEVCContext *s);
|
||||
int ff_hevc_merge_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_inter_pred_idc_decode(HEVCContext *s, int nPbW, int nPbH);
|
||||
int ff_hevc_ref_idx_lx_decode(HEVCContext *s, int num_ref_idx_lx);
|
||||
int ff_hevc_mvp_lx_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_no_residual_syntax_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_abs_mvd_greater0_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_abs_mvd_greater1_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_mvd_decode(HEVCContext *s);
|
||||
int ff_hevc_mvd_sign_flag_decode(HEVCContext *s);
|
||||
int ff_hevc_split_transform_flag_decode(HEVCContext *s, int log2_trafo_size);
|
||||
int ff_hevc_cbf_cb_cr_decode(HEVCContext *s, int trafo_depth);
|
||||
int ff_hevc_cbf_luma_decode(HEVCContext *s, int trafo_depth);
|
||||
int ff_hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx);
|
||||
int ff_hevc_last_significant_coeff_x_prefix_decode(HEVCContext *s, int c_idx,
|
||||
int log2_size);
|
||||
int ff_hevc_last_significant_coeff_y_prefix_decode(HEVCContext *s, int c_idx,
|
||||
int log2_size);
|
||||
int ff_hevc_last_significant_coeff_suffix_decode(HEVCContext *s,
|
||||
int last_significant_coeff_prefix);
|
||||
int ff_hevc_significant_coeff_group_flag_decode(HEVCContext *s, int c_idx, int x_cg,
|
||||
int y_cg, int log2_trafo_size);
|
||||
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 ff_hevc_coeff_abs_level_greater1_flag_decode(HEVCContext *s, int c_idx,
|
||||
int i, int n,
|
||||
int first_greater1_coeff_idx,
|
||||
int first_subset);
|
||||
int ff_hevc_coeff_abs_level_greater2_flag_decode(HEVCContext *s, int c_idx,
|
||||
int i, int n);
|
||||
int ff_hevc_coeff_abs_level_remaining(HEVCContext *s, int n, int base_level);
|
||||
int ff_hevc_coeff_sign_flag(HEVCContext *s, uint8_t nb);
|
||||
|
||||
/**
|
||||
* Get the number of candidate references for the current frame.
|
||||
*/
|
||||
int ff_hevc_frame_nb_refs(HEVCContext *s);
|
||||
|
||||
int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc);
|
||||
|
||||
/**
|
||||
* Find next frame in output order and put a reference to it in frame.
|
||||
* @return 1 if a frame was output, 0 otherwise
|
||||
*/
|
||||
int ff_hevc_output_frame(HEVCContext *s, AVFrame *frame, int flush);
|
||||
|
||||
void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags);
|
||||
|
||||
void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0, int nPbW, int nPbH);
|
||||
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);
|
||||
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);
|
||||
void ff_hevc_set_qPy(HEVCContext *s, int xC, int yC, int xBase, int yBase, int log2_cb_size);
|
||||
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);
|
||||
int ff_hevc_cu_qp_delta_sign_flag(HEVCContext *s);
|
||||
int ff_hevc_cu_qp_delta_abs(HEVCContext *s);
|
||||
void ff_hevc_hls_filter(HEVCContext *s, int x, int y);
|
||||
void ff_hevc_hls_filters(HEVCContext *s, int x_ctb, int y_ctb, int ctb_size);
|
||||
|
||||
void ff_hevc_pps_free(HEVCPPS **ppps);
|
||||
|
||||
extern const uint8_t ff_hevc_qpel_extra_before[4];
|
||||
extern const uint8_t ff_hevc_qpel_extra_after[4];
|
||||
extern const uint8_t ff_hevc_qpel_extra[4];
|
||||
|
||||
extern const uint8_t ff_hevc_diag_scan4x4_x[16];
|
||||
extern const uint8_t ff_hevc_diag_scan4x4_y[16];
|
||||
extern const uint8_t ff_hevc_diag_scan8x8_x[64];
|
||||
extern const uint8_t ff_hevc_diag_scan8x8_y[64];
|
||||
|
||||
#endif // AVCODEC_HEVC_H
|
928
libavcodec/hevc_cabac.c
Normal file
928
libavcodec/hevc_cabac.c
Normal file
@ -0,0 +1,928 @@
|
||||
/*
|
||||
* HEVC CABAC decoding
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Guillaume Martres
|
||||
* Copyright (C) 2012 - 2013 Gildas Cocherel
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; 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 pic_width_in_ctb = s->sps->width >> s->sps->log2_min_coding_block_size;
|
||||
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_coding_block_size;
|
||||
int y_cb = y0 >> s->sps->log2_min_coding_block_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_coding_block_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 x_cg,
|
||||
int y_cg, int log2_trafo_size)
|
||||
{
|
||||
int ctx_cg = 0;
|
||||
int inc;
|
||||
|
||||
if (x_cg < (1 << (log2_trafo_size - 2)) - 1)
|
||||
ctx_cg += s->HEVClc.rc.significant_coeff_group_flag[x_cg + 1][y_cg];
|
||||
if (y_cg < (1 << (log2_trafo_size - 2)) - 1)
|
||||
ctx_cg += s->HEVClc.rc.significant_coeff_group_flag[x_cg][y_cg + 1];
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
int 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 {
|
||||
int prev_sig = 0;
|
||||
|
||||
if (x_cg < ((1 << log2_trafo_size) - 1) >> 2)
|
||||
prev_sig += s->HEVClc.rc.significant_coeff_group_flag[x_cg + 1][y_cg];
|
||||
if (y_cg < ((1 << log2_trafo_size) - 1) >> 2)
|
||||
prev_sig += (s->HEVClc.rc.significant_coeff_group_flag[x_cg][y_cg + 1] << 1);
|
||||
|
||||
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 i, int n,
|
||||
int first_elem,
|
||||
int first_subset)
|
||||
{
|
||||
|
||||
int inc;
|
||||
|
||||
if (first_elem) {
|
||||
s->HEVClc.ctx_set = (i > 0 && c_idx == 0) ? 2 : 0;
|
||||
|
||||
if (!first_subset && s->HEVClc.greater1_ctx == 0)
|
||||
s->HEVClc.ctx_set++;
|
||||
s->HEVClc.greater1_ctx = 1;
|
||||
}
|
||||
|
||||
inc = (s->HEVClc.ctx_set << 2) + s->HEVClc.greater1_ctx;
|
||||
if (c_idx > 0)
|
||||
inc += 16;
|
||||
|
||||
s->HEVClc.last_coeff_abs_level_greater1_flag =
|
||||
GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER1_FLAG] + inc);
|
||||
|
||||
if (s->HEVClc.last_coeff_abs_level_greater1_flag) {
|
||||
s->HEVClc.greater1_ctx = 0;
|
||||
} else if (s->HEVClc.greater1_ctx > 0 && s->HEVClc.greater1_ctx < 3) {
|
||||
s->HEVClc.greater1_ctx++;
|
||||
}
|
||||
|
||||
return s->HEVClc.last_coeff_abs_level_greater1_flag;
|
||||
}
|
||||
|
||||
int ff_hevc_coeff_abs_level_greater2_flag_decode(HEVCContext *s, int c_idx,
|
||||
int i, int n)
|
||||
{
|
||||
int inc;
|
||||
|
||||
inc = s->HEVClc.ctx_set;
|
||||
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 first_elem, int base_level)
|
||||
{
|
||||
int i;
|
||||
HEVCLocalContext *lc = &s->HEVClc;
|
||||
int prefix = 0;
|
||||
int suffix = 0;
|
||||
|
||||
if (first_elem) {
|
||||
lc->c_rice_param = 0;
|
||||
lc->last_coeff_abs_level_remaining = 0;
|
||||
}
|
||||
|
||||
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 < lc->c_rice_param; i++)
|
||||
suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc.cc);
|
||||
lc->last_coeff_abs_level_remaining = (prefix << lc->c_rice_param) + suffix;
|
||||
} else {
|
||||
for (i = 0; i < prefix - 3 + lc->c_rice_param; i++)
|
||||
suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc.cc);
|
||||
lc->last_coeff_abs_level_remaining = (((1 << (prefix - 3)) + 3 - 1)
|
||||
<< lc->c_rice_param) + suffix;
|
||||
}
|
||||
|
||||
lc->c_rice_param = FFMIN(lc->c_rice_param +
|
||||
((base_level + lc->last_coeff_abs_level_remaining) >
|
||||
(3 * (1 << lc->c_rice_param))), 4);
|
||||
|
||||
return lc->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;
|
||||
}
|
698
libavcodec/hevc_filter.c
Normal file
698
libavcodec/hevc_filter.c
Normal file
@ -0,0 +1,698 @@
|
||||
/*
|
||||
* HEVC video Decoder
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Guillaume Martres
|
||||
* Copyright (C) 2013 Seppo Tomperi
|
||||
* Copyright (C) 2013 Wassim Hamidouche
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; 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"
|
||||
#include "bit_depth_template.c"
|
||||
|
||||
#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_i, offset;
|
||||
int qp;
|
||||
int 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 pic_width = s->sps->width >> s->sps->log2_min_coding_block_size;
|
||||
int pic_height = s->sps->height >> s->sps->log2_min_coding_block_size;
|
||||
int x_cb = xQgBase >> s->sps->log2_min_coding_block_size;
|
||||
int y_cb = yQgBase >> s->sps->log2_min_coding_block_size;
|
||||
int availableA = (xBase & ctb_size_mask) && (xQgBase & ctb_size_mask);
|
||||
int availableB = (yBase & ctb_size_mask) && (yQgBase & ctb_size_mask);
|
||||
int qPy_pred;
|
||||
int qPy_a;
|
||||
int 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_coding_block_size;
|
||||
int yC0b = (yC - (yC & ctb_size_mask)) >> s->sps->log2_min_coding_block_size;
|
||||
int idxX = (xQgBase & ctb_size_mask) >> s->sps->log2_min_coding_block_size;
|
||||
int idxY = (yQgBase & ctb_size_mask) >> s->sps->log2_min_coding_block_size;
|
||||
int idx_mask = ctb_size_mask >> s->sps->log2_min_coding_block_size;
|
||||
int x, y;
|
||||
|
||||
x = FFMIN(xC0b + offsetX[idxX][idxY], pic_width - 1);
|
||||
y = FFMIN(yC0b + (offsetY[idxX][idxY] & idx_mask), pic_height - 1);
|
||||
|
||||
if (xC0b == (lc->start_of_tiles_x >> s->sps->log2_min_coding_block_size) &&
|
||||
offsetX[idxX][idxY] == -1) {
|
||||
x = (lc->end_of_tiles_x >> s->sps->log2_min_coding_block_size) - 1;
|
||||
y = yC0b - 1;
|
||||
}
|
||||
qPy_pred = s->qp_y_tab[y * pic_width + x];
|
||||
}
|
||||
}
|
||||
|
||||
// qPy_a
|
||||
if (availableA == 0)
|
||||
qPy_a = qPy_pred;
|
||||
else
|
||||
qPy_a = s->qp_y_tab[(x_cb - 1) + y_cb * pic_width];
|
||||
|
||||
// qPy_b
|
||||
if (availableB == 0)
|
||||
qPy_b = qPy_pred;
|
||||
else
|
||||
qPy_b = s->qp_y_tab[x_cb + (y_cb - 1) * pic_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_coding_block_size;
|
||||
int pic_width = s->sps->width>>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 * pic_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, int c_idx_min, int c_idx_max)
|
||||
{
|
||||
// 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;
|
||||
uint8_t 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 && c_idx >= c_idx_min &&
|
||||
c_idx < c_idx_max; 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 pic_width_in_min_pu = s->sps->width >> s->sps->log2_min_pu_size;
|
||||
int pic_height_in_min_pu = s->sps->height >> 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 >= pic_width_in_min_pu || y < 0 || y_pu >= pic_height_in_min_pu)
|
||||
return 2;
|
||||
return s->is_pcm[y_pu * pic_width_in_min_pu + 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;
|
||||
int chroma;
|
||||
int c_tc[2];
|
||||
int beta[2];
|
||||
int tc[2];
|
||||
uint8_t no_p[2] = {0};
|
||||
uint8_t no_q[2] = {0};
|
||||
|
||||
int log2_ctb_size = s->sps->log2_ctb_size;
|
||||
int x_end, y_end;
|
||||
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 left_tc_offset, left_beta_offset;
|
||||
int tc_offset, beta_offset;
|
||||
int pcmf = (s->sps->pcm_enabled_flag && s->sps->pcm.loop_filter_disable_flag) ||
|
||||
s->pps->transquant_bypass_enable_flag;
|
||||
|
||||
if (s->deblock[ctb].disable)
|
||||
return;
|
||||
|
||||
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;
|
||||
int 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_transform_block_size;
|
||||
int pic_width_in_min_pu = s->sps->width >> log2_min_pu_size;
|
||||
int pic_width_in_min_tu = s->sps->width >> log2_min_tu_size;
|
||||
int is_intra = tab_mvf[(y0 >> log2_min_pu_size) * pic_width_in_min_pu + (x0 >> log2_min_pu_size)].is_intra;
|
||||
|
||||
int i, j;
|
||||
int 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 * pic_width_in_min_pu + x_pu];
|
||||
MvField *curr = &tab_mvf[yq_pu * pic_width_in_min_pu + x_pu];
|
||||
uint8_t top_cbf_luma = s->cbf_luma[yp_tu * pic_width_in_min_tu + x_tu];
|
||||
uint8_t curr_cbf_luma = s->cbf_luma[yq_tu * pic_width_in_min_tu + 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 * pic_width_in_min_pu + x_pu];
|
||||
MvField *curr = &tab_mvf[yq_pu * pic_width_in_min_pu + x_pu];
|
||||
uint8_t top_cbf_luma = s->cbf_luma[yp_tu * pic_width_in_min_tu + x_tu];
|
||||
uint8_t curr_cbf_luma = s->cbf_luma[yq_tu * pic_width_in_min_tu + 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 * pic_width_in_min_pu + xp_pu];
|
||||
MvField *curr = &tab_mvf[y_pu * pic_width_in_min_pu + xq_pu];
|
||||
|
||||
uint8_t left_cbf_luma = s->cbf_luma[y_tu * pic_width_in_min_tu + xp_tu];
|
||||
uint8_t curr_cbf_luma = s->cbf_luma[y_tu * pic_width_in_min_tu + 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 > s->sps->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 * pic_width_in_min_pu + xp_pu];
|
||||
MvField *curr = &tab_mvf[y_pu * pic_width_in_min_pu + xq_pu];
|
||||
uint8_t left_cbf_luma = s->cbf_luma[y_tu * pic_width_in_min_tu + xp_tu];
|
||||
uint8_t curr_cbf_luma = s->cbf_luma[y_tu * pic_width_in_min_tu + 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)
|
||||
{
|
||||
int c_idx_min = s->sh.slice_sample_adaptive_offset_flag[0] != 0 ? 0 : 1;
|
||||
int c_idx_max = s->sh.slice_sample_adaptive_offset_flag[1] != 0 ? 3 : 1;
|
||||
deblocking_filter_CTB(s, x, y);
|
||||
if (s->sps->sao_enabled)
|
||||
sao_filter_CTB(s, x, y, c_idx_min, c_idx_max);
|
||||
}
|
||||
|
||||
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);
|
||||
if (x_ctb && y_ctb >= s->sps->height - ctb_size)
|
||||
ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb);
|
||||
}
|
1011
libavcodec/hevc_mvs.c
Normal file
1011
libavcodec/hevc_mvs.c
Normal file
File diff suppressed because it is too large
Load Diff
125
libavcodec/hevc_parser.c
Normal file
125
libavcodec/hevc_parser.c
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* HEVC Annex B format parser
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Guillaume Martres
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; 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,
|
||||
};
|
1242
libavcodec/hevc_ps.c
Normal file
1242
libavcodec/hevc_ps.c
Normal file
File diff suppressed because it is too large
Load Diff
481
libavcodec/hevc_refs.c
Normal file
481
libavcodec/hevc_refs.c
Normal file
@ -0,0 +1,481 @@
|
||||
/*
|
||||
* HEVC video Decoder
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Guillaume Martres
|
||||
* Copyright (C) 2012 - 2013 Gildas Cocherel
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; 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 "internal.h"
|
||||
#include "thread.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)
|
||||
{
|
||||
int nb_output = 0;
|
||||
int min_poc = 0xFFFF;
|
||||
int i, j, min_idx, ret;
|
||||
|
||||
do {
|
||||
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->temporal_id].num_reorder_pics)
|
||||
return 0;
|
||||
|
||||
if (nb_output) {
|
||||
HEVCFrame *frame = &s->DPB[min_idx];
|
||||
AVFrame *dst = out;
|
||||
AVFrame *src = frame->frame;
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(src->format);
|
||||
int pixel_shift = !!(desc->comp[0].depth_minus1 > 7);
|
||||
|
||||
ret = av_frame_ref(out, src);
|
||||
ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
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) * dst->linesize[j];
|
||||
dst->data[j] += 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; 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->height >> s->sps->vshift[i]); y++)
|
||||
for (x = 0; x < (s->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)
|
||||
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;
|
||||
}
|
129
libavcodec/hevc_sei.c
Normal file
129
libavcodec/hevc_sei.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "hevc.h"
|
||||
#include "golomb.h"
|
||||
|
||||
static void decode_nal_sei_decoded_picture_hash(HEVCContext *s, int payload_size)
|
||||
{
|
||||
int cIdx, i;
|
||||
uint8_t hash_type;
|
||||
//uint16_t picture_crc;
|
||||
//uint32_t picture_checksum;
|
||||
GetBitContext *gb = &s->HEVClc.gb;
|
||||
hash_type = get_bits(gb, 8);
|
||||
|
||||
|
||||
for( cIdx = 0; cIdx < 3/*((s->sps->chroma_format_idc == 0) ? 1 : 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 /*&& s->decode_checksum_sei*/)
|
||||
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 /* && s->decode_checksum_sei */)
|
||||
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;
|
||||
}
|
192
libavcodec/hevcdsp.c
Normal file
192
libavcodec/hevcdsp.c
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* HEVC video Decoder
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Guillaume Martres
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "hevc.h"
|
||||
#include "hevcdsp.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;
|
||||
}
|
||||
}
|
77
libavcodec/hevcdsp.h
Normal file
77
libavcodec/hevcdsp.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* HEVC video Decoder
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Guillaume Martres
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_HEVCDSP_H
|
||||
#define AVCODEC_HEVCDSP_H
|
||||
|
||||
#include "get_bits.h"
|
||||
|
||||
struct SAOParams;
|
||||
|
||||
typedef struct HEVCDSPContext {
|
||||
void (*put_pcm)(uint8_t *_dst, ptrdiff_t _stride, int size,
|
||||
GetBitContext *gb, int pcm_bit_depth);
|
||||
|
||||
void (*transquant_bypass[4])(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride);
|
||||
|
||||
void (*transform_skip)(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
|
||||
|
||||
void (*transform_4x4_luma_add)(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
|
||||
|
||||
void (*transform_add[4])(uint8_t *dst, int16_t *coeffs, ptrdiff_t _stride);
|
||||
|
||||
void (*sao_band_filter[4])( uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride, struct SAOParams *sao, int *borders, int width, int height, int c_idx);
|
||||
|
||||
void (*sao_edge_filter[4])(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride, struct SAOParams *sao, int *borders, int _width, int _height, int c_idx, uint8_t vert_edge, uint8_t horiz_edge, uint8_t diag_edge);
|
||||
|
||||
|
||||
void (*put_hevc_qpel[4][4])(int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
|
||||
int width, int height, int16_t* mcbuffer);
|
||||
|
||||
void (*put_hevc_epel[2][2])(int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
|
||||
int width, int height, int mx, int my, int16_t* mcbuffer);
|
||||
|
||||
void (*put_unweighted_pred)(uint8_t *dst, ptrdiff_t dststride, int16_t *src, ptrdiff_t srcstride,
|
||||
int width, int height);
|
||||
|
||||
void (*put_weighted_pred_avg)(uint8_t *dst, ptrdiff_t dststride, int16_t *src1, int16_t *src2,
|
||||
ptrdiff_t srcstride, int width, int height);
|
||||
void (*weighted_pred)(uint8_t denom, int16_t wlxFlag, int16_t olxFlag, uint8_t *dst, ptrdiff_t dststride, int16_t *src,
|
||||
ptrdiff_t srcstride, int width, int height);
|
||||
void (*weighted_pred_avg)(uint8_t denom, int16_t wl0Flag, int16_t wl1Flag, int16_t ol0Flag, int16_t ol1Flag,
|
||||
uint8_t *dst, ptrdiff_t dststride, int16_t *src1, int16_t *src2,
|
||||
ptrdiff_t srcstride, int width, int height);
|
||||
void (*hevc_h_loop_filter_luma)(uint8_t *_pix, ptrdiff_t _stride, int *_beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
|
||||
void (*hevc_v_loop_filter_luma)(uint8_t *_pix, ptrdiff_t _stride, int *_beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
|
||||
void (*hevc_h_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
|
||||
void (*hevc_v_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
|
||||
void (*hevc_h_loop_filter_luma_c)(uint8_t *_pix, ptrdiff_t _stride, int *_beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
|
||||
void (*hevc_v_loop_filter_luma_c)(uint8_t *_pix, ptrdiff_t _stride, int *_beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
|
||||
void (*hevc_h_loop_filter_chroma_c)(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
|
||||
void (*hevc_v_loop_filter_chroma_c)(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
|
||||
} HEVCDSPContext;
|
||||
|
||||
void ff_hevc_dsp_init(HEVCDSPContext *hpc, int bit_depth);
|
||||
|
||||
extern const int8_t ff_hevc_epel_filters[7][16];
|
||||
|
||||
#endif /* AVCODEC_HEVCDSP_H */
|
1366
libavcodec/hevcdsp_template.c
Normal file
1366
libavcodec/hevcdsp_template.c
Normal file
File diff suppressed because it is too large
Load Diff
66
libavcodec/hevcpred.c
Normal file
66
libavcodec/hevcpred.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* HEVC video Decoder
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Guillaume Martres
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "hevc.h"
|
||||
#include "hevcpred.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;
|
||||
}
|
||||
}
|
40
libavcodec/hevcpred.h
Normal file
40
libavcodec/hevcpred.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* HEVC video Decoder
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Guillaume Martres
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_HEVCPRED_H
|
||||
#define AVCODEC_HEVCPRED_H
|
||||
|
||||
struct HEVCContext;
|
||||
|
||||
typedef struct HEVCPredContext {
|
||||
void (*intra_pred)(struct HEVCContext *s, int x0, int y0, int log2_size, int c_idx);
|
||||
|
||||
void(*pred_planar[4])(uint8_t *src, const uint8_t *top, const uint8_t *left, ptrdiff_t stride);
|
||||
void(*pred_dc)(uint8_t *src, const uint8_t *top, const uint8_t *left, ptrdiff_t stride,
|
||||
int log2_size, int c_idx);
|
||||
void(*pred_angular[4])(uint8_t *src, const uint8_t *top, const uint8_t *left, ptrdiff_t stride,
|
||||
int c_idx, int mode);
|
||||
} HEVCPredContext;
|
||||
|
||||
void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth);
|
||||
|
||||
#endif /* AVCODEC_HEVCPRED_H */
|
533
libavcodec/hevcpred_template.c
Normal file
533
libavcodec/hevcpred_template.c
Normal file
@ -0,0 +1,533 @@
|
||||
/*
|
||||
* HEVC video Decoder
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Guillaume Martres
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/pixdesc.h"
|
||||
#include "bit_depth_template.c"
|
||||
#include "hevcpred.h"
|
||||
|
||||
#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) * pic_width_in_min_pu])
|
||||
#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 || !s->pps->constrained_intra_pred_flag)
|
||||
#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_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_transform_block_size;
|
||||
int x = x0 >> hshift;
|
||||
int y = y0 >> vshift;
|
||||
int x_tb = x0 >> s->sps->log2_min_transform_block_size;
|
||||
int y_tb = y0 >> s->sps->log2_min_transform_block_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 pic_width_in_min_pu = PU(s->sps->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);
|
||||
cand_bottom_left = 0;
|
||||
for(i = 0; i < size_in_luma_pu; 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);
|
||||
cand_left = 0;
|
||||
for(i = 0; i < size_in_luma_pu; 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);
|
||||
cand_up = 0;
|
||||
for(i = 0; i < size_in_luma_pu; 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);
|
||||
cand_up_right = 0;
|
||||
for(i = 0; i < size_in_luma_pu; 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))
|
||||
left[i] = POS(-1, size + bottom_left_size - 1);
|
||||
for (i = size + bottom_left_size - 1; i >= size; i--)
|
||||
if (IS_INTRA(-1, i))
|
||||
left[i] = POS(-1, i);
|
||||
}
|
||||
if (cand_left)
|
||||
for (i = size - 1; i >= 0; i--)
|
||||
if (IS_INTRA(-1, i))
|
||||
left[i] = POS(-1, i);
|
||||
if (cand_up_left)
|
||||
if (IS_INTRA(-1, -1)) {
|
||||
left[-1] = POS(-1, -1);
|
||||
top[-1] = left[-1];
|
||||
}
|
||||
if (cand_up)
|
||||
for (i = size - 1; i >= 0; i--)
|
||||
if (IS_INTRA(i, -1))
|
||||
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))
|
||||
top[i] = POS(size + top_right_size - 1, -1);
|
||||
for (i = size + top_right_size - 1; i >= size; i--)
|
||||
if (IS_INTRA(i, -1))
|
||||
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_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)
|
||||
EXTEND_LEFT_CIP(top, j, j+1);
|
||||
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 {
|
||||
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];
|
||||
|
||||
#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
|
||||
|
||||
// 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 POS
|
@ -29,7 +29,7 @@
|
||||
#include "libavutil/avutil.h"
|
||||
|
||||
#define LIBAVCODEC_VERSION_MAJOR 55
|
||||
#define LIBAVCODEC_VERSION_MINOR 36
|
||||
#define LIBAVCODEC_VERSION_MINOR 37
|
||||
#define LIBAVCODEC_VERSION_MICRO 100
|
||||
|
||||
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
||||
|
Loading…
Reference in New Issue
Block a user