This commit is contained in:
2025-08-27 15:09:05 +09:00
parent 57961d84de
commit a13f66d917
9896 changed files with 2193048 additions and 730 deletions
+28
View File
@@ -0,0 +1,28 @@
clean::
$(RM) $(CLEANSUFFIXES:%=libavcodec/hevc/%)
OBJS-$(CONFIG_HEVC_DECODER) += \
hevc/cabac.o \
hevc/data.o \
hevc/dsp.o \
hevc/filter.o \
hevc/hevcdec.o \
hevc/mvs.o \
hevc/pred.o \
hevc/refs.o \
OBJS-$(CONFIG_HEVC_PARSER) += \
hevc/parser.o \
OBJS-$(CONFIG_HEVCPARSE) += \
hevc/data.o \
hevc/parse.o \
hevc/ps.o \
OBJS-$(CONFIG_HEVC_SEI) += \
hevc/sei.o \
libavcodec/hevc/%.o: CPPFLAGS += -I$(SRC_PATH)/libavcodec/
File diff suppressed because it is too large Load Diff
+75
View File
@@ -0,0 +1,75 @@
/*
* HEVC shared tables
*
* 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 <stdint.h>
#include "data.h"
const uint8_t ff_hevc_diag_scan4x4_x[16] = {
0, 0, 1, 0,
1, 2, 0, 1,
2, 3, 1, 2,
3, 2, 3, 3,
};
const uint8_t ff_hevc_diag_scan4x4_y[16] = {
0, 1, 0, 2,
1, 0, 3, 2,
1, 0, 3, 2,
1, 3, 2, 3,
};
const uint8_t ff_hevc_diag_scan8x8_x[64] = {
0, 0, 1, 0,
1, 2, 0, 1,
2, 3, 0, 1,
2, 3, 4, 0,
1, 2, 3, 4,
5, 0, 1, 2,
3, 4, 5, 6,
0, 1, 2, 3,
4, 5, 6, 7,
1, 2, 3, 4,
5, 6, 7, 2,
3, 4, 5, 6,
7, 3, 4, 5,
6, 7, 4, 5,
6, 7, 5, 6,
7, 6, 7, 7,
};
const uint8_t ff_hevc_diag_scan8x8_y[64] = {
0, 1, 0, 2,
1, 0, 3, 2,
1, 0, 4, 3,
2, 1, 0, 5,
4, 3, 2, 1,
0, 6, 5, 4,
3, 2, 1, 0,
7, 6, 5, 4,
3, 2, 1, 0,
7, 6, 5, 4,
3, 2, 1, 7,
6, 5, 4, 3,
2, 7, 6, 5,
4, 3, 7, 6,
5, 4, 7, 6,
5, 7, 6, 7,
};
+31
View File
@@ -0,0 +1,31 @@
/*
* HEVC shared data tables
*
* 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_DATA_H
#define AVCODEC_HEVC_DATA_H
#include <stdint.h>
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_DATA_H */
+279
View File
@@ -0,0 +1,279 @@
/*
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2013 - 2014 Pierre-Edouard Lepere
*
*
* 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 "dsp.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)[8][4] = {
{ 0 },
{ -2, 58, 10, -2},
{ -4, 54, 16, -2},
{ -6, 46, 28, -4},
{ -4, 36, 36, -4},
{ -4, 28, 46, -6},
{ -2, 16, 54, -4},
{ -2, 10, 58, -2},
};
DECLARE_ALIGNED(16, const int8_t, ff_hevc_qpel_filters)[4][16] = {
{ 0 },
{ -1, 4,-10, 58, 17, -5, 1, 0, -1, 4,-10, 58, 17, -5, 1, 0},
{ -1, 4,-11, 40, 40,-11, 4, -1, -1, 4,-11, 40, 40,-11, 4, -1},
{ 0, 1, -5, 17, 58,-10, 4, -1, 0, 1, -5, 17, 58,-10, 4, -1}
};
#define BIT_DEPTH 8
#include "dsp_template.c"
#undef BIT_DEPTH
#define BIT_DEPTH 9
#include "dsp_template.c"
#undef BIT_DEPTH
#define BIT_DEPTH 10
#include "dsp_template.c"
#undef BIT_DEPTH
#define BIT_DEPTH 12
#include "dsp_template.c"
#undef BIT_DEPTH
void ff_hevc_dsp_init(HEVCDSPContext *hevcdsp, int bit_depth)
{
#undef FUNC
#define FUNC(a, depth) a ## _ ## depth
#undef PEL_FUNC
#define PEL_FUNC(dst1, idx1, idx2, a, depth) \
for(i = 0 ; i < 10 ; i++) \
{ \
hevcdsp->dst1[i][idx1][idx2] = a ## _ ## depth; \
}
#undef EPEL_FUNCS
#define EPEL_FUNCS(depth) \
PEL_FUNC(put_hevc_epel, 0, 0, put_hevc_pel_pixels, depth); \
PEL_FUNC(put_hevc_epel, 0, 1, put_hevc_epel_h, depth); \
PEL_FUNC(put_hevc_epel, 1, 0, put_hevc_epel_v, depth); \
PEL_FUNC(put_hevc_epel, 1, 1, put_hevc_epel_hv, depth)
#undef EPEL_UNI_FUNCS
#define EPEL_UNI_FUNCS(depth) \
PEL_FUNC(put_hevc_epel_uni, 0, 0, put_hevc_pel_uni_pixels, depth); \
PEL_FUNC(put_hevc_epel_uni, 0, 1, put_hevc_epel_uni_h, depth); \
PEL_FUNC(put_hevc_epel_uni, 1, 0, put_hevc_epel_uni_v, depth); \
PEL_FUNC(put_hevc_epel_uni, 1, 1, put_hevc_epel_uni_hv, depth); \
PEL_FUNC(put_hevc_epel_uni_w, 0, 0, put_hevc_pel_uni_w_pixels, depth); \
PEL_FUNC(put_hevc_epel_uni_w, 0, 1, put_hevc_epel_uni_w_h, depth); \
PEL_FUNC(put_hevc_epel_uni_w, 1, 0, put_hevc_epel_uni_w_v, depth); \
PEL_FUNC(put_hevc_epel_uni_w, 1, 1, put_hevc_epel_uni_w_hv, depth)
#undef EPEL_BI_FUNCS
#define EPEL_BI_FUNCS(depth) \
PEL_FUNC(put_hevc_epel_bi, 0, 0, put_hevc_pel_bi_pixels, depth); \
PEL_FUNC(put_hevc_epel_bi, 0, 1, put_hevc_epel_bi_h, depth); \
PEL_FUNC(put_hevc_epel_bi, 1, 0, put_hevc_epel_bi_v, depth); \
PEL_FUNC(put_hevc_epel_bi, 1, 1, put_hevc_epel_bi_hv, depth); \
PEL_FUNC(put_hevc_epel_bi_w, 0, 0, put_hevc_pel_bi_w_pixels, depth); \
PEL_FUNC(put_hevc_epel_bi_w, 0, 1, put_hevc_epel_bi_w_h, depth); \
PEL_FUNC(put_hevc_epel_bi_w, 1, 0, put_hevc_epel_bi_w_v, depth); \
PEL_FUNC(put_hevc_epel_bi_w, 1, 1, put_hevc_epel_bi_w_hv, depth)
#undef QPEL_FUNCS
#define QPEL_FUNCS(depth) \
PEL_FUNC(put_hevc_qpel, 0, 0, put_hevc_pel_pixels, depth); \
PEL_FUNC(put_hevc_qpel, 0, 1, put_hevc_qpel_h, depth); \
PEL_FUNC(put_hevc_qpel, 1, 0, put_hevc_qpel_v, depth); \
PEL_FUNC(put_hevc_qpel, 1, 1, put_hevc_qpel_hv, depth)
#undef QPEL_UNI_FUNCS
#define QPEL_UNI_FUNCS(depth) \
PEL_FUNC(put_hevc_qpel_uni, 0, 0, put_hevc_pel_uni_pixels, depth); \
PEL_FUNC(put_hevc_qpel_uni, 0, 1, put_hevc_qpel_uni_h, depth); \
PEL_FUNC(put_hevc_qpel_uni, 1, 0, put_hevc_qpel_uni_v, depth); \
PEL_FUNC(put_hevc_qpel_uni, 1, 1, put_hevc_qpel_uni_hv, depth); \
PEL_FUNC(put_hevc_qpel_uni_w, 0, 0, put_hevc_pel_uni_w_pixels, depth); \
PEL_FUNC(put_hevc_qpel_uni_w, 0, 1, put_hevc_qpel_uni_w_h, depth); \
PEL_FUNC(put_hevc_qpel_uni_w, 1, 0, put_hevc_qpel_uni_w_v, depth); \
PEL_FUNC(put_hevc_qpel_uni_w, 1, 1, put_hevc_qpel_uni_w_hv, depth)
#undef QPEL_BI_FUNCS
#define QPEL_BI_FUNCS(depth) \
PEL_FUNC(put_hevc_qpel_bi, 0, 0, put_hevc_pel_bi_pixels, depth); \
PEL_FUNC(put_hevc_qpel_bi, 0, 1, put_hevc_qpel_bi_h, depth); \
PEL_FUNC(put_hevc_qpel_bi, 1, 0, put_hevc_qpel_bi_v, depth); \
PEL_FUNC(put_hevc_qpel_bi, 1, 1, put_hevc_qpel_bi_hv, depth); \
PEL_FUNC(put_hevc_qpel_bi_w, 0, 0, put_hevc_pel_bi_w_pixels, depth); \
PEL_FUNC(put_hevc_qpel_bi_w, 0, 1, put_hevc_qpel_bi_w_h, depth); \
PEL_FUNC(put_hevc_qpel_bi_w, 1, 0, put_hevc_qpel_bi_w_v, depth); \
PEL_FUNC(put_hevc_qpel_bi_w, 1, 1, put_hevc_qpel_bi_w_hv, depth)
#define HEVC_DSP(depth) \
hevcdsp->put_pcm = FUNC(put_pcm, depth); \
hevcdsp->add_residual[0] = FUNC(add_residual4x4, depth); \
hevcdsp->add_residual[1] = FUNC(add_residual8x8, depth); \
hevcdsp->add_residual[2] = FUNC(add_residual16x16, depth); \
hevcdsp->add_residual[3] = FUNC(add_residual32x32, depth); \
hevcdsp->dequant = FUNC(dequant, depth); \
hevcdsp->transform_rdpcm = FUNC(transform_rdpcm, depth); \
hevcdsp->transform_4x4_luma = FUNC(transform_4x4_luma, depth); \
hevcdsp->idct[0] = FUNC(idct_4x4, depth); \
hevcdsp->idct[1] = FUNC(idct_8x8, depth); \
hevcdsp->idct[2] = FUNC(idct_16x16, depth); \
hevcdsp->idct[3] = FUNC(idct_32x32, depth); \
\
hevcdsp->idct_dc[0] = FUNC(idct_4x4_dc, depth); \
hevcdsp->idct_dc[1] = FUNC(idct_8x8_dc, depth); \
hevcdsp->idct_dc[2] = FUNC(idct_16x16_dc, depth); \
hevcdsp->idct_dc[3] = FUNC(idct_32x32_dc, depth); \
\
hevcdsp->sao_band_filter[0] = \
hevcdsp->sao_band_filter[1] = \
hevcdsp->sao_band_filter[2] = \
hevcdsp->sao_band_filter[3] = \
hevcdsp->sao_band_filter[4] = FUNC(sao_band_filter, depth); \
hevcdsp->sao_edge_filter[0] = \
hevcdsp->sao_edge_filter[1] = \
hevcdsp->sao_edge_filter[2] = \
hevcdsp->sao_edge_filter[3] = \
hevcdsp->sao_edge_filter[4] = FUNC(sao_edge_filter, depth); \
hevcdsp->sao_edge_restore[0] = FUNC(sao_edge_restore_0, depth); \
hevcdsp->sao_edge_restore[1] = FUNC(sao_edge_restore_1, depth); \
\
QPEL_FUNCS(depth); \
QPEL_UNI_FUNCS(depth); \
QPEL_BI_FUNCS(depth); \
EPEL_FUNCS(depth); \
EPEL_UNI_FUNCS(depth); \
EPEL_BI_FUNCS(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)
int i = 0;
switch (bit_depth) {
case 9:
HEVC_DSP(9);
break;
case 10:
HEVC_DSP(10);
break;
case 12:
HEVC_DSP(12);
break;
default:
HEVC_DSP(8);
break;
}
#if ARCH_AARCH64
ff_hevc_dsp_init_aarch64(hevcdsp, bit_depth);
#elif ARCH_ARM
ff_hevc_dsp_init_arm(hevcdsp, bit_depth);
#elif ARCH_PPC
ff_hevc_dsp_init_ppc(hevcdsp, bit_depth);
#elif ARCH_RISCV
ff_hevc_dsp_init_riscv(hevcdsp, bit_depth);
#elif ARCH_WASM
ff_hevc_dsp_init_wasm(hevcdsp, bit_depth);
#elif ARCH_X86
ff_hevc_dsp_init_x86(hevcdsp, bit_depth);
#elif ARCH_MIPS
ff_hevc_dsp_init_mips(hevcdsp, bit_depth);
#elif ARCH_LOONGARCH
ff_hevc_dsp_init_loongarch(hevcdsp, bit_depth);
#endif
}
+142
View File
@@ -0,0 +1,142 @@
/*
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2013 - 2014 Pierre-Edouard Lepere
*
*
* 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_DSP_H
#define AVCODEC_HEVC_DSP_H
#include "libavutil/mem_internal.h"
#include "libavcodec/get_bits.h"
#define MAX_PB_SIZE 64
typedef struct SAOParams {
int offset_abs[3][4]; ///< sao_offset_abs
int offset_sign[3][4]; ///< sao_offset_sign
uint8_t band_position[3]; ///< sao_band_position
int eo_class[3]; ///< sao_eo_class
int16_t offset_val[3][5]; ///<SaoOffsetVal
uint8_t type_idx[3]; ///< sao_type_idx
} SAOParams;
typedef struct HEVCDSPContext {
void (*put_pcm)(uint8_t *_dst, ptrdiff_t _stride, int width, int height,
struct GetBitContext *gb, int pcm_bit_depth);
void (*add_residual[4])(uint8_t *dst, const int16_t *res, ptrdiff_t stride);
void (*dequant)(int16_t *coeffs, int16_t log2_size);
void (*transform_rdpcm)(int16_t *coeffs, int16_t log2_size, int mode);
void (*transform_4x4_luma)(int16_t *coeffs);
void (*idct[4])(int16_t *coeffs, int col_limit);
void (*idct_dc[4])(int16_t *coeffs);
void (*sao_band_filter[5])(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src,
const int16_t *sao_offset_val, int sao_left_class, int width, int height);
/* implicit stride_src parameter has value of 2 * MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE */
void (*sao_edge_filter[5])(uint8_t *_dst /* align 16 */, const uint8_t *_src /* align 32 */, ptrdiff_t stride_dst,
const int16_t *sao_offset_val, int sao_eo_class, int width, int height);
void (*sao_edge_restore[2])(uint8_t *_dst, const uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src,
const struct SAOParams *sao, const int *borders, int _width, int _height, int c_idx,
const uint8_t *vert_edge, const uint8_t *horiz_edge, const uint8_t *diag_edge);
void (*put_hevc_qpel[10][2][2])(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride,
int height, intptr_t mx, intptr_t my, int width);
void (*put_hevc_qpel_uni[10][2][2])(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride,
int height, intptr_t mx, intptr_t my, int width);
void (*put_hevc_qpel_uni_w[10][2][2])(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride,
int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width);
void (*put_hevc_qpel_bi[10][2][2])(uint8_t *dst, ptrdiff_t dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, intptr_t mx, intptr_t my, int width);
void (*put_hevc_qpel_bi_w[10][2][2])(uint8_t *dst, ptrdiff_t dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, int denom, int wx0, int wx1,
int ox0, int ox1, intptr_t mx, intptr_t my, int width);
void (*put_hevc_epel[10][2][2])(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride,
int height, intptr_t mx, intptr_t my, int width);
void (*put_hevc_epel_uni[10][2][2])(uint8_t *dst, ptrdiff_t dststride, const uint8_t *_src, ptrdiff_t _srcstride,
int height, intptr_t mx, intptr_t my, int width);
void (*put_hevc_epel_uni_w[10][2][2])(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride,
int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width);
void (*put_hevc_epel_bi[10][2][2])(uint8_t *dst, ptrdiff_t dststride, const uint8_t *_src, ptrdiff_t _srcstride,
const int16_t *src2,
int height, intptr_t mx, intptr_t my, int width);
void (*put_hevc_epel_bi_w[10][2][2])(uint8_t *dst, ptrdiff_t dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, int denom, int wx0, int ox0, int wx1,
int ox1, intptr_t mx, intptr_t my, int width);
void (*hevc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
int beta, const int32_t *tc,
const uint8_t *no_p, const uint8_t *no_q);
void (*hevc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
int beta, const int32_t *tc,
const uint8_t *no_p, const uint8_t *no_q);
void (*hevc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
const int32_t *tc, const uint8_t *no_p, const uint8_t *no_q);
void (*hevc_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
const int32_t *tc, const uint8_t *no_p, const uint8_t *no_q);
void (*hevc_h_loop_filter_luma_c)(uint8_t *pix, ptrdiff_t stride,
int beta, const int32_t *tc,
const uint8_t *no_p, const uint8_t *no_q);
void (*hevc_v_loop_filter_luma_c)(uint8_t *pix, ptrdiff_t stride,
int beta, const int32_t *tc,
const uint8_t *no_p, const uint8_t *no_q);
void (*hevc_h_loop_filter_chroma_c)(uint8_t *pix, ptrdiff_t stride,
const int32_t *tc, const uint8_t *no_p,
const uint8_t *no_q);
void (*hevc_v_loop_filter_chroma_c)(uint8_t *pix, ptrdiff_t stride,
const int32_t *tc, const uint8_t *no_p,
const uint8_t *no_q);
} HEVCDSPContext;
void ff_hevc_dsp_init(HEVCDSPContext *hpc, int bit_depth);
/** ff_hevc_.pel_filters[0] are dummies to simplify array addressing */
extern const int8_t ff_hevc_epel_filters[8][4];
extern const int8_t ff_hevc_qpel_filters[4][16];
void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth);
void ff_hevc_dsp_init_arm(HEVCDSPContext *c, const int bit_depth);
void ff_hevc_dsp_init_ppc(HEVCDSPContext *c, const int bit_depth);
void ff_hevc_dsp_init_riscv(HEVCDSPContext *c, const int bit_depth);
void ff_hevc_dsp_init_wasm(HEVCDSPContext *c, const int bit_depth);
void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth);
void ff_hevc_dsp_init_mips(HEVCDSPContext *c, const int bit_depth);
void ff_hevc_dsp_init_loongarch(HEVCDSPContext *c, const int bit_depth);
#endif /* AVCODEC_HEVC_DSP_H */
+934
View File
@@ -0,0 +1,934 @@
/*
* 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 "get_bits.h"
#include "hevcdec.h"
#include "bit_depth_template.c"
#include "dsp.h"
#include "h26x/h2656_sao_template.c"
#include "h26x/h2656_inter_template.c"
static void FUNC(put_pcm)(uint8_t *_dst, ptrdiff_t stride, int width, int height,
GetBitContext *gb, int pcm_bit_depth)
{
int x, y;
pixel *dst = (pixel *)_dst;
stride /= sizeof(pixel);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = get_bits(gb, pcm_bit_depth) << (BIT_DEPTH - pcm_bit_depth);
dst += stride;
}
}
static av_always_inline void FUNC(add_residual)(uint8_t *_dst, const int16_t *res,
ptrdiff_t stride, int size)
{
int x, y;
pixel *dst = (pixel *)_dst;
stride /= sizeof(pixel);
for (y = 0; y < size; y++) {
for (x = 0; x < size; x++) {
dst[x] = av_clip_pixel(dst[x] + *res);
res++;
}
dst += stride;
}
}
static void FUNC(add_residual4x4)(uint8_t *_dst, const int16_t *res,
ptrdiff_t stride)
{
FUNC(add_residual)(_dst, res, stride, 4);
}
static void FUNC(add_residual8x8)(uint8_t *_dst, const int16_t *res,
ptrdiff_t stride)
{
FUNC(add_residual)(_dst, res, stride, 8);
}
static void FUNC(add_residual16x16)(uint8_t *_dst, const int16_t *res,
ptrdiff_t stride)
{
FUNC(add_residual)(_dst, res, stride, 16);
}
static void FUNC(add_residual32x32)(uint8_t *_dst, const int16_t *res,
ptrdiff_t stride)
{
FUNC(add_residual)(_dst, res, stride, 32);
}
static void FUNC(transform_rdpcm)(int16_t *_coeffs, int16_t log2_size, int mode)
{
int16_t *coeffs = (int16_t *) _coeffs;
int x, y;
int size = 1 << log2_size;
if (mode) {
coeffs += size;
for (y = 0; y < size - 1; y++) {
for (x = 0; x < size; x++)
coeffs[x] += coeffs[x - size];
coeffs += size;
}
} else {
for (y = 0; y < size; y++) {
for (x = 1; x < size; x++)
coeffs[x] += coeffs[x - 1];
coeffs += size;
}
}
}
static void FUNC(dequant)(int16_t *coeffs, int16_t log2_size)
{
int shift = 15 - BIT_DEPTH - log2_size;
int x, y;
int size = 1 << log2_size;
if (shift > 0) {
int offset = 1 << (shift - 1);
for (y = 0; y < size; y++) {
for (x = 0; x < size; x++) {
*coeffs = (*coeffs + offset) >> shift;
coeffs++;
}
}
} else {
for (y = 0; y < size; y++) {
for (x = 0; x < size; x++) {
*coeffs = *(uint16_t*)coeffs << -shift;
coeffs++;
}
}
}
}
#define SET(dst, x) (dst) = (x)
#define SCALE(dst, x) (dst) = av_clip_int16(((x) + add) >> shift)
#define TR_4x4_LUMA(dst, src, step, assign) \
do { \
int c0 = src[0 * step] + src[2 * step]; \
int c1 = src[2 * step] + src[3 * step]; \
int c2 = src[0 * step] - src[3 * step]; \
int c3 = 74 * src[1 * step]; \
\
assign(dst[2 * step], 74 * (src[0 * step] - \
src[2 * step] + \
src[3 * step])); \
assign(dst[0 * step], 29 * c0 + 55 * c1 + c3); \
assign(dst[1 * step], 55 * c2 - 29 * c1 + c3); \
assign(dst[3 * step], 55 * c0 + 29 * c2 - c3); \
} while (0)
static void FUNC(transform_4x4_luma)(int16_t *coeffs)
{
int i;
int shift = 7;
int add = 1 << (shift - 1);
int16_t *src = coeffs;
for (i = 0; i < 4; i++) {
TR_4x4_LUMA(src, src, 4, SCALE);
src++;
}
shift = 20 - BIT_DEPTH;
add = 1 << (shift - 1);
for (i = 0; i < 4; i++) {
TR_4x4_LUMA(coeffs, coeffs, 1, SCALE);
coeffs += 4;
}
}
#undef TR_4x4_LUMA
#define TR_4(dst, src, dstep, sstep, assign, end) \
do { \
const int e0 = 64 * src[0 * sstep] + 64 * src[2 * sstep]; \
const int e1 = 64 * src[0 * sstep] - 64 * src[2 * sstep]; \
const int o0 = 83 * src[1 * sstep] + 36 * src[3 * sstep]; \
const int o1 = 36 * src[1 * sstep] - 83 * src[3 * sstep]; \
\
assign(dst[0 * dstep], e0 + o0); \
assign(dst[1 * dstep], e1 + o1); \
assign(dst[2 * dstep], e1 - o1); \
assign(dst[3 * dstep], e0 - o0); \
} while (0)
#define TR_8(dst, src, dstep, sstep, assign, end) \
do { \
int i, j; \
int e_8[4]; \
int o_8[4] = { 0 }; \
for (i = 0; i < 4; i++) \
for (j = 1; j < end; j += 2) \
o_8[i] += transform[4 * j][i] * src[j * sstep]; \
TR_4(e_8, src, 1, 2 * sstep, SET, 4); \
\
for (i = 0; i < 4; i++) { \
assign(dst[i * dstep], e_8[i] + o_8[i]); \
assign(dst[(7 - i) * dstep], e_8[i] - o_8[i]); \
} \
} while (0)
#define TR_16(dst, src, dstep, sstep, assign, end) \
do { \
int i, j; \
int e_16[8]; \
int o_16[8] = { 0 }; \
for (i = 0; i < 8; i++) \
for (j = 1; j < end; j += 2) \
o_16[i] += transform[2 * j][i] * src[j * sstep]; \
TR_8(e_16, src, 1, 2 * sstep, SET, 8); \
\
for (i = 0; i < 8; i++) { \
assign(dst[i * dstep], e_16[i] + o_16[i]); \
assign(dst[(15 - i) * dstep], e_16[i] - o_16[i]); \
} \
} while (0)
#define TR_32(dst, src, dstep, sstep, assign, end) \
do { \
int i, j; \
int e_32[16]; \
int o_32[16] = { 0 }; \
for (i = 0; i < 16; i++) \
for (j = 1; j < end; j += 2) \
o_32[i] += transform[j][i] * src[j * sstep]; \
TR_16(e_32, src, 1, 2 * sstep, SET, end / 2); \
\
for (i = 0; i < 16; i++) { \
assign(dst[i * dstep], e_32[i] + o_32[i]); \
assign(dst[(31 - i) * dstep], e_32[i] - o_32[i]); \
} \
} while (0)
#define IDCT_VAR4(H) \
int limit2 = FFMIN(col_limit + 4, H)
#define IDCT_VAR8(H) \
int limit = FFMIN(col_limit, H); \
int limit2 = FFMIN(col_limit + 4, H)
#define IDCT_VAR16(H) IDCT_VAR8(H)
#define IDCT_VAR32(H) IDCT_VAR8(H)
#define IDCT(H) \
static void FUNC(idct_ ## H ## x ## H )(int16_t *coeffs, \
int col_limit) \
{ \
int i; \
int shift = 7; \
int add = 1 << (shift - 1); \
int16_t *src = coeffs; \
IDCT_VAR ## H(H); \
\
for (i = 0; i < H; i++) { \
TR_ ## H(src, src, H, H, SCALE, limit2); \
if (limit2 < H && i%4 == 0 && !!i) \
limit2 -= 4; \
src++; \
} \
\
shift = 20 - BIT_DEPTH; \
add = 1 << (shift - 1); \
for (i = 0; i < H; i++) { \
TR_ ## H(coeffs, coeffs, 1, 1, SCALE, limit); \
coeffs += H; \
} \
}
#define IDCT_DC(H) \
static void FUNC(idct_ ## H ## x ## H ## _dc)(int16_t *coeffs) \
{ \
int i, j; \
int shift = 14 - BIT_DEPTH; \
int add = 1 << (shift - 1); \
int coeff = (((coeffs[0] + 1) >> 1) + add) >> shift; \
\
for (j = 0; j < H; j++) { \
for (i = 0; i < H; i++) { \
coeffs[i + j * H] = coeff; \
} \
} \
}
IDCT( 4)
IDCT( 8)
IDCT(16)
IDCT(32)
IDCT_DC( 4)
IDCT_DC( 8)
IDCT_DC(16)
IDCT_DC(32)
#undef TR_4
#undef TR_8
#undef TR_16
#undef TR_32
#undef SET
#undef SCALE
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
#define ff_hevc_pel_filters ff_hevc_qpel_filters
#define DECL_HV_FILTER(f) \
const int8_t *hf = ff_hevc_ ## f ## _filters[mx]; \
const int8_t *vf = ff_hevc_ ## f ## _filters[my];
#define FW_PUT(p, f, t) \
static void FUNC(put_hevc_## f)(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, int height, \
intptr_t mx, intptr_t my, int width) \
{ \
DECL_HV_FILTER(p) \
FUNC(put_ ## t)(dst, src, srcstride, height, hf, vf, width); \
}
#define FW_PUT_UNI(p, f, t) \
static void FUNC(put_hevc_ ## f)(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \
ptrdiff_t srcstride, int height, intptr_t mx, intptr_t my, int width) \
{ \
DECL_HV_FILTER(p) \
FUNC(put_ ## t)(dst, dststride, src, srcstride, height, hf, vf, width); \
}
#define FW_PUT_UNI_W(p, f, t) \
static void FUNC(put_hevc_ ## f)(uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, \
ptrdiff_t srcstride,int height, int denom, int wx, int ox, \
intptr_t mx, intptr_t my, int width) \
{ \
DECL_HV_FILTER(p) \
FUNC(put_ ## t)(dst, dststride, src, srcstride, height, denom, wx, ox, hf, vf, width); \
}
#define FW_PUT_FUNCS(f, t, dir) \
FW_PUT(f, f ## _ ## dir, t ## _ ## dir) \
FW_PUT_UNI(f, f ## _uni_ ## dir, uni_ ## t ## _ ## dir) \
FW_PUT_UNI_W(f, f ## _uni_w_ ## dir, uni_## t ## _w_ ## dir)
FW_PUT(pel, pel_pixels, pixels)
FW_PUT_UNI(pel, pel_uni_pixels, uni_pixels)
FW_PUT_UNI_W(pel, pel_uni_w_pixels, uni_w_pixels)
FW_PUT_FUNCS(qpel, luma, h )
FW_PUT_FUNCS(qpel, luma, v )
FW_PUT_FUNCS(qpel, luma, hv )
FW_PUT_FUNCS(epel, chroma, h )
FW_PUT_FUNCS(epel, chroma, v )
FW_PUT_FUNCS(epel, chroma, hv )
static void FUNC(put_hevc_pel_bi_pixels)(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride,
const int16_t *src2,
int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
int shift = 14 + 1 - BIT_DEPTH;
#if BIT_DEPTH < 14
int offset = 1 << (shift - 1);
#else
int offset = 0;
#endif
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((src[x] << (14 - BIT_DEPTH)) + src2[x] + offset) >> shift);
src += srcstride;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_pel_bi_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride,
const int16_t *src2,
int height, int denom, int wx0, int wx1,
int ox0, int ox1, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
int shift = 14 + 1 - BIT_DEPTH;
int log2Wd = denom + shift - 1;
ox0 = ox0 * (1 << (BIT_DEPTH - 8));
ox1 = ox1 * (1 << (BIT_DEPTH - 8));
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
dst[x] = av_clip_pixel(( (src[x] << (14 - BIT_DEPTH)) * wx1 + src2[x] * wx0 + (ox0 + ox1 + 1) * (1 << log2Wd)) >> (log2Wd + 1));
}
src += srcstride;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
#define QPEL_FILTER(src, stride) \
(filter[0] * src[x - 3 * stride] + \
filter[1] * src[x - 2 * stride] + \
filter[2] * src[x - stride] + \
filter[3] * src[x ] + \
filter[4] * src[x + stride] + \
filter[5] * src[x + 2 * stride] + \
filter[6] * src[x + 3 * stride] + \
filter[7] * src[x + 4 * stride])
static void FUNC(put_hevc_qpel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, ptrdiff_t _srcstride,
const int16_t *src2,
int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel*)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
const int8_t *filter = ff_hevc_qpel_filters[mx];
int shift = 14 + 1 - BIT_DEPTH;
#if BIT_DEPTH < 14
int offset = 1 << (shift - 1);
#else
int offset = 0;
#endif
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);
src += srcstride;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_qpel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel*)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
const int8_t *filter = ff_hevc_qpel_filters[my];
int shift = 14 + 1 - BIT_DEPTH;
#if BIT_DEPTH < 14
int offset = 1 << (shift - 1);
#else
int offset = 0;
#endif
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);
src += srcstride;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_qpel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
const int8_t *filter;
const pixel *src = (const pixel*)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];
int16_t *tmp = tmp_array;
int shift = 14 + 1 - BIT_DEPTH;
#if BIT_DEPTH < 14
int offset = 1 << (shift - 1);
#else
int offset = 0;
#endif
src -= QPEL_EXTRA_BEFORE * srcstride;
filter = ff_hevc_qpel_filters[mx];
for (y = 0; y < height + QPEL_EXTRA; y++) {
for (x = 0; x < width; x++)
tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
src += srcstride;
tmp += MAX_PB_SIZE;
}
tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;
filter = ff_hevc_qpel_filters[my];
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);
tmp += MAX_PB_SIZE;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_qpel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, int denom, int wx0, int wx1,
int ox0, int ox1, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel*)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
const int8_t *filter = ff_hevc_qpel_filters[mx];
int shift = 14 + 1 - BIT_DEPTH;
int log2Wd = denom + shift - 1;
ox0 = ox0 * (1 << (BIT_DEPTH - 8));
ox1 = ox1 * (1 << (BIT_DEPTH - 8));
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +
((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));
src += srcstride;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_qpel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, int denom, int wx0, int wx1,
int ox0, int ox1, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel*)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
const int8_t *filter = ff_hevc_qpel_filters[my];
int shift = 14 + 1 - BIT_DEPTH;
int log2Wd = denom + shift - 1;
ox0 = ox0 * (1 << (BIT_DEPTH - 8));
ox1 = ox1 * (1 << (BIT_DEPTH - 8));
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +
((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));
src += srcstride;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_qpel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, int denom, int wx0, int wx1,
int ox0, int ox1, intptr_t mx, intptr_t my, int width)
{
int x, y;
const int8_t *filter;
const pixel *src = (const pixel*)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];
int16_t *tmp = tmp_array;
int shift = 14 + 1 - BIT_DEPTH;
int log2Wd = denom + shift - 1;
src -= QPEL_EXTRA_BEFORE * srcstride;
filter = ff_hevc_qpel_filters[mx];
for (y = 0; y < height + QPEL_EXTRA; y++) {
for (x = 0; x < width; x++)
tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
src += srcstride;
tmp += MAX_PB_SIZE;
}
tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;
filter = ff_hevc_qpel_filters[my];
ox0 = ox0 * (1 << (BIT_DEPTH - 8));
ox1 = ox1 * (1 << (BIT_DEPTH - 8));
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +
((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));
tmp += MAX_PB_SIZE;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
#define EPEL_FILTER(src, stride) \
(filter[0] * src[x - stride] + \
filter[1] * src[x] + \
filter[2] * src[x + stride] + \
filter[3] * src[x + 2 * stride])
static void FUNC(put_hevc_epel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
const int8_t *filter = ff_hevc_epel_filters[mx];
int shift = 14 + 1 - BIT_DEPTH;
#if BIT_DEPTH < 14
int offset = 1 << (shift - 1);
#else
int offset = 0;
#endif
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);
}
dst += dststride;
src += srcstride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_epel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
const int8_t *filter = ff_hevc_epel_filters[my];
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
int shift = 14 + 1 - BIT_DEPTH;
#if BIT_DEPTH < 14
int offset = 1 << (shift - 1);
#else
int offset = 0;
#endif
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);
dst += dststride;
src += srcstride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_epel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
const int8_t *filter = ff_hevc_epel_filters[mx];
int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];
int16_t *tmp = tmp_array;
int shift = 14 + 1 - BIT_DEPTH;
#if BIT_DEPTH < 14
int offset = 1 << (shift - 1);
#else
int offset = 0;
#endif
src -= EPEL_EXTRA_BEFORE * srcstride;
for (y = 0; y < height + EPEL_EXTRA; y++) {
for (x = 0; x < width; x++)
tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
src += srcstride;
tmp += MAX_PB_SIZE;
}
tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;
filter = ff_hevc_epel_filters[my];
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);
tmp += MAX_PB_SIZE;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_epel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, int denom, int wx0, int wx1,
int ox0, int ox1, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
const int8_t *filter = ff_hevc_epel_filters[mx];
int shift = 14 + 1 - BIT_DEPTH;
int log2Wd = denom + shift - 1;
ox0 = ox0 * (1 << (BIT_DEPTH - 8));
ox1 = ox1 * (1 << (BIT_DEPTH - 8));
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +
((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));
src += srcstride;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_epel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, int denom, int wx0, int wx1,
int ox0, int ox1, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
const int8_t *filter = ff_hevc_epel_filters[my];
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
int shift = 14 + 1 - BIT_DEPTH;
int log2Wd = denom + shift - 1;
ox0 = ox0 * (1 << (BIT_DEPTH - 8));
ox1 = ox1 * (1 << (BIT_DEPTH - 8));
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +
((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));
src += srcstride;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
static void FUNC(put_hevc_epel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride,
const uint8_t *_src, ptrdiff_t _srcstride, const int16_t *src2,
int height, int denom, int wx0, int wx1,
int ox0, int ox1, intptr_t mx, intptr_t my, int width)
{
int x, y;
const pixel *src = (const pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
const int8_t *filter = ff_hevc_epel_filters[mx];
int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];
int16_t *tmp = tmp_array;
int shift = 14 + 1 - BIT_DEPTH;
int log2Wd = denom + shift - 1;
src -= EPEL_EXTRA_BEFORE * srcstride;
for (y = 0; y < height + EPEL_EXTRA; y++) {
for (x = 0; x < width; x++)
tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
src += srcstride;
tmp += MAX_PB_SIZE;
}
tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;
filter = ff_hevc_epel_filters[my];
ox0 = ox0 * (1 << (BIT_DEPTH - 8));
ox1 = ox1 * (1 << (BIT_DEPTH - 8));
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +
((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));
tmp += MAX_PB_SIZE;
dst += dststride;
src2 += MAX_PB_SIZE;
}
}
// line zero
#define P3 pix[-4 * xstride]
#define P2 pix[-3 * xstride]
#define P1 pix[-2 * xstride]
#define P0 pix[-1 * xstride]
#define Q0 pix[0 * xstride]
#define Q1 pix[1 * xstride]
#define Q2 pix[2 * xstride]
#define Q3 pix[3 * xstride]
// line three. used only for deblocking decision
#define TP3 pix[-4 * xstride + 3 * ystride]
#define TP2 pix[-3 * xstride + 3 * ystride]
#define TP1 pix[-2 * xstride + 3 * ystride]
#define TP0 pix[-1 * xstride + 3 * ystride]
#define TQ0 pix[0 * xstride + 3 * ystride]
#define TQ1 pix[1 * xstride + 3 * ystride]
#define TQ2 pix[2 * xstride + 3 * ystride]
#define TQ3 pix[3 * xstride + 3 * ystride]
#include "h26x/h2656_deblock_template.c"
static void FUNC(hevc_loop_filter_luma)(uint8_t *_pix,
ptrdiff_t _xstride, ptrdiff_t _ystride,
int beta, const int *_tc,
const uint8_t *_no_p, const uint8_t *_no_q)
{
ptrdiff_t xstride = _xstride / sizeof(pixel);
ptrdiff_t ystride = _ystride / sizeof(pixel);
beta <<= BIT_DEPTH - 8;
for (int j = 0; j < 2; j++) {
pixel* pix = (pixel*)_pix + j * 4 * ystride;
const int dp0 = abs(P2 - 2 * P1 + P0);
const int dq0 = abs(Q2 - 2 * Q1 + Q0);
const int dp3 = abs(TP2 - 2 * TP1 + TP0);
const int dq3 = abs(TQ2 - 2 * TQ1 + TQ0);
const int d0 = dp0 + dq0;
const int d3 = dp3 + dq3;
const int tc = _tc[j] << (BIT_DEPTH - 8);
const int no_p = _no_p[j];
const int no_q = _no_q[j];
if (d0 + d3 < beta) {
const int beta_3 = beta >> 3;
const int beta_2 = beta >> 2;
const int tc25 = ((tc * 5 + 1) >> 1);
if (abs(P3 - P0) + abs(Q3 - Q0) < beta_3 && abs(P0 - Q0) < tc25 &&
abs(TP3 - TP0) + abs(TQ3 - TQ0) < beta_3 && abs(TP0 - TQ0) < tc25 &&
(d0 << 1) < beta_2 && (d3 << 1) < beta_2) {
const int tc2 = tc << 1;
FUNC(loop_filter_luma_strong)(pix, xstride, ystride, tc2, tc2, tc2, no_p, no_q);
} else {
int nd_p = 1;
int nd_q = 1;
if (dp0 + dp3 < ((beta + (beta >> 1)) >> 3))
nd_p = 2;
if (dq0 + dq3 < ((beta + (beta >> 1)) >> 3))
nd_q = 2;
FUNC(loop_filter_luma_weak)(pix, xstride, ystride, tc, beta, no_p, no_q, nd_p, nd_q);
}
}
}
}
static void FUNC(hevc_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _xstride,
ptrdiff_t _ystride, const int *_tc,
const uint8_t *_no_p, const uint8_t *_no_q)
{
int no_p, no_q;
ptrdiff_t xstride = _xstride / sizeof(pixel);
ptrdiff_t ystride = _ystride / sizeof(pixel);
const int size = 4;
for (int j = 0; j < 2; j++) {
pixel *pix = (pixel *)_pix + j * size * ystride;
const int tc = _tc[j] << (BIT_DEPTH - 8);
if (tc > 0) {
no_p = _no_p[j];
no_q = _no_q[j];
FUNC(loop_filter_chroma_weak)(pix, xstride, ystride, size, tc, no_p, no_q);
}
}
}
static void FUNC(hevc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
const int32_t *tc, const uint8_t *no_p,
const uint8_t *no_q)
{
FUNC(hevc_loop_filter_chroma)(pix, stride, sizeof(pixel), tc, no_p, no_q);
}
static void FUNC(hevc_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
const int32_t *tc, const uint8_t *no_p,
const uint8_t *no_q)
{
FUNC(hevc_loop_filter_chroma)(pix, sizeof(pixel), stride, tc, no_p, no_q);
}
static void FUNC(hevc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
int beta, const int32_t *tc, const uint8_t *no_p,
const uint8_t *no_q)
{
FUNC(hevc_loop_filter_luma)(pix, stride, sizeof(pixel),
beta, tc, no_p, no_q);
}
static void FUNC(hevc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
int beta, const int32_t *tc, const uint8_t *no_p,
const uint8_t *no_q)
{
FUNC(hevc_loop_filter_luma)(pix, sizeof(pixel), stride,
beta, tc, no_p, no_q);
}
#undef P3
#undef P2
#undef P1
#undef P0
#undef Q0
#undef Q1
#undef Q2
#undef Q3
#undef TP3
#undef TP2
#undef TP1
#undef TP0
#undef TQ0
#undef TQ1
#undef TQ2
#undef TQ3
+924
View File
@@ -0,0 +1,924 @@
/*
* 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 "hevcdec.h"
#include "progressframe.h"
#define LUMA 0
#define CB 1
#define CR 2
static const uint8_t tctable[54] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // QP 0...18
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, // QP 19...37
5, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 24 // QP 38...53
};
static const uint8_t betatable[52] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, // QP 0...18
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, // QP 19...37
38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64 // QP 38...51
};
static int chroma_tc(const HEVCPPS *pps, const HEVCSPS *sps,
int qp_y, int c_idx, int tc_offset)
{
static const int qp_c[] = {
29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37
};
int qp, qp_i, offset, idxt;
// slice qp offset is not used for deblocking
if (c_idx == 1)
offset = pps->cb_qp_offset;
else
offset = pps->cr_qp_offset;
qp_i = av_clip(qp_y + offset, 0, 57);
if (sps->chroma_format_idc == 1) {
if (qp_i < 30)
qp = qp_i;
else if (qp_i > 43)
qp = qp_i - 6;
else
qp = qp_c[qp_i - 30];
} else {
qp = av_clip(qp_i, 0, 51);
}
idxt = av_clip(qp + DEFAULT_INTRA_TC_OFFSET + tc_offset, 0, 53);
return tctable[idxt];
}
static int get_qPy_pred(HEVCLocalContext *lc, const HEVCContext *s,
const HEVCLayerContext *l,
const HEVCPPS *pps, const HEVCSPS *sps,
int xBase, int yBase, int log2_cb_size)
{
int ctb_size_mask = (1 << sps->log2_ctb_size) - 1;
int MinCuQpDeltaSizeMask = (1 << (sps->log2_ctb_size -
pps->diff_cu_qp_delta_depth)) - 1;
int xQgBase = xBase - (xBase & MinCuQpDeltaSizeMask);
int yQgBase = yBase - (yBase & MinCuQpDeltaSizeMask);
int min_cb_width = sps->min_cb_width;
int x_cb = xQgBase >> sps->log2_min_cb_size;
int y_cb = yQgBase >> sps->log2_min_cb_size;
int availableA = (xBase & ctb_size_mask) &&
(xQgBase & ctb_size_mask);
int availableB = (yBase & ctb_size_mask) &&
(yQgBase & ctb_size_mask);
int qPy_pred, qPy_a, qPy_b;
// qPy_pred
if (lc->first_qp_group || (!xQgBase && !yQgBase)) {
lc->first_qp_group = !lc->tu.is_cu_qp_delta_coded;
qPy_pred = s->sh.slice_qp;
} else {
qPy_pred = lc->qPy_pred;
}
// qPy_a
if (availableA == 0)
qPy_a = qPy_pred;
else
qPy_a = l->qp_y_tab[(x_cb - 1) + y_cb * min_cb_width];
// qPy_b
if (availableB == 0)
qPy_b = qPy_pred;
else
qPy_b = l->qp_y_tab[x_cb + (y_cb - 1) * min_cb_width];
av_assert2(qPy_a >= -sps->qp_bd_offset && qPy_a < 52);
av_assert2(qPy_b >= -sps->qp_bd_offset && qPy_b < 52);
return (qPy_a + qPy_b + 1) >> 1;
}
void ff_hevc_set_qPy(HEVCLocalContext *lc,
const HEVCLayerContext *l, const HEVCPPS *pps,
int xBase, int yBase, int log2_cb_size)
{
const HEVCSPS *const sps = pps->sps;
const HEVCContext *const s = lc->parent;
int qp_y = get_qPy_pred(lc, s, l, pps, sps, xBase, yBase, log2_cb_size);
if (lc->tu.cu_qp_delta != 0) {
int off = sps->qp_bd_offset;
lc->qp_y = FFUMOD(qp_y + lc->tu.cu_qp_delta + 52 + 2 * off,
52 + off) - off;
} else
lc->qp_y = qp_y;
}
static int get_qPy(const HEVCSPS *sps, const int8_t *qp_y_tab, int xC, int yC)
{
int log2_min_cb_size = sps->log2_min_cb_size;
int x = xC >> log2_min_cb_size;
int y = yC >> log2_min_cb_size;
return qp_y_tab[x + y * sps->min_cb_width];
}
static void copy_CTB(uint8_t *dst, const uint8_t *src, int width, int height,
ptrdiff_t stride_dst, ptrdiff_t stride_src)
{
int i, j;
if (((intptr_t)dst | (intptr_t)src | stride_dst | stride_src) & 15) {
for (i = 0; i < height; i++) {
for (j = 0; j < width - 7; j+=8)
AV_COPY64U(dst+j, src+j);
dst += stride_dst;
src += stride_src;
}
if (width&7) {
dst += ((width>>3)<<3) - stride_dst * height;
src += ((width>>3)<<3) - stride_src * height;
width &= 7;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++)
dst[j] = src[j];
dst += stride_dst;
src += stride_src;
}
}
} else {
for (i = 0; i < height; i++) {
for (j = 0; j < width; j+=16)
AV_COPY128(dst+j, src+j);
dst += stride_dst;
src += stride_src;
}
}
}
static void copy_pixel(uint8_t *dst, const uint8_t *src, int pixel_shift)
{
if (pixel_shift)
*(uint16_t *)dst = *(uint16_t *)src;
else
*dst = *src;
}
static void copy_vert(uint8_t *dst, const uint8_t *src,
int pixel_shift, int height,
ptrdiff_t stride_dst, ptrdiff_t stride_src)
{
int i;
if (pixel_shift == 0) {
for (i = 0; i < height; i++) {
*dst = *src;
dst += stride_dst;
src += stride_src;
}
} else {
for (i = 0; i < height; i++) {
*(uint16_t *)dst = *(uint16_t *)src;
dst += stride_dst;
src += stride_src;
}
}
}
static void copy_CTB_to_hv(const HEVCLayerContext *l, const HEVCSPS *sps,
const uint8_t *src,
ptrdiff_t stride_src, int x, int y, int width, int height,
int c_idx, int x_ctb, int y_ctb)
{
int sh = sps->pixel_shift;
int w = sps->width >> sps->hshift[c_idx];
int h = sps->height >> sps->vshift[c_idx];
/* copy horizontal edges */
memcpy(l->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb) * w + x) << sh),
src, width << sh);
memcpy(l->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 1) * w + x) << sh),
src + stride_src * (height - 1), width << sh);
/* copy vertical edges */
copy_vert(l->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb) * h + y) << sh), src, sh, height, 1 << sh, stride_src);
copy_vert(l->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 1) * h + y) << sh), src + ((width - 1) << sh), sh, height, 1 << sh, stride_src);
}
static void restore_tqb_pixels(const HEVCLayerContext *l,
const HEVCPPS *pps, const HEVCSPS *sps,
uint8_t *src1, const uint8_t *dst1,
ptrdiff_t stride_src, ptrdiff_t stride_dst,
int x0, int y0, int width, int height, int c_idx)
{
if (pps->transquant_bypass_enable_flag ||
(sps->pcm_loop_filter_disabled && sps->pcm_enabled)) {
int x, y;
int min_pu_size = 1 << sps->log2_min_pu_size;
int hshift = sps->hshift[c_idx];
int vshift = sps->vshift[c_idx];
int x_min = ((x0 ) >> sps->log2_min_pu_size);
int y_min = ((y0 ) >> sps->log2_min_pu_size);
int x_max = ((x0 + width ) >> sps->log2_min_pu_size);
int y_max = ((y0 + height) >> sps->log2_min_pu_size);
int len = (min_pu_size >> hshift) << sps->pixel_shift;
for (y = y_min; y < y_max; y++) {
for (x = x_min; x < x_max; x++) {
if (l->is_pcm[y * sps->min_pu_width + x]) {
int n;
uint8_t *src = src1 +
(((y << sps->log2_min_pu_size) - y0) >> vshift) * stride_src +
((((x << sps->log2_min_pu_size) - x0) >> hshift) << sps->pixel_shift);
const uint8_t *dst = dst1 +
(((y << sps->log2_min_pu_size) - y0) >> vshift) * stride_dst +
((((x << sps->log2_min_pu_size) - x0) >> hshift) << sps->pixel_shift);
for (n = 0; n < (min_pu_size >> vshift); n++) {
memcpy(src, dst, len);
src += stride_src;
dst += stride_dst;
}
}
}
}
}
}
#define CTB(tab, x, y) ((tab)[(y) * sps->ctb_width + (x)])
static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCLayerContext *l,
const HEVCContext *s,
const HEVCPPS *pps, const HEVCSPS *sps,
int x, int y)
{
static const uint8_t sao_tab[8] = { 0, 1, 2, 2, 3, 3, 4, 4 };
int c_idx;
int edges[4]; // 0 left 1 top 2 right 3 bottom
int x_ctb = x >> sps->log2_ctb_size;
int y_ctb = y >> sps->log2_ctb_size;
int ctb_addr_rs = y_ctb * sps->ctb_width + x_ctb;
int ctb_addr_ts = pps->ctb_addr_rs_to_ts[ctb_addr_rs];
SAOParams *sao = &CTB(l->sao, x_ctb, y_ctb);
// flags indicating unfilterable edges
uint8_t vert_edge[] = { 0, 0 };
uint8_t horiz_edge[] = { 0, 0 };
uint8_t diag_edge[] = { 0, 0, 0, 0 };
uint8_t lfase = CTB(l->filter_slice_edges, x_ctb, y_ctb);
uint8_t no_tile_filter = pps->tiles_enabled_flag &&
!pps->loop_filter_across_tiles_enabled_flag;
uint8_t restore = no_tile_filter || !lfase;
uint8_t left_tile_edge = 0;
uint8_t right_tile_edge = 0;
uint8_t up_tile_edge = 0;
uint8_t bottom_tile_edge = 0;
edges[0] = x_ctb == 0;
edges[1] = y_ctb == 0;
edges[2] = x_ctb == sps->ctb_width - 1;
edges[3] = y_ctb == sps->ctb_height - 1;
if (restore) {
if (!edges[0]) {
left_tile_edge = no_tile_filter && pps->tile_id[ctb_addr_ts] != pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs-1]];
vert_edge[0] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb - 1, y_ctb)) || left_tile_edge;
}
if (!edges[2]) {
right_tile_edge = no_tile_filter && pps->tile_id[ctb_addr_ts] != pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs+1]];
vert_edge[1] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb + 1, y_ctb)) || right_tile_edge;
}
if (!edges[1]) {
up_tile_edge = no_tile_filter && pps->tile_id[ctb_addr_ts] != pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs - sps->ctb_width]];
horiz_edge[0] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb, y_ctb - 1)) || up_tile_edge;
}
if (!edges[3]) {
bottom_tile_edge = no_tile_filter && pps->tile_id[ctb_addr_ts] != pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs + sps->ctb_width]];
horiz_edge[1] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb, y_ctb + 1)) || bottom_tile_edge;
}
if (!edges[0] && !edges[1]) {
diag_edge[0] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb - 1, y_ctb - 1)) || left_tile_edge || up_tile_edge;
}
if (!edges[1] && !edges[2]) {
diag_edge[1] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb + 1, y_ctb - 1)) || right_tile_edge || up_tile_edge;
}
if (!edges[2] && !edges[3]) {
diag_edge[2] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb + 1, y_ctb + 1)) || right_tile_edge || bottom_tile_edge;
}
if (!edges[0] && !edges[3]) {
diag_edge[3] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb - 1, y_ctb + 1)) || left_tile_edge || bottom_tile_edge;
}
}
for (c_idx = 0; c_idx < (sps->chroma_format_idc ? 3 : 1); c_idx++) {
int x0 = x >> sps->hshift[c_idx];
int y0 = y >> sps->vshift[c_idx];
ptrdiff_t stride_src = s->cur_frame->f->linesize[c_idx];
int ctb_size_h = (1 << (sps->log2_ctb_size)) >> sps->hshift[c_idx];
int ctb_size_v = (1 << (sps->log2_ctb_size)) >> sps->vshift[c_idx];
int width = FFMIN(ctb_size_h, (sps->width >> sps->hshift[c_idx]) - x0);
int height = FFMIN(ctb_size_v, (sps->height >> sps->vshift[c_idx]) - y0);
int tab = sao_tab[(FFALIGN(width, 8) >> 3) - 1];
uint8_t *src = &s->cur_frame->f->data[c_idx][y0 * stride_src + (x0 << sps->pixel_shift)];
ptrdiff_t stride_dst;
uint8_t *dst;
switch (sao->type_idx[c_idx]) {
case SAO_BAND:
copy_CTB_to_hv(l, sps, src, stride_src, x0, y0, width, height, c_idx,
x_ctb, y_ctb);
if (pps->transquant_bypass_enable_flag ||
(sps->pcm_loop_filter_disabled && sps->pcm_enabled)) {
dst = lc->edge_emu_buffer;
stride_dst = 2*MAX_PB_SIZE;
copy_CTB(dst, src, width << sps->pixel_shift, height, stride_dst, stride_src);
s->hevcdsp.sao_band_filter[tab](src, dst, stride_src, stride_dst,
sao->offset_val[c_idx], sao->band_position[c_idx],
width, height);
restore_tqb_pixels(l, pps, sps, src, dst, stride_src, stride_dst,
x, y, width, height, c_idx);
} else {
s->hevcdsp.sao_band_filter[tab](src, src, stride_src, stride_src,
sao->offset_val[c_idx], sao->band_position[c_idx],
width, height);
}
sao->type_idx[c_idx] = SAO_APPLIED;
break;
case SAO_EDGE:
{
int w = sps->width >> sps->hshift[c_idx];
int h = sps->height >> sps->vshift[c_idx];
int left_edge = edges[0];
int top_edge = edges[1];
int right_edge = edges[2];
int bottom_edge = edges[3];
int sh = sps->pixel_shift;
int left_pixels, right_pixels;
stride_dst = 2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE;
dst = lc->edge_emu_buffer + stride_dst + AV_INPUT_BUFFER_PADDING_SIZE;
if (!top_edge) {
int left = 1 - left_edge;
int right = 1 - right_edge;
const uint8_t *src1[2];
uint8_t *dst1;
int src_idx, pos;
dst1 = dst - stride_dst - (left << sh);
src1[0] = src - stride_src - (left << sh);
src1[1] = l->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb - 1) * w + x0 - left) << sh);
pos = 0;
if (left) {
src_idx = (CTB(l->sao, x_ctb-1, y_ctb-1).type_idx[c_idx] ==
SAO_APPLIED);
copy_pixel(dst1, src1[src_idx], sh);
pos += (1 << sh);
}
src_idx = (CTB(l->sao, x_ctb, y_ctb-1).type_idx[c_idx] ==
SAO_APPLIED);
memcpy(dst1 + pos, src1[src_idx] + pos, width << sh);
if (right) {
pos += width << sh;
src_idx = (CTB(l->sao, x_ctb+1, y_ctb-1).type_idx[c_idx] ==
SAO_APPLIED);
copy_pixel(dst1 + pos, src1[src_idx] + pos, sh);
}
}
if (!bottom_edge) {
int left = 1 - left_edge;
int right = 1 - right_edge;
const uint8_t *src1[2];
uint8_t *dst1;
int src_idx, pos;
dst1 = dst + height * stride_dst - (left << sh);
src1[0] = src + height * stride_src - (left << sh);
src1[1] = l->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 2) * w + x0 - left) << sh);
pos = 0;
if (left) {
src_idx = (CTB(l->sao, x_ctb-1, y_ctb+1).type_idx[c_idx] ==
SAO_APPLIED);
copy_pixel(dst1, src1[src_idx], sh);
pos += (1 << sh);
}
src_idx = (CTB(l->sao, x_ctb, y_ctb+1).type_idx[c_idx] ==
SAO_APPLIED);
memcpy(dst1 + pos, src1[src_idx] + pos, width << sh);
if (right) {
pos += width << sh;
src_idx = (CTB(l->sao, x_ctb+1, y_ctb+1).type_idx[c_idx] ==
SAO_APPLIED);
copy_pixel(dst1 + pos, src1[src_idx] + pos, sh);
}
}
left_pixels = 0;
if (!left_edge) {
if (CTB(l->sao, x_ctb-1, y_ctb).type_idx[c_idx] == SAO_APPLIED) {
copy_vert(dst - (1 << sh),
l->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb - 1) * h + y0) << sh),
sh, height, stride_dst, 1 << sh);
} else {
left_pixels = 1;
}
}
right_pixels = 0;
if (!right_edge) {
if (CTB(l->sao, x_ctb+1, y_ctb).type_idx[c_idx] == SAO_APPLIED) {
copy_vert(dst + (width << sh),
l->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 2) * h + y0) << sh),
sh, height, stride_dst, 1 << sh);
} else {
right_pixels = 1;
}
}
copy_CTB(dst - (left_pixels << sh),
src - (left_pixels << sh),
(width + left_pixels + right_pixels) << sh,
height, stride_dst, stride_src);
copy_CTB_to_hv(l, sps, src, stride_src, x0, y0, width, height, c_idx,
x_ctb, y_ctb);
s->hevcdsp.sao_edge_filter[tab](src, dst, stride_src, sao->offset_val[c_idx],
sao->eo_class[c_idx], width, height);
s->hevcdsp.sao_edge_restore[restore](src, dst,
stride_src, stride_dst,
sao,
edges, width,
height, c_idx,
vert_edge,
horiz_edge,
diag_edge);
restore_tqb_pixels(l, pps, sps, src, dst, stride_src, stride_dst,
x, y, width, height, c_idx);
sao->type_idx[c_idx] = SAO_APPLIED;
break;
}
}
}
}
static int get_pcm(const HEVCSPS *sps, const uint8_t *is_pcm, int x, int y)
{
int log2_min_pu_size = sps->log2_min_pu_size;
int x_pu, y_pu;
if (x < 0 || y < 0)
return 2;
x_pu = x >> log2_min_pu_size;
y_pu = y >> log2_min_pu_size;
if (x_pu >= sps->min_pu_width || y_pu >= sps->min_pu_height)
return 2;
return is_pcm[y_pu * sps->min_pu_width + x_pu];
}
#define TC_CALC(qp, bs) \
tctable[av_clip((qp) + DEFAULT_INTRA_TC_OFFSET * ((bs) - 1) + \
(tc_offset & -2), \
0, MAX_QP + DEFAULT_INTRA_TC_OFFSET)]
static void deblocking_filter_CTB(const HEVCContext *s, const HEVCLayerContext *l,
const HEVCPPS *pps, const HEVCSPS *sps,
int x0, int y0)
{
uint8_t **data = s->cur_frame->f->data;
int *linesize = s->cur_frame->f->linesize;
uint8_t *src;
int x, y;
int chroma, beta;
int32_t c_tc[2], tc[2];
uint8_t no_p[2] = { 0 };
uint8_t no_q[2] = { 0 };
int log2_ctb_size = sps->log2_ctb_size;
int x_end, x_end2, y_end;
int ctb_size = 1 << log2_ctb_size;
int ctb = (x0 >> log2_ctb_size) +
(y0 >> log2_ctb_size) * sps->ctb_width;
int cur_tc_offset = l->deblock[ctb].tc_offset;
int cur_beta_offset = l->deblock[ctb].beta_offset;
int left_tc_offset, left_beta_offset;
int tc_offset, beta_offset;
int pcmf = (sps->pcm_enabled &&
sps->pcm_loop_filter_disabled) ||
pps->transquant_bypass_enable_flag;
if (x0) {
left_tc_offset = l->deblock[ctb - 1].tc_offset;
left_beta_offset = l->deblock[ctb - 1].beta_offset;
} else {
left_tc_offset = 0;
left_beta_offset = 0;
}
x_end = x0 + ctb_size;
if (x_end > sps->width)
x_end = sps->width;
y_end = y0 + ctb_size;
if (y_end > sps->height)
y_end = sps->height;
tc_offset = cur_tc_offset;
beta_offset = cur_beta_offset;
x_end2 = x_end;
if (x_end2 != sps->width)
x_end2 -= 8;
for (y = y0; y < y_end; y += 8) {
// vertical filtering luma
for (x = x0 ? x0 : 8; x < x_end; x += 8) {
const int bs0 = l->vertical_bs[(x + y * l->bs_width) >> 2];
const int bs1 = l->vertical_bs[(x + (y + 4) * l->bs_width) >> 2];
if (bs0 || bs1) {
const int qp = (get_qPy(sps, l->qp_y_tab, x - 1, y) +
get_qPy(sps, l->qp_y_tab, x, y) + 1) >> 1;
beta = betatable[av_clip(qp + beta_offset, 0, MAX_QP)];
tc[0] = bs0 ? TC_CALC(qp, bs0) : 0;
tc[1] = bs1 ? TC_CALC(qp, bs1) : 0;
src = &data[LUMA][y * linesize[LUMA] + (x << sps->pixel_shift)];
if (pcmf) {
no_p[0] = get_pcm(sps, l->is_pcm, x - 1, y);
no_p[1] = get_pcm(sps, l->is_pcm, x - 1, y + 4);
no_q[0] = get_pcm(sps, l->is_pcm, x, y);
no_q[1] = get_pcm(sps, l->is_pcm, x, y + 4);
s->hevcdsp.hevc_v_loop_filter_luma_c(src, linesize[LUMA],
beta, tc, no_p, no_q);
} else
s->hevcdsp.hevc_v_loop_filter_luma(src, linesize[LUMA],
beta, tc, no_p, no_q);
}
}
if(!y)
continue;
// horizontal filtering luma
for (x = x0 ? x0 - 8 : 0; x < x_end2; x += 8) {
const int bs0 = l->horizontal_bs[( x + y * l->bs_width) >> 2];
const int bs1 = l->horizontal_bs[((x + 4) + y * l->bs_width) >> 2];
if (bs0 || bs1) {
const int qp = (get_qPy(sps, l->qp_y_tab, x, y - 1) +
get_qPy(sps, l->qp_y_tab, x, y) + 1) >> 1;
tc_offset = x >= x0 ? cur_tc_offset : left_tc_offset;
beta_offset = x >= x0 ? cur_beta_offset : left_beta_offset;
beta = betatable[av_clip(qp + beta_offset, 0, MAX_QP)];
tc[0] = bs0 ? TC_CALC(qp, bs0) : 0;
tc[1] = bs1 ? TC_CALC(qp, bs1) : 0;
src = &data[LUMA][y * linesize[LUMA] + (x << sps->pixel_shift)];
if (pcmf) {
no_p[0] = get_pcm(sps, l->is_pcm, x, y - 1);
no_p[1] = get_pcm(sps, l->is_pcm, x + 4, y - 1);
no_q[0] = get_pcm(sps, l->is_pcm, x, y);
no_q[1] = get_pcm(sps, l->is_pcm, x + 4, y);
s->hevcdsp.hevc_h_loop_filter_luma_c(src, linesize[LUMA],
beta, tc, no_p, no_q);
} else
s->hevcdsp.hevc_h_loop_filter_luma(src, linesize[LUMA],
beta, tc, no_p, no_q);
}
}
}
if (sps->chroma_format_idc) {
for (chroma = 1; chroma <= 2; chroma++) {
int h = 1 << sps->hshift[chroma];
int v = 1 << sps->vshift[chroma];
// vertical filtering chroma
for (y = y0; y < y_end; y += (8 * v)) {
for (x = x0 ? x0 : 8 * h; x < x_end; x += (8 * h)) {
const int bs0 = l->vertical_bs[(x + y * l->bs_width) >> 2];
const int bs1 = l->vertical_bs[(x + (y + (4 * v)) * l->bs_width) >> 2];
if ((bs0 == 2) || (bs1 == 2)) {
const int qp0 = (get_qPy(sps, l->qp_y_tab, x - 1, y) +
get_qPy(sps, l->qp_y_tab, x, y) + 1) >> 1;
const int qp1 = (get_qPy(sps, l->qp_y_tab, x - 1, y + (4 * v)) +
get_qPy(sps, l->qp_y_tab, x, y + (4 * v)) + 1) >> 1;
c_tc[0] = (bs0 == 2) ? chroma_tc(pps, sps, qp0, chroma, tc_offset) : 0;
c_tc[1] = (bs1 == 2) ? chroma_tc(pps, sps, qp1, chroma, tc_offset) : 0;
src = &data[chroma][(y >> sps->vshift[chroma]) * linesize[chroma] + ((x >> sps->hshift[chroma]) << sps->pixel_shift)];
if (pcmf) {
no_p[0] = get_pcm(sps, l->is_pcm, x - 1, y);
no_p[1] = get_pcm(sps, l->is_pcm, x - 1, y + (4 * v));
no_q[0] = get_pcm(sps, l->is_pcm, x, y);
no_q[1] = get_pcm(sps, l->is_pcm, x, y + (4 * v));
s->hevcdsp.hevc_v_loop_filter_chroma_c(src, linesize[chroma],
c_tc, no_p, no_q);
} else
s->hevcdsp.hevc_v_loop_filter_chroma(src, linesize[chroma],
c_tc, no_p, no_q);
}
}
if(!y)
continue;
// horizontal filtering chroma
tc_offset = x0 ? left_tc_offset : cur_tc_offset;
x_end2 = x_end;
if (x_end != sps->width)
x_end2 = x_end - 8 * h;
for (x = x0 ? x0 - 8 * h : 0; x < x_end2; x += (8 * h)) {
const int bs0 = l->horizontal_bs[( x + y * l->bs_width) >> 2];
const int bs1 = l->horizontal_bs[((x + 4 * h) + y * l->bs_width) >> 2];
if ((bs0 == 2) || (bs1 == 2)) {
const int qp0 = bs0 == 2 ? (get_qPy(sps, l->qp_y_tab, x, y - 1) +
get_qPy(sps, l->qp_y_tab, x, y) + 1) >> 1 : 0;
const int qp1 = bs1 == 2 ? (get_qPy(sps, l->qp_y_tab, x + (4 * h), y - 1) +
get_qPy(sps, l->qp_y_tab, x + (4 * h), y) + 1) >> 1 : 0;
c_tc[0] = bs0 == 2 ? chroma_tc(pps, sps, qp0, chroma, tc_offset) : 0;
c_tc[1] = bs1 == 2 ? chroma_tc(pps, sps, qp1, chroma, cur_tc_offset) : 0;
src = &data[chroma][(y >> sps->vshift[1]) * linesize[chroma] + ((x >> sps->hshift[1]) << sps->pixel_shift)];
if (pcmf) {
no_p[0] = get_pcm(sps, l->is_pcm, x, y - 1);
no_p[1] = get_pcm(sps, l->is_pcm, x + (4 * h), y - 1);
no_q[0] = get_pcm(sps, l->is_pcm, x, y);
no_q[1] = get_pcm(sps, l->is_pcm, x + (4 * h), y);
s->hevcdsp.hevc_h_loop_filter_chroma_c(src, linesize[chroma],
c_tc, no_p, no_q);
} else
s->hevcdsp.hevc_h_loop_filter_chroma(src, linesize[chroma],
c_tc, no_p, no_q);
}
}
}
}
}
}
static int boundary_strength(const HEVCContext *s, const MvField *curr, const MvField *neigh,
const RefPicList *neigh_refPicList)
{
if (curr->pred_flag == PF_BI && neigh->pred_flag == PF_BI) {
// same L0 and L1
if (s->cur_frame->refPicList[0].list[curr->ref_idx[0]] == neigh_refPicList[0].list[neigh->ref_idx[0]] &&
s->cur_frame->refPicList[0].list[curr->ref_idx[0]] == s->cur_frame->refPicList[1].list[curr->ref_idx[1]] &&
neigh_refPicList[0].list[neigh->ref_idx[0]] == neigh_refPicList[1].list[neigh->ref_idx[1]]) {
if ((FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4) &&
(FFABS(neigh->mv[1].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
FFABS(neigh->mv[0].x - curr->mv[1].x) >= 4 || FFABS(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->cur_frame->refPicList[0].list[curr->ref_idx[0]] &&
neigh_refPicList[1].list[neigh->ref_idx[1]] == s->cur_frame->refPicList[1].list[curr->ref_idx[1]]) {
if (FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(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->cur_frame->refPicList[0].list[curr->ref_idx[0]] &&
neigh_refPicList[0].list[neigh->ref_idx[0]] == s->cur_frame->refPicList[1].list[curr->ref_idx[1]]) {
if (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
FFABS(neigh->mv[0].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[1].y) >= 4)
return 1;
else
return 0;
} else {
return 1;
}
} else if ((curr->pred_flag != PF_BI) && (neigh->pred_flag != PF_BI)){ // 1 MV
Mv A, B;
int ref_A, ref_B;
if (curr->pred_flag & 1) {
A = curr->mv[0];
ref_A = s->cur_frame->refPicList[0].list[curr->ref_idx[0]];
} else {
A = curr->mv[1];
ref_A = s->cur_frame->refPicList[1].list[curr->ref_idx[1]];
}
if (neigh->pred_flag & 1) {
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 (FFABS(A.x - B.x) >= 4 || FFABS(A.y - B.y) >= 4)
return 1;
else
return 0;
} else
return 1;
}
return 1;
}
void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayerContext *l,
const HEVCPPS *pps,
int x0, int y0, int log2_trafo_size)
{
const HEVCSPS *const sps = pps->sps;
const HEVCContext *s = lc->parent;
const MvField *tab_mvf = s->cur_frame->tab_mvf;
int log2_min_pu_size = sps->log2_min_pu_size;
int log2_min_tu_size = sps->log2_min_tb_size;
int min_pu_width = sps->min_pu_width;
int min_tu_width = sps->min_tb_width;
int is_intra = tab_mvf[(y0 >> log2_min_pu_size) * min_pu_width +
(x0 >> log2_min_pu_size)].pred_flag == PF_INTRA;
int boundary_upper, boundary_left;
int i, j, bs;
boundary_upper = y0 > 0 && !(y0 & 7);
if (boundary_upper &&
((!s->sh.slice_loop_filter_across_slices_enabled_flag &&
lc->boundary_flags & BOUNDARY_UPPER_SLICE &&
(y0 % (1 << sps->log2_ctb_size)) == 0) ||
(!pps->loop_filter_across_tiles_enabled_flag &&
lc->boundary_flags & BOUNDARY_UPPER_TILE &&
(y0 % (1 << sps->log2_ctb_size)) == 0)))
boundary_upper = 0;
if (boundary_upper) {
const RefPicList *rpl_top = (lc->boundary_flags & BOUNDARY_UPPER_SLICE) ?
ff_hevc_get_ref_list(s->cur_frame, x0, y0 - 1) :
s->cur_frame->refPicList;
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;
const MvField *top = &tab_mvf[yp_pu * min_pu_width + x_pu];
const MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu];
uint8_t top_cbf_luma = l->cbf_luma[yp_tu * min_tu_width + x_tu];
uint8_t curr_cbf_luma = l->cbf_luma[yq_tu * min_tu_width + x_tu];
if (curr->pred_flag == PF_INTRA || top->pred_flag == PF_INTRA)
bs = 2;
else if (curr_cbf_luma || top_cbf_luma)
bs = 1;
else
bs = boundary_strength(s, curr, top, rpl_top);
l->horizontal_bs[((x0 + i) + y0 * l->bs_width) >> 2] = bs;
}
}
// bs for vertical TU boundaries
boundary_left = x0 > 0 && !(x0 & 7);
if (boundary_left &&
((!s->sh.slice_loop_filter_across_slices_enabled_flag &&
lc->boundary_flags & BOUNDARY_LEFT_SLICE &&
(x0 % (1 << sps->log2_ctb_size)) == 0) ||
(!pps->loop_filter_across_tiles_enabled_flag &&
lc->boundary_flags & BOUNDARY_LEFT_TILE &&
(x0 % (1 << sps->log2_ctb_size)) == 0)))
boundary_left = 0;
if (boundary_left) {
const RefPicList *rpl_left = (lc->boundary_flags & BOUNDARY_LEFT_SLICE) ?
ff_hevc_get_ref_list(s->cur_frame, x0 - 1, y0) :
s->cur_frame->refPicList;
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;
const MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
const MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];
uint8_t left_cbf_luma = l->cbf_luma[y_tu * min_tu_width + xp_tu];
uint8_t curr_cbf_luma = l->cbf_luma[y_tu * min_tu_width + xq_tu];
if (curr->pred_flag == PF_INTRA || left->pred_flag == PF_INTRA)
bs = 2;
else if (curr_cbf_luma || left_cbf_luma)
bs = 1;
else
bs = boundary_strength(s, curr, left, rpl_left);
l->vertical_bs[(x0 + (y0 + i) * l->bs_width) >> 2] = bs;
}
}
if (log2_trafo_size > log2_min_pu_size && !is_intra) {
const RefPicList *rpl = s->cur_frame->refPicList;
// bs for TU internal horizontal PU boundaries
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;
for (i = 0; i < (1 << log2_trafo_size); i += 4) {
int x_pu = (x0 + i) >> log2_min_pu_size;
const MvField *top = &tab_mvf[yp_pu * min_pu_width + x_pu];
const MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu];
bs = boundary_strength(s, curr, top, rpl);
l->horizontal_bs[((x0 + i) + (y0 + j) * l->bs_width) >> 2] = bs;
}
}
// bs for TU internal vertical PU boundaries
for (j = 0; j < (1 << log2_trafo_size); j += 4) {
int y_pu = (y0 + j) >> log2_min_pu_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;
const MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
const MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];
bs = boundary_strength(s, curr, left, rpl);
l->vertical_bs[((x0 + i) + (y0 + j) * l->bs_width) >> 2] = bs;
}
}
}
}
#undef LUMA
#undef CB
#undef CR
void ff_hevc_hls_filter(HEVCLocalContext *lc, const HEVCLayerContext *l,
const HEVCPPS *pps,
int x, int y, int ctb_size)
{
const HEVCSPS *const sps = pps->sps;
const HEVCContext *const s = lc->parent;
int x_end = x >= sps->width - ctb_size;
int skip = 0;
if (s->avctx->skip_loop_filter >= AVDISCARD_ALL ||
(s->avctx->skip_loop_filter >= AVDISCARD_NONKEY && !IS_IDR(s)) ||
(s->avctx->skip_loop_filter >= AVDISCARD_NONINTRA &&
s->sh.slice_type != HEVC_SLICE_I) ||
(s->avctx->skip_loop_filter >= AVDISCARD_BIDIR &&
s->sh.slice_type == HEVC_SLICE_B) ||
(s->avctx->skip_loop_filter >= AVDISCARD_NONREF &&
ff_hevc_nal_is_nonref(s->nal_unit_type)))
skip = 1;
if (!skip)
deblocking_filter_CTB(s, l, pps, sps, x, y);
if (sps->sao_enabled && !skip) {
int y_end = y >= sps->height - ctb_size;
if (y && x)
sao_filter_CTB(lc, l, s, pps, sps, x - ctb_size, y - ctb_size);
if (x && y_end)
sao_filter_CTB(lc, l, s, pps, sps, x - ctb_size, y);
if (y && x_end) {
sao_filter_CTB(lc, l, s, pps, sps, x, y - ctb_size);
if (s->avctx->active_thread_type & FF_THREAD_FRAME )
ff_progress_frame_report(&s->cur_frame->tf, y);
}
if (x_end && y_end) {
sao_filter_CTB(lc, l, s, pps, sps, x , y);
if (s->avctx->active_thread_type & FF_THREAD_FRAME )
ff_progress_frame_report(&s->cur_frame->tf, y + ctb_size);
}
} else if (s->avctx->active_thread_type & FF_THREAD_FRAME && x_end)
ff_progress_frame_report(&s->cur_frame->tf, y + ctb_size - 4);
}
void ff_hevc_hls_filters(HEVCLocalContext *lc, const HEVCLayerContext *l,
const HEVCPPS *pps,
int x_ctb, int y_ctb, int ctb_size)
{
int x_end = x_ctb >= pps->sps->width - ctb_size;
int y_end = y_ctb >= pps->sps->height - ctb_size;
if (y_ctb && x_ctb)
ff_hevc_hls_filter(lc, l, pps, x_ctb - ctb_size, y_ctb - ctb_size, ctb_size);
if (y_ctb && x_end)
ff_hevc_hls_filter(lc, l, pps, x_ctb, y_ctb - ctb_size, ctb_size);
if (x_ctb && y_end)
ff_hevc_hls_filter(lc, l, pps, x_ctb - ctb_size, y_ctb, ctb_size);
}
+178
View File
@@ -0,0 +1,178 @@
/*
* HEVC shared code
*
* 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_HEVC_H
#define AVCODEC_HEVC_HEVC_H
/**
* Table 7-1 NAL unit type codes and NAL unit type classes in
* T-REC-H.265-201802
*/
enum HEVCNALUnitType {
HEVC_NAL_TRAIL_N = 0,
HEVC_NAL_TRAIL_R = 1,
HEVC_NAL_TSA_N = 2,
HEVC_NAL_TSA_R = 3,
HEVC_NAL_STSA_N = 4,
HEVC_NAL_STSA_R = 5,
HEVC_NAL_RADL_N = 6,
HEVC_NAL_RADL_R = 7,
HEVC_NAL_RASL_N = 8,
HEVC_NAL_RASL_R = 9,
HEVC_NAL_VCL_N10 = 10,
HEVC_NAL_VCL_R11 = 11,
HEVC_NAL_VCL_N12 = 12,
HEVC_NAL_VCL_R13 = 13,
HEVC_NAL_VCL_N14 = 14,
HEVC_NAL_VCL_R15 = 15,
HEVC_NAL_BLA_W_LP = 16,
HEVC_NAL_BLA_W_RADL = 17,
HEVC_NAL_BLA_N_LP = 18,
HEVC_NAL_IDR_W_RADL = 19,
HEVC_NAL_IDR_N_LP = 20,
HEVC_NAL_CRA_NUT = 21,
HEVC_NAL_RSV_IRAP_VCL22 = 22,
HEVC_NAL_RSV_IRAP_VCL23 = 23,
HEVC_NAL_RSV_VCL24 = 24,
HEVC_NAL_RSV_VCL25 = 25,
HEVC_NAL_RSV_VCL26 = 26,
HEVC_NAL_RSV_VCL27 = 27,
HEVC_NAL_RSV_VCL28 = 28,
HEVC_NAL_RSV_VCL29 = 29,
HEVC_NAL_RSV_VCL30 = 30,
HEVC_NAL_RSV_VCL31 = 31,
HEVC_NAL_VPS = 32,
HEVC_NAL_SPS = 33,
HEVC_NAL_PPS = 34,
HEVC_NAL_AUD = 35,
HEVC_NAL_EOS_NUT = 36,
HEVC_NAL_EOB_NUT = 37,
HEVC_NAL_FD_NUT = 38,
HEVC_NAL_SEI_PREFIX = 39,
HEVC_NAL_SEI_SUFFIX = 40,
HEVC_NAL_RSV_NVCL41 = 41,
HEVC_NAL_RSV_NVCL42 = 42,
HEVC_NAL_RSV_NVCL43 = 43,
HEVC_NAL_RSV_NVCL44 = 44,
HEVC_NAL_RSV_NVCL45 = 45,
HEVC_NAL_RSV_NVCL46 = 46,
HEVC_NAL_RSV_NVCL47 = 47,
HEVC_NAL_UNSPEC48 = 48,
HEVC_NAL_UNSPEC49 = 49,
HEVC_NAL_UNSPEC50 = 50,
HEVC_NAL_UNSPEC51 = 51,
HEVC_NAL_UNSPEC52 = 52,
HEVC_NAL_UNSPEC53 = 53,
HEVC_NAL_UNSPEC54 = 54,
HEVC_NAL_UNSPEC55 = 55,
HEVC_NAL_UNSPEC56 = 56,
HEVC_NAL_UNSPEC57 = 57,
HEVC_NAL_UNSPEC58 = 58,
HEVC_NAL_UNSPEC59 = 59,
HEVC_NAL_UNSPEC60 = 60,
HEVC_NAL_UNSPEC61 = 61,
HEVC_NAL_UNSPEC62 = 62,
HEVC_NAL_UNSPEC63 = 63,
};
enum HEVCSliceType {
HEVC_SLICE_B = 0,
HEVC_SLICE_P = 1,
HEVC_SLICE_I = 2,
};
enum {
// 7.4.3.1: vps_max_layers_minus1 is in [0, 62].
HEVC_MAX_LAYERS = 63,
// 7.4.3.1: vps_max_sub_layers_minus1 is in [0, 6].
HEVC_MAX_SUB_LAYERS = 7,
// 7.4.3.1: vps_num_layer_sets_minus1 is in [0, 1023].
HEVC_MAX_LAYER_SETS = 1024,
// 7.4.3.1: vps_max_layer_id is in [0, 63].
HEVC_MAX_LAYER_ID = 63,
HEVC_MAX_NUH_LAYER_ID = 62,
// 7.4.2.1: vps_video_parameter_set_id is u(4).
HEVC_MAX_VPS_COUNT = 16,
// 7.4.3.2.1: sps_seq_parameter_set_id is in [0, 15].
HEVC_MAX_SPS_COUNT = 16,
// 7.4.3.3.1: pps_pic_parameter_set_id is in [0, 63].
HEVC_MAX_PPS_COUNT = 64,
// A.4.2: MaxDpbSize is bounded above by 16.
HEVC_MAX_DPB_SIZE = 16,
// 7.4.3.1: vps_max_dec_pic_buffering_minus1[i] is in [0, MaxDpbSize - 1].
HEVC_MAX_REFS = HEVC_MAX_DPB_SIZE,
// 7.4.3.2.1: num_short_term_ref_pic_sets is in [0, 64].
HEVC_MAX_SHORT_TERM_REF_PIC_SETS = 64,
// 7.4.3.2.1: num_long_term_ref_pics_sps is in [0, 32].
HEVC_MAX_LONG_TERM_REF_PICS = 32,
// A.3: all profiles require that CtbLog2SizeY is in [4, 6].
HEVC_MIN_LOG2_CTB_SIZE = 4,
HEVC_MAX_LOG2_CTB_SIZE = 6,
// E.3.2: cpb_cnt_minus1[i] is in [0, 31].
HEVC_MAX_CPB_CNT = 32,
// A.4.1: in table A.6 the highest level allows a MaxLumaPs of 35 651 584.
HEVC_MAX_LUMA_PS = 35651584,
// A.4.1: pic_width_in_luma_samples and pic_height_in_luma_samples are
// constrained to be not greater than sqrt(MaxLumaPs * 8). Hence height/
// width are bounded above by sqrt(8 * 35651584) = 16888.2 samples.
HEVC_MAX_WIDTH = 16888,
HEVC_MAX_HEIGHT = 16888,
// A.4.1: table A.6 allows at most 22 tile rows for any level.
HEVC_MAX_TILE_ROWS = 22,
// A.4.1: table A.6 allows at most 20 tile columns for any level.
HEVC_MAX_TILE_COLUMNS = 20,
// A.4.2: table A.6 allows at most 600 slice segments for any level.
HEVC_MAX_SLICE_SEGMENTS = 600,
// 7.4.7.1: in the worst case (tiles_enabled_flag and
// entropy_coding_sync_enabled_flag are both set), entry points can be
// placed at the beginning of every Ctb row in every tile, giving an
// upper bound of (num_tile_columns_minus1 + 1) * PicHeightInCtbsY - 1.
// Only a stream with very high resolution and perverse parameters could
// get near that, though, so set a lower limit here with the maximum
// possible value for 4K video (at most 135 16x16 Ctb rows).
HEVC_MAX_ENTRY_POINT_OFFSETS = HEVC_MAX_TILE_COLUMNS * 135,
// A.3.7: Screen content coding extensions
HEVC_MAX_PALETTE_PREDICTOR_SIZE = 128,
};
enum HEVCScalabilityMask {
HEVC_SCALABILITY_DEPTH = 1 << (15 - 0),
HEVC_SCALABILITY_MULTIVIEW = 1 << (15 - 1),
HEVC_SCALABILITY_SPATIAL = 1 << (15 - 2),
HEVC_SCALABILITY_AUXILIARY = 1 << (15 - 3),
HEVC_SCALABILITY_MASK_MAX = 0xFFFF,
};
enum HEVCAuxId {
HEVC_AUX_ALPHA = 1,
HEVC_AUX_DEPTH = 2,
};
#endif /* AVCODEC_HEVC_HEVC_H */
File diff suppressed because it is too large Load Diff
+729
View File
@@ -0,0 +1,729 @@
/*
* 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_HEVCDEC_H
#define AVCODEC_HEVC_HEVCDEC_H
#include <stdatomic.h>
#include "libavutil/buffer.h"
#include "libavutil/mem_internal.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/bswapdsp.h"
#include "libavcodec/cabac.h"
#include "libavcodec/dovi_rpu.h"
#include "libavcodec/get_bits.h"
#include "libavcodec/h2645_parse.h"
#include "libavcodec/h274.h"
#include "libavcodec/progressframe.h"
#include "libavcodec/videodsp.h"
#include "dsp.h"
#include "hevc.h"
#include "pred.h"
#include "ps.h"
#include "sei.h"
#define SHIFT_CTB_WPP 2
#define MAX_TB_SIZE 32
#define MAX_QP 51
#define DEFAULT_INTRA_TC_OFFSET 2
#define HEVC_CONTEXTS 199
#define HEVC_STAT_COEFFS 4
#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
#define QPEL_EXTRA_BEFORE 3
#define QPEL_EXTRA_AFTER 4
#define QPEL_EXTRA 7
#define EDGE_EMU_BUFFER_STRIDE 80
/**
* 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) * min_cb_width + (x)])
#define IS_IDR(s) ((s)->nal_unit_type == HEVC_NAL_IDR_W_RADL || (s)->nal_unit_type == HEVC_NAL_IDR_N_LP)
#define IS_BLA(s) ((s)->nal_unit_type == HEVC_NAL_BLA_W_RADL || (s)->nal_unit_type == HEVC_NAL_BLA_W_LP || \
(s)->nal_unit_type == HEVC_NAL_BLA_N_LP)
#define IS_IRAP(s) ((s)->nal_unit_type >= HEVC_NAL_BLA_W_LP && (s)->nal_unit_type <= HEVC_NAL_RSV_IRAP_VCL23)
#define HEVC_RECOVERY_UNSPECIFIED INT_MAX
#define HEVC_RECOVERY_END INT_MIN
#define HEVC_IS_RECOVERING(s) ((s)->recovery_poc != HEVC_RECOVERY_UNSPECIFIED && (s)->recovery_poc != HEVC_RECOVERY_END)
enum RPSType {
ST_CURR_BEF = 0,
ST_CURR_AFT,
ST_FOLL,
LT_CURR,
LT_FOLL,
INTER_LAYER0,
INTER_LAYER1,
NB_RPS_TYPE,
};
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 PredFlag {
PF_INTRA = 0,
PF_L0,
PF_L1,
PF_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,
SAO_APPLIED
};
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 HEVCCABACState {
uint8_t state[HEVC_CONTEXTS];
uint8_t stat_coeff[HEVC_STAT_COEFFS];
} HEVCCABACState;
typedef struct LongTermRPS {
int poc[32];
uint8_t poc_msb_present[32];
uint8_t used[32];
uint8_t nb_refs;
} LongTermRPS;
typedef struct RefPicList {
struct HEVCFrame *ref[HEVC_MAX_REFS];
int list[HEVC_MAX_REFS];
int isLongTerm[HEVC_MAX_REFS];
int nb_refs;
} RefPicList;
typedef struct RefPicListTab {
RefPicList refPicList[2];
} RefPicListTab;
typedef struct SliceHeader {
unsigned 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 HEVCSliceType slice_type;
int pic_order_cnt_lsb;
int poc;
uint8_t first_slice_in_pic_flag;
uint8_t dependent_slice_segment_flag;
uint8_t pic_output_flag;
uint8_t colour_plane_id;
uint8_t inter_layer_pred;
/// RPS coded in the slice header itself is stored here
int short_term_ref_pic_set_sps_flag;
int short_term_ref_pic_set_size;
ShortTermRPS slice_rps;
const ShortTermRPS *short_term_rps;
int long_term_ref_pic_set_size;
LongTermRPS long_term_rps;
unsigned int list_entry_lx[2][32];
uint8_t rpl_modification_flag[2];
uint8_t no_output_of_prior_pics_flag;
uint8_t slice_temporal_mvp_enabled_flag;
unsigned int nb_refs[2];
uint8_t slice_sample_adaptive_offset_flag[3];
uint8_t mvd_l1_zero_flag;
uint8_t cabac_init_flag;
uint8_t disable_deblocking_filter_flag; ///< slice_header_disable_deblocking_filter_flag
uint8_t slice_loop_filter_across_slices_enabled_flag;
uint8_t collocated_list;
unsigned int collocated_ref_idx;
int slice_qp_delta;
int slice_cb_qp_offset;
int slice_cr_qp_offset;
int slice_act_y_qp_offset;
int slice_act_cb_qp_offset;
int slice_act_cr_qp_offset;
uint8_t cu_chroma_qp_offset_enabled_flag;
int beta_offset; ///< beta_offset_div2 * 2
int tc_offset; ///< tc_offset_div2 * 2
uint8_t max_num_merge_cand; ///< 5 - 5_minus_max_num_merge_cand
uint8_t use_integer_mv_flag;
unsigned *entry_point_offset;
int * offset;
int * size;
int num_entry_point_offsets;
int8_t slice_qp;
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];
int slice_ctb_addr_rs;
unsigned data_offset;
} SliceHeader;
typedef struct CodingUnit {
int x;
int y;
enum PredMode pred_mode; ///< PredMode
enum PartMode part_mode; ///< PartMode
// Inferred parameters
uint8_t intra_split_flag; ///< IntraSplitFlag
uint8_t max_trafo_depth; ///< MaxTrafoDepth
uint8_t cu_transquant_bypass_flag;
} CodingUnit;
typedef struct Mv {
int16_t x; ///< horizontal component of motion vector
int16_t y; ///< vertical component of motion vector
} Mv;
typedef struct MvField {
DECLARE_ALIGNED(4, Mv, mv)[2];
int8_t ref_idx[2];
int8_t pred_flag;
} 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 {
int mpm_idx;
int rem_intra_luma_pred_mode;
uint8_t intra_pred_mode[4];
Mv mvd;
uint8_t merge_flag;
uint8_t intra_pred_mode_c[4];
uint8_t chroma_mode_c[4];
} PredictionUnit;
typedef struct TransformUnit {
int cu_qp_delta;
int res_scale_val;
// Inferred parameters;
int intra_pred_mode;
int intra_pred_mode_c;
int chroma_mode_c;
uint8_t is_cu_qp_delta_coded;
uint8_t is_cu_chroma_qp_offset_coded;
int8_t cu_qp_offset_cb;
int8_t cu_qp_offset_cr;
uint8_t cross_pf;
} TransformUnit;
typedef struct DBParams {
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)
#define HEVC_FRAME_FLAG_UNAVAILABLE (1 << 3)
#define HEVC_FRAME_FLAG_CORRUPT (1 << 4)
typedef struct HEVCFrame {
union {
struct {
AVFrame *f;
};
ProgressFrame tf;
};
AVFrame *frame_grain;
int needs_fg; /* 1 if grain needs to be applied by the decoder */
MvField *tab_mvf; ///< RefStruct reference
RefPicList *refPicList;
RefPicListTab **rpl_tab; ///< RefStruct reference
int ctb_count;
int poc;
const HEVCPPS *pps; ///< RefStruct reference
RefPicListTab *rpl; ///< RefStruct reference
int nb_rpl_elems;
void *hwaccel_picture_private; ///< RefStruct reference
// for secondary-layer frames, this is the DPB index of the base-layer frame
// from the same AU, if it exists, otherwise -1
int base_layer_frame;
/**
* A combination of HEVC_FRAME_FLAG_*
*/
uint8_t flags;
} HEVCFrame;
typedef struct HEVCLocalContext {
uint8_t cabac_state[HEVC_CONTEXTS];
uint8_t stat_coeff[HEVC_STAT_COEFFS];
uint8_t first_qp_group;
void *logctx;
const struct HEVCContext *parent;
CABACContext cc;
/**
* This is a pointer to the common CABAC state.
* In case entropy_coding_sync_enabled_flag is set,
* the CABAC state after decoding the second CTU in a row is
* stored here and used to initialize the CABAC state before
* decoding the first CTU in the next row.
* This is the basis for WPP and in case slice-threading is used,
* the next row is decoded by another thread making this state
* shared between threads.
*/
HEVCCABACState *common_cabac_state;
int8_t qp_y;
int8_t curr_qp_y;
int qPy_pred;
TransformUnit tu;
uint8_t ctb_left_flag;
uint8_t ctb_up_flag;
uint8_t ctb_up_right_flag;
uint8_t ctb_up_left_flag;
int end_of_tiles_x;
int end_of_tiles_y;
/* +7 is for subpixel interpolation, *2 for high bit depths */
DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2];
/* The extended size between the new edge emu buffer is abused by SAO */
DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer2)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2];
DECLARE_ALIGNED(32, int16_t, tmp)[MAX_PB_SIZE * MAX_PB_SIZE];
int ct_depth;
CodingUnit cu;
PredictionUnit pu;
NeighbourAvailable na;
#define BOUNDARY_LEFT_SLICE (1 << 0)
#define BOUNDARY_LEFT_TILE (1 << 1)
#define BOUNDARY_UPPER_SLICE (1 << 2)
#define BOUNDARY_UPPER_TILE (1 << 3)
/* properties of the boundary of the current CTB for the purposes
* of the deblocking filter */
int boundary_flags;
// an array of these structs is used for per-thread state - pad its size
// to avoid false sharing
char padding[128];
} HEVCLocalContext;
typedef struct HEVCLayerContext {
HEVCFrame DPB[32];
HEVCFrame *cur_frame;
const HEVCSPS *sps; // RefStruct reference
int bs_width;
int bs_height;
SAOParams *sao;
DBParams *deblock;
// CU
uint8_t *skip_flag;
uint8_t *tab_ct_depth;
// PU
uint8_t *cbf_luma; // cbf_luma of colocated TU
uint8_t *tab_ipm;
uint8_t *is_pcm;
// CTB-level flags affecting loop filter operation
uint8_t *filter_slice_edges;
int32_t *tab_slice_address;
int8_t *qp_y_tab;
uint8_t *horizontal_bs;
uint8_t *vertical_bs;
uint8_t *sao_pixel_buffer_h[3];
uint8_t *sao_pixel_buffer_v[3];
struct AVRefStructPool *tab_mvf_pool;
struct AVRefStructPool *rpl_tab_pool;
} HEVCLayerContext;
typedef struct HEVCContext {
const AVClass *c; // needed by private avoptions
AVCodecContext *avctx;
HEVCLocalContext *local_ctx;
unsigned nb_local_ctx;
// per-layer decoding state, addressed by VPS layer indices
HEVCLayerContext layers[HEVC_VPS_MAX_LAYERS];
// VPS index of the layer currently being decoded
unsigned cur_layer;
// bitmask of layer indices that are active for decoding/output
unsigned layers_active_decode;
unsigned layers_active_output;
/** 1 if the independent slice segment header was successfully parsed */
uint8_t slice_initialized;
struct AVContainerFifo *output_fifo;
HEVCParamSets ps;
HEVCSEI sei;
struct AVMD5 *md5_ctx;
/// candidate references for the current frame
RefPicList rps[NB_RPS_TYPE];
const HEVCVPS *vps; ///< RefStruct reference
const HEVCPPS *pps; ///< RefStruct reference
SliceHeader sh;
enum HEVCNALUnitType nal_unit_type;
int temporal_id; ///< temporal_id_plus1 - 1
HEVCFrame *cur_frame;
HEVCFrame *collocated_ref;
int poc;
int poc_tid0;
int slice_idx; ///< number of the slice being currently decoded
int eos; ///< current packet contains an EOS/EOB NAL
int last_eos; ///< last packet contains an EOS/EOB NAL
int recovery_poc;
// NoRaslOutputFlag associated with the last IRAP frame
int no_rasl_output_flag;
HEVCPredContext hpc;
HEVCDSPContext hevcdsp;
VideoDSPContext vdsp;
BswapDSPContext bdsp;
H274FilmGrainDatabase h274db;
/** used on BE to byteswap the lines for checksumming */
uint8_t *checksum_buf;
int checksum_buf_size;
/** The target for the common_cabac_state of the local contexts. */
HEVCCABACState cabac;
struct ThreadProgress *wpp_progress;
unsigned nb_wpp_progress;
atomic_int wpp_err;
const uint8_t *data;
H2645Packet pkt;
// type of the first VCL NAL of the current frame
enum HEVCNALUnitType first_nal_type;
// index in pkt.nals of the NAL unit after which we can call
// ff_thread_finish_setup()
unsigned finish_setup_nal_idx;
int is_nalff; ///< this flag is != 0 if bitstream is encapsulated
///< as a format defined in 14496-15
int apply_defdispwin;
// multi-layer AVOptions
int *view_ids;
unsigned nb_view_ids;
unsigned *view_ids_available;
unsigned nb_view_ids_available;
unsigned *view_pos_available;
unsigned nb_view_pos_available;
int nal_length_size; ///< Number of bytes used for nal length (1, 2 or 4)
int nuh_layer_id;
int film_grain_warning_shown;
// dts of the packet currently being decoded
int64_t pkt_dts;
AVBufferRef *rpu_buf; ///< 0 or 1 Dolby Vision RPUs.
DOVIContext dovi_ctx; ///< Dolby Vision decoding context
} HEVCContext;
/**
* Mark all frames in DPB as unused for reference.
*/
void ff_hevc_clear_refs(HEVCLayerContext *l);
/**
* Drop all frames currently in DPB.
*/
void ff_hevc_flush_dpb(HEVCContext *s);
const RefPicList *ff_hevc_get_ref_list(const HEVCFrame *frame, int x0, int y0);
/**
* Construct the reference picture sets for the current frame.
*/
int ff_hevc_frame_rps(HEVCContext *s, HEVCLayerContext *l);
/**
* Construct the reference picture list(s) for the current slice.
*/
int ff_hevc_slice_rpl(HEVCContext *s);
void ff_hevc_save_states(HEVCLocalContext *lc, const HEVCPPS *pps,
int ctb_addr_ts);
int ff_hevc_cabac_init(HEVCLocalContext *lc, const HEVCPPS *pps,
int ctb_addr_ts, const uint8_t *data, size_t size,
int is_wpp);
int ff_hevc_sao_merge_flag_decode(HEVCLocalContext *lc);
int ff_hevc_sao_type_idx_decode(HEVCLocalContext *lc);
int ff_hevc_sao_band_position_decode(HEVCLocalContext *lc);
int ff_hevc_sao_offset_abs_decode(HEVCLocalContext *lc, int bit_depth);
int ff_hevc_sao_offset_sign_decode(HEVCLocalContext *lc);
int ff_hevc_sao_eo_class_decode(HEVCLocalContext *lc);
int ff_hevc_end_of_slice_flag_decode(HEVCLocalContext *lc);
int ff_hevc_cu_transquant_bypass_flag_decode(HEVCLocalContext *lc);
int ff_hevc_skip_flag_decode(HEVCLocalContext *lc, uint8_t *skip_flag,
int x0, int y0, int x_cb, int y_cb, int min_cb_width);
int ff_hevc_pred_mode_decode(HEVCLocalContext *lc);
int ff_hevc_split_coding_unit_flag_decode(HEVCLocalContext *lc, uint8_t *tab_ct_depth,
const HEVCSPS *sps,
int ct_depth, int x0, int y0);
int ff_hevc_part_mode_decode(HEVCLocalContext *lc, const HEVCSPS *sps, int log2_cb_size);
int ff_hevc_pcm_flag_decode(HEVCLocalContext *lc);
int ff_hevc_prev_intra_luma_pred_flag_decode(HEVCLocalContext *lc);
int ff_hevc_mpm_idx_decode(HEVCLocalContext *lc);
int ff_hevc_rem_intra_luma_pred_mode_decode(HEVCLocalContext *lc);
int ff_hevc_intra_chroma_pred_mode_decode(HEVCLocalContext *lc);
int ff_hevc_merge_idx_decode(HEVCLocalContext *lc);
int ff_hevc_merge_flag_decode(HEVCLocalContext *lc);
int ff_hevc_inter_pred_idc_decode(HEVCLocalContext *lc, int nPbW, int nPbH);
int ff_hevc_ref_idx_lx_decode(HEVCLocalContext *lc, int num_ref_idx_lx);
int ff_hevc_mvp_lx_flag_decode(HEVCLocalContext *lc);
int ff_hevc_no_residual_syntax_flag_decode(HEVCLocalContext *lc);
int ff_hevc_split_transform_flag_decode(HEVCLocalContext *lc, int log2_trafo_size);
int ff_hevc_cbf_cb_cr_decode(HEVCLocalContext *lc, int trafo_depth);
int ff_hevc_cbf_luma_decode(HEVCLocalContext *lc, int trafo_depth);
int ff_hevc_log2_res_scale_abs(HEVCLocalContext *lc, int idx);
int ff_hevc_res_scale_sign_flag(HEVCLocalContext *lc, int idx);
/**
* Get the number of candidate references for the current frame.
*/
int ff_hevc_frame_nb_refs(const SliceHeader *sh, const HEVCPPS *pps,
unsigned layer_idx);
int ff_hevc_set_new_ref(HEVCContext *s, HEVCLayerContext *l, int poc);
static av_always_inline int ff_hevc_nal_is_nonref(enum HEVCNALUnitType type)
{
switch (type) {
case HEVC_NAL_TRAIL_N:
case HEVC_NAL_TSA_N:
case HEVC_NAL_STSA_N:
case HEVC_NAL_RADL_N:
case HEVC_NAL_RASL_N:
case HEVC_NAL_VCL_N10:
case HEVC_NAL_VCL_N12:
case HEVC_NAL_VCL_N14:
return 1;
default: break;
}
return 0;
}
/**
* Find frames in the DPB that are ready for output and either write them to the
* output FIFO or drop their output flag, depending on the value of discard.
*
* @param max_output maximum number of AUs with an output-pending frame in at
* least one layer that can be present in the DPB before output
* is triggered
* @param max_dpb maximum number of any frames that can be present in the DPB
* for any layer before output is triggered
*/
int ff_hevc_output_frames(HEVCContext *s,
unsigned layers_active_decode, unsigned layers_active_output,
unsigned max_output, unsigned max_dpb, int discard);
void ff_hevc_unref_frame(HEVCFrame *frame, int flags);
void ff_hevc_set_neighbour_available(HEVCLocalContext *lc, int x0, int y0,
int nPbW, int nPbH, int log2_ctb_size);
void ff_hevc_luma_mv_merge_mode(HEVCLocalContext *lc, const HEVCPPS *pps,
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(HEVCLocalContext *lc, const HEVCPPS *pps,
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_hls_filter(HEVCLocalContext *lc, const HEVCLayerContext *l,
const HEVCPPS *pps,
int x, int y, int ctb_size);
void ff_hevc_hls_filters(HEVCLocalContext *lc, const HEVCLayerContext *l,
const HEVCPPS *pps,
int x_ctb, int y_ctb, int ctb_size);
void ff_hevc_set_qPy(HEVCLocalContext *lc,
const HEVCLayerContext *l, const HEVCPPS *pps,
int xBase, int yBase, int log2_cb_size);
void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayerContext *l,
const HEVCPPS *pps,
int x0, int y0, int log2_trafo_size);
int ff_hevc_cu_qp_delta_sign_flag(HEVCLocalContext *lc);
int ff_hevc_cu_qp_delta_abs(HEVCLocalContext *lc);
int ff_hevc_cu_chroma_qp_offset_flag(HEVCLocalContext *lc);
int ff_hevc_cu_chroma_qp_offset_idx(HEVCLocalContext *lc, int chroma_qp_offset_list_len_minus1);
void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
int x0, int y0,
int log2_trafo_size, enum ScanType scan_idx,
int c_idx);
void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
int ff_hevc_is_alpha_video(const HEVCContext *s);
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];
#endif /* AVCODEC_HEVC_HEVCDEC_H */
+783
View File
@@ -0,0 +1,783 @@
/*
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2013 Anand Meher Kotra
*
* 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 "hevcdec.h"
#include "progressframe.h"
static const uint8_t l0_l1_cand_idx[12][2] = {
{ 0, 1, },
{ 1, 0, },
{ 0, 2, },
{ 2, 0, },
{ 1, 2, },
{ 2, 1, },
{ 0, 3, },
{ 3, 0, },
{ 1, 3, },
{ 3, 1, },
{ 2, 3, },
{ 3, 2, },
};
void ff_hevc_set_neighbour_available(HEVCLocalContext *lc, int x0, int y0,
int nPbW, int nPbH, int log2_ctb_size)
{
int x0b = av_zero_extend(x0, log2_ctb_size);
int y0b = av_zero_extend(y0, log2_ctb_size);
lc->na.cand_up = (lc->ctb_up_flag || y0b);
lc->na.cand_left = (lc->ctb_left_flag || x0b);
lc->na.cand_up_left = (x0b || y0b) ? lc->na.cand_left && lc->na.cand_up : lc->ctb_up_left_flag;
lc->na.cand_up_right_sap =
(x0b + nPbW == 1 << log2_ctb_size) ?
lc->ctb_up_right_flag && !y0b : lc->na.cand_up;
lc->na.cand_up_right =
lc->na.cand_up_right_sap
&& (x0 + nPbW) < lc->end_of_tiles_x;
lc->na.cand_bottom_left = ((y0 + nPbH) >= lc->end_of_tiles_y) ? 0 : lc->na.cand_left;
}
/*
* 6.4.1 Derivation process for z-scan order block availability
*/
static av_always_inline int
z_scan_block_avail(const HEVCPPS *pps, const HEVCSPS *sps,
int xCurr, int yCurr, int xN, int yN)
{
#define MIN_TB_ADDR_ZS(x, y) \
pps->min_tb_addr_zs[(y) * (sps->tb_mask+2) + (x)]
int xCurr_ctb = xCurr >> sps->log2_ctb_size;
int yCurr_ctb = yCurr >> sps->log2_ctb_size;
int xN_ctb = xN >> sps->log2_ctb_size;
int yN_ctb = yN >> sps->log2_ctb_size;
if( yN_ctb < yCurr_ctb || xN_ctb < xCurr_ctb )
return 1;
else {
int Curr = MIN_TB_ADDR_ZS((xCurr >> sps->log2_min_tb_size) & sps->tb_mask,
(yCurr >> sps->log2_min_tb_size) & sps->tb_mask);
int N = MIN_TB_ADDR_ZS((xN >> sps->log2_min_tb_size) & sps->tb_mask,
(yN >> sps->log2_min_tb_size) & sps->tb_mask);
return N <= Curr;
}
}
//check if the two luma locations belong to the same motion estimation region
static av_always_inline int is_diff_mer(const HEVCPPS *pps, int xN, int yN, int xP, int yP)
{
uint8_t plevel = pps->log2_parallel_merge_level;
return xN >> plevel == xP >> plevel &&
yN >> plevel == yP >> plevel;
}
#define MATCH_MV(x) (AV_RN32A(&A.x) == AV_RN32A(&B.x))
#define MATCH(x) (A.x == B.x)
// check if the mv's and refidx are the same between A and B
static av_always_inline int compare_mv_ref_idx(struct MvField A, struct MvField B)
{
int a_pf = A.pred_flag;
int b_pf = B.pred_flag;
if (a_pf == b_pf) {
if (a_pf == PF_BI) {
return MATCH(ref_idx[0]) && MATCH_MV(mv[0]) &&
MATCH(ref_idx[1]) && MATCH_MV(mv[1]);
} else if (a_pf == PF_L0) {
return MATCH(ref_idx[0]) && MATCH_MV(mv[0]);
} else if (a_pf == PF_L1) {
return MATCH(ref_idx[1]) && MATCH_MV(mv[1]);
}
}
return 0;
}
static av_always_inline void mv_scale(Mv *dst, const Mv *src, int td, int tb)
{
int tx, scale_factor;
td = av_clip_int8(td);
tb = av_clip_int8(tb);
tx = (0x4000 + abs(td / 2)) / td;
scale_factor = av_clip_intp2((tb * tx + 32) >> 6, 12);
dst->x = av_clip_int16((scale_factor * src->x + 127 +
(scale_factor * src->x < 0)) >> 8);
dst->y = av_clip_int16((scale_factor * src->y + 127 +
(scale_factor * src->y < 0)) >> 8);
}
static int check_mvset(Mv *mvLXCol, const Mv *mvCol,
int colPic, int poc,
const RefPicList *refPicList, int X, int refIdxLx,
const RefPicList *refPicList_col, int listCol, int refidxCol)
{
int cur_lt = refPicList[X].isLongTerm[refIdxLx];
int col_lt = refPicList_col[listCol].isLongTerm[refidxCol];
int col_poc_diff, cur_poc_diff;
if (cur_lt != col_lt) {
mvLXCol->x = 0;
mvLXCol->y = 0;
return 0;
}
col_poc_diff = colPic - refPicList_col[listCol].list[refidxCol];
cur_poc_diff = poc - refPicList[X].list[refIdxLx];
if (cur_lt || col_poc_diff == cur_poc_diff || !col_poc_diff) {
mvLXCol->x = mvCol->x;
mvLXCol->y = mvCol->y;
} else {
mv_scale(mvLXCol, mvCol, col_poc_diff, cur_poc_diff);
}
return 1;
}
#define CHECK_MVSET(l) \
check_mvset(mvLXCol, temp_col.mv + l, \
colPic, s->poc, \
refPicList, X, refIdxLx, \
refPicList_col, L ## l, temp_col.ref_idx[l])
// derive the motion vectors section 8.5.3.1.8
static int derive_temporal_colocated_mvs(const HEVCContext *s, MvField temp_col,
int refIdxLx, Mv *mvLXCol, int X,
int colPic, const RefPicList *refPicList_col)
{
const RefPicList *refPicList = s->cur_frame->refPicList;
if (temp_col.pred_flag == PF_INTRA)
return 0;
if (!(temp_col.pred_flag & PF_L0))
return CHECK_MVSET(1);
else if (temp_col.pred_flag == PF_L0)
return CHECK_MVSET(0);
else if (temp_col.pred_flag == PF_BI) {
int check_diffpicount = 0;
int i, j;
for (j = 0; j < 2; j++) {
for (i = 0; i < refPicList[j].nb_refs; i++) {
if (refPicList[j].list[i] > s->poc) {
check_diffpicount++;
break;
}
}
}
if (!check_diffpicount) {
if (X==0)
return CHECK_MVSET(0);
else
return CHECK_MVSET(1);
} else {
if (s->sh.collocated_list == L1)
return CHECK_MVSET(0);
else
return CHECK_MVSET(1);
}
}
return 0;
}
#define TAB_MVF(x, y) \
tab_mvf[(y) * min_pu_width + x]
#define TAB_MVF_PU(v) \
TAB_MVF(((x ## v) >> sps->log2_min_pu_size), \
((y ## v) >> sps->log2_min_pu_size))
#define DERIVE_TEMPORAL_COLOCATED_MVS \
derive_temporal_colocated_mvs(s, temp_col, \
refIdxLx, mvLXCol, X, colPic, \
ff_hevc_get_ref_list(ref, x, y))
/*
* 8.5.3.1.7 temporal luma motion vector prediction
*/
static int temporal_luma_motion_vector(const HEVCContext *s, const HEVCSPS *sps,
int x0, int y0,
int nPbW, int nPbH, int refIdxLx,
Mv *mvLXCol, int X)
{
const MvField *tab_mvf;
MvField temp_col;
int x, y, x_pu, y_pu;
int min_pu_width = sps->min_pu_width;
int availableFlagLXCol = 0;
int colPic;
const HEVCFrame *ref = s->collocated_ref;
if (!ref) {
memset(mvLXCol, 0, sizeof(*mvLXCol));
return 0;
}
tab_mvf = ref->tab_mvf;
colPic = ref->poc;
//bottom right collocated motion vector
x = x0 + nPbW;
y = y0 + nPbH;
if (tab_mvf &&
(y0 >> sps->log2_ctb_size) == (y >> sps->log2_ctb_size) &&
y < sps->height &&
x < sps->width) {
x &= ~15;
y &= ~15;
if (s->avctx->active_thread_type == FF_THREAD_FRAME)
ff_progress_frame_await(&ref->tf, y);
x_pu = x >> sps->log2_min_pu_size;
y_pu = y >> sps->log2_min_pu_size;
temp_col = TAB_MVF(x_pu, y_pu);
availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS;
}
// derive center collocated motion vector
if (tab_mvf && !availableFlagLXCol) {
x = x0 + (nPbW >> 1);
y = y0 + (nPbH >> 1);
x &= ~15;
y &= ~15;
if (s->avctx->active_thread_type == FF_THREAD_FRAME)
ff_progress_frame_await(&ref->tf, y);
x_pu = x >> sps->log2_min_pu_size;
y_pu = y >> sps->log2_min_pu_size;
temp_col = TAB_MVF(x_pu, y_pu);
availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS;
}
return availableFlagLXCol;
}
#define AVAILABLE(cand, v) \
(cand && !(TAB_MVF_PU(v).pred_flag == PF_INTRA))
#define PRED_BLOCK_AVAILABLE(v) \
z_scan_block_avail(pps, sps, x0, y0, x ## v, y ## v)
#define COMPARE_MV_REFIDX(a, b) \
compare_mv_ref_idx(TAB_MVF_PU(a), TAB_MVF_PU(b))
/*
* 8.5.3.1.2 Derivation process for spatial merging candidates
*/
static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCContext *s,
const HEVCPPS *pps, const HEVCSPS *sps,
int x0, int y0,
int nPbW, int nPbH,
int log2_cb_size,
int singleMCLFlag, int part_idx,
int merge_idx,
struct MvField mergecandlist[])
{
const RefPicList *refPicList = s->cur_frame->refPicList;
const MvField *tab_mvf = s->cur_frame->tab_mvf;
const int min_pu_width = sps->min_pu_width;
const int cand_bottom_left = lc->na.cand_bottom_left;
const int cand_left = lc->na.cand_left;
const int cand_up_left = lc->na.cand_up_left;
const int cand_up = lc->na.cand_up;
const int cand_up_right = lc->na.cand_up_right_sap;
const int xA1 = x0 - 1;
const int yA1 = y0 + nPbH - 1;
const int xB1 = x0 + nPbW - 1;
const int yB1 = y0 - 1;
const int xB0 = x0 + nPbW;
const int yB0 = y0 - 1;
const int xA0 = x0 - 1;
const int yA0 = y0 + nPbH;
const int xB2 = x0 - 1;
const int yB2 = y0 - 1;
const int nb_refs = (s->sh.slice_type == HEVC_SLICE_P) ?
s->sh.nb_refs[0] : FFMIN(s->sh.nb_refs[0], s->sh.nb_refs[1]);
int zero_idx = 0;
int nb_merge_cand = 0;
int nb_orig_merge_cand = 0;
int is_available_a0;
int is_available_a1;
int is_available_b0;
int is_available_b1;
int is_available_b2;
if (!singleMCLFlag && part_idx == 1 &&
(lc->cu.part_mode == PART_Nx2N ||
lc->cu.part_mode == PART_nLx2N ||
lc->cu.part_mode == PART_nRx2N) ||
is_diff_mer(pps, xA1, yA1, x0, y0)) {
is_available_a1 = 0;
} else {
is_available_a1 = AVAILABLE(cand_left, A1);
if (is_available_a1) {
mergecandlist[nb_merge_cand] = TAB_MVF_PU(A1);
if (merge_idx == 0)
return;
nb_merge_cand++;
}
}
if (!singleMCLFlag && part_idx == 1 &&
(lc->cu.part_mode == PART_2NxN ||
lc->cu.part_mode == PART_2NxnU ||
lc->cu.part_mode == PART_2NxnD) ||
is_diff_mer(pps, xB1, yB1, x0, y0)) {
is_available_b1 = 0;
} else {
is_available_b1 = AVAILABLE(cand_up, B1);
if (is_available_b1 &&
!(is_available_a1 && COMPARE_MV_REFIDX(B1, A1))) {
mergecandlist[nb_merge_cand] = TAB_MVF_PU(B1);
if (merge_idx == nb_merge_cand)
return;
nb_merge_cand++;
}
}
// above right spatial merge candidate
is_available_b0 = AVAILABLE(cand_up_right, B0) &&
xB0 < sps->width &&
PRED_BLOCK_AVAILABLE(B0) &&
!is_diff_mer(pps, xB0, yB0, x0, y0);
if (is_available_b0 &&
!(is_available_b1 && COMPARE_MV_REFIDX(B0, B1))) {
mergecandlist[nb_merge_cand] = TAB_MVF_PU(B0);
if (merge_idx == nb_merge_cand)
return;
nb_merge_cand++;
}
// left bottom spatial merge candidate
is_available_a0 = AVAILABLE(cand_bottom_left, A0) &&
yA0 < sps->height &&
PRED_BLOCK_AVAILABLE(A0) &&
!is_diff_mer(pps, xA0, yA0, x0, y0);
if (is_available_a0 &&
!(is_available_a1 && COMPARE_MV_REFIDX(A0, A1))) {
mergecandlist[nb_merge_cand] = TAB_MVF_PU(A0);
if (merge_idx == nb_merge_cand)
return;
nb_merge_cand++;
}
// above left spatial merge candidate
is_available_b2 = AVAILABLE(cand_up_left, B2) &&
!is_diff_mer(pps, xB2, yB2, x0, y0);
if (is_available_b2 &&
!(is_available_a1 && COMPARE_MV_REFIDX(B2, A1)) &&
!(is_available_b1 && COMPARE_MV_REFIDX(B2, B1)) &&
nb_merge_cand != 4) {
mergecandlist[nb_merge_cand] = TAB_MVF_PU(B2);
if (merge_idx == nb_merge_cand)
return;
nb_merge_cand++;
}
// temporal motion vector candidate
if (s->sh.slice_temporal_mvp_enabled_flag &&
nb_merge_cand < s->sh.max_num_merge_cand) {
Mv mv_l0_col = { 0 }, mv_l1_col = { 0 };
int available_l0 = temporal_luma_motion_vector(s, sps, x0, y0, nPbW, nPbH,
0, &mv_l0_col, 0);
int available_l1 = (s->sh.slice_type == HEVC_SLICE_B) ?
temporal_luma_motion_vector(s, sps, x0, y0, nPbW, nPbH,
0, &mv_l1_col, 1) : 0;
if (available_l0 || available_l1) {
mergecandlist[nb_merge_cand].pred_flag = available_l0 + (available_l1 << 1);
AV_ZERO16(mergecandlist[nb_merge_cand].ref_idx);
mergecandlist[nb_merge_cand].mv[0] = mv_l0_col;
mergecandlist[nb_merge_cand].mv[1] = mv_l1_col;
if (merge_idx == nb_merge_cand)
return;
nb_merge_cand++;
}
}
nb_orig_merge_cand = nb_merge_cand;
// combined bi-predictive merge candidates (applies for B slices)
if (s->sh.slice_type == HEVC_SLICE_B && nb_orig_merge_cand > 1 &&
nb_orig_merge_cand < s->sh.max_num_merge_cand) {
int comb_idx = 0;
for (comb_idx = 0; nb_merge_cand < s->sh.max_num_merge_cand &&
comb_idx < nb_orig_merge_cand * (nb_orig_merge_cand - 1); comb_idx++) {
int l0_cand_idx = l0_l1_cand_idx[comb_idx][0];
int l1_cand_idx = l0_l1_cand_idx[comb_idx][1];
MvField l0_cand = mergecandlist[l0_cand_idx];
MvField l1_cand = mergecandlist[l1_cand_idx];
if ((l0_cand.pred_flag & PF_L0) && (l1_cand.pred_flag & PF_L1) &&
(refPicList[0].list[l0_cand.ref_idx[0]] !=
refPicList[1].list[l1_cand.ref_idx[1]] ||
AV_RN32A(&l0_cand.mv[0]) != AV_RN32A(&l1_cand.mv[1]))) {
mergecandlist[nb_merge_cand].ref_idx[0] = l0_cand.ref_idx[0];
mergecandlist[nb_merge_cand].ref_idx[1] = l1_cand.ref_idx[1];
mergecandlist[nb_merge_cand].pred_flag = PF_BI;
AV_COPY32(&mergecandlist[nb_merge_cand].mv[0], &l0_cand.mv[0]);
AV_COPY32(&mergecandlist[nb_merge_cand].mv[1], &l1_cand.mv[1]);
if (merge_idx == nb_merge_cand)
return;
nb_merge_cand++;
}
}
}
// append Zero motion vector candidates
while (nb_merge_cand < s->sh.max_num_merge_cand) {
mergecandlist[nb_merge_cand].pred_flag = PF_L0 + ((s->sh.slice_type == HEVC_SLICE_B) << 1);
AV_ZERO32(mergecandlist[nb_merge_cand].mv + 0);
AV_ZERO32(mergecandlist[nb_merge_cand].mv + 1);
mergecandlist[nb_merge_cand].ref_idx[0] = zero_idx < nb_refs ? zero_idx : 0;
mergecandlist[nb_merge_cand].ref_idx[1] = zero_idx < nb_refs ? zero_idx : 0;
if (merge_idx == nb_merge_cand)
return;
nb_merge_cand++;
zero_idx++;
}
}
/*
* 8.5.3.1.1 Derivation process of luma Mvs for merge mode
*/
void ff_hevc_luma_mv_merge_mode(HEVCLocalContext *lc, const HEVCPPS *pps,
int x0, int y0, int nPbW,
int nPbH, int log2_cb_size, int part_idx,
int merge_idx, MvField *mv)
{
const HEVCSPS *const sps = pps->sps;
const HEVCContext *const s = lc->parent;
int singleMCLFlag = 0;
int nCS = 1 << log2_cb_size;
MvField mergecand_list[MRG_MAX_NUM_CANDS];
int nPbW2 = nPbW;
int nPbH2 = nPbH;
if (pps->log2_parallel_merge_level > 2 && nCS == 8) {
singleMCLFlag = 1;
x0 = lc->cu.x;
y0 = lc->cu.y;
nPbW = nCS;
nPbH = nCS;
part_idx = 0;
}
ff_hevc_set_neighbour_available(lc, x0, y0, nPbW, nPbH, sps->log2_ctb_size);
derive_spatial_merge_candidates(lc, s, pps, sps, x0, y0, nPbW, nPbH, log2_cb_size,
singleMCLFlag, part_idx,
merge_idx, mergecand_list);
if (mergecand_list[merge_idx].pred_flag == PF_BI &&
(nPbW2 + nPbH2) == 12) {
mergecand_list[merge_idx].pred_flag = PF_L0;
}
*mv = mergecand_list[merge_idx];
}
static av_always_inline void dist_scale(const HEVCContext *s, Mv *mv,
int min_pu_width, int x, int y,
int elist, int ref_idx_curr, int ref_idx)
{
const RefPicList *refPicList = s->cur_frame->refPicList;
const MvField *tab_mvf = s->cur_frame->tab_mvf;
int ref_pic_elist = refPicList[elist].list[TAB_MVF(x, y).ref_idx[elist]];
int ref_pic_curr = refPicList[ref_idx_curr].list[ref_idx];
if (ref_pic_elist != ref_pic_curr) {
int poc_diff = s->poc - ref_pic_elist;
if (!poc_diff)
poc_diff = 1;
mv_scale(mv, mv, poc_diff, s->poc - ref_pic_curr);
}
}
static int mv_mp_mode_mx(const HEVCContext *s, const HEVCSPS *sps,
int x, int y, int pred_flag_index,
Mv *mv, int ref_idx_curr, int ref_idx)
{
const MvField *tab_mvf = s->cur_frame->tab_mvf;
int min_pu_width = sps->min_pu_width;
const RefPicList *refPicList = s->cur_frame->refPicList;
if (((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) &&
refPicList[pred_flag_index].list[TAB_MVF(x, y).ref_idx[pred_flag_index]] == refPicList[ref_idx_curr].list[ref_idx]) {
*mv = TAB_MVF(x, y).mv[pred_flag_index];
return 1;
}
return 0;
}
static int mv_mp_mode_mx_lt(const HEVCContext *s, const HEVCSPS *sps,
int x, int y, int pred_flag_index,
Mv *mv, int ref_idx_curr, int ref_idx)
{
const MvField *tab_mvf = s->cur_frame->tab_mvf;
int min_pu_width = sps->min_pu_width;
const RefPicList *refPicList = s->cur_frame->refPicList;
if ((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) {
int currIsLongTerm = refPicList[ref_idx_curr].isLongTerm[ref_idx];
int colIsLongTerm =
refPicList[pred_flag_index].isLongTerm[(TAB_MVF(x, y).ref_idx[pred_flag_index])];
if (colIsLongTerm == currIsLongTerm) {
*mv = TAB_MVF(x, y).mv[pred_flag_index];
if (!currIsLongTerm)
dist_scale(s, mv, min_pu_width, x, y,
pred_flag_index, ref_idx_curr, ref_idx);
return 1;
}
}
return 0;
}
#define MP_MX(v, pred, mx) \
mv_mp_mode_mx(s, sps, \
(x ## v) >> sps->log2_min_pu_size, \
(y ## v) >> sps->log2_min_pu_size, \
pred, &mx, ref_idx_curr, ref_idx)
#define MP_MX_LT(v, pred, mx) \
mv_mp_mode_mx_lt(s, sps, \
(x ## v) >> sps->log2_min_pu_size, \
(y ## v) >> sps->log2_min_pu_size, \
pred, &mx, ref_idx_curr, ref_idx)
void ff_hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, const HEVCPPS *pps,
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)
{
const HEVCSPS *const sps = pps->sps;
const HEVCContext *const s = lc->parent;
const MvField *const tab_mvf = s->cur_frame->tab_mvf;
int isScaledFlag_L0 = 0;
int availableFlagLXA0 = 1;
int availableFlagLXB0 = 1;
int numMVPCandLX = 0;
int min_pu_width = sps->min_pu_width;
int xA0, yA0;
int is_available_a0;
int xA1, yA1;
int is_available_a1;
int xB0, yB0;
int is_available_b0;
int xB1, yB1;
int is_available_b1;
int xB2, yB2;
int is_available_b2;
Mv mvpcand_list[2] = { { 0 } };
Mv mxA;
Mv mxB;
int ref_idx_curr;
int ref_idx = 0;
int pred_flag_index_l0;
int pred_flag_index_l1;
const int cand_bottom_left = lc->na.cand_bottom_left;
const int cand_left = lc->na.cand_left;
const int cand_up_left = lc->na.cand_up_left;
const int cand_up = lc->na.cand_up;
const int cand_up_right = lc->na.cand_up_right_sap;
ref_idx_curr = LX;
ref_idx = mv->ref_idx[LX];
pred_flag_index_l0 = LX;
pred_flag_index_l1 = !LX;
// left bottom spatial candidate
xA0 = x0 - 1;
yA0 = y0 + nPbH;
is_available_a0 = AVAILABLE(cand_bottom_left, A0) &&
yA0 < sps->height &&
PRED_BLOCK_AVAILABLE(A0);
//left spatial merge candidate
xA1 = x0 - 1;
yA1 = y0 + nPbH - 1;
is_available_a1 = AVAILABLE(cand_left, A1);
if (is_available_a0 || is_available_a1)
isScaledFlag_L0 = 1;
if (is_available_a0) {
if (MP_MX(A0, pred_flag_index_l0, mxA)) {
goto b_candidates;
}
if (MP_MX(A0, pred_flag_index_l1, mxA)) {
goto b_candidates;
}
}
if (is_available_a1) {
if (MP_MX(A1, pred_flag_index_l0, mxA)) {
goto b_candidates;
}
if (MP_MX(A1, pred_flag_index_l1, mxA)) {
goto b_candidates;
}
}
if (is_available_a0) {
if (MP_MX_LT(A0, pred_flag_index_l0, mxA)) {
goto b_candidates;
}
if (MP_MX_LT(A0, pred_flag_index_l1, mxA)) {
goto b_candidates;
}
}
if (is_available_a1) {
if (MP_MX_LT(A1, pred_flag_index_l0, mxA)) {
goto b_candidates;
}
if (MP_MX_LT(A1, pred_flag_index_l1, mxA)) {
goto b_candidates;
}
}
availableFlagLXA0 = 0;
b_candidates:
// B candidates
// above right spatial merge candidate
xB0 = x0 + nPbW;
yB0 = y0 - 1;
is_available_b0 = AVAILABLE(cand_up_right, B0) &&
xB0 < sps->width &&
PRED_BLOCK_AVAILABLE(B0);
// above spatial merge candidate
xB1 = x0 + nPbW - 1;
yB1 = y0 - 1;
is_available_b1 = AVAILABLE(cand_up, B1);
// above left spatial merge candidate
xB2 = x0 - 1;
yB2 = y0 - 1;
is_available_b2 = AVAILABLE(cand_up_left, B2);
// above right spatial merge candidate
if (is_available_b0) {
if (MP_MX(B0, pred_flag_index_l0, mxB)) {
goto scalef;
}
if (MP_MX(B0, pred_flag_index_l1, mxB)) {
goto scalef;
}
}
// above spatial merge candidate
if (is_available_b1) {
if (MP_MX(B1, pred_flag_index_l0, mxB)) {
goto scalef;
}
if (MP_MX(B1, pred_flag_index_l1, mxB)) {
goto scalef;
}
}
// above left spatial merge candidate
if (is_available_b2) {
if (MP_MX(B2, pred_flag_index_l0, mxB)) {
goto scalef;
}
if (MP_MX(B2, pred_flag_index_l1, mxB)) {
goto scalef;
}
}
availableFlagLXB0 = 0;
scalef:
if (!isScaledFlag_L0) {
if (availableFlagLXB0) {
availableFlagLXA0 = 1;
mxA = mxB;
}
availableFlagLXB0 = 0;
// XB0 and L1
if (is_available_b0) {
availableFlagLXB0 = MP_MX_LT(B0, pred_flag_index_l0, mxB);
if (!availableFlagLXB0)
availableFlagLXB0 = MP_MX_LT(B0, pred_flag_index_l1, mxB);
}
if (is_available_b1 && !availableFlagLXB0) {
availableFlagLXB0 = MP_MX_LT(B1, pred_flag_index_l0, mxB);
if (!availableFlagLXB0)
availableFlagLXB0 = MP_MX_LT(B1, pred_flag_index_l1, mxB);
}
if (is_available_b2 && !availableFlagLXB0) {
availableFlagLXB0 = MP_MX_LT(B2, pred_flag_index_l0, mxB);
if (!availableFlagLXB0)
availableFlagLXB0 = MP_MX_LT(B2, pred_flag_index_l1, mxB);
}
}
if (availableFlagLXA0)
mvpcand_list[numMVPCandLX++] = mxA;
if (availableFlagLXB0 && (!availableFlagLXA0 || mxA.x != mxB.x || mxA.y != mxB.y))
mvpcand_list[numMVPCandLX++] = mxB;
//temporal motion vector prediction candidate
if (numMVPCandLX < 2 && s->sh.slice_temporal_mvp_enabled_flag &&
mvp_lx_flag == numMVPCandLX) {
Mv mv_col;
int available_col = temporal_luma_motion_vector(s, sps, x0, y0, nPbW,
nPbH, ref_idx,
&mv_col, LX);
if (available_col)
mvpcand_list[numMVPCandLX++] = mv_col;
}
mv->mv[LX] = mvpcand_list[mvp_lx_flag];
}
+146
View File
@@ -0,0 +1,146 @@
/*
* 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 "bytestream.h"
#include "h2645_parse.h"
#include "hevc.h"
#include "parse.h"
static int hevc_decode_nal_units(const uint8_t *buf, int buf_size, HEVCParamSets *ps,
HEVCSEI *sei, int is_nalff, int nal_length_size,
int err_recognition, int apply_defdispwin, void *logctx)
{
int i;
int ret = 0;
int flags = (H2645_FLAG_IS_NALFF * !!is_nalff) | H2645_FLAG_SMALL_PADDING;
H2645Packet pkt = { 0 };
ret = ff_h2645_packet_split(&pkt, buf, buf_size, logctx,
nal_length_size, AV_CODEC_ID_HEVC, flags);
if (ret < 0) {
goto done;
}
for (i = 0; i < pkt.nb_nals; i++) {
H2645NAL *nal = &pkt.nals[i];
/* ignore everything except parameter sets and VCL NALUs */
switch (nal->type) {
case HEVC_NAL_VPS:
ret = ff_hevc_decode_nal_vps(&nal->gb, logctx, ps);
if (ret < 0)
goto done;
break;
case HEVC_NAL_SPS:
ret = ff_hevc_decode_nal_sps(&nal->gb, logctx, ps,
nal->nuh_layer_id, apply_defdispwin);
if (ret < 0)
goto done;
break;
case HEVC_NAL_PPS:
ret = ff_hevc_decode_nal_pps(&nal->gb, logctx, ps);
if (ret < 0)
goto done;
break;
case HEVC_NAL_SEI_PREFIX:
case HEVC_NAL_SEI_SUFFIX:
ret = ff_hevc_decode_nal_sei(&nal->gb, logctx, sei, ps, nal->type);
if (ret < 0)
goto done;
break;
default:
av_log(logctx, AV_LOG_VERBOSE, "Ignoring NAL type %d in extradata\n", nal->type);
break;
}
}
done:
ff_h2645_packet_uninit(&pkt);
if (err_recognition & AV_EF_EXPLODE)
return ret;
return 0;
}
int ff_hevc_decode_extradata(const uint8_t *data, int size, HEVCParamSets *ps,
HEVCSEI *sei, int *is_nalff, int *nal_length_size,
int err_recognition, int apply_defdispwin, void *logctx)
{
int ret = 0;
GetByteContext gb;
bytestream2_init(&gb, data, size);
/* data[0] == 1 is configurationVersion from 14496-15.
* data[0] == 0 is for backward compatibility predates the standard.
*
* Minimum number of bytes of hvcC with 0 numOfArrays is 23.
*/
if (size >= 23 && ((data[0] == 1) || (data[0] == 0 && (data[1] || data[2] > 1)))) {
/* It seems the extradata is encoded as hvcC format. */
int i, j, num_arrays, nal_len_size;
*is_nalff = 1;
bytestream2_skip(&gb, 21);
nal_len_size = (bytestream2_get_byte(&gb) & 3) + 1;
num_arrays = bytestream2_get_byte(&gb);
/* nal units in the hvcC always have length coded with 2 bytes,
* so put a fake nal_length_size = 2 while parsing them */
*nal_length_size = 2;
/* Decode nal units from hvcC. */
for (i = 0; i < num_arrays; i++) {
int type = bytestream2_get_byte(&gb) & 0x3f;
int cnt = bytestream2_get_be16(&gb);
for (j = 0; j < cnt; j++) {
// +2 for the nal size field
int nalsize = bytestream2_peek_be16(&gb) + 2;
if (bytestream2_get_bytes_left(&gb) < nalsize) {
av_log(logctx, AV_LOG_ERROR,
"Invalid NAL unit size in extradata.\n");
return AVERROR_INVALIDDATA;
}
ret = hevc_decode_nal_units(gb.buffer, nalsize, ps, sei, *is_nalff,
*nal_length_size, err_recognition, apply_defdispwin,
logctx);
if (ret < 0) {
av_log(logctx, AV_LOG_ERROR,
"Decoding nal unit %d %d from hvcC failed\n",
type, i);
return ret;
}
bytestream2_skip(&gb, nalsize);
}
}
/* Now store right nal length size, that will be used to parse
* all other nals */
*nal_length_size = nal_len_size;
} else {
*is_nalff = 0;
ret = hevc_decode_nal_units(data, size, ps, sei, *is_nalff, *nal_length_size,
err_recognition, apply_defdispwin, logctx);
if (ret < 0)
return ret;
}
return ret;
}
+36
View File
@@ -0,0 +1,36 @@
/*
* 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
*/
/**
* @file
* H.265 parser code
*/
#ifndef AVCODEC_HEVC_PARSE_H
#define AVCODEC_HEVC_PARSE_H
#include <stdint.h>
#include "ps.h"
#include "sei.h"
int ff_hevc_decode_extradata(const uint8_t *data, int size, HEVCParamSets *ps,
HEVCSEI *sei, int *is_nalff, int *nal_length_size,
int err_recognition, int apply_defdispwin, void *logctx);
#endif /* AVCODEC_HEVC_PARSE_H */
+360
View File
@@ -0,0 +1,360 @@
/*
* 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 "libavutil/mem.h"
#include "golomb.h"
#include "hevc.h"
#include "parse.h"
#include "ps.h"
#include "sei.h"
#include "h2645_parse.h"
#include "parser.h"
#define START_CODE 0x000001 ///< start_code_prefix_one_3bytes
#define IS_IRAP_NAL(nal) (nal->type >= 16 && nal->type <= 23)
#define IS_IDR_NAL(nal) (nal->type == HEVC_NAL_IDR_W_RADL || nal->type == HEVC_NAL_IDR_N_LP)
typedef struct HEVCParserContext {
ParseContext pc;
H2645Packet pkt;
HEVCParamSets ps;
HEVCSEI sei;
int is_avc;
int nal_length_size;
int parsed_extradata;
int poc;
int pocTid0;
} HEVCParserContext;
static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal,
AVCodecContext *avctx)
{
HEVCParserContext *ctx = s->priv_data;
HEVCParamSets *ps = &ctx->ps;
HEVCSEI *sei = &ctx->sei;
GetBitContext *gb = &nal->gb;
const HEVCPPS *pps;
const HEVCSPS *sps;
const HEVCWindow *ow;
int i, num = 0, den = 0;
unsigned int pps_id, first_slice_in_pic_flag, dependent_slice_segment_flag;
enum HEVCSliceType slice_type;
first_slice_in_pic_flag = get_bits1(gb);
s->picture_structure = sei->picture_timing.picture_struct;
s->field_order = sei->picture_timing.picture_struct;
if (IS_IRAP_NAL(nal)) {
s->key_frame = 1;
skip_bits1(gb); // no_output_of_prior_pics_flag
}
pps_id = get_ue_golomb(gb);
if (pps_id >= HEVC_MAX_PPS_COUNT || !ps->pps_list[pps_id]) {
av_log(avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", pps_id);
return AVERROR_INVALIDDATA;
}
pps = ps->pps_list[pps_id];
sps = pps->sps;
ow = &sps->output_window;
s->coded_width = sps->width;
s->coded_height = sps->height;
s->width = sps->width - ow->left_offset - ow->right_offset;
s->height = sps->height - ow->top_offset - ow->bottom_offset;
s->format = sps->pix_fmt;
avctx->profile = sps->ptl.general_ptl.profile_idc;
avctx->level = sps->ptl.general_ptl.level_idc;
if (sps->vps->vps_timing_info_present_flag) {
num = sps->vps->vps_num_units_in_tick;
den = sps->vps->vps_time_scale;
} else if (sps->vui.vui_timing_info_present_flag) {
num = sps->vui.vui_num_units_in_tick;
den = sps->vui.vui_time_scale;
}
if (num > 0 && den > 0)
av_reduce(&avctx->framerate.den, &avctx->framerate.num,
num, den, 1 << 30);
if (!first_slice_in_pic_flag) {
unsigned int slice_segment_addr;
int slice_address_length;
if (pps->dependent_slice_segments_enabled_flag)
dependent_slice_segment_flag = get_bits1(gb);
else
dependent_slice_segment_flag = 0;
slice_address_length = av_ceil_log2_c(sps->ctb_width *
sps->ctb_height);
slice_segment_addr = get_bitsz(gb, slice_address_length);
if (slice_segment_addr >= sps->ctb_width * sps->ctb_height) {
av_log(avctx, AV_LOG_ERROR, "Invalid slice segment address: %u.\n",
slice_segment_addr);
return AVERROR_INVALIDDATA;
}
} else
dependent_slice_segment_flag = 0;
if (dependent_slice_segment_flag)
return 0; /* break; */
for (i = 0; i < pps->num_extra_slice_header_bits; i++)
skip_bits(gb, 1); // slice_reserved_undetermined_flag[]
slice_type = get_ue_golomb_31(gb);
if (!(slice_type == HEVC_SLICE_I || slice_type == HEVC_SLICE_P ||
slice_type == HEVC_SLICE_B)) {
av_log(avctx, AV_LOG_ERROR, "Unknown slice type: %d.\n",
slice_type);
return AVERROR_INVALIDDATA;
}
s->pict_type = slice_type == HEVC_SLICE_B ? AV_PICTURE_TYPE_B :
slice_type == HEVC_SLICE_P ? AV_PICTURE_TYPE_P :
AV_PICTURE_TYPE_I;
if (pps->output_flag_present_flag)
skip_bits1(gb); // pic_output_flag
if (sps->separate_colour_plane)
skip_bits(gb, 2); // colour_plane_id
if (!IS_IDR_NAL(nal)) {
int pic_order_cnt_lsb = get_bits(gb, sps->log2_max_poc_lsb);
s->output_picture_number = ctx->poc =
ff_hevc_compute_poc(sps, ctx->pocTid0, pic_order_cnt_lsb, nal->type);
} else
s->output_picture_number = ctx->poc = 0;
if (nal->temporal_id == 0 &&
nal->type != HEVC_NAL_TRAIL_N &&
nal->type != HEVC_NAL_TSA_N &&
nal->type != HEVC_NAL_STSA_N &&
nal->type != HEVC_NAL_RADL_N &&
nal->type != HEVC_NAL_RASL_N &&
nal->type != HEVC_NAL_RADL_R &&
nal->type != HEVC_NAL_RASL_R)
ctx->pocTid0 = ctx->poc;
return 1; /* no need to evaluate the rest */
}
/**
* Parse NAL units of found picture and decode some basic information.
*
* @param s parser context.
* @param avctx codec context.
* @param buf buffer with field/frame data.
* @param buf_size size of the buffer.
*/
static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf,
int buf_size, AVCodecContext *avctx)
{
HEVCParserContext *ctx = s->priv_data;
HEVCParamSets *ps = &ctx->ps;
HEVCSEI *sei = &ctx->sei;
int flags = (H2645_FLAG_IS_NALFF * !!ctx->is_avc) | H2645_FLAG_SMALL_PADDING;
int ret, i;
/* set some sane default values */
s->pict_type = AV_PICTURE_TYPE_I;
s->key_frame = 0;
s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN;
ff_hevc_reset_sei(sei);
ret = ff_h2645_packet_split(&ctx->pkt, buf, buf_size, avctx,
ctx->nal_length_size, AV_CODEC_ID_HEVC, flags);
if (ret < 0)
return ret;
for (i = 0; i < ctx->pkt.nb_nals; i++) {
H2645NAL *nal = &ctx->pkt.nals[i];
GetBitContext *gb = &nal->gb;
if (nal->nuh_layer_id > 0)
continue;
switch (nal->type) {
case HEVC_NAL_VPS:
ff_hevc_decode_nal_vps(gb, avctx, ps);
break;
case HEVC_NAL_SPS:
ff_hevc_decode_nal_sps(gb, avctx, ps, nal->nuh_layer_id, 1);
break;
case HEVC_NAL_PPS:
ff_hevc_decode_nal_pps(gb, avctx, ps);
break;
case HEVC_NAL_SEI_PREFIX:
case HEVC_NAL_SEI_SUFFIX:
ff_hevc_decode_nal_sei(gb, avctx, sei, ps, nal->type);
break;
case HEVC_NAL_TRAIL_N:
case HEVC_NAL_TRAIL_R:
case HEVC_NAL_TSA_N:
case HEVC_NAL_TSA_R:
case HEVC_NAL_STSA_N:
case HEVC_NAL_STSA_R:
case HEVC_NAL_BLA_W_LP:
case HEVC_NAL_BLA_W_RADL:
case HEVC_NAL_BLA_N_LP:
case HEVC_NAL_IDR_W_RADL:
case HEVC_NAL_IDR_N_LP:
case HEVC_NAL_CRA_NUT:
case HEVC_NAL_RADL_N:
case HEVC_NAL_RADL_R:
case HEVC_NAL_RASL_N:
case HEVC_NAL_RASL_R:
if (ctx->sei.picture_timing.picture_struct == HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING) {
s->repeat_pict = 1;
} else if (ctx->sei.picture_timing.picture_struct == HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING) {
s->repeat_pict = 2;
}
ret = hevc_parse_slice_header(s, nal, avctx);
if (ret)
return ret;
break;
}
}
/* didn't find a picture! */
av_log(avctx, AV_LOG_ERROR, "missing picture in access unit with size %d\n", buf_size);
return -1;
}
/**
* 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)
{
HEVCParserContext *ctx = s->priv_data;
ParseContext *pc = &ctx->pc;
int i;
for (i = 0; i < buf_size; i++) {
int nut, layer_id;
pc->state64 = (pc->state64 << 8) | buf[i];
if (((pc->state64 >> 3 * 8) & 0xFFFFFF) != START_CODE)
continue;
nut = (pc->state64 >> 2 * 8 + 1) & 0x3F;
layer_id = (pc->state64 >> 11) & 0x3F;
if (layer_id > 0)
continue;
// Beginning of access unit
if ((nut >= HEVC_NAL_VPS && nut <= HEVC_NAL_EOB_NUT) || nut == HEVC_NAL_SEI_PREFIX ||
(nut >= 41 && nut <= 44) || (nut >= 48 && nut <= 55)) {
if (pc->frame_start_found) {
pc->frame_start_found = 0;
if (!((pc->state64 >> 6 * 8) & 0xFF))
return i - 6;
return i - 5;
}
} else if (nut <= HEVC_NAL_RASL_R ||
(nut >= HEVC_NAL_BLA_W_LP && nut <= HEVC_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;
} else { // First slice of next frame found
pc->frame_start_found = 0;
if (!((pc->state64 >> 6 * 8) & 0xFF))
return i - 6;
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;
HEVCParserContext *ctx = s->priv_data;
ParseContext *pc = &ctx->pc;
int is_dummy_buf = !buf_size;
const uint8_t *dummy_buf = buf;
if (avctx->extradata && !ctx->parsed_extradata) {
ff_hevc_decode_extradata(avctx->extradata, avctx->extradata_size, &ctx->ps, &ctx->sei,
&ctx->is_avc, &ctx->nal_length_size, avctx->err_recognition,
1, avctx);
ctx->parsed_extradata = 1;
}
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;
}
}
is_dummy_buf &= (dummy_buf == buf);
if (!is_dummy_buf)
parse_nal_units(s, buf, buf_size, avctx);
*poutbuf = buf;
*poutbuf_size = buf_size;
return next;
}
static void hevc_parser_close(AVCodecParserContext *s)
{
HEVCParserContext *ctx = s->priv_data;
ff_hevc_ps_uninit(&ctx->ps);
ff_h2645_packet_uninit(&ctx->pkt);
ff_hevc_reset_sei(&ctx->sei);
av_freep(&ctx->pc.buffer);
}
const AVCodecParser ff_hevc_parser = {
.codec_ids = { AV_CODEC_ID_HEVC },
.priv_data_size = sizeof(HEVCParserContext),
.parser_parse = hevc_parse,
.parser_close = hevc_parser_close,
};
+81
View File
@@ -0,0 +1,81 @@
/*
* 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 "hevcdec.h"
#include "pred.h"
#define BIT_DEPTH 8
#include "pred_template.c"
#undef BIT_DEPTH
#define BIT_DEPTH 9
#include "pred_template.c"
#undef BIT_DEPTH
#define BIT_DEPTH 10
#include "pred_template.c"
#undef BIT_DEPTH
#define BIT_DEPTH 12
#include "pred_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[0] = FUNC(intra_pred_2, depth); \
hpc->intra_pred[1] = FUNC(intra_pred_3, depth); \
hpc->intra_pred[2] = FUNC(intra_pred_4, depth); \
hpc->intra_pred[3] = FUNC(intra_pred_5, 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;
case 12:
HEVC_PRED(12);
break;
default:
HEVC_PRED(8);
break;
}
#if ARCH_MIPS
ff_hevc_pred_init_mips(hpc, bit_depth);
#endif
}
+48
View File
@@ -0,0 +1,48 @@
/*
* 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_PRED_H
#define AVCODEC_HEVC_PRED_H
#include <stddef.h>
#include <stdint.h>
struct HEVCLocalContext;
struct HEVCPPS;
typedef struct HEVCPredContext {
void (*intra_pred[4])(struct HEVCLocalContext *lc,
const struct HEVCPPS *pps, int x0, int y0, 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);
void ff_hevc_pred_init_mips(HEVCPredContext *hpc, int bit_depth);
#endif /* AVCODEC_HEVC_PRED_H */
+553
View File
@@ -0,0 +1,553 @@
/*
* 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 "pred.h"
#define POS(x, y) src[(x) + stride * (y)]
static av_always_inline void FUNC(intra_pred)(HEVCLocalContext *lc,
const HEVCPPS *pps,
int x0, int y0,
int log2_size, int c_idx)
{
#define PU(x) \
((x) >> sps->log2_min_pu_size)
#define MVF(x, y) \
(s->cur_frame->tab_mvf[(x) + (y) * min_pu_width])
#define MVF_PU(x, y) \
MVF(PU(x0 + ((x) * (1 << hshift))), PU(y0 + ((y) * (1 << vshift))))
#define IS_INTRA(x, y) \
(MVF_PU(x, y).pred_flag == PF_INTRA)
#define MIN_TB_ADDR_ZS(x, y) \
pps->min_tb_addr_zs[(y) * (sps->tb_mask+2) + (x)]
#define EXTEND(ptr, val, len) \
do { \
pixel4 pix = PIXEL_SPLAT_X4(val); \
for (i = 0; i < (len); i += 4) \
AV_WN4P(ptr + i, pix); \
} while (0)
#define EXTEND_RIGHT_CIP(ptr, start, length) \
for (i = start; i < (start) + (length); i += 4) \
if (!IS_INTRA(i, -1)) \
AV_WN4P(&ptr[i], a); \
else \
a = PIXEL_SPLAT_X4(ptr[i+3])
#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_UP_CIP(ptr, start, length) \
for (i = (start); i > (start) - (length); i -= 4) \
if (!IS_INTRA(-1, i - 3)) \
AV_WN4P(&ptr[i - 3], a); \
else \
a = PIXEL_SPLAT_X4(ptr[i - 3])
#define EXTEND_DOWN_CIP(ptr, start, length) \
for (i = start; i < (start) + (length); i += 4) \
if (!IS_INTRA(-1, i)) \
AV_WN4P(&ptr[i], a); \
else \
a = PIXEL_SPLAT_X4(ptr[i + 3])
const HEVCSPS *const sps = pps->sps;
const HEVCContext *const s = lc->parent;
int i;
int hshift = sps->hshift[c_idx];
int vshift = sps->vshift[c_idx];
int size = (1 << log2_size);
int size_in_luma_h = size << hshift;
int size_in_tbs_h = size_in_luma_h >> sps->log2_min_tb_size;
int size_in_luma_v = size << vshift;
int size_in_tbs_v = size_in_luma_v >> sps->log2_min_tb_size;
int x = x0 >> hshift;
int y = y0 >> vshift;
int x_tb = (x0 >> sps->log2_min_tb_size) & sps->tb_mask;
int y_tb = (y0 >> sps->log2_min_tb_size) & sps->tb_mask;
int spin = c_idx && !size_in_tbs_v && ((2 * y0) & (1 << sps->log2_min_tb_size));
int cur_tb_addr = MIN_TB_ADDR_ZS(x_tb, y_tb);
ptrdiff_t stride = s->cur_frame->f->linesize[c_idx] / sizeof(pixel);
pixel *src = (pixel*)s->cur_frame->f->data[c_idx] + x + y * stride;
int min_pu_width = sps->min_pu_width;
enum IntraPredMode mode = c_idx ? lc->tu.intra_pred_mode_c :
lc->tu.intra_pred_mode;
pixel4 a;
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_v + spin) & sps->tb_mask);
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 && !spin && cur_tb_addr > MIN_TB_ADDR_ZS((x_tb + size_in_tbs_h) & sps->tb_mask, y_tb - 1);
int bottom_left_size = (FFMIN(y0 + 2 * size_in_luma_v, sps->height) -
(y0 + size_in_luma_v)) >> vshift;
int top_right_size = (FFMIN(x0 + 2 * size_in_luma_h, sps->width) -
(x0 + size_in_luma_h)) >> hshift;
if (pps->constrained_intra_pred_flag == 1) {
int size_in_luma_pu_v = PU(size_in_luma_v);
int size_in_luma_pu_h = PU(size_in_luma_h);
int on_pu_edge_x = !av_zero_extend(x0, sps->log2_min_pu_size);
int on_pu_edge_y = !av_zero_extend(y0, sps->log2_min_pu_size);
if (!size_in_luma_pu_h)
size_in_luma_pu_h++;
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_v);
int max = FFMIN(size_in_luma_pu_v, sps->min_pu_height - y_bottom_pu);
cand_bottom_left = 0;
for (i = 0; i < max; i += 2)
cand_bottom_left |= (MVF(x_left_pu, y_bottom_pu + i).pred_flag == PF_INTRA);
}
if (cand_left == 1 && on_pu_edge_x) {
int x_left_pu = PU(x0 - 1);
int y_left_pu = PU(y0);
int max = FFMIN(size_in_luma_pu_v, sps->min_pu_height - y_left_pu);
cand_left = 0;
for (i = 0; i < max; i += 2)
cand_left |= (MVF(x_left_pu, y_left_pu + i).pred_flag == PF_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).pred_flag == PF_INTRA;
}
if (cand_up == 1 && on_pu_edge_y) {
int x_top_pu = PU(x0);
int y_top_pu = PU(y0 - 1);
int max = FFMIN(size_in_luma_pu_h, sps->min_pu_width - x_top_pu);
cand_up = 0;
for (i = 0; i < max; i += 2)
cand_up |= (MVF(x_top_pu + i, y_top_pu).pred_flag == PF_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_h);
int max = FFMIN(size_in_luma_pu_h, sps->min_pu_width - x_right_pu);
cand_up_right = 0;
for (i = 0; i < max; i += 2)
cand_up_right |= (MVF(x_right_pu + i, y_top_pu).pred_flag == PF_INTRA);
}
memset(left, 128, 2 * MAX_TB_SIZE*sizeof(pixel));
memset(top , 128, 2 * MAX_TB_SIZE*sizeof(pixel));
top[-1] = 128;
}
if (cand_up_left) {
left[-1] = POS(-1, -1);
top[-1] = left[-1];
}
if (cand_up)
memcpy(top, src - stride, size * sizeof(pixel));
if (cand_up_right) {
memcpy(top + size, src - stride + size, size * sizeof(pixel));
EXTEND(top + size + top_right_size, POS(size + top_right_size - 1, -1),
size - top_right_size);
}
if (cand_left)
for (i = 0; i < size; i++)
left[i] = POS(-1, i);
if (cand_bottom_left) {
for (i = size; i < size + bottom_left_size; i++)
left[i] = POS(-1, i);
EXTEND(left + size + bottom_left_size, POS(-1, size + bottom_left_size - 1),
size - bottom_left_size);
}
if (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) < sps->width ?
2 * size : (sps->width - x0) >> hshift;
int size_max_y = y0 + ((2 * size) << vshift) < sps->height ?
2 * size : (sps->height - y0) >> vshift;
int j = size + (cand_bottom_left? bottom_left_size: 0) -1;
if (!cand_up_right) {
size_max_x = x0 + ((size) << hshift) < sps->width ?
size : (sps->width - x0) >> hshift;
}
if (!cand_bottom_left) {
size_max_y = y0 + (( size) << vshift) < sps->height ?
size : (sps->height - y0) >> vshift;
}
if (cand_bottom_left || cand_left || cand_up_left) {
while (j > -1 && !IS_INTRA(-1, j))
j--;
if (!IS_INTRA(-1, j)) {
j = 0;
while (j < size_max_x && !IS_INTRA(j, -1))
j++;
EXTEND_LEFT_CIP(top, j, j + 1);
left[-1] = top[-1];
}
} else {
j = 0;
while (j < size_max_x && !IS_INTRA(j, -1))
j++;
if (j > 0) {
EXTEND_LEFT_CIP(top, j, j);
top[-1] = top[0];
}
left[-1] = top[-1];
}
left[-1] = top[-1];
if (cand_bottom_left || cand_left) {
a = PIXEL_SPLAT_X4(left[-1]);
EXTEND_DOWN_CIP(left, 0, size_max_y);
}
if (!cand_left)
EXTEND(left, left[-1], size);
if (!cand_bottom_left)
EXTEND(left + size, left[size - 1], size);
if (x0 != 0 && y0 != 0) {
a = PIXEL_SPLAT_X4(left[size_max_y - 1]);
EXTEND_UP_CIP(left, size_max_y - 1, size_max_y);
if (!IS_INTRA(-1, - 1))
left[-1] = left[0];
} else if (x0 == 0) {
EXTEND(left, 0, size_max_y);
} else {
a = PIXEL_SPLAT_X4(left[size_max_y - 1]);
EXTEND_UP_CIP(left, size_max_y - 1, size_max_y);
}
top[-1] = left[-1];
if (y0 != 0) {
a = PIXEL_SPLAT_X4(left[-1]);
EXTEND_RIGHT_CIP(top, 0, size_max_x);
}
}
}
// Infer the unavailable samples
if (!cand_bottom_left) {
if (cand_left) {
EXTEND(left + size, left[size - 1], size);
} else if (cand_up_left) {
EXTEND(left, left[-1], 2 * size);
cand_left = 1;
} else if (cand_up) {
left[-1] = top[0];
EXTEND(left, left[-1], 2 * size);
cand_up_left = 1;
cand_left = 1;
} else if (cand_up_right) {
EXTEND(top, top[size], size);
left[-1] = top[size];
EXTEND(left, left[-1], 2 * size);
cand_up = 1;
cand_up_left = 1;
cand_left = 1;
} else { // No samples available
left[-1] = (1 << (BIT_DEPTH - 1));
EXTEND(top, left[-1], 2 * size);
EXTEND(left, left[-1], 2 * size);
}
}
if (!cand_left)
EXTEND(left, left[size], size);
if (!cand_up_left) {
left[-1] = left[0];
}
if (!cand_up)
EXTEND(top, left[-1], size);
if (!cand_up_right)
EXTEND(top + size, top[size - 1], size);
top[-1] = left[-1];
// Filtering process
if (!sps->intra_smoothing_disabled && (c_idx == 0 || sps->chroma_format_idc == 3)) {
if (mode != INTRA_DC && size != 4){
int intra_hor_ver_dist_thresh[] = { 7, 1, 0 };
int min_dist_vert_hor = FFMIN(FFABS((int)(mode - 26U)),
FFABS((int)(mode - 10U)));
if (min_dist_vert_hor > intra_hor_ver_dist_thresh[log2_size - 3]) {
int threshold = 1 << (BIT_DEPTH - 5);
if (sps->strong_intra_smoothing_enabled && c_idx == 0 &&
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;
}
}
#define INTRA_PRED(size) \
static void FUNC(intra_pred_ ## size)(HEVCLocalContext *lc, const HEVCPPS *pps, \
int x0, int y0, int c_idx) \
{ \
FUNC(intra_pred)(lc, pps, x0, y0, size, c_idx); \
}
INTRA_PRED(2)
INTRA_PRED(3)
INTRA_PRED(4)
INTRA_PRED(5)
#undef INTRA_PRED
static av_always_inline void FUNC(pred_planar)(uint8_t *_src, const uint8_t *_top,
const uint8_t *_left, ptrdiff_t stride,
int trafo_size)
{
int x, y;
pixel *src = (pixel *)_src;
const pixel *top = (const pixel *)_top;
const pixel *left = (const pixel *)_left;
int size = 1 << trafo_size;
for (y = 0; y < size; y++)
for (x = 0; x < size; x++)
POS(x, y) = ((size - 1 - x) * left[y] + (x + 1) * top[size] +
(size - 1 - y) * top[x] + (y + 1) * left[size] + size) >> (trafo_size + 1);
}
#define PRED_PLANAR(size)\
static void FUNC(pred_planar_ ## size)(uint8_t *src, const uint8_t *top, \
const uint8_t *left, ptrdiff_t stride) \
{ \
FUNC(pred_planar)(src, top, left, stride, size + 2); \
}
PRED_PLANAR(0)
PRED_PLANAR(1)
PRED_PLANAR(2)
PRED_PLANAR(3)
#undef PRED_PLANAR
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; j+=4)
AV_WN4P(&POS(j, 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 + 4];
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 += 4)
AV_WN4P(&ref_tmp[x], AV_RN4P(&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 += 4) {
POS(x , y) = ((32 - fact) * ref[x + idx + 1] +
fact * ref[x + idx + 2] + 16) >> 5;
POS(x + 1, y) = ((32 - fact) * ref[x + 1 + idx + 1] +
fact * ref[x + 1 + idx + 2] + 16) >> 5;
POS(x + 2, y) = ((32 - fact) * ref[x + 2 + idx + 1] +
fact * ref[x + 2 + idx + 2] + 16) >> 5;
POS(x + 3, y) = ((32 - fact) * ref[x + 3 + idx + 1] +
fact * ref[x + 3 + idx + 2] + 16) >> 5;
}
} else {
for (x = 0; x < size; x += 4)
AV_WN4P(&POS(x, y), AV_RN4P(&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 += 4)
AV_WN4P(&ref_tmp[x], AV_RN4P(&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 += 4) {
POS(x, 0) = av_clip_pixel(left[0] + ((top[x ] - top[-1]) >> 1));
POS(x + 1, 0) = av_clip_pixel(left[0] + ((top[x + 1] - top[-1]) >> 1));
POS(x + 2, 0) = av_clip_pixel(left[0] + ((top[x + 2] - top[-1]) >> 1));
POS(x + 3, 0) = av_clip_pixel(left[0] + ((top[x + 3] - top[-1]) >> 1));
}
}
}
}
static void FUNC(pred_angular_0)(uint8_t *src, const uint8_t *top,
const uint8_t *left,
ptrdiff_t stride, int c_idx, int mode)
{
FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 2);
}
static void FUNC(pred_angular_1)(uint8_t *src, const uint8_t *top,
const uint8_t *left,
ptrdiff_t stride, int c_idx, int mode)
{
FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 3);
}
static void FUNC(pred_angular_2)(uint8_t *src, const uint8_t *top,
const uint8_t *left,
ptrdiff_t stride, int c_idx, int mode)
{
FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 4);
}
static void FUNC(pred_angular_3)(uint8_t *src, const uint8_t *top,
const uint8_t *left,
ptrdiff_t stride, int c_idx, int mode)
{
FUNC(pred_angular)(src, top, left, stride, c_idx, mode, 1 << 5);
}
#undef EXTEND_LEFT_CIP
#undef EXTEND_RIGHT_CIP
#undef EXTEND_UP_CIP
#undef EXTEND_DOWN_CIP
#undef IS_INTRA
#undef MVF_PU
#undef MVF
#undef PU
#undef EXTEND
#undef MIN_TB_ADDR_ZS
#undef POS
File diff suppressed because it is too large Load Diff
+551
View File
@@ -0,0 +1,551 @@
/*
* HEVC parameter set parsing
*
* 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_PS_H
#define AVCODEC_HEVC_PS_H
#include <stdint.h>
#include "libavutil/pixfmt.h"
#include "libavutil/rational.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/get_bits.h"
#include "libavcodec/h2645_vui.h"
#include "hevc.h"
#define HEVC_VPS_MAX_LAYERS 2
typedef struct HEVCSublayerHdrParams {
uint32_t bit_rate_value_minus1[HEVC_MAX_CPB_CNT];
uint32_t cpb_size_value_minus1[HEVC_MAX_CPB_CNT];
uint32_t cpb_size_du_value_minus1[HEVC_MAX_CPB_CNT];
uint32_t bit_rate_du_value_minus1[HEVC_MAX_CPB_CNT];
uint32_t cbr_flag;
} HEVCSublayerHdrParams;
// flags in bitmask form
typedef struct HEVCHdrFlagParams {
uint8_t fixed_pic_rate_general_flag;
uint8_t fixed_pic_rate_within_cvs_flag;
uint8_t low_delay_hrd_flag;
} HEVCHdrFlagParams;
typedef struct HEVCHdrParams {
HEVCHdrFlagParams flags;
uint8_t nal_hrd_parameters_present_flag;
uint8_t vcl_hrd_parameters_present_flag;
uint8_t sub_pic_hrd_params_present_flag;
uint8_t sub_pic_cpb_params_in_pic_timing_sei_flag;
uint8_t tick_divisor_minus2;
uint8_t du_cpb_removal_delay_increment_length_minus1;
uint8_t dpb_output_delay_du_length_minus1;
uint8_t bit_rate_scale;
uint8_t cpb_size_scale;
uint8_t cpb_size_du_scale;
uint8_t initial_cpb_removal_delay_length_minus1;
uint8_t au_cpb_removal_delay_length_minus1;
uint8_t dpb_output_delay_length_minus1;
uint8_t cpb_cnt_minus1[HEVC_MAX_SUB_LAYERS];
uint16_t elemental_duration_in_tc_minus1[HEVC_MAX_SUB_LAYERS];
HEVCSublayerHdrParams nal_params[HEVC_MAX_SUB_LAYERS];
HEVCSublayerHdrParams vcl_params[HEVC_MAX_SUB_LAYERS];
} HEVCHdrParams;
typedef struct ShortTermRPS {
int32_t delta_poc[32];
uint32_t used;
uint8_t delta_idx;
uint8_t num_negative_pics;
uint8_t num_delta_pocs;
uint8_t rps_idx_num_delta_pocs;
uint16_t abs_delta_rps;
unsigned delta_rps_sign:1;
unsigned rps_predict:1;
unsigned use_delta:1;
} ShortTermRPS;
typedef struct HEVCWindow {
unsigned int left_offset;
unsigned int right_offset;
unsigned int top_offset;
unsigned int bottom_offset;
} HEVCWindow;
typedef struct VUI {
H2645VUI common;
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 PTLCommon {
uint8_t profile_space;
uint8_t tier_flag;
uint8_t profile_idc;
uint8_t profile_compatibility_flag[32];
uint8_t progressive_source_flag;
uint8_t interlaced_source_flag;
uint8_t non_packed_constraint_flag;
uint8_t frame_only_constraint_flag;
uint8_t max_12bit_constraint_flag;
uint8_t max_10bit_constraint_flag;
uint8_t max_8bit_constraint_flag;
uint8_t max_422chroma_constraint_flag;
uint8_t max_420chroma_constraint_flag;
uint8_t max_monochrome_constraint_flag;
uint8_t intra_constraint_flag;
uint8_t one_picture_only_constraint_flag;
uint8_t lower_bit_rate_constraint_flag;
uint8_t max_14bit_constraint_flag;
uint8_t inbld_flag;
uint8_t level_idc;
} PTLCommon;
typedef struct PTL {
PTLCommon general_ptl;
PTLCommon sub_layer_ptl[HEVC_MAX_SUB_LAYERS];
uint8_t sub_layer_profile_present_flag[HEVC_MAX_SUB_LAYERS];
uint8_t sub_layer_level_present_flag[HEVC_MAX_SUB_LAYERS];
} PTL;
typedef struct RepFormat {
uint16_t pic_width_in_luma_samples;
uint16_t pic_height_in_luma_samples;
uint8_t chroma_format_idc;
uint8_t separate_colour_plane_flag;
uint8_t bit_depth_luma; ///< bit_depth_vps_luma_minus8 + 8
uint8_t bit_depth_chroma; ///< bit_depth_vps_chroma_minus8 + 8
uint16_t conf_win_left_offset;
uint16_t conf_win_right_offset;
uint16_t conf_win_top_offset;
uint16_t conf_win_bottom_offset;
} RepFormat;
typedef struct HEVCVPS {
unsigned int vps_id;
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[HEVC_MAX_SUB_LAYERS];
unsigned int vps_num_reorder_pics[HEVC_MAX_SUB_LAYERS];
unsigned int vps_max_latency_increase[HEVC_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;
HEVCHdrParams *hdr;
/* VPS extension */
/* Number of layers this VPS was parsed for, between 1 and
* min(HEVC_VPS_MAX_LAYERS, vps_max_layers).
*
* Note that vps_max_layers contains the layer count declared in the
* bitstream, while nb_layers contains the number of layers exported to
* users of this API (which may be smaller as we only support a subset of
* multilayer extensions).
*
* Arrays below documented as [layer_idx] have nb_layers valid entries.
*/
int nb_layers;
uint16_t scalability_mask_flag;
// LayerIdxInVps[nuh_layer_id], i.e. a mapping of nuh_layer_id to VPS layer
// indices. Valid values are between 0 and HEVC_VPS_MAX_LAYERS. Entries for
// unmapped values of nuh_layer_id are set to -1.
int8_t layer_idx[HEVC_MAX_NUH_LAYER_ID + 1];
uint8_t layer_id_in_nuh[HEVC_VPS_MAX_LAYERS];
uint8_t default_ref_layers_active;
uint8_t max_one_active_ref_layer;
uint8_t poc_lsb_aligned;
// bitmask of poc_lsb_not_present[layer_idx]
uint8_t poc_lsb_not_present;
struct {
unsigned max_dec_pic_buffering; // max_vps_dec_pic_buffering_minus1 + 1
unsigned max_num_reorder_pics; // max_vps_num_reorder_pics
unsigned max_latency_increase; // max_vps_latency_increase_plus1 - 1
} dpb_size;
// ViewId[layer_idx]
uint16_t view_id[HEVC_VPS_MAX_LAYERS];
// NumOutputLayerSets
uint8_t num_output_layer_sets;
// Bitmasks specifying output layer sets. i-th bit set means layer with VPS
// index i is present in the layer set.
uint64_t ols[HEVC_VPS_MAX_LAYERS];
// NumDirectRefLayers[layer_idx]
uint8_t num_direct_ref_layers[HEVC_VPS_MAX_LAYERS];
uint8_t num_add_layer_sets;
RepFormat rep_format;
uint8_t *data;
int data_size;
} HEVCVPS;
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 {
unsigned vps_id;
int chroma_format_idc;
HEVCWindow output_window;
HEVCWindow pic_conf_win;
HEVCHdrParams hdr;
int bit_depth;
int bit_depth_chroma;
int pixel_shift;
enum AVPixelFormat pix_fmt;
unsigned int log2_max_poc_lsb;
int max_sub_layers;
struct {
int max_dec_pic_buffering;
int num_reorder_pics;
int max_latency_increase;
} temporal_layer[HEVC_MAX_SUB_LAYERS];
int vui_present;
VUI vui;
PTL ptl;
ScalingList scaling_list;
unsigned int nb_st_rps;
ShortTermRPS st_rps[HEVC_MAX_SHORT_TERM_REF_PIC_SETS];
uint16_t lt_ref_pic_poc_lsb_sps[HEVC_MAX_LONG_TERM_REF_PICS];
uint32_t used_by_curr_pic_lt;
uint8_t num_long_term_ref_pics_sps;
struct {
uint8_t bit_depth;
uint8_t bit_depth_chroma;
unsigned int log2_min_pcm_cb_size;
unsigned int log2_max_pcm_cb_size;
} pcm;
unsigned int log2_min_cb_size;
unsigned int log2_diff_max_min_coding_block_size;
unsigned int log2_min_tb_size;
unsigned int log2_max_trafo_size;
unsigned int log2_ctb_size;
unsigned int log2_min_pu_size;
unsigned int log2_diff_max_min_transform_block_size;
int max_transform_hierarchy_depth_inter;
int max_transform_hierarchy_depth_intra;
uint8_t separate_colour_plane;
uint8_t conformance_window;
uint8_t pcm_enabled;
uint8_t pcm_loop_filter_disabled;
uint8_t sublayer_ordering_info;
uint8_t temporal_id_nesting;
uint8_t extension_present;
uint8_t scaling_list_enabled;
uint8_t amp_enabled;
uint8_t sao_enabled;
uint8_t long_term_ref_pics_present;
uint8_t temporal_mvp_enabled;
uint8_t strong_intra_smoothing_enabled;
uint8_t range_extension;
uint8_t transform_skip_rotation_enabled;
uint8_t transform_skip_context_enabled;
uint8_t implicit_rdpcm_enabled;
uint8_t explicit_rdpcm_enabled;
uint8_t extended_precision_processing;
uint8_t intra_smoothing_disabled;
uint8_t high_precision_offsets_enabled;
uint8_t persistent_rice_adaptation_enabled;
uint8_t cabac_bypass_alignment_enabled;
uint8_t multilayer_extension;
uint8_t sps_3d_extension;
uint8_t scc_extension;
uint8_t curr_pic_ref_enabled;
uint8_t palette_mode_enabled;
uint8_t palette_predictor_initializers_present;
uint8_t intra_boundary_filtering_disabled;
int palette_max_size;
int delta_palette_max_predictor_size;
int sps_num_palette_predictor_initializers;
int sps_palette_predictor_initializer[3][HEVC_MAX_PALETTE_PREDICTOR_SIZE];
int motion_vector_resolution_control_idc;
/// 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 min_pu_width;
int min_pu_height;
int tb_mask;
int hshift[3];
int vshift[3];
int qp_bd_offset;
uint8_t *data;
int data_size;
const HEVCVPS *vps; ///< RefStruct reference
} HEVCSPS;
typedef struct HEVCPPS {
unsigned int pps_id;
unsigned 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;
uint16_t num_tile_columns; ///< num_tile_columns_minus1 + 1
uint16_t 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 disable_dbf;
int beta_offset; ///< beta_offset_div2 * 2
int tc_offset; ///< tc_offset_div2 * 2
uint8_t 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 log2_max_transform_skip_block_size;
uint8_t pps_extension_present_flag;
uint8_t pps_range_extensions_flag;
uint8_t pps_multilayer_extension_flag;
uint8_t pps_3d_extension_flag;
uint8_t pps_scc_extension_flag;
uint8_t cross_component_prediction_enabled_flag;
uint8_t chroma_qp_offset_list_enabled_flag;
uint8_t diff_cu_chroma_qp_offset_depth;
uint8_t chroma_qp_offset_list_len_minus1;
int8_t cb_qp_offset_list[6];
int8_t cr_qp_offset_list[6];
uint8_t log2_sao_offset_scale_luma;
uint8_t log2_sao_offset_scale_chroma;
// Multilayer extension parameters
uint8_t poc_reset_info_present_flag;
uint8_t pps_infer_scaling_list_flag;
uint8_t pps_scaling_list_ref_layer_id;
uint8_t num_ref_loc_offsets;
uint8_t ref_loc_offset_layer_id[64];
uint8_t scaled_ref_layer_offset_present_flag[64];
int16_t scaled_ref_layer_left_offset[64];
int16_t scaled_ref_layer_top_offset[64];
int16_t scaled_ref_layer_right_offset[64];
int16_t scaled_ref_layer_bottom_offset[64];
uint8_t ref_region_offset_present_flag[64];
int16_t ref_region_left_offset[64];
int16_t ref_region_top_offset[64];
int16_t ref_region_right_offset[64];
int16_t ref_region_bottom_offset[64];
uint8_t resample_phase_set_present_flag[64];
uint8_t phase_hor_luma[64];
uint8_t phase_ver_luma[64];
int8_t phase_hor_chroma[64];
int8_t phase_ver_chroma[64];
uint8_t colour_mapping_enabled_flag;
uint8_t num_cm_ref_layers;
uint8_t cm_ref_layer_id[62];
uint8_t cm_octant_depth;
uint8_t cm_y_part_num_log2;
uint8_t luma_bit_depth_cm_input;
uint8_t chroma_bit_depth_cm_input;
uint8_t luma_bit_depth_cm_output;
uint8_t chroma_bit_depth_cm_output;
uint8_t cm_res_quant_bits;
uint8_t cm_delta_flc_bits;
int8_t cm_adapt_threshold_u_delta;
int8_t cm_adapt_threshold_v_delta;
// 3D extension parameters
uint8_t pps_bit_depth_for_depth_layers_minus8;
// SCC extension parameters
uint8_t pps_curr_pic_ref_enabled_flag;
uint8_t residual_adaptive_colour_transform_enabled_flag;
uint8_t pps_slice_act_qp_offsets_present_flag;
int8_t pps_act_y_qp_offset; // _plus5
int8_t pps_act_cb_qp_offset; // _plus5
int8_t pps_act_cr_qp_offset; // _plus3
uint8_t pps_palette_predictor_initializers_present_flag;
uint8_t pps_num_palette_predictor_initializers;
uint8_t monochrome_palette_flag;
uint8_t luma_bit_depth_entry;
uint8_t chroma_bit_depth_entry;
uint16_t pps_palette_predictor_initializer[3][HEVC_MAX_PALETTE_PREDICTOR_SIZE];
// Inferred parameters
unsigned int *column_width; ///< ColumnWidth
unsigned int *row_height; ///< RowHeight
unsigned int *col_bd; ///< ColBd
unsigned 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_tb_addr_zs; ///< MinTbAddrZS
int *min_tb_addr_zs_tab;///< MinTbAddrZS
uint8_t *data;
int data_size;
const HEVCSPS *sps; ///< RefStruct reference
} HEVCPPS;
typedef struct HEVCParamSets {
const HEVCVPS *vps_list[HEVC_MAX_VPS_COUNT]; ///< RefStruct references
const HEVCSPS *sps_list[HEVC_MAX_SPS_COUNT]; ///< RefStruct references
const HEVCPPS *pps_list[HEVC_MAX_PPS_COUNT]; ///< RefStruct references
} HEVCParamSets;
/**
* Parse the SPS from the bitstream into the provided HEVCSPS struct.
*
* @param sps_id the SPS id will be written here
* @param apply_defdispwin if set 1, the default display window from the VUI
* will be applied to the video dimensions
* @param vps_list if non-NULL, this function will validate that the SPS refers
* to an existing VPS
*/
int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id,
unsigned nuh_layer_id, int apply_defdispwin,
const HEVCVPS * const *vps_list, AVCodecContext *avctx);
int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx,
HEVCParamSets *ps);
int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx,
HEVCParamSets *ps, unsigned nuh_layer_id,
int apply_defdispwin);
int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx,
HEVCParamSets *ps);
void ff_hevc_ps_uninit(HEVCParamSets *ps);
int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx,
ShortTermRPS *rps, const HEVCSPS *sps, int is_slice_header);
int ff_hevc_encode_nal_vps(HEVCVPS *vps, unsigned int id,
uint8_t *buf, int buf_size);
/**
* Compute POC of the current frame and return it.
*/
int ff_hevc_compute_poc(const HEVCSPS *sps, int pocTid0, int poc_lsb, int nal_unit_type);
#endif /* AVCODEC_HEVC_PS_H */
+121
View File
@@ -0,0 +1,121 @@
/*
* HEVC Parameter Set encoding
*
* 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 "put_golomb.h"
#include "ps.h"
#include "put_bits.h"
static void write_ptl_layer(PutBitContext *pb, PTLCommon *ptl)
{
int i;
put_bits(pb, 2, ptl->profile_space);
put_bits(pb, 1, ptl->tier_flag);
put_bits(pb, 5, ptl->profile_idc);
for (i = 0; i < 32; i++)
put_bits(pb, 1, ptl->profile_compatibility_flag[i]);
put_bits(pb, 1, ptl->progressive_source_flag);
put_bits(pb, 1, ptl->interlaced_source_flag);
put_bits(pb, 1, ptl->non_packed_constraint_flag);
put_bits(pb, 1, ptl->frame_only_constraint_flag);
put_bits32(pb, 0); // reserved
put_bits(pb, 12, 0); // reserved
}
static void write_ptl(PutBitContext *pb, PTL *ptl, int max_num_sub_layers)
{
int i;
write_ptl_layer(pb, &ptl->general_ptl);
put_bits(pb, 8, ptl->general_ptl.level_idc);
for (i = 0; i < max_num_sub_layers - 1; i++) {
put_bits(pb, 1, ptl->sub_layer_profile_present_flag[i]);
put_bits(pb, 1, ptl->sub_layer_level_present_flag[i]);
}
if (max_num_sub_layers > 1)
for (i = max_num_sub_layers - 1; i < 8; i++)
put_bits(pb, 2, 0); // reserved
for (i = 0; i < max_num_sub_layers - 1; i++) {
if (ptl->sub_layer_profile_present_flag[i])
write_ptl_layer(pb, &ptl->sub_layer_ptl[i]);
if (ptl->sub_layer_level_present_flag[i])
put_bits(pb, 8, ptl->sub_layer_ptl[i].level_idc);
}
}
int ff_hevc_encode_nal_vps(HEVCVPS *vps, unsigned int id,
uint8_t *buf, int buf_size)
{
PutBitContext pb;
int i, data_size;
init_put_bits(&pb, buf, buf_size);
put_bits(&pb, 4, id);
put_bits(&pb, 2, 3); // reserved
put_bits(&pb, 6, vps->vps_max_layers - 1);
put_bits(&pb, 3, vps->vps_max_sub_layers - 1);
put_bits(&pb, 1, vps->vps_temporal_id_nesting_flag);
put_bits(&pb, 16, 0xffff); // reserved
write_ptl(&pb, &vps->ptl, vps->vps_max_sub_layers);
put_bits(&pb, 1, vps->vps_sub_layer_ordering_info_present_flag);
for (i = vps->vps_sub_layer_ordering_info_present_flag ? 0 : vps->vps_max_layers - 1;
i < vps->vps_max_sub_layers; i++) {
set_ue_golomb(&pb, vps->vps_max_dec_pic_buffering[i] - 1);
set_ue_golomb(&pb, vps->vps_num_reorder_pics[i]);
set_ue_golomb(&pb, vps->vps_max_latency_increase[i] + 1);
}
put_bits(&pb, 6, vps->vps_max_layer_id);
set_ue_golomb(&pb, vps->vps_num_layer_sets - 1);
if (vps->vps_num_layer_sets > 1) {
avpriv_report_missing_feature(NULL, "Writing layer_id_included_flag");
return AVERROR_PATCHWELCOME;
}
put_bits(&pb, 1, vps->vps_timing_info_present_flag);
if (vps->vps_timing_info_present_flag) {
put_bits32(&pb, vps->vps_num_units_in_tick);
put_bits32(&pb, vps->vps_time_scale);
put_bits(&pb, 1, vps->vps_poc_proportional_to_timing_flag);
if (vps->vps_poc_proportional_to_timing_flag)
set_ue_golomb(&pb, vps->vps_num_ticks_poc_diff_one - 1);
set_ue_golomb(&pb, vps->vps_num_hrd_parameters);
if (vps->vps_num_hrd_parameters) {
avpriv_report_missing_feature(NULL, "Writing HRD parameters");
return AVERROR_PATCHWELCOME;
}
}
put_bits(&pb, 1, 0); // extension flag
put_bits(&pb, 1, 1); // stop bit
flush_put_bits(&pb);
data_size = put_bytes_output(&pb);
return data_size;
}
+642
View File
@@ -0,0 +1,642 @@
/*
* 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/container_fifo.h"
#include "libavutil/mem.h"
#include "libavutil/stereo3d.h"
#include "decode.h"
#include "hevc.h"
#include "hevcdec.h"
#include "progressframe.h"
#include "thread.h"
#include "libavutil/refstruct.h"
void ff_hevc_unref_frame(HEVCFrame *frame, int flags)
{
frame->flags &= ~flags;
if (!(frame->flags & ~HEVC_FRAME_FLAG_CORRUPT))
frame->flags = 0;
if (!frame->flags) {
ff_progress_frame_unref(&frame->tf);
av_frame_unref(frame->frame_grain);
frame->needs_fg = 0;
av_refstruct_unref(&frame->pps);
av_refstruct_unref(&frame->tab_mvf);
av_refstruct_unref(&frame->rpl);
frame->nb_rpl_elems = 0;
av_refstruct_unref(&frame->rpl_tab);
frame->refPicList = NULL;
av_refstruct_unref(&frame->hwaccel_picture_private);
}
}
const RefPicList *ff_hevc_get_ref_list(const HEVCFrame *ref, int x0, int y0)
{
const HEVCSPS *sps = ref->pps->sps;
int x_cb = x0 >> sps->log2_ctb_size;
int y_cb = y0 >> sps->log2_ctb_size;
int pic_width_cb = sps->ctb_width;
int ctb_addr_ts = ref->pps->ctb_addr_rs_to_ts[y_cb * pic_width_cb + x_cb];
return &ref->rpl_tab[ctb_addr_ts]->refPicList[0];
}
void ff_hevc_clear_refs(HEVCLayerContext *l)
{
int i;
for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++)
ff_hevc_unref_frame(&l->DPB[i],
HEVC_FRAME_FLAG_SHORT_REF |
HEVC_FRAME_FLAG_LONG_REF);
}
void ff_hevc_flush_dpb(HEVCContext *s)
{
for (int layer = 0; layer < FF_ARRAY_ELEMS(s->layers); layer++) {
HEVCLayerContext *l = &s->layers[layer];
for (int i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++)
ff_hevc_unref_frame(&l->DPB[i], ~0);
}
}
static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
{
AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
uintptr_t data = (uintptr_t)alpha->data[0];
int ret;
for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
AVBufferRef *buf = alpha->buf[i];
uintptr_t buf_begin = (uintptr_t)buf->data;
if (data >= buf_begin && data < buf_begin + buf->size) {
ret = av_buffer_replace(&alpha->buf[i], base_a);
if (ret < 0)
return ret;
alpha->linesize[0] = base->linesize[3];
alpha->data[0] = base->data[3];
return 0;
}
}
return AVERROR_BUG;
}
static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
{
const HEVCVPS *vps = l->sps->vps;
const int view_id = vps->view_id[s->cur_layer];
int i, j, ret;
for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) {
HEVCFrame *frame = &l->DPB[i];
if (frame->f)
continue;
ret = ff_progress_frame_alloc(s->avctx, &frame->tf);
if (ret < 0)
return NULL;
// Add LCEVC SEI metadata here, as it's needed in get_buffer()
if (s->sei.common.lcevc.info) {
HEVCSEILCEVC *lcevc = &s->sei.common.lcevc;
ret = ff_frame_new_side_data_from_buf(s->avctx, frame->tf.f,
AV_FRAME_DATA_LCEVC, &lcevc->info);
if (ret < 0)
goto fail;
}
// add view ID side data if it's nontrivial
if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) {
HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data,
&frame->f->nb_side_data,
AV_FRAME_DATA_VIEW_ID,
sizeof(int), 0);
if (!sd)
goto fail;
*(int*)sd->data = view_id;
if (tdrdi->num_ref_displays) {
AVStereo3D *stereo_3d;
stereo_3d = av_stereo3d_create_side_data(frame->f);
if (!stereo_3d)
goto fail;
stereo_3d->type = AV_STEREO3D_FRAMESEQUENCE;
if (tdrdi->left_view_id[0] == view_id)
stereo_3d->view = AV_STEREO3D_VIEW_LEFT;
else if (tdrdi->right_view_id[0] == view_id)
stereo_3d->view = AV_STEREO3D_VIEW_RIGHT;
else
stereo_3d->view = AV_STEREO3D_VIEW_UNSPEC;
}
}
ret = ff_thread_get_buffer(s->avctx, frame->f, AV_GET_BUFFER_FLAG_REF);
if (ret < 0)
goto fail;
frame->rpl = av_refstruct_allocz(s->pkt.nb_nals * sizeof(*frame->rpl));
if (!frame->rpl)
goto fail;
frame->nb_rpl_elems = s->pkt.nb_nals;
frame->tab_mvf = av_refstruct_pool_get(l->tab_mvf_pool);
if (!frame->tab_mvf)
goto fail;
frame->rpl_tab = av_refstruct_pool_get(l->rpl_tab_pool);
if (!frame->rpl_tab)
goto fail;
frame->ctb_count = l->sps->ctb_width * l->sps->ctb_height;
for (j = 0; j < frame->ctb_count; j++)
frame->rpl_tab[j] = frame->rpl;
if (s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD)
frame->f->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
if ((s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD) ||
(s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_BOTTOM_FIELD))
frame->f->flags |= AV_FRAME_FLAG_INTERLACED;
ret = ff_hwaccel_frame_priv_alloc(s->avctx, &frame->hwaccel_picture_private);
if (ret < 0)
goto fail;
frame->pps = av_refstruct_ref_c(s->pps);
if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) {
AVFrame *alpha = frame->f;
AVFrame *base = s->layers[0].cur_frame->f;
ret = replace_alpha_plane(alpha, base);
if (ret < 0)
goto fail;
}
return frame;
fail:
ff_hevc_unref_frame(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, HEVCLayerContext *l, int poc)
{
HEVCFrame *ref;
int i;
int no_output;
/* check that this POC doesn't already exist */
for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) {
HEVCFrame *frame = &l->DPB[i];
if (frame->f && 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, l);
if (!ref)
return AVERROR(ENOMEM);
s->cur_frame = ref;
l->cur_frame = ref;
s->collocated_ref = NULL;
ref->base_layer_frame = (l != &s->layers[0] && s->layers[0].cur_frame) ?
s->layers[0].cur_frame - s->layers[0].DPB : -1;
no_output = !IS_IRAP(s) && (s->poc < s->recovery_poc) &&
!(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) &&
!(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL);
if (s->sh.pic_output_flag && !no_output)
ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF;
else
ref->flags = HEVC_FRAME_FLAG_SHORT_REF;
ref->poc = poc;
ref->f->crop_left = l->sps->output_window.left_offset;
ref->f->crop_right = l->sps->output_window.right_offset;
ref->f->crop_top = l->sps->output_window.top_offset;
ref->f->crop_bottom = l->sps->output_window.bottom_offset;
return 0;
}
static void unref_missing_refs(HEVCLayerContext *l)
{
for (int i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) {
HEVCFrame *frame = &l->DPB[i];
if (frame->flags & HEVC_FRAME_FLAG_UNAVAILABLE) {
ff_hevc_unref_frame(frame, ~0);
}
}
}
int ff_hevc_output_frames(HEVCContext *s,
unsigned layers_active_decode, unsigned layers_active_output,
unsigned max_output, unsigned max_dpb, int discard)
{
while (1) {
int nb_dpb[HEVC_VPS_MAX_LAYERS] = { 0 };
int nb_output = 0;
int min_poc = INT_MAX;
int min_layer = -1;
int min_idx, ret = 0;
for (int layer = 0; layer < FF_ARRAY_ELEMS(s->layers); layer++) {
HEVCLayerContext *l = &s->layers[layer];
if (!(layers_active_decode & (1 << layer)))
continue;
for (int i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) {
HEVCFrame *frame = &l->DPB[i];
if (frame->flags & HEVC_FRAME_FLAG_OUTPUT) {
// nb_output counts AUs with an output-pending frame
// in at least one layer
if (!(frame->base_layer_frame >= 0 &&
(s->layers[0].DPB[frame->base_layer_frame].flags & HEVC_FRAME_FLAG_OUTPUT)))
nb_output++;
if (min_layer < 0 || frame->poc < min_poc) {
min_poc = frame->poc;
min_idx = i;
min_layer = layer;
}
}
nb_dpb[layer] += !!frame->flags;
}
}
if (nb_output > max_output ||
(nb_output &&
(nb_dpb[0] > max_dpb || nb_dpb[1] > max_dpb))) {
HEVCFrame *frame = &s->layers[min_layer].DPB[min_idx];
AVFrame *f = frame->needs_fg ? frame->frame_grain : frame->f;
int output = !discard && (layers_active_output & (1 << min_layer));
if (output) {
if (frame->flags & HEVC_FRAME_FLAG_CORRUPT)
f->flags |= AV_FRAME_FLAG_CORRUPT;
f->pkt_dts = s->pkt_dts;
ret = av_container_fifo_write(s->output_fifo, f, AV_CONTAINER_FIFO_FLAG_REF);
}
ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT);
if (ret < 0)
return ret;
av_log(s->avctx, AV_LOG_DEBUG, "%s frame with POC %d/%d.\n",
output ? "Output" : "Discarded", min_layer, frame->poc);
continue;
}
return 0;
}
}
static int init_slice_rpl(HEVCContext *s)
{
HEVCFrame *frame = s->cur_frame;
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->nb_rpl_elems)
return AVERROR_INVALIDDATA;
for (i = ctb_addr_ts; i < ctb_count; i++)
frame->rpl_tab[i] = frame->rpl + 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 == HEVC_SLICE_B ? 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 +
s->rps[INTER_LAYER0].nb_refs + s->rps[INTER_LAYER1].nb_refs) &&
!s->pps->pps_curr_pic_ref_enabled_flag) {
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->cur_frame->refPicList[list_idx];
/* The order of the elements is
* ST_CURR_BEF - INTER_LAYER0 - ST_CURR_AFT - LT_CURR - INTER_LAYER1 for the L0 and
* ST_CURR_AFT - INTER_LAYER1 - ST_CURR_BEF - LT_CURR - INTER_LAYER0 for the L1 */
int cand_lists[] = { list_idx ? ST_CURR_AFT : ST_CURR_BEF,
list_idx ? INTER_LAYER1 : INTER_LAYER0,
list_idx ? ST_CURR_BEF : ST_CURR_AFT,
LT_CURR,
list_idx ? INTER_LAYER0 : INTER_LAYER1
};
/* concatenate the candidate lists for the current frame */
while (rpl_tmp.nb_refs < sh->nb_refs[list_idx]) {
for (i = 0; i < FF_ARRAY_ELEMS(cand_lists); i++) {
RefPicList *rps = &s->rps[cand_lists[i]];
for (j = 0; j < rps->nb_refs && rpl_tmp.nb_refs < HEVC_MAX_REFS; j++) {
rpl_tmp.list[rpl_tmp.nb_refs] = rps->list[j];
rpl_tmp.ref[rpl_tmp.nb_refs] = rps->ref[j];
// multiview inter-layer refs are treated as long-term here,
// cf. G.8.1.3
rpl_tmp.isLongTerm[rpl_tmp.nb_refs] = cand_lists[i] == LT_CURR ||
cand_lists[i] == INTER_LAYER0 ||
cand_lists[i] == INTER_LAYER1;
rpl_tmp.nb_refs++;
}
}
// Construct RefPicList0, RefPicList1 (8-8, 8-10)
if (s->pps->pps_curr_pic_ref_enabled_flag && rpl_tmp.nb_refs < HEVC_MAX_REFS) {
rpl_tmp.list[rpl_tmp.nb_refs] = s->cur_frame->poc;
rpl_tmp.ref[rpl_tmp.nb_refs] = s->cur_frame;
rpl_tmp.isLongTerm[rpl_tmp.nb_refs] = 1;
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]);
}
// 8-9
if (s->pps->pps_curr_pic_ref_enabled_flag &&
!sh->rpl_modification_flag[list_idx] &&
rpl_tmp.nb_refs > sh->nb_refs[L0]) {
rpl->list[sh->nb_refs[L0] - 1] = s->cur_frame->poc;
rpl->ref[sh->nb_refs[L0] - 1] = s->cur_frame;
}
if (sh->collocated_list == list_idx &&
sh->collocated_ref_idx < rpl->nb_refs)
s->collocated_ref = rpl->ref[sh->collocated_ref_idx];
}
return 0;
}
static HEVCFrame *find_ref_idx(HEVCContext *s, HEVCLayerContext *l,
int poc, uint8_t use_msb)
{
int mask = use_msb ? ~0 : (1 << l->sps->log2_max_poc_lsb) - 1;
int i;
for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) {
HEVCFrame *ref = &l->DPB[i];
if (ref->f) {
if ((ref->poc & mask) == poc && (use_msb || ref->poc != s->poc))
return ref;
}
}
if (s->nal_unit_type != HEVC_NAL_CRA_NUT && !IS_BLA(s))
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, HEVCLayerContext *l, int poc)
{
HEVCFrame *frame;
int i, y;
frame = alloc_frame(s, l);
if (!frame)
return NULL;
if (!s->avctx->hwaccel) {
if (!l->sps->pixel_shift) {
for (i = 0; frame->f->data[i]; i++)
memset(frame->f->data[i], 1 << (l->sps->bit_depth - 1),
frame->f->linesize[i] * AV_CEIL_RSHIFT(l->sps->height, l->sps->vshift[i]));
} else {
for (i = 0; frame->f->data[i]; i++)
for (y = 0; y < (l->sps->height >> l->sps->vshift[i]); y++) {
uint8_t *dst = frame->f->data[i] + y * frame->f->linesize[i];
AV_WN16(dst, 1 << (l->sps->bit_depth - 1));
av_memcpy_backptr(dst + 2, 2, 2*(l->sps->width >> l->sps->hshift[i]) - 2);
}
}
}
frame->poc = poc;
frame->flags = HEVC_FRAME_FLAG_UNAVAILABLE;
if (s->avctx->active_thread_type == FF_THREAD_FRAME)
ff_progress_frame_report(&frame->tf, INT_MAX);
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, HEVCLayerContext *l,
RefPicList *list,
int poc, int ref_flag, uint8_t use_msb)
{
HEVCFrame *ref = find_ref_idx(s, l, poc, use_msb);
if (ref == s->cur_frame || list->nb_refs >= HEVC_MAX_REFS)
return AVERROR_INVALIDDATA;
if (!IS_IRAP(s)) {
int ref_corrupt = !ref || ref->flags & (HEVC_FRAME_FLAG_CORRUPT |
HEVC_FRAME_FLAG_UNAVAILABLE);
int recovering = HEVC_IS_RECOVERING(s);
if (ref_corrupt && !recovering) {
if (!(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) &&
!(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL))
return AVERROR_INVALIDDATA;
s->cur_frame->flags |= HEVC_FRAME_FLAG_CORRUPT;
}
}
if (!ref) {
ref = generate_missing_ref(s, l, 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, HEVCLayerContext *l)
{
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 = 0;
unref_missing_refs(l);
/* clear the reference flags on all frames except the current one */
for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) {
HEVCFrame *frame = &l->DPB[i];
if (frame == s->cur_frame)
continue;
mark_ref(frame, 0);
}
for (i = 0; i < NB_RPS_TYPE; i++)
rps[i].nb_refs = 0;
if (!short_rps)
goto inter_layer;
/* 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 & (1 << 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, l, &rps[list], poc,
HEVC_FRAME_FLAG_SHORT_REF, 1);
if (ret < 0)
goto fail;
}
/* 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, l, &rps[list], poc,
HEVC_FRAME_FLAG_LONG_REF, long_rps->poc_msb_present[i]);
if (ret < 0)
goto fail;
}
inter_layer:
/* add inter-layer refs */
if (s->sh.inter_layer_pred) {
HEVCLayerContext *l0 = &s->layers[0];
av_assert0(l != l0);
/* Given the assumption of at most two layers, refPicSet0Flag is
* always 1, so only RefPicSetInterLayer0 can ever contain a frame. */
if (l0->cur_frame) {
// inter-layer refs are treated as short-term here, cf. F.8.1.6
ret = add_candidate_ref(s, l0, &rps[INTER_LAYER0], l0->cur_frame->poc,
HEVC_FRAME_FLAG_SHORT_REF, 1);
if (ret < 0)
goto fail;
}
}
fail:
/* release any frames that are now unused */
for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++)
ff_hevc_unref_frame(&l->DPB[i], 0);
return ret;
}
int ff_hevc_frame_nb_refs(const SliceHeader *sh, const HEVCPPS *pps,
unsigned layer_idx)
{
int ret = 0;
int i;
const ShortTermRPS *rps = sh->short_term_rps;
const LongTermRPS *long_rps = &sh->long_term_rps;
if (rps) {
for (i = 0; i < rps->num_negative_pics; i++)
ret += !!(rps->used & (1 << i));
for (; i < rps->num_delta_pocs; i++)
ret += !!(rps->used & (1 << i));
}
if (long_rps) {
for (i = 0; i < long_rps->nb_refs; i++)
ret += !!long_rps->used[i];
}
if (sh->inter_layer_pred) {
av_assert0(pps->sps->vps->num_direct_ref_layers[layer_idx] < 2);
ret++;
}
if (pps->pps_curr_pic_ref_enabled_flag)
ret++;
return ret;
}
+315
View File
@@ -0,0 +1,315 @@
/*
* 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 "bytestream.h"
#include "golomb.h"
#include "ps.h"
#include "sei.h"
static int decode_nal_sei_decoded_picture_hash(HEVCSEIPictureHash *s,
GetByteContext *gb)
{
int cIdx;
uint8_t hash_type;
//uint16_t picture_crc;
//uint32_t picture_checksum;
hash_type = bytestream2_get_byte(gb);
for (cIdx = 0; cIdx < 3/*((s->sps->chroma_format_idc == 0) ? 1 : 3)*/; cIdx++) {
if (hash_type == 0) {
s->is_md5 = 1;
bytestream2_get_buffer(gb, s->md5[cIdx], sizeof(s->md5[cIdx]));
} else if (hash_type == 1) {
// picture_crc = get_bits(gb, 16);
} else if (hash_type == 2) {
// picture_checksum = get_bits_long(gb, 32);
}
}
return 0;
}
static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb,
const HEVCParamSets *ps, void *logctx)
{
HEVCSEIPictureTiming *h = &s->picture_timing;
const HEVCSPS *sps = ps->sps_list[s->active_seq_parameter_set_id];
if (!sps)
return AVERROR_INVALIDDATA;
if (sps->vui.frame_field_info_present_flag) {
int pic_struct = get_bits(gb, 4);
h->picture_struct = AV_PICTURE_STRUCTURE_UNKNOWN;
if (pic_struct == 2 || pic_struct == 10 || pic_struct == 12) {
av_log(logctx, AV_LOG_DEBUG, "BOTTOM Field\n");
h->picture_struct = AV_PICTURE_STRUCTURE_BOTTOM_FIELD;
} else if (pic_struct == 1 || pic_struct == 9 || pic_struct == 11) {
av_log(logctx, AV_LOG_DEBUG, "TOP Field\n");
h->picture_struct = AV_PICTURE_STRUCTURE_TOP_FIELD;
} else if (pic_struct == 7) {
av_log(logctx, AV_LOG_DEBUG, "Frame/Field Doubling\n");
h->picture_struct = HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING;
} else if (pic_struct == 8) {
av_log(logctx, AV_LOG_DEBUG, "Frame/Field Tripling\n");
h->picture_struct = HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING;
}
}
return 0;
}
static int decode_nal_sei_recovery_point(HEVCSEI *s, GetBitContext *gb)
{
HEVCSEIRecoveryPoint *rec = &s->recovery_point;
int recovery_poc_cnt = get_se_golomb(gb);
if (recovery_poc_cnt > INT16_MAX || recovery_poc_cnt < INT16_MIN)
return AVERROR_INVALIDDATA;
rec->recovery_poc_cnt = recovery_poc_cnt;
rec->exact_match_flag = get_bits1(gb);
rec->broken_link_flag = get_bits1(gb);
rec->has_recovery_poc = 1;
return 0;
}
static int decode_nal_sei_active_parameter_sets(HEVCSEI *s, GetBitContext *gb, void *logctx)
{
int num_sps_ids_minus1;
unsigned active_seq_parameter_set_id;
get_bits(gb, 4); // active_video_parameter_set_id
get_bits(gb, 1); // self_contained_cvs_flag
get_bits(gb, 1); // num_sps_ids_minus1
num_sps_ids_minus1 = get_ue_golomb_long(gb); // num_sps_ids_minus1
if (num_sps_ids_minus1 < 0 || num_sps_ids_minus1 > 15) {
av_log(logctx, AV_LOG_ERROR, "num_sps_ids_minus1 %d invalid\n", num_sps_ids_minus1);
return AVERROR_INVALIDDATA;
}
active_seq_parameter_set_id = get_ue_golomb_long(gb);
if (active_seq_parameter_set_id >= HEVC_MAX_SPS_COUNT) {
av_log(logctx, AV_LOG_ERROR, "active_parameter_set_id %d invalid\n", active_seq_parameter_set_id);
return AVERROR_INVALIDDATA;
}
s->active_seq_parameter_set_id = active_seq_parameter_set_id;
return 0;
}
static int decode_nal_sei_timecode(HEVCSEITimeCode *s, GetBitContext *gb)
{
s->num_clock_ts = get_bits(gb, 2);
for (int i = 0; i < s->num_clock_ts; i++) {
s->clock_timestamp_flag[i] = get_bits(gb, 1);
if (s->clock_timestamp_flag[i]) {
s->units_field_based_flag[i] = get_bits(gb, 1);
s->counting_type[i] = get_bits(gb, 5);
s->full_timestamp_flag[i] = get_bits(gb, 1);
s->discontinuity_flag[i] = get_bits(gb, 1);
s->cnt_dropped_flag[i] = get_bits(gb, 1);
s->n_frames[i] = get_bits(gb, 9);
if (s->full_timestamp_flag[i]) {
s->seconds_value[i] = av_clip(get_bits(gb, 6), 0, 59);
s->minutes_value[i] = av_clip(get_bits(gb, 6), 0, 59);
s->hours_value[i] = av_clip(get_bits(gb, 5), 0, 23);
} else {
s->seconds_flag[i] = get_bits(gb, 1);
if (s->seconds_flag[i]) {
s->seconds_value[i] = av_clip(get_bits(gb, 6), 0, 59);
s->minutes_flag[i] = get_bits(gb, 1);
if (s->minutes_flag[i]) {
s->minutes_value[i] = av_clip(get_bits(gb, 6), 0, 59);
s->hours_flag[i] = get_bits(gb, 1);
if (s->hours_flag[i]) {
s->hours_value[i] = av_clip(get_bits(gb, 5), 0, 23);
}
}
}
}
s->time_offset_length[i] = get_bits(gb, 5);
if (s->time_offset_length[i] > 0) {
s->time_offset_value[i] = get_bits_long(gb, s->time_offset_length[i]);
}
}
}
s->present = 1;
return 0;
}
static int decode_nal_sei_3d_reference_displays_info(HEVCSEITDRDI *s, GetBitContext *gb)
{
s->prec_ref_display_width = get_ue_golomb(gb);
if (s->prec_ref_display_width > 31)
return AVERROR_INVALIDDATA;
s->ref_viewing_distance_flag = get_bits1(gb);
if (s->ref_viewing_distance_flag) {
s->prec_ref_viewing_dist = get_ue_golomb(gb);
if (s->prec_ref_viewing_dist > 31)
return AVERROR_INVALIDDATA;
}
s->num_ref_displays = get_ue_golomb(gb);
if (s->num_ref_displays > 31)
return AVERROR_INVALIDDATA;
s->num_ref_displays += 1;
for (int i = 0; i < s->num_ref_displays; i++) {
int length;
s->left_view_id[i] = get_ue_golomb(gb);
s->right_view_id[i] = get_ue_golomb(gb);
s->exponent_ref_display_width[i] = get_bits(gb, 6);
if (s->exponent_ref_display_width[i] > 62)
return AVERROR_INVALIDDATA;
else if (!s->exponent_ref_display_width[i])
length = FFMAX(0, (int)s->prec_ref_display_width - 30);
else
length = FFMAX(0, (int)s->exponent_ref_display_width[i] +
(int)s->prec_ref_display_width - 31);
s->mantissa_ref_display_width[i] = get_bits_long(gb, length);
if (s->ref_viewing_distance_flag) {
s->exponent_ref_viewing_distance[i] = get_bits(gb, 6);
if (s->exponent_ref_viewing_distance[i] > 62)
return AVERROR_INVALIDDATA;
else if (!s->exponent_ref_viewing_distance[i])
length = FFMAX(0, (int)s->prec_ref_viewing_dist - 30);
else
length = FFMAX(0, (int)s->exponent_ref_viewing_distance[i] +
(int)s->prec_ref_viewing_dist - 31);
s->mantissa_ref_viewing_distance[i] = get_bits_long(gb, length);
}
s->additional_shift_present_flag[i] = get_bits1(gb);
if (s->additional_shift_present_flag[i]) {
s->num_sample_shift[i] = get_bits(gb, 10);
if (s->num_sample_shift[i] > 1023)
return AVERROR_INVALIDDATA;
s->num_sample_shift[i] -= 512;
}
}
s->three_dimensional_reference_displays_extension_flag = get_bits1(gb);
return 0;
}
static int decode_nal_sei_prefix(GetBitContext *gb, GetByteContext *gbyte,
void *logctx, HEVCSEI *s,
const HEVCParamSets *ps, int type)
{
switch (type) {
case 256: // Mismatched value from HM 8.1
return decode_nal_sei_decoded_picture_hash(&s->picture_hash, gbyte);
case SEI_TYPE_PIC_TIMING:
return decode_nal_sei_pic_timing(s, gb, ps, logctx);
case SEI_TYPE_RECOVERY_POINT:
return decode_nal_sei_recovery_point(s, gb);
case SEI_TYPE_ACTIVE_PARAMETER_SETS:
return decode_nal_sei_active_parameter_sets(s, gb, logctx);
case SEI_TYPE_TIME_CODE:
return decode_nal_sei_timecode(&s->timecode, gb);
case SEI_TYPE_THREE_DIMENSIONAL_REFERENCE_DISPLAYS_INFO:
return decode_nal_sei_3d_reference_displays_info(&s->tdrdi, gb);
default: {
int ret = ff_h2645_sei_message_decode(&s->common, type, AV_CODEC_ID_HEVC,
gb, gbyte, logctx);
if (ret == FF_H2645_SEI_MESSAGE_UNHANDLED)
av_log(logctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", type);
return ret;
}
}
}
static int decode_nal_sei_suffix(GetBitContext *gb, GetByteContext *gbyte,
void *logctx, HEVCSEI *s, int type)
{
switch (type) {
case SEI_TYPE_DECODED_PICTURE_HASH:
return decode_nal_sei_decoded_picture_hash(&s->picture_hash, gbyte);
default:
av_log(logctx, AV_LOG_DEBUG, "Skipped SUFFIX SEI %d\n", type);
return 0;
}
}
static int decode_nal_sei_message(GetByteContext *gb, void *logctx, HEVCSEI *s,
const HEVCParamSets *ps, int nal_unit_type)
{
GetByteContext message_gbyte;
GetBitContext message_gb;
int payload_type = 0;
int payload_size = 0;
int byte = 0xFF;
av_unused int ret;
av_log(logctx, AV_LOG_DEBUG, "Decoding SEI\n");
while (byte == 0xFF) {
if (bytestream2_get_bytes_left(gb) < 2 || payload_type > INT_MAX - 255)
return AVERROR_INVALIDDATA;
byte = bytestream2_get_byteu(gb);
payload_type += byte;
}
byte = 0xFF;
while (byte == 0xFF) {
if (bytestream2_get_bytes_left(gb) < 1 + payload_size)
return AVERROR_INVALIDDATA;
byte = bytestream2_get_byteu(gb);
payload_size += byte;
}
if (bytestream2_get_bytes_left(gb) < payload_size)
return AVERROR_INVALIDDATA;
bytestream2_init(&message_gbyte, gb->buffer, payload_size);
ret = init_get_bits8(&message_gb, gb->buffer, payload_size);
av_assert1(ret >= 0);
bytestream2_skipu(gb, payload_size);
if (nal_unit_type == HEVC_NAL_SEI_PREFIX) {
return decode_nal_sei_prefix(&message_gb, &message_gbyte,
logctx, s, ps, payload_type);
} else { /* nal_unit_type == NAL_SEI_SUFFIX */
return decode_nal_sei_suffix(&message_gb, &message_gbyte,
logctx, s, payload_type);
}
}
int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEI *s,
const HEVCParamSets *ps, enum HEVCNALUnitType type)
{
GetByteContext gbyte;
int ret;
av_assert1((get_bits_count(gb) % 8) == 0);
bytestream2_init(&gbyte, gb->buffer + get_bits_count(gb) / 8,
get_bits_left(gb) / 8);
do {
ret = decode_nal_sei_message(&gbyte, logctx, s, ps, type);
if (ret < 0)
return ret;
} while (bytestream2_get_bytes_left(&gbyte) > 0);
return 1;
}
+132
View File
@@ -0,0 +1,132 @@
/*
* HEVC Supplementary Enhancement Information messages
*
* 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_SEI_H
#define AVCODEC_HEVC_SEI_H
#include <stdint.h>
#include "libavutil/buffer.h"
#include "libavcodec/get_bits.h"
#include "libavcodec/h2645_sei.h"
#include "libavcodec/sei.h"
#include "hevc.h"
typedef enum {
HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING = 7,
HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING = 8
} HEVC_SEI_PicStructType;
typedef struct HEVCSEIPictureHash {
uint8_t md5[3][16];
uint8_t is_md5;
} HEVCSEIPictureHash;
typedef struct HEVCSEIFramePacking {
int present;
int arrangement_type;
int content_interpretation_type;
int quincunx_subsampling;
int current_frame_is_frame0_flag;
} HEVCSEIFramePacking;
typedef struct HEVCSEIPictureTiming {
int picture_struct;
} HEVCSEIPictureTiming;
typedef struct HEVCSEIAlternativeTransfer {
int present;
int preferred_transfer_characteristics;
} HEVCSEIAlternativeTransfer;
typedef struct HEVCSEITimeCode {
int present;
uint8_t num_clock_ts;
uint8_t clock_timestamp_flag[3];
uint8_t units_field_based_flag[3];
uint8_t counting_type[3];
uint8_t full_timestamp_flag[3];
uint8_t discontinuity_flag[3];
uint8_t cnt_dropped_flag[3];
uint16_t n_frames[3];
uint8_t seconds_value[3];
uint8_t minutes_value[3];
uint8_t hours_value[3];
uint8_t seconds_flag[3];
uint8_t minutes_flag[3];
uint8_t hours_flag[3];
uint8_t time_offset_length[3];
int32_t time_offset_value[3];
} HEVCSEITimeCode;
typedef struct HEVCSEITDRDI {
uint8_t prec_ref_display_width;
uint8_t ref_viewing_distance_flag;
uint8_t prec_ref_viewing_dist;
uint8_t num_ref_displays;
uint16_t left_view_id[32];
uint16_t right_view_id[32];
uint8_t exponent_ref_display_width[32];
uint8_t mantissa_ref_display_width[32];
uint8_t exponent_ref_viewing_distance[32];
uint8_t mantissa_ref_viewing_distance[32];
uint8_t additional_shift_present_flag[32];
int16_t num_sample_shift[32];
uint8_t three_dimensional_reference_displays_extension_flag;
} HEVCSEITDRDI;
typedef struct HEVCSEIRecoveryPoint {
int16_t recovery_poc_cnt;
uint8_t exact_match_flag;
uint8_t broken_link_flag;
uint8_t has_recovery_poc;
} HEVCSEIRecoveryPoint;
typedef struct HEVCSEI {
H2645SEI common;
HEVCSEIPictureHash picture_hash;
HEVCSEIPictureTiming picture_timing;
int active_seq_parameter_set_id;
HEVCSEITimeCode timecode;
HEVCSEITDRDI tdrdi;
HEVCSEIRecoveryPoint recovery_point;
} HEVCSEI;
struct HEVCParamSets;
int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEI *s,
const struct HEVCParamSets *ps, enum HEVCNALUnitType type);
/**
* Reset SEI values that are stored on the Context.
* e.g. Caption data that was extracted during NAL
* parsing.
*
* @param sei HEVCSEI.
*/
static inline void ff_hevc_reset_sei(HEVCSEI *sei)
{
ff_h2645_sei_reset(&sei->common);
}
#endif /* AVCODEC_HEVC_SEI_H */