1 /*
2 * decoder-jpeg.cc --
3 *
4 * Motion Jpeg decoder source file
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-jpeg.cc,v 1.43 2003/11/19 19:20:17 aswan Exp $";
36
37 #include <fstream.h>
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <iostream.h>
43 #include "rtp/inet.h"
44 #include "rtp/rtp.h"
45 #include "codec/decoder.h"
46 #include "misc/bsd-endian.h"
47 #include "tclcl.h"
48 #include "codec/jpeg/jpeg.h"
49 #include "render/renderer.h"
50 #include "net/pktbuf.h"
51 #include "codec/postdct.h"
52
53 #include "codec/decoder-jpeg.h"
54
55
56 static class MotionJpegDecoderClass : public TclClass {
57 public:
58 MotionJpegDecoderClass() : TclClass("Module/VideoDecoder/JPEG") {}
59 TclObject* create(int /* argc */, const char*const* /* argv */) {
60 return (new MotionJpegDecoder());
61 }
62 } dm_mjpeg;
63
64
65 // end of image
66 #define EOI 0xd9
67
68 // bit in the jpeg header type field that
69 // indicates if the image has restart markers
70 #define JPEG_HDR_RESTART_BIT 0x40
71 struct restarthdr {
72 u_int16_t interval;
73 u_int16_t count;
74 };
75
76 // initial/max size of each reassembly buffer.
77 #define JPEG_BUFSIZE (16*1024)
78 #define JPEG_MAXSIZE (512*1024)
79
80 #define STAT_BADOFF 0
81 #define STAT_HUGEFRM 1
82 #define STAT_BADTYPE 2
83
84
85 //
86 // JpegReassembler --
87 //
88
89 JpegReassembler::JpegReassembler()
90 : decimate_(0), ndec_(0), hugefrm_(0), badoff_(0)
91 {
92 rbsize_ = JPEG_BUFSIZE;
93 rb0_.bp = new u_char[2 * JPEG_BUFSIZE];
94 rb0_.ts = ~0;
95 rb0_.drop = 0;
96 rb0_.current = rb0_.bp;
97 rb0_.restartInterval = 0;
98 rb0_.restartCount = 0;
99 rb0_.len = 0;
100 rb1_.bp = &rb0_.bp[JPEG_BUFSIZE];
101 rb1_.ts = ~0;
102 rb1_.drop = 0;
103 rb1_.current = rb1_.bp;
104 rb1_.restartInterval = 0;
105 rb1_.restartCount = 0;
106 rb1_.len = 0;
107 memset(rb0_.bp, 0, 2*JPEG_BUFSIZE);
108
109 nslots_ = 64;
110 slotmask_ = nslots_ - 1;
111 slots_ = new slot[nslots_];
112 memset(slots_, 0, nslots_ * sizeof(slot));
113 prev_ = NULL;
114 current_ = NULL;
115 doneodd = false;
116 }
117
118 JpegReassembler::~JpegReassembler()
119 {
120 delete[] rb0_.bp;
121 }
122
123 /*
124 * Reassemble an RTP/JPEG stream. Return a pointer to a buffer
125 * each time we encounter an entire frame. Otherwise, return 0.
126 * Set len to the length of the jpeg data in the buffer.
127 */
128 u_char* JpegReassembler::reassemble(const rtphdr* rh,
129 const u_char* bp, int& len)
130 {
131 jpeghdr* p = (jpeghdr*)(rh + 1);
132 int off = int(ntohl(p->off) & 0xffffff);
133
134 int cc = len;
135 if (off < 0) {
136 ++badoff_;
137 return (0);
138 }
139
140 if (off + cc > rbsize_) {
141 /*
142 * Check for outrageous frame size.
143 */
144 if (off + cc > JPEG_MAXSIZE) {
145 ++hugefrm_;
146 return (0);
147 }
148
149 /*
150 * Grow reassembly buffers.
151 */
152 int nsize = rbsize_;
153 do {
154 nsize <<= 1;
155 } while (off + cc > nsize);
156 u_char* p = new u_char[2 * nsize];
157 memcpy(p, rb0_.bp, rbsize_);
158 memcpy(p + nsize, rb1_.bp, rbsize_);
159 delete[] rb0_.bp;
160 rb0_.bp = p;
161 rb1_.bp = p + nsize;
162 rbsize_ = nsize;
163 }
164
165 /*
166 * Initialize the slot data structure.
167 */
168 int seqno = ntohs(rh->rh_seqno);
169 int s = seqno & slotmask_;
170 u_int32_t ts = ntohl(rh->rh_ts);
171 slots_[s].seqno = seqno;
172 slots_[s].off = off;
173 slots_[s].ts = ts;
174
175 /*
176 * Figure out which reassembly-buffer to use. If we're not
177 * already reassembling this frame, take over the older buffer.
178 */
179 rbuf* rb;
180
181 if (ts == rb0_.ts)
182 rb = &rb0_;
183 else if (ts == rb1_.ts)
184 rb = &rb1_;
185 else {
186 rb = ((int)(rb0_.ts - rb1_.ts) < 0) ? &rb0_ : &rb1_;
187 rb->ts = ts;
188 rb->drop = 0;
189 /*
190 * If we're decimating frames (to save cycles),
191 * remember that we might want to drop the rest
192 * of the packets from this frame.
193 */
194
195 if (decimate_) {
196 if (--ndec_ <= 0)
197 ndec_ = decimate_;
198 else
199 rb->drop = 1;
200 }
201 }
202 if (rb->drop)
203 return (0);
204
205 memcpy((char*)&rb->bp[off], (char*)bp, cc);
206
207 /*
208 * Check if we're at end-of-frame. If not, see if we're
209 * filling a hole. If not, return. Otherwise, drop out
210 * below and check for an entire frame. We set cc to be
211 * the entire frame size in the if-else below.
212 */
213 if ((ntohs(rh->rh_flags) & RTP_M) != 0) {
214 slots_[s].eof = cc;
215 cc += off;
216 } else {
217 slots_[s].eof = 0;
218 startsearch:
219 int ns = s;
220 do {
221 ns = (ns + 1) & slotmask_;
222 if (slots_[ns].ts != ts)
223 return (0);
224
225 /*
226 * If we wrap all the way around, our
227 * slots_ data structure is too small
228 * for the frame we're receiving so
229 * resize it now.
230 */
231 if (ns == s) {
232 if (nslots_ > MAX_JPEG_SLOTS) {
233 ++hugefrm_;
234 return (0);
235 }
236 slot* newslots = new slot[2*nslots_];
237 memset(newslots, 0, 2*nslots_*sizeof(slot));
238
239 int newmask = 2*nslots_ - 1;
240 int i;
241 for (i=0; i<nslots_; i++) {
242 int seqno = slots_[i].seqno;
243 if (seqno == 0)
244 continue;
245 memcpy(&newslots[seqno&newmask],
246 &slots_[seqno&slotmask_],
247 sizeof(slot));
248 }
249 nslots_ *= 2;
250 slotmask_ = newmask;
251 delete[] slots_;
252 slots_ = newslots;
253 goto startsearch;
254 }
255 } while (slots_[ns].eof == 0);
256 cc = int(slots_[ns].eof + slots_[ns].off);
257 }
258
259 /*
260 * At this point, we know we have an end-of-frame, and
261 * all packets from slot 's' up until the end-of-frame.
262 * Scan backward from slot 's' making sure we have all
263 * packets from the start-of-frame (off == 0) to 's'.
264 */
265 int ps = s;
266 do {
267 ps = (ps - 1) & slotmask_;
268 if (slots_[ps].ts != ts || ps == s)
269 return (0);
270 } while (slots_[ps].off != 0);
271
272 len = cc;
273 return (rb->bp);
274 }
275
276 #ifdef notyet
277 /*
278 * Part of the recovery code. Took from Matt. Modified to fit into Mash
279 */
280 bool JpegReassembler::advancePrevPtr(rbuf * curr, rbuf * prev)
281 {
282 // check to see if we don't need to (or can't) advance the pointer
283 if(prev->restartCount>=curr->restartCount) {
284 // return true if equal, false if prev is ahead of us
285 if (prev->restartCount != curr->restartCount) {
286 #ifndef NDEBUG
287 cout << "ERROR !!!" << endl;
288 #endif
289 // Error
290 return false;
291 } else {
292 return true;
293 }
294
295 }
296
297 // compute how far we need to advance the pointer
298 int advance=curr->restartCount-prev->restartCount;
299
300 // scan ahead through the appropriate number of restart intervals
301 unsigned char * currPtr=prev->current;
302 for(; advance>0; --advance) {
303 int lastFF=0;
304 while(1) {
305 if(lastFF) { // if last character was a 0xff
306 if(*currPtr!=0) { // if not a 0xff in the byte stream
307 if(*currPtr==EOI && advance>1) { // if got eoi when need more data
308 #ifndef NDEBUG
309 cout << "ERROR: got EOI when when still need more to copy!!!"
310 << endl;
311 #endif
312 advance=0;
313 return false;
314 }
315 ++currPtr; // advance past the 'opcode' for the 0xff
316 break;
317 }
318 lastFF=0; // we've processed the 0xff, so unmark
319 }
320 else if(*currPtr==0xff)
321 lastFF=1; // mark that we saw a 0xff
322 ++currPtr;
323 }
324 }
325
326 // update the pointers and corresponding restart interval #
327 prev->current=currPtr;
328 // cout << "In AdvPrePt, before prev->RestartCount is " << prev->restartCount << endl;
329 prev->restartCount=curr->restartCount;
330 // cout << "In AdvPrePt, after prev->RestartCount is " << prev->restartCount << endl;
331 return true;
332 }
333
334
335 /*
336 * New Recover function. Took from Matt's recovery code. Modified to fit
337 * into Mash code
338 */
339
340 bool JpegReassembler::recoverFromPrev(rbuf * curr, rbuf * prev, int recoverTo)
341 {
342 // cout << "Doing recovering" << endl;
343 bool result;
344 result = advancePrevPtr(curr, prev);
345 if (!result) {
346 #ifndef NDEBUG
347 cout << "ERROR in AdvancePrevPtr" << endl;
348 #endif
349 abort();
350 }
351 // get the starting/ending pointers for copying data
352 unsigned char * startPtr=prev->current;
353 unsigned char * endPtr=prev->current;
354
355 if(recoverTo>=0) { // if we need to recover to a particular location
356
357 int i=recoverTo - (curr->restartCount*curr->restartInterval); // count how many to copy
358
359 if(!i)
360 return true; // no need to advance
361 else if(i<0)
362 return false; // we've already got this recovered
363
364 i/=prev->restartInterval; // convert MCUs to restart intervals
365
366 // scan for restart intervals to discover how much data to copy
367 for(; i>0; --i) { // see previous function for comments on code
368 int lastFF=0;
369 while(1) {
370 if(lastFF) {
371 if(*endPtr!=0) {
372 if(*endPtr==EOI && i>1) {
373 #ifndef NDEBUG
374 cout << "ERROR: got EOI when when still need more to copy!!!"
375 << endl;
376 #endif
377 return false;
378 }
379 ++endPtr;
380 break;
381 }
382 lastFF=0;
383 }
384 else if(*endPtr==0xff)
385 lastFF=1;
386 ++endPtr;
387 }
388 }
389 curr->restartCount=recoverTo / (curr->restartInterval);
390 }
391 else { // recover until EOI (the end of the jpeg image)
392 int lastFF=0;
393 while(1) {
394 if(lastFF) {
395 if(*endPtr==EOI) {
396 ++endPtr;
397 break;
398 }
399 lastFF=0;
400 }
401 else if(*endPtr==0xff)
402 lastFF=1;
403 ++endPtr;
404 }
405 #ifndef NDEBUG
406 cout << " Recover to " << (unsigned int)(endPtr-startPtr) << endl;
407 #endif
408 // what should nextIn be updated to?????
409 }
410
411 // copy data and update/advance the pointers (if something to copy)
412 if(endPtr-startPtr) {
413 memcpy(curr->current, startPtr, endPtr-startPtr);
414 curr->current+=endPtr-startPtr;
415 curr->len+=endPtr-startPtr;
416 // curr->recoveredFrame=1; // mark that recovery was performed
417 }
418 return true;
419 }
420
421
422
423
424 /*
425 * New Reassemble function. This function will attempt recover on an RTP/JPEG
426 * Stream. If a complete frame is done, it will return the entire frame,
427 * Otherwise, return 0.
428 */
429 u_char* JpegReassembler::recoverReassem(const rtphdr* rh, const u_char* bp, int& len, u_int32_t restartInterval, u_int32_t restartCount)
430 {
431
432 jpeghdr* p = (jpeghdr*)(rh + 1);
433 bool result = false;
434 unsigned int firstWord=(unsigned int)(ntohl(p->off)); // first word of jpeg header
435 unsigned int typeSpec=(firstWord&0xff000000)>>24;
436 int off = firstWord&0x00ffffff;
437 rbuf* returnFrame = NULL;
438
439 int cc = len;
440 if (off < 0) {
441 ++badoff_;
442 return (0);
443 }
444
445 /*
446 * Check for outrageous frame size.
447 */
448 if (off + cc > 256*1024) {
449 ++hugefrm_;
450 return (0);
451 }
452
453 if (off + cc > rbsize_) {
454 // This should be an error
455 #ifndef NDEBUG
456 cout << " Error in rbsize_ " << endl;
457 #endif
458 return (0);
459 }
460 // int seqno = ntohs(rh->rh_seqno);
461 // int s = seqno & JPEG_SLOTMASK;
462 u_int32_t ts = ntohl(rh->rh_ts);
463
464 // Check to see if we are in the middle of a frame
465
466 if ((current_ != NULL) && (ts == current_->ts)) {
467 if (restartCount == current_->restartCount) {
468 // Don't need recovery
469 memcpy((char*)(current_->current), (char*)bp, cc);
470 current_->len = current_->len + cc;
471
472
473 /*
474 ** count number of intervals in data so we know what to expect next time
475 */
476
477 int lastFF=0;
478 for( unsigned char * i= current_->current; i< current_->current+cc; ++i) {
479 if(lastFF) {
480 if(*i!=0)
481 current_->restartCount = current_->restartCount + 1;
482 lastFF=0;
483 }
484 else if(*i==0xff)
485 lastFF=1;
486 }
487 current_->current = current_->current + cc;
488
489 } else if (restartCount < current_->restartCount) {
490 // toss the frame because we have recovered
491 return (0);
492 } else {
493 // Need recovery
494 if (!((typeSpec == 1) && (doneodd))) {
495 // Don't have a previous frame
496 current_ = NULL;
497 return (0);
498 } else {
499 recoverFromPrev(current_, prev_, restartInterval*restartCount);
500
501 // Copy in the rest
502 memcpy((char*)(current_->current), (char*)bp, cc);
503 current_->len = current_->len + cc;
504 /*
505 ** count number of intervals in data so we know what to expect next time
506 */
507
508 int lastFF=0;
509 for( unsigned char * i= current_->current; i< current_->current+cc; ++i) {
510 if(lastFF) {
511 if(*i!=0)
512 current_->restartCount = current_->restartCount + 1;
513 lastFF=0;
514 }
515 else if(*i==0xff)
516 lastFF=1;
517 }
518 current_->current = current_->current + cc;
519
520 }
521 }
522 // Need to check if we are at the end of a frame
523 if ((ntohs(rh->rh_flags) & RTP_M) != 0) {
524 // We are indeed at the end of the frame
525 // Need to setup for the next field
526 if (typeSpec == 1) {
527 doneodd = true;
528 }
529 returnFrame = current_;
530 current_->current = current_->bp;
531 current_->restartCount = 0;
532 current_ = NULL;
533 prev_->current = prev_->bp;
534 prev_->restartCount = 0;
535 len = returnFrame->len;
536 return returnFrame->bp;
537 } else {
538 // Not at the end of the frame yet
539 return (0);
540 }
541 } else {
542 // New Frame
543 // We need to recover if current frame exists
544 if (current_ != NULL) {
545 // Need to recover
546 // cout << "Recover with recoverto == -1" << endl;
547 if (doneodd) {
548 result = recoverFromPrev(current_, prev_, -1);
549 current_->current = current_->bp;
550 current_->restartCount = 0;
551 prev_->current = prev_->bp;
552 prev_->restartCount = 0;
553 current_ = NULL;
554 returnFrame = current_;
555 }
556 }
557 if ((ts - rb0_.ts) <= (ts - rb1_.ts)) {
558 // Picking rb1_ as the current odd field and
559 // rb0_ as the previous
560 // cout << "Picking rb2" << endl;
561 current_ = &rb1_;
562 prev_ = &rb0_;
563 prev_->current = prev_->bp;
564 prev_->restartCount = 0;
565 } else {
566 // Picking rb0_ as the current odd field and
567 // rb1_ as the old
568 // cout << "Picking r0" << endl;
569 current_ = &rb0_;
570 prev_ = &rb1_;
571 prev_->current = prev_->bp;
572 prev_->restartCount = 0;
573 }
574 // Copying
575 current_->ts = ts;
576 current_->len = 0;
577 current_->restartInterval = restartInterval;
578 current_->restartCount = 0;
579 current_->current = current_->bp;
580 if (restartCount != 0) {
581 // Missing front of a frame
582 // FIXME When Prev_ is not initialized, need to do something else
583 if (doneodd)
584 if ((ntohs(rh->rh_flags) & RTP_M) == 0) {
585 recoverFromPrev(current_, prev_, restartInterval*restartCount);
586 } else {
587 current_ = NULL;
588 return (0);
589 }
590 else {
591 #ifndef NDEBUG
592 cout << "can't handle without the start" << endl;
593 cout << "The number for restartCount is " << restartCount << endl;
594 #endif
595 current_=NULL;
596 return(0);
597 }
598 }
599 // Copying
600 memcpy((char*)(current_->current), (char*)bp, cc);
601 current_->len += cc;
602 /*
603 ** count number of intervals in data so we know what to expect next time
604 */
605
606 int lastFF=0;
607 for( unsigned char * i= current_->current; i< current_->current+cc; ++i) {
608 if(lastFF) {
609 if(*i!=0)
610 current_->restartCount = current_->restartCount + 1;
611 lastFF=0;
612 }
613 else if(*i==0xff)
614 lastFF=1;
615 }
616
617 current_->current = current_->current + cc;
618 if (returnFrame != NULL) {
619 len = returnFrame->len;
620 return returnFrame->bp;
621 } else {
622 return (0);
623 }
624 }
625 }
626 #endif
627
628
629
630 //
631 // MotionJpegDecoder --
632 //
633
634 MotionJpegDecoder::MotionJpegDecoder()
635 : Decoder(sizeof(jpeghdr)), codec_(0)
636 {
637 JpegDecoder::defaults(config_);
638
639 inw_ = 0;
640 inh_ = 0;
641 inq_ = 0;
642 /* guess type 0 */
643 type_ = 0;
644 csss_ = 422;
645
646 stat_[STAT_BADOFF].name = "Bad-Offset";
647 stat_[STAT_HUGEFRM].name = "Huge-Frame";
648 stat_[STAT_BADTYPE].name = "Unsupported-Type";
649 nstat_ = 3;
650
651 drop_even_ = 1;
652 }
653
654 MotionJpegDecoder::~MotionJpegDecoder()
655 {
656 delete codec_;
657 }
658
659 void MotionJpegDecoder::stats(char* wrk)
660 {
661 /* pull stats out of reassembler */
662 setstat(STAT_BADOFF, reasm_.badoff());
663 setstat(STAT_HUGEFRM, reasm_.hugefrm());
664 setstat(STAT_BADTYPE, badtype_);
665 Decoder::stats(wrk);
666 }
667
668 int
669 MotionJpegDecoder::command(int argc, const char*const* argv)
670 {
671 Tcl& tcl = Tcl::instance();
672 if (strcmp(argv[1], "drop-even") == 0) {
673 if (argc == 2) {
674 tcl.resultf("%d", drop_even_);
675 return (TCL_OK);
676 }
677 else if (argc == 3) {
678 int d;
679 if (Tcl_GetBoolean(tcl.interp(), (char*)argv[2], &d) != TCL_OK)
680 return (TCL_ERROR);
681
682 drop_even_ = d;
683 return (TCL_OK);
684 }
685 }
686 return (Decoder::command(argc, argv));
687 }
688
689
690 void MotionJpegDecoder::configure()
691 {
692 config_.comp[0].hsf = 2;
693 int old_csss = csss_;
694 if (type_ == 1 || type_ == 65 ) { // MattD: spec now says 1, 65
695 csss_ = 420;
696 config_.comp[0].vsf = 2;
697 }
698 else if (type_ == 0 || type_ == 64) {
699 csss_ = 422;
700 config_.comp[0].vsf = 1;
701 }
702 else { // undefined type
703 // TODO: MattD: now what??; following old example
704 csss_ = 422;
705 config_.comp[0].vsf = 1;
706 }
707 config_.comp[1].hsf = 1;
708 config_.comp[1].vsf = 1;
709 config_.comp[2].hsf = 1;
710 config_.comp[2].vsf = 1;
711 config_.width = inw_;
712 config_.height = inh_;
713 JpegDecoder::quantizer(config_, inq_);
714
715 delete codec_;
716 codec_ = JpegPixelDecoder::create(config_, inw_, inh_);
717 Tcl& tcl = Tcl::instance();
718 int q;
719 #ifdef notyet
720 q = atoi(tcl.attr("softJPEGthresh"));
721 if (q < 0)
722 #endif
723 q = JpegDecoder::q_to_thresh(inq_);
724 codec_->thresh(q);
725 #ifdef notyet
726 int ct = atoi(tcl.attr("softJPEGcthresh"));
727 #else
728 int ct = 6;
729 #endif
730 codec_->cthresh(ct);
731
732 if (old_csss != csss_)
733 tcl.evalf("%s parameters_changed", name());
734 }
735
736 int MotionJpegDecoder::colorhist(u_int* hist) const
737 {
738 const u_char* frm = codec_->frame();
739 int off = inw_ * inh_;
740 if (csss_ == 420)
741 colorhist_420_556(hist, frm, frm + off, frm + off + (off >> 2),
742 inw_, inh_);
743 else
744 colorhist_422_556(hist, frm, frm + off, frm + off + (off >> 1),
745 inw_, inh_);
746 return (1);
747 }
748
749 void MotionJpegDecoder::recv(pktbuf* pb)
750 {
751 rtphdr* rh = (rtphdr*)pb->dp;
752 const jpeghdr* p = (const jpeghdr*)(rh + 1);
753 unsigned int typeSpec = ntohl(p->off) >> 24;
754
755 if (typeSpec != JPEG_FULL_FRAME
756 && typeSpec != JPEG_ODD_FIELD
757 && typeSpec != JPEG_EVEN_FIELD
758 && typeSpec != JPEG_SINGLE_FIELD) {
759
760 ++badtype_;
761 pb->release();
762 return;
763 }
764
765 int needConfig = 0;
766 if (p->q != inq_ || p->type != type_) {
767 type_ = p->type;
768 inq_ = p->q;
769 needConfig = 1;
770 }
771
772 int inw = p->width << 3;
773 int inh = p->height << 3;
774 if (typeSpec != JPEG_FULL_FRAME)
775 inh *= 2;
776
777 if (inw_ != inw || inh_ != inh) {
778 resize(inw, inh);
779 needConfig = 1;
780 }
781
782 if (needConfig) {
783 configure();
784 }
785
786 u_int8_t* bp = (u_int8_t*)(p + 1);
787 int cc = pb->len - (sizeof(*rh) + sizeof(*p));
788
789 // skip over the restart header
790 if (type_ & JPEG_HDR_RESTART_BIT) {
791 restarthdr* rh = (restarthdr*) bp;
792 bp += sizeof(restarthdr);
793 cc -= sizeof(restarthdr);
794
795 // FIXME Need to handle the case where F and L are not 1
796 restart_interval_ = ntohs(rh->interval);
797 restart_count_ = ntohs(rh->count) & 0x3fff;
798 } else {
799 restart_interval_ = 0;
800 }
801
802 /*
803 * If we're not doing interlacing, drop the
804 * even fields and line double the odd fields
805 */
806 if (drop_even_) {
807 if (typeSpec == JPEG_EVEN_FIELD) {
808 pb->release();
809 return;
810 }
811 else if (typeSpec == JPEG_ODD_FIELD) {
812 typeSpec = JPEG_SINGLE_FIELD;
813 }
814 }
815
816 #ifdef ERROR_RECOVERY
817 if (type_ & JPEG_HDR_RESTART_BIT) {
818 bp = reasm_.recoverReassem(r, bp, cc,
819 restart_interval_, restart_count_);
820 }
821 else
822 #endif
823 bp = reasm_.reassemble(rh, bp, cc);
824
825
826 if (bp != 0) {
827 // Spin through all the software renderers and only
828 // decode the frame if at least one renderer wants it.
829 // (e.g., in the case of a single thumbnail window,
830 // we don't want to decode the stream at full rate).
831 int doSoftwareDecode = 0;
832 /*FIXME need to make HW path work again */
833 #ifdef HW_JPEG
834 JpegFrame jf(0, (u_int8_t*)bp, cc, inq_, type_, inw_, inh_, csss_);
835 #endif
836 for (Renderer* r = engines_; r != 0; r = r->next_) {
837 if (r->update_interval() == 0 || r->need_update()) {
838 /*FIXME need to make HW path work again */
839 #ifdef HW_JPEG
840 if (r->ft() == FT_JPEG) {
841 r->consume(&jf);
842 } else
843 #endif
844 doSoftwareDecode = 1;
845 }
846 }
847 if (doSoftwareDecode) {
848 if (restart_interval_ != 0)
849 codec_->setRestartInterval(restart_interval_);
850
851 // decode the frame
852 codec_->decode(bp, cc, typeSpec, rvts_, now_);
853
854 ndblk_ = codec_->ndblk();
855 render_frame(codec_->frame(), CODEC_JPEG, inq_);
856 codec_->resetndblk();
857 }
858 }
859 pb->release();
860 }
861
862
863 void MotionJpegDecoder::redraw()
864 {
865 if (codec_ != 0) {
866 Decoder::redraw(codec_->frame());
867 }
868 }
869
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.