Overview

Request 4568 (accepted)

No description set
Submit package Staging / x265 to package Essentials / x265

x265.changes Changed
x
 
1
@@ -1,4 +1,30 @@
2
 -------------------------------------------------------------------
3
+Tue Oct 01 12:21:19 UTC 2019 - enzokiel@kabelmail.de
4
+
5
+- Update to version 3.2
6
+  New features
7
+  * 3-level hierarchical motion estimation using --hme and
8
+    --hme-search.
9
+  * New AQ mode (--aq-mode 4) with variance and edge information.
10
+  * selective-sao to selectively enable SAO at slice level.
11
+  Enhancements to existing features
12
+  * New implementation of --refine-mv with 3 refinement levels.
13
+  Encoder enhancements
14
+  * Improved quality in the frames following dark scenes in ABR
15
+    mode.
16
+  API changes
17
+  * Additions to x265_param structure to support the newly added
18
+    features --hme, --hme-search and selective-sao.
19
+  Bug fixes
20
+  * Fixed encoder crash with --zonefile during failures in
21
+    encoder_open().
22
+  * Fixed JSON11 build errors with HDR10+ on MacOS high sierra.
23
+  * Signalling out of range scaling list data fixed.
24
+  * Inconsistent output fix for 2-pass rate-control with cutree ON.
25
+  Known issues
26
+  * Build dependency on changeset cf37911 of SVT-HEVC.
27
+
28
+-------------------------------------------------------------------
29
 Sun Aug 11 09:32:37 UTC 2019 - Luigi Baldoni <aloisio@gmx.com>
30
 
31
 - Update to version 3.1.2
32
x265.spec Changed
15
 
1
@@ -17,11 +17,11 @@
2
 #
3
 
4
 
5
-%define soname  176
6
+%define soname  179
7
 %define libname lib%{name}
8
 %define libsoname %{libname}-%{soname}
9
 Name:           x265
10
-Version:        3.1.2
11
+Version:        3.2
12
 Release:        0
13
 Summary:        A free h265/HEVC encoder - encoder binary
14
 License:        GPL-2.0-or-later
15
baselibs.conf Changed
4
 
1
@@ -1,1 +1,1 @@
2
-libx265-176
3
+libx265-179
4
x265_3.1.2.tar.gz/.hg_archival.txt -> x265_3.2.tar.gz/.hg_archival.txt Changed
11
 
1
@@ -1,6 +1,4 @@
2
 repo: 09fe40627f03a0f9c3e6ac78b22ac93da23f9fdf
3
-node: 76650bab70f9ef9f06b91ba51926ef560d6fa6ff
4
-branch: Release_3.1
5
-latesttag: 3.1.2
6
-latesttagdistance: 1
7
-changessincelatesttag: 1
8
+node: 353572437201d551381002aebf20d244bd49ef17
9
+branch: Release_3.2
10
+tag: 3.2
11
x265_3.1.2.tar.gz/.hgtags -> x265_3.2.tar.gz/.hgtags Changed
9
 
1
@@ -35,6 +35,4 @@
2
 72188bd2f03447e71e789a5fd2f10364bb232c2c 3.0
3
 113518629fa54ffb491dd479e15c1f00dd39d376 3.1_RC1
4
 b4e38ce16d7c4b37a6482dc7ae61fd31071b6ff1 3.1_RC2
5
-acce27790559b68f93319cd21b588f90aa93c0b1 3.1
6
-6f7c2ae0d5bd46506b7a772abebd7eff3fa3bbcb 3.1.1
7
-4472578f9adfb383e4a479491218f37251c8ab60 3.1.2
8
+20c9994e8bfbeb9443851b2b3a050cd98c8b147b 3.2_RC1
9
x265_3.1.2.tar.gz/doc/reST/cli.rst -> x265_3.2.tar.gz/doc/reST/cli.rst Changed
89
 
1
@@ -1,3 +1,4 @@
2
+
3
 *********************
4
 Command Line Options
5
 *********************
6
@@ -996,11 +997,16 @@
7
    the encoder settings. It is recommended to use :option:`--refine-intra` 4 with dynamic 
8
    refinement. Default disabled.
9
 
10
-.. option:: --refine-mv
11
-   
12
+.. option:: --refine-mv <1..3>
13
+
14
    Enables refinement of motion vector for scaled video. Evaluates the best 
15
-   motion vector by searching the surrounding eight integer and subpel pixel
16
-   positions.
17
+   motion vector based on the level selected. Default 1.
18
+
19
+   Level 1 - Search around scaled MV.
20
+   
21
+   Level 2 - Level 1 + Search around best AMVP cand.
22
+   
23
+   Level 3 - Level 2 + Search around the other AMVP cand.
24
 
25
 Options which affect the transform unit quad-tree, sometimes referred to
26
 as the residual quad-tree (RQT).
27
@@ -1261,6 +1267,18 @@
28
    Enable motion estimation with source frame pixels, in this mode, 
29
    motion estimation can be computed independently. Default disabled.
30
 
31
+.. option:: --hme, --no-hme
32
+
33
+       Enable 3-level Hierarchical motion estimation at One-Sixteenth, 
34
+       Quarter and Full resolution. Default disabled.
35
+
36
+.. option:: --hme-search <integer|string>,<integer|string>,<integer|string>
37
+
38
+       Motion search method for HME Level 0, 1 and 2. Refer to :option:`--me` for values.
39
+       Specify search method for each level. Alternatively, specify a single value
40
+       which will apply to all levels. Default is hex,umh,umh for 
41
+       levels 0,1,2 respectively.
42
+
43
 Spatial/intra options
44
 =====================
45
 
46
@@ -1633,7 +1651,7 @@
47
    ignored. Slower presets will generally achieve better compression
48
    efficiency (and generate smaller bitstreams). Default disabled.
49
 
50
-.. option:: --aq-mode <0|1|2|3>
51
+.. option:: --aq-mode <0|1|2|3|4>
52
 
53
    Adaptive Quantization operating mode. Raise or lower per-block
54
    quantization based on complexity analysis of the source image. The
55
@@ -1647,6 +1665,7 @@
56
    3. AQ enabled with auto-variance and bias to dark scenes. This is 
57
    recommended for 8-bit encodes or low-bitrate 10-bit encodes, to 
58
    prevent color banding/blocking. 
59
+   4. AQ enabled with auto-variance and edge information.
60
 
61
 .. option:: --aq-strength <float>
62
 
63
@@ -1979,6 +1998,25 @@
64
    on inter prediction mode, CTU spatial-domain correlations, and relations
65
    between luma and chroma.
66
    Default disabled
67
+   
68
+.. option:: --selective-sao <0..4>
69
+
70
+   Toggles SAO at slice level. Default 0.
71
+
72
+   +--------------+------------------------------------------+
73
+   | Level        | Description                              |
74
+   +==============+==========================================+
75
+   | 0            | Disable SAO for all slices               |
76
+   +--------------+------------------------------------------+
77
+   | 1            | Enable SAO only for I-slices             |
78
+   +--------------+------------------------------------------+
79
+   | 2            | Enable SAO for I-slices & P-slices       |
80
+   +--------------+------------------------------------------+
81
+   | 3            | Enable SAO for all reference slices      |
82
+   +--------------+------------------------------------------+
83
+   | 4            | Enable SAO for all slices                |
84
+   +--------------+------------------------------------------+
85
+
86
 
87
 VUI (Video Usability Information) options
88
 =========================================
89
x265_3.1.2.tar.gz/doc/reST/releasenotes.rst -> x265_3.2.tar.gz/doc/reST/releasenotes.rst Changed
42
 
1
@@ -2,6 +2,40 @@
2
 Release Notes
3
 *************
4
 
5
+Version 3.2
6
+===========
7
+
8
+Release date - 25th September, 2019.
9
+
10
+New features
11
+------------
12
+1. 3-level hierarchical motion estimation using :option:`--hme` and :option:`--hme-search`.
13
+2. New AQ mode (:option:`--aq-mode` 4) with variance and edge information.
14
+3. :option:`selective-sao` to selectively enable SAO at slice level.
15
+
16
+Enhancements to existing features
17
+---------------------------------
18
+1. New implementation of :option:`--refine-mv` with 3 refinement levels.
19
+
20
+Encoder enhancements
21
+--------------------
22
+1. Improved quality in the frames following dark scenes in ABR mode.
23
+
24
+API changes
25
+-----------
26
+1. Additions to x265_param structure to support the newly added features :option:`--hme`, :option:`--hme-search` and :option:`selective-sao`.
27
+
28
+Bug fixes
29
+---------
30
+1. Fixed encoder crash with :option:`--zonefile` during failures in encoder_open().
31
+2. Fixed JSON11 build errors with HDR10+ on MacOS high sierra.
32
+3. Signalling out of range scaling list data fixed.
33
+4. Inconsistent output fix for 2-pass rate-control with cutree ON.
34
+
35
+Known issues
36
+------------
37
+1. Build dependency on changeset cf37911 of SVT-HEVC.
38
+
39
 Version 3.1
40
 ===========
41
 
42
x265_3.1.2.tar.gz/source/CMakeLists.txt -> x265_3.2.tar.gz/source/CMakeLists.txt Changed
10
 
1
@@ -29,7 +29,7 @@
2
 option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)
3
 mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
4
 # X265_BUILD must be incremented each time the public API is changed
5
-set(X265_BUILD 176)
6
+set(X265_BUILD 179)
7
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
8
                "${PROJECT_BINARY_DIR}/x265.def")
9
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
10
x265_3.1.2.tar.gz/source/common/lowres.cpp -> x265_3.2.tar.gz/source/common/lowres.cpp Changed
118
 
1
@@ -55,6 +55,7 @@
2
     heightFullRes = origPic->m_picHeight;
3
     width = origPic->m_picWidth / 2;
4
     lines = origPic->m_picHeight / 2;
5
+    bEnableHME = param->bEnableHME ? 1 : 0;
6
     lumaStride = width + 2 * origPic->m_lumaMarginX;
7
     if (lumaStride & 31)
8
         lumaStride += 32 - (lumaStride & 31);
9
@@ -64,6 +65,7 @@
10
     maxBlocksInColFullRes = maxBlocksInCol * 2;
11
     int cuCount = maxBlocksInRow * maxBlocksInCol;
12
     int cuCountFullRes = (qgSize > 8) ? cuCount : cuCount << 2;
13
+    isHMELowres = param->bEnableHME ? 1 : 0;
14
 
15
     /* rounding the width to multiple of lowres CU size */
16
     width = maxBlocksInRow * X265_LOWRES_CU_SIZE;
17
@@ -78,6 +80,7 @@
18
         CHECKED_MALLOC_ZERO(qpCuTreeOffset, double, cuCountFullRes);
19
         if (qgSize == 8)
20
             CHECKED_MALLOC_ZERO(invQscaleFactor8x8, int, cuCount);
21
+        CHECKED_MALLOC_ZERO(edgeInclined, int, cuCountFullRes);
22
     }
23
 
24
     if (origPic->m_param->bAQMotion)
25
@@ -137,6 +140,26 @@
26
     lowresPlane[2] = buffer[2] + padoffset;
27
     lowresPlane[3] = buffer[3] + padoffset;
28
 
29
+    if (bEnableHME)
30
+    {
31
+        intptr_t lumaStrideHalf = lumaStride / 2;
32
+        if (lumaStrideHalf & 31)
33
+            lumaStrideHalf += 32 - (lumaStrideHalf & 31);
34
+        size_t planesizeHalf = planesize / 2;
35
+        size_t padoffsetHalf = padoffset / 2;
36
+        /* allocate lower-res buffers */
37
+        CHECKED_MALLOC_ZERO(lowerResBuffer[0], pixel, 4 * planesizeHalf);
38
+
39
+        lowerResBuffer[1] = lowerResBuffer[0] + planesizeHalf;
40
+        lowerResBuffer[2] = lowerResBuffer[1] + planesizeHalf;
41
+        lowerResBuffer[3] = lowerResBuffer[2] + planesizeHalf;
42
+
43
+        lowerResPlane[0] = lowerResBuffer[0] + padoffsetHalf;
44
+        lowerResPlane[1] = lowerResBuffer[1] + padoffsetHalf;
45
+        lowerResPlane[2] = lowerResBuffer[2] + padoffsetHalf;
46
+        lowerResPlane[3] = lowerResBuffer[3] + padoffsetHalf;
47
+    }
48
+
49
     CHECKED_MALLOC(intraCost, int32_t, cuCount);
50
     CHECKED_MALLOC(intraMode, uint8_t, cuCount);
51
 
52
@@ -155,6 +178,16 @@
53
         CHECKED_MALLOC(lowresMvs[1][i], MV, cuCount);
54
         CHECKED_MALLOC(lowresMvCosts[0][i], int32_t, cuCount);
55
         CHECKED_MALLOC(lowresMvCosts[1][i], int32_t, cuCount);
