]> git.sesse.net Git - x264/commitdiff
custom quant matrices
authorLoren Merritt <pengvado@videolan.org>
Mon, 20 Jun 2005 00:08:28 +0000 (00:08 +0000)
committerLoren Merritt <pengvado@videolan.org>
Mon, 20 Jun 2005 00:08:28 +0000 (00:08 +0000)
git-svn-id: svn://svn.videolan.org/x264/trunk@266 df754926-b1dd-0310-bc7b-ec298dee348c

12 files changed:
Makefile
common/common.c
common/common.h
common/macroblock.c
common/macroblock.h
common/set.c [new file with mode: 0644]
common/set.h
encoder/encoder.c
encoder/macroblock.c
encoder/set.c
x264.c
x264.h

index c030cbdc733b113a7cdb4ae560bd4f6637c6306d..687146d8a23016160ba53fadcf6f86298f9d4738 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ include config.mak
 
 SRCS = common/mc.c common/predict.c common/pixel.c common/macroblock.c \
        common/frame.c common/dct.c common/cpu.c common/cabac.c \
-       common/common.c common/mdate.c common/csp.c \
+       common/common.c common/mdate.c common/csp.c common/set.c\
        encoder/analyse.c encoder/me.c encoder/ratecontrol.c \
        encoder/set.c encoder/macroblock.c encoder/cabac.c \
        encoder/cavlc.c encoder/encoder.c encoder/eval.c
index 3554d193d9854b35fb7566116931ecdf85f2e8cf..c6286f92a45ea38baf42b8d3ff649626bcf041fe 100644 (file)
@@ -116,6 +116,14 @@ void    x264_param_default( x264_param_t *param )
     param->analyse.i_chroma_qp_offset = 0;
     param->analyse.b_psnr = 1;
 
+    param->i_cqm_preset = X264_CQM_FLAT;
+    memset( param->cqm_4iy, 16, 16 );
+    memset( param->cqm_4ic, 16, 16 );
+    memset( param->cqm_4py, 16, 16 );
+    memset( param->cqm_4pc, 16, 16 );
+    memset( param->cqm_8iy, 16, 64 );
+    memset( param->cqm_8py, 16, 64 );
+
     param->b_aud = 0;
 }
 
index 162c632dbd8e7962df58885da5e184582a898965..e561cccaec675faaaa04539abee083f2380a2f3b 100644 (file)
@@ -239,6 +239,11 @@ struct x264_t
     x264_pps_t      *pps;
     int             i_idr_pic_id;
 
+    int             dequant4_mf[4][6][4][4];
+    int             dequant8_mf[2][6][8][8];
+    int             quant4_mf[4][6][4][4];
+    int             quant8_mf[2][6][8][8];
+
     /* Slice header */
     x264_slice_header_t sh;
 
index 85a73c7de922d5c2e5ad7bafa7a76e04d2fe08dc..f9fb030ce70c03bff1d66b2f619e36602bdf52d4 100644 (file)
@@ -163,34 +163,35 @@ int x264_mb_transform_8x8_allowed( x264_t *h )
 /****************************************************************************
  * Scan and Quant functions
  ****************************************************************************/
-void x264_mb_dequant_2x2_dc( int16_t dct[2][2], int i_qscale )
+void x264_mb_dequant_2x2_dc( int16_t dct[2][2], int dequant_mf[6][4][4], int i_qscale )
 {
-    const int i_qbits = i_qscale/6 - 1;
+    const int i_qbits = i_qscale/6 - 5;
 
     if( i_qbits >= 0 )
     {
         const int i_dmf = dequant_mf[i_qscale%6][0][0] << i_qbits;
 
-        dct[0][0] = dct[0][0] * i_dmf;
-        dct[0][1] = dct[0][1] * i_dmf;
-        dct[1][0] = dct[1][0] * i_dmf;
-        dct[1][1] = dct[1][1] * i_dmf;
+        dct[0][0] *= i_dmf;
+        dct[0][1] *= i_dmf;
+        dct[1][0] *= i_dmf;
+        dct[1][1] *= i_dmf;
     }
     else
     {
         const int i_dmf = dequant_mf[i_qscale%6][0][0];
+        // chroma DC is truncated, not rounded
 
-        dct[0][0] = ( dct[0][0] * i_dmf ) >> 1;
-        dct[0][1] = ( dct[0][1] * i_dmf ) >> 1;
-        dct[1][0] = ( dct[1][0] * i_dmf ) >> 1;
-        dct[1][1] = ( dct[1][1] * i_dmf ) >> 1;
+        dct[0][0] = ( dct[0][0] * i_dmf ) >> (-i_qbits);
+        dct[0][1] = ( dct[0][1] * i_dmf ) >> (-i_qbits);
+        dct[1][0] = ( dct[1][0] * i_dmf ) >> (-i_qbits);
+        dct[1][1] = ( dct[1][1] * i_dmf ) >> (-i_qbits);
     }
 }
 
-void x264_mb_dequant_4x4_dc( int16_t dct[4][4], int i_qscale )
+void x264_mb_dequant_4x4_dc( int16_t dct[4][4], int dequant_mf[6][4][4], int i_qscale )
 {
-    const int i_qbits = i_qscale/6 - 2;
-    int x,y;
+    const int i_qbits = i_qscale/6 - 6;
+    int y;
 
     if( i_qbits >= 0 )
     {
@@ -198,76 +199,89 @@ void x264_mb_dequant_4x4_dc( int16_t dct[4][4], int i_qscale )
 
         for( y = 0; y < 4; y++ )
         {
-            for( x = 0; x < 4; x++ )
-            {
-                dct[y][x] = dct[y][x] * i_dmf;
-            }
+            dct[y][0] *= i_dmf;
+            dct[y][1] *= i_dmf;
+            dct[y][2] *= i_dmf;
+            dct[y][3] *= i_dmf;
         }
     }
     else
     {
         const int i_dmf = dequant_mf[i_qscale%6][0][0];
-        const int f = -i_qbits; // 1 << (-1-i_qbits)
+        const int f = 1 << (-i_qbits-1);
 
         for( y = 0; y < 4; y++ )
         {
-            for( x = 0; x < 4; x++ )
-            {
-                dct[y][x] = ( dct[y][x] * i_dmf + f ) >> (-i_qbits);
-            }
+            dct[y][0] = ( dct[y][0] * i_dmf + f ) >> (-i_qbits);
+            dct[y][1] = ( dct[y][1] * i_dmf + f ) >> (-i_qbits);
+            dct[y][2] = ( dct[y][2] * i_dmf + f ) >> (-i_qbits);
+            dct[y][3] = ( dct[y][3] * i_dmf + f ) >> (-i_qbits);
         }
     }
 }
 
