~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Open Mash Cross Reference
mash/codec/decoder-jpeg.cc

Component: ~ [ mash ] ~ [ apps ] ~ [ gsm ] ~ [ lib ] ~ [ otcl ] ~ [ srm ] ~ [ tcl8.3 ] ~ [ tclcl ] ~ [ tk8.3 ] ~ [ tutorials ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.