56
+        if (bEnableHME)
57
+        {
58
+            int maxBlocksInRowLowerRes = ((width/2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
59
+            int maxBlocksInColLowerRes = ((lines/2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
60
+            int cuCountLowerRes = maxBlocksInRowLowerRes * maxBlocksInColLowerRes;
61
+            CHECKED_MALLOC(lowerResMvs[0][i], MV, cuCountLowerRes);
62
+            CHECKED_MALLOC(lowerResMvs[1][i], MV, cuCountLowerRes);
63
+            CHECKED_MALLOC(lowerResMvCosts[0][i], int32_t, cuCountLowerRes);
64
+            CHECKED_MALLOC(lowerResMvCosts[1][i], int32_t, cuCountLowerRes);
65
+        }
66
     }
67
 
68
     return true;
69
@@ -166,6 +199,8 @@
70
 void Lowres::destroy()
71
 {
72
     X265_FREE(buffer[0]);
73
+    if(bEnableHME)
74
+        X265_FREE(lowerResBuffer[0]);
75
     X265_FREE(intraCost);
76
     X265_FREE(intraMode);
77
 
78
@@ -184,12 +219,20 @@
79
         X265_FREE(lowresMvs[1][i]);
80
         X265_FREE(lowresMvCosts[0][i]);
81
         X265_FREE(lowresMvCosts[1][i]);
82
+        if (bEnableHME)
83
+        {
84
+            X265_FREE(lowerResMvs[0][i]);
85
+            X265_FREE(lowerResMvs[1][i]);
86
+            X265_FREE(lowerResMvCosts[0][i]);
87
+            X265_FREE(lowerResMvCosts[1][i]);
88
+        }
89
     }
90
     X265_FREE(qpAqOffset);
91
     X265_FREE(invQscaleFactor);
92
     X265_FREE(qpCuTreeOffset);
93
     X265_FREE(propagateCost);
94
     X265_FREE(invQscaleFactor8x8);
95
+    X265_FREE(edgeInclined);
96
     X265_FREE(qpAqMotionOffset);
97
     X265_FREE(blockVariance);
98
     if (maxAQDepth > 0)
99
@@ -253,5 +296,18 @@
100
     extendPicBorder(lowresPlane[1], lumaStride, width, lines, origPic->m_lumaMarginX, origPic->m_lumaMarginY);
101
     extendPicBorder(lowresPlane[2], lumaStride, width, lines, origPic->m_lumaMarginX, origPic->m_lumaMarginY);
102
     extendPicBorder(lowresPlane[3], lumaStride, width, lines, origPic->m_lumaMarginX, origPic->m_lumaMarginY);
103
+    
104
+    if (origPic->m_param->bEnableHME)
105
+    {
106
+        primitives.frameInitLowerRes(lowresPlane[0],
107
+            lowerResPlane[0], lowerResPlane[1], lowerResPlane[2], lowerResPlane[3],
108
+            lumaStride, lumaStride/2, (width / 2), (lines / 2));
109
+        extendPicBorder(lowerResPlane[0], lumaStride/2, width/2, lines/2, origPic->m_lumaMarginX/2, origPic->m_lumaMarginY/2);
110
+        extendPicBorder(lowerResPlane[1], lumaStride/2, width/2, lines/2, origPic->m_lumaMarginX/2, origPic->m_lumaMarginY/2);
111
+        extendPicBorder(lowerResPlane[2], lumaStride/2, width/2, lines/2, origPic->m_lumaMarginX/2, origPic->m_lumaMarginY/2);
112
+        extendPicBorder(lowerResPlane[3], lumaStride/2, width/2, lines/2, origPic->m_lumaMarginX/2, origPic->m_lumaMarginY/2);
113
+        fpelLowerResPlane[0] = lowerResPlane[0];
114
+    }
115
+
116
     fpelPlane[0] = lowresPlane[0];
117
 }
118
x265_3.1.2.tar.gz/source/common/lowres.h -> x265_3.2.tar.gz/source/common/lowres.h Changed
115
 
1
@@ -40,8 +40,13 @@
2
     pixel*   lowresPlane[4];
3
     PicYuv*  reconPic;
4
 
5
+    /* 1/16th resolution : Level-0 HME planes */
6
+    pixel*   fpelLowerResPlane[3];
7
+    pixel*   lowerResPlane[4];
8
+
9
     bool     isWeighted;
10
     bool     isLowres;
11
+    bool     isHMELowres;
12
 
13
     intptr_t lumaStride;
14
     intptr_t chromaStride;
15
@@ -59,46 +64,58 @@
16
 
17
     /* lowres motion compensation, you must provide a buffer and stride for QPEL averaged pixels
18
      * in case QPEL is required.  Else it returns a pointer to the HPEL pixels */
19
-    inline pixel *lowresMC(intptr_t blockOffset, const MV& qmv, pixel *buf, intptr_t& outstride)
20
+    inline pixel *lowresMC(intptr_t blockOffset, const MV& qmv, pixel *buf, intptr_t& outstride, bool hme)
21
     {
22
+        intptr_t YStride = hme ? lumaStride / 2 : lumaStride;
23
+        pixel *plane[4];
24
+        for (int i = 0; i < 4; i++)
25
+        {
26
+            plane[i] = hme ? lowerResPlane[i] : lowresPlane[i];
27
+        }
28
         if ((qmv.x | qmv.y) & 1)
29
         {
30
             int hpelA = (qmv.y & 2) | ((qmv.x & 2) >> 1);
31
-            pixel *frefA = lowresPlane[hpelA] + blockOffset + (qmv.x >> 2) + (qmv.y >> 2) * lumaStride;
32
+            pixel *frefA = plane[hpelA] + blockOffset + (qmv.x >> 2) + (qmv.y >> 2) * YStride;
33
             int qmvx = qmv.x + (qmv.x & 1);
34
             int qmvy = qmv.y + (qmv.y & 1);
35
             int hpelB = (qmvy & 2) | ((qmvx & 2) >> 1);
36
-            pixel *frefB = lowresPlane[hpelB] + blockOffset + (qmvx >> 2) + (qmvy >> 2) * lumaStride;
37
-            primitives.pu[LUMA_8x8].pixelavg_pp[(outstride % 64 == 0) && (lumaStride % 64 == 0)](buf, outstride, frefA, lumaStride, frefB, lumaStride, 32);
38
+            pixel *frefB = plane[hpelB] + blockOffset + (qmvx >> 2) + (qmvy >> 2) * YStride;
39
+            primitives.pu[LUMA_8x8].pixelavg_pp[(outstride % 64 == 0) && (YStride % 64 == 0)](buf, outstride, frefA, YStride, frefB, YStride, 32);
40
             return buf;
41
         }
42
         else
43
         {
44
-            outstride = lumaStride;
45
+            outstride = YStride;
46
             int hpel = (qmv.y & 2) | ((qmv.x & 2) >> 1);
47
-            return lowresPlane[hpel] + blockOffset + (qmv.x >> 2) + (qmv.y >> 2) * lumaStride;
48
+            return plane[hpel] + blockOffset + (qmv.x >> 2) + (qmv.y >> 2) * YStride;
49
         }
50
     }
51
 
52
-    inline int lowresQPelCost(pixel *fenc, intptr_t blockOffset, const MV& qmv, pixelcmp_t comp)
53
+    inline int lowresQPelCost(pixel *fenc, intptr_t blockOffset, const MV& qmv, pixelcmp_t comp, bool hme)
54
     {
55
+        intptr_t YStride = hme ? lumaStride / 2 : lumaStride;
56
+        pixel *plane[4];
57
+        for (int i = 0; i < 4; i++)
58
+        {
59
+            plane[i] = hme ? lowerResPlane[i] : lowresPlane[i];
60
+        }
61
         if ((qmv.x | qmv.y) & 1)
62
         {
63
             ALIGN_VAR_16(pixel, subpelbuf[8 * 8]);
64
             int hpelA = (qmv.y & 2) | ((qmv.x & 2) >> 1);
65
-            pixel *frefA = lowresPlane[hpelA] + blockOffset + (qmv.x >> 2) + (qmv.y >> 2) * lumaStride;
66
+            pixel *frefA = plane[hpelA] + blockOffset + (qmv.x >> 2) + (qmv.y >> 2) * YStride;
67
             int qmvx = qmv.x + (qmv.x & 1);
68
             int qmvy = qmv.y + (qmv.y & 1);
69
             int hpelB = (qmvy & 2) | ((qmvx & 2) >> 1);
70
-            pixel *frefB = lowresPlane[hpelB] + blockOffset + (qmvx >> 2) + (qmvy >> 2) * lumaStride;
71
-            primitives.pu[LUMA_8x8].pixelavg_pp[NONALIGNED](subpelbuf, 8, frefA, lumaStride, frefB, lumaStride, 32);
72
+            pixel *frefB = plane[hpelB] + blockOffset + (qmvx >> 2) + (qmvy >> 2) * YStride;
73
+            primitives.pu[LUMA_8x8].pixelavg_pp[NONALIGNED](subpelbuf, 8, frefA, YStride, frefB, YStride, 32);
74
             return comp(fenc, FENC_STRIDE, subpelbuf, 8);
75
         }
76
         else
77
         {
78
             int hpel = (qmv.y & 2) | ((qmv.x & 2) >> 1);
79
-            pixel *fref = lowresPlane[hpel] + blockOffset + (qmv.x >> 2) + (qmv.y >> 2) * lumaStride;
80
-            return comp(fenc, FENC_STRIDE, fref, lumaStride);
81
+            pixel *fref = plane[hpel] + blockOffset + (qmv.x >> 2) + (qmv.y >> 2) * YStride;
82
+            return comp(fenc, FENC_STRIDE, fref, YStride);
83
         }
84
     }
85
 };
86
@@ -150,6 +167,7 @@
87
 struct Lowres : public ReferencePlanes
88
 {
89
     pixel *buffer[4];
90
+    pixel *lowerResBuffer[4]; // Level-0 buffer
91
 
92
     int    frameNum;         // Presentation frame number
93
     int    sliceType;        // Slice type decided by lookahead
94
@@ -181,6 +199,11 @@
95
     uint32_t  maxBlocksInRowFullRes;
96
     uint32_t  maxBlocksInColFullRes;
97
 
98
+    /* Hierarchical Motion Estimation */
99
+    bool      bEnableHME;
100
+    int32_t*  lowerResMvCosts[2][X265_BFRAME_MAX + 2];
101
+    MV*       lowerResMvs[2][X265_BFRAME_MAX + 2];
102
+
103
     /* used for vbvLookahead */
104
     int       plannedType[X265_LOOKAHEAD_MAX + 1];
105
     int64_t   plannedSatd[X265_LOOKAHEAD_MAX + 1];
106
@@ -197,6 +220,8 @@
107
     uint64_t  wp_ssd[3];       // This is different than SSDY, this is sum(pixel^2) - sum(pixel)^2 for entire frame
108
     uint64_t  wp_sum[3];
109
     double    frameVariance;
110
+    int* edgeInclined;
111
+
112
 
113
     /* cutree intermediate data */
114
     PicQPAdaptationLayer* pAQLayer;
115
x265_3.1.2.tar.gz/source/common/param.cpp -> x265_3.2.tar.gz/source/common/param.cpp Changed
261
 
1
@@ -185,12 +185,12 @@
2
     param->searchMethod = X265_HEX_SEARCH;
3
     param->subpelRefine = 2;
4
     param->searchRange = 57;
5
-   param->maxNumMergeCand = 3;
6
-   param->limitReferences = 1;
7
+    param->maxNumMergeCand = 3;
8
+    param->limitReferences = 1;
9
     param->limitModes = 0;
10
     param->bEnableWeightedPred = 1;
11
     param->bEnableWeightedBiPred = 0;
12
-   param->bEnableEarlySkip = 1;
13
+    param->bEnableEarlySkip = 1;
14
     param->bEnableRecursionSkip = 1;
15
     param->bEnableAMP = 0;
16
     param->bEnableRectInter = 0;
17
@@ -201,6 +201,9 @@
18
     param->bEnableTSkipFast = 0;
19
     param->maxNumReferences = 3;
20
     param->bEnableTemporalMvp = 1;
21
+    param->bEnableHME = 0;
22
+    param->hmeSearchMethod[0] = X265_HEX_SEARCH;
23
+    param->hmeSearchMethod[1] = param->hmeSearchMethod[2] = X265_UMH_SEARCH;
24
     param->bSourceReferenceEstimation = 0;
25
     param->limitTU = 0;
26
     param->dynamicRd = 0;
27
@@ -212,6 +215,7 @@
28
     param->bEnableSAO = 1;
29
     param->bSaoNonDeblocked = 0;
30
     param->bLimitSAO = 0;
31
+    param->selectiveSAO = 0;
32
 
33
     /* Coding Quality */
34
     param->cbQpOffset = 0;
35
@@ -225,7 +229,7 @@
36
     param->analysisReuseFileName = NULL;
37
     param->analysisSave = NULL;
38
     param->analysisLoad = NULL;
39
-   param->bIntraInBFrames = 1;
40
+    param->bIntraInBFrames = 1;
41
     param->bLossless = 0;
42
     param->bCULossless = 0;
43
     param->bEnableTemporalSubLayers = 0;
44
@@ -314,7 +318,7 @@
45
     param->intraRefine = 0;
46
     param->interRefine = 0;
47
     param->bDynamicRefine = 0;
48
-    param->mvRefine = 0;
49
+    param->mvRefine = 1;
50
     param->ctuDistortionRefine = 0;
51
     param->bUseAnalysisFile = 1;
52
     param->csvfpt = NULL;
53
@@ -361,7 +365,7 @@
54
 
55
         if (!strcmp(preset, "ultrafast"))
56
         {
57
-            param->maxNumMergeCand = 2;
58
+            param->maxNumMergeCand = 2;
59
             param->bIntraInBFrames = 0;
60
             param->lookaheadDepth = 5;
61
             param->scenecutThreshold = 0; // disable lookahead
62
@@ -385,7 +389,7 @@
63
         }
64
         else if (!strcmp(preset, "superfast"))
65
         {
66
-            param->maxNumMergeCand = 2;
67
+            param->maxNumMergeCand = 2;
68
             param->bIntraInBFrames = 0;
69
             param->lookaheadDepth = 10;
70
             param->maxCUSize = 32;
71
@@ -405,8 +409,8 @@
72
         }
73
         else if (!strcmp(preset, "veryfast"))
74
         {
75
-            param->maxNumMergeCand = 2;
76
-            param->limitReferences = 3;
77
+            param->maxNumMergeCand = 2;
78
+            param->limitReferences = 3;
79
             param->bIntraInBFrames = 0;
80
             param->lookaheadDepth = 15;
81
             param->bFrameAdaptive = 0;
82
@@ -418,8 +422,8 @@
83
         }
84
         else if (!strcmp(preset, "faster"))
85
         {
86
-            param->maxNumMergeCand = 2;
87
-            param->limitReferences = 3;
88
+            param->maxNumMergeCand = 2;
89
+            param->limitReferences = 3;
90
             param->bIntraInBFrames = 0;
91
             param->lookaheadDepth = 15;
92
             param->bFrameAdaptive = 0;
93
@@ -429,9 +433,9 @@
94
         }
95
         else if (!strcmp(preset, "fast"))
96
         {
97
-            param->maxNumMergeCand = 2;
98
-            param->limitReferences = 3;
99
-            param->bEnableEarlySkip = 0;
100
+            param->maxNumMergeCand = 2;
101
+            param->limitReferences = 3;
102
+            param->bEnableEarlySkip = 0;
103
             param->bIntraInBFrames = 0;
104
             param->lookaheadDepth = 15;
105
             param->bFrameAdaptive = 0;
106
@@ -445,8 +449,8 @@
107
         }
108
         else if (!strcmp(preset, "slow"))
109
         {
110
-            param->limitReferences = 3;
111
-            param->bEnableEarlySkip = 0;
112
+            param->limitReferences = 3;
113
+            param->bEnableEarlySkip = 0;
114
             param->bIntraInBFrames = 0;
115
             param->bEnableRectInter = 1;
116
             param->lookaheadDepth = 25;
117
@@ -1206,7 +1210,7 @@
118
         OPT("scale-factor") p->scaleFactor = atoi(value);
119
         OPT("refine-intra")p->intraRefine = atoi(value);
120
         OPT("refine-inter")p->interRefine = atoi(value);
121
-        OPT("refine-mv")p->mvRefine = atobool(value);
122
+        OPT("refine-mv")p->mvRefine = atoi(value);
123
         OPT("force-flush")p->forceFlush = atoi(value);
124
         OPT("splitrd-skip") p->bEnableSplitRdSkip = atobool(value);
125
         OPT("lowpass-dct") p->bLowPassDct = atobool(value);
126
@@ -1279,9 +1283,34 @@
127
         OPT("svt-pred-struct") x265_log(p, X265_LOG_WARNING, "Option %s is SVT-HEVC Encoder specific; Disabling it here \n", name);
128
         OPT("svt-fps-in-vps") x265_log(p, X265_LOG_WARNING, "Option %s is SVT-HEVC Encoder specific; Disabling it here \n", name);
129
 #endif
130
+        OPT("selective-sao")
131
+        {
132
+            p->selectiveSAO = atoi(value);
133
+        }
134
         OPT("fades") p->bEnableFades = atobool(value);
135
         OPT("field") p->bField = atobool( value );
136
         OPT("cll") p->bEmitCLL = atobool(value);
137
+        OPT("hme") p->bEnableHME = atobool(value);
138
+        OPT("hme-search")
139
+        {
140
+            char search[3][5];
141
+            memset(search, '\0', 15 * sizeof(char));
142
+            if(3 == sscanf(value, "%d,%d,%d", &p->hmeSearchMethod[0], &p->hmeSearchMethod[1], &p->hmeSearchMethod[2]) ||
143
+               3 == sscanf(value, "%4[^,],%4[^,],%4[^,]", search[0], search[1], search[2]))
144
+            {
145
+                if(search[0][0])
146
+                    for(int level = 0; level < 3; level++)
147
+                        p->hmeSearchMethod[level] = parseName(search[level], x265_motion_est_names, bError);
148
+            }
149
+            else if (sscanf(value, "%d", &p->hmeSearchMethod[0]) || sscanf(value, "%s", search[0]))
150
+            {
151
+                if (search[0][0]) {
152
+                    p->hmeSearchMethod[0] = parseName(search[0], x265_motion_est_names, bError);
153
+                    p->hmeSearchMethod[1] = p->hmeSearchMethod[2] = p->hmeSearchMethod[0];
154
+                }
155
+            }
156
+            p->bEnableHME = true;
157
+        }
158
         else
159
             return X265_PARAM_BAD_NAME;
160
     }
161
@@ -1522,7 +1551,7 @@
162
           "Lookahead depth must be less than 256");
163
     CHECK(param->lookaheadSlices > 16 || param->lookaheadSlices < 0,
164
           "Lookahead slices must between 0 and 16");
165
-    CHECK(param->rc.aqMode < X265_AQ_NONE || X265_AQ_AUTO_VARIANCE_BIASED < param->rc.aqMode,
166
+    CHECK(param->rc.aqMode < X265_AQ_NONE || X265_AQ_EDGE < param->rc.aqMode,
167
           "Aq-Mode is out of range");
168
     CHECK(param->rc.aqStrength < 0 || param->rc.aqStrength > 3,
169
           "Aq-Strength is out of range");
170
@@ -1626,6 +1655,8 @@
171
           "Strict-cbr cannot be applied without specifying target bitrate or vbv bufsize");
172
     CHECK((param->analysisSave || param->analysisLoad) && (param->analysisReuseLevel < 1 || param->analysisReuseLevel > 10),
173
         "Invalid analysis refine level. Value must be between 1 and 10 (inclusive)");
174
+    CHECK(param->analysisLoad && (param->mvRefine < 1 || param->mvRefine > 3),
175
+        "Invalid mv refinement level. Value must be between 1 and 3 (inclusive)");
176
     CHECK(param->scaleFactor > 2, "Invalid scale-factor. Supports factor <= 2");
177
     CHECK(param->rc.qpMax < QP_MIN || param->rc.qpMax > QP_MAX_MAX,
178
         "qpmax exceeds supported range (0 to 69)");
179
@@ -1660,6 +1691,8 @@
180
         CHECK( (param->bFrameAdaptive==0), "Adaptive B-frame decision method should be closed for field feature.\n" );
181
         // to do
182
     }
183
+    CHECK(param->selectiveSAO < 0 || param->selectiveSAO > 4,
184
+        "Invalid SAO tune level. Value must be between 0 and 4 (inclusive)");
185
 #if !X86_64
186
     CHECK(param->searchMethod == X265_SEA && (param->sourceWidth > 840 || param->sourceHeight > 480),
187
         "SEA motion search does not support resolutions greater than 480p in 32 bit build");
188
@@ -1732,8 +1765,13 @@
189
     x265_log(param, X265_LOG_INFO, "Residual QT: max TU size, max depth : %d / %d inter / %d intra\n",
190
              param->maxTUSize, param->tuQTMaxInterDepth, param->tuQTMaxIntraDepth);
191
 
192
-    x265_log(param, X265_LOG_INFO, "ME / range / subpel / merge         : %s / %d / %d / %d\n",
193
-             x265_motion_est_names[param->searchMethod], param->searchRange, param->subpelRefine, param->maxNumMergeCand);
194
+    if (param->bEnableHME)
195
+        x265_log(param, X265_LOG_INFO, "HME L0,1,2 / range / subpel / merge : %s, %s, %s / %d / %d / %d\n",
196
+            x265_motion_est_names[param->hmeSearchMethod[0]], x265_motion_est_names[param->hmeSearchMethod[1]], x265_motion_est_names[param->hmeSearchMethod[2]], param->searchRange, param->subpelRefine, param->maxNumMergeCand);
197
+    else
198
+        x265_log(param, X265_LOG_INFO, "ME / range / subpel / merge         : %s / %d / %d / %d\n",
199
+            x265_motion_est_names[param->searchMethod], param->searchRange, param->subpelRefine, param->maxNumMergeCand);
200
+
201
     if (param->keyframeMax != INT_MAX || param->scenecutThreshold)
202
         x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut / bias: %d / %d / %d / %.2lf\n", param->keyframeMin, param->keyframeMax, param->scenecutThreshold, param->scenecutBias * 100);
203
     else
204
@@ -1831,6 +1869,8 @@
205
     }
206
     TOOLOPT(param->bSaoNonDeblocked, "sao-non-deblock");
207
     TOOLOPT(!param->bSaoNonDeblocked && param->bEnableSAO, "sao");
208
+    if (param->selectiveSAO && param->selectiveSAO != 4)
209
+        TOOLOPT(param->selectiveSAO, "selective-sao");
210
     TOOLOPT(param->rc.bStatWrite, "stats-write");
211
     TOOLOPT(param->rc.bStatRead,  "stats-read");
212
     TOOLOPT(param->bSingleSeiNal, "single-sei");
213
@@ -1928,6 +1968,9 @@
214
     s += sprintf(s, " subme=%d", p->subpelRefine);
215
     s += sprintf(s, " merange=%d", p->searchRange);
216
     BOOL(p->bEnableTemporalMvp, "temporal-mvp");
217
+    BOOL(p->bEnableHME, "hme");
218
+    if (p->bEnableHME)
219
+        s += sprintf(s, " Level 0,1,2=%d,%d,%d", p->hmeSearchMethod[0], p->hmeSearchMethod[1], p->hmeSearchMethod[2]);
220
     BOOL(p->bEnableWeightedPred, "weightp");