-void x264_mb_dequant_4x4( int16_t dct[4][4], int i_qscale )
+void x264_mb_dequant_4x4( int16_t dct[4][4], int dequant_mf[6][4][4], int i_qscale )
 {
     const int i_mf = i_qscale%6;
-    const int i_qbits = i_qscale/6;
+    const int i_qbits = i_qscale/6 - 4;
     int y;
 
-    for( y = 0; y < 4; y++ )
+    if( i_qbits >= 0 )
+    {
+        for( y = 0; y < 4; y++ )
+        {
+            dct[y][0] = ( dct[y][0] * dequant_mf[i_mf][y][0] ) << i_qbits;
+            dct[y][1] = ( dct[y][1] * dequant_mf[i_mf][y][1] ) << i_qbits;
+            dct[y][2] = ( dct[y][2] * dequant_mf[i_mf][y][2] ) << i_qbits;
+            dct[y][3] = ( dct[y][3] * dequant_mf[i_mf][y][3] ) << i_qbits;
+        }
+    }
+    else
     {
-        dct[y][0] = ( dct[y][0] * dequant_mf[i_mf][y][0] ) << i_qbits;
-        dct[y][1] = ( dct[y][1] * dequant_mf[i_mf][y][1] ) << i_qbits;
-        dct[y][2] = ( dct[y][2] * dequant_mf[i_mf][y][2] ) << i_qbits;
-        dct[y][3] = ( dct[y][3] * dequant_mf[i_mf][y][3] ) << i_qbits;
+        const int f = 1 << (-i_qbits-1);
+        for( y = 0; y < 4; y++ )
+        {
+            dct[y][0] = ( dct[y][0] * dequant_mf[i_mf][y][0] + f ) >> (-i_qbits);
+            dct[y][1] = ( dct[y][1] * dequant_mf[i_mf][y][1] + f ) >> (-i_qbits);
+            dct[y][2] = ( dct[y][2] * dequant_mf[i_mf][y][2] + f ) >> (-i_qbits);
+            dct[y][3] = ( dct[y][3] * dequant_mf[i_mf][y][3] + f ) >> (-i_qbits);
+        }
     }
 }
 
-void x264_mb_dequant_8x8( int16_t dct[8][8], int i_qscale )
+void x264_mb_dequant_8x8( int16_t dct[8][8], int dequant_mf[6][8][8], int i_qscale )
 {
     const int i_mf = i_qscale%6;
+    const int i_qbits = i_qscale/6 - 6;
     int y;
 
-    if( i_qscale >= 12 )
+    if( i_qbits >= 0 )
     {
-        const int i_qbits = (i_qscale/6) - 2;
         for( y = 0; y < 8; y++ )
         {
-            dct[y][0] = ( dct[y][0] * dequant8_mf[i_mf][y][0] ) << i_qbits;
-            dct[y][1] = ( dct[y][1] * dequant8_mf[i_mf][y][1] ) << i_qbits;
-            dct[y][2] = ( dct[y][2] * dequant8_mf[i_mf][y][2] ) << i_qbits;
-            dct[y][3] = ( dct[y][3] * dequant8_mf[i_mf][y][3] ) << i_qbits;
-            dct[y][4] = ( dct[y][4] * dequant8_mf[i_mf][y][4] ) << i_qbits;
-            dct[y][5] = ( dct[y][5] * dequant8_mf[i_mf][y][5] ) << i_qbits;
-            dct[y][6] = ( dct[y][6] * dequant8_mf[i_mf][y][6] ) << i_qbits;
-            dct[y][7] = ( dct[y][7] * dequant8_mf[i_mf][y][7] ) << i_qbits;
+            dct[y][0] = ( dct[y][0] * dequant_mf[i_mf][y][0] ) << i_qbits;
+            dct[y][1] = ( dct[y][1] * dequant_mf[i_mf][y][1] ) << i_qbits;
+            dct[y][2] = ( dct[y][2] * dequant_mf[i_mf][y][2] ) << i_qbits;
+            dct[y][3] = ( dct[y][3] * dequant_mf[i_mf][y][3] ) << i_qbits;
+            dct[y][4] = ( dct[y][4] * dequant_mf[i_mf][y][4] ) << i_qbits;
+            dct[y][5] = ( dct[y][5] * dequant_mf[i_mf][y][5] ) << i_qbits;
+            dct[y][6] = ( dct[y][6] * dequant_mf[i_mf][y][6] ) << i_qbits;
+            dct[y][7] = ( dct[y][7] * dequant_mf[i_mf][y][7] ) << i_qbits;
         }
     }
     else
     {
-        const int i_qbits = 2 - (i_qscale/6);
-        const int i_round = i_qbits; // 1<<(i_qbits-1)
+        const int f = 1 << (-i_qbits-1);
         for( y = 0; y < 8; y++ )
         {
-            dct[y][0] = ( dct[y][0] * dequant8_mf[i_mf][y][0] + i_round ) >> i_qbits;
-            dct[y][1] = ( dct[y][1] * dequant8_mf[i_mf][y][1] + i_round ) >> i_qbits;
-            dct[y][2] = ( dct[y][2] * dequant8_mf[i_mf][y][2] + i_round ) >> i_qbits;
-            dct[y][3] = ( dct[y][3] * dequant8_mf[i_mf][y][3] + i_round ) >> i_qbits;
-            dct[y][4] = ( dct[y][4] * dequant8_mf[i_mf][y][4] + i_round ) >> i_qbits;
-            dct[y][5] = ( dct[y][5] * dequant8_mf[i_mf][y][5] + i_round ) >> i_qbits;
-            dct[y][6] = ( dct[y][6] * dequant8_mf[i_mf][y][6] + i_round ) >> i_qbits;
-            dct[y][7] = ( dct[y][7] * dequant8_mf[i_mf][y][7] + i_round ) >> i_qbits;
+            dct[y][0] = ( dct[y][0] * dequant_mf[i_mf][y][0] + f ) >> (-i_qbits);
+            dct[y][1] = ( dct[y][1] * dequant_mf[i_mf][y][1] + f ) >> (-i_qbits);
+            dct[y][2] = ( dct[y][2] * dequant_mf[i_mf][y][2] + f ) >> (-i_qbits);
+            dct[y][3] = ( dct[y][3] * dequant_mf[i_mf][y][3] + f ) >> (-i_qbits);
+            dct[y][4] = ( dct[y][4] * dequant_mf[i_mf][y][4] + f ) >> (-i_qbits);
+            dct[y][5] = ( dct[y][5] * dequant_mf[i_mf][y][5] + f ) >> (-i_qbits);
+            dct[y][6] = ( dct[y][6] * dequant_mf[i_mf][y][6] + f ) >> (-i_qbits);
+            dct[y][7] = ( dct[y][7] * dequant_mf[i_mf][y][7] + f ) >> (-i_qbits);
         }
     }
 }
