1 /*
2 * transcoder-h261.cc --
3 *
4 * H.261 Transcoder
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 #ifndef lint
35 static const char rcsid[] =
36 "@(#) $Header: /usr/mash/src/repository/mash/mash-1/codec/video/transcoder-h261.cc,v 1.13 2003/11/19 19:20:24 aswan Exp $";
37 #endif
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #ifndef WIN32
43 #include <sys/param.h>
44 #include <netinet/in.h>
45 #endif
46 #include "rtp/inet.h"
47 #include "rtp/rtp.h"
48 #include "codec/transcoder.h"
49 #include "net/transmitter.h"
50 #include "codec/p64/p64.h"
51 #include "codec/crdef.h"
52
53 class H261Transcoder : public VideoTranscoder {
54 public:
55 H261Transcoder();
56 ~H261Transcoder();
57 protected:
58 virtual void configure() = 0;
59 P64Decoder* decoder_;
60 int ibit_;
61 int h261_rtp_bug_;
62 };
63
64 #ifdef notyet
65 class H261DCTTranscoder : public H261Transcoder {
66 public:
67 virtual void configure();
68 virtual void recv_data(pktbuf* pb);
69 };
70 #endif
71
72 class H261PixelTranscoder : public H261Transcoder {
73 public:
74 virtual void configure();
75 virtual void recv_data(pktbuf* pb);
76 };
77
78 #ifdef notyet
79 static class H261DCTTranscoderClass : public TclClass {
80 public:
81 H261DCTTranscoderClass() : TclClass("Transcoder/H261/DCT") {}
82 TclObject* create(int, const char*const*) {
83 return (new H261DCTTranscoder);
84 }
85 } h261_dct_transcoder_class;
86 #endif
87
88 static class H261PixelTranscoderClass : public TclClass {
89 public:
90 H261PixelTranscoderClass() : TclClass("Transcoder/H261/Pixel") {}
91 TclObject* create(int, const char*const*) {
92 return (new H261PixelTranscoder);
93 }
94 } h261_pixel_transcoder_class;
95
96 H261Transcoder::H261Transcoder()
97 :VideoTranscoder(4), decoder_(0),
98 ibit_(-1), h261_rtp_bug_(0)
99 {}
100
101 H261Transcoder::~H261Transcoder()
102 {
103 delete decoder_;
104 }
105
106 #ifdef notyet
107 void H261DCTTranscoder::configure()
108 {
109 delete decoder_;
110 if (ibit_ != 0)
111 decoder_ = new IntraP64DCTDecoder();
112 else
113 decoder_ = new FullP64Decoder();
114
115 decoder_->mark(CR_SEND|CR_MOTION);
116 }
117 #endif
118
119 void H261PixelTranscoder::configure()
120 {
121 delete decoder_;
122 if (ibit_ != 0)
123 decoder_ = new IntraP64Decoder();
124 else
125 decoder_ = new FullP64Decoder();
126
127 decoder_->mark(CR_MOTION_BIT | CR_LQ);
128 }
129
130 void H261PixelTranscoder::recv_data(pktbuf* pb)
131 {
132 rtphdr* rh = (rtphdr*)(pb->dp);
133 int cc = pb->len - sizeof(rtphdr);
134 const u_char* bp = (const u_char*)(rh + 1);
135
136 u_int v = ntohl(*(u_int*)(rh + 1));
137 int sbit = v >> 29;
138 int ebit = (v >> 26) & 7;
139 int quant = (v >> 10) & 0x1f;
140 int mvdh = (v >> 5) & 0x1f;
141 int mvdv = v & 0x1f;
142 int mba, gob;
143 /*
144 * vic-2.7 swapped the GOB and MBA fields in the RTP packet header
145 * with respect to the spec. To maintain backward compat, whenever
146 * we see an out of range gob, we change our assumption about the
147 * stream and continue.
148 */
149 if (!h261_rtp_bug_) {
150 mba = (v >> 15) & 0x1f;
151 gob = (v >> 20) & 0xf;
152 if (gob > 12) {
153 h261_rtp_bug_ = 1;
154 mba = (v >> 19) & 0x1f;
155 gob = (v >> 15) & 0xf;
156 }
157 } else {
158 mba = (v >> 19) & 0x1f;
159 gob = (v >> 15) & 0xf;
160 if (gob > 12) {
161 h261_rtp_bug_ = 0;
162 mba = (v >> 15) & 0x1f;
163 gob = (v >> 20) & 0xf;
164 }
165 }
166
167 if (gob > 12) {
168 pb->release();
169 return;
170 }
171
172 int ibit = (v >> 25) & 1;
173 if (ibit != ibit_) {
174 ibit_ = ibit;
175 configure();
176 }
177
178 bp += 4;;
179 cc -= 4;
180
181 decoder_->marks(crvec_);
182 (void)decoder_->decode(bp, cc, sbit, ebit, mba, gob, quant, mvdh,
183 mvdv);
184 pb->release();
185 /*
186 * If the stream changes format, issue a resize.
187 */
188 if (decoder_->width() != inw_ || decoder_->height() != inh_) {
189 inw_ = decoder_->width();
190 inh_ = decoder_->height();
191 Tcl& tcl = Tcl::instance();
192 tcl.evalf("%s frame_width %d", encoder_->name(), inw_);
193 outw_ = atoi(tcl.result());
194 tcl.evalf("%s frame_height %d", encoder_->name(), inh_);
195 outh_ = atoi(tcl.result());
196 pixel_crinit(outw_, outh_);
197 decoder_->marks(crvec_);
198 }
199
200 if (!(ntohs(rh->rh_flags) & RTP_M))
201 return;
202
203 /*
204 * Have a frame.
205 */
206 decoder_->sync();
207
208 double now;
209 if (!txonly_) {
210 if (bps_ == 0)
211 return;
212 now = gettimeofday();
213 }
214
215 if (fc_ <= now || txonly_) {
216 /* If we have fallen behind (>200ms), re-sync. */
217 if (now - fc_ > 200000.)
218 fc_ = now;
219 blk_to_mb_cr();
220 YuvFrame vf(ntohl(rh->rh_ts),
221 ((P64Decoder*)decoder_)->frame(),
222 mb_crvec_, outw_, outh_, 420);
223 int nb = encoder_->nb();
224 encoder_->recv(&vf);
225 obytes_ = encoder_->nb();
226 nb = obytes_ - nb;
227 double bits = 8 * nb;
228 lastfc_ = fc_;
229 fc_ += 1e6 * bits / bps_;
230 ofrms_++;
231
232 decoder_->mark(age_blocks() | CR_MOTION_BIT | CR_LQ);
233 }
234 }
235
236 #ifdef notyet
237 void H261DCTTranscoder::recv_data(pktbuf* pb)
238 {
239 rtphdr* rh = (rtphdr*)(pb->dp);
240 int cc = pb->len - sizeof(rtphdr);
241 const u_char* bp = (const u_char*)(rh + 1);
242
243 u_int v = ntohl(*(u_int*)(rh + 1));
244 int sbit = v >> 29;
245 int ebit = (v >> 26) & 7;
246 int quant = (v >> 10) & 0x1f;
247 int mvdh = (v >> 5) & 0x1f;
248 int mvdv = v & 0x1f;
249 int mba, gob;
250 /*
251 * vic-2.7 swapped the GOB and MBA fields in the RTP packet header
252 * with respect to the spec. To maintain backward compat, whenever
253 * we see an out of range gob, we change our assumption about the
254 * stream and continue.
255 */
256 if (!h261_rtp_bug_) {
257 mba = (v >> 15) & 0x1f;
258 gob = (v >> 20) & 0xf;
259 if (gob > 12) {
260 h261_rtp_bug_ = 1;
261 mba = (v >> 19) & 0x1f;
262 gob = (v >> 15) & 0xf;
263 }
264 } else {
265 mba = (v >> 19) & 0x1f;
266 gob = (v >> 15) & 0xf;
267 if (gob > 12) {
268 h261_rtp_bug_ = 0;
269 mba = (v >> 15) & 0x1f;
270 gob = (v >> 20) & 0xf;
271 }
272 }
273
274 int ibit = (v >> 25) & 1;
275 if (ibit != ibit_) {
276 ibit_ = ibit;
277 configure();
278 }
279
280 bp += sizeof(h261hdr);
281 cc -= sizeof(h261hdr);
282
283 (void)decoder_->decode(bp, cc, sbit, ebit, mba, gob, quant, mvdh,
284 mvdv);
285 pb->release();
286 /*
287 * If the stream changes format, issue a resize.
288 */
289 if (decoder_->width() != inw_ || decoder_->height() != inh_) {
290 inw_ = decoder_->width();
291 inh_ = decoder_->height();
292 Tcl& tcl = Tcl::instance();
293 tcl.evalf("%s frame_width %d", encoder_->name(), inw);
294 outw_ = atoi(tcl.result());
295 tcl.evalf("%s frame_height %d", encoder_->name(), inh);
296 outh_ = atoi(tcl.result());
297 crinit(outw_, outh_);
298 decoder_->marks(crvec_);
299 }
300
301 if (!(ntohs(rh->rh_flags) & RTP_M))
302 return;
303
304 /*
305 * Have a frame.
306 */
307 decoder_->sync();
308
309 if (bps_ == 0)
310 return;
311
312 double now = gettimeofday();
313 if (fc_ <= now) {
314 /* If we have fallen behind (>200ms), re-sync. */
315 if (now - fc_ > 200000.)
316 fc_ = now;
317 DCTFrame df(ntohl(rh->rh_ts),
318 (IntraP64DCTDecoder*)decoder_->frame(), crvec_,
319 outw_, outh_, 420);
320 int nb = encoder_->nb();
321 encoder_->recv(&df);
322 obytes_ = encoder_->nb();
323 nb = obytes_ - nb;
324 double bits = 8 * nb;
325 lastfc_ = fc_;
326 fc_ += 1e6 * bits / bps_;
327 ofrms_++;
328
329 mark_ = age_blocks() | CR_MOTION_BIT | CR_LQ;
330 }
331 }
332 #endif
333
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.