221
     BOOL(p->bEnableWeightedBiPred, "weightb");
222
     BOOL(p->bSourceReferenceEstimation, "analyze-src-pics");
223
@@ -1937,6 +1980,7 @@
224
     BOOL(p->bEnableSAO, "sao");
225
     BOOL(p->bSaoNonDeblocked, "sao-non-deblock");
226
     s += sprintf(s, " rd=%d", p->rdLevel);
227
+    s += sprintf(s, " selective-sao=%d", p->selectiveSAO);
228
     BOOL(p->bEnableEarlySkip, "early-skip");
229
     BOOL(p->bEnableRecursionSkip, "rskip");
230
     BOOL(p->bEnableFastIntra, "fast-intra");
231
@@ -2030,7 +2074,7 @@
232
     if (p->masteringDisplayColorVolume)
233
         s += sprintf(s, " master-display=%s", p->masteringDisplayColorVolume);
234
     if (p->bEmitCLL)
235
-        s += sprintf(s, "cll=%hu,%hu", p->maxCLL, p->maxFALL);
236
+        s += sprintf(s, " cll=%hu,%hu", p->maxCLL, p->maxFALL);
237
     s += sprintf(s, " min-luma=%hu", p->minLuma);
238
     s += sprintf(s, " max-luma=%hu", p->maxLuma);
239
     s += sprintf(s, " log2-max-poc-lsb=%d", p->log2MaxPocLsb);
240
@@ -2215,6 +2259,12 @@
241
     dst->subpelRefine = src->subpelRefine;
242
     dst->searchRange = src->searchRange;
243
     dst->bEnableTemporalMvp = src->bEnableTemporalMvp;
244
+    dst->bEnableHME = src->bEnableHME;
245
+    if (src->bEnableHME)
246
+    {
247
+        for (int level = 0; level < 3; level++)
248
+            dst->hmeSearchMethod[level] = src->hmeSearchMethod[level];
249
+    }
250
     dst->bEnableWeightedBiPred = src->bEnableWeightedBiPred;
251
     dst->bEnableWeightedPred = src->bEnableWeightedPred;
252
     dst->bSourceReferenceEstimation = src->bSourceReferenceEstimation;
253
@@ -2380,6 +2430,7 @@
254
     else dst->analysisLoad = NULL;
255
     dst->gopLookahead = src->gopLookahead;
256
     dst->radl = src->radl;
257
+    dst->selectiveSAO = src->selectiveSAO;
258
     dst->maxAUSizeFactor = src->maxAUSizeFactor;
259
     dst->bEmitIDRRecoverySEI = src->bEmitIDRRecoverySEI;
260
     dst->bDynamicRefine = src->bDynamicRefine;
261
x265_3.1.2.tar.gz/source/common/pixel.cpp -> x265_3.2.tar.gz/source/common/pixel.cpp Changed
9
 
1
@@ -1309,6 +1309,7 @@
2
     p.scale1D_128to64[NONALIGNED] = p.scale1D_128to64[ALIGNED] = scale1D_128to64;
3
     p.scale2D_64to32 = scale2D_64to32;
4
     p.frameInitLowres = frame_init_lowres_core;
5
+    p.frameInitLowerRes = frame_init_lowres_core;
6
     p.ssim_4x4x2_core = ssim_4x4x2_core;
7
     p.ssim_end_4 = ssim_end_4;
8
 
9
x265_3.1.2.tar.gz/source/common/primitives.h -> x265_3.2.tar.gz/source/common/primitives.h Changed
9
 
1
@@ -349,6 +349,7 @@
2
     saoCuStatsE3_t        saoCuStatsE3;
3
 
4
     downscale_t           frameInitLowres;
5
+    downscale_t           frameInitLowerRes;
6
     cutree_propagate_cost propagateCost;
7
     cutree_fix8_unpack    fix8Unpack;
8
     cutree_fix8_pack      fix8Pack;
9
x265_3.1.2.tar.gz/source/common/slice.h -> x265_3.2.tar.gz/source/common/slice.h Changed
9
 
1
@@ -356,6 +356,7 @@
2
     bool        m_bCheckLDC;       // TODO: is this necessary?
3
     bool        m_sLFaseFlag;      // loop filter boundary flag
4
     bool        m_colFromL0Flag;   // collocated picture from List0 or List1 flag
5
+    int         m_bUseSao;
6
 
7
     int         m_iPPSQpMinus26;
8
     int         numRefIdxDefault[2];
9
x265_3.1.2.tar.gz/source/common/x86/asm-primitives.cpp -> x265_3.2.tar.gz/source/common/x86/asm-primitives.cpp Changed
82
 
1
@@ -1090,6 +1090,7 @@
2
         LUMA_VSS_FILTERS(sse2);
3
 
4
         p.frameInitLowres = PFX(frame_init_lowres_core_sse2);
5
+        p.frameInitLowerRes = PFX(frame_init_lowres_core_sse2);
6
         // TODO: the planecopy_sp is really planecopy_SC now, must be fix it 
7
         //p.planecopy_sp = PFX(downShift_16_sse2);
8
         p.planecopy_sp_shl = PFX(upShift_16_sse2);
9
@@ -1132,6 +1133,7 @@
10
         p.cu[BLOCK_8x8].idct = PFX(idct8_ssse3);
11
 
12
         p.frameInitLowres = PFX(frame_init_lowres_core_ssse3);
13
+        p.frameInitLowerRes = PFX(frame_init_lowres_core_ssse3);
14
 
15
         ALL_LUMA_PU(convert_p2s[ALIGNED], filterPixelToShort, ssse3);
16
         ALL_LUMA_PU(convert_p2s[NONALIGNED], filterPixelToShort, ssse3);
17
@@ -1453,6 +1455,7 @@
18
         p.cu[BLOCK_64x64].copy_sp = (copy_sp_t)PFX(blockcopy_ss_64x64_avx);
19
 
20
         p.frameInitLowres = PFX(frame_init_lowres_core_avx);
21
+        p.frameInitLowerRes = PFX(frame_init_lowres_core_avx);
22
 
23
         p.pu[LUMA_64x16].copy_pp = (copy_pp_t)PFX(blockcopy_ss_64x16_avx);
24
         p.pu[LUMA_64x32].copy_pp = (copy_pp_t)PFX(blockcopy_ss_64x32_avx);
25
@@ -1469,6 +1472,7 @@
26
 #endif
27
         LUMA_VAR(xop);
28
         p.frameInitLowres = PFX(frame_init_lowres_core_xop);
29
+        p.frameInitLowerRes = PFX(frame_init_lowres_core_xop);
30
     }
31
     if (cpuMask & X265_CPU_AVX2)
32
     {
33
@@ -2296,6 +2300,7 @@
34
         p.chroma[X265_CSP_I444].pu[LUMA_64x64].filter_vsp = PFX(interp_4tap_vert_sp_64x64_avx2);
35
 
36
         p.frameInitLowres = PFX(frame_init_lowres_core_avx2);
37
+        p.frameInitLowerRes = PFX(frame_init_lowres_core_avx2);
38
         p.propagateCost = PFX(mbtree_propagate_cost_avx2);
39
         p.fix8Unpack = PFX(cutree_fix8_unpack_avx2);
40
         p.fix8Pack = PFX(cutree_fix8_pack_avx2);
41
@@ -3294,6 +3299,7 @@
42
 
43
         //p.frameInitLowres = PFX(frame_init_lowres_core_mmx2);
44
         p.frameInitLowres = PFX(frame_init_lowres_core_sse2);
45
+        p.frameInitLowerRes = PFX(frame_init_lowres_core_sse2);
46
 
47
         ALL_LUMA_TU(blockfill_s[NONALIGNED], blockfill_s, sse2);
48
         ALL_LUMA_TU(blockfill_s[ALIGNED], blockfill_s, sse2);
49
@@ -3414,6 +3420,7 @@
50
         p.pu[LUMA_8x8].luma_hvpp = PFX(interp_8tap_hv_pp_8x8_ssse3);
51
 
52
         p.frameInitLowres = PFX(frame_init_lowres_core_ssse3);
53
+        p.frameInitLowerRes = PFX(frame_init_lowres_core_ssse3);
54
         ASSIGN2(p.scale1D_128to64, scale1D_128to64_ssse3);
55
         p.scale2D_64to32 = PFX(scale2D_64to32_ssse3);
56
 
57
@@ -3682,6 +3689,7 @@
58
         p.pu[LUMA_48x64].copy_pp = PFX(blockcopy_pp_48x64_avx);
59
 
60
         p.frameInitLowres = PFX(frame_init_lowres_core_avx);
61
+        p.frameInitLowerRes = PFX(frame_init_lowres_core_avx);
62
         p.propagateCost = PFX(mbtree_propagate_cost_avx);
63
     }
64
     if (cpuMask & X265_CPU_XOP)
65
@@ -3693,6 +3701,8 @@
66
         p.cu[BLOCK_8x8].sse_pp = PFX(pixel_ssd_8x8_xop);
67
         p.cu[BLOCK_16x16].sse_pp = PFX(pixel_ssd_16x16_xop);
68
         p.frameInitLowres = PFX(frame_init_lowres_core_xop);
69
+        p.frameInitLowerRes = PFX(frame_init_lowres_core_xop);
70
+
71
     }
72
 #if X86_64
73
     if (cpuMask & X265_CPU_AVX2)
74
@@ -4667,6 +4677,7 @@
75
         p.chroma[X265_CSP_I444].pu[LUMA_64x16].filter_vpp = PFX(interp_4tap_vert_pp_64x16_avx2);
76
 
77
         p.frameInitLowres = PFX(frame_init_lowres_core_avx2);
78
+        p.frameInitLowerRes = PFX(frame_init_lowres_core_avx2);
79
         p.propagateCost = PFX(mbtree_propagate_cost_avx2);
80
         p.saoCuStatsE0 = PFX(saoCuStatsE0_avx2);
81
         p.saoCuStatsE1 = PFX(saoCuStatsE1_avx2);
82
x265_3.1.2.tar.gz/source/dynamicHDR10/json11/json11.cpp -> x265_3.2.tar.gz/source/dynamicHDR10/json11/json11.cpp Changed
35
 
1
@@ -43,11 +43,20 @@
2
 using std::initializer_list;
3
 using std::move;
4
 
5
+    /* Helper for representing null - just a do-nothing struct, plus comparison
6
+     * operators so the helpers in JsonValue work. We can't use nullptr_t because
7
+     * it may not be orderable.
8
+     */
9
+    struct NullStruct {
10
+        bool operator==(NullStruct) const { return true; }
11
+        bool operator<(NullStruct) const { return false; }
12
+    };
13
+
14
 /* * * * * * * * * * * * * * * * * * * *
15
  * Serialization
16
  */
17
 
18
-static void dump(std::nullptr_t, string &out) {
19
+static void dump(NullStruct, string &out) {
20
     out += "null";
21
 }
22
 
23
@@ -214,9 +223,9 @@
24
     explicit JsonObject(Json::object &&value)      : Value(move(value)) {}
25
 };
26
 
27
-class JsonNull final : public Value<Json::NUL, std::nullptr_t> {
28
+class JsonNull final : public Value<Json::NUL, NullStruct> {
29
 public:
30
-    JsonNull() : Value(nullptr) {}
31
+    JsonNull() : Value({}) {}
32
 };
33
 
34
 /* * * * * * * * * * * * * * * * * * * *
35
x265_3.1.2.tar.gz/source/encoder/analysis.cpp -> x265_3.2.tar.gz/source/encoder/analysis.cpp Changed
26
 
1
@@ -2488,14 +2488,18 @@
2
                             MV mvp;
3
 
4
                             int numMvc = mode.cu.getPMV(mode.interNeighbours, list, ref, mode.amvpCand[list][ref], mvc);
5
-                            if (m_param->interRefine != 1)
6
-                                mvp = mode.amvpCand[list][ref][mode.cu.m_mvpIdx[list][pu.puAbsPartIdx]];
7
-                            else
8
-                                mvp = interDataCTU->mv[list][cuIdx + part].word;
9
+                            mvp = mode.amvpCand[list][ref][mode.cu.m_mvpIdx[list][pu.puAbsPartIdx]];
10
                             if (m_param->mvRefine || m_param->interRefine == 1)
11
                             {
12
-                                MV outmv;
13
-                                searchMV(mode, pu, list, ref, outmv, mvp, numMvc, mvc);
14
+                                MV outmv, mvpSelect[3];
15
+                                mvpSelect[0] = interDataCTU->mv[list][cuIdx + part].word;
16
+                                if (m_param->mvRefine > 1)
17
+                                {
18
+                                    mvpSelect[1] = mvp;
19
+                                    if(m_param->mvRefine > 2)
20
+                                        mvpSelect[2] = mode.amvpCand[list][ref][!(mode.cu.m_mvpIdx[list][pu.puAbsPartIdx])];
21
+                                }
22
+                                searchMV(mode, list, ref, outmv, mvpSelect, numMvc, mvc);
23
                                 mode.cu.setPUMv(list, outmv, pu.puAbsPartIdx, part);
24
                             }
25
                             mode.cu.m_mvd[list][pu.puAbsPartIdx] = mode.cu.m_mv[list][pu.puAbsPartIdx] - mode.amvpCand[list][ref][mode.cu.m_mvpIdx[list][pu.puAbsPartIdx]]/*mvp*/;
26
x265_3.1.2.tar.gz/source/encoder/api.cpp -> x265_3.2.tar.gz/source/encoder/api.cpp Changed
46
 
1
@@ -96,7 +96,12 @@
2
     x265_param* param = PARAM_NS::x265_param_alloc();
3
     x265_param* latestParam = PARAM_NS::x265_param_alloc();
4
     x265_param* zoneParam = PARAM_NS::x265_param_alloc();
5
-    if (!param || !latestParam)
6
+
7
+    if(param) PARAM_NS::x265_param_default(param);
8
+    if(latestParam) PARAM_NS::x265_param_default(latestParam);
9
+    if(zoneParam) PARAM_NS::x265_param_default(zoneParam);
10
+
11
+    if (!param || !latestParam || !zoneParam)
12
         goto fail;
13
     if (p->rc.zoneCount || p->rc.zonefileCount)
14
     {
15
@@ -106,6 +111,8 @@
16
     }
17
 
18
     x265_copy_params(param, p);
19
+    x265_copy_params(latestParam, p);
20
+    x265_copy_params(zoneParam, p);
21
     x265_log(param, X265_LOG_INFO, "HEVC encoder version %s\n", PFX(version_str));
22
     x265_log(param, X265_LOG_INFO, "build info %s\n", PFX(build_info_str));
23
 
24
@@ -212,6 +219,7 @@
25
     delete encoder;
26
     PARAM_NS::x265_param_free(param);
27
     PARAM_NS::x265_param_free(latestParam);
28
+    PARAM_NS::x265_param_free(zoneParam);
29
     return NULL;
30
 }
31
 
32
@@ -944,11 +952,11 @@
33
 
34
 void x265_zone_free(x265_param *param)
35
 {
36
-    if (param->rc.zonefileCount) {
37
+    if (param && param->rc.zonefileCount) {
38
         for (int i = 0; i < param->rc.zonefileCount; i++)
39
             x265_free(param->rc.zones[i].zoneParam);
40
     }
41
-    if (param->rc.zoneCount || param->rc.zonefileCount)
42
+    if (param && (param->rc.zoneCount || param->rc.zonefileCount))
43
         x265_free(param->rc.zones);
44
 }
45
 
46
x265_3.1.2.tar.gz/source/encoder/encoder.cpp -> x265_3.2.tar.gz/source/encoder/encoder.cpp Changed
86
 
1
@@ -1621,6 +1621,28 @@
2
             }
3
             /* determine references, setup RPS, etc */
4
             m_dpb->prepareEncode(frameEnc);
5
+            if (!!m_param->selectiveSAO)
6
+            {
7
+                Slice* slice = frameEnc->m_encData->m_slice;
8
+                slice->m_bUseSao = curEncoder->m_frameFilter.m_useSao = 1;
9
+                switch (m_param->selectiveSAO)
10
+                {
11
+                case 3: if (!IS_REFERENCED(frameEnc))
12
+                            slice->m_bUseSao = curEncoder->m_frameFilter.m_useSao = 0;
13
+                        break;
14
+                case 2: if (!!m_param->bframes && slice->m_sliceType == B_SLICE)
15
+                            slice->m_bUseSao = curEncoder->m_frameFilter.m_useSao = 0;
16
+                        break;
17
+                case 1: if (slice->m_sliceType != I_SLICE)
18
+                            slice->m_bUseSao = curEncoder->m_frameFilter.m_useSao = 0;
19
+                        break;
20
+                }
21
+            }
22
+            else
23
+            {
24
+                Slice* slice = frameEnc->m_encData->m_slice;
25
+                slice->m_bUseSao = curEncoder->m_frameFilter.m_useSao = 0;
26
+            }
27
 
28
             if (m_param->rc.rateControlMode != X265_RC_CQP)
29
                 m_lookahead->getEstimatedPictureCost(frameEnc);
30
@@ -2891,6 +2913,14 @@
31
 
32
     }
33
 
34
+    if (p->selectiveSAO && !p->bEnableSAO)
35
+    {
36
+        p->bEnableSAO = 1;
37
+        x265_log(p, X265_LOG_WARNING, "SAO turned ON when selective-sao is ON\n");
38
+    }
39
+
40
+    if (!p->selectiveSAO && p->bEnableSAO)
41
+        p->selectiveSAO = 4;
42
 
43
     if (p->interlaceMode)
44
         x265_log(p, X265_LOG_WARNING, "Support for interlaced video is experimental\n");
45
@@ -2976,20 +3006,6 @@
46
         p->limitTU = 0;
47
     }
48
 
49
-    if (p->mvRefine)
50
-    {
51
-        if (!p->analysisLoad || p->analysisReuseLevel < 10)
52
-        {
53
-            x265_log(p, X265_LOG_WARNING, "MV refinement requires analysis load, analysis-reuse-level 10. Disabling MV refine.\n");
54
-            p->mvRefine = 0;
55
-        }
56
-        else if (p->interRefine >= 2)
57
-        {
58
-            x265_log(p, X265_LOG_WARNING, "MVs are recomputed when refine-inter >= 2. MV refinement not applicable. Disabling MV refine\n");
59
-            p->mvRefine = 0;
60
-        }
61
-    }
62
-
63
     if (p->ctuDistortionRefine == CTU_DISTORTION_INTERNAL)
