1 /*
2 * encoder-cellb.cc --
3 *
4 * CellB video encoder
5 */
6
7 /* This code was originally derived from a cellb reference encoder from
8 * Sun Microsystems with the following copyright:
9 *
10 * Copyright (c) Sun Microsystems, Inc. 1992, 1993. All rights reserved.
11 *
12 * License is granted to copy, to use, and to make and to use derivative
13 * works for research and evaluation purposes, provided that Sun Microsystems is
14 * acknowledged in all documentation pertaining to any such copy or derivative
15 * work. Sun Microsystems grants no other licenses expressed or implied. The
16 * Sun Microsystems trade name should not be used in any advertising without
17 * its written permission.
18 *
19 * SUN MICROSYSTEMS MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF
20 * THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is provided "as is"
21 * without express or implied warranty of any kind.
22 *
23 * These notices must be retained in any copies of any part of this software.
24 */
25
26 static const char rcsid[] =
27 "@(#) $Header: /usr/mash/src/repository/mash/mash-1/codec/encoder-cellb.cc,v 1.14 2003/11/19 19:20:17 aswan Exp $";
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include "rtp/inet.h"
34 #include "rtp/rtp.h"
35 #include "misc/bsd-endian.h"
36 #include "codec/crdef.h"
37 #include "rtp/pktbuf-rtp.h"
38 #include "codec/module.h"
39
40 #define MAXSKIP 32
41
42 extern "C" u_char cellb_yyremap[];
43 extern "C" u_char cellb_uvremap[];
44
45 #define HLEN (sizeof(rtphdr) + sizeof(cellbhdr))
46
47 class CellbEncoder : public EncoderModule {
48 public:
49 CellbEncoder();
50 ~CellbEncoder();
51 virtual void recv(Buffer*);
52 private:
53 void size(int w, int h);
54 int diff(const u_char blk1[4], const u_char blk2[4]) const;
55 void send(pktbuf* pb, int sync, int x, int y, int cc);
56 u_int encode_cell(const u_char* lum, const u_char* chm, int stride);
57
58 int nw_;
59 int nh_;
60
61 /*
62 * Tables for CellB.
63 */
64 u_char* divtable_[17];/*FIXME*/
65 u_char dtbl_[34816];
66 };
67
68 static class CellbEncoderClass : public TclClass {
69 public:
70 CellbEncoderClass() : TclClass("Module/VideoEncoder/Pixel/CellB") {}
71 TclObject* create(int /* argc */, const char*const* /* argv */) {
72 return (new CellbEncoder);
73 }
74 } encoder_matcher_cellb;
75
76 void CellbEncoder::send(pktbuf* pb, int sync, int x, int y, int cc)
77 {
78 pb->len = cc + HLEN;
79 rtphdr* rh = (rtphdr*)pb->data;
80 if (sync)
81 rh->rh_flags |= htons(RTP_M);
82
83 cellbhdr* ch = (cellbhdr*)(rh + 1);
84 ch->width = nw_;
85 ch->height = nh_;
86 ch->x = htons(x);
87 ch->y = htons(y);
88 target_->recv(pb);
89 }
90
91 /*
92 * Returns 32-bit encoded cell in host order.
93 */
94 u_int CellbEncoder::encode_cell(const u_char* lum,
95 const u_char* chm,
96 int stride)
97 {
98 u_int mask = 0xff00ff;
99 u_int q0 = *(u_int *)lum;
100 u_int q1 = *(u_int *)&lum[stride];
101 u_int q2 = *(u_int *)&lum[stride << 1];
102 u_int q3 = *(u_int *)&lum[(stride << 1) + stride];
103
104 /*
105 * Compute the mean of the luminance component.
106 * Do some of the adds in parallel.
107 */
108 u_int ymean = q0 & mask;
109 ymean += (q0 >> 8) & mask;
110 ymean += q1 & mask;
111 ymean += (q1 >> 8) & mask;
112 ymean += q2 & mask;
113 ymean += (q2 >> 8) & mask;
114 ymean += q3 & mask;
115 ymean += (q3 >> 8) & mask;
116 ymean = (ymean & 0xffff) + (ymean >> 16);
117 u_int sum = ymean;
118 ymean >>= 4;
119
120 /*
121 .... next the bit mask for the tile is generated. for
122 the first fifteen bits this is done by comparing each
123 luminance value to the mean. if that value is greater
124 than the mean the correnponding bit in the mask is set,
125 otherwise the counter for the number of zeros in the mask,
126 tmp, is incremented. also, the values of those pixels less
127 than the mean are accumulted in ylo ....
128 */
129
130 mask = 0;
131 int ylo = 0;
132 int nb = 0;
133
134 #define ACCUMULATE(pix, mean, n, slow, mask, pos) \
135 { \
136 int t = (pix) & 0xff; \
137 t -= (mean); \
138 int neg = t >> 31; \
139 (slow) += neg & t; \
140 (slow) += neg & (mean); \
141 neg &= 1; \
142 (n) += neg; \
143 (mask) |= neg << (pos); \
144 }
145 #if BYTE_ORDER == LITTLE_ENDIAN
146 #define BYTE(b, n) ((b) >> (8 * (3 - (n))))
147 #else
148 #define BYTE(b, n) ((b) >> (8 * (n)))
149 #endif
150 ACCUMULATE(BYTE(q3, 0), ymean, nb, ylo, mask, 0);
151 ACCUMULATE(BYTE(q3, 1), ymean, nb, ylo, mask, 1);
152 ACCUMULATE(BYTE(q3, 2), ymean, nb, ylo, mask, 2);
153 ACCUMULATE(BYTE(q3, 3), ymean, nb, ylo, mask, 3);
154
155 ACCUMULATE(BYTE(q2, 0), ymean, nb, ylo, mask, 4);
156 ACCUMULATE(BYTE(q2, 1), ymean, nb, ylo, mask, 5);
157 ACCUMULATE(BYTE(q2, 2), ymean, nb, ylo, mask, 6);
158 ACCUMULATE(BYTE(q2, 3), ymean, nb, ylo, mask, 7);
159
160 ACCUMULATE(BYTE(q1, 0), ymean, nb, ylo, mask, 8);
161 ACCUMULATE(BYTE(q1, 1), ymean, nb, ylo, mask, 9);
162 ACCUMULATE(BYTE(q1, 2), ymean, nb, ylo, mask, 10);
163 ACCUMULATE(BYTE(q1, 3), ymean, nb, ylo, mask, 11);
164
165 ACCUMULATE(BYTE(q0, 0), ymean, nb, ylo, mask, 12);
166 ACCUMULATE(BYTE(q0, 1), ymean, nb, ylo, mask, 13);
167 ACCUMULATE(BYTE(q0, 2), ymean, nb, ylo, mask, 14);
168 ACCUMULATE(BYTE(q0, 3), ymean, nb, ylo, mask, 15);
169 #undef BYTE
170 #undef ACCUMULATE
171
172 int yhi = sum - ylo;
173 yhi = divtable_[16 - nb][yhi];
174 ylo = divtable_[nb][ylo];
175 /*
176 * Normalize bitmask. Note mask is
177 * computed in negative logic.
178 */
179 if (mask & 0x8000) {
180 mask ^= 0xffff;
181 ylo <<= 8;
182 ylo |= yhi;
183 } else
184 ylo |= yhi << 8;
185
186 mask <<= 16;
187
188 /*
189 .... the high mean and low mean values are finally quantized
190 by the cellb_yyremap[] table, the Y/Y vector codeword byte, the
191 U/V codeword byte and the bitmask are then assembled into
192 a Normal Cell bytecode and returned form the routine ....
193 */
194 mask |= cellb_yyremap[ylo];
195
196 /*
197 * Simply downsample the chroma components, then
198 * vector quantize according to the CellB spec.
199 * (The encoder in nv computes a mean of the 16
200 * chroma components. This is probably not a good
201 * idea first because it's computationally more
202 * expensive and second because it doesn't buy
203 * much. This is equivalent to placing a low-pass
204 * (rectangular) filter in front of the downsampling
205 * stage. But the chroma signal in most cases
206 * doesn't have much of a high frequency component.
207 * Try visually comparing this coder with nv's.
208 * You will probably see little difference.)
209 */
210 int u = chm[0];
211 int v = chm[framesize_ >> 1];
212 mask |= cellb_uvremap[u >> 2 << 6 | v >> 2] << 8;
213
214 return (mask);
215 }
216
217 void CellbEncoder::size(int w, int h)
218 {
219 FrameModule::size(w, h);
220 nw_ = htons(w);
221 nh_ = htons(h);
222 }
223
224 CellbEncoder::CellbEncoder()
225 {
226 /* .... initialize division table .... */
227 u_char* p = dtbl_;
228 divtable_[0] = p;
229 for (int i = 1; i <= 16; i++) {
230 divtable_[i] = p;
231 for (int j = 0; j < 256*i; j++)
232 *p++ = j / i;
233 }
234 width_ = 0;
235 height_ = 0;
236 nw_ = 0;
237 nh_ = 0;
238 }
239
240 CellbEncoder::~CellbEncoder()
241 {
242 }
243
244 /*
245 * Encode a cellb frame. this code can be improved by pruning
246 * skip-code runs off the front and back of the frame.
247 */
248 void CellbEncoder::recv(Buffer* bp)
249 {
250 const VideoFrame* vf = (VideoFrame*)bp;
251 if (!samesize(vf))
252 size(vf->width_, vf->height_);
253 YuvFrame* p = (YuvFrame*)vf;
254
255 pktbuf* pb = pool_->alloc(p->ts_, RTP_PT_CELLB);
256 u_char* op = &pb->data[HLEN];
257 u_char* ep = op + mtu_ - HLEN;
258 int x0 = 0;
259 int y0 = 0;
260
261 int cc = 0;
262 int nskip = 0;
263 int stride = 3 * width_;
264
265 int blkbase = 0;
266 /*
267 * Compute width and height in cells.
268 */
269 int w = width_ >> 2;
270 int h = height_ >> 2;
271
272 /*
273 * Loop over 4x4 cells, encoding those indicated by the 16x16
274 * CR vector. Because there are 4 cells per 16x16 replenishment
275 * block, the blocks are incremented only every other interation
276 * of each loop.
277 */
278
279 const u_int8_t* lum = p->bp_;
280 const u_int8_t* chm = lum + framesize_;
281 const u_int8_t* crvec = p->crvec_;
282 for (int y = 0; y < h; ) {
283 int blkno = blkbase;
284 for (int x = 0; x < w; ) {
285 if (op + 2*5 >= ep) {
286 nb_ += cc + HLEN;
287 send(pb, 0, x0, y0, cc);
288 cc = 0;
289 pb = pool_->alloc(p->ts_, RTP_PT_CELLB);
290 op = &pb->data[HLEN];
291 ep = op + mtu_ - HLEN;
292 x0 = x;
293 y0 = y;
294 }
295 if (crvec[blkno] & CR_SEND) {
296 /*
297 * cell has seen recent change. send it.
298 */
299 if (nskip > 0) {
300 ++cc;
301 *op++ = 0x80 | (nskip - 1);
302 nskip = 0;
303 }
304 int code = encode_cell(lum, chm, width_);
305 op[0] = code >> 24;
306 op[1] = code >> 16;
307 op[2] = code >> 8;
308 op[3] = code;
309 op += 4;
310 cc += 4;
311 } else {
312 if (++nskip >= MAXSKIP) {
313 ++cc;
314 *op++ = 0x80 | (MAXSKIP - 1);
315 nskip = 0;
316 }
317 }
318 if ((++x & 3) == 0)
319 ++blkno;
320 lum += 4;
321 chm += 2;
322 }
323 if ((++y & 3) == 0)
324 blkbase += w >> 2;
325
326 lum += stride;
327 chm += stride >> 1;
328 }
329 nb_ += cc;
330 send(pb, 1, x0, y0, cc);
331 }
332
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.