index bbbed8f365646c8dbd7a983f9a75444cf1448c7e..c545d5cff04b8e3a77a1398c275cf0cd490ea7a0 100644 (file)
@@ -157,6 +157,19 @@ static const int x264_mb_partition_count_table[17] =
     4, 2, 2, 1
 };
 
+static const int x264_zigzag_scan4[16] =
+{
+    0,  1,  4,  8,  5,  2,  3,  6,  9, 12, 13, 10,  7, 11, 14, 15
+};
+static const int x264_zigzag_scan8[64] =
+{
+    0,  1,  8, 16,  9,  2,  3, 10, 17, 24, 32, 25, 18, 11,  4,  5,
+   12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13,  6,  7, 14, 21, 28,
+   35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
+   58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
+};  
+
+
 void x264_macroblock_cache_init( x264_t *h );
 void x264_macroblock_slice_init( x264_t *h );
 void x264_macroblock_cache_load( x264_t *h, int i_mb_x, int i_mb_y );
@@ -165,10 +178,10 @@ void x264_macroblock_cache_end( x264_t *h );
 
 void x264_macroblock_bipred_init( x264_t *h );
 
-void x264_mb_dequant_4x4_dc( int16_t dct[4][4], int i_qscale );
-void x264_mb_dequant_2x2_dc( int16_t dct[2][2], int i_qscale );
-void x264_mb_dequant_4x4( int16_t dct[4][4], int i_qscale );
-void x264_mb_dequant_8x8( int16_t dct[8][8], int i_qscale );
+void x264_mb_dequant_4x4_dc( int16_t dct[4][4], int dequant_mf[6][4][4], int i_qscale );
+void x264_mb_dequant_2x2_dc( int16_t dct[2][2], int dequant_mf[6][4][4], int i_qscale );
+void x264_mb_dequant_4x4( int16_t dct[4][4], int dequant_mf[6][4][4], int i_qscale );
+void x264_mb_dequant_8x8( int16_t dct[8][8], int dequant_mf[6][8][8], int i_qscale );
 
 /* x264_mb_predict_mv_16x16:
  *      set mvp with predicted mv for D_16x16 block
diff --git a/common/set.c b/common/set.c
new file mode 100644 (file)
index 0000000..60bad3a
--- /dev/null
@@ -0,0 +1,107 @@
+/*****************************************************************************
+ * set.c: h264 encoder library
+ *****************************************************************************
+ * Copyright (C) 2005 x264 project
+ *
+ * Authors: Loren Merritt <lorenm@u.washington.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#include "common.h"
+
+static const int dequant4_scale[6][3] =
+{
+    { 10, 13, 16 },
+    { 11, 14, 18 },
+    { 13, 16, 20 },
+    { 14, 18, 23 },
+    { 16, 20, 25 },
+    { 18, 23, 29 }
+};
+static const int quant4_scale[6][3] =
+{
+    { 13107, 8066, 5243 },
+    { 11916, 7490, 4660 },
+    { 10082, 6554, 4194 },
+    {  9362, 5825, 3647 },
+    {  8192, 5243, 3355 },
+    {  7282, 4559, 2893 },
+};
+
+static const int quant8_scan[16] =
+{
+    0,3,4,3, 3,1,5,1, 4,5,2,5, 3,1,5,1
+};
+static const int dequant8_scale[6][6] =
+{
+    { 20, 18, 32, 19, 25, 24 },
+    { 22, 19, 35, 21, 28, 26 },
+    { 26, 23, 42, 24, 33, 31 },
+    { 28, 25, 45, 26, 35, 33 },
+    { 32, 28, 51, 30, 40, 38 },
+    { 36, 32, 58, 34, 46, 43 },
+};
+static const int quant8_scale[6][6] =
+{
+    { 13107, 11428, 20972, 12222, 16777, 15481 },
+    { 11916, 10826, 19174, 11058, 14980, 14290 },
+    { 10082,  8943, 15978,  9675, 12710, 11985 },
+    {  9362,  8228, 14913,  8931, 11984, 11259 },
+    {  8192,  7346, 13159,  7740, 10486,  9777 },
+    {  7282,  6428, 11570,  6830,  9118,  8640 }
+};
+
+void x264_cqm_init( x264_t *h )
+{
+    int def_quant4[6][16];
+    int def_quant8[6][64];
+    int def_dequant4[6][16];
+    int def_dequant8[6][64];
+    int q, i, i_list;
+
+    for( q = 0; q < 6; q++ )
+    {
+        for( i = 0; i < 16; i++ )
+        {
+            int j = (i&1) + ((i>>2)&1);
+            def_dequant4[q][i] = dequant4_scale[q][j];
+            def_quant4[q][i]   =   quant4_scale[q][j];
+        }
+        for( i = 0; i < 64; i++ )
+        {
+            int j = quant8_scan[((i>>1)&12) | (i&3)];
+            def_dequant8[q][i] = dequant8_scale[q][j];
+            def_quant8[q][i]   =   quant8_scale[q][j];
+        }
+    }
+
+    for( q = 0; q < 6; q++ )
+    {
+        for( i_list = 0; i_list < 4; i_list++ )
+            for( i = 0; i < 16; i++ )
+            {
+                h->dequant4_mf[i_list][q][0][i] = def_dequant4[q][i] * h->pps->scaling_list[i_list][i];
+                h->  quant4_mf[i_list][q][0][i] = def_quant4[q][i] * 16 / h->pps->scaling_list[i_list][i];
+            }
+        for( i_list = 0; i_list < 2; i_list++ )
+            for( i = 0; i < 64; i++ )
+            {
+                h->dequant8_mf[i_list][q][0][i] = def_dequant8[q][i] * h->pps->scaling_list[4+i_list][i];
+                h->  quant8_mf[i_list][q][0][i] = def_quant8[q][i] * 16 / h->pps->scaling_list[4+i_list][i];
+            }
+    }
+}
+
index b29a00dd88b1ee6ff72a15b7064f37b5e72a01ec..3f588fccf65c9321b6821dd43ed3a2d856ba1c02 100644 (file)
@@ -35,6 +35,19 @@ enum profile_e
     PROFILE_HIGH444 = 144
 };
 
+enum cqm4_e
+{
+    CQM_4IY = 0,
+    CQM_4PY = 1,
+    CQM_4IC = 2,
+    CQM_4PC = 3
+};
+enum cqm8_e
+{
+    CQM_8IY = 0,
+    CQM_8PY = 1
+};
+
 typedef struct
 {
     int i_id;
@@ -147,6 +160,60 @@ typedef struct
 
     int b_transform_8x8_mode;
 
+    int i_cqm_preset;
+    const uint8_t *scaling_list[6]; /* could be 8, but we don't allow separate Cb/Cr lists */
+
 } x264_pps_t;
 
