]> git.sesse.net Git - vlc/blob - modules/codec/ogt/pixmap.c
* access2: added shortcuts for vcd/svcd.
[vlc] / modules / codec / ogt / pixmap.c
1 /*****************************************************************************
2  * Common pixel/chroma manipulation routines.
3  *****************************************************************************
4  * Copyright (C) 2003, 2004 VideoLAN
5  * $Id: pixmap.c,v 1.3 2004/01/31 05:53:35 rocky Exp $
6  *
7  * Author: Rocky Bernstein
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include <vlc/vlc.h>
25 #include <vlc/vout.h>
26
27 #include "pixmap.h"
28
29 /* FIXME: This is copied from modules/video_chroma/i420_rgb.h. 
30    Include from a more common location.
31  */
32
33 /*****************************************************************************
34  * chroma_sys_t: chroma method descriptor
35  *****************************************************************************
36  * This structure is part of the chroma transformation descriptor, it
37  * describes the yuv2rgb specific properties.
38  *****************************************************************************/
39 struct chroma_sys_t
40 {
41     uint8_t  *p_buffer;
42     int *p_offset;
43
44     /* Pre-calculated conversion tables */
45     void *p_base;                         /* base for all conversion tables */
46     uint8_t   *p_rgb8;                    /* RGB 8 bits table */
47     uint16_t  *p_rgb16;                   /* RGB 16 bits table */
48     uint32_t  *p_rgb32;                   /* RGB 32 bits table */
49
50     /* To get RGB value for palette entry i, use (p_rgb_r[i], p_rgb_g[i],
51        p_rgb_b[i])
52      */
53     uint16_t  p_rgb_r[CMAP_RGB2_SIZE];    /* Red values of palette */
54     uint16_t  p_rgb_g[CMAP_RGB2_SIZE];    /* Green values of palette */
55     uint16_t  p_rgb_b[CMAP_RGB2_SIZE];    /* Blue values of palette */
56 };
57
58
59 /* 
60     From
61     http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC11
62     http://people.ee.ethz.ch/~buc/brechbuehler/mirror/color/ColorFAQ.html#RTFToC1
63  
64     11. What is "luma"?
65
66     It is useful in a video system to convey a component representative of
67     luminance and two other components representative of colour. It is
68     important to convey the component representative of luminance in such
69     a way that noise (or quantization) introduced in transmission,
70     processing and storage has a perceptually similar effect across the
71     entire tone scale from black to white. The ideal way to accomplish
72     these goals would be to form a luminance signal by matrixing RGB, then
73     subjecting luminance to a nonlinear transfer function similar to the
74     L* function.
75
76     There are practical reasons in video to perform these operations
77     in the opposite order. First a nonlinear transfer function - gamma
78     correction - is applied to each of the linear R, G and B. Then a
79     weighted sum of the nonlinear components is computed to form a
80     signal representative of luminance. The resulting component is
81     related to brightness but is not CIE luminance. Many video
82     engineers call it luma and give it the symbol Y'. It is often
83     carelessly called luminance and given the symbol Y. You must be
84     careful to determine whether a particular author assigns a linear
85     or nonlinear interpretation to the term luminance and the symbol
86     Y.
87
88     The coefficients that correspond to the "NTSC" red, green and blue
89     CRT phosphors of 1953 are standardized in ITU-R Recommendation BT.
90     601-2 (formerly CCIR Rec.  601-2). I call it Rec.  601. To compute
91     nonlinear video luma from nonlinear red, green and blue:
92
93     Y'601 = 0.299R' 0.587G' + 0.114B'
94
95     We will use the integer scaled versions of these numbers below
96     as RED_COEF, GREEN_COEF and BLUE_COEF.
97  */
98
99 /* 19 = round(0.299 * 64) */
100 #define RED_COEF   ((int32_t) 19)
101
102 /* 38 = round(0.587 * 64) */
103 #define GREEN_COEF ((int32_t) 37)
104
105 /* 7 = round(0.114 * 64) */
106 #define BLUE_COEF  ((int32_t)  7)
107
108 /** 
109    Find the nearest colormap entry in p_vout (assumed to have RGB2
110    chroma, i.e. 256 RGB 8bpp entries) that is closest in color to p_rgb.  Set
111    out_rgb to the color found and return the colormap index.
112    INVALID_CMAP_ENTRY is returned if there is some error.
113
114    The closest match is determined by the the Euclidean distance
115    using integer-scaled 601-2 coefficients described above.
116
117    Actually, we use the square of the Euclidean distance; but in
118    comparisons it amounts to the same thing.
119 */
120
121 cmap_t
122 find_cmap_rgb8_nearest(const vout_thread_t *p_vout, const uint8_t *rgb,
123                        uint8_t *out_rgb) 
124 {
125   uint16_t *p_cmap_r;
126   uint16_t *p_cmap_g;
127   uint16_t *p_cmap_b;
128   
129   int i;
130   cmap_t i_bestmatch = INVALID_CMAP_ENTRY;
131   uint32_t i_mindist = 0xFFFFFFFF; /* The largest number here. */
132
133   /* Check that we really have RGB2. */
134   
135   if ( !p_vout && p_vout->output.i_chroma  != VLC_FOURCC('R','G','B','2') )
136     return INVALID_CMAP_ENTRY;
137
138   p_cmap_r=p_vout->chroma.p_sys->p_rgb_r;
139   p_cmap_g=p_vout->chroma.p_sys->p_rgb_g;
140   p_cmap_b=p_vout->chroma.p_sys->p_rgb_b;
141
142   for (i = 0; i < CMAP_RGB2_SIZE; i++) {
143     /* Interval range calculations to show that we don't overflow the
144        word sizes below. pixels component values start out 8
145        bits. When we subtract two components we get 9 bits, then
146        square to 10 bits.  Next we scale by 6 to give 16
147        bits. XXX_COEF all fit into 5 bits, so when we multiply we
148        should have 21 bits maximum. So computations can be done using
149        32-bit precision. However before storing back distance
150        components we scale back down by 12 bits making the precision 9
151        bits. (This checks out since it is basically the range of the
152        square of the initial 8-bit value.)
153
154        The squared distance is the sum of three of the 9-bit components
155        described above. This then uses 27-bits and also fits in a
156        32-bit word.
157      */
158
159     /* We use in integer fixed-point fractions rather than floating
160        point for speed. We multiply by 64 (= 1 << 6) before computing
161        the product, and divide the result by 64*64 (= 1 >> (6*2)).
162     */
163
164 #define SCALEBITS 6 
165 #define int32_sqr(x) ( ((int32_t) (x)) * ((int32_t) x) )
166
167     /* colormap entires are scaled to 16 bits, so we need to shift
168        them back down to 8. */
169 #define CMAP8_RED(i) (p_cmap_r[i]>>8)
170 #define CMAP8_GREEN(i) (p_cmap_g[i]>>8)
171 #define CMAP8_BLUE(i) (p_cmap_b[i]>>8)
172
173     uint32_t dr = ( RED_COEF   * ( int32_sqr(rgb[RED_PIXEL]   - CMAP8_RED(i))
174                                  << SCALEBITS ) ) >> (SCALEBITS*2);
175     uint32_t dg = ( GREEN_COEF * ( int32_sqr(rgb[GREEN_PIXEL] - CMAP8_GREEN(i))
176                                  << SCALEBITS ) ) >> (SCALEBITS*2);
177     uint32_t db = ( BLUE_COEF  * ( int32_sqr(rgb[BLUE_PIXEL]  - CMAP8_BLUE(i))
178                                  << SCALEBITS ) ) >> (SCALEBITS*2);
179
180     uint32_t i_dist = dr + dg + db;
181     if (i_dist < i_mindist) {
182       i_bestmatch = i;
183       i_mindist = i_dist;
184 #if 0      
185       printf("+++Change dist to %d RGB cmap %d (%0x, %0x, %0x)\n", 
186              i_dist, i, p_cmap_r[ i ], p_cmap_g[ i ], p_cmap_b[ i ]);
187 #endif
188     }
189   }
190
191   if (out_rgb) 
192     {
193       out_rgb[RED_PIXEL]   = CMAP8_RED(i_bestmatch);
194       out_rgb[GREEN_PIXEL] = CMAP8_GREEN(i_bestmatch);
195       out_rgb[BLUE_PIXEL]  = CMAP8_BLUE(i_bestmatch);
196     }
197
198   return i_bestmatch;
199 }
200
201 /**
202    Get the the rgb value for a given colormap entry for p_vout (which is'
203    assumed to have RGB2 chroma). 
204
205    VLC_FALSE is returned if there was some error.
206 */
207 vlc_bool_t
208 query_color(const vout_thread_t *p_vout, cmap_t i_cmap,
209             /*out*/ uint8_t *out_rgb) 
210 {
211   uint16_t *p_cmap_r;
212   uint16_t *p_cmap_g;
213   uint16_t *p_cmap_b;
214
215   /* Check that we really have RGB2. */
216   
217   if ( !p_vout && p_vout->output.i_chroma  != VLC_FOURCC('R','G','B','2') )
218     return VLC_FALSE;
219
220   if ( !out_rgb ) 
221     return VLC_FALSE;
222
223   p_cmap_r=p_vout->chroma.p_sys->p_rgb_r;
224   p_cmap_g=p_vout->chroma.p_sys->p_rgb_g;
225   p_cmap_b=p_vout->chroma.p_sys->p_rgb_b;
226
227   out_rgb[RED_PIXEL]   = CMAP8_RED(i_cmap);
228   out_rgb[GREEN_PIXEL] = CMAP8_GREEN(i_cmap);
229   out_rgb[BLUE_PIXEL]  = CMAP8_BLUE(i_cmap);
230
231   return VLC_TRUE;
232 }
233
234 \f
235 /* 
236  * Local variables:
237  *  c-file-style: "gnu"
238  *  tab-width: 8
239  *  indent-tabs-mode: nil
240  * End:
241  */