1 /*
2 * Copyright (C) 2012-2019 the xine project
3 *
4 * This file is part of xine, a free video player.
5 *
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 */
21
22
23 /*
24 TJ. the output color matrix selection feature.
25 Example use:
26 */
27 #if 0
28 #define CM_LUT /* recommended optimization */
29
30 typedef struct {
31 ...
32 int cm_state;
33 #ifdef CM_LUT
34 uint8_t cm_lut[32];
35 #endif
36 ...
37 } xxxx_driver_t;
38
39 #define CM_HAVE_YCGCO_SUPPORT /* if you already handle that */
40 #define CM_DRIVER_T xxxx_driver_t
41 #include "color_matrix.c"
42 #endif
43 /*
44 cm_from_frame () returns current (color_matrix << 1) | color_range control value.
45 Having only 1 var simplifies change event handling and avoids unecessary vo
46 reconfiguration. In the libyuv2rgb case, they are even handled by same code.
47
48 In theory, HD video uses a different YUV->RGB matrix than the rest.
49 It shall come closer to the human eye's brightness feel, and give
50 more shades of green even without higher bit depth.
51
52 I discussed this topic with local TV engineers earlier.
53 They say their studio equipment throws around uncompressed YUV with no
54 extra info attached to it. Anything smaller than 720p is assumed to be
55 ITU-R 601, otherwise ITU-R 709. A rematrix filter applies whenever
56 video is scaled across the above mentioned HD threshold.
57
58 However, the weak point of their argumentation is potentially non-standard
59 input material. Those machines obviously dont verify input data, and
60 ocasionally they dont even respect stream info (tested by comparing TV
61 against retail DVD version of same movie).
62
63 Consumer TV sets handle this fairly inconsistent - stream info, video size,
64 hard-wired matrix, user choice or so-called intelligent picture enhancers
65 that effectively go way off standards.
66 So I decided to provide functionality, and let the user decide if and how
67 to actually use it.
68 */
69
70 /* eveybody gets these */
71
72 /* user configuration settings */
73 #define CM_CONFIG_NAME "video.output.color_matrix"
74 #define CM_CONFIG_SIGNAL 0
75 #define CM_CONFIG_SIZE 1
76 #define CM_CONFIG_SD 2
77 #define CM_CONFIG_HD 3
78
79 #define CR_CONFIG_NAME "video.output.color_range"
80 #define CR_CONFIG_AUTO 0
81 #define CR_CONFIG_MPEG 1
82 #define CR_CONFIG_FULL 2
83
84 static const char * const cm_names[] = {
85 "RGB",
86 "RGB",
87 "ITU-R 709 / HDTV",
88 "full range ITU-R 709 / HDTV",
89 "undefined",
90 "full range, undefined",
91 "ITU-R 470 BG / SDTV",
92 "full range ITU-R 470 BG / SDTV",
93 "FCC",
94 "full range FCC",
95 "ITU-R 470 BG / SDTV",
96 "full range ITU-R 470 BG / SDTV",
97 "SMPTE 170M",
98 "full range SMPTE 170M",
99 "SMPTE 240M",
100 "full range SMPTE 240M"
101 #ifdef CM_HAVE_YCGCO_SUPPORT
102 ,
103 "YCgCo",
104 "YCgCo", /* this is always fullrange */
105 "#9",
106 "fullrange #9",
107 "#10",
108 "fullrange #10",
109 "#11",
110 "fullrange #11",
111 "#12",
112 "fullrange #12",
113 "#13",
114 "fullrange #13",
115 "#14",
116 "fullrange #14",
117 "#15",
118 "fullrange #15"
119 #endif
120 };
121
122 #ifdef CM_DRIVER_T
123
124 /* this is for vo plugins only */
125
126 /* the option names */
127 static const char * const cm_conf_labels[] = {
128 "Signal", "Signal+Size", "SD", "HD", NULL
129 };
130
131 static const char * const cr_conf_labels[] = {
132 "Auto", "MPEG", "FULL", NULL
133 };
134
135 #ifdef CM_HAVE_YCGCO_SUPPORT
136 # define CM_G 16
137 #else
138 # define CM_G 10
139 #endif
140
141 static
142 #ifdef CM_LUT
143 const
144 #endif
145 uint8_t cm_m[] = {
146 10, 2,10, 6, 8,10,12,14,CM_G,10,10,10,10,10,10,10, /* SIGNAL */
147 10, 2, 0, 6, 8,10,12,14,CM_G,10,10,10,10,10,10,10, /* SIZE */
148 10,10,10,10,10,10,10,10,CM_G,10,10,10,10,10,10,10, /* SD */
149 10, 2, 2, 2, 2, 2, 2, 2,CM_G, 2, 2, 2, 2, 2, 2, 2 /* HD */
150 };
151
cm_lut_setup(CM_DRIVER_T * this)152 static void cm_lut_setup (CM_DRIVER_T *this) {
153 #ifdef CM_LUT
154 {
155 const uint8_t *a = cm_m + ((this->cm_state >> 2) << 4);
156 uint8_t *d = this->cm_lut, *e = d + 32;
157 while (d < e) {
158 d[0] = d[1] = *a++;
159 d += 2;
160 }
161 }
162 if ((this->cm_state & 3) == CR_CONFIG_AUTO) {
163 /* keep range */
164 int i;
165 for (i = 1; i < 32; i += 2)
166 this->cm_lut[i] |= 1;
167 } else if ((this->cm_state & 3) == CR_CONFIG_FULL) {
168 /* force full range */
169 int i;
170 for (i = 0; i < 32; i += 1)
171 this->cm_lut[i] |= 1;
172 }
173 #endif
174 }
175
176 /* callback when user changes them */
cm_cb_config(void * this_gen,xine_cfg_entry_t * entry)177 static void cm_cb_config (void *this_gen, xine_cfg_entry_t *entry) {
178 CM_DRIVER_T *this = (CM_DRIVER_T *)this_gen;
179 this->cm_state = (this->cm_state & 3) | (entry->num_value << 2);
180 cm_lut_setup (this);
181 }
182
cr_cb_config(void * this_gen,xine_cfg_entry_t * entry)183 static void cr_cb_config (void *this_gen, xine_cfg_entry_t *entry) {
184 CM_DRIVER_T *this = (CM_DRIVER_T *)this_gen;
185 this->cm_state = (this->cm_state & 0x1c) | entry->num_value;
186 cm_lut_setup (this);
187 }
188
cm_init(CM_DRIVER_T * this)189 static void cm_init (CM_DRIVER_T *this) {
190 /* register configuration */
191 this->cm_state = this->xine->config->register_enum (
192 this->xine->config,
193 CM_CONFIG_NAME,
194 CM_CONFIG_SIZE,
195 (char **)cm_conf_labels,
196 _("Output colour matrix"),
197 _("Tell how output colours should be calculated.\n\n"
198 "Signal: Do as current stream suggests.\n"
199 " This may be wrong sometimes.\n\n"
200 "Signal+Size: Same as above,\n"
201 " but assume HD colour for unmarked HD streams.\n\n"
202 "SD: Force SD video standard ITU-R 470/601.\n"
203 " Try this if you get too little green.\n\n"
204 "HD: Force HD video standard ITU-R 709.\n"
205 " Try when there is too much green coming out.\n\n"),
206 10,
207 cm_cb_config,
208 this
209 ) << 2;
210 this->cm_state |= this->xine->config->register_enum (
211 this->xine->config,
212 CR_CONFIG_NAME,
213 CR_CONFIG_AUTO,
214 (char **)cr_conf_labels,
215 _("Output colour range"),
216 _("Tell how output colours should be ranged.\n\n"
217 "Auto: Do as current stream suggests.\n"
218 " This may be wrong sometimes.\n\n"
219 "MPEG: Force MPEG colour range (16..235) / studio swing / video mode.\n"
220 " Try if image looks dull (no real black or white in it).\n\n"
221 "FULL: Force FULL colour range (0..255) / full swing / PC mode.\n"
222 " Try when flat black and white spots appear.\n\n"),
223 10,
224 cr_cb_config,
225 this
226 );
227 cm_lut_setup (this);
228 }
229
cm_from_frame(vo_frame_t * frame)230 static int cm_from_frame (vo_frame_t *frame) {
231 CM_DRIVER_T *this = (CM_DRIVER_T *)frame->driver;
232 int cm = VO_GET_FLAGS_CM (frame->flags);
233 #ifdef CM_LUT
234 cm = this->cm_lut[cm & 31];
235 if (cm & ~1)
236 return cm;
237 return cm | ((frame->height - frame->crop_top - frame->crop_bottom >= 720) ||
238 (frame->width - frame->crop_left - frame->crop_right >= 1280) ? 2 : 10);
239 #else
240 static uint8_t cm_r[] = {0, 0, 1, 0}; /* AUTO, MPEG, FULL, safety */
241 int cf = this->cm_state;
242 cm_m[18] = (frame->height - frame->crop_top - frame->crop_bottom >= 720) ||
243 (frame->width - frame->crop_left - frame->crop_right >= 1280) ? 2 : 10;
244 cm_r[0] = cm & 1;
245 return cm_m[((cf >> 2) << 4) | (cm >> 1)] | cm_r[cf & 3];
246 #endif
247 }
248
cm_close(CM_DRIVER_T * this)249 static void cm_close (CM_DRIVER_T *this) {
250 /* dont know whether this is really necessary */
251 this->xine->config->unregister_callbacks (this->xine->config, NULL, NULL, this, sizeof (*this));
252 }
253
254 #endif /* defined CM_DRIVER_T */
255