1 /*
2 * decoder.cc --
3 *
4 * Video Decoder class
5 *
6 * Copyright (c) 1993-2002 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * A. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * B. Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * C. Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
22 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 static const char rcsid[] =
35 "@(#) $Header: /usr/mash/src/repository/mash/mash-1/codec/decoder.cc,v 1.29 2003/11/19 19:20:17 aswan Exp $";
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #ifndef WIN32
40 #include <sys/param.h>
41 #endif
42 #include "misc/sys-time.h"
43 #include "rtp/inet.h"
44 #include "rtp/rtp.h"
45 #include "codec/decoder.h"
46 #include "render/renderer.h"
47 #include "render/color-hist.h"
48 #include "codec/postdct.h"
49 #include "misc/isblue_black.h"
50 extern "C" {
51 #ifdef USE_SHM
52 #include <sys/ipc.h>
53 #include <sys/shm.h>
54 #if defined(sun) && !defined(__svr4__)
55 int shmget(key_t, int, int);
56 char *shmat(int, char*, int);
57 int shmdt(char*);
58 int shmctl(int, int, struct shmid_ds*);
59 #endif
60 #endif
61 }
62
63 Decoder::Decoder(int hdrlen) : PacketHandler(hdrlen),
64 nstat_(0), color_(1), csss_(422), inw_(0), inh_(0),
65 suppress_(0), engines_(0), rvts_(0), nblk_(0), ndblk_(0)
66 {
67 /*FIXME*/
68 now_ = 1;
69
70 for (int i = 0; i < MAXSTAT; ++i)
71 stat_[i].cnt = 0;
72 }
73
74
75 Decoder::~Decoder()
76 {
77 if (rvts_) delete[] rvts_;
78 }
79
80 int Decoder::command(int argc, const char*const* argv)
81 {
82 Tcl& tcl = Tcl::instance();
83 if (argc == 2) {
84 if (strcmp(argv[1], "width") == 0) {
85 tcl.resultf("%d", width());
86 return (TCL_OK);
87 }
88 if (strcmp(argv[1], "height") == 0) {
89 tcl.resultf("%d", height());
90 return (TCL_OK);
91 }
92 if (strcmp(argv[1], "info") == 0) {
93 char* bp = tcl.buffer();
94 info(bp);
95 tcl.result(bp);
96 return (TCL_OK);
97 }
98 if (strcmp(argv[1], "stats") == 0) {
99 char* bp = tcl.buffer();
100 tcl.result(bp);
101 stats(bp);
102 return (TCL_OK);
103 }
104 if (strcmp(argv[1], "csss") == 0) {
105 tcl.resultf("%d", csss());
106 return (TCL_OK);
107 }
108 if (strcmp(argv[1], "redraw") == 0) {
109 redraw();
110 return (TCL_OK);
111 }
112 if (strcmp(argv[1], "playout") == 0) {
113 /*FIXME*/
114 tcl.result("");
115 return (TCL_OK);
116 }
117 } else if (argc == 3) {
118 if (strcmp(argv[1], "color") == 0) {
119 setcolor(atoi(argv[2]));
120 return (TCL_OK);
121 }
122 if (strcmp(argv[1], "suppress") == 0) {
123 suppress_ = atoi(argv[2]);
124 return (TCL_OK);
125 }
126 if (strcmp(argv[1], "attach") == 0) {
127 Renderer* r = (Renderer*)TclObject::lookup(argv[2]);
128 if (r == 0) {
129 tcl.resultf("%s attach: no such renderer: %s",
130 argv[0], argv[2]);
131 return (TCL_ERROR);
132 }
133 attach(r);
134 return (TCL_OK);
135 }
136 if (strcmp(argv[1], "detach") == 0) {
137 Renderer* r = (Renderer*)TclObject::lookup(argv[2]);
138 if (r == 0) {
139 tcl.resultf("%s detach: no such target: %s",
140 argv[0], argv[2]);
141 return (TCL_ERROR);
142 }
143 return detach(r);
144 }
145 if (strcmp(argv[1], "histogram") == 0) {
146 ColorHist* ch = ColorHist::lookup(argv[2]);
147 if (ch == 0) {
148 tcl.resultf("%s histogram: no such histogram: %s",
149 argv[0], argv[2]);
150 return (TCL_ERROR);
151 }
152 colorhist(ch->histogram());
153 return (TCL_OK);
154 }
155 }
156 return (TclObject::command(argc, argv));
157 }
158
159 void Decoder::info(char* wrk) const
160 {
161 *wrk = 0;
162 }
163
164 void Decoder::stats(char* bp)
165 {
166 if (nstat_ == 0) {
167 *bp = 0;
168 return;
169 }
170 for (int i = 0; i < nstat_; ++i) {
171 sprintf(bp, "%s %d ", stat_[i].name, stat_[i].cnt);
172 bp += strlen(bp);
173 }
174 bp[-1] = 0;
175 }
176
177 void Decoder::allocshm(dmabuf& d, int size, int flag)
178 {
179 #ifdef USE_SHM
180 d.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777);
181 if (d.shmid < 0) {
182 perror("shmget");
183 exit(1);
184 }
185 d.bp = (u_char *)shmat(d.shmid, 0, flag);
186 if (d.bp == (u_char*)-1) {
187 perror("shmat");
188 exit(1);
189 }
190 #endif
191 }
192
193 /*FIXME not used*/
194 void Decoder::freeshm(dmabuf& d)
195 {
196 #ifdef USE_SHM
197 if (shmdt((char*)d.bp) < 0)
198 perror("shmdt");
199 #endif
200 }
201
202 /*
203 * Return time of day in microseconds.
204 */
205 double Decoder::gettimeofday()
206 {
207 timeval tv;
208 ::gettimeofday(&tv, 0);
209 return (1e6 * double(tv.tv_sec) + double(tv.tv_usec));
210 }
211
212 void Decoder::attach(Renderer* r)
213 {
214 r->next_ = engines_;
215 engines_ = r;
216 r->setcolor(color_);
217 r->now(0);
218 redraw();
219 }
220
221 void Decoder::redraw(const u_char* /* frm */)
222 {
223 /* make sure all the renderer's are synced */
224 now_ = 1;
225 memset(rvts_, 1, nblk_);
226 for (Renderer* p = engines_; p != 0; p = p->next_)
227 p->now(0);
228 // render_frame(frm);
229 }
230
231 int Decoder::detach(Renderer* r)
232 {
233 Renderer** p;
234 for (p = &engines_; *p != r; p = &(*p)->next_)
235 if (*p == 0)
236 return TCL_ERROR;
237 *p = (*p)->next_;
238 return TCL_OK;
239 }
240
241 void Decoder::colorhist_422_556(u_int* hist, const u_char* yp,
242 const u_char* up, const u_char* vp,
243 int width, int h) const
244 {
245 while (--h >= 0) {
246 for (int w = width; w > 0; w -= 2) {
247 /* 5V:5U:6Y */
248 int uv = vp[0] >> 3 << 11 | up[0] >> 3 << 6;
249 ++hist[uv | yp[0] >> 2];
250 ++hist[uv | yp[1] >> 2];
251 yp += 2;
252 up += 1;
253 vp += 1;
254 }
255 }
256 }
257
258 void Decoder::colorhist_411_556(u_int* hist, const u_char* yp,
259 const u_char* up, const u_char* vp,
260 int width, int h) const
261 {
262 while (--h >= 0) {
263 for (int w = width; w > 0; w -= 4) {
264 /* 5V:5U:6Y */
265 int uv = vp[0] >> 3 << 11 | up[0] >> 3 << 6;
266 ++hist[uv | yp[0] >> 2];
267 ++hist[uv | yp[1] >> 2];
268 ++hist[uv | yp[2] >> 2];
269 ++hist[uv | yp[3] >> 2];
270 yp += 4;
271 up += 1;
272 vp += 1;
273 }
274 }
275 }
276
277 void Decoder::colorhist_420_556(u_int* hist, const u_char* yp,
278 const u_char* up, const u_char* vp,
279 int width, int h) const
280 {
281 for (; h > 0; h -= 2) {
282 for (int w = width; w > 0; w -= 2) {
283 /* 5V:5U:6Y */
284 int uv = vp[0] >> 3 << 11 | up[0] >> 3 << 6;
285 ++hist[uv | yp[0] >> 2];
286 ++hist[uv | yp[1] >> 2];
287 ++hist[uv | yp[width] >> 2];
288 ++hist[uv | yp[width + 1] >> 2];
289 yp += 2;
290 up += 1;
291 vp += 1;
292 }
293 yp += width;
294 }
295 }
296
297 void Decoder::render_frame(const u_char* frm)
298 {
299 render_frame(frm, CODEC_ANY, 0);
300 }
301
302 void Decoder::render_frame(const u_char* frm, int codec, int quality)
303 {
304 //
305 // rvts_
306 //
307 // rvts_ is the Replenishment Vector of "TimeStamps" buffer, and it's
308 // composed of one byte per 8-pixel-wide, 8-pixel-high block. The
309 // purpose of carrying a replenishment vector in the decoder is to
310 // relieve the renderer of the task of refreshing the full video
311 // window if only a small number of blocks were updated by the source.
312 //
313 // The structure is created by the main decoder object (Decoder::resize()),
314 // and is used by it, the particular decoder (e.g., H261Decoder and its
315 // implementation P64Decoder, where it's called marks_), and the
316 // Renderer. Every time the particular decoder decodes a block, it
317 // marks up the corresponding byte in the rvts_ with a commonly-agreed
318 // "timestamp" (check P64Decoder::decode_mb()). These timestamps have
319 // nothing in common with RTP timestamps (they are for sure 1-byte
320 // numbers).
321 //
322 // When the renderer receives the frame, it only renders those blocks
323 // whose timestamp is the current one. To avoid old blocks being
324 // rendered because they were updated 256 time ticks ago (and therefore
325 // whose timestamp coincides with the current timestamp),
326 // Decoder::render_frame() takes care of adding one to those
327 // timestamps before permitting the particular decoder accessing to
328 // the structure. Therefore, the meaning of each table's value is the
329 // following:
330 //
331 // (now_ - rvts_[i]) mod 256 = how long ago was this block updated (255
332 // meaning 255 ticks or more)
333 //
334 // This decoder optimization only works for codecs where you can send
335 // only some blocks of a frame. I.e., it doesn't make sense for MJPEG.
336 //
337
338 Renderer *p, *q;
339 long int engine_footprint, new_engine_footprint;
340
341 // get the initial renderer list footprint
342 engine_footprint = 0;
343 for (p = engines_; p != 0; p = p->next_) {
344 engine_footprint = engine_footprint ^ (long int)p;
345 }
346
347 YuvFrame f(now_, (u_int8_t*)frm, rvts_, inw_, inh_, csss_);
348 //Fixme: A more elegant way to do figure out if an activeSource has
349 //been attached
350 if (suppress_) {
351 if (isBlue_Black(f.bp_, f.csss_, f.height_, f.width_, suppress_)) {
352 mute_hide();
353 return;
354 }
355 else {
356 unhide();
357 }
358 }
359 for (p = engines_; p != 0; p = p->next_) {
360 p->recv(&f, codec, quality);
361
362 // get the new renderer list footprint
363 new_engine_footprint = 0;
364 for (q = engines_; q != 0; q = q->next_) {
365 new_engine_footprint = new_engine_footprint ^ (long int)q;
366 }
367
368 // compare both footprints and exit if there were changes
369 if (new_engine_footprint != engine_footprint) {
370 // the renderer list has changed
371 break;
372 }
373 }
374
375 // get the new timestamp
376 now_ = (now_ + 1) & 0xff;
377
378 // actualize the replenishment vector (add one with saturation to
379 // the blocks whose timestamp coincides with the new timestamp)
380 u_char* ts = rvts_;
381 for (int k = nblk_; --k >= 0; ++ts) {
382 if (*ts == now_) {
383 *ts = (*ts + 1) & 0xff;
384 }
385 }
386 }
387
388 void Decoder::setcolor(int color)
389 {
390 if (color != color_) {
391 color_ = color;
392 for (Renderer* p = engines_; p != 0; p = p->next_)
393 p->setcolor(color_);
394 }
395 }
396
397 /*
398 * This method is called by a decoder (e.g., H261Decoder, etc.) when
399 * the incoming packet stream changes sizes or when decoder is created.
400 * The tricky thing is that this points to an instance of the specific
401 * decoder, not to an instance of Decoder. The method call on redraw()
402 * at the end of the method does not call Decoder::redraw(...) defined
403 * above - it actually calls the redraw routine for the specific decoder
404 * which in turn might call Decoder::redraw.
405 */
406 void Decoder::resize(int width, int height)
407 {
408 inw_ = width;
409 inh_ = height;
410 nblk_ = (width * height) / 64;
411 delete[] rvts_;
412 rvts_ = new u_char[nblk_];
413 memset(rvts_, 0, nblk_);
414 redraw();
415 }
416
417 void Decoder::mute_hide() {
418 Tcl& tcl = Tcl::instance();
419 tcl.evalf("[%s set as_] mute-hide", name());
420 }
421
422 void Decoder::unhide() {
423 Tcl& tcl = Tcl::instance();
424 tcl.evalf("[%s set as_] unhide", name());
425 }
426 /*
427 * Dummy class for streams that we recognize but cannot decode (for lack
428 * of software support). We still want to put all the stats etc. --
429 * especially the format -- but can't decode it. FIXME We need to somehow
430 * mark the stream in the user-interface so that the user knows that
431 * vic cannot decode the stream (to avoid assuming something else is
432 * wrong with the tranmission)
433 */
434 class NullDecoder : public Decoder {
435 public:
436 NullDecoder() : Decoder(0) {}
437 int colorhist(u_int* /* histogram */) const { return (0); }
438 void redraw() {}
439 virtual void recv(pktbuf* pb) { pb->release();}
440 };
441
442 static class VideoNullDecoderClass : public TclClass {
443 public:
444 VideoNullDecoderClass() : TclClass("Module/VideoDecoder/Null") {}
445 TclObject* create(int /* argc */, const char*const* /* argv */) {
446 return (new NullDecoder);
447 }
448 } dm_null;
449
450 PlaneDecoder::PlaneDecoder(int hdrlen) : Decoder(hdrlen), frm_(0)
451 {
452 }
453
454 PlaneDecoder::~PlaneDecoder()
455 {
456 delete[] frm_;
457 }
458
459 void PlaneDecoder::redraw()
460 {
461 Decoder::redraw(frm_);
462 }
463
464 void PlaneDecoder::resize(int width, int height)
465 {
466 delete[] frm_;
467 int size = width * height;
468 frm_ = new u_char[2 * size];
469 /*
470 * Initialize image to gray.
471 */
472 memset(frm_, 0x80, 2 * size);
473 Decoder::resize(width, height);
474 }
475
476 int PlaneDecoder::colorhist(u_int* histogram) const
477 {
478 int w = inw_;
479 int h = inh_;
480 int s = w * h;
481 u_char* up = frm_ + s;
482 colorhist_422_556(histogram, frm_, up, up + (s >> 1), w, h);
483 return (1);
484 }
485
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.