FFmpeg  4.3
h264pred.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Henrik Gramner
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <string.h>
22 #include "checkasm.h"
23 #include "libavcodec/avcodec.h"
24 #include "libavcodec/h264pred.h"
25 #include "libavutil/common.h"
26 #include "libavutil/internal.h"
27 #include "libavutil/intreadwrite.h"
28 
30 
31 static const char * const pred4x4_modes[4][15] = {
32  { /* H.264 */
33  [VERT_PRED ] = "vertical",
34  [HOR_PRED ] = "horizontal",
35  [DC_PRED ] = "dc",
36  [DIAG_DOWN_LEFT_PRED ] = "down_left",
37  [DIAG_DOWN_RIGHT_PRED] = "down_right",
38  [VERT_RIGHT_PRED ] = "vertical_right",
39  [HOR_DOWN_PRED ] = "horizontal_right",
40  [VERT_LEFT_PRED ] = "vertical_left",
41  [HOR_UP_PRED ] = "horizontal_up",
42  [LEFT_DC_PRED ] = "left_dc",
43  [TOP_DC_PRED ] = "top_dc",
44  [DC_128_PRED ] = "dc_128",
45  },
46  { /* VP8 */
47  [VERT_PRED ] = "vertical_vp8",
48  [HOR_PRED ] = "horizontal_vp8",
49  [VERT_LEFT_PRED] = "vertical_left_vp8",
50  [TM_VP8_PRED ] = "tm_vp8",
51  [DC_127_PRED ] = "dc_127_vp8",
52  [DC_129_PRED ] = "dc_129_vp8",
53  },
54  { /* RV40 */
55  [DIAG_DOWN_LEFT_PRED ] = "down_left_rv40",
56  [VERT_LEFT_PRED ] = "vertical_left_rv40",
57  [HOR_UP_PRED ] = "horizontal_up_rv40",
58  [DIAG_DOWN_LEFT_PRED_RV40_NODOWN] = "down_left_nodown_rv40",
59  [HOR_UP_PRED_RV40_NODOWN ] = "horizontal_up_nodown_rv40",
60  [VERT_LEFT_PRED_RV40_NODOWN ] = "vertical_left_nodown_rv40",
61  },
62  { /* SVQ3 */
63  [DIAG_DOWN_LEFT_PRED] = "down_left_svq3",
64  },
65 };
66 
67 static const char * const pred8x8_modes[4][11] = {
68  { /* H.264 */
69  [DC_PRED8x8 ] = "dc",
70  [HOR_PRED8x8 ] = "horizontal",
71  [VERT_PRED8x8 ] = "vertical",
72  [PLANE_PRED8x8 ] = "plane",
73  [LEFT_DC_PRED8x8 ] = "left_dc",
74  [TOP_DC_PRED8x8 ] = "top_dc",
75  [DC_128_PRED8x8 ] = "dc_128",
76  [ALZHEIMER_DC_L0T_PRED8x8] = "mad_cow_dc_l0t",
77  [ALZHEIMER_DC_0LT_PRED8x8] = "mad_cow_dc_0lt",
78  [ALZHEIMER_DC_L00_PRED8x8] = "mad_cow_dc_l00",
79  [ALZHEIMER_DC_0L0_PRED8x8] = "mad_cow_dc_0l0",
80  },
81  { /* VP8 */
82  [PLANE_PRED8x8 ] = "tm_vp8",
83  [DC_127_PRED8x8] = "dc_127_vp8",
84  [DC_129_PRED8x8] = "dc_129_vp8",
85  },
86  { /* RV40 */
87  [DC_PRED8x8 ] = "dc_rv40",
88  [LEFT_DC_PRED8x8] = "left_dc_rv40",
89  [TOP_DC_PRED8x8 ] = "top_dc_rv40",
90  },
91  /* nothing for SVQ3 */
92 };
93 
94 static const char * const pred16x16_modes[4][9] = {
95  { /* H.264 */
96  [DC_PRED8x8 ] = "dc",
97  [HOR_PRED8x8 ] = "horizontal",
98  [VERT_PRED8x8 ] = "vertical",
99  [PLANE_PRED8x8 ] = "plane",
100  [LEFT_DC_PRED8x8] = "left_dc",
101  [TOP_DC_PRED8x8 ] = "top_dc",
102  [DC_128_PRED8x8 ] = "dc_128",
103  },
104  { /* VP8 */
105  [PLANE_PRED8x8 ] = "tm_vp8",
106  [DC_127_PRED8x8] = "dc_127_vp8",
107  [DC_129_PRED8x8] = "dc_129_vp8",
108  },
109  { /* RV40 */
110  [PLANE_PRED8x8] = "plane_rv40",
111  },
112  { /* SVQ3 */
113  [PLANE_PRED8x8] = "plane_svq3",
114  },
115 };
116 
117 static const uint32_t pixel_mask[3] = { 0xffffffff, 0x01ff01ff, 0x03ff03ff };
118 
119 #define SIZEOF_PIXEL ((bit_depth + 7) / 8)
120 #define BUF_SIZE (3 * 16 * 17)
121 
122 #define check_pred_func(func, name, mode_name) \
123  (mode_name && ((codec_ids[codec] == AV_CODEC_ID_H264) ? \
124  check_func(func, "pred%s_%s_%d", name, mode_name, bit_depth) : \
125  check_func(func, "pred%s_%s", name, mode_name)))
126 
127 #define randomize_buffers() \
128  do { \
129  uint32_t mask = pixel_mask[bit_depth - 8]; \
130  int i; \
131  for (i = 0; i < BUF_SIZE; i += 4) { \
132  uint32_t r = rnd() & mask; \
133  AV_WN32A(buf0 + i, r); \
134  AV_WN32A(buf1 + i, r); \
135  } \
136  } while (0)
137 
138 #define src0 (buf0 + 4 * 16) /* Offset to allow room for top and left */
139 #define src1 (buf1 + 4 * 16)
140 
141 static void check_pred4x4(H264PredContext *h, uint8_t *buf0, uint8_t *buf1,
142  int codec, int chroma_format, int bit_depth)
143 {
144  if (chroma_format == 1) {
145  uint8_t *topright = buf0 + 2*16;
146  int pred_mode;
147  declare_func_emms(AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMXEXT, void, uint8_t *src, const uint8_t *topright, ptrdiff_t stride);
148 
149  for (pred_mode = 0; pred_mode < 15; pred_mode++) {
150  if (check_pred_func(h->pred4x4[pred_mode], "4x4", pred4x4_modes[codec][pred_mode])) {
152  call_ref(src0, topright, 12*SIZEOF_PIXEL);
153  call_new(src1, topright, 12*SIZEOF_PIXEL);
154  if (memcmp(buf0, buf1, BUF_SIZE))
155  fail();
156  bench_new(src1, topright, 12*SIZEOF_PIXEL);
157  }
158  }
159  }
160 }
161 
162 static void check_pred8x8(H264PredContext *h, uint8_t *buf0, uint8_t *buf1,
163  int codec, int chroma_format, int bit_depth)
164 {
165  int pred_mode;
167 
168  for (pred_mode = 0; pred_mode < 11; pred_mode++) {
169  if (check_pred_func(h->pred8x8[pred_mode], (chroma_format == 2) ? "8x16" : "8x8",
170  pred8x8_modes[codec][pred_mode])) {
174  if (memcmp(buf0, buf1, BUF_SIZE))
175  fail();
177  }
178  }
179 }
180 
181 static void check_pred16x16(H264PredContext *h, uint8_t *buf0, uint8_t *buf1,
182  int codec, int chroma_format, int bit_depth)
183 {
184  if (chroma_format == 1) {
185  int pred_mode;
187 
188  for (pred_mode = 0; pred_mode < 9; pred_mode++) {
189  if (check_pred_func(h->pred16x16[pred_mode], "16x16", pred16x16_modes[codec][pred_mode])) {
191  call_ref(src0, 48);
192  call_new(src1, 48);
193  if (memcmp(buf0, buf1, BUF_SIZE))
194  fail();
195  bench_new(src1, 48);
196  }
197  }
198  }
199 }
200 
201 static void check_pred8x8l(H264PredContext *h, uint8_t *buf0, uint8_t *buf1,
202  int codec, int chroma_format, int bit_depth)
203 {
204  if (chroma_format == 1 && codec_ids[codec] == AV_CODEC_ID_H264) {
205  int pred_mode;
206  declare_func_emms(AV_CPU_FLAG_MMXEXT, void, uint8_t *src, int topleft, int topright, ptrdiff_t stride);
207 
208  for (pred_mode = 0; pred_mode < 12; pred_mode++) {
209  if (check_pred_func(h->pred8x8l[pred_mode], "8x8l", pred4x4_modes[codec][pred_mode])) {
210  int neighbors;
211  for (neighbors = 0; neighbors <= 0xc000; neighbors += 0x4000) {
212  int has_topleft = neighbors & 0x8000;
213  int has_topright = neighbors & 0x4000;
214 
215  if ((pred_mode == DIAG_DOWN_RIGHT_PRED || pred_mode == VERT_RIGHT_PRED) && !has_topleft)
216  continue; /* Those aren't allowed according to the spec */
217 
219  call_ref(src0, has_topleft, has_topright, 24*SIZEOF_PIXEL);
220  call_new(src1, has_topleft, has_topright, 24*SIZEOF_PIXEL);
221  if (memcmp(buf0, buf1, BUF_SIZE))
222  fail();
223  bench_new(src1, has_topleft, has_topright, 24*SIZEOF_PIXEL);
224  }
225  }
226  }
227  }
228 }
229 
230 /* TODO: Add tests for H.264 lossless H/V prediction */
231 
233 {
234  static const struct {
236  const char *name;
237  } tests[] = {
238  { check_pred4x4, "pred4x4" },
239  { check_pred8x8, "pred8x8" },
240  { check_pred16x16, "pred16x16" },
241  { check_pred8x8l, "pred8x8l" },
242  };
243 
247  int test, codec, chroma_format, bit_depth;
248 
249  for (test = 0; test < FF_ARRAY_ELEMS(tests); test++) {
250  for (codec = 0; codec < 4; codec++) {
251  int codec_id = codec_ids[codec];
252  for (bit_depth = 8; bit_depth <= (codec_id == AV_CODEC_ID_H264 ? 10 : 8); bit_depth++)
253  for (chroma_format = 1; chroma_format <= (codec_id == AV_CODEC_ID_H264 ? 2 : 1); chroma_format++) {
254  ff_h264_pred_init(&h, codec_id, bit_depth, chroma_format);
255  tests[test].func(&h, buf0, buf1, codec, chroma_format, bit_depth);
256  }
257  }
258  report("%s", tests[test].name);
259  }
260 }
func
int(* func)(AVBPrint *dst, const char *in, const char *arg)
Definition: jacosubdec.c:67
declare_func_emms
#define declare_func_emms(cpu_flags, ret,...)
Definition: checkasm.h:120
HOR_PRED8x8
#define HOR_PRED8x8
Definition: h264pred.h:69
stride
int stride
Definition: mace.c:144
bit_depth
static void bit_depth(AudioStatsContext *s, uint64_t mask, uint64_t imask, AVRational *depth)
Definition: af_astats.c:254
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
DC_PRED8x8
#define DC_PRED8x8
Definition: h264pred.h:68
DC_128_PRED
@ DC_128_PRED
Definition: vp9.h:58
pred16x16_modes
static const char *const pred16x16_modes[4][9]
Definition: h264pred.c:94
TM_VP8_PRED
@ TM_VP8_PRED
Definition: vp9.h:55
DC_PRED
@ DC_PRED
Definition: vp9.h:48
VERT_LEFT_PRED
@ VERT_LEFT_PRED
Definition: vp9.h:53
SIZEOF_PIXEL
#define SIZEOF_PIXEL
Definition: h264pred.c:119
call_ref
#define call_ref(...)
Definition: checkasm.h:129
DC_127_PRED
@ DC_127_PRED
Definition: vp9.h:59
fail
#define fail()
Definition: checkasm.h:123
VERT_PRED
@ VERT_PRED
Definition: vp9.h:46
checkasm.h
DIAG_DOWN_RIGHT_PRED
@ DIAG_DOWN_RIGHT_PRED
Definition: vp9.h:50
pred4x4_modes
static const char *const pred4x4_modes[4][15]
Definition: h264pred.c:31
HOR_PRED
@ HOR_PRED
Definition: vp9.h:47
pixel_mask
static const uint32_t pixel_mask[3]
Definition: h264pred.c:117
intreadwrite.h
pred8x8_modes
static const char *const pred8x8_modes[4][11]
Definition: h264pred.c:67
DC_129_PRED8x8
#define DC_129_PRED8x8
Definition: h264pred.h:86
VERT_LEFT_PRED_RV40_NODOWN
#define VERT_LEFT_PRED_RV40_NODOWN
Definition: h264pred.h:56
LEFT_DC_PRED
@ LEFT_DC_PRED
Definition: vp9.h:56
check_pred8x8
static void check_pred8x8(H264PredContext *h, uint8_t *buf0, uint8_t *buf1, int codec, int chroma_format, int bit_depth)
Definition: h264pred.c:162
codec_id
enum AVCodecID codec_id
Definition: vaapi_decode.c:369
AV_CODEC_ID_SVQ3
@ AV_CODEC_ID_SVQ3
Definition: codec_id.h:72
check_pred4x4
static void check_pred4x4(H264PredContext *h, uint8_t *buf0, uint8_t *buf1, int codec, int chroma_format, int bit_depth)
Definition: h264pred.c:141
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: codec_id.h:76
TOP_DC_PRED8x8
#define TOP_DC_PRED8x8
Definition: h264pred.h:75
codec_ids
static const int codec_ids[4]
Definition: h264pred.c:29
BUF_SIZE
#define BUF_SIZE
Definition: h264pred.c:120
call_new
#define call_new(...)
Definition: checkasm.h:201
check_pred_func
#define check_pred_func(func, name, mode_name)
Definition: h264pred.c:122
src
#define src
Definition: vp8dsp.c:254
checkasm_check_h264pred
void checkasm_check_h264pred(void)
Definition: h264pred.c:232
VERT_PRED8x8
#define VERT_PRED8x8
Definition: h264pred.h:70
DC_127_PRED8x8
#define DC_127_PRED8x8
Definition: h264pred.h:85
tests
FFmpeg Automated Testing Environment ************************************Introduction Using FATE from your FFmpeg source directory Submitting the results to the FFmpeg result aggregation server Uploading new samples to the fate suite FATE makefile targets and variables Makefile targets Makefile variables Examples Introduction **************FATE is an extended regression suite on the client side and a means for results aggregation and presentation on the server side The first part of this document explains how you can use FATE from your FFmpeg source directory to test your ffmpeg binary The second part describes how you can run FATE to submit the results to FFmpeg’s FATE server In any way you can have a look at the publicly viewable FATE results by visiting this as it can be seen if some test on some platform broke with their recent contribution This usually happens on the platforms the developers could not test on The second part of this document describes how you can run FATE to submit your results to FFmpeg’s FATE server If you want to submit your results be sure to check that your combination of OS and compiler is not already listed on the above mentioned website In the third part you can find a comprehensive listing of FATE makefile targets and variables Using FATE from your FFmpeg source directory **********************************************If you want to run FATE on your machine you need to have the samples in place You can get the samples via the build target fate rsync Use this command from the top level source this will cause FATE to fail NOTE To use a custom wrapper to run the pass ‘ target exec’ to ‘configure’ or set the TARGET_EXEC Make variable Submitting the results to the FFmpeg result aggregation server ****************************************************************To submit your results to the server you should run fate through the shell script ‘tests fate sh’ from the FFmpeg sources This script needs to be invoked with a configuration file as its first argument tests fate sh path to fate_config A configuration file template with comments describing the individual configuration variables can be found at ‘doc fate_config sh template’ Create a configuration that suits your based on the configuration template The ‘slot’ configuration variable can be any string that is not yet but it is suggested that you name it adhering to the following pattern ‘ARCH OS COMPILER COMPILER VERSION’ The configuration file itself will be sourced in a shell therefore all shell features may be used This enables you to setup the environment as you need it for your build For your first test runs the ‘fate_recv’ variable should be empty or commented out This will run everything as normal except that it will omit the submission of the results to the server The following files should be present in $workdir as specified in the configuration it may help to try out the ‘ssh’ command with one or more ‘ v’ options You should get detailed output concerning your SSH configuration and the authentication process The only thing left is to automate the execution of the fate sh script and the synchronisation of the samples directory Uploading new samples to the fate suite *****************************************If you need a sample uploaded send a mail to samples request This is for developers who have an account on the fate suite server If you upload new please make sure they are as small as space on each network bandwidth and so on benefit from smaller test cases Also keep in mind older checkouts use existing sample that means in practice generally do not remove or overwrite files as it likely would break older checkouts or releases Also all needed samples for a commit should be ideally before the push If you need an account for frequently uploading samples or you wish to help others by doing that send a mail to ffmpeg devel rsync vauL Duo ug o o X fate suite ffmpeg Duo ug o o X fate suite fate suite ffmpeg Duo ug o o X fate suite fate suite ffmpeg can be set or it has a meaning only while running the regression tests ‘THREADS’ Specify how many threads to use while running regression tests
Definition: fate.txt:188
VERT_RIGHT_PRED
@ VERT_RIGHT_PRED
Definition: vp9.h:51
DC_128_PRED8x8
#define DC_128_PRED8x8
Definition: h264pred.h:76
test
FFmpeg Automated Testing Environment ************************************Introduction Using FATE from your FFmpeg source directory Submitting the results to the FFmpeg result aggregation server Uploading new samples to the fate suite FATE makefile targets and variables Makefile targets Makefile variables Examples Introduction **************FATE is an extended regression suite on the client side and a means for results aggregation and presentation on the server side The first part of this document explains how you can use FATE from your FFmpeg source directory to test your ffmpeg binary The second part describes how you can run FATE to submit the results to FFmpeg’s FATE server In any way you can have a look at the publicly viewable FATE results by visiting this as it can be seen if some test on some platform broke with their recent contribution This usually happens on the platforms the developers could not test on The second part of this document describes how you can run FATE to submit your results to FFmpeg’s FATE server If you want to submit your results be sure to check that your combination of OS and compiler is not already listed on the above mentioned website In the third part you can find a comprehensive listing of FATE makefile targets and variables Using FATE from your FFmpeg source directory **********************************************If you want to run FATE on your machine you need to have the samples in place You can get the samples via the build target fate rsync Use this command from the top level source this will cause FATE to fail NOTE To use a custom wrapper to run the test
Definition: fate.txt:76
PLANE_PRED8x8
#define PLANE_PRED8x8
Definition: h264pred.h:71
src0
#define src0
Definition: h264pred.c:138
DIAG_DOWN_LEFT_PRED_RV40_NODOWN
#define DIAG_DOWN_LEFT_PRED_RV40_NODOWN
Definition: h264pred.h:54
src1
#define src1
Definition: h264pred.c:139
check_pred16x16
static void check_pred16x16(H264PredContext *h, uint8_t *buf0, uint8_t *buf1, int codec, int chroma_format, int bit_depth)
Definition: h264pred.c:181
report
#define report
Definition: checkasm.h:126
AV_CODEC_ID_RV40
@ AV_CODEC_ID_RV40
Definition: codec_id.h:118
check_pred8x8l
static void check_pred8x8l(H264PredContext *h, uint8_t *buf0, uint8_t *buf1, int codec, int chroma_format, int bit_depth)
Definition: h264pred.c:201
bench_new
#define bench_new(...)
Definition: checkasm.h:261
DC_129_PRED
@ DC_129_PRED
Definition: vp9.h:60
internal.h
HOR_UP_PRED_RV40_NODOWN
#define HOR_UP_PRED_RV40_NODOWN
Definition: h264pred.h:55
common.h
ALZHEIMER_DC_L00_PRED8x8
#define ALZHEIMER_DC_L00_PRED8x8
Definition: h264pred.h:81
uint8_t
uint8_t
Definition: audio_convert.c:194
LEFT_DC_PRED8x8
#define LEFT_DC_PRED8x8
Definition: h264pred.h:74
avcodec.h
randomize_buffers
#define randomize_buffers()
Definition: h264pred.c:127
h264pred.h
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen_template.c:38
AV_CPU_FLAG_MMX
#define AV_CPU_FLAG_MMX
standard MMX
Definition: cpu.h:31
void
typedef void(RENAME(mix_any_func_type))
Definition: rematrix_template.c:52
ff_h264_pred_init
av_cold void ff_h264_pred_init(H264PredContext *h, int codec_id, const int bit_depth, int chroma_format_idc)
Set the intra prediction function pointers.
Definition: h264pred.c:411
HOR_UP_PRED
@ HOR_UP_PRED
Definition: vp9.h:54
HOR_DOWN_PRED
@ HOR_DOWN_PRED
Definition: vp9.h:52
AV_CPU_FLAG_MMXEXT
#define AV_CPU_FLAG_MMXEXT
SSE integer functions or AMD MMX ext.
Definition: cpu.h:32
ALZHEIMER_DC_0L0_PRED8x8
#define ALZHEIMER_DC_0L0_PRED8x8
Definition: h264pred.h:82
H264PredContext
Context for storing H.264 prediction functions.
Definition: h264pred.h:92
ALZHEIMER_DC_L0T_PRED8x8
#define ALZHEIMER_DC_L0T_PRED8x8
Definition: h264pred.h:79
TOP_DC_PRED
@ TOP_DC_PRED
Definition: vp9.h:57
LOCAL_ALIGNED_16
#define LOCAL_ALIGNED_16(t, v,...)
Definition: internal.h:131
DIAG_DOWN_LEFT_PRED
@ DIAG_DOWN_LEFT_PRED
Definition: vp9.h:49
AV_CODEC_ID_VP8
@ AV_CODEC_ID_VP8
Definition: codec_id.h:189
ALZHEIMER_DC_0LT_PRED8x8
#define ALZHEIMER_DC_0LT_PRED8x8
Definition: h264pred.h:80
h
h
Definition: vp9dsp_template.c:2038
int
int
Definition: ffmpeg_filter.c:192