64
     {
65
         if (!p->analysisLoad && !p->analysisSave)
66
@@ -3379,6 +3395,19 @@
67
         p->bRepeatHeaders = 1;
68
         x265_log(p, X265_LOG_WARNING, "Turning on repeat - headers for zone encoding\n");
69
     }
70
+
71
+    if (m_param->bEnableHME)
72
+    {
73
+        if (m_param->sourceHeight < 540)
74
+        {
75
+            x265_log(p, X265_LOG_WARNING, "Source height < 540p is too low for HME. Disabling HME.\n");
76
+            p->bEnableHME = 0;
77
+        }
78
+        if (m_param->bEnableHME && m_param->searchMethod != m_param->hmeSearchMethod[2])
79
+        {
80
+            m_param->searchMethod = m_param->hmeSearchMethod[2];
81
+        }
82
+    }
83
 }
84
 
85
 void Encoder::readAnalysisFile(x265_analysis_data* analysis, int curPoc, const x265_picture* picIn, int paramBytes)
86
x265_3.1.2.tar.gz/source/encoder/entropy.cpp -> x265_3.2.tar.gz/source/encoder/entropy.cpp Changed
41
 
1
@@ -530,6 +530,10 @@
2
     for (int i = 0; i < coefNum; i++)
3
     {
4
         data = src[scan[i]] - nextCoef;
5
+        if (data < -128)
6
+            data += 256;
7
+        if (data > 127)
8
+            data -= 256;
9
         nextCoef = (nextCoef + data + 256) % 256;
10
         WRITE_SVLC(data,  "scaling_list_delta_coef");
11
     }
12
@@ -637,12 +641,18 @@
13
             WRITE_FLAG(1, "slice_temporal_mvp_enable_flag");
14
     }
15
     const SAOParam *saoParam = encData.m_saoParam;
16
-    if (slice.m_sps->bUseSAO)
17
+    if (slice.m_bUseSao)
18
     {
19
         WRITE_FLAG(saoParam->bSaoFlag[0], "slice_sao_luma_flag");
20
         if (encData.m_param->internalCsp != X265_CSP_I400)
21
             WRITE_FLAG(saoParam->bSaoFlag[1], "slice_sao_chroma_flag");
22
     }
23
+    else if(encData.m_param->selectiveSAO)
24
+    {
25
+        WRITE_FLAG(0, "slice_sao_luma_flag");
26
+        if (encData.m_param->internalCsp != X265_CSP_I400)
27
+            WRITE_FLAG(0, "slice_sao_chroma_flag");
28
+    }
29
 
30
     // check if numRefIdx match the defaults (1, hard-coded in PPS). If not, override
31
     // TODO: this might be a place to optimize a few bits per slice, by using param->refs for L0 default
32
@@ -702,7 +712,7 @@
33
 
34
     if (encData.m_param->maxSlices <= 1)
35
     {
36
-        bool isSAOEnabled = slice.m_sps->bUseSAO ? saoParam->bSaoFlag[0] || saoParam->bSaoFlag[1] : false;
37
+        bool isSAOEnabled = slice.m_sps->bUseSAO && slice.m_bUseSao ? saoParam->bSaoFlag[0] || saoParam->bSaoFlag[1] : false;
38
         bool isDBFEnabled = !slice.m_pps->bPicDisableDeblockingFilter;
39
 
40
         if (isSAOEnabled || isDBFEnabled)
41
x265_3.1.2.tar.gz/source/encoder/frameencoder.cpp -> x265_3.2.tar.gz/source/encoder/frameencoder.cpp Changed
73
 
1
@@ -634,14 +634,22 @@
2
         if (!m_param->bEnableWavefront)
3
             m_backupStreams = new Bitstream[numSubstreams];
4
         m_substreamSizes = X265_MALLOC(uint32_t, numSubstreams);
5
-        if (!m_param->bEnableSAO)
6
+        if (!slice->m_bUseSao)
7
+        {
8
             for (uint32_t i = 0; i < numSubstreams; i++)
9
                 m_rows[i].rowGoOnCoder.setBitstream(&m_outStreams[i]);
10
+        }
11
     }
12
     else
13
     {
14
         for (uint32_t i = 0; i < numSubstreams; i++)
15
+        {
16
             m_outStreams[i].resetBits();
17
+            if (!slice->m_bUseSao)
18
+                m_rows[i].rowGoOnCoder.setBitstream(&m_outStreams[i]);
19
+            else
20
+                m_rows[i].rowGoOnCoder.setBitstream(NULL);
21
+        }
22
     }
23
 
24
     m_rce.encodeOrder = m_frame->m_encodeOrder;
25
@@ -981,7 +989,7 @@
26
     m_entropyCoder.setBitstream(&m_bs);
27
 
28
     // finish encode of each CTU row, only required when SAO is enabled
29
-    if (m_param->bEnableSAO)
30
+    if (slice->m_bUseSao)
31
         encodeSlice(0);
32
 
33
     m_entropyCoder.setBitstream(&m_bs);
34
@@ -1221,7 +1229,7 @@
35
     const uint32_t lastCUAddr = (slice->m_endCUAddr + m_param->num4x4Partitions - 1) / m_param->num4x4Partitions;
36
     const uint32_t numSubstreams = m_param->bEnableWavefront ? slice->m_sps->numCuInHeight : 1;
37
 
38
-    SAOParam* saoParam = slice->m_sps->bUseSAO ? m_frame->m_encData->m_saoParam : NULL;
39
+    SAOParam* saoParam = slice->m_sps->bUseSAO && slice->m_bUseSao ? m_frame->m_encData->m_saoParam : NULL;
40
     for (uint32_t cuAddr = sliceAddr; cuAddr < lastCUAddr; cuAddr++)
