1 /*
2 * pipe_rend.cc --
3 *
4 * FIXME: This file needs a description here.
5 *
6 * Copyright (c) 2001-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 #include "pipe_rend.h"
35 #define ALPHA 90 // convergence for average diff size (out of 100)
36
37 // Note: pntypes.h must be included before windows.h for MSVC6.0
38 #include <stdio.h>
39 #include <assert.h>
40
41 // This class is a psuedo renderer that grabs the YUV frames and instead of
42 // passing it to the screen, it gives it to a RealNetworks encoding engine. For use
43 // in tgw.
44
45 static class PipeRendererClass : public TclClass {
46 public:
47 PipeRendererClass() : TclClass ("Module/Renderer/PipeRenderer") {};
48 TclObject* create(int /* argc */, const char*const* /* argv */) {
49 return (new PipeRenderer);
50 };
51 } rm_Pipe;
52
53 PipeRenderer::PipeRenderer() : ConditionalReplenisher(), encoder_(0),frame_data_(0), avg_diff_size_(0), bidder_house_(0), diff_threshold(24), diffs_want_to_send(0) {
54 // fd = fopen ("blah", "w");
55 frame_ = new YuvFrame(0,0,0,0,420,0);
56 }
57
58 PipeRenderer::~PipeRenderer() {
59 // fclose (fd);
60 }
61
62 // This is to report the bandwidht usage for this source back to the UI (which is bandwidthObj)
63 void PipeRenderer::bandwidthUsage(int x) {
64 Tcl& tcl = Tcl::instance();
65 tcl.evalf("%s %d", bandwidthObj, x);
66 }
67
68 // receive a YUV frame, setup structures if this is the first frame, else do the conditional
69 // replenishment checks and report to the auction house how much data you want to send...
70 void PipeRenderer::recv(Buffer* b) {
71 YuvFrame* in_frame_ = (YuvFrame*)b;
72 int y;
73
74 if ((in_frame_->width_ != frame_->width_) ||
75 (in_frame_->height_ != frame_->height_)) {
76
77 /* First time called or frame size changed. Reallocate frame data space and reinit crvec */
78
79 if (frame_data_ != 0) {
80 delete [] frame_data_;
81 }
82 y = in_frame_->width_*in_frame_->height_*3/2;
83 frame_data_ = new u_int8_t[y];
84
85 memcpy(frame_data_, in_frame_->bp_, y);
86
87 crinit(in_frame_->width_, in_frame_->height_);
88 y = ((in_frame_->width_ >> 4) * (in_frame_->height_ >>4));
89 crvec_to_send_ = new u_char[y];
90 crvec_not_sent_ = new u_char[y];
91 bzero(crvec_not_sent_, y);
92
93 frame_->crvec_ = crvec_to_send_;
94 frame_->bp_ = frame_data_;
95 frame_->width_ = in_frame_->width_;
96 frame_->height_ = in_frame_->height_;
97 frame_->layer_ = 0;
98 } else {
99 // Frame size is the same, so do conditional replenishment.
100 int mark = age_blocks() | CR_MOTION_BIT | CR_LQ;
101
102 register int _stride = in_frame_->width_;
103
104 const u_char* rb = &(frame_data_[scan_ * _stride]);
105 const u_char* lb = &(in_frame_->bp_[scan_ * _stride]);
106
107 u_char* crv = crvec_;
108
109 int bw = frame_->width_/16;
110 int bh = frame_->height_/16;
111
112 for (y = 0; y < bh; y++) {
113 const u_char* nrb = rb;
114 const u_char* nlb = lb;
115 u_char* ncrv = crv;
116
117 for (int x = 0; x < bw; x++) {
118 int tl = 0;
119 int tc1 = 0;
120 int tc2 = 0;
121 int tr = 0;
122 int bl = 0;
123 int bc1 = 0;
124 int bc2 = 0;
125 int br = 0;
126
127 tl = lb[0] - rb[0] + lb[1] - rb[1] + lb[2] - rb[2] + lb[3] - rb[3];
128 if (tl < 0) tl = -tl;
129
130 tc1 = lb[4] - rb[4] + lb[5] - rb[5] + lb[6] - rb[6] + lb[7] - rb[7];
131 if (tc1 < 0) tc1 = -tc1;
132
133 tc2 = lb[8] - rb[8] + lb[9] - rb[9] + lb[10] - rb[10] + lb[11] -rb[11];
134 if (tc2 < 0) tc2 = -tc2;
135
136 tr = lb[12] - rb[12] + lb[13] - rb[13] + lb[14] - rb[14] +
137 lb[15] - rb[15];
138 if (tr < 0) tr = -tr;
139
140 lb += _stride << 3;
141 rb += _stride << 3;
142
143 bl = lb[0] - rb[0] + lb[1] - rb[1] + lb[2] - rb[2] + lb[3] - rb[3];
144 if (bl < 0) bl = -bl;
145
146 bc1 = lb[4] - rb[4] + lb[5] - rb[5] + lb[6] - rb[6] + lb[7] - rb[7];
147 if (bc1 < 0) bc1 = -bc1;
148
149 bc2 = lb[8] - rb[8] + lb[9] - rb[9] + lb[10] - rb[10] + lb[11] -rb[11];
150 if (bc2 < 0) bc2 = -bc2;
151
152 br = lb[12] - rb[12] + lb[13] - rb[13] + lb[14] - rb[14] +
153 lb[15] - rb[15];
154 if (br < 0) br = -br;
155
156 lb -= _stride << 3;
157 rb -= _stride << 3;
158
159 if (scan_ < 4) {
160 /* // north-west
161 if ((tl >= diff_threshold) && (x > 0) && (y > 0)) {
162 crv[-bw-1] = mark;
163 }
164 // north
165 if (((tl >= diff_threshold) || (tc1 >= diff_threshold) || (tc2 >= diff_threshold) || (tr >= diff_threshold)) &&
166 (y > 0)) {
167 crv[-bw] = mark;
168 }
169 // north-east
170 if ((tr >= diff_threshold) && (x < bw - 1) && (y > 0)) {
171 crv[-bw+1] = mark;
172 }
173 // west
174 if (((tl >= diff_threshold) || (bl >= diff_threshold)) && (x > 0)) {
175 crv[-1] = mark;
176 } */
177 // middle
178 if ((tl >= diff_threshold) || (tc1 >= diff_threshold) || (tc2 >= diff_threshold) || (tr >= diff_threshold) ||
179 (bl >= diff_threshold) || (bc1 >= diff_threshold) || (bc2 >= diff_threshold) || (br >= diff_threshold)) {
180 crv[0] = mark;
181 }/*
182 // east
183 if (((tr >= diff_threshold) || (br >=diff_threshold)) && (x < bw - 1)) {
184 crv[1] = 0;
185 }*/
186 } else {
187 /* // south-west
188 if ((bl >= diff_threshold) && (x > 0) && (y < bh-1)) {
189 crv[bw-1] = mark;
190 }
191 // south
192 if (((bl >= diff_threshold) || (bc1 >= diff_threshold) || (bc2 >= diff_threshold) || (br >= diff_threshold)) &&
193 (y < bh-1)) {
194 crv[bw] = mark;
195 }
196 // south-east
197 if ((br >= diff_threshold) && (x < bw - 1) && (y < bh - 1)) {
198 crv[bw+1] = mark;
199 }
200 // west
201 if (((bl >= diff_threshold) || (tl >= diff_threshold)) && (x > 0)) {
202 crv[-1] = mark;
203 } */
204 // middle
205 if ((bl >= diff_threshold) || (bc1 >= diff_threshold) || (bc2 >= diff_threshold) || (br >= diff_threshold) ||
206 (tl >= diff_threshold) || (tc1 >= diff_threshold) || (tc2 >= diff_threshold) || (tr >= diff_threshold)) {
207 crv[0] = mark;
208 }
209 /* // east
210 if (((br >= diff_threshold) || (tr >=diff_threshold)) && (x < bw - 1)) {
211 crv[1] = 0;
212 } */
213 }
214 lb += 16;
215 rb += 16;
216 crv++;
217 }
218 lb = nlb + (_stride << 4);
219 rb = nrb + (_stride << 4);
220 crv = ncrv + bw;
221 }
222
223 // Copy blocks into frame based on conditional replenishment
224
225 crv = crvec_;
226 int off = frame_->width_ * frame_->height_;
227 u_char* dest_lum = frame_data_;
228 u_char* dest_cr = frame_data_+off;
229 u_char* dest_cb = frame_data_+off+(off/4);
230 u_char* src_lum = in_frame_->bp_;
231 u_char* src_cr = in_frame_->bp_+off;
232 u_char* src_cb = in_frame_->bp_+off+(off/4);
233
234 for (y = 0; y < bh; y++) {
235 int i;
236 for (int x = 0; x < bw; x++) {
237 int s = *crv++;
238 if ((s & CR_SEND) != 0) {
239 int idx = y*_stride*16+x*16;
240 u_int32_t* sl = (u_int32_t*) &(src_lum[idx]);
241 u_int32_t* dl = (u_int32_t*) &(dest_lum[idx]);
242 for(i=0; i<16; i++) {
243 dl[0] = sl[0];
244 dl[1] = sl[1];
245 dl[2] = sl[2];
246 dl[3] = sl[3];
247 dl += (_stride / 4);
248 sl += (_stride / 4);
249 }
250
251 idx = y*(_stride/2)*8+x*8;
252 u_int32_t* scr = (u_int32_t*) &(src_cr[idx]);
253 u_int32_t* scb = (u_int32_t*) &(src_cb[idx]);
254 u_int32_t* dcr = (u_int32_t*) &(dest_cr[idx]);
255 u_int32_t* dcb = (u_int32_t*) &(dest_cb[idx]);
256 for(i=0; i<8; i++) {
257 dcr[0] = scr[0];
258 dcr[1] = scr[1];
259 dcb[0] = scb[0];
260 dcb[1] = scb[1];
261 dcr += _stride / 8;
262 dcb += _stride / 8;
263 scr += _stride / 8;
264 scb += _stride / 8;
265 }
266 }
267 }
268 }
269 }
270 frame_->ts_ = in_frame_->ts_;
271
272 // calculate how many diffs you want to send.
273 diffs_want_to_send = 0;
274 for (y=((in_frame_->width_ >> 4) * (in_frame_->height_ >>4))-1;y>=0;y--) {
275 if ((crvec_[y] & CR_SEND) != 0) {
276 crvec_not_sent_[y] = crvec_[y];
277 diffs_want_to_send++;
278 } else if ((crvec_not_sent_[y] & CR_SEND) != 0) {
279 diffs_want_to_send++;
280 }
281 }
282
283 // should only occur at startup...
284 if (avg_diff_size_ == 0)
285 avg_diff_size_ = 50;
286
287 // printf("diffs_want_to_send: %x, %d, avg_diff_size:%d\n", this, diffs_want_to_send, avg_diff_size_);
288 // tell the auction house how much data you want to send.
289 bidder_house_->setDiffCount(this, diffs_want_to_send, avg_diff_size_);
290 }
291
292 // The auction house now tells the source that it can go ahead and send its data.
293 void PipeRenderer::giveToEncoder(int diffs_to_send) {
294 // fprintf(fd, "diffs_going_to_send: %x, %d\n", this, diffs_to_send);
295 int x, marker, rand_num;
296 int bytes_sent = 0;
297 int size_of_crvec = ((frame_->width_ >> 4) * (frame_->height_ >>4));
298
299 bzero(crvec_to_send_, size_of_crvec);
300
301 if (diffs_to_send <= 0) {
302 return;
303 } else if (diffs_to_send >= diffs_want_to_send) {
304 // we can send all our updates.
305 memcpy(crvec_to_send_, crvec_not_sent_, size_of_crvec);
306 bzero(crvec_not_sent_, size_of_crvec);
307 } else {
308 // we can only send a subset (randomly chosen) of our data.
309 for (x = 0; x < diffs_to_send; x++) {
310 rand_num = random()%size_of_crvec;
311 marker = rand_num;
312 while (((crvec_not_sent_[rand_num]) & CR_SEND) == 0) {
313 rand_num = (rand_num+1)%size_of_crvec;
314 if (rand_num == marker) {
315 // fprintf(fd, "we were told to send too much\n");
316 Tcl::instance().eval("puts \"we were told to send more diffs then we have to send\"");
317 break;
318 }
319 }
320 crvec_to_send_[rand_num] = crvec_not_sent_[rand_num];
321 crvec_not_sent_[rand_num] = 0;
322 }
323 }
324
325 if (encoder_ != 0) {
326 // record how much data was actually sent.
327 bytes_sent = encoder_->nb();
328 encoder_->recv(frame_);
329 bytes_sent = encoder_->nb() - bytes_sent;
330 avg_diff_size_ = ((ALPHA*avg_diff_size_) + ((100-ALPHA)*(bytes_sent/diffs_to_send)))/100;
331 }
332 }
333
334 int PipeRenderer::command(int argc, const char*const* argv) {
335 Tcl& tcl = Tcl::instance();
336 if (argc == 3) {
337 if (strcmp(argv[1], "attach_encoder") == 0) {
338 encoder_ = (EncoderModule*)TclObject::lookup(argv[2]);
339 if (encoder_ == 0) {
340 tcl.resultf("%s attach_encoder: no such encoder: %s", argv[0], argv[2]);
341 return (TCL_ERROR);
342 }
343 return (TCL_OK);
344 } else if (strcmp(argv[1], "use_auction_house") == 0) {
345 bidder_house_ = (BidderHouse*)TclObject::lookup(argv[2]);
346 if (bidder_house_ == 0) {
347 tcl.resultf("%s use_auction_house: no such bidder house: %s", argv[0], argv[2]);
348 return (TCL_ERROR);
349 }
350 bidder_house_->addSource(this);
351 return (TCL_OK);
352 } else if (strcmp(argv[1], "bandwidth_display") == 0) {
353 sprintf(bandwidthObj, "%s change_bwUsage", argv[2]);
354 return (TCL_OK);
355 }
356 }
357 return (Renderer::command(argc, argv));
358 }
359
360
361
362
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.