video-matrices.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /******************************************************************************
  2. Copyright (C) 2014 by Ruwen Hahn <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include "../util/bmem.h"
  15. #include "video-io.h"
  16. //#define COMPUTE_MATRICES
  17. #ifdef COMPUTE_MATRICES
  18. #include "../graphics/matrix3.h"
  19. #endif
  20. static struct {
  21. enum video_colorspace const color_space;
  22. float const Kb, Kr;
  23. int const range_min[3];
  24. int const range_max[3];
  25. int const black_levels[2][3];
  26. float float_range_min[3];
  27. float float_range_max[3];
  28. float matrix[2][16];
  29. } format_info[] = {
  30. {VIDEO_CS_601,
  31. 0.114f,
  32. 0.299f,
  33. {16, 16, 16},
  34. {235, 240, 240},
  35. {{16, 128, 128}, {0, 128, 128}},
  36. #ifndef COMPUTE_MATRICES
  37. {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f},
  38. {235.0f / 255.0f, 240.0f / 255.0f, 240.0f / 255.0f},
  39. {{1.164384f, 0.000000f, 1.596027f, -0.874202f, 1.164384f, -0.391762f,
  40. -0.812968f, 0.531668f, 1.164384f, 2.017232f, 0.000000f, -1.085631f,
  41. 0.000000f, 0.000000f, 0.000000f, 1.000000f},
  42. {1.000000f, 0.000000f, 1.407520f, -0.706520f, 1.000000f, -0.345491f,
  43. -0.716948f, 0.533303f, 1.000000f, 1.778976f, 0.000000f, -0.892976f,
  44. 0.000000f, 0.000000f, 0.000000f, 1.000000f}}
  45. #endif
  46. },
  47. {VIDEO_CS_709,
  48. 0.0722f,
  49. 0.2126f,
  50. {16, 16, 16},
  51. {235, 240, 240},
  52. {{16, 128, 128}, {0, 128, 128}},
  53. #ifndef COMPUTE_MATRICES
  54. {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f},
  55. {235.0f / 255.0f, 240.0f / 255.0f, 240.0f / 255.0f},
  56. {{1.164384f, 0.000000f, 1.792741f, -0.972945f, 1.164384f, -0.213249f,
  57. -0.532909f, 0.301483f, 1.164384f, 2.112402f, 0.000000f, -1.133402f,
  58. 0.000000f, 0.000000f, 0.000000f, 1.000000f},
  59. {1.000000f, 0.000000f, 1.581000f, -0.793600f, 1.000000f, -0.188062f,
  60. -0.469967f, 0.330305f, 1.000000f, 1.862906f, 0.000000f, -0.935106f,
  61. 0.000000f, 0.000000f, 0.000000f, 1.000000f}}
  62. #endif
  63. },
  64. };
  65. #define NUM_FORMATS (sizeof(format_info) / sizeof(format_info[0]))
  66. #ifdef COMPUTE_MATRICES
  67. static void log_matrix(float const matrix[16])
  68. {
  69. blog(LOG_DEBUG,
  70. "\n% f, % f, % f, % f"
  71. "\n% f, % f, % f, % f"
  72. "\n% f, % f, % f, % f"
  73. "\n% f, % f, % f, % f",
  74. matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5],
  75. matrix[6], matrix[7], matrix[8], matrix[9], matrix[10], matrix[11],
  76. matrix[12], matrix[13], matrix[14], matrix[15]);
  77. }
  78. static void initialize_matrix(float const Kb, float const Kr,
  79. int const range_min[3], int const range_max[3],
  80. int const black_levels[3], float matrix[16])
  81. {
  82. struct matrix3 color_matrix;
  83. int yvals = range_max[0] - range_min[0];
  84. int uvals = (range_max[1] - range_min[1]) / 2;
  85. int vvals = (range_max[2] - range_min[2]) / 2;
  86. vec3_set(&color_matrix.x, 255. / yvals, 0., 255. / vvals * (1. - Kr));
  87. vec3_set(&color_matrix.y, 255. / yvals,
  88. 255. / uvals * (Kb - 1.) * Kb / (1. - Kb - Kr),
  89. 255. / vvals * (Kr - 1.) * Kr / (1. - Kb - Kr));
  90. vec3_set(&color_matrix.z, 255. / yvals, 255. / uvals * (1. - Kb), 0.);
  91. struct vec3 offsets, multiplied;
  92. vec3_set(&offsets, -black_levels[0] / 255., -black_levels[1] / 255.,
  93. -black_levels[2] / 255.);
  94. vec3_rotate(&multiplied, &offsets, &color_matrix);
  95. matrix[0] = color_matrix.x.x;
  96. matrix[1] = color_matrix.x.y;
  97. matrix[2] = color_matrix.x.z;
  98. matrix[3] = multiplied.x;
  99. matrix[4] = color_matrix.y.x;
  100. matrix[5] = color_matrix.y.y;
  101. matrix[6] = color_matrix.y.z;
  102. matrix[7] = multiplied.y;
  103. matrix[8] = color_matrix.z.x;
  104. matrix[9] = color_matrix.z.y;
  105. matrix[10] = color_matrix.z.z;
  106. matrix[11] = multiplied.z;
  107. matrix[12] = matrix[13] = matrix[14] = 0.;
  108. matrix[15] = 1.;
  109. log_matrix(matrix);
  110. }
  111. static void initialize_matrices()
  112. {
  113. static int range_min[] = {0, 0, 0};
  114. static int range_max[] = {255, 255, 255};
  115. for (size_t i = 0; i < NUM_FORMATS; i++) {
  116. initialize_matrix(format_info[i].Kb, format_info[i].Kr,
  117. range_min, range_max,
  118. format_info[i].black_levels[1],
  119. format_info[i].matrix[1]);
  120. initialize_matrix(format_info[i].Kb, format_info[i].Kr,
  121. format_info[i].range_min,
  122. format_info[i].range_max,
  123. format_info[i].black_levels[0],
  124. format_info[i].matrix[0]);
  125. for (int j = 0; j < 3; j++) {
  126. format_info[i].float_range_min[j] =
  127. format_info[i].range_min[j] / 255.;
  128. format_info[i].float_range_max[j] =
  129. format_info[i].range_max[j] / 255.;
  130. }
  131. }
  132. }
  133. static bool matrices_initialized = false;
  134. #endif
  135. static const float full_min[3] = {0.0f, 0.0f, 0.0f};
  136. static const float full_max[3] = {1.0f, 1.0f, 1.0f};
  137. bool video_format_get_parameters(enum video_colorspace color_space,
  138. enum video_range_type range, float matrix[16],
  139. float range_min[3], float range_max[3])
  140. {
  141. #ifdef COMPUTE_MATRICES
  142. if (!matrices_initialized) {
  143. initialize_matrices();
  144. matrices_initialized = true;
  145. }
  146. #endif
  147. if ((color_space == VIDEO_CS_DEFAULT) || (color_space == VIDEO_CS_SRGB))
  148. color_space = VIDEO_CS_709;
  149. for (size_t i = 0; i < NUM_FORMATS; i++) {
  150. if (format_info[i].color_space != color_space)
  151. continue;
  152. int full_range = range == VIDEO_RANGE_FULL ? 1 : 0;
  153. memcpy(matrix, format_info[i].matrix[full_range],
  154. sizeof(float) * 16);
  155. if (range == VIDEO_RANGE_FULL) {
  156. if (range_min)
  157. memcpy(range_min, full_min, sizeof(float) * 3);
  158. if (range_max)
  159. memcpy(range_max, full_max, sizeof(float) * 3);
  160. return true;
  161. }
  162. if (range_min)
  163. memcpy(range_min, format_info[i].float_range_min,
  164. sizeof(float) * 3);
  165. if (range_max)
  166. memcpy(range_max, format_info[i].float_range_max,
  167. sizeof(float) * 3);
  168. return true;
  169. }
  170. return false;
  171. }