1 /*
2 * decoder-h261v1.cc --
3 *
4 * H.261 v1 decoder object source code
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-h261v1.cc,v 1.15 2003/11/19 19:20:17 aswan Exp $";
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include "rtp/inet.h"
41 #include "rtp/rtp.h"
42 #include "codec/decoder.h"
43 #include "codec/p64/p64.h"
44 #include "net/pktbuf.h"
45
46 class RTPv1H261Decoder : public Decoder {
47 public:
48 RTPv1H261Decoder();
49 ~RTPv1H261Decoder();
50 int colorhist(u_int* hist) const;
51 virtual void recv(pktbuf*);
52 void stats(char* wrk);
53 protected:
54 const u_char* reassemble(const u_char* bp, int& cc, u_int& seqno,
55 u_int& flags);
56 virtual void redraw();
57
58 u_short seqno_; /* last rtp seqno */
59 /*
60 * Reassembly buffer 'slots' for resequencing & reassembling
61 * gobs split across packet boundaries.
62 */
63 #define H261_SLOTS 64
64 #define H261_SLOTMASK (H261_SLOTS - 1)
65 static u_char* wrkbuf_;
66 static u_int wrkbuflen_;
67 int packetsize_; /* max size of gob fragments */
68 struct slot {
69 int len;
70 u_short flags;
71 u_short seqno;
72 u_char* bp;
73 int pad;
74 } slot_[H261_SLOTS];
75 u_char* slotbuf_;
76
77 P64Decoder* codec_;
78 };
79
80 static class RTPv1H261DecoderClass : public TclClass {
81 public:
82 RTPv1H261DecoderClass() : TclClass("Module/VideoDecoder/H261v1") {}
83 TclObject* create(int /* argc */, const char*const* /* argv */) {
84 return (new RTPv1H261Decoder);
85 };
86 } dm_h261v1;
87
88 #define STAT_BAD_PSC 0
89 #define STAT_BAD_GOB 1
90 #define STAT_BAD_SYNTAX 2
91 #define STAT_BAD_FMT 3
92 #define STAT_BAD_SIZE 4 /* packet dropped for unsupported fmt */
93 #define STAT_BAD_BITOFF 5 /* unexpected non-zero sbits or ebits */
94 #define STAT_SIZE_CHANGE 6 /* packet dropped because frag size changed */
95 #define STAT_FMT_CHANGE 7 /* # times fmt changed */
96
97 u_char* RTPv1H261Decoder::wrkbuf_;
98 u_int RTPv1H261Decoder::wrkbuflen_;
99
100 RTPv1H261Decoder::RTPv1H261Decoder() : Decoder(2)
101 {
102 stat_[STAT_BAD_PSC].name = "Bad-PSC";
103 stat_[STAT_BAD_GOB].name = "Bad-GOB";
104 stat_[STAT_BAD_SYNTAX].name = "Bad-Syntax";
105 stat_[STAT_BAD_FMT].name = "Bad-fmt";
106 stat_[STAT_BAD_SIZE].name = "Bad-size";
107 stat_[STAT_BAD_BITOFF].name = "Bad-bitoff";
108 stat_[STAT_SIZE_CHANGE].name = "Size-change";
109 stat_[STAT_FMT_CHANGE].name = "Fmt-change";
110 nstat_ = 8;
111
112 /* cause a resize trigger later */
113 inw_ = 0;
114 inh_ = 0;
115 csss_ = 420;
116 seqno_ = 0;
117 packetsize_ = 0;
118 for (int i = 0; i < H261_SLOTS; ++i) {
119 slot_[i].len = 0;
120 slot_[i].flags = 0;
121 slot_[i].seqno = 0;
122 slot_[i].bp = 0;
123 }
124 slotbuf_ = 0;
125 codec_ = new FullP64Decoder();
126 resize(codec_->width(), codec_->height());
127 codec_->marks(rvts_);
128 }
129
130 RTPv1H261Decoder::~RTPv1H261Decoder()
131 {
132 delete slotbuf_;
133 delete codec_;
134 }
135
136 void RTPv1H261Decoder::stats(char* wrk)
137 {
138 /* pull stats out of vic indepdendent P64Decoder */
139 setstat(STAT_BAD_PSC, codec_->bad_psc());
140 setstat(STAT_BAD_GOB, codec_->bad_GOBno());
141 setstat(STAT_BAD_SYNTAX, codec_->bad_bits());
142 setstat(STAT_BAD_FMT, codec_->bad_fmt());
143 Decoder::stats(wrk);
144 }
145
146 /*
147 * Packets waiting for reassembly are kept in 'slots'
148 * indexed by the low bits of the sequence number.
149 * To try to avoid copying packets twice, we assume
150 * that the packet source is breaking packets at some
151 * fixed, max size (which we can determine from the size
152 * of a packet with the SOG marker) and we allocate the buffer
153 * for slots to be this size. As long as a packet doesn't
154 * wrap, this should make the final packets contiguous.
155 */
156 inline const u_char*
157 RTPv1H261Decoder::reassemble(const u_char* bp, int& cc,
158 u_int& rseqno, u_int& rflags)
159 {
160 register int flags = rflags;
161 /* FIXME if the packet is complete just render it */
162 if ((flags & 0x88) == 0x88)
163 return (bp);
164
165 register u_int seqno = rseqno;
166 if (packetsize_ != cc) {
167 if (packetsize_ == 0) {
168 if ((flags & 0x80) == 0)
169 return (0);
170 packetsize_ = cc;
171 u_int len = cc * H261_SLOTS;
172 slotbuf_ = new u_char[len+4];
173 u_char* bp = slotbuf_ + 4;
174 for (int i = 0; i < H261_SLOTS; ++i) {
175 slot_[i].bp = bp;
176 bp += cc;
177 }
178 if (len > wrkbuflen_) {
179 delete wrkbuf_;
180 wrkbuf_ = new u_char[len+4];
181 wrkbuflen_ = len;
182 }
183 } else if ((flags & 0x08) == 0 || cc > packetsize_) {
184 count(STAT_SIZE_CHANGE);
185 delete slotbuf_;
186 slotbuf_ = 0;
187 packetsize_ = 0;
188 for (int i = 0; i < H261_SLOTS; ++i) {
189 slot_[i].len = 0;
190 slot_[i].flags = 0;
191 slot_[i].seqno = 0;
192 slot_[i].bp = 0;
193 }
194 return (0);
195 }
196 }
197 register u_int l = seqno & H261_SLOTMASK;
198
199 slot_[l].len = cc;
200 slot_[l].seqno = seqno;
201 slot_[l].flags = flags;
202 memcpy((char*)slot_[l].bp, (char*)bp, cc);
203
204 /*
205 * Don't bother trying to reassemble packet unless it
206 * has an EOG marker or we have the next packet.
207 */
208 if ((flags & 0x08) == 0 &&
209 ((seqno + 1) & 0xffff) !=
210 slot_[(l + 1) & H261_SLOTMASK].seqno)
211 return (0);
212
213 /* scan backward for BOG */
214 register u_int pseq = seqno;
215 register u_int f = l;
216 while ((slot_[f].flags & 0x80) == 0) {
217 pseq = (pseq - 1) & 0xffff;
218 f = pseq & H261_SLOTMASK;
219 if (slot_[f].seqno != pseq)
220 /* packet missing */
221 return (0);
222 }
223
224 /* scan forward for EOG */
225 while ((slot_[l].flags & 0x08) == 0) {
226 seqno = (seqno + 1) & 0xffff;
227 l = seqno & H261_SLOTMASK;
228 if (slot_[l].seqno != seqno)
229 /* packet missing */
230 return (0);
231 }
232
233 if (l < f) {
234 /* packet wraps around buffer, have to copy it */
235 u_char* wp = wrkbuf_ + 4;
236 register u_int i = f - 1;
237 do {
238 i = (i + 1) & H261_SLOTMASK;
239 register int slen = slot_[i].len;
240 memcpy((char*)wp, (char*)slot_[i].bp, slen);
241 wp += slen;
242 } while (i != l);
243 bp = wrkbuf_ + 4;
244 cc = wp - bp;
245 } else {
246 bp = slot_[f].bp;
247 cc = slot_[l].bp - bp + slot_[l].len;
248 }
249
250 /*
251 * At this point, all we care about is ebit and sbit.
252 */
253 flags = slot_[f].flags & 0x70;
254 flags |= slot_[l].flags & 0x07;
255 rflags = flags;
256 rseqno = seqno;
257
258 return (bp);
259 }
260
261 void RTPv1H261Decoder::recv(pktbuf* pb)
262 {
263 rtphdr* rh = (rtphdr*)pb->dp;
264 u_int8_t* vh = (u_int8_t*)(rh + 1);
265 /*
266 * if the packet has a non-zero sbit but no SOG or
267 * a non-zero ebit but no EOG, toss it.
268 * if the packet contains both start & end gobs we can
269 * just render it. Otherwise we wait until we get the
270 * start and end markers and all the packets in between.
271 */
272 u_int v = ntohs(*(u_int16_t*)vh);
273 u_int flags = v >> 8;
274 if (((flags & 0x70) != 0 && (flags & 0x80) == 0) ||
275 ((flags & 0x07) != 0 && (flags & 0x08) == 0)) {
276 count(STAT_BAD_BITOFF);
277 return;
278 }
279
280 int cc = pb->len - (sizeof(*rh) + 2);
281 const u_int8_t* bp = vh + 2;
282 u_int seqno = ntohs(rh->rh_seqno);
283 bp = reassemble(bp, cc, seqno, flags);
284 if (bp == 0)
285 return;
286
287 int sbit = (flags >> 4) & 7;
288 int ebit = flags & 7;
289
290 /* FIXME tack on the start code */
291 /*FIXME*/
292 cc += 2;
293 bp -= 2;
294 ((u_char*)bp)[0] = 0;
295 if (sbit == 0)
296 ((u_char*)bp)[1] = 1;
297 else {
298 ((u_char*)bp)[1] = 0;
299 ((u_char*)bp)[2] |= 0x100 >> sbit;
300 }
301
302 codec_->mark(now_);
303 (void)codec_->decode(bp, cc, sbit, ebit, 0, 0, 0, 0, 0);
304 /*
305 * If the stream changes format, issue a resize.
306 */
307 if (codec_->width() != inw_) {
308 count(STAT_FMT_CHANGE);
309 resize(codec_->width(), codec_->height());
310 codec_->marks(rvts_);
311 }
312
313 /*FIXME*/
314 if (ntohs(rh->rh_flags) & RTP_M) {
315 codec_->sync();
316 ndblk_ = codec_->ndblk();
317 render_frame(codec_->frame());
318 codec_->resetndblk();
319 }
320 pb->release();
321 }
322
323 int RTPv1H261Decoder::colorhist(u_int* hist) const
324 {
325 const u_char* frm = codec_->frame();
326 int w = inw_;
327 int h = inh_;
328 int s = w * h;
329 colorhist_420_556(hist, frm, frm + s, frm + s + (s >> 2), w, h);
330 return (1);
331 }
332
333 void RTPv1H261Decoder::redraw()
334 {
335 if (codec_ != 0)
336 Decoder::redraw(codec_->frame());
337 }
338
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.