41
     {
42
         uint32_t col = cuAddr % widthInLCUs;
43
@@ -1515,11 +1523,11 @@
44
             curRow.bufferedEntropy.loadContexts(rowCoder);
45
 
46
         /* SAO parameter estimation using non-deblocked pixels for CTU bottom and right boundary areas */
47
-        if (m_param->bEnableSAO && m_param->bSaoNonDeblocked)
48
+        if (slice->m_bUseSao && m_param->bSaoNonDeblocked)
49
             m_frameFilter.m_parallelFilter[row].m_sao.calcSaoStatsCu_BeforeDblk(m_frame, col, row);
50
 
51
         /* Deblock with idle threading */
52
-        if (m_param->bEnableLoopFilter | m_param->bEnableSAO)
53
+        if (m_param->bEnableLoopFilter | slice->m_bUseSao)
54
         {
55
             // NOTE: in VBV mode, we may reencode anytime, so we can't do Deblock stage-Horizon and SAO
56
             if (!bIsVbv)
57
@@ -1833,12 +1841,12 @@
58
 
59
     /* flush row bitstream (if WPP and no SAO) or flush frame if no WPP and no SAO */
60
     /* end_of_sub_stream_one_bit / end_of_slice_segment_flag */
61
-    if (!m_param->bEnableSAO && (m_param->bEnableWavefront || bLastRowInSlice))
62
-        rowCoder.finishSlice();
63
+       if (!slice->m_bUseSao && (m_param->bEnableWavefront || bLastRowInSlice))
64
+               rowCoder.finishSlice();
65
 
66
 
67
     /* Processing left Deblock block with current threading */
68
-    if ((m_param->bEnableLoopFilter | m_param->bEnableSAO) & (rowInSlice >= 2))
69
+    if ((m_param->bEnableLoopFilter | slice->m_bUseSao) & (rowInSlice >= 2))
70
     {
71
         /* Check conditional to start previous row process with current threading */
72
         if (m_frameFilter.m_parallelFilter[row - 2].m_lastDeblocked.get() == (int)numCols)
73
x265_3.1.2.tar.gz/source/encoder/frameencoder.h -> x265_3.2.tar.gz/source/encoder/frameencoder.h Changed
9
 
1
@@ -150,6 +150,7 @@
2
     uint32_t                 m_filterRowDelay;
3
     uint32_t                 m_filterRowDelayCus;
4
     uint32_t                 m_refLagRows;
5
+    bool                     m_bUseSao;
6
 
7
     CTURow*                  m_rows;
8
     uint16_t                 m_sliceAddrBits;
9
x265_3.1.2.tar.gz/source/encoder/framefilter.cpp -> x265_3.2.tar.gz/source/encoder/framefilter.cpp Changed
107
 
1
@@ -163,7 +163,7 @@
2
 
3
     if (m_parallelFilter)
4
     {
5
-        if (m_param->bEnableSAO)
6
+        if (m_useSao)
7
         {
8
             for(int row = 0; row < m_numRows; row++)
9
                 m_parallelFilter[row].m_sao.destroy((row == 0 ? 1 : 0));
10
@@ -178,6 +178,7 @@
11
 {
12
     m_param = frame->m_param;
13
     m_frameEncoder = frame;
14
+    m_useSao = 1;
15
     m_numRows = numRows;
16
     m_numCols = numCols;
17
     m_hChromaShift = CHROMA_H_SHIFT(m_param->internalCsp);
18
@@ -196,12 +197,12 @@
19
 
20
     if (m_parallelFilter)
21
     {
22
-        if (m_param->bEnableSAO)
23
+        if (m_useSao)
24
         {
25
             for(int row = 0; row < numRows; row++)
26
             {
27
                 if (!m_parallelFilter[row].m_sao.create(m_param, (row == 0 ? 1 : 0)))
28
-                    m_param->bEnableSAO = 0;
29
+                    m_useSao = 0;
30
                 else
31
                 {
32
                     if (row != 0)
33
@@ -235,7 +236,7 @@
34
     {
35
         for(int row = 0; row < m_numRows; row++)
36
         {
37
-            if (m_param->bEnableSAO)
38
+            if (m_useSao)
39
                 m_parallelFilter[row].m_sao.startSlice(frame, initState);
40
 
41
             m_parallelFilter[row].m_lastCol.set(0);
42
@@ -245,7 +246,7 @@
43
         }
44
 
45
         // Reset SAO common statistics
46
-        if (m_param->bEnableSAO)
47
+        if (m_useSao)
48
             m_parallelFilter[0].m_sao.resetStats();
49
     }
50
 }
51
@@ -472,11 +473,11 @@
52
                 deblockCTU(ctuPrev, cuGeoms[ctuGeomMap[cuAddr - 1]], Deblock::EDGE_HOR);
53
 
54
                 // When SAO Disable, setting column counter here
55
-                if (!m_frameFilter->m_param->bEnableSAO & !ctuPrev->m_bFirstRowInSlice)
56
+                if (!m_frameFilter->m_useSao & !ctuPrev->m_bFirstRowInSlice)
57
                     m_prevRow->processPostCu(col - 1);
58
             }
59
 
60
-            if (m_frameFilter->m_param->bEnableSAO)
61
+            if (m_frameFilter->m_useSao)
62
             {
63
                 // Save SAO bottom row reference pixels
64
                 copySaoAboveRef(ctuPrev, reconPic, cuAddr - 1, col - 1);
65
@@ -514,12 +515,12 @@
66
             deblockCTU(ctuPrev, cuGeoms[ctuGeomMap[cuAddr]], Deblock::EDGE_HOR);
67
 
68
             // When SAO Disable, setting column counter here
69
-            if (!m_frameFilter->m_param->bEnableSAO & !ctuPrev->m_bFirstRowInSlice)
70
+            if (!m_frameFilter->m_useSao & !ctuPrev->m_bFirstRowInSlice)
71
                 m_prevRow->processPostCu(numCols - 1);
72
         }
73
 
74
         // TODO: move processPostCu() into processSaoUnitCu()
75
-        if (m_frameFilter->m_param->bEnableSAO)
76
+        if (m_frameFilter->m_useSao)
77
         {
78
             const CUData* ctu = m_encData->getPicCTU(m_rowAddr + numCols - 2);
79
 
80
@@ -570,7 +571,7 @@
81
     m_frameEncoder->m_cuStats.countLoopFilter++;
82
 #endif
83
 
84
-    if (!m_param->bEnableLoopFilter && !m_param->bEnableSAO)
85
+    if (!m_param->bEnableLoopFilter && !m_useSao)
86
     {
87
         processPostRow(row);
88
         return;
89
@@ -596,7 +597,7 @@
90
                 x265_log(m_param, X265_LOG_WARNING, "detected ParallelFilter race condition on last row\n");
91
 
92
             /* Apply SAO on last row of CUs, because we always apply SAO on row[X-1] */
93
-            if (m_param->bEnableSAO)
94
+            if (m_useSao)
95
             {
96
                 for(int col = 0; col < m_numCols; col++)
97
                 {
98
@@ -634,7 +635,7 @@
99
 
100
     if (numRowFinished == m_numRows)
101
     {
102
-        if (m_param->bEnableSAO)
103
+        if (m_useSao)
104
         {
105
             // Merge numNoSao into RootNode (Node0)
106
             for(int i = 1; i < m_numRows; i++)
107
x265_3.1.2.tar.gz/source/encoder/framefilter.h -> x265_3.2.tar.gz/source/encoder/framefilter.h Changed
9
 
1
@@ -46,6 +46,7 @@
2
 
3
     x265_param*   m_param;
4
     Frame*        m_frame;
5
+    int           m_useSao;
6
     FrameEncoder* m_frameEncoder;
7
     int           m_hChromaShift;
8
     int           m_vChromaShift;
9
x265_3.1.2.tar.gz/source/encoder/motion.cpp -> x265_3.2.tar.gz/source/encoder/motion.cpp Changed
142
 
1
@@ -104,6 +104,8 @@
2
     ctuAddr = -1;
3
     absPartIdx = -1;
4
     searchMethod = X265_HEX_SEARCH;
5
+    searchMethodL0 = X265_HEX_SEARCH;
6
+    searchMethodL1 = X265_HEX_SEARCH;
7
     subpelRefine = 2;
8
     blockwidth = blockheight = 0;
9
     blockOffset = 0;
10
@@ -162,7 +164,7 @@
11
 }
12
 
13
 /* Called by lookahead, luma only, no use of PicYuv */
14
-void MotionEstimate::setSourcePU(pixel *fencY, intptr_t stride, intptr_t offset, int pwidth, int pheight, const int method, const int refine)
15
+void MotionEstimate::setSourcePU(pixel *fencY, intptr_t stride, intptr_t offset, int pwidth, int pheight, const int method, const int searchL0, const int searchL1, const int refine)
16
 {
17
     partEnum = partitionFromSizes(pwidth, pheight);
18
     X265_CHECK(LUMA_4x4 != partEnum, "4x4 inter partition detected!\n");
19
@@ -179,6 +181,8 @@
20
 
21
     /* Search params */
22
     searchMethod = method;
23
+    searchMethodL0 = searchL0;
24
+    searchMethodL1 = searchL1;
25
     subpelRefine = refine;
26
 
27
     /* copy PU block into cache */
28
@@ -363,12 +367,13 @@
29
                                        int &            bPointNr,
30
                                        int &            bDistance,
31
                                        int              earlyExitIters,
32
-                                       int              merange)
33
+                                       int              merange,
34
+                                       int              hme)
35
 {
36
     ALIGN_VAR_16(int, costs[16]);
37
     pixel* fenc = fencPUYuv.m_buf[0];
38
-    pixel* fref = ref->fpelPlane[0] + blockOffset;
39
-    intptr_t stride = ref->lumaStride;
40
+    pixel* fref = (hme? ref->fpelLowerResPlane[0] : ref->fpelPlane[0]) + blockOffset;
41
+    intptr_t stride = hme? ref->lumaStride / 2 : ref->lumaStride;
42
 
43
     MV omv = bmv;
44
     int saved = bcost;
45
@@ -743,9 +748,10 @@
46
                                    pixel *          srcReferencePlane)
47
 {
48
     ALIGN_VAR_16(int, costs[16]);
49
+    bool hme = srcReferencePlane && srcReferencePlane == ref->fpelLowerResPlane[0];
50
     if (ctuAddr >= 0)
51
         blockOffset = ref->reconPic->getLumaAddr(ctuAddr, absPartIdx) - ref->reconPic->getLumaAddr(0);
52
-    intptr_t stride = ref->lumaStride;
53
+    intptr_t stride = hme ? ref->lumaStride / 2 : ref->lumaStride;
54
     pixel* fenc = fencPUYuv.m_buf[0];
55
     pixel* fref = srcReferencePlane == 0 ? ref->fpelPlane[0] + blockOffset : srcReferencePlane + blockOffset;
56
 
57
@@ -767,7 +773,7 @@
58
     int bprecost;
59
 
60
     if (ref->isLowres)
61
-        bprecost = ref->lowresQPelCost(fenc, blockOffset, pmv, sad);
62
+        bprecost = ref->lowresQPelCost(fenc, blockOffset, pmv, sad, hme);
63
     else
64
         bprecost = subpelCompare(ref, pmv, sad);
65
 
66
@@ -808,7 +814,8 @@
67
     pmv = pmv.roundToFPel();
68
     MV omv = bmv;  // current search origin or starting point
69
 
70
-    switch (searchMethod)
71
+    int search = ref->isHMELowres ? (hme ? searchMethodL0 : searchMethodL1) : searchMethod;
72
+    switch (search)
73
     {
74
     case X265_DIA_SEARCH:
75
     {
76
@@ -1128,7 +1135,7 @@
77
         int bDistance = 0;
78
 
79
         const int EarlyExitIters = 3;
80
-        StarPatternSearch(ref, mvmin, mvmax, bmv, bcost, bPointNr, bDistance, EarlyExitIters, merange);
81
+        StarPatternSearch(ref, mvmin, mvmax, bmv, bcost, bPointNr, bDistance, EarlyExitIters, merange, hme);
82
         if (bDistance == 1)
83
         {
84
             // if best distance was only 1, check two missing points.  If no new point is found, stop
85
@@ -1201,7 +1208,7 @@
86
             bDistance = 0;
87
             bPointNr = 0;
88
             const int MaxIters = 32;
89
-            StarPatternSearch(ref, mvmin, mvmax, bmv, bcost, bPointNr, bDistance, MaxIters, merange);
90
+            StarPatternSearch(ref, mvmin, mvmax, bmv, bcost, bPointNr, bDistance, MaxIters, merange, hme);
91
 
92
             if (bDistance == 1)
93
             {
94
@@ -1391,11 +1398,20 @@
95
     {
96
         // dead slow exhaustive search, but at least it uses sad_x4()
97
         MV tmv;
98
-        for (tmv.y = mvmin.y; tmv.y <= mvmax.y; tmv.y++)
99
+        int32_t mvmin_y = mvmin.y, mvmin_x = mvmin.x, mvmax_y = mvmax.y, mvmax_x = mvmax.x;
100
+        if (ref->isHMELowres)
101
+        {
102
+            merange = (merange < 0 ? -merange : merange);
103
+            mvmin_y = X265_MAX(mvmin.y, -merange);
104
+            mvmin_x = X265_MAX(mvmin.x, -merange);
105
+            mvmax_y = X265_MIN(mvmax.y, merange);
106
+            mvmax_x = X265_MIN(mvmax.x, merange);
107
+        }
108
+        for (tmv.y = mvmin_y; tmv.y <= mvmax_y; tmv.y++)
109
         {
110
-            for (tmv.x = mvmin.x; tmv.x <= mvmax.x; tmv.x++)
111
+            for (tmv.x = mvmin_x; tmv.x <= mvmax_x; tmv.x++)
112
             {
113
-                if (tmv.x + 3 <= mvmax.x)
114
+                if (tmv.x + 3 <= mvmax_x)
115
                 {
116
                     pixel *pix_base = fref + tmv.y * stride + tmv.x;
117
                     sad_x4(fenc,
118
@@ -1463,12 +1479,12 @@
119
             if ((qmv.y < qmvmin.y) | (qmv.y > qmvmax.y))
120
                 continue;
121
 
122
-            int cost = ref->lowresQPelCost(fenc, blockOffset, qmv, sad) + mvcost(qmv);
123
+            int cost = ref->lowresQPelCost(fenc, blockOffset, qmv, sad, hme) + mvcost(qmv);
124
             COPY2_IF_LT(bcost, cost, bdir, i);
125
         }
126
 
127
         bmv += square1[bdir] * 2;
128
-        bcost = ref->lowresQPelCost(fenc, blockOffset, bmv, satd) + mvcost(bmv);
129
+        bcost = ref->lowresQPelCost(fenc, blockOffset, bmv, satd, hme) + mvcost(bmv);
130
 
131
         bdir = 0;
132
         for (int i = 1; i <= wl.qpel_dirs; i++)
133
@@ -1479,7 +1495,7 @@
134
             if ((qmv.y < qmvmin.y) | (qmv.y > qmvmax.y))
135
                 continue;
136
 
137
-            int cost = ref->lowresQPelCost(fenc, blockOffset, qmv, satd) + mvcost(qmv);
138
+            int cost = ref->lowresQPelCost(fenc, blockOffset, qmv, satd, hme) + mvcost(qmv);
139
             COPY2_IF_LT(bcost, cost, bdir, i);
140
         }
141
 
142
x265_3.1.2.tar.gz/source/encoder/motion.h -> x265_3.2.tar.gz/source/encoder/motion.h Changed
29
 
1
@@ -44,6 +44,8 @@
2
     int absPartIdx;  // part index of PU, including CU offset within CTU
3
 
4
     int searchMethod;
5
+    int searchMethodL0;
6
+    int searchMethodL1;
7
     int subpelRefine;
8
 
9
     int blockwidth;
10
@@ -76,7 +78,7 @@
11
 
12
     /* Methods called at slice setup */
13
 
14
-    void setSourcePU(pixel *fencY, intptr_t stride, intptr_t offset, int pwidth, int pheight, const int searchMethod, const int subpelRefine);
15
+    void setSourcePU(pixel *fencY, intptr_t stride, intptr_t offset, int pwidth, int pheight, const int searchMethod, const int searchL0, const int searchL1, const int subpelRefine);
16
     void setSourcePU(const Yuv& srcFencYuv, int ctuAddr, int cuPartIdx, int puPartIdx, int pwidth, int pheight, const int searchMethod, const int subpelRefine, bool bChroma);
17
 
18
     /* buf*() and motionEstimate() methods all use cached fenc pixels and thus
19
@@ -107,7 +109,8 @@
20
                                   int &            bPointNr,
21
                                   int &            bDistance,
22
                                   int              earlyExitIters,
23
-                                  int              merange);
24
+                                  int              merange,
25
+                                  int              hme);
26
 };
27
 }
28
 
29
x265_3.1.2.tar.gz/source/encoder/ratecontrol.cpp -> x265_3.2.tar.gz/source/encoder/ratecontrol.cpp Changed
11
 
1
@@ -2116,6 +2116,9 @@
2
             if ((underflow < epsilon || rce->isFadeEnd) && !isFrameDone)
3
             {
4
                 init(*m_curSlice->m_sps);
5
+                // Reduce tune complexity factor for scenes that follow blank frames
6
+                double tuneCplxFactor = (m_ncu > 3600 && m_param->rc.cuTree && !m_param->rc.hevcAq) ? 2.5 : m_param->rc.hevcAq ? 1.5 : m_isGrainEnabled ? 1.9 : 1.0;
7
+                m_cplxrSum /= tuneCplxFactor;
8
                 m_shortTermCplxSum = rce->lastSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);
9
                 m_shortTermCplxCount = 1;
10
                 m_isAbrReset = true;
11
x265_3.1.2.tar.gz/source/encoder/search.cpp -> x265_3.2.tar.gz/source/encoder/search.cpp Changed
225
 
1
@@ -2096,13 +2096,16 @@
2
 
3
     const MV* amvp = interMode.amvpCand[list][ref];
4
     int mvpIdx = selectMVP(interMode.cu, pu, amvp, list, ref);
5
-    MV mvmin, mvmax, outmv, mvp = amvp[mvpIdx];
6
+    bool bLowresMVP = false;
7
+    MV mvmin, mvmax, outmv, mvp = amvp[mvpIdx], mvp_lowres;
8
 
9
     if (!m_param->analysisSave && !m_param->analysisLoad) /* Prevents load/save outputs from diverging if lowresMV is not available */
10
     {
11
         MV lmv = getLowresMV(interMode.cu, pu, list, ref);
12
         if (lmv.notZero())
13
             mvc[numMvc++] = lmv;
14
+        if (m_param->bEnableHME)
15
+            mvp_lowres = lmv;
16
     }
17
 
18
     setSearchRange(interMode.cu, mvp, m_param->searchRange, mvmin, mvmax);
19
@@ -2110,11 +2113,28 @@
20
     int satdCost = m_me.motionEstimate(&m_slice->m_mref[list][ref], mvmin, mvmax, mvp, numMvc, mvc, m_param->searchRange, outmv, m_param->maxSlices, 
21
       m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
22
 
23
+    if (m_param->bEnableHME && mvp_lowres.notZero() && mvp_lowres != mvp)
24
+    {
25
+        MV outmv_lowres;
26
+        setSearchRange(interMode.cu, mvp_lowres, m_param->searchRange, mvmin, mvmax);
27
+        int lowresMvCost = m_me.motionEstimate(&m_slice->m_mref[list][ref], mvmin, mvmax, mvp_lowres, numMvc, mvc, m_param->searchRange, outmv_lowres, m_param->maxSlices,
28
+            m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
29
+        if (lowresMvCost < satdCost)
30
+        {
31
+            outmv = outmv_lowres;
32
+            satdCost = lowresMvCost;
33
+            bLowresMVP = true;
34
+        }
35
+    }
36
     /* Get total cost of partition, but only include MV bit cost once */
37
     bits += m_me.bitcost(outmv);
38
     uint32_t mvCost = m_me.mvcost(outmv);
39
     uint32_t cost = (satdCost - mvCost) + m_rdCost.getCost(bits);
40
 
41
+    /* Update LowresMVP to best AMVP cand*/
42
+    if (bLowresMVP)
43
+        updateMVP(amvp[mvpIdx], outmv, bits, cost, mvp_lowres);
44
+
45
     /* Refine MVP selection, updates: mvpIdx, bits, cost */
46
     mvp = checkBestMVP(amvp, outmv, mvpIdx, bits, cost);
47
 
48
@@ -2132,23 +2152,27 @@
49
         bestME[list].mvCost  = mvCost;
50
     }
51
 }
52
-void Search::searchMV(Mode& interMode, const PredictionUnit& pu, int list, int ref, MV& outmv, MV mvp, int numMvc, MV* mvc)
53
+void Search::searchMV(Mode& interMode, int list, int ref, MV& outmv, MV mvp[3], int numMvc, MV* mvc)
54
 {
55
     CUData& cu = interMode.cu;
56
-    const Slice *slice = m_slice;
57
-    MV mv;
58
-    if (m_param->interRefine == 1)
59
-        mv = mvp;
60
-    else
61
-        mv = cu.m_mv[list][pu.puAbsPartIdx];
62
+    MV mv, mvmin, mvmax;
63
     cu.clipMv(mv);
64
-    MV mvmin, mvmax;
65
-    setSearchRange(cu, mv, m_param->searchRange, mvmin, mvmax);
66
-    if (m_param->interRefine == 1)
67
-        m_me.motionEstimate(&m_slice->m_mref[list][ref], mvmin, mvmax, mv, numMvc, mvc, m_param->searchRange, outmv, m_param->maxSlices,
68
+    int cand = 0, bestcost = INT_MAX;
69
+    do
70
+    {
71
+        if (cand && (mvp[cand] == mvp[cand - 1] || (cand == 2 && mvp[cand] == mvp[cand - 2])))
72
+            continue;
73
+        MV bestMV;
74
+        mv = mvp[cand];
75
+        setSearchRange(cu, mv, m_param->searchRange, mvmin, mvmax);
76
+        int cost = m_me.motionEstimate(&m_slice->m_mref[list][ref], mvmin, mvmax, mv, numMvc, mvc, m_param->searchRange, bestMV, m_param->maxSlices,
77
         m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
78
-    else
79
-        m_me.refineMV(&slice->m_mref[list][ref], mvmin, mvmax, mv, outmv);
80
+        if (bestcost > cost)
81
+        {
82
+            bestcost = cost;
83
+            outmv = bestMV;
84
+        }
85
+    }while (++cand < m_param->mvRefine);
86
 }
87
 /* find the best inter prediction for each PU of specified mode */
88
 void Search::predInterSearch(Mode& interMode, const CUGeom& cuGeom, bool bChromaMC, uint32_t refMasks[2])
89
@@ -2209,7 +2233,6 @@
90
                 int ref = -1;
91
                 if (useAsMVP)
92
                     ref = interDataCTU->refIdx[list][cuIdx + puIdx];
93
-
94
                 else
95
                     ref = bestME[list].ref;
96
                 if (ref < 0)
97
@@ -2223,13 +2246,7 @@
98
                 const MV* amvp = interMode.amvpCand[list][ref];
99
                 int mvpIdx = selectMVP(cu, pu, amvp, list, ref);
100
                 MV mvmin, mvmax, outmv, mvp;
101
-                if (useAsMVP)
102
-                {
103
-                    mvp = interDataCTU->mv[list][cuIdx + puIdx].word;
104
-                    mvpIdx = interDataCTU->mvpIdx[list][cuIdx + puIdx];
105
-                }
106
-                else
107
-                    mvp = amvp[mvpIdx];
108
+                mvp = amvp[mvpIdx];
109
                 if (m_param->searchMethod == X265_SEA)
110
                 {
111
                     int puX = puIdx & 1;
112
@@ -2239,11 +2256,47 @@
113
                 }
114
                 setSearchRange(cu, mvp, m_param->searchRange, mvmin, mvmax);
115
                 MV mvpIn = mvp;
116
+                int satdCost;
117
                 if (m_param->analysisMultiPassRefine && m_param->rc.bStatRead && mvpIdx == bestME[list].mvpIdx)
118
                     mvpIn = bestME[list].mv;
119
-                    
120
-                int satdCost = m_me.motionEstimate(&slice->m_mref[list][ref], mvmin, mvmax, mvpIn, numMvc, mvc, m_param->searchRange, outmv, m_param->maxSlices, 
121
-                  m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
122
+                if (useAsMVP)
123
+                {
124
+                    MV bestmv, mvpSel[3];
125
+                    int mvpIdxSel[3];
126
+                    satdCost = m_me.COST_MAX;
127
+                    mvpSel[0] = interDataCTU->mv[list][cuIdx + puIdx].word;
128
+                    mvpIdxSel[0] = interDataCTU->mvpIdx[list][cuIdx + puIdx];
129
+                    if (m_param->mvRefine > 1)
130
+                    {
131
+                        mvpSel[1] = interMode.amvpCand[list][ref][mvpIdx];
132
+                        mvpIdxSel[1] = mvpIdx;
133
+                        if (m_param->mvRefine > 2)
134
+                        {
135
+                            mvpSel[2] = interMode.amvpCand[list][ref][!mvpIdx];
136
+                            mvpIdxSel[2] = !mvpIdx;
137
+                        }
138
+                    }
139
+                    for (int cand = 0; cand < m_param->mvRefine; cand++)
140
+                    {
141
+                        if (cand && (mvpSel[cand] == mvpSel[cand - 1] || (cand == 2 && mvpSel[cand] == mvpSel[cand - 2])))
142
+                            continue;
143
+                        setSearchRange(cu, mvp, m_param->searchRange, mvmin, mvmax);
144
+                        int bcost = m_me.motionEstimate(&m_slice->m_mref[list][ref], mvmin, mvmax, mvpSel[cand], numMvc, mvc, m_param->searchRange, bestmv, m_param->maxSlices,
145
+                            m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
146
+                        if (satdCost > bcost)
147
+                        {
148
+                            satdCost = bcost;
149
+                            outmv = bestmv;
150
+                            mvp = mvpSel[cand];
151
+                            mvpIdx = mvpIdxSel[cand];
152
+                        }
153
+                    }
154
+                }
155
+                else
156
+                {
157
+                    satdCost = m_me.motionEstimate(&slice->m_mref[list][ref], mvmin, mvmax, mvpIn, numMvc, mvc, m_param->searchRange, outmv, m_param->maxSlices,
158
+                        m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
159
+                }
160
 
161
                 /* Get total cost of partition, but only include MV bit cost once */
162
                 bits += m_me.bitcost(outmv);
163
@@ -2346,13 +2399,16 @@
164
 
165
                     const MV* amvp = interMode.amvpCand[list][ref];
166
                     int mvpIdx = selectMVP(cu, pu, amvp, list, ref);
167
-                    MV mvmin, mvmax, outmv, mvp = amvp[mvpIdx];
168
+                    MV mvmin, mvmax, outmv, mvp = amvp[mvpIdx], mvp_lowres;
169
+                    bool bLowresMVP = false;
170
 
171
                     if (!m_param->analysisSave && !m_param->analysisLoad) /* Prevents load/save outputs from diverging when lowresMV is not available */
172
                     {
173
                         MV lmv = getLowresMV(cu, pu, list, ref);
174
                         if (lmv.notZero())
175
                             mvc[numMvc++] = lmv;
176
+                        if (m_param->bEnableHME)
177
+                            mvp_lowres = lmv;
178
                     }
179
                     if (m_param->searchMethod == X265_SEA)
180
                     {
181
@@ -2365,10 +2421,27 @@
182
                     int satdCost = m_me.motionEstimate(&slice->m_mref[list][ref], mvmin, mvmax, mvp, numMvc, mvc, m_param->searchRange, outmv, m_param->maxSlices, 
183
                       m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
184
 
185
+                    if (m_param->bEnableHME && mvp_lowres.notZero() && mvp_lowres != mvp)
186
+                    {
187
+                        MV outmv_lowres;
188
+                        setSearchRange(cu, mvp_lowres, m_param->searchRange, mvmin, mvmax);
189
+                        int lowresMvCost = m_me.motionEstimate(&slice->m_mref[list][ref], mvmin, mvmax, mvp_lowres, numMvc, mvc, m_param->searchRange, outmv_lowres, m_param->maxSlices,
190
+                            m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
191
+                        if (lowresMvCost < satdCost)
192
+                        {
193
+                            outmv = outmv_lowres;
194
+                            satdCost = lowresMvCost;
195
+                            bLowresMVP = true;
196
+                        }
197
+                    }
198
+
199
                     /* Get total cost of partition, but only include MV bit cost once */
200
                     bits += m_me.bitcost(outmv);
201
                     uint32_t mvCost = m_me.mvcost(outmv);
202
                     uint32_t cost = (satdCost - mvCost) + m_rdCost.getCost(bits);
203
+                    /* Update LowresMVP to best AMVP cand*/
204
+                    if (bLowresMVP)
205
+                        updateMVP(amvp[mvpIdx], outmv, bits, cost, mvp_lowres);
206
 
207
                     /* Refine MVP selection, updates: mvpIdx, bits, cost */
208
                     mvp = checkBestMVP(amvp, outmv, mvpIdx, bits, cost);
209
@@ -2631,6 +2704,15 @@
210
     return amvpCand[mvpIdx];
211
 }
212
 
213
+/* Update to default MVP when using an alternative mvp */
214
+void Search::updateMVP(const MV amvp, const MV& mv, uint32_t& outBits, uint32_t& outCost, const MV& alterMVP)
215
+{
216
+    int diffBits = m_me.bitcost(mv, amvp) - m_me.bitcost(mv, alterMVP);
217
+    uint32_t origOutBits = outBits;
218
+    outBits = origOutBits + diffBits;
219
+    outCost = (outCost - m_rdCost.getCost(origOutBits)) + m_rdCost.getCost(outBits);
220
+}
221
+
222
 void Search::setSearchRange(const CUData& cu, const MV& mvp, int merange, MV& mvmin, MV& mvmax) const
223
 {
224
     MV dist((int32_t)merange << 2, (int32_t)merange << 2);
225
x265_3.1.2.tar.gz/source/encoder/search.h -> x265_3.2.tar.gz/source/encoder/search.h Changed
18
 
1
@@ -310,7 +310,7 @@
2
 
3
     // estimation inter prediction (non-skip)
4
     void     predInterSearch(Mode& interMode, const CUGeom& cuGeom, bool bChromaMC, uint32_t masks[2]);
5
-    void     searchMV(Mode& interMode, const PredictionUnit& pu, int list, int ref, MV& outmv, MV mvp, int numMvc, MV* mvc);
6
+    void     searchMV(Mode& interMode, int list, int ref, MV& outmv, MV mvp[3], int numMvc, MV* mvc);
7
     // encode residual and compute rd-cost for inter mode
8
     void     encodeResAndCalcRdInterCU(Mode& interMode, const CUGeom& cuGeom);
9
     void     encodeResAndCalcRdSkipCU(Mode& interMode);
10
@@ -425,6 +425,7 @@
11
     void     setSearchRange(const CUData& cu, const MV& mvp, int merange, MV& mvmin, MV& mvmax) const;
12
     uint32_t mergeEstimation(CUData& cu, const CUGeom& cuGeom, const PredictionUnit& pu, int puIdx, MergeData& m);
13
     static void getBlkBits(PartSize cuMode, bool bPSlice, int puIdx, uint32_t lastMode, uint32_t blockBit[3]);
14
+    void      updateMVP(const MV amvp, const MV& mv, uint32_t& outBits, uint32_t& outCost, const MV& alterMVP);
15
 
16
     /* intra helper functions */
17
     enum { MAX_RD_INTRA_MODES = 16 };
18
x265_3.1.2.tar.gz/source/encoder/slicetype.cpp -> x265_3.2.tar.gz/source/encoder/slicetype.cpp Changed
652
 
1
@@ -85,6 +85,140 @@
2
 
3
 } // end anonymous namespace
4
 
5
+void edgeFilter(Frame *curFrame, pixel *pic1, pixel *pic2, pixel *pic3, intptr_t stride, int height, int width)
6
+{
7
+    pixel *src = (pixel*)curFrame->m_fencPic->m_picOrg[0];
8
+    pixel *edgePic = pic1 + curFrame->m_fencPic->m_lumaMarginY * stride + curFrame->m_fencPic->m_lumaMarginX;
9
+    pixel *refPic = pic2 + curFrame->m_fencPic->m_lumaMarginY * stride + curFrame->m_fencPic->m_lumaMarginX;
10
+    pixel *edgeTheta = pic3 + curFrame->m_fencPic->m_lumaMarginY * stride + curFrame->m_fencPic->m_lumaMarginX;
11
+
12
+    for (int i = 0; i < height; i++)
13
+    {
14
+        memcpy(edgePic, src, width * sizeof(pixel));
15
+        memcpy(refPic, src, width * sizeof(pixel));
16
+        src += stride;
17
+        edgePic += stride;
18
+        refPic += stride;
19
+    }
20
+
21
+    //Applying Gaussian filter on the picture
22
+    src = (pixel*)curFrame->m_fencPic->m_picOrg[0];
23
+    refPic = pic2 + curFrame->m_fencPic->m_lumaMarginY * stride + curFrame->m_fencPic->m_lumaMarginX;
24
+    pixel pixelValue = 0;
25
+
26
+    for (int rowNum = 0; rowNum < height; rowNum++)
27
+    {
28
+        for (int colNum = 0; colNum < width; colNum++)
29
+        {
30
+            if ((rowNum >= 2) && (colNum >= 2) && (rowNum != height - 2) && (colNum != width - 2)) //Ignoring the border pixels of the picture
31
+            {
32
+                /*  5x5 Gaussian filter
33
+                    [2   4   5   4   2]
34
+                 1  [4   9   12  9   4]
35
+                --- [5   12  15  12  5]
36
+                159 [4   9   12  9   4]
37
+                    [2   4   5   4   2]*/
38
+
39
+                const intptr_t rowOne = (rowNum - 2)*stride, colOne = colNum - 2;
40
+                const intptr_t rowTwo = (rowNum - 1)*stride, colTwo = colNum - 1;
41
+                const intptr_t rowThree = rowNum * stride, colThree = colNum;
42
+                const intptr_t rowFour = (rowNum + 1)*stride, colFour = colNum + 1;
43
+                const intptr_t rowFive = (rowNum + 2)*stride, colFive = colNum + 2;
44
+                const intptr_t index = (rowNum*stride) + colNum;
45
+
46
+                pixelValue = ((2 * src[rowOne + colOne] + 4 * src[rowOne + colTwo] + 5 * src[rowOne + colThree] + 4 * src[rowOne + colFour] + 2 * src[rowOne + colFive] +
47
+                    4 * src[rowTwo + colOne] + 9 * src[rowTwo + colTwo] + 12 * src[rowTwo + colThree] + 9 * src[rowTwo + colFour] + 4 * src[rowTwo + colFive] +
48
+                    5 * src[rowThree + colOne] + 12 * src[rowThree + colTwo] + 15 * src[rowThree + colThree] + 12 * src[rowThree + colFour] + 5 * src[rowThree + colFive] +
49
+                    4 * src[rowFour + colOne] + 9 * src[rowFour + colTwo] + 12 * src[rowFour + colThree] + 9 * src[rowFour + colFour] + 4 * src[rowFour + colFive] +
50
+                    2 * src[rowFive + colOne] + 4 * src[rowFive + colTwo] + 5 * src[rowFive + colThree] + 4 * src[rowFive + colFour] + 2 * src[rowFive + colFive]) / 159);
51
+                refPic[index] = pixelValue;
52
+            }
53
+        }
54
+    }
55
+
56
+#if HIGH_BIT_DEPTH //10-bit build
57
+    float threshold = 1023;
58
+    pixel whitePixel = 1023;
59
+#else
60
+    float threshold = 255;
61
+    pixel whitePixel = 255;
62
+#endif
63
+#define PI 3.14159265 
64
+
65
+    float gradientH = 0, gradientV = 0, radians = 0, theta = 0;
66
+    float gradientMagnitude = 0;
67
+    pixel blackPixel = 0;
68
+    edgePic = pic1 + curFrame->m_fencPic->m_lumaMarginY * stride + curFrame->m_fencPic->m_lumaMarginX;
69
+    //Applying Sobel filter on the gaussian filtered picture
70
+    for (int rowNum = 0; rowNum < height; rowNum++)
71
+    {
72
+        for (int colNum = 0; colNum < width; colNum++)
73
+        {
74
+            edgeTheta[(rowNum*stride) + colNum] = 0;
75
+            if ((rowNum != 0) && (colNum != 0) && (rowNum != height - 1) && (colNum != width - 1)) //Ignoring the border pixels of the picture
76
+            {
77
+                /*Horizontal and vertical gradients
78
+                       [ -3   0   3 ]        [-3   -10  -3 ]
79
+                  gH = [ -10  0   10]   gV = [ 0    0    0 ]
80
+                       [ -3   0   3 ]        [ 3    10   3 ]*/
81
+
82
+                const intptr_t rowOne = (rowNum - 1)*stride, colOne = colNum -1;
83
+                const intptr_t rowTwo = rowNum * stride, colTwo = colNum;
84
+                const intptr_t rowThree = (rowNum + 1)*stride, colThree = colNum + 1;
85
+                const intptr_t index = (rowNum*stride) + colNum;
86
+
87
+                gradientH = (float)(-3 * refPic[rowOne + colOne] + 3 * refPic[rowOne + colThree] - 10 * refPic[rowTwo + colOne] + 10 * refPic[rowTwo + colThree] - 3 * refPic[rowThree + colOne] + 3 * refPic[rowThree + colThree]);
88
+                gradientV = (float)(-3 * refPic[rowOne + colOne] - 10 * refPic[rowOne + colTwo] - 3 * refPic[rowOne + colThree] + 3 * refPic[rowThree + colOne] + 10 * refPic[rowThree + colTwo] + 3 * refPic[rowThree + colThree]);
89
+
90
+                gradientMagnitude = sqrtf(gradientH * gradientH + gradientV * gradientV);
91
+                radians = atan2(gradientV, gradientH);
92
+                theta = (float)((radians * 180) / PI);
93
+                if (theta < 0)
94
+                    theta = 180 + theta;
95
+                edgeTheta[(rowNum*stride) + colNum] = (pixel)theta;
96
+
97
+                edgePic[index] = gradientMagnitude >= threshold ? whitePixel : blackPixel;
98
+            }
99
+        }
100
+    }
101
+}
102
+
103
+//Find the angle of a block by averaging the pixel angles 
104
+inline void findAvgAngle(const pixel* block, intptr_t stride, uint32_t size, uint32_t &angle)
105
+{
106
+    int sum = 0;
107
+    for (uint32_t y = 0; y < size; y++)
108
+    {
109
+        for (uint32_t x = 0; x < size; x++)
110
+        {
111
+            sum += block[x];
112
+        }
113
+        block += stride;
114
+    }
115
+    angle = sum / (size*size);
116
+}
117
+
118
+uint32_t LookaheadTLD::edgeDensityCu(Frame* curFrame,pixel *edgeImage, pixel *edgeTheta, uint32_t &avgAngle, uint32_t blockX, uint32_t blockY, uint32_t qgSize)
119
+{
120
+    intptr_t srcStride = curFrame->m_fencPic->m_stride;
121
+    intptr_t blockOffsetLuma = blockX + (blockY * srcStride);
122
+    int plane = 0; // Sobel filter is applied only on Y component
123
+    uint32_t var;
124
+
125
+    if (qgSize == 8)
126
+    {
127
+        findAvgAngle(edgeTheta + blockOffsetLuma, srcStride, qgSize, avgAngle);
128
+        var = acEnergyVar(curFrame, primitives.cu[BLOCK_8x8].var(edgeImage + blockOffsetLuma, srcStride), 6, plane);
129
+    }
130
+    else
131
+    {
132
+        findAvgAngle(edgeTheta + blockOffsetLuma, srcStride, 16, avgAngle);
133
+        var = acEnergyVar(curFrame, primitives.cu[BLOCK_16x16].var(edgeImage + blockOffsetLuma, srcStride), 8, plane);
134
+    }
135
+    x265_emms();
136
+    return var;
137
+}
138
+
139
 /* Find the total AC energy of each block in all planes */
140
 uint32_t LookaheadTLD::acEnergyCu(Frame* curFrame, uint32_t blockX, uint32_t blockY, int csp, uint32_t qgSize)
141
 {
142
@@ -303,146 +437,203 @@
143
         curFrame->m_lowres.wp_sum[y] = 0;
144
     }
145
 
146
-    /* Calculate Qp offset for each 16x16 or 8x8 block in the frame */    
147
-    if ((param->rc.aqMode == X265_AQ_NONE || param->rc.aqStrength == 0) || (param->rc.bStatRead && param->rc.cuTree && IS_REFERENCED(curFrame)))
148
+    if (!(param->rc.bStatRead && param->rc.cuTree && IS_REFERENCED(curFrame)))
149
     {
150
-        if (param->rc.aqMode && param->rc.aqStrength == 0)
151
+        /* Calculate Qp offset for each 16x16 or 8x8 block in the frame */
152
+        if (param->rc.aqMode == X265_AQ_NONE || param->rc.aqStrength == 0)
153
         {
154
-            if (quantOffsets)
155
+            if (param->rc.aqMode && param->rc.aqStrength == 0)
156
             {
157
-                for (int cuxy = 0; cuxy < blockCount; cuxy++)
158
+                if (quantOffsets)
159
+                {
160
+                    for (int cuxy = 0; cuxy < blockCount; cuxy++)
161
+                    {
162
+                        curFrame->m_lowres.qpCuTreeOffset[cuxy] = curFrame->m_lowres.qpAqOffset[cuxy] = quantOffsets[cuxy];
163
+                        curFrame->m_lowres.invQscaleFactor[cuxy] = x265_exp2fix8(curFrame->m_lowres.qpCuTreeOffset[cuxy]);
164
+                    }
165
+                }
166
+                else
167
                 {
168
-                    curFrame->m_lowres.qpCuTreeOffset[cuxy] = curFrame->m_lowres.qpAqOffset[cuxy] = quantOffsets[cuxy];
169
-                    curFrame->m_lowres.invQscaleFactor[cuxy] = x265_exp2fix8(curFrame->m_lowres.qpCuTreeOffset[cuxy]);
170
+                    memset(curFrame->m_lowres.qpCuTreeOffset, 0, blockCount * sizeof(double));
171
+                    memset(curFrame->m_lowres.qpAqOffset, 0, blockCount * sizeof(double));
172
+                    for (int cuxy = 0; cuxy < blockCount; cuxy++)
173
+                        curFrame->m_lowres.invQscaleFactor[cuxy] = 256;
174
                 }
175
             }
176
-            else
177
+
178
+            /* Need variance data for weighted prediction and dynamic refinement*/
179
+            if (param->bEnableWeightedPred || param->bEnableWeightedBiPred)
180
             {
181
-               memset(curFrame->m_lowres.qpCuTreeOffset, 0, blockCount * sizeof(double));
182
-               memset(curFrame->m_lowres.qpAqOffset, 0, blockCount * sizeof(double));
183
-               for (int cuxy = 0; cuxy < blockCount; cuxy++)
184
-                   curFrame->m_lowres.invQscaleFactor[cuxy] = 256;
185
+                for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
186
+                    for (int blockX = 0; blockX < maxCol; blockX += loopIncr)
187
+                        acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
188
             }
189
         }
190
-
191
-        /* Need variance data for weighted prediction and dynamic refinement*/
192
-        if (param->bEnableWeightedPred || param->bEnableWeightedBiPred)
193
-        {
194
-            for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
195
-                for (int blockX = 0; blockX < maxCol; blockX += loopIncr)
196
-                    acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
197
-        }
198
-    }
199
-    else
200
-    {
201
-        if (param->rc.hevcAq)
202
-        {
203
-            // New method for calculating variance and qp offset
204
-            xPreanalyze(curFrame);
205
-        }
206
         else
207
         {
208
-            int blockXY = 0;
209
-            double avg_adj_pow2 = 0, avg_adj = 0, qp_adj = 0;
210
-            double bias_strength = 0.f;
211
-            double strength = 0.f;
212
-            if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE || param->rc.aqMode == X265_AQ_AUTO_VARIANCE_BIASED)
213
+            if (param->rc.hevcAq)
214
+            {
215
+                // New method for calculating variance and qp offset
216
+                xPreanalyze(curFrame);
217
+            }
218
+            else
219
             {
220
-                double bit_depth_correction = 1.f / (1 << (2 * (X265_DEPTH - 8)));
221
+#define AQ_EDGE_BIAS 0.5
222
+#define EDGE_INCLINATION 45
223
+                uint32_t numCuInHeight = (maxRow + param->maxCUSize - 1) / param->maxCUSize;
224
+                int maxHeight = numCuInHeight * param->maxCUSize;
225
+                intptr_t stride = curFrame->m_fencPic->m_stride;
226
+                pixel *edgePic = X265_MALLOC(pixel, stride * (maxHeight + (curFrame->m_fencPic->m_lumaMarginY * 2)));
227
+                pixel *gaussianPic = X265_MALLOC(pixel, stride * (maxHeight + (curFrame->m_fencPic->m_lumaMarginY * 2)));
228
+                pixel *thetaPic = X265_MALLOC(pixel, stride * (maxHeight + (curFrame->m_fencPic->m_lumaMarginY * 2)));
229
+                memset(edgePic, 0, stride * (maxHeight + (curFrame->m_fencPic->m_lumaMarginY * 2)) * sizeof(pixel));
230
+                memset(gaussianPic, 0, stride * (maxHeight + (curFrame->m_fencPic->m_lumaMarginY * 2)) * sizeof(pixel));
231
+                memset(thetaPic, 0, stride * (maxHeight + (curFrame->m_fencPic->m_lumaMarginY * 2)) * sizeof(pixel));
232
+                if (param->rc.aqMode == X265_AQ_EDGE)
233
+                    edgeFilter(curFrame, edgePic, gaussianPic, thetaPic, stride, maxRow, maxCol);
234
+
235
+                int blockXY = 0, inclinedEdge = 0;
236
+                double avg_adj_pow2 = 0, avg_adj = 0, qp_adj = 0;
237
+                double bias_strength = 0.f;
238
+                double strength = 0.f;
239
+                if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE || param->rc.aqMode == X265_AQ_AUTO_VARIANCE_BIASED || param->rc.aqMode == X265_AQ_EDGE)
240
+                {
241
+                    double bit_depth_correction = 1.f / (1 << (2 * (X265_DEPTH - 8)));
242
+                    for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
243
+                    {
244
+                        for (int blockX = 0; blockX < maxCol; blockX += loopIncr)
245
+                        {
246
+                            uint32_t energy, edgeDensity, avgAngle;
247
+                            energy = acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
248
+                            if (param->rc.aqMode == X265_AQ_EDGE)
249
+                            {
250
+                                pixel *edgeImage = edgePic + curFrame->m_fencPic->m_lumaMarginY * stride + curFrame->m_fencPic->m_lumaMarginX;
251
+                                pixel *edgeTheta = thetaPic + curFrame->m_fencPic->m_lumaMarginY * stride + curFrame->m_fencPic->m_lumaMarginX;
252
+                                edgeDensity = edgeDensityCu(curFrame, edgeImage, edgeTheta, avgAngle, blockX, blockY, param->rc.qgSize);
253
+                                if (edgeDensity)
254
+                                {
255
+                                    qp_adj = pow(edgeDensity * bit_depth_correction + 1, 0.1);
256
+                                    //Increasing the QP of a block if its edge orientation lies around the multiples of 45 degree
257
+                                    if ((avgAngle >= EDGE_INCLINATION - 15 && avgAngle <= EDGE_INCLINATION + 15) || (avgAngle >= EDGE_INCLINATION + 75 && avgAngle <= EDGE_INCLINATION + 105))
258
+                                        curFrame->m_lowres.edgeInclined[blockXY] = 1;
259
+                                    else
260
+                                        curFrame->m_lowres.edgeInclined[blockXY] = 0;
261
+                                }
262
+                                else
263
+                                {
264
+                                    qp_adj = pow(energy * bit_depth_correction + 1, 0.1);
265
+                                    curFrame->m_lowres.edgeInclined[blockXY] = 0;
266
+                                }
267
+                            }
268
+                            else
269
+                                qp_adj = pow(energy * bit_depth_correction + 1, 0.1);
270
+                            curFrame->m_lowres.qpCuTreeOffset[blockXY] = qp_adj;
271
+                            avg_adj += qp_adj;
272
+                            avg_adj_pow2 += qp_adj * qp_adj;
273
+                            blockXY++;
274
+                        }
275
+                    }
276
+                    avg_adj /= blockCount;
277
+                    avg_adj_pow2 /= blockCount;
278
+                    strength = param->rc.aqStrength * avg_adj;
279
+                    avg_adj = avg_adj - 0.5f * (avg_adj_pow2 - modeTwoConst) / avg_adj;
280
+                    bias_strength = param->rc.aqStrength;
281
+                }
282
+                else
283
+                    strength = param->rc.aqStrength * 1.0397f;
284
 
285
+                X265_FREE(edgePic);
286
+                X265_FREE(gaussianPic);
287
+                X265_FREE(thetaPic);
288
+                blockXY = 0;
289
                 for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
290
                 {
291
                     for (int blockX = 0; blockX < maxCol; blockX += loopIncr)
292
                     {
293
-                        uint32_t energy = acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
294
-                        qp_adj = pow(energy * bit_depth_correction + 1, 0.1);
295
+                        if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE_BIASED)
296
+                        {
297
+                            qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY];
298
+                            qp_adj = strength * (qp_adj - avg_adj) + bias_strength * (1.f - modeTwoConst / (qp_adj * qp_adj));
299
+                        }
300
+                        else if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE)
301
+                        {
302
+                            qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY];
303
+                            qp_adj = strength * (qp_adj - avg_adj);
304
+                        }
305
+                        else if (param->rc.aqMode == X265_AQ_EDGE)
306
+                        {
307
+                            inclinedEdge = curFrame->m_lowres.edgeInclined[blockXY];
308
+                            qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY];
309
+                            if(inclinedEdge && (qp_adj - avg_adj > 0))
310
+                                qp_adj = ((strength + AQ_EDGE_BIAS) * (qp_adj - avg_adj));
311
+                            else
312
+                                qp_adj = strength * (qp_adj - avg_adj);
313
+                        }
314
+                        else
315
+                        {
316
+                            uint32_t energy = acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
317
+                            qp_adj = strength * (X265_LOG2(X265_MAX(energy, 1)) - (modeOneConst + 2 * (X265_DEPTH - 8)));
318
+                        }
319
+
320
+                        if (param->bHDROpt)
321
+                        {
322
+                            uint32_t sum = lumaSumCu(curFrame, blockX, blockY, param->rc.qgSize);
323
+                            uint32_t lumaAvg = sum / (loopIncr * loopIncr);
324
+                            if (lumaAvg < 301)
325
+                                qp_adj += 3;
326
+                            else if (lumaAvg >= 301 && lumaAvg < 367)
327
+                                qp_adj += 2;
328
+                            else if (lumaAvg >= 367 && lumaAvg < 434)
329
+                                qp_adj += 1;
330
+                            else if (lumaAvg >= 501 && lumaAvg < 567)
331
+                                qp_adj -= 1;
332
+                            else if (lumaAvg >= 567 && lumaAvg < 634)
333
+                                qp_adj -= 2;
334
+                            else if (lumaAvg >= 634 && lumaAvg < 701)
335
+                                qp_adj -= 3;
336
+                            else if (lumaAvg >= 701 && lumaAvg < 767)
337
+                                qp_adj -= 4;
338
+                            else if (lumaAvg >= 767 && lumaAvg < 834)
339
+                                qp_adj -= 5;
340
+                            else if (lumaAvg >= 834)
341
+                                qp_adj -= 6;
342
+                        }
343
+                        if (quantOffsets != NULL)
344
+                            qp_adj += quantOffsets[blockXY];
345
+                        curFrame->m_lowres.qpAqOffset[blockXY] = qp_adj;
346
                         curFrame->m_lowres.qpCuTreeOffset[blockXY] = qp_adj;
347
-                        avg_adj += qp_adj;
348
-                        avg_adj_pow2 += qp_adj * qp_adj;
349
+                        curFrame->m_lowres.invQscaleFactor[blockXY] = x265_exp2fix8(qp_adj);
350
                         blockXY++;
351
                     }
352
                 }
353
-                avg_adj /= blockCount;
354
-                avg_adj_pow2 /= blockCount;
355
-                strength = param->rc.aqStrength * avg_adj;
356
-                avg_adj = avg_adj - 0.5f * (avg_adj_pow2 - modeTwoConst) / avg_adj;
357
-                bias_strength = param->rc.aqStrength;
358
             }
359
-            else
360
-                strength = param->rc.aqStrength * 1.0397f;
361
+        }
362
 
363
-            blockXY = 0;
364
-            for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
365
+        if (param->rc.qgSize == 8)
366
+        {
367
+            for (int cuY = 0; cuY < heightInCU; cuY++)
368
             {
369
-                for (int blockX = 0; blockX < maxCol; blockX += loopIncr)
370
+                for (int cuX = 0; cuX < widthInCU; cuX++)
371
                 {
372
-                    if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE_BIASED)
373
-                    {
374
-                        qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY];
375
-                        qp_adj = strength * (qp_adj - avg_adj) + bias_strength * (1.f - modeTwoConst / (qp_adj * qp_adj));
376
-                    }
377
-                    else if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE)
378
-                    {
379
-                        qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY];
380
-                        qp_adj = strength * (qp_adj - avg_adj);
381
-                    }
382
-                    else
383
-                    {
384
-                        uint32_t energy = acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
385
-                        qp_adj = strength * (X265_LOG2(X265_MAX(energy, 1)) - (modeOneConst + 2 * (X265_DEPTH - 8)));
386
-                    }
387
-
388
-                    if (param->bHDROpt)
389
-                    {
390
-                        uint32_t sum = lumaSumCu(curFrame, blockX, blockY, param->rc.qgSize);
391
-                        uint32_t lumaAvg = sum / (loopIncr * loopIncr);
392
-                        if (lumaAvg < 301)
393
-                            qp_adj += 3;
394
-                        else if (lumaAvg >= 301 && lumaAvg < 367)
395
-                            qp_adj += 2;
396
-                        else if (lumaAvg >= 367 && lumaAvg < 434)
397
-                            qp_adj += 1;
398
-                        else if (lumaAvg >= 501 && lumaAvg < 567)
399
-                            qp_adj -= 1;
400
-                        else if (lumaAvg >= 567 && lumaAvg < 634)
401
-                            qp_adj -= 2;
402
-                        else if (lumaAvg >= 634 && lumaAvg < 701)
403
-                            qp_adj -= 3;
404
-                        else if (lumaAvg >= 701 && lumaAvg < 767)
405
-                            qp_adj -= 4;
406
-                        else if (lumaAvg >= 767 && lumaAvg < 834)
407
-                            qp_adj -= 5;
408
-                        else if (lumaAvg >= 834)
409
-                            qp_adj -= 6;
410
-                    }
411
-                    if (quantOffsets != NULL)
412
-                        qp_adj += quantOffsets[blockXY];
413
-                    curFrame->m_lowres.qpAqOffset[blockXY] = qp_adj;
414
-                    curFrame->m_lowres.qpCuTreeOffset[blockXY] = qp_adj;
415
-                    curFrame->m_lowres.invQscaleFactor[blockXY] = x265_exp2fix8(qp_adj);
416
-                    blockXY++;
417
+                    const int cuXY = cuX + cuY * widthInCU;
418
+                    curFrame->m_lowres.invQscaleFactor8x8[cuXY] = (curFrame->m_lowres.invQscaleFactor[cuX * 2 + cuY * widthInCU * 4] +
419
+                        curFrame->m_lowres.invQscaleFactor[cuX * 2 + cuY * widthInCU * 4 + 1] +
420
+                        curFrame->m_lowres.invQscaleFactor[cuX * 2 + cuY * widthInCU * 4 + curFrame->m_lowres.maxBlocksInRowFullRes] +
421
+                        curFrame->m_lowres.invQscaleFactor[cuX * 2 + cuY * widthInCU * 4 + curFrame->m_lowres.maxBlocksInRowFullRes + 1]) / 4;
422
                 }
423
             }
424
         }
425
     }
426
 
427
-    if (param->rc.qgSize == 8)
428
+    if (param->bEnableWeightedPred || param->bEnableWeightedBiPred)
429
     {
430
-        for (int cuY = 0; cuY < heightInCU; cuY++)
431
+        if (param->rc.bStatRead && param->rc.cuTree && IS_REFERENCED(curFrame))
432
         {
433
-            for (int cuX = 0; cuX < widthInCU; cuX++)
434
-            {
435
-                const int cuXY = cuX + cuY * widthInCU;
436
-                curFrame->m_lowres.invQscaleFactor8x8[cuXY] = (curFrame->m_lowres.invQscaleFactor[cuX * 2 + cuY * widthInCU * 4] +
437
-                                                               curFrame->m_lowres.invQscaleFactor[cuX * 2 + cuY * widthInCU * 4 + 1] +
438
-                                                               curFrame->m_lowres.invQscaleFactor[cuX * 2 + cuY * widthInCU * 4 + curFrame->m_lowres.maxBlocksInRowFullRes] +
439
-                                                               curFrame->m_lowres.invQscaleFactor[cuX * 2 + cuY * widthInCU * 4 + curFrame->m_lowres.maxBlocksInRowFullRes + 1]) / 4;
440
-            }
441
+            for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
442
+                for (int blockX = 0; blockX < maxCol; blockX += loopIncr)
443
+                    acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
444
         }
445
-    }
446
 
447
-    if (param->bEnableWeightedPred || param->bEnableWeightedBiPred)
448
-    {
449
         int hShift = CHROMA_H_SHIFT(param->internalCsp);
450
         int vShift = CHROMA_V_SHIFT(param->internalCsp);
451
         maxCol = ((maxCol + 8) >> 4) << 4;
452
@@ -664,6 +855,7 @@
453
     weightedRef.lumaStride = fenc.lumaStride;
454
     weightedRef.isLowres = true;
455
     weightedRef.isWeighted = false;
456
+    weightedRef.isHMELowres = ref.bEnableHME;
457
 
458
     /* epsilon is chosen to require at least a numerator of 127 (with denominator = 128) */
459
     float guessScale, fencMean, refMean;
460
@@ -759,6 +951,8 @@
461
     m_extendGopBoundary = false;
462
     m_8x8Height = ((m_param->sourceHeight / 2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
463
     m_8x8Width = ((m_param->sourceWidth / 2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
464
+    m_4x4Height = ((m_param->sourceHeight / 4) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
465
+    m_4x4Width = ((m_param->sourceWidth / 4) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
466
     m_cuCount = m_8x8Width * m_8x8Height;
467
     m_8x8Blocks = m_8x8Width > 2 && m_8x8Height > 2 ? (m_cuCount + 4 - 2 * (m_8x8Width + m_8x8Height)) : m_cuCount;
468
     m_isFadeIn = false;
469
@@ -1172,9 +1366,7 @@
470
         ProfileScopeEvent(prelookahead);
471
         m_lock.release();
472
         preFrame->m_lowres.init(preFrame->m_fencPic, preFrame->m_poc);
473
-        if (m_lookahead.m_param->rc.bStatRead && m_lookahead.m_param->rc.cuTree && IS_REFERENCED(preFrame))
474
-            /* cu-tree offsets were read from stats file */;
475
-        else if (m_lookahead.m_bAdaptiveQuant)
476
+        if (m_lookahead.m_bAdaptiveQuant)
477
             tld.calcAdaptiveQuantFrame(preFrame, m_lookahead.m_param);
478
         tld.lowresIntraEstimate(preFrame->m_lowres, m_lookahead.m_param->rc.qgSize);
479
         preFrame->m_lowresInit = true;
480
@@ -2782,16 +2974,32 @@
481
 
482
             X265_CHECK(i < MAX_COOP_SLICES, "impossible number of coop slices\n");
483
 
484
-            int firstY = m_lookahead.m_numRowsPerSlice * i;
485
-            int lastY = (i == m_jobTotal - 1) ? m_lookahead.m_8x8Height - 1 : m_lookahead.m_numRowsPerSlice * (i + 1) - 1;
486
+            int firstY, lastY;
487
+            bool lastRow;
488
+            if (m_lookahead.m_param->bEnableHME)
489
+            {
490
+                int numRowsPerSlice = m_lookahead.m_4x4Height / m_lookahead.m_param->lookaheadSlices;
491
+                numRowsPerSlice = X265_MIN(X265_MAX(numRowsPerSlice, 5), m_lookahead.m_4x4Height);
492
+                firstY = numRowsPerSlice * i;
493
+                lastY = (i == m_jobTotal - 1) ? m_lookahead.m_4x4Height - 1 : numRowsPerSlice * (i + 1) - 1;
494
+                lastRow = true;
495
+                for (int cuY = lastY; cuY >= firstY; cuY--)
496
+                {
497
+                    for (int cuX = m_lookahead.m_4x4Width - 1; cuX >= 0; cuX--)
498
+                        estimateCUCost(tld, cuX, cuY, m_coop.p0, m_coop.p1, m_coop.b, m_coop.bDoSearch, lastRow, i, 1);
499
+                    lastRow = false;
500
+                }
501
+            }
502
 
503
-            bool lastRow = true;
504
+            firstY = m_lookahead.m_numRowsPerSlice * i;
505
+            lastY = (i == m_jobTotal - 1) ? m_lookahead.m_8x8Height - 1 : m_lookahead.m_numRowsPerSlice * (i + 1) - 1;
506
+            lastRow = true;
507
             for (int cuY = lastY; cuY >= firstY; cuY--)
508
             {
509
                 m_frames[m_coop.b]->rowSatds[m_coop.b - m_coop.p0][m_coop.p1 - m_coop.b][cuY] = 0;
510
 
511
                 for (int cuX = m_lookahead.m_8x8Width - 1; cuX >= 0; cuX--)
512
-                    estimateCUCost(tld, cuX, cuY, m_coop.p0, m_coop.p1, m_coop.b, m_coop.bDoSearch, lastRow, i);
513
+                    estimateCUCost(tld, cuX, cuY, m_coop.p0, m_coop.p1, m_coop.b, m_coop.bDoSearch, lastRow, i, 0);
514
 
515
                 lastRow = false;
516
             }
517
@@ -2864,13 +3072,25 @@
518
         }
519
         else
520
         {
521
-            bool lastRow = true;
522
+            /* Calculate MVs for 1/16th resolution*/
523
+            bool lastRow;
524
+            if (param->bEnableHME)
525
+            {
526
+                lastRow = true;
527
+                for (int cuY = m_lookahead.m_4x4Height - 1; cuY >= 0; cuY--)
528
+                {
529
+                    for (int cuX = m_lookahead.m_4x4Width - 1; cuX >= 0; cuX--)
530
+                        estimateCUCost(tld, cuX, cuY, p0, p1, b, bDoSearch, lastRow, -1, 1);
531
+                    lastRow = false;
532
+                }
533
+            }
534
+            lastRow = true;
535
             for (int cuY = m_lookahead.m_8x8Height - 1; cuY >= 0; cuY--)
536
             {
537
                 fenc->rowSatds[b - p0][p1 - b][cuY] = 0;
538
 
539
                 for (int cuX = m_lookahead.m_8x8Width - 1; cuX >= 0; cuX--)
540
-                    estimateCUCost(tld, cuX, cuY, p0, p1, b, bDoSearch, lastRow, -1);
541
+                    estimateCUCost(tld, cuX, cuY, p0, p1, b, bDoSearch, lastRow, -1, 0);
542
 
543
                 lastRow = false;
544
             }
545
@@ -2891,23 +3111,27 @@
546
     return score;
547
 }
548
 
549
-void CostEstimateGroup::estimateCUCost(LookaheadTLD& tld, int cuX, int cuY, int p0, int p1, int b, bool bDoSearch[2], bool lastRow, int slice)
550
+void CostEstimateGroup::estimateCUCost(LookaheadTLD& tld, int cuX, int cuY, int p0, int p1, int b, bool bDoSearch[2], bool lastRow, int slice, bool hme)
551
 {
552
     Lowres *fref0 = m_frames[p0];
553
     Lowres *fref1 = m_frames[p1];
554
     Lowres *fenc  = m_frames[b];
555
 
556
-    ReferencePlanes *wfref0 = fenc->weightedRef[b - p0].isWeighted ? &fenc->weightedRef[b - p0] : fref0;
557
+    ReferencePlanes *wfref0 = fenc->weightedRef[b - p0].isWeighted && !hme ? &fenc->weightedRef[b - p0] : fref0;
558
 
559
-    const int widthInCU = m_lookahead.m_8x8Width;
560
-    const int heightInCU = m_lookahead.m_8x8Height;
561
+    const int widthInCU = hme ? m_lookahead.m_4x4Width : m_lookahead.m_8x8Width;
562
+    const int heightInCU = hme ? m_lookahead.m_4x4Height : m_lookahead.m_8x8Height;
563
     const int bBidir = (b < p1);
564
     const int cuXY = cuX + cuY * widthInCU;
565
+    const int cuXY_4x4 = (cuX / 2) + (cuY / 2) * widthInCU / 2;
566
     const int cuSize = X265_LOWRES_CU_SIZE;
567
-    const intptr_t pelOffset = cuSize * cuX + cuSize * cuY * fenc->lumaStride;
568
+    const intptr_t pelOffset = cuSize * cuX + cuSize * cuY * (hme ? fenc->lumaStride/2 : fenc->lumaStride);
569
+
570
+    if ((bBidir || bDoSearch[0] || bDoSearch[1]) && hme)
571
+        tld.me.setSourcePU(fenc->lowerResPlane[0], fenc->lumaStride / 2, pelOffset, cuSize, cuSize, X265_HEX_SEARCH, m_lookahead.m_param->hmeSearchMethod[0], m_lookahead.m_param->hmeSearchMethod[1], 1);
572
+    else if((bBidir || bDoSearch[0] || bDoSearch[1]) && !hme)
573
+        tld.me.setSourcePU(fenc->lowresPlane[0], fenc->lumaStride, pelOffset, cuSize, cuSize, X265_HEX_SEARCH, m_lookahead.m_param->hmeSearchMethod[0], m_lookahead.m_param->hmeSearchMethod[1], 1);
574
 
575
-    if (bBidir || bDoSearch[0] || bDoSearch[1])
576
-        tld.me.setSourcePU(fenc->lowresPlane[0], fenc->lumaStride, pelOffset, cuSize, cuSize, X265_HEX_SEARCH, 1);
577
 
578
     /* A small, arbitrary bias to avoid VBV problems caused by zero-residual lookahead blocks. */
579
     int lowresPenalty = 4;
580
@@ -2926,7 +3150,7 @@
581
 
582
     for (int i = 0; i < 1 + bBidir; i++)
583
     {
584
-        int& fencCost = fenc->lowresMvCosts[i][listDist[i]][cuXY];
585
+        int& fencCost = hme ? fenc->lowerResMvCosts[i][listDist[i]][cuXY] : fenc->lowresMvCosts[i][listDist[i]][cuXY];
586
         int skipCost = INT_MAX;
587
 
588
         if (!bDoSearch[i])
589
@@ -2936,8 +3160,8 @@
590
         }
591
 
592
         int numc = 0;
593
-        MV mvc[4], mvp;
594
-        MV* fencMV = &fenc->lowresMvs[i][listDist[i]][cuXY];
595
+        MV mvc[5], mvp;
596
+        MV* fencMV = hme ? &fenc->lowerResMvs[i][listDist[i]][cuXY] : &fenc->lowresMvs[i][listDist[i]][cuXY];
597
         ReferencePlanes* fref = i ? fref1 : wfref0;
598
 
599
         /* Reverse-order MV prediction */
600
@@ -2952,6 +3176,10 @@
601
             if (cuX < widthInCU - 1)
602
                 MVC(fencMV[widthInCU + 1]);
603
         }
604
+        if (fenc->lowerResMvs[0][0] && !hme && fenc->lowerResMvCosts[i][listDist[i]][cuXY_4x4] > 0)
605
+        {
606
+            MVC((fenc->lowerResMvs[i][listDist[i]][cuXY_4x4]) * 2);
607
+        }
608
 #undef MVC
609
 
610
         if (!numc)
611
@@ -2967,7 +3195,7 @@
612
             for (int idx = 0; idx < numc; idx++)
613
             {
614
                 intptr_t stride = X265_LOWRES_CU_SIZE;
615
-                pixel *src = fref->lowresMC(pelOffset, mvc[idx], subpelbuf, stride);
616
+                pixel *src = fref->lowresMC(pelOffset, mvc[idx], subpelbuf, stride, hme);
617
                 int cost = tld.me.bufSATD(src, stride);
618
                 COPY2_IF_LT(mvpcost, cost, mvp, mvc[idx]);
619
                 /* Except for mv0 case, everyting else is likely to have enough residual to not trigger the skip. */
620
@@ -2978,7 +3206,10 @@
621
 
622
         /* ME will never return a cost larger than the cost @MVP, so we do not
623
          * have to check that ME cost is more than the estimated merge cost */
624
-        fencCost = tld.me.motionEstimate(fref, mvmin, mvmax, mvp, 0, NULL, s_merange, *fencMV, m_lookahead.m_param->maxSlices);
625
+        if(!hme)
626
+            fencCost = tld.me.motionEstimate(fref, mvmin, mvmax, mvp, 0, NULL, s_merange, *fencMV, m_lookahead.m_param->maxSlices);
627
+        else
628
+            fencCost = tld.me.motionEstimate(fref, mvmin, mvmax, mvp, 0, NULL, s_merange, *fencMV, m_lookahead.m_param->maxSlices, fref->lowerResPlane[0]);
629
         if (skipCost < 64 && skipCost < fencCost && bBidir)
630
         {
631
             fencCost = skipCost;
632
@@ -2986,6 +3217,8 @@
633
         }
634
         COPY2_IF_LT(bcost, fencCost, listused, i + 1);
635
     }
636
+    if (hme)
637
+        return;
638
 
639
     if (bBidir) /* B, also consider bidir */
640
     {
641
@@ -2995,8 +3228,8 @@
642
         ALIGN_VAR_32(pixel, subpelbuf0[X265_LOWRES_CU_SIZE * X265_LOWRES_CU_SIZE]);
643
         ALIGN_VAR_32(pixel, subpelbuf1[X265_LOWRES_CU_SIZE * X265_LOWRES_CU_SIZE]);
644
         intptr_t stride0 = X265_LOWRES_CU_SIZE, stride1 = X265_LOWRES_CU_SIZE;
645
-        pixel *src0 = fref0->lowresMC(pelOffset, fenc->lowresMvs[0][listDist[0]][cuXY], subpelbuf0, stride0);
646
-        pixel *src1 = fref1->lowresMC(pelOffset, fenc->lowresMvs[1][listDist[1]][cuXY], subpelbuf1, stride1);
647
+        pixel *src0 = fref0->lowresMC(pelOffset, fenc->lowresMvs[0][listDist[0]][cuXY], subpelbuf0, stride0, 0);
648
+        pixel *src1 = fref1->lowresMC(pelOffset, fenc->lowresMvs[1][listDist[1]][cuXY], subpelbuf1, stride1, 0);
649
         ALIGN_VAR_32(pixel, ref[X265_LOWRES_CU_SIZE * X265_LOWRES_CU_SIZE]);
650
         primitives.pu[LUMA_8x8].pixelavg_pp[NONALIGNED](ref, X265_LOWRES_CU_SIZE, src0, stride0, src1, stride1, 32);
651
         int bicost = tld.me.bufSATD(ref, X265_LOWRES_CU_SIZE);
652
x265_3.1.2.tar.gz/source/encoder/slicetype.h -> x265_3.2.tar.gz/source/encoder/slicetype.h Changed
29
 
1
@@ -92,6 +92,7 @@
2
 protected:
3
 
4
     uint32_t acEnergyCu(Frame* curFrame, uint32_t blockX, uint32_t blockY, int csp, uint32_t qgSize);
5
+    uint32_t edgeDensityCu(Frame*curFrame, pixel *edgeImage, pixel *edgeTheta, uint32_t &avgAngle, uint32_t blockX, uint32_t blockY, uint32_t qgSize);
6
     uint32_t lumaSumCu(Frame* curFrame, uint32_t blockX, uint32_t blockY, uint32_t qgSize);
7
     uint32_t weightCostLuma(Lowres& fenc, Lowres& ref, WeightParam& wp);
8
     bool     allocWeightedRef(Lowres& fenc);
9
@@ -124,6 +125,10 @@
10
     int           m_inputCount;
11
     double        m_cuTreeStrength;
12
 
13
+    /* HME */
14
+    int           m_4x4Width;
15
+    int           m_4x4Height;
16
+
17
     bool          m_isActive;
18
     bool          m_sliceTypeBusy;
19
     bool          m_bAdaptiveQuant;
20
@@ -246,7 +251,7 @@
21
     void    processTasks(int workerThreadID);
22
 
23
     int64_t estimateFrameCost(LookaheadTLD& tld, int p0, int p1, int b, bool intraPenalty);
24
-    void    estimateCUCost(LookaheadTLD& tld, int cux, int cuy, int p0, int p1, int b, bool bDoSearch[2], bool lastRow, int slice);
25
+    void    estimateCUCost(LookaheadTLD& tld, int cux, int cuy, int p0, int p1, int b, bool bDoSearch[2], bool lastRow, int slice, bool hme);
26
 
27
     CostEstimateGroup& operator=(const CostEstimateGroup&);
28
 };
29
x265_3.1.2.tar.gz/source/encoder/weightPrediction.cpp -> x265_3.2.tar.gz/source/encoder/weightPrediction.cpp Changed
10
 
1
@@ -82,7 +82,7 @@
2
             /* clip MV to available pixels */
3
             MV mv = mvs[cu];
4
             mv = mv.clipped(mvmin, mvmax);
5
-            pixel *tmp = ref.lowresMC(pixoff, mv, buf8x8, bstride);
6
+            pixel *tmp = ref.lowresMC(pixoff, mv, buf8x8, bstride, 0);
7
             primitives.cu[BLOCK_8x8].copy_pp(mcout + pixoff, stride, tmp, bstride);
8
         }
9
     }
10
x265_3.1.2.tar.gz/source/test/regression-tests.txt -> x265_3.2.tar.gz/source/test/regression-tests.txt Changed
11
 
1
@@ -153,6 +153,9 @@
2
 big_buck_bunny_360p24.y4m, --keyint 60 --min-keyint 40 --gop-lookahead 14
3
 BasketballDrive_1920x1080_50.y4m, --preset medium --no-open-gop --keyint 50 --min-keyint 50 --radl 2 --vbv-maxrate 5000 --vbv-bufsize 5000
4
 big_buck_bunny_360p24.y4m, --bitrate 500 --fades
5
+720p50_parkrun_ter.y4m,--preset medium --bitrate 400 --hme
6
+ducks_take_off_420_1_720p50.y4m,--preset medium --aq-mode 4 --crf 22 --no-cutree
7
+ducks_take_off_420_1_720p50.y4m,--preset medium --selective-sao 4 --sao --crf 20
8
 
9
 # Main12 intraCost overflow bug test
10
 720p50_parkrun_ter.y4m,--preset medium
11
x265_3.1.2.tar.gz/source/x265.h -> x265_3.2.tar.gz/source/x265.h Changed
37
 
1
@@ -561,6 +561,7 @@
2
 #define X265_AQ_VARIANCE             1
3
 #define X265_AQ_AUTO_VARIANCE        2
4
 #define X265_AQ_AUTO_VARIANCE_BIASED 3
5
+#define X265_AQ_EDGE                 4
6
 #define x265_ADAPT_RD_STRENGTH   4
7
 #define X265_REFINE_INTER_LEVELS 3
8
 /* NOTE! For this release only X265_CSP_I420 and X265_CSP_I444 are supported */
9
@@ -1172,6 +1173,14 @@
10
     /* Enable availability of temporal motion vector for AMVP, default is enabled */
11
     int       bEnableTemporalMvp;
12
 
13
+    /* Enable 3-level Hierarchical motion estimation at One-Sixteenth, Quarter and Full resolution.
14
+     * Default is disabled */
15
+    int       bEnableHME;
16
+
17
+    /* Enable HME search method (DIA, HEX, UMH, STAR, SEA, FULL) for level 0, 1 and 2.
18
+     * Default is hex, umh, umh for L0, L1 and L2 respectively. */
19
+    int       hmeSearchMethod[3];
20
+
21
     /* Enable weighted prediction in P slices.  This enables weighting analysis
22
      * in the lookahead, which influences slice decisions, and enables weighting
23
      * analysis in the main encoder which allows P reference samples to have a
24
@@ -1214,6 +1223,12 @@
25
      * non-deblocked pixels are used entirely. Default is disabled */
26
     int       bSaoNonDeblocked;
27
 
28
+    /* Select tune rate in which SAO has to be applied.
29
+    1 - Filtering applied only on I-frames(I) [Light tune]
30
+    2 - No Filtering on B frames (I, P) [Medium tune]
31
+    3 - No Filtering on non-ref b frames  (I, P, B) [Strong tune] */
32
+    int       selectiveSAO;
33
+
34
     /*== Analysis tools ==*/
35
 
36
     /* A value between 1 and 6 (both inclusive) which determines the level of 
37
x265_3.1.2.tar.gz/source/x265cli.h -> x265_3.2.tar.gz/source/x265cli.h Changed
66
 
1
@@ -95,6 +95,9 @@
2
     { "max-merge",      required_argument, NULL, 0 },
3
     { "no-temporal-mvp",      no_argument, NULL, 0 },
4
     { "temporal-mvp",         no_argument, NULL, 0 },
5
+    { "hme",                  no_argument, NULL, 0 },
6
+    { "no-hme",               no_argument, NULL, 0 },
7
+    { "hme-search",     required_argument, NULL, 0 },
8
     { "rdpenalty",      required_argument, NULL, 0 },
9
     { "no-rect",              no_argument, NULL, 0 },
10
     { "rect",                 no_argument, NULL, 0 },
11
@@ -197,6 +200,7 @@
12
     { "no-deblock",           no_argument, NULL, 0 },
13
     { "deblock",        required_argument, NULL, 0 },
14
     { "no-sao",               no_argument, NULL, 0 },
15
+    { "selective-sao",  required_argument, NULL, 0 },
16
     { "sao",                  no_argument, NULL, 0 },
17
     { "no-sao-non-deblock",   no_argument, NULL, 0 },
18
     { "sao-non-deblock",      no_argument, NULL, 0 },
19
@@ -294,8 +298,7 @@
20
     { "dhdr10-opt",           no_argument, NULL, 0},
21
     { "no-dhdr10-opt",        no_argument, NULL, 0},
22
     { "dolby-vision-profile",  required_argument, NULL, 0 },
23
-    { "refine-mv",            no_argument, NULL, 0 },
24
-    { "no-refine-mv",         no_argument, NULL, 0 },
25
+    { "refine-mv",      required_argument, NULL, 0 },
26
     { "refine-ctu-distortion", required_argument, NULL, 0 },
27
     { "force-flush",    required_argument, NULL, 0 },
28
     { "splitrd-skip",         no_argument, NULL, 0 },
29
@@ -464,6 +467,8 @@
30
     H0("   --[no-]amp                    Enable asymmetric motion partitions, requires --rect. Default %s\n", OPT(param->bEnableAMP));
31
     H0("   --[no-]limit-modes            Limit rectangular and asymmetric motion predictions. Default %d\n", param->limitModes);
32
     H1("   --[no-]temporal-mvp           Enable temporal MV predictors. Default %s\n", OPT(param->bEnableTemporalMvp));
33
+    H1("   --[no-]hme                    Enable Hierarchical Motion Estimation. Default %s\n", OPT(param->bEnableHME));
34
+    H1("   --hme-search <string>         Motion search-method for HME L0,L1 and L2. Default(L0,L1,L2) is %d,%d,%d\n", param->hmeSearchMethod[0], param->hmeSearchMethod[1], param->hmeSearchMethod[2]);
35
     H0("\nSpatial / intra options:\n");
36
     H0("   --[no-]strong-intra-smoothing Enable strong intra smoothing for 32x32 blocks. Default %s\n", OPT(param->bEnableStrongIntraSmoothing));
37
     H0("   --[no-]constrained-intra      Constrained intra prediction (use only intra coded reference pixels) Default %s\n", OPT(param->bEnableConstrainedIntra));
38
@@ -544,16 +549,16 @@
39
         "                                    - 3 : Functionality of (1) + irrespective of size evaluate all inter modes.\n"
40
         "                                Default:%d\n", param->interRefine);
41
     H0("   --[no-]dynamic-refine         Dynamically changes refine-inter level for each CU. Default %s\n", OPT(param->bDynamicRefine));
42
-    H0("   --[no-]refine-mv              Enable mv refinement for load mode. Default %s\n", OPT(param->mvRefine));
43
+    H0("   --refine-mv <1..3>            Enable mv refinement for load mode. Default %d\n", param->mvRefine);
44
     H0("   --refine-ctu-distortion       Store/normalize ctu distortion in analysis-save/load.\n"
45
         "                                    - 0 : Disabled.\n"
46
         "                                    - 1 : Store/Load ctu distortion to/from the file specified in analysis-save/load.\n"
47
         "                                Default 0 - Disabled\n");
48
-    H0("   --aq-mode <integer>           Mode for Adaptive Quantization - 0:none 1:uniform AQ 2:auto variance 3:auto variance with bias to dark scenes. Default %d\n", param->rc.aqMode);
49
+    H0("   --aq-mode <integer>           Mode for Adaptive Quantization - 0:none 1:uniform AQ 2:auto variance 3:auto variance with bias to dark scenes 4:auto variance with edge information. Default %d\n", param->rc.aqMode);
50
     H0("   --[no-]hevc-aq                Mode for HEVC Adaptive Quantization. Default %s\n", OPT(param->rc.hevcAq));
51
     H0("   --aq-strength <float>         Reduces blocking and blurring in flat and textured areas (0 to 3.0). Default %.2f\n", param->rc.aqStrength);
52
     H0("   --qp-adaptation-range <float> Delta QP range by QP adaptation based on a psycho-visual model (1.0 to 6.0). Default %.2f\n", param->rc.qpAdaptationRange);
53
-    H0("   --[no-]aq-motion              Adaptive Quantization based on the relative motion of each CU w.r.t., frame. Default %s\n", OPT(param->bOptCUDeltaQP));
54
+    H0("   --[no-]aq-motion              Block level QP adaptation based on the relative motion between the block and the frame. Default %s\n", OPT(param->bAQMotion));
55
     H0("   --qg-size <int>               Specifies the size of the quantization group (64, 32, 16, 8). Default %d\n", param->rc.qgSize);
56
     H0("   --[no-]cutree                 Enable cutree for Adaptive Quantization. Default %s\n", OPT(param->rc.cuTree));
57
     H0("   --[no-]rc-grain               Enable ratecontrol mode to handle grains specifically. turned on with tune grain. Default %s\n", OPT(param->rc.bEnableGrain));
58
@@ -585,6 +590,7 @@
59
     H0("   --[no-]sao                    Enable Sample Adaptive Offset. Default %s\n", OPT(param->bEnableSAO));
60
     H1("   --[no-]sao-non-deblock        Use non-deblocked pixels, else right/bottom boundary areas skipped. Default %s\n", OPT(param->bSaoNonDeblocked));
61
     H0("   --[no-]limit-sao              Limit Sample Adaptive Offset types. Default %s\n", OPT(param->bLimitSAO));
62
+    H0("   --selective-sao <int>         Enable slice-level SAO filter. Default %d\n", param->selectiveSAO);
63
     H0("\nVUI options:\n");
64
     H0("   --sar <width:height|int>      Sample Aspect Ratio, the ratio of width to height of an individual pixel.\n");
65
     H0("                                 Choose from 0=undef, 1=1:1(\"square\"), 2=12:11, 3=10:11, 4=16:11,\n");
66
Refresh
Refresh


Request History
enzokiel's avatar

enzokiel created request over 5 years ago


enzokiel's avatar

enzokiel accepted request over 5 years ago