+/* default quant matrices */
+static const uint8_t x264_cqm_jvt4i[16] =
+{
+      6,13,20,28,
+     13,20,28,32,
+     20,28,32,37,
+     28,32,37,42
+};
+static const uint8_t x264_cqm_jvt4p[16] =
+{
+    10,14,20,24,
+    14,20,24,27,
+    20,24,27,30,
+    24,27,30,34
+};
+static const uint8_t x264_cqm_jvt8i[64] =
+{
+     6,10,13,16,18,23,25,27,
+    10,11,16,18,23,25,27,29,
+    13,16,18,23,25,27,29,31,
+    16,18,23,25,27,29,31,33,
+    18,23,25,27,29,31,33,36,
+    23,25,27,29,31,33,36,38,
+    25,27,29,31,33,36,38,40,
+    27,29,31,33,36,38,40,42
+};
+static const uint8_t x264_cqm_jvt8p[64] =
+{
+     9,13,15,17,19,21,22,24,
+    13,13,17,19,21,22,24,25,
+    15,17,19,21,22,24,25,27,
+    17,19,21,22,24,25,27,28,
+    19,21,22,24,25,27,28,30,
+    21,22,24,25,27,28,30,32,
+    22,24,25,27,28,30,32,33,
+    24,25,27,28,30,32,33,35
+};
+static const uint8_t x264_cqm_flat16[64] =
+{
+    16,16,16,16,16,16,16,16,
+    16,16,16,16,16,16,16,16,
+    16,16,16,16,16,16,16,16,
+    16,16,16,16,16,16,16,16,
+    16,16,16,16,16,16,16,16,
+    16,16,16,16,16,16,16,16,
+    16,16,16,16,16,16,16,16,
+    16,16,16,16,16,16,16,16
+};
+
+void x264_cqm_init( x264_t *h );
+
 #endif
index 79857cc770e1515797e48780cc12b62192ab2361..32c5072c74847db6564c5d262cf98b060a1cdb64 100644 (file)
@@ -387,6 +387,7 @@ static int x264_validate_parameters( x264_t *h )
     {
         h->mb.b_lossless = 1;
         h->param.analyse.b_transform_8x8 = 0;
+        h->param.i_cqm_preset = X264_CQM_FLAT;
         h->param.rc.f_ip_factor = 1;
         h->param.rc.f_pb_factor = 1;
         h->param.analyse.b_psnr = 0;
@@ -414,6 +415,9 @@ static int x264_validate_parameters( x264_t *h )
     if( h->param.i_threads > 1 && h->param.i_cabac_init_idc == -1 )
         h->param.i_cabac_init_idc = 0;
 
+    if( h->param.i_cqm_preset < X264_CQM_FLAT || h->param.i_cqm_preset > X264_CQM_CUSTOM )
+        h->param.i_cqm_preset = X264_CQM_FLAT;
+
     if( h->param.analyse.i_me_method < X264_ME_DIA ||
         h->param.analyse.i_me_method > X264_ME_ESA )
         h->param.analyse.i_me_method = X264_ME_HEX;
@@ -523,6 +527,8 @@ x264_t *x264_encoder_open   ( x264_param_t *param )
 
     h->pps = &h->pps_array[0];
     x264_pps_init( h->pps, 0, &h->param, h->sps);
+
+    x264_cqm_init( h );
     
     h->mb.i_mb_count = h->sps->i_mb_width * h->sps->i_mb_height;
 
index 40f53974fe90d31d9e070d0c2430bbdca9c26b1c..650c414d46eb6c1ec57f290864374e556d541071 100644 (file)
@@ -45,7 +45,10 @@ static const uint8_t block_idx_xy[4][4] =
     { 5, 7, 13, 15 }
 };
 
-static const int quant_mf[6][4][4] =
+/* def_quant4_mf only for probe_skip; actual encoding uses matrices from set.c */
+/* FIXME this seems to make better decisions with cqm=jvt, but could screw up
+ * with general custom matrices. */
+static const int def_quant4_mf[6][4][4] =
 {
     { { 13107, 8066, 13107, 8066 }, { 8066, 5243, 8066, 5243 },
       { 13107, 8066, 13107, 8066 }, { 8066, 5243, 8066, 5243 } },
@@ -61,65 +64,6 @@ static const int quant_mf[6][4][4] =
       {  7282, 4559,  7282, 4559 }, { 4559, 2893, 4559, 2893 } }
 };
 
