Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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.  
  29. static const int codec_ids[4] = { AV_CODEC_ID_H264, AV_CODEC_ID_VP8, AV_CODEC_ID_RV40, AV_CODEC_ID_SVQ3 };
  30.  
  31. static const char * const pred4x4_modes[4][15] = {
  32.     { /* H264 */
  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.     { /* H264 */
  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.     { /* H264 */
  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(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])) {
  151.                 randomize_buffers();
  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;
  166.     declare_func(void, uint8_t *src, ptrdiff_t stride);
  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])) {
  171.             randomize_buffers();
  172.             call_ref(src0, 24*SIZEOF_PIXEL);
  173.             call_new(src1, 24*SIZEOF_PIXEL);
  174.             if (memcmp(buf0, buf1, BUF_SIZE))
  175.                 fail();
  176.             bench_new(src1, 24*SIZEOF_PIXEL);
  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;
  186.         declare_func(void, uint8_t *src, ptrdiff_t stride);
  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])) {
  190.                 randomize_buffers();
  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(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.  
  218.                     randomize_buffers();
  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.  
  232. void checkasm_check_h264pred(void)
  233. {
  234.     static const struct {
  235.         void (*func)(H264PredContext*, uint8_t*, uint8_t*, int, int, int);
  236.         const char *name;
  237.     } tests[] = {
  238.         { check_pred4x4,   "pred4x4"   },
  239.         { check_pred8x8,   "pred8x8"   },
  240.         { check_pred16x16, "pred16x16" },
  241.         { check_pred8x8l,  "pred8x8l"  },
  242.     };
  243.  
  244.     LOCAL_ALIGNED_16(uint8_t, buf0, [BUF_SIZE]);
  245.     LOCAL_ALIGNED_16(uint8_t, buf1, [BUF_SIZE]);
  246.     H264PredContext h;
  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. }
  261.