-const int quant8_mf[6][8][8] =
-{
-  {
-    { 13107, 12222, 16777, 12222, 13107, 12222, 16777, 12222 },
-    { 12222, 11428, 15481, 11428, 12222, 11428, 15481, 11428 },
-    { 16777, 15481, 20972, 15481, 16777, 15481, 20972, 15481 },
-    { 12222, 11428, 15481, 11428, 12222, 11428, 15481, 11428 },
-    { 13107, 12222, 16777, 12222, 13107, 12222, 16777, 12222 },
-    { 12222, 11428, 15481, 11428, 12222, 11428, 15481, 11428 },
-    { 16777, 15481, 20972, 15481, 16777, 15481, 20972, 15481 },
-    { 12222, 11428, 15481, 11428, 12222, 11428, 15481, 11428 }
-  }, {
-    { 11916, 11058, 14980, 11058, 11916, 11058, 14980, 11058 },
-    { 11058, 10826, 14290, 10826, 11058, 10826, 14290, 10826 },
-    { 14980, 14290, 19174, 14290, 14980, 14290, 19174, 14290 },
-    { 11058, 10826, 14290, 10826, 11058, 10826, 14290, 10826 },
-    { 11916, 11058, 14980, 11058, 11916, 11058, 14980, 11058 },
-    { 11058, 10826, 14290, 10826, 11058, 10826, 14290, 10826 },
-    { 14980, 14290, 19174, 14290, 14980, 14290, 19174, 14290 },
-    { 11058, 10826, 14290, 10826, 11058, 10826, 14290, 10826 }
-  }, {
-    { 10082,  9675, 12710,  9675, 10082,  9675, 12710,  9675 },
-    {  9675,  8943, 11985,  8943,  9675,  8943, 11985,  8943 },
-    { 12710, 11985, 15978, 11985, 12710, 11985, 15978, 11985 },
-    {  9675,  8943, 11985,  8943,  9675,  8943, 11985,  8943 },
-    { 10082,  9675, 12710,  9675, 10082,  9675, 12710,  9675 },
-    {  9675,  8943, 11985,  8943,  9675,  8943, 11985,  8943 },
-    { 12710, 11985, 15978, 11985, 12710, 11985, 15978, 11985 },
-    {  9675,  8943, 11985,  8943,  9675,  8943, 11985,  8943 }
-  }, {
-    {  9362,  8931, 11984,  8931,  9362,  8931, 11984,  8931 },
-    {  8931,  8228, 11259,  8228,  8931,  8228, 11259,  8228 },
-    { 11984, 11259, 14913, 11259, 11984, 11259, 14913, 11259 },
-    {  8931,  8228, 11259,  8228,  8931,  8228, 11259,  8228 },
-    {  9362,  8931, 11984,  8931,  9362,  8931, 11984,  8931 },
-    {  8931,  8228, 11259,  8228,  8931,  8228, 11259,  8228 },
-    { 11984, 11259, 14913, 11259, 11984, 11259, 14913, 11259 },
-    {  8931,  8228, 11259,  8228,  8931,  8228, 11259,  8228 }
-  }, {
-    {  8192,  7740, 10486,  7740,  8192,  7740, 10486,  7740 },
-    {  7740,  7346,  9777,  7346,  7740,  7346,  9777,  7346 },
-    { 10486,  9777, 13159,  9777, 10486,  9777, 13159,  9777 },
-    {  7740,  7346,  9777,  7346,  7740,  7346,  9777,  7346 },
-    {  8192,  7740, 10486,  7740,  8192,  7740, 10486,  7740 },
-    {  7740,  7346,  9777,  7346,  7740,  7346,  9777,  7346 },
-    { 10486,  9777, 13159,  9777, 10486,  9777, 13159,  9777 },
-    {  7740,  7346,  9777,  7346,  7740,  7346,  9777,  7346 }
-  }, {
-    {  7282,  6830,  9118,  6830,  7282,  6830,  9118,  6830 },
-    {  6830,  6428,  8640,  6428,  6830,  6428,  8640,  6428 },
-    {  9118,  8640, 11570,  8640,  9118,  8640, 11570,  8640 },
-    {  6830,  6428,  8640,  6428,  6830,  6428,  8640,  6428 },
-    {  7282,  6830,  9118,  6830,  7282,  6830,  9118,  6830 },
-    {  6830,  6428,  8640,  6428,  6830,  6428,  8640,  6428 },
-    {  9118,  8640, 11570,  8640,  9118,  8640, 11570,  8640 },
-    {  6830,  6428,  8640,  6428,  6830,  6428,  8640,  6428 }
-  }
-};
-
 static const int i_chroma_qp_table[52] =
 {
      0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
@@ -200,7 +144,7 @@ static inline void sub_zigzag_4x4( int level[15], const uint8_t *p_src, uint8_t
 }
 #undef ZIG
 
-static void quant_8x8( int16_t dct[8][8], int i_qscale, int b_intra )
+static void quant_8x8( int16_t dct[8][8], int quant_mf[6][8][8], int i_qscale, int b_intra )
 {
     const int i_qbits = 16 + i_qscale / 6;
     const int i_mf = i_qscale % 6;
@@ -212,13 +156,13 @@ static void quant_8x8( int16_t dct[8][8], int i_qscale, int b_intra )
         for( x = 0; x < 8; x++ )
         {
             if( dct[y][x] > 0 )
-                dct[y][x] = ( f + dct[y][x] * quant8_mf[i_mf][y][x] ) >> i_qbits;
+                dct[y][x] = ( f + dct[y][x] * quant_mf[i_mf][y][x] ) >> i_qbits;
             else
-                dct[y][x] = - ( ( f - dct[y][x] * quant8_mf[i_mf][y][x] ) >> i_qbits );
+                dct[y][x] = - ( ( f - dct[y][x] * quant_mf[i_mf][y][x] ) >> i_qbits );
         }
     }
 }
-static void quant_4x4( int16_t dct[4][4], int i_qscale, int b_intra )
+static void quant_4x4( int16_t dct[4][4], int quant_mf[6][4][4], int i_qscale, int b_intra )
 {
     const int i_qbits = 15 + i_qscale / 6;
     const int i_mf = i_qscale % 6;
@@ -236,7 +180,7 @@ static void quant_4x4( int16_t dct[4][4], int i_qscale, int b_intra )
         }
     }
 }
-static void quant_4x4_dc( int16_t dct[4][4], int i_qscale )
+static void quant_4x4_dc( int16_t dct[4][4], int quant_mf[6][4][4], int i_qscale )
 {
     const int i_qbits = 15 + i_qscale / 6;
     const int f2 = ( 2 << i_qbits ) / 3;
@@ -254,7 +198,7 @@ static void quant_4x4_dc( int16_t dct[4][4], int i_qscale )
         }
     }
 }
-static void quant_2x2_dc( int16_t dct[2][2], int i_qscale, int b_intra )
+static void quant_2x2_dc( int16_t dct[2][2], int quant_mf[6][4][4], int i_qscale, int b_intra )
 {
     int const i_qbits = 15 + i_qscale / 6;
     const int f2 = ( 2 << i_qbits ) / ( b_intra ? 3 : 6 );
@@ -433,9 +377,9 @@ void x264_mb_encode_i4x4( x264_t *h, int idx, int i_qscale )
     }
 
     h->dctf.sub4x4_dct( dct4x4, p_src, i_stride, p_dst, i_stride );
-    quant_4x4( dct4x4, i_qscale, 1 );
+    quant_4x4( dct4x4, h->quant4_mf[CQM_4IY], i_qscale, 1 );
     scan_zigzag_4x4full( h->dct.block[idx].luma4x4, dct4x4 );
-    x264_mb_dequant_4x4( dct4x4, i_qscale );
+    x264_mb_dequant_4x4( dct4x4, h->dequant4_mf[CQM_4IY], i_qscale );
 
     /* output samples to fdec */
     h->dctf.add4x4_idct( p_dst, i_stride, dct4x4 );
@@ -450,9 +394,9 @@ void x264_mb_encode_i8x8( x264_t *h, int idx, int i_qscale )
     int16_t dct8x8[8][8];
 
     h->dctf.sub8x8_dct8( dct8x8, p_src, i_stride, p_dst, i_stride );
-    quant_8x8( dct8x8, i_qscale, 1 );
+    quant_8x8( dct8x8, h->quant8_mf[CQM_8IY], i_qscale, 1 );
     scan_zigzag_8x8full( h->dct.luma8x8[idx], dct8x8 );
-    x264_mb_dequant_8x8( dct8x8, i_qscale );
+    x264_mb_dequant_8x8( dct8x8, h->dequant8_mf[CQM_8IY], i_qscale );
     h->dctf.add8x8_idct8( p_dst, i_stride, dct8x8 );
 }
 
@@ -486,18 +430,18 @@ static void x264_mb_encode_i16x16( x264_t *h, int i_qscale )
         dct4x4[0][block_idx_y[i]][block_idx_x[i]] = dct4x4[1+i][0][0];
 
         /* quant/scan/dequant */
-        quant_4x4( dct4x4[1+i], i_qscale, 1 );
+        quant_4x4( dct4x4[1+i], h->quant4_mf[CQM_4IY], i_qscale, 1 );
         scan_zigzag_4x4( h->dct.block[i].residual_ac, dct4x4[1+i] );
-        x264_mb_dequant_4x4( dct4x4[1+i], i_qscale );
+        x264_mb_dequant_4x4( dct4x4[1+i], h->dequant4_mf[CQM_4IY], i_qscale );
     }
 
     h->dctf.dct4x4dc( dct4x4[0] );
-    quant_4x4_dc( dct4x4[0], i_qscale );
+    quant_4x4_dc( dct4x4[0], h->quant4_mf[CQM_4IY], i_qscale );
     scan_zigzag_4x4full( h->dct.luma16x16_dc, dct4x4[0] );
 
     /* output samples to fdec */
     h->dctf.idct4x4dc( dct4x4[0] );
-    x264_mb_dequant_4x4_dc( dct4x4[0], i_qscale );  /* XXX not inversed */
+    x264_mb_dequant_4x4_dc( dct4x4[0], h->dequant4_mf[CQM_4IY], i_qscale );  /* XXX not inversed */
 
     /* calculate dct coeffs */
     for( i = 0; i < 16; i++ )
@@ -542,9 +486,9 @@ static void x264_mb_encode_8x8_chroma( x264_t *h, int b_inter, int i_qscale )
             /* copy dc coeff */
             dct2x2[block_idx_y[i]][block_idx_x[i]] = dct4x4[i][0][0];
 
-            quant_4x4( dct4x4[i], i_qscale, b_inter ? 0 : 1 );
+            quant_4x4( dct4x4[i], h->quant4_mf[CQM_4IC + b_inter], i_qscale, b_inter ? 0 : 1 );
             scan_zigzag_4x4( h->dct.block[16+i+ch*4].residual_ac, dct4x4[i] );
-            x264_mb_dequant_4x4( dct4x4[i], i_qscale );
+            x264_mb_dequant_4x4( dct4x4[i], h->dequant4_mf[CQM_4IC + b_inter], i_qscale );
 
             if( b_inter )
             {
@@ -553,12 +497,12 @@ static void x264_mb_encode_8x8_chroma( x264_t *h, int b_inter, int i_qscale )
         }
 
         h->dctf.dct2x2dc( dct2x2 );
-        quant_2x2_dc( dct2x2, i_qscale, b_inter ? 0 : 1 );
+        quant_2x2_dc( dct2x2, h->quant4_mf[CQM_4IC + b_inter], i_qscale, b_inter ? 0 : 1 );
         scan_zigzag_2x2_dc( h->dct.chroma_dc[ch], dct2x2 );
 
         /* output samples to fdec */
         h->dctf.idct2x2dc( dct2x2 );
-        x264_mb_dequant_2x2_dc( dct2x2, i_qscale );  /* XXX not inversed */
+        x264_mb_dequant_2x2_dc( dct2x2, h->dequant4_mf[CQM_4IC + b_inter], i_qscale );  /* XXX not inversed */
 
         if( b_inter && i_decimate_score < 7 )
         {
@@ -724,9 +668,9 @@ void x264_macroblock_encode( x264_t *h )
             {
                 int i_decimate_8x8;
 
-                quant_8x8( dct8x8[idx], i_qp, 0 );
+                quant_8x8( dct8x8[idx], h->quant8_mf[CQM_8PY], i_qp, 0 );
                 scan_zigzag_8x8full( h->dct.luma8x8[idx], dct8x8[idx] );
-                x264_mb_dequant_8x8( dct8x8[idx], i_qp );
+                x264_mb_dequant_8x8( dct8x8[idx], h->dequant8_mf[CQM_8PY], i_qp );
 
                 i_decimate_8x8 = x264_mb_decimate_score( h->dct.luma8x8[idx], 64 );
                 i_decimate_mb += i_decimate_8x8;
@@ -759,9 +703,9 @@ void x264_macroblock_encode( x264_t *h )
                 {
                     idx = i8x8 * 4 + i4x4;
 
-                    quant_4x4( dct4x4[idx], i_qp, 0 );
+                    quant_4x4( dct4x4[idx], h->quant4_mf[CQM_4PY], i_qp, 0 );
                     scan_zigzag_4x4full( h->dct.block[idx].luma4x4, dct4x4[idx] );
-                    x264_mb_dequant_4x4( dct4x4[idx], i_qp );
+                    x264_mb_dequant_4x4( dct4x4[idx], h->dequant4_mf[CQM_4PY], i_qp );
 
                     i_decimate_8x8 += x264_mb_decimate_score( h->dct.block[idx].luma4x4, 16 );
                 }
@@ -955,7 +899,7 @@ int x264_macroblock_probe_skip( x264_t *h, int b_bidir )
         {
             const int idx = i8x8 * 4 + i4x4;
 
-            quant_4x4( dct4x4[idx], i_qp, 0 );
+            quant_4x4( dct4x4[idx], (int(*)[4][4])def_quant4_mf, i_qp, 0 );
             scan_zigzag_4x4full( dctscan, dct4x4[idx] );
 
             i_decimate_mb += x264_mb_decimate_score( dctscan, 16 );
@@ -992,7 +936,7 @@ int x264_macroblock_probe_skip( x264_t *h, int b_bidir )
         dct2x2[1][0] = dct4x4[2][0][0];
         dct2x2[1][1] = dct4x4[3][0][0];
         h->dctf.dct2x2dc( dct2x2 );
-        quant_2x2_dc( dct2x2, i_qp, 0 );
+        quant_2x2_dc( dct2x2, (int(*)[4][4])def_quant4_mf, i_qp, 0 );
         if( dct2x2[0][0] || dct2x2[0][1] || dct2x2[1][0] || dct2x2[1][1]  )
         {
             /* can't be */
@@ -1002,7 +946,7 @@ int x264_macroblock_probe_skip( x264_t *h, int b_bidir )
         /* calculate dct coeffs */
         for( i4x4 = 0, i_decimate_mb = 0; i4x4 < 4; i4x4++ )
         {
-            quant_4x4( dct4x4[i4x4], i_qp, 0 );
+            quant_4x4( dct4x4[i4x4], (int(*)[4][4])def_quant4_mf, i_qp, 0 );
             scan_zigzag_4x4( dctscan, dct4x4[i4x4] );
 
             i_decimate_mb += x264_mb_decimate_score( dctscan, 15 );
index 0471edb7c03add942d80972b87fc9d0bc842e3d0..212bdb013717f61f953377fa59a70ac639a32cd6 100644 (file)
 
 #include "x264.h"
 #include "common/common.h"
+#include "common/macroblock.h"
 #ifndef _MSC_VER
 #include "config.h"
 #endif
 
+static const uint8_t *const x264_cqm_jvt[6] =
+{
+    x264_cqm_jvt4i, x264_cqm_jvt4p,
+    x264_cqm_jvt4i, x264_cqm_jvt4p,
+    x264_cqm_jvt8i, x264_cqm_jvt8p
+};
+
+static void scaling_list_write( bs_t *s, x264_pps_t *pps, int idx )
+{
+    const int len = idx<4 ? 16 : 64;
+    const int *zigzag = idx<4 ? x264_zigzag_scan4 : x264_zigzag_scan8;
+    const uint8_t *list = pps->scaling_list[idx];
+    const uint8_t *def_list = (idx==CQM_4IC) ? pps->scaling_list[CQM_4IY]
+                            : (idx==CQM_4PC) ? pps->scaling_list[CQM_4PY]
+                            : x264_cqm_jvt[idx];
+    int j;
+    if( memcmp( list, def_list, len ) )
+    {
+        bs_write( s, 1, 1 ); // scaling_list_present_flag
+        for( j = 0; j < len; j++ )
+            bs_write_se( s, list[zigzag[j]] - (j>0 ? list[zigzag[j-1]] : 8) ); // delta
+    }
+    else
+        bs_write( s, 1, 0 ); // scaling_list_present_flag
+}
+
 void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
 {
     sps->i_id = i_id;
@@ -45,7 +72,7 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
     sps->b_qpprime_y_zero_transform_bypass = !param->rc.b_cbr && param->rc.i_qp_constant == 0;
     if( sps->b_qpprime_y_zero_transform_bypass )
         sps->i_profile_idc  = PROFILE_HIGH444;
-    else if( param->analyse.b_transform_8x8 )
+    else if( param->analyse.b_transform_8x8 || param->i_cqm_preset != X264_CQM_FLAT )
         sps->i_profile_idc  = PROFILE_HIGH;
     else if( param->b_cabac || param->i_bframe > 0 )
         sps->i_profile_idc  = PROFILE_MAIN;
@@ -286,6 +313,8 @@ void x264_sps_write( bs_t *s, x264_sps_t *sps )
 
 void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t *sps )
 {
+    int i, j;
+
     pps->i_id = i_id;
     pps->i_sps_id = sps->i_id;
     pps->b_cabac = param->b_cabac;
@@ -296,8 +325,6 @@ void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t *
 #if 0
     if( pps->i_num_slice_groups > 1 )
     {
-        int i;
-
         pps->i_slice_group_map_type = 0;
         if( pps->i_slice_group_map_type == 0 )
         {
@@ -345,6 +372,31 @@ void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t *
     pps->b_redundant_pic_cnt = 0;
 
     pps->b_transform_8x8_mode = param->analyse.b_transform_8x8 ? 1 : 0;
+
+    pps->i_cqm_preset = param->i_cqm_preset;
+    switch( pps->i_cqm_preset )
+    {
+    case X264_CQM_FLAT:
+        for( i = 0; i < 6; i++ )
+            pps->scaling_list[i] = x264_cqm_flat16;
+        break;
+    case X264_CQM_JVT:
+        for( i = 0; i < 6; i++ )
+            pps->scaling_list[i] = x264_cqm_jvt[i];
+        break;
+    case X264_CQM_CUSTOM:
+        pps->scaling_list[CQM_4IY] = param->cqm_4iy;
+        pps->scaling_list[CQM_4IC] = param->cqm_4ic;
+        pps->scaling_list[CQM_4PY] = param->cqm_4py;
+        pps->scaling_list[CQM_4PC] = param->cqm_4pc;
+        pps->scaling_list[CQM_8IY+4] = param->cqm_8iy;
+        pps->scaling_list[CQM_8PY+4] = param->cqm_8py;
+        for( i = 0; i < 6; i++ )
+            for( j = 0; j < (i<4?16:64); j++ )
+                if( pps->scaling_list[i][j] == 0 )
+                    pps->scaling_list[i] = x264_cqm_jvt[i];
+        break;
+    }
 }
 
 void x264_pps_write( bs_t *s, x264_pps_t *pps )
@@ -410,11 +462,25 @@ void x264_pps_write( bs_t *s, x264_pps_t *pps )
     bs_write( s, 1, pps->b_constrained_intra_pred );
     bs_write( s, 1, pps->b_redundant_pic_cnt );
 
-    if( pps->b_transform_8x8_mode )
+    if( pps->b_transform_8x8_mode || pps->i_cqm_preset != X264_CQM_FLAT )
     {
         bs_write( s, 1, pps->b_transform_8x8_mode );
-        bs_write( s, 1, 0 ); // pic_scaling_matrix_present_flag
-        bs_write_se( s, 0 ); // second_chroma_qp_index_offset
+        bs_write( s, 1, (pps->i_cqm_preset != X264_CQM_FLAT) );
+        if( pps->i_cqm_preset != X264_CQM_FLAT )
+        {
+            scaling_list_write( s, pps, CQM_4IY );
+            scaling_list_write( s, pps, CQM_4IC );
+            bs_write( s, 1, 0 ); // Cr = Cb
+            scaling_list_write( s, pps, CQM_4PY );
+            scaling_list_write( s, pps, CQM_4PC );
+            bs_write( s, 1, 0 ); // Cr = Cb
+            if( pps->b_transform_8x8_mode )
+            {
+                scaling_list_write( s, pps, CQM_8IY+4 );
+                scaling_list_write( s, pps, CQM_8PY+4 );
+            }
+        }
+        bs_write_se( s, pps->i_chroma_qp_index_offset );
     }
 
     bs_rbsp_trailing( s );
diff --git a/x264.c b/x264.c
index 2d261868e26b1e401faf020f2340f1f8baeaa309..f81eb188f07c5440321d77340e73128acf63e45f 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -232,6 +232,17 @@ static void Help( x264_param_t *defaults )
              "      --no-chroma-me          Ignore chroma in motion estimation\n"
              "  -8, --8x8dct                Adaptive spatial transform size\n"
              "\n"
+             "      --cqm <string>          Preset quant matrices [\"flat\"]\n"
+             "                                  - jvt, flat\n"
+             "      --cqm4 <list>           Set all 4x4 quant matrices\n"
+             "                                  Takes a comma-separated list of 16 integers.\n"
+             "      --cqm8 <list>           Set all 8x8 quant matrices\n"
+             "                                  Takes a comma-separated list of 64 integers.\n"
+             "      --cqm4i, --cqm4p, --cqm8i, --cqm8p\n"
+             "                              Set both luma and chroma quant matrices\n"
+             "      --cqm4iy, --cqm4ic, --cqm4py, --cqm4pc\n"
+             "                              Set individual quant matrices\n"
+             "\n"
              "Input/Output:\n"
              "\n"
              "      --level <integer>       Specify level (as defined by Annex A)\n"
@@ -294,6 +305,18 @@ static void Help( x264_param_t *defaults )
            );
 }
 
+static int parse_cqm( const char *str, uint8_t *cqm, int length )
+{
+    int i = 0;
+    do {
+        int coef;
+        if( !sscanf( str, "%d", &coef ) || coef < 1 || coef > 255 )
+            return -1;
+        cqm[i++] = coef;
+    } while( i < length && (str = strchr( str, ',' )) && str++ );
+    return (i == length) ? 0 : -1;
+}
+
 /*****************************************************************************
  * Parse:
  *****************************************************************************/
@@ -324,6 +347,7 @@ static int  Parse( int argc, char **argv,
     opterr = 0; // no error message
     for( ;; )
     {
+        int b_error = 0;
         int long_options_index;
 #define OPT_QPMIN 256
 #define OPT_QPMAX 257
@@ -360,6 +384,17 @@ static int  Parse( int argc, char **argv,
 #define OPT_SEEK 291
 #define OPT_ZONES 292
 #define OPT_THREADS 293
+#define OPT_CQM 294
+#define OPT_CQM4 295
+#define OPT_CQM4I 296
+#define OPT_CQM4IY 297
+#define OPT_CQM4IC 298
+#define OPT_CQM4P 299
+#define OPT_CQM4PY 300
+#define OPT_CQM4PC 301
+#define OPT_CQM8 302
+#define OPT_CQM8I 303
+#define OPT_CQM8P 304
 
         static struct option long_options[] =
         {
@@ -416,6 +451,17 @@ static int  Parse( int argc, char **argv,
             { "progress",no_argument,       NULL, OPT_PROGRESS },
             { "visualize",no_argument,      NULL, OPT_VISUALIZE },
             { "aud",     no_argument,       NULL, OPT_AUD },
+            { "cqm",     required_argument, NULL, OPT_CQM },
+            { "cqm4",    required_argument, NULL, OPT_CQM4 },
+            { "cqm4i",   required_argument, NULL, OPT_CQM4I },
+            { "cqm4iy",  required_argument, NULL, OPT_CQM4IY },
+            { "cqm4ic",  required_argument, NULL, OPT_CQM4IC },
+            { "cqm4p",   required_argument, NULL, OPT_CQM4P },
+            { "cqm4py",  required_argument, NULL, OPT_CQM4PY },
+            { "cqm4pc",  required_argument, NULL, OPT_CQM4PC },
+            { "cqm8",    required_argument, NULL, OPT_CQM8 },
+            { "cqm8i",   required_argument, NULL, OPT_CQM8I },
+            { "cqm8p",   required_argument, NULL, OPT_CQM8P },
             {0, 0, 0, 0}
         };
 
@@ -680,10 +726,73 @@ static int  Parse( int argc, char **argv,
                 fprintf( stderr, "not compiled with visualization support\n" );
 #endif
                 break;
+            case OPT_CQM:
+                if( strstr( optarg, "flat" ) )
+                    param->i_cqm_preset = X264_CQM_FLAT;
+                else if( strstr( optarg, "jvt" ) )
+                    param->i_cqm_preset = X264_CQM_JVT;
+                else
+                {
+                    fprintf( stderr, "bad CQM preset `%s'\n", optarg );
+                    return -1;
+                }
+                break;
+            case OPT_CQM4:
+                param->i_cqm_preset = X264_CQM_CUSTOM;
+                b_error |= parse_cqm( optarg, param->cqm_4iy, 16 );
+                b_error |= parse_cqm( optarg, param->cqm_4ic, 16 );
+                b_error |= parse_cqm( optarg, param->cqm_4py, 16 );
+                b_error |= parse_cqm( optarg, param->cqm_4pc, 16 );
+                break;
+            case OPT_CQM8:
+                param->i_cqm_preset = X264_CQM_CUSTOM;
+                b_error |= parse_cqm( optarg, param->cqm_8iy, 64 );
+                b_error |= parse_cqm( optarg, param->cqm_8py, 64 );
+                break;
+            case OPT_CQM4I:
+                param->i_cqm_preset = X264_CQM_CUSTOM;
+                b_error |= parse_cqm( optarg, param->cqm_4iy, 16 );
+                b_error |= parse_cqm( optarg, param->cqm_4ic, 16 );
+                break;
+            case OPT_CQM4P:
+                param->i_cqm_preset = X264_CQM_CUSTOM;
+                b_error |= parse_cqm( optarg, param->cqm_4py, 16 );
+                b_error |= parse_cqm( optarg, param->cqm_4pc, 16 );
+                break;
+            case OPT_CQM4IY:
+                param->i_cqm_preset = X264_CQM_CUSTOM;
+                b_error |= parse_cqm( optarg, param->cqm_4iy, 16 );
+                break;
+            case OPT_CQM4IC:
+                param->i_cqm_preset = X264_CQM_CUSTOM;
+                b_error |= parse_cqm( optarg, param->cqm_4ic, 16 );
+                break;
+            case OPT_CQM4PY:
+                param->i_cqm_preset = X264_CQM_CUSTOM;
+                b_error |= parse_cqm( optarg, param->cqm_4iy, 16 );
+                break;
+            case OPT_CQM4PC:
+                param->i_cqm_preset = X264_CQM_CUSTOM;
+                b_error |= parse_cqm( optarg, param->cqm_4ic, 16 );
+                break;
+            case OPT_CQM8I:
+                param->i_cqm_preset = X264_CQM_CUSTOM;
+                b_error |= parse_cqm( optarg, param->cqm_8iy, 64 );
+                break;
+            case OPT_CQM8P:
+                param->i_cqm_preset = X264_CQM_CUSTOM;
+                b_error |= parse_cqm( optarg, param->cqm_8py, 64 );
+                break;
             default:
                 fprintf( stderr, "unknown option (%c)\n", optopt );
                 return -1;
         }
+
+        if( b_error )
+        {
+            fprintf( stderr, "bad argument (%s)\n", optarg );
+            return -1;
+        }
     }
 
     /* Get the file name */
diff --git a/x264.h b/x264.h
index bde985c538545cb088868c634732754689723bec..e3eedf3b5641336e9a8a1d33326bd7cf8a98692e 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -59,6 +59,9 @@ typedef struct x264_t x264_t;
 #define X264_ME_HEX                  1
 #define X264_ME_UMH                  2
 #define X264_ME_ESA                  3
+#define X264_CQM_FLAT                0
+#define X264_CQM_JVT                 1
+#define X264_CQM_CUSTOM              2
 
 /* Colorspace type
  */
@@ -140,6 +143,13 @@ typedef struct
     int         b_cabac;
     int         i_cabac_init_idc;
 
+    int         i_cqm_preset;
+    int8_t      cqm_4iy[16];        /* used only if i_cqm_preset == X264_CQM_CUSTOM */
+    int8_t      cqm_4ic[16];
+    int8_t      cqm_4py[16];
+    int8_t      cqm_4pc[16];
+    int8_t      cqm_8iy[64];
+    int8_t      cqm_8py[64];
 
     /* Log */
     void        (*pf_log)( void *, int i_level, const char *